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