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