]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/helperfuncs.cpp
Patch: /rehash (not /rehash ssl) will now rebind SSL ports, but not dh params etc...
[user/henk/code/inspircd.git] / src / helperfuncs.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core: libIRCDhelper */
15
16 #include "inspircd.h"
17 #include <stdarg.h>
18 #include "wildcard.h"
19 #include "xline.h"
20 #include "exitcodes.h"
21
22 static char TIMESTR[26];
23 static time_t LAST = 0;
24
25 /** Log()
26  *  Write a line of text `text' to the logfile (and stdout, if in nofork) if the level `level'
27  *  is greater than the configured loglevel.
28  */
29 void InspIRCd::Log(int level, const char* text, ...)
30 {
31         /* sanity check, just in case */
32         if (!this->Config || !this->Logger)
33                 return;
34
35         /* Do this check again here so that we save pointless vsnprintf calls */
36         if ((level < Config->LogLevel) && !Config->forcedebug)
37                 return;
38
39         va_list argsPtr;
40         char textbuffer[65536];
41
42         va_start(argsPtr, text);
43         vsnprintf(textbuffer, 65536, text, argsPtr);
44         va_end(argsPtr);
45
46         this->Log(level, std::string(textbuffer));
47 }
48
49 void InspIRCd::Log(int level, const std::string &text)
50 {
51         /* sanity check, just in case */
52         if (!this->Config || !this->Logger)
53                 return;
54
55         /* If we were given -debug we output all messages, regardless of configured loglevel */
56         if ((level < Config->LogLevel) && !Config->forcedebug)
57                 return;
58
59         if (Time() != LAST)
60         {
61                 time_t local = Time();
62                 struct tm *timeinfo = localtime(&local);
63
64                 strlcpy(TIMESTR,asctime(timeinfo),26);
65                 TIMESTR[24] = ':';
66                 LAST = Time();
67         }
68
69         if (Config->log_file && Config->writelog)
70         {
71                 std::string out = std::string(TIMESTR) + " " + text.c_str() + "\n";
72                 this->Logger->WriteLogLine(out);
73         }
74
75         if (Config->nofork)
76         {
77                 printf("%s %s\n", TIMESTR, text.c_str());
78         }
79 }
80
81 std::string InspIRCd::GetServerDescription(const char* servername)
82 {
83         std::string description;
84
85         FOREACH_MOD_I(this,I_OnGetServerDescription,OnGetServerDescription(servername,description));
86
87         if (!description.empty())
88         {
89                 return description;
90         }
91         else
92         {
93                 // not a remote server that can be found, it must be me.
94                 return Config->ServerDesc;
95         }
96 }
97
98 void InspIRCd::ServerNoticeAll(char* text, ...)
99 {
100         if (!text)
101                 return;
102
103         char textbuffer[MAXBUF];
104         char formatbuffer[MAXBUF];
105         va_list argsPtr;
106         va_start (argsPtr, text);
107         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
108         va_end(argsPtr);
109
110         snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s",Config->ServerName,textbuffer);
111
112         for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
113         {
114                 User* t = *i;
115                 t->WriteServ(std::string(formatbuffer));
116         }
117 }
118
119 void InspIRCd::ServerPrivmsgAll(char* text, ...)
120 {
121         if (!text)
122                 return;
123
124         char textbuffer[MAXBUF];
125         char formatbuffer[MAXBUF];
126         va_list argsPtr;
127         va_start (argsPtr, text);
128         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
129         va_end(argsPtr);
130
131         snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s",Config->ServerName,textbuffer);
132
133         for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
134         {
135                 User* t = *i;
136                 t->WriteServ(std::string(formatbuffer));
137         }
138 }
139
140 void InspIRCd::WriteMode(const char* modes, int flags, const char* text, ...)
141 {
142         char textbuffer[MAXBUF];
143         int modelen;
144         va_list argsPtr;
145
146         if (!text || !modes || !flags)
147         {
148                 this->Log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
149                 return;
150         }
151
152         va_start(argsPtr, text);
153         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
154         va_end(argsPtr);
155         modelen = strlen(modes);
156
157         if (flags == WM_AND)
158         {
159                 for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
160                 {
161                         User* t = *i;
162                         bool send_to_user = true;
163
164                         for (int n = 0; n < modelen; n++)
165                         {
166                                 if (!t->IsModeSet(modes[n]))
167                                 {
168                                         send_to_user = false;
169                                         break;
170                                 }
171                         }
172                         if (send_to_user)
173                         {
174                                 t->WriteServ("NOTICE %s :%s", t->nick, textbuffer);
175                         }
176                 }
177         }
178         else if (flags == WM_OR)
179         {
180                 for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
181                 {
182                         User* t = *i;
183                         bool send_to_user = false;
184
185                         for (int n = 0; n < modelen; n++)
186                         {
187                                 if (t->IsModeSet(modes[n]))
188                                 {
189                                         send_to_user = true;
190                                         break;
191                                 }
192                         }
193
194                         if (send_to_user)
195                         {
196                                 t->WriteServ("NOTICE %s :%s", t->nick, textbuffer);
197                         }
198                 }
199         }
200 }
201
202 /* Find a user record by nickname and return a pointer to it */
203 User* InspIRCd::FindNick(const std::string &nick)
204 {
205         if (!nick.empty() && isdigit(*nick.begin()))
206                 return FindUUID(nick);
207
208         user_hash::iterator iter = clientlist->find(nick);
209
210         if (iter == clientlist->end())
211                 /* Couldn't find it */
212                 return NULL;
213
214         return iter->second;
215 }
216
217 User* InspIRCd::FindNick(const char* nick)
218 {
219         if (isdigit(*nick))
220                 return FindUUID(nick);
221
222         user_hash::iterator iter = clientlist->find(nick);
223         
224         if (iter == clientlist->end())
225                 return NULL;
226
227         return iter->second;
228 }
229
230 User* InspIRCd::FindNickOnly(const std::string &nick)
231 {
232         user_hash::iterator iter = clientlist->find(nick);
233
234         if (iter == clientlist->end())
235                 return NULL;
236
237         return iter->second;
238 }
239
240 User* InspIRCd::FindNickOnly(const char* nick)
241 {
242         user_hash::iterator iter = clientlist->find(nick);
243
244         if (iter == clientlist->end())
245                 return NULL;
246
247         return iter->second;
248 }
249
250 User *InspIRCd::FindUUID(const std::string &uid)
251 {
252         return FindUUID(uid.c_str());
253 }
254
255 User *InspIRCd::FindUUID(const char *uid)
256 {
257         user_hash::iterator finduuid = uuidlist->find(uid);
258
259         if (finduuid == uuidlist->end())
260                 return NULL;
261
262         return finduuid->second;
263 }
264
265 /* find a channel record by channel name and return a pointer to it */
266 Channel* InspIRCd::FindChan(const char* chan)
267 {
268         chan_hash::iterator iter = chanlist->find(chan);
269
270         if (iter == chanlist->end())
271                 /* Couldn't find it */
272                 return NULL;
273
274         return iter->second;
275 }
276
277 Channel* InspIRCd::FindChan(const std::string &chan)
278 {
279         chan_hash::iterator iter = chanlist->find(chan);
280
281         if (iter == chanlist->end())
282                 /* Couldn't find it */
283                 return NULL;
284
285         return iter->second;
286 }
287
288 /* Send an error notice to all users, registered or not */
289 void InspIRCd::SendError(const std::string &s)
290 {
291         for (std::vector<User*>::const_iterator i = this->local_users.begin(); i != this->local_users.end(); i++)
292         {
293                 if ((*i)->registered == REG_ALL)
294                 {
295                         (*i)->WriteServ("NOTICE %s :%s",(*i)->nick,s.c_str());
296                 }
297                 else
298                 {
299                         /* Unregistered connections receive ERROR, not a NOTICE */
300                         (*i)->Write("ERROR :" + s);
301                 }
302                 /* This might generate a whole load of EAGAIN, but we dont really
303                  * care about this, as if we call SendError something catastrophic
304                  * has occured anyway, and we wont receive the events for these.
305                  */
306                 (*i)->FlushWriteBuf();
307         }
308 }
309
310 /* return how many users have a given mode e.g. 'a' */
311 int InspIRCd::ModeCount(const char mode)
312 {
313         ModeHandler* mh = this->Modes->FindMode(mode, MODETYPE_USER);
314
315         if (mh)
316                 return mh->GetCount();
317         else
318                 return 0;
319 }
320
321 /* return channel count */
322 long InspIRCd::ChannelCount()
323 {
324         return chanlist->size();
325 }
326
327 bool InspIRCd::IsValidMask(const std::string &mask)
328 {
329         char* dest = (char*)mask.c_str();
330         int exclamation = 0;
331         int atsign = 0;
332
333         for (char* i = dest; *i; i++)
334         {
335                 /* out of range character, bad mask */
336                 if (*i < 32 || *i > 126)
337                 {
338                         return false;
339                 }
340
341                 switch (*i)
342                 {
343                         case '!':
344                                 exclamation++;
345                                 break;
346                         case '@':
347                                 atsign++;
348                                 break;
349                 }
350         }
351
352         /* valid masks only have 1 ! and @ */
353         if (exclamation != 1 || atsign != 1)
354                 return false;
355
356         return true;
357 }
358
359 /* true for valid channel name, false else */
360 bool InspIRCd::IsChannel(const char *chname)
361 {
362         char *c;
363
364         /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
365         if (!chname || *chname != '#')
366         {
367                 return false;
368         }
369
370         c = (char *)chname + 1;
371         while (*c)
372         {
373                 switch (*c)
374                 {
375                         case ' ':
376                         case ',':
377                         case 7:
378                                 return false;
379                 }
380
381                 c++;
382         }
383                 
384         /* too long a name - note funky pointer arithmetic here. */
385         if ((c - chname) > CHANMAX)
386         {
387                         return false;
388         }
389
390         return true;
391 }
392
393 /* true for valid nickname, false else */
394 bool IsNickHandler::Call(const char* n)
395 {
396         if (!n || !*n)
397                 return false;
398  
399         int p = 0;
400         for (char* i = (char*)n; *i; i++, p++)
401         {
402                 if ((*i >= 'A') && (*i <= '}'))
403                 {
404                         /* "A"-"}" can occur anywhere in a nickname */
405                         continue;
406                 }
407
408                 if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n))
409                 {
410                         /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */
411                         continue;
412                 }
413
414                 /* invalid character! abort */
415                 return false;
416         }
417
418         /* too long? or not -- pointer arithmetic rocks */
419         return (p < NICKMAX - 1);
420 }
421
422 /* return true for good ident, false else */
423 bool IsIdentHandler::Call(const char* n)
424 {
425         if (!n || !*n)
426                 return false;
427
428         for (char* i = (char*)n; *i; i++)
429         {
430                 if ((*i >= 'A') && (*i <= '}'))
431                 {
432                         continue;
433                 }
434
435                 if (((*i >= '0') && (*i <= '9')) || (*i == '-') || (*i == '.'))
436                 {
437                         continue;
438                 }
439
440                 return false;
441         }
442
443         return true;
444 }
445
446 bool InspIRCd::IsSID(const std::string &str)
447 {
448         /* Returns true if the string given is exactly 3 characters long,
449          * starts with a digit, and the other two characters are A-Z or digits
450          */
451         return ((str.length() == 3) && isdigit(str[0]) &&
452                         ((str[1] >= 'A' && str[1] <= 'Z') || isdigit(str[1])) &&
453                          ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2])));
454 }
455
456 /* open the proper logfile */
457 bool InspIRCd::OpenLog(char**, int)
458 {
459         Config->MyDir = Config->GetFullProgDir();
460
461         if (!*this->LogFileName)
462         {
463                 if (Config->logpath.empty())
464                 {
465                         Config->logpath = Config->MyDir + "/ircd.log";
466                 }
467
468                 Config->log_file = fopen(Config->logpath.c_str(),"a+");
469         }
470         else
471         {
472                 Config->log_file = fopen(this->LogFileName,"a+");
473         }
474
475         if (!Config->log_file)
476         {
477                 this->Logger = NULL;
478                 return false;
479         }
480
481         this->Logger = new FileLogger(this, Config->log_file);
482         return true;
483 }
484
485 void InspIRCd::CheckRoot()
486 {
487         if (geteuid() == 0)
488         {
489                 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
490                 this->Log(DEFAULT,"Cant start as root");
491                 Exit(EXIT_STATUS_ROOT);
492         }
493 }
494
495 void InspIRCd::CheckDie()
496 {
497         if (*Config->DieValue)
498         {
499                 printf("WARNING: %s\n\n",Config->DieValue);
500                 this->Log(DEFAULT,"Died because of <die> tag: %s",Config->DieValue);
501                 Exit(EXIT_STATUS_DIETAG);
502         }
503 }
504
505 void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const std::string &text)
506 {
507         std::string copy_text = text;
508
509         int MOD_RESULT = 0;
510         FOREACH_RESULT_I(this, I_OnWhoisLine, OnWhoisLine(user, dest, numeric, copy_text));
511
512         if (!MOD_RESULT)
513                 user->WriteServ("%d %s", numeric, copy_text.c_str());
514 }
515
516 void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const char* format, ...)
517 {
518         char textbuffer[MAXBUF];
519         va_list argsPtr;
520         va_start (argsPtr, format);
521         vsnprintf(textbuffer, MAXBUF, format, argsPtr);
522         va_end(argsPtr);
523
524         this->SendWhoisLine(user, dest, numeric, std::string(textbuffer));
525 }
526
527 /** Refactored by Brain, Jun 2008. Much faster with some clever O(1) array
528  * lookups and pointer maths.
529  */
530 long InspIRCd::Duration(const std::string &str)
531 {
532         unsigned char multiplier = 0;
533         long total = 0;
534         long times = 1;
535         long subtotal = 0;
536
537         /* Iterate each item in the string, looking for number or multiplier */
538         for (std::string::const_reverse_iterator i = str.rbegin(); i != str.rend(); ++i)
539         {
540                 /* Found a number, queue it onto the current number */
541                 if ((*i >= '0') && (*i <= '9'))
542                 {
543                         subtotal = subtotal + ((*i - '0') * times);
544                         times = times * 10;
545                 }
546                 else
547                 {
548                         /* Found something thats not a number, find out how much
549                          * it multiplies the built up number by, multiply the total
550                          * and reset the built up number.
551                          */
552                         if (subtotal)
553                                 total += subtotal * duration_multi[multiplier];
554
555                         /* Next subtotal please */
556                         subtotal = 0;
557                         multiplier = *i;
558                         times = 1;
559                 }
560         }
561         if (multiplier)
562         {
563                 total += subtotal * duration_multi[multiplier];
564                 subtotal = 0;
565         }
566         /* Any trailing values built up are treated as raw seconds */
567         return total + subtotal;
568 }
569
570 bool InspIRCd::ULine(const char* server)
571 {
572         if (!server)
573                 return false;
574         if (!*server)
575                 return true;
576
577         return (Config->ulines.find(server) != Config->ulines.end());
578 }
579
580 bool InspIRCd::SilentULine(const char* server)
581 {
582         std::map<irc::string,bool>::iterator n = Config->ulines.find(server);
583         if (n != Config->ulines.end())
584                 return n->second;
585         else return false;
586 }
587
588 std::string InspIRCd::TimeString(time_t curtime)
589 {
590         return std::string(ctime(&curtime),24);
591 }
592