]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands.cpp
Full removal of inspircd_util.h
[user/henk/code/inspircd.git] / src / commands.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2004 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 using namespace std;
18
19 #include "inspircd_config.h"
20 #include "inspircd.h"
21 #include "inspircd_io.h"
22 #include <unistd.h>
23 #include <sys/errno.h>
24 #include <sys/ioctl.h>
25 #include <sys/utsname.h>
26 #include <cstdio>
27 #include <time.h>
28 #include <string>
29 #ifdef GCC3
30 #include <ext/hash_map>
31 #else
32 #include <hash_map>
33 #endif
34 #include <map>
35 #include <sstream>
36 #include <vector>
37 #include <deque>
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #ifdef THREADED_DNS
42 #include <pthread.h>
43 #endif
44 #ifndef RUSAGE_SELF
45 #define   RUSAGE_SELF     0
46 #define   RUSAGE_CHILDREN     -1
47 #endif
48 #include "users.h"
49 #include "ctables.h"
50 #include "globals.h"
51 #include "modules.h"
52 #include "dynamic.h"
53 #include "wildcard.h"
54 #include "message.h"
55 #include "commands.h"
56 #include "mode.h"
57 #include "xline.h"
58 #include "inspstring.h"
59 #include "dnsqueue.h"
60 #include "helperfuncs.h"
61 #include "hashcomp.h"
62 #include "socketengine.h"
63 #include "typedefs.h"
64
65 extern SocketEngine* SE;
66 extern ServerConfig* Config;
67 extern InspIRCd* ServerInstance;
68
69 extern int MODCOUNT;
70 extern std::vector<Module*> modules;
71 extern std::vector<ircd_module*> factory;
72 extern time_t TIME;
73
74 const long duration_m = 60;
75 const long duration_h = duration_m * 60;
76 const long duration_d = duration_h * 24;
77 const long duration_w = duration_d * 7;
78 const long duration_y = duration_w * 52;
79
80 extern user_hash clientlist;
81 extern chan_hash chanlist;
82 extern whowas_hash whowas;
83 extern command_table cmdlist;
84
85 extern std::vector<userrec*> all_opers;
86
87 // This table references users by file descriptor.
88 // its an array to make it VERY fast, as all lookups are referenced
89 // by an integer, meaning there is no need for a scan/search operation.
90 extern userrec* fd_ref_table[65536];
91
92 extern serverstats* stats;
93
94 void handle_join(char **parameters, int pcnt, userrec *user)
95 {
96         chanrec* Ptr;
97         
98         if (loop_call(handle_join,parameters,pcnt,user,0,0,1))
99                 return;
100         if (parameters[0][0] == '#')
101         {
102                 Ptr = add_channel(user,parameters[0],parameters[1],false);
103         }
104 }
105
106
107 void handle_part(char **parameters, int pcnt, userrec *user)
108 {
109         if (pcnt > 1)
110         {
111                 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-2,0))
112                         return;
113                 del_channel(user,parameters[0],parameters[1],false);
114         }
115         else
116         {
117                 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-1,0))
118                         return;
119                 del_channel(user,parameters[0],NULL,false);
120         }
121 }
122
123 void handle_commands(char **parameters, int pcnt, userrec *user)
124 {
125         for (unsigned int i = 0; i < cmdlist.size(); i++)
126         {
127                 WriteServ(user->fd,"902 %s :%s %s %d",user->nick,cmdlist[i].command,cmdlist[i].source,cmdlist[i].min_params);
128         }
129         WriteServ(user->fd,"903 %s :End of COMMANDS list",user->nick);
130 }
131
132 void handle_kick(char **parameters, int pcnt, userrec *user)
133 {
134         chanrec* Ptr = FindChan(parameters[0]);
135         userrec* u   = Find(parameters[1]);
136
137         if ((!u) || (!Ptr))
138         {
139                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
140                 return;
141         }
142         
143         if ((!has_channel(user,Ptr)) && (!is_uline(user->server)))
144         {
145                 WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, parameters[0]);
146                 return;
147         }
148         
149         char reason[MAXBUF];
150         
151         if (pcnt > 2)
152         {
153                 strlcpy(reason,parameters[2],MAXBUF);
154                 if (strlen(reason)>MAXKICK)
155                 {
156                         reason[MAXKICK-1] = '\0';
157                 }
158
159                 kick_channel(user,u,Ptr,reason);
160         }
161         else
162         {
163                 strlcpy(reason,user->nick,MAXBUF);
164                 kick_channel(user,u,Ptr,reason);
165         }
166         
167 }
168
169 void handle_loadmodule(char **parameters, int pcnt, userrec *user)
170 {
171         if (ServerInstance->LoadModule(parameters[0]))
172         {
173                 WriteOpers("*** NEW MODULE: %s",parameters[0]);
174                 WriteServ(user->fd,"975 %s %s :Module successfully loaded.",user->nick, parameters[0]);
175         }
176         else
177         {
178                 WriteServ(user->fd,"974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
179         }
180 }
181
182 void handle_unloadmodule(char **parameters, int pcnt, userrec *user)
183 {
184         if (ServerInstance->UnloadModule(parameters[0]))
185         {
186                 WriteOpers("*** MODULE UNLOADED: %s",parameters[0]);
187                 WriteServ(user->fd,"973 %s %s :Module successfully unloaded.",user->nick, parameters[0]);
188         }
189         else
190         {
191                 WriteServ(user->fd,"972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
192         }
193 }
194
195 void handle_die(char **parameters, int pcnt, userrec *user)
196 {
197         log(DEBUG,"die: %s",user->nick);
198         if (!strcmp(parameters[0],Config->diepass))
199         {
200                 WriteOpers("*** DIE command from %s!%s@%s, terminating...",user->nick,user->ident,user->host);
201                 sleep(Config->DieDelay);
202                 Exit(ERROR);
203         }
204         else
205         {
206                 WriteOpers("*** Failed DIE Command from %s!%s@%s.",user->nick,user->ident,user->host);
207         }
208 }
209
210 void handle_restart(char **parameters, int pcnt, userrec *user)
211 {
212         char *argv[32];
213         log(DEFAULT,"Restart: %s",user->nick);
214         if (!strcmp(parameters[0],Config->restartpass))
215         {
216                 WriteOpers("*** RESTART command from %s!%s@%s, restarting server.",user->nick,user->ident,user->host);
217
218                 argv[0] = Config->MyExecutable;
219                 argv[1] = "-wait";
220                 if (Config->nofork)
221                 {
222                         argv[2] = "-nofork";
223                 }
224                 else
225                 {
226                         argv[2] = NULL;
227                 }
228                 argv[3] = NULL;
229                 
230                 // close ALL file descriptors
231                 send_error("Server restarting.");
232                 sleep(1);
233                 for (int i = 0; i < 65536; i++)
234                 {
235                         shutdown(i,2);
236                         close(i);
237                 }
238                 sleep(2);
239                 
240                 execv(Config->MyExecutable,argv);
241
242                 exit(0);
243         }
244         else
245         {
246                 WriteOpers("*** Failed RESTART Command from %s!%s@%s.",user->nick,user->ident,user->host);
247         }
248 }
249
250 void handle_kill(char **parameters, int pcnt, userrec *user)
251 {
252         userrec *u = Find(parameters[0]);
253         char killreason[MAXBUF];
254
255         log(DEBUG,"kill: %s %s",parameters[0],parameters[1]);
256         if (u)
257         {
258                 log(DEBUG,"into kill mechanism");
259                 int MOD_RESULT = 0;
260                 FOREACH_RESULT(OnKill(user,u,parameters[1]));
261                 if (MOD_RESULT) {
262                         log(DEBUG,"A module prevented the kill with result %d",MOD_RESULT);
263                         return;
264                 }
265
266                 if (u->fd < 0)
267                 {
268                         // remote kill
269                         WriteOpers("*** Remote kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
270                         snprintf(killreason,MAXBUF,"[%s] Killed (%s (%s))",Config->ServerName,user->nick,parameters[1]);
271                         WriteCommonExcept(u,"QUIT :%s",killreason);
272
273                         FOREACH_MOD OnRemoteKill(user,u,killreason);
274                         
275                         user_hash::iterator iter = clientlist.find(u->nick);
276                         if (iter != clientlist.end())
277                         {
278                                 log(DEBUG,"deleting user hash value %d",iter->second);
279                                 clientlist.erase(iter);
280                         }
281                         if (u->registered == 7)
282                         {
283                                 purge_empty_chans(u);
284                         }
285                         if (u->fd > -1)
286                                 fd_ref_table[u->fd] = NULL;
287                         delete u;
288                 }
289                 else
290                 {
291                         // local kill
292                         log(DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick, Config->ServerName,user->dhost,user->nick,parameters[1]);
293                         WriteTo(user, u, "KILL %s :%s!%s!%s (%s)", u->nick, Config->ServerName,user->dhost,user->nick,parameters[1]);
294                         WriteOpers("*** Local Kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
295                         snprintf(killreason,MAXBUF,"Killed (%s (%s))",user->nick,parameters[1]);
296                         kill_link(u,killreason);
297                 }
298         }
299         else
300         {
301                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
302         }
303 }
304
305 void handle_summon(char **parameters, int pcnt, userrec *user)
306 {
307         WriteServ(user->fd,"445 %s :SUMMON has been disabled (depreciated command)",user->nick);
308 }
309
310 void handle_users(char **parameters, int pcnt, userrec *user)
311 {
312         WriteServ(user->fd,"445 %s :USERS has been disabled (depreciated command)",user->nick);
313 }
314
315 void handle_pass(char **parameters, int pcnt, userrec *user)
316 {
317         // Check to make sure they havnt registered -- Fix by FCS
318         if (user->registered == 7)
319         {
320                 WriteServ(user->fd,"462 %s :You may not reregister",user->nick);
321                 return;
322         }
323         strlcpy(user->password,parameters[0],MAXBUF);
324         if (!strcasecmp(parameters[0],Passwd(user)))
325         {
326                 user->haspassed = true;
327         }
328 }
329
330 void handle_invite(char **parameters, int pcnt, userrec *user)
331 {
332         if (pcnt == 2)
333         {
334                 userrec* u = Find(parameters[0]);
335                 chanrec* c = FindChan(parameters[1]);
336
337                 if ((!c) || (!u))
338                 {
339                         if (!c)
340                         {
341                                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[1]);
342                         }
343                         else
344                         {
345                                 if (c->binarymodes & CM_INVITEONLY)
346                                 {
347                                         WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
348                                 }
349                         }
350
351                         return;
352                 }
353
354                 if (c->binarymodes & CM_INVITEONLY)
355                 {
356                         if (cstatus(user,c) < STATUS_HOP)
357                         {
358                                 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, c->name);
359                                 return;
360                         }
361                 }
362                 if (has_channel(u,c))
363                 {
364                         WriteServ(user->fd,"443 %s %s %s :Is already on channel %s",user->nick,u->nick,c->name,c->name);
365                         return;
366                 }
367                 if (!has_channel(user,c))
368                 {
369                         WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, c->name);
370                         return;
371                 }
372
373                 int MOD_RESULT = 0;
374                 FOREACH_RESULT(OnUserPreInvite(user,u,c));
375                 if (MOD_RESULT == 1) {
376                         return;
377                 }
378
379                 irc::string xname(c->name);
380                 u->InviteTo(xname);
381                 WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name);
382                 WriteServ(user->fd,"341 %s %s %s",user->nick,u->nick,c->name);
383                 FOREACH_MOD OnUserInvite(user,u,c);
384         }
385         else
386         {
387                 // pinched from ircu - invite with not enough parameters shows channels
388                 // youve been invited to but haven't joined yet.
389                 InvitedList* il = user->GetInviteList();
390                 for (InvitedList::iterator i = il->begin(); i != il->end(); i++)
391                 {
392                         WriteServ(user->fd,"346 %s :%s",user->nick,i->channel.c_str());
393                 }
394                 WriteServ(user->fd,"347 %s :End of INVITE list",user->nick);
395         }
396 }
397
398 void handle_topic(char **parameters, int pcnt, userrec *user)
399 {
400         chanrec* Ptr;
401
402         if (pcnt == 1)
403         {
404                 if (strlen(parameters[0]) <= CHANMAX)
405                 {
406                         Ptr = FindChan(parameters[0]);
407                         if (Ptr)
408                         {
409                                 if (((Ptr) && (!has_channel(user,Ptr))) && (Ptr->binarymodes & CM_SECRET))
410                                 {
411                                         WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, Ptr->name);
412                                         return;
413                                 }
414                                 if (Ptr->topicset)
415                                 {
416                                         WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
417                                         WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
418                                 }
419                                 else
420                                 {
421                                         WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name);
422                                 }
423                         }
424                         else
425                         {
426                                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
427                         }
428                 }
429                 return;
430         }
431         else if (pcnt>1)
432         {
433                 if (strlen(parameters[0]) <= CHANMAX)
434                 {
435                         Ptr = FindChan(parameters[0]);
436                         if (Ptr)
437                         {
438                                 if ((Ptr) && (!has_channel(user,Ptr)))
439                                 {
440                                         WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, Ptr->name);
441                                         return;
442                                 }
443                                 if ((Ptr->binarymodes & CM_TOPICLOCK) && (cstatus(user,Ptr)<STATUS_HOP))
444                                 {
445                                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel", user->nick, Ptr->name);
446                                         return;
447                                 }
448
449                                 char topic[MAXBUF];
450                                 strlcpy(topic,parameters[1],MAXBUF);
451                                 if (strlen(topic)>MAXTOPIC)
452                                 {
453                                         topic[MAXTOPIC] = '\0';
454                                 }
455
456                                 if (user->fd > -1)
457                                 {
458                                         int MOD_RESULT = 0;
459                                         FOREACH_RESULT(OnLocalTopicChange(user,Ptr,topic));
460                                         if (MOD_RESULT)
461                                                 return;
462                                 }
463
464                                 strlcpy(Ptr->topic,topic,MAXTOPIC);
465                                 strlcpy(Ptr->setby,user->nick,NICKMAX);
466                                 Ptr->topicset = TIME;
467                                 WriteChannel(Ptr,user,"TOPIC %s :%s",Ptr->name, Ptr->topic);
468                                 if (user->fd > -1)
469                                 {
470                                         FOREACH_MOD OnPostLocalTopicChange(user,Ptr,topic);
471                                 }
472                         }
473                         else
474                         {
475                                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
476                         }
477                 }
478         }
479 }
480
481 void handle_names(char **parameters, int pcnt, userrec *user)
482 {
483         chanrec* c;
484
485         if (!pcnt)
486         {
487                 WriteServ(user->fd,"366 %s * :End of /NAMES list.",user->nick);
488                 return;
489         }
490
491         if (loop_call(handle_names,parameters,pcnt,user,0,pcnt-1,0))
492                 return;
493         c = FindChan(parameters[0]);
494         if (c)
495         {
496                 if (((c) && (!has_channel(user,c))) && (c->binarymodes & CM_SECRET))
497                 {
498                       WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, c->name);
499                       return;
500                 }
501                 userlist(user,c);
502                 WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, c->name);
503         }
504         else
505         {
506                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
507         }
508 }
509
510 void handle_privmsg(char **parameters, int pcnt, userrec *user)
511 {
512         userrec *dest;
513         chanrec *chan;
514
515         user->idle_lastmsg = TIME;
516         
517         if (loop_call(handle_privmsg,parameters,pcnt,user,0,pcnt-2,0))
518                 return;
519         if (parameters[0][0] == '$')
520         {
521                 // notice to server mask
522                 char* servermask = parameters[0];
523                 servermask++;
524                 if (match(Config->ServerName,servermask))
525                 {
526                         ServerPrivmsgAll("%s",parameters[1]);
527                 }
528                 return;
529         }
530         else if (parameters[0][0] == '#')
531         {
532                 chan = FindChan(parameters[0]);
533                 if (chan)
534                 {
535                         if ((chan->binarymodes & CM_NOEXTERNAL) && (!has_channel(user,chan)))
536                         {
537                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
538                                 return;
539                         }
540                         if ((chan->binarymodes & CM_MODERATED) && (cstatus(user,chan)<STATUS_VOICE))
541                         {
542                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
543                                 return;
544                         }
545                         
546                         int MOD_RESULT = 0;
547
548                         std::string temp = parameters[1];
549                         FOREACH_RESULT(OnUserPreMessage(user,chan,TYPE_CHANNEL,temp));
550                         if (MOD_RESULT) {
551                                 return;
552                         }
553                         parameters[1] = (char*)temp.c_str();
554
555                         if (temp == "")
556                         {
557                                 WriteServ(user->fd,"412 %s No text to send", user->nick);
558                                 return;
559                         }
560                         
561                         ChanExceptSender(chan, user, "PRIVMSG %s :%s", chan->name, parameters[1]);
562                         FOREACH_MOD OnUserMessage(user,chan,TYPE_CHANNEL,parameters[1]);
563                 }
564                 else
565                 {
566                         /* no such nick/channel */
567                         WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
568                 }
569                 return;
570         }
571
572         dest = Find(parameters[0]);
573         if (dest)
574         {
575                 if (strcmp(dest->awaymsg,""))
576                 {
577                         /* auto respond with aweh msg */
578                         WriteServ(user->fd,"301 %s %s :%s",user->nick,dest->nick,dest->awaymsg);
579                 }
580
581                 int MOD_RESULT = 0;
582                 
583                 std::string temp = parameters[1];
584                 FOREACH_RESULT(OnUserPreMessage(user,dest,TYPE_USER,temp));
585                 if (MOD_RESULT) {
586                         return;
587                 }
588                 parameters[1] = (char*)temp.c_str();
589
590                 if (dest->fd > -1)
591                 {
592                         // direct write, same server
593                         WriteTo(user, dest, "PRIVMSG %s :%s", dest->nick, parameters[1]);
594                 }
595
596                 FOREACH_MOD OnUserMessage(user,dest,TYPE_USER,parameters[1]);
597         }
598         else
599         {
600                 /* no such nick/channel */
601                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
602         }
603 }
604
605 void handle_notice(char **parameters, int pcnt, userrec *user)
606 {
607         userrec *dest;
608         chanrec *chan;
609
610         user->idle_lastmsg = TIME;
611         
612         if (loop_call(handle_notice,parameters,pcnt,user,0,pcnt-2,0))
613                 return;
614         if (parameters[0][0] == '$')
615         {
616                 // notice to server mask
617                 char* servermask = parameters[0];
618                 servermask++;
619                 if (match(Config->ServerName,servermask))
620                 {
621                         NoticeAll(user, true, "%s",parameters[1]);
622                 }
623                 return;
624         }
625         else if (parameters[0][0] == '#')
626         {
627                 chan = FindChan(parameters[0]);
628                 if (chan)
629                 {
630                         if ((chan->binarymodes & CM_NOEXTERNAL) && (!has_channel(user,chan)))
631                         {
632                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
633                                 return;
634                         }
635                         if ((chan->binarymodes & CM_MODERATED) && (cstatus(user,chan)<STATUS_VOICE))
636                         {
637                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
638                                 return;
639                         }
640
641                         int MOD_RESULT = 0;
642
643                         std::string temp = parameters[1];
644                         FOREACH_RESULT(OnUserPreNotice(user,chan,TYPE_CHANNEL,temp));
645                         if (MOD_RESULT) {
646                                 return;
647                         }
648                         parameters[1] = (char*)temp.c_str();
649
650                         if (temp == "")
651                         {
652                                 WriteServ(user->fd,"412 %s No text to send", user->nick);
653                                 return;
654                         }
655
656                         ChanExceptSender(chan, user, "NOTICE %s :%s", chan->name, parameters[1]);
657
658                         FOREACH_MOD OnUserNotice(user,chan,TYPE_CHANNEL,parameters[1]);
659                 }
660                 else
661                 {
662                         /* no such nick/channel */
663                         WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
664                 }
665                 return;
666         }
667         
668         dest = Find(parameters[0]);
669         if (dest)
670         {
671                 int MOD_RESULT = 0;
672                 
673                 std::string temp = parameters[1];
674                 FOREACH_RESULT(OnUserPreNotice(user,dest,TYPE_USER,temp));
675                 if (MOD_RESULT) {
676                         return;
677                 }
678                 parameters[1] = (char*)temp.c_str();
679
680                 if (dest->fd > -1)
681                 {
682                         // direct write, same server
683                         WriteTo(user, dest, "NOTICE %s :%s", dest->nick, parameters[1]);
684                 }
685
686                 FOREACH_MOD OnUserNotice(user,dest,TYPE_USER,parameters[1]);
687         }
688         else
689         {
690                 /* no such nick/channel */
691                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
692         }
693 }
694
695 void handle_server(char **parameters, int pcnt, userrec *user)
696 {
697         WriteServ(user->fd,"666 %s :You cannot identify as a server, you are a USER. IRC Operators informed.",user->nick);
698         WriteOpers("*** WARNING: %s attempted to issue a SERVER command and is registered as a user!",user->nick);
699 }
700
701 void handle_info(char **parameters, int pcnt, userrec *user)
702 {
703         WriteServ(user->fd,"371 %s :. o O (The Inspire Internet Relay Chat Server) O o .",user->nick);
704         WriteServ(user->fd,"371 %s : ",user->nick);
705         WriteServ(user->fd,"371 %s :Core developers: Craig Edwards (Brain)",user->nick);
706         WriteServ(user->fd,"371 %s :                 Craig McLure",user->nick);
707         WriteServ(user->fd,"371 %s : ",user->nick);
708         WriteServ(user->fd,"371 %s :Contributors:    typobox43",user->nick);
709         WriteServ(user->fd,"371 %s :                 w00t",user->nick);
710         WriteServ(user->fd,"371 %s :                 Om",user->nick);
711         WriteServ(user->fd,"371 %s :                 Jazza",user->nick);
712         WriteServ(user->fd,"371 %s : ",user->nick);
713         WriteServ(user->fd,"371 %s :Testers:         CC",user->nick);
714         WriteServ(user->fd,"371 %s :                 Om",user->nick);
715         WriteServ(user->fd,"371 %s :                 Piggles",user->nick);
716         WriteServ(user->fd,"371 %s :                 Foamy",user->nick);
717         WriteServ(user->fd,"371 %s :                 Hart",user->nick);
718         WriteServ(user->fd,"371 %s :                 RageD",user->nick);
719         WriteServ(user->fd,"371 %s :                 [ed]",user->nick);
720         WriteServ(user->fd,"371 %s :                 Azhrarn",user->nick);
721         WriteServ(user->fd,"371 %s :                 nenolod",user->nick);
722         WriteServ(user->fd,"371 %s :                 luigiman",user->nick);
723         WriteServ(user->fd,"371 %s :                 Chu",user->nick);
724         WriteServ(user->fd,"371 %s :                 aquanight",user->nick);
725         WriteServ(user->fd,"371 %s :                 xptek",user->nick);
726         WriteServ(user->fd,"371 %s :                 Grantlinks",user->nick);
727         WriteServ(user->fd,"371 %s :                 Rob",user->nick);
728         WriteServ(user->fd,"371 %s :                 angelic",user->nick);
729         WriteServ(user->fd,"371 %s :                 Jason",user->nick);
730         WriteServ(user->fd,"371 %s :                 ThaPrince",user->nick);
731         WriteServ(user->fd,"371 %s : ",user->nick);
732         WriteServ(user->fd,"371 %s :Thanks to irc-junkie and searchirc",user->nick);
733         WriteServ(user->fd,"371 %s :for the nice comments and the help",user->nick);
734         WriteServ(user->fd,"371 %s :you gave us in attracting users to",user->nick);
735         WriteServ(user->fd,"371 %s :this software.",user->nick);
736         WriteServ(user->fd,"371 %s : ",user->nick);
737         WriteServ(user->fd,"371 %s :Best experienced with: An IRC client.",user->nick);
738         FOREACH_MOD OnInfo(user);
739         WriteServ(user->fd,"374 %s :End of /INFO list",user->nick);
740 }
741
742 void handle_time(char **parameters, int pcnt, userrec *user)
743 {
744         time_t rawtime;
745         struct tm * timeinfo;
746
747         time(&rawtime);
748         timeinfo = localtime(&rawtime);
749         WriteServ(user->fd,"391 %s %s :%s",user->nick,Config->ServerName,asctime(timeinfo));
750   
751 }
752
753 void handle_whois(char **parameters, int pcnt, userrec *user)
754 {
755         userrec *dest;
756         if (loop_call(handle_whois,parameters,pcnt,user,0,pcnt-1,0))
757                 return;
758         dest = Find(parameters[0]);
759         if (dest)
760         {
761                 do_whois(user,dest,0,0,parameters[0]);
762         }
763         else
764         {
765                 /* no such nick/channel */
766                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
767                 WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, parameters[0]);
768         }
769 }
770
771 void split_chlist(userrec* user, userrec* dest, std::string &cl)
772 {
773         std::stringstream channels(cl);
774         std::string line = "";
775         std::string cname = "";
776         while (!channels.eof())
777         {
778                 channels >> cname;
779                 line = line + cname + " ";
780                 if (line.length() > 400)
781                 {
782                         WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, line.c_str());
783                         line = "";
784                 }
785         }
786         if (line.length())
787         {
788                 WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, line.c_str());
789         }
790 }
791
792 void do_whois(userrec* user, userrec* dest,unsigned long signon, unsigned long idle, char* nick)
793 {
794         // bug found by phidjit - were able to whois an incomplete connection if it had sent a NICK or USER
795         if (dest->registered == 7)
796         {
797                 WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
798                 if ((user == dest) || (strchr(user->modes,'o')))
799                 {
800                         WriteServ(user->fd,"378 %s %s :is connecting from *@%s %s",user->nick, dest->nick, dest->host, dest->ip);
801                 }
802                 std::string cl = chlist(dest,user);
803                 if (cl.length())
804                 {
805                         if (cl.length() > 400)
806                         {
807                                 split_chlist(user,dest,cl);
808                         }
809                         else
810                         {
811                                 WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, cl.c_str());
812                         }
813                 }
814                 WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, GetServerDescription(dest->server).c_str());
815                 if (*dest->awaymsg)
816                 {
817                         WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg);
818                 }
819                 if (strchr(dest->modes,'o'))
820                 {
821                         if (*dest->oper)
822                         {
823                                 WriteServ(user->fd,"313 %s %s :is %s %s on %s",user->nick, dest->nick, (strchr("aeiou",dest->oper[0]) ? "an" : "a"),dest->oper, Config->Network);
824                         }
825                         else
826                         {
827                                 WriteServ(user->fd,"313 %s %s :is opered but has an unknown type",user->nick, dest->nick);
828                         }
829                 }
830                 if ((!signon) && (!idle))
831                 {
832                         FOREACH_MOD OnWhois(user,dest);
833                 }
834                 if (!strcasecmp(user->server,dest->server))
835                 {
836                         // idle time and signon line can only be sent if youre on the same server (according to RFC)
837                         WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-TIME), dest->signon);
838                 }
839                 else
840                 {
841                         if ((idle) || (signon))
842                                 WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, idle, signon);
843                 }
844                 WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick);
845         }
846         else
847         {
848                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, nick);
849                 WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, nick);
850         }
851 }
852
853 void handle_quit(char **parameters, int pcnt, userrec *user)
854 {
855         user_hash::iterator iter = clientlist.find(user->nick);
856         char* reason;
857
858         if (user->registered == 7)
859         {
860                 /* theres more to do here, but for now just close the socket */
861                 if (pcnt == 1)
862                 {
863                         if (parameters[0][0] == ':')
864                         {
865                                 *parameters[0]++;
866                         }
867                         reason = parameters[0];
868
869                         if (strlen(reason)>MAXQUIT)
870                         {
871                                 reason[MAXQUIT-1] = '\0';
872                         }
873
874                         /* We should only prefix the quit for a local user. Remote users have
875                          * already been prefixed, where neccessary, by the upstream server.
876                          */
877                         if (user->fd > -1)
878                         {
879                                 Write(user->fd,"ERROR :Closing link (%s@%s) [%s%s]",user->ident,user->host,Config->PrefixQuit,parameters[0]);
880                                 WriteOpers("*** Client exiting: %s!%s@%s [%s%s]",user->nick,user->ident,user->host,Config->PrefixQuit,parameters[0]);
881                                 WriteCommonExcept(user,"QUIT :%s%s",Config->PrefixQuit,parameters[0]);
882                         }
883                         else
884                         {
885                                 WriteOpers("*** Client exiting at %s: %s!%s@%s [%s]",user->server,user->nick,user->ident,user->host,parameters[0]);
886                                 WriteCommonExcept(user,"QUIT :%s",parameters[0]);
887                         }
888                         FOREACH_MOD OnUserQuit(user,std::string(Config->PrefixQuit)+std::string(parameters[0]));
889
890                 }
891                 else
892                 {
893                         Write(user->fd,"ERROR :Closing link (%s@%s) [QUIT]",user->ident,user->host);
894                         WriteOpers("*** Client exiting: %s!%s@%s [Client exited]",user->nick,user->ident,user->host);
895                         WriteCommonExcept(user,"QUIT :Client exited");
896                         FOREACH_MOD OnUserQuit(user,"Client exited");
897
898                 }
899                 AddWhoWas(user);
900         }
901
902         FOREACH_MOD OnUserDisconnect(user);
903
904         /* push the socket on a stack of sockets due to be closed at the next opportunity */
905         if (user->fd > -1)
906         {
907                 SE->DelFd(user->fd);
908                 user->CloseSocket();
909         }
910         
911         if (iter != clientlist.end())
912         {
913                 clientlist.erase(iter);
914         }
915
916         if (user->registered == 7) {
917                 purge_empty_chans(user);
918         }
919         if (user->fd > -1)
920                 fd_ref_table[user->fd] = NULL;
921         delete user;
922 }
923
924 void handle_who(char **parameters, int pcnt, userrec *user)
925 {
926         chanrec* Ptr = NULL;
927         char tmp[10];
928         
929         /* theres more to do here, but for now just close the socket */
930         if (pcnt == 1)
931         {
932                 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")))
933                 {
934                         if ((user->chans.size()) && (user->chans[0].channel))
935                         {
936                                 int n_list = 0;
937                                 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
938                                 {
939                                         Ptr = i->second->chans[0].channel;
940                                         // suggested by phidjit and FCS
941                                         if ((!common_channels(user,i->second)) && (isnick(i->second->nick)))
942                                         {
943                                                 // Bug Fix #29
944                                                 strcpy(tmp, "");
945                                                 if (strcmp(i->second->awaymsg, "")) {
946                                                         strlcat(tmp, "G", 9);
947                                                 } else {
948                                                         strlcat(tmp, "H", 9);
949                                                 }
950                                                 if (strchr(i->second->modes,'o')) { strlcat(tmp, "*", 9); }
951                                                 WriteServ(user->fd,"352 %s %s %s %s %s %s %s :0 %s",user->nick, Ptr ? Ptr->name : "*", i->second->ident, i->second->dhost, i->second->server, i->second->nick, tmp, i->second->fullname);
952                                                 n_list++;
953                                                 if (n_list > Config->MaxWhoResults)
954                                                 {
955                                                         WriteServ(user->fd,"523 %s WHO :Command aborted: More results than configured limit",user->nick);
956                                                         break;
957                                                 }
958                                         }
959                                 }
960                         }
961                         if (Ptr)
962                         {
963                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick , parameters[0]);
964                         }
965                         else
966                         {
967                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, parameters[0]);
968                         }
969                         return;
970                 }
971                 if (parameters[0][0] == '#')
972                 {
973                         Ptr = FindChan(parameters[0]);
974                         if (Ptr)
975                         {
976                                 int n_list = 0;
977                                 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
978                                 {
979                                         if ((has_channel(i->second,Ptr)) && (isnick(i->second->nick)))
980                                         {
981                                                 // Fix Bug #29 - Part 2..
982                                                 strcpy(tmp, "");
983                                                 if (strcmp(i->second->awaymsg, "")) {
984                                                         strlcat(tmp, "G", 9);
985                                                 } else {
986                                                         strlcat(tmp, "H", 9);
987                                                 }
988                                                 if (strchr(i->second->modes,'o')) { strlcat(tmp, "*", 9); }
989                                                 strlcat(tmp, cmode(i->second, Ptr),5);
990                                                 WriteServ(user->fd,"352 %s %s %s %s %s %s %s :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, i->second->server, i->second->nick, tmp, i->second->fullname);
991                                                 n_list++;
992                                                 if (n_list > Config->MaxWhoResults)
993                                                 {
994                                                         WriteServ(user->fd,"523 %s WHO :Command aborted: More results than configured limit",user->nick);
995                                                         break;
996                                                 }
997
998                                         }
999                                 }
1000                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, parameters[0]);
1001                         }
1002                         else
1003                         {
1004                                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
1005                         }
1006                 }
1007                 else
1008                 {
1009                         userrec* u = Find(parameters[0]);
1010                         if (u)
1011                         {
1012                                 // Bug Fix #29 -- Part 29..
1013                                 strcpy(tmp, "");
1014                                 if (strcmp(u->awaymsg, "")) {
1015                                         strlcat(tmp, "G" ,9);
1016                                 } else {
1017                                         strlcat(tmp, "H" ,9);
1018                                 }
1019                                 if (strchr(u->modes,'o')) { strlcat(tmp, "*" ,9); }
1020                                 WriteServ(user->fd,"352 %s %s %s %s %s %s %s :0 %s",user->nick, u->chans.size() ? u->chans[0].channel->name
1021                                 : "*", u->ident, u->dhost, u->server, u->nick, tmp, u->fullname);
1022                         }
1023                         WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, parameters[0]);
1024                 }
1025         }
1026         if (pcnt == 2)
1027         {
1028                 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")) && (!strcmp(parameters[1],"o")))
1029                 {
1030                         for (std::vector<userrec*>::iterator i = all_opers.begin(); i != all_opers.end(); i++)
1031                         {
1032                                 // If i were a rich man.. I wouldn't need to me making these bugfixes..
1033                                 // But i'm a poor bastard with nothing better to do.
1034                                 userrec* oper = *i;
1035                                 strcpy(tmp, "");
1036                                 if (strcmp(oper->awaymsg, "")) {
1037                                         strlcat(tmp, "G" ,9);
1038                                 } else {
1039                                         strlcat(tmp, "H" ,9);
1040                                 }
1041                                 WriteServ(user->fd,"352 %s %s %s %s %s %s %s* :0 %s", user->nick, oper->chans.size() ? oper->chans[0].channel->name 
1042                                 : "*", oper->ident, oper->dhost, oper->server, oper->nick, tmp, oper->fullname);
1043                         }
1044                         WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, parameters[0]);
1045                         return;
1046                 }
1047         }
1048 }
1049
1050 void handle_wallops(char **parameters, int pcnt, userrec *user)
1051 {
1052         WriteWallOps(user,false,"%s",parameters[0]);
1053         FOREACH_MOD OnWallops(user,parameters[0]);
1054 }
1055
1056 void handle_list(char **parameters, int pcnt, userrec *user)
1057 {
1058         WriteServ(user->fd,"321 %s Channel :Users Name",user->nick);
1059         for (chan_hash::const_iterator i = chanlist.begin(); i != chanlist.end(); i++)
1060         {
1061                 // if the channel is not private/secret, OR the user is on the channel anyway
1062                 if (((!(i->second->binarymodes & CM_PRIVATE)) && (!(i->second->binarymodes & CM_SECRET))) || (has_channel(user,i->second)))
1063                 {
1064                         WriteServ(user->fd,"322 %s %s %d :[+%s] %s",user->nick,i->second->name,usercount_i(i->second),chanmodes(i->second),i->second->topic);
1065                 }
1066         }
1067         WriteServ(user->fd,"323 %s :End of channel list.",user->nick);
1068 }
1069
1070
1071 void handle_rehash(char **parameters, int pcnt, userrec *user)
1072 {
1073         WriteServ(user->fd,"382 %s %s :Rehashing",user->nick,CleanFilename(CONFIG_FILE));
1074         std::string parameter = "";
1075         if (pcnt)
1076         {
1077                 parameter = parameters[0];
1078         }
1079         else
1080         {
1081                 WriteOpers("%s is rehashing config file %s",user->nick,CleanFilename(CONFIG_FILE));
1082                 Config->Read(false,user);
1083         }
1084         FOREACH_MOD OnRehash(parameter);
1085 }
1086
1087 void handle_lusers(char **parameters, int pcnt, userrec *user)
1088 {
1089         // this lusers command shows one server at all times because
1090         // a protocol module must override it to show those stats.
1091         WriteServ(user->fd,"251 %s :There are %d users and %d invisible on 1 server",user->nick,usercnt()-usercount_invisible(),usercount_invisible());
1092         WriteServ(user->fd,"252 %s %d :operator(s) online",user->nick,usercount_opers());
1093         WriteServ(user->fd,"253 %s %d :unknown connections",user->nick,usercount_unknown());
1094         WriteServ(user->fd,"254 %s %d :channels formed",user->nick,chancount());
1095         WriteServ(user->fd,"254 %s :I have %d clients and 0 servers",user->nick,local_count());
1096 }
1097
1098 void handle_admin(char **parameters, int pcnt, userrec *user)
1099 {
1100         WriteServ(user->fd,"256 %s :Administrative info for %s",user->nick,Config->ServerName);
1101         WriteServ(user->fd,"257 %s :Name     - %s",user->nick,Config->AdminName);
1102         WriteServ(user->fd,"258 %s :Nickname - %s",user->nick,Config->AdminNick);
1103         WriteServ(user->fd,"258 %s :E-Mail   - %s",user->nick,Config->AdminEmail);
1104 }
1105
1106 void handle_ping(char **parameters, int pcnt, userrec *user)
1107 {
1108         WriteServ(user->fd,"PONG %s :%s",Config->ServerName,parameters[0]);
1109 }
1110
1111 void handle_pong(char **parameters, int pcnt, userrec *user)
1112 {
1113         // set the user as alive so they survive to next ping
1114         user->lastping = 1;
1115 }
1116
1117 void handle_motd(char **parameters, int pcnt, userrec *user)
1118 {
1119         ShowMOTD(user);
1120 }
1121
1122 void handle_rules(char **parameters, int pcnt, userrec *user)
1123 {
1124         ShowRULES(user);
1125 }
1126
1127 void handle_user(char **parameters, int pcnt, userrec *user)
1128 {
1129         if (user->registered < 3)
1130         {
1131                 if (isident(parameters[0]) == 0) {
1132                         // This kinda Sucks, According to the RFC thou, its either this,
1133                         // or "You have already registered" :p -- Craig
1134                         WriteServ(user->fd,"461 %s USER :Not enough parameters",user->nick);
1135                 }
1136                 else {
1137                         /* We're not checking ident, but I'm not sure I like the idea of '~' prefixing.. */
1138                         /* XXX - Should this IDENTMAX + 1 be IDENTMAX - 1? Ok, users.h has it defined as
1139                          * char ident[IDENTMAX+2]; - WTF?
1140                          */
1141                         snprintf(user->ident, IDENTMAX+1, "~%s", parameters[0]);
1142                         strlcpy(user->fullname,parameters[3],MAXGECOS);
1143                         user->registered = (user->registered | 1);
1144                 }
1145         }
1146         else
1147         {
1148                 WriteServ(user->fd,"462 %s :You may not reregister",user->nick);
1149                 return;
1150         }
1151         /* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */
1152         if (user->registered == 3)
1153         {
1154                 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
1155                 FOREACH_MOD OnUserRegister(user);
1156                 ConnectUser(user);
1157         }
1158 }
1159
1160 void handle_userhost(char **parameters, int pcnt, userrec *user)
1161 {
1162         char Return[MAXBUF],junk[MAXBUF];
1163         snprintf(Return,MAXBUF,"302 %s :",user->nick);
1164         for (int i = 0; i < pcnt; i++)
1165         {
1166                 userrec *u = Find(parameters[i]);
1167                 if (u)
1168                 {
1169                         if (strchr(u->modes,'o'))
1170                         {
1171                                 snprintf(junk,MAXBUF,"%s*=+%s@%s ",u->nick,u->ident,u->host);
1172                                 strlcat(Return,junk,MAXBUF);
1173                         }
1174                         else
1175                         {
1176                                 snprintf(junk,MAXBUF,"%s=+%s@%s ",u->nick,u->ident,u->host);
1177                                 strlcat(Return,junk,MAXBUF);
1178                         }
1179                 }
1180         }
1181         WriteServ(user->fd,Return);
1182 }
1183
1184
1185 void handle_ison(char **parameters, int pcnt, userrec *user)
1186 {
1187         char Return[MAXBUF];
1188         snprintf(Return,MAXBUF,"303 %s :",user->nick);
1189         for (int i = 0; i < pcnt; i++)
1190         {
1191                 userrec *u = Find(parameters[i]);
1192                 if (u)
1193                 {
1194                         strlcat(Return,u->nick,MAXBUF);
1195                         strlcat(Return," ",MAXBUF);
1196                 }
1197         }
1198         WriteServ(user->fd,Return);
1199 }
1200
1201
1202 void handle_away(char **parameters, int pcnt, userrec *user)
1203 {
1204         if (pcnt)
1205         {
1206                 strlcpy(user->awaymsg,parameters[0],MAXAWAY);
1207                 WriteServ(user->fd,"306 %s :You have been marked as being away",user->nick);
1208         }
1209         else
1210         {
1211                 strlcpy(user->awaymsg,"",MAXAWAY);
1212                 WriteServ(user->fd,"305 %s :You are no longer marked as being away",user->nick);
1213         }
1214 }
1215
1216 void handle_whowas(char **parameters, int pcnt, userrec* user)
1217 {
1218         whowas_hash::iterator i = whowas.find(parameters[0]);
1219
1220         if (i == whowas.end())
1221         {
1222                 WriteServ(user->fd,"406 %s %s :There was no such nickname",user->nick,parameters[0]);
1223                 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
1224         }
1225         else
1226         {
1227                 time_t rawtime = i->second->signon;
1228                 tm *timeinfo;
1229                 char b[MAXBUF];
1230                 
1231                 timeinfo = localtime(&rawtime);
1232                 strlcpy(b,asctime(timeinfo),MAXBUF);
1233                 b[strlen(b)-1] = '\0';
1234                 
1235                 WriteServ(user->fd,"314 %s %s %s %s * :%s",user->nick,i->second->nick,i->second->ident,i->second->dhost,i->second->fullname);
1236                 WriteServ(user->fd,"312 %s %s %s :%s",user->nick,i->second->nick,i->second->server,b);
1237                 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
1238         }
1239
1240 }
1241
1242 void handle_trace(char **parameters, int pcnt, userrec *user)
1243 {
1244         for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
1245         {
1246                 if (i->second)
1247                 {
1248                         if (isnick(i->second->nick))
1249                         {
1250                                 if (strchr(i->second->modes,'o'))
1251                                 {
1252                                         WriteServ(user->fd,"205 %s :Oper 0 %s",user->nick,i->second->nick);
1253                                 }
1254                                 else
1255                                 {
1256                                         WriteServ(user->fd,"204 %s :User 0 %s",user->nick,i->second->nick);
1257                                 }
1258                         }
1259                         else
1260                         {
1261                                 WriteServ(user->fd,"203 %s :???? 0 [%s]",user->nick,i->second->host);
1262                         }
1263                 }
1264         }
1265 }
1266
1267 void handle_modules(char **parameters, int pcnt, userrec *user)
1268 {
1269         for (unsigned int i = 0; i < Config->module_names.size(); i++)
1270         {
1271                 Version V = modules[i]->GetVersion();
1272                 char modulename[MAXBUF];
1273                 char flagstate[MAXBUF];
1274                 strcpy(flagstate,"");
1275                 if (V.Flags & VF_STATIC)
1276                         strlcat(flagstate,", static",MAXBUF);
1277                 if (V.Flags & VF_VENDOR)
1278                         strlcat(flagstate,", vendor",MAXBUF);
1279                 if (V.Flags & VF_COMMON)
1280                         strlcat(flagstate,", common",MAXBUF);
1281                 if (V.Flags & VF_SERVICEPROVIDER)
1282                         strlcat(flagstate,", service provider",MAXBUF);
1283                 if (!flagstate[0])
1284                         strcpy(flagstate,"  <no flags>");
1285                 strlcpy(modulename,Config->module_names[i].c_str(),256);
1286                 if (strchr(user->modes,'o'))
1287                 {
1288                         WriteServ(user->fd,"900 %s :0x%08lx %d.%d.%d.%d %s (%s)",user->nick,modules[i],V.Major,V.Minor,V.Revision,V.Build,CleanFilename(modulename),flagstate+2);
1289                 }
1290                 else
1291                 {
1292                         WriteServ(user->fd,"900 %s :%s",user->nick,CleanFilename(modulename));
1293                 }
1294         }
1295         WriteServ(user->fd,"901 %s :End of MODULES list",user->nick);
1296 }
1297
1298 void handle_stats(char **parameters, int pcnt, userrec *user)
1299 {
1300         if (pcnt != 1)
1301         {
1302                 return;
1303         }
1304         if (strlen(parameters[0])>1)
1305         {
1306                 /* make the stats query 1 character long */
1307                 parameters[0][1] = '\0';
1308         }
1309
1310
1311         FOREACH_MOD OnStats(*parameters[0]);
1312
1313         if (*parameters[0] == 'c')
1314         {
1315                 /* This stats symbol must be handled by a linking module */
1316         }
1317         
1318         if (*parameters[0] == 'i')
1319         {
1320                 int idx = 0;
1321                 for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
1322                 {
1323                         WriteServ(user->fd,"215 %s I * * * %d %d %s *",user->nick,MAXCLIENTS,idx,Config->ServerName);
1324                         idx++;
1325                 }
1326         }
1327         
1328         if (*parameters[0] == 'y')
1329         {
1330                 int idx = 0;
1331                 for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
1332                 {
1333                         WriteServ(user->fd,"218 %s Y %d %d 0 %d %d",user->nick,idx,120,i->flood,i->registration_timeout);
1334                         idx++;
1335                 }
1336         }
1337
1338         if (*parameters[0] == 'U')
1339         {
1340                 char ulined[MAXBUF];
1341                 for (int i = 0; i < Config->ConfValueEnum("uline",&Config->config_f); i++)
1342                 {
1343                         Config->ConfValue("uline","server",i,ulined,&Config->config_f);
1344                         WriteServ(user->fd,"248 %s U %s",user->nick,ulined);
1345                 }
1346         }
1347         
1348         if (*parameters[0] == 'P')
1349         {
1350                 int idx = 0;
1351                 for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
1352                 {
1353                         if (strchr(i->second->modes,'o'))
1354                         {
1355                                 WriteServ(user->fd,"249 %s :%s (%s@%s) Idle: %d",user->nick,i->second->nick,i->second->ident,i->second->dhost,(TIME - i->second->idle_lastmsg));
1356                                 idx++;
1357                         }
1358                 }
1359                 WriteServ(user->fd,"249 %s :%d OPER(s)",user->nick,idx);
1360         }
1361         
1362         if (*parameters[0] == 'k')
1363         {
1364                 stats_k(user);
1365         }
1366
1367         if (*parameters[0] == 'g')
1368         {
1369                 stats_g(user);
1370         }
1371
1372         if (*parameters[0] == 'q')
1373         {
1374                 stats_q(user);
1375         }
1376
1377         if (*parameters[0] == 'Z')
1378         {
1379                 stats_z(user);
1380         }
1381
1382         if (*parameters[0] == 'e')
1383         {
1384                 stats_e(user);
1385         }
1386
1387         /* stats m (list number of times each command has been used, plus bytecount) */
1388         if (*parameters[0] == 'm')
1389         {
1390                 for (unsigned int i = 0; i < cmdlist.size(); i++)
1391                 {
1392                         if (cmdlist[i].handler_function)
1393                         {
1394                                 if (cmdlist[i].use_count)
1395                                 {
1396                                         /* RPL_STATSCOMMANDS */
1397                                         WriteServ(user->fd,"212 %s %s %d %d",user->nick,cmdlist[i].command,cmdlist[i].use_count,cmdlist[i].total_bytes);
1398                                 }
1399                         }
1400                 }
1401                         
1402         }
1403
1404         /* stats z (debug and memory info) */
1405         if (*parameters[0] == 'z')
1406         {
1407                 rusage R;
1408                 WriteServ(user->fd,"249 %s :Users(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,clientlist.size(),clientlist.size()*sizeof(userrec),clientlist.bucket_count());
1409                 WriteServ(user->fd,"249 %s :Channels(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,chanlist.size(),chanlist.size()*sizeof(chanrec),chanlist.bucket_count());
1410                 WriteServ(user->fd,"249 %s :Commands(VECTOR) %d (%d bytes)",user->nick,cmdlist.size(),cmdlist.size()*sizeof(command_t));
1411                 WriteServ(user->fd,"249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d",user->nick,Config->MOTD.size(),Config->RULES.size());
1412                 WriteServ(user->fd,"249 %s :Modules(VECTOR) %d (%d)",user->nick,modules.size(),modules.size()*sizeof(Module));
1413                 WriteServ(user->fd,"249 %s :ClassFactories(VECTOR) %d (%d)",user->nick,factory.size(),factory.size()*sizeof(ircd_module));
1414                 if (!getrusage(RUSAGE_SELF,&R))
1415                 {
1416                         WriteServ(user->fd,"249 %s :Total allocation: %luK (0x%lx)",user->nick,R.ru_maxrss,R.ru_maxrss);
1417                         WriteServ(user->fd,"249 %s :Signals:          %lu  (0x%lx)",user->nick,R.ru_nsignals,R.ru_nsignals);
1418                         WriteServ(user->fd,"249 %s :Page faults:      %lu  (0x%lx)",user->nick,R.ru_majflt,R.ru_majflt);
1419                         WriteServ(user->fd,"249 %s :Swaps:            %lu  (0x%lx)",user->nick,R.ru_nswap,R.ru_nswap);
1420                         WriteServ(user->fd,"249 %s :Context Switches: %lu  (0x%lx)",user->nick,R.ru_nvcsw+R.ru_nivcsw,R.ru_nvcsw+R.ru_nivcsw);
1421                 }
1422         }
1423
1424         if (*parameters[0] == 'T')
1425         {
1426                 WriteServ(user->fd,"249 Brain :accepts %d refused %d",stats->statsAccept,stats->statsRefused);
1427                 WriteServ(user->fd,"249 Brain :unknown commands %d",stats->statsUnknown);
1428                 WriteServ(user->fd,"249 Brain :nick collisions %d",stats->statsCollisions);
1429                 WriteServ(user->fd,"249 Brain :dns requests %d succeeded %d failed %d",stats->statsDns,stats->statsDnsGood,stats->statsDnsBad);
1430                 WriteServ(user->fd,"249 Brain :connections %d",stats->statsConnects);
1431                 WriteServ(user->fd,"249 Brain :bytes sent %dK recv %dK",(stats->statsSent / 1024),(stats->statsRecv / 1024));
1432         }
1433         
1434         /* stats o */
1435         if (*parameters[0] == 'o')
1436         {
1437                 for (int i = 0; i < Config->ConfValueEnum("oper",&Config->config_f); i++)
1438                 {
1439                         char LoginName[MAXBUF];
1440                         char HostName[MAXBUF];
1441                         char OperType[MAXBUF];
1442                         Config->ConfValue("oper","name",i,LoginName,&Config->config_f);
1443                         Config->ConfValue("oper","host",i,HostName,&Config->config_f);
1444                         Config->ConfValue("oper","type",i,OperType,&Config->config_f);
1445                         WriteServ(user->fd,"243 %s O %s * %s %s 0",user->nick,HostName,LoginName,OperType);
1446                 }
1447         }
1448         
1449         /* stats l (show user I/O stats) */
1450         if (*parameters[0] == 'l')
1451         {
1452                 WriteServ(user->fd,"211 %s :server:port nick bytes_in cmds_in bytes_out cmds_out",user->nick);
1453                 for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
1454                 {
1455                         if (isnick(i->second->nick))
1456                         {
1457                                 WriteServ(user->fd,"211 %s :%s:%d %s %d %d %d %d",user->nick,i->second->server,i->second->port,i->second->nick,i->second->bytes_in,i->second->cmds_in,i->second->bytes_out,i->second->cmds_out);
1458                         }
1459                         else
1460                         {
1461                                 WriteServ(user->fd,"211 %s :%s:%d (unknown@%d) %d %d %d %d",user->nick,i->second->server,i->second->port,i->second->fd,i->second->bytes_in,i->second->cmds_in,i->second->bytes_out,i->second->cmds_out);
1462                         }
1463                         
1464                 }
1465         }
1466         
1467         /* stats u (show server uptime) */
1468         if (*parameters[0] == 'u')
1469         {
1470                 time_t current_time = 0;
1471                 current_time = TIME;
1472                 time_t server_uptime = current_time - ServerInstance->startup_time;
1473                 struct tm* stime;
1474                 stime = gmtime(&server_uptime);
1475                 /* i dont know who the hell would have an ircd running for over a year nonstop, but
1476                  * Craig suggested this, and it seemed a good idea so in it went */
1477                 if (stime->tm_year > 70)
1478                 {
1479                         WriteServ(user->fd,"242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick,(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
1480                 }
1481                 else
1482                 {
1483                         WriteServ(user->fd,"242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick,stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
1484                 }
1485         }
1486
1487         WriteServ(user->fd,"219 %s %s :End of /STATS report",user->nick,parameters[0]);
1488         WriteOpers("*** Notice: Stats '%s' requested by %s (%s@%s)",parameters[0],user->nick,user->ident,user->host);
1489         
1490 }
1491
1492
1493 void handle_connect(char **parameters, int pcnt, userrec *user)
1494 {
1495 }
1496
1497 void handle_squit(char **parameters, int pcnt, userrec *user)
1498 {
1499 }
1500
1501 void handle_links(char **parameters, int pcnt, userrec *user)
1502 {
1503         WriteServ(user->fd,"364 %s %s %s :0 %s",user->nick,Config->ServerName,Config->ServerName,Config->ServerDesc);
1504         WriteServ(user->fd,"365 %s * :End of /LINKS list.",user->nick);
1505 }
1506
1507 void handle_map(char **parameters, int pcnt, userrec *user)
1508 {
1509         // as with /LUSERS this does nothing without a linking
1510         // module to override its behaviour and display something
1511         // better.
1512         WriteServ(user->fd,"006 %s :%s",user->nick,Config->ServerName);
1513         WriteServ(user->fd,"007 %s :End of /MAP",user->nick);
1514 }
1515
1516 bool is_uline(const char* server)
1517 {
1518         char ServName[MAXBUF];
1519
1520         if (!server)
1521                 return false;
1522         if (!(*server))
1523                 return true;
1524
1525         for (int i = 0; i < Config->ConfValueEnum("uline",&Config->config_f); i++)
1526         {
1527                 Config->ConfValue("uline","server",i,ServName,&Config->config_f);
1528                 if (!strcasecmp(server,ServName))
1529                 {
1530                         return true;
1531                 }
1532         }
1533         return false;
1534 }
1535 int operstrcmp(char* data,char* input)
1536 {
1537         int MOD_RESULT = 0;
1538         FOREACH_RESULT(OnOperCompare(data,input))
1539         log(DEBUG,"operstrcmp: %d",MOD_RESULT);
1540         if (MOD_RESULT == 1)
1541                 return 0;
1542         if (MOD_RESULT == -1)
1543                 return 1;
1544         log(DEBUG,"strcmp fallback: '%s' '%s' %d",data,input,strcmp(data,input));
1545         return strcmp(data,input);
1546 }
1547
1548 void handle_oper(char **parameters, int pcnt, userrec *user)
1549 {
1550         char LoginName[MAXBUF];
1551         char Password[MAXBUF];
1552         char OperType[MAXBUF];
1553         char TypeName[MAXBUF];
1554         char HostName[MAXBUF];
1555         char TheHost[MAXBUF];
1556         int j;
1557         bool found = false;
1558         bool fail2 = false;
1559
1560         snprintf(TheHost,MAXBUF,"%s@%s",user->ident,user->host);
1561
1562         for (int i = 0; i < Config->ConfValueEnum("oper",&Config->config_f); i++)
1563         {
1564                 Config->ConfValue("oper","name",i,LoginName,&Config->config_f);
1565                 Config->ConfValue("oper","password",i,Password,&Config->config_f);
1566                 Config->ConfValue("oper","type",i,OperType,&Config->config_f);
1567                 Config->ConfValue("oper","host",i,HostName,&Config->config_f);
1568                 if ((!strcmp(LoginName,parameters[0])) && (!operstrcmp(Password,parameters[1])) && (match(TheHost,HostName)))
1569                 {
1570                         fail2 = true;
1571                         for (j =0; j < Config->ConfValueEnum("type",&Config->config_f); j++)
1572                         {
1573                                 Config->ConfValue("type","name",j,TypeName,&Config->config_f);
1574
1575                                 if (!strcmp(TypeName,OperType))
1576                                 {
1577                                         /* found this oper's opertype */
1578                                         Config->ConfValue("type","host",j,HostName,&Config->config_f);
1579                                         if (*HostName)
1580                                                 ChangeDisplayedHost(user,HostName);
1581                                         strlcpy(user->oper,TypeName,NICKMAX);
1582                                         found = true;
1583                                         fail2 = false;
1584                                         break;
1585                                 }
1586                         }
1587                 }
1588                 if (found)
1589                         break;
1590         }
1591         if (found)
1592         {
1593                 /* correct oper credentials */
1594                 WriteOpers("*** %s (%s@%s) is now an IRC operator of type %s",user->nick,user->ident,user->host,OperType);
1595                 WriteServ(user->fd,"381 %s :You are now an IRC operator of type %s",user->nick,OperType);
1596                 if (!strchr(user->modes,'o'))
1597                 {
1598                         strcat(user->modes,"o");
1599                         WriteServ(user->fd,"MODE %s :+o",user->nick);
1600                         FOREACH_MOD OnOper(user,OperType);
1601                         log(DEFAULT,"OPER: %s!%s@%s opered as type: %s",user->nick,user->ident,user->host,OperType);
1602                         AddOper(user);
1603                 }
1604         }
1605         else
1606         {
1607                 if (!fail2)
1608                 {
1609                         WriteServ(user->fd,"491 %s :Invalid oper credentials",user->nick);
1610                         WriteOpers("*** WARNING! Failed oper attempt by %s!%s@%s!",user->nick,user->ident,user->host);
1611                         log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: user, host or password did not match.",user->nick,user->ident,user->host);
1612                 }
1613                 else
1614                 {
1615                         WriteServ(user->fd,"491 %s :Your oper block does not have a valid opertype associated with it",user->nick);
1616                         WriteOpers("*** CONFIGURATION ERROR! Oper block mismatch for OperType %s",OperType);
1617                         log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: credentials valid, but oper type nonexistent.",user->nick,user->ident,user->host);
1618                 }
1619         }
1620         return;
1621 }
1622
1623 void handle_nick(char **parameters, int pcnt, userrec *user)
1624 {
1625         if (pcnt < 1) 
1626         {
1627                 log(DEBUG,"not enough params for handle_nick");
1628                 return;
1629         }
1630         if (!parameters[0])
1631         {
1632                 log(DEBUG,"invalid parameter passed to handle_nick");
1633                 return;
1634         }
1635         if (!parameters[0][0])
1636         {
1637                 log(DEBUG,"zero length new nick passed to handle_nick");
1638                 return;
1639         }
1640         if (!user)
1641         {
1642                 log(DEBUG,"invalid user passed to handle_nick");
1643                 return;
1644         }
1645         if (!user->nick)
1646         {
1647                 log(DEBUG,"invalid old nick passed to handle_nick");
1648                 return;
1649         }
1650         if (!strcasecmp(user->nick,parameters[0]))
1651         {
1652                 log(DEBUG,"old nick is new nick, skipping");
1653                 return;
1654         }
1655         else
1656         {
1657                 if (strlen(parameters[0]) > 1)
1658                 {
1659                         if (parameters[0][0] == ':')
1660                         {
1661                                 *parameters[0]++;
1662                         }
1663                 }
1664                 if (matches_qline(parameters[0]))
1665                 {
1666                         WriteOpers("*** Q-Lined nickname %s from %s!%s@%s: %s",parameters[0],user->nick,user->ident,user->host,matches_qline(parameters[0]));
1667                         WriteServ(user->fd,"432 %s %s :Invalid nickname: %s",user->nick,parameters[0],matches_qline(parameters[0]));
1668                         return;
1669                 }
1670                 if ((Find(parameters[0])) && (Find(parameters[0]) != user))
1671                 {
1672                         WriteServ(user->fd,"433 %s %s :Nickname is already in use.",user->nick,parameters[0]);
1673                         return;
1674                 }
1675         }
1676         if (isnick(parameters[0]) == 0)
1677         {
1678                 WriteServ(user->fd,"432 %s %s :Erroneous Nickname",user->nick,parameters[0]);
1679                 return;
1680         }
1681
1682         if (user->registered == 7)
1683         {
1684                 int MOD_RESULT = 0;
1685                 FOREACH_RESULT(OnUserPreNick(user,parameters[0]));
1686                 if (MOD_RESULT) {
1687                         // if a module returns true, the nick change is silently forbidden.
1688                         return;
1689                 }
1690
1691                 WriteCommon(user,"NICK %s",parameters[0]);
1692                 
1693         }
1694         
1695         char oldnick[NICKMAX];
1696         strlcpy(oldnick,user->nick,NICKMAX);
1697
1698         /* change the nick of the user in the users_hash */
1699         user = ReHashNick(user->nick, parameters[0]);
1700         /* actually change the nick within the record */
1701         if (!user) return;
1702         if (!user->nick) return;
1703
1704         strlcpy(user->nick, parameters[0],NICKMAX);
1705
1706         log(DEBUG,"new nick set: %s",user->nick);
1707         
1708         if (user->registered < 3)
1709         {
1710                 user->registered = (user->registered | 2);
1711                 // dont attempt to look up the dns until they pick a nick... because otherwise their pointer WILL change
1712                 // and unless we're lucky we'll get a duff one later on.
1713                 //user->dns_done = (!lookup_dns(user->nick));
1714                 //if (user->dns_done)
1715                 //      log(DEBUG,"Aborting dns lookup of %s because dns server experienced a failure.",user->nick);
1716
1717 #ifdef THREADED_DNS
1718                 // initialize their dns lookup thread
1719                 if (pthread_create(&user->dnsthread, NULL, dns_task, (void *)user) != 0)
1720                 {
1721                         log(DEBUG,"Failed to create DNS lookup thread for user %s",user->nick);
1722                 }
1723 #else
1724                 user->dns_done = (!lookup_dns(user->nick));
1725                 if (user->dns_done)
1726                         log(DEBUG,"Aborting dns lookup of %s because dns server experienced a failure.",user->nick);
1727 #endif
1728         
1729         }
1730         if (user->registered == 3)
1731         {
1732                 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
1733                 FOREACH_MOD OnUserRegister(user);
1734                 ConnectUser(user);
1735         }
1736         if (user->registered == 7)
1737         {
1738                 FOREACH_MOD OnUserPostNick(user,oldnick);
1739         }
1740 }
1741
1742 long duration(const char* str)
1743 {
1744         char n_field[MAXBUF];
1745         long total = 0;
1746         const char* str_end = str + strlen(str);
1747         n_field[0] = 0;
1748
1749         if ((!strchr(str,'s')) && (!strchr(str,'m')) && (!strchr(str,'h')) && (!strchr(str,'d')) && (!strchr(str,'w')) && (!strchr(str,'y')))
1750         {
1751                 std::string n = str;
1752                 n = n + "s";
1753                 return duration(n.c_str());
1754         }
1755         
1756         for (char* i = (char*)str; i < str_end; i++)
1757         {
1758                 // if we have digits, build up a string for the value in n_field,
1759                 // up to 10 digits in size.
1760                 if ((*i >= '0') && (*i <= '9'))
1761                 {
1762                         strlcat(n_field,i,10);
1763                 }
1764                 else
1765                 {
1766                         // we dont have a digit, check for numeric tokens
1767                         switch (tolower(*i))
1768                         {
1769                                 case 's':
1770                                         total += atoi(n_field);
1771                                 break;
1772
1773                                 case 'm':
1774                                         total += (atoi(n_field)*duration_m);
1775                                 break;
1776
1777                                 case 'h':
1778                                         total += (atoi(n_field)*duration_h);
1779                                 break;
1780
1781                                 case 'd':
1782                                         total += (atoi(n_field)*duration_d);
1783                                 break;
1784
1785                                 case 'w':
1786                                         total += (atoi(n_field)*duration_w);
1787                                 break;
1788
1789                                 case 'y':
1790                                         total += (atoi(n_field)*duration_y);
1791                                 break;
1792                         }
1793                         n_field[0] = 0;
1794                 }
1795         }
1796         // add trailing seconds
1797         total += atoi(n_field);
1798         
1799         return total;
1800 }
1801
1802 /* All other ircds when doing this check usually just look for a string of *@* or *. We're smarter than that, though. */
1803
1804 bool host_matches_everyone(std::string mask, userrec* user)
1805 {
1806         char insanemasks[MAXBUF];
1807         char buffer[MAXBUF];
1808         char itrigger[MAXBUF];
1809         Config->ConfValue("insane","hostmasks",0,insanemasks,&Config->config_f);
1810         Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f);
1811         if (*itrigger == 0)
1812                 strlcpy(itrigger,"95.5",MAXBUF);
1813         if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
1814                 return false;
1815         long matches = 0;
1816         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
1817         {
1818                 strlcpy(buffer,u->second->ident,MAXBUF);
1819                 strlcat(buffer,"@",MAXBUF);
1820                 strlcat(buffer,u->second->host,MAXBUF);
1821                 if (match(buffer,mask.c_str()))
1822                         matches++;
1823         }
1824         float percent = ((float)matches / (float)clientlist.size()) * 100;
1825         if (percent > (float)atof(itrigger))
1826         {
1827                 WriteOpers("*** \2WARNING\2: %s tried to set a G/K/E line mask of %s, which covers %.2f%% of the network!",user->nick,mask.c_str(),percent);
1828                 return true;
1829         }
1830         return false;
1831 }
1832
1833 bool ip_matches_everyone(std::string ip, userrec* user)
1834 {
1835         char insanemasks[MAXBUF];
1836         char itrigger[MAXBUF];
1837         Config->ConfValue("insane","ipmasks",0,insanemasks,&Config->config_f);
1838         Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f);
1839         if (*itrigger == 0)
1840                 strlcpy(itrigger,"95.5",MAXBUF);
1841         if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
1842                 return false;
1843         long matches = 0;
1844         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
1845         {
1846                 if (match(u->second->ip,ip.c_str()))
1847                         matches++;
1848         }
1849         float percent = ((float)matches / (float)clientlist.size()) * 100;
1850         if (percent > (float)atof(itrigger))
1851         {
1852                 WriteOpers("*** \2WARNING\2: %s tried to set a Z line mask of %s, which covers %.2f%% of the network!",user->nick,ip.c_str(),percent);
1853                 return true;
1854         }
1855         return false;
1856 }
1857
1858 bool nick_matches_everyone(std::string nick, userrec* user)
1859 {
1860         char insanemasks[MAXBUF];
1861         char itrigger[MAXBUF];
1862         Config->ConfValue("insane","nickmasks",0,insanemasks,&Config->config_f);
1863         Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f);
1864         if (*itrigger == 0)
1865                 strlcpy(itrigger,"95.5",MAXBUF);
1866         if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
1867                 return false;
1868         long matches = 0;
1869         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
1870         {
1871                 if (match(u->second->nick,nick.c_str()))
1872                         matches++;
1873         }
1874         float percent = ((float)matches / (float)clientlist.size()) * 100;
1875         if (percent > (float)atof(itrigger))
1876         {
1877                 WriteOpers("*** \2WARNING\2: %s tried to set a Q line mask of %s, which covers %.2f%% of the network!",user->nick,nick.c_str(),percent);
1878                 return true;
1879         }
1880         return false;
1881 }
1882
1883 void handle_kline(char **parameters, int pcnt, userrec *user)
1884 {
1885         if (pcnt >= 3)
1886         {
1887                 if (host_matches_everyone(parameters[0],user))
1888                         return;
1889                 add_kline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
1890                 FOREACH_MOD OnAddKLine(duration(parameters[1]), user, parameters[2], parameters[0]);
1891                 if (!duration(parameters[1]))
1892                 {
1893                         WriteOpers("*** %s added permenant K-line for %s.",user->nick,parameters[0]);
1894                 }
1895                 else
1896                 {
1897                         WriteOpers("*** %s added timed K-line for %s, expires in %d seconds.",user->nick,parameters[0],duration(parameters[1]));
1898                 }
1899                 apply_lines(APPLY_KLINES);
1900         }
1901         else
1902         {
1903                 if (del_kline(parameters[0]))
1904                 {
1905                         FOREACH_MOD OnDelKLine(user, parameters[0]);
1906                         WriteOpers("*** %s Removed K-line on %s.",user->nick,parameters[0]);
1907                 }
1908                 else
1909                 {
1910                         WriteServ(user->fd,"NOTICE %s :*** K-Line %s not found in list, try /stats k.",user->nick,parameters[0]);
1911                 }
1912         }
1913 }
1914
1915 void handle_eline(char **parameters, int pcnt, userrec *user)
1916 {
1917         if (pcnt >= 3)
1918         {
1919                 if (host_matches_everyone(parameters[0],user))
1920                         return;
1921                 add_eline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
1922                 FOREACH_MOD OnAddELine(duration(parameters[1]), user, parameters[2], parameters[0]);
1923                 if (!duration(parameters[1]))
1924                 {
1925                         WriteOpers("*** %s added permenant E-line for %s.",user->nick,parameters[0]);
1926                 }
1927                 else
1928                 {
1929                         WriteOpers("*** %s added timed E-line for %s, expires in %d seconds.",user->nick,parameters[0],duration(parameters[1]));
1930                 }
1931         }
1932         else
1933         {
1934                 if (del_eline(parameters[0]))
1935                 {
1936                         FOREACH_MOD OnDelELine(user, parameters[0]);
1937                         WriteOpers("*** %s Removed E-line on %s.",user->nick,parameters[0]);
1938                 }
1939                 else
1940                 {
1941                         WriteServ(user->fd,"NOTICE %s :*** E-Line %s not found in list, try /stats e.",user->nick,parameters[0]);
1942                 }
1943         }
1944         // no need to apply the lines for an eline
1945 }
1946
1947 void handle_gline(char **parameters, int pcnt, userrec *user)
1948 {
1949         if (pcnt >= 3)
1950         {
1951                 if (host_matches_everyone(parameters[0],user))
1952                         return;
1953                 add_gline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
1954                 FOREACH_MOD OnAddGLine(duration(parameters[1]), user, parameters[2], parameters[0]);
1955                 if (!duration(parameters[1]))
1956                 {
1957                         WriteOpers("*** %s added permenant G-line for %s.",user->nick,parameters[0]);
1958                 }
1959                 else
1960                 {
1961                         WriteOpers("*** %s added timed G-line for %s, expires in %d seconds.",user->nick,parameters[0],duration(parameters[1]));
1962                 }
1963                 apply_lines(APPLY_GLINES);
1964         }
1965         else
1966         {
1967                 if (del_gline(parameters[0]))
1968                 {
1969                         FOREACH_MOD OnDelGLine(user, parameters[0]);
1970                         WriteOpers("*** %s Removed G-line on %s.",user->nick,parameters[0]);
1971                 }
1972                 else
1973                 {
1974                         WriteServ(user->fd,"NOTICE %s :*** G-Line %s not found in list, try /stats g.",user->nick,parameters[0]);
1975                 }
1976         }
1977 }
1978
1979 void handle_zline(char **parameters, int pcnt, userrec *user)
1980 {
1981         if (pcnt >= 3)
1982         {
1983                 if (strchr(parameters[0],'@'))
1984                 {
1985                         WriteServ(user->fd,"NOTICE %s :*** You cannot include a username in a zline, a zline must ban only an IP mask",user->nick);
1986                         return;
1987                 }
1988                 if (ip_matches_everyone(parameters[0],user))
1989                         return;
1990                 add_zline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
1991                 FOREACH_MOD OnAddZLine(duration(parameters[1]), user, parameters[2], parameters[0]);
1992                 if (!duration(parameters[1]))
1993                 {
1994                         WriteOpers("*** %s added permenant Z-line for %s.",user->nick,parameters[0]);
1995                 }
1996                 else
1997                 {
1998                         WriteOpers("*** %s added timed Z-line for %s, expires in %d seconds.",user->nick,parameters[0],duration(parameters[1]));
1999                 }
2000                 apply_lines(APPLY_ZLINES);
2001         }
2002         else
2003         {
2004                 if (del_zline(parameters[0]))
2005                 {
2006                         FOREACH_MOD OnDelZLine(user, parameters[0]);
2007                         WriteOpers("*** %s Removed Z-line on %s.",user->nick,parameters[0]);
2008                 }
2009                 else
2010                 {
2011                         WriteServ(user->fd,"NOTICE %s :*** Z-Line %s not found in list, try /stats Z.",user->nick,parameters[0]);
2012                 }
2013         }
2014 }
2015
2016 void handle_qline(char **parameters, int pcnt, userrec *user)
2017 {
2018         if (pcnt >= 3)
2019         {
2020                 if (nick_matches_everyone(parameters[0],user))
2021                         return;
2022                 add_qline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
2023                 FOREACH_MOD OnAddQLine(duration(parameters[1]), user, parameters[2], parameters[0]);
2024                 if (!duration(parameters[1]))
2025                 {
2026                         WriteOpers("*** %s added permenant Q-line for %s.",user->nick,parameters[0]);
2027                 }
2028                 else
2029                 {
2030                         WriteOpers("*** %s added timed Q-line for %s, expires in %d seconds.",user->nick,parameters[0],duration(parameters[1]));
2031                 }
2032                 apply_lines(APPLY_QLINES);
2033         }
2034         else
2035         {
2036                 if (del_qline(parameters[0]))
2037                 {
2038                         FOREACH_MOD OnDelQLine(user, parameters[0]);
2039                         WriteOpers("*** %s Removed Q-line on %s.",user->nick,parameters[0]);
2040                 }
2041                 else
2042                 {
2043                         WriteServ(user->fd,"NOTICE %s :*** Q-Line %s not found in list, try /stats q.",user->nick,parameters[0]);
2044                 }
2045         }
2046 }
2047
2048 void handle_version(char **parameters, int pcnt, userrec *user)
2049 {
2050                 WriteServ(user->fd,"351 %s :%s",user->nick,ServerInstance->GetVersionString().c_str());
2051 }
2052