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