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