]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/helperfuncs.cpp
WriteChannel* functions and ChanExceptSender* functions are now methods of chanrec...
[user/henk/code/inspircd.git] / src / helperfuncs.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 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 #include <stdarg.h>
18 #include "inspircd_config.h"
19 #include "inspircd.h"
20 #include "configreader.h"
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <sys/errno.h>
24 #include <signal.h>
25 #include <time.h>
26 #include <string>
27 #include <sstream>
28 #ifdef HAS_EXECINFO
29 #include <execinfo.h>
30 #endif
31 #include "connection.h"
32 #include "users.h"
33 #include "ctables.h"
34 #include "globals.h"
35 #include "modules.h"
36 #include "dynamic.h"
37 #include "wildcard.h"
38 #include "message.h"
39 #include "mode.h"
40 #include "xline.h"
41 #include "commands.h"
42 #include "inspstring.h"
43 #include "helperfuncs.h"
44 #include "hashcomp.h"
45 #include "typedefs.h"
46
47 extern int MODCOUNT;
48 extern ModuleList modules;
49 extern ServerConfig *Config;
50 extern InspIRCd* ServerInstance;
51 extern time_t TIME;
52 extern char lowermap[255];
53 extern userrec* fd_ref_table[MAX_DESCRIPTORS];
54 static unsigned long already_sent[MAX_DESCRIPTORS] = {0};
55 extern std::vector<userrec*> all_opers;
56 extern user_hash clientlist;
57 extern chan_hash chanlist;
58
59 char LOG_FILE[MAXBUF];
60
61 extern std::vector<userrec*> local_users;
62
63 static char TIMESTR[26];
64 static time_t LAST = 0;
65
66 /* XXX: Used for speeding up WriteCommon operations */
67 unsigned long uniq_id = 0;
68
69 /** log()
70  *  Write a line of text `text' to the logfile (and stdout, if in nofork) if the level `level'
71  *  is greater than the configured loglevel.
72  */
73 void do_log(int level, const char *text, ...)
74 {
75         va_list argsPtr;
76         char textbuffer[MAXBUF];
77
78         /* If we were given -debug we output all messages, regardless of configured loglevel */
79         if ((level < Config->LogLevel) && !Config->forcedebug)
80                 return;
81
82         if (TIME != LAST)
83         {
84                 struct tm *timeinfo = localtime(&TIME);
85
86                 strlcpy(TIMESTR,asctime(timeinfo),26);
87                 TIMESTR[24] = ':';
88                 LAST = TIME;
89         }
90
91         if (Config->log_file)
92         {
93                 va_start(argsPtr, text);
94                 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
95                 va_end(argsPtr);
96
97                 if (Config->writelog)
98                 {
99                         fprintf(Config->log_file,"%s %s\n",TIMESTR,textbuffer);
100                         fflush(Config->log_file);
101                 }
102         }
103         
104         if (Config->nofork)
105         {
106                 printf("%s %s\n", TIMESTR, textbuffer);
107         }
108 }
109
110 /** readfile()
111  *  Read the contents of a file located by `fname' into a file_cache pointed at by `F'.
112  *
113  *  XXX - we may want to consider returning a file_cache or pointer to one, less confusing.
114  */
115 void readfile(file_cache &F, const char* fname)
116 {
117         FILE* file;
118         char linebuf[MAXBUF];
119
120         log(DEBUG,"readfile: loading %s",fname);
121         F.clear();
122         file =  fopen(fname,"r");
123
124         if (file)
125         {
126                 while (!feof(file))
127                 {
128                         fgets(linebuf,sizeof(linebuf),file);
129                         linebuf[strlen(linebuf)-1]='\0';
130
131                         if (!*linebuf)
132                         {
133                                 strcpy(linebuf,"  ");
134                         }
135
136                         if (!feof(file))
137                         {
138                                 F.push_back(linebuf);
139                         }
140                 }
141
142                 fclose(file);
143         }
144         else
145         {
146                 log(DEBUG,"readfile: failed to load file: %s",fname);
147         }
148
149         log(DEBUG,"readfile: loaded %s, %lu lines",fname,(unsigned long)F.size());
150 }
151
152 /** Write_NoFormat()
153  *  Writes a given string in `text' to the socket on fd `sock' - only if the socket
154  *  is a valid entry in the local FD table.
155  */
156 void Write_NoFormat(int sock, const char *text)
157 {
158         char tb[MAXBUF];
159         int bytes;
160
161         if ((sock < 0) || (!text) || (sock > MAX_DESCRIPTORS))
162                 return;
163
164         if (fd_ref_table[sock])
165         {
166                 bytes = snprintf(tb,MAXBUF,"%s\r\n",text);
167
168                 if (Config->GetIOHook(fd_ref_table[sock]->GetPort()))
169                 {
170                         try
171                         {
172                                 Config->GetIOHook(fd_ref_table[sock]->GetPort())->OnRawSocketWrite(sock,tb,bytes);
173                         }
174                         catch (ModuleException& modexcept)
175                         {
176                                 log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
177                         }
178                 }
179                 else
180                 {
181                         fd_ref_table[sock]->AddWriteBuf(tb);
182                 }
183                 ServerInstance->stats->statsSent += bytes;
184         }
185         else
186                 log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
187 }
188
189 /** Write()
190  *  Same as Write_NoFormat(), but formatted printf() style first.
191  */
192 void Write(int sock, char *text, ...)
193 {
194         va_list argsPtr;
195         char textbuffer[MAXBUF];
196         char tb[MAXBUF];
197         int bytes;
198
199         if ((sock < 0) || (sock > MAX_DESCRIPTORS))
200                 return;
201
202         if (!text)
203         {
204                 log(DEFAULT,"*** BUG *** Write was given an invalid parameter");
205                 return;
206         }
207
208         if (fd_ref_table[sock])
209         {
210
211                 va_start(argsPtr, text);
212                 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
213                 va_end(argsPtr);
214                 bytes = snprintf(tb,MAXBUF,"%s\r\n",textbuffer);
215
216                 if (Config->GetIOHook(fd_ref_table[sock]->GetPort()))
217                 {
218                         try
219                         {
220                                 Config->GetIOHook(fd_ref_table[sock]->GetPort())->OnRawSocketWrite(sock,tb,bytes);
221                         }
222                         catch (ModuleException& modexcept)
223                         {
224                                 log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
225                         }                                               
226                 }
227                 else
228                 {
229                         fd_ref_table[sock]->AddWriteBuf(tb);
230                 }
231                 ServerInstance->stats->statsSent += bytes;
232         }
233         else
234                 log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
235 }
236
237 /** WriteServ_NoFormat()
238  *  Same as Write_NoFormat(), except prefixes `text' with `:server.name '.
239  */
240 void WriteServ_NoFormat(int sock, const char* text)
241 {
242         char tb[MAXBUF];
243         int bytes;
244
245         if ((sock < 0) || (!text) || (sock > MAX_DESCRIPTORS))
246                 return;
247
248         if (fd_ref_table[sock])
249         {
250                 bytes = snprintf(tb,MAXBUF,":%s %s\r\n",Config->ServerName,text);
251
252                 if (Config->GetIOHook(fd_ref_table[sock]->GetPort()))
253                 {
254                         try
255                         {
256                                 Config->GetIOHook(fd_ref_table[sock]->GetPort())->OnRawSocketWrite(sock,tb,bytes);
257                         }
258                         catch (ModuleException& modexcept)
259                         {
260                                 log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
261                         }
262                 }
263                 else
264                 {
265                         fd_ref_table[sock]->AddWriteBuf(tb);
266                 }
267                 ServerInstance->stats->statsSent += bytes;
268         }
269         else
270                 log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
271 }
272
273 /** WriteServ()
274  *  Same as Write(), except `text' is prefixed with `:server.name '.
275  */
276 void WriteServ(int sock, char* text, ...)
277 {
278         va_list argsPtr;
279         char textbuffer[MAXBUF];
280
281         if ((sock < 0) || (sock > MAX_DESCRIPTORS))
282                 return;
283
284         if (!text)
285         {
286                 log(DEFAULT,"*** BUG *** WriteServ was given an invalid parameter");
287                 return;
288         }
289
290         if (!fd_ref_table[sock])
291                 return;
292
293         va_start(argsPtr, text);
294         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
295         va_end(argsPtr);
296         
297         WriteServ_NoFormat(sock, textbuffer);
298 }
299
300 /** WriteFrom_NoFormat()
301  * Write `text' to a socket with fd `sock' prefixed with `:n!u@h' - taken from
302  * the nick, user, and host of `user'.
303  */
304 void WriteFrom_NoFormat(int sock, userrec *user, const char* text)
305 {
306         char tb[MAXBUF];
307         int bytes;
308
309         if ((sock < 0) || (!text) || (!user) || (sock > MAX_DESCRIPTORS))
310                 return;
311
312         if (fd_ref_table[sock])
313         {
314                 bytes = snprintf(tb,MAXBUF,":%s %s\r\n",user->GetFullHost(),text);
315
316                 if (Config->GetIOHook(fd_ref_table[sock]->GetPort()))
317                 {
318                         try
319                         {
320                                 Config->GetIOHook(fd_ref_table[sock]->GetPort())->OnRawSocketWrite(sock,tb,bytes);
321                         }
322                         catch (ModuleException& modexcept)
323                         {
324                                 log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
325                         }
326                 }
327                 else
328                 {
329                         fd_ref_table[sock]->AddWriteBuf(tb);
330                 }
331                 ServerInstance->stats->statsSent += bytes;
332         }
333         else
334                 log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
335 }
336
337 /* write text from an originating user to originating user */
338
339 void WriteFrom(int sock, userrec *user,char* text, ...)
340 {
341         va_list argsPtr;
342         char textbuffer[MAXBUF];
343         char tb[MAXBUF];
344         int bytes;
345
346         if ((sock < 0) || (sock > MAX_DESCRIPTORS))
347                 return;
348
349         if ((!text) || (!user))
350         {
351                 log(DEFAULT,"*** BUG *** WriteFrom was given an invalid parameter");
352                 return;
353         }
354
355         if (fd_ref_table[sock])
356         {
357
358                 va_start(argsPtr, text);
359                 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
360                 va_end(argsPtr);
361                 bytes = snprintf(tb,MAXBUF,":%s %s\r\n",user->GetFullHost(),textbuffer);
362
363                 if (Config->GetIOHook(fd_ref_table[sock]->GetPort()))
364                 {
365                         try
366                         {
367                                 Config->GetIOHook(fd_ref_table[sock]->GetPort())->OnRawSocketWrite(sock,tb,bytes);
368                         }
369                         catch (ModuleException& modexcept)
370                         {
371                                 log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
372                         }
373                 }
374                 else
375                 {
376                         fd_ref_table[sock]->AddWriteBuf(tb);
377                 }
378
379                 ServerInstance->stats->statsSent += bytes;
380         }
381         else
382                 log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
383 }
384
385 /* write text to an destination user from a source user (e.g. user privmsg) */
386
387 void WriteTo(userrec *source, userrec *dest,char *data, ...)
388 {
389         char textbuffer[MAXBUF];
390         va_list argsPtr;
391
392         if ((!dest) || (!data))
393         {
394                 log(DEFAULT,"*** BUG *** WriteTo was given an invalid parameter");
395                 return;
396         }
397
398         if (!IS_LOCAL(dest))
399                 return;
400
401         va_start(argsPtr, data);
402         vsnprintf(textbuffer, MAXBUF, data, argsPtr);
403         va_end(argsPtr);
404
405         // if no source given send it from the server.
406         if (!source)
407         {
408                 WriteServ_NoFormat(dest->fd,textbuffer);
409         }
410         else
411         {
412                 WriteFrom_NoFormat(dest->fd,source,textbuffer);
413         }
414 }
415
416 void WriteTo_NoFormat(userrec *source, userrec *dest, const char *data)
417 {
418         if ((!dest) || (!data))
419                 return;
420
421         if (!source)
422         {
423                 WriteServ_NoFormat(dest->fd,data);
424         }
425         else
426         {
427                 WriteFrom_NoFormat(dest->fd,source,data);
428         }
429 }
430
431 std::string GetServerDescription(const char* servername)
432 {
433         std::string description = "";
434
435         FOREACH_MOD(I_OnGetServerDescription,OnGetServerDescription(servername,description));
436
437         if (description != "")
438         {
439                 return description;
440         }
441         else
442         {
443                 // not a remote server that can be found, it must be me.
444                 return Config->ServerDesc;
445         }
446 }
447
448 /* write a formatted string to all users who share at least one common
449  * channel, including the source user e.g. for use in NICK */
450
451 void WriteCommon(userrec *u, char* text, ...)
452 {
453         char textbuffer[MAXBUF];
454         va_list argsPtr;
455         bool sent_to_at_least_one = false;
456
457         if (!u)
458         {
459                 log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter");
460                 return;
461         }
462
463         if (u->registered != REG_ALL)
464         {
465                 log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user");
466                 return;
467         }
468
469         va_start(argsPtr, text);
470         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
471         va_end(argsPtr);
472
473         // XXX: Save on memset calls by using an ID. This clever trick thought of during discussion with nazzy and w00t.
474         uniq_id++;
475
476         for (std::vector<ucrec*>::const_iterator v = u->chans.begin(); v != u->chans.end(); v++)
477         {
478                 if (((ucrec*)(*v))->channel)
479                 {
480                         CUList *ulist= ((ucrec*)(*v))->channel->GetUsers();
481
482                         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
483                         {
484                                 if ((IS_LOCAL(i->second)) && (already_sent[i->second->fd] != uniq_id))
485                                 {
486                                         already_sent[i->second->fd] = uniq_id;
487                                         WriteFrom_NoFormat(i->second->fd,u,textbuffer);
488                                         sent_to_at_least_one = true;
489                                 }
490                         }
491                 }
492         }
493
494         /*
495          * if the user was not in any channels, no users will receive the text. Make sure the user
496          * receives their OWN message for WriteCommon
497          */
498         if (!sent_to_at_least_one)
499         {
500                 WriteFrom_NoFormat(u->fd,u,textbuffer);
501         }
502 }
503
504 void WriteCommon_NoFormat(userrec *u, const char* text)
505 {
506         bool sent_to_at_least_one = false;
507
508         if (!u)
509         {
510                 log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter");
511                 return;
512         }
513
514         if (u->registered != REG_ALL)
515         {
516                 log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user");
517                 return;
518         }
519
520         // XXX: See comment in WriteCommon
521         uniq_id++;
522
523         for (std::vector<ucrec*>::const_iterator v = u->chans.begin(); v != u->chans.end(); v++)
524         {
525                 if (((ucrec*)(*v))->channel)
526                 {
527                         CUList *ulist= ((ucrec*)(*v))->channel->GetUsers();
528
529                         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
530                         {
531                                 if ((IS_LOCAL(i->second)) && (already_sent[i->second->fd] != uniq_id))
532                                 {
533                                         already_sent[i->second->fd] = uniq_id;
534                                         WriteFrom_NoFormat(i->second->fd,u,text);
535                                         sent_to_at_least_one = true;
536                                 }
537                         }
538                 }
539         }
540
541         /*
542          * if the user was not in any channels, no users will receive the text. Make sure the user
543          * receives their OWN message for WriteCommon
544          */
545         if (!sent_to_at_least_one)
546         {
547                 WriteFrom_NoFormat(u->fd,u,text);
548         }
549 }
550
551
552 /* write a formatted string to all users who share at least one common
553  * channel, NOT including the source user e.g. for use in QUIT
554  */
555
556 void WriteCommonExcept(userrec *u, char* text, ...)
557 {
558         char textbuffer[MAXBUF];
559         char oper_quit[MAXBUF];
560         bool quit_munge = false;
561         va_list argsPtr;
562         int total;
563
564         if (!u)
565         {
566                 log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter");
567                 return;
568         }
569
570         if (u->registered != REG_ALL)
571         {
572                 log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user");
573                 return;
574         }
575
576         va_start(argsPtr, text);
577         total = vsnprintf(textbuffer, MAXBUF, text, argsPtr);
578         va_end(argsPtr);
579
580         if ((Config->HideSplits) && (total > 6))
581         {
582                 /* Yeah yeah, this is ugly. But its fast, live with it. */
583                 char* check = textbuffer;
584
585                 if ((*check++ == 'Q') && (*check++ == 'U') && (*check++ == 'I') && (*check++ == 'T') && (*check++ == ' ') && (*check++ == ':'))
586                 {
587                         std::stringstream split(check);
588                         std::string server_one;
589                         std::string server_two;
590
591                         split >> server_one;
592                         split >> server_two;
593
594                         if ((FindServerName(server_one)) && (FindServerName(server_two)))
595                         {
596                                 strlcpy(oper_quit,textbuffer,MAXQUIT);
597                                 strlcpy(check,"*.net *.split",MAXQUIT);
598                                 quit_munge = true;
599                         }
600                 }
601         }
602
603         if ((Config->HideBans) && (total > 13) && (!quit_munge))
604         {
605                 char* check = textbuffer;
606
607                 /* XXX - as above */
608                 if ((*check++ == 'Q') && (*check++ == 'U') && (*check++ == 'I') && (*check++ == 'T') && (*check++ == ' ') && (*check++ == ':'))
609                 {
610                         check++;
611
612                         if ((*check++ == '-') && (*check++ == 'L') && (*check++ == 'i') && (*check++ == 'n') && (*check++ == 'e') && (*check++ == 'd') && (*check++ == ':'))
613                         {
614                                 strlcpy(oper_quit,textbuffer,MAXQUIT);
615                                 *(--check) = 0;         // We don't need to strlcpy, we just chop it from the :
616                                 quit_munge = true;
617                         }
618                 }
619         }
620
621         uniq_id++;
622
623         for (std::vector<ucrec*>::const_iterator v = u->chans.begin(); v != u->chans.end(); v++)
624         {
625                 if (((ucrec*)(*v))->channel)
626                 {
627                         CUList *ulist= ((ucrec*)(*v))->channel->GetUsers();
628
629                         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
630                         {
631                                 if (u != i->second)
632                                 {
633                                         if ((IS_LOCAL(i->second)) && (already_sent[i->second->fd] != uniq_id))
634                                         {
635                                                 already_sent[i->second->fd] = uniq_id;
636
637                                                 if (quit_munge)
638                                                 {
639                                                         WriteFrom_NoFormat(i->second->fd,u,*i->second->oper ? oper_quit : textbuffer);
640                                                 }
641                                                 else
642                                                         WriteFrom_NoFormat(i->second->fd,u,textbuffer);
643                                         }
644                                 }
645                         }
646                 }
647         }
648 }
649
650 void WriteCommonExcept_NoFormat(userrec *u, const char* text)
651 {
652         if (!u)
653         {
654                 log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter");
655                 return;
656         }
657  
658         if (u->registered != REG_ALL)
659         {
660                 log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user");
661                 return;
662         }
663
664         uniq_id++;
665
666         for (std::vector<ucrec*>::const_iterator v = u->chans.begin(); v != u->chans.end(); v++)
667         {
668                 if (((ucrec*)(*v))->channel)
669                 {
670                         CUList *ulist= ((ucrec*)(*v))->channel->GetUsers();
671
672                         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
673                         {
674                                 if (u != i->second)
675                                 {
676                                         if ((IS_LOCAL(i->second)) && (already_sent[i->second->fd] != uniq_id))
677                                         {
678                                                 already_sent[i->second->fd] = uniq_id;
679                                                 WriteFrom_NoFormat(i->second->fd,u,text);
680                                         }
681                                 }
682                         }
683                 }
684         }
685 }
686
687
688 /* XXX - We don't use WriteMode for this because WriteMode is very slow and
689  * this isnt. Basically WriteMode has to iterate ALL the users 'n' times for
690  * the number of modes provided, e.g. if you send WriteMode 'og' to write to
691  * opers with globops, and you have 2000 users, thats 4000 iterations. WriteOpers
692  * uses the oper list, which means if you have 2000 users but only 5 opers,
693  * it iterates 5 times.
694  */
695 void WriteOpers(const char* text, ...)
696 {
697         char textbuffer[MAXBUF];
698         va_list argsPtr;
699
700         if (!text)
701         {
702                 log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
703                 return;
704         }
705
706         va_start(argsPtr, text);
707         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
708         va_end(argsPtr);
709
710         WriteOpers_NoFormat(textbuffer);
711 }
712
713 void WriteOpers_NoFormat(const char* text)
714 {
715         if (!text)
716         {
717                 log(DEFAULT,"*** BUG *** WriteOpers_NoFormat was given an invalid parameter");
718                 return;
719         }
720
721         for (std::vector<userrec*>::iterator i = all_opers.begin(); i != all_opers.end(); i++)
722         {
723                 userrec* a = *i;
724
725                 if (IS_LOCAL(a))
726                 {
727                         if (a->modes[UM_SERVERNOTICE])
728                         {
729                                 // send server notices to all with +s
730                                 WriteServ(a->fd,"NOTICE %s :%s",a->nick,text);
731                         }
732                 }
733         }
734 }
735
736 void ServerNoticeAll(char* text, ...)
737 {
738         if (!text)
739                 return;
740
741         char textbuffer[MAXBUF];
742         char formatbuffer[MAXBUF];
743         va_list argsPtr;
744         va_start (argsPtr, text);
745         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
746         va_end(argsPtr);
747
748         snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s",Config->ServerName,textbuffer);
749
750         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
751         {
752                 userrec* t = (userrec*)(*i);
753                 WriteServ_NoFormat(t->fd,formatbuffer);
754         }
755 }
756
757 void ServerPrivmsgAll(char* text, ...)
758 {
759         if (!text)
760                 return;
761
762         char textbuffer[MAXBUF];
763         char formatbuffer[MAXBUF];
764         va_list argsPtr;
765         va_start (argsPtr, text);
766         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
767         va_end(argsPtr);
768
769         snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s",Config->ServerName,textbuffer);
770
771         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
772         {
773                 userrec* t = (userrec*)(*i);
774                 WriteServ_NoFormat(t->fd,formatbuffer);
775         }
776 }
777
778 void WriteMode(const char* modes, int flags, const char* text, ...)
779 {
780         char textbuffer[MAXBUF];
781         int modelen;
782         va_list argsPtr;
783
784         if ((!text) || (!modes) || (!flags))
785         {
786                 log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
787                 return;
788         }
789
790         va_start(argsPtr, text);
791         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
792         va_end(argsPtr);
793         modelen = strlen(modes);
794
795         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
796         {
797                 userrec* t = (userrec*)(*i);
798                 bool send_to_user = false;
799
800                 if (flags == WM_AND)
801                 {
802                         send_to_user = true;
803
804                         for (int n = 0; n < modelen; n++)
805                         {
806                                 if (!t->modes[modes[n]-65])
807                                 {
808                                         send_to_user = false;
809                                         break;
810                                 }
811                         }
812                 }
813                 else if (flags == WM_OR)
814                 {
815                         send_to_user = false;
816
817                         for (int n = 0; n < modelen; n++)
818                         {
819                                 if (t->modes[modes[n]-65])
820                                 {
821                                         send_to_user = true;
822                                         break;
823                                 }
824                         }
825                 }
826
827                 if (send_to_user)
828                 {
829                         WriteServ(t->fd,"NOTICE %s :%s",t->nick,textbuffer);
830                 }
831         }
832 }
833
834 void NoticeAll(userrec *source, bool local_only, char* text, ...)
835 {
836         char textbuffer[MAXBUF];
837         char formatbuffer[MAXBUF];
838         va_list argsPtr;
839
840         if ((!text) || (!source))
841         {
842                 log(DEFAULT,"*** BUG *** NoticeAll was given an invalid parameter");
843                 return;
844         }
845
846         va_start(argsPtr, text);
847         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
848         va_end(argsPtr);
849
850         snprintf(formatbuffer,MAXBUF,"NOTICE $* :%s",textbuffer);
851
852         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
853         {
854                 userrec* t = (userrec*)(*i);
855                 WriteFrom_NoFormat(t->fd,source,formatbuffer);
856         }
857 }
858
859
860 void WriteWallOps(userrec *source, bool local_only, char* text, ...)
861 {
862         char textbuffer[MAXBUF];
863         char formatbuffer[MAXBUF];
864         va_list argsPtr;
865
866         if ((!text) || (!source))
867         {
868                 log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
869                 return;
870         }
871
872         va_start(argsPtr, text);
873         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
874         va_end(argsPtr);
875
876         snprintf(formatbuffer,MAXBUF,"WALLOPS :%s",textbuffer);
877
878         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
879         {
880                 userrec* t = (userrec*)(*i);
881
882                 if ((IS_LOCAL(t)) && (t->modes[UM_WALLOPS]))
883                 {
884                         WriteTo_NoFormat(source,t,formatbuffer);
885                 }
886         }
887 }
888
889 /* convert a string to lowercase. Note following special circumstances
890  * taken from RFC 1459. Many "official" server branches still hold to this
891  * rule so i will too;
892  *
893  *  Because of IRC's scandanavian origin, the characters {}| are
894  *  considered to be the lower case equivalents of the characters []\,
895  *  respectively. This is a critical issue when determining the
896  *  equivalence of two nicknames.
897  */
898 void strlower(char *n)
899 {
900         if (n)
901         {
902                 for (char* t = n; *t; t++)
903                         *t = lowermap[(unsigned char)*t];
904         }
905 }
906
907 /* Find a user record by nickname and return a pointer to it */
908
909 userrec* Find(const std::string &nick)
910 {
911         user_hash::iterator iter = clientlist.find(nick);
912
913         if (iter == clientlist.end())
914                 /* Couldn't find it */
915                 return NULL;
916
917         return iter->second;
918 }
919
920 userrec* Find(const char* nick)
921 {
922         user_hash::iterator iter;
923
924         if (!nick)
925                 return NULL;
926
927         iter = clientlist.find(nick);
928         
929         if (iter == clientlist.end())
930                 return NULL;
931
932         return iter->second;
933 }
934
935 /* find a channel record by channel name and return a pointer to it */
936
937 chanrec* FindChan(const char* chan)
938 {
939         chan_hash::iterator iter;
940
941         if (!chan)
942         {
943                 log(DEFAULT,"*** BUG *** Findchan was given an invalid parameter");
944                 return NULL;
945         }
946
947         iter = chanlist.find(chan);
948
949         if (iter == chanlist.end())
950                 /* Couldn't find it */
951                 return NULL;
952
953         return iter->second;
954 }
955
956
957 long GetMaxBans(char* name)
958 {
959         std::string x;
960         for (std::map<std::string,int>::iterator n = Config->maxbans.begin(); n != Config->maxbans.end(); n++)
961         {
962                 x = n->first;
963                 if (match(name,x.c_str()))
964                 {
965                         return n->second;
966                 }
967         }
968         return 64;
969 }
970
971 void purge_empty_chans(userrec* u)
972 {
973         std::vector<chanrec*> to_delete;
974
975         // firstly decrement the count on each channel
976         for (std::vector<ucrec*>::iterator f = u->chans.begin(); f != u->chans.end(); f++)
977         {
978                 ucrec* uc = (ucrec*)(*f);
979                 if (uc->channel)
980                 {
981                         if (uc->channel->DelUser(u) == 0)
982                         {
983                                 /* No users left in here, mark it for deletion */
984                                 to_delete.push_back(uc->channel);
985                                 uc->channel = NULL;
986                         }
987                 }
988         }
989
990         log(DEBUG,"purge_empty_chans: %d channels to delete",to_delete.size());
991
992         for (std::vector<chanrec*>::iterator n = to_delete.begin(); n != to_delete.end(); n++)
993         {
994                 chanrec* thischan = (chanrec*)*n;
995                 chan_hash::iterator i2 = chanlist.find(thischan->name);
996                 if (i2 != chanlist.end())
997                 {
998                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second));
999                         DELETE(i2->second);
1000                         chanlist.erase(i2);
1001                 }
1002         }
1003
1004         if (*u->oper)
1005                 DeleteOper(u);
1006 }
1007
1008
1009 char* chanmodes(chanrec *chan, bool showkey)
1010 {
1011         static char scratch[MAXBUF];
1012         static char sparam[MAXBUF];
1013         char* offset = scratch;
1014         std::string extparam = "";
1015
1016         if (!chan)
1017         {
1018                 log(DEFAULT,"*** BUG *** chanmodes was given an invalid parameter");
1019                 *scratch = '\0';
1020                 return scratch;
1021         }
1022
1023         *scratch = '\0';
1024         *sparam = '\0';
1025
1026         /* This was still iterating up to 190, chanrec::custom_modes is only 64 elements -- Om */
1027         for(int n = 0; n < 64; n++)
1028         {
1029                 if(chan->modes[n])
1030                 {
1031                         *offset++ = n+65;
1032                         extparam = "";
1033                         switch (n)
1034                         {
1035                                 case CM_KEY:
1036                                         extparam = (showkey ? chan->key : "<key>");
1037                                 break;
1038                                 case CM_LIMIT:
1039                                         extparam = ConvToStr(chan->limit);
1040                                 break;
1041                                 case CM_NOEXTERNAL:
1042                                 case CM_TOPICLOCK:
1043                                 case CM_INVITEONLY:
1044                                 case CM_MODERATED:
1045                                 case CM_SECRET:
1046                                 case CM_PRIVATE:
1047                                         /* We know these have no parameters */
1048                                 break;
1049                                 default:
1050                                         extparam = chan->GetModeParameter(n+65);
1051                                 break;
1052                         }
1053                         if (extparam != "")
1054                         {
1055                                 charlcat(sparam,' ',MAXBUF);
1056                                 strlcat(sparam,extparam.c_str(),MAXBUF);
1057                         }
1058                 }
1059         }
1060
1061         /* Null terminate scratch */
1062         *offset = '\0';
1063         strlcat(scratch,sparam,MAXBUF);
1064         return scratch;
1065 }
1066
1067
1068 /* compile a userlist of a channel into a string, each nick seperated by
1069  * spaces and op, voice etc status shown as @ and + */
1070
1071 void userlist(userrec *user,chanrec *c)
1072 {
1073         if ((!c) || (!user))
1074         {
1075                 log(DEFAULT,"*** BUG *** userlist was given an invalid parameter");
1076                 return;
1077         }
1078
1079         char list[MAXBUF];
1080         size_t dlen, curlen;
1081
1082         dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1083
1084         int numusers = 0;
1085         char* ptr = list + dlen;
1086
1087         CUList *ulist= c->GetUsers();
1088
1089         /* Improvement by Brain - this doesnt change in value, so why was it inside
1090          * the loop?
1091          */
1092         bool has_user = c->HasUser(user);
1093
1094         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
1095         {
1096                 if ((!has_user) && (i->second->modes[UM_INVISIBLE]))
1097                 {
1098                         /*
1099                          * user is +i, and source not on the channel, does not show
1100                          * nick in NAMES list
1101                          */
1102                         continue;
1103                 }
1104
1105                 size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", cmode(i->second, c), i->second->nick);
1106
1107                 curlen += ptrlen;
1108                 ptr += ptrlen;
1109
1110                 numusers++;
1111
1112                 if (curlen > (480-NICKMAX))
1113                 {
1114                         /* list overflowed into multiple numerics */
1115                         WriteServ_NoFormat(user->fd,list);
1116
1117                         /* reset our lengths */
1118                         dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1119                         ptr = list + dlen;
1120
1121                         ptrlen = 0;
1122                         numusers = 0;
1123                 }
1124         }
1125
1126         /* if whats left in the list isnt empty, send it */
1127         if (numusers)
1128         {
1129                 WriteServ_NoFormat(user->fd,list);
1130         }
1131 }
1132
1133 /*
1134  * return a count of the users on a specific channel accounting for
1135  * invisible users who won't increase the count. e.g. for /LIST
1136  */
1137 int usercount_i(chanrec *c)
1138 {
1139         int count = 0;
1140
1141         if (!c)
1142                 return 0;
1143
1144         CUList *ulist= c->GetUsers();
1145         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
1146         {
1147                 if (!(i->second->modes[UM_INVISIBLE]))
1148                         count++;
1149         }
1150
1151         return count;
1152 }
1153
1154 int usercount(chanrec *c)
1155 {
1156         return (c ? c->GetUserCounter() : 0);
1157 }
1158
1159
1160 /* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
1161  * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
1162  * then their ip will be taken as 'priority' anyway, so for example,
1163  * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
1164  */
1165 ConnectClass GetClass(userrec *user)
1166 {
1167         for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
1168         {
1169                 if ((match(user->GetIPString(),i->host.c_str(),true)) || (match(user->host,i->host.c_str())))
1170                 {
1171                         return *i;
1172                 }
1173         }
1174
1175         return *(Config->Classes.begin());
1176 }
1177
1178 /*
1179  * sends out an error notice to all connected clients (not to be used
1180  * lightly!)
1181  */
1182 void send_error(char *s)
1183 {
1184         log(DEBUG,"send_error: %s",s);
1185
1186         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1187         {
1188                 userrec* t = (userrec*)(*i);
1189                 if (t->registered == REG_ALL)
1190                 {
1191                         WriteServ(t->fd,"NOTICE %s :%s",t->nick,s);
1192                 }
1193                 else
1194                 {
1195                         // fix - unregistered connections receive ERROR, not NOTICE
1196                         Write(t->fd,"ERROR :%s",s);
1197                 }
1198         }
1199 }
1200
1201 void Error(int status)
1202 {
1203         void *array[300];
1204         size_t size;
1205         char **strings;
1206
1207         signal(SIGALRM, SIG_IGN);
1208         signal(SIGPIPE, SIG_IGN);
1209         signal(SIGTERM, SIG_IGN);
1210         signal(SIGABRT, SIG_IGN);
1211         signal(SIGSEGV, SIG_IGN);
1212         signal(SIGURG, SIG_IGN);
1213         signal(SIGKILL, SIG_IGN);
1214         log(DEFAULT,"*** fell down a pothole in the road to perfection ***");
1215 #ifdef HAS_EXECINFO
1216         log(DEFAULT,"Please report the backtrace lines shown below with any bugreport to the bugtracker at http://www.inspircd.org/bugtrack/");
1217         size = backtrace(array, 30);
1218         strings = backtrace_symbols(array, size);
1219         for (size_t i = 0; i < size; i++) {
1220                 log(DEFAULT,"[%d] %s", i, strings[i]);
1221         }
1222         free(strings);
1223         WriteOpers("*** SIGSEGV: Please see the ircd.log for backtrace and report the error to http://www.inspircd.org/bugtrack/");
1224 #else
1225         log(DEFAULT,"You do not have execinfo.h so i could not backtrace -- on FreeBSD, please install the libexecinfo port.");
1226 #endif
1227         send_error("Somebody screwed up... Whoops. IRC Server terminating.");
1228         signal(SIGSEGV, SIG_DFL);
1229         if (raise(SIGSEGV) == -1)
1230         {
1231                 log(DEFAULT,"What the hell, i couldnt re-raise SIGSEGV! Error: %s",strerror(errno));
1232         }
1233         Exit(status);
1234 }
1235
1236 // this function counts all users connected, wether they are registered or NOT.
1237 int usercnt(void)
1238 {
1239         return clientlist.size();
1240 }
1241
1242 // this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state
1243 int registered_usercount(void)
1244 {
1245         int c = 0;
1246
1247         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1248         {
1249                 c += (i->second->registered == REG_ALL);
1250         }
1251
1252         return c;
1253 }
1254
1255 int usercount_invisible(void)
1256 {
1257         int c = 0;
1258
1259         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1260         {
1261                 c += ((i->second->registered == REG_ALL) && (i->second->modes[UM_INVISIBLE]));
1262         }
1263
1264         return c;
1265 }
1266
1267 int usercount_opers(void)
1268 {
1269         int c = 0;
1270
1271         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1272         {
1273                 if (*(i->second->oper))
1274                         c++;
1275         }
1276         return c;
1277 }
1278
1279 int usercount_unknown(void)
1280 {
1281         int c = 0;
1282
1283         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1284         {
1285                 userrec* t = (userrec*)(*i);
1286                 if (t->registered != REG_ALL)
1287                         c++;
1288         }
1289
1290         return c;
1291 }
1292
1293 long chancount(void)
1294 {
1295         return chanlist.size();
1296 }
1297
1298 long local_count()
1299 {
1300         int c = 0;
1301
1302         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1303         {
1304                 userrec* t = (userrec*)(*i);
1305                 if (t->registered == REG_ALL)
1306                         c++;
1307         }
1308
1309         return c;
1310 }
1311
1312 void ShowMOTD(userrec *user)
1313 {
1314         if (!Config->MOTD.size())
1315         {
1316                 WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
1317                 return;
1318         }
1319         WriteServ(user->fd,"375 %s :%s message of the day", user->nick, Config->ServerName);
1320
1321         for (unsigned int i = 0; i < Config->MOTD.size(); i++)
1322                 WriteServ(user->fd,"372 %s :- %s",user->nick,Config->MOTD[i].c_str());
1323
1324         WriteServ(user->fd,"376 %s :End of message of the day.", user->nick);
1325 }
1326
1327 void ShowRULES(userrec *user)
1328 {
1329         if (!Config->RULES.size())
1330         {
1331                 WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
1332                 return;
1333         }
1334         WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,Config->ServerName);
1335
1336         for (unsigned int i = 0; i < Config->RULES.size(); i++)
1337                 WriteServ(user->fd,"NOTICE %s :%s",user->nick,Config->RULES[i].c_str());
1338
1339         WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,Config->ServerName);
1340 }
1341
1342 // this returns 1 when all modules are satisfied that the user should be allowed onto the irc server
1343 // (until this returns true, a user will block in the waiting state, waiting to connect up to the
1344 // registration timeout maximum seconds)
1345 bool AllModulesReportReady(userrec* user)
1346 {
1347         if (!Config->global_implementation[I_OnCheckReady])
1348                 return true;
1349
1350         for (int i = 0; i <= MODCOUNT; i++)
1351         {
1352                 if (Config->implement_lists[i][I_OnCheckReady])
1353                 {
1354                         int res = modules[i]->OnCheckReady(user);
1355                         if (!res)
1356                                 return false;
1357                 }
1358         }
1359
1360         return true;
1361 }
1362
1363 /* Make Sure Modules Are Avaliable!
1364  * (BugFix By Craig.. See? I do work! :p)
1365  * Modified by brain, requires const char*
1366  * to work with other API functions
1367  */
1368
1369 /* XXX - Needed? */
1370 bool FileExists (const char* file)
1371 {
1372         FILE *input;
1373         if ((input = fopen (file, "r")) == NULL)
1374         {
1375                 return(false);
1376         }
1377         else
1378         {
1379                 fclose (input);
1380                 return(true);
1381         }
1382 }
1383
1384 char* CleanFilename(char* name)
1385 {
1386         char* p = name + strlen(name);
1387         while ((p != name) && (*p != '/')) p--;
1388         return (p != name ? ++p : p);
1389 }
1390
1391 bool DirValid(char* dirandfile)
1392 {
1393         char work[MAXBUF];
1394         char buffer[MAXBUF];
1395         char otherdir[MAXBUF];
1396         int p;
1397
1398         strlcpy(work, dirandfile, MAXBUF);
1399         p = strlen(work);
1400
1401         // we just want the dir
1402         while (*work)
1403         {
1404                 if (work[p] == '/')
1405                 {
1406                         work[p] = '\0';
1407                         break;
1408                 }
1409
1410                 work[p--] = '\0';
1411         }
1412
1413         // Get the current working directory
1414         if (getcwd(buffer, MAXBUF ) == NULL )
1415                 return false;
1416
1417         chdir(work);
1418
1419         if (getcwd(otherdir, MAXBUF ) == NULL )
1420                 return false;
1421
1422         chdir(buffer);
1423
1424         size_t t = strlen(work);
1425
1426         if (strlen(otherdir) >= t)
1427         {
1428                 otherdir[t] = '\0';
1429
1430                 if (!strcmp(otherdir,work))
1431                 {
1432                         return true;
1433                 }
1434
1435                 return false;
1436         }
1437         else
1438         {
1439                 return false;
1440         }
1441 }
1442
1443 std::string GetFullProgDir(char** argv, int argc)
1444 {
1445         char work[MAXBUF];
1446         char buffer[MAXBUF];
1447         char otherdir[MAXBUF];
1448         int p;
1449
1450         strlcpy(work,argv[0],MAXBUF);
1451         p = strlen(work);
1452
1453         // we just want the dir
1454         while (*work)
1455         {
1456                 if (work[p] == '/')
1457                 {
1458                         work[p] = '\0';
1459                         break;
1460                 }
1461
1462                 work[p--] = '\0';
1463         }
1464
1465         // Get the current working directory
1466         if (getcwd(buffer, MAXBUF) == NULL)
1467                 return "";
1468
1469         chdir(work);
1470
1471         if (getcwd(otherdir, MAXBUF) == NULL)
1472                 return "";
1473
1474         chdir(buffer);
1475         return otherdir;
1476 }
1477
1478 int InsertMode(std::string &output, const char* mode, unsigned short section)
1479 {
1480         unsigned short currsection = 1;
1481         unsigned int pos = output.find("CHANMODES=", 0) + 10; // +10 for the length of "CHANMODES="
1482         
1483         if(section > 4 || section == 0)
1484         {
1485                 log(DEBUG, "InsertMode: CHANMODES doesn't have a section %dh :/", section);
1486                 return 0;
1487         }
1488         
1489         for(; pos < output.size(); pos++)
1490         {
1491                 if(section == currsection)
1492                         break;
1493                         
1494                 if(output[pos] == ',')
1495                         currsection++;
1496         }
1497         
1498         output.insert(pos, mode);
1499         return 1;
1500 }
1501
1502 bool IsValidChannelName(const char *chname)
1503 {
1504         char *c;
1505
1506         /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
1507         if (!chname || *chname != '#')
1508         {
1509                 return false;
1510         }
1511
1512         c = (char *)chname + 1;
1513         while (*c)
1514         {
1515                 switch (*c)
1516                 {
1517                         case ' ':
1518                         case ',':
1519                         case 7:
1520                                 return false;
1521                 }
1522
1523                 c++;
1524         }
1525                 
1526         /* too long a name - note funky pointer arithmetic here. */
1527         if ((c - chname) > CHANMAX)
1528         {
1529                         return false;
1530         }
1531
1532         return true;
1533 }
1534
1535 inline int charlcat(char* x,char y,int z)
1536 {
1537         char* x__n = x;
1538         int v = 0;
1539
1540         while(*x__n++)
1541                 v++;
1542
1543         if (v < z - 1)
1544         {
1545                 *--x__n = y;
1546                 *++x__n = 0;
1547         }
1548
1549         return v;
1550 }
1551
1552 bool charremove(char* mp, char remove)
1553 {
1554         char* mptr = mp;
1555         bool shift_down = false;
1556
1557         while (*mptr)
1558         {
1559                 if (*mptr == remove)
1560                 shift_down = true;
1561
1562                 if (shift_down)
1563                         *mptr = *(mptr+1);
1564
1565                 mptr++;
1566         }
1567
1568         return shift_down;
1569 }
1570
1571 void OpenLog(char** argv, int argc)
1572 {
1573         if (!*LOG_FILE)
1574         {
1575                 if (Config->logpath == "")
1576                 {
1577                         Config->logpath = GetFullProgDir(argv,argc) + "/ircd.log";
1578                 }
1579         }
1580         else
1581         {
1582                 Config->log_file = fopen(LOG_FILE,"a+");
1583
1584                 if (!Config->log_file)
1585                 {
1586                         printf("ERROR: Could not write to logfile %s, bailing!\n\n",Config->logpath.c_str());
1587                         Exit(ERROR);
1588                 }
1589                 
1590                 return;
1591         }
1592
1593         Config->log_file = fopen(Config->logpath.c_str(),"a+");
1594
1595         if (!Config->log_file)
1596         {
1597                 printf("ERROR: Could not write to logfile %s, bailing!\n\n",Config->logpath.c_str());
1598                 Exit(ERROR);
1599         }
1600 }
1601
1602 void CheckRoot()
1603 {
1604         if (geteuid() == 0)
1605         {
1606                 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
1607                 log(DEFAULT,"InspIRCd: startup: not starting with UID 0!");
1608                 Exit(ERROR);
1609         }
1610 }
1611
1612 void CheckDie()
1613 {
1614         if (*Config->DieValue)
1615         {
1616                 printf("WARNING: %s\n\n",Config->DieValue);
1617                 log(DEFAULT,"Uh-Oh, somebody didn't read their config file: '%s'",Config->DieValue);
1618                 Exit(ERROR);
1619         }
1620 }
1621
1622 /* We must load the modules AFTER initializing the socket engine, now */
1623 void LoadAllModules(InspIRCd* ServerInstance)
1624 {
1625         char configToken[MAXBUF];
1626         Config->module_names.clear();
1627         MODCOUNT = -1;
1628
1629         for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "module"); count++)
1630         {
1631                 Config->ConfValue(Config->config_data, "module","name",count,configToken,MAXBUF);
1632                 printf("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",configToken);
1633                 
1634                 if (!ServerInstance->LoadModule(configToken))           
1635                 {
1636                         log(DEFAULT,"Exiting due to a module loader error.");
1637                         printf("\nThere was an error loading a module: %s\n\n",ServerInstance->ModuleError());
1638                         Exit(0);
1639                 }
1640         }
1641         
1642         log(DEFAULT,"Total loaded modules: %lu",(unsigned long)MODCOUNT+1);
1643 }