]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/helperfuncs.cpp
Re-added required parts of connection.h
[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 }
552 // returns TRUE of any users on channel C occupy server 'servername'.
553
554 bool ChanAnyOnThisServer(chanrec *c,char* servername)
555 {
556         log(DEBUG,"ChanAnyOnThisServer");
557
558         std::vector<char*> *ulist = c->GetUsers();
559         for (unsigned int j = 0; j < ulist->size(); j++)
560         {
561                 char* o = (*ulist)[j];
562                 userrec* user = (userrec*)o;
563                 if (!strcasecmp(user->server,servername))
564                         return true;
565         }
566         return false;
567 }
568
569 // returns true if user 'u' shares any common channels with any users on server 'servername'
570
571 bool CommonOnThisServer(userrec* u,const char* servername)
572 {
573         log(DEBUG,"ChanAnyOnThisServer");
574
575         for (int i = 0; i < MAXCHANS; i++)
576         {
577                 if (u->chans[i].channel)
578                 {
579                         std::vector<char*> *ulist = u->chans[i].channel->GetUsers();
580                         for (unsigned int j = 0; j < ulist->size(); j++)
581                         {
582                                 char* o = (*ulist)[j];
583                                 userrec* user = (userrec*)o;
584                                 if (!strcasecmp(user->server,servername))
585                                         return true;
586                         }
587                 }
588         }
589         return false;
590 }
591
592
593 void WriteMode(const char* modes, int flags, const char* text, ...)
594 {
595         if ((!text) || (!modes) || (!flags))
596         {
597                 log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
598                 return;
599         }
600
601         char textbuffer[MAXBUF];
602         va_list argsPtr;
603         va_start (argsPtr, text);
604         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
605         va_end(argsPtr);
606         int modelen = strlen(modes);
607
608         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
609         {
610                 if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
611                 {
612                         bool send_to_user = false;
613
614                         if (flags == WM_AND)
615                         {
616                                 send_to_user = true;
617                                 for (int n = 0; n < modelen; n++)
618                                 {
619                                         if (!hasumode(i->second,modes[n]))
620                                         {
621                                                 send_to_user = false;
622                                                 break;
623                                         }
624                                 }
625                         }
626                         else if (flags == WM_OR)
627                         {
628                                 send_to_user = false;
629                                 for (int n = 0; n < modelen; n++)
630                                 {
631                                         if (hasumode(i->second,modes[n]))
632                                         {
633                                                 send_to_user = true;
634                                                 break;
635                                         }
636                                 }
637                         }
638
639                         if (send_to_user)
640                         {
641                                 WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer);
642                         }
643                 }
644         }
645 }
646
647 void NoticeAll(userrec *source, bool local_only, char* text, ...)
648 {
649         if ((!text) || (!source))
650         {
651                 log(DEFAULT,"*** BUG *** NoticeAll was given an invalid parameter");
652                 return;
653         }
654
655         char textbuffer[MAXBUF];
656         va_list argsPtr;
657         va_start (argsPtr, text);
658         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
659         va_end(argsPtr);
660
661         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
662         {
663                 if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
664                 {
665                         WriteFrom(i->second->fd,source,"NOTICE $* :%s",textbuffer);
666                 }
667         }
668
669 }
670
671
672 void WriteWallOps(userrec *source, bool local_only, char* text, ...)
673 {
674         if ((!text) || (!source))
675         {
676                 log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
677                 return;
678         }
679
680         char textbuffer[MAXBUF];
681         va_list argsPtr;
682         va_start (argsPtr, text);
683         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
684         va_end(argsPtr);
685
686         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
687         {
688                 if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
689                 {
690                         if (strchr(i->second->modes,'w'))
691                         {
692                                 WriteTo(source,i->second,"WALLOPS :%s",textbuffer);
693                         }
694                 }
695         }
696 }
697
698 /* convert a string to lowercase. Note following special circumstances
699  * taken from RFC 1459. Many "official" server branches still hold to this
700  * rule so i will too;
701  *
702  *  Because of IRC's scandanavian origin, the characters {}| are
703  *  considered to be the lower case equivalents of the characters []\,
704  *  respectively. This is a critical issue when determining the
705  *  equivalence of two nicknames.
706  */
707
708 void strlower(char *n)
709 {
710         if (n)
711         {
712                 for (char* t = n; *t; t++)
713                         *t = lowermap[(unsigned)*t];
714         }
715 }
716
717 /* Find a user record by nickname and return a pointer to it */
718
719 userrec* Find(std::string nick)
720 {
721         user_hash::iterator iter = clientlist.find(nick);
722
723         if (iter == clientlist.end())
724                 /* Couldn't find it */
725                 return NULL;
726
727         return iter->second;
728 }
729
730 /* find a channel record by channel name and return a pointer to it */
731
732 chanrec* FindChan(const char* chan)
733 {
734         if (!chan)
735         {
736                 log(DEFAULT,"*** BUG *** Findchan was given an invalid parameter");
737                 return NULL;
738         }
739
740         chan_hash::iterator iter = chanlist.find(chan);
741
742         if (iter == chanlist.end())
743                 /* Couldn't find it */
744                 return NULL;
745
746         return iter->second;
747 }
748
749
750 long GetMaxBans(char* name)
751 {
752         char CM[MAXBUF];
753         for (int count = 0; count < ConfValueEnum("banlist",&config_f); count++)
754         {
755                 ConfValue("banlist","chan",count,CM,&config_f);
756                 if (match(name,CM))
757                 {
758                         ConfValue("banlist","limit",count,CM,&config_f);
759                         return atoi(CM);
760                 }
761         }
762         return 64;
763 }
764
765 void purge_empty_chans(userrec* u)
766 {
767
768         int go_again = 1, purge = 0;
769
770         // firstly decrement the count on each channel
771         for (int f = 0; f < MAXCHANS; f++)
772         {
773                 if (u->chans[f].channel)
774                 {
775                         u->chans[f].channel->DelUser((char*)u);
776                 }
777         }
778
779         for (int i = 0; i < MAXCHANS; i++)
780         {
781                 if (u->chans[i].channel)
782                 {
783                         if (!usercount(u->chans[i].channel))
784                         {
785                                 chan_hash::iterator i2 = chanlist.find(u->chans[i].channel->name);
786                                 /* kill the record */
787                                 if (i2 != chanlist.end())
788                                 {
789                                         log(DEBUG,"del_channel: destroyed: %s",i2->second->name);
790                                         if (i2->second)
791                                                 delete i2->second;
792                                         chanlist.erase(i2);
793                                         go_again = 1;
794                                         purge++;
795                                         u->chans[i].channel = NULL;
796                                 }
797                         }
798                         else
799                         {
800                                 log(DEBUG,"skipped purge for %s",u->chans[i].channel->name);
801                         }
802                 }
803         }
804         log(DEBUG,"completed channel purge, killed %lu",(unsigned long)purge);
805
806         DeleteOper(u);
807 }
808
809
810 char scratch[MAXBUF];
811 char sparam[MAXBUF];
812
813 char* chanmodes(chanrec *chan)
814 {
815         if (!chan)
816         {
817                 log(DEFAULT,"*** BUG *** chanmodes was given an invalid parameter");
818                 strcpy(scratch,"");
819                 return scratch;
820         }
821
822         strcpy(scratch,"");
823         strcpy(sparam,"");
824         if (chan->binarymodes & CM_NOEXTERNAL)
825         {
826                 strlcat(scratch,"n",MAXMODES);
827         }
828         if (chan->binarymodes & CM_TOPICLOCK)
829         {
830                 strlcat(scratch,"t",MAXMODES);
831         }
832         if (chan->key[0])
833         {
834                 strlcat(scratch,"k",MAXMODES);
835         }
836         if (chan->limit)
837         {
838                 strlcat(scratch,"l",MAXMODES);
839         }
840         if (chan->binarymodes & CM_INVITEONLY)
841         {
842                 strlcat(scratch,"i",MAXMODES);
843         }
844         if (chan->binarymodes & CM_MODERATED)
845         {
846                 strlcat(scratch,"m",MAXMODES);
847         }
848         if (chan->binarymodes & CM_SECRET)
849         {
850                 strlcat(scratch,"s",MAXMODES);
851         }
852         if (chan->binarymodes & CM_PRIVATE)
853         {
854                 strlcat(scratch,"p",MAXMODES);
855         }
856         if (chan->key[0])
857         {
858                 strlcat(sparam," ",MAXBUF);
859                 strlcat(sparam,chan->key,MAXBUF);
860         }
861         if (chan->limit)
862         {
863                 char foo[24];
864                 sprintf(foo," %lu",(unsigned long)chan->limit);
865                 strlcat(sparam,foo,MAXBUF);
866         }
867         if (*chan->custom_modes)
868         {
869                 strlcat(scratch,chan->custom_modes,MAXMODES);
870                 for (int z = 0; chan->custom_modes[z] != 0; z++)
871                 {
872                         std::string extparam = chan->GetModeParameter(chan->custom_modes[z]);
873                         if (extparam != "")
874                         {
875                                 strlcat(sparam," ",MAXBUF);
876                                 strlcat(sparam,extparam.c_str(),MAXBUF);
877                         }
878                 }
879         }
880         log(DEBUG,"chanmodes: %s %s%s",chan->name,scratch,sparam);
881         strlcat(scratch,sparam,MAXMODES);
882         return scratch;
883 }
884
885
886 /* compile a userlist of a channel into a string, each nick seperated by
887  * spaces and op, voice etc status shown as @ and + */
888
889 void userlist(userrec *user,chanrec *c)
890 {
891         if ((!c) || (!user))
892         {
893                 log(DEFAULT,"*** BUG *** userlist was given an invalid parameter");
894                 return;
895         }
896
897         snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
898
899         std::vector<char*> *ulist = c->GetUsers();
900         for (unsigned int i = 0; i < ulist->size(); i++)
901         {
902                 char* o = (*ulist)[i];
903                 userrec* otheruser = (userrec*)o;
904                 if ((!has_channel(user,c)) && (strchr(otheruser->modes,'i')))
905                 {
906                         /* user is +i, and source not on the channel, does not show
907                          * nick in NAMES list */
908                         continue;
909                 }
910                 strlcat(list,cmode(otheruser,c),MAXBUF);
911                 strlcat(list,otheruser->nick,MAXBUF);
912                 strlcat(list," ",MAXBUF);
913                 if (strlen(list)>(480-NICKMAX))
914                 {
915                         /* list overflowed into
916                          * multiple numerics */
917                         WriteServ(user->fd,"%s",list);
918                         snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
919                 }
920         }
921         /* if whats left in the list isnt empty, send it */
922         if (list[strlen(list)-1] != ':')
923         {
924                 WriteServ(user->fd,"%s",list);
925         }
926 }
927
928 /* return a count of the users on a specific channel accounting for
929  * invisible users who won't increase the count. e.g. for /LIST */
930
931 int usercount_i(chanrec *c)
932 {
933         int count = 0;
934
935         if (!c)
936         {
937                 log(DEFAULT,"*** BUG *** usercount_i was given an invalid parameter");
938                 return 0;
939         }
940
941         strcpy(list,"");
942         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
943         {
944                 if (i->second)
945                 {
946                         if (has_channel(i->second,c))
947                         {
948                                 if (isnick(i->second->nick))
949                                 {
950                                         if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
951                                         {
952                                                 /* user is +i, and source not on the channel, does not show
953                                                  * nick in NAMES list */
954                                                 continue;
955                                         }
956                                         count++;
957                                 }
958                         }
959                 }
960         }
961         log(DEBUG,"usercount_i: %s %lu",c->name,(unsigned long)count);
962         return count;
963 }
964
965
966 int usercount(chanrec *c)
967 {
968         if (!c)
969         {
970                 log(DEFAULT,"*** BUG *** usercount was given an invalid parameter");
971                 return 0;
972         }
973         int count = c->GetUserCounter();
974         log(DEBUG,"usercount: %s %lu",c->name,(unsigned long)count);
975         return count;
976 }
977
978
979 // looks up a users password for their connection class (<ALLOW>/<DENY> tags)
980
981 char* Passwd(userrec *user)
982 {
983         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
984         {
985                 if (match(user->host,i->host) && (i->type == CC_ALLOW))
986                 {
987                         return i->pass;
988                 }
989         }
990         return "";
991 }
992
993 bool IsDenied(userrec *user)
994 {
995         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
996         {
997                 if (match(user->host,i->host) && (i->type == CC_DENY))
998                 {
999                         return true;
1000                 }
1001         }
1002         return false;
1003 }
1004
1005
1006
1007
1008 /* sends out an error notice to all connected clients (not to be used
1009  * lightly!) */
1010
1011 void send_error(char *s)
1012 {
1013         log(DEBUG,"send_error: %s",s);
1014         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1015         {
1016                 if (isnick(i->second->nick))
1017                 {
1018                         WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,s);
1019                 }
1020                 else
1021                 {
1022                         // fix - unregistered connections receive ERROR, not NOTICE
1023                         Write(i->second->fd,"ERROR :%s",s);
1024                 }
1025         }
1026 }
1027
1028 void Error(int status)
1029 {
1030         signal (SIGALRM, SIG_IGN);
1031         signal (SIGPIPE, SIG_IGN);
1032         signal (SIGTERM, SIG_IGN);
1033         signal (SIGABRT, SIG_IGN);
1034         signal (SIGSEGV, SIG_IGN);
1035         signal (SIGURG, SIG_IGN);
1036         signal (SIGKILL, SIG_IGN);
1037         log(DEFAULT,"*** fell down a pothole in the road to perfection ***");
1038         send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*");
1039         Exit(status);
1040 }
1041
1042 // this function counts all users connected, wether they are registered or NOT.
1043 int usercnt(void)
1044 {
1045         return clientlist.size();
1046 }
1047
1048 // this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state
1049 int registered_usercount(void)
1050 {
1051         int c = 0;
1052         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1053         {
1054                 if ((i->second->fd) && (isnick(i->second->nick))) c++;
1055         }
1056         return c;
1057 }
1058
1059 int usercount_invisible(void)
1060 {
1061         int c = 0;
1062
1063         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1064         {
1065                 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'i'))) c++;
1066         }
1067         return c;
1068 }
1069
1070 int usercount_opers(void)
1071 {
1072         int c = 0;
1073
1074         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1075         {
1076                 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'o'))) c++;
1077         }
1078         return c;
1079 }
1080
1081 int usercount_unknown(void)
1082 {
1083         int c = 0;
1084
1085         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1086         {
1087                 if ((i->second->fd) && (i->second->registered != 7))
1088                         c++;
1089         }
1090         return c;
1091 }
1092
1093 long chancount(void)
1094 {
1095         return chanlist.size();
1096 }
1097
1098 long count_servs(void)
1099 {
1100         int c = 0;
1101         for (int i = 0; i < 32; i++)
1102         {
1103                 if (me[i] != NULL)
1104                 {
1105                         for (vector<ircd_connector>::iterator j = me[i]->connectors.begin(); j != me[i]->connectors.end(); j++)
1106                         {
1107                                 if (strcasecmp(j->GetServerName().c_str(),ServerName))
1108                                 {
1109                                         c++;
1110                                 }
1111                         }
1112                 }
1113         }
1114         return c;
1115 }
1116
1117 long servercount(void)
1118 {
1119         return count_servs()+1;
1120 }
1121
1122 long local_count()
1123 {
1124         int c = 0;
1125         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1126         {
1127                 if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,ServerName))) c++;
1128         }
1129         return c;
1130 }
1131
1132 void ShowMOTD(userrec *user)
1133 {
1134         char buf[65536];
1135         std::string WholeMOTD = "";
1136         if (!MOTD.size())
1137         {
1138                 WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
1139                 return;
1140         }
1141         snprintf(buf,65535,":%s 375 %s :- %s message of the day\r\n", ServerName, user->nick, ServerName);
1142         WholeMOTD = WholeMOTD + buf;
1143         for (unsigned int i = 0; i != MOTD.size(); i++)
1144         {
1145                 snprintf(buf,65535,":%s 372 %s :- %s\r\n", ServerName, user->nick, MOTD[i].c_str());
1146                 WholeMOTD = WholeMOTD + buf;
1147         }
1148         snprintf(buf,65535,":%s 376 %s :End of message of the day.\r\n", ServerName, user->nick);
1149         WholeMOTD = WholeMOTD + buf;
1150         // only one write operation
1151         user->AddWriteBuf(WholeMOTD);
1152         statsSent += WholeMOTD.length();
1153 }
1154
1155 void ShowRULES(userrec *user)
1156 {
1157         if (!RULES.size())
1158         {
1159                 WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
1160                 return;
1161         }
1162         WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,ServerName);
1163         for (unsigned int i = 0; i != RULES.size(); i++)
1164         {
1165                                 WriteServ(user->fd,"NOTICE %s :%s",user->nick,RULES[i].c_str());
1166         }
1167         WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,ServerName);
1168 }
1169
1170 // this returns 1 when all modules are satisfied that the user should be allowed onto the irc server
1171 // (until this returns true, a user will block in the waiting state, waiting to connect up to the
1172 // registration timeout maximum seconds)
1173 bool AllModulesReportReady(userrec* user)
1174 {
1175         for (int i = 0; i <= MODCOUNT; i++)
1176         {
1177                 int res = modules[i]->OnCheckReady(user);
1178                         if (!res)
1179                                 return false;
1180         }
1181         return true;
1182 }
1183
1184 char islast(const char* s)
1185 {
1186         char c = '`';
1187         for (int j = 0; j < 32; j++)
1188         {
1189                 if (me[j] != NULL)
1190                 {
1191                         for (unsigned int k = 0; k < me[j]->connectors.size(); k++)
1192                         {
1193                                 if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),s))
1194                                 {
1195                                         c = '|';
1196                                 }
1197                                 if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),s))
1198                                 {
1199                                         c = '`';
1200                                 }
1201                         }
1202                 }
1203         }
1204         return c;
1205 }
1206
1207 long map_count(const char* s)
1208 {
1209         int c = 0;
1210         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1211         {
1212                 if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,s))) c++;
1213         }
1214         return c;
1215 }
1216
1217 void createcommand(char* cmd, handlerfunc f, char flags, int minparams,char* source)
1218 {
1219         command_t comm;
1220         /* create the command and push it onto the table */
1221         strlcpy(comm.command,cmd,MAXBUF);
1222         strlcpy(comm.source,source,MAXBUF);
1223         comm.handler_function = f;
1224         comm.flags_needed = flags;
1225         comm.min_params = minparams;
1226         comm.use_count = 0;
1227         comm.total_bytes = 0;
1228         cmdlist.push_back(comm);
1229         log(DEBUG,"Added command %s (%lu parameters)",cmd,(unsigned long)minparams);
1230 }
1231
1232
1233 void SetupCommandTable(void)
1234 {
1235         createcommand("USER",handle_user,0,4,"<core>");
1236         createcommand("NICK",handle_nick,0,1,"<core>");
1237         createcommand("QUIT",handle_quit,0,0,"<core>");
1238         createcommand("VERSION",handle_version,0,0,"<core>");
1239         createcommand("PING",handle_ping,0,1,"<core>");
1240         createcommand("PONG",handle_pong,0,1,"<core>");
1241         createcommand("ADMIN",handle_admin,0,0,"<core>");
1242         createcommand("PRIVMSG",handle_privmsg,0,2,"<core>");
1243         createcommand("INFO",handle_info,0,0,"<core>");
1244         createcommand("TIME",handle_time,0,0,"<core>");
1245         createcommand("WHOIS",handle_whois,0,1,"<core>");
1246         createcommand("WALLOPS",handle_wallops,'o',1,"<core>");
1247         createcommand("NOTICE",handle_notice,0,2,"<core>");
1248         createcommand("JOIN",handle_join,0,1,"<core>");
1249         createcommand("NAMES",handle_names,0,0,"<core>");
1250         createcommand("PART",handle_part,0,1,"<core>");
1251         createcommand("KICK",handle_kick,0,2,"<core>");
1252         createcommand("MODE",handle_mode,0,1,"<core>");
1253         createcommand("TOPIC",handle_topic,0,1,"<core>");
1254         createcommand("WHO",handle_who,0,1,"<core>");
1255         createcommand("MOTD",handle_motd,0,0,"<core>");
1256         createcommand("RULES",handle_rules,0,0,"<core>");
1257         createcommand("OPER",handle_oper,0,2,"<core>");
1258         createcommand("LIST",handle_list,0,0,"<core>");
1259         createcommand("DIE",handle_die,'o',1,"<core>");
1260         createcommand("RESTART",handle_restart,'o',1,"<core>");
1261         createcommand("KILL",handle_kill,'o',2,"<core>");
1262         createcommand("REHASH",handle_rehash,'o',0,"<core>");
1263         createcommand("LUSERS",handle_lusers,0,0,"<core>");
1264         createcommand("STATS",handle_stats,0,1,"<core>");
1265         createcommand("USERHOST",handle_userhost,0,1,"<core>");
1266         createcommand("AWAY",handle_away,0,0,"<core>");
1267         createcommand("ISON",handle_ison,0,0,"<core>");
1268         createcommand("SUMMON",handle_summon,0,0,"<core>");
1269         createcommand("USERS",handle_users,0,0,"<core>");
1270         createcommand("INVITE",handle_invite,0,0,"<core>");
1271         createcommand("PASS",handle_pass,0,1,"<core>");
1272         createcommand("TRACE",handle_trace,'o',0,"<core>");
1273         createcommand("WHOWAS",handle_whowas,0,1,"<core>");
1274         createcommand("CONNECT",handle_connect,'o',1,"<core>");
1275         createcommand("SQUIT",handle_squit,'o',0,"<core>");
1276         createcommand("MODULES",handle_modules,0,0,"<core>");
1277         createcommand("LINKS",handle_links,0,0,"<core>");
1278         createcommand("MAP",handle_map,0,0,"<core>");
1279         createcommand("KLINE",handle_kline,'o',1,"<core>");
1280         createcommand("GLINE",handle_gline,'o',1,"<core>");
1281         createcommand("ZLINE",handle_zline,'o',1,"<core>");
1282         createcommand("QLINE",handle_qline,'o',1,"<core>");
1283         createcommand("ELINE",handle_eline,'o',1,"<core>");
1284         createcommand("LOADMODULE",handle_loadmodule,'o',1,"<core>");
1285         createcommand("UNLOADMODULE",handle_unloadmodule,'o',1,"<core>");
1286         createcommand("SERVER",handle_server,0,0,"<core>");
1287         createcommand("COMMANDS",handle_commands,0,0,"<core>");
1288 }
1289
1290 bool DirValid(char* dirandfile)
1291 {
1292         char work[MAXBUF];
1293         strlcpy(work,dirandfile,MAXBUF);
1294         int p = strlen(work);
1295         // we just want the dir
1296         while (strlen(work))
1297         {
1298                 if (work[p] == '/')
1299                 {
1300                         work[p] = '\0';
1301                         break;
1302                 }
1303                 work[p--] = '\0';
1304         }
1305         char buffer[MAXBUF], otherdir[MAXBUF];
1306         // Get the current working directory
1307         if( getcwd( buffer, MAXBUF ) == NULL )
1308                 return false;
1309         chdir(work);
1310         if( getcwd( otherdir, MAXBUF ) == NULL )
1311                 return false;
1312         chdir(buffer);
1313         if (strlen(otherdir) >= strlen(work))
1314         {
1315                 otherdir[strlen(work)] = '\0';
1316                 if (!strcmp(otherdir,work))
1317                 {
1318                         return true;
1319                 }
1320                 return false;
1321         }
1322         else return false;
1323 }
1324
1325 std::string GetFullProgDir(char** argv, int argc)
1326 {
1327         char work[MAXBUF];
1328         strlcpy(work,argv[0],MAXBUF);
1329         int p = strlen(work);
1330         // we just want the dir
1331         while (strlen(work))
1332         {
1333                 if (work[p] == '/')
1334                 {
1335                         work[p] = '\0';
1336                         break;
1337                 }
1338                 work[p--] = '\0';
1339         }
1340         char buffer[MAXBUF], otherdir[MAXBUF];
1341         // Get the current working directory
1342         if( getcwd( buffer, MAXBUF ) == NULL )
1343                 return "";
1344         chdir(work);
1345         if( getcwd( otherdir, MAXBUF ) == NULL )
1346                 return "";
1347         chdir(buffer);
1348         return otherdir;
1349 }
1350