]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/inspircd.cpp
Now clears the autoconns map on rehash
[user/henk/code/inspircd.git] / src / inspircd.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2004 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.h"
22 #include "inspircd_io.h"
23 #include "inspircd_util.h"
24 #include "inspircd_config.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 50
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 #include "connection.h"
55 #include "users.h"
56 #include "servers.h"
57 #include "ctables.h"
58 #include "globals.h"
59 #include "modules.h"
60 #include "dynamic.h"
61 #include "wildcard.h"
62 #include "message.h"
63 #include "mode.h"
64 #include "commands.h"
65 #include "xline.h"
66 #include "inspstring.h"
67 #include "dnsqueue.h"
68 #include "helperfuncs.h"
69 #include "hashcomp.h"
70
71 int LogLevel = DEFAULT;
72 char ServerName[MAXBUF];
73 char Network[MAXBUF];
74 char ServerDesc[MAXBUF];
75 char AdminName[MAXBUF];
76 char AdminEmail[MAXBUF];
77 char AdminNick[MAXBUF];
78 char diepass[MAXBUF];
79 char restartpass[MAXBUF];
80 char motd[MAXBUF];
81 char rules[MAXBUF];
82 char list[MAXBUF];
83 char PrefixQuit[MAXBUF];
84 char DieValue[MAXBUF];
85 char DNSServer[MAXBUF];
86 int debugging =  0;
87 int WHOWAS_STALE = 48; // default WHOWAS Entries last 2 days before they go 'stale'
88 int WHOWAS_MAX = 100;  // default 100 people maximum in the WHOWAS list
89 int DieDelay  =  5;
90 time_t startup_time = time(NULL);
91 int NetBufferSize = 10240;      // NetBufferSize used as the buffer size for all read() ops
92 int MaxConn = SOMAXCONN;        // size of accept() backlog (128 by default on *BSD)
93 extern int MaxWhoResults;
94 time_t nb_start = 0;
95 int dns_timeout = 5;
96
97 char DisabledCommands[MAXBUF];
98
99 bool AllowHalfop = true;
100 bool AllowProtect = true;
101 bool AllowFounder = true;
102
103 extern std::vector<Module*> modules;
104 std::vector<std::string> module_names;
105 extern std::vector<ircd_module*> factory;
106
107 extern int MODCOUNT;
108 int openSockfd[MAXSOCKS];
109 bool nofork = false;
110 bool unlimitcore = false;
111
112 time_t TIME = time(NULL), OLDTIME = time(NULL);
113
114 #ifdef USE_KQUEUE
115 int kq, lkq, skq;
116 #endif
117
118 #ifdef USE_EPOLL
119 int ep, lep, sep;
120 #endif
121
122 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;
123 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHashComp> chan_hash;
124 typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, irc::InAddr_HashComp> address_cache;
125 typedef nspace::hash_map<std::string, WhoWasUser*, nspace::hash<string>, irc::StrHashComp> whowas_hash;
126 typedef std::deque<command_t> command_table;
127 typedef std::map<std::string,time_t> autoconnects;
128
129 // This table references users by file descriptor.
130 // its an array to make it VERY fast, as all lookups are referenced
131 // by an integer, meaning there is no need for a scan/search operation.
132 userrec* fd_ref_table[65536];
133
134 int statsAccept = 0, statsRefused = 0, statsUnknown = 0, statsCollisions = 0, statsDns = 0, statsDnsGood = 0, statsDnsBad = 0, statsConnects = 0, statsSent= 0, statsRecv = 0;
135
136 serverrec* me[32];
137
138 FILE *log_file;
139
140 user_hash clientlist;
141 chan_hash chanlist;
142 whowas_hash whowas;
143 command_table cmdlist;
144 autoconnects autoconns;
145 file_cache MOTD;
146 file_cache RULES;
147 address_cache IP;
148
149 ClassVector Classes;
150
151 struct linger linger = { 0 };
152 char MyExecutable[1024];
153 int boundPortCount = 0;
154 int portCount = 0, SERVERportCount = 0, ports[MAXSOCKS];
155 int defaultRoute = 0;
156 char ModPath[MAXBUF];
157
158 /* prototypes */
159
160 int has_channel(userrec *u, chanrec *c);
161 int usercount(chanrec *c);
162 int usercount_i(chanrec *c);
163 char* Passwd(userrec *user);
164 bool IsDenied(userrec *user);
165 void AddWhoWas(userrec* u);
166
167 std::vector<long> auth_cookies;
168 std::stringstream config_f(stringstream::in | stringstream::out);
169
170 std::vector<userrec*> all_opers;
171
172 char lowermap[255];
173
174 void AddOper(userrec* user)
175 {
176         log(DEBUG,"Oper added to optimization list");
177         all_opers.push_back(user);
178 }
179
180 void DeleteOper(userrec* user)
181 {
182         for (std::vector<userrec*>::iterator a = all_opers.begin(); a < all_opers.end(); a++)
183         {
184                 if (*a == user)
185                 {
186                         log(DEBUG,"Oper removed from optimization list");
187                         all_opers.erase(a);
188                         return;
189                 }
190         }
191 }
192
193 std::string GetRevision()
194 {
195         char Revision[] = "$Revision$";
196         char *s1 = Revision;
197         char *savept;
198         char *v2 = strtok_r(s1," ",&savept);
199         s1 = savept;
200         v2 = strtok_r(s1," ",&savept);
201         s1 = savept;
202         return std::string(v2);
203 }
204
205
206 std::string getservername()
207 {
208         return ServerName;
209 }
210
211 std::string getserverdesc()
212 {
213         return ServerDesc;
214 }
215
216 std::string getnetworkname()
217 {
218         return Network;
219 }
220
221 std::string getadminname()
222 {
223         return AdminName;
224 }
225
226 std::string getadminemail()
227 {
228         return AdminEmail;
229 }
230
231 std::string getadminnick()
232 {
233         return AdminNick;
234 }
235
236 void ReadConfig(bool bail, userrec* user)
237 {
238         char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF],MW[MAXBUF],MCON[MAXBUF];
239         char AH[MAXBUF],AP[MAXBUF],AF[MAXBUF],DNT[MAXBUF],pfreq[MAXBUF],thold[MAXBUF],sqmax[MAXBUF],rqmax[MAXBUF];
240         ConnectClass c;
241         std::stringstream errstr;
242         
243         if (!LoadConf(CONFIG_FILE,&config_f,&errstr))
244         {
245                 errstr.seekg(0);
246                 if (bail)
247                 {
248                         printf("There were errors in your configuration:\n%s",errstr.str().c_str());
249                         Exit(0);
250                 }
251                 else
252                 {
253                         char dataline[1024];
254                         if (user)
255                         {
256                                 WriteServ(user->fd,"NOTICE %s :There were errors in the configuration file:",user->nick);
257                                 while (!errstr.eof())
258                                 {
259                                         errstr.getline(dataline,1024);
260                                         WriteServ(user->fd,"NOTICE %s :%s",user->nick,dataline);
261                                 }
262                         }
263                         else
264                         {
265                                 WriteOpers("There were errors in the configuration file:",user->nick);
266                                 while (!errstr.eof())
267                                 {
268                                         errstr.getline(dataline,1024);
269                                         WriteOpers(dataline);
270                                 }
271                         }
272                         return;
273                 }
274         }
275           
276         ConfValue("server","name",0,ServerName,&config_f);
277         ConfValue("server","description",0,ServerDesc,&config_f);
278         ConfValue("server","network",0,Network,&config_f);
279         ConfValue("admin","name",0,AdminName,&config_f);
280         ConfValue("admin","email",0,AdminEmail,&config_f);
281         ConfValue("admin","nick",0,AdminNick,&config_f);
282         ConfValue("files","motd",0,motd,&config_f);
283         ConfValue("files","rules",0,rules,&config_f);
284         ConfValue("power","diepass",0,diepass,&config_f);
285         ConfValue("power","pause",0,pauseval,&config_f);
286         ConfValue("power","restartpass",0,restartpass,&config_f);
287         ConfValue("options","prefixquit",0,PrefixQuit,&config_f);
288         ConfValue("die","value",0,DieValue,&config_f);
289         ConfValue("options","loglevel",0,dbg,&config_f);
290         ConfValue("options","netbuffersize",0,NB,&config_f);
291         ConfValue("options","maxwho",0,MW,&config_f);
292         ConfValue("options","allowhalfop",0,AH,&config_f);
293         ConfValue("options","allowprotect",0,AP,&config_f);
294         ConfValue("options","allowfounder",0,AF,&config_f);
295         ConfValue("dns","server",0,DNSServer,&config_f);
296         ConfValue("dns","timeout",0,DNT,&config_f);
297         ConfValue("options","moduledir",0,ModPath,&config_f);
298         ConfValue("disabled","commands",0,DisabledCommands,&config_f);
299         ConfValue("options","somaxconn",0,MCON,&config_f);
300
301         MaxConn = atoi(MCON);
302         if (MaxConn > SOMAXCONN)
303                 log(DEFAULT,"WARNING: <options:somaxconn> value may be higher than the system-defined SOMAXCONN value!");
304         NetBufferSize = atoi(NB);
305         MaxWhoResults = atoi(MW);
306         dns_timeout = atoi(DNT);
307         if (!dns_timeout)
308                 dns_timeout = 5;
309         if (!MaxConn)
310                 MaxConn = SOMAXCONN;
311         if (!DNSServer[0])
312                 strlcpy(DNSServer,"127.0.0.1",MAXBUF);
313         if (!ModPath[0])
314                 strlcpy(ModPath,MOD_PATH,MAXBUF);
315         AllowHalfop = ((!strcasecmp(AH,"true")) || (!strcasecmp(AH,"1")) || (!strcasecmp(AH,"yes")));
316         AllowProtect = ((!strcasecmp(AP,"true")) || (!strcasecmp(AP,"1")) || (!strcasecmp(AP,"yes")));
317         AllowFounder = ((!strcasecmp(AF,"true")) || (!strcasecmp(AF,"1")) || (!strcasecmp(AF,"yes")));
318         if ((!NetBufferSize) || (NetBufferSize > 65535) || (NetBufferSize < 1024))
319         {
320                 log(DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240.");
321                 NetBufferSize = 10240;
322         }
323         if ((!MaxWhoResults) || (MaxWhoResults > 65535) || (MaxWhoResults < 1))
324         {
325                 log(DEFAULT,"No MaxWhoResults specified or size out of range, setting to default of 128.");
326                 MaxWhoResults = 128;
327         }
328         if (!strcmp(dbg,"debug"))
329                 LogLevel = DEBUG;
330         if (!strcmp(dbg,"verbose"))
331                 LogLevel = VERBOSE;
332         if (!strcmp(dbg,"default"))
333                 LogLevel = DEFAULT;
334         if (!strcmp(dbg,"sparse"))
335                 LogLevel = SPARSE;
336         if (!strcmp(dbg,"none"))
337                 LogLevel = NONE;
338         readfile(MOTD,motd);
339         log(DEFAULT,"Reading message of the day...");
340         readfile(RULES,rules);
341         log(DEFAULT,"Reading connect classes...");
342         Classes.clear();
343         for (int i = 0; i < ConfValueEnum("connect",&config_f); i++)
344         {
345                 strcpy(Value,"");
346                 ConfValue("connect","allow",i,Value,&config_f);
347                 ConfValue("connect","timeout",i,timeout,&config_f);
348                 ConfValue("connect","flood",i,flood,&config_f);
349                 ConfValue("connect","pingfreq",i,pfreq,&config_f);
350                 ConfValue("connect","threshold",i,thold,&config_f);
351                 ConfValue("connect","sendq",i,sqmax,&config_f);
352                 ConfValue("connect","recvq",i,rqmax,&config_f);
353                 if (Value[0])
354                 {
355                         strlcpy(c.host,Value,MAXBUF);
356                         c.type = CC_ALLOW;
357                         strlcpy(Value,"",MAXBUF);
358                         ConfValue("connect","password",i,Value,&config_f);
359                         strlcpy(c.pass,Value,MAXBUF);
360                         c.registration_timeout = 90; // default is 2 minutes
361                         c.pingtime = 120;
362                         c.flood = atoi(flood);
363                         c.threshold = 5;
364                         c.sendqmax = 262144; // 256k
365                         c.recvqmax = 4096;   // 4k
366                         if (atoi(thold)>0)
367                         {
368                                 c.threshold = atoi(thold);
369                         }
370                         if (atoi(sqmax)>0)
371                         {
372                                 c.sendqmax = atoi(sqmax);
373                         }
374                         if (atoi(rqmax)>0)
375                         {
376                                 c.recvqmax = atoi(rqmax);
377                         }
378                         if (atoi(timeout)>0)
379                         {
380                                 c.registration_timeout = atoi(timeout);
381                         }
382                         if (atoi(pfreq)>0)
383                         {
384                                 c.pingtime = atoi(pfreq);
385                         }
386                         Classes.push_back(c);
387                         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);
388                 }
389                 else
390                 {
391                         ConfValue("connect","deny",i,Value,&config_f);
392                         strlcpy(c.host,Value,MAXBUF);
393                         c.type = CC_DENY;
394                         Classes.push_back(c);
395                         log(DEBUG,"Read connect class type DENY, host=%s",c.host);
396                 }
397         
398         }
399         log(DEFAULT,"Reading K lines,Q lines and Z lines from config...");
400         read_xline_defaults();
401         log(DEFAULT,"Applying K lines, Q lines and Z lines...");
402         apply_lines();
403
404         autoconns.clear();
405         for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
406         {
407                 char Link_ServerName[MAXBUF],Link_AConn[MAXBUF];
408                 ConfValue("link","name",i,Link_ServerName,&config_f);
409                 ConfValue("link","autoconnect",i,Link_AConn,&config_f);
410                 if (strcmp(Link_AConn,""))
411                 {
412                         autoconns[std::string(Link_ServerName)] = atoi(Link_AConn) + time(NULL);
413                 }
414         }
415
416
417         log(DEFAULT,"Done reading configuration file, InspIRCd is now starting.");
418         if (!bail)
419         {
420                 log(DEFAULT,"Adding and removing modules due to rehash...");
421
422                 std::vector<std::string> old_module_names, new_module_names, added_modules, removed_modules;
423
424                 // store the old module names
425                 for (std::vector<std::string>::iterator t = module_names.begin(); t != module_names.end(); t++)
426                 {
427                         old_module_names.push_back(*t);
428                 }
429
430                 // get the new module names
431                 for (int count2 = 0; count2 < ConfValueEnum("module",&config_f); count2++)
432                 {
433                         ConfValue("module","name",count2,Value,&config_f);
434                         new_module_names.push_back(Value);
435                 }
436
437                 // now create a list of new modules that are due to be loaded
438                 // and a seperate list of modules which are due to be unloaded
439                 for (std::vector<std::string>::iterator _new = new_module_names.begin(); _new != new_module_names.end(); _new++)
440                 {
441                         bool added = true;
442                         for (std::vector<std::string>::iterator old = old_module_names.begin(); old != old_module_names.end(); old++)
443                         {
444                                 if (*old == *_new)
445                                         added = false;
446                         }
447                         if (added)
448                                 added_modules.push_back(*_new);
449                 }
450                 for (std::vector<std::string>::iterator oldm = old_module_names.begin(); oldm != old_module_names.end(); oldm++)
451                 {
452                         bool removed = true;
453                         for (std::vector<std::string>::iterator newm = new_module_names.begin(); newm != new_module_names.end(); newm++)
454                         {
455                                 if (*newm == *oldm)
456                                         removed = false;
457                         }
458                         if (removed)
459                                 removed_modules.push_back(*oldm);
460                 }
461                 // now we have added_modules, a vector of modules to be loaded, and removed_modules, a vector of modules
462                 // to be removed.
463                 int rem = 0, add = 0;
464                 if (!removed_modules.empty())
465                 for (std::vector<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
466                 {
467                         if (UnloadModule(removing->c_str()))
468                         {
469                                 WriteOpers("*** REHASH UNLOADED MODULE: %s",removing->c_str());
470                                 WriteServ(user->fd,"973 %s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str());
471                                 rem++;
472                         }
473                         else
474                         {
475                                 WriteServ(user->fd,"972 %s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ModuleError());
476                         }
477                 }
478                 if (!added_modules.empty())
479                 for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++)
480                 {
481                         if (LoadModule(adding->c_str()))
482                         {
483                                 WriteOpers("*** REHASH LOADED MODULE: %s",adding->c_str());
484                                 WriteServ(user->fd,"975 %s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str());
485                                 add++;
486                         }
487                         else
488                         {
489                                 WriteServ(user->fd,"974 %s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ModuleError());
490                         }
491                 }
492                 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());
493         }
494 }
495
496
497 /* add a channel to a user, creating the record for it if needed and linking
498  * it to the user record */
499
500 chanrec* add_channel(userrec *user, const char* cn, const char* key, bool override)
501 {
502         if ((!user) || (!cn))
503         {
504                 log(DEFAULT,"*** BUG *** add_channel was given an invalid parameter");
505                 return 0;
506         }
507
508         chanrec* Ptr;
509         int created = 0;
510         char cname[MAXBUF];
511
512         strncpy(cname,cn,MAXBUF);
513         
514         // we MUST declare this wherever we use FOREACH_RESULT
515         int MOD_RESULT = 0;
516
517         if (strlen(cname) > CHANMAX-1)
518         {
519                 cname[CHANMAX-1] = '\0';
520         }
521
522         log(DEBUG,"add_channel: %s %s",user->nick,cname);
523         
524         if ((FindChan(cname)) && (has_channel(user,FindChan(cname))))
525         {
526                 return NULL; // already on the channel!
527         }
528
529
530         if (!FindChan(cname))
531         {
532                 MOD_RESULT = 0;
533                 FOREACH_RESULT(OnUserPreJoin(user,NULL,cname));
534                 if (MOD_RESULT == 1) {
535                         return NULL;
536                 }
537
538                 /* create a new one */
539                 log(DEBUG,"add_channel: creating: %s",cname);
540                 {
541                         chanlist[cname] = new chanrec();
542
543                         strlcpy(chanlist[cname]->name, cname,CHANMAX);
544                         chanlist[cname]->binarymodes = CM_TOPICLOCK | CM_NOEXTERNAL;
545                         chanlist[cname]->created = TIME;
546                         strcpy(chanlist[cname]->topic, "");
547                         strncpy(chanlist[cname]->setby, user->nick,NICKMAX);
548                         chanlist[cname]->topicset = 0;
549                         Ptr = chanlist[cname];
550                         log(DEBUG,"add_channel: created: %s",cname);
551                         /* set created to 2 to indicate user
552                          * is the first in the channel
553                          * and should be given ops */
554                         created = 2;
555                 }
556         }
557         else
558         {
559                 /* channel exists, just fish out a pointer to its struct */
560                 Ptr = FindChan(cname);
561                 if (Ptr)
562                 {
563                         log(DEBUG,"add_channel: joining to: %s",Ptr->name);
564                         
565                         // the override flag allows us to bypass channel modes
566                         // and bans (used by servers)
567                         if ((!override) || (!strcasecmp(user->server,ServerName)))
568                         {
569                                 log(DEBUG,"Not overriding...");
570                                 MOD_RESULT = 0;
571                                 FOREACH_RESULT(OnUserPreJoin(user,Ptr,cname));
572                                 if (MOD_RESULT == 1) {
573                                         return NULL;
574                                 }
575                                 log(DEBUG,"MOD_RESULT=%d",MOD_RESULT);
576                                 
577                                 if (!MOD_RESULT) 
578                                 {
579                                         log(DEBUG,"add_channel: checking key, invite, etc");
580                                         MOD_RESULT = 0;
581                                         FOREACH_RESULT(OnCheckKey(user, Ptr, key ? key : ""));
582                                         if (MOD_RESULT == 0)
583                                         {
584                                                 if (Ptr->key[0])
585                                                 {
586                                                         log(DEBUG,"add_channel: %s has key %s",Ptr->name,Ptr->key);
587                                                         if (!key)
588                                                         {
589                                                                 log(DEBUG,"add_channel: no key given in JOIN");
590                                                                 WriteServ(user->fd,"475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
591                                                                 return NULL;
592                                                         }
593                                                         else
594                                                         {
595                                                                 if (strcasecmp(key,Ptr->key))
596                                                                 {
597                                                                         log(DEBUG,"add_channel: bad key given in JOIN");
598                                                                         WriteServ(user->fd,"475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
599                                                                         return NULL;
600                                                                 }
601                                                         }
602                                                 }
603                                                 log(DEBUG,"add_channel: no key");
604                                         }
605                                         MOD_RESULT = 0;
606                                         FOREACH_RESULT(OnCheckInvite(user, Ptr));
607                                         if (MOD_RESULT == 0)
608                                         {
609                                                 if (Ptr->binarymodes & CM_INVITEONLY)
610                                                 {
611                                                         log(DEBUG,"add_channel: channel is +i");
612                                                         if (user->IsInvited(Ptr->name))
613                                                         {
614                                                                 /* user was invited to channel */
615                                                                 /* there may be an optional channel NOTICE here */
616                                                         }
617                                                         else
618                                                         {
619                                                                 WriteServ(user->fd,"473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
620                                                                 return NULL;
621                                                         }
622                                                 }
623                                                 log(DEBUG,"add_channel: channel is not +i");
624                                         }
625                                         MOD_RESULT = 0;
626                                         FOREACH_RESULT(OnCheckLimit(user, Ptr));
627                                         if (MOD_RESULT == 0)
628                                         {
629                                                 if (Ptr->limit)
630                                                 {
631                                                         if (usercount(Ptr) >= Ptr->limit)
632                                                         {
633                                                                 WriteServ(user->fd,"471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
634                                                                 return NULL;
635                                                         }
636                                                 }
637                                         }
638                                         log(DEBUG,"add_channel: about to walk banlist");
639                                         MOD_RESULT = 0;
640                                         FOREACH_RESULT(OnCheckBan(user, Ptr));
641                                         if (MOD_RESULT == 0)
642                                         {
643                                                 /* check user against the channel banlist */
644                                                 if (Ptr)
645                                                 {
646                                                         if (Ptr->bans.size())
647                                                         {
648                                                                 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
649                                                                 {
650                                                                         if (match(user->GetFullHost(),i->data))
651                                                                         {
652                                                                                 WriteServ(user->fd,"474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
653                                                                                 return NULL;
654                                                                         }
655                                                                 }
656                                                         }
657                                                 }
658                                                 log(DEBUG,"add_channel: bans checked");
659                                         }
660                                 
661                                 }
662                                 
663
664                                 if ((Ptr) && (user))
665                                 {
666                                         user->RemoveInvite(Ptr->name);
667                                 }
668         
669                                 log(DEBUG,"add_channel: invites removed");
670
671                         }
672                         else
673                         {
674                                 log(DEBUG,"Overridden checks");
675                         }
676
677                         
678                 }
679                 created = 1;
680         }
681
682         log(DEBUG,"Passed channel checks");
683         
684         for (int index =0; index != MAXCHANS; index++)
685         {
686                 log(DEBUG,"Check location %d",index);
687                 if (user->chans[index].channel == NULL)
688                 {
689                         log(DEBUG,"Adding into their channel list at location %d",index);
690
691                         if (created == 2) 
692                         {
693                                 /* first user in is given ops */
694                                 user->chans[index].uc_modes = UCMODE_OP;
695                         }
696                         else
697                         {
698                                 user->chans[index].uc_modes = 0;
699                         }
700                         user->chans[index].channel = Ptr;
701                         Ptr->AddUser((char*)user);
702                         WriteChannel(Ptr,user,"JOIN :%s",Ptr->name);
703                         
704                         if (!override) // we're not overriding... so this isnt part of a netburst, broadcast it.
705                         {
706                                 // use the stamdard J token with no privilages.
707                                 char buffer[MAXBUF];
708                                 if (created == 2)
709                                 {
710                                         snprintf(buffer,MAXBUF,"J %s @%s",user->nick,Ptr->name);
711                                 }
712                                 else
713                                 {
714                                         snprintf(buffer,MAXBUF,"J %s %s",user->nick,Ptr->name);
715                                 }
716                                 NetSendToAll(buffer);
717                         }
718
719                         log(DEBUG,"Sent JOIN to client");
720
721                         if (Ptr->topicset)
722                         {
723                                 WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
724                                 WriteServ(user->fd,"333 %s %s %s %lu", user->nick, Ptr->name, Ptr->setby, (unsigned long)Ptr->topicset);
725                         }
726                         userlist(user,Ptr);
727                         WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
728                         //WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name,chanmodes(Ptr));
729                         //WriteServ(user->fd,"329 %s %s %lu", user->nick, Ptr->name, (unsigned long)Ptr->created);
730                         FOREACH_MOD OnUserJoin(user,Ptr);
731                         return Ptr;
732                 }
733         }
734         log(DEBUG,"add_channel: user channel max exceeded: %s %s",user->nick,cname);
735         WriteServ(user->fd,"405 %s %s :You are on too many channels",user->nick, cname);
736         return NULL;
737 }
738
739 /* remove a channel from a users record, and remove the record from memory
740  * if the channel has become empty */
741
742 chanrec* del_channel(userrec *user, const char* cname, const char* reason, bool local)
743 {
744         if ((!user) || (!cname))
745         {
746                 log(DEFAULT,"*** BUG *** del_channel was given an invalid parameter");
747                 return NULL;
748         }
749
750         chanrec* Ptr;
751
752         if ((!cname) || (!user))
753         {
754                 return NULL;
755         }
756
757         Ptr = FindChan(cname);
758         
759         if (!Ptr)
760         {
761                 return NULL;
762         }
763
764         FOREACH_MOD OnUserPart(user,Ptr);
765         log(DEBUG,"del_channel: removing: %s %s",user->nick,Ptr->name);
766         
767         for (int i =0; i != MAXCHANS; i++)
768         {
769                 /* zap it from the channel list of the user */
770                 if (user->chans[i].channel == Ptr)
771                 {
772                         if (reason)
773                         {
774                                 WriteChannel(Ptr,user,"PART %s :%s",Ptr->name, reason);
775
776                                 if (!local)
777                                 {
778                                         char buffer[MAXBUF];
779                                         snprintf(buffer,MAXBUF,"L %s %s :%s",user->nick,Ptr->name,reason);
780                                         NetSendToAll(buffer);
781                                 }
782
783                                 
784                         }
785                         else
786                         {
787                                 if (!local)
788                                 {
789                                         char buffer[MAXBUF];
790                                         snprintf(buffer,MAXBUF,"L %s %s :",user->nick,Ptr->name);
791                                         NetSendToAll(buffer);
792                                 }
793                         
794                                 WriteChannel(Ptr,user,"PART :%s",Ptr->name);
795                         }
796                         user->chans[i].uc_modes = 0;
797                         user->chans[i].channel = NULL;
798                         log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
799                         break;
800                 }
801         }
802
803         Ptr->DelUser((char*)user);
804         
805         /* if there are no users left on the channel */
806         if (!usercount(Ptr))
807         {
808                 chan_hash::iterator iter = chanlist.find(Ptr->name);
809
810                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
811
812                 /* kill the record */
813                 if (iter != chanlist.end())
814                 {
815                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
816                         delete Ptr;
817                         chanlist.erase(iter);
818                 }
819         }
820 }
821
822
823 void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
824 {
825         if ((!src) || (!user) || (!Ptr) || (!reason))
826         {
827                 log(DEFAULT,"*** BUG *** kick_channel was given an invalid parameter");
828                 return;
829         }
830
831         if ((!Ptr) || (!user) || (!src))
832         {
833                 return;
834         }
835
836         log(DEBUG,"kick_channel: removing: %s %s %s",user->nick,Ptr->name,src->nick);
837
838         if (!has_channel(user,Ptr))
839         {
840                 WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name);
841                 return;
842         }
843
844         int MOD_RESULT = 0;
845         FOREACH_RESULT(OnAccessCheck(src,user,Ptr,AC_KICK));
846         if (MOD_RESULT == ACR_DENY)
847                 return;
848
849         if (MOD_RESULT == ACR_DEFAULT)
850         {
851                 if (((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr))) && (!is_uline(src->server)))
852                 {
853                         if (cstatus(src,Ptr) == STATUS_HOP)
854                         {
855                                 WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name);
856                         }
857                         else
858                         {
859                                 WriteServ(src->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",src->nick, Ptr->name);
860                         }
861                         
862                         return;
863                 }
864         }
865
866         MOD_RESULT = 0;
867         FOREACH_RESULT(OnUserPreKick(src,user,Ptr,reason));
868         if (MOD_RESULT)
869                 return;
870
871         FOREACH_MOD OnUserKick(src,user,Ptr,reason);
872
873         for (int i =0; i != MAXCHANS; i++)
874         {
875                 /* zap it from the channel list of the user */
876                 if (user->chans[i].channel)
877                 if (!strcasecmp(user->chans[i].channel->name,Ptr->name))
878                 {
879                         WriteChannel(Ptr,src,"KICK %s %s :%s",Ptr->name, user->nick, reason);
880                         user->chans[i].uc_modes = 0;
881                         user->chans[i].channel = NULL;
882                         log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
883                         break;
884                 }
885         }
886
887         Ptr->DelUser((char*)user);
888
889         /* if there are no users left on the channel */
890         if (!usercount(Ptr))
891         {
892                 chan_hash::iterator iter = chanlist.find(Ptr->name);
893
894                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
895
896                 /* kill the record */
897                 if (iter != chanlist.end())
898                 {
899                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
900                         delete Ptr;
901                         chanlist.erase(iter);
902                 }
903         }
904 }
905
906
907
908
909 /* This function pokes and hacks at a parameter list like the following:
910  *
911  * PART #winbot,#darkgalaxy :m00!
912  *
913  * to turn it into a series of individual calls like this:
914  *
915  * PART #winbot :m00!
916  * PART #darkgalaxy :m00!
917  *
918  * The seperate calls are sent to a callback function provided by the caller
919  * (the caller will usually call itself recursively). The callback function
920  * must be a command handler. Calling this function on a line with no list causes
921  * no action to be taken. You must provide a starting and ending parameter number
922  * where the range of the list can be found, useful if you have a terminating
923  * parameter as above which is actually not part of the list, or parameters
924  * before the actual list as well. This code is used by many functions which
925  * can function as "one to list" (see the RFC) */
926
927 int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins)
928 {
929         char plist[MAXBUF];
930         char *param;
931         char *pars[32];
932         char blog[32][MAXBUF];
933         char blog2[32][MAXBUF];
934         int j = 0, q = 0, total = 0, t = 0, t2 = 0, total2 = 0;
935         char keystr[MAXBUF];
936         char moo[MAXBUF];
937
938         for (int i = 0; i <32; i++)
939                 strcpy(blog[i],"");
940
941         for (int i = 0; i <32; i++)
942                 strcpy(blog2[i],"");
943
944         strcpy(moo,"");
945         for (int i = 0; i <10; i++)
946         {
947                 if (!parameters[i])
948                 {
949                         parameters[i] = moo;
950                 }
951         }
952         if (joins)
953         {
954                 if (pcnt > 1) /* we have a key to copy */
955                 {
956                         strlcpy(keystr,parameters[1],MAXBUF);
957                 }
958         }
959
960         if (!parameters[start])
961         {
962                 return 0;
963         }
964         if (!strchr(parameters[start],','))
965         {
966                 return 0;
967         }
968         strcpy(plist,"");
969         for (int i = start; i <= end; i++)
970         {
971                 if (parameters[i])
972                 {
973                         strlcat(plist,parameters[i],MAXBUF);
974                 }
975         }
976         
977         j = 0;
978         param = plist;
979
980         t = strlen(plist);
981         for (int i = 0; i < t; i++)
982         {
983                 if (plist[i] == ',')
984                 {
985                         plist[i] = '\0';
986                         strlcpy(blog[j++],param,MAXBUF);
987                         param = plist+i+1;
988                         if (j>20)
989                         {
990                                 WriteServ(u->fd,"407 %s %s :Too many targets in list, message not delivered.",u->nick,blog[j-1]);
991                                 return 1;
992                         }
993                 }
994         }
995         strlcpy(blog[j++],param,MAXBUF);
996         total = j;
997
998         if ((joins) && (keystr) && (total>0)) // more than one channel and is joining
999         {
1000                 strcat(keystr,",");
1001         }
1002         
1003         if ((joins) && (keystr))
1004         {
1005                 if (strchr(keystr,','))
1006                 {
1007                         j = 0;
1008                         param = keystr;
1009                         t2 = strlen(keystr);
1010                         for (int i = 0; i < t2; i++)
1011                         {
1012                                 if (keystr[i] == ',')
1013                                 {
1014                                         keystr[i] = '\0';
1015                                         strlcpy(blog2[j++],param,MAXBUF);
1016                                         param = keystr+i+1;
1017                                 }
1018                         }
1019                         strlcpy(blog2[j++],param,MAXBUF);
1020                         total2 = j;
1021                 }
1022         }
1023
1024         for (j = 0; j < total; j++)
1025         {
1026                 if (blog[j])
1027                 {
1028                         pars[0] = blog[j];
1029                 }
1030                 for (q = end; q < pcnt-1; q++)
1031                 {
1032                         if (parameters[q+1])
1033                         {
1034                                 pars[q-end+1] = parameters[q+1];
1035                         }
1036                 }
1037                 if ((joins) && (parameters[1]))
1038                 {
1039                         if (pcnt > 1)
1040                         {
1041                                 pars[1] = blog2[j];
1042                         }
1043                         else
1044                         {
1045                                 pars[1] = NULL;
1046                         }
1047                 }
1048                 /* repeatedly call the function with the hacked parameter list */
1049                 if ((joins) && (pcnt > 1))
1050                 {
1051                         if (pars[1])
1052                         {
1053                                 // pars[1] already set up and containing key from blog2[j]
1054                                 fn(pars,2,u);
1055                         }
1056                         else
1057                         {
1058                                 pars[1] = parameters[1];
1059                                 fn(pars,2,u);
1060                         }
1061                 }
1062                 else
1063                 {
1064                         fn(pars,pcnt-(end-start),u);
1065                 }
1066         }
1067
1068         return 1;
1069 }
1070
1071
1072
1073 void kill_link(userrec *user,const char* r)
1074 {
1075         user_hash::iterator iter = clientlist.find(user->nick);
1076         
1077         char reason[MAXBUF];
1078         
1079         strncpy(reason,r,MAXBUF);
1080
1081         if (strlen(reason)>MAXQUIT)
1082         {
1083                 reason[MAXQUIT-1] = '\0';
1084         }
1085
1086         log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
1087         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
1088         log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
1089
1090         if (user->registered == 7) {
1091                 FOREACH_MOD OnUserQuit(user);
1092                 WriteCommonExcept(user,"QUIT :%s",reason);
1093
1094                 // Q token must go to ALL servers!!!
1095                 char buffer[MAXBUF];
1096                 snprintf(buffer,MAXBUF,"Q %s :%s",user->nick,reason);
1097                 NetSendToAll(buffer);
1098         }
1099
1100         user->FlushWriteBuf();
1101
1102         FOREACH_MOD OnUserDisconnect(user);
1103
1104         if (user->fd > -1)
1105         {
1106                 FOREACH_MOD OnRawSocketClose(user->fd);
1107 #ifdef USE_KQUEUE
1108                 struct kevent ke;
1109                 EV_SET(&ke, user->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
1110                 int i = kevent(kq, &ke, 1, 0, 0, NULL);
1111                 if (i == -1)
1112                 {
1113                         log(DEBUG,"kqueue: Failed to remove user from queue!");
1114                 }
1115 #endif
1116 #ifdef USE_EPOLL
1117                 struct epoll_event ev;
1118                 ev.events = EPOLLIN | EPOLLET;
1119                 ev.data.fd = user->fd;
1120                 int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev);
1121                 if (i < 0)
1122                 {
1123                         log(DEBUG,"epoll: List deletion failure!");
1124                 }
1125 #endif
1126                 user->CloseSocket();
1127         }
1128
1129         // this must come before the WriteOpers so that it doesnt try to fill their buffer with anything
1130         // if they were an oper with +s.
1131         if (user->registered == 7) {
1132                 purge_empty_chans(user);
1133                 WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
1134                 AddWhoWas(user);
1135         }
1136
1137         if (iter != clientlist.end())
1138         {
1139                 log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
1140                 if (user->fd > -1)
1141                         fd_ref_table[user->fd] = NULL;
1142                 clientlist.erase(iter);
1143         }
1144         delete user;
1145 }
1146
1147 void kill_link_silent(userrec *user,const char* r)
1148 {
1149         user_hash::iterator iter = clientlist.find(user->nick);
1150         
1151         char reason[MAXBUF];
1152         
1153         strncpy(reason,r,MAXBUF);
1154
1155         if (strlen(reason)>MAXQUIT)
1156         {
1157                 reason[MAXQUIT-1] = '\0';
1158         }
1159
1160         log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
1161         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
1162         log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
1163
1164         user->FlushWriteBuf();
1165
1166         if (user->registered == 7) {
1167                 FOREACH_MOD OnUserQuit(user);
1168                 WriteCommonExcept(user,"QUIT :%s",reason);
1169
1170                 // Q token must go to ALL servers!!!
1171                 char buffer[MAXBUF];
1172                 snprintf(buffer,MAXBUF,"Q %s :%s",user->nick,reason);
1173                 NetSendToAll(buffer);
1174         }
1175
1176         FOREACH_MOD OnUserDisconnect(user);
1177
1178         if (user->fd > -1)
1179         {
1180                 FOREACH_MOD OnRawSocketClose(user->fd);
1181 #ifdef USE_KQUEUE
1182                 struct kevent ke;
1183                 EV_SET(&ke, user->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
1184                 int i = kevent(kq, &ke, 1, 0, 0, NULL);
1185                 if (i == -1)
1186                 {
1187                         log(DEBUG,"kqueue: Failed to remove user from queue!");
1188                 }
1189 #endif
1190 #ifdef USE_EPOLL
1191                 struct epoll_event ev;
1192                 ev.events = EPOLLIN | EPOLLET;
1193                 ev.data.fd = user->fd;
1194                 int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev);
1195                 if (i < 0)
1196                 {
1197                         log(DEBUG,"epoll: List deletion failure!");
1198                 }
1199 #endif
1200                 user->CloseSocket();
1201         }
1202
1203         if (user->registered == 7) {
1204                 purge_empty_chans(user);
1205         }
1206         
1207         if (iter != clientlist.end())
1208         {
1209                 log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
1210                 if (user->fd > -1)
1211                         fd_ref_table[user->fd] = NULL;
1212                 clientlist.erase(iter);
1213         }
1214         delete user;
1215 }
1216
1217
1218 int main(int argc, char** argv)
1219 {
1220         Start();
1221         srand(time(NULL));
1222         log(DEBUG,"*** InspIRCd starting up!");
1223         if (!FileExists(CONFIG_FILE))
1224         {
1225                 printf("ERROR: Cannot open config file: %s\nExiting...\n",CONFIG_FILE);
1226                 log(DEFAULT,"main: no config");
1227                 printf("ERROR: Your config file is missing, this IRCd will self destruct in 10 seconds!\n");
1228                 Exit(ERROR);
1229         }
1230         if (argc > 1) {
1231                 for (int i = 1; i < argc; i++)
1232                 {
1233                         if (!strcmp(argv[i],"-nofork")) {
1234                                 nofork = true;
1235                         }
1236                         if (!strcmp(argv[i],"-wait")) {
1237                                 sleep(6);
1238                         }
1239                         if (!strcmp(argv[i],"-nolimit")) {
1240                                 unlimitcore = true;
1241                         }
1242                 }
1243         }
1244         strlcpy(MyExecutable,argv[0],MAXBUF);
1245         
1246         // initialize the lowercase mapping table
1247         for (int cn = 0; cn < 256; cn++)
1248                 lowermap[cn] = cn;
1249         // lowercase the uppercase chars
1250         for (int cn = 65; cn < 91; cn++)
1251                 lowermap[cn] = tolower(cn);
1252         // now replace the specific chars for scandanavian comparison
1253         lowermap['['] = '{';
1254         lowermap[']'] = '}';
1255         lowermap['\\'] = '|';
1256
1257         if (InspIRCd(argv,argc) == ERROR)
1258         {
1259                 log(DEFAULT,"main: daemon function bailed");
1260                 printf("ERROR: could not initialise. Shutting down.\n");
1261                 Exit(ERROR);
1262         }
1263         Exit(TRUE);
1264         return 0;
1265 }
1266
1267 template<typename T> inline string ConvToStr(const T &in)
1268 {
1269         stringstream tmp;
1270         if (!(tmp << in)) return string();
1271         return tmp.str();
1272 }
1273
1274 /* re-allocates a nick in the user_hash after they change nicknames,
1275  * returns a pointer to the new user as it may have moved */
1276
1277 userrec* ReHashNick(char* Old, char* New)
1278 {
1279         //user_hash::iterator newnick;
1280         user_hash::iterator oldnick = clientlist.find(Old);
1281
1282         log(DEBUG,"ReHashNick: %s %s",Old,New);
1283         
1284         if (!strcasecmp(Old,New))
1285         {
1286                 log(DEBUG,"old nick is new nick, skipping");
1287                 return oldnick->second;
1288         }
1289         
1290         if (oldnick == clientlist.end()) return NULL; /* doesnt exist */
1291
1292         log(DEBUG,"ReHashNick: Found hashed nick %s",Old);
1293
1294         userrec* olduser = oldnick->second;
1295         clientlist[New] = olduser;
1296         clientlist.erase(oldnick);
1297
1298         log(DEBUG,"ReHashNick: Nick rehashed as %s",New);
1299         
1300         return clientlist[New];
1301 }
1302
1303 /* adds or updates an entry in the whowas list */
1304 void AddWhoWas(userrec* u)
1305 {
1306         whowas_hash::iterator iter = whowas.find(u->nick);
1307         WhoWasUser *a = new WhoWasUser();
1308         strlcpy(a->nick,u->nick,NICKMAX);
1309         strlcpy(a->ident,u->ident,15);
1310         strlcpy(a->dhost,u->dhost,160);
1311         strlcpy(a->host,u->host,160);
1312         strlcpy(a->fullname,u->fullname,128);
1313         strlcpy(a->server,u->server,256);
1314         a->signon = u->signon;
1315
1316         /* MAX_WHOWAS:   max number of /WHOWAS items
1317          * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
1318          *               can be replaced by a newer one
1319          */
1320         
1321         if (iter == whowas.end())
1322         {
1323                 if (whowas.size() >= WHOWAS_MAX)
1324                 {
1325                         for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
1326                         {
1327                                 // 3600 seconds in an hour ;)
1328                                 if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600)))
1329                                 {
1330                                         // delete the old one
1331                                         if (i->second) delete i->second;
1332                                         // replace with new one
1333                                         i->second = a;
1334                                         log(DEBUG,"added WHOWAS entry, purged an old record");
1335                                         return;
1336                                 }
1337                         }
1338                         // no space left and user doesnt exist. Don't leave ram in use!
1339                         log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram");
1340                         delete a;
1341                 }
1342                 else
1343                 {
1344                         log(DEBUG,"added fresh WHOWAS entry");
1345                         whowas[a->nick] = a;
1346                 }
1347         }
1348         else
1349         {
1350                 log(DEBUG,"updated WHOWAS entry");
1351                 if (iter->second) delete iter->second;
1352                 iter->second = a;
1353         }
1354 }
1355
1356
1357 /* add a client connection to the sockets list */
1358 void AddClient(int socket, char* host, int port, bool iscached, char* ip)
1359 {
1360         string tempnick;
1361         char tn2[MAXBUF];
1362         user_hash::iterator iter;
1363
1364         tempnick = ConvToStr(socket) + "-unknown";
1365         sprintf(tn2,"%lu-unknown",(unsigned long)socket);
1366
1367         iter = clientlist.find(tempnick);
1368
1369         // fix by brain.
1370         // as these nicknames are 'RFC impossible', we can be sure nobody is going to be
1371         // using one as a registered connection. As theyre per fd, we can also safely assume
1372         // that we wont have collisions. Therefore, if the nick exists in the list, its only
1373         // used by a dead socket, erase the iterator so that the new client may reclaim it.
1374         // this was probably the cause of 'server ignores me when i hammer it with reconnects'
1375         // issue in earlier alphas/betas
1376         if (iter != clientlist.end())
1377         {
1378                 userrec* goner = iter->second;
1379                 delete goner;
1380                 clientlist.erase(iter);
1381         }
1382
1383         /*
1384          * It is OK to access the value here this way since we know
1385          * it exists, we just created it above.
1386          *
1387          * At NO other time should you access a value in a map or a
1388          * hash_map this way.
1389          */
1390         clientlist[tempnick] = new userrec();
1391
1392         NonBlocking(socket);
1393         log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip);
1394
1395         clientlist[tempnick]->fd = socket;
1396         strncpy(clientlist[tempnick]->nick, tn2,NICKMAX);
1397         strncpy(clientlist[tempnick]->host, host,160);
1398         strncpy(clientlist[tempnick]->dhost, host,160);
1399         strncpy(clientlist[tempnick]->server, ServerName,256);
1400         strncpy(clientlist[tempnick]->ident, "unknown",15);
1401         clientlist[tempnick]->registered = 0;
1402         clientlist[tempnick]->signon = TIME+dns_timeout;
1403         clientlist[tempnick]->lastping = 1;
1404         clientlist[tempnick]->port = port;
1405         strncpy(clientlist[tempnick]->ip,ip,16);
1406
1407         // set the registration timeout for this user
1408         unsigned long class_regtimeout = 90;
1409         int class_flood = 0;
1410         long class_threshold = 5;
1411         long class_sqmax = 262144;      // 256kb
1412         long class_rqmax = 4096;        // 4k
1413
1414         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
1415         {
1416                 if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW))
1417                 {
1418                         class_regtimeout = (unsigned long)i->registration_timeout;
1419                         class_flood = i->flood;
1420                         clientlist[tempnick]->pingmax = i->pingtime;
1421                         class_threshold = i->threshold;
1422                         class_sqmax = i->sendqmax;
1423                         class_rqmax = i->recvqmax;
1424                         break;
1425                 }
1426         }
1427
1428         clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax+dns_timeout;
1429         clientlist[tempnick]->timeout = TIME+class_regtimeout;
1430         clientlist[tempnick]->flood = class_flood;
1431         clientlist[tempnick]->threshold = class_threshold;
1432         clientlist[tempnick]->sendqmax = class_sqmax;
1433         clientlist[tempnick]->recvqmax = class_rqmax;
1434
1435         for (int i = 0; i < MAXCHANS; i++)
1436         {
1437                 clientlist[tempnick]->chans[i].channel = NULL;
1438                 clientlist[tempnick]->chans[i].uc_modes = 0;
1439         }
1440
1441         if (clientlist.size() == MAXCLIENTS)
1442         {
1443                 kill_link(clientlist[tempnick],"No more connections allowed in this class");
1444                 return;
1445         }
1446
1447         // this is done as a safety check to keep the file descriptors within range of fd_ref_table.
1448         // its a pretty big but for the moment valid assumption:
1449         // file descriptors are handed out starting at 0, and are recycled as theyre freed.
1450         // therefore if there is ever an fd over 65535, 65536 clients must be connected to the
1451         // irc server at once (or the irc server otherwise initiating this many connections, files etc)
1452         // which for the time being is a physical impossibility (even the largest networks dont have more
1453         // than about 10,000 users on ONE server!)
1454         if (socket > 65534)
1455         {
1456                 kill_link(clientlist[tempnick],"Server is full");
1457                 return;
1458         }
1459                 
1460
1461         char* e = matches_exception(ip);
1462         if (!e)
1463         {
1464                 char* r = matches_zline(ip);
1465                 if (r)
1466                 {
1467                         char reason[MAXBUF];
1468                         snprintf(reason,MAXBUF,"Z-Lined: %s",r);
1469                         kill_link(clientlist[tempnick],reason);
1470                         return;
1471                 }
1472         }
1473         fd_ref_table[socket] = clientlist[tempnick];
1474
1475 #ifdef USE_EPOLL
1476         struct epoll_event ev;
1477         log(DEBUG,"epoll: Adduser to events, ep=%d socket=%d",ep,socket);
1478         ev.events = EPOLLIN | EPOLLET;
1479         ev.data.fd = socket;
1480         int i = epoll_ctl(ep, EPOLL_CTL_ADD, socket, &ev);
1481         if (i < 0)
1482         {
1483                 log(DEBUG,"epoll: List insertion failure!");
1484         }
1485 #endif
1486 #ifdef USE_KQUEUE
1487         struct kevent ke;
1488         log(DEBUG,"kqueue: Add user to events, kq=%d socket=%d",kq,socket);
1489         EV_SET(&ke, socket, EVFILT_READ, EV_ADD, 0, 0, NULL);
1490         int i = kevent(kq, &ke, 1, 0, 0, NULL);
1491         if (i == -1)
1492         {
1493                 log(DEBUG,"kqueue: List insertion failure!");
1494         }
1495
1496 #endif
1497 }
1498
1499 /* shows the message of the day, and any other on-logon stuff */
1500 void FullConnectUser(userrec* user)
1501 {
1502         statsConnects++;
1503         user->idle_lastmsg = TIME;
1504         log(DEBUG,"ConnectUser: %s",user->nick);
1505
1506         if ((strcmp(Passwd(user),"")) && (!user->haspassed))
1507         {
1508                 kill_link(user,"Invalid password");
1509                 return;
1510         }
1511         if (IsDenied(user))
1512         {
1513                 kill_link(user,"Unauthorised connection");
1514                 return;
1515         }
1516
1517         char match_against[MAXBUF];
1518         snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host);
1519         char* e = matches_exception(match_against);
1520         if (!e)
1521         {
1522                 char* r = matches_gline(match_against);
1523                 if (r)
1524                 {
1525                         char reason[MAXBUF];
1526                         snprintf(reason,MAXBUF,"G-Lined: %s",r);
1527                         kill_link_silent(user,reason);
1528                         return;
1529                 }
1530                 r = matches_kline(user->host);
1531                 if (r)
1532                 {
1533                         char reason[MAXBUF];
1534                         snprintf(reason,MAXBUF,"K-Lined: %s",r);
1535                         kill_link_silent(user,reason);
1536                         return;
1537                 }
1538         }
1539
1540         // fix by brain: move this below the xline checks to prevent spurious quits going onto the net that dont belong
1541         user->registered = 7;
1542
1543         WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Network);
1544         WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Network,user->nick,user->ident,user->host);
1545         WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,ServerName,VERSION);
1546         WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
1547         WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION);
1548         // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...
1549         std::stringstream v;
1550         v << "MESHED WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS;
1551         v << " MAXBANS=60 NICKLEN=" << NICKMAX;
1552         v << " TOPICLEN=307 KICKLEN=307 MAXTARGETS=20 AWAYLEN=307 CHANMODES=ohvb,k,l,psmnti NETWORK=";
1553         v << Network;
1554         std::string data005 = v.str();
1555         FOREACH_MOD On005Numeric(data005);
1556         // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line...
1557         // so i'd better split it :)
1558         std::stringstream out(data005);
1559         std::string token = "";
1560         std::string line5 = "";
1561         int token_counter = 0;
1562         while (!out.eof())
1563         {
1564                 out >> token;
1565                 line5 = line5 + token + " ";
1566                 token_counter++;
1567                 if ((token_counter >= 13) || (out.eof() == true))
1568                 {
1569                         WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str());
1570                         line5 = "";
1571                         token_counter = 0;
1572                 }
1573         }
1574         ShowMOTD(user);
1575
1576         char buffer[MAXBUF];
1577         snprintf(buffer,MAXBUF,"N %lu %s %s %s %s +%s %s %s :%s",(unsigned long)user->age,user->nick,user->host,user->dhost,user->ident,user->modes,user->ip,ServerName,user->fullname);
1578         NetSendToAll(buffer);
1579
1580         // fix by brain: these should be AFTER the N token, so other servers know what the HELL we're on about... :)
1581         FOREACH_MOD OnUserConnect(user);
1582         WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip);
1583 }
1584
1585
1586 /* shows the message of the day, and any other on-logon stuff */
1587 void ConnectUser(userrec *user)
1588 {
1589         // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on
1590         if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user)))
1591         {
1592                 FullConnectUser(user);
1593         }
1594 }
1595
1596 std::string GetVersionString()
1597 {
1598         char Revision[] = "$Revision$";
1599         char versiondata[MAXBUF];
1600         char *s1 = Revision;
1601         char *savept;
1602         char *v2 = strtok_r(s1," ",&savept);
1603         s1 = savept;
1604         v2 = strtok_r(s1," ",&savept);
1605         s1 = savept;
1606 #ifdef USE_KQUEUE
1607         char socketengine[] = "kqueue";
1608 #endif
1609 #ifdef USE_SELECT
1610         char socketengine[] = "select";
1611 #endif
1612 #ifdef USE_EPOLL
1613         char socketengine[] = "epoll";
1614 #endif
1615         snprintf(versiondata,MAXBUF,"%s Rev. %s %s :%s (O=%lu) [SE=%s]",VERSION,v2,ServerName,SYSTEM,(unsigned long)OPTIMISATION,socketengine);
1616         return versiondata;
1617 }
1618
1619 void handle_version(char **parameters, int pcnt, userrec *user)
1620 {
1621         if (!pcnt)
1622         {
1623                 WriteServ(user->fd,"351 %s :%s",user->nick,GetVersionString().c_str());
1624         }
1625         else
1626         {
1627                 if (!strcmp(parameters[0],"*"))
1628                 {
1629                         for (int j = 0; j < 32; j++)
1630                         {
1631                                 if (me[j] != NULL)
1632                                 {
1633                                         for (int x = 0; x < me[j]->connectors.size(); x++)
1634                                         {
1635                                                 WriteServ(user->fd,"351 %s :Server %d:%d (%s): %s",user->nick,j,x,me[j]->connectors[x].GetServerName().c_str(),me[j]->connectors[x].GetVersionString().c_str());
1636                                         }
1637                                 }
1638                         }
1639                         return;
1640                 }
1641                 if (match(ServerName,parameters[0]))
1642                 {
1643                         WriteServ(user->fd,"351 %s :%s",user->nick,GetVersionString().c_str());
1644                         return;
1645                 }
1646                 bool displayed = false, found = false;
1647                 for (int j = 0; j < 32; j++)
1648                 {
1649                         if (me[j] != NULL)
1650                         {
1651                                 for (int x = 0; x < me[j]->connectors.size(); x++)
1652                                 {
1653                                         if (match(me[j]->connectors[x].GetServerName().c_str(),parameters[0]))
1654                                         {
1655                                                 found = true;
1656                                                 if ((me[j]->connectors[x].GetVersionString() != "") && (!displayed))
1657                                                 {
1658                                                         displayed = true;
1659                                                         WriteServ(user->fd,"351 %s :%s",user->nick,me[j]->connectors[x].GetVersionString().c_str());
1660                                                 }
1661                                         }
1662                                 }
1663                         }
1664                 }
1665                 if ((!displayed) && (found))
1666                 {
1667                         WriteServ(user->fd,"402 %s %s :Server %s has no version information",user->nick,parameters[0],parameters[0]);
1668                         return;
1669                 }
1670                 if (!found)
1671                 {
1672                         WriteServ(user->fd,"402 %s %s :No such server",user->nick,parameters[0]);
1673                 }
1674         }
1675         return;
1676 }
1677
1678
1679 // calls a handler function for a command
1680
1681 void call_handler(const char* commandname,char **parameters, int pcnt, userrec *user)
1682 {
1683                 for (int i = 0; i < cmdlist.size(); i++)
1684                 {
1685                         if (!strcasecmp(cmdlist[i].command,commandname))
1686                         {
1687                                 if (cmdlist[i].handler_function)
1688                                 {
1689                                         if (pcnt>=cmdlist[i].min_params)
1690                                         {
1691                                                 if (strchr(user->modes,cmdlist[i].flags_needed))
1692                                                 {
1693                                                         cmdlist[i].handler_function(parameters,pcnt,user);
1694                                                 }
1695                                         }
1696                                 }
1697                         }
1698                 }
1699 }
1700
1701 void DoSplitEveryone()
1702 {
1703         bool go_again = true;
1704         while (go_again)
1705         {
1706                 go_again = false;
1707                 for (int i = 0; i < 32; i++)
1708                 {
1709                         if (me[i] != NULL)
1710                         {
1711                                 for (vector<ircd_connector>::iterator j = me[i]->connectors.begin(); j != me[i]->connectors.end(); j++)
1712                                 {
1713                                         if (strcasecmp(j->GetServerName().c_str(),ServerName))
1714                                         {
1715                                                 j->routes.clear();
1716                                                 j->CloseConnection();
1717                                                 me[i]->connectors.erase(j);
1718                                                 go_again = true;
1719                                                 break;
1720                                         }
1721                                 }
1722                         }
1723                 }
1724         }
1725         log(DEBUG,"Removed server. Will remove clients...");
1726         // iterate through the userlist and remove all users on this server.
1727         // because we're dealing with a mesh, we dont have to deal with anything
1728         // "down-route" from this server (nice huh)
1729         go_again = true;
1730         char reason[MAXBUF];
1731         while (go_again)
1732         {
1733                 go_again = false;
1734                 for (user_hash::const_iterator u = clientlist.begin(); u != clientlist.end(); u++)
1735                 {
1736                         if (strcasecmp(u->second->server,ServerName))
1737                         {
1738                                 snprintf(reason,MAXBUF,"%s %s",ServerName,u->second->server);
1739                                 kill_link(u->second,reason);
1740                                 go_again = true;
1741                                 break;
1742                         }
1743                 }
1744         }
1745 }
1746
1747
1748
1749 void force_nickchange(userrec* user,const char* newnick)
1750 {
1751         char nick[MAXBUF];
1752         int MOD_RESULT = 0;
1753         
1754         strcpy(nick,"");
1755
1756         FOREACH_RESULT(OnUserPreNick(user,newnick));
1757         if (MOD_RESULT) {
1758                 statsCollisions++;
1759                 kill_link(user,"Nickname collision");
1760                 return;
1761         }
1762         if (matches_qline(newnick))
1763         {
1764                 statsCollisions++;
1765                 kill_link(user,"Nickname collision");
1766                 return;
1767         }
1768         
1769         if (user)
1770         {
1771                 if (newnick)
1772                 {
1773                         strncpy(nick,newnick,MAXBUF);
1774                 }
1775                 if (user->registered == 7)
1776                 {
1777                         char* pars[1];
1778                         pars[0] = nick;
1779                         handle_nick(pars,1,user);
1780                 }
1781         }
1782 }
1783                                 
1784
1785 int process_parameters(char **command_p,char *parameters)
1786 {
1787         int j = 0;
1788         int q = strlen(parameters);
1789         if (!q)
1790         {
1791                 /* no parameters, command_p invalid! */
1792                 return 0;
1793         }
1794         if (parameters[0] == ':')
1795         {
1796                 command_p[0] = parameters+1;
1797                 return 1;
1798         }
1799         if (q)
1800         {
1801                 if ((strchr(parameters,' ')==NULL) || (parameters[0] == ':'))
1802                 {
1803                         /* only one parameter */
1804                         command_p[0] = parameters;
1805                         if (parameters[0] == ':')
1806                         {
1807                                 if (strchr(parameters,' ') != NULL)
1808                                 {
1809                                         command_p[0]++;
1810                                 }
1811                         }
1812                         return 1;
1813                 }
1814         }
1815         command_p[j++] = parameters;
1816         for (int i = 0; i <= q; i++)
1817         {
1818                 if (parameters[i] == ' ')
1819                 {
1820                         command_p[j++] = parameters+i+1;
1821                         parameters[i] = '\0';
1822                         if (command_p[j-1][0] == ':')
1823                         {
1824                                 *command_p[j-1]++; /* remove dodgy ":" */
1825                                 break;
1826                                 /* parameter like this marks end of the sequence */
1827                         }
1828                 }
1829         }
1830         return j; /* returns total number of items in the list */
1831 }
1832
1833 void process_command(userrec *user, char* cmd)
1834 {
1835         char *parameters;
1836         char *command;
1837         char *command_p[127];
1838         char p[MAXBUF], temp[MAXBUF];
1839         int j, items, cmd_found;
1840
1841         for (int i = 0; i < 127; i++)
1842                 command_p[i] = NULL;
1843
1844         if (!user)
1845         {
1846                 return;
1847         }
1848         if (!cmd)
1849         {
1850                 return;
1851         }
1852         if (!cmd[0])
1853         {
1854                 return;
1855         }
1856         
1857         int total_params = 0;
1858         if (strlen(cmd)>2)
1859         {
1860                 for (int q = 0; q < strlen(cmd)-1; q++)
1861                 {
1862                         if ((cmd[q] == ' ') && (cmd[q+1] == ':'))
1863                         {
1864                                 total_params++;
1865                                 // found a 'trailing', we dont count them after this.
1866                                 break;
1867                         }
1868                         if (cmd[q] == ' ')
1869                                 total_params++;
1870                 }
1871         }
1872
1873         // another phidjit bug...
1874         if (total_params > 126)
1875         {
1876                 *(strchr(cmd,' ')) = '\0';
1877                 WriteServ(user->fd,"421 %s %s :Too many parameters given",user->nick,cmd);
1878                 return;
1879         }
1880
1881         strlcpy(temp,cmd,MAXBUF);
1882         
1883         std::string tmp = cmd;
1884         for (int i = 0; i <= MODCOUNT; i++)
1885         {
1886                 std::string oldtmp = tmp;
1887                 modules[i]->OnServerRaw(tmp,true,user);
1888                 if (oldtmp != tmp)
1889                 {
1890                         log(DEBUG,"A Module changed the input string!");
1891                         log(DEBUG,"New string: %s",tmp.c_str());
1892                         log(DEBUG,"Old string: %s",oldtmp.c_str());
1893                         break;
1894                 }
1895         }
1896         strlcpy(cmd,tmp.c_str(),MAXBUF);
1897         strlcpy(temp,cmd,MAXBUF);
1898
1899         if (!strchr(cmd,' '))
1900         {
1901                 /* no parameters, lets skip the formalities and not chop up
1902                  * the string */
1903                 log(DEBUG,"About to preprocess command with no params");
1904                 items = 0;
1905                 command_p[0] = NULL;
1906                 parameters = NULL;
1907                 for (int i = 0; i <= strlen(cmd); i++)
1908                 {
1909                         cmd[i] = toupper(cmd[i]);
1910                 }
1911                 command = cmd;
1912         }
1913         else
1914         {
1915                 strcpy(cmd,"");
1916                 j = 0;
1917                 /* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */
1918                 for (int i = 0; i < strlen(temp); i++)
1919                 {
1920                         if ((temp[i] != 10) && (temp[i] != 13) && (temp[i] != 0) && (temp[i] != 7))
1921                         {
1922                                 cmd[j++] = temp[i];
1923                                 cmd[j] = 0;
1924                         }
1925                 }
1926                 /* split the full string into a command plus parameters */
1927                 parameters = p;
1928                 strcpy(p," ");
1929                 command = cmd;
1930                 if (strchr(cmd,' '))
1931                 {
1932                         for (int i = 0; i <= strlen(cmd); i++)
1933                         {
1934                                 /* capitalise the command ONLY, leave params intact */
1935                                 cmd[i] = toupper(cmd[i]);
1936                                 /* are we nearly there yet?! :P */
1937                                 if (cmd[i] == ' ')
1938                                 {
1939                                         command = cmd;
1940                                         parameters = cmd+i+1;
1941                                         cmd[i] = '\0';
1942                                         break;
1943                                 }
1944                         }
1945                 }
1946                 else
1947                 {
1948                         for (int i = 0; i <= strlen(cmd); i++)
1949                         {
1950                                 cmd[i] = toupper(cmd[i]);
1951                         }
1952                 }
1953
1954         }
1955         cmd_found = 0;
1956         
1957         if (strlen(command)>MAXCOMMAND)
1958         {
1959                 WriteServ(user->fd,"421 %s %s :Command too long",user->nick,command);
1960                 return;
1961         }
1962         
1963         for (int x = 0; x < strlen(command); x++)
1964         {
1965                 if (((command[x] < 'A') || (command[x] > 'Z')) && (command[x] != '.'))
1966                 {
1967                         if (((command[x] < '0') || (command[x]> '9')) && (command[x] != '-'))
1968                         {
1969                                 if (strchr("@!\"$%^&*(){}[]_=+;:'#~,<>/?\\|`",command[x]))
1970                                 {
1971                                         statsUnknown++;
1972                                         WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
1973                                         return;
1974                                 }
1975                         }
1976                 }
1977         }
1978
1979         for (int i = 0; i != cmdlist.size(); i++)
1980         {
1981                 if (cmdlist[i].command[0])
1982                 {
1983                         if (strlen(command)>=(strlen(cmdlist[i].command))) if (!strncmp(command, cmdlist[i].command,MAXCOMMAND))
1984                         {
1985                                 if (parameters)
1986                                 {
1987                                         if (parameters[0])
1988                                         {
1989                                                 items = process_parameters(command_p,parameters);
1990                                         }
1991                                         else
1992                                         {
1993                                                 items = 0;
1994                                                 command_p[0] = NULL;
1995                                         }
1996                                 }
1997                                 else
1998                                 {
1999                                         items = 0;
2000                                         command_p[0] = NULL;
2001                                 }
2002                                 
2003                                 if (user)
2004                                 {
2005                                         /* activity resets the ping pending timer */
2006                                         user->nping = TIME + user->pingmax;
2007                                         if ((items) < cmdlist[i].min_params)
2008                                         {
2009                                                 log(DEBUG,"process_command: not enough parameters: %s %s",user->nick,command);
2010                                                 WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,command);
2011                                                 return;
2012                                         }
2013                                         if ((!strchr(user->modes,cmdlist[i].flags_needed)) && (cmdlist[i].flags_needed))
2014                                         {
2015                                                 log(DEBUG,"process_command: permission denied: %s %s",user->nick,command);
2016                                                 WriteServ(user->fd,"481 %s :Permission Denied- You do not have the required operator privilages",user->nick);
2017                                                 cmd_found = 1;
2018                                                 return;
2019                                         }
2020                                         if ((cmdlist[i].flags_needed) && (!user->HasPermission(command)))
2021                                         {
2022                                                 log(DEBUG,"process_command: permission denied: %s %s",user->nick,command);
2023                                                 WriteServ(user->fd,"481 %s :Permission Denied- Oper type %s does not have access to command %s",user->nick,user->oper,command);
2024                                                 cmd_found = 1;
2025                                                 return;
2026                                         }
2027                                         /* if the command isnt USER, PASS, or NICK, and nick is empty,
2028                                          * deny command! */
2029                                         if ((strncmp(command,"USER",4)) && (strncmp(command,"NICK",4)) && (strncmp(command,"PASS",4)))
2030                                         {
2031                                                 if ((!isnick(user->nick)) || (user->registered != 7))
2032                                                 {
2033                                                         log(DEBUG,"process_command: not registered: %s %s",user->nick,command);
2034                                                         WriteServ(user->fd,"451 %s :You have not registered",command);
2035                                                         return;
2036                                                 }
2037                                         }
2038                                         if ((user->registered == 7) && (!strchr(user->modes,'o')))
2039                                         {
2040                                                 char* mycmd;
2041                                                 char* savept2;
2042                                                 mycmd = strtok_r(DisabledCommands," ",&savept2);
2043                                                 while (mycmd)
2044                                                 {
2045                                                         if (!strcasecmp(mycmd,command))
2046                                                         {
2047                                                                 // command is disabled!
2048                                                                 WriteServ(user->fd,"421 %s %s :This command has been disabled.",user->nick,command);
2049                                                                 return;
2050                                                         }
2051                                                         mycmd = strtok_r(NULL," ",&savept2);
2052                                                 }
2053         
2054
2055                                         }
2056                                         if ((user->registered == 7) || (!strncmp(command,"USER",4)) || (!strncmp(command,"NICK",4)) || (!strncmp(command,"PASS",4)))
2057                                         {
2058                                                 if (cmdlist[i].handler_function)
2059                                                 {
2060                                                         
2061                                                         /* ikky /stats counters */
2062                                                         if (temp)
2063                                                         {
2064                                                                 cmdlist[i].use_count++;
2065                                                                 cmdlist[i].total_bytes+=strlen(temp);
2066                                                         }
2067
2068                                                         int MOD_RESULT = 0;
2069                                                         FOREACH_RESULT(OnPreCommand(command,command_p,items,user));
2070                                                         if (MOD_RESULT == 1) {
2071                                                                 return;
2072                                                         }
2073
2074                                                         /* WARNING: nothing may come after the
2075                                                          * command handler call, as the handler
2076                                                          * may free the user structure! */
2077
2078                                                         cmdlist[i].handler_function(command_p,items,user);
2079                                                 }
2080                                                 return;
2081                                         }
2082                                         else
2083                                         {
2084                                                 WriteServ(user->fd,"451 %s :You have not registered",command);
2085                                                 return;
2086                                         }
2087                                 }
2088                                 cmd_found = 1;
2089                         }
2090                 }
2091         }
2092         if ((!cmd_found) && (user))
2093         {
2094                 statsUnknown++;
2095                 WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
2096         }
2097 }
2098
2099 bool removecommands(const char* source)
2100 {
2101         bool go_again = true;
2102         while (go_again)
2103         {
2104                 go_again = false;
2105                 for (std::deque<command_t>::iterator i = cmdlist.begin(); i != cmdlist.end(); i++)
2106                 {
2107                         if (!strcmp(i->source,source))
2108                         {
2109                                 log(DEBUG,"removecommands(%s) Removing dependent command: %s",i->source,i->command);
2110                                 cmdlist.erase(i);
2111                                 go_again = true;
2112                                 break;
2113                         }
2114                 }
2115         }
2116         return true;
2117 }
2118
2119
2120 void process_buffer(const char* cmdbuf,userrec *user)
2121 {
2122         if (!user)
2123         {
2124                 log(DEFAULT,"*** BUG *** process_buffer was given an invalid parameter");
2125                 return;
2126         }
2127         char cmd[MAXBUF];
2128         if (!cmdbuf)
2129         {
2130                 log(DEFAULT,"*** BUG *** process_buffer was given an invalid parameter");
2131                 return;
2132         }
2133         if (!cmdbuf[0])
2134         {
2135                 return;
2136         }
2137         while (*cmdbuf == ' ') cmdbuf++; // strip leading spaces
2138
2139         strlcpy(cmd,cmdbuf,MAXBUF);
2140         if (!cmd[0])
2141         {
2142                 return;
2143         }
2144         int sl = strlen(cmd)-1;
2145         if ((cmd[sl] == 13) || (cmd[sl] == 10))
2146         {
2147                 cmd[sl] = '\0';
2148         }
2149         sl = strlen(cmd)-1;
2150         if ((cmd[sl] == 13) || (cmd[sl] == 10))
2151         {
2152                 cmd[sl] = '\0';
2153         }
2154         sl = strlen(cmd)-1;
2155         while (cmd[sl] == ' ') // strip trailing spaces
2156         {
2157                 cmd[sl] = '\0';
2158                 sl = strlen(cmd)-1;
2159         }
2160
2161         if (!cmd[0])
2162         {
2163                 return;
2164         }
2165         log(DEBUG,"CMDIN: %s %s",user->nick,cmd);
2166         tidystring(cmd);
2167         if ((user) && (cmd))
2168         {
2169                 process_command(user,cmd);
2170         }
2171 }
2172
2173 void DoSync(serverrec* serv, char* tcp_host)
2174 {
2175         char data[MAXBUF];
2176         log(DEBUG,"Sending sync");
2177         // send start of sync marker: Y <timestamp>
2178         // at this point the ircd receiving it starts broadcasting this netburst to all ircds
2179         // except the ones its receiving it from.
2180         snprintf(data,MAXBUF,"%s Y %lu",CreateSum().c_str(),(unsigned long)TIME);
2181         serv->SendPacket(data,tcp_host);
2182         // send users and channels
2183
2184         NetSendMyRoutingTable();
2185
2186         // send all routing table and uline voodoo. The ordering of these commands is IMPORTANT!
2187         for (int j = 0; j < 32; j++)
2188         {
2189                 if (me[j] != NULL)
2190                 {
2191                         for (int k = 0; k < me[j]->connectors.size(); k++)
2192                         {
2193                                 if (is_uline(me[j]->connectors[k].GetServerName().c_str()))
2194                                 {
2195                                         snprintf(data,MAXBUF,"%s H %s",CreateSum().c_str(),me[j]->connectors[k].GetServerName().c_str());
2196                                         serv->SendPacket(data,tcp_host);
2197                                 }
2198                         }
2199                 }
2200         }
2201
2202         // send our version for the remote side to cache
2203         snprintf(data,MAXBUF,"%s v %s %s",CreateSum().c_str(),ServerName,GetVersionString().c_str());
2204         serv->SendPacket(data,tcp_host);
2205
2206         // sync the users and channels, give the modules a look-in.
2207         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
2208         {
2209                 snprintf(data,MAXBUF,"%s N %lu %s %s %s %s +%s %s %s :%s",CreateSum().c_str(),(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->modes,u->second->ip,u->second->server,u->second->fullname);
2210                 serv->SendPacket(data,tcp_host);
2211                 if (strchr(u->second->modes,'o'))
2212                 {
2213                         snprintf(data,MAXBUF,"%s | %s %s",CreateSum().c_str(),u->second->nick,u->second->oper);
2214                         serv->SendPacket(data,tcp_host);
2215                 }
2216                 for (int i = 0; i <= MODCOUNT; i++)
2217                 {
2218                         string_list l = modules[i]->OnUserSync(u->second);
2219                         for (int j = 0; j < l.size(); j++)
2220                         {
2221                                 snprintf(data,MAXBUF,"%s %s",CreateSum().c_str(),l[j].c_str());
2222                                 serv->SendPacket(data,tcp_host);
2223                         }
2224                 }
2225                 char* chl = chlist(u->second,u->second);
2226                 if (strcmp(chl,""))
2227                 {
2228                         snprintf(data,MAXBUF,"%s J %s %s",CreateSum().c_str(),u->second->nick,chl);
2229                         serv->SendPacket(data,tcp_host);
2230                 }
2231         }
2232         // send channel modes, topics etc...
2233         for (chan_hash::iterator c = chanlist.begin(); c != chanlist.end(); c++)
2234         {
2235                 snprintf(data,MAXBUF,"M %s +%s",c->second->name,chanmodes(c->second));
2236                 serv->SendPacket(data,tcp_host);
2237                 for (int i = 0; i <= MODCOUNT; i++)
2238                 {
2239                         string_list l = modules[i]->OnChannelSync(c->second);
2240                         for (int j = 0; j < l.size(); j++)
2241                         {
2242                                 snprintf(data,MAXBUF,"%s %s",CreateSum().c_str(),l[j].c_str());
2243                                 serv->SendPacket(data,tcp_host);
2244                         }
2245                 }
2246                 if (c->second->topic[0])
2247                 {
2248                         snprintf(data,MAXBUF,"%s T %lu %s %s :%s",CreateSum().c_str(),(unsigned long)c->second->topicset,c->second->setby,c->second->name,c->second->topic);
2249                         serv->SendPacket(data,tcp_host);
2250                 }
2251                 // send current banlist
2252                 
2253                 for (BanList::iterator b = c->second->bans.begin(); b != c->second->bans.end(); b++)
2254                 {
2255                         snprintf(data,MAXBUF,"%s M %s +b %s",CreateSum().c_str(),c->second->name,b->data);
2256                         serv->SendPacket(data,tcp_host);
2257                 }
2258         }
2259         // sync global zlines, glines, etc
2260         sync_xlines(serv,tcp_host);
2261
2262         snprintf(data,MAXBUF,"%s F %lu",CreateSum().c_str(),(unsigned long)TIME);
2263         serv->SendPacket(data,tcp_host);
2264         log(DEBUG,"Sent sync");
2265         // ircd sends its serverlist after the end of sync here
2266 }
2267
2268
2269 void NetSendMyRoutingTable()
2270 {
2271         // send out a line saying what is reachable to us.
2272         // E.g. if A is linked to B C and D, send out:
2273         // $ A B C D
2274         // if its only linked to B and D send out:
2275         // $ A B D
2276         // if it has no links, dont even send out the line at all.
2277         char buffer[MAXBUF];
2278         snprintf(buffer,MAXBUF,"$ %s",ServerName);
2279         bool sendit = false;
2280         for (int i = 0; i < 32; i++)
2281         {
2282                 if (me[i] != NULL)
2283                 {
2284                         for (int j = 0; j < me[i]->connectors.size(); j++)
2285                         {
2286                                 if ((me[i]->connectors[j].GetState() != STATE_DISCONNECTED) || (is_uline(me[i]->connectors[j].GetServerName().c_str())))
2287                                 {
2288                                         strlcat(buffer," ",MAXBUF);
2289                                         strlcat(buffer,me[i]->connectors[j].GetServerName().c_str(),MAXBUF);
2290                                         sendit = true;
2291                                 }
2292                         }
2293                 }
2294         }
2295         if (sendit)
2296                 NetSendToAll(buffer);
2297 }
2298
2299
2300 void DoSplit(const char* params)
2301 {
2302         bool go_again = true;
2303         while (go_again)
2304         {
2305                 go_again = false;
2306                 for (int i = 0; i < 32; i++)
2307                 {
2308                         if (me[i] != NULL)
2309                         {
2310                                 for (vector<ircd_connector>::iterator j = me[i]->connectors.begin(); j != me[i]->connectors.end(); j++)
2311                                 {
2312                                         if (!strcasecmp(j->GetServerName().c_str(),params))
2313                                         {
2314                                                 j->routes.clear();
2315                                                 j->CloseConnection();
2316                                                 me[i]->connectors.erase(j);
2317                                                 go_again = true;
2318                                                 break;
2319                                         }
2320                                 }
2321                         }
2322                 }
2323         }
2324         log(DEBUG,"Removed server. Will remove clients...");
2325         // iterate through the userlist and remove all users on this server.
2326         // because we're dealing with a mesh, we dont have to deal with anything
2327         // "down-route" from this server (nice huh)
2328         go_again = true;
2329         char reason[MAXBUF];
2330         snprintf(reason,MAXBUF,"%s %s",ServerName,params);
2331         while (go_again)
2332         {
2333                 go_again = false;
2334                 for (user_hash::const_iterator u = clientlist.begin(); u != clientlist.end(); u++)
2335                 {
2336                         if (!strcasecmp(u->second->server,params))
2337                         {
2338                                 kill_link(u->second,reason);
2339                                 go_again = true;
2340                                 break;
2341                         }
2342                 }
2343         }
2344 }
2345
2346 // removes a server. Will NOT remove its users!
2347
2348 void RemoveServer(const char* name)
2349 {
2350         bool go_again = true;
2351         while (go_again)
2352         {
2353                 go_again = false;
2354                 for (int i = 0; i < 32; i++)
2355                 {
2356                         if (me[i] != NULL)
2357                         {
2358                                 for (vector<ircd_connector>::iterator j = me[i]->connectors.begin(); j != me[i]->connectors.end(); j++)
2359                                 {
2360                                         if (!strcasecmp(j->GetServerName().c_str(),name))
2361                                         {
2362                                                 j->routes.clear();
2363                                                 j->CloseConnection();
2364                                                 me[i]->connectors.erase(j);
2365                                                 go_again = true;
2366                                                 break;
2367                                         }
2368                                 }
2369                         }
2370                 }
2371         }
2372 }
2373
2374
2375 char MODERR[MAXBUF];
2376
2377 char* ModuleError()
2378 {
2379         return MODERR;
2380 }
2381
2382 void erase_factory(int j)
2383 {
2384         int v = 0;
2385         for (std::vector<ircd_module*>::iterator t = factory.begin(); t != factory.end(); t++)
2386         {
2387                 if (v == j)
2388                 {
2389                         factory.erase(t);
2390                         factory.push_back(NULL);
2391                         return;
2392                 }
2393                 v++;
2394         }
2395 }
2396
2397 void erase_module(int j)
2398 {
2399         int v1 = 0;
2400         for (std::vector<Module*>::iterator m = modules.begin(); m!= modules.end(); m++)
2401         {
2402                 if (v1 == j)
2403                 {
2404                         delete *m;
2405                         modules.erase(m);
2406                         modules.push_back(NULL);
2407                         break;
2408                 }
2409                 v1++;
2410         }
2411         int v2 = 0;
2412         for (std::vector<std::string>::iterator v = module_names.begin(); v != module_names.end(); v++)
2413         {
2414                 if (v2 == j)
2415                 {
2416                        module_names.erase(v);
2417                        break;
2418                 }
2419                 v2++;
2420         }
2421
2422 }
2423
2424 bool UnloadModule(const char* filename)
2425 {
2426         std::string filename_str = filename;
2427         for (int j = 0; j != module_names.size(); j++)
2428         {
2429                 if (module_names[j] == filename_str)
2430                 {
2431                         if (modules[j]->GetVersion().Flags & VF_STATIC)
2432                         {
2433                                 log(DEFAULT,"Failed to unload STATIC module %s",filename);
2434                                 snprintf(MODERR,MAXBUF,"Module not unloadable (marked static)");
2435                                 return false;
2436                         }
2437                         // found the module
2438                         log(DEBUG,"Deleting module...");
2439                         erase_module(j);
2440                         log(DEBUG,"Erasing module entry...");
2441                         erase_factory(j);
2442                         log(DEBUG,"Removing dependent commands...");
2443                         removecommands(filename);
2444                         log(DEFAULT,"Module %s unloaded",filename);
2445                         MODCOUNT--;
2446                         return true;
2447                 }
2448         }
2449         log(DEFAULT,"Module %s is not loaded, cannot unload it!",filename);
2450         snprintf(MODERR,MAXBUF,"Module not loaded");
2451         return false;
2452 }
2453
2454 bool LoadModule(const char* filename)
2455 {
2456         char modfile[MAXBUF];
2457 #ifdef STATIC_LINK
2458         snprintf(modfile,MAXBUF,"%s",filename);
2459 #else
2460         snprintf(modfile,MAXBUF,"%s/%s",ModPath,filename);
2461 #endif
2462         std::string filename_str = filename;
2463 #ifndef STATIC_LINK
2464         if (!DirValid(modfile))
2465         {
2466                 log(DEFAULT,"Module %s is not within the modules directory.",modfile);
2467                 snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile);
2468                 return false;
2469         }
2470 #endif
2471         log(DEBUG,"Loading module: %s",modfile);
2472 #ifndef STATIC_LINK
2473         if (FileExists(modfile))
2474         {
2475 #endif
2476                 for (int j = 0; j < module_names.size(); j++)
2477                 {
2478                         if (module_names[j] == filename_str)
2479                         {
2480                                 log(DEFAULT,"Module %s is already loaded, cannot load a module twice!",modfile);
2481                                 snprintf(MODERR,MAXBUF,"Module already loaded");
2482                                 return false;
2483                         }
2484                 }
2485                 ircd_module* a = new ircd_module(modfile);
2486                 factory[MODCOUNT+1] = a;
2487                 if (factory[MODCOUNT+1]->LastError())
2488                 {
2489                         log(DEFAULT,"Unable to load %s: %s",modfile,factory[MODCOUNT+1]->LastError());
2490                         snprintf(MODERR,MAXBUF,"Loader/Linker error: %s",factory[MODCOUNT+1]->LastError());
2491                         MODCOUNT--;
2492                         return false;
2493                 }
2494                 if (factory[MODCOUNT+1]->factory)
2495                 {
2496                         Module* m = factory[MODCOUNT+1]->factory->CreateModule();
2497                         modules[MODCOUNT+1] = m;
2498                         /* save the module and the module's classfactory, if
2499                          * this isnt done, random crashes can occur :/ */
2500                         module_names.push_back(filename);
2501                 }
2502                 else
2503                 {
2504                         log(DEFAULT,"Unable to load %s",modfile);
2505                         snprintf(MODERR,MAXBUF,"Factory function failed!");
2506                         return false;
2507                 }
2508 #ifndef STATIC_LINK
2509         }
2510         else
2511         {
2512                 log(DEFAULT,"InspIRCd: startup: Module Not Found %s",modfile);
2513                 snprintf(MODERR,MAXBUF,"Module file could not be found");
2514                 return false;
2515         }
2516 #endif
2517         MODCOUNT++;
2518         return true;
2519 }
2520
2521
2522 bool GotServer(std::string name)
2523 {
2524         for (int j = 0; j < 32; j++)
2525         {
2526                 if (me[j] != NULL)
2527                 {
2528                         for (int k = 0; k < me[j]->connectors.size(); k++)
2529                         {
2530                                 if (name == me[j]->connectors[k].GetServerName())
2531                                 {
2532                                         return true;
2533                                 }
2534                         }
2535                 }
2536         }
2537         return false;
2538 }
2539
2540
2541 int InspIRCd(char** argv, int argc)
2542 {
2543         struct sockaddr_in client,server;
2544         char addrs[MAXBUF][255];
2545         int incomingSockfd, result = TRUE;
2546         socklen_t length;
2547         int count = 0;
2548         int selectResult = 0, selectResult2 = 0;
2549         char configToken[MAXBUF], Addr[MAXBUF], Type[MAXBUF];
2550         fd_set selectFds;
2551         timeval tv;
2552
2553         std::string logpath = GetFullProgDir(argv,argc) + "/ircd.log";
2554         log_file = fopen(logpath.c_str(),"a+");
2555         if (!log_file)
2556         {
2557                 printf("ERROR: Could not write to logfile %s, bailing!\n\n",logpath.c_str());
2558                 Exit(ERROR);
2559         }
2560
2561 #ifdef IS_CYGWIN
2562         printf("Logging to ircd.log...\n");
2563 #else
2564         printf("Logging to %s...\n",logpath.c_str());
2565 #endif
2566
2567         log(DEFAULT,"$Id$");
2568         if (geteuid() == 0)
2569         {
2570                 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
2571                 Exit(ERROR);
2572                 log(DEFAULT,"InspIRCd: startup: not starting with UID 0!");
2573         }
2574         SetupCommandTable();
2575         log(DEBUG,"InspIRCd: startup: default command table set up");
2576         
2577         ReadConfig(true,NULL);
2578         if (DieValue[0])
2579         { 
2580                 printf("WARNING: %s\n\n",DieValue);
2581                 log(DEFAULT,"Ut-Oh, somebody didn't read their config file: '%s'",DieValue);
2582                 exit(0); 
2583         }  
2584         log(DEBUG,"InspIRCd: startup: read config");
2585
2586         int clientportcount = 0, serverportcount = 0;
2587
2588         for (count = 0; count < ConfValueEnum("bind",&config_f); count++)
2589         {
2590                 ConfValue("bind","port",count,configToken,&config_f);
2591                 ConfValue("bind","address",count,Addr,&config_f);
2592                 ConfValue("bind","type",count,Type,&config_f);
2593                 if (!strcmp(Type,"servers"))
2594                 {
2595                         char Default[MAXBUF];
2596                         strcpy(Default,"no");
2597                         ConfValue("bind","default",count,Default,&config_f);
2598                         if (strchr(Default,'y'))
2599                         {
2600                                 defaultRoute = serverportcount;
2601                                 log(DEBUG,"InspIRCd: startup: binding '%s:%s' is default server route",Addr,configToken);
2602                         }
2603                         me[serverportcount] = new serverrec(ServerName,100L,false);
2604                         if (!me[serverportcount]->CreateListener(Addr,atoi(configToken)))
2605                         {
2606                                 log(DEFAULT,"Warning: Failed to bind port %lu",(unsigned long)atoi(configToken));
2607                                 printf("Warning: Failed to bind port %lu\n",(unsigned long)atoi(configToken));
2608                         }
2609                         else
2610                         {
2611                                 serverportcount++;
2612                         }
2613                 }
2614                 else
2615                 {
2616                         ports[clientportcount] = atoi(configToken);
2617                         strlcpy(addrs[clientportcount],Addr,256);
2618                         clientportcount++;
2619                 }
2620                 log(DEBUG,"InspIRCd: startup: read binding %s:%s [%s] from config",Addr,configToken, Type);
2621         }
2622         portCount = clientportcount;
2623         SERVERportCount = serverportcount;
2624           
2625         log(DEBUG,"InspIRCd: startup: read %lu total client ports and %lu total server ports",(unsigned long)portCount,(unsigned long)SERVERportCount);
2626         log(DEBUG,"InspIRCd: startup: InspIRCd is now starting!");
2627         
2628         printf("\n");
2629         
2630         /* BugFix By Craig! :p */
2631         MODCOUNT = -1;
2632         for (count = 0; count < ConfValueEnum("module",&config_f); count++)
2633         {
2634                 ConfValue("module","name",count,configToken,&config_f);
2635                 printf("Loading module... \033[1;32m%s\033[0m\n",configToken);
2636                 if (!LoadModule(configToken))
2637                 {
2638                         log(DEFAULT,"Exiting due to a module loader error.");
2639                         printf("\nThere was an error loading a module: %s\n\nYou might want to do './inspircd start' instead of 'bin/inspircd'\n\n",ModuleError());
2640                         Exit(0);
2641                 }
2642         }
2643         log(DEFAULT,"Total loaded modules: %lu",(unsigned long)MODCOUNT+1);
2644         
2645         startup_time = time(NULL);
2646           
2647         char PID[MAXBUF];
2648         ConfValue("pid","file",0,PID,&config_f);
2649         // write once here, to try it out and make sure its ok
2650         WritePID(PID);
2651           
2652         /* setup select call */
2653 #ifndef USE_KQUEUE
2654         FD_ZERO(&selectFds);
2655 #endif
2656         log(DEBUG,"InspIRCd: startup: zero selects");
2657         log(VERBOSE,"InspIRCd: startup: portCount = %lu", (unsigned long)portCount);
2658         
2659         for (count = 0; count < portCount; count++)
2660         {
2661                 if ((openSockfd[boundPortCount] = OpenTCPSocket()) == ERROR)
2662                 {
2663                         log(DEBUG,"InspIRCd: startup: bad fd %lu",(unsigned long)openSockfd[boundPortCount]);
2664                         return(ERROR);
2665                 }
2666                 if (BindSocket(openSockfd[boundPortCount],client,server,ports[count],addrs[count]) == ERROR)
2667                 {
2668                         log(DEFAULT,"InspIRCd: startup: failed to bind port %lu",(unsigned long)ports[count]);
2669                 }
2670                 else    /* well we at least bound to one socket so we'll continue */
2671                 {
2672                         boundPortCount++;
2673                 }
2674         }
2675         
2676         log(DEBUG,"InspIRCd: startup: total bound ports %lu",(unsigned long)boundPortCount);
2677           
2678         /* if we didn't bind to anything then abort */
2679         if (boundPortCount == 0)
2680         {
2681                 log(DEFAULT,"InspIRCd: startup: no ports bound, bailing!");
2682                 printf("\nERROR: Was not able to bind any of %lu ports! Please check your configuration.\n\n", (unsigned long)portCount);
2683                 return (ERROR);
2684         }
2685         
2686
2687         printf("\nInspIRCd is now running!\n");
2688
2689         if (nofork)
2690         {
2691                 log(VERBOSE,"Not forking as -nofork was specified");
2692         }
2693         else
2694         {
2695                 if (DaemonSeed() == ERROR)
2696                 {
2697                         log(DEFAULT,"InspIRCd: startup: can't daemonise");
2698                         printf("ERROR: could not go into daemon mode. Shutting down.\n");
2699                         Exit(ERROR);
2700                 }
2701         }
2702
2703         // BUGFIX: We cannot initialize this before forking, as the kqueue data is not inherited by child processes!
2704 #ifdef USE_KQUEUE
2705         kq = kqueue();
2706         lkq = kqueue();
2707         skq = kqueue();
2708         if ((kq == -1) || (lkq == -1) || (skq == -1))
2709         {
2710                 log(DEFAULT,"main: kqueue() failed!");
2711                 printf("ERROR: could not initialise kqueue event system. Shutting down.\n");
2712                 Exit(ERROR);
2713         }
2714 #endif
2715
2716 #ifdef USE_EPOLL
2717         ep = epoll_create(MAXCLIENTS);
2718         lep = epoll_create(32);
2719         sep = epoll_create(128);
2720         if ((ep == -1) || (lep == -1) || (sep == -1))
2721         {
2722                 log(DEFAULT,"main: epoll_create() failed!");
2723                 printf("ERROR: could not initialise epoll event system. Shutting down.\n");
2724                 Exit(ERROR);
2725         }
2726 #endif
2727
2728 #ifdef USE_EPOLL
2729         log(DEFAULT,"epoll socket engine is enabled. Filling listen list. boundPortcount=%d",boundPortCount);
2730         for (count = 0; count < boundPortCount; count++)
2731         {
2732                 struct epoll_event ev;
2733                 log(DEBUG,"epoll: Add listening socket to events, ep=%d socket=%d",lep,openSockfd[count]);
2734                 ev.events = EPOLLIN | EPOLLET;
2735                 ev.data.fd = openSockfd[count];
2736                 int i = epoll_ctl(lep, EPOLL_CTL_ADD, openSockfd[count], &ev);
2737                 if (i < 0)
2738                 {
2739                         log(DEFAULT,"main: add listen ports, epoll_ctl failed!");
2740                         printf("ERROR: could not initialise listening sockets in epoll list. Shutting down.\n");
2741                         Exit(ERROR);
2742                 }
2743                 
2744         }
2745         for (int t = 0; t != SERVERportCount; t++)
2746         {
2747                 struct epoll_event ev;
2748                 log(DEBUG,"epoll: Add listening server socket to events, ep=%d socket=%d",sep,me[t]->fd);
2749                 ev.events = EPOLLIN | EPOLLET;
2750                 ev.data.fd = me[t]->fd;
2751                 int i = epoll_ctl(sep, EPOLL_CTL_ADD, me[t]->fd, &ev);
2752                 if (i == -1)
2753                 {
2754                         log(DEFAULT,"main: add server listen ports, epoll_ctl failed!");
2755                         printf("ERROR: could not initialise server listening sockets in epoll list. Shutting down.\n");
2756                         Exit(ERROR);
2757                 }
2758         }
2759 #else
2760 #ifdef USE_KQUEUE
2761         log(DEFAULT,"kqueue socket engine is enabled. Filling listen list.");
2762         for (count = 0; count < boundPortCount; count++)
2763         {
2764                 struct kevent ke;
2765                 log(DEBUG,"kqueue: Add listening socket to events, kq=%d socket=%d",lkq,openSockfd[count]);
2766                 EV_SET(&ke, openSockfd[count], EVFILT_READ, EV_ADD, 0, MaxConn, NULL);
2767                 int i = kevent(lkq, &ke, 1, 0, 0, NULL);
2768                 if (i == -1)
2769                 {
2770                         log(DEFAULT,"main: add listen ports to kqueue failed!");
2771                         printf("ERROR: could not initialise listening sockets in kqueue. Shutting down.\n");
2772                         Exit(ERROR);
2773                 }
2774         }
2775         for (int t = 0; t != SERVERportCount; t++)
2776         {
2777                 struct kevent ke;
2778                 if (me[t])
2779                 {
2780                         log(DEBUG,"kqueue: Add listening SERVER socket to events, kq=%d socket=%d",skq,me[t]->fd);
2781                         EV_SET(&ke, me[t]->fd, EVFILT_READ, EV_ADD, 0, MaxConn, NULL);
2782                         int i = kevent(skq, &ke, 1, 0, 0, NULL);
2783                         if (i == -1)
2784                         {
2785                                 log(DEFAULT,"main: add server listen ports to kqueue failed!");
2786                                 printf("ERROR: could not initialise listening server sockets in kqueue. Shutting down.\n");
2787                                 Exit(ERROR);
2788                         }
2789                 }
2790         }
2791
2792
2793 #else
2794         log(DEFAULT,"Using standard select socket engine.");
2795 #endif
2796 #endif
2797
2798         WritePID(PID);
2799
2800         length = sizeof (client);
2801         char tcp_msg[MAXBUF],tcp_host[MAXBUF],tcp_sum[MAXBUF];
2802
2803 #ifdef USE_KQUEUE
2804         struct kevent ke;
2805         struct kevent ke_list[33];
2806         struct timespec ts;
2807 #endif
2808 #ifdef USE_EPOLL
2809         struct epoll_event event[33];
2810 #endif
2811         fd_set serverfds;
2812         timeval tvs;
2813         tvs.tv_usec = 10000L;
2814         tvs.tv_sec = 0;
2815         tv.tv_sec = 0;
2816         tv.tv_usec = 10000L;
2817         char data[65536];
2818         timeval tval;
2819         fd_set sfd;
2820         tval.tv_usec = 10000L;
2821         tval.tv_sec = 0;
2822         int total_in_this_set = 0;
2823         int i = 0, v = 0, j = 0, cycle_iter = 0;
2824         bool expire_run = false;
2825           
2826         /* main loop, this never returns */
2827         for (;;)
2828         {
2829 #ifdef _POSIX_PRIORITY_SCHEDULING
2830                 sched_yield();
2831 #endif
2832 #ifdef USE_SELECT
2833                 FD_ZERO(&sfd);
2834 #endif
2835                 // we only read time() once per iteration rather than tons of times!
2836                 OLDTIME = TIME;
2837                 TIME = time(NULL);
2838
2839                 dns_poll();
2840
2841                 // *FIX* Instead of closing sockets in kill_link when they receive the ERROR :blah line, we should queue
2842                 // them in a list, then reap the list every second or so.
2843                 if (((TIME % 5) == 0) && (!expire_run))
2844                 {
2845                         for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
2846                         {
2847                                 char Link_ServerName[MAXBUF],Link_AConn[MAXBUF];
2848                                 ConfValue("link","name",i,Link_ServerName,&config_f);
2849                                 ConfValue("link","autoconnect",i,Link_AConn,&config_f);
2850                                 if ((Link_AConn[0]) && (!GotServer(Link_ServerName)))
2851                                 {
2852                                         autoconnects::iterator a = autoconns.find(std::string(Link_ServerName));
2853                                         if (a != autoconns.end())
2854                                         {
2855                                                 if (TIME > a->second)
2856                                                 {
2857                                                         ConnectServer(Link_ServerName,NULL);
2858                                                         a->second = TIME + atoi(Link_AConn);
2859                                                 }
2860                                         }
2861                                 }
2862                         }
2863
2864                         expire_lines();
2865                         FOREACH_MOD OnBackgroundTimer(TIME);
2866                         expire_run = true;
2867                         continue;
2868                 }
2869                 if ((TIME % 5) == 1)
2870                         expire_run = false;
2871                 
2872                 // fix by brain - this must be below any manipulation of the hashmap by modules
2873                 user_hash::iterator count2 = clientlist.begin();
2874
2875 #ifdef USE_EPOLL
2876                 i = epoll_wait(sep, event, 1, EP_DELAY);
2877                 if (i > 0)
2878                 {
2879                         log(DEBUG,"epoll: Listening server socket event, i=%d, event.data.fd=%d",i,event[0].data.fd);
2880                         for (int x = 0; x != SERVERportCount; x++)
2881                         {
2882                                 if ((me[x]) && (event[0].data.fd == me[x]->fd))
2883                                 {
2884 #endif
2885 #ifdef USE_KQUEUE
2886                 ts.tv_sec = 0;
2887                 ts.tv_nsec = 30000L;
2888                 i = kevent(skq, NULL, 0, &ke, 1, &ts);
2889                 if (i > 0)
2890                 {
2891                         log(DEBUG,"kqueue: Listening server socket event, i=%d, ke.ident=%d",i,ke.ident);
2892                         for (int x = 0; x != SERVERportCount; x++)
2893                         {
2894                                 if ((me[x]) && (ke.ident == me[x]->fd))
2895                                 {
2896
2897 #endif
2898 #ifdef USE_SELECT
2899                 FD_ZERO(&serverfds);
2900                 for (int x = 0; x != SERVERportCount; x++)
2901                 {
2902                         if (me[x])
2903                                 FD_SET(me[x]->fd, &serverfds);
2904                 }
2905                 tvs.tv_usec = 30000L;
2906                 tvs.tv_sec = 0;
2907                 int servresult = select(FD_SETSIZE, &serverfds, NULL, NULL, &tvs);
2908                 if (servresult > 0)
2909                 {
2910                         for (int x = 0; x != SERVERportCount; x++)
2911                         {
2912                                 if ((me[x]) && (FD_ISSET (me[x]->fd, &serverfds)))
2913                                 {
2914 #endif
2915                                         char remotehost[MAXBUF],resolved[MAXBUF];
2916                                         length = sizeof (client);
2917                                         incomingSockfd = accept (me[x]->fd, (sockaddr *) &client, &length);
2918                                         if (incomingSockfd != -1)
2919                                         {
2920                                                 strlcpy(remotehost,(char *)inet_ntoa(client.sin_addr),MAXBUF);
2921                                                 if(CleanAndResolve(resolved, remotehost) != TRUE)
2922                                                 {
2923                                                         strlcpy(resolved,remotehost,MAXBUF);
2924                                                 }
2925                                                 // add to this connections ircd_connector vector
2926                                                 // *FIX* - we need the LOCAL port not the remote port in &client!
2927                                                 me[x]->AddIncoming(incomingSockfd,resolved,me[x]->port);
2928                                         }
2929                                 }
2930                         }
2931                 }
2932      
2933                 std::deque<std::string> msgs;
2934                 std::deque<std::string> sums;
2935                 for (int x = 0; x < SERVERportCount; x++)
2936                 {
2937                         if (me[x])
2938                                 me[x]->FlushWriteBuffers();
2939                         sums.clear();
2940                         msgs.clear();
2941                         while ((me[x]) && (me[x]->RecvPacket(msgs, tcp_host, sums))) // returns 0 or more lines (can be multiple lines!)
2942                         {
2943                                 for (int ctr = 0; ctr < msgs.size(); ctr++)
2944                                 {
2945                                         strlcpy(tcp_msg,msgs[ctr].c_str(),MAXBUF);
2946                                         strlcpy(tcp_sum,msgs[ctr].c_str(),MAXBUF);
2947                                         log(DEBUG,"Processing: %s",tcp_msg);
2948                                         if (!tcp_msg[0])
2949                                         {
2950                                                 log(DEBUG,"Invalid string from %s [route%lu]",tcp_host,(unsigned long)x);
2951                                                 break;
2952                                         }
2953                                         // during a netburst, send all data to all other linked servers
2954                                         if ((((nb_start>0) && (tcp_msg[0] != 'Y') && (tcp_msg[0] != 'X') && (tcp_msg[0] != 'F'))) || (is_uline(tcp_host)))
2955                                         {
2956                                                 if (is_uline(tcp_host))
2957                                                 {
2958                                                         if ((tcp_msg[0] != 'Y') && (tcp_msg[0] != 'X') && (tcp_msg[0] != 'F'))
2959                                                         {
2960                                                                 NetSendToAllExcept_WithSum(tcp_host,tcp_msg,tcp_sum);
2961                                                         }
2962                                                 }
2963                                                 else
2964                                                         NetSendToAllExcept_WithSum(tcp_host,tcp_msg,tcp_sum);
2965                                         }
2966                                         std::string msg = tcp_msg;
2967                                         FOREACH_MOD OnPacketReceive(msg,tcp_host);
2968                                         strlcpy(tcp_msg,msg.c_str(),MAXBUF);
2969                                         if (me[x])
2970                                                 handle_link_packet(tcp_msg, tcp_host, me[x], tcp_sum);
2971                                         if (!me[x]->FindHost(tcp_host))
2972                                         {
2973                                                 log(DEBUG,"Connector gone, bailing!");
2974                                                 goto label;
2975                                         }
2976                                 }
2977                                         sums.clear();   // we're done, clear the list for the next operation
2978                                         msgs.clear();
2979                         }
2980                 }
2981         
2982         while (count2 != clientlist.end())
2983         {
2984 #ifdef USE_SELECT
2985                 FD_ZERO(&sfd);
2986 #endif
2987
2988                 total_in_this_set = 0;
2989
2990                 user_hash::iterator xcount = count2;
2991                 user_hash::iterator endingiter = count2;
2992
2993                 if (count2 == clientlist.end()) break;
2994
2995                 userrec* curr = NULL;
2996
2997                 if (count2->second)
2998                         curr = count2->second;
2999
3000                 if ((long)curr == -1)
3001                         goto label;
3002
3003                 if ((curr) && (curr->fd != 0))
3004                 {
3005 #ifdef _POSIX_PRIORITY_SCHEDULING
3006         sched_yield();
3007 #endif
3008                         // assemble up to 64 sockets into an fd_set
3009                         // to implement a pooling mechanism.
3010                         //
3011                         // This should be up to 64x faster than the
3012                         // old implementation.
3013 #ifdef USE_SELECT
3014                         while (total_in_this_set < 1024)
3015                         {
3016                                 if (count2 != clientlist.end())
3017                                 {
3018                                         curr = count2->second;
3019                                         if ((long)curr == -1)
3020                                                 goto label;
3021                                         int currfd = curr->fd;
3022                                         // we don't check the state of remote users.
3023                                         if ((currfd != -1) && (currfd != FD_MAGIC_NUMBER))
3024                                         {
3025                                                 curr->FlushWriteBuf();
3026                                                 if (curr->GetWriteError() != "")
3027                                                 {
3028                                                         log(DEBUG,"InspIRCd: write error: %s",curr->GetWriteError().c_str());
3029                                                         kill_link(curr,curr->GetWriteError().c_str());
3030                                                         goto label;
3031                                                 }
3032
3033                                                 FD_SET (curr->fd, &sfd);
3034
3035                                                 // registration timeout -- didnt send USER/NICK/HOST in the time specified in
3036                                                 // their connection class.
3037                                                 if ((TIME > curr->timeout) && (curr->registered != 7)) 
3038                                                 {
3039                                                         log(DEBUG,"InspIRCd: registration timeout: %s",curr->nick);
3040                                                         kill_link(curr,"Registration timeout");
3041                                                         goto label;
3042                                                 }
3043                                                 if ((TIME > curr->signon) && (curr->registered == 3) && (AllModulesReportReady(curr)))
3044                                                 {
3045                                                         log(DEBUG,"signon exceed, registered=3, and modules ready, OK");
3046                                                         curr->dns_done = true;
3047                                                         statsDnsBad++;
3048                                                         FullConnectUser(curr);
3049                                                         if (fd_ref_table[currfd] != curr) // something changed, bail pronto
3050                                                                 goto label;                                                        
3051                                                 }
3052                                                 if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr))) // both NICK and USER... and DNS
3053                                                 {
3054                                                         log(DEBUG,"dns done, registered=3, and modules ready, OK");
3055                                                         FullConnectUser(curr);
3056                                                         if (fd_ref_table[currfd] != curr) // something changed, bail pronto
3057                                                                 goto label;
3058                                                 }
3059                                                 if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7))
3060                                                 {
3061                                                         if ((!curr->lastping) && (curr->registered == 7))
3062                                                         {
3063                                                                 log(DEBUG,"InspIRCd: ping timeout: %s",curr->nick);
3064                                                                 kill_link(curr,"Ping timeout");
3065                                                                 goto label;
3066                                                         }
3067                                                         Write(curr->fd,"PING :%s",ServerName);
3068                                                         log(DEBUG,"InspIRCd: pinging: %s",curr->nick);
3069                                                         curr->lastping = 0;
3070                                                         curr->nping = TIME+curr->pingmax;       // was hard coded to 120
3071                                                 }
3072                                         }
3073                                         count2++;
3074                                         total_in_this_set++;
3075                                 }
3076                                 else break;
3077                         }
3078                         endingiter = count2;
3079                         count2 = xcount; // roll back to where we were
3080 #else
3081                         // KQUEUE and EPOLL: We don't go through a loop to fill the fd_set so instead we must manually do this loop every now and again.
3082                         // TODO: We dont need to do all this EVERY loop iteration, tone down the visits to this if we're using kqueue.
3083                         cycle_iter++;
3084                         if (cycle_iter > 20) while (count2 != clientlist.end())
3085                         {
3086                                 cycle_iter = 0;
3087                                 if (count2 != clientlist.end())
3088                                 {
3089                                         curr = count2->second;
3090                                         if ((long)curr == -1)
3091                                                 goto label;
3092                                         int currfd = curr->fd;
3093                                         // we don't check the state of remote users.
3094                                         if ((currfd != -1) && (currfd != FD_MAGIC_NUMBER))
3095                                         {
3096
3097                                                 curr->FlushWriteBuf();
3098                                                 if (curr->GetWriteError() != "")
3099                                                 {
3100                                                         log(DEBUG,"InspIRCd: write error: %s",curr->GetWriteError().c_str());
3101                                                         kill_link(curr,curr->GetWriteError().c_str());
3102                                                         goto label;
3103                                                 }
3104
3105                                                 // registration timeout -- didnt send USER/NICK/HOST in the time specified in
3106                                                 // their connection class.
3107                                                 if ((TIME > curr->timeout) && (curr->registered != 7))
3108                                                 {
3109                                                         log(DEBUG,"InspIRCd: registration timeout: %s",curr->nick);
3110                                                         kill_link(curr,"Registration timeout");
3111                                                         goto label;
3112
3113                                                 }
3114                                                 if ((TIME > curr->signon) && (curr->registered == 3) && (AllModulesReportReady(curr)))
3115                                                 {
3116                                                         log(DEBUG,"signon exceed, registered=3, and modules ready, OK: %d %d",TIME,curr->signon);
3117                                                         curr->dns_done = true;
3118                                                         statsDnsBad++;
3119                                                         FullConnectUser(curr);
3120                                                         if (fd_ref_table[currfd] != curr) // something changed, bail pronto
3121                                                                 goto label;
3122                                                 }
3123                                                 if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr)))
3124                                                 {
3125                                                         log(DEBUG,"dns done, registered=3, and modules ready, OK");
3126                                                         FullConnectUser(curr);
3127                                                         if (fd_ref_table[currfd] != curr) // something changed, bail pronto
3128                                                                 goto label;
3129                                                 }
3130                                                 if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7))
3131                                                 {
3132                                                         if ((!curr->lastping) && (curr->registered == 7))
3133                                                         {
3134                                                                 log(DEBUG,"InspIRCd: ping timeout: %s",curr->nick);
3135                                                                 kill_link(curr,"Ping timeout");
3136                                                                 goto label;
3137                                                         }
3138                                                         Write(curr->fd,"PING :%s",ServerName);
3139                                                         log(DEBUG,"InspIRCd: pinging: %s",curr->nick);
3140                                                         curr->lastping = 0;
3141                                                         curr->nping = TIME+curr->pingmax;       // was hard coded to 120
3142                                                 }
3143                                         }
3144                                 }
3145                                 else break;
3146                                 count2++;
3147                         }
3148                         // increment the counter right to the end of the list, as kqueue processes everything in one go
3149 #endif
3150         
3151                         v = 0;
3152 #ifdef USE_EPOLL
3153                         int i = epoll_wait(ep, event, 1, 5);
3154                         if (i > 0)
3155                         {
3156                                 log(DEBUG,"epoll_wait call: ep=%d, i=%d",ep,i);
3157                                 // EPOLL: we asked epoll_wait for ONE fd which is ready. Do something.
3158                                 userrec* cu = fd_ref_table[event[0].data.fd];
3159 #endif
3160 #ifdef USE_KQUEUE
3161                         ts.tv_sec = 0;
3162                         ts.tv_nsec = 1000L;
3163                         // for now, we only read 1 event. We could read soooo many more :)
3164                         int i = kevent(kq, NULL, 0, &ke, 1, &ts);
3165                         if (i > 0)
3166                         {
3167                                 log(DEBUG,"kevent call: kq=%d, i=%d",kq,i);
3168                                 // KQUEUE: kevent gives us ONE fd which is ready to have something done to it. Do something to it.
3169                                 userrec* cu = fd_ref_table[ke.ident];
3170 #endif
3171 #ifdef USE_SELECT
3172                         tval.tv_sec = 0;
3173                         tval.tv_usec = 1000L;
3174                         selectResult2 = select(FD_SETSIZE, &sfd, NULL, NULL, &tval);
3175                         // now loop through all of the items in this pool if any are waiting
3176                         if ((selectResult2 > 0) && (xcount != clientlist.end()))
3177                         for (user_hash::iterator count2a = xcount; count2a != endingiter; count2a++)
3178                         {
3179                                 // SELECT: we have to iterate...
3180                                 if (count2a == clientlist.end())
3181                                         break;
3182                                 userrec* cu = count2a->second;
3183 #endif
3184
3185 #ifdef _POSIX_PRIORITY_SCHEDULING
3186                                 sched_yield();
3187 #endif
3188                                 result = EAGAIN;
3189 #ifdef USE_EPOLL
3190                                 // EPOLL: We already know we have a valid FD. No checks needed.
3191                                 if ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
3192 #endif
3193 #ifdef USE_KQUEUE
3194                                 // KQUEUE: We already know we have a valid FD. No checks needed.
3195                                 if ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
3196 #endif
3197 #ifdef USE_SELECT
3198                                 // SELECT: We don't know if our FD is valid.
3199                                 if ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1) && (FD_ISSET (cu->fd, &sfd)))
3200 #endif
3201                                 {
3202                                         log(DEBUG,"Data waiting on socket %d",cu->fd);
3203                                         int MOD_RESULT = 0;
3204                                         int result2 = 0;
3205                                         FOREACH_RESULT(OnRawSocketRead(cu->fd,data,65535,result2));
3206                                         if (!MOD_RESULT)
3207                                         {
3208                                                 result = cu->ReadData(data, 65535);
3209                                         }
3210                                         else result = result2;
3211                                         log(DEBUG,"Read result: %d",result);
3212                                         if (result)
3213                                         {
3214                                                 statsRecv += result;
3215                                                 // perform a check on the raw buffer as an array (not a string!) to remove
3216                                                 // characters 0 and 7 which are illegal in the RFC - replace them with spaces.
3217                                                 // hopefully this should stop even more people whining about "Unknown command: *"
3218                                                 for (int checker = 0; checker < result; checker++)
3219                                                 {
3220                                                         if ((data[checker] == 0) || (data[checker] == 7))
3221                                                                 data[checker] = ' ';
3222                                                 }
3223                                                 if (result > 0)
3224                                                         data[result] = '\0';
3225                                                 userrec* current = cu;
3226                                                 int currfd = current->fd;
3227                                                 int floodlines = 0;
3228                                                 // add the data to the users buffer
3229                                                 if (result > 0)
3230                                                 if (!current->AddBuffer(data))
3231                                                 {
3232                                                         // AddBuffer returned false, theres too much data in the user's buffer and theyre up to no good.
3233                                                         if (current->registered == 7)
3234                                                         {
3235                                                                 kill_link(current,"RecvQ exceeded");
3236                                                         }
3237                                                         else
3238                                                         {
3239                                                                 WriteOpers("*** Excess flood from %s",current->ip);
3240                                                                 log(DEFAULT,"Excess flood from: %s",current->ip);
3241                                                                 add_zline(120,ServerName,"Flood from unregistered connection",current->ip);
3242                                                                 apply_lines();
3243                                                         }
3244                                                         goto label;
3245                                                 }
3246                                                 if (current->recvq.length() > NetBufferSize)
3247                                                 {
3248                                                         if (current->registered == 7)
3249                                                         {
3250                                                                 kill_link(current,"RecvQ exceeded");
3251                                                         }
3252                                                         else
3253                                                         {
3254                                                                 WriteOpers("*** Excess flood from %s",current->ip);
3255                                                                 log(DEFAULT,"Excess flood from: %s",current->ip);
3256                                                                 add_zline(120,ServerName,"Flood from unregistered connection",current->ip);
3257                                                                 apply_lines();
3258                                                         }
3259                                                         goto label;
3260                                                 }
3261                                                 // while there are complete lines to process...
3262                                                 while (current->BufferIsReady())
3263                                                 {
3264                                                         floodlines++;
3265                                                         if (TIME > current->reset_due)
3266                                                         {
3267                                                                 current->reset_due = TIME + current->threshold;
3268                                                                 current->lines_in = 0;
3269                                                         }
3270                                                         current->lines_in++;
3271                                                         if (current->lines_in > current->flood)
3272                                                         {
3273                                                                 log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
3274                                                                 WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
3275                                                                 kill_link(current,"Excess flood");
3276                                                                 goto label;
3277                                                         }
3278                                                         if ((floodlines > current->flood) && (current->flood != 0))
3279                                                         {
3280                                                                 if (current->registered == 7)
3281                                                                 {
3282                                                                         log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
3283                                                                         WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
3284                                                                         kill_link(current,"Excess flood");
3285                                                                 }
3286                                                                 else
3287                                                                 {
3288                                                                         add_zline(120,ServerName,"Flood from unregistered connection",current->ip);
3289                                                                         apply_lines();
3290                                                                 }
3291                                                                 goto label;
3292                                                         }
3293                                                         char sanitized[MAXBUF];
3294                                                         // use GetBuffer to copy single lines into the sanitized string
3295                                                         std::string single_line = current->GetBuffer();
3296                                                         current->bytes_in += single_line.length();
3297                                                         current->cmds_in++;
3298                                                         if (single_line.length()>512)
3299                                                         {
3300                                                                 log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
3301                                                                 WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host);
3302                                                                 kill_link(current,"Excess flood");
3303                                                                 goto label;
3304                                                         }
3305                                                         strlcpy(sanitized,single_line.c_str(),MAXBUF);
3306                                                         if (*sanitized)
3307                                                         {
3308                                                                 userrec* old_comp = fd_ref_table[currfd];
3309                                                                 // we're gonna re-scan to check if the nick is gone, after every
3310                                                                 // command - if it has, we're gonna bail
3311                                                                 process_buffer(sanitized,current);
3312                                                                 // look for the user's record in case it's changed... if theyve quit,
3313                                                                 // we cant do anything more with their buffer, so bail.
3314                                                                 // there used to be an ugly, slow loop here. Now we have a reference
3315                                                                 // table, life is much easier (and FASTER)
3316                                                                 userrec* new_comp = fd_ref_table[currfd];
3317                                                                 if ((currfd < 0) || (!fd_ref_table[currfd]) || (old_comp != new_comp))
3318                                                                         goto label;
3319
3320                                                         }
3321                                                 }
3322                                                 goto label;
3323                                         }
3324
3325                                         if ((result == -1) && (errno != EAGAIN) && (errno != EINTR))
3326                                         {
3327                                                 log(DEBUG,"killing: %s",cu->nick);
3328                                                 kill_link(cu,strerror(errno));
3329                                                 goto label;
3330                                         }
3331                                 }
3332                                 // result EAGAIN means nothing read
3333                                 if (result == EAGAIN)
3334                                 {
3335                                 }
3336                                 else
3337                                 if (result == 0)
3338                                 {
3339 #ifdef USE_SELECT
3340                                         if (count2->second)
3341                                         {
3342 #endif
3343                                                 log(DEBUG,"InspIRCd: Exited: %s",cu->nick);
3344                                                 kill_link(cu,"Client exited");
3345                                                 // must bail here? kill_link removes the hash, corrupting the iterator
3346                                                 log(DEBUG,"Bailing from client exit");
3347                                                 goto label;
3348 #ifdef USE_SELECT
3349                                         }
3350 #endif
3351                                 }
3352                                 else if (result > 0)
3353                                 {
3354                                 }
3355                         }
3356                 }
3357                 for (int q = 0; q < total_in_this_set; q++)
3358                 {
3359                         count2++;
3360                 }
3361         }
3362
3363 #ifdef _POSIX_PRIORITY_SCHEDULING
3364         sched_yield();
3365 #endif
3366         
3367 #ifdef USE_SELECT
3368         // set up select call
3369         for (count = 0; count < boundPortCount; count++)
3370         {
3371                 FD_SET (openSockfd[count], &selectFds);
3372         }
3373
3374         tv.tv_usec = 30000L;
3375         selectResult = select(MAXSOCKS, &selectFds, NULL, NULL, &tv);
3376
3377         /* select is reporting a waiting socket. Poll them all to find out which */
3378         if (selectResult > 0)
3379         {
3380                 for (count = 0; count < boundPortCount; count++)
3381                 {
3382                         if (FD_ISSET (openSockfd[count], &selectFds))
3383                         {
3384 #endif
3385 #ifdef USE_KQUEUE
3386         ts.tv_sec = 0;
3387         ts.tv_nsec = 30000L;
3388         i = kevent(lkq, NULL, 0, ke_list, 32, &ts);
3389         if (i > 0) for (j = 0; j < i; j++)
3390         {
3391                 log(DEBUG,"kqueue: Listening socket event, i=%d, ke.ident=%d",i,ke_list[j].ident);
3392                 // this isnt as efficient as it could be, we could create a reference table
3393                 // to reference bound ports by fd, but this isnt a big bottleneck as the actual
3394                 // number of listening ports on the average ircd is a small number (less than 20)
3395                 // compared to the number of clients (possibly over 2000)
3396                 for (count = 0; count < boundPortCount; count++)
3397                 {
3398                         if (ke_list[j].ident == openSockfd[count])
3399                         {
3400 #endif
3401 #ifdef USE_EPOLL
3402         i = epoll_wait(lep, event, 32, EP_DELAY);
3403         if (i > 0) for (j = 0; j < i; j++)
3404         {
3405                 log(DEBUG,"epoll: Listening socket event, i=%d,events[j].data.fd=%d",i,event[j].data.fd);
3406                 for (count = 0; count < boundPortCount; count++)
3407                 {
3408                         if (event[j].data.fd == openSockfd[count])
3409                         {
3410 #endif
3411                                 char target[MAXBUF], resolved[MAXBUF];
3412                                 length = sizeof (client);
3413                                 incomingSockfd = accept (openSockfd[count], (struct sockaddr *) &client, &length);
3414                               
3415                                 strlcpy (target, (char *) inet_ntoa (client.sin_addr), MAXBUF);
3416                                 strlcpy (resolved, target, MAXBUF);
3417                         
3418                                 if (incomingSockfd < 0)
3419                                 {
3420                                         WriteOpers("*** WARNING: Accept failed on port %lu (%s)",(unsigned long)ports[count],target);
3421                                         log(DEBUG,"InspIRCd: accept failed: %lu",(unsigned long)ports[count]);
3422                                         statsRefused++;
3423                                 }
3424                                 else
3425                                 {
3426                                         FOREACH_MOD OnRawSocketAccept(incomingSockfd, resolved, ports[count]);
3427                                         statsAccept++;
3428                                         AddClient(incomingSockfd, resolved, ports[count], false, inet_ntoa (client.sin_addr));
3429                                         log(DEBUG,"InspIRCd: adding client on port %lu fd=%lu",(unsigned long)ports[count],(unsigned long)incomingSockfd);
3430                                 }
3431                         }
3432                 }
3433         }
3434         label:
3435         if (0) {};
3436 #ifdef _POSIX_PRIORITY_SCHEDULING
3437         sched_yield();
3438         sched_yield();
3439 #endif
3440 }
3441 /* not reached */
3442 close (incomingSockfd);
3443 }
3444