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