]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/helperfuncs.cpp
Changed to use __single_client_alloc, supposedly faster in single-thread situations
[user/henk/code/inspircd.git] / src / helperfuncs.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 #include "inspircd.h"
18 #include "inspircd_io.h"
19 #include "inspircd_util.h"
20 #include "inspircd_config.h"
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <sys/errno.h>
24 #include <time.h>
25 #include <string>
26 #ifdef GCC3
27 #include <ext/hash_map>
28 #else
29 #include <hash_map>
30 #endif
31 #include <sstream>
32 #include <vector>
33 #include <deque>
34 #include <stdarg.h>
35 #include "connection.h"
36 #include "users.h"
37 #include "servers.h"
38 #include "ctables.h"
39 #include "globals.h"
40 #include "modules.h"
41 #include "dynamic.h"
42 #include "wildcard.h"
43 #include "message.h"
44 #include "mode.h"
45 #include "xline.h"
46 #include "commands.h"
47 #include "inspstring.h"
48 #include "helperfuncs.h"
49 #include "hashcomp.h"
50
51 using namespace std;
52
53 extern int MODCOUNT;
54 extern std::vector<Module*, __single_client_alloc> modules;
55
56 extern time_t TIME;
57 extern bool nofork;
58 extern char lowermap[255];
59 extern char ServerName[MAXBUF];
60 extern char Network[MAXBUF];
61 extern char ServerDesc[MAXBUF];
62 extern char list[MAXBUF];
63
64 extern int debugging;
65 extern int LogLevel;
66
67 extern std::stringstream config_f;
68
69 extern serverrec* me[32];
70
71 extern FILE *log_file;
72 extern userrec* fd_ref_table[65536];
73
74 extern int statsAccept, statsRefused, statsUnknown, statsCollisions, statsDns, statsDnsGood, statsDnsBad, statsConnects, statsSent, statsRecv;
75
76 static char already_sent[65536];
77 extern std::vector<userrec*, __single_client_alloc> all_opers;
78
79 extern ClassVector Classes;
80
81 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp, __single_client_alloc> user_hash;
82 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHashComp, __single_client_alloc> chan_hash;
83 typedef std::deque<command_t, __single_client_alloc> command_table;
84
85 extern user_hash clientlist;
86 extern chan_hash chanlist;
87 extern command_table cmdlist;
88 extern file_cache MOTD;
89 extern file_cache RULES;
90
91 void log(int level,char *text, ...)
92 {
93         char textbuffer[MAXBUF];
94         va_list argsPtr;
95         time_t rawtime;
96         struct tm * timeinfo;
97         if (level < LogLevel)
98                 return;
99
100         time(&rawtime);
101         timeinfo = localtime (&rawtime);
102
103         if (log_file)
104         {
105                 char b[MAXBUF];
106                 va_start (argsPtr, text);
107                 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
108                 va_end(argsPtr);
109                 strlcpy(b,asctime(timeinfo),MAXBUF);
110                 b[24] = ':';    // we know this is the end of the time string
111                 fprintf(log_file,"%s %s\n",b,textbuffer);
112                 if (nofork)
113                 {
114                         // nofork enabled? display it on terminal too
115                         printf("%s %s\n",b,textbuffer);
116                 }
117         }
118 }
119
120 void readfile(file_cache &F, const char* fname)
121 {
122         FILE* file;
123         char linebuf[MAXBUF];
124
125         log(DEBUG,"readfile: loading %s",fname);
126         F.clear();
127         file =  fopen(fname,"r");
128         if (file)
129         {
130                 while (!feof(file))
131                 {
132                         fgets(linebuf,sizeof(linebuf),file);
133                         linebuf[strlen(linebuf)-1]='\0';
134                         if (linebuf[0] == 0)
135                         {
136                                 strcpy(linebuf,"  ");
137                         }
138                         if (!feof(file))
139                         {
140                                 F.push_back(linebuf);
141                         }
142                 }
143                 fclose(file);
144         }
145         else
146         {
147                 log(DEBUG,"readfile: failed to load file: %s",fname);
148         }
149         log(DEBUG,"readfile: loaded %s, %lu lines",fname,(unsigned long)F.size());
150 }
151
152 void Write(int sock,char *text, ...)
153 {
154         if (sock < 0)
155                 return;
156         if (!text)
157         {
158                 log(DEFAULT,"*** BUG *** Write was given an invalid parameter");
159                 return;
160         }
161         char textbuffer[MAXBUF];
162         va_list argsPtr;
163         char tb[MAXBUF];
164         int res;
165
166         va_start (argsPtr, text);
167         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
168         va_end(argsPtr);
169         int bytes = snprintf(tb,MAXBUF,"%s\r\n",textbuffer);
170         chop(tb);
171         if (fd_ref_table[sock])
172         {
173                 int MOD_RESULT = 0;
174                 FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes));
175                 fd_ref_table[sock]->AddWriteBuf(tb);
176                 statsSent += bytes;
177         }
178         else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
179 }
180
181 /* write a server formatted numeric response to a single socket */
182
183 void WriteServ(int sock, char* text, ...)
184 {
185         if (sock < 0)
186                 return;
187         if (!text)
188         {
189                 log(DEFAULT,"*** BUG *** WriteServ was given an invalid parameter");
190                 return;
191         }
192         char textbuffer[MAXBUF],tb[MAXBUF];
193         int res;
194         va_list argsPtr;
195         va_start (argsPtr, text);
196
197         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
198         va_end(argsPtr);
199         int bytes = snprintf(tb,MAXBUF,":%s %s\r\n",ServerName,textbuffer);
200         chop(tb);
201         if (fd_ref_table[sock])
202         {
203                 int MOD_RESULT = 0;
204                 FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes));
205                 fd_ref_table[sock]->AddWriteBuf(tb);
206                 statsSent += bytes;
207         }
208         else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
209 }
210
211 /* write text from an originating user to originating user */
212
213 void WriteFrom(int sock, userrec *user,char* text, ...)
214 {
215         if (sock < 0)
216                 return;
217         if ((!text) || (!user))
218         {
219                 log(DEFAULT,"*** BUG *** WriteFrom was given an invalid parameter");
220                 return;
221         }
222         char textbuffer[MAXBUF],tb[MAXBUF];
223         va_list argsPtr;
224         int res;
225         va_start (argsPtr, text);
226
227         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
228         va_end(argsPtr);
229         int bytes = snprintf(tb,MAXBUF,":%s!%s@%s %s\r\n",user->nick,user->ident,user->dhost,textbuffer);
230         chop(tb);
231         if (fd_ref_table[sock])
232         {
233                 int MOD_RESULT = 0;
234                 FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes));
235                 fd_ref_table[sock]->AddWriteBuf(tb);
236                 statsSent += bytes;
237         }
238         else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
239 }
240
241 /* write text to an destination user from a source user (e.g. user privmsg) */
242
243 void WriteTo(userrec *source, userrec *dest,char *data, ...)
244 {
245         if ((!dest) || (!data))
246         {
247                 log(DEFAULT,"*** BUG *** WriteTo was given an invalid parameter");
248                 return;
249         }
250         if (dest->fd == FD_MAGIC_NUMBER)
251                 return;
252         char textbuffer[MAXBUF],tb[MAXBUF];
253         va_list argsPtr;
254         va_start (argsPtr, data);
255         vsnprintf(textbuffer, MAXBUF, data, argsPtr);
256         va_end(argsPtr);
257         chop(tb);
258
259         // if no source given send it from the server.
260         if (!source)
261         {
262                 WriteServ(dest->fd,":%s %s",ServerName,textbuffer);
263         }
264         else
265         {
266                 WriteFrom(dest->fd,source,"%s",textbuffer);
267         }
268 }
269
270 /* write formatted text from a source user to all users on a channel
271  * including the sender (NOT for privmsg, notice etc!) */
272
273 void WriteChannel(chanrec* Ptr, userrec* user, char* text, ...)
274 {
275         if ((!Ptr) || (!user) || (!text))
276         {
277                 log(DEFAULT,"*** BUG *** WriteChannel was given an invalid parameter");
278                 return;
279         }
280         char textbuffer[MAXBUF];
281         va_list argsPtr;
282         va_start (argsPtr, text);
283         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
284         va_end(argsPtr);
285
286         std::vector<char*> *ulist = Ptr->GetUsers();
287         for (int j = 0; j < ulist->size(); j++)
288         {
289                 char* o = (*ulist)[j];
290                 userrec* otheruser = (userrec*)o;
291                 if (otheruser->fd != FD_MAGIC_NUMBER)
292                         WriteTo(user,otheruser,"%s",textbuffer);
293         }
294 }
295
296 /* write formatted text from a source user to all users on a channel
297  * including the sender (NOT for privmsg, notice etc!) doesnt send to
298  * users on remote servers */
299
300 void WriteChannelLocal(chanrec* Ptr, userrec* user, char* text, ...)
301 {
302         if ((!Ptr) || (!text))
303         {
304                 log(DEFAULT,"*** BUG *** WriteChannel was given an invalid parameter");
305                 return;
306         }
307         char textbuffer[MAXBUF];
308         va_list argsPtr;
309         va_start (argsPtr, text);
310         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
311         va_end(argsPtr);
312
313         std::vector<char*> *ulist = Ptr->GetUsers();
314         for (int j = 0; j < ulist->size(); j++)
315         {
316                 char* o = (*ulist)[j];
317                 userrec* otheruser = (userrec*)o;
318                 if ((otheruser->fd != FD_MAGIC_NUMBER) && (otheruser->fd != -1) && (otheruser != user))
319                 {
320                         if (!user)
321                         {
322                                 WriteServ(otheruser->fd,"%s",textbuffer);
323                         }
324                         else
325                         {
326                                 WriteTo(user,otheruser,"%s",textbuffer);
327                         }
328                 }
329         }
330 }
331
332 void WriteChannelWithServ(char* ServName, chanrec* Ptr, char* text, ...)
333 {
334         if ((!Ptr) || (!text))
335         {
336                 log(DEFAULT,"*** BUG *** WriteChannelWithServ was given an invalid parameter");
337                 return;
338         }
339         char textbuffer[MAXBUF];
340         va_list argsPtr;
341         va_start (argsPtr, text);
342         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
343         va_end(argsPtr);
344
345
346         std::vector<char*> *ulist = Ptr->GetUsers();
347         for (int j = 0; j < ulist->size(); j++)
348         {
349                 char* o = (*ulist)[j];
350                 userrec* otheruser = (userrec*)o;
351                 if (otheruser->fd != FD_MAGIC_NUMBER)
352                         WriteServ(otheruser->fd,"%s",textbuffer);
353         }
354 }
355
356 /* write formatted text from a source user to all users on a channel except
357  * for the sender (for privmsg etc) */
358
359 void ChanExceptSender(chanrec* Ptr, userrec* user, char* text, ...)
360 {
361         if ((!Ptr) || (!user) || (!text))
362         {
363                 log(DEFAULT,"*** BUG *** ChanExceptSender was given an invalid parameter");
364                 return;
365         }
366         char textbuffer[MAXBUF];
367         va_list argsPtr;
368         va_start (argsPtr, text);
369         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
370         va_end(argsPtr);
371
372         std::vector<char*> *ulist = Ptr->GetUsers();
373         for (int j = 0; j < ulist->size(); j++)
374         {
375                 char* o = (*ulist)[j];
376                 userrec* otheruser = (userrec*)o;
377                 if ((otheruser->fd != FD_MAGIC_NUMBER) && (user != otheruser))
378                         WriteFrom(otheruser->fd,user,"%s",textbuffer);
379         }
380 }
381
382 std::string GetServerDescription(char* servername)
383 {
384         for (int j = 0; j < 32; j++)
385         {
386                 if (me[j] != NULL)
387                 {
388                         for (int k = 0; k < me[j]->connectors.size(); k++)
389                         {
390                                 if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),servername))
391                                 {
392                                         return me[j]->connectors[k].GetDescription();
393                                 }
394                         }
395                 }
396                 return ServerDesc; // not a remote server that can be found, it must be me.
397         }
398 }
399
400 /* write a formatted string to all users who share at least one common
401  * channel, including the source user e.g. for use in NICK */
402
403 void WriteCommon(userrec *u, char* text, ...)
404 {
405         if (!u)
406         {
407                 log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter");
408                 return;
409         }
410
411         if (u->registered != 7) {
412                 log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user");
413                 return;
414         }
415
416         char textbuffer[MAXBUF];
417         va_list argsPtr;
418         va_start (argsPtr, text);
419         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
420         va_end(argsPtr);
421
422         // FIX: Stops a message going to the same person more than once
423         bzero(&already_sent,65536);
424
425         bool sent_to_at_least_one = false;
426
427         for (int i = 0; i < MAXCHANS; i++)
428         {
429                 if (u->chans[i].channel)
430                 {
431                         std::vector<char*> *ulist = u->chans[i].channel->GetUsers();
432                         for (int j = 0; j < ulist->size(); j++)
433                         {
434                                 char* o = (*ulist)[j];
435                                 userrec* otheruser = (userrec*)o;
436                                 if ((otheruser->fd > 0) && (!already_sent[otheruser->fd]))
437                                 {
438                                         already_sent[otheruser->fd] = 1;
439                                         WriteFrom(otheruser->fd,u,"%s",textbuffer);
440                                         sent_to_at_least_one = true;
441                                 }
442                         }
443                 }
444         }
445         // if the user was not in any channels, no users will receive the text. Make sure the user
446         // receives their OWN message for WriteCommon
447         if (!sent_to_at_least_one)
448         {
449                 WriteFrom(u->fd,u,"%s",textbuffer);
450         }
451 }
452
453 /* write a formatted string to all users who share at least one common
454  * channel, NOT including the source user e.g. for use in QUIT */
455
456 void WriteCommonExcept(userrec *u, char* text, ...)
457 {
458         if (!u)
459         {
460                 log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter");
461                 return;
462         }
463
464         if (u->registered != 7) {
465                 log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user");
466                 return;
467         }
468
469         char textbuffer[MAXBUF];
470         va_list argsPtr;
471         va_start (argsPtr, text);
472         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
473         va_end(argsPtr);
474
475         bzero(&already_sent,65536);
476
477         for (int i = 0; i < MAXCHANS; i++)
478         {
479                 if (u->chans[i].channel)
480                 {
481                         std::vector<char*> *ulist = u->chans[i].channel->GetUsers();
482                         for (int j = 0; j < ulist->size(); j++)
483                         {
484                                 char* o = (*ulist)[j];
485                                 userrec* otheruser = (userrec*)o;
486                                 if (u != otheruser)
487                                 {
488                                         if ((otheruser->fd > 0) && (!already_sent[otheruser->fd]))
489                                         {
490                                                 already_sent[otheruser->fd] = 1;
491                                                 WriteFrom(otheruser->fd,u,"%s",textbuffer);
492                                         }
493                                 }
494                         }
495                 }
496         }
497 }
498
499 void WriteOpers(char* text, ...)
500 {
501         if (!text)
502         {
503                 log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
504                 return;
505         }
506
507         char textbuffer[MAXBUF];
508         va_list argsPtr;
509         va_start (argsPtr, text);
510         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
511         va_end(argsPtr);
512
513         for (std::vector<userrec*>::iterator i = all_opers.begin(); i != all_opers.end(); i++)
514         {
515                 userrec* a = *i;
516                 if ((a) && (a->fd != FD_MAGIC_NUMBER))
517                 {
518                         if (strchr(a->modes,'s'))
519                         {
520                                 // send server notices to all with +s
521                                 WriteServ(a->fd,"NOTICE %s :%s",a->nick,textbuffer);
522                         }
523                 }
524         }
525 }
526
527 void NoticeAllOpers(userrec *source, bool local_only, char* text, ...)
528 {
529         if ((!text) || (!source))
530         {
531                 log(DEFAULT,"*** BUG *** NoticeAllOpers was given an invalid parameter");
532                 return;
533         }
534
535         char textbuffer[MAXBUF];
536         va_list argsPtr;
537         va_start (argsPtr, text);
538         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
539         va_end(argsPtr);
540
541         for (std::vector<userrec*>::iterator i = all_opers.begin(); i != all_opers.end(); i++)
542         {
543                 userrec* a = *i;
544                 if ((a) && (a->fd != FD_MAGIC_NUMBER))
545                 {
546                         if (strchr(a->modes,'s'))
547                         {
548                                 // send server notices to all with +s
549                                 WriteServ(a->fd,"NOTICE %s :*** Notice From %s: %s",a->nick,source->nick,textbuffer);
550                         }
551                 }
552         }
553
554         if (!local_only)
555         {
556                 char buffer[MAXBUF];
557                 snprintf(buffer,MAXBUF,"V %s @* :%s",source->nick,textbuffer);
558                 NetSendToAll(buffer);
559         }
560 }
561 // returns TRUE of any users on channel C occupy server 'servername'.
562
563 bool ChanAnyOnThisServer(chanrec *c,char* servername)
564 {
565         log(DEBUG,"ChanAnyOnThisServer");
566
567         std::vector<char*> *ulist = c->GetUsers();
568         for (int j = 0; j < ulist->size(); j++)
569         {
570                 char* o = (*ulist)[j];
571                 userrec* user = (userrec*)o;
572                 if (!strcasecmp(user->server,servername))
573                         return true;
574         }
575         return false;
576 }
577
578 // returns true if user 'u' shares any common channels with any users on server 'servername'
579
580 bool CommonOnThisServer(userrec* u,const char* servername)
581 {
582         log(DEBUG,"ChanAnyOnThisServer");
583
584         for (int i = 0; i < MAXCHANS; i++)
585         {
586                 if (u->chans[i].channel)
587                 {
588                         std::vector<char*> *ulist = u->chans[i].channel->GetUsers();
589                         for (int j = 0; j < ulist->size(); j++)
590                         {
591                                 char* o = (*ulist)[j];
592                                 userrec* user = (userrec*)o;
593                                 if (!strcasecmp(user->server,servername))
594                                         return true;
595                         }
596                 }
597         }
598         return false;
599 }
600
601 void NetSendToCommon(userrec* u, char* s)
602 {
603         char buffer[MAXBUF];
604         snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
605
606         log(DEBUG,"NetSendToCommon: '%s' '%s'",u->nick,s);
607
608         std::string msg = buffer;
609         FOREACH_MOD OnPacketTransmit(msg,s);
610         strlcpy(buffer,msg.c_str(),MAXBUF);
611
612         for (int j = 0; j < 32; j++)
613         {
614                 if (me[j] != NULL)
615                 {
616                         for (int k = 0; k < me[j]->connectors.size(); k++)
617                         {
618                                 if (CommonOnThisServer(u,me[j]->connectors[k].GetServerName().c_str()))
619                                 {
620                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
621                                 }
622                         }
623                 }
624         }
625 }
626
627
628 void NetSendToAll(char* s)
629 {
630         char buffer[MAXBUF];
631         snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
632
633         log(DEBUG,"NetSendToAll: '%s'",s);
634
635         std::string msg = buffer;
636         FOREACH_MOD OnPacketTransmit(msg,s);
637         strlcpy(buffer,msg.c_str(),MAXBUF);
638
639         for (int j = 0; j < 32; j++)
640         {
641                 if (me[j] != NULL)
642                 {
643                         for (int k = 0; k < me[j]->connectors.size(); k++)
644                         {
645                                 me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
646                         }
647                 }
648         }
649 }
650
651
652 void NetSendToAll_WithSum(char* s,char* u)
653 {
654         char buffer[MAXBUF];
655         snprintf(buffer,MAXBUF,":%s %s",u,s);
656
657         log(DEBUG,"NetSendToAll: '%s'",s);
658
659         std::string msg = buffer;
660         FOREACH_MOD OnPacketTransmit(msg,s);
661         strlcpy(buffer,msg.c_str(),MAXBUF);
662
663         for (int j = 0; j < 32; j++)
664         {
665                 if (me[j] != NULL)
666                 {
667                         for (int k = 0; k < me[j]->connectors.size(); k++)
668                         {
669                                 me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
670                         }
671                 }
672         }
673 }
674
675 void NetSendToAllAlive(char* s)
676 {
677         char buffer[MAXBUF];
678         snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
679
680         log(DEBUG,"NetSendToAllAlive: '%s'",s);
681
682         std::string msg = buffer;
683         FOREACH_MOD OnPacketTransmit(msg,s);
684         strlcpy(buffer,msg.c_str(),MAXBUF);
685
686         for (int j = 0; j < 32; j++)
687         {
688                 if (me[j] != NULL)
689                 {
690                         for (int k = 0; k < me[j]->connectors.size(); k++)
691                         {
692                                 if (me[j]->connectors[k].GetState() != STATE_DISCONNECTED)
693                                 {
694                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
695                                 }
696                                 else
697                                 {
698                                         log(DEBUG,"%s is dead, not sending to it.",me[j]->connectors[k].GetServerName().c_str());
699                                 }
700                         }
701                 }
702         }
703 }
704
705
706 void NetSendToOne(char* target,char* s)
707 {
708         char buffer[MAXBUF];
709         snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
710
711         log(DEBUG,"NetSendToOne: '%s' '%s'",target,s);
712
713         std::string msg = buffer;
714         FOREACH_MOD OnPacketTransmit(msg,s);
715         strlcpy(buffer,msg.c_str(),MAXBUF);
716
717         for (int j = 0; j < 32; j++)
718         {
719                 if (me[j] != NULL)
720                 {
721                         for (int k = 0; k < me[j]->connectors.size(); k++)
722                         {
723                                 if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
724                                 {
725                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
726                                 }
727                         }
728                 }
729         }
730 }
731
732 void NetSendToAllExcept(const char* target,char* s)
733 {
734         char buffer[MAXBUF];
735         snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
736
737         log(DEBUG,"NetSendToAllExcept: '%s' '%s'",target,s);
738
739         std::string msg = buffer;
740         FOREACH_MOD OnPacketTransmit(msg,s);
741         strlcpy(buffer,msg.c_str(),MAXBUF);
742
743         for (int j = 0; j < 32; j++)
744         {
745                 if (me[j] != NULL)
746                 {
747                         for (int k = 0; k < me[j]->connectors.size(); k++)
748                         {
749                                 if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
750                                 {
751                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
752                                 }
753                         }
754                 }
755         }
756 }
757
758 void NetSendToAllExcept_WithSum(const char* target,char* s,char* u)
759 {
760         char buffer[MAXBUF];
761         snprintf(buffer,MAXBUF,":%s %s",u,s);
762
763         log(DEBUG,"NetSendToAllExcept: '%s' '%s'",target,s);
764
765         std::string msg = buffer;
766         FOREACH_MOD OnPacketTransmit(msg,s);
767         strlcpy(buffer,msg.c_str(),MAXBUF);
768
769         for (int j = 0; j < 32; j++)
770         {
771                 if (me[j] != NULL)
772                 {
773                         for (int k = 0; k < me[j]->connectors.size(); k++)
774                         {
775                                 if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
776                                 {
777                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
778                                 }
779                         }
780                 }
781         }
782 }
783
784
785 void WriteMode(const char* modes, int flags, const char* text, ...)
786 {
787         if ((!text) || (!modes) || (!flags))
788         {
789                 log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
790                 return;
791         }
792
793         char textbuffer[MAXBUF];
794         va_list argsPtr;
795         va_start (argsPtr, text);
796         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
797         va_end(argsPtr);
798         int modelen = strlen(modes);
799
800         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
801         {
802                 if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
803                 {
804                         bool send_to_user = false;
805
806                         if (flags == WM_AND)
807                         {
808                                 send_to_user = true;
809                                 for (int n = 0; n < modelen; n++)
810                                 {
811                                         if (!hasumode(i->second,modes[n]))
812                                         {
813                                                 send_to_user = false;
814                                                 break;
815                                         }
816                                 }
817                         }
818                         else if (flags == WM_OR)
819                         {
820                                 send_to_user = false;
821                                 for (int n = 0; n < modelen; n++)
822                                 {
823                                         if (hasumode(i->second,modes[n]))
824                                         {
825                                                 send_to_user = true;
826                                                 break;
827                                         }
828                                 }
829                         }
830
831                         if (send_to_user)
832                         {
833                                 WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer);
834                         }
835                 }
836         }
837 }
838
839 void NoticeAll(userrec *source, bool local_only, char* text, ...)
840 {
841         if ((!text) || (!source))
842         {
843                 log(DEFAULT,"*** BUG *** NoticeAll was given an invalid parameter");
844                 return;
845         }
846
847         char textbuffer[MAXBUF];
848         va_list argsPtr;
849         va_start (argsPtr, text);
850         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
851         va_end(argsPtr);
852
853         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
854         {
855                 if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
856                 {
857                         WriteFrom(i->second->fd,source,"NOTICE $* :%s",textbuffer);
858                 }
859         }
860
861         if (!local_only)
862         {
863                 char buffer[MAXBUF];
864                 snprintf(buffer,MAXBUF,"V %s * :%s",source->nick,textbuffer);
865                 NetSendToAll(buffer);
866         }
867
868 }
869
870
871 void WriteWallOps(userrec *source, bool local_only, char* text, ...)
872 {
873         if ((!text) || (!source))
874         {
875                 log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
876                 return;
877         }
878
879         char textbuffer[MAXBUF];
880         va_list argsPtr;
881         va_start (argsPtr, text);
882         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
883         va_end(argsPtr);
884
885         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
886         {
887                 if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
888                 {
889                         if (strchr(i->second->modes,'w'))
890                         {
891                                 WriteTo(source,i->second,"WALLOPS :%s",textbuffer);
892                         }
893                 }
894         }
895
896         if (!local_only)
897         {
898                 char buffer[MAXBUF];
899                 snprintf(buffer,MAXBUF,"@ %s :%s",source->nick,textbuffer);
900                 NetSendToAll(buffer);
901         }
902 }
903
904 /* convert a string to lowercase. Note following special circumstances
905  * taken from RFC 1459. Many "official" server branches still hold to this
906  * rule so i will too;
907  *
908  *  Because of IRC's scandanavian origin, the characters {}| are
909  *  considered to be the lower case equivalents of the characters []\,
910  *  respectively. This is a critical issue when determining the
911  *  equivalence of two nicknames.
912  */
913
914 void strlower(char *n)
915 {
916         if (n)
917         {
918                 for (char* t = n; *t; t++)
919                         *t = lowermap[*t];
920         }
921 }
922
923 /* Find a user record by nickname and return a pointer to it */
924
925 userrec* Find(std::string nick)
926 {
927         user_hash::iterator iter = clientlist.find(nick);
928
929         if (iter == clientlist.end())
930                 /* Couldn't find it */
931                 return NULL;
932
933         return iter->second;
934 }
935
936 /* find a channel record by channel name and return a pointer to it */
937
938 chanrec* FindChan(const char* chan)
939 {
940         if (!chan)
941         {
942                 log(DEFAULT,"*** BUG *** Findchan was given an invalid parameter");
943                 return NULL;
944         }
945
946         chan_hash::iterator iter = chanlist.find(chan);
947
948         if (iter == chanlist.end())
949                 /* Couldn't find it */
950                 return NULL;
951
952         return iter->second;
953 }
954
955
956 long GetMaxBans(char* name)
957 {
958         char CM[MAXBUF];
959         for (int count = 0; count < ConfValueEnum("banlist",&config_f); count++)
960         {
961                 ConfValue("banlist","chan",count,CM,&config_f);
962                 if (match(name,CM))
963                 {
964                         ConfValue("banlist","limit",count,CM,&config_f);
965                         return atoi(CM);
966                 }
967         }
968         return 64;
969 }
970
971 void purge_empty_chans(userrec* u)
972 {
973
974         int go_again = 1, purge = 0;
975
976         // firstly decrement the count on each channel
977         for (int f = 0; f < MAXCHANS; f++)
978         {
979                 if (u->chans[f].channel)
980                 {
981                         u->chans[f].channel->DelUser((char*)u);
982                 }
983         }
984
985         for (int i = 0; i < MAXCHANS; i++)
986         {
987                 if (u->chans[i].channel)
988                 {
989                         if (!usercount(u->chans[i].channel))
990                         {
991                                 chan_hash::iterator i2 = chanlist.find(u->chans[i].channel->name);
992                                 /* kill the record */
993                                 if (i2 != chanlist.end())
994                                 {
995                                         log(DEBUG,"del_channel: destroyed: %s",i2->second->name);
996                                         if (i2->second)
997                                                 delete i2->second;
998                                         chanlist.erase(i2);
999                                         go_again = 1;
1000                                         purge++;
1001                                         u->chans[i].channel = NULL;
1002                                 }
1003                         }
1004                         else
1005                         {
1006                                 log(DEBUG,"skipped purge for %s",u->chans[i].channel->name);
1007                         }
1008                 }
1009         }
1010         log(DEBUG,"completed channel purge, killed %lu",(unsigned long)purge);
1011
1012         DeleteOper(u);
1013 }
1014
1015
1016 char scratch[MAXBUF];
1017 char sparam[MAXBUF];
1018
1019 char* chanmodes(chanrec *chan)
1020 {
1021         if (!chan)
1022         {
1023                 log(DEFAULT,"*** BUG *** chanmodes was given an invalid parameter");
1024                 strcpy(scratch,"");
1025                 return scratch;
1026         }
1027
1028         strcpy(scratch,"");
1029         strcpy(sparam,"");
1030         if (chan->binarymodes & CM_NOEXTERNAL)
1031         {
1032                 strlcat(scratch,"n",MAXMODES);
1033         }
1034         if (chan->binarymodes & CM_TOPICLOCK)
1035         {
1036                 strlcat(scratch,"t",MAXMODES);
1037         }
1038         if (chan->key[0])
1039         {
1040                 strlcat(scratch,"k",MAXMODES);
1041         }
1042         if (chan->limit)
1043         {
1044                 strlcat(scratch,"l",MAXMODES);
1045         }
1046         if (chan->binarymodes & CM_INVITEONLY)
1047         {
1048                 strlcat(scratch,"i",MAXMODES);
1049         }
1050         if (chan->binarymodes & CM_MODERATED)
1051         {
1052                 strlcat(scratch,"m",MAXMODES);
1053         }
1054         if (chan->binarymodes & CM_SECRET)
1055         {
1056                 strlcat(scratch,"s",MAXMODES);
1057         }
1058         if (chan->binarymodes & CM_PRIVATE)
1059         {
1060                 strlcat(scratch,"p",MAXMODES);
1061         }
1062         if (chan->key[0])
1063         {
1064                 strlcat(sparam," ",MAXBUF);
1065                 strlcat(sparam,chan->key,MAXBUF);
1066         }
1067         if (chan->limit)
1068         {
1069                 char foo[24];
1070                 sprintf(foo," %lu",(unsigned long)chan->limit);
1071                 strlcat(sparam,foo,MAXBUF);
1072         }
1073         if (*chan->custom_modes)
1074         {
1075                 strlcat(scratch,chan->custom_modes,MAXMODES);
1076                 for (int z = 0; chan->custom_modes[z] != 0; z++)
1077                 {
1078                         std::string extparam = chan->GetModeParameter(chan->custom_modes[z]);
1079                         if (extparam != "")
1080                         {
1081                                 strlcat(sparam," ",MAXBUF);
1082                                 strlcat(sparam,extparam.c_str(),MAXBUF);
1083                         }
1084                 }
1085         }
1086         log(DEBUG,"chanmodes: %s %s%s",chan->name,scratch,sparam);
1087         strlcat(scratch,sparam,MAXMODES);
1088         return scratch;
1089 }
1090
1091
1092 /* compile a userlist of a channel into a string, each nick seperated by
1093  * spaces and op, voice etc status shown as @ and + */
1094
1095 void userlist(userrec *user,chanrec *c)
1096 {
1097         if ((!c) || (!user))
1098         {
1099                 log(DEFAULT,"*** BUG *** userlist was given an invalid parameter");
1100                 return;
1101         }
1102
1103         snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1104
1105         std::vector<char*> *ulist = c->GetUsers();
1106         for (int i = 0; i < ulist->size(); i++)
1107         {
1108                 char* o = (*ulist)[i];
1109                 userrec* otheruser = (userrec*)o;
1110                 if ((!has_channel(user,c)) && (strchr(otheruser->modes,'i')))
1111                 {
1112                         /* user is +i, and source not on the channel, does not show
1113                          * nick in NAMES list */
1114                         continue;
1115                 }
1116                 strlcat(list,cmode(otheruser,c),MAXBUF);
1117                 strlcat(list,otheruser->nick,MAXBUF);
1118                 strlcat(list," ",MAXBUF);
1119                 if (strlen(list)>(480-NICKMAX))
1120                 {
1121                         /* list overflowed into
1122                          * multiple numerics */
1123                         WriteServ(user->fd,"%s",list);
1124                         snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1125                 }
1126         }
1127         /* if whats left in the list isnt empty, send it */
1128         if (list[strlen(list)-1] != ':')
1129         {
1130                 WriteServ(user->fd,"%s",list);
1131         }
1132 }
1133
1134 /* return a count of the users on a specific channel accounting for
1135  * invisible users who won't increase the count. e.g. for /LIST */
1136
1137 int usercount_i(chanrec *c)
1138 {
1139         int count = 0;
1140
1141         if (!c)
1142         {
1143                 log(DEFAULT,"*** BUG *** usercount_i was given an invalid parameter");
1144                 return 0;
1145         }
1146
1147         strcpy(list,"");
1148         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1149         {
1150                 if (i->second)
1151                 {
1152                         if (has_channel(i->second,c))
1153                         {
1154                                 if (isnick(i->second->nick))
1155                                 {
1156                                         if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
1157                                         {
1158                                                 /* user is +i, and source not on the channel, does not show
1159                                                  * nick in NAMES list */
1160                                                 continue;
1161                                         }
1162                                         count++;
1163                                 }
1164                         }
1165                 }
1166         }
1167         log(DEBUG,"usercount_i: %s %lu",c->name,(unsigned long)count);
1168         return count;
1169 }
1170
1171
1172 int usercount(chanrec *c)
1173 {
1174         if (!c)
1175         {
1176                 log(DEFAULT,"*** BUG *** usercount was given an invalid parameter");
1177                 return 0;
1178         }
1179         int count = c->GetUserCounter();
1180         log(DEBUG,"usercount: %s %lu",c->name,(unsigned long)count);
1181         return count;
1182 }
1183
1184
1185 // looks up a users password for their connection class (<ALLOW>/<DENY> tags)
1186
1187 char* Passwd(userrec *user)
1188 {
1189         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
1190         {
1191                 if (match(user->host,i->host) && (i->type == CC_ALLOW))
1192                 {
1193                         return i->pass;
1194                 }
1195         }
1196         return "";
1197 }
1198
1199 bool IsDenied(userrec *user)
1200 {
1201         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
1202         {
1203                 if (match(user->host,i->host) && (i->type == CC_DENY))
1204                 {
1205                         return true;
1206                 }
1207         }
1208         return false;
1209 }
1210
1211
1212
1213
1214 /* sends out an error notice to all connected clients (not to be used
1215  * lightly!) */
1216
1217 void send_error(char *s)
1218 {
1219         log(DEBUG,"send_error: %s",s);
1220         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1221         {
1222                 if (isnick(i->second->nick))
1223                 {
1224                         WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,s);
1225                 }
1226                 else
1227                 {
1228                         // fix - unregistered connections receive ERROR, not NOTICE
1229                         Write(i->second->fd,"ERROR :%s",s);
1230                 }
1231         }
1232 }
1233
1234 void Error(int status)
1235 {
1236         signal (SIGALRM, SIG_IGN);
1237         signal (SIGPIPE, SIG_IGN);
1238         signal (SIGTERM, SIG_IGN);
1239         signal (SIGABRT, SIG_IGN);
1240         signal (SIGSEGV, SIG_IGN);
1241         signal (SIGURG, SIG_IGN);
1242         signal (SIGKILL, SIG_IGN);
1243         log(DEFAULT,"*** fell down a pothole in the road to perfection ***");
1244         send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*");
1245         Exit(status);
1246 }
1247
1248 // this function counts all users connected, wether they are registered or NOT.
1249 int usercnt(void)
1250 {
1251         return clientlist.size();
1252 }
1253
1254 // this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state
1255 int registered_usercount(void)
1256 {
1257         int c = 0;
1258         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1259         {
1260                 if ((i->second->fd) && (isnick(i->second->nick))) c++;
1261         }
1262         return c;
1263 }
1264
1265 int usercount_invisible(void)
1266 {
1267         int c = 0;
1268
1269         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1270         {
1271                 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'i'))) c++;
1272         }
1273         return c;
1274 }
1275
1276 int usercount_opers(void)
1277 {
1278         int c = 0;
1279
1280         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1281         {
1282                 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'o'))) c++;
1283         }
1284         return c;
1285 }
1286
1287 int usercount_unknown(void)
1288 {
1289         int c = 0;
1290
1291         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1292         {
1293                 if ((i->second->fd) && (i->second->registered != 7))
1294                         c++;
1295         }
1296         return c;
1297 }
1298
1299 long chancount(void)
1300 {
1301         return chanlist.size();
1302 }
1303
1304 long count_servs(void)
1305 {
1306         int c = 0;
1307         for (int i = 0; i < 32; i++)
1308         {
1309                 if (me[i] != NULL)
1310                 {
1311                         for (vector<ircd_connector>::iterator j = me[i]->connectors.begin(); j != me[i]->connectors.end(); j++)
1312                         {
1313                                 if (strcasecmp(j->GetServerName().c_str(),ServerName))
1314                                 {
1315                                         c++;
1316                                 }
1317                         }
1318                 }
1319         }
1320         return c;
1321 }
1322
1323 long servercount(void)
1324 {
1325         return count_servs()+1;
1326 }
1327
1328 long local_count()
1329 {
1330         int c = 0;
1331         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1332         {
1333                 if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,ServerName))) c++;
1334         }
1335         return c;
1336 }
1337
1338 void ShowMOTD(userrec *user)
1339 {
1340         char buf[65536];
1341         std::string WholeMOTD = "";
1342         if (!MOTD.size())
1343         {
1344                 WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
1345                 return;
1346         }
1347         snprintf(buf,65535,":%s 375 %s :- %s message of the day\r\n", ServerName, user->nick, ServerName);
1348         WholeMOTD = WholeMOTD + buf;
1349         for (int i = 0; i != MOTD.size(); i++)
1350         {
1351                 snprintf(buf,65535,":%s 372 %s :- %s\r\n", ServerName, user->nick, MOTD[i].c_str());
1352                 WholeMOTD = WholeMOTD + buf;
1353         }
1354         snprintf(buf,65535,":%s 376 %s :End of message of the day.\r\n", ServerName, user->nick);
1355         WholeMOTD = WholeMOTD + buf;
1356         // only one write operation
1357         user->AddWriteBuf(WholeMOTD);
1358         statsSent += WholeMOTD.length();
1359 }
1360
1361 void ShowRULES(userrec *user)
1362 {
1363         if (!RULES.size())
1364         {
1365                 WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
1366                 return;
1367         }
1368         WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,ServerName);
1369         for (int i = 0; i != RULES.size(); i++)
1370         {
1371                                 WriteServ(user->fd,"NOTICE %s :%s",user->nick,RULES[i].c_str());
1372         }
1373         WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,ServerName);
1374 }
1375
1376 // this returns 1 when all modules are satisfied that the user should be allowed onto the irc server
1377 // (until this returns true, a user will block in the waiting state, waiting to connect up to the
1378 // registration timeout maximum seconds)
1379 bool AllModulesReportReady(userrec* user)
1380 {
1381         for (int i = 0; i <= MODCOUNT; i++)
1382         {
1383                 int res = modules[i]->OnCheckReady(user);
1384                         if (!res)
1385                                 return false;
1386         }
1387         return true;
1388 }
1389
1390 char islast(const char* s)
1391 {
1392         char c = '`';
1393         for (int j = 0; j < 32; j++)
1394         {
1395                 if (me[j] != NULL)
1396                 {
1397                         for (int k = 0; k < me[j]->connectors.size(); k++)
1398                         {
1399                                 if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),s))
1400                                 {
1401                                         c = '|';
1402                                 }
1403                                 if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),s))
1404                                 {
1405                                         c = '`';
1406                                 }
1407                         }
1408                 }
1409         }
1410         return c;
1411 }
1412
1413 long map_count(const char* s)
1414 {
1415         int c = 0;
1416         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1417         {
1418                 if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,s))) c++;
1419         }
1420         return c;
1421 }
1422
1423 void createcommand(char* cmd, handlerfunc f, char flags, int minparams,char* source)
1424 {
1425         command_t comm;
1426         /* create the command and push it onto the table */
1427         strlcpy(comm.command,cmd,MAXBUF);
1428         strlcpy(comm.source,source,MAXBUF);
1429         comm.handler_function = f;
1430         comm.flags_needed = flags;
1431         comm.min_params = minparams;
1432         comm.use_count = 0;
1433         comm.total_bytes = 0;
1434         cmdlist.push_back(comm);
1435         log(DEBUG,"Added command %s (%lu parameters)",cmd,(unsigned long)minparams);
1436 }
1437
1438
1439 void SetupCommandTable(void)
1440 {
1441         createcommand("USER",handle_user,0,4,"<core>");
1442         createcommand("NICK",handle_nick,0,1,"<core>");
1443         createcommand("QUIT",handle_quit,0,0,"<core>");
1444         createcommand("VERSION",handle_version,0,0,"<core>");
1445         createcommand("PING",handle_ping,0,1,"<core>");
1446         createcommand("PONG",handle_pong,0,1,"<core>");
1447         createcommand("ADMIN",handle_admin,0,0,"<core>");
1448         createcommand("PRIVMSG",handle_privmsg,0,2,"<core>");
1449         createcommand("INFO",handle_info,0,0,"<core>");
1450         createcommand("TIME",handle_time,0,0,"<core>");
1451         createcommand("WHOIS",handle_whois,0,1,"<core>");
1452         createcommand("WALLOPS",handle_wallops,'o',1,"<core>");
1453         createcommand("NOTICE",handle_notice,0,2,"<core>");
1454         createcommand("JOIN",handle_join,0,1,"<core>");
1455         createcommand("NAMES",handle_names,0,0,"<core>");
1456         createcommand("PART",handle_part,0,1,"<core>");
1457         createcommand("KICK",handle_kick,0,2,"<core>");
1458         createcommand("MODE",handle_mode,0,1,"<core>");
1459         createcommand("TOPIC",handle_topic,0,1,"<core>");
1460         createcommand("WHO",handle_who,0,1,"<core>");
1461         createcommand("MOTD",handle_motd,0,0,"<core>");
1462         createcommand("RULES",handle_rules,0,0,"<core>");
1463         createcommand("OPER",handle_oper,0,2,"<core>");
1464         createcommand("LIST",handle_list,0,0,"<core>");
1465         createcommand("DIE",handle_die,'o',1,"<core>");
1466         createcommand("RESTART",handle_restart,'o',1,"<core>");
1467         createcommand("KILL",handle_kill,'o',2,"<core>");
1468         createcommand("REHASH",handle_rehash,'o',0,"<core>");
1469         createcommand("LUSERS",handle_lusers,0,0,"<core>");
1470         createcommand("STATS",handle_stats,0,1,"<core>");
1471         createcommand("USERHOST",handle_userhost,0,1,"<core>");
1472         createcommand("AWAY",handle_away,0,0,"<core>");
1473         createcommand("ISON",handle_ison,0,0,"<core>");
1474         createcommand("SUMMON",handle_summon,0,0,"<core>");
1475         createcommand("USERS",handle_users,0,0,"<core>");
1476         createcommand("INVITE",handle_invite,0,0,"<core>");
1477         createcommand("PASS",handle_pass,0,1,"<core>");
1478         createcommand("TRACE",handle_trace,'o',0,"<core>");
1479         createcommand("WHOWAS",handle_whowas,0,1,"<core>");
1480         createcommand("CONNECT",handle_connect,'o',1,"<core>");
1481         createcommand("SQUIT",handle_squit,'o',0,"<core>");
1482         createcommand("MODULES",handle_modules,0,0,"<core>");
1483         createcommand("LINKS",handle_links,0,0,"<core>");
1484         createcommand("MAP",handle_map,0,0,"<core>");
1485         createcommand("KLINE",handle_kline,'o',1,"<core>");
1486         createcommand("GLINE",handle_gline,'o',1,"<core>");
1487         createcommand("ZLINE",handle_zline,'o',1,"<core>");
1488         createcommand("QLINE",handle_qline,'o',1,"<core>");
1489         createcommand("ELINE",handle_eline,'o',1,"<core>");
1490         createcommand("LOADMODULE",handle_loadmodule,'o',1,"<core>");
1491         createcommand("UNLOADMODULE",handle_unloadmodule,'o',1,"<core>");
1492         createcommand("SERVER",handle_server,0,0,"<core>");
1493 }
1494
1495 bool DirValid(char* dirandfile)
1496 {
1497         char work[MAXBUF];
1498         strlcpy(work,dirandfile,MAXBUF);
1499         int p = strlen(work);
1500         // we just want the dir
1501         while (strlen(work))
1502         {
1503                 if (work[p] == '/')
1504                 {
1505                         work[p] = '\0';
1506                         break;
1507                 }
1508                 work[p--] = '\0';
1509         }
1510         char buffer[MAXBUF], otherdir[MAXBUF];
1511         // Get the current working directory
1512         if( getcwd( buffer, MAXBUF ) == NULL )
1513                 return false;
1514         chdir(work);
1515         if( getcwd( otherdir, MAXBUF ) == NULL )
1516                 return false;
1517         chdir(buffer);
1518         if (strlen(otherdir) >= strlen(work))
1519         {
1520                 otherdir[strlen(work)] = '\0';
1521                 if (!strcmp(otherdir,work))
1522                 {
1523                         return true;
1524                 }
1525                 return false;
1526         }
1527         else return false;
1528 }
1529
1530 std::string GetFullProgDir(char** argv, int argc)
1531 {
1532         char work[MAXBUF];
1533         strlcpy(work,argv[0],MAXBUF);
1534         int p = strlen(work);
1535         // we just want the dir
1536         while (strlen(work))
1537         {
1538                 if (work[p] == '/')
1539                 {
1540                         work[p] = '\0';
1541                         break;
1542                 }
1543                 work[p--] = '\0';
1544         }
1545         char buffer[MAXBUF], otherdir[MAXBUF];
1546         // Get the current working directory
1547         if( getcwd( buffer, MAXBUF ) == NULL )
1548                 return "";
1549         chdir(work);
1550         if( getcwd( otherdir, MAXBUF ) == NULL )
1551                 return "";
1552         chdir(buffer);
1553         return otherdir;
1554 }
1555