2 * InspIRCd -- Internet Relay Chat Daemon
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>
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.
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
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/>.
32 #include "exitcodes.h"
35 /* Find a user record by nickname and return a pointer to it */
36 User* InspIRCd::FindNick(const std::string &nick)
38 if (!nick.empty() && isdigit(*nick.begin()))
39 return FindUUID(nick);
40 return FindNickOnly(nick);
43 User* InspIRCd::FindNickOnly(const std::string &nick)
45 user_hash::iterator iter = this->Users->clientlist.find(nick);
47 if (iter == this->Users->clientlist.end())
53 User *InspIRCd::FindUUID(const std::string &uid)
55 user_hash::iterator finduuid = this->Users->uuidlist.find(uid);
57 if (finduuid == this->Users->uuidlist.end())
60 return finduuid->second;
62 /* find a channel record by channel name and return a pointer to it */
64 Channel* InspIRCd::FindChan(const std::string &chan)
66 chan_hash::iterator iter = chanlist.find(chan);
68 if (iter == chanlist.end())
69 /* Couldn't find it */
75 bool InspIRCd::IsValidMask(const std::string &mask)
77 const char* dest = mask.c_str();
81 for (const char* i = dest; *i; i++)
83 /* out of range character, bad mask */
84 if (*i < 32 || *i > 126)
100 /* valid masks only have 1 ! and @ */
101 if (exclamation != 1 || atsign != 1)
104 if (mask.length() > ServerInstance->Config->Limits.GetMaxMask())
110 void InspIRCd::StripColor(std::string &sentence)
112 /* refactor this completely due to SQUIT bug since the old code would strip last char and replace with \0 --peavey */
115 for (std::string::iterator i = sentence.begin(); i != sentence.end();)
119 else if (seq && (( ((*i >= '0') && (*i <= '9')) || (*i == ',') ) ))
122 if ( (seq <= 4) && (*i == ',') )
130 // Strip all control codes too except \001 for CTCP
131 if (seq || ((*i >= 0) && (*i < 32) && (*i != 1)))
132 i = sentence.erase(i);
138 void InspIRCd::ProcessColors(file_cache& input)
141 * Replace all color codes from the special[] array to actual
142 * color code chars using C++ style escape sequences. You
143 * can append other chars to replace if you like -- Justasic
145 static struct special_chars
147 std::string character;
149 special_chars(const std::string& c, const std::string& r)
155 special_chars("\\b", "\x02"), // Bold
156 special_chars("\\c", "\x03"), // Color
157 special_chars("\\i", "\x1D"), // Italic
158 special_chars("\\m", "\x11"), // Monospace
159 special_chars("\\r", "\x16"), // Reverse
160 special_chars("\\s", "\x1E"), // Strikethrough
161 special_chars("\\u", "\x1F"), // Underline
162 special_chars("\\x", "\x0F"), // Reset
163 special_chars("", "")
166 for(file_cache::iterator it = input.begin(), it_end = input.end(); it != it_end; it++)
168 std::string ret = *it;
169 for(int i = 0; special[i].character.empty() == false; ++i)
171 std::string::size_type pos = ret.find(special[i].character);
172 if(pos == std::string::npos) // Couldn't find the character, skip this line
175 if((pos > 0) && (ret[pos-1] == '\\') && (ret[pos] == '\\'))
176 continue; // Skip double slashes.
178 // Replace all our characters in the array
179 while(pos != std::string::npos)
181 ret = ret.substr(0, pos) + special[i].replace + ret.substr(pos + special[i].character.size());
182 pos = ret.find(special[i].character, pos + special[i].replace.size());
186 // Replace double slashes with a single slash before we return
187 std::string::size_type pos = ret.find("\\\\");
188 while(pos != std::string::npos)
190 ret = ret.substr(0, pos) + "\\" + ret.substr(pos + 2);
191 pos = ret.find("\\\\", pos + 1);
197 /* true for valid channel name, false else */
198 bool InspIRCd::DefaultIsChannel(const std::string& chname)
200 if (chname.empty() || chname.length() > ServerInstance->Config->Limits.ChanMax)
203 if (chname[0] != '#')
206 for (std::string::const_iterator i = chname.begin()+1; i != chname.end(); ++i)
220 /* true for valid nickname, false else */
221 bool InspIRCd::DefaultIsNick(const std::string& n)
223 if (n.empty() || n.length() > ServerInstance->Config->Limits.NickMax)
226 for (std::string::const_iterator i = n.begin(); i != n.end(); ++i)
228 if ((*i >= 'A') && (*i <= '}'))
230 /* "A"-"}" can occur anywhere in a nickname */
234 if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i != n.begin()))
236 /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */
240 /* invalid character! abort */
247 /* return true for good ident, false else */
248 bool InspIRCd::DefaultIsIdent(const std::string& n)
253 for (std::string::const_iterator i = n.begin(); i != n.end(); ++i)
255 if ((*i >= 'A') && (*i <= '}'))
260 if (((*i >= '0') && (*i <= '9')) || (*i == '-') || (*i == '.'))
271 bool InspIRCd::IsHost(const std::string& host)
273 // Hostnames must be non-empty and shorter than the maximum hostname length.
274 if (host.empty() || host.length() > ServerInstance->Config->Limits.MaxHost)
277 unsigned int numdashes = 0;
278 unsigned int numdots = 0;
279 bool seendot = false;
280 const std::string::const_iterator hostend = host.end() - 1;
281 for (std::string::const_iterator iter = host.begin(); iter != host.end(); ++iter)
283 unsigned char chr = static_cast<unsigned char>(*iter);
285 // If the current character is a label separator.
290 // Consecutive separators are not allowed and dashes can not exist at the start or end
291 // of labels and separators must only exist between labels.
292 if (seendot || numdashes || iter == host.begin() || iter == hostend)
299 // If this point is reached then the character is not a dot.
302 // If the current character is a dash.
305 // Consecutive separators are not allowed and dashes can not exist at the start or end
306 // of labels and separators must only exist between labels.
307 if (seendot || numdashes >= 2 || iter == host.begin() || iter == hostend)
314 // If this point is reached then the character is not a dash.
317 // Alphanumeric characters are allowed at any position.
318 if ((chr >= '0' && chr <= '9') || (chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z'))
324 // Whilst simple hostnames (e.g. localhost) are valid we do not allow the server to use
325 // them to prevent issues with clients that differentiate between short client and server
326 // prefixes by checking whether the nickname contains a dot.
330 bool InspIRCd::IsSID(const std::string &str)
332 /* Returns true if the string given is exactly 3 characters long,
333 * starts with a digit, and the other two characters are A-Z or digits
335 return ((str.length() == 3) && isdigit(str[0]) &&
336 ((str[1] >= 'A' && str[1] <= 'Z') || isdigit(str[1])) &&
337 ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2])));
340 void InspIRCd::CheckRoot()
345 std::cout << "ERROR: You are running an irc server as root! DO NOT DO THIS!" << std::endl << std::endl;
346 this->Logs->Log("STARTUP", LOG_DEFAULT, "Can't start as root");
347 Exit(EXIT_STATUS_ROOT);
352 /** A lookup table of values for multiplier characters used by
353 * InspIRCd::Duration(). In this lookup table, the indexes for
354 * the ascii values 'm' and 'M' have the value '60', the indexes
355 * for the ascii values 'D' and 'd' have a value of '86400', etc.
357 static const unsigned int duration_multi[] =
359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
363 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0,
364 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 0, 0, 0, 0, 0, 0,
365 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0,
366 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 0, 0, 0, 0, 0, 0,
367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
377 bool InspIRCd::Duration(const std::string& str, unsigned long& duration)
379 unsigned long total = 0;
380 unsigned long subtotal = 0;
382 /* Iterate each item in the string, looking for number or multiplier */
383 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
385 /* Found a number, queue it onto the current number */
386 if ((*i >= '0') && (*i <= '9'))
388 subtotal = (subtotal * 10) + (*i - '0');
392 /* Found something thats not a number, find out how much
393 * it multiplies the built up number by, multiply the total
394 * and reset the built up number.
396 unsigned int multiplier = duration_multi[static_cast<unsigned char>(*i)];
400 total += subtotal * multiplier;
402 /* Next subtotal please */
406 /* Any trailing values built up are treated as raw seconds */
407 duration = total + subtotal;
411 unsigned long InspIRCd::Duration(const std::string& str)
413 unsigned long out = 0;
414 InspIRCd::Duration(str, out);
418 bool InspIRCd::IsValidDuration(const std::string& duration)
420 for (std::string::const_iterator i = duration.begin(); i != duration.end(); ++i)
422 unsigned char c = *i;
423 if (((c >= '0') && (c <= '9')))
426 if (!duration_multi[c])
432 std::string InspIRCd::Format(va_list& vaList, const char* formatString)
434 static std::vector<char> formatBuffer(1024);
439 va_copy(dst, vaList);
441 int vsnret = vsnprintf(&formatBuffer[0], formatBuffer.size(), formatString, dst);
444 if (vsnret > 0 && static_cast<unsigned>(vsnret) < formatBuffer.size())
449 formatBuffer.resize(formatBuffer.size() * 2);
452 return std::string(&formatBuffer[0]);
455 std::string InspIRCd::Format(const char* formatString, ...)
458 VAFORMAT(ret, formatString, formatString);
462 std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc)
469 struct tm* timeinfo = utc ? gmtime(&curtime) : localtime(&curtime);
473 timeinfo = localtime(&curtime);
476 // If the calculated year exceeds four digits or is less than the year 1000,
477 // the behavior of asctime() is undefined
478 if (timeinfo->tm_year + 1900 > 9999)
479 timeinfo->tm_year = 9999 - 1900;
480 else if (timeinfo->tm_year + 1900 < 1000)
481 timeinfo->tm_year = 0;
483 // This is the default format used by asctime without the terminating new line.
485 format = "%a %b %d %Y %H:%M:%S";
488 if (!strftime(buffer, sizeof(buffer), format, timeinfo))
494 std::string InspIRCd::GenRandomStr(unsigned int length, bool printable)
496 char* buf = new char[length];
497 GenRandom(buf, length);
500 for(size_t i = 0; i < length; i++)
501 rv[i] = printable ? 0x3F + (buf[i] & 0x3F) : buf[i];
506 // NOTE: this has a slight bias for lower values if max is not a power of 2.
507 // Don't use it if that matters.
508 unsigned long InspIRCd::GenRandomInt(unsigned long max)
511 GenRandom((char*)&rv, sizeof(rv));
515 // This is overridden by a higher-quality algorithm when SSL support is loaded
516 void InspIRCd::DefaultGenRandom(char* output, size_t max)
518 #if defined HAS_ARC4RANDOM_BUF
519 arc4random_buf(output, max);
521 for (unsigned int i = 0; i < max; ++i)
525 if(rand_s(&uTemp) != 0)
531 output[i] = random();