]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/inspircd.cpp
5d10c088f4b71d130613b1ee6f29d5b92dadc785
[user/henk/code/inspircd.git] / src / inspircd.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2005 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 /* Now with added unF! ;) */
18
19 using namespace std;
20
21 #include "inspircd_config.h"
22 #include "inspircd.h"
23 #include "inspircd_io.h"
24 #include "inspircd_util.h"
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/errno.h>
28 #include <sys/ioctl.h>
29 #include <sys/utsname.h>
30
31 #ifdef USE_KQUEUE
32 #include <sys/types.h>
33 #include <sys/event.h>
34 #include <sys/time.h>
35 #endif
36
37 #ifdef USE_EPOLL
38 #include <sys/epoll.h>
39 #define EP_DELAY 5
40 #endif
41
42 #include <time.h>
43 #include <string>
44 #ifdef GCC3
45 #include <ext/hash_map>
46 #else
47 #include <hash_map>
48 #endif
49 #include <map>
50 #include <sstream>
51 #include <vector>
52 #include <deque>
53 #include <sched.h>
54 #ifdef THREADED_DNS
55 #include <pthread.h>
56 #endif
57 #include "users.h"
58 #include "ctables.h"
59 #include "globals.h"
60 #include "modules.h"
61 #include "dynamic.h"
62 #include "wildcard.h"
63 #include "message.h"
64 #include "mode.h"
65 #include "commands.h"
66 #include "xline.h"
67 #include "inspstring.h"
68 #include "dnsqueue.h"
69 #include "helperfuncs.h"
70 #include "hashcomp.h"
71 #include "socketengine.h"
72 #include "socket.h"
73 #include "dns.h"
74
75 int LogLevel = DEFAULT;
76 char ServerName[MAXBUF];
77 char Network[MAXBUF];
78 char ServerDesc[MAXBUF];
79 char AdminName[MAXBUF];
80 char AdminEmail[MAXBUF];
81 char AdminNick[MAXBUF];
82 char diepass[MAXBUF];
83 char restartpass[MAXBUF];
84 char motd[MAXBUF];
85 char rules[MAXBUF];
86 char list[MAXBUF];
87 char PrefixQuit[MAXBUF];
88 char DieValue[MAXBUF];
89 char DNSServer[MAXBUF];
90 char data[65536];
91 int debugging =  0;
92 int WHOWAS_STALE = 48; // default WHOWAS Entries last 2 days before they go 'stale'
93 int WHOWAS_MAX = 100;  // default 100 people maximum in the WHOWAS list
94 int DieDelay  =  5;
95 time_t startup_time = time(NULL);
96 int NetBufferSize = 10240;      // NetBufferSize used as the buffer size for all read() ops
97 int MaxConn = SOMAXCONN;        // size of accept() backlog (128 by default on *BSD)
98 unsigned int SoftLimit = MAXCLIENTS;
99 extern int MaxWhoResults;
100 time_t nb_start = 0;
101 int dns_timeout = 5;
102
103 char DisabledCommands[MAXBUF];
104
105 bool AllowHalfop = true;
106 bool AllowProtect = true;
107 bool AllowFounder = true;
108
109 extern std::vector<Module*> modules;
110 std::vector<std::string> module_names;
111 extern std::vector<ircd_module*> factory;
112
113 std::vector<InspSocket*> module_sockets;
114
115 extern int MODCOUNT;
116 int openSockfd[MAXSOCKS];
117 bool nofork = false;
118 bool unlimitcore = false;
119
120 time_t TIME = time(NULL), OLDTIME = time(NULL);
121
122 SocketEngine* SE = NULL;
123
124 bool has_been_netsplit = false;
125 extern std::vector<std::string> include_stack;
126
127 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;
128 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHashComp> chan_hash;
129 typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, irc::InAddr_HashComp> address_cache;
130 typedef nspace::hash_map<std::string, WhoWasUser*, nspace::hash<string>, irc::StrHashComp> whowas_hash;
131 typedef std::deque<command_t> command_table;
132 typedef std::map<std::string,time_t> autoconnects;
133 typedef std::vector<std::string> servernamelist;
134
135 // This table references users by file descriptor.
136 // its an array to make it VERY fast, as all lookups are referenced
137 // by an integer, meaning there is no need for a scan/search operation.
138 userrec* fd_ref_table[65536];
139
140 int statsAccept = 0, statsRefused = 0, statsUnknown = 0, statsCollisions = 0, statsDns = 0, statsDnsGood = 0, statsDnsBad = 0, statsConnects = 0, statsSent= 0, statsRecv = 0;
141
142 Server* MyServer = new Server;
143
144 FILE *log_file;
145
146 user_hash clientlist;
147 chan_hash chanlist;
148 whowas_hash whowas;
149 command_table cmdlist;
150 autoconnects autoconns;
151 file_cache MOTD;
152 file_cache RULES;
153 address_cache IP;
154
155 ClassVector Classes;
156 servernamelist servernames;
157
158 struct linger linger = { 0 };
159 char MyExecutable[1024];
160 int boundPortCount = 0;
161 int portCount = 0, SERVERportCount = 0, ports[MAXSOCKS];
162
163 char ModPath[MAXBUF];
164
165 /* prototypes */
166
167 int has_channel(userrec *u, chanrec *c);
168 int usercount(chanrec *c);
169 int usercount_i(chanrec *c);
170 char* Passwd(userrec *user);
171 bool IsDenied(userrec *user);
172 void AddWhoWas(userrec* u);
173
174 std::stringstream config_f(stringstream::in | stringstream::out);
175
176 std::vector<userrec*> all_opers;
177
178 char lowermap[255];
179
180 void AddOper(userrec* user)
181 {
182         log(DEBUG,"Oper added to optimization list");
183         all_opers.push_back(user);
184 }
185
186 void AddServerName(std::string servername)
187 {
188         log(DEBUG,"Adding server name: %s",servername.c_str());
189         for (servernamelist::iterator a = servernames.begin(); a < servernames.end(); a++)
190         {
191                 if (*a == servername)
192                         return;
193         }
194         servernames.push_back(servername);
195 }
196
197 const char* FindServerNamePtr(std::string servername)
198 {
199         for (servernamelist::iterator a = servernames.begin(); a < servernames.end(); a++)
200         {
201                 if (*a == servername)
202                         return a->c_str();
203         }
204         AddServerName(servername);
205         return FindServerNamePtr(servername);
206 }
207
208 void DeleteOper(userrec* user)
209 {
210         for (std::vector<userrec*>::iterator a = all_opers.begin(); a < all_opers.end(); a++)
211         {
212                 if (*a == user)
213                 {
214                         log(DEBUG,"Oper removed from optimization list");
215                         all_opers.erase(a);
216                         return;
217                 }
218         }
219 }
220
221 std::string GetRevision()
222 {
223         char Revision[] = "$Revision$";
224         char *s1 = Revision;
225         char *savept;
226         char *v2 = strtok_r(s1," ",&savept);
227         s1 = savept;
228         v2 = strtok_r(s1," ",&savept);
229         s1 = savept;
230         return std::string(v2);
231 }
232
233
234 std::string getservername()
235 {
236         return ServerName;
237 }
238
239 std::string getserverdesc()
240 {
241         return ServerDesc;
242 }
243
244 std::string getnetworkname()
245 {
246         return Network;
247 }
248
249 std::string getadminname()
250 {
251         return AdminName;
252 }
253
254 std::string getadminemail()
255 {
256         return AdminEmail;
257 }
258
259 std::string getadminnick()
260 {
261         return AdminNick;
262 }
263
264 void ReadConfig(bool bail, userrec* user)
265 {
266         char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF],MW[MAXBUF],MCON[MAXBUF];
267         char AH[MAXBUF],AP[MAXBUF],AF[MAXBUF],DNT[MAXBUF],pfreq[MAXBUF],thold[MAXBUF],sqmax[MAXBUF],rqmax[MAXBUF],SLIMT[MAXBUF];
268         ConnectClass c;
269         std::stringstream errstr;
270         include_stack.clear();
271         
272         if (!LoadConf(CONFIG_FILE,&config_f,&errstr))
273         {
274                 errstr.seekg(0);
275                 log(DEFAULT,"There were errors in your configuration:\n%s",errstr.str().c_str());
276                 if (bail)
277                 {
278                         printf("There were errors in your configuration:\n%s",errstr.str().c_str());
279                         Exit(0);
280                 }
281                 else
282                 {
283                         char dataline[1024];
284                         if (user)
285                         {
286                                 WriteServ(user->fd,"NOTICE %s :There were errors in the configuration file:",user->nick);
287                                 while (!errstr.eof())
288                                 {
289                                         errstr.getline(dataline,1024);
290                                         WriteServ(user->fd,"NOTICE %s :%s",user->nick,dataline);
291                                 }
292                         }
293                         else
294                         {
295                                 WriteOpers("There were errors in the configuration file:");
296                                 while (!errstr.eof())
297                                 {
298                                         errstr.getline(dataline,1024);
299                                         WriteOpers(dataline);
300                                 }
301                         }
302                         return;
303                 }
304         }
305           
306         ConfValue("server","name",0,ServerName,&config_f);
307         ConfValue("server","description",0,ServerDesc,&config_f);
308         ConfValue("server","network",0,Network,&config_f);
309         ConfValue("admin","name",0,AdminName,&config_f);
310         ConfValue("admin","email",0,AdminEmail,&config_f);
311         ConfValue("admin","nick",0,AdminNick,&config_f);
312         ConfValue("files","motd",0,motd,&config_f);
313         ConfValue("files","rules",0,rules,&config_f);
314         ConfValue("power","diepass",0,diepass,&config_f);
315         ConfValue("power","pause",0,pauseval,&config_f);
316         ConfValue("power","restartpass",0,restartpass,&config_f);
317         ConfValue("options","prefixquit",0,PrefixQuit,&config_f);
318         ConfValue("die","value",0,DieValue,&config_f);
319         ConfValue("options","loglevel",0,dbg,&config_f);
320         ConfValue("options","netbuffersize",0,NB,&config_f);
321         ConfValue("options","maxwho",0,MW,&config_f);
322         ConfValue("options","allowhalfop",0,AH,&config_f);
323         ConfValue("options","allowprotect",0,AP,&config_f);
324         ConfValue("options","allowfounder",0,AF,&config_f);
325         ConfValue("dns","server",0,DNSServer,&config_f);
326         ConfValue("dns","timeout",0,DNT,&config_f);
327         ConfValue("options","moduledir",0,ModPath,&config_f);
328         ConfValue("disabled","commands",0,DisabledCommands,&config_f);
329         ConfValue("options","somaxconn",0,MCON,&config_f);
330         ConfValue("options","softlimit",0,SLIMT,&config_f);
331
332         SoftLimit = atoi(SLIMT);
333         if ((SoftLimit < 1) || (SoftLimit > MAXCLIENTS))
334         {
335                 log(DEFAULT,"WARNING: <options:softlimit> value is greater than %d or less than 0, set to %d.",MAXCLIENTS,MAXCLIENTS);
336                 SoftLimit = MAXCLIENTS;
337         }
338         MaxConn = atoi(MCON);
339         if (MaxConn > SOMAXCONN)
340                 log(DEFAULT,"WARNING: <options:somaxconn> value may be higher than the system-defined SOMAXCONN value!");
341         NetBufferSize = atoi(NB);
342         MaxWhoResults = atoi(MW);
343         dns_timeout = atoi(DNT);
344         if (!dns_timeout)
345                 dns_timeout = 5;
346         if (!MaxConn)
347                 MaxConn = SOMAXCONN;
348         if (!DNSServer[0])
349                 strlcpy(DNSServer,"127.0.0.1",MAXBUF);
350         if (!ModPath[0])
351                 strlcpy(ModPath,MOD_PATH,MAXBUF);
352         AllowHalfop = ((!strcasecmp(AH,"true")) || (!strcasecmp(AH,"1")) || (!strcasecmp(AH,"yes")));
353         AllowProtect = ((!strcasecmp(AP,"true")) || (!strcasecmp(AP,"1")) || (!strcasecmp(AP,"yes")));
354         AllowFounder = ((!strcasecmp(AF,"true")) || (!strcasecmp(AF,"1")) || (!strcasecmp(AF,"yes")));
355         if ((!NetBufferSize) || (NetBufferSize > 65535) || (NetBufferSize < 1024))
356         {
357                 log(DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240.");
358                 NetBufferSize = 10240;
359         }
360         if ((!MaxWhoResults) || (MaxWhoResults > 65535) || (MaxWhoResults < 1))
361         {
362                 log(DEFAULT,"No MaxWhoResults specified or size out of range, setting to default of 128.");
363                 MaxWhoResults = 128;
364         }
365         if (!strcmp(dbg,"debug"))
366                 LogLevel = DEBUG;
367         if (!strcmp(dbg,"verbose"))
368                 LogLevel = VERBOSE;
369         if (!strcmp(dbg,"default"))
370                 LogLevel = DEFAULT;
371         if (!strcmp(dbg,"sparse"))
372                 LogLevel = SPARSE;
373         if (!strcmp(dbg,"none"))
374                 LogLevel = NONE;
375         readfile(MOTD,motd);
376         log(DEFAULT,"Reading message of the day...");
377         readfile(RULES,rules);
378         log(DEFAULT,"Reading connect classes...");
379         Classes.clear();
380         for (int i = 0; i < ConfValueEnum("connect",&config_f); i++)
381         {
382                 strcpy(Value,"");
383                 ConfValue("connect","allow",i,Value,&config_f);
384                 ConfValue("connect","timeout",i,timeout,&config_f);
385                 ConfValue("connect","flood",i,flood,&config_f);
386                 ConfValue("connect","pingfreq",i,pfreq,&config_f);
387                 ConfValue("connect","threshold",i,thold,&config_f);
388                 ConfValue("connect","sendq",i,sqmax,&config_f);
389                 ConfValue("connect","recvq",i,rqmax,&config_f);
390                 if (Value[0])
391                 {
392                         strlcpy(c.host,Value,MAXBUF);
393                         c.type = CC_ALLOW;
394                         strlcpy(Value,"",MAXBUF);
395                         ConfValue("connect","password",i,Value,&config_f);
396                         strlcpy(c.pass,Value,MAXBUF);
397                         c.registration_timeout = 90; // default is 2 minutes
398                         c.pingtime = 120;
399                         c.flood = atoi(flood);
400                         c.threshold = 5;
401                         c.sendqmax = 262144; // 256k
402                         c.recvqmax = 4096;   // 4k
403                         if (atoi(thold)>0)
404                         {
405                                 c.threshold = atoi(thold);
406                         }
407                         if (atoi(sqmax)>0)
408                         {
409                                 c.sendqmax = atoi(sqmax);
410                         }
411                         if (atoi(rqmax)>0)
412                         {
413                                 c.recvqmax = atoi(rqmax);
414                         }
415                         if (atoi(timeout)>0)
416                         {
417                                 c.registration_timeout = atoi(timeout);
418                         }
419                         if (atoi(pfreq)>0)
420                         {
421                                 c.pingtime = atoi(pfreq);
422                         }
423                         Classes.push_back(c);
424                         log(DEBUG,"Read connect class type ALLOW, host=%s password=%s timeout=%lu flood=%lu",c.host,c.pass,(unsigned long)c.registration_timeout,(unsigned long)c.flood);
425                 }
426                 else
427                 {
428                         ConfValue("connect","deny",i,Value,&config_f);
429                         strlcpy(c.host,Value,MAXBUF);
430                         c.type = CC_DENY;
431                         Classes.push_back(c);
432                         log(DEBUG,"Read connect class type DENY, host=%s",c.host);
433                 }
434         
435         }
436         log(DEFAULT,"Reading K lines,Q lines and Z lines from config...");
437         read_xline_defaults();
438         log(DEFAULT,"Applying K lines, Q lines and Z lines...");
439         apply_lines();
440
441         autoconns.clear();
442         for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
443         {
444                 char Link_ServerName[MAXBUF],Link_AConn[MAXBUF];
445                 ConfValue("link","name",i,Link_ServerName,&config_f);
446                 ConfValue("link","autoconnect",i,Link_AConn,&config_f);
447                 if (strcmp(Link_AConn,""))
448                 {
449                         autoconns[std::string(Link_ServerName)] = atoi(Link_AConn) + time(NULL);
450                 }
451         }
452
453
454         log(DEFAULT,"Done reading configuration file, InspIRCd is now starting.");
455         if (!bail)
456         {
457                 log(DEFAULT,"Adding and removing modules due to rehash...");
458
459                 std::vector<std::string> old_module_names, new_module_names, added_modules, removed_modules;
460
461                 // store the old module names
462                 for (std::vector<std::string>::iterator t = module_names.begin(); t != module_names.end(); t++)
463                 {
464                         old_module_names.push_back(*t);
465                 }
466
467                 // get the new module names
468                 for (int count2 = 0; count2 < ConfValueEnum("module",&config_f); count2++)
469                 {
470                         ConfValue("module","name",count2,Value,&config_f);
471                         new_module_names.push_back(Value);
472                 }
473
474                 // now create a list of new modules that are due to be loaded
475                 // and a seperate list of modules which are due to be unloaded
476                 for (std::vector<std::string>::iterator _new = new_module_names.begin(); _new != new_module_names.end(); _new++)
477                 {
478                         bool added = true;
479                         for (std::vector<std::string>::iterator old = old_module_names.begin(); old != old_module_names.end(); old++)
480                         {
481                                 if (*old == *_new)
482                                         added = false;
483                         }
484                         if (added)
485                                 added_modules.push_back(*_new);
486                 }
487                 for (std::vector<std::string>::iterator oldm = old_module_names.begin(); oldm != old_module_names.end(); oldm++)
488                 {
489                         bool removed = true;
490                         for (std::vector<std::string>::iterator newm = new_module_names.begin(); newm != new_module_names.end(); newm++)
491                         {
492                                 if (*newm == *oldm)
493                                         removed = false;
494                         }
495                         if (removed)
496                                 removed_modules.push_back(*oldm);
497                 }
498                 // now we have added_modules, a vector of modules to be loaded, and removed_modules, a vector of modules
499                 // to be removed.
500                 int rem = 0, add = 0;
501                 if (!removed_modules.empty())
502                 for (std::vector<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
503                 {
504                         if (UnloadModule(removing->c_str()))
505                         {
506                                 WriteOpers("*** REHASH UNLOADED MODULE: %s",removing->c_str());
507                                 WriteServ(user->fd,"973 %s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str());
508                                 rem++;
509                         }
510                         else
511                         {
512                                 WriteServ(user->fd,"972 %s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ModuleError());
513                         }
514                 }
515                 if (!added_modules.empty())
516                 for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++)
517                 {
518                         if (LoadModule(adding->c_str()))
519                         {
520                                 WriteOpers("*** REHASH LOADED MODULE: %s",adding->c_str());
521                                 WriteServ(user->fd,"975 %s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str());
522                                 add++;
523                         }
524                         else
525                         {
526                                 WriteServ(user->fd,"974 %s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ModuleError());
527                         }
528                 }
529                 log(DEFAULT,"Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size());
530         }
531 }
532
533
534 /* add a channel to a user, creating the record for it if needed and linking
535  * it to the user record */
536
537 chanrec* add_channel(userrec *user, const char* cn, const char* key, bool override)
538 {
539         if ((!user) || (!cn))
540         {
541                 log(DEFAULT,"*** BUG *** add_channel was given an invalid parameter");
542                 return 0;
543         }
544
545         chanrec* Ptr;
546         int created = 0;
547         char cname[MAXBUF];
548
549         strncpy(cname,cn,MAXBUF);
550         
551         // we MUST declare this wherever we use FOREACH_RESULT
552         int MOD_RESULT = 0;
553
554         if (strlen(cname) > CHANMAX)
555         {
556                 cname[CHANMAX] = '\0';
557         }
558
559         log(DEBUG,"add_channel: %s %s",user->nick,cname);
560         
561         if ((FindChan(cname)) && (has_channel(user,FindChan(cname))))
562         {
563                 return NULL; // already on the channel!
564         }
565
566
567         if (!FindChan(cname))
568         {
569                 if (!strcasecmp(ServerName,user->server))
570                 {
571                         MOD_RESULT = 0;
572                         FOREACH_RESULT(OnUserPreJoin(user,NULL,cname));
573                         if (MOD_RESULT == 1) {
574                                 return NULL;
575                         }
576                 }
577
578                 /* create a new one */
579                 log(DEBUG,"add_channel: creating: %s",cname);
580                 {
581                         chanlist[cname] = new chanrec();
582
583                         strlcpy(chanlist[cname]->name, cname,CHANMAX);
584                         chanlist[cname]->binarymodes = CM_TOPICLOCK | CM_NOEXTERNAL;
585                         chanlist[cname]->created = TIME;
586                         strcpy(chanlist[cname]->topic, "");
587                         strncpy(chanlist[cname]->setby, user->nick,NICKMAX);
588                         chanlist[cname]->topicset = 0;
589                         Ptr = chanlist[cname];
590                         log(DEBUG,"add_channel: created: %s",cname);
591                         /* set created to 2 to indicate user
592                          * is the first in the channel
593                          * and should be given ops */
594                         created = 2;
595                 }
596         }
597         else
598         {
599                 /* channel exists, just fish out a pointer to its struct */
600                 Ptr = FindChan(cname);
601                 if (Ptr)
602                 {
603                         log(DEBUG,"add_channel: joining to: %s",Ptr->name);
604                         
605                         // remote users are allowed us to bypass channel modes
606                         // and bans (used by servers)
607                         if (!strcasecmp(ServerName,user->server))
608                         {
609                                 log(DEBUG,"Not overriding...");
610                                 MOD_RESULT = 0;
611                                 FOREACH_RESULT(OnUserPreJoin(user,Ptr,cname));
612                                 if (MOD_RESULT == 1) {
613                                         return NULL;
614                                 }
615                                 log(DEBUG,"MOD_RESULT=%d",MOD_RESULT);
616                                 
617                                 if (!MOD_RESULT) 
618                                 {
619                                         log(DEBUG,"add_channel: checking key, invite, etc");
620                                         MOD_RESULT = 0;
621                                         FOREACH_RESULT(OnCheckKey(user, Ptr, key ? key : ""));
622                                         if (MOD_RESULT == 0)
623                                         {
624                                                 if (Ptr->key[0])
625                                                 {
626                                                         log(DEBUG,"add_channel: %s has key %s",Ptr->name,Ptr->key);
627                                                         if (!key)
628                                                         {
629                                                                 log(DEBUG,"add_channel: no key given in JOIN");
630                                                                 WriteServ(user->fd,"475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
631                                                                 return NULL;
632                                                         }
633                                                         else
634                                                         {
635                                                                 if (strcasecmp(key,Ptr->key))
636                                                                 {
637                                                                         log(DEBUG,"add_channel: bad key given in JOIN");
638                                                                         WriteServ(user->fd,"475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
639                                                                         return NULL;
640                                                                 }
641                                                         }
642                                                 }
643                                                 log(DEBUG,"add_channel: no key");
644                                         }
645                                         MOD_RESULT = 0;
646                                         FOREACH_RESULT(OnCheckInvite(user, Ptr));
647                                         if (MOD_RESULT == 0)
648                                         {
649                                                 if (Ptr->binarymodes & CM_INVITEONLY)
650                                                 {
651                                                         log(DEBUG,"add_channel: channel is +i");
652                                                         if (user->IsInvited(Ptr->name))
653                                                         {
654                                                                 /* user was invited to channel */
655                                                                 /* there may be an optional channel NOTICE here */
656                                                         }
657                                                         else
658                                                         {
659                                                                 WriteServ(user->fd,"473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
660                                                                 return NULL;
661                                                         }
662                                                 }
663                                                 log(DEBUG,"add_channel: channel is not +i");
664                                         }
665                                         MOD_RESULT = 0;
666                                         FOREACH_RESULT(OnCheckLimit(user, Ptr));
667                                         if (MOD_RESULT == 0)
668                                         {
669                                                 if (Ptr->limit)
670                                                 {
671                                                         if (usercount(Ptr) >= Ptr->limit)
672                                                         {
673                                                                 WriteServ(user->fd,"471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
674                                                                 return NULL;
675                                                         }
676                                                 }
677                                         }
678                                         log(DEBUG,"add_channel: about to walk banlist");
679                                         MOD_RESULT = 0;
680                                         FOREACH_RESULT(OnCheckBan(user, Ptr));
681                                         if (MOD_RESULT == 0)
682                                         {
683                                                 /* check user against the channel banlist */
684                                                 if (Ptr)
685                                                 {
686                                                         if (Ptr->bans.size())
687                                                         {
688                                                                 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
689                                                                 {
690                                                                         if (match(user->GetFullHost(),i->data))
691                                                                         {
692                                                                                 WriteServ(user->fd,"474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
693                                                                                 return NULL;
694                                                                         }
695                                                                 }
696                                                         }
697                                                 }
698                                                 log(DEBUG,"add_channel: bans checked");
699                                         }
700                                 
701                                 }
702                                 
703
704                                 if ((Ptr) && (user))
705                                 {
706                                         user->RemoveInvite(Ptr->name);
707                                 }
708         
709                                 log(DEBUG,"add_channel: invites removed");
710
711                         }
712                         else
713                         {
714                                 log(DEBUG,"Overridden checks");
715                         }
716
717                         
718                 }
719                 created = 1;
720         }
721
722         log(DEBUG,"Passed channel checks");
723         
724         for (int index =0; index != MAXCHANS; index++)
725         {
726                 log(DEBUG,"Check location %d",index);
727                 if (user->chans[index].channel == NULL)
728                 {
729                         log(DEBUG,"Adding into their channel list at location %d",index);
730
731                         if (created == 2) 
732                         {
733                                 /* first user in is given ops */
734                                 user->chans[index].uc_modes = UCMODE_OP;
735                         }
736                         else
737                         {
738                                 user->chans[index].uc_modes = 0;
739                         }
740                         user->chans[index].channel = Ptr;
741                         Ptr->AddUser((char*)user);
742                         WriteChannel(Ptr,user,"JOIN :%s",Ptr->name);
743                         
744                         log(DEBUG,"Sent JOIN to client");
745
746                         if (Ptr->topicset)
747                         {
748                                 WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
749                                 WriteServ(user->fd,"333 %s %s %s %lu", user->nick, Ptr->name, Ptr->setby, (unsigned long)Ptr->topicset);
750                         }
751                         userlist(user,Ptr);
752                         WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
753                         //WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name,chanmodes(Ptr));
754                         //WriteServ(user->fd,"329 %s %s %lu", user->nick, Ptr->name, (unsigned long)Ptr->created);
755                         FOREACH_MOD OnUserJoin(user,Ptr);
756                         return Ptr;
757                 }
758         }
759         log(DEBUG,"add_channel: user channel max exceeded: %s %s",user->nick,cname);
760         WriteServ(user->fd,"405 %s %s :You are on too many channels",user->nick, cname);
761         return NULL;
762 }
763
764 /* remove a channel from a users record, and remove the record from memory
765  * if the channel has become empty */
766
767 chanrec* del_channel(userrec *user, const char* cname, const char* reason, bool local)
768 {
769         if ((!user) || (!cname))
770         {
771                 log(DEFAULT,"*** BUG *** del_channel was given an invalid parameter");
772                 return NULL;
773         }
774
775         chanrec* Ptr;
776
777         if ((!cname) || (!user))
778         {
779                 return NULL;
780         }
781
782         Ptr = FindChan(cname);
783         
784         if (!Ptr)
785         {
786                 return NULL;
787         }
788
789         FOREACH_MOD OnUserPart(user,Ptr);
790         log(DEBUG,"del_channel: removing: %s %s",user->nick,Ptr->name);
791         
792         for (int i =0; i != MAXCHANS; i++)
793         {
794                 /* zap it from the channel list of the user */
795                 if (user->chans[i].channel == Ptr)
796                 {
797                         if (reason)
798                         {
799                                 WriteChannel(Ptr,user,"PART %s :%s",Ptr->name, reason);
800                         }
801                         else
802                         {
803                                 WriteChannel(Ptr,user,"PART :%s",Ptr->name);
804                         }
805                         user->chans[i].uc_modes = 0;
806                         user->chans[i].channel = NULL;
807                         log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
808                         break;
809                 }
810         }
811
812         Ptr->DelUser((char*)user);
813         
814         /* if there are no users left on the channel */
815         if (!usercount(Ptr))
816         {
817                 chan_hash::iterator iter = chanlist.find(Ptr->name);
818
819                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
820
821                 /* kill the record */
822                 if (iter != chanlist.end())
823                 {
824                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
825                         delete Ptr;
826                         chanlist.erase(iter);
827                 }
828         }
829
830         return NULL;
831 }
832
833
834 void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
835 {
836         if ((!src) || (!user) || (!Ptr) || (!reason))
837         {
838                 log(DEFAULT,"*** BUG *** kick_channel was given an invalid parameter");
839                 return;
840         }
841
842         if ((!Ptr) || (!user) || (!src))
843         {
844                 return;
845         }
846
847         log(DEBUG,"kick_channel: removing: %s %s %s",user->nick,Ptr->name,src->nick);
848
849         if (!has_channel(user,Ptr))
850         {
851                 WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name);
852                 return;
853         }
854
855         int MOD_RESULT = 0;
856         FOREACH_RESULT(OnAccessCheck(src,user,Ptr,AC_KICK));
857         if ((MOD_RESULT == ACR_DENY) && (!is_uline(src->server)))
858                 return;
859
860         if ((MOD_RESULT == ACR_DEFAULT) || (!is_uline(src->server)))
861         {
862                 if ((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr)))
863                 {
864                         if (cstatus(src,Ptr) == STATUS_HOP)
865                         {
866                                 WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name);
867                         }
868                         else
869                         {
870                                 WriteServ(src->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",src->nick, Ptr->name);
871                         }
872                         
873                         return;
874                 }
875         }
876
877         if (!is_uline(src->server))
878         {
879                 MOD_RESULT = 0;
880                 FOREACH_RESULT(OnUserPreKick(src,user,Ptr,reason));
881                 if (MOD_RESULT)
882                         return;
883         }
884
885         FOREACH_MOD OnUserKick(src,user,Ptr,reason);
886
887         for (int i =0; i != MAXCHANS; i++)
888         {
889                 /* zap it from the channel list of the user */
890                 if (user->chans[i].channel)
891                 if (!strcasecmp(user->chans[i].channel->name,Ptr->name))
892                 {
893                         WriteChannel(Ptr,src,"KICK %s %s :%s",Ptr->name, user->nick, reason);
894                         user->chans[i].uc_modes = 0;
895                         user->chans[i].channel = NULL;
896                         log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
897                         break;
898                 }
899         }
900
901         Ptr->DelUser((char*)user);
902
903         /* if there are no users left on the channel */
904         if (!usercount(Ptr))
905         {
906                 chan_hash::iterator iter = chanlist.find(Ptr->name);
907
908                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
909
910                 /* kill the record */
911                 if (iter != chanlist.end())
912                 {
913                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
914                         delete Ptr;
915                         chanlist.erase(iter);
916                 }
917         }
918 }
919
920
921
922
923 /* This function pokes and hacks at a parameter list like the following:
924  *
925  * PART #winbot,#darkgalaxy :m00!
926  *
927  * to turn it into a series of individual calls like this:
928  *
929  * PART #winbot :m00!
930  * PART #darkgalaxy :m00!
931  *
932  * The seperate calls are sent to a callback function provided by the caller
933  * (the caller will usually call itself recursively). The callback function
934  * must be a command handler. Calling this function on a line with no list causes
935  * no action to be taken. You must provide a starting and ending parameter number
936  * where the range of the list can be found, useful if you have a terminating
937  * parameter as above which is actually not part of the list, or parameters
938  * before the actual list as well. This code is used by many functions which
939  * can function as "one to list" (see the RFC) */
940
941 int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins)
942 {
943         char plist[MAXBUF];
944         char *param;
945         char *pars[32];
946         char blog[32][MAXBUF];
947         char blog2[32][MAXBUF];
948         int j = 0, q = 0, total = 0, t = 0, t2 = 0, total2 = 0;
949         char keystr[MAXBUF];
950         char moo[MAXBUF];
951
952         for (int i = 0; i <32; i++)
953                 strcpy(blog[i],"");
954
955         for (int i = 0; i <32; i++)
956                 strcpy(blog2[i],"");
957
958         strcpy(moo,"");
959         for (int i = 0; i <10; i++)
960         {
961                 if (!parameters[i])
962                 {
963                         parameters[i] = moo;
964                 }
965         }
966         if (joins)
967         {
968                 if (pcnt > 1) /* we have a key to copy */
969                 {
970                         strlcpy(keystr,parameters[1],MAXBUF);
971                 }
972         }
973
974         if (!parameters[start])
975         {
976                 return 0;
977         }
978         if (!strchr(parameters[start],','))
979         {
980                 return 0;
981         }
982         strcpy(plist,"");
983         for (int i = start; i <= end; i++)
984         {
985                 if (parameters[i])
986                 {
987                         strlcat(plist,parameters[i],MAXBUF);
988                 }
989         }
990         
991         j = 0;
992         param = plist;
993
994         t = strlen(plist);
995         for (int i = 0; i < t; i++)
996         {
997                 if (plist[i] == ',')
998                 {
999                         plist[i] = '\0';
1000                         strlcpy(blog[j++],param,MAXBUF);
1001                         param = plist+i+1;
1002                         if (j>20)
1003                         {
1004                                 WriteServ(u->fd,"407 %s %s :Too many targets in list, message not delivered.",u->nick,blog[j-1]);
1005                                 return 1;
1006                         }
1007                 }
1008         }
1009         strlcpy(blog[j++],param,MAXBUF);
1010         total = j;
1011
1012         if ((joins) && (keystr) && (total>0)) // more than one channel and is joining
1013         {
1014                 strcat(keystr,",");
1015         }
1016         
1017         if ((joins) && (keystr))
1018         {
1019                 if (strchr(keystr,','))
1020                 {
1021                         j = 0;
1022                         param = keystr;
1023                         t2 = strlen(keystr);
1024                         for (int i = 0; i < t2; i++)
1025                         {
1026                                 if (keystr[i] == ',')
1027                                 {
1028                                         keystr[i] = '\0';
1029                                         strlcpy(blog2[j++],param,MAXBUF);
1030                                         param = keystr+i+1;
1031                                 }
1032                         }
1033                         strlcpy(blog2[j++],param,MAXBUF);
1034                         total2 = j;
1035                 }
1036         }
1037
1038         for (j = 0; j < total; j++)
1039         {
1040                 if (blog[j])
1041                 {
1042                         pars[0] = blog[j];
1043                 }
1044                 for (q = end; q < pcnt-1; q++)
1045                 {
1046                         if (parameters[q+1])
1047                         {
1048                                 pars[q-end+1] = parameters[q+1];
1049                         }
1050                 }
1051                 if ((joins) && (parameters[1]))
1052                 {
1053                         if (pcnt > 1)
1054                         {
1055                                 pars[1] = blog2[j];
1056                         }
1057                         else
1058                         {
1059                                 pars[1] = NULL;
1060                         }
1061                 }
1062                 /* repeatedly call the function with the hacked parameter list */
1063                 if ((joins) && (pcnt > 1))
1064                 {
1065                         if (pars[1])
1066                         {
1067                                 // pars[1] already set up and containing key from blog2[j]
1068                                 fn(pars,2,u);
1069                         }
1070                         else
1071                         {
1072                                 pars[1] = parameters[1];
1073                                 fn(pars,2,u);
1074                         }
1075                 }
1076                 else
1077                 {
1078                         fn(pars,pcnt-(end-start),u);
1079                 }
1080         }
1081
1082         return 1;
1083 }
1084
1085
1086
1087 void kill_link(userrec *user,const char* r)
1088 {
1089         user_hash::iterator iter = clientlist.find(user->nick);
1090         
1091         char reason[MAXBUF];
1092         
1093         strncpy(reason,r,MAXBUF);
1094
1095         if (strlen(reason)>MAXQUIT)
1096         {
1097                 reason[MAXQUIT-1] = '\0';
1098         }
1099
1100         log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
1101         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
1102         log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
1103
1104         if (user->registered == 7) {
1105                 FOREACH_MOD OnUserQuit(user,reason);
1106                 WriteCommonExcept(user,"QUIT :%s",reason);
1107         }
1108
1109         user->FlushWriteBuf();
1110
1111         FOREACH_MOD OnUserDisconnect(user);
1112
1113         if (user->fd > -1)
1114         {
1115                 FOREACH_MOD OnRawSocketClose(user->fd);
1116                 SE->DelFd(user->fd);
1117                 user->CloseSocket();
1118         }
1119
1120         // this must come before the WriteOpers so that it doesnt try to fill their buffer with anything
1121         // if they were an oper with +s.
1122         if (user->registered == 7) {
1123                 purge_empty_chans(user);
1124                 // fix by brain: only show local quits because we only show local connects (it just makes SENSE)
1125                 if (!strcmp(user->server,ServerName))
1126                         WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
1127                 AddWhoWas(user);
1128         }
1129
1130         if (iter != clientlist.end())
1131         {
1132                 log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
1133                 if (user->fd > -1)
1134                         fd_ref_table[user->fd] = NULL;
1135                 clientlist.erase(iter);
1136         }
1137         delete user;
1138 }
1139
1140 void kill_link_silent(userrec *user,const char* r)
1141 {
1142         user_hash::iterator iter = clientlist.find(user->nick);
1143         
1144         char reason[MAXBUF];
1145         
1146         strncpy(reason,r,MAXBUF);
1147
1148         if (strlen(reason)>MAXQUIT)
1149         {
1150                 reason[MAXQUIT-1] = '\0';
1151         }
1152
1153         log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
1154         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
1155         log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
1156
1157         user->FlushWriteBuf();
1158
1159         if (user->registered == 7) {
1160                 FOREACH_MOD OnUserQuit(user,reason);
1161                 WriteCommonExcept(user,"QUIT :%s",reason);
1162         }
1163
1164         FOREACH_MOD OnUserDisconnect(user);
1165
1166         if (user->fd > -1)
1167         {
1168                 FOREACH_MOD OnRawSocketClose(user->fd);
1169                 SE->DelFd(user->fd);
1170                 user->CloseSocket();
1171         }
1172
1173         if (user->registered == 7) {
1174                 purge_empty_chans(user);
1175         }
1176         
1177         if (iter != clientlist.end())
1178         {
1179                 log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
1180                 if (user->fd > -1)
1181                         fd_ref_table[user->fd] = NULL;
1182                 clientlist.erase(iter);
1183         }
1184         delete user;
1185 }
1186
1187
1188 /*void *task(void *arg)
1189 {
1190         for (;;) { 
1191                 cout << (char *)arg;
1192                 cout.flush();
1193         }
1194         return NULL;
1195 }*/
1196
1197 int main(int argc, char** argv)
1198 {
1199         Start();
1200         srand(time(NULL));
1201         log(DEBUG,"*** InspIRCd starting up!");
1202         if (!FileExists(CONFIG_FILE))
1203         {
1204                 printf("ERROR: Cannot open config file: %s\nExiting...\n",CONFIG_FILE);
1205                 log(DEFAULT,"main: no config");
1206                 printf("ERROR: Your config file is missing, this IRCd will self destruct in 10 seconds!\n");
1207                 Exit(ERROR);
1208         }
1209         if (argc > 1) {
1210                 for (int i = 1; i < argc; i++)
1211                 {
1212                         if (!strcmp(argv[i],"-nofork")) {
1213                                 nofork = true;
1214                         }
1215                         if (!strcmp(argv[i],"-wait")) {
1216                                 sleep(6);
1217                         }
1218                         if (!strcmp(argv[i],"-nolimit")) {
1219                                 unlimitcore = true;
1220                         }
1221                 }
1222         }
1223
1224         strlcpy(MyExecutable,argv[0],MAXBUF);
1225         
1226         // initialize the lowercase mapping table
1227         for (unsigned int cn = 0; cn < 256; cn++)
1228                 lowermap[cn] = cn;
1229         // lowercase the uppercase chars
1230         for (unsigned int cn = 65; cn < 91; cn++)
1231                 lowermap[cn] = tolower(cn);
1232         // now replace the specific chars for scandanavian comparison
1233         lowermap[(unsigned)'['] = '{';
1234         lowermap[(unsigned)']'] = '}';
1235         lowermap[(unsigned)'\\'] = '|';
1236
1237         if (InspIRCd(argv,argc) == ERROR)
1238         {
1239                 log(DEFAULT,"main: daemon function bailed");
1240                 printf("ERROR: could not initialise. Shutting down.\n");
1241                 Exit(ERROR);
1242         }
1243         Exit(TRUE);
1244         return 0;
1245 }
1246
1247 template<typename T> inline string ConvToStr(const T &in)
1248 {
1249         stringstream tmp;
1250         if (!(tmp << in)) return string();
1251         return tmp.str();
1252 }
1253
1254 /* re-allocates a nick in the user_hash after they change nicknames,
1255  * returns a pointer to the new user as it may have moved */
1256
1257 userrec* ReHashNick(char* Old, char* New)
1258 {
1259         //user_hash::iterator newnick;
1260         user_hash::iterator oldnick = clientlist.find(Old);
1261
1262         log(DEBUG,"ReHashNick: %s %s",Old,New);
1263         
1264         if (!strcasecmp(Old,New))
1265         {
1266                 log(DEBUG,"old nick is new nick, skipping");
1267                 return oldnick->second;
1268         }
1269         
1270         if (oldnick == clientlist.end()) return NULL; /* doesnt exist */
1271
1272         log(DEBUG,"ReHashNick: Found hashed nick %s",Old);
1273
1274         userrec* olduser = oldnick->second;
1275         clientlist[New] = olduser;
1276         clientlist.erase(oldnick);
1277
1278         log(DEBUG,"ReHashNick: Nick rehashed as %s",New);
1279         
1280         return clientlist[New];
1281 }
1282
1283 /* adds or updates an entry in the whowas list */
1284 void AddWhoWas(userrec* u)
1285 {
1286         whowas_hash::iterator iter = whowas.find(u->nick);
1287         WhoWasUser *a = new WhoWasUser();
1288         strlcpy(a->nick,u->nick,NICKMAX);
1289         strlcpy(a->ident,u->ident,IDENTMAX);
1290         strlcpy(a->dhost,u->dhost,160);
1291         strlcpy(a->host,u->host,160);
1292         strlcpy(a->fullname,u->fullname,MAXGECOS);
1293         strlcpy(a->server,u->server,256);
1294         a->signon = u->signon;
1295
1296         /* MAX_WHOWAS:   max number of /WHOWAS items
1297          * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
1298          *               can be replaced by a newer one
1299          */
1300         
1301         if (iter == whowas.end())
1302         {
1303                 if (whowas.size() >= (unsigned)WHOWAS_MAX)
1304                 {
1305                         for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
1306                         {
1307                                 // 3600 seconds in an hour ;)
1308                                 if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600)))
1309                                 {
1310                                         // delete the old one
1311                                         if (i->second) delete i->second;
1312                                         // replace with new one
1313                                         i->second = a;
1314                                         log(DEBUG,"added WHOWAS entry, purged an old record");
1315                                         return;
1316                                 }
1317                         }
1318                         // no space left and user doesnt exist. Don't leave ram in use!
1319                         log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram");
1320                         delete a;
1321                 }
1322                 else
1323                 {
1324                         log(DEBUG,"added fresh WHOWAS entry");
1325                         whowas[a->nick] = a;
1326                 }
1327         }
1328         else
1329         {
1330                 log(DEBUG,"updated WHOWAS entry");
1331                 if (iter->second) delete iter->second;
1332                 iter->second = a;
1333         }
1334 }
1335
1336 #ifdef THREADED_DNS
1337 void* dns_task(void* arg)
1338 {
1339         userrec* u = (userrec*)arg;
1340         log(DEBUG,"DNS thread for user %s",u->nick);
1341         DNS dns1;
1342         DNS dns2;
1343         std::string host;
1344         std::string ip;
1345         if (dns1.ReverseLookup(u->ip))
1346         {
1347                 log(DEBUG,"DNS Step 1");
1348                 while (!dns1.HasResult())
1349                 {
1350                         usleep(100);
1351                 }
1352                 host = dns1.GetResult();
1353                 if (host != "")
1354                 {
1355                         log(DEBUG,"DNS Step 2: '%s'",host.c_str());
1356                         if (dns2.ForwardLookup(host))
1357                         {
1358                                 while (!dns2.HasResult())
1359                                 {
1360                                         usleep(100);
1361                                 }
1362                                 ip = dns2.GetResultIP();
1363                                 log(DEBUG,"DNS Step 3 '%s'(%d) '%s'(%d)",ip.c_str(),ip.length(),u->ip,strlen(u->ip));
1364                                 if (ip == std::string(u->ip))
1365                                 {
1366                                         log(DEBUG,"DNS Step 4");
1367                                         if (host.length() < 160)
1368                                         {
1369                                                 log(DEBUG,"DNS Step 5");
1370                                                 strcpy(u->host,host.c_str());
1371                                                 strcpy(u->dhost,host.c_str());
1372                                         }
1373                                 }
1374                         }
1375                 }
1376         }
1377         u->dns_done = true;
1378         return NULL;
1379 }
1380 #endif
1381
1382 /* add a client connection to the sockets list */
1383 void AddClient(int socket, char* host, int port, bool iscached, char* ip)
1384 {
1385         string tempnick;
1386         char tn2[MAXBUF];
1387         user_hash::iterator iter;
1388
1389         tempnick = ConvToStr(socket) + "-unknown";
1390         sprintf(tn2,"%lu-unknown",(unsigned long)socket);
1391
1392         iter = clientlist.find(tempnick);
1393
1394         // fix by brain.
1395         // as these nicknames are 'RFC impossible', we can be sure nobody is going to be
1396         // using one as a registered connection. As theyre per fd, we can also safely assume
1397         // that we wont have collisions. Therefore, if the nick exists in the list, its only
1398         // used by a dead socket, erase the iterator so that the new client may reclaim it.
1399         // this was probably the cause of 'server ignores me when i hammer it with reconnects'
1400         // issue in earlier alphas/betas
1401         if (iter != clientlist.end())
1402         {
1403                 userrec* goner = iter->second;
1404                 delete goner;
1405                 clientlist.erase(iter);
1406         }
1407
1408         /*
1409          * It is OK to access the value here this way since we know
1410          * it exists, we just created it above.
1411          *
1412          * At NO other time should you access a value in a map or a
1413          * hash_map this way.
1414          */
1415         clientlist[tempnick] = new userrec();
1416
1417         NonBlocking(socket);
1418         log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip);
1419
1420         clientlist[tempnick]->fd = socket;
1421         strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX);
1422         strlcpy(clientlist[tempnick]->host, host,160);
1423         strlcpy(clientlist[tempnick]->dhost, host,160);
1424         clientlist[tempnick]->server = (char*)FindServerNamePtr(ServerName);
1425         strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX);
1426         clientlist[tempnick]->registered = 0;
1427         clientlist[tempnick]->signon = TIME+dns_timeout;
1428         clientlist[tempnick]->lastping = 1;
1429         clientlist[tempnick]->port = port;
1430         strlcpy(clientlist[tempnick]->ip,ip,16);
1431
1432         // set the registration timeout for this user
1433         unsigned long class_regtimeout = 90;
1434         int class_flood = 0;
1435         long class_threshold = 5;
1436         long class_sqmax = 262144;      // 256kb
1437         long class_rqmax = 4096;        // 4k
1438
1439         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
1440         {
1441                 if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW))
1442                 {
1443                         class_regtimeout = (unsigned long)i->registration_timeout;
1444                         class_flood = i->flood;
1445                         clientlist[tempnick]->pingmax = i->pingtime;
1446                         class_threshold = i->threshold;
1447                         class_sqmax = i->sendqmax;
1448                         class_rqmax = i->recvqmax;
1449                         break;
1450                 }
1451         }
1452
1453         clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax+dns_timeout;
1454         clientlist[tempnick]->timeout = TIME+class_regtimeout;
1455         clientlist[tempnick]->flood = class_flood;
1456         clientlist[tempnick]->threshold = class_threshold;
1457         clientlist[tempnick]->sendqmax = class_sqmax;
1458         clientlist[tempnick]->recvqmax = class_rqmax;
1459
1460         for (int i = 0; i < MAXCHANS; i++)
1461         {
1462                 clientlist[tempnick]->chans[i].channel = NULL;
1463                 clientlist[tempnick]->chans[i].uc_modes = 0;
1464         }
1465
1466         if (clientlist.size() > SoftLimit)
1467         {
1468                 kill_link(clientlist[tempnick],"No more connections allowed");
1469                 return;
1470         }
1471
1472         if (clientlist.size() >= MAXCLIENTS)
1473         {
1474                 kill_link(clientlist[tempnick],"No more connections allowed");
1475                 return;
1476         }
1477
1478         // this is done as a safety check to keep the file descriptors within range of fd_ref_table.
1479         // its a pretty big but for the moment valid assumption:
1480         // file descriptors are handed out starting at 0, and are recycled as theyre freed.
1481         // therefore if there is ever an fd over 65535, 65536 clients must be connected to the
1482         // irc server at once (or the irc server otherwise initiating this many connections, files etc)
1483         // which for the time being is a physical impossibility (even the largest networks dont have more
1484         // than about 10,000 users on ONE server!)
1485         if ((unsigned)socket > 65534)
1486         {
1487                 kill_link(clientlist[tempnick],"Server is full");
1488                 return;
1489         }
1490                 
1491
1492         char* e = matches_exception(ip);
1493         if (!e)
1494         {
1495                 char* r = matches_zline(ip);
1496                 if (r)
1497                 {
1498                         char reason[MAXBUF];
1499                         snprintf(reason,MAXBUF,"Z-Lined: %s",r);
1500                         kill_link(clientlist[tempnick],reason);
1501                         return;
1502                 }
1503         }
1504         fd_ref_table[socket] = clientlist[tempnick];
1505         SE->AddFd(socket,true,X_ESTAB_CLIENT);
1506
1507         // initialize their dns lookup thread
1508         //if (pthread_create(&clientlist[tempnick]->dnsthread, NULL, dns_task, (void *)clientlist[tempnick]) != 0)
1509         //{
1510         //      log(DEBUG,"Failed to create DNS lookup thread for user %s",clientlist[tempnick]->nick);
1511         //}
1512 }
1513
1514 /* shows the message of the day, and any other on-logon stuff */
1515 void FullConnectUser(userrec* user)
1516 {
1517         statsConnects++;
1518         user->idle_lastmsg = TIME;
1519         log(DEBUG,"ConnectUser: %s",user->nick);
1520
1521         if ((strcmp(Passwd(user),"")) && (!user->haspassed))
1522         {
1523                 kill_link(user,"Invalid password");
1524                 return;
1525         }
1526         if (IsDenied(user))
1527         {
1528                 kill_link(user,"Unauthorised connection");
1529                 return;
1530         }
1531
1532         char match_against[MAXBUF];
1533         snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host);
1534         char* e = matches_exception(match_against);
1535         if (!e)
1536         {
1537                 char* r = matches_gline(match_against);
1538                 if (r)
1539                 {
1540                         char reason[MAXBUF];
1541                         snprintf(reason,MAXBUF,"G-Lined: %s",r);
1542                         kill_link_silent(user,reason);
1543                         return;
1544                 }
1545                 r = matches_kline(user->host);
1546                 if (r)
1547                 {
1548                         char reason[MAXBUF];
1549                         snprintf(reason,MAXBUF,"K-Lined: %s",r);
1550                         kill_link_silent(user,reason);
1551                         return;
1552                 }
1553         }
1554
1555
1556         WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Network);
1557         WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Network,user->nick,user->ident,user->host);
1558         WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,ServerName,VERSION);
1559         WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
1560         WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION);
1561         // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...
1562         std::stringstream v;
1563         v << "WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS;
1564         v << " MAXBANS=60 NICKLEN=" << NICKMAX;
1565         v << " TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=20 AWAYLEN=" << MAXAWAY << " CHANMODES=ohvb,k,l,psmnti NETWORK=";
1566         v << Network;
1567         std::string data005 = v.str();
1568         FOREACH_MOD On005Numeric(data005);
1569         // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line...
1570         // so i'd better split it :)
1571         std::stringstream out(data005);
1572         std::string token = "";
1573         std::string line5 = "";
1574         int token_counter = 0;
1575         while (!out.eof())
1576         {
1577                 out >> token;
1578                 line5 = line5 + token + " ";
1579                 token_counter++;
1580                 if ((token_counter >= 13) || (out.eof() == true))
1581                 {
1582                         WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str());
1583                         line5 = "";
1584                         token_counter = 0;
1585                 }
1586         }
1587         ShowMOTD(user);
1588
1589         // fix 3 by brain, move registered = 7 below these so that spurious modes and host changes dont go out
1590         // onto the network and produce 'fake direction'
1591         FOREACH_MOD OnUserConnect(user);
1592         FOREACH_MOD OnGlobalConnect(user);
1593         user->registered = 7;
1594         WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip);
1595 }
1596
1597
1598 /* shows the message of the day, and any other on-logon stuff */
1599 void ConnectUser(userrec *user)
1600 {
1601         // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on
1602         if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user)))
1603         {
1604                 FullConnectUser(user);
1605         }
1606 }
1607
1608 std::string GetVersionString()
1609 {
1610         char Revision[] = "$Revision$";
1611         char versiondata[MAXBUF];
1612         char *s1 = Revision;
1613         char *savept;
1614         char *v2 = strtok_r(s1," ",&savept);
1615         s1 = savept;
1616         v2 = strtok_r(s1," ",&savept);
1617         s1 = savept;
1618         char socketengine[] = engine_name;
1619 #ifdef THREADED_DNS
1620         char dnsengine[] = "multithread";
1621 #else
1622         char dnsengine[] = "singlethread";
1623 #endif
1624         snprintf(versiondata,MAXBUF,"%s Rev. %s %s :%s [FLAGS=%lu,%s,%s]",VERSION,v2,ServerName,SYSTEM,(unsigned long)OPTIMISATION,socketengine,dnsengine);
1625         return versiondata;
1626 }
1627
1628 void handle_version(char **parameters, int pcnt, userrec *user)
1629 {
1630         WriteServ(user->fd,"351 %s :%s",user->nick,GetVersionString().c_str());
1631 }
1632
1633
1634 bool is_valid_cmd(const char* commandname, int pcnt, userrec * user)
1635 {
1636         for (unsigned int i = 0; i < cmdlist.size(); i++)
1637         {
1638                 if (!strcasecmp(cmdlist[i].command,commandname))
1639                 {
1640                         if (cmdlist[i].handler_function)
1641                         {
1642                                 if ((pcnt>=cmdlist[i].min_params) && (strcasecmp(cmdlist[i].source,"<core>")))
1643                                 {
1644                                         if ((strchr(user->modes,cmdlist[i].flags_needed)) || (!cmdlist[i].flags_needed))
1645                                         {
1646                                                 if (cmdlist[i].flags_needed)
1647                                                 {
1648                                                         if ((user->HasPermission((char*)commandname)) || (is_uline(user->server)))
1649                                                         {
1650                                                                 return true;
1651                                                         }
1652                                                         else
1653                                                         {
1654                                                                 return false;
1655                                                         }
1656                                                 }
1657                                                 return true;
1658                                         }
1659                                 }
1660                         }
1661                 }
1662         }
1663         return false;
1664 }
1665
1666 // calls a handler function for a command
1667
1668 void call_handler(const char* commandname,char **parameters, int pcnt, userrec *user)
1669 {
1670         for (unsigned int i = 0; i < cmdlist.size(); i++)
1671         {
1672                 if (!strcasecmp(cmdlist[i].command,commandname))
1673                 {
1674                         if (cmdlist[i].handler_function)
1675                         {
1676                                 if (pcnt>=cmdlist[i].min_params)
1677                                 {
1678                                         if ((strchr(user->modes,cmdlist[i].flags_needed)) || (!cmdlist[i].flags_needed))
1679                                         {
1680                                                 if (cmdlist[i].flags_needed)
1681                                                 {
1682                                                         if ((user->HasPermission((char*)commandname)) || (is_uline(user->server)))
1683                                                         {
1684                                                                 cmdlist[i].handler_function(parameters,pcnt,user);
1685                                                         }
1686                                                 }
1687                                                 else
1688                                                 {
1689                                                         cmdlist[i].handler_function(parameters,pcnt,user);
1690                                                 }
1691                                         }
1692                                 }
1693                         }
1694                 }
1695         }
1696 }
1697
1698
1699 void force_nickchange(userrec* user,const char* newnick)
1700 {
1701         char nick[MAXBUF];
1702         int MOD_RESULT = 0;
1703         
1704         strcpy(nick,"");
1705
1706         FOREACH_RESULT(OnUserPreNick(user,newnick));
1707         if (MOD_RESULT) {
1708                 statsCollisions++;
1709                 kill_link(user,"Nickname collision");
1710                 return;
1711         }
1712         if (matches_qline(newnick))
1713         {
1714                 statsCollisions++;
1715                 kill_link(user,"Nickname collision");
1716                 return;
1717         }
1718         
1719         if (user)
1720         {
1721                 if (newnick)
1722                 {
1723                         strncpy(nick,newnick,MAXBUF);
1724                 }
1725                 if (user->registered == 7)
1726                 {
1727                         char* pars[1];
1728                         pars[0] = nick;
1729                         handle_nick(pars,1,user);
1730                 }
1731         }
1732 }
1733                                 
1734
1735 int process_parameters(char **command_p,char *parameters)
1736 {
1737         int j = 0;
1738         int q = strlen(parameters);
1739         if (!q)
1740         {
1741                 /* no parameters, command_p invalid! */
1742                 return 0;
1743         }
1744         if (parameters[0] == ':')
1745         {
1746                 command_p[0] = parameters+1;
1747                 return 1;
1748         }
1749         if (q)
1750         {
1751                 if ((strchr(parameters,' ')==NULL) || (parameters[0] == ':'))
1752                 {
1753                         /* only one parameter */
1754                         command_p[0] = parameters;
1755                         if (parameters[0] == ':')
1756                         {
1757                                 if (strchr(parameters,' ') != NULL)
1758                                 {
1759                                         command_p[0]++;
1760                                 }
1761                         }
1762                         return 1;
1763                 }
1764         }
1765         command_p[j++] = parameters;
1766         for (int i = 0; i <= q; i++)
1767         {
1768                 if (parameters[i] == ' ')
1769                 {
1770                         command_p[j++] = parameters+i+1;
1771                         parameters[i] = '\0';
1772                         if (command_p[j-1][0] == ':')
1773                         {
1774                                 *command_p[j-1]++; /* remove dodgy ":" */
1775                                 break;
1776                                 /* parameter like this marks end of the sequence */
1777                         }
1778                 }
1779         }
1780         return j; /* returns total number of items in the list */
1781 }
1782
1783 void process_command(userrec *user, char* cmd)
1784 {
1785         char *parameters;
1786         char *command;
1787         char *command_p[127];
1788         char p[MAXBUF], temp[MAXBUF];
1789         int j, items, cmd_found;
1790
1791         for (int i = 0; i < 127; i++)
1792                 command_p[i] = NULL;
1793
1794         if (!user)
1795         {
1796                 return;
1797         }
1798         if (!cmd)
1799         {
1800                 return;
1801         }
1802         if (!cmd[0])
1803         {
1804                 return;
1805         }
1806         
1807         int total_params = 0;
1808         if (strlen(cmd)>2)
1809         {
1810                 for (unsigned int q = 0; q < strlen(cmd)-1; q++)
1811                 {
1812                         if ((cmd[q] == ' ') && (cmd[q+1] == ':'))
1813                         {
1814                                 total_params++;
1815                                 // found a 'trailing', we dont count them after this.
1816                                 break;
1817                         }
1818                         if (cmd[q] == ' ')
1819                                 total_params++;
1820                 }
1821         }
1822
1823         // another phidjit bug...
1824         if (total_params > 126)
1825         {
1826                 *(strchr(cmd,' ')) = '\0';
1827                 WriteServ(user->fd,"421 %s %s :Too many parameters given",user->nick,cmd);
1828                 return;
1829         }
1830
1831         strlcpy(temp,cmd,MAXBUF);
1832         
1833         std::string tmp = cmd;
1834         for (int i = 0; i <= MODCOUNT; i++)
1835         {
1836                 std::string oldtmp = tmp;
1837                 modules[i]->OnServerRaw(tmp,true,user);
1838                 if (oldtmp != tmp)
1839                 {
1840                         log(DEBUG,"A Module changed the input string!");
1841                         log(DEBUG,"New string: %s",tmp.c_str());
1842                         log(DEBUG,"Old string: %s",oldtmp.c_str());
1843                         break;
1844                 }
1845         }
1846         strlcpy(cmd,tmp.c_str(),MAXBUF);
1847         strlcpy(temp,cmd,MAXBUF);
1848
1849         if (!strchr(cmd,' '))
1850         {
1851                 /* no parameters, lets skip the formalities and not chop up
1852                  * the string */
1853                 log(DEBUG,"About to preprocess command with no params");
1854                 items = 0;
1855                 command_p[0] = NULL;
1856                 parameters = NULL;
1857                 for (unsigned int i = 0; i <= strlen(cmd); i++)
1858                 {
1859                         cmd[i] = toupper(cmd[i]);
1860                 }
1861                 command = cmd;
1862         }
1863         else
1864         {
1865                 strcpy(cmd,"");
1866                 j = 0;
1867                 /* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */
1868                 for (unsigned int i = 0; i < strlen(temp); i++)
1869                 {
1870                         if ((temp[i] != 10) && (temp[i] != 13) && (temp[i] != 0) && (temp[i] != 7))
1871                         {
1872                                 cmd[j++] = temp[i];
1873                                 cmd[j] = 0;
1874                         }
1875                 }
1876                 /* split the full string into a command plus parameters */
1877                 parameters = p;
1878                 strcpy(p," ");
1879                 command = cmd;
1880                 if (strchr(cmd,' '))
1881                 {
1882                         for (unsigned int i = 0; i <= strlen(cmd); i++)
1883                         {
1884                                 /* capitalise the command ONLY, leave params intact */
1885                                 cmd[i] = toupper(cmd[i]);
1886                                 /* are we nearly there yet?! :P */
1887                                 if (cmd[i] == ' ')
1888                                 {
1889                                         command = cmd;
1890                                         parameters = cmd+i+1;
1891                                         cmd[i] = '\0';
1892                                         break;
1893                                 }
1894                         }
1895                 }
1896                 else
1897                 {
1898                         for (unsigned int i = 0; i <= strlen(cmd); i++)
1899                         {
1900                                 cmd[i] = toupper(cmd[i]);
1901                         }
1902                 }
1903
1904         }
1905         cmd_found = 0;
1906         
1907         if (strlen(command)>MAXCOMMAND)
1908         {
1909                 WriteServ(user->fd,"421 %s %s :Command too long",user->nick,command);
1910                 return;
1911         }
1912         
1913         for (unsigned int x = 0; x < strlen(command); x++)
1914         {
1915                 if (((command[x] < 'A') || (command[x] > 'Z')) && (command[x] != '.'))
1916                 {
1917                         if (((command[x] < '0') || (command[x]> '9')) && (command[x] != '-'))
1918                         {
1919                                 if (strchr("@!\"$%^&*(){}[]_=+;:'#~,<>/?\\|`",command[x]))
1920                                 {
1921                                         statsUnknown++;
1922                                         WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
1923                                         return;
1924                                 }
1925                         }
1926                 }
1927         }
1928
1929         for (unsigned int i = 0; i != cmdlist.size(); i++)
1930         {
1931                 if (cmdlist[i].command[0])
1932                 {
1933                         if (strlen(command)>=(strlen(cmdlist[i].command))) if (!strncmp(command, cmdlist[i].command,MAXCOMMAND))
1934                         {
1935                                 if (parameters)
1936                                 {
1937                                         if (parameters[0])
1938                                         {
1939                                                 items = process_parameters(command_p,parameters);
1940                                         }
1941                                         else
1942                                         {
1943                                                 items = 0;
1944                                                 command_p[0] = NULL;
1945                                         }
1946                                 }
1947                                 else
1948                                 {
1949                                         items = 0;
1950                                         command_p[0] = NULL;
1951                                 }
1952                                 
1953                                 if (user)
1954                                 {
1955                                         /* activity resets the ping pending timer */
1956                                         user->nping = TIME + user->pingmax;
1957                                         if ((items) < cmdlist[i].min_params)
1958                                         {
1959                                                 log(DEBUG,"process_command: not enough parameters: %s %s",user->nick,command);
1960                                                 WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,command);
1961                                                 return;
1962                                         }
1963                                         if ((!strchr(user->modes,cmdlist[i].flags_needed)) && (cmdlist[i].flags_needed))
1964                                         {
1965                                                 log(DEBUG,"process_command: permission denied: %s %s",user->nick,command);
1966                                                 WriteServ(user->fd,"481 %s :Permission Denied- You do not have the required operator privilages",user->nick);
1967                                                 cmd_found = 1;
1968                                                 return;
1969                                         }
1970                                         if ((cmdlist[i].flags_needed) && (!user->HasPermission(command)))
1971                                         {
1972                                                 log(DEBUG,"process_command: permission denied: %s %s",user->nick,command);
1973                                                 WriteServ(user->fd,"481 %s :Permission Denied- Oper type %s does not have access to command %s",user->nick,user->oper,command);
1974                                                 cmd_found = 1;
1975                                                 return;
1976                                         }
1977                                         /* if the command isnt USER, PASS, or NICK, and nick is empty,
1978                                          * deny command! */
1979                                         if ((strncmp(command,"USER",4)) && (strncmp(command,"NICK",4)) && (strncmp(command,"PASS",4)))
1980                                         {
1981                                                 if ((!isnick(user->nick)) || (user->registered != 7))
1982                                                 {
1983                                                         log(DEBUG,"process_command: not registered: %s %s",user->nick,command);
1984                                                         WriteServ(user->fd,"451 %s :You have not registered",command);
1985                                                         return;
1986                                                 }
1987                                         }
1988                                         if ((user->registered == 7) && (!strchr(user->modes,'o')))
1989                                         {
1990                                                 std::stringstream dcmds(DisabledCommands);
1991                                                 while (!dcmds.eof())
1992                                                 {
1993                                                         std::string thiscmd;
1994                                                         dcmds >> thiscmd;
1995                                                         if (!strcasecmp(thiscmd.c_str(),command))
1996                                                         {
1997                                                                 // command is disabled!
1998                                                                 WriteServ(user->fd,"421 %s %s :This command has been disabled.",user->nick,command);
1999                                                                 return;
2000                                                         }
2001                                                 }
2002                                         }
2003                                         if ((user->registered == 7) || (!strncmp(command,"USER",4)) || (!strncmp(command,"NICK",4)) || (!strncmp(command,"PASS",4)))
2004                                         {
2005                                                 if (cmdlist[i].handler_function)
2006                                                 {
2007                                                         
2008                                                         /* ikky /stats counters */
2009                                                         if (temp)
2010                                                         {
2011                                                                 cmdlist[i].use_count++;
2012                                                                 cmdlist[i].total_bytes+=strlen(temp);
2013                                                         }
2014
2015                                                         int MOD_RESULT = 0;
2016                                                         FOREACH_RESULT(OnPreCommand(command,command_p,items,user));
2017                                                         if (MOD_RESULT == 1) {
2018                                                                 return;
2019                                                         }
2020
2021                                                         /* WARNING: nothing may come after the
2022                                                          * command handler call, as the handler
2023                                                          * may free the user structure! */
2024
2025                                                         cmdlist[i].handler_function(command_p,items,user);
2026                                                 }
2027                                                 return;
2028                                         }
2029                                         else
2030                                         {
2031                                                 WriteServ(user->fd,"451 %s :You have not registered",command);
2032                                                 return;
2033                                         }
2034                                 }
2035                                 cmd_found = 1;
2036                         }
2037                 }
2038         }
2039         if ((!cmd_found) && (user))
2040         {
2041                 statsUnknown++;
2042                 WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
2043         }
2044 }
2045
2046 bool removecommands(const char* source)
2047 {
2048         bool go_again = true;
2049         while (go_again)
2050         {
2051                 go_again = false;
2052                 for (std::deque<command_t>::iterator i = cmdlist.begin(); i != cmdlist.end(); i++)
2053                 {
2054                         if (!strcmp(i->source,source))
2055                         {
2056                                 log(DEBUG,"removecommands(%s) Removing dependent command: %s",i->source,i->command);
2057                                 cmdlist.erase(i);
2058                                 go_again = true;
2059                                 break;
2060                         }
2061                 }
2062         }
2063         return true;
2064 }
2065
2066
2067 void process_buffer(const char* cmdbuf,userrec *user)
2068 {
2069         if (!user)
2070         {
2071                 log(DEFAULT,"*** BUG *** process_buffer was given an invalid parameter");
2072                 return;
2073         }
2074         char cmd[MAXBUF];
2075         if (!cmdbuf)
2076         {
2077                 log(DEFAULT,"*** BUG *** process_buffer was given an invalid parameter");
2078                 return;
2079         }
2080         if (!cmdbuf[0])
2081         {
2082                 return;
2083         }
2084         while (*cmdbuf == ' ') cmdbuf++; // strip leading spaces
2085
2086         strlcpy(cmd,cmdbuf,MAXBUF);
2087         if (!cmd[0])
2088         {
2089                 return;
2090         }
2091         int sl = strlen(cmd)-1;
2092         if ((cmd[sl] == 13) || (cmd[sl] == 10))
2093         {
2094                 cmd[sl] = '\0';
2095         }
2096         sl = strlen(cmd)-1;
2097         if ((cmd[sl] == 13) || (cmd[sl] == 10))
2098         {
2099                 cmd[sl] = '\0';
2100         }
2101         sl = strlen(cmd)-1;
2102         while (cmd[sl] == ' ') // strip trailing spaces
2103         {
2104                 cmd[sl] = '\0';
2105                 sl = strlen(cmd)-1;
2106         }
2107
2108         if (!cmd[0])
2109         {
2110                 return;
2111         }
2112         log(DEBUG,"CMDIN: %s %s",user->nick,cmd);
2113         tidystring(cmd);
2114         if ((user) && (cmd))
2115         {
2116                 process_command(user,cmd);
2117         }
2118 }
2119
2120 char MODERR[MAXBUF];
2121
2122 char* ModuleError()
2123 {
2124         return MODERR;
2125 }
2126
2127 void erase_factory(int j)
2128 {
2129         int v = 0;
2130         for (std::vector<ircd_module*>::iterator t = factory.begin(); t != factory.end(); t++)
2131         {
2132                 if (v == j)
2133                 {
2134                         factory.erase(t);
2135                         factory.push_back(NULL);
2136                         return;
2137                 }
2138                 v++;
2139         }
2140 }
2141
2142 void erase_module(int j)
2143 {
2144         int v1 = 0;
2145         for (std::vector<Module*>::iterator m = modules.begin(); m!= modules.end(); m++)
2146         {
2147                 if (v1 == j)
2148                 {
2149                         delete *m;
2150                         modules.erase(m);
2151                         modules.push_back(NULL);
2152                         break;
2153                 }
2154                 v1++;
2155         }
2156         int v2 = 0;
2157         for (std::vector<std::string>::iterator v = module_names.begin(); v != module_names.end(); v++)
2158         {
2159                 if (v2 == j)
2160                 {
2161                        module_names.erase(v);
2162                        break;
2163                 }
2164                 v2++;
2165         }
2166
2167 }
2168
2169 bool UnloadModule(const char* filename)
2170 {
2171         std::string filename_str = filename;
2172         for (unsigned int j = 0; j != module_names.size(); j++)
2173         {
2174                 if (module_names[j] == filename_str)
2175                 {
2176                         if (modules[j]->GetVersion().Flags & VF_STATIC)
2177                         {
2178                                 log(DEFAULT,"Failed to unload STATIC module %s",filename);
2179                                 snprintf(MODERR,MAXBUF,"Module not unloadable (marked static)");
2180                                 return false;
2181                         }
2182                         /* Give the module a chance to tidy out all its metadata */
2183                         for (chan_hash::iterator c = chanlist.begin(); c != chanlist.end(); c++)
2184                         {
2185                                 modules[j]->OnCleanup(TYPE_CHANNEL,c->second);
2186                         }
2187                         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
2188                         {
2189                                 modules[j]->OnCleanup(TYPE_USER,u->second);
2190                         }
2191                         FOREACH_MOD OnUnloadModule(modules[j],module_names[j]);
2192                         // found the module
2193                         log(DEBUG,"Deleting module...");
2194                         erase_module(j);
2195                         log(DEBUG,"Erasing module entry...");
2196                         erase_factory(j);
2197                         log(DEBUG,"Removing dependent commands...");
2198                         removecommands(filename);
2199                         log(DEFAULT,"Module %s unloaded",filename);
2200                         MODCOUNT--;
2201                         return true;
2202                 }
2203         }
2204         log(DEFAULT,"Module %s is not loaded, cannot unload it!",filename);
2205         snprintf(MODERR,MAXBUF,"Module not loaded");
2206         return false;
2207 }
2208
2209 bool LoadModule(const char* filename)
2210 {
2211         char modfile[MAXBUF];
2212 #ifdef STATIC_LINK
2213         snprintf(modfile,MAXBUF,"%s",filename);
2214 #else
2215         snprintf(modfile,MAXBUF,"%s/%s",ModPath,filename);
2216 #endif
2217         std::string filename_str = filename;
2218 #ifndef STATIC_LINK
2219         if (!DirValid(modfile))
2220         {
2221                 log(DEFAULT,"Module %s is not within the modules directory.",modfile);
2222                 snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile);
2223                 return false;
2224         }
2225 #endif
2226         log(DEBUG,"Loading module: %s",modfile);
2227 #ifndef STATIC_LINK
2228         if (FileExists(modfile))
2229         {
2230 #endif
2231                 for (unsigned int j = 0; j < module_names.size(); j++)
2232                 {
2233                         if (module_names[j] == filename_str)
2234                         {
2235                                 log(DEFAULT,"Module %s is already loaded, cannot load a module twice!",modfile);
2236                                 snprintf(MODERR,MAXBUF,"Module already loaded");
2237                                 return false;
2238                         }
2239                 }
2240                 ircd_module* a = new ircd_module(modfile);
2241                 factory[MODCOUNT+1] = a;
2242                 if (factory[MODCOUNT+1]->LastError())
2243                 {
2244                         log(DEFAULT,"Unable to load %s: %s",modfile,factory[MODCOUNT+1]->LastError());
2245                         snprintf(MODERR,MAXBUF,"Loader/Linker error: %s",factory[MODCOUNT+1]->LastError());
2246                         MODCOUNT--;
2247                         return false;
2248                 }
2249                 if (factory[MODCOUNT+1]->factory)
2250                 {
2251                         Module* m = factory[MODCOUNT+1]->factory->CreateModule(MyServer);
2252                         modules[MODCOUNT+1] = m;
2253                         /* save the module and the module's classfactory, if
2254                          * this isnt done, random crashes can occur :/ */
2255                         module_names.push_back(filename);
2256                 }
2257                 else
2258                 {
2259                         log(DEFAULT,"Unable to load %s",modfile);
2260                         snprintf(MODERR,MAXBUF,"Factory function failed!");
2261                         return false;
2262                 }
2263 #ifndef STATIC_LINK
2264         }
2265         else
2266         {
2267                 log(DEFAULT,"InspIRCd: startup: Module Not Found %s",modfile);
2268                 snprintf(MODERR,MAXBUF,"Module file could not be found");
2269                 return false;
2270         }
2271 #endif
2272         MODCOUNT++;
2273         FOREACH_MOD OnLoadModule(modules[MODCOUNT],filename_str);
2274         return true;
2275 }
2276
2277
2278 void ProcessUser(userrec* cu)
2279 {
2280         int result = EAGAIN;
2281         log(DEBUG,"Processing user with fd %d",cu->fd);
2282         int MOD_RESULT = 0;
2283         int result2 = 0;
2284         FOREACH_RESULT(OnRawSocketRead(cu->fd,data,65535,result2));
2285         if (!MOD_RESULT)
2286         {
2287                 result = cu->ReadData(data, 65535);
2288         }
2289         else
2290         {
2291                 log(DEBUG,"Data result returned by module: %d",MOD_RESULT);
2292                 result = result2;
2293         }
2294         log(DEBUG,"Read result: %d",result);
2295         if (result)
2296         {
2297                 statsRecv += result;
2298                 // perform a check on the raw buffer as an array (not a string!) to remove
2299                 // characters 0 and 7 which are illegal in the RFC - replace them with spaces.
2300                 // hopefully this should stop even more people whining about "Unknown command: *"
2301                 for (int checker = 0; checker < result; checker++)
2302                 {
2303                         if ((data[checker] == 0) || (data[checker] == 7))
2304                                 data[checker] = ' ';
2305                 }
2306                 if (result > 0)
2307                         data[result] = '\0';
2308                 userrec* current = cu;
2309                 int currfd = current->fd;
2310                 int floodlines = 0;
2311                 // add the data to the users buffer
2312                 if (result > 0)
2313                 {
2314                         if (!current->AddBuffer(data))
2315                         {
2316                                 // AddBuffer returned false, theres too much data in the user's buffer and theyre up to no good.
2317                                 if (current->registered == 7)
2318                                 {
2319                                         kill_link(current,"RecvQ exceeded");
2320                                 }
2321                                 else
2322                                 {
2323                                         WriteOpers("*** Excess flood from %s",current->ip);
2324                                         log(DEFAULT,"Excess flood from: %s",current->ip);
2325                                         add_zline(120,ServerName,"Flood from unregistered connection",current->ip);
2326                                         apply_lines();
2327                                 }
2328                                 return;
2329                         }
2330                         if (current->recvq.length() > (unsigned)NetBufferSize)
2331                         {
2332                                 if (current->registered == 7)
2333                                 {
2334                                         kill_link(current,"RecvQ exceeded");
2335                                 }
2336                                 else
2337                                 {
2338                                         WriteOpers("*** Excess flood from %s",current->ip);
2339                                         log(DEFAULT,"Excess flood from: %s",current->ip);
2340                                         add_zline(120,ServerName,"Flood from unregistered connection",current->ip);
2341                                         apply_lines();
2342                                 }
2343                                 return;
2344                         }
2345                         // while there are complete lines to process...
2346                         while (current->BufferIsReady())
2347                         {
2348                                 floodlines++;
2349                                 if (TIME > current->reset_due)
2350                                 {
2351                                         current->reset_due = TIME + current->threshold;
2352                                         current->lines_in = 0;
2353                                 }
2354                                 current->lines_in++;
2355                                 if (current->lines_in > current->flood)
2356                                 {
2357                                         log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
2358                                         WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
2359                                         kill_link(current,"Excess flood");
2360                                         return;
2361                                 }
2362                                 if ((floodlines > current->flood) && (current->flood != 0))
2363                                 {
2364                                         if (current->registered == 7)
2365                                         {
2366                                                 log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
2367                                                 WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
2368                                                 kill_link(current,"Excess flood");
2369                                         }
2370                                         else
2371                                         {
2372                                                 add_zline(120,ServerName,"Flood from unregistered connection",current->ip);
2373                                                 apply_lines();
2374                                         }
2375                                         return;
2376                                 }
2377                                 char sanitized[MAXBUF];
2378                                 // use GetBuffer to copy single lines into the sanitized string
2379                                 std::string single_line = current->GetBuffer();
2380                                 current->bytes_in += single_line.length();
2381                                 current->cmds_in++;
2382                                 if (single_line.length()>512)
2383                                 {
2384                                         log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
2385                                         WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
2386                                         kill_link(current,"Excess flood");
2387                                         return;
2388                                 }
2389                                 strlcpy(sanitized,single_line.c_str(),MAXBUF);
2390                                 if (*sanitized)
2391                                 {
2392                                         userrec* old_comp = fd_ref_table[currfd];
2393                                         // we're gonna re-scan to check if the nick is gone, after every
2394                                         // command - if it has, we're gonna bail
2395                                         process_buffer(sanitized,current);
2396                                         // look for the user's record in case it's changed... if theyve quit,
2397                                         // we cant do anything more with their buffer, so bail.
2398                                         // there used to be an ugly, slow loop here. Now we have a reference
2399                                         // table, life is much easier (and FASTER)
2400                                         userrec* new_comp = fd_ref_table[currfd];
2401                                         if ((currfd < 0) || (!fd_ref_table[currfd]) || (old_comp != new_comp))
2402                                                 return;
2403                                 }
2404                         }
2405                         return;
2406                 }
2407                 if ((result == -1) && (errno != EAGAIN) && (errno != EINTR))
2408                 {
2409                         log(DEBUG,"killing: %s",cu->nick);
2410                         kill_link(cu,strerror(errno));
2411                         return;
2412                 }
2413         }
2414         // result EAGAIN means nothing read
2415         else if (result == EAGAIN)
2416         {
2417         }
2418         else if (result == 0)
2419         {
2420                 log(DEBUG,"InspIRCd: Exited: %s",cu->nick);
2421                 kill_link(cu,"Client exited");
2422                 log(DEBUG,"Bailing from client exit");
2423                 return;
2424         }
2425 }
2426
2427 void DoBackgroundUserStuff()
2428 {
2429         for (user_hash::iterator count2 = clientlist.begin(); count2 != clientlist.end(); count2++)
2430         {
2431                 userrec* curr = NULL;
2432                 if (count2->second)
2433                         curr = count2->second;
2434                 if ((long)curr == -1)
2435                         return;
2436
2437                 if ((curr) && (curr->fd != 0))
2438                 {
2439                         int currfd = curr->fd;
2440                         // we don't check the state of remote users.
2441                         if ((currfd != -1) && (currfd != FD_MAGIC_NUMBER))
2442                         {
2443                                 curr->FlushWriteBuf();
2444                                 if (curr->GetWriteError() != "")
2445                                 {
2446                                         log(DEBUG,"InspIRCd: write error: %s",curr->GetWriteError().c_str());
2447                                         kill_link(curr,curr->GetWriteError().c_str());
2448                                         return;
2449                                 }
2450                                 // registration timeout -- didnt send USER/NICK/HOST in the time specified in
2451                                 // their connection class.
2452                                 if (((unsigned)TIME > (unsigned)curr->timeout) && (curr->registered != 7))
2453                                 {
2454                                         log(DEBUG,"InspIRCd: registration timeout: %s",curr->nick);
2455                                         kill_link(curr,"Registration timeout");
2456                                         return;
2457                                 }
2458                                 if ((TIME > curr->signon) && (curr->registered == 3) && (AllModulesReportReady(curr)))
2459                                 {
2460                                         log(DEBUG,"signon exceed, registered=3, and modules ready, OK: %d %d",TIME,curr->signon);
2461                                         curr->dns_done = true;
2462                                         statsDnsBad++;
2463                                         FullConnectUser(curr);
2464                                         if (fd_ref_table[currfd] != curr) // something changed, bail pronto
2465                                                 return;
2466                                  }
2467                                  if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr)))
2468                                  {
2469                                        log(DEBUG,"dns done, registered=3, and modules ready, OK");
2470                                        FullConnectUser(curr);
2471                                        if (fd_ref_table[currfd] != curr) // something changed, bail pronto
2472                                                 return;
2473                                  }
2474                                  if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7))
2475                                  {
2476                                        if ((!curr->lastping) && (curr->registered == 7))
2477                                        {
2478                                                log(DEBUG,"InspIRCd: ping timeout: %s",curr->nick);
2479                                                kill_link(curr,"Ping timeout");
2480                                                return;
2481                                        }
2482                                        Write(curr->fd,"PING :%s",ServerName);
2483                                        log(DEBUG,"InspIRCd: pinging: %s",curr->nick);
2484                                        curr->lastping = 0;
2485                                        curr->nping = TIME+curr->pingmax;       // was hard coded to 120
2486                                  }
2487                          }
2488                  }
2489          }
2490 }
2491
2492 void OpenLog(char** argv, int argc)
2493 {
2494         std::string logpath = GetFullProgDir(argv,argc) + "/ircd.log";
2495         log_file = fopen(logpath.c_str(),"a+");
2496         if (!log_file)
2497         {
2498                 printf("ERROR: Could not write to logfile %s, bailing!\n\n",logpath.c_str());
2499                 Exit(ERROR);
2500         }
2501 #ifdef IS_CYGWIN
2502         printf("Logging to ircd.log...\n");
2503 #else
2504         printf("Logging to %s...\n",logpath.c_str());
2505 #endif
2506 }
2507
2508 void CheckRoot()
2509 {
2510         if (geteuid() == 0)
2511         {
2512                 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
2513                 log(DEFAULT,"InspIRCd: startup: not starting with UID 0!");
2514                 Exit(ERROR);
2515         }
2516 }
2517
2518 int InspIRCd(char** argv, int argc)
2519 {
2520         struct sockaddr_in client,server;
2521         char addrs[MAXBUF][255];
2522         int incomingSockfd;
2523         socklen_t length;
2524         int count = 0;
2525         int clientportcount = 0;
2526         char configToken[MAXBUF], Addr[MAXBUF], Type[MAXBUF];
2527
2528         OpenLog(argv, argc);
2529         CheckRoot();
2530         SetupCommandTable();
2531         ReadConfig(true,NULL);
2532         AddServerName(ServerName);
2533         
2534         if (DieValue[0])
2535         { 
2536                 printf("WARNING: %s\n\n",DieValue);
2537                 log(DEFAULT,"Ut-Oh, somebody didn't read their config file: '%s'",DieValue);
2538                 exit(0); 
2539         }  
2540         log(DEBUG,"InspIRCd: startup: read config");
2541
2542         for (count = 0; count < ConfValueEnum("bind",&config_f); count++)
2543         {
2544                 ConfValue("bind","port",count,configToken,&config_f);
2545                 ConfValue("bind","address",count,Addr,&config_f);
2546                 ConfValue("bind","type",count,Type,&config_f);
2547                 if (!strcmp(Type,"servers"))
2548                 {
2549                         // modules handle this bind type now.
2550                 }
2551                 else
2552                 {
2553                         ports[clientportcount] = atoi(configToken);
2554                         strlcpy(addrs[clientportcount],Addr,256);
2555                         clientportcount++;
2556                 }
2557                 log(DEBUG,"InspIRCd: startup: read binding %s:%s [%s] from config",Addr,configToken, Type);
2558         }
2559         portCount = clientportcount;
2560   
2561         log(DEBUG,"InspIRCd: startup: read %lu total client ports",(unsigned long)portCount);
2562
2563         printf("\n");
2564         
2565         /* BugFix By Craig! :p */
2566         MODCOUNT = -1;
2567         for (count = 0; count < ConfValueEnum("module",&config_f); count++)
2568         {
2569                 ConfValue("module","name",count,configToken,&config_f);
2570                 printf("Loading module... \033[1;32m%s\033[0m\n",configToken);
2571                 if (!LoadModule(configToken))
2572                 {
2573                         log(DEFAULT,"Exiting due to a module loader error.");
2574                         printf("\nThere was an error loading a module: %s\n\nYou might want to do './inspircd start' instead of 'bin/inspircd'\n\n",ModuleError());
2575                         Exit(0);
2576                 }
2577         }
2578         log(DEFAULT,"Total loaded modules: %lu",(unsigned long)MODCOUNT+1);
2579         
2580         startup_time = time(NULL);
2581           
2582         char PID[MAXBUF];
2583         ConfValue("pid","file",0,PID,&config_f);
2584         // write once here, to try it out and make sure its ok
2585         WritePID(PID);
2586
2587         log(VERBOSE,"InspIRCd: startup: portCount = %lu", (unsigned long)portCount);
2588         
2589         for (count = 0; count < portCount; count++)
2590         {
2591                 if ((openSockfd[boundPortCount] = OpenTCPSocket()) == ERROR)
2592                 {
2593                         log(DEBUG,"InspIRCd: startup: bad fd %lu",(unsigned long)openSockfd[boundPortCount]);
2594                         return(ERROR);
2595                 }
2596                 if (BindSocket(openSockfd[boundPortCount],client,server,ports[count],addrs[count]) == ERROR)
2597                 {
2598                         log(DEFAULT,"InspIRCd: startup: failed to bind port %lu",(unsigned long)ports[count]);
2599                 }
2600                 else    /* well we at least bound to one socket so we'll continue */
2601                 {
2602                         boundPortCount++;
2603                 }
2604         }
2605         
2606         log(DEBUG,"InspIRCd: startup: total bound ports %lu",(unsigned long)boundPortCount);
2607           
2608         /* if we didn't bind to anything then abort */
2609         if (boundPortCount == 0)
2610         {
2611                 log(DEFAULT,"InspIRCd: startup: no ports bound, bailing!");
2612                 printf("\nERROR: Was not able to bind any of %lu ports! Please check your configuration.\n\n", (unsigned long)portCount);
2613                 return (ERROR);
2614         }
2615         
2616
2617         printf("\nInspIRCd is now running!\n");
2618
2619         if (nofork)
2620         {
2621                 log(VERBOSE,"Not forking as -nofork was specified");
2622         }
2623         else
2624         {
2625                 if (DaemonSeed() == ERROR)
2626                 {
2627                         log(DEFAULT,"InspIRCd: startup: can't daemonise");
2628                         printf("ERROR: could not go into daemon mode. Shutting down.\n");
2629                         Exit(ERROR);
2630                 }
2631         }
2632
2633         SE = new SocketEngine();
2634
2635         /* Add the listening sockets used for client inbound connections
2636          * to the socket engine
2637          */
2638         for (count = 0; count < portCount; count++)
2639                 SE->AddFd(openSockfd[count],true,X_LISTEN);
2640
2641         std::vector<int> activefds;
2642
2643         WritePID(PID);
2644         bool expire_run = false;
2645
2646         /* main loop, this never returns */
2647         for (;;)
2648         {
2649 #ifdef _POSIX_PRIORITY_SCHEDULING
2650                 sched_yield();
2651 #endif
2652                 // we only read time() once per iteration rather than tons of times!
2653                 OLDTIME = TIME;
2654                 TIME = time(NULL);
2655
2656 #ifndef THREADED_DNS
2657                 dns_poll();
2658 #endif
2659
2660                 unsigned int numsockets = module_sockets.size();
2661                 for (std::vector<InspSocket*>::iterator a = module_sockets.begin(); a < module_sockets.end(); a++)
2662                 {
2663                         InspSocket* s = (InspSocket*)*a;
2664                         if ((s) && (!s->Poll()))
2665                         {
2666                                 log(DEBUG,"Socket poll returned false, close and bail");
2667                                 s->Close();
2668                                 module_sockets.erase(a);
2669                                 delete s;
2670                                 break;
2671                         }
2672                         // we gained a socket, sarper
2673                         if (module_sockets.size() != numsockets) break;
2674                 }
2675
2676                 // *FIX* Instead of closing sockets in kill_link when they receive the ERROR :blah line, we should queue
2677                 // them in a list, then reap the list every second or so.
2678                 if (((TIME % 5) == 0) && (!expire_run))
2679                 {
2680                         expire_lines();
2681                         FOREACH_MOD OnBackgroundTimer(TIME);
2682                         expire_run = true;
2683                         continue;
2684                 }
2685                 if ((TIME % 5) == 1)
2686                         expire_run = false;
2687                 
2688                 DoBackgroundUserStuff();
2689
2690                 SE->Wait(activefds);
2691         
2692                 for (unsigned int activefd = 0; activefd < activefds.size(); activefd++)
2693                 {
2694                         userrec* cu = fd_ref_table[activefds[activefd]];
2695                         if (cu)
2696                         {
2697                                 /* It's a user */
2698                                 ProcessUser(cu);
2699                         }
2700                         else
2701                         {
2702                                 /* It maybe a listener */
2703                                 for (count = 0; count < boundPortCount; count++)
2704                                 {
2705                                         if (activefds[activefd] == openSockfd[count])
2706                                         {
2707                                                 char target[MAXBUF], resolved[MAXBUF];
2708                                                 length = sizeof (client);
2709                                                 incomingSockfd = accept (openSockfd[count], (struct sockaddr *) &client, &length);
2710                                                 log(DEBUG,"Accepted socket %d",incomingSockfd);
2711                                                 strlcpy (target, (char *) inet_ntoa (client.sin_addr), MAXBUF);
2712                                                 strlcpy (resolved, target, MAXBUF);
2713                                                 if (incomingSockfd >= 0)
2714                                                 {
2715                                                         FOREACH_MOD OnRawSocketAccept(incomingSockfd, resolved, ports[count]);
2716                                                         statsAccept++;
2717                                                         AddClient(incomingSockfd, resolved, ports[count], false, inet_ntoa (client.sin_addr));
2718                                                         log(DEBUG,"Adding client on port %lu fd=%lu",(unsigned long)ports[count],(unsigned long)incomingSockfd);
2719                                                 }
2720                                                 else
2721                                                 {
2722                                                         WriteOpers("*** WARNING: accept() failed on port %lu (%s)",(unsigned long)ports[count],target);
2723                                                         log(DEBUG,"accept failed: %lu",(unsigned long)ports[count]);
2724                                                         statsRefused++;
2725                                                 }
2726                                         }
2727                                 }
2728                         }
2729                 }
2730
2731         }
2732         /* This is never reached -- we hope! */
2733         return 0;
2734 }
2735