]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/helperfuncs.cpp
Remove 'validation' for server description and network name (didn't do anything)
[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         WriteOpers_NoFormat(textbuffer);
974 }
975
976 void WriteOpers_NoFormat(const char* text)
977 {
978         if (!text)
979         {
980                 log(DEFAULT,"*** BUG *** WriteOpers_NoFormat was given an invalid parameter");
981                 return;
982         }
983
984         for (std::vector<userrec*>::iterator i = all_opers.begin(); i != all_opers.end(); i++)
985         {
986                 userrec* a = *i;
987
988                 if (IS_LOCAL(a))
989                 {
990                         if (a->modebits & UM_SERVERNOTICE)
991                         {
992                                 // send server notices to all with +s
993                                 WriteServ(a->fd,"NOTICE %s :%s",a->nick,text);
994                         }
995                 }
996         }
997 }
998
999 void ServerNoticeAll(char* text, ...)
1000 {
1001         if (!text)
1002                 return;
1003
1004         char textbuffer[MAXBUF];
1005         char formatbuffer[MAXBUF];
1006         va_list argsPtr;
1007         va_start (argsPtr, text);
1008         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1009         va_end(argsPtr);
1010
1011         snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s",Config->ServerName,textbuffer);
1012
1013         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1014         {
1015                 userrec* t = (userrec*)(*i);
1016                 WriteServ_NoFormat(t->fd,formatbuffer);
1017         }
1018 }
1019
1020 void ServerPrivmsgAll(char* text, ...)
1021 {
1022         if (!text)
1023                 return;
1024
1025         char textbuffer[MAXBUF];
1026         char formatbuffer[MAXBUF];
1027         va_list argsPtr;
1028         va_start (argsPtr, text);
1029         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1030         va_end(argsPtr);
1031
1032         snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s",Config->ServerName,textbuffer);
1033
1034         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1035         {
1036                 userrec* t = (userrec*)(*i);
1037                 WriteServ_NoFormat(t->fd,formatbuffer);
1038         }
1039 }
1040
1041 void WriteMode(const char* modes, int flags, const char* text, ...)
1042 {
1043         char textbuffer[MAXBUF];
1044         int modelen;
1045         va_list argsPtr;
1046
1047         if ((!text) || (!modes) || (!flags))
1048         {
1049                 log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
1050                 return;
1051         }
1052
1053         va_start(argsPtr, text);
1054         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1055         va_end(argsPtr);
1056         modelen = strlen(modes);
1057
1058         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1059         {
1060                 userrec* t = (userrec*)(*i);
1061                 bool send_to_user = false;
1062
1063                 if (flags == WM_AND)
1064                 {
1065                         send_to_user = true;
1066
1067                         for (int n = 0; n < modelen; n++)
1068                         {
1069                                 if (!hasumode(t,modes[n]))
1070                                 {
1071                                         send_to_user = false;
1072                                         break;
1073                                 }
1074                         }
1075                 }
1076                 else if (flags == WM_OR)
1077                 {
1078                         send_to_user = false;
1079
1080                         for (int n = 0; n < modelen; n++)
1081                         {
1082                                 if (hasumode(t,modes[n]))
1083                                 {
1084                                         send_to_user = true;
1085                                         break;
1086                                 }
1087                         }
1088                 }
1089
1090                 if (send_to_user)
1091                 {
1092                         WriteServ(t->fd,"NOTICE %s :%s",t->nick,textbuffer);
1093                 }
1094         }
1095 }
1096
1097 void NoticeAll(userrec *source, bool local_only, char* text, ...)
1098 {
1099         char textbuffer[MAXBUF];
1100         char formatbuffer[MAXBUF];
1101         va_list argsPtr;
1102
1103         if ((!text) || (!source))
1104         {
1105                 log(DEFAULT,"*** BUG *** NoticeAll was given an invalid parameter");
1106                 return;
1107         }
1108
1109         va_start(argsPtr, text);
1110         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1111         va_end(argsPtr);
1112
1113         snprintf(formatbuffer,MAXBUF,"NOTICE $* :%s",textbuffer);
1114
1115         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1116         {
1117                 userrec* t = (userrec*)(*i);
1118                 WriteFrom_NoFormat(t->fd,source,formatbuffer);
1119         }
1120 }
1121
1122
1123 void WriteWallOps(userrec *source, bool local_only, char* text, ...)
1124 {
1125         char textbuffer[MAXBUF];
1126         char formatbuffer[MAXBUF];
1127         va_list argsPtr;
1128
1129         if ((!text) || (!source))
1130         {
1131                 log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
1132                 return;
1133         }
1134
1135         va_start(argsPtr, text);
1136         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1137         va_end(argsPtr);
1138
1139         snprintf(formatbuffer,MAXBUF,"WALLOPS :%s",textbuffer);
1140
1141         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1142         {
1143                 userrec* t = (userrec*)(*i);
1144
1145                 if ((IS_LOCAL(t)) && (t->modebits & UM_WALLOPS))
1146                 {
1147                         WriteTo_NoFormat(source,t,formatbuffer);
1148                 }
1149         }
1150 }
1151
1152 /* convert a string to lowercase. Note following special circumstances
1153  * taken from RFC 1459. Many "official" server branches still hold to this
1154  * rule so i will too;
1155  *
1156  *  Because of IRC's scandanavian origin, the characters {}| are
1157  *  considered to be the lower case equivalents of the characters []\,
1158  *  respectively. This is a critical issue when determining the
1159  *  equivalence of two nicknames.
1160  */
1161 void strlower(char *n)
1162 {
1163         if (n)
1164         {
1165                 for (char* t = n; *t; t++)
1166                         *t = lowermap[(unsigned char)*t];
1167         }
1168 }
1169
1170 /* Find a user record by nickname and return a pointer to it */
1171
1172 userrec* Find(const std::string &nick)
1173 {
1174         user_hash::iterator iter = clientlist.find(nick);
1175
1176         if (iter == clientlist.end())
1177                 /* Couldn't find it */
1178                 return NULL;
1179
1180         return iter->second;
1181 }
1182
1183 userrec* Find(const char* nick)
1184 {
1185         user_hash::iterator iter;
1186
1187         if (!nick)
1188                 return NULL;
1189
1190         iter = clientlist.find(nick);
1191         
1192         if (iter == clientlist.end())
1193                 return NULL;
1194
1195         return iter->second;
1196 }
1197
1198 /* find a channel record by channel name and return a pointer to it */
1199
1200 chanrec* FindChan(const char* chan)
1201 {
1202         chan_hash::iterator iter;
1203
1204         if (!chan)
1205         {
1206                 log(DEFAULT,"*** BUG *** Findchan was given an invalid parameter");
1207                 return NULL;
1208         }
1209
1210         iter = chanlist.find(chan);
1211
1212         if (iter == chanlist.end())
1213                 /* Couldn't find it */
1214                 return NULL;
1215
1216         return iter->second;
1217 }
1218
1219
1220 long GetMaxBans(char* name)
1221 {
1222         std::string x;
1223         for (std::map<std::string,int>::iterator n = Config->maxbans.begin(); n != Config->maxbans.end(); n++)
1224         {
1225                 x = n->first;
1226                 if (match(name,x.c_str()))
1227                 {
1228                         return n->second;
1229                 }
1230         }
1231         return 64;
1232 }
1233
1234 void purge_empty_chans(userrec* u)
1235 {
1236         std::vector<chanrec*> to_delete;
1237
1238         // firstly decrement the count on each channel
1239         for (std::vector<ucrec*>::iterator f = u->chans.begin(); f != u->chans.end(); f++)
1240         {
1241                 if (((ucrec*)(*f))->channel)
1242                 {
1243                         if (((ucrec*)(*f))->channel->DelUser(u) == 0)
1244                         {
1245                                 /* No users left in here, mark it for deletion */
1246                                 to_delete.push_back(((ucrec*)(*f))->channel);
1247                                 ((ucrec*)(*f))->channel = NULL;
1248                         }
1249                 }
1250         }
1251
1252         log(DEBUG,"purge_empty_chans: %d channels to delete",to_delete.size());
1253
1254         for (std::vector<chanrec*>::iterator n = to_delete.begin(); n != to_delete.end(); n++)
1255         {
1256                 chanrec* thischan = (chanrec*)*n;
1257                 chan_hash::iterator i2 = chanlist.find(thischan->name);
1258                 if (i2 != chanlist.end())
1259                 {
1260                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second));
1261                         delete i2->second;
1262                         chanlist.erase(i2);
1263                 }
1264         }
1265
1266         if (*u->oper)
1267                 DeleteOper(u);
1268 }
1269
1270
1271 char* chanmodes(chanrec *chan, bool showkey)
1272 {
1273         static char scratch[MAXBUF];
1274         static char sparam[MAXBUF];
1275         char* offset = scratch;
1276         std::string extparam = "";
1277
1278         if (!chan)
1279         {
1280                 log(DEFAULT,"*** BUG *** chanmodes was given an invalid parameter");
1281                 *scratch = '\0';
1282                 return scratch;
1283         }
1284
1285         *scratch = '\0';
1286         *sparam = '\0';
1287
1288         /* This was still iterating up to 190, chanrec::custom_modes is only 64 elements -- Om */
1289         for(int n = 0; n < 64; n++)
1290         {
1291                 if(chan->modes[n])
1292                 {
1293                         *offset++ = n+65;
1294                         extparam = "";
1295                         switch (n)
1296                         {
1297                                 case CM_KEY:
1298                                         extparam = (showkey ? chan->key : "<key>");
1299                                 break;
1300                                 case CM_LIMIT:
1301                                         extparam = ConvToStr(chan->limit);
1302                                 break;
1303                                 case CM_NOEXTERNAL:
1304                                 case CM_TOPICLOCK:
1305                                 case CM_INVITEONLY:
1306                                 case CM_MODERATED:
1307                                 case CM_SECRET:
1308                                 case CM_PRIVATE:
1309                                         /* We know these have no parameters */
1310                                 break;
1311                                 default:
1312                                         extparam = chan->GetModeParameter(n+65);
1313                                 break;
1314                         }
1315                         if (extparam != "")
1316                         {
1317                                 charlcat(sparam,' ',MAXBUF);
1318                                 strlcat(sparam,extparam.c_str(),MAXBUF);
1319                         }
1320                 }
1321         }
1322
1323         /* Null terminate scratch */
1324         *offset = '\0';
1325         strlcat(scratch,sparam,MAXMODES);
1326         return scratch;
1327 }
1328
1329
1330 /* compile a userlist of a channel into a string, each nick seperated by
1331  * spaces and op, voice etc status shown as @ and + */
1332
1333 void userlist(userrec *user,chanrec *c)
1334 {
1335         if ((!c) || (!user))
1336         {
1337                 log(DEFAULT,"*** BUG *** userlist was given an invalid parameter");
1338                 return;
1339         }
1340
1341         char list[MAXBUF];
1342         size_t dlen, curlen;
1343
1344         dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1345
1346         int numusers = 0;
1347         char* ptr = list + dlen;
1348
1349         CUList *ulist= c->GetUsers();
1350
1351         /* Improvement by Brain - this doesnt change in value, so why was it inside
1352          * the loop?
1353          */
1354         bool has_user = c->HasUser(user);
1355
1356         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
1357         {
1358                 if ((!has_user) && (i->second->modebits & UM_INVISIBLE))
1359                 {
1360                         /*
1361                          * user is +i, and source not on the channel, does not show
1362                          * nick in NAMES list
1363                          */
1364                         continue;
1365                 }
1366
1367                 size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", cmode(i->second, c), i->second->nick);
1368
1369                 curlen += ptrlen;
1370                 ptr += ptrlen;
1371
1372                 numusers++;
1373
1374                 if (curlen > (480-NICKMAX))
1375                 {
1376                         /* list overflowed into multiple numerics */
1377                         WriteServ_NoFormat(user->fd,list);
1378
1379                         /* reset our lengths */
1380                         dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
1381                         ptr = list + dlen;
1382
1383                         ptrlen = 0;
1384                         numusers = 0;
1385                 }
1386         }
1387
1388         /* if whats left in the list isnt empty, send it */
1389         if (numusers)
1390         {
1391                 WriteServ_NoFormat(user->fd,list);
1392         }
1393 }
1394
1395 /*
1396  * return a count of the users on a specific channel accounting for
1397  * invisible users who won't increase the count. e.g. for /LIST
1398  */
1399 int usercount_i(chanrec *c)
1400 {
1401         int count = 0;
1402
1403         if (!c)
1404                 return 0;
1405
1406         CUList *ulist= c->GetUsers();
1407         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
1408         {
1409                 if (!(i->second->modebits & UM_INVISIBLE))
1410                         count++;
1411         }
1412
1413         return count;
1414 }
1415
1416 int usercount(chanrec *c)
1417 {
1418         return (c ? c->GetUserCounter() : 0);
1419 }
1420
1421
1422 /* looks up a users password for their connection class (<ALLOW>/<DENY> tags) */
1423 ConnectClass GetClass(userrec *user)
1424 {
1425         for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
1426         {
1427                 if (match(user->host,i->host.c_str()))
1428                 {
1429                         return *i;
1430                 }
1431         }
1432
1433         return *(Config->Classes.begin());
1434 }
1435
1436 /*
1437  * sends out an error notice to all connected clients (not to be used
1438  * lightly!)
1439  */
1440 void send_error(char *s)
1441 {
1442         log(DEBUG,"send_error: %s",s);
1443
1444         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1445         {
1446                 userrec* t = (userrec*)(*i);
1447                 if (t->registered == 7)
1448                 {
1449                         WriteServ(t->fd,"NOTICE %s :%s",t->nick,s);
1450                 }
1451                 else
1452                 {
1453                         // fix - unregistered connections receive ERROR, not NOTICE
1454                         Write(t->fd,"ERROR :%s",s);
1455                 }
1456         }
1457 }
1458
1459 void Error(int status)
1460 {
1461         signal(SIGALRM, SIG_IGN);
1462         signal(SIGPIPE, SIG_IGN);
1463         signal(SIGTERM, SIG_IGN);
1464         signal(SIGABRT, SIG_IGN);
1465         signal(SIGSEGV, SIG_IGN);
1466         signal(SIGURG, SIG_IGN);
1467         signal(SIGKILL, SIG_IGN);
1468         log(DEFAULT,"*** fell down a pothole in the road to perfection ***");
1469         send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*");
1470         Exit(status);
1471 }
1472
1473 // this function counts all users connected, wether they are registered or NOT.
1474 int usercnt(void)
1475 {
1476         return clientlist.size();
1477 }
1478
1479 // this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state
1480 int registered_usercount(void)
1481 {
1482         int c = 0;
1483
1484         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1485         {
1486                 if (i->second->registered == 7) c++;
1487         }
1488
1489         return c;
1490 }
1491
1492 int usercount_invisible(void)
1493 {
1494         int c = 0;
1495
1496         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1497         {
1498                 if ((i->second->registered == 7) && (i->second->modebits & UM_INVISIBLE))
1499                         c++;
1500         }
1501
1502         return c;
1503 }
1504
1505 int usercount_opers(void)
1506 {
1507         int c = 0;
1508
1509         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
1510         {
1511                 if (*(i->second->oper))
1512                         c++;
1513         }
1514         return c;
1515 }
1516
1517 int usercount_unknown(void)
1518 {
1519         int c = 0;
1520
1521         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1522         {
1523                 userrec* t = (userrec*)(*i);
1524                 if (t->registered != 7)
1525                         c++;
1526         }
1527
1528         return c;
1529 }
1530
1531 long chancount(void)
1532 {
1533         return chanlist.size();
1534 }
1535
1536 long local_count()
1537 {
1538         int c = 0;
1539
1540         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
1541         {
1542                 userrec* t = (userrec*)(*i);
1543                 if (t->registered == 7)
1544                         c++;
1545         }
1546
1547         return c;
1548 }
1549
1550 void ShowMOTD(userrec *user)
1551 {
1552         static char mbuf[MAXBUF];
1553         static char crud[MAXBUF];
1554         std::string WholeMOTD = "";
1555
1556         if (!Config->MOTD.size())
1557         {
1558                 WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
1559                 return;
1560         }
1561
1562         snprintf(crud,MAXBUF,":%s 372 %s :- ", Config->ServerName, user->nick);
1563         snprintf(mbuf,MAXBUF,":%s 375 %s :- %s message of the day\r\n", Config->ServerName, user->nick, Config->ServerName);
1564         WholeMOTD = WholeMOTD + mbuf;
1565
1566         for (unsigned int i = 0; i < Config->MOTD.size(); i++)
1567                 WholeMOTD = WholeMOTD + std::string(crud) + Config->MOTD[i].c_str() + std::string("\r\n");
1568
1569         snprintf(mbuf,MAXBUF,":%s 376 %s :End of message of the day.\r\n", Config->ServerName, user->nick);
1570         WholeMOTD = WholeMOTD + mbuf;
1571
1572         // only one write operation
1573         if (Config->GetIOHook(user->port))
1574         {
1575                 try
1576                 {
1577                         Config->GetIOHook(user->port)->OnRawSocketWrite(user->fd,(char*)WholeMOTD.c_str(),WholeMOTD.length());
1578                 }
1579                 catch (ModuleException& modexcept)
1580                 {
1581                         log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
1582                 }
1583         }
1584         else
1585         {
1586                 user->AddWriteBuf(WholeMOTD);
1587         }
1588
1589         ServerInstance->stats->statsSent += WholeMOTD.length();
1590 }
1591
1592 void ShowRULES(userrec *user)
1593 {
1594         if (!Config->RULES.size())
1595         {
1596                 WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
1597                 return;
1598         }
1599         WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,Config->ServerName);
1600
1601         for (unsigned int i = 0; i < Config->RULES.size(); i++)
1602                 WriteServ(user->fd,"NOTICE %s :%s",user->nick,Config->RULES[i].c_str());
1603
1604         WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,Config->ServerName);
1605 }
1606
1607 // this returns 1 when all modules are satisfied that the user should be allowed onto the irc server
1608 // (until this returns true, a user will block in the waiting state, waiting to connect up to the
1609 // registration timeout maximum seconds)
1610 bool AllModulesReportReady(userrec* user)
1611 {
1612         if (!Config->global_implementation[I_OnCheckReady])
1613                 return true;
1614
1615         for (int i = 0; i <= MODCOUNT; i++)
1616         {
1617                 if (Config->implement_lists[i][I_OnCheckReady])
1618                 {
1619                         int res = modules[i]->OnCheckReady(user);
1620                         if (!res)
1621                                 return false;
1622                 }
1623         }
1624
1625         return true;
1626 }
1627
1628 bool DirValid(char* dirandfile)
1629 {
1630         char work[MAXBUF];
1631         char buffer[MAXBUF];
1632         char otherdir[MAXBUF];
1633         int p;
1634
1635         strlcpy(work, dirandfile, MAXBUF);
1636         p = strlen(work);
1637
1638         // we just want the dir
1639         while (*work)
1640         {
1641                 if (work[p] == '/')
1642                 {
1643                         work[p] = '\0';
1644                         break;
1645                 }
1646
1647                 work[p--] = '\0';
1648         }
1649
1650         // Get the current working directory
1651         if (getcwd(buffer, MAXBUF ) == NULL )
1652                 return false;
1653
1654         chdir(work);
1655
1656         if (getcwd(otherdir, MAXBUF ) == NULL )
1657                 return false;
1658
1659         chdir(buffer);
1660
1661         size_t t = strlen(work);
1662
1663         if (strlen(otherdir) >= t)
1664         {
1665                 otherdir[t] = '\0';
1666
1667                 if (!strcmp(otherdir,work))
1668                 {
1669                         return true;
1670                 }
1671
1672                 return false;
1673         }
1674         else
1675         {
1676                 return false;
1677         }
1678 }
1679
1680 std::string GetFullProgDir(char** argv, int argc)
1681 {
1682         char work[MAXBUF];
1683         char buffer[MAXBUF];
1684         char otherdir[MAXBUF];
1685         int p;
1686
1687         strlcpy(work,argv[0],MAXBUF);
1688         p = strlen(work);
1689
1690         // we just want the dir
1691         while (*work)
1692         {
1693                 if (work[p] == '/')
1694                 {
1695                         work[p] = '\0';
1696                         break;
1697                 }
1698
1699                 work[p--] = '\0';
1700         }
1701
1702         // Get the current working directory
1703         if (getcwd(buffer, MAXBUF) == NULL)
1704                 return "";
1705
1706         chdir(work);
1707
1708         if (getcwd(otherdir, MAXBUF) == NULL)
1709                 return "";
1710
1711         chdir(buffer);
1712         return otherdir;
1713 }
1714
1715 int InsertMode(std::string &output, const char* mode, unsigned short section)
1716 {
1717         unsigned short currsection = 1;
1718         unsigned int pos = output.find("CHANMODES=", 0) + 10; // +10 for the length of "CHANMODES="
1719         
1720         if(section > 4 || section == 0)
1721         {
1722                 log(DEBUG, "InsertMode: CHANMODES doesn't have a section %dh :/", section);
1723                 return 0;
1724         }
1725         
1726         for(; pos < output.size(); pos++)
1727         {
1728                 if(section == currsection)
1729                         break;
1730                         
1731                 if(output[pos] == ',')
1732                         currsection++;
1733         }
1734         
1735         output.insert(pos, mode);
1736         return 1;
1737 }
1738
1739 bool IsValidChannelName(const char *chname)
1740 {
1741         char *c;
1742
1743         /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
1744         if (!chname || *chname != '#')
1745         {
1746                 return false;
1747         }
1748
1749         c = (char *)chname + 1;
1750         while (*c)
1751         {
1752                 switch (*c)
1753                 {
1754                         case ' ':
1755                         case ',':
1756                         case 7:
1757                                 return false;
1758                 }
1759
1760                 c++;
1761         }
1762                 
1763         /* too long a name - note funky pointer arithmetic here. */
1764         if ((c - chname) > CHANMAX)
1765         {
1766                         return false;
1767         }
1768
1769         return true;
1770 }
1771
1772 inline int charlcat(char* x,char y,int z)
1773 {
1774         char* x__n = x;
1775         int v = 0;
1776
1777         while(*x__n++)
1778                 v++;
1779
1780         if (v < z - 1)
1781         {
1782                 *--x__n = y;
1783                 *++x__n = 0;
1784         }
1785
1786         return v;
1787 }
1788
1789 bool charremove(char* mp, char remove)
1790 {
1791         char* mptr = mp;
1792         bool shift_down = false;
1793
1794         while (*mptr)
1795         {
1796                 if (*mptr == remove)
1797                 shift_down = true;
1798
1799                 if (shift_down)
1800                         *mptr = *(mptr+1);
1801
1802                 mptr++;
1803         }
1804
1805         return shift_down;
1806 }
1807
1808 void OpenLog(char** argv, int argc)
1809 {
1810         if (!*LOG_FILE)
1811         {
1812                 if (Config->logpath == "")
1813                 {
1814                         Config->logpath = GetFullProgDir(argv,argc) + "/ircd.log";
1815                 }
1816         }
1817         else
1818         {
1819                 Config->log_file = fopen(LOG_FILE,"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                 return;
1828         }
1829
1830         Config->log_file = fopen(Config->logpath.c_str(),"a+");
1831
1832         if (!Config->log_file)
1833         {
1834                 printf("ERROR: Could not write to logfile %s, bailing!\n\n",Config->logpath.c_str());
1835                 Exit(ERROR);
1836         }
1837 }
1838
1839 void CheckRoot()
1840 {
1841         if (geteuid() == 0)
1842         {
1843                 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
1844                 log(DEFAULT,"InspIRCd: startup: not starting with UID 0!");
1845                 Exit(ERROR);
1846         }
1847 }
1848
1849 void CheckDie()
1850 {
1851         if (*Config->DieValue)
1852         {
1853                 printf("WARNING: %s\n\n",Config->DieValue);
1854                 log(DEFAULT,"Uh-Oh, somebody didn't read their config file: '%s'",Config->DieValue);
1855                 Exit(ERROR);
1856         }
1857 }
1858
1859 /* We must load the modules AFTER initializing the socket engine, now */
1860 void LoadAllModules(InspIRCd* ServerInstance)
1861 {
1862         char configToken[MAXBUF];
1863         Config->module_names.clear();
1864         MODCOUNT = -1;
1865                                         
1866         for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "module"); count++)
1867         {
1868                 Config->ConfValue(Config->config_data, "module","name",count,configToken,MAXBUF);
1869                 printf("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",configToken);
1870                 
1871                 if (!ServerInstance->LoadModule(configToken))                
1872                 {
1873                         log(DEFAULT,"Exiting due to a module loader error.");
1874                         printf("\nThere was an error loading a module: %s\n\n",ServerInstance->ModuleError());
1875                         Exit(0);
1876                 }
1877         }
1878         
1879         log(DEFAULT,"Total loaded modules: %lu",(unsigned long)MODCOUNT+1);
1880 }