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