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