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