]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/helperfuncs.cpp
m_spanningtree Return const references from several TreeServer getter functions
[user/henk/code/inspircd.git] / src / helperfuncs.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
6  *   Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc>
7  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
8  *   Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com>
9  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
10  *
11  * This file is part of InspIRCd.  InspIRCd is free software: you can
12  * redistribute it and/or modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation, version 2.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24
25 /* $Core */
26
27 #include "inspircd.h"
28 #include "xline.h"
29 #include "exitcodes.h"
30
31 std::string InspIRCd::GetServerDescription(const std::string& servername)
32 {
33         std::string description;
34
35         FOREACH_MOD(I_OnGetServerDescription,OnGetServerDescription(servername,description));
36
37         if (!description.empty())
38         {
39                 return description;
40         }
41         else
42         {
43                 // not a remote server that can be found, it must be me.
44                 return Config->ServerDesc;
45         }
46 }
47
48 /* Find a user record by nickname and return a pointer to it */
49 User* InspIRCd::FindNick(const std::string &nick)
50 {
51         if (!nick.empty() && isdigit(*nick.begin()))
52                 return FindUUID(nick);
53
54         user_hash::iterator iter = this->Users->clientlist->find(nick);
55
56         if (iter == this->Users->clientlist->end())
57                 /* Couldn't find it */
58                 return NULL;
59
60         return iter->second;
61 }
62
63 User* InspIRCd::FindNick(const char* nick)
64 {
65         if (isdigit(*nick))
66                 return FindUUID(nick);
67
68         user_hash::iterator iter = this->Users->clientlist->find(nick);
69
70         if (iter == this->Users->clientlist->end())
71                 return NULL;
72
73         return iter->second;
74 }
75
76 User* InspIRCd::FindNickOnly(const std::string &nick)
77 {
78         user_hash::iterator iter = this->Users->clientlist->find(nick);
79
80         if (iter == this->Users->clientlist->end())
81                 return NULL;
82
83         return iter->second;
84 }
85
86 User* InspIRCd::FindNickOnly(const char* nick)
87 {
88         user_hash::iterator iter = this->Users->clientlist->find(nick);
89
90         if (iter == this->Users->clientlist->end())
91                 return NULL;
92
93         return iter->second;
94 }
95
96 User *InspIRCd::FindUUID(const std::string &uid)
97 {
98         return FindUUID(uid.c_str());
99 }
100
101 User *InspIRCd::FindUUID(const char *uid)
102 {
103         user_hash::iterator finduuid = this->Users->uuidlist->find(uid);
104
105         if (finduuid == this->Users->uuidlist->end())
106                 return NULL;
107
108         return finduuid->second;
109 }
110
111 /* find a channel record by channel name and return a pointer to it */
112 Channel* InspIRCd::FindChan(const char* chan)
113 {
114         chan_hash::iterator iter = chanlist->find(chan);
115
116         if (iter == chanlist->end())
117                 /* Couldn't find it */
118                 return NULL;
119
120         return iter->second;
121 }
122
123 Channel* InspIRCd::FindChan(const std::string &chan)
124 {
125         chan_hash::iterator iter = chanlist->find(chan);
126
127         if (iter == chanlist->end())
128                 /* Couldn't find it */
129                 return NULL;
130
131         return iter->second;
132 }
133
134 /* Send an error notice to all users, registered or not */
135 void InspIRCd::SendError(const std::string &s)
136 {
137         for (std::vector<LocalUser*>::const_iterator i = this->Users->local_users.begin(); i != this->Users->local_users.end(); i++)
138         {
139                 User* u = *i;
140                 if (u->registered == REG_ALL)
141                 {
142                         u->WriteServ("NOTICE %s :%s",u->nick.c_str(),s.c_str());
143                 }
144                 else
145                 {
146                         /* Unregistered connections receive ERROR, not a NOTICE */
147                         u->Write("ERROR :" + s);
148                 }
149         }
150 }
151
152 /* return channel count */
153 long InspIRCd::ChannelCount()
154 {
155         return chanlist->size();
156 }
157
158 bool InspIRCd::IsValidMask(const std::string &mask)
159 {
160         const char* dest = mask.c_str();
161         int exclamation = 0;
162         int atsign = 0;
163
164         for (const char* i = dest; *i; i++)
165         {
166                 /* out of range character, bad mask */
167                 if (*i < 32 || *i > 126)
168                 {
169                         return false;
170                 }
171
172                 switch (*i)
173                 {
174                         case '!':
175                                 exclamation++;
176                                 break;
177                         case '@':
178                                 atsign++;
179                                 break;
180                 }
181         }
182
183         /* valid masks only have 1 ! and @ */
184         if (exclamation != 1 || atsign != 1)
185                 return false;
186
187         if (mask.length() > 250)
188                 return false;
189
190         return true;
191 }
192
193 /* true for valid channel name, false else */
194 bool IsChannelHandler::Call(const char *chname, size_t max)
195 {
196         const char *c = chname + 1;
197
198         /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
199         if (!chname || *chname != '#')
200         {
201                 return false;
202         }
203
204         while (*c)
205         {
206                 switch (*c)
207                 {
208                         case ' ':
209                         case ',':
210                         case 7:
211                                 return false;
212                 }
213
214                 c++;
215         }
216
217         size_t len = c - chname;
218         /* too long a name - note funky pointer arithmetic here. */
219         if (len > max)
220         {
221                         return false;
222         }
223
224         return true;
225 }
226
227 /* true for valid nickname, false else */
228 bool IsNickHandler::Call(const char* n, size_t max)
229 {
230         if (!n || !*n)
231                 return false;
232
233         unsigned int p = 0;
234         for (const char* i = n; *i; i++, p++)
235         {
236                 if ((*i >= 'A') && (*i <= '}'))
237                 {
238                         /* "A"-"}" can occur anywhere in a nickname */
239                         continue;
240                 }
241
242                 if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n))
243                 {
244                         /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */
245                         continue;
246                 }
247
248                 /* invalid character! abort */
249                 return false;
250         }
251
252         /* too long? or not -- pointer arithmetic rocks */
253         return (p < max);
254 }
255
256 /* return true for good ident, false else */
257 bool IsIdentHandler::Call(const char* n)
258 {
259         if (!n || !*n)
260                 return false;
261
262         for (const char* i = n; *i; i++)
263         {
264                 if ((*i >= 'A') && (*i <= '}'))
265                 {
266                         continue;
267                 }
268
269                 if (((*i >= '0') && (*i <= '9')) || (*i == '-') || (*i == '.'))
270                 {
271                         continue;
272                 }
273
274                 return false;
275         }
276
277         return true;
278 }
279
280 bool IsSIDHandler::Call(const std::string &str)
281 {
282         /* Returns true if the string given is exactly 3 characters long,
283          * starts with a digit, and the other two characters are A-Z or digits
284          */
285         return ((str.length() == 3) && isdigit(str[0]) &&
286                         ((str[1] >= 'A' && str[1] <= 'Z') || isdigit(str[1])) &&
287                          ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2])));
288 }
289
290 /* open the proper logfile */
291 bool InspIRCd::OpenLog(char**, int)
292 {
293         if (!Config->cmdline.writelog) return true; // Skip opening default log if -nolog
294
295         if (Config->cmdline.startup_log.empty())
296                 Config->cmdline.startup_log = "logs/startup.log";
297         FILE* startup = fopen(Config->cmdline.startup_log.c_str(), "a+");
298
299         if (!startup)
300         {
301                 return false;
302         }
303
304         FileWriter* fw = new FileWriter(startup);
305         FileLogStream *f = new FileLogStream((Config->cmdline.forcedebug ? DEBUG : DEFAULT), fw);
306
307         this->Logs->AddLogType("*", f, true);
308
309         return true;
310 }
311
312 void InspIRCd::CheckRoot()
313 {
314         if (geteuid() == 0)
315         {
316                 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
317                 this->Logs->Log("STARTUP",DEFAULT,"Cant start as root");
318                 Exit(EXIT_STATUS_ROOT);
319         }
320 }
321
322 void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const std::string &text)
323 {
324         std::string copy_text = text;
325
326         ModResult MOD_RESULT;
327         FIRST_MOD_RESULT(OnWhoisLine, MOD_RESULT, (user, dest, numeric, copy_text));
328
329         if (MOD_RESULT != MOD_RES_DENY)
330                 user->WriteServ("%d %s", numeric, copy_text.c_str());
331 }
332
333 void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const char* format, ...)
334 {
335         char textbuffer[MAXBUF];
336         va_list argsPtr;
337         va_start (argsPtr, format);
338         vsnprintf(textbuffer, MAXBUF, format, argsPtr);
339         va_end(argsPtr);
340
341         this->SendWhoisLine(user, dest, numeric, std::string(textbuffer));
342 }
343
344 /** Refactored by Brain, Jun 2009. Much faster with some clever O(1) array
345  * lookups and pointer maths.
346  */
347 long InspIRCd::Duration(const std::string &str)
348 {
349         unsigned char multiplier = 0;
350         long total = 0;
351         long times = 1;
352         long subtotal = 0;
353
354         /* Iterate each item in the string, looking for number or multiplier */
355         for (std::string::const_reverse_iterator i = str.rbegin(); i != str.rend(); ++i)
356         {
357                 /* Found a number, queue it onto the current number */
358                 if ((*i >= '0') && (*i <= '9'))
359                 {
360                         subtotal = subtotal + ((*i - '0') * times);
361                         times = times * 10;
362                 }
363                 else
364                 {
365                         /* Found something thats not a number, find out how much
366                          * it multiplies the built up number by, multiply the total
367                          * and reset the built up number.
368                          */
369                         if (subtotal)
370                                 total += subtotal * duration_multi[multiplier];
371
372                         /* Next subtotal please */
373                         subtotal = 0;
374                         multiplier = *i;
375                         times = 1;
376                 }
377         }
378         if (multiplier)
379         {
380                 total += subtotal * duration_multi[multiplier];
381                 subtotal = 0;
382         }
383         /* Any trailing values built up are treated as raw seconds */
384         return total + subtotal;
385 }
386
387 bool InspIRCd::ULine(const std::string& sserver)
388 {
389         if (sserver.empty())
390                 return true;
391
392         return (Config->ulines.find(sserver.c_str()) != Config->ulines.end());
393 }
394
395 bool InspIRCd::SilentULine(const std::string& sserver)
396 {
397         std::map<irc::string,bool>::iterator n = Config->ulines.find(sserver.c_str());
398         if (n != Config->ulines.end())
399                 return n->second;
400         else
401                 return false;
402 }
403
404 std::string InspIRCd::TimeString(time_t curtime)
405 {
406         return std::string(ctime(&curtime),24);
407 }
408
409 // You should only pass a single character to this.
410 void InspIRCd::AddExtBanChar(char c)
411 {
412         std::string &tok = Config->data005;
413         std::string::size_type ebpos = tok.find(" EXTBAN=,");
414
415         if (ebpos == std::string::npos)
416         {
417                 tok.append(" EXTBAN=,");
418                 tok.push_back(c);
419         }
420         else
421         {
422                 ebpos += 9;
423                 while (isalpha(tok[ebpos]) && tok[ebpos] < c)
424                         ebpos++;
425                 tok.insert(ebpos, 1, c);
426         }
427 }
428
429 std::string InspIRCd::GenRandomStr(int length, bool printable)
430 {
431         char* buf = new char[length];
432         GenRandom(buf, length);
433         std::string rv;
434         rv.resize(length);
435         for(int i=0; i < length; i++)
436                 rv[i] = printable ? 0x3F + (buf[i] & 0x3F) : buf[i];
437         delete[] buf;
438         return rv;
439 }
440
441 // NOTE: this has a slight bias for lower values if max is not a power of 2.
442 // Don't use it if that matters.
443 unsigned long InspIRCd::GenRandomInt(unsigned long max)
444 {
445         unsigned long rv;
446         GenRandom((char*)&rv, sizeof(rv));
447         return rv % max;
448 }
449
450 // This is overridden by a higher-quality algorithm when SSL support is loaded
451 void GenRandomHandler::Call(char *output, size_t max)
452 {
453         for(unsigned int i=0; i < max; i++)
454                 output[i] = random();
455 }
456
457 ModResult OnCheckExemptionHandler::Call(User* user, Channel* chan, const std::string& restriction)
458 {
459         unsigned int mypfx = chan->GetPrefixValue(user);
460         char minmode = 0;
461         std::string current;
462
463         irc::spacesepstream defaultstream(ServerInstance->Config->ConfValue("options")->getString("exemptchanops"));
464
465         while (defaultstream.GetToken(current))
466         {
467                 std::string::size_type pos = current.find(':');
468                 if (pos == std::string::npos)
469                         continue;
470                 if (current.substr(0,pos) == restriction)
471                         minmode = current[pos+1];
472         }
473
474         ModeHandler* mh = ServerInstance->Modes->FindMode(minmode, MODETYPE_CHANNEL);
475         if (mh && mypfx >= mh->GetPrefixRank())
476                 return MOD_RES_ALLOW;
477         if (mh || minmode == '*')
478                 return MOD_RES_DENY;
479         return MOD_RES_PASSTHRU;
480 }