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