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