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