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 /** A lookup table of values for multiplier characters used by
342 * InspIRCd::Duration(). In this lookup table, the indexes for
343 * the ascii values 'm' and 'M' have the value '60', the indexes
344 * for the ascii values 'D' and 'd' have a value of '86400', etc.
346 static const unsigned int duration_multi[] =
348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
352 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0,
353 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 0, 0, 0, 0, 0, 0,
354 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0,
355 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 0, 0, 0, 0, 0, 0,
356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
366 bool InspIRCd::Duration(const std::string& str, unsigned long& duration)
368 unsigned long total = 0;
369 unsigned long subtotal = 0;
371 /* Iterate each item in the string, looking for number or multiplier */
372 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
374 /* Found a number, queue it onto the current number */
375 if ((*i >= '0') && (*i <= '9'))
377 subtotal = (subtotal * 10) + (*i - '0');
381 /* Found something thats not a number, find out how much
382 * it multiplies the built up number by, multiply the total
383 * and reset the built up number.
385 unsigned int multiplier = duration_multi[static_cast<unsigned char>(*i)];
389 total += subtotal * multiplier;
391 /* Next subtotal please */
395 /* Any trailing values built up are treated as raw seconds */
396 duration = total + subtotal;
400 unsigned long InspIRCd::Duration(const std::string& str)
402 unsigned long out = 0;
403 InspIRCd::Duration(str, out);
407 bool InspIRCd::IsValidDuration(const std::string& duration)
409 for (std::string::const_iterator i = duration.begin(); i != duration.end(); ++i)
411 unsigned char c = *i;
412 if (((c >= '0') && (c <= '9')))
415 if (!duration_multi[c])
421 std::string InspIRCd::DurationString(time_t duration)
426 time_t years = duration / 31449600;
427 time_t weeks = (duration / 604800) % 52;
428 time_t days = (duration / 86400) % 7;
429 time_t hours = (duration / 3600) % 24;
430 time_t minutes = (duration / 60) % 60;
431 time_t seconds = duration % 60;
436 ret = ConvToStr(years) + "y";
438 ret += ConvToStr(weeks) + "w";
440 ret += ConvToStr(days) + "d";
442 ret += ConvToStr(hours) + "h";
444 ret += ConvToStr(minutes) + "m";
446 ret += ConvToStr(seconds) + "s";
451 std::string InspIRCd::Format(va_list& vaList, const char* formatString)
453 static std::vector<char> formatBuffer(1024);
458 va_copy(dst, vaList);
460 int vsnret = vsnprintf(&formatBuffer[0], formatBuffer.size(), formatString, dst);
463 if (vsnret > 0 && static_cast<unsigned>(vsnret) < formatBuffer.size())
468 formatBuffer.resize(formatBuffer.size() * 2);
471 return std::string(&formatBuffer[0]);
474 std::string InspIRCd::Format(const char* formatString, ...)
477 VAFORMAT(ret, formatString, formatString);
481 std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc)
488 struct tm* timeinfo = utc ? gmtime(&curtime) : localtime(&curtime);
492 timeinfo = localtime(&curtime);
495 // If the calculated year exceeds four digits or is less than the year 1000,
496 // the behavior of asctime() is undefined
497 if (timeinfo->tm_year + 1900 > 9999)
498 timeinfo->tm_year = 9999 - 1900;
499 else if (timeinfo->tm_year + 1900 < 1000)
500 timeinfo->tm_year = 0;
502 // This is the default format used by asctime without the terminating new line.
504 format = "%a %b %d %Y %H:%M:%S";
507 if (!strftime(buffer, sizeof(buffer), format, timeinfo))
513 std::string InspIRCd::GenRandomStr(unsigned int length, bool printable)
515 char* buf = new char[length];
516 GenRandom(buf, length);
519 for(size_t i = 0; i < length; i++)
520 rv[i] = printable ? 0x3F + (buf[i] & 0x3F) : buf[i];
525 // NOTE: this has a slight bias for lower values if max is not a power of 2.
526 // Don't use it if that matters.
527 unsigned long InspIRCd::GenRandomInt(unsigned long max)
530 GenRandom((char*)&rv, sizeof(rv));
534 // This is overridden by a higher-quality algorithm when SSL support is loaded
535 void InspIRCd::DefaultGenRandom(char* output, size_t max)
537 #if defined HAS_ARC4RANDOM_BUF
538 arc4random_buf(output, max);
540 for (unsigned int i = 0; i < max; ++i)
544 if(rand_s(&uTemp) != 0)
550 output[i] = random();