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