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