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