Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

users.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
00006  *                       E-mail:
00007  *                <brain@chatspike.net>
00008  *                <Craig@chatspike.net>
00009  *     
00010  * Written by Craig Edwards, Craig McLure, and others.
00011  * This program is free but copyrighted software; see
00012  *            the file COPYING for details.
00013  *
00014  * ---------------------------------------------------
00015  */
00016 
00017 using namespace std;
00018 
00019 #include "inspircd_config.h" 
00020 #include "channels.h"
00021 #include "connection.h"
00022 #include "users.h"
00023 #include "inspircd.h"
00024 #include <stdio.h>
00025 #ifdef THREADED_DNS
00026 #include <pthread.h>
00027 #include <signal.h>
00028 #endif
00029 #include "inspstring.h"
00030 #include "commands.h"
00031 #include "helperfuncs.h"
00032 #include "typedefs.h"
00033 #include "socketengine.h"
00034 #include "hashcomp.h"
00035 #include "message.h"
00036 #include "wildcard.h"
00037 #include "xline.h"
00038 
00039 extern InspIRCd* ServerInstance;
00040 extern int WHOWAS_STALE;
00041 extern int WHOWAS_MAX;
00042 extern std::vector<Module*> modules;
00043 extern std::vector<ircd_module*> factory;
00044 extern std::vector<InspSocket*> module_sockets;
00045 extern int MODCOUNT;
00046 extern InspSocket* socket_ref[65535];
00047 extern time_t TIME;
00048 extern userrec* fd_ref_table[65536];
00049 extern ServerConfig *Config;
00050 extern user_hash clientlist;
00051 extern whowas_hash whowas;
00052 std::vector<userrec*> local_users;
00053 
00054 std::vector<userrec*> all_opers;
00055 
00056 template<typename T> inline string ConvToStr(const T &in)
00057 {
00058         stringstream tmp;
00059         if (!(tmp << in)) return string();
00060         return tmp.str();
00061 }
00062 
00063 userrec::userrec()
00064 {
00065         // the PROPER way to do it, AVOID bzero at *ALL* costs
00066         strcpy(nick,"");
00067         strcpy(ip,"127.0.0.1");
00068         timeout = 0;
00069         strcpy(ident,"");
00070         strcpy(host,"");
00071         strcpy(dhost,"");
00072         strcpy(fullname,"");
00073         strcpy(modes,"");
00074         server = (char*)FindServerNamePtr(Config->ServerName);
00075         strcpy(awaymsg,"");
00076         strcpy(oper,"");
00077         reset_due = TIME;
00078         lines_in = 0;
00079         fd = lastping = signon = idle_lastmsg = nping = registered = 0;
00080         flood = port = bytes_in = bytes_out = cmds_in = cmds_out = 0;
00081         haspassed = false;
00082         dns_done = false;
00083         recvq = "";
00084         sendq = "";
00085         chans.clear();
00086         invites.clear();
00087 }
00088 
00089 userrec::~userrec()
00090 {
00091 }
00092 
00093 void userrec::CloseSocket()
00094 {
00095         shutdown(this->fd,2);
00096         close(this->fd);
00097 }
00098  
00099 char* userrec::GetFullHost()
00100 {
00101         static char result[MAXBUF];
00102         snprintf(result,MAXBUF,"%s!%s@%s",nick,ident,dhost);
00103         return result;
00104 }
00105 
00106 int userrec::ReadData(void* buffer, size_t size)
00107 {
00108         if (this->fd > -1)
00109         {
00110                 return read(this->fd, buffer, size);
00111         }
00112         else return 0;
00113 }
00114 
00115 
00116 char* userrec::GetFullRealHost()
00117 {
00118         static char fresult[MAXBUF];
00119         snprintf(fresult,MAXBUF,"%s!%s@%s",nick,ident,host);
00120         return fresult;
00121 }
00122 
00123 bool userrec::IsInvited(irc::string &channel)
00124 {
00125         for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
00126         {
00127                 irc::string compare = i->channel;
00128                 if (compare == channel)
00129                 {
00130                         return true;
00131                 }
00132         }
00133         return false;
00134 }
00135 
00136 InvitedList* userrec::GetInviteList()
00137 {
00138         return &invites;
00139 }
00140 
00141 void userrec::InviteTo(irc::string &channel)
00142 {
00143         Invited i;
00144         i.channel = channel;
00145         invites.push_back(i);
00146 }
00147 
00148 void userrec::RemoveInvite(irc::string &channel)
00149 {
00150         log(DEBUG,"Removing invites");
00151         if (invites.size())
00152         {
00153                 for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
00154                 {
00155                         irc::string compare = i->channel;
00156                         if (compare == channel)
00157                         {
00158                                 invites.erase(i);
00159                                 return;
00160                         }
00161                 }
00162         }
00163 }
00164 
00165 bool userrec::HasPermission(std::string &command)
00166 {
00167         char TypeName[MAXBUF],Classes[MAXBUF],ClassName[MAXBUF],CommandList[MAXBUF];
00168         char* mycmd;
00169         char* savept;
00170         char* savept2;
00171         
00172         // users on u-lined servers can completely bypass
00173         // all permissions based checks.
00174         //
00175         // of course, if this is sent to a remote server and this
00176         // server is not ulined there, then that other server
00177         // silently drops the command.
00178         if (is_uline(this->server))
00179                 return true;
00180         
00181         // are they even an oper at all?
00182         if (strchr(this->modes,'o'))
00183         {
00184                 for (int j =0; j < Config->ConfValueEnum("type",&Config->config_f); j++)
00185                 {
00186                         Config->ConfValue("type","name",j,TypeName,&Config->config_f);
00187                         if (!strcmp(TypeName,this->oper))
00188                         {
00189                                 Config->ConfValue("type","classes",j,Classes,&Config->config_f);
00190                                 char* myclass = strtok_r(Classes," ",&savept);
00191                                 while (myclass)
00192                                 {
00193                                         for (int k =0; k < Config->ConfValueEnum("class",&Config->config_f); k++)
00194                                         {
00195                                                 Config->ConfValue("class","name",k,ClassName,&Config->config_f);
00196                                                 if (!strcmp(ClassName,myclass))
00197                                                 {
00198                                                         Config->ConfValue("class","commands",k,CommandList,&Config->config_f);
00199                                                         mycmd = strtok_r(CommandList," ",&savept2);
00200                                                         while (mycmd)
00201                                                         {
00202                                                                 if ((!strcasecmp(mycmd,command.c_str())) || (*mycmd == '*'))
00203                                                                 {
00204                                                                         return true;
00205                                                                 }
00206                                                                 mycmd = strtok_r(NULL," ",&savept2);
00207                                                         }
00208                                                 }
00209                                         }
00210                                         myclass = strtok_r(NULL," ",&savept);
00211                                 }
00212                         }
00213                 }
00214         }
00215         return false;
00216 }
00217 
00218 
00219 bool userrec::AddBuffer(std::string a)
00220 {
00221         std::string b = "";
00222         for (unsigned int i = 0; i < a.length(); i++)
00223                 if ((a[i] != '\r') && (a[i] != '\0') && (a[i] != 7))
00224                         b = b + a[i];
00225         std::stringstream stream(recvq);
00226         stream << b;
00227         recvq = stream.str();
00228         unsigned int i = 0;
00229         // count the size of the first line in the buffer.
00230         while (i < recvq.length())
00231         {
00232                 if (recvq[i++] == '\n')
00233                         break;
00234         }
00235         if (recvq.length() > (unsigned)this->recvqmax)
00236         {
00237                 this->SetWriteError("RecvQ exceeded");
00238                 WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax);
00239         }
00240         // return false if we've had more than 600 characters WITHOUT
00241         // a carriage return (this is BAD, drop the socket)
00242         return (i < 600);
00243 }
00244 
00245 bool userrec::BufferIsReady()
00246 {
00247         for (unsigned int i = 0; i < recvq.length(); i++)
00248                 if (recvq[i] == '\n')
00249                         return true;
00250         return false;
00251 }
00252 
00253 void userrec::ClearBuffer()
00254 {
00255         recvq = "";
00256 }
00257 
00258 std::string userrec::GetBuffer()
00259 {
00260         if (recvq == "")
00261                 return "";
00262         char* line = (char*)recvq.c_str();
00263         std::string ret = "";
00264         while ((*line != '\n') && (strlen(line)))
00265         {
00266                 ret = ret + *line;
00267                 line++;
00268         }
00269         if ((*line == '\n') || (*line == '\r'))
00270                 line++;
00271         recvq = line;
00272         return ret;
00273 }
00274 
00275 void userrec::AddWriteBuf(std::string data)
00276 {
00277         if (this->GetWriteError() != "")
00278                 return;
00279         if (sendq.length() + data.length() > (unsigned)this->sendqmax)
00280         {
00281                 /* Fix by brain - Set the error text BEFORE calling writeopers, because
00282                  * if we dont it'll recursively  call here over and over again trying
00283                  * to repeatedly add the text to the sendq!
00284                  */
00285                 this->SetWriteError("SendQ exceeded");
00286                 WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax);
00287                 return;
00288         }
00289         std::stringstream stream;
00290         stream << sendq << data;
00291         sendq = stream.str();
00292 }
00293 
00294 // send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
00295 void userrec::FlushWriteBuf()
00296 {
00297         if (sendq.length())
00298         {
00299                 char* tb = (char*)this->sendq.c_str();
00300                 int n_sent = write(this->fd,tb,this->sendq.length());
00301                 if (n_sent == -1)
00302                 {
00303                         this->SetWriteError(strerror(errno));
00304                 }
00305                 else
00306                 {
00307                         // advance the queue
00308                         tb += n_sent;
00309                         this->sendq = tb;
00310                         // update the user's stats counters
00311                         this->bytes_out += n_sent;
00312                         this->cmds_out++;
00313                 }
00314         }
00315 }
00316 
00317 void userrec::SetWriteError(std::string error)
00318 {
00319         log(DEBUG,"Setting error string for %s to '%s'",this->nick,error.c_str());
00320         // don't try to set the error twice, its already set take the first string.
00321         if (this->WriteError == "")
00322                 this->WriteError = error;
00323 }
00324 
00325 std::string userrec::GetWriteError()
00326 {
00327         return this->WriteError;
00328 }
00329 
00330 void AddOper(userrec* user)
00331 {
00332         log(DEBUG,"Oper added to optimization list");
00333         all_opers.push_back(user);
00334 }
00335 
00336 void DeleteOper(userrec* user)
00337 {
00338         for (std::vector<userrec*>::iterator a = all_opers.begin(); a < all_opers.end(); a++)
00339         {
00340                 if (*a == user)
00341                 {
00342                         log(DEBUG,"Oper removed from optimization list");
00343                         all_opers.erase(a);
00344                         return;
00345                 }
00346         }
00347 }
00348 
00349 void kill_link(userrec *user,const char* r)
00350 {
00351         user_hash::iterator iter = clientlist.find(user->nick);
00352 
00353         char reason[MAXBUF];
00354 
00355         strncpy(reason,r,MAXBUF);
00356 
00357         if (strlen(reason)>MAXQUIT)
00358         {
00359                 reason[MAXQUIT-1] = '\0';
00360         }
00361 
00362         log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
00363         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
00364         log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
00365 
00366         if (user->registered == 7) {
00367                 FOREACH_MOD OnUserQuit(user,reason);
00368                 WriteCommonExcept(user,"QUIT :%s",reason);
00369         }
00370 
00371         user->FlushWriteBuf();
00372 
00373         FOREACH_MOD OnUserDisconnect(user);
00374 
00375         if (user->fd > -1)
00376         {
00377                 if (Config->GetIOHook(user->port))
00378                 {
00379                         Config->GetIOHook(user->port)->OnRawSocketClose(user->fd);
00380                 }
00381                 ServerInstance->SE->DelFd(user->fd);
00382                 user->CloseSocket();
00383         }
00384 
00385         // this must come before the WriteOpers so that it doesnt try to fill their buffer with anything
00386         // if they were an oper with +s.
00387         if (user->registered == 7) {
00388                 purge_empty_chans(user);
00389                 // fix by brain: only show local quits because we only show local connects (it just makes SENSE)
00390                 if (user->fd > -1)
00391                         WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
00392                 AddWhoWas(user);
00393         }
00394 
00395         if (iter != clientlist.end())
00396         {
00397                 log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
00398                 if (user->fd > -1)
00399                 {
00400                         fd_ref_table[user->fd] = NULL;
00401                         if (find(local_users.begin(),local_users.end(),user) != local_users.end())
00402                         {
00403                                 local_users.erase(find(local_users.begin(),local_users.end(),user));
00404                                 log(DEBUG,"Delete local user");
00405                         }
00406                 }
00407                 clientlist.erase(iter);
00408         }
00409         delete user;
00410 }
00411 
00412 void kill_link_silent(userrec *user,const char* r)
00413 {
00414         user_hash::iterator iter = clientlist.find(user->nick);
00415 
00416         char reason[MAXBUF];
00417 
00418         strncpy(reason,r,MAXBUF);
00419 
00420         if (strlen(reason)>MAXQUIT)
00421         {
00422                 reason[MAXQUIT-1] = '\0';
00423         }
00424 
00425         log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
00426         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
00427         log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
00428 
00429         user->FlushWriteBuf();
00430 
00431         if (user->registered == 7) {
00432                 FOREACH_MOD OnUserQuit(user,reason);
00433                 WriteCommonExcept(user,"QUIT :%s",reason);
00434         }
00435 
00436         FOREACH_MOD OnUserDisconnect(user);
00437 
00438         if (user->fd > -1)
00439         {
00440                 if (Config->GetIOHook(user->port))
00441                 {
00442                         Config->GetIOHook(user->port)->OnRawSocketClose(user->fd);
00443                 }
00444                 ServerInstance->SE->DelFd(user->fd);
00445                 user->CloseSocket();
00446         }
00447 
00448         if (user->registered == 7) {
00449                 purge_empty_chans(user);
00450         }
00451 
00452         if (iter != clientlist.end())
00453         {
00454                 log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
00455                 if (user->fd > -1)
00456                 {
00457                         fd_ref_table[user->fd] = NULL;
00458                         if (find(local_users.begin(),local_users.end(),user) != local_users.end())
00459                         {
00460                                 log(DEBUG,"Delete local user");
00461                                 local_users.erase(find(local_users.begin(),local_users.end(),user));
00462                         }
00463                 }
00464                 clientlist.erase(iter);
00465         }
00466         delete user;
00467 }
00468 
00469 
00470 /* adds or updates an entry in the whowas list */
00471 void AddWhoWas(userrec* u)
00472 {
00473         whowas_hash::iterator iter = whowas.find(u->nick);
00474         WhoWasUser *a = new WhoWasUser();
00475         strlcpy(a->nick,u->nick,NICKMAX);
00476         strlcpy(a->ident,u->ident,IDENTMAX);
00477         strlcpy(a->dhost,u->dhost,160);
00478         strlcpy(a->host,u->host,160);
00479         strlcpy(a->fullname,u->fullname,MAXGECOS);
00480         strlcpy(a->server,u->server,256);
00481         a->signon = u->signon;
00482 
00483         /* MAX_WHOWAS:   max number of /WHOWAS items
00484          * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
00485          *               can be replaced by a newer one
00486          */
00487 
00488         if (iter == whowas.end())
00489         {
00490                 if (whowas.size() >= (unsigned)WHOWAS_MAX)
00491                 {
00492                         for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
00493                         {
00494                                 // 3600 seconds in an hour ;)
00495                                 if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600)))
00496                                 {
00497                                         // delete the old one
00498                                         if (i->second) delete i->second;
00499                                         // replace with new one
00500                                         i->second = a;
00501                                         log(DEBUG,"added WHOWAS entry, purged an old record");
00502                                         return;
00503                                 }
00504                         }
00505                         // no space left and user doesnt exist. Don't leave ram in use!
00506                         log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram");
00507                         delete a;
00508                 }
00509                 else
00510                 {
00511                         log(DEBUG,"added fresh WHOWAS entry");
00512                         whowas[a->nick] = a;
00513                 }
00514         }
00515         else
00516         {
00517                 log(DEBUG,"updated WHOWAS entry");
00518                 if (iter->second) delete iter->second;
00519                 iter->second = a;
00520         }
00521 }
00522 
00523 /* add a client connection to the sockets list */
00524 void AddClient(int socket, char* host, int port, bool iscached, char* ip)
00525 {
00526         string tempnick;
00527         char tn2[MAXBUF];
00528         user_hash::iterator iter;
00529 
00530         tempnick = ConvToStr(socket) + "-unknown";
00531         sprintf(tn2,"%lu-unknown",(unsigned long)socket);
00532 
00533         iter = clientlist.find(tempnick);
00534 
00535         // fix by brain.
00536         // as these nicknames are 'RFC impossible', we can be sure nobody is going to be
00537         // using one as a registered connection. As theyre per fd, we can also safely assume
00538         // that we wont have collisions. Therefore, if the nick exists in the list, its only
00539         // used by a dead socket, erase the iterator so that the new client may reclaim it.
00540         // this was probably the cause of 'server ignores me when i hammer it with reconnects'
00541         // issue in earlier alphas/betas
00542         if (iter != clientlist.end())
00543         {
00544                 userrec* goner = iter->second;
00545                 delete goner;
00546                 clientlist.erase(iter);
00547         }
00548 
00549         /*
00550          * It is OK to access the value here this way since we know
00551          * it exists, we just created it above.
00552          *
00553          * At NO other time should you access a value in a map or a
00554          * hash_map this way.
00555          */
00556         clientlist[tempnick] = new userrec();
00557 
00558         log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip);
00559 
00560         clientlist[tempnick]->fd = socket;
00561         strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX);
00562         strlcpy(clientlist[tempnick]->host, host,160);
00563         strlcpy(clientlist[tempnick]->dhost, host,160);
00564         clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName);
00565         strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX);
00566         clientlist[tempnick]->registered = 0;
00567         clientlist[tempnick]->signon = TIME + Config->dns_timeout;
00568         clientlist[tempnick]->lastping = 1;
00569         clientlist[tempnick]->port = port;
00570         strlcpy(clientlist[tempnick]->ip,ip,16);
00571 
00572         // set the registration timeout for this user
00573         unsigned long class_regtimeout = 90;
00574         int class_flood = 0;
00575         long class_threshold = 5;
00576         long class_sqmax = 262144;      // 256kb
00577         long class_rqmax = 4096;        // 4k
00578 
00579         for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
00580         {
00581                 if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW))
00582                 {
00583                         class_regtimeout = (unsigned long)i->registration_timeout;
00584                         class_flood = i->flood;
00585                         clientlist[tempnick]->pingmax = i->pingtime;
00586                         class_threshold = i->threshold;
00587                         class_sqmax = i->sendqmax;
00588                         class_rqmax = i->recvqmax;
00589                         break;
00590                 }
00591         }
00592 
00593         clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax + Config->dns_timeout;
00594         clientlist[tempnick]->timeout = TIME+class_regtimeout;
00595         clientlist[tempnick]->flood = class_flood;
00596         clientlist[tempnick]->threshold = class_threshold;
00597         clientlist[tempnick]->sendqmax = class_sqmax;
00598         clientlist[tempnick]->recvqmax = class_rqmax;
00599 
00600         ucrec a;
00601         a.channel = NULL;
00602         a.uc_modes = 0;
00603         for (int i = 0; i < MAXCHANS; i++)
00604                 clientlist[tempnick]->chans.push_back(a);
00605 
00606         if (clientlist.size() > Config->SoftLimit)
00607         {
00608                 kill_link(clientlist[tempnick],"No more connections allowed");
00609                 return;
00610         }
00611 
00612         if (clientlist.size() >= MAXCLIENTS)
00613         {
00614                 kill_link(clientlist[tempnick],"No more connections allowed");
00615                 return;
00616         }
00617 
00618         // this is done as a safety check to keep the file descriptors within range of fd_ref_table.
00619         // its a pretty big but for the moment valid assumption:
00620         // file descriptors are handed out starting at 0, and are recycled as theyre freed.
00621         // therefore if there is ever an fd over 65535, 65536 clients must be connected to the
00622         // irc server at once (or the irc server otherwise initiating this many connections, files etc)
00623         // which for the time being is a physical impossibility (even the largest networks dont have more
00624         // than about 10,000 users on ONE server!)
00625         if ((unsigned)socket > 65534)
00626         {
00627                 kill_link(clientlist[tempnick],"Server is full");
00628                 return;
00629         }
00630         char* e = matches_exception(ip);
00631         if (!e)
00632         {
00633                 char* r = matches_zline(ip);
00634                 if (r)
00635                 {
00636                         char reason[MAXBUF];
00637                         snprintf(reason,MAXBUF,"Z-Lined: %s",r);
00638                         kill_link(clientlist[tempnick],reason);
00639                         return;
00640                 }
00641         }
00642         fd_ref_table[socket] = clientlist[tempnick];
00643         local_users.push_back(clientlist[tempnick]);
00644         ServerInstance->SE->AddFd(socket,true,X_ESTAB_CLIENT);
00645 }
00646 
00647 void FullConnectUser(userrec* user)
00648 {
00649         ServerInstance->stats->statsConnects++;
00650         user->idle_lastmsg = TIME;
00651         log(DEBUG,"ConnectUser: %s",user->nick);
00652 
00653         if ((strcmp(Passwd(user),"")) && (!user->haspassed))
00654         {
00655                 kill_link(user,"Invalid password");
00656                 return;
00657         }
00658         if (IsDenied(user))
00659         {
00660                 kill_link(user,"Unauthorised connection");
00661                 return;
00662         }
00663 
00664         char match_against[MAXBUF];
00665         snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host);
00666         char* e = matches_exception(match_against);
00667         if (!e)
00668         {
00669                 char* r = matches_gline(match_against);
00670                 if (r)
00671                 {
00672                         char reason[MAXBUF];
00673                         snprintf(reason,MAXBUF,"G-Lined: %s",r);
00674                         kill_link_silent(user,reason);
00675                         return;
00676                 }
00677                 r = matches_kline(user->host);
00678                 if (r)
00679                 {
00680                         char reason[MAXBUF];
00681                         snprintf(reason,MAXBUF,"K-Lined: %s",r);
00682                         kill_link_silent(user,reason);
00683                         return;
00684                 }
00685         }
00686 
00687 
00688         WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Config->Network);
00689         WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Config->Network,user->nick,user->ident,user->host);
00690         WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,Config->ServerName,VERSION);
00691         WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
00692         WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,Config->ServerName,VERSION);
00693         // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...
00694         std::stringstream v;
00695         v << "WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS;
00696         v << " MAXBANS=60 NICKLEN=" << NICKMAX;
00697         v << " TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=20 AWAYLEN=" << MAXAWAY << " CHANMODES=ohvb,k,l,psmnti NETWORK=";
00698         v << Config->Network;
00699         std::string data005 = v.str();
00700         FOREACH_MOD On005Numeric(data005);
00701         // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line...
00702         // so i'd better split it :)
00703         std::stringstream out(data005);
00704         std::string token = "";
00705         std::string line5 = "";
00706         int token_counter = 0;
00707         while (!out.eof())
00708         {
00709                 out >> token;
00710                 line5 = line5 + token + " ";
00711                 token_counter++;
00712                 if ((token_counter >= 13) || (out.eof() == true))
00713                 {
00714                         WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str());
00715                         line5 = "";
00716                         token_counter = 0;
00717                 }
00718         }
00719         ShowMOTD(user);
00720 
00721         // fix 3 by brain, move registered = 7 below these so that spurious modes and host changes dont go out
00722         // onto the network and produce 'fake direction'
00723         FOREACH_MOD OnUserConnect(user);
00724         FOREACH_MOD OnGlobalConnect(user);
00725         user->registered = 7;
00726         WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip);
00727 }
00728 
00729 
00730 /* shows the message of the day, and any other on-logon stuff */
00731 void ConnectUser(userrec *user)
00732 {
00733         // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on
00734         if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user)))
00735         {
00736                 FullConnectUser(user);
00737         }
00738 }
00739 
00740 /* re-allocates a nick in the user_hash after they change nicknames,
00741  * returns a pointer to the new user as it may have moved */
00742 
00743 userrec* ReHashNick(char* Old, char* New)
00744 {
00745         //user_hash::iterator newnick;
00746         user_hash::iterator oldnick = clientlist.find(Old);
00747 
00748         log(DEBUG,"ReHashNick: %s %s",Old,New);
00749 
00750         if (!strcasecmp(Old,New))
00751         {
00752                 log(DEBUG,"old nick is new nick, skipping");
00753                 return oldnick->second;
00754         }
00755 
00756         if (oldnick == clientlist.end()) return NULL; /* doesnt exist */
00757 
00758         log(DEBUG,"ReHashNick: Found hashed nick %s",Old);
00759 
00760         userrec* olduser = oldnick->second;
00761         clientlist[New] = olduser;
00762         clientlist.erase(oldnick);
00763 
00764         log(DEBUG,"ReHashNick: Nick rehashed as %s",New);
00765 
00766         return clientlist[New];
00767 }
00768 
00769 void force_nickchange(userrec* user,const char* newnick)
00770 {
00771         char nick[MAXBUF];
00772         int MOD_RESULT = 0;
00773 
00774         strcpy(nick,"");
00775 
00776         FOREACH_RESULT(OnUserPreNick(user,newnick));
00777         if (MOD_RESULT) {
00778                 ServerInstance->stats->statsCollisions++;
00779                 kill_link(user,"Nickname collision");
00780                 return;
00781         }
00782         if (matches_qline(newnick))
00783         {
00784                 ServerInstance->stats->statsCollisions++;
00785                 kill_link(user,"Nickname collision");
00786                 return;
00787         }
00788 
00789         if (user)
00790         {
00791                 if (newnick)
00792                 {
00793                         strncpy(nick,newnick,MAXBUF);
00794                 }
00795                 if (user->registered == 7)
00796                 {
00797                         char* pars[1];
00798                         pars[0] = nick;
00799                         std::string cmd = "NICK";
00800                         ServerInstance->Parser->CallHandler(cmd,pars,1,user);
00801                 }
00802         }
00803 }
00804 

Generated on Mon Dec 19 18:02:13 2005 for InspIRCd by  doxygen 1.4.4-20050815