]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/inspircd.cpp
Moved classes out of inspircd.cpp
[user/henk/code/inspircd.git] / src / inspircd.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2005 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 /* Now with added unF! ;) */
18
19 using namespace std;
20
21 #include "inspircd_config.h"
22 #include "inspircd.h"
23 #include "inspircd_io.h"
24 #include "inspircd_util.h"
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/errno.h>
28 #include <sys/ioctl.h>
29 #include <sys/utsname.h>
30 #include <time.h>
31 #include <string>
32 #ifdef GCC3
33 #include <ext/hash_map>
34 #else
35 #include <hash_map>
36 #endif
37 #include <map>
38 #include <sstream>
39 #include <vector>
40 #include <deque>
41 #include <sched.h>
42 #ifdef THREADED_DNS
43 #include <pthread.h>
44 #endif
45 #include "users.h"
46 #include "ctables.h"
47 #include "globals.h"
48 #include "modules.h"
49 #include "dynamic.h"
50 #include "wildcard.h"
51 #include "message.h"
52 #include "mode.h"
53 #include "commands.h"
54 #include "xline.h"
55 #include "inspstring.h"
56 #include "dnsqueue.h"
57 #include "helperfuncs.h"
58 #include "hashcomp.h"
59 #include "socketengine.h"
60 #include "userprocess.h"
61 #include "socket.h"
62 #include "dns.h"
63 #include "typedefs.h"
64
65 int WHOWAS_STALE = 48; // default WHOWAS Entries last 2 days before they go 'stale'
66 int WHOWAS_MAX = 100;  // default 100 people maximum in the WHOWAS list
67 int DieDelay  =  5;
68 time_t startup_time = time(NULL);
69
70 extern std::vector<Module*> modules;
71 std::vector<std::string> module_names;
72 extern std::vector<ircd_module*> factory;
73
74 std::vector<InspSocket*> module_sockets;
75
76 extern int MODCOUNT;
77 int openSockfd[MAXSOCKS];
78 struct sockaddr_in client,server;
79 socklen_t length;
80
81 extern InspSocket* socket_ref[65535];
82
83 time_t TIME = time(NULL), OLDTIME = time(NULL);
84
85 SocketEngine* SE = NULL;
86
87 extern std::vector<std::string> include_stack;
88
89 // This table references users by file descriptor.
90 // its an array to make it VERY fast, as all lookups are referenced
91 // by an integer, meaning there is no need for a scan/search operation.
92 userrec* fd_ref_table[65536];
93
94 serverstats* stats = new serverstats;
95 Server* MyServer = new Server;
96 ServerConfig *Config = new ServerConfig;
97
98 user_hash clientlist;
99 chan_hash chanlist;
100 whowas_hash whowas;
101 command_table cmdlist;
102 address_cache IP;
103
104 servernamelist servernames;
105
106 int boundPortCount = 0;
107 int portCount = 0, ports[MAXSOCKS];
108
109 /* prototypes */
110
111 /*int has_channel(userrec *u, chanrec *c);
112 int usercount(chanrec *c);
113 int usercount_i(chanrec *c);
114 char* Passwd(userrec *user);
115 bool IsDenied(userrec *user);
116 void AddWhoWas(userrec* u);*/
117
118 std::vector<userrec*> all_opers;
119
120 char lowermap[255];
121
122 void AddOper(userrec* user)
123 {
124         log(DEBUG,"Oper added to optimization list");
125         all_opers.push_back(user);
126 }
127
128 void AddServerName(std::string servername)
129 {
130         log(DEBUG,"Adding server name: %s",servername.c_str());
131         for (servernamelist::iterator a = servernames.begin(); a < servernames.end(); a++)
132         {
133                 if (*a == servername)
134                         return;
135         }
136         servernames.push_back(servername);
137 }
138
139 const char* FindServerNamePtr(std::string servername)
140 {
141         for (servernamelist::iterator a = servernames.begin(); a < servernames.end(); a++)
142         {
143                 if (*a == servername)
144                         return a->c_str();
145         }
146         AddServerName(servername);
147         return FindServerNamePtr(servername);
148 }
149
150 void DeleteOper(userrec* user)
151 {
152         for (std::vector<userrec*>::iterator a = all_opers.begin(); a < all_opers.end(); a++)
153         {
154                 if (*a == user)
155                 {
156                         log(DEBUG,"Oper removed from optimization list");
157                         all_opers.erase(a);
158                         return;
159                 }
160         }
161 }
162
163 std::string GetRevision()
164 {
165         /* w00t got me to replace a bunch of strtok_r
166          * with something nicer, so i did this. Its the
167          * same thing really, only in C++. It places the
168          * text into a std::stringstream which is a readable
169          * and writeable buffer stream, and then pops two
170          * words off it, space delimited. Because it reads
171          * into the same variable twice, the first word
172          * is discarded, and the second one returned.
173          */
174         std::stringstream Revision("$Revision$");
175         std::string single;
176         Revision >> single >> single;
177         return single;
178 }
179
180
181 std::string getservername()
182 {
183         return Config->ServerName;
184 }
185
186 std::string getserverdesc()
187 {
188         return Config->ServerDesc;
189 }
190
191 std::string getnetworkname()
192 {
193         return Config->Network;
194 }
195
196 std::string getadminname()
197 {
198         return Config->AdminName;
199 }
200
201 std::string getadminemail()
202 {
203         return Config->AdminEmail;
204 }
205
206 std::string getadminnick()
207 {
208         return Config->AdminNick;
209 }
210
211 /* add a channel to a user, creating the record for it if needed and linking
212  * it to the user record */
213
214 chanrec* add_channel(userrec *user, const char* cn, const char* key, bool override)
215 {
216         if ((!user) || (!cn))
217         {
218                 log(DEFAULT,"*** BUG *** add_channel was given an invalid parameter");
219                 return 0;
220         }
221
222         int created = 0;
223         char cname[MAXBUF];
224         int MOD_RESULT = 0;
225         strncpy(cname,cn,CHANMAX);
226
227         log(DEBUG,"add_channel: %s %s",user->nick,cname);
228
229         chanrec* Ptr = FindChan(cname);
230
231         if (!Ptr)
232         {
233                 if (user->fd > -1)
234                 {
235                         MOD_RESULT = 0;
236                         FOREACH_RESULT(OnUserPreJoin(user,NULL,cname));
237                         if (MOD_RESULT == 1)
238                                 return NULL;
239                 }
240                 /* create a new one */
241                 chanlist[cname] = new chanrec();
242                 strlcpy(chanlist[cname]->name, cname,CHANMAX);
243                 chanlist[cname]->binarymodes = CM_TOPICLOCK | CM_NOEXTERNAL;
244                 chanlist[cname]->created = TIME;
245                 strcpy(chanlist[cname]->topic, "");
246                 strncpy(chanlist[cname]->setby, user->nick,NICKMAX);
247                 chanlist[cname]->topicset = 0;
248                 Ptr = chanlist[cname];
249                 log(DEBUG,"add_channel: created: %s",cname);
250                 /* set created to 2 to indicate user
251                  * is the first in the channel
252                  * and should be given ops */
253                 created = 2;
254         }
255         else
256         {
257                 /* Already on the channel */
258                 if (has_channel(user,Ptr))
259                         return NULL;
260                         
261                 // remote users are allowed us to bypass channel modes
262                 // and bans (used by servers)
263                 if (user->fd > -1)
264                 {
265                         MOD_RESULT = 0;
266                         FOREACH_RESULT(OnUserPreJoin(user,Ptr,cname));
267                         if (MOD_RESULT == 1)
268                         {
269                                 return NULL;
270                         }
271                         else
272                         {
273                                 if (*Ptr->key)
274                                 {
275                                         MOD_RESULT = 0;
276                                         FOREACH_RESULT(OnCheckKey(user, Ptr, key ? key : ""));
277                                         if (!MOD_RESULT)
278                                         {
279                                                 if (!key)
280                                                 {
281                                                         log(DEBUG,"add_channel: no key given in JOIN");
282                                                         WriteServ(user->fd,"475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
283                                                         return NULL;
284                                                 }
285                                                 else
286                                                 {
287                                                         if (strcasecmp(key,Ptr->key))
288                                                         {
289                                                                 log(DEBUG,"add_channel: bad key given in JOIN");
290                                                                 WriteServ(user->fd,"475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
291                                                                 return NULL;
292                                                         }
293                                                 }
294                                         }
295                                 }
296                                 if (Ptr->binarymodes & CM_INVITEONLY)
297                                 {
298                                         MOD_RESULT = 0;
299                                         FOREACH_RESULT(OnCheckInvite(user, Ptr));
300                                         if (!MOD_RESULT)
301                                         {
302                                                 log(DEBUG,"add_channel: channel is +i");
303                                                 if (user->IsInvited(Ptr->name))
304                                                 {
305                                                         /* user was invited to channel */
306                                                         /* there may be an optional channel NOTICE here */
307                                                 }
308                                                 else
309                                                 {
310                                                         WriteServ(user->fd,"473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
311                                                         return NULL;
312                                                 }
313                                         }
314                                         user->RemoveInvite(Ptr->name);
315                                 }
316                                 if (Ptr->limit)
317                                 {
318                                         MOD_RESULT = 0;
319                                         FOREACH_RESULT(OnCheckLimit(user, Ptr));
320                                         if (!MOD_RESULT)
321                                         {
322                                                 if (usercount(Ptr) >= Ptr->limit)
323                                                 {
324                                                         WriteServ(user->fd,"471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
325                                                         return NULL;
326                                                 }
327                                         }
328                                 }
329                                 if (Ptr->bans.size())
330                                 {
331                                         log(DEBUG,"add_channel: about to walk banlist");
332                                         MOD_RESULT = 0;
333                                         FOREACH_RESULT(OnCheckBan(user, Ptr));
334                                         if (!MOD_RESULT)
335                                         {
336                                                 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
337                                                 {
338                                                         if (match(user->GetFullHost(),i->data))
339                                                         {
340                                                                 WriteServ(user->fd,"474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
341                                                                 return NULL;
342                                                         }
343                                                 }
344                                         }
345                                 }
346                         }
347                 }
348                 else
349                 {
350                         log(DEBUG,"Overridden checks");
351                 }
352                 created = 1;
353         }
354
355         log(DEBUG,"Passed channel checks");
356         
357         for (unsigned int index =0; index < user->chans.size(); index++)
358         {
359                 if (user->chans[index].channel == NULL)
360                 {
361                         return ForceChan(Ptr,user->chans[index],user,created);
362                 }
363         }
364         /* XXX: If the user is an oper here, we can just extend their user->chans vector by one
365          * and put the channel in here. Same for remote users which are not bound by
366          * the channel limits. Otherwise, nope, youre boned.
367          */
368         if (user->fd < 0)
369         {
370                 ucrec a;
371                 chanrec* c = ForceChan(Ptr,a,user,created);
372                 user->chans.push_back(a);
373                 return c;
374         }
375         else if (strchr(user->modes,'o'))
376         {
377                 /* Oper allows extension up to the OPERMAXCHANS value */
378                 if (user->chans.size() < OPERMAXCHANS)
379                 {
380                         ucrec a;
381                         chanrec* c = ForceChan(Ptr,a,user,created);
382                         user->chans.push_back(a);
383                         return c;
384                 }
385         }
386         log(DEBUG,"add_channel: user channel max exceeded: %s %s",user->nick,cname);
387         WriteServ(user->fd,"405 %s %s :You are on too many channels",user->nick, cname);
388         return NULL;
389 }
390
391 chanrec* ForceChan(chanrec* Ptr,ucrec &a,userrec* user, int created)
392 {
393         if (created == 2)
394         {
395                 /* first user in is given ops */
396                 a.uc_modes = UCMODE_OP;
397         }
398         else
399         {
400                 a.uc_modes = 0;
401         }
402         a.channel = Ptr;
403         Ptr->AddUser((char*)user);
404         WriteChannel(Ptr,user,"JOIN :%s",Ptr->name);
405         log(DEBUG,"Sent JOIN to client");
406         if (Ptr->topicset)
407         {
408                 WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
409                 WriteServ(user->fd,"333 %s %s %s %lu", user->nick, Ptr->name, Ptr->setby, (unsigned long)Ptr->topicset);
410         }
411         userlist(user,Ptr);
412         WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
413         FOREACH_MOD OnUserJoin(user,Ptr);
414         return Ptr;
415 }
416
417 /* remove a channel from a users record, and remove the record from memory
418  * if the channel has become empty */
419
420 chanrec* del_channel(userrec *user, const char* cname, const char* reason, bool local)
421 {
422         if ((!user) || (!cname))
423         {
424                 log(DEFAULT,"*** BUG *** del_channel was given an invalid parameter");
425                 return NULL;
426         }
427
428         chanrec* Ptr = FindChan(cname);
429         
430         if (!Ptr)
431                 return NULL;
432
433         FOREACH_MOD OnUserPart(user,Ptr);
434         log(DEBUG,"del_channel: removing: %s %s",user->nick,Ptr->name);
435         
436         for (unsigned int i =0; i < user->chans.size(); i++)
437         {
438                 /* zap it from the channel list of the user */
439                 if (user->chans[i].channel == Ptr)
440                 {
441                         if (reason)
442                         {
443                                 WriteChannel(Ptr,user,"PART %s :%s",Ptr->name, reason);
444                         }
445                         else
446                         {
447                                 WriteChannel(Ptr,user,"PART :%s",Ptr->name);
448                         }
449                         user->chans[i].uc_modes = 0;
450                         user->chans[i].channel = NULL;
451                         log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
452                         break;
453                 }
454         }
455
456         Ptr->DelUser((char*)user);
457         
458         /* if there are no users left on the channel */
459         if (!usercount(Ptr))
460         {
461                 chan_hash::iterator iter = chanlist.find(Ptr->name);
462
463                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
464
465                 /* kill the record */
466                 if (iter != chanlist.end())
467                 {
468                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
469                         delete Ptr;
470                         chanlist.erase(iter);
471                 }
472         }
473
474         return NULL;
475 }
476
477
478 void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
479 {
480         if ((!src) || (!user) || (!Ptr) || (!reason))
481         {
482                 log(DEFAULT,"*** BUG *** kick_channel was given an invalid parameter");
483                 return;
484         }
485
486         if ((!Ptr) || (!user) || (!src))
487         {
488                 return;
489         }
490
491         log(DEBUG,"kick_channel: removing: %s %s %s",user->nick,Ptr->name,src->nick);
492
493         if (!has_channel(user,Ptr))
494         {
495                 WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name);
496                 return;
497         }
498
499         int MOD_RESULT = 0;
500         FOREACH_RESULT(OnAccessCheck(src,user,Ptr,AC_KICK));
501         if ((MOD_RESULT == ACR_DENY) && (!is_uline(src->server)))
502                 return;
503
504         if ((MOD_RESULT == ACR_DEFAULT) || (!is_uline(src->server)))
505         {
506                 if ((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr)))
507                 {
508                         if (cstatus(src,Ptr) == STATUS_HOP)
509                         {
510                                 WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name);
511                         }
512                         else
513                         {
514                                 WriteServ(src->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",src->nick, Ptr->name);
515                         }
516                         
517                         return;
518                 }
519         }
520
521         if (!is_uline(src->server))
522         {
523                 MOD_RESULT = 0;
524                 FOREACH_RESULT(OnUserPreKick(src,user,Ptr,reason));
525                 if (MOD_RESULT)
526                         return;
527         }
528
529         FOREACH_MOD OnUserKick(src,user,Ptr,reason);
530
531         for (unsigned int i =0; i < user->chans.size(); i++)
532         {
533                 /* zap it from the channel list of the user */
534                 if (user->chans[i].channel)
535                 if (!strcasecmp(user->chans[i].channel->name,Ptr->name))
536                 {
537                         WriteChannel(Ptr,src,"KICK %s %s :%s",Ptr->name, user->nick, reason);
538                         user->chans[i].uc_modes = 0;
539                         user->chans[i].channel = NULL;
540                         log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
541                         break;
542                 }
543         }
544
545         Ptr->DelUser((char*)user);
546
547         /* if there are no users left on the channel */
548         if (!usercount(Ptr))
549         {
550                 chan_hash::iterator iter = chanlist.find(Ptr->name);
551
552                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
553
554                 /* kill the record */
555                 if (iter != chanlist.end())
556                 {
557                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
558                         delete Ptr;
559                         chanlist.erase(iter);
560                 }
561         }
562 }
563
564
565
566
567 /* This function pokes and hacks at a parameter list like the following:
568  *
569  * PART #winbot,#darkgalaxy :m00!
570  *
571  * to turn it into a series of individual calls like this:
572  *
573  * PART #winbot :m00!
574  * PART #darkgalaxy :m00!
575  *
576  * The seperate calls are sent to a callback function provided by the caller
577  * (the caller will usually call itself recursively). The callback function
578  * must be a command handler. Calling this function on a line with no list causes
579  * no action to be taken. You must provide a starting and ending parameter number
580  * where the range of the list can be found, useful if you have a terminating
581  * parameter as above which is actually not part of the list, or parameters
582  * before the actual list as well. This code is used by many functions which
583  * can function as "one to list" (see the RFC) */
584
585 int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins)
586 {
587         char plist[MAXBUF];
588         char *param;
589         char *pars[32];
590         char blog[32][MAXBUF];
591         char blog2[32][MAXBUF];
592         int j = 0, q = 0, total = 0, t = 0, t2 = 0, total2 = 0;
593         char keystr[MAXBUF];
594         char moo[MAXBUF];
595
596         for (int i = 0; i <32; i++)
597                 strcpy(blog[i],"");
598
599         for (int i = 0; i <32; i++)
600                 strcpy(blog2[i],"");
601
602         strcpy(moo,"");
603         for (int i = 0; i <10; i++)
604         {
605                 if (!parameters[i])
606                 {
607                         parameters[i] = moo;
608                 }
609         }
610         if (joins)
611         {
612                 if (pcnt > 1) /* we have a key to copy */
613                 {
614                         strlcpy(keystr,parameters[1],MAXBUF);
615                 }
616         }
617
618         if (!parameters[start])
619         {
620                 return 0;
621         }
622         if (!strchr(parameters[start],','))
623         {
624                 return 0;
625         }
626         strcpy(plist,"");
627         for (int i = start; i <= end; i++)
628         {
629                 if (parameters[i])
630                 {
631                         strlcat(plist,parameters[i],MAXBUF);
632                 }
633         }
634         
635         j = 0;
636         param = plist;
637
638         t = strlen(plist);
639         for (int i = 0; i < t; i++)
640         {
641                 if (plist[i] == ',')
642                 {
643                         plist[i] = '\0';
644                         strlcpy(blog[j++],param,MAXBUF);
645                         param = plist+i+1;
646                         if (j>20)
647                         {
648                                 WriteServ(u->fd,"407 %s %s :Too many targets in list, message not delivered.",u->nick,blog[j-1]);
649                                 return 1;
650                         }
651                 }
652         }
653         strlcpy(blog[j++],param,MAXBUF);
654         total = j;
655
656         if ((joins) && (keystr) && (total>0)) // more than one channel and is joining
657         {
658                 strcat(keystr,",");
659         }
660         
661         if ((joins) && (keystr))
662         {
663                 if (strchr(keystr,','))
664                 {
665                         j = 0;
666                         param = keystr;
667                         t2 = strlen(keystr);
668                         for (int i = 0; i < t2; i++)
669                         {
670                                 if (keystr[i] == ',')
671                                 {
672                                         keystr[i] = '\0';
673                                         strlcpy(blog2[j++],param,MAXBUF);
674                                         param = keystr+i+1;
675                                 }
676                         }
677                         strlcpy(blog2[j++],param,MAXBUF);
678                         total2 = j;
679                 }
680         }
681
682         for (j = 0; j < total; j++)
683         {
684                 if (blog[j])
685                 {
686                         pars[0] = blog[j];
687                 }
688                 for (q = end; q < pcnt-1; q++)
689                 {
690                         if (parameters[q+1])
691                         {
692                                 pars[q-end+1] = parameters[q+1];
693                         }
694                 }
695                 if ((joins) && (parameters[1]))
696                 {
697                         if (pcnt > 1)
698                         {
699                                 pars[1] = blog2[j];
700                         }
701                         else
702                         {
703                                 pars[1] = NULL;
704                         }
705                 }
706                 /* repeatedly call the function with the hacked parameter list */
707                 if ((joins) && (pcnt > 1))
708                 {
709                         if (pars[1])
710                         {
711                                 // pars[1] already set up and containing key from blog2[j]
712                                 fn(pars,2,u);
713                         }
714                         else
715                         {
716                                 pars[1] = parameters[1];
717                                 fn(pars,2,u);
718                         }
719                 }
720                 else
721                 {
722                         fn(pars,pcnt-(end-start),u);
723                 }
724         }
725
726         return 1;
727 }
728
729
730
731 void kill_link(userrec *user,const char* r)
732 {
733         user_hash::iterator iter = clientlist.find(user->nick);
734         
735         char reason[MAXBUF];
736         
737         strncpy(reason,r,MAXBUF);
738
739         if (strlen(reason)>MAXQUIT)
740         {
741                 reason[MAXQUIT-1] = '\0';
742         }
743
744         log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
745         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
746         log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
747
748         if (user->registered == 7) {
749                 FOREACH_MOD OnUserQuit(user,reason);
750                 WriteCommonExcept(user,"QUIT :%s",reason);
751         }
752
753         user->FlushWriteBuf();
754
755         FOREACH_MOD OnUserDisconnect(user);
756
757         if (user->fd > -1)
758         {
759                 FOREACH_MOD OnRawSocketClose(user->fd);
760                 SE->DelFd(user->fd);
761                 user->CloseSocket();
762         }
763
764         // this must come before the WriteOpers so that it doesnt try to fill their buffer with anything
765         // if they were an oper with +s.
766         if (user->registered == 7) {
767                 purge_empty_chans(user);
768                 // fix by brain: only show local quits because we only show local connects (it just makes SENSE)
769                 if (user->fd > -1)
770                         WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
771                 AddWhoWas(user);
772         }
773
774         if (iter != clientlist.end())
775         {
776                 log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
777                 if (user->fd > -1)
778                         fd_ref_table[user->fd] = NULL;
779                 clientlist.erase(iter);
780         }
781         delete user;
782 }
783
784 void kill_link_silent(userrec *user,const char* r)
785 {
786         user_hash::iterator iter = clientlist.find(user->nick);
787         
788         char reason[MAXBUF];
789         
790         strncpy(reason,r,MAXBUF);
791
792         if (strlen(reason)>MAXQUIT)
793         {
794                 reason[MAXQUIT-1] = '\0';
795         }
796
797         log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
798         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
799         log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
800
801         user->FlushWriteBuf();
802
803         if (user->registered == 7) {
804                 FOREACH_MOD OnUserQuit(user,reason);
805                 WriteCommonExcept(user,"QUIT :%s",reason);
806         }
807
808         FOREACH_MOD OnUserDisconnect(user);
809
810         if (user->fd > -1)
811         {
812                 FOREACH_MOD OnRawSocketClose(user->fd);
813                 SE->DelFd(user->fd);
814                 user->CloseSocket();
815         }
816
817         if (user->registered == 7) {
818                 purge_empty_chans(user);
819         }
820         
821         if (iter != clientlist.end())
822         {
823                 log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
824                 if (user->fd > -1)
825                         fd_ref_table[user->fd] = NULL;
826                 clientlist.erase(iter);
827         }
828         delete user;
829 }
830
831
832 int main(int argc, char** argv)
833 {
834         Start();
835         srand(time(NULL));
836         log(DEBUG,"*** InspIRCd starting up!");
837         if (!FileExists(CONFIG_FILE))
838         {
839                 printf("ERROR: Cannot open config file: %s\nExiting...\n",CONFIG_FILE);
840                 log(DEFAULT,"main: no config");
841                 printf("ERROR: Your config file is missing, this IRCd will self destruct in 10 seconds!\n");
842                 Exit(ERROR);
843         }
844         if (argc > 1) {
845                 for (int i = 1; i < argc; i++)
846                 {
847                         if (!strcmp(argv[i],"-nofork")) {
848                                 Config->nofork = true;
849                         }
850                         if (!strcmp(argv[i],"-wait")) {
851                                 sleep(6);
852                         }
853                         if (!strcmp(argv[i],"-nolimit")) {
854                                 Config->unlimitcore = true;
855                         }
856                 }
857         }
858
859         strlcpy(Config->MyExecutable,argv[0],MAXBUF);
860         
861         // initialize the lowercase mapping table
862         for (unsigned int cn = 0; cn < 256; cn++)
863                 lowermap[cn] = cn;
864         // lowercase the uppercase chars
865         for (unsigned int cn = 65; cn < 91; cn++)
866                 lowermap[cn] = tolower(cn);
867         // now replace the specific chars for scandanavian comparison
868         lowermap[(unsigned)'['] = '{';
869         lowermap[(unsigned)']'] = '}';
870         lowermap[(unsigned)'\\'] = '|';
871
872         if (InspIRCd(argv,argc) == ERROR)
873         {
874                 log(DEFAULT,"main: daemon function bailed");
875                 printf("ERROR: could not initialise. Shutting down.\n");
876                 Exit(ERROR);
877         }
878         Exit(TRUE);
879         return 0;
880 }
881
882 template<typename T> inline string ConvToStr(const T &in)
883 {
884         stringstream tmp;
885         if (!(tmp << in)) return string();
886         return tmp.str();
887 }
888
889 /* re-allocates a nick in the user_hash after they change nicknames,
890  * returns a pointer to the new user as it may have moved */
891
892 userrec* ReHashNick(char* Old, char* New)
893 {
894         //user_hash::iterator newnick;
895         user_hash::iterator oldnick = clientlist.find(Old);
896
897         log(DEBUG,"ReHashNick: %s %s",Old,New);
898         
899         if (!strcasecmp(Old,New))
900         {
901                 log(DEBUG,"old nick is new nick, skipping");
902                 return oldnick->second;
903         }
904         
905         if (oldnick == clientlist.end()) return NULL; /* doesnt exist */
906
907         log(DEBUG,"ReHashNick: Found hashed nick %s",Old);
908
909         userrec* olduser = oldnick->second;
910         clientlist[New] = olduser;
911         clientlist.erase(oldnick);
912
913         log(DEBUG,"ReHashNick: Nick rehashed as %s",New);
914         
915         return clientlist[New];
916 }
917
918 /* adds or updates an entry in the whowas list */
919 void AddWhoWas(userrec* u)
920 {
921         whowas_hash::iterator iter = whowas.find(u->nick);
922         WhoWasUser *a = new WhoWasUser();
923         strlcpy(a->nick,u->nick,NICKMAX);
924         strlcpy(a->ident,u->ident,IDENTMAX);
925         strlcpy(a->dhost,u->dhost,160);
926         strlcpy(a->host,u->host,160);
927         strlcpy(a->fullname,u->fullname,MAXGECOS);
928         strlcpy(a->server,u->server,256);
929         a->signon = u->signon;
930
931         /* MAX_WHOWAS:   max number of /WHOWAS items
932          * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
933          *               can be replaced by a newer one
934          */
935         
936         if (iter == whowas.end())
937         {
938                 if (whowas.size() >= (unsigned)WHOWAS_MAX)
939                 {
940                         for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
941                         {
942                                 // 3600 seconds in an hour ;)
943                                 if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600)))
944                                 {
945                                         // delete the old one
946                                         if (i->second) delete i->second;
947                                         // replace with new one
948                                         i->second = a;
949                                         log(DEBUG,"added WHOWAS entry, purged an old record");
950                                         return;
951                                 }
952                         }
953                         // no space left and user doesnt exist. Don't leave ram in use!
954                         log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram");
955                         delete a;
956                 }
957                 else
958                 {
959                         log(DEBUG,"added fresh WHOWAS entry");
960                         whowas[a->nick] = a;
961                 }
962         }
963         else
964         {
965                 log(DEBUG,"updated WHOWAS entry");
966                 if (iter->second) delete iter->second;
967                 iter->second = a;
968         }
969 }
970
971 #ifdef THREADED_DNS
972 void* dns_task(void* arg)
973 {
974         userrec* u = (userrec*)arg;
975         log(DEBUG,"DNS thread for user %s",u->nick);
976         DNS dns1;
977         DNS dns2;
978         std::string host;
979         std::string ip;
980         if (dns1.ReverseLookup(u->ip))
981         {
982                 log(DEBUG,"DNS Step 1");
983                 while (!dns1.HasResult())
984                 {
985                         usleep(100);
986                 }
987                 host = dns1.GetResult();
988                 if (host != "")
989                 {
990                         log(DEBUG,"DNS Step 2: '%s'",host.c_str());
991                         if (dns2.ForwardLookup(host))
992                         {
993                                 while (!dns2.HasResult())
994                                 {
995                                         usleep(100);
996                                 }
997                                 ip = dns2.GetResultIP();
998                                 log(DEBUG,"DNS Step 3 '%s'(%d) '%s'(%d)",ip.c_str(),ip.length(),u->ip,strlen(u->ip));
999                                 if (ip == std::string(u->ip))
1000                                 {
1001                                         log(DEBUG,"DNS Step 4");
1002                                         if (host.length() < 160)
1003                                         {
1004                                                 log(DEBUG,"DNS Step 5");
1005                                                 strcpy(u->host,host.c_str());
1006                                                 strcpy(u->dhost,host.c_str());
1007                                         }
1008                                 }
1009                         }
1010                 }
1011         }
1012         u->dns_done = true;
1013         return NULL;
1014 }
1015 #endif
1016
1017 /* add a client connection to the sockets list */
1018 void AddClient(int socket, char* host, int port, bool iscached, char* ip)
1019 {
1020         string tempnick;
1021         char tn2[MAXBUF];
1022         user_hash::iterator iter;
1023
1024         tempnick = ConvToStr(socket) + "-unknown";
1025         sprintf(tn2,"%lu-unknown",(unsigned long)socket);
1026
1027         iter = clientlist.find(tempnick);
1028
1029         // fix by brain.
1030         // as these nicknames are 'RFC impossible', we can be sure nobody is going to be
1031         // using one as a registered connection. As theyre per fd, we can also safely assume
1032         // that we wont have collisions. Therefore, if the nick exists in the list, its only
1033         // used by a dead socket, erase the iterator so that the new client may reclaim it.
1034         // this was probably the cause of 'server ignores me when i hammer it with reconnects'
1035         // issue in earlier alphas/betas
1036         if (iter != clientlist.end())
1037         {
1038                 userrec* goner = iter->second;
1039                 delete goner;
1040                 clientlist.erase(iter);
1041         }
1042
1043         /*
1044          * It is OK to access the value here this way since we know
1045          * it exists, we just created it above.
1046          *
1047          * At NO other time should you access a value in a map or a
1048          * hash_map this way.
1049          */
1050         clientlist[tempnick] = new userrec();
1051
1052         NonBlocking(socket);
1053         log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip);
1054
1055         clientlist[tempnick]->fd = socket;
1056         strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX);
1057         strlcpy(clientlist[tempnick]->host, host,160);
1058         strlcpy(clientlist[tempnick]->dhost, host,160);
1059         clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName);
1060         strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX);
1061         clientlist[tempnick]->registered = 0;
1062         clientlist[tempnick]->signon = TIME + Config->dns_timeout;
1063         clientlist[tempnick]->lastping = 1;
1064         clientlist[tempnick]->port = port;
1065         strlcpy(clientlist[tempnick]->ip,ip,16);
1066
1067         // set the registration timeout for this user
1068         unsigned long class_regtimeout = 90;
1069         int class_flood = 0;
1070         long class_threshold = 5;
1071         long class_sqmax = 262144;      // 256kb
1072         long class_rqmax = 4096;        // 4k
1073
1074         for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
1075         {
1076                 if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW))
1077                 {
1078                         class_regtimeout = (unsigned long)i->registration_timeout;
1079                         class_flood = i->flood;
1080                         clientlist[tempnick]->pingmax = i->pingtime;
1081                         class_threshold = i->threshold;
1082                         class_sqmax = i->sendqmax;
1083                         class_rqmax = i->recvqmax;
1084                         break;
1085                 }
1086         }
1087
1088         clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax + Config->dns_timeout;
1089         clientlist[tempnick]->timeout = TIME+class_regtimeout;
1090         clientlist[tempnick]->flood = class_flood;
1091         clientlist[tempnick]->threshold = class_threshold;
1092         clientlist[tempnick]->sendqmax = class_sqmax;
1093         clientlist[tempnick]->recvqmax = class_rqmax;
1094
1095         ucrec a;
1096         a.channel = NULL;
1097         a.uc_modes = 0;
1098         for (int i = 0; i < MAXCHANS; i++)
1099                 clientlist[tempnick]->chans.push_back(a);
1100
1101         if (clientlist.size() > Config->SoftLimit)
1102         {
1103                 kill_link(clientlist[tempnick],"No more connections allowed");
1104                 return;
1105         }
1106
1107         if (clientlist.size() >= MAXCLIENTS)
1108         {
1109                 kill_link(clientlist[tempnick],"No more connections allowed");
1110                 return;
1111         }
1112
1113         // this is done as a safety check to keep the file descriptors within range of fd_ref_table.
1114         // its a pretty big but for the moment valid assumption:
1115         // file descriptors are handed out starting at 0, and are recycled as theyre freed.
1116         // therefore if there is ever an fd over 65535, 65536 clients must be connected to the
1117         // irc server at once (or the irc server otherwise initiating this many connections, files etc)
1118         // which for the time being is a physical impossibility (even the largest networks dont have more
1119         // than about 10,000 users on ONE server!)
1120         if ((unsigned)socket > 65534)
1121         {
1122                 kill_link(clientlist[tempnick],"Server is full");
1123                 return;
1124         }
1125                 
1126
1127         char* e = matches_exception(ip);
1128         if (!e)
1129         {
1130                 char* r = matches_zline(ip);
1131                 if (r)
1132                 {
1133                         char reason[MAXBUF];
1134                         snprintf(reason,MAXBUF,"Z-Lined: %s",r);
1135                         kill_link(clientlist[tempnick],reason);
1136                         return;
1137                 }
1138         }
1139         fd_ref_table[socket] = clientlist[tempnick];
1140         SE->AddFd(socket,true,X_ESTAB_CLIENT);
1141 }
1142
1143 /* shows the message of the day, and any other on-logon stuff */
1144 void FullConnectUser(userrec* user)
1145 {
1146         stats->statsConnects++;
1147         user->idle_lastmsg = TIME;
1148         log(DEBUG,"ConnectUser: %s",user->nick);
1149
1150         if ((strcmp(Passwd(user),"")) && (!user->haspassed))
1151         {
1152                 kill_link(user,"Invalid password");
1153                 return;
1154         }
1155         if (IsDenied(user))
1156         {
1157                 kill_link(user,"Unauthorised connection");
1158                 return;
1159         }
1160
1161         char match_against[MAXBUF];
1162         snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host);
1163         char* e = matches_exception(match_against);
1164         if (!e)
1165         {
1166                 char* r = matches_gline(match_against);
1167                 if (r)
1168                 {
1169                         char reason[MAXBUF];
1170                         snprintf(reason,MAXBUF,"G-Lined: %s",r);
1171                         kill_link_silent(user,reason);
1172                         return;
1173                 }
1174                 r = matches_kline(user->host);
1175                 if (r)
1176                 {
1177                         char reason[MAXBUF];
1178                         snprintf(reason,MAXBUF,"K-Lined: %s",r);
1179                         kill_link_silent(user,reason);
1180                         return;
1181                 }
1182         }
1183
1184
1185         WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Config->Network);
1186         WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Config->Network,user->nick,user->ident,user->host);
1187         WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,Config->ServerName,VERSION);
1188         WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
1189         WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,Config->ServerName,VERSION);
1190         // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...
1191         std::stringstream v;
1192         v << "WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS;
1193         v << " MAXBANS=60 NICKLEN=" << NICKMAX;
1194         v << " TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=20 AWAYLEN=" << MAXAWAY << " CHANMODES=ohvb,k,l,psmnti NETWORK=";
1195         v << Config->Network;
1196         std::string data005 = v.str();
1197         FOREACH_MOD On005Numeric(data005);
1198         // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line...
1199         // so i'd better split it :)
1200         std::stringstream out(data005);
1201         std::string token = "";
1202         std::string line5 = "";
1203         int token_counter = 0;
1204         while (!out.eof())
1205         {
1206                 out >> token;
1207                 line5 = line5 + token + " ";
1208                 token_counter++;
1209                 if ((token_counter >= 13) || (out.eof() == true))
1210                 {
1211                         WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str());
1212                         line5 = "";
1213                         token_counter = 0;
1214                 }
1215         }
1216         ShowMOTD(user);
1217
1218         // fix 3 by brain, move registered = 7 below these so that spurious modes and host changes dont go out
1219         // onto the network and produce 'fake direction'
1220         FOREACH_MOD OnUserConnect(user);
1221         FOREACH_MOD OnGlobalConnect(user);
1222         user->registered = 7;
1223         WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip);
1224 }
1225
1226
1227 /* shows the message of the day, and any other on-logon stuff */
1228 void ConnectUser(userrec *user)
1229 {
1230         // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on
1231         if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user)))
1232         {
1233                 FullConnectUser(user);
1234         }
1235 }
1236
1237 std::string GetVersionString()
1238 {
1239         char versiondata[MAXBUF];
1240 #ifdef THREADED_DNS
1241         char dnsengine[] = "multithread";
1242 #else
1243         char dnsengine[] = "singlethread";
1244 #endif
1245         snprintf(versiondata,MAXBUF,"%s Rev. %s %s :%s [FLAGS=%lu,%s,%s]",VERSION,GetRevision().c_str(),Config->ServerName,SYSTEM,(unsigned long)OPTIMISATION,SE->GetName().c_str(),dnsengine);
1246         return versiondata;
1247 }
1248
1249 void handle_version(char **parameters, int pcnt, userrec *user)
1250 {
1251         WriteServ(user->fd,"351 %s :%s",user->nick,GetVersionString().c_str());
1252 }
1253
1254
1255 bool is_valid_cmd(const char* commandname, int pcnt, userrec * user)
1256 {
1257         for (unsigned int i = 0; i < cmdlist.size(); i++)
1258         {
1259                 if (!strcasecmp(cmdlist[i].command,commandname))
1260                 {
1261                         if (cmdlist[i].handler_function)
1262                         {
1263                                 if ((pcnt>=cmdlist[i].min_params) && (strcasecmp(cmdlist[i].source,"<core>")))
1264                                 {
1265                                         if ((strchr(user->modes,cmdlist[i].flags_needed)) || (!cmdlist[i].flags_needed))
1266                                         {
1267                                                 if (cmdlist[i].flags_needed)
1268                                                 {
1269                                                         if ((user->HasPermission((char*)commandname)) || (is_uline(user->server)))
1270                                                         {
1271                                                                 return true;
1272                                                         }
1273                                                         else
1274                                                         {
1275                                                                 return false;
1276                                                         }
1277                                                 }
1278                                                 return true;
1279                                         }
1280                                 }
1281                         }
1282                 }
1283         }
1284         return false;
1285 }
1286
1287 // calls a handler function for a command
1288
1289 void call_handler(const char* commandname,char **parameters, int pcnt, userrec *user)
1290 {
1291         for (unsigned int i = 0; i < cmdlist.size(); i++)
1292         {
1293                 if (!strcasecmp(cmdlist[i].command,commandname))
1294                 {
1295                         if (cmdlist[i].handler_function)
1296                         {
1297                                 if (pcnt>=cmdlist[i].min_params)
1298                                 {
1299                                         if ((strchr(user->modes,cmdlist[i].flags_needed)) || (!cmdlist[i].flags_needed))
1300                                         {
1301                                                 if (cmdlist[i].flags_needed)
1302                                                 {
1303                                                         if ((user->HasPermission((char*)commandname)) || (is_uline(user->server)))
1304                                                         {
1305                                                                 cmdlist[i].handler_function(parameters,pcnt,user);
1306                                                         }
1307                                                 }
1308                                                 else
1309                                                 {
1310                                                         cmdlist[i].handler_function(parameters,pcnt,user);
1311                                                 }
1312                                         }
1313                                 }
1314                         }
1315                 }
1316         }
1317 }
1318
1319
1320 void force_nickchange(userrec* user,const char* newnick)
1321 {
1322         char nick[MAXBUF];
1323         int MOD_RESULT = 0;
1324         
1325         strcpy(nick,"");
1326
1327         FOREACH_RESULT(OnUserPreNick(user,newnick));
1328         if (MOD_RESULT) {
1329                 stats->statsCollisions++;
1330                 kill_link(user,"Nickname collision");
1331                 return;
1332         }
1333         if (matches_qline(newnick))
1334         {
1335                 stats->statsCollisions++;
1336                 kill_link(user,"Nickname collision");
1337                 return;
1338         }
1339         
1340         if (user)
1341         {
1342                 if (newnick)
1343                 {
1344                         strncpy(nick,newnick,MAXBUF);
1345                 }
1346                 if (user->registered == 7)
1347                 {
1348                         char* pars[1];
1349                         pars[0] = nick;
1350                         handle_nick(pars,1,user);
1351                 }
1352         }
1353 }
1354                                 
1355
1356 int process_parameters(char **command_p,char *parameters)
1357 {
1358         int j = 0;
1359         int q = strlen(parameters);
1360         if (!q)
1361         {
1362                 /* no parameters, command_p invalid! */
1363                 return 0;
1364         }
1365         if (parameters[0] == ':')
1366         {
1367                 command_p[0] = parameters+1;
1368                 return 1;
1369         }
1370         if (q)
1371         {
1372                 if ((strchr(parameters,' ')==NULL) || (parameters[0] == ':'))
1373                 {
1374                         /* only one parameter */
1375                         command_p[0] = parameters;
1376                         if (parameters[0] == ':')
1377                         {
1378                                 if (strchr(parameters,' ') != NULL)
1379                                 {
1380                                         command_p[0]++;
1381                                 }
1382                         }
1383                         return 1;
1384                 }
1385         }
1386         command_p[j++] = parameters;
1387         for (int i = 0; i <= q; i++)
1388         {
1389                 if (parameters[i] == ' ')
1390                 {
1391                         command_p[j++] = parameters+i+1;
1392                         parameters[i] = '\0';
1393                         if (command_p[j-1][0] == ':')
1394                         {
1395                                 *command_p[j-1]++; /* remove dodgy ":" */
1396                                 break;
1397                                 /* parameter like this marks end of the sequence */
1398                         }
1399                 }
1400         }
1401         return j; /* returns total number of items in the list */
1402 }
1403
1404 void process_command(userrec *user, char* cmd)
1405 {
1406         char *parameters;
1407         char *command;
1408         char *command_p[127];
1409         char p[MAXBUF], temp[MAXBUF];
1410         int j, items, cmd_found;
1411
1412         for (int i = 0; i < 127; i++)
1413                 command_p[i] = NULL;
1414
1415         if (!user)
1416         {
1417                 return;
1418         }
1419         if (!cmd)
1420         {
1421                 return;
1422         }
1423         if (!cmd[0])
1424         {
1425                 return;
1426         }
1427         
1428         int total_params = 0;
1429         if (strlen(cmd)>2)
1430         {
1431                 for (unsigned int q = 0; q < strlen(cmd)-1; q++)
1432                 {
1433                         if ((cmd[q] == ' ') && (cmd[q+1] == ':'))
1434                         {
1435                                 total_params++;
1436                                 // found a 'trailing', we dont count them after this.
1437                                 break;
1438                         }
1439                         if (cmd[q] == ' ')
1440                                 total_params++;
1441                 }
1442         }
1443
1444         // another phidjit bug...
1445         if (total_params > 126)
1446         {
1447                 *(strchr(cmd,' ')) = '\0';
1448                 WriteServ(user->fd,"421 %s %s :Too many parameters given",user->nick,cmd);
1449                 return;
1450         }
1451
1452         strlcpy(temp,cmd,MAXBUF);
1453         
1454         std::string tmp = cmd;
1455         for (int i = 0; i <= MODCOUNT; i++)
1456         {
1457                 std::string oldtmp = tmp;
1458                 modules[i]->OnServerRaw(tmp,true,user);
1459                 if (oldtmp != tmp)
1460                 {
1461                         log(DEBUG,"A Module changed the input string!");
1462                         log(DEBUG,"New string: %s",tmp.c_str());
1463                         log(DEBUG,"Old string: %s",oldtmp.c_str());
1464                         break;
1465                 }
1466         }
1467         strlcpy(cmd,tmp.c_str(),MAXBUF);
1468         strlcpy(temp,cmd,MAXBUF);
1469
1470         if (!strchr(cmd,' '))
1471         {
1472                 /* no parameters, lets skip the formalities and not chop up
1473                  * the string */
1474                 log(DEBUG,"About to preprocess command with no params");
1475                 items = 0;
1476                 command_p[0] = NULL;
1477                 parameters = NULL;
1478                 for (unsigned int i = 0; i <= strlen(cmd); i++)
1479                 {
1480                         cmd[i] = toupper(cmd[i]);
1481                 }
1482                 command = cmd;
1483         }
1484         else
1485         {
1486                 strcpy(cmd,"");
1487                 j = 0;
1488                 /* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */
1489                 for (unsigned int i = 0; i < strlen(temp); i++)
1490                 {
1491                         if ((temp[i] != 10) && (temp[i] != 13) && (temp[i] != 0) && (temp[i] != 7))
1492                         {
1493                                 cmd[j++] = temp[i];
1494                                 cmd[j] = 0;
1495                         }
1496                 }
1497                 /* split the full string into a command plus parameters */
1498                 parameters = p;
1499                 strcpy(p," ");
1500                 command = cmd;
1501                 if (strchr(cmd,' '))
1502                 {
1503                         for (unsigned int i = 0; i <= strlen(cmd); i++)
1504                         {
1505                                 /* capitalise the command ONLY, leave params intact */
1506                                 cmd[i] = toupper(cmd[i]);
1507                                 /* are we nearly there yet?! :P */
1508                                 if (cmd[i] == ' ')
1509                                 {
1510                                         command = cmd;
1511                                         parameters = cmd+i+1;
1512                                         cmd[i] = '\0';
1513                                         break;
1514                                 }
1515                         }
1516                 }
1517                 else
1518                 {
1519                         for (unsigned int i = 0; i <= strlen(cmd); i++)
1520                         {
1521                                 cmd[i] = toupper(cmd[i]);
1522                         }
1523                 }
1524
1525         }
1526         cmd_found = 0;
1527         
1528         if (strlen(command)>MAXCOMMAND)
1529         {
1530                 WriteServ(user->fd,"421 %s %s :Command too long",user->nick,command);
1531                 return;
1532         }
1533         
1534         for (unsigned int x = 0; x < strlen(command); x++)
1535         {
1536                 if (((command[x] < 'A') || (command[x] > 'Z')) && (command[x] != '.'))
1537                 {
1538                         if (((command[x] < '0') || (command[x]> '9')) && (command[x] != '-'))
1539                         {
1540                                 if (strchr("@!\"$%^&*(){}[]_=+;:'#~,<>/?\\|`",command[x]))
1541                                 {
1542                                         stats->statsUnknown++;
1543                                         WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
1544                                         return;
1545                                 }
1546                         }
1547                 }
1548         }
1549
1550         for (unsigned int i = 0; i != cmdlist.size(); i++)
1551         {
1552                 if (cmdlist[i].command[0])
1553                 {
1554                         if (strlen(command)>=(strlen(cmdlist[i].command))) if (!strncmp(command, cmdlist[i].command,MAXCOMMAND))
1555                         {
1556                                 if (parameters)
1557                                 {
1558                                         if (parameters[0])
1559                                         {
1560                                                 items = process_parameters(command_p,parameters);
1561                                         }
1562                                         else
1563                                         {
1564                                                 items = 0;
1565                                                 command_p[0] = NULL;
1566                                         }
1567                                 }
1568                                 else
1569                                 {
1570                                         items = 0;
1571                                         command_p[0] = NULL;
1572                                 }
1573                                 
1574                                 if (user)
1575                                 {
1576                                         /* activity resets the ping pending timer */
1577                                         user->nping = TIME + user->pingmax;
1578                                         if ((items) < cmdlist[i].min_params)
1579                                         {
1580                                                 log(DEBUG,"process_command: not enough parameters: %s %s",user->nick,command);
1581                                                 WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,command);
1582                                                 return;
1583                                         }
1584                                         if ((!strchr(user->modes,cmdlist[i].flags_needed)) && (cmdlist[i].flags_needed))
1585                                         {
1586                                                 log(DEBUG,"process_command: permission denied: %s %s",user->nick,command);
1587                                                 WriteServ(user->fd,"481 %s :Permission Denied- You do not have the required operator privilages",user->nick);
1588                                                 cmd_found = 1;
1589                                                 return;
1590                                         }
1591                                         if ((cmdlist[i].flags_needed) && (!user->HasPermission(command)))
1592                                         {
1593                                                 log(DEBUG,"process_command: permission denied: %s %s",user->nick,command);
1594                                                 WriteServ(user->fd,"481 %s :Permission Denied- Oper type %s does not have access to command %s",user->nick,user->oper,command);
1595                                                 cmd_found = 1;
1596                                                 return;
1597                                         }
1598                                         /* if the command isnt USER, PASS, or NICK, and nick is empty,
1599                                          * deny command! */
1600                                         if ((strncmp(command,"USER",4)) && (strncmp(command,"NICK",4)) && (strncmp(command,"PASS",4)))
1601                                         {
1602                                                 if ((!isnick(user->nick)) || (user->registered != 7))
1603                                                 {
1604                                                         log(DEBUG,"process_command: not registered: %s %s",user->nick,command);
1605                                                         WriteServ(user->fd,"451 %s :You have not registered",command);
1606                                                         return;
1607                                                 }
1608                                         }
1609                                         if ((user->registered == 7) && (!strchr(user->modes,'o')))
1610                                         {
1611                                                 std::stringstream dcmds(Config->DisabledCommands);
1612                                                 while (!dcmds.eof())
1613                                                 {
1614                                                         std::string thiscmd;
1615                                                         dcmds >> thiscmd;
1616                                                         if (!strcasecmp(thiscmd.c_str(),command))
1617                                                         {
1618                                                                 // command is disabled!
1619                                                                 WriteServ(user->fd,"421 %s %s :This command has been disabled.",user->nick,command);
1620                                                                 return;
1621                                                         }
1622                                                 }
1623                                         }
1624                                         if ((user->registered == 7) || (!strncmp(command,"USER",4)) || (!strncmp(command,"NICK",4)) || (!strncmp(command,"PASS",4)))
1625                                         {
1626                                                 if (cmdlist[i].handler_function)
1627                                                 {
1628                                                         
1629                                                         /* ikky /stats counters */
1630                                                         if (temp)
1631                                                         {
1632                                                                 cmdlist[i].use_count++;
1633                                                                 cmdlist[i].total_bytes+=strlen(temp);
1634                                                         }
1635
1636                                                         int MOD_RESULT = 0;
1637                                                         FOREACH_RESULT(OnPreCommand(command,command_p,items,user));
1638                                                         if (MOD_RESULT == 1) {
1639                                                                 return;
1640                                                         }
1641
1642                                                         /* WARNING: nothing may come after the
1643                                                          * command handler call, as the handler
1644                                                          * may free the user structure! */
1645
1646                                                         cmdlist[i].handler_function(command_p,items,user);
1647                                                 }
1648                                                 return;
1649                                         }
1650                                         else
1651                                         {
1652                                                 WriteServ(user->fd,"451 %s :You have not registered",command);
1653                                                 return;
1654                                         }
1655                                 }
1656                                 cmd_found = 1;
1657                         }
1658                 }
1659         }
1660         if ((!cmd_found) && (user))
1661         {
1662                 stats->statsUnknown++;
1663                 WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
1664         }
1665 }
1666
1667 bool removecommands(const char* source)
1668 {
1669         bool go_again = true;
1670         while (go_again)
1671         {
1672                 go_again = false;
1673                 for (std::deque<command_t>::iterator i = cmdlist.begin(); i != cmdlist.end(); i++)
1674                 {
1675                         if (!strcmp(i->source,source))
1676                         {
1677                                 log(DEBUG,"removecommands(%s) Removing dependent command: %s",i->source,i->command);
1678                                 cmdlist.erase(i);
1679                                 go_again = true;
1680                                 break;
1681                         }
1682                 }
1683         }
1684         return true;
1685 }
1686
1687
1688 void process_buffer(const char* cmdbuf,userrec *user)
1689 {
1690         if (!user)
1691         {
1692                 log(DEFAULT,"*** BUG *** process_buffer was given an invalid parameter");
1693                 return;
1694         }
1695         char cmd[MAXBUF];
1696         if (!cmdbuf)
1697         {
1698                 log(DEFAULT,"*** BUG *** process_buffer was given an invalid parameter");
1699                 return;
1700         }
1701         if (!cmdbuf[0])
1702         {
1703                 return;
1704         }
1705         while (*cmdbuf == ' ') cmdbuf++; // strip leading spaces
1706
1707         strlcpy(cmd,cmdbuf,MAXBUF);
1708         if (!cmd[0])
1709         {
1710                 return;
1711         }
1712         int sl = strlen(cmd)-1;
1713         if ((cmd[sl] == 13) || (cmd[sl] == 10))
1714         {
1715                 cmd[sl] = '\0';
1716         }
1717         sl = strlen(cmd)-1;
1718         if ((cmd[sl] == 13) || (cmd[sl] == 10))
1719         {
1720                 cmd[sl] = '\0';
1721         }
1722         sl = strlen(cmd)-1;
1723         while (cmd[sl] == ' ') // strip trailing spaces
1724         {
1725                 cmd[sl] = '\0';
1726                 sl = strlen(cmd)-1;
1727         }
1728
1729         if (!cmd[0])
1730         {
1731                 return;
1732         }
1733         log(DEBUG,"CMDIN: %s %s",user->nick,cmd);
1734         tidystring(cmd);
1735         if ((user) && (cmd))
1736         {
1737                 process_command(user,cmd);
1738         }
1739 }
1740
1741 char MODERR[MAXBUF];
1742
1743 char* ModuleError()
1744 {
1745         return MODERR;
1746 }
1747
1748 void erase_factory(int j)
1749 {
1750         int v = 0;
1751         for (std::vector<ircd_module*>::iterator t = factory.begin(); t != factory.end(); t++)
1752         {
1753                 if (v == j)
1754                 {
1755                         factory.erase(t);
1756                         factory.push_back(NULL);
1757                         return;
1758                 }
1759                 v++;
1760         }
1761 }
1762
1763 void erase_module(int j)
1764 {
1765         int v1 = 0;
1766         for (std::vector<Module*>::iterator m = modules.begin(); m!= modules.end(); m++)
1767         {
1768                 if (v1 == j)
1769                 {
1770                         delete *m;
1771                         modules.erase(m);
1772                         modules.push_back(NULL);
1773                         break;
1774                 }
1775                 v1++;
1776         }
1777         int v2 = 0;
1778         for (std::vector<std::string>::iterator v = module_names.begin(); v != module_names.end(); v++)
1779         {
1780                 if (v2 == j)
1781                 {
1782                        module_names.erase(v);
1783                        break;
1784                 }
1785                 v2++;
1786         }
1787
1788 }
1789
1790 bool UnloadModule(const char* filename)
1791 {
1792         std::string filename_str = filename;
1793         for (unsigned int j = 0; j != module_names.size(); j++)
1794         {
1795                 if (module_names[j] == filename_str)
1796                 {
1797                         if (modules[j]->GetVersion().Flags & VF_STATIC)
1798                         {
1799                                 log(DEFAULT,"Failed to unload STATIC module %s",filename);
1800                                 snprintf(MODERR,MAXBUF,"Module not unloadable (marked static)");
1801                                 return false;
1802                         }
1803                         /* Give the module a chance to tidy out all its metadata */
1804                         for (chan_hash::iterator c = chanlist.begin(); c != chanlist.end(); c++)
1805                         {
1806                                 modules[j]->OnCleanup(TYPE_CHANNEL,c->second);
1807                         }
1808                         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
1809                         {
1810                                 modules[j]->OnCleanup(TYPE_USER,u->second);
1811                         }
1812                         FOREACH_MOD OnUnloadModule(modules[j],module_names[j]);
1813                         // found the module
1814                         log(DEBUG,"Deleting module...");
1815                         erase_module(j);
1816                         log(DEBUG,"Erasing module entry...");
1817                         erase_factory(j);
1818                         log(DEBUG,"Removing dependent commands...");
1819                         removecommands(filename);
1820                         log(DEFAULT,"Module %s unloaded",filename);
1821                         MODCOUNT--;
1822                         return true;
1823                 }
1824         }
1825         log(DEFAULT,"Module %s is not loaded, cannot unload it!",filename);
1826         snprintf(MODERR,MAXBUF,"Module not loaded");
1827         return false;
1828 }
1829
1830 bool LoadModule(const char* filename)
1831 {
1832         char modfile[MAXBUF];
1833 #ifdef STATIC_LINK
1834         snprintf(modfile,MAXBUF,"%s",filename);
1835 #else
1836         snprintf(modfile,MAXBUF,"%s/%s",Config->ModPath,filename);
1837 #endif
1838         std::string filename_str = filename;
1839 #ifndef STATIC_LINK
1840         if (!DirValid(modfile))
1841         {
1842                 log(DEFAULT,"Module %s is not within the modules directory.",modfile);
1843                 snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile);
1844                 return false;
1845         }
1846 #endif
1847         log(DEBUG,"Loading module: %s",modfile);
1848 #ifndef STATIC_LINK
1849         if (FileExists(modfile))
1850         {
1851 #endif
1852                 for (unsigned int j = 0; j < module_names.size(); j++)
1853                 {
1854                         if (module_names[j] == filename_str)
1855                         {
1856                                 log(DEFAULT,"Module %s is already loaded, cannot load a module twice!",modfile);
1857                                 snprintf(MODERR,MAXBUF,"Module already loaded");
1858                                 return false;
1859                         }
1860                 }
1861                 ircd_module* a = new ircd_module(modfile);
1862                 factory[MODCOUNT+1] = a;
1863                 if (factory[MODCOUNT+1]->LastError())
1864                 {
1865                         log(DEFAULT,"Unable to load %s: %s",modfile,factory[MODCOUNT+1]->LastError());
1866                         snprintf(MODERR,MAXBUF,"Loader/Linker error: %s",factory[MODCOUNT+1]->LastError());
1867                         MODCOUNT--;
1868                         return false;
1869                 }
1870                 if (factory[MODCOUNT+1]->factory)
1871                 {
1872                         Module* m = factory[MODCOUNT+1]->factory->CreateModule(MyServer);
1873                         modules[MODCOUNT+1] = m;
1874                         /* save the module and the module's classfactory, if
1875                          * this isnt done, random crashes can occur :/ */
1876                         module_names.push_back(filename);
1877                 }
1878                 else
1879                 {
1880                         log(DEFAULT,"Unable to load %s",modfile);
1881                         snprintf(MODERR,MAXBUF,"Factory function failed!");
1882                         return false;
1883                 }
1884 #ifndef STATIC_LINK
1885         }
1886         else
1887         {
1888                 log(DEFAULT,"InspIRCd: startup: Module Not Found %s",modfile);
1889                 snprintf(MODERR,MAXBUF,"Module file could not be found");
1890                 return false;
1891         }
1892 #endif
1893         MODCOUNT++;
1894         FOREACH_MOD OnLoadModule(modules[MODCOUNT],filename_str);
1895         return true;
1896 }
1897
1898 int BindPorts()
1899 {
1900         char configToken[MAXBUF], Addr[MAXBUF], Type[MAXBUF];
1901         int clientportcount = 0;
1902         for (int count = 0; count < ConfValueEnum("bind",&Config->config_f); count++)
1903         {
1904                 ConfValue("bind","port",count,configToken,&Config->config_f);
1905                 ConfValue("bind","address",count,Addr,&Config->config_f);
1906                 ConfValue("bind","type",count,Type,&Config->config_f);
1907                 if (strcmp(Type,"servers"))
1908                 {
1909                         // modules handle server bind types now,
1910                         // its not a typo in the strcmp.
1911                         ports[clientportcount] = atoi(configToken);
1912                         strlcpy(Config->addrs[clientportcount],Addr,256);
1913                         clientportcount++;
1914                         log(DEBUG,"InspIRCd: startup: read binding %s:%s [%s] from config",Addr,configToken, Type);
1915                 }
1916         }
1917         portCount = clientportcount;
1918
1919         for (int count = 0; count < portCount; count++)
1920         {
1921                 if ((openSockfd[boundPortCount] = OpenTCPSocket()) == ERROR)
1922                 {
1923                         log(DEBUG,"InspIRCd: startup: bad fd %lu",(unsigned long)openSockfd[boundPortCount]);
1924                         return(ERROR);
1925                 }
1926                 if (BindSocket(openSockfd[boundPortCount],client,server,ports[count],Config->addrs[count]) == ERROR)
1927                 {
1928                         log(DEFAULT,"InspIRCd: startup: failed to bind port %lu",(unsigned long)ports[count]);
1929                 }
1930                 else    /* well we at least bound to one socket so we'll continue */
1931                 {
1932                         boundPortCount++;
1933                 }
1934         }
1935
1936         /* if we didn't bind to anything then abort */
1937         if (!boundPortCount)
1938         {
1939                 log(DEFAULT,"InspIRCd: startup: no ports bound, bailing!");
1940                 printf("\nERROR: Was not able to bind any of %lu ports! Please check your configuration.\n\n", (unsigned long)portCount);
1941                 return (ERROR);
1942         }
1943
1944         return boundPortCount;
1945 }
1946
1947 int InspIRCd(char** argv, int argc)
1948 {
1949         bool expire_run = false;
1950         std::vector<int> activefds;
1951         int incomingSockfd;
1952         int in_port;
1953         userrec* cu = NULL;
1954         InspSocket* s = NULL;
1955         InspSocket* s_del = NULL;
1956         char* target;
1957         unsigned int numberactive;
1958         sockaddr_in sock_us;     // our port number
1959         socklen_t uslen;         // length of our port number
1960
1961         /* Beta 7 moved all this stuff out of the main function
1962          * into smaller sub-functions, much tidier -- Brain
1963          */
1964         OpenLog(argv, argc);
1965         Config->Read(true,NULL);
1966         CheckRoot();
1967         SetupCommandTable();
1968         AddServerName(Config->ServerName);
1969         CheckDie();
1970         boundPortCount = BindPorts();
1971
1972         printf("\n");
1973         startup_time = time(NULL);
1974         
1975         if (!Config->nofork)
1976         {
1977                 if (DaemonSeed() == ERROR)
1978                 {
1979                         printf("ERROR: could not go into daemon mode. Shutting down.\n");
1980                         Exit(ERROR);
1981                 }
1982         }
1983
1984         /* Because of limitations in kqueue on freebsd, we must fork BEFORE we
1985          * initialize the socket engine.
1986          */
1987         SE = new SocketEngine();
1988
1989         /* We must load the modules AFTER initializing the socket engine, now */
1990         LoadAllModules();
1991
1992         printf("\nInspIRCd is now running!\n");
1993         if (!Config->nofork)
1994         {
1995                 freopen("/dev/null","w",stdout);
1996                 freopen("/dev/null","w",stderr);
1997         }
1998
1999         /* Add the listening sockets used for client inbound connections
2000          * to the socket engine
2001          */
2002         for (int count = 0; count < portCount; count++)
2003                 SE->AddFd(openSockfd[count],true,X_LISTEN);
2004
2005         WritePID(Config->PID);
2006
2007         /* main loop, this never returns */
2008         for (;;)
2009         {
2010                 /* time() seems to be a pretty expensive syscall, so avoid calling it too much.
2011                  * Once per loop iteration is pleanty.
2012                  */
2013                 OLDTIME = TIME;
2014                 TIME = time(NULL);
2015
2016                 /* Run background module timers every few seconds
2017                  * (the docs say modules shouldnt rely on accurate
2018                  * timing using this event, so we dont have to
2019                  * time this exactly).
2020                  */
2021                 if (((TIME % 8) == 0) && (!expire_run))
2022                 {
2023                         expire_lines();
2024                         FOREACH_MOD OnBackgroundTimer(TIME);
2025                         expire_run = true;
2026                         continue;
2027                 }
2028                 if ((TIME % 8) == 1)
2029                         expire_run = false;
2030                 
2031                 /* Once a second, do the background processing */
2032                 if (TIME != OLDTIME)
2033                         while (DoBackgroundUserStuff(TIME));
2034
2035                 /* Call the socket engine to wait on the active
2036                  * file descriptors. The socket engine has everything's
2037                  * descriptors in its list... dns, modules, users,
2038                  * servers... so its nice and easy, just one call.
2039                  */
2040                 SE->Wait(activefds);
2041
2042                 /**
2043                  * Now process each of the fd's. For users, we have a fast
2044                  * lookup table which can find a user by file descriptor, so
2045                  * processing them by fd isnt expensive. If we have a lot of
2046                  * listening ports or module sockets though, things could get
2047                  * ugly.
2048                  */
2049                 numberactive = activefds.size();
2050                 for (unsigned int activefd = 0; activefd < numberactive; activefd++)
2051                 {
2052                         int socket_type = SE->GetType(activefds[activefd]);
2053                         switch (socket_type)
2054                         {
2055                                 case X_ESTAB_CLIENT:
2056
2057                                         cu = fd_ref_table[activefds[activefd]];
2058                                         if (cu)
2059                                                 ProcessUser(cu);
2060
2061                                 break;
2062
2063                                 case X_ESTAB_MODULE:
2064
2065                                         /* Process module-owned sockets.
2066                                          * Modules are encouraged to inherit their sockets from
2067                                          * InspSocket so we can process them neatly like this.
2068                                          */
2069                                         s = socket_ref[activefds[activefd]];
2070
2071                                         if ((s) && (!s->Poll()))
2072                                         {
2073                                                 log(DEBUG,"Socket poll returned false, close and bail");
2074                                                 SE->DelFd(s->GetFd());
2075                                                 for (std::vector<InspSocket*>::iterator a = module_sockets.begin(); a < module_sockets.end(); a++)
2076                                                 {
2077                                                         s_del = (InspSocket*)*a;
2078                                                         if ((s_del) && (s_del->GetFd() == activefds[activefd]))
2079                                                         {
2080                                                                 module_sockets.erase(a);
2081                                                                 break;
2082                                                         }
2083                                                 }
2084                                                 s->Close();
2085                                                 delete s;
2086                                         }
2087
2088                                 break;
2089
2090                                 case X_ESTAB_DNS:
2091
2092                                         /* When we are using single-threaded dns,
2093                                          * the sockets for dns end up in our mainloop.
2094                                          * When we are using multi-threaded dns,
2095                                          * each thread has its own basic poll() loop
2096                                          * within it, making them 'fire and forget'
2097                                          * and independent of the mainloop.
2098                                          */
2099 #ifndef THREADED_DNS
2100                                         dns_poll(activefds[activefd]);
2101 #endif
2102                                 break;
2103                                 
2104                                 case X_LISTEN:
2105
2106                                         /* It's a listener */
2107                                         uslen = sizeof(sock_us);
2108                                         length = sizeof(client);
2109                                         incomingSockfd = accept (activefds[activefd],(struct sockaddr*)&client,&length);
2110                                         if (!getsockname(incomingSockfd,(sockaddr*)&sock_us,&uslen))
2111                                         {
2112                                                 in_port = ntohs(sock_us.sin_port);
2113                                                 log(DEBUG,"Accepted socket %d",incomingSockfd);
2114                                                 target = (char*)inet_ntoa(client.sin_addr);
2115                                                 /* Years and years ago, we used to resolve here
2116                                                  * using gethostbyaddr(). That is sucky and we
2117                                                  * don't do that any more...
2118                                                  */
2119                                                 if (incomingSockfd >= 0)
2120                                                 {
2121                                                         FOREACH_MOD OnRawSocketAccept(incomingSockfd, target, in_port);
2122                                                         stats->statsAccept++;
2123                                                         AddClient(incomingSockfd, target, in_port, false, target);
2124                                                         log(DEBUG,"Adding client on port %lu fd=%lu",(unsigned long)in_port,(unsigned long)incomingSockfd);
2125                                                 }
2126                                                 else
2127                                                 {
2128                                                         WriteOpers("*** WARNING: accept() failed on port %lu (%s)",(unsigned long)in_port,target);
2129                                                         log(DEBUG,"accept failed: %lu",(unsigned long)in_port);
2130                                                         stats->statsRefused++;
2131                                                 }
2132                                         }
2133                                         else
2134                                         {
2135                                                 log(DEBUG,"Couldnt look up the port number for fd %lu (OS BROKEN?!)",incomingSockfd);
2136                                                 shutdown(incomingSockfd,2);
2137                                                 close(incomingSockfd);
2138                                         }
2139                                 break;
2140
2141                                 default:
2142                                         /* Something went wrong if we're in here.
2143                                          * In fact, so wrong, im not quite sure
2144                                          * what we would do, so for now, its going
2145                                          * to safely do bugger all.
2146                                          */
2147                                 break;
2148                         }
2149                 }
2150
2151         }
2152         /* This is never reached -- we hope! */
2153         return 0;
2154 }
2155