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