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