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