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>
10 * Copyright (C) 2003-2019 Anope Team <team@anope.org>
12 * This file is part of InspIRCd. InspIRCd is free software: you can
13 * redistribute it and/or modify it under the terms of the GNU General Public
14 * License as published by the Free Software Foundation, version 2.
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33 #include "exitcodes.h"
36 /* Find a user record by nickname and return a pointer to it */
37 User* InspIRCd::FindNick(const std::string &nick)
39 if (!nick.empty() && isdigit(*nick.begin()))
40 return FindUUID(nick);
41 return FindNickOnly(nick);
44 User* InspIRCd::FindNickOnly(const std::string &nick)
46 user_hash::iterator iter = this->Users->clientlist.find(nick);
48 if (iter == this->Users->clientlist.end())
54 User *InspIRCd::FindUUID(const std::string &uid)
56 user_hash::iterator finduuid = this->Users->uuidlist.find(uid);
58 if (finduuid == this->Users->uuidlist.end())
61 return finduuid->second;
63 /* find a channel record by channel name and return a pointer to it */
65 Channel* InspIRCd::FindChan(const std::string &chan)
67 chan_hash::iterator iter = chanlist.find(chan);
69 if (iter == chanlist.end())
70 /* Couldn't find it */
76 bool InspIRCd::IsValidMask(const std::string &mask)
78 const char* dest = mask.c_str();
82 for (const char* i = dest; *i; i++)
84 /* out of range character, bad mask */
85 if (*i < 32 || *i > 126)
101 /* valid masks only have 1 ! and @ */
102 if (exclamation != 1 || atsign != 1)
105 if (mask.length() > ServerInstance->Config->Limits.GetMaxMask())
111 void InspIRCd::StripColor(std::string &sentence)
113 /* refactor this completely due to SQUIT bug since the old code would strip last char and replace with \0 --peavey */
116 for (std::string::iterator i = sentence.begin(); i != sentence.end();)
120 else if (seq && (( ((*i >= '0') && (*i <= '9')) || (*i == ',') ) ))
123 if ( (seq <= 4) && (*i == ',') )
131 // Strip all control codes too except \001 for CTCP
132 if (seq || ((*i >= 0) && (*i < 32) && (*i != 1)))
133 i = sentence.erase(i);
139 void InspIRCd::ProcessColors(file_cache& input)
142 * Replace all color codes from the special[] array to actual
143 * color code chars using C++ style escape sequences. You
144 * can append other chars to replace if you like -- Justasic
146 static struct special_chars
148 std::string character;
150 special_chars(const std::string& c, const std::string& r)
156 special_chars("\\b", "\x02"), // Bold
157 special_chars("\\c", "\x03"), // Color
158 special_chars("\\i", "\x1D"), // Italic
159 special_chars("\\m", "\x11"), // Monospace
160 special_chars("\\r", "\x16"), // Reverse
161 special_chars("\\s", "\x1E"), // Strikethrough
162 special_chars("\\u", "\x1F"), // Underline
163 special_chars("\\x", "\x0F"), // Reset
164 special_chars("", "")
167 for(file_cache::iterator it = input.begin(), it_end = input.end(); it != it_end; it++)
169 std::string ret = *it;
170 for(int i = 0; special[i].character.empty() == false; ++i)
172 std::string::size_type pos = ret.find(special[i].character);
173 if(pos == std::string::npos) // Couldn't find the character, skip this line
176 if((pos > 0) && (ret[pos-1] == '\\') && (ret[pos] == '\\'))
177 continue; // Skip double slashes.
179 // Replace all our characters in the array
180 while(pos != std::string::npos)
182 ret = ret.substr(0, pos) + special[i].replace + ret.substr(pos + special[i].character.size());
183 pos = ret.find(special[i].character, pos + special[i].replace.size());
187 // Replace double slashes with a single slash before we return
188 std::string::size_type pos = ret.find("\\\\");
189 while(pos != std::string::npos)
191 ret = ret.substr(0, pos) + "\\" + ret.substr(pos + 2);
192 pos = ret.find("\\\\", pos + 1);
198 /* true for valid channel name, false else */
199 bool InspIRCd::DefaultIsChannel(const std::string& chname)
201 if (chname.empty() || chname.length() > ServerInstance->Config->Limits.ChanMax)
204 if (chname[0] != '#')
207 for (std::string::const_iterator i = chname.begin()+1; i != chname.end(); ++i)
221 /* true for valid nickname, false else */
222 bool InspIRCd::DefaultIsNick(const std::string& n)
224 if (n.empty() || n.length() > ServerInstance->Config->Limits.NickMax)
227 for (std::string::const_iterator i = n.begin(); i != n.end(); ++i)
229 if ((*i >= 'A') && (*i <= '}'))
231 /* "A"-"}" can occur anywhere in a nickname */
235 if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i != n.begin()))
237 /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */
241 /* invalid character! abort */
248 /* return true for good ident, false else */
249 bool InspIRCd::DefaultIsIdent(const std::string& n)
254 for (std::string::const_iterator i = n.begin(); i != n.end(); ++i)
256 if ((*i >= 'A') && (*i <= '}'))
261 if (((*i >= '0') && (*i <= '9')) || (*i == '-') || (*i == '.'))
272 bool InspIRCd::IsHost(const std::string& host)
274 // Hostnames must be non-empty and shorter than the maximum hostname length.
275 if (host.empty() || host.length() > ServerInstance->Config->Limits.MaxHost)
278 unsigned int numdashes = 0;
279 unsigned int numdots = 0;
280 bool seendot = false;
281 const std::string::const_iterator hostend = host.end() - 1;
282 for (std::string::const_iterator iter = host.begin(); iter != host.end(); ++iter)
284 unsigned char chr = static_cast<unsigned char>(*iter);
286 // If the current character is a label separator.
291 // Consecutive separators are not allowed and dashes can not exist at the start or end
292 // of labels and separators must only exist between labels.
293 if (seendot || numdashes || iter == host.begin() || iter == hostend)
300 // If this point is reached then the character is not a dot.
303 // If the current character is a dash.
306 // Consecutive separators are not allowed and dashes can not exist at the start or end
307 // of labels and separators must only exist between labels.
308 if (seendot || numdashes >= 2 || iter == host.begin() || iter == hostend)
315 // If this point is reached then the character is not a dash.
318 // Alphanumeric characters are allowed at any position.
319 if ((chr >= '0' && chr <= '9') || (chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z'))
325 // Whilst simple hostnames (e.g. localhost) are valid we do not allow the server to use
326 // them to prevent issues with clients that differentiate between short client and server
327 // prefixes by checking whether the nickname contains a dot.
331 bool InspIRCd::IsSID(const std::string &str)
333 /* Returns true if the string given is exactly 3 characters long,
334 * starts with a digit, and the other two characters are A-Z or digits
336 return ((str.length() == 3) && isdigit(str[0]) &&
337 ((str[1] >= 'A' && str[1] <= 'Z') || isdigit(str[1])) &&
338 ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2])));
341 void InspIRCd::CheckRoot()
346 std::cout << "ERROR: You are running an irc server as root! DO NOT DO THIS!" << std::endl << std::endl;
347 this->Logs->Log("STARTUP", LOG_DEFAULT, "Can't start as root");
348 Exit(EXIT_STATUS_ROOT);
353 /** A lookup table of values for multiplier characters used by
354 * InspIRCd::Duration(). In this lookup table, the indexes for
355 * the ascii values 'm' and 'M' have the value '60', the indexes
356 * for the ascii values 'D' and 'd' have a value of '86400', etc.
358 static const unsigned int duration_multi[] =
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
364 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0,
365 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 0, 0, 0, 0, 0, 0,
366 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0,
367 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 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,
375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
378 bool InspIRCd::Duration(const std::string& str, unsigned long& duration)
380 unsigned long total = 0;
381 unsigned long subtotal = 0;
383 /* Iterate each item in the string, looking for number or multiplier */
384 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
386 /* Found a number, queue it onto the current number */
387 if ((*i >= '0') && (*i <= '9'))
389 subtotal = (subtotal * 10) + (*i - '0');
393 /* Found something thats not a number, find out how much
394 * it multiplies the built up number by, multiply the total
395 * and reset the built up number.
397 unsigned int multiplier = duration_multi[static_cast<unsigned char>(*i)];
401 total += subtotal * multiplier;
403 /* Next subtotal please */
407 /* Any trailing values built up are treated as raw seconds */
408 duration = total + subtotal;
412 unsigned long InspIRCd::Duration(const std::string& str)
414 unsigned long out = 0;
415 InspIRCd::Duration(str, out);
419 bool InspIRCd::IsValidDuration(const std::string& duration)
421 for (std::string::const_iterator i = duration.begin(); i != duration.end(); ++i)
423 unsigned char c = *i;
424 if (((c >= '0') && (c <= '9')))
427 if (!duration_multi[c])
433 std::string InspIRCd::DurationString(time_t duration)
435 time_t years = duration / 31536000;
436 time_t weeks = (duration / 604800) % 52;
437 time_t days = (duration / 86400) % 7;
438 time_t hours = (duration / 3600) % 24;
439 time_t minutes = (duration / 60) % 60;
440 time_t seconds = duration % 60;
445 ret = ConvToStr(years) + "y";
447 ret += ConvToStr(weeks) + "w";
449 ret += ConvToStr(days) + "d";
451 ret += ConvToStr(hours) + "h";
453 ret += ConvToStr(minutes) + "m";
455 ret += ConvToStr(seconds) + "s";
460 std::string InspIRCd::Format(va_list& vaList, const char* formatString)
462 static std::vector<char> formatBuffer(1024);
467 va_copy(dst, vaList);
469 int vsnret = vsnprintf(&formatBuffer[0], formatBuffer.size(), formatString, dst);
472 if (vsnret > 0 && static_cast<unsigned>(vsnret) < formatBuffer.size())
477 formatBuffer.resize(formatBuffer.size() * 2);
480 return std::string(&formatBuffer[0]);
483 std::string InspIRCd::Format(const char* formatString, ...)
486 VAFORMAT(ret, formatString, formatString);
490 std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc)
497 struct tm* timeinfo = utc ? gmtime(&curtime) : localtime(&curtime);
501 timeinfo = localtime(&curtime);
504 // If the calculated year exceeds four digits or is less than the year 1000,
505 // the behavior of asctime() is undefined
506 if (timeinfo->tm_year + 1900 > 9999)
507 timeinfo->tm_year = 9999 - 1900;
508 else if (timeinfo->tm_year + 1900 < 1000)
509 timeinfo->tm_year = 0;
511 // This is the default format used by asctime without the terminating new line.
513 format = "%a %b %d %Y %H:%M:%S";
516 if (!strftime(buffer, sizeof(buffer), format, timeinfo))
522 std::string InspIRCd::GenRandomStr(unsigned int length, bool printable)
524 char* buf = new char[length];
525 GenRandom(buf, length);
528 for(size_t i = 0; i < length; i++)
529 rv[i] = printable ? 0x3F + (buf[i] & 0x3F) : buf[i];
534 // NOTE: this has a slight bias for lower values if max is not a power of 2.
535 // Don't use it if that matters.
536 unsigned long InspIRCd::GenRandomInt(unsigned long max)
539 GenRandom((char*)&rv, sizeof(rv));
543 // This is overridden by a higher-quality algorithm when SSL support is loaded
544 void InspIRCd::DefaultGenRandom(char* output, size_t max)
546 #if defined HAS_ARC4RANDOM_BUF
547 arc4random_buf(output, max);
549 for (unsigned int i = 0; i < max; ++i)
553 if(rand_s(&uTemp) != 0)
559 output[i] = random();