]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/helperfuncs.cpp
6d4bcfe3e65502336fa7d7941405696c9eb54364
[user/henk/code/inspircd.git] / src / helperfuncs.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                     E-mail:
7  *              <brain@chatspike.net>
8  *              <Craig@chatspike.net>
9  *
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *          the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 #include <stdarg.h>
18 #include "inspircd_config.h"
19 #include "configreader.h"
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <sys/errno.h>
23 #include <signal.h>
24 #include <time.h>
25 #include <string>
26 #include <sstream>
27 #ifdef HAS_EXECINFO
28 #include <execinfo.h>
29 #endif
30 #include "connection.h"
31 #include "users.h"
32 #include "ctables.h"
33 #include "globals.h"
34 #include "modules.h"
35 #include "dynamic.h"
36 #include "wildcard.h"
37 #include "mode.h"
38 #include "xline.h"
39 #include "commands.h"
40 #include "inspstring.h"
41 #include "helperfuncs.h"
42 #include "hashcomp.h"
43 #include "typedefs.h"
44 #include "inspircd.h"
45
46 static char TIMESTR[26];
47 static time_t LAST = 0;
48
49 /** Log()
50  *  Write a line of text `text' to the logfile (and stdout, if in nofork) if the level `level'
51  *  is greater than the configured loglevel.
52  */
53 void InspIRCd::Log(int level, const char* text, ...)
54 {
55         va_list argsPtr;
56         char textbuffer[MAXBUF];
57
58         va_start(argsPtr, text);
59         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
60         va_end(argsPtr);
61
62         InspIRCd::Log(level, std::string(textbuffer));
63 }
64
65 void InspIRCd::Log(int level, const std::string &text)
66 {
67         extern InspIRCd* ServerInstance;
68
69         if (!ServerInstance || !ServerInstance->Config)
70                 return;
71
72         /* If we were given -debug we output all messages, regardless of configured loglevel */
73         if ((level < ServerInstance->Config->LogLevel) && !ServerInstance->Config->forcedebug)
74                 return;
75
76         if (ServerInstance->Time() != LAST)
77         {
78                 time_t local = ServerInstance->Time();
79                 struct tm *timeinfo = localtime(&local);
80
81                 strlcpy(TIMESTR,asctime(timeinfo),26);
82                 TIMESTR[24] = ':';
83                 LAST = ServerInstance->Time();
84         }
85
86         if (ServerInstance->Config->log_file && ServerInstance->Config->writelog)
87         {
88                 fprintf(ServerInstance->Config->log_file,"%s %s\n",TIMESTR,text.c_str());
89                 fflush(ServerInstance->Config->log_file);
90         }
91
92         if (ServerInstance->Config->nofork)
93         {
94                 printf("%s %s\n", TIMESTR, text.c_str());
95         }
96 }
97
98 std::string InspIRCd::GetServerDescription(const char* servername)
99 {
100         std::string description = "";
101
102         FOREACH_MOD_I(this,I_OnGetServerDescription,OnGetServerDescription(servername,description));
103
104         if (description != "")
105         {
106                 return description;
107         }
108         else
109         {
110                 // not a remote server that can be found, it must be me.
111                 return Config->ServerDesc;
112         }
113 }
114
115 /* XXX - We don't use WriteMode for this because WriteMode is very slow and
116  * this isnt. Basically WriteMode has to iterate ALL the users 'n' times for
117  * the number of modes provided, e.g. if you send WriteMode 'og' to write to
118  * opers with globops, and you have 2000 users, thats 4000 iterations. WriteOpers
119  * uses the oper list, which means if you have 2000 users but only 5 opers,
120  * it iterates 5 times.
121  */
122 void InspIRCd::WriteOpers(const char* text, ...)
123 {
124         char textbuffer[MAXBUF];
125         va_list argsPtr;
126
127         va_start(argsPtr, text);
128         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
129         va_end(argsPtr);
130
131         this->WriteOpers(std::string(textbuffer));
132 }
133
134 void InspIRCd::WriteOpers(const std::string &text)
135 {
136         for (std::vector<userrec*>::iterator i = this->all_opers.begin(); i != this->all_opers.end(); i++)
137         {
138                 userrec* a = *i;
139                 if (IS_LOCAL(a) && a->modes[UM_SERVERNOTICE])
140                 {
141                         // send server notices to all with +s
142                         a->WriteServ("NOTICE %s :%s",a->nick,text.c_str());
143                 }
144         }
145 }
146
147 void InspIRCd::ServerNoticeAll(char* text, ...)
148 {
149         if (!text)
150                 return;
151
152         char textbuffer[MAXBUF];
153         char formatbuffer[MAXBUF];
154         va_list argsPtr;
155         va_start (argsPtr, text);
156         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
157         va_end(argsPtr);
158
159         snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s",Config->ServerName,textbuffer);
160
161         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
162         {
163                 userrec* t = *i;
164                 t->WriteServ(std::string(formatbuffer));
165         }
166 }
167
168 void InspIRCd::ServerPrivmsgAll(char* text, ...)
169 {
170         if (!text)
171                 return;
172
173         char textbuffer[MAXBUF];
174         char formatbuffer[MAXBUF];
175         va_list argsPtr;
176         va_start (argsPtr, text);
177         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
178         va_end(argsPtr);
179
180         snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s",Config->ServerName,textbuffer);
181
182         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
183         {
184                 userrec* t = *i;
185                 t->WriteServ(std::string(formatbuffer));
186         }
187 }
188
189 void InspIRCd::WriteMode(const char* modes, int flags, const char* text, ...)
190 {
191         char textbuffer[MAXBUF];
192         int modelen;
193         va_list argsPtr;
194
195         if ((!text) || (!modes) || (!flags))
196         {
197                 log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
198                 return;
199         }
200
201         va_start(argsPtr, text);
202         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
203         va_end(argsPtr);
204         modelen = strlen(modes);
205
206         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
207         {
208                 userrec* t = (userrec*)(*i);
209                 bool send_to_user = false;
210
211                 if (flags == WM_AND)
212                 {
213                         send_to_user = true;
214
215                         for (int n = 0; n < modelen; n++)
216                         {
217                                 if (!t->modes[modes[n]-65])
218                                 {
219                                         send_to_user = false;
220                                         break;
221                                 }
222                         }
223                 }
224                 else if (flags == WM_OR)
225                 {
226                         send_to_user = false;
227
228                         for (int n = 0; n < modelen; n++)
229                         {
230                                 if (t->modes[modes[n]-65])
231                                 {
232                                         send_to_user = true;
233                                         break;
234                                 }
235                         }
236                 }
237
238                 if (send_to_user)
239                 {
240                         t->WriteServ("NOTICE %s :%s",t->nick,textbuffer);
241                 }
242         }
243 }
244
245 /* Find a user record by nickname and return a pointer to it */
246
247 userrec* InspIRCd::FindNick(const std::string &nick)
248 {
249         user_hash::iterator iter = clientlist.find(nick);
250
251         if (iter == clientlist.end())
252                 /* Couldn't find it */
253                 return NULL;
254
255         return iter->second;
256 }
257
258 userrec* InspIRCd::FindNick(const char* nick)
259 {
260         user_hash::iterator iter;
261
262         if (!nick)
263                 return NULL;
264
265         iter = clientlist.find(nick);
266         
267         if (iter == clientlist.end())
268                 return NULL;
269
270         return iter->second;
271 }
272
273 /* find a channel record by channel name and return a pointer to it */
274
275 chanrec* InspIRCd::FindChan(const char* chan)
276 {
277         chan_hash::iterator iter;
278
279         if (!chan)
280                 return NULL;
281
282         iter = chanlist.find(chan);
283
284         if (iter == chanlist.end())
285                 /* Couldn't find it */
286                 return NULL;
287
288         return iter->second;
289 }
290
291 chanrec* InspIRCd::FindChan(const std::string &chan)
292 {
293         chan_hash::iterator iter = chanlist.find(chan);
294
295         if (iter == chanlist.end())
296                 /* Couldn't find it */
297                 return NULL;
298
299         return iter->second;
300 }
301
302
303 /*
304  * sends out an error notice to all connected clients (not to be used
305  * lightly!)
306  */
307 void InspIRCd::SendError(const char *s)
308 {
309         for (std::vector<userrec*>::const_iterator i = this->local_users.begin(); i != this->local_users.end(); i++)
310         {
311                 userrec* t = (userrec*)(*i);
312                 if (t->registered == REG_ALL)
313                 {
314                         t->WriteServ("NOTICE %s :%s",t->nick,s);
315                 }
316                 else
317                 {
318                         // fix - unregistered connections receive ERROR, not NOTICE
319                         t->Write("ERROR :%s",s);
320                 }
321         }
322 }
323
324 void InspIRCd::Error(int status)
325 {
326         void *array[300];
327         size_t size;
328         char **strings;
329
330         signal(SIGALRM, SIG_IGN);
331         signal(SIGPIPE, SIG_IGN);
332         signal(SIGTERM, SIG_IGN);
333         signal(SIGABRT, SIG_IGN);
334         signal(SIGSEGV, SIG_IGN);
335         signal(SIGURG, SIG_IGN);
336         signal(SIGKILL, SIG_IGN);
337         log(DEFAULT,"*** fell down a pothole in the road to perfection ***");
338 #ifdef HAS_EXECINFO
339         log(DEFAULT,"Please report the backtrace lines shown below with any bugreport to the bugtracker at http://www.inspircd.org/bugtrack/");
340         size = backtrace(array, 30);
341         strings = backtrace_symbols(array, size);
342         for (size_t i = 0; i < size; i++) {
343                 log(DEFAULT,"[%d] %s", i, strings[i]);
344         }
345         free(strings);
346 #else
347         log(DEFAULT,"You do not have execinfo.h so i could not backtrace -- on FreeBSD, please install the libexecinfo port.");
348 #endif
349         signal(SIGSEGV, SIG_DFL);
350         if (raise(SIGSEGV) == -1)
351         {
352                 log(DEFAULT,"What the hell, i couldnt re-raise SIGSEGV! Error: %s",strerror(errno));
353         }
354         Exit(status);
355 }
356
357 // this function counts all users connected, wether they are registered or NOT.
358 int InspIRCd::usercnt()
359 {
360         return clientlist.size();
361 }
362
363 // this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state
364 int InspIRCd::registered_usercount()
365 {
366         int c = 0;
367
368         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
369         {
370                 c += (i->second->registered == REG_ALL);
371         }
372
373         return c;
374 }
375
376 int InspIRCd::usercount_invisible()
377 {
378         int c = 0;
379
380         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
381         {
382                 c += ((i->second->registered == REG_ALL) && (i->second->modes[UM_INVISIBLE]));
383         }
384
385         return c;
386 }
387
388 int InspIRCd::usercount_opers()
389 {
390         int c = 0;
391
392         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
393         {
394                 if (*(i->second->oper))
395                         c++;
396         }
397         return c;
398 }
399
400 int InspIRCd::usercount_unknown()
401 {
402         int c = 0;
403
404         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
405         {
406                 userrec* t = (userrec*)(*i);
407                 if (t->registered != REG_ALL)
408                         c++;
409         }
410
411         return c;
412 }
413
414 long InspIRCd::chancount()
415 {
416         return chanlist.size();
417 }
418
419 long InspIRCd::local_count()
420 {
421         int c = 0;
422
423         for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
424         {
425                 userrec* t = (userrec*)(*i);
426                 if (t->registered == REG_ALL)
427                         c++;
428         }
429
430         return c;
431 }
432
433 bool InspIRCd::IsChannel(const char *chname)
434 {
435         char *c;
436
437         /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
438         if (!chname || *chname != '#')
439         {
440                 return false;
441         }
442
443         c = (char *)chname + 1;
444         while (*c)
445         {
446                 switch (*c)
447                 {
448                         case ' ':
449                         case ',':
450                         case 7:
451                                 return false;
452                 }
453
454                 c++;
455         }
456                 
457         /* too long a name - note funky pointer arithmetic here. */
458         if ((c - chname) > CHANMAX)
459         {
460                         return false;
461         }
462
463         return true;
464 }
465
466 void InspIRCd::OpenLog(char** argv, int argc)
467 {
468         if (!*this->LogFileName)
469         {
470                 if (Config->logpath == "")
471                 {
472                         Config->logpath = ServerConfig::GetFullProgDir(argv,argc) + "/ircd.log";
473                 }
474         }
475         else
476         {
477                 Config->log_file = fopen(this->LogFileName,"a+");
478
479                 if (!Config->log_file)
480                 {
481                         printf("ERROR: Could not write to logfile %s, bailing!\n\n",Config->logpath.c_str());
482                         Exit(ERROR);
483                 }
484                 return;
485         }
486
487         Config->log_file = fopen(Config->logpath.c_str(),"a+");
488
489         if (!Config->log_file)
490         {
491                 printf("ERROR: Could not write to logfile %s, bailing!\n\n",Config->logpath.c_str());
492                 Exit(ERROR);
493         }
494 }
495
496 void InspIRCd::CheckRoot()
497 {
498         if (geteuid() == 0)
499         {
500                 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
501                 log(DEFAULT,"InspIRCd: startup: not starting with UID 0!");
502                 Exit(ERROR);
503         }
504 }
505
506 void InspIRCd::CheckDie()
507 {
508         if (*Config->DieValue)
509         {
510                 printf("WARNING: %s\n\n",Config->DieValue);
511                 log(DEFAULT,"Uh-Oh, somebody didn't read their config file: '%s'",Config->DieValue);
512                 Exit(ERROR);
513         }
514 }
515
516 /* We must load the modules AFTER initializing the socket engine, now */
517 void InspIRCd::LoadAllModules()
518 {
519         char configToken[MAXBUF];
520         Config->module_names.clear();
521         this->ModCount = -1;
522
523         for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "module"); count++)
524         {
525                 Config->ConfValue(Config->config_data, "module","name",count,configToken,MAXBUF);
526                 printf("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",configToken);
527                 
528                 if (!this->LoadModule(configToken))             
529                 {
530                         log(DEFAULT,"Exiting due to a module loader error.");
531                         printf("\nThere was an error loading a module: %s\n\n",this->ModuleError());
532                         Exit(ERROR);
533                 }
534         }
535         printf("\nA total of \033[1;32m%d\033[0m module%s been loaded.\n", this->ModCount+1, this->ModCount+1 == 1 ? " has" : "s have");
536         log(DEFAULT,"Total loaded modules: %d", this->ModCount+1);
537 }
538