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