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