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