]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/helperfuncs.cpp
Forward port of CullList and my bragging rights
[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 do_log(int level, const 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         if (fd_ref_table[sock])
159         {
160                 bytes = snprintf(tb,MAXBUF,"%s\r\n",text);
161                 chop(tb);
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         if (fd_ref_table[sock])
204         {
205
206                 va_start(argsPtr, text);
207                 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
208                 va_end(argsPtr);
209                 bytes = snprintf(tb,MAXBUF,"%s\r\n",textbuffer);
210                 chop(tb);
211
212                 if (Config->GetIOHook(fd_ref_table[sock]->port))
213                 {
214                         try
215                         {
216                                 Config->GetIOHook(fd_ref_table[sock]->port)->OnRawSocketWrite(sock,tb,bytes);
217                         }
218                         catch (ModuleException& modexcept)
219                         {
220                                 log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
221                         }                                               
222                 }
223                 else
224                 {
225                         fd_ref_table[sock]->AddWriteBuf(tb);
226                 }
227                 ServerInstance->stats->statsSent += bytes;
228         }
229         else
230                 log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
231 }
232
233 /** WriteServ_NoFormat()
234  *  Same as Write_NoFormat(), except prefixes `text' with `:server.name '.
235  */
236 void WriteServ_NoFormat(int sock, const char* text)
237 {
238         char tb[MAXBUF];
239         int bytes;
240
241         if ((sock < 0) || (!text) || (sock > MAX_DESCRIPTORS))
242                 return;
243
244         if (fd_ref_table[sock])
245         {
246                 bytes = snprintf(tb,MAXBUF,":%s %s\r\n",Config->ServerName,text);
247                 chop(tb);
248
249                 if (Config->GetIOHook(fd_ref_table[sock]->port))
250                 {
251                         try
252                         {
253                                 Config->GetIOHook(fd_ref_table[sock]->port)->OnRawSocketWrite(sock,tb,bytes);
254                         }
255                         catch (ModuleException& modexcept)
256                         {
257                                 log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
258                         }
259                 }
260                 else
261                 {
262                         fd_ref_table[sock]->AddWriteBuf(tb);
263                 }
264                 ServerInstance->stats->statsSent += bytes;
265         }
266         else
267                 log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
268 }
269
270 /** WriteServ()
271  *  Same as Write(), except `text' is prefixed with `:server.name '.
272  */
273 void WriteServ(int sock, char* text, ...)
274 {
275         va_list argsPtr;
276         char textbuffer[MAXBUF];
277
278         if ((sock < 0) || (sock > MAX_DESCRIPTORS))
279                 return;
280
281         if (!text)
282         {
283                 log(DEFAULT,"*** BUG *** WriteServ was given an invalid parameter");
284                 return;
285         }
286
287         if (!fd_ref_table[sock])
288                 return;
289
290         va_start(argsPtr, text);
291         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
292         va_end(argsPtr);
293         
294         WriteServ_NoFormat(sock, textbuffer);
295 }
296
297 /** WriteFrom_NoFormat()
298  * Write `text' to a socket with fd `sock' prefixed with `:n!u@h' - taken from
299  * the nick, user, and host of `user'.
300  */
301 void WriteFrom_NoFormat(int sock, userrec *user, const char* text)
302 {
303         char tb[MAXBUF];
304         int bytes;
305
306         if ((sock < 0) || (!text) || (!user) || (sock > MAX_DESCRIPTORS))
307                 return;
308
309         if (fd_ref_table[sock])
310         {
311                 bytes = snprintf(tb,MAXBUF,":%s %s\r\n",user->GetFullHost(),text);
312                 chop(tb);
313
314                 if (Config->GetIOHook(fd_ref_table[sock]->port))
315                 {
316                         try
317                         {
318                                 Config->GetIOHook(fd_ref_table[sock]->port)->OnRawSocketWrite(sock,tb,bytes);
319                         }
320                         catch (ModuleException& modexcept)
321                         {
322                                 log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
323                         }
324                 }
325                 else
326                 {
327                         fd_ref_table[sock]->AddWriteBuf(tb);
328                 }
329                 ServerInstance->stats->statsSent += bytes;
330         }
331         else
332                 log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
333 }
334
335 /* write text from an originating user to originating user */
336
337 void WriteFrom(int sock, userrec *user,char* text, ...)
338 {
339         va_list argsPtr;
340         char textbuffer[MAXBUF];
341         char tb[MAXBUF];
342         int bytes;
343
344         if ((sock < 0) || (sock > MAX_DESCRIPTORS))
345                 return;
346
347         if ((!text) || (!user))
348         {
349                 log(DEFAULT,"*** BUG *** WriteFrom was given an invalid parameter");
350                 return;
351         }
352
353         if (fd_ref_table[sock])
354         {
355
356                 va_start(argsPtr, text);
357                 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
358                 va_end(argsPtr);
359                 bytes = snprintf(tb,MAXBUF,":%s %s\r\n",user->GetFullHost(),textbuffer);
360                 chop(tb);
361
362                 if (Config->GetIOHook(fd_ref_table[sock]->port))
363                 {
364                         try
365                         {
366                                 Config->GetIOHook(fd_ref_table[sock]->port)->OnRawSocketWrite(sock,tb,bytes);
367                         }
368                         catch (ModuleException& modexcept)
369                         {
370                                 log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
371                         }
372                 }
373                 else
374                 {
375                         fd_ref_table[sock]->AddWriteBuf(tb);
376                 }
377
378                 ServerInstance->stats->statsSent += bytes;
379         }
380         else
381                 log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
382 }
383
384 /* write text to an destination user from a source user (e.g. user privmsg) */
385
386 void WriteTo(userrec *source, userrec *dest,char *data, ...)
387 {
388         char textbuffer[MAXBUF];
389         va_list argsPtr;
390
391         if ((!dest) || (!data))
392         {
393                 log(DEFAULT,"*** BUG *** WriteTo was given an invalid parameter");
394                 return;
395         }
396
397         if (!IS_LOCAL(dest))
398                 return;
399
400         va_start(argsPtr, data);
401         vsnprintf(textbuffer, MAXBUF, data, argsPtr);
402         va_end(argsPtr);
403         chop(textbuffer);
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(char* ServName, chanrec* Ptr, 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(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(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         // FIX: Stops a message going to the same person more than once
713         memset(&already_sent,0,MAX_DESCRIPTORS);
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]))
724                                 {
725                                         already_sent[i->second->fd] = 1;
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         // FIX: Stops a message going to the same person more than once
760         memset(&already_sent,0,MAX_DESCRIPTORS);
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]))
771                                 {
772                                         already_sent[i->second->fd] = 1;
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         memset(&already_sent,0,MAX_DESCRIPTORS);
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]))
873                                         {
874                                                 already_sent[i->second->fd] = 1;
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         memset(&already_sent,0,MAX_DESCRIPTORS);
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]))
916                                         {
917                                                 already_sent[i->second->fd] = 1;
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->modebits & 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 (!hasumode(t,modes[n]))
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 (hasumode(t,modes[n]))
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->modebits & 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                 if (((ucrec*)(*f))->channel)
1218                 {
1219                         if (((ucrec*)(*f))->channel->DelUser(u) == 0)
1220                         {
1221                                 /* No users left in here, mark it for deletion */
1222                                 to_delete.push_back(((ucrec*)(*f))->channel);
1223                                 ((ucrec*)(*f))->channel = NULL;
1224                         }
1225                 }
1226         }
1227
1228         log(DEBUG,"purge_empty_chans: %d channels to delete",to_delete.size());
1229
1230         for (std::vector<chanrec*>::iterator n = to_delete.begin(); n != to_delete.end(); n++)
1231         {
1232                 chanrec* thischan = (chanrec*)*n;
1233                 chan_hash::iterator i2 = chanlist.find(thischan->name);
1234                 if (i2 != chanlist.end())
1235                 {
1236                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second));
1237                         DELETE(i2->second);
1238                         chanlist.erase(i2);
1239                 }
1240         }
1241
1242         if (*u->oper)
1243                 DeleteOper(u);
1244 }
1245
1246
1247 char* chanmodes(chanrec *chan, bool showkey)
1248 {
1249         static char scratch[MAXBUF];
1250         static char sparam[MAXBUF];
1251         char* offset = scratch;
1252         std::string extparam = "";
1253
1254         if (!chan)
1255         {
1256                 log(DEFAULT,"*** BUG *** chanmodes was given an invalid parameter");
1257                 *scratch = '\0';
1258                 return scratch;
1259         }
1260
1261         *scratch = '\0';
1262         *sparam = '\0';
1263
1264         /* This was still iterating up to 190, chanrec::custom_modes is only 64 elements -- Om */
1265         for(int n = 0; n < 64; n++)
1266         {
1267                 if(chan->modes[n])
1268                 {
1269                         *offset++ = n+65;
1270                         extparam = "";
1271                         switch (n)
1272                         {
1273                                 case CM_KEY:
1274                                         extparam = (showkey ? chan->key : "<key>");
1275                                 break;
1276                                 case CM_LIMIT:
1277                                         extparam = ConvToStr(chan->limit);
1278                                 break;
1279                                 case CM_NOEXTERNAL:
1280                                 case CM_TOPICLOCK:
1281                                 case CM_INVITEONLY:
1282                                 case CM_MODERATED:
1283                                 case CM_SECRET:
1284                                 case CM_PRIVATE:
1285                                         /* We know these have no parameters */
1286                                 break;
1287                                 default:
1288                                         extparam = chan->GetModeParameter(n+65);
1289                                 break;
1290                         }
1291                         if (extparam != "")
1292                         {
1293                                 charlcat(sparam,' ',MAXBUF);
1294                                 strlcat(sparam,extparam.c_str(),MAXBUF);
1295                         }
1296                 }
1297         }
1298
1299         /* Null terminate scratch */
1300         *offset = '\0';
1301         strlcat(scratch,sparam,MAXBUF);
1302         return scratch;
1303 }
1304
1305
1306 /* compile a userlist of a channel into a string, each nick seperated by
1307  * spaces and op, voice etc status shown as @ and + */
1308
1309 void userlist(userrec *user,chanrec *c)
1310 {
1311         if ((!c) || (!user))
1312         {
1313                 log(DEFAULT,"*** BUG *** userlist was given an invalid parameter");
1314                 return;
1315         }
1316
1317         char list[MAXBUF];
1318         size_t dlen, curlen;
1319
1320         dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1321
1322         int numusers = 0;
1323         char* ptr = list + dlen;
1324
1325         CUList *ulist= c->GetUsers();
1326
1327         /* Improvement by Brain - this doesnt change in value, so why was it inside
1328          * the loop?
1329          */
1330         bool has_user = c->HasUser(user);
1331
1332         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
1333         {
1334                 if ((!has_user) && (i->second->modebits & UM_INVISIBLE))
1335                 {
1336                         /*
1337                          * user is +i, and source not on the channel, does not show
1338                          * nick in NAMES list
1339                          */
1340                         continue;
1341                 }
1342
1343                 size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", cmode(i->second, c), i->second->nick);
1344
1345                 curlen += ptrlen;
1346                 ptr += ptrlen;
1347
1348                 numusers++;
1349
1350                 if (curlen > (480-NICKMAX))
1351                 {
1352                         /* list overflowed into multiple numerics */
1353                         WriteServ_NoFormat(user->fd,list);
1354
1355                         /* reset our lengths */
1356                         dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1357                         ptr = list + dlen;
1358
1359                         ptrlen = 0;
1360                         numusers = 0;
1361                 }
1362         }
1363
1364         /* if whats left in the list isnt empty, send it */
1365         if (numusers)
1366         {
1367                 WriteServ_NoFormat(user->fd,list);
1368         }
1369 }
1370
1371 /*
1372  * return a count of the users on a specific channel accounting for
1373  * invisible users who won't increase the count. e.g. for /LIST
1374  */
1375 int usercount_i(chanrec *c)
1376 {
1377         int count = 0;
1378
1379         if (!c)
1380                 return 0;
1381
1382         CUList *ulist= c->GetUsers();
1383         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
1384         {
1385                 if (!(i->second->modebits & UM_INVISIBLE))
1386                         count++;
1387         }
1388
1389         return count;
1390 }
1391
1392 int usercount(chanrec *c)
1393 {
1394         return (c ? c->GetUserCounter() : 0);
1395 }
1396
1397
1398 /* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
1399  * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
1400  * then their ip will be taken as 'priority' anyway, so for example,
1401  * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
1402  */
1403 ConnectClass GetClass(userrec *user)
1404 {
1405         for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
1406         {
1407                 if ((match(inet_ntoa(user->ip4),i->host.c_str())) || (match(user->host,i->host.c_str())))
1408                 {
1409                         return *i;
1410                 }
1411         }
1412
1413         return *(Config->Classes.begin());
1414 }
1415
1416 /*
1417  * sends out an error notice to all connected clients (not to be used
1418  * lightly!)
1419  */
1420 void send_error(char *s)
1421 {
1422         log(DEBUG,"send_error: %s",s);
1423
1424         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1425         {
1426                 userrec* t = (userrec*)(*i);
1427                 if (t->registered == 7)
1428                 {
1429                         WriteServ(t->fd,"NOTICE %s :%s",t->nick,s);
1430                 }
1431                 else
1432                 {
1433                         // fix - unregistered connections receive ERROR, not NOTICE
1434                         Write(t->fd,"ERROR :%s",s);
1435                 }
1436         }
1437 }
1438
1439 void Error(int status)
1440 {
1441         void *array[300];
1442         size_t size;
1443         char **strings;
1444
1445         signal(SIGALRM, SIG_IGN);
1446         signal(SIGPIPE, SIG_IGN);
1447         signal(SIGTERM, SIG_IGN);
1448         signal(SIGABRT, SIG_IGN);
1449         signal(SIGSEGV, SIG_IGN);
1450         signal(SIGURG, SIG_IGN);
1451         signal(SIGKILL, SIG_IGN);
1452         log(DEFAULT,"*** fell down a pothole in the road to perfection ***");
1453 #ifdef HAS_EXECINFO
1454         log(DEFAULT,"Please report the backtrace lines shown below with any bugreport to the bugtracker at http://www.inspircd.org/bugtrack/");
1455         size = backtrace(array, 30);
1456         strings = backtrace_symbols(array, size);
1457         for (size_t i = 0; i < size; i++) {
1458                 log(DEFAULT,"[%d] %s", i, strings[i]);
1459         }
1460         free(strings);
1461         WriteOpers("*** SIGSEGV: Please see the ircd.log for backtrace and report the error to http://www.inspircd.org/bugtrack/");
1462 #else
1463         log(DEFAULT,"You do not have execinfo.h so i could not backtrace -- on FreeBSD, please install the libexecinfo port.");
1464 #endif
1465         send_error("Somebody screwed up... Whoops. IRC Server terminating.");
1466         signal(SIGSEGV, SIG_DFL);
1467         if (raise(SIGSEGV) == -1)
1468         {
1469                 log(DEFAULT,"What the hell, i couldnt re-raise SIGSEGV! Error: %s",strerror(errno));
1470         }
1471         Exit(status);
1472 }
1473
1474 // this function counts all users connected, wether they are registered or NOT.
1475 int usercnt(void)
1476 {
1477         return clientlist.size();
1478 }
1479
1480 // this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state
1481 int registered_usercount(void)
1482 {
1483         int c = 0;
1484
1485         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1486         {
1487                 if (i->second->registered == 7) c++;
1488         }
1489
1490         return c;
1491 }
1492
1493 int usercount_invisible(void)
1494 {
1495         int c = 0;
1496
1497         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1498         {
1499                 if ((i->second->registered == 7) && (i->second->modebits & UM_INVISIBLE))
1500                         c++;
1501         }
1502
1503         return c;
1504 }
1505
1506 int usercount_opers(void)
1507 {
1508         int c = 0;
1509
1510         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1511         {
1512                 if (*(i->second->oper))
1513                         c++;
1514         }
1515         return c;
1516 }
1517
1518 int usercount_unknown(void)
1519 {
1520         int c = 0;
1521
1522         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1523         {
1524                 userrec* t = (userrec*)(*i);
1525                 if (t->registered != 7)
1526                         c++;
1527         }
1528
1529         return c;
1530 }
1531
1532 long chancount(void)
1533 {
1534         return chanlist.size();
1535 }
1536
1537 long local_count()
1538 {
1539         int c = 0;
1540
1541         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1542         {
1543                 userrec* t = (userrec*)(*i);
1544                 if (t->registered == 7)
1545                         c++;
1546         }
1547
1548         return c;
1549 }
1550
1551 void ShowMOTD(userrec *user)
1552 {
1553         static char mbuf[MAXBUF];
1554         static char crud[MAXBUF];
1555         std::string WholeMOTD = "";
1556
1557         if (!Config->MOTD.size())
1558         {
1559                 WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
1560                 return;
1561         }
1562
1563         snprintf(crud,MAXBUF,":%s 372 %s :- ", Config->ServerName, user->nick);
1564         snprintf(mbuf,MAXBUF,":%s 375 %s :- %s message of the day\r\n", Config->ServerName, user->nick, Config->ServerName);
1565         WholeMOTD = WholeMOTD + mbuf;
1566
1567         for (unsigned int i = 0; i < Config->MOTD.size(); i++)
1568                 WholeMOTD = WholeMOTD + std::string(crud) + Config->MOTD[i].c_str() + std::string("\r\n");
1569
1570         snprintf(mbuf,MAXBUF,":%s 376 %s :End of message of the day.\r\n", Config->ServerName, user->nick);
1571         WholeMOTD = WholeMOTD + mbuf;
1572
1573         // only one write operation
1574         if (Config->GetIOHook(user->port))
1575         {
1576                 try
1577                 {
1578                         Config->GetIOHook(user->port)->OnRawSocketWrite(user->fd,(char*)WholeMOTD.c_str(),WholeMOTD.length());
1579                 }
1580                 catch (ModuleException& modexcept)
1581                 {
1582                         log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
1583                 }
1584         }
1585         else
1586         {
1587                 user->AddWriteBuf(WholeMOTD);
1588         }
1589
1590         ServerInstance->stats->statsSent += WholeMOTD.length();
1591 }
1592
1593 void ShowRULES(userrec *user)
1594 {
1595         if (!Config->RULES.size())
1596         {
1597                 WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
1598                 return;
1599         }
1600         WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,Config->ServerName);
1601
1602         for (unsigned int i = 0; i < Config->RULES.size(); i++)
1603                 WriteServ(user->fd,"NOTICE %s :%s",user->nick,Config->RULES[i].c_str());
1604
1605         WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,Config->ServerName);
1606 }
1607
1608 // this returns 1 when all modules are satisfied that the user should be allowed onto the irc server
1609 // (until this returns true, a user will block in the waiting state, waiting to connect up to the
1610 // registration timeout maximum seconds)
1611 bool AllModulesReportReady(userrec* user)
1612 {
1613         if (!Config->global_implementation[I_OnCheckReady])
1614                 return true;
1615
1616         for (int i = 0; i <= MODCOUNT; i++)
1617         {
1618                 if (Config->implement_lists[i][I_OnCheckReady])
1619                 {
1620                         int res = modules[i]->OnCheckReady(user);
1621                         if (!res)
1622                                 return false;
1623                 }
1624         }
1625
1626         return true;
1627 }
1628
1629 /* Make Sure Modules Are Avaliable!
1630  * (BugFix By Craig.. See? I do work! :p)
1631  * Modified by brain, requires const char*
1632  * to work with other API functions
1633  */
1634
1635 /* XXX - Needed? */
1636 bool FileExists (const char* file)
1637 {
1638         FILE *input;
1639         if ((input = fopen (file, "r")) == NULL)
1640         {
1641                 return(false);
1642         }
1643         else
1644         {
1645                 fclose (input);
1646                 return(true);
1647         }
1648 }
1649
1650 char* CleanFilename(char* name)
1651 {
1652         char* p = name + strlen(name);
1653         while ((p != name) && (*p != '/')) p--;
1654         return (p != name ? ++p : p);
1655 }
1656
1657 bool DirValid(char* dirandfile)
1658 {
1659         char work[MAXBUF];
1660         char buffer[MAXBUF];
1661         char otherdir[MAXBUF];
1662         int p;
1663
1664         strlcpy(work, dirandfile, MAXBUF);
1665         p = strlen(work);
1666
1667         // we just want the dir
1668         while (*work)
1669         {
1670                 if (work[p] == '/')
1671                 {
1672                         work[p] = '\0';
1673                         break;
1674                 }
1675
1676                 work[p--] = '\0';
1677         }
1678
1679         // Get the current working directory
1680         if (getcwd(buffer, MAXBUF ) == NULL )
1681                 return false;
1682
1683         chdir(work);
1684
1685         if (getcwd(otherdir, MAXBUF ) == NULL )
1686                 return false;
1687
1688         chdir(buffer);
1689
1690         size_t t = strlen(work);
1691
1692         if (strlen(otherdir) >= t)
1693         {
1694                 otherdir[t] = '\0';
1695
1696                 if (!strcmp(otherdir,work))
1697                 {
1698                         return true;
1699                 }
1700
1701                 return false;
1702         }
1703         else
1704         {
1705                 return false;
1706         }
1707 }
1708
1709 std::string GetFullProgDir(char** argv, int argc)
1710 {
1711         char work[MAXBUF];
1712         char buffer[MAXBUF];
1713         char otherdir[MAXBUF];
1714         int p;
1715
1716         strlcpy(work,argv[0],MAXBUF);
1717         p = strlen(work);
1718
1719         // we just want the dir
1720         while (*work)
1721         {
1722                 if (work[p] == '/')
1723                 {
1724                         work[p] = '\0';
1725                         break;
1726                 }
1727
1728                 work[p--] = '\0';
1729         }
1730
1731         // Get the current working directory
1732         if (getcwd(buffer, MAXBUF) == NULL)
1733                 return "";
1734
1735         chdir(work);
1736
1737         if (getcwd(otherdir, MAXBUF) == NULL)
1738                 return "";
1739
1740         chdir(buffer);
1741         return otherdir;
1742 }
1743
1744 int InsertMode(std::string &output, const char* mode, unsigned short section)
1745 {
1746         unsigned short currsection = 1;
1747         unsigned int pos = output.find("CHANMODES=", 0) + 10; // +10 for the length of "CHANMODES="
1748         
1749         if(section > 4 || section == 0)
1750         {
1751                 log(DEBUG, "InsertMode: CHANMODES doesn't have a section %dh :/", section);
1752                 return 0;
1753         }
1754         
1755         for(; pos < output.size(); pos++)
1756         {
1757                 if(section == currsection)
1758                         break;
1759                         
1760                 if(output[pos] == ',')
1761                         currsection++;
1762         }
1763         
1764         output.insert(pos, mode);
1765         return 1;
1766 }
1767
1768 bool IsValidChannelName(const char *chname)
1769 {
1770         char *c;
1771
1772         /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
1773         if (!chname || *chname != '#')
1774         {
1775                 return false;
1776         }
1777
1778         c = (char *)chname + 1;
1779         while (*c)
1780         {
1781                 switch (*c)
1782                 {
1783                         case ' ':
1784                         case ',':
1785                         case 7:
1786                                 return false;
1787                 }
1788
1789                 c++;
1790         }
1791                 
1792         /* too long a name - note funky pointer arithmetic here. */
1793         if ((c - chname) > CHANMAX)
1794         {
1795                         return false;
1796         }
1797
1798         return true;
1799 }
1800
1801 inline int charlcat(char* x,char y,int z)
1802 {
1803         char* x__n = x;
1804         int v = 0;
1805
1806         while(*x__n++)
1807                 v++;
1808
1809         if (v < z - 1)
1810         {
1811                 *--x__n = y;
1812                 *++x__n = 0;
1813         }
1814
1815         return v;
1816 }
1817
1818 bool charremove(char* mp, char remove)
1819 {
1820         char* mptr = mp;
1821         bool shift_down = false;
1822
1823         while (*mptr)
1824         {
1825                 if (*mptr == remove)
1826                 shift_down = true;
1827
1828                 if (shift_down)
1829                         *mptr = *(mptr+1);
1830
1831                 mptr++;
1832         }
1833
1834         return shift_down;
1835 }
1836
1837 void OpenLog(char** argv, int argc)
1838 {
1839         if (!*LOG_FILE)
1840         {
1841                 if (Config->logpath == "")
1842                 {
1843                         Config->logpath = GetFullProgDir(argv,argc) + "/ircd.log";
1844                 }
1845         }
1846         else
1847         {
1848                 Config->log_file = fopen(LOG_FILE,"a+");
1849
1850                 if (!Config->log_file)
1851                 {
1852                         printf("ERROR: Could not write to logfile %s, bailing!\n\n",Config->logpath.c_str());
1853                         Exit(ERROR);
1854                 }
1855                 
1856                 return;
1857         }
1858
1859         Config->log_file = fopen(Config->logpath.c_str(),"a+");
1860
1861         if (!Config->log_file)
1862         {
1863                 printf("ERROR: Could not write to logfile %s, bailing!\n\n",Config->logpath.c_str());
1864                 Exit(ERROR);
1865         }
1866 }
1867
1868 void CheckRoot()
1869 {
1870         if (geteuid() == 0)
1871         {
1872                 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
1873                 log(DEFAULT,"InspIRCd: startup: not starting with UID 0!");
1874                 Exit(ERROR);
1875         }
1876 }
1877
1878 void CheckDie()
1879 {
1880         if (*Config->DieValue)
1881         {
1882                 printf("WARNING: %s\n\n",Config->DieValue);
1883                 log(DEFAULT,"Uh-Oh, somebody didn't read their config file: '%s'",Config->DieValue);
1884                 Exit(ERROR);
1885         }
1886 }
1887
1888 /* We must load the modules AFTER initializing the socket engine, now */
1889 void LoadAllModules(InspIRCd* ServerInstance)
1890 {
1891         char configToken[MAXBUF];
1892         Config->module_names.clear();
1893         MODCOUNT = -1;
1894
1895         for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "module"); count++)
1896         {
1897                 Config->ConfValue(Config->config_data, "module","name",count,configToken,MAXBUF);
1898                 printf("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",configToken);
1899                 
1900                 if (!ServerInstance->LoadModule(configToken))                
1901                 {
1902                         log(DEFAULT,"Exiting due to a module loader error.");
1903                         printf("\nThere was an error loading a module: %s\n\n",ServerInstance->ModuleError());
1904                         Exit(0);
1905                 }
1906         }
1907         
1908         log(DEFAULT,"Total loaded modules: %lu",(unsigned long)MODCOUNT+1);
1909 }