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