From 0c55e6d24b32f2cc4e2b8106f2f4032e3197c211 Mon Sep 17 00:00:00 2001
From: brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>
Date: Thu, 15 Dec 2005 13:44:17 +0000
Subject: Moved a ton of user related functions from inspircd.cpp to users.cpp

git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@2468 e03df62e-2008-0410-955e-edbf42e46eb7
---
 src/commands.cpp |   4 +
 src/inspircd.cpp | 400 --------------------------------------------------
 src/users.cpp    | 436 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 418 insertions(+), 422 deletions(-)

(limited to 'src')

diff --git a/src/commands.cpp b/src/commands.cpp
index 8cfc4d77b..eb9d12f4e 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -2047,4 +2047,8 @@ void handle_qline(char **parameters, int pcnt, userrec *user)
 	}
 }
 
+void handle_version(char **parameters, int pcnt, userrec *user)
+{
+	        WriteServ(user->fd,"351 %s :%s",user->nick,ServerInstance->GetVersionString().c_str());
+}
 
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index 0a1eb14e6..f409fcc18 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -97,16 +97,8 @@ whowas_hash whowas;
 command_table cmdlist;
 servernamelist servernames;
 int BoundPortCount = 0;
-std::vector<userrec*> all_opers;
 char lowermap[255];
 
-
-void AddOper(userrec* user)
-{
-	log(DEBUG,"Oper added to optimization list");
-	all_opers.push_back(user);
-}
-
 void AddServerName(std::string servername)
 {
 	log(DEBUG,"Adding server name: %s",servername.c_str());
@@ -129,19 +121,6 @@ const char* FindServerNamePtr(std::string servername)
 	return FindServerNamePtr(servername);
 }
 
-void DeleteOper(userrec* user)
-{
-        for (std::vector<userrec*>::iterator a = all_opers.begin(); a < all_opers.end(); a++)
-        {
-                if (*a == user)
-                {
-                        log(DEBUG,"Oper removed from optimization list");
-                        all_opers.erase(a);
-                        return;
-                }
-        }
-}
-
 std::string InspIRCd::GetRevision()
 {
 	/* w00t got me to replace a bunch of strtok_r
@@ -324,107 +303,6 @@ int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start
 
 
 
-void kill_link(userrec *user,const char* r)
-{
-	user_hash::iterator iter = clientlist.find(user->nick);
-	
-	char reason[MAXBUF];
-	
-	strncpy(reason,r,MAXBUF);
-
-	if (strlen(reason)>MAXQUIT)
-	{
-		reason[MAXQUIT-1] = '\0';
-	}
-
-	log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
-	Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
-	log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
-
-	if (user->registered == 7) {
-		FOREACH_MOD OnUserQuit(user,reason);
-		WriteCommonExcept(user,"QUIT :%s",reason);
-	}
-
-	user->FlushWriteBuf();
-
-	FOREACH_MOD OnUserDisconnect(user);
-
-	if (user->fd > -1)
-	{
-		FOREACH_MOD OnRawSocketClose(user->fd);
-		SE->DelFd(user->fd);
-		user->CloseSocket();
-	}
-
-	// this must come before the WriteOpers so that it doesnt try to fill their buffer with anything
-	// if they were an oper with +s.
-        if (user->registered == 7) {
-                purge_empty_chans(user);
-		// fix by brain: only show local quits because we only show local connects (it just makes SENSE)
-		if (user->fd > -1)
-			WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
-		AddWhoWas(user);
-	}
-
-	if (iter != clientlist.end())
-	{
-		log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
-		if (user->fd > -1)
-			fd_ref_table[user->fd] = NULL;
-		clientlist.erase(iter);
-	}
-	delete user;
-}
-
-void kill_link_silent(userrec *user,const char* r)
-{
-	user_hash::iterator iter = clientlist.find(user->nick);
-	
-	char reason[MAXBUF];
-	
-	strncpy(reason,r,MAXBUF);
-
-	if (strlen(reason)>MAXQUIT)
-	{
-		reason[MAXQUIT-1] = '\0';
-	}
-
-	log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
-	Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
-	log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
-
-	user->FlushWriteBuf();
-
-	if (user->registered == 7) {
-		FOREACH_MOD OnUserQuit(user,reason);
-		WriteCommonExcept(user,"QUIT :%s",reason);
-	}
-
-	FOREACH_MOD OnUserDisconnect(user);
-
-        if (user->fd > -1)
-        {
-		FOREACH_MOD OnRawSocketClose(user->fd);
-		SE->DelFd(user->fd);
-		user->CloseSocket();
-        }
-
-        if (user->registered == 7) {
-                purge_empty_chans(user);
-        }
-	
-	if (iter != clientlist.end())
-	{
-		log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
-                if (user->fd > -1)
-                        fd_ref_table[user->fd] = NULL;
-		clientlist.erase(iter);
-	}
-	delete user;
-}
-
-
 InspIRCd::InspIRCd(int argc, char** argv)
 {
 	Start();
@@ -536,59 +414,6 @@ userrec* ReHashNick(char* Old, char* New)
 	return clientlist[New];
 }
 
-/* adds or updates an entry in the whowas list */
-void AddWhoWas(userrec* u)
-{
-	whowas_hash::iterator iter = whowas.find(u->nick);
-	WhoWasUser *a = new WhoWasUser();
-	strlcpy(a->nick,u->nick,NICKMAX);
-	strlcpy(a->ident,u->ident,IDENTMAX);
-	strlcpy(a->dhost,u->dhost,160);
-	strlcpy(a->host,u->host,160);
-	strlcpy(a->fullname,u->fullname,MAXGECOS);
-	strlcpy(a->server,u->server,256);
-	a->signon = u->signon;
-
-	/* MAX_WHOWAS:   max number of /WHOWAS items
-	 * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
-	 *		 can be replaced by a newer one
-	 */
-	
-	if (iter == whowas.end())
-	{
-		if (whowas.size() >= (unsigned)WHOWAS_MAX)
-		{
-			for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
-			{
-				// 3600 seconds in an hour ;)
-				if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600)))
-				{
-					// delete the old one
-					if (i->second) delete i->second;
-					// replace with new one
-					i->second = a;
-					log(DEBUG,"added WHOWAS entry, purged an old record");
-					return;
-				}
-			}
-			// no space left and user doesnt exist. Don't leave ram in use!
-			log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram");
-			delete a;
-		}
-		else
-		{
-			log(DEBUG,"added fresh WHOWAS entry");
-			whowas[a->nick] = a;
-		}
-	}
-	else
-	{
-		log(DEBUG,"updated WHOWAS entry");
-		if (iter->second) delete iter->second;
-		iter->second = a;
-	}
-}
-
 #ifdef THREADED_DNS
 void* dns_task(void* arg)
 {
@@ -635,226 +460,6 @@ void* dns_task(void* arg)
 }
 #endif
 
-/* add a client connection to the sockets list */
-void AddClient(int socket, char* host, int port, bool iscached, char* ip)
-{
-	string tempnick;
-	char tn2[MAXBUF];
-	user_hash::iterator iter;
-
-	tempnick = ConvToStr(socket) + "-unknown";
-	sprintf(tn2,"%lu-unknown",(unsigned long)socket);
-
-	iter = clientlist.find(tempnick);
-
-	// fix by brain.
-	// as these nicknames are 'RFC impossible', we can be sure nobody is going to be
-	// using one as a registered connection. As theyre per fd, we can also safely assume
-	// that we wont have collisions. Therefore, if the nick exists in the list, its only
-	// used by a dead socket, erase the iterator so that the new client may reclaim it.
-	// this was probably the cause of 'server ignores me when i hammer it with reconnects'
-	// issue in earlier alphas/betas
-	if (iter != clientlist.end())
-	{
-		userrec* goner = iter->second;
-		delete goner;
-		clientlist.erase(iter);
-	}
-
-	/*
-	 * It is OK to access the value here this way since we know
-	 * it exists, we just created it above.
-	 *
-	 * At NO other time should you access a value in a map or a
-	 * hash_map this way.
-	 */
-	clientlist[tempnick] = new userrec();
-
-	NonBlocking(socket);
-	log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip);
-
-	clientlist[tempnick]->fd = socket;
-	strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX);
-	strlcpy(clientlist[tempnick]->host, host,160);
-	strlcpy(clientlist[tempnick]->dhost, host,160);
-	clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName);
-	strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX);
-	clientlist[tempnick]->registered = 0;
-	clientlist[tempnick]->signon = TIME + Config->dns_timeout;
-	clientlist[tempnick]->lastping = 1;
-	clientlist[tempnick]->port = port;
-	strlcpy(clientlist[tempnick]->ip,ip,16);
-
-	// set the registration timeout for this user
-	unsigned long class_regtimeout = 90;
-	int class_flood = 0;
-	long class_threshold = 5;
-	long class_sqmax = 262144;	// 256kb
-	long class_rqmax = 4096;	// 4k
-
-	for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
-	{
-		if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW))
-		{
-			class_regtimeout = (unsigned long)i->registration_timeout;
-			class_flood = i->flood;
-			clientlist[tempnick]->pingmax = i->pingtime;
-			class_threshold = i->threshold;
-			class_sqmax = i->sendqmax;
-			class_rqmax = i->recvqmax;
-			break;
-		}
-	}
-
-	clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax + Config->dns_timeout;
-	clientlist[tempnick]->timeout = TIME+class_regtimeout;
-	clientlist[tempnick]->flood = class_flood;
-	clientlist[tempnick]->threshold = class_threshold;
-	clientlist[tempnick]->sendqmax = class_sqmax;
-	clientlist[tempnick]->recvqmax = class_rqmax;
-
-	ucrec a;
-	a.channel = NULL;
-	a.uc_modes = 0;
-	for (int i = 0; i < MAXCHANS; i++)
-		clientlist[tempnick]->chans.push_back(a);
-
-	if (clientlist.size() > Config->SoftLimit)
-	{
-		kill_link(clientlist[tempnick],"No more connections allowed");
-		return;
-	}
-
-	if (clientlist.size() >= MAXCLIENTS)
-	{
-		kill_link(clientlist[tempnick],"No more connections allowed");
-		return;
-	}
-
-	// this is done as a safety check to keep the file descriptors within range of fd_ref_table.
-	// its a pretty big but for the moment valid assumption:
-	// file descriptors are handed out starting at 0, and are recycled as theyre freed.
-	// therefore if there is ever an fd over 65535, 65536 clients must be connected to the
-	// irc server at once (or the irc server otherwise initiating this many connections, files etc)
-	// which for the time being is a physical impossibility (even the largest networks dont have more
-	// than about 10,000 users on ONE server!)
-	if ((unsigned)socket > 65534)
-	{
-		kill_link(clientlist[tempnick],"Server is full");
-		return;
-	}
-		
-
-        char* e = matches_exception(ip);
-	if (!e)
-	{
-		char* r = matches_zline(ip);
-		if (r)
-		{
-			char reason[MAXBUF];
-			snprintf(reason,MAXBUF,"Z-Lined: %s",r);
-			kill_link(clientlist[tempnick],reason);
-			return;
-		}
-	}
-	fd_ref_table[socket] = clientlist[tempnick];
-	SE->AddFd(socket,true,X_ESTAB_CLIENT);
-}
-
-/* shows the message of the day, and any other on-logon stuff */
-void FullConnectUser(userrec* user)
-{
-	stats->statsConnects++;
-        user->idle_lastmsg = TIME;
-        log(DEBUG,"ConnectUser: %s",user->nick);
-
-        if ((strcmp(Passwd(user),"")) && (!user->haspassed))
-        {
-                kill_link(user,"Invalid password");
-                return;
-        }
-        if (IsDenied(user))
-        {
-                kill_link(user,"Unauthorised connection");
-                return;
-        }
-
-        char match_against[MAXBUF];
-        snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host);
-	char* e = matches_exception(match_against);
-	if (!e)
-	{
-        	char* r = matches_gline(match_against);
-        	if (r)
-        	{
-                	char reason[MAXBUF];
-                	snprintf(reason,MAXBUF,"G-Lined: %s",r);
-                	kill_link_silent(user,reason);
-                	return;
-        	}
-        	r = matches_kline(user->host);
-        	if (r)
-        	{
-                	char reason[MAXBUF];
-                	snprintf(reason,MAXBUF,"K-Lined: %s",r);
-                	kill_link_silent(user,reason);
-                	return;
-	        }
-	}
-
-
-        WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Config->Network);
-        WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Config->Network,user->nick,user->ident,user->host);
-        WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,Config->ServerName,VERSION);
-        WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
-        WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,Config->ServerName,VERSION);
-        // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...
-        std::stringstream v;
-        v << "WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS;
-        v << " MAXBANS=60 NICKLEN=" << NICKMAX;
-        v << " TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=20 AWAYLEN=" << MAXAWAY << " CHANMODES=ohvb,k,l,psmnti NETWORK=";
-        v << Config->Network;
-        std::string data005 = v.str();
-        FOREACH_MOD On005Numeric(data005);
-        // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line...
-        // so i'd better split it :)
-        std::stringstream out(data005);
-        std::string token = "";
-        std::string line5 = "";
-        int token_counter = 0;
-        while (!out.eof())
-        {
-                out >> token;
-                line5 = line5 + token + " ";
-                token_counter++;
-                if ((token_counter >= 13) || (out.eof() == true))
-                {
-                        WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str());
-                        line5 = "";
-                        token_counter = 0;
-                }
-        }
-        ShowMOTD(user);
-
-	// fix 3 by brain, move registered = 7 below these so that spurious modes and host changes dont go out
-	// onto the network and produce 'fake direction'
-	FOREACH_MOD OnUserConnect(user);
-	FOREACH_MOD OnGlobalConnect(user);
-	user->registered = 7;
-	WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip);
-}
-
-
-/* shows the message of the day, and any other on-logon stuff */
-void ConnectUser(userrec *user)
-{
-	// dns is already done, things are fast. no need to wait for dns to complete just pass them straight on
-	if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user)))
-	{
-		FullConnectUser(user);
-	}
-}
-
 std::string InspIRCd::GetVersionString()
 {
 	char versiondata[MAXBUF];
@@ -867,11 +472,6 @@ std::string InspIRCd::GetVersionString()
 	return versiondata;
 }
 
-void handle_version(char **parameters, int pcnt, userrec *user)
-{
-	WriteServ(user->fd,"351 %s :%s",user->nick,ServerInstance->GetVersionString().c_str());
-}
-
 
 bool is_valid_cmd(const char* commandname, int pcnt, userrec * user)
 {
diff --git a/src/users.cpp b/src/users.cpp
index 35279cee6..06c34955e 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -32,6 +32,7 @@ using namespace std;
 
 extern ServerConfig* Config;
 extern time_t TIME;
+std::vector<userrec*> all_opers;
 
 userrec::userrec()
 {
@@ -93,12 +94,14 @@ char* userrec::GetFullRealHost()
 	return fresult;
 }
 
-bool userrec::IsInvited(char* channel)
+bool userrec::IsInvited(irc::string &channel)
 {
 	for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
 	{
-		if (i->channel) {
-			if (!strcasecmp(i->channel,channel))
+		if (i->channel)
+		{
+			irc::string compare = i->channel;
+			if (compare == channel)
 			{
 				return true;
 			}
@@ -112,36 +115,34 @@ InvitedList* userrec::GetInviteList()
 	return &invites;
 }
 
-void userrec::InviteTo(char* channel)
+void userrec::InviteTo(irc::string &channel)
 {
 	Invited i;
-	strlcpy(i.channel,channel,CHANMAX);
+	i.channel = channel;
 	invites.push_back(i);
 }
 
-void userrec::RemoveInvite(char* channel)
+void userrec::RemoveInvite(std::string &channel)
 {
 	log(DEBUG,"Removing invites");
-	if (channel)
+	if (invites.size())
 	{
-		if (invites.size())
+		for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
 		{
- 			for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
- 			{
-				if (i->channel)
+			if (i->channel)
+			{
+				irc::string compare = i->channel;
+				if (compare == channel)
 				{
-					if (!strcasecmp(i->channel,channel))
-					{
-						invites.erase(i);
-						return;
-		       	         	}
-				}
-        		}
-        	}
-        }
+					invites.erase(i);
+					return;
+	       	         	}
+			}
+       		}
+       	}
 }
 
-bool userrec::HasPermission(char* command)
+bool userrec::HasPermission(std::string &command)
 {
 	char TypeName[MAXBUF],Classes[MAXBUF],ClassName[MAXBUF],CommandList[MAXBUF];
 	char* mycmd;
@@ -178,7 +179,7 @@ bool userrec::HasPermission(char* command)
 							mycmd = strtok_r(CommandList," ",&savept2);
 							while (mycmd)
 							{
-								if ((!strcasecmp(mycmd,command)) || (*mycmd == '*'))
+								if ((!strcasecmp(mycmd,command.c_str())) || (*mycmd == '*'))
 								{
 									return true;
 								}
@@ -301,3 +302,394 @@ std::string userrec::GetWriteError()
 {
 	return this->WriteError;
 }
+
+void AddOper(userrec* user)
+{
+        log(DEBUG,"Oper added to optimization list");
+        all_opers.push_back(user);
+}
+
+void DeleteOper(userrec* user)
+{
+        for (std::vector<userrec*>::iterator a = all_opers.begin(); a < all_opers.end(); a++)
+        {
+                if (*a == user)
+                {
+                        log(DEBUG,"Oper removed from optimization list");
+                        all_opers.erase(a);
+                        return;
+                }
+        }
+}
+
+void kill_link(userrec *user,const char* r)
+{
+        user_hash::iterator iter = clientlist.find(user->nick);
+
+        char reason[MAXBUF];
+
+        strncpy(reason,r,MAXBUF);
+
+        if (strlen(reason)>MAXQUIT)
+        {
+                reason[MAXQUIT-1] = '\0';
+        }
+
+        log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
+        Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
+        log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
+
+        if (user->registered == 7) {
+                FOREACH_MOD OnUserQuit(user,reason);
+                WriteCommonExcept(user,"QUIT :%s",reason);
+        }
+
+        user->FlushWriteBuf();
+
+        FOREACH_MOD OnUserDisconnect(user);
+
+        if (user->fd > -1)
+        {
+                FOREACH_MOD OnRawSocketClose(user->fd);
+                SE->DelFd(user->fd);
+                user->CloseSocket();
+        }
+
+        // this must come before the WriteOpers so that it doesnt try to fill their buffer with anything
+        // if they were an oper with +s.
+        if (user->registered == 7) {
+                purge_empty_chans(user);
+                // fix by brain: only show local quits because we only show local connects (it just makes SENSE)
+                if (user->fd > -1)
+                        WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
+                AddWhoWas(user);
+        }
+
+        if (iter != clientlist.end())
+        {
+                log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
+                if (user->fd > -1)
+                        fd_ref_table[user->fd] = NULL;
+                clientlist.erase(iter);
+        }
+        delete user;
+}
+
+void kill_link_silent(userrec *user,const char* r)
+{
+        user_hash::iterator iter = clientlist.find(user->nick);
+
+        char reason[MAXBUF];
+
+        strncpy(reason,r,MAXBUF);
+
+        if (strlen(reason)>MAXQUIT)
+        {
+                reason[MAXQUIT-1] = '\0';
+        }
+
+        log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
+        Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
+        log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
+
+        user->FlushWriteBuf();
+
+        if (user->registered == 7) {
+                FOREACH_MOD OnUserQuit(user,reason);
+                WriteCommonExcept(user,"QUIT :%s",reason);
+        }
+
+        FOREACH_MOD OnUserDisconnect(user);
+
+        if (user->fd > -1)
+        {
+                FOREACH_MOD OnRawSocketClose(user->fd);
+                SE->DelFd(user->fd);
+                user->CloseSocket();
+        }
+
+        if (user->registered == 7) {
+                purge_empty_chans(user);
+        }
+
+        if (iter != clientlist.end())
+        {
+                log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
+                if (user->fd > -1)
+                        fd_ref_table[user->fd] = NULL;
+                clientlist.erase(iter);
+        }
+        delete user;
+}
+
+
+/* adds or updates an entry in the whowas list */
+void AddWhoWas(userrec* u)
+{
+        whowas_hash::iterator iter = whowas.find(u->nick);
+        WhoWasUser *a = new WhoWasUser();
+        strlcpy(a->nick,u->nick,NICKMAX);
+        strlcpy(a->ident,u->ident,IDENTMAX);
+        strlcpy(a->dhost,u->dhost,160);
+        strlcpy(a->host,u->host,160);
+        strlcpy(a->fullname,u->fullname,MAXGECOS);
+        strlcpy(a->server,u->server,256);
+        a->signon = u->signon;
+
+        /* MAX_WHOWAS:   max number of /WHOWAS items
+         * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
+         *               can be replaced by a newer one
+         */
+
+        if (iter == whowas.end())
+        {
+                if (whowas.size() >= (unsigned)WHOWAS_MAX)
+                {
+                        for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
+                        {
+                                // 3600 seconds in an hour ;)
+                                if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600)))
+                                {
+                                        // delete the old one
+                                        if (i->second) delete i->second;
+                                        // replace with new one
+                                        i->second = a;
+                                        log(DEBUG,"added WHOWAS entry, purged an old record");
+                                        return;
+                                }
+                        }
+                        // no space left and user doesnt exist. Don't leave ram in use!
+                        log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram");
+                        delete a;
+                }
+                else
+                {
+                        log(DEBUG,"added fresh WHOWAS entry");
+                        whowas[a->nick] = a;
+                }
+        }
+        else
+        {
+                log(DEBUG,"updated WHOWAS entry");
+                if (iter->second) delete iter->second;
+                iter->second = a;
+        }
+}
+
+/* add a client connection to the sockets list */
+void AddClient(int socket, char* host, int port, bool iscached, char* ip)
+{
+        string tempnick;
+        char tn2[MAXBUF];
+        user_hash::iterator iter;
+
+        tempnick = ConvToStr(socket) + "-unknown";
+        sprintf(tn2,"%lu-unknown",(unsigned long)socket);
+
+        iter = clientlist.find(tempnick);
+
+        // fix by brain.
+        // as these nicknames are 'RFC impossible', we can be sure nobody is going to be
+        // using one as a registered connection. As theyre per fd, we can also safely assume
+        // that we wont have collisions. Therefore, if the nick exists in the list, its only
+        // used by a dead socket, erase the iterator so that the new client may reclaim it.
+        // this was probably the cause of 'server ignores me when i hammer it with reconnects'
+        // issue in earlier alphas/betas
+        if (iter != clientlist.end())
+        {
+                userrec* goner = iter->second;
+                delete goner;
+                clientlist.erase(iter);
+        }
+
+        /*
+         * It is OK to access the value here this way since we know
+         * it exists, we just created it above.
+         *
+         * At NO other time should you access a value in a map or a
+         * hash_map this way.
+         */
+        clientlist[tempnick] = new userrec();
+
+        NonBlocking(socket);
+        log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip);
+
+        clientlist[tempnick]->fd = socket;
+        strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX);
+        strlcpy(clientlist[tempnick]->host, host,160);
+        strlcpy(clientlist[tempnick]->dhost, host,160);
+        clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName);
+        strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX);
+        clientlist[tempnick]->registered = 0;
+        clientlist[tempnick]->signon = TIME + Config->dns_timeout;
+        clientlist[tempnick]->lastping = 1;
+        clientlist[tempnick]->port = port;
+        strlcpy(clientlist[tempnick]->ip,ip,16);
+
+        // set the registration timeout for this user
+        unsigned long class_regtimeout = 90;
+        int class_flood = 0;
+        long class_threshold = 5;
+        long class_sqmax = 262144;      // 256kb
+        long class_rqmax = 4096;        // 4k
+
+        for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
+        {
+                if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW))
+                {
+                        class_regtimeout = (unsigned long)i->registration_timeout;
+                        class_flood = i->flood;
+                        clientlist[tempnick]->pingmax = i->pingtime;
+                        class_threshold = i->threshold;
+                        class_sqmax = i->sendqmax;
+                        class_rqmax = i->recvqmax;
+                        break;
+                }
+        }
+
+        clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax + Config->dns_timeout;
+        clientlist[tempnick]->timeout = TIME+class_regtimeout;
+        clientlist[tempnick]->flood = class_flood;
+        clientlist[tempnick]->threshold = class_threshold;
+        clientlist[tempnick]->sendqmax = class_sqmax;
+        clientlist[tempnick]->recvqmax = class_rqmax;
+
+        ucrec a;
+        a.channel = NULL;
+        a.uc_modes = 0;
+        for (int i = 0; i < MAXCHANS; i++)
+                clientlist[tempnick]->chans.push_back(a);
+
+        if (clientlist.size() > Config->SoftLimit)
+        {
+                kill_link(clientlist[tempnick],"No more connections allowed");
+                return;
+        }
+
+        if (clientlist.size() >= MAXCLIENTS)
+        {
+                kill_link(clientlist[tempnick],"No more connections allowed");
+                return;
+        }
+
+        // this is done as a safety check to keep the file descriptors within range of fd_ref_table.
+        // its a pretty big but for the moment valid assumption:
+        // file descriptors are handed out starting at 0, and are recycled as theyre freed.
+        // therefore if there is ever an fd over 65535, 65536 clients must be connected to the
+        // irc server at once (or the irc server otherwise initiating this many connections, files etc)
+        // which for the time being is a physical impossibility (even the largest networks dont have more
+        // than about 10,000 users on ONE server!)
+        if ((unsigned)socket > 65534)
+        {
+                kill_link(clientlist[tempnick],"Server is full");
+                return;
+        }
+        char* e = matches_exception(ip);
+        if (!e)
+        {
+                char* r = matches_zline(ip);
+                if (r)
+                {
+                        char reason[MAXBUF];
+                        snprintf(reason,MAXBUF,"Z-Lined: %s",r);
+                        kill_link(clientlist[tempnick],reason);
+                        return;
+                }
+        }
+        fd_ref_table[socket] = clientlist[tempnick];
+        SE->AddFd(socket,true,X_ESTAB_CLIENT);
+}
+
+void FullConnectUser(userrec* user)
+{
+        stats->statsConnects++;
+        user->idle_lastmsg = TIME;
+        log(DEBUG,"ConnectUser: %s",user->nick);
+
+        if ((strcmp(Passwd(user),"")) && (!user->haspassed))
+        {
+                kill_link(user,"Invalid password");
+                return;
+        }
+        if (IsDenied(user))
+        {
+                kill_link(user,"Unauthorised connection");
+                return;
+        }
+
+        char match_against[MAXBUF];
+        snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host);
+        char* e = matches_exception(match_against);
+        if (!e)
+        {
+                char* r = matches_gline(match_against);
+                if (r)
+                {
+                        char reason[MAXBUF];
+                        snprintf(reason,MAXBUF,"G-Lined: %s",r);
+                        kill_link_silent(user,reason);
+                        return;
+                }
+                r = matches_kline(user->host);
+                if (r)
+                {
+                        char reason[MAXBUF];
+                        snprintf(reason,MAXBUF,"K-Lined: %s",r);
+                        kill_link_silent(user,reason);
+                        return;
+                }
+        }
+
+
+        WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Config->Network);
+        WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Config->Network,user->nick,user->ident,user->host);
+        WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,Config->ServerName,VERSION);
+        WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
+        WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,Config->ServerName,VERSION);
+        // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...
+        std::stringstream v;
+        v << "WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS;
+        v << " MAXBANS=60 NICKLEN=" << NICKMAX;
+        v << " TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=20 AWAYLEN=" << MAXAWAY << " CHANMODES=ohvb,k,l,psmnti NETWORK=";
+        v << Config->Network;
+        std::string data005 = v.str();
+        FOREACH_MOD On005Numeric(data005);
+        // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line...
+        // so i'd better split it :)
+        std::stringstream out(data005);
+        std::string token = "";
+        std::string line5 = "";
+        int token_counter = 0;
+        while (!out.eof())
+        {
+                out >> token;
+                line5 = line5 + token + " ";
+                token_counter++;
+                if ((token_counter >= 13) || (out.eof() == true))
+                {
+                        WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str());
+                        line5 = "";
+                        token_counter = 0;
+                }
+        }
+        ShowMOTD(user);
+
+        // fix 3 by brain, move registered = 7 below these so that spurious modes and host changes dont go out
+        // onto the network and produce 'fake direction'
+        FOREACH_MOD OnUserConnect(user);
+        FOREACH_MOD OnGlobalConnect(user);
+        user->registered = 7;
+        WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip);
+}
+
+
+/* shows the message of the day, and any other on-logon stuff */
+void ConnectUser(userrec *user)
+{
+        // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on
+        if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user)))
+        {
+                FullConnectUser(user);
+        }
+}
+
-- 
cgit v1.2.3