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