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