]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/helperfuncs.cpp
Fixed fd_Setsize in cygwin
[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 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 <fcntl.h>
25 #include <sys/errno.h>
26 #include <time.h>
27 #include <string>
28 #ifdef GCC3
29 #include <ext/hash_map>
30 #else
31 #include <hash_map>
32 #endif
33 #include <sstream>
34 #include <vector>
35 #include <deque>
36 #include <stdarg.h>
37 #include "connection.h"
38 #include "users.h"
39 #include "servers.h"
40 #include "ctables.h"
41 #include "globals.h"
42 #include "modules.h"
43 #include "dynamic.h"
44 #include "wildcard.h"
45 #include "message.h"
46 #include "mode.h"
47 #include "xline.h"
48 #include "commands.h"
49 #include "inspstring.h"
50 #include "helperfuncs.h"
51 #include "hashcomp.h"
52
53 extern int MODCOUNT;
54 extern std::vector<Module*> 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*> all_opers;
78
79 extern ClassVector Classes;
80
81 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;
82 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHashComp> chan_hash;
83 typedef std::deque<command_t> 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         memset(&already_sent,0,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         memset(&already_sent,0,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         if (*s == ':')
605         {
606                         snprintf(buffer,MAXBUF,"%s",s);
607         }
608         else snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
609
610         log(DEBUG,"NetSendToCommon: '%s' '%s'",u->nick,s);
611
612         std::string msg = buffer;
613         FOREACH_MOD OnPacketTransmit(msg,s);
614         strlcpy(buffer,msg.c_str(),MAXBUF);
615
616         for (int j = 0; j < 32; j++)
617         {
618                 if (me[j] != NULL)
619                 {
620                         for (int k = 0; k < me[j]->connectors.size(); k++)
621                         {
622                                 if (CommonOnThisServer(u,me[j]->connectors[k].GetServerName().c_str()))
623                                 {
624                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
625                                 }
626                         }
627                 }
628         }
629 }
630
631
632 void NetSendToAll(char* s)
633 {
634         char buffer[MAXBUF];
635         if (*s == ':')
636         {
637                         snprintf(buffer,MAXBUF,"%s",s);
638         }
639         else snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
640
641         log(DEBUG,"NetSendToAll: '%s'",s);
642
643         std::string msg = buffer;
644         FOREACH_MOD OnPacketTransmit(msg,s);
645         strlcpy(buffer,msg.c_str(),MAXBUF);
646
647         for (int j = 0; j < 32; j++)
648         {
649                 if (me[j] != NULL)
650                 {
651                         for (int k = 0; k < me[j]->connectors.size(); k++)
652                         {
653                                 me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
654                         }
655                 }
656         }
657 }
658
659
660 void NetSendToAll_WithSum(char* s,char* u)
661 {
662         char buffer[MAXBUF];
663         if (*s == ':')
664         {
665                         snprintf(buffer,MAXBUF,"%s",s);
666         }
667         else snprintf(buffer,MAXBUF,":%s %s",u,s);
668
669         log(DEBUG,"NetSendToAll: '%s'",s);
670
671         std::string msg = buffer;
672         FOREACH_MOD OnPacketTransmit(msg,s);
673         strlcpy(buffer,msg.c_str(),MAXBUF);
674
675         for (int j = 0; j < 32; j++)
676         {
677                 if (me[j] != NULL)
678                 {
679                         for (int k = 0; k < me[j]->connectors.size(); k++)
680                         {
681                                 me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
682                         }
683                 }
684         }
685 }
686
687 void NetSendToAllAlive(char* s)
688 {
689         char buffer[MAXBUF];
690         if (*s == ':')
691         {
692                         snprintf(buffer,MAXBUF,"%s",s);
693         }
694         else snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
695
696         log(DEBUG,"NetSendToAllAlive: '%s'",s);
697
698         std::string msg = buffer;
699         FOREACH_MOD OnPacketTransmit(msg,s);
700         strlcpy(buffer,msg.c_str(),MAXBUF);
701
702         for (int j = 0; j < 32; j++)
703         {
704                 if (me[j] != NULL)
705                 {
706                         for (int k = 0; k < me[j]->connectors.size(); k++)
707                         {
708                                 if (me[j]->connectors[k].GetState() != STATE_DISCONNECTED)
709                                 {
710                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
711                                 }
712                                 else
713                                 {
714                                         log(DEBUG,"%s is dead, not sending to it.",me[j]->connectors[k].GetServerName().c_str());
715                                 }
716                         }
717                 }
718         }
719 }
720
721
722 void NetSendToOne(char* target,char* s)
723 {
724         char buffer[MAXBUF];
725         if (*s == ':')
726         {
727                         snprintf(buffer,MAXBUF,"%s",s);
728         }
729         else snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
730
731         log(DEBUG,"NetSendToOne: '%s' '%s'",target,s);
732
733         std::string msg = buffer;
734         FOREACH_MOD OnPacketTransmit(msg,s);
735         strlcpy(buffer,msg.c_str(),MAXBUF);
736
737         for (int j = 0; j < 32; j++)
738         {
739                 if (me[j] != NULL)
740                 {
741                         for (int k = 0; k < me[j]->connectors.size(); k++)
742                         {
743                                 if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
744                                 {
745                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
746                                 }
747                         }
748                 }
749         }
750 }
751
752 void NetSendToAllExcept(const char* target,char* s)
753 {
754         char buffer[MAXBUF];
755         if (*s == ':')
756         {
757                         snprintf(buffer,MAXBUF,"%s",s);
758         }
759         else snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
760
761         log(DEBUG,"NetSendToAllExcept: '%s' '%s'",target,s);
762
763         std::string msg = buffer;
764         FOREACH_MOD OnPacketTransmit(msg,s);
765         strlcpy(buffer,msg.c_str(),MAXBUF);
766
767         for (int j = 0; j < 32; j++)
768         {
769                 if (me[j] != NULL)
770                 {
771                         for (int k = 0; k < me[j]->connectors.size(); k++)
772                         {
773                                 if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
774                                 {
775                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
776                                 }
777                         }
778                 }
779         }
780 }
781
782 void NetSendToAllExcept_WithSum(const char* target,char* s,char* u)
783 {
784         char buffer[MAXBUF];
785         if (*s == ':')
786         {
787                         snprintf(buffer,MAXBUF,"%s",s);
788         }
789         else snprintf(buffer,MAXBUF,":%s %s",u,s);
790
791         log(DEBUG,"NetSendToAllExcept: '%s' '%s'",target,s);
792
793         std::string msg = buffer;
794         FOREACH_MOD OnPacketTransmit(msg,s);
795         strlcpy(buffer,msg.c_str(),MAXBUF);
796
797         for (int j = 0; j < 32; j++)
798         {
799                 if (me[j] != NULL)
800                 {
801                         for (int k = 0; k < me[j]->connectors.size(); k++)
802                         {
803                                 if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
804                                 {
805                                         me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
806                                 }
807                         }
808                 }
809         }
810 }
811
812
813 void WriteMode(const char* modes, int flags, const char* text, ...)
814 {
815         if ((!text) || (!modes) || (!flags))
816         {
817                 log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
818                 return;
819         }
820
821         char textbuffer[MAXBUF];
822         va_list argsPtr;
823         va_start (argsPtr, text);
824         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
825         va_end(argsPtr);
826         int modelen = strlen(modes);
827
828         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
829         {
830                 if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
831                 {
832                         bool send_to_user = false;
833
834                         if (flags == WM_AND)
835                         {
836                                 send_to_user = true;
837                                 for (int n = 0; n < modelen; n++)
838                                 {
839                                         if (!hasumode(i->second,modes[n]))
840                                         {
841                                                 send_to_user = false;
842                                                 break;
843                                         }
844                                 }
845                         }
846                         else if (flags == WM_OR)
847                         {
848                                 send_to_user = false;
849                                 for (int n = 0; n < modelen; n++)
850                                 {
851                                         if (hasumode(i->second,modes[n]))
852                                         {
853                                                 send_to_user = true;
854                                                 break;
855                                         }
856                                 }
857                         }
858
859                         if (send_to_user)
860                         {
861                                 WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer);
862                         }
863                 }
864         }
865 }
866
867 void NoticeAll(userrec *source, bool local_only, char* text, ...)
868 {
869         if ((!text) || (!source))
870         {
871                 log(DEFAULT,"*** BUG *** NoticeAll was given an invalid parameter");
872                 return;
873         }
874
875         char textbuffer[MAXBUF];
876         va_list argsPtr;
877         va_start (argsPtr, text);
878         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
879         va_end(argsPtr);
880
881         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
882         {
883                 if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
884                 {
885                         WriteFrom(i->second->fd,source,"NOTICE $* :%s",textbuffer);
886                 }
887         }
888
889         if (!local_only)
890         {
891                 char buffer[MAXBUF];
892                 snprintf(buffer,MAXBUF,"V %s * :%s",source->nick,textbuffer);
893                 NetSendToAll(buffer);
894         }
895
896 }
897
898
899 void WriteWallOps(userrec *source, bool local_only, char* text, ...)
900 {
901         if ((!text) || (!source))
902         {
903                 log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
904                 return;
905         }
906
907         char textbuffer[MAXBUF];
908         va_list argsPtr;
909         va_start (argsPtr, text);
910         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
911         va_end(argsPtr);
912
913         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
914         {
915                 if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
916                 {
917                         if (strchr(i->second->modes,'w'))
918                         {
919                                 WriteTo(source,i->second,"WALLOPS :%s",textbuffer);
920                         }
921                 }
922         }
923
924         if (!local_only)
925         {
926                 char buffer[MAXBUF];
927                 snprintf(buffer,MAXBUF,"@ %s :%s",source->nick,textbuffer);
928                 NetSendToAll(buffer);
929         }
930 }
931
932 /* convert a string to lowercase. Note following special circumstances
933  * taken from RFC 1459. Many "official" server branches still hold to this
934  * rule so i will too;
935  *
936  *  Because of IRC's scandanavian origin, the characters {}| are
937  *  considered to be the lower case equivalents of the characters []\,
938  *  respectively. This is a critical issue when determining the
939  *  equivalence of two nicknames.
940  */
941
942 void strlower(char *n)
943 {
944         if (n)
945         {
946                 for (char* t = n; *t; t++)
947                         *t = lowermap[*t];
948         }
949 }
950
951 /* Find a user record by nickname and return a pointer to it */
952
953 userrec* Find(std::string nick)
954 {
955         user_hash::iterator iter = clientlist.find(nick);
956
957         if (iter == clientlist.end())
958                 /* Couldn't find it */
959                 return NULL;
960
961         return iter->second;
962 }
963
964 /* find a channel record by channel name and return a pointer to it */
965
966 chanrec* FindChan(const char* chan)
967 {
968         if (!chan)
969         {
970                 log(DEFAULT,"*** BUG *** Findchan was given an invalid parameter");
971                 return NULL;
972         }
973
974         chan_hash::iterator iter = chanlist.find(chan);
975
976         if (iter == chanlist.end())
977                 /* Couldn't find it */
978                 return NULL;
979
980         return iter->second;
981 }
982
983
984 long GetMaxBans(char* name)
985 {
986         char CM[MAXBUF];
987         for (int count = 0; count < ConfValueEnum("banlist",&config_f); count++)
988         {
989                 ConfValue("banlist","chan",count,CM,&config_f);
990                 if (match(name,CM))
991                 {
992                         ConfValue("banlist","limit",count,CM,&config_f);
993                         return atoi(CM);
994                 }
995         }
996         return 64;
997 }
998
999 void purge_empty_chans(userrec* u)
1000 {
1001
1002         int go_again = 1, purge = 0;
1003
1004         // firstly decrement the count on each channel
1005         for (int f = 0; f < MAXCHANS; f++)
1006         {
1007                 if (u->chans[f].channel)
1008                 {
1009                         u->chans[f].channel->DelUser((char*)u);
1010                 }
1011         }
1012
1013         for (int i = 0; i < MAXCHANS; i++)
1014         {
1015                 if (u->chans[i].channel)
1016                 {
1017                         if (!usercount(u->chans[i].channel))
1018                         {
1019                                 chan_hash::iterator i2 = chanlist.find(u->chans[i].channel->name);
1020                                 /* kill the record */
1021                                 if (i2 != chanlist.end())
1022                                 {
1023                                         log(DEBUG,"del_channel: destroyed: %s",i2->second->name);
1024                                         if (i2->second)
1025                                                 delete i2->second;
1026                                         chanlist.erase(i2);
1027                                         go_again = 1;
1028                                         purge++;
1029                                         u->chans[i].channel = NULL;
1030                                 }
1031                         }
1032                         else
1033                         {
1034                                 log(DEBUG,"skipped purge for %s",u->chans[i].channel->name);
1035                         }
1036                 }
1037         }
1038         log(DEBUG,"completed channel purge, killed %lu",(unsigned long)purge);
1039
1040         DeleteOper(u);
1041 }
1042
1043
1044 char scratch[MAXBUF];
1045 char sparam[MAXBUF];
1046
1047 char* chanmodes(chanrec *chan)
1048 {
1049         if (!chan)
1050         {
1051                 log(DEFAULT,"*** BUG *** chanmodes was given an invalid parameter");
1052                 strcpy(scratch,"");
1053                 return scratch;
1054         }
1055
1056         strcpy(scratch,"");
1057         strcpy(sparam,"");
1058         if (chan->binarymodes & CM_NOEXTERNAL)
1059         {
1060                 strlcat(scratch,"n",MAXMODES);
1061         }
1062         if (chan->binarymodes & CM_TOPICLOCK)
1063         {
1064                 strlcat(scratch,"t",MAXMODES);
1065         }
1066         if (chan->key[0])
1067         {
1068                 strlcat(scratch,"k",MAXMODES);
1069         }
1070         if (chan->limit)
1071         {
1072                 strlcat(scratch,"l",MAXMODES);
1073         }
1074         if (chan->binarymodes & CM_INVITEONLY)
1075         {
1076                 strlcat(scratch,"i",MAXMODES);
1077         }
1078         if (chan->binarymodes & CM_MODERATED)
1079         {
1080                 strlcat(scratch,"m",MAXMODES);
1081         }
1082         if (chan->binarymodes & CM_SECRET)
1083         {
1084                 strlcat(scratch,"s",MAXMODES);
1085         }
1086         if (chan->binarymodes & CM_PRIVATE)
1087         {
1088                 strlcat(scratch,"p",MAXMODES);
1089         }
1090         if (chan->key[0])
1091         {
1092                 strlcat(sparam," ",MAXBUF);
1093                 strlcat(sparam,chan->key,MAXBUF);
1094         }
1095         if (chan->limit)
1096         {
1097                 char foo[24];
1098                 sprintf(foo," %lu",(unsigned long)chan->limit);
1099                 strlcat(sparam,foo,MAXBUF);
1100         }
1101         if (*chan->custom_modes)
1102         {
1103                 strlcat(scratch,chan->custom_modes,MAXMODES);
1104                 for (int z = 0; chan->custom_modes[z] != 0; z++)
1105                 {
1106                         std::string extparam = chan->GetModeParameter(chan->custom_modes[z]);
1107                         if (extparam != "")
1108                         {
1109                                 strlcat(sparam," ",MAXBUF);
1110                                 strlcat(sparam,extparam.c_str(),MAXBUF);
1111                         }
1112                 }
1113         }
1114         log(DEBUG,"chanmodes: %s %s%s",chan->name,scratch,sparam);
1115         strlcat(scratch,sparam,MAXMODES);
1116         return scratch;
1117 }
1118
1119
1120 /* compile a userlist of a channel into a string, each nick seperated by
1121  * spaces and op, voice etc status shown as @ and + */
1122
1123 void userlist(userrec *user,chanrec *c)
1124 {
1125         if ((!c) || (!user))
1126         {
1127                 log(DEFAULT,"*** BUG *** userlist was given an invalid parameter");
1128                 return;
1129         }
1130
1131         snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1132
1133         std::vector<char*> *ulist = c->GetUsers();
1134         for (int i = 0; i < ulist->size(); i++)
1135         {
1136                 char* o = (*ulist)[i];
1137                 userrec* otheruser = (userrec*)o;
1138                 if ((!has_channel(user,c)) && (strchr(otheruser->modes,'i')))
1139                 {
1140                         /* user is +i, and source not on the channel, does not show
1141                          * nick in NAMES list */
1142                         continue;
1143                 }
1144                 strlcat(list,cmode(otheruser,c),MAXBUF);
1145                 strlcat(list,otheruser->nick,MAXBUF);
1146                 strlcat(list," ",MAXBUF);
1147                 if (strlen(list)>(480-NICKMAX))
1148                 {
1149                         /* list overflowed into
1150                          * multiple numerics */
1151                         WriteServ(user->fd,"%s",list);
1152                         snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1153                 }
1154         }
1155         /* if whats left in the list isnt empty, send it */
1156         if (list[strlen(list)-1] != ':')
1157         {
1158                 WriteServ(user->fd,"%s",list);
1159         }
1160 }
1161
1162 /* return a count of the users on a specific channel accounting for
1163  * invisible users who won't increase the count. e.g. for /LIST */
1164
1165 int usercount_i(chanrec *c)
1166 {
1167         int count = 0;
1168
1169         if (!c)
1170         {
1171                 log(DEFAULT,"*** BUG *** usercount_i was given an invalid parameter");
1172                 return 0;
1173         }
1174
1175         strcpy(list,"");
1176         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1177         {
1178                 if (i->second)
1179                 {
1180                         if (has_channel(i->second,c))
1181                         {
1182                                 if (isnick(i->second->nick))
1183                                 {
1184                                         if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
1185                                         {
1186                                                 /* user is +i, and source not on the channel, does not show
1187                                                  * nick in NAMES list */
1188                                                 continue;
1189                                         }
1190                                         count++;
1191                                 }
1192                         }
1193                 }
1194         }
1195         log(DEBUG,"usercount_i: %s %lu",c->name,(unsigned long)count);
1196         return count;
1197 }
1198
1199
1200 int usercount(chanrec *c)
1201 {
1202         if (!c)
1203         {
1204                 log(DEFAULT,"*** BUG *** usercount was given an invalid parameter");
1205                 return 0;
1206         }
1207         int count = c->GetUserCounter();
1208         log(DEBUG,"usercount: %s %lu",c->name,(unsigned long)count);
1209         return count;
1210 }
1211
1212
1213 // looks up a users password for their connection class (<ALLOW>/<DENY> tags)
1214
1215 char* Passwd(userrec *user)
1216 {
1217         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
1218         {
1219                 if (match(user->host,i->host) && (i->type == CC_ALLOW))
1220                 {
1221                         return i->pass;
1222                 }
1223         }
1224         return "";
1225 }
1226
1227 bool IsDenied(userrec *user)
1228 {
1229         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
1230         {
1231                 if (match(user->host,i->host) && (i->type == CC_DENY))
1232                 {
1233                         return true;
1234                 }
1235         }
1236         return false;
1237 }
1238
1239
1240
1241
1242 /* sends out an error notice to all connected clients (not to be used
1243  * lightly!) */
1244
1245 void send_error(char *s)
1246 {
1247         log(DEBUG,"send_error: %s",s);
1248         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1249         {
1250                 if (isnick(i->second->nick))
1251                 {
1252                         WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,s);
1253                 }
1254                 else
1255                 {
1256                         // fix - unregistered connections receive ERROR, not NOTICE
1257                         Write(i->second->fd,"ERROR :%s",s);
1258                 }
1259         }
1260 }
1261
1262 void Error(int status)
1263 {
1264         signal (SIGALRM, SIG_IGN);
1265         signal (SIGPIPE, SIG_IGN);
1266         signal (SIGTERM, SIG_IGN);
1267         signal (SIGABRT, SIG_IGN);
1268         signal (SIGSEGV, SIG_IGN);
1269         signal (SIGURG, SIG_IGN);
1270         signal (SIGKILL, SIG_IGN);
1271         log(DEFAULT,"*** fell down a pothole in the road to perfection ***");
1272         send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*");
1273         Exit(status);
1274 }
1275
1276 // this function counts all users connected, wether they are registered or NOT.
1277 int usercnt(void)
1278 {
1279         return clientlist.size();
1280 }
1281
1282 // this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state
1283 int registered_usercount(void)
1284 {
1285         int c = 0;
1286         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1287         {
1288                 if ((i->second->fd) && (isnick(i->second->nick))) c++;
1289         }
1290         return c;
1291 }
1292
1293 int usercount_invisible(void)
1294 {
1295         int c = 0;
1296
1297         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1298         {
1299                 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'i'))) c++;
1300         }
1301         return c;
1302 }
1303
1304 int usercount_opers(void)
1305 {
1306         int c = 0;
1307
1308         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1309         {
1310                 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'o'))) c++;
1311         }
1312         return c;
1313 }
1314
1315 int usercount_unknown(void)
1316 {
1317         int c = 0;
1318
1319         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1320         {
1321                 if ((i->second->fd) && (i->second->registered != 7))
1322                         c++;
1323         }
1324         return c;
1325 }
1326
1327 long chancount(void)
1328 {
1329         return chanlist.size();
1330 }
1331
1332 long count_servs(void)
1333 {
1334         int c = 0;
1335         for (int i = 0; i < 32; i++)
1336         {
1337                 if (me[i] != NULL)
1338                 {
1339                         for (vector<ircd_connector>::iterator j = me[i]->connectors.begin(); j != me[i]->connectors.end(); j++)
1340                         {
1341                                 if (strcasecmp(j->GetServerName().c_str(),ServerName))
1342                                 {
1343                                         c++;
1344                                 }
1345                         }
1346                 }
1347         }
1348         return c;
1349 }
1350
1351 long servercount(void)
1352 {
1353         return count_servs()+1;
1354 }
1355
1356 long local_count()
1357 {
1358         int c = 0;
1359         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1360         {
1361                 if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,ServerName))) c++;
1362         }
1363         return c;
1364 }
1365
1366 void ShowMOTD(userrec *user)
1367 {
1368         char buf[65536];
1369         std::string WholeMOTD = "";
1370         if (!MOTD.size())
1371         {
1372                 WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
1373                 return;
1374         }
1375         snprintf(buf,65535,":%s 375 %s :- %s message of the day\r\n", ServerName, user->nick, ServerName);
1376         WholeMOTD = WholeMOTD + buf;
1377         for (int i = 0; i != MOTD.size(); i++)
1378         {
1379                 snprintf(buf,65535,":%s 372 %s :- %s\r\n", ServerName, user->nick, MOTD[i].c_str());
1380                 WholeMOTD = WholeMOTD + buf;
1381         }
1382         snprintf(buf,65535,":%s 376 %s :End of message of the day.\r\n", ServerName, user->nick);
1383         WholeMOTD = WholeMOTD + buf;
1384         // only one write operation
1385         user->AddWriteBuf(WholeMOTD);
1386         statsSent += WholeMOTD.length();
1387 }
1388
1389 void ShowRULES(userrec *user)
1390 {
1391         if (!RULES.size())
1392         {
1393                 WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
1394                 return;
1395         }
1396         WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,ServerName);
1397         for (int i = 0; i != RULES.size(); i++)
1398         {
1399                                 WriteServ(user->fd,"NOTICE %s :%s",user->nick,RULES[i].c_str());
1400         }
1401         WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,ServerName);
1402 }
1403
1404 // this returns 1 when all modules are satisfied that the user should be allowed onto the irc server
1405 // (until this returns true, a user will block in the waiting state, waiting to connect up to the
1406 // registration timeout maximum seconds)
1407 bool AllModulesReportReady(userrec* user)
1408 {
1409         for (int i = 0; i <= MODCOUNT; i++)
1410         {
1411                 int res = modules[i]->OnCheckReady(user);
1412                         if (!res)
1413                                 return false;
1414         }
1415         return true;
1416 }
1417
1418 char islast(const char* s)
1419 {
1420         char c = '`';
1421         for (int j = 0; j < 32; j++)
1422         {
1423                 if (me[j] != NULL)
1424                 {
1425                         for (int k = 0; k < me[j]->connectors.size(); k++)
1426                         {
1427                                 if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),s))
1428                                 {
1429                                         c = '|';
1430                                 }
1431                                 if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),s))
1432                                 {
1433                                         c = '`';
1434                                 }
1435                         }
1436                 }
1437         }
1438         return c;
1439 }
1440
1441 long map_count(const char* s)
1442 {
1443         int c = 0;
1444         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1445         {
1446                 if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,s))) c++;
1447         }
1448         return c;
1449 }
1450
1451 void createcommand(char* cmd, handlerfunc f, char flags, int minparams,char* source)
1452 {
1453         command_t comm;
1454         /* create the command and push it onto the table */
1455         strlcpy(comm.command,cmd,MAXBUF);
1456         strlcpy(comm.source,source,MAXBUF);
1457         comm.handler_function = f;
1458         comm.flags_needed = flags;
1459         comm.min_params = minparams;
1460         comm.use_count = 0;
1461         comm.total_bytes = 0;
1462         cmdlist.push_back(comm);
1463         log(DEBUG,"Added command %s (%lu parameters)",cmd,(unsigned long)minparams);
1464 }
1465
1466
1467 void SetupCommandTable(void)
1468 {
1469         createcommand("USER",handle_user,0,4,"<core>");
1470         createcommand("NICK",handle_nick,0,1,"<core>");
1471         createcommand("QUIT",handle_quit,0,0,"<core>");
1472         createcommand("VERSION",handle_version,0,0,"<core>");
1473         createcommand("PING",handle_ping,0,1,"<core>");
1474         createcommand("PONG",handle_pong,0,1,"<core>");
1475         createcommand("ADMIN",handle_admin,0,0,"<core>");
1476         createcommand("PRIVMSG",handle_privmsg,0,2,"<core>");
1477         createcommand("INFO",handle_info,0,0,"<core>");
1478         createcommand("TIME",handle_time,0,0,"<core>");
1479         createcommand("WHOIS",handle_whois,0,1,"<core>");
1480         createcommand("WALLOPS",handle_wallops,'o',1,"<core>");
1481         createcommand("NOTICE",handle_notice,0,2,"<core>");
1482         createcommand("JOIN",handle_join,0,1,"<core>");
1483         createcommand("NAMES",handle_names,0,0,"<core>");
1484         createcommand("PART",handle_part,0,1,"<core>");
1485         createcommand("KICK",handle_kick,0,2,"<core>");
1486         createcommand("MODE",handle_mode,0,1,"<core>");
1487         createcommand("TOPIC",handle_topic,0,1,"<core>");
1488         createcommand("WHO",handle_who,0,1,"<core>");
1489         createcommand("MOTD",handle_motd,0,0,"<core>");
1490         createcommand("RULES",handle_rules,0,0,"<core>");
1491         createcommand("OPER",handle_oper,0,2,"<core>");
1492         createcommand("LIST",handle_list,0,0,"<core>");
1493         createcommand("DIE",handle_die,'o',1,"<core>");
1494         createcommand("RESTART",handle_restart,'o',1,"<core>");
1495         createcommand("KILL",handle_kill,'o',2,"<core>");
1496         createcommand("REHASH",handle_rehash,'o',0,"<core>");
1497         createcommand("LUSERS",handle_lusers,0,0,"<core>");
1498         createcommand("STATS",handle_stats,0,1,"<core>");
1499         createcommand("USERHOST",handle_userhost,0,1,"<core>");
1500         createcommand("AWAY",handle_away,0,0,"<core>");
1501         createcommand("ISON",handle_ison,0,0,"<core>");
1502         createcommand("SUMMON",handle_summon,0,0,"<core>");
1503         createcommand("USERS",handle_users,0,0,"<core>");
1504         createcommand("INVITE",handle_invite,0,0,"<core>");
1505         createcommand("PASS",handle_pass,0,1,"<core>");
1506         createcommand("TRACE",handle_trace,'o',0,"<core>");
1507         createcommand("WHOWAS",handle_whowas,0,1,"<core>");
1508         createcommand("CONNECT",handle_connect,'o',1,"<core>");
1509         createcommand("SQUIT",handle_squit,'o',0,"<core>");
1510         createcommand("MODULES",handle_modules,0,0,"<core>");
1511         createcommand("LINKS",handle_links,0,0,"<core>");
1512         createcommand("MAP",handle_map,0,0,"<core>");
1513         createcommand("KLINE",handle_kline,'o',1,"<core>");
1514         createcommand("GLINE",handle_gline,'o',1,"<core>");
1515         createcommand("ZLINE",handle_zline,'o',1,"<core>");
1516         createcommand("QLINE",handle_qline,'o',1,"<core>");
1517         createcommand("ELINE",handle_eline,'o',1,"<core>");
1518         createcommand("LOADMODULE",handle_loadmodule,'o',1,"<core>");
1519         createcommand("UNLOADMODULE",handle_unloadmodule,'o',1,"<core>");
1520         createcommand("SERVER",handle_server,0,0,"<core>");
1521         createcommand("COMMANDS",handle_commands,0,0,"<core>");
1522 }
1523
1524 bool DirValid(char* dirandfile)
1525 {
1526         char work[MAXBUF];
1527         strlcpy(work,dirandfile,MAXBUF);
1528         int p = strlen(work);
1529         // we just want the dir
1530         while (strlen(work))
1531         {
1532                 if (work[p] == '/')
1533                 {
1534                         work[p] = '\0';
1535                         break;
1536                 }
1537                 work[p--] = '\0';
1538         }
1539         char buffer[MAXBUF], otherdir[MAXBUF];
1540         // Get the current working directory
1541         if( getcwd( buffer, MAXBUF ) == NULL )
1542                 return false;
1543         chdir(work);
1544         if( getcwd( otherdir, MAXBUF ) == NULL )
1545                 return false;
1546         chdir(buffer);
1547         if (strlen(otherdir) >= strlen(work))
1548         {
1549                 otherdir[strlen(work)] = '\0';
1550                 if (!strcmp(otherdir,work))
1551                 {
1552                         return true;
1553                 }
1554                 return false;
1555         }
1556         else return false;
1557 }
1558
1559 std::string GetFullProgDir(char** argv, int argc)
1560 {
1561         char work[MAXBUF];
1562         strlcpy(work,argv[0],MAXBUF);
1563         int p = strlen(work);
1564         // we just want the dir
1565         while (strlen(work))
1566         {
1567                 if (work[p] == '/')
1568                 {
1569                         work[p] = '\0';
1570                         break;
1571                 }
1572                 work[p--] = '\0';
1573         }
1574         char buffer[MAXBUF], otherdir[MAXBUF];
1575         // Get the current working directory
1576         if( getcwd( buffer, MAXBUF ) == NULL )
1577                 return "";
1578         chdir(work);
1579         if( getcwd( otherdir, MAXBUF ) == NULL )
1580                 return "";
1581         chdir(buffer);
1582         return otherdir;
1583 }
1584