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