@Override
	public LoginResult completeLogin(final Session session, final MOB mob, final Room startRoom, final boolean resetStats) throws IOException
	{
		if(loginsDisabled(mob))
			return LoginResult.NO_LOGIN;
		mob.bringToLife(startRoom,resetStats);
		CMLib.coffeeTables().bump(mob,CoffeeTableRow.STAT_LOGINS);
		mob.location().showOthers(mob,startRoom,CMMsg.MASK_ALWAYS|CMMsg.MSG_ENTER,L("<S-NAME> appears!"));
		for(int f=0;f<mob.numFollowers();f++)
		{
			final MOB follower=mob.fetchFollower(f);
			if(follower==null)
				continue;
			Room R=follower.location();
			if((follower.isMonster())
			&&(!follower.isPossessing())
			&&(!CMLib.flags().isInTheGame(follower, true))
			&&((R==null)||(!R.isInhabitant(follower))))
			{
				if(R==null)
					R=mob.location();
				follower.setLocation(R);
				follower.setFollowing(mob); // before for bestow names sake
				follower.bringToLife(R,false);
				follower.setFollowing(mob);
				R.showOthers(follower,R,CMMsg.MASK_ALWAYS|CMMsg.MSG_ENTER,L("<S-NAME> appears!"));
			}
		}
		@SuppressWarnings("unchecked")
		List<Triad<String,Long,Integer>> accessed= (LinkedList<Triad<String,Long,Integer>>)Resources.staticInstance()._getResource("SYSTEM_IPACCESS_STATS");
		if(accessed != null)
		{
			synchronized(accessed)
			{
				for(final Iterator<Triad<String,Long,Integer>> i=accessed.iterator();i.hasNext();)
				{
					final Triad<String,Long,Integer> triad=i.next();
					if(triad.first.equals(session.getAddress()))
					{
						i.remove();
						break;
					}
				}
			}
		}
		final PlayerStats pstats = mob.playerStats();
		if(((pstats.getEmail()==null)||(pstats.getEmail().length()==0))
		&&(!CMProps.getVar(CMProps.Str.EMAILREQ).toUpperCase().startsWith("OPTION")))
		{
			final Command C=CMClass.getCommand("Email");
			if(C!=null)
			{
				if(!C.execute(mob,null,0))
				{
					session.stopSession(false,false,false);
					return LoginResult.NO_LOGIN;
				}
			}
			CMLib.database().DBUpdateEmail(mob);
		}
		if((pstats.getEmail()!=null)&&CMSecurity.isBanned(pstats.getEmail()))
		{
			session.println(L("\n\rYou are unwelcome.  No one likes you here. Go away.\n\r\n\r"));
			session.stopSession(false,false,false);
			return LoginResult.NO_LOGIN;
		}
		if(mob.playerStats()!=null)
			mob.playerStats().setLastIP(session.getAddress());
		notifyFriends(mob,L("^X@x1 has logged on.^.^?",mob.Name()));
		if((CMProps.getVar(CMProps.Str.PKILL).startsWith("ALWAYS"))
		&&(!mob.isAttributeSet(MOB.Attrib.PLAYERKILL)))
			mob.setAttribute(MOB.Attrib.PLAYERKILL,true);
		if((CMProps.getVar(CMProps.Str.PKILL).startsWith("NEVER"))
		&&(mob.isAttributeSet(MOB.Attrib.PLAYERKILL)))
			mob.setAttribute(MOB.Attrib.PLAYERKILL,false);
		final List<String> channels=CMLib.channels().getFlaggedChannelNames(ChannelsLibrary.ChannelFlag.LOGINS);
		if(!CMLib.flags().isCloaked(mob))
		{
			for(int i=0;i<channels.size();i++)
				CMLib.commands().postChannel(channels.get(i),mob.clans(),L("@x1 has logged on.",mob.Name()),true);
		}
		setGlobalBitmaps(mob);
		return LoginResult.NORMAL_LOGIN;
	}