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