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