summaryrefslogtreecommitdiff
path: root/src/helperfuncs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/helperfuncs.cpp')
-rw-r--r--src/helperfuncs.cpp387
1 files changed, 141 insertions, 246 deletions
diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp
index 439320c1e..6830612c7 100644
--- a/src/helperfuncs.cpp
+++ b/src/helperfuncs.cpp
@@ -22,8 +22,6 @@
*/
-/* $Core */
-
#ifdef _WIN32
#define _CRT_RAND_S
#include <stdlib.h>
@@ -34,66 +32,19 @@
#include "exitcodes.h"
#include <iostream>
-std::string InspIRCd::GetServerDescription(const std::string& servername)
-{
- std::string description;
-
- FOREACH_MOD(I_OnGetServerDescription,OnGetServerDescription(servername,description));
-
- if (!description.empty())
- {
- return description;
- }
- else
- {
- // not a remote server that can be found, it must be me.
- return Config->ServerDesc;
- }
-}
-
/* Find a user record by nickname and return a pointer to it */
User* InspIRCd::FindNick(const std::string &nick)
{
if (!nick.empty() && isdigit(*nick.begin()))
return FindUUID(nick);
-
- user_hash::iterator iter = this->Users->clientlist->find(nick);
-
- if (iter == this->Users->clientlist->end())
- /* Couldn't find it */
- return NULL;
-
- return iter->second;
-}
-
-User* InspIRCd::FindNick(const char* nick)
-{
- if (isdigit(*nick))
- return FindUUID(nick);
-
- user_hash::iterator iter = this->Users->clientlist->find(nick);
-
- if (iter == this->Users->clientlist->end())
- return NULL;
-
- return iter->second;
+ return FindNickOnly(nick);
}
User* InspIRCd::FindNickOnly(const std::string &nick)
{
- user_hash::iterator iter = this->Users->clientlist->find(nick);
-
- if (iter == this->Users->clientlist->end())
- return NULL;
-
- return iter->second;
-}
-
-User* InspIRCd::FindNickOnly(const char* nick)
-{
- user_hash::iterator iter = this->Users->clientlist->find(nick);
+ user_hash::iterator iter = this->Users->clientlist.find(nick);
- if (iter == this->Users->clientlist->end())
+ if (iter == this->Users->clientlist.end())
return NULL;
return iter->second;
@@ -101,66 +52,26 @@ User* InspIRCd::FindNickOnly(const char* nick)
User *InspIRCd::FindUUID(const std::string &uid)
{
- user_hash::iterator finduuid = this->Users->uuidlist->find(uid);
+ user_hash::iterator finduuid = this->Users->uuidlist.find(uid);
- if (finduuid == this->Users->uuidlist->end())
+ if (finduuid == this->Users->uuidlist.end())
return NULL;
return finduuid->second;
}
-
-User *InspIRCd::FindUUID(const char *uid)
-{
- return FindUUID(std::string(uid));
-}
-
/* find a channel record by channel name and return a pointer to it */
-Channel* InspIRCd::FindChan(const char* chan)
-{
- chan_hash::iterator iter = chanlist->find(chan);
-
- if (iter == chanlist->end())
- /* Couldn't find it */
- return NULL;
-
- return iter->second;
-}
Channel* InspIRCd::FindChan(const std::string &chan)
{
- chan_hash::iterator iter = chanlist->find(chan);
+ chan_hash::iterator iter = chanlist.find(chan);
- if (iter == chanlist->end())
+ if (iter == chanlist.end())
/* Couldn't find it */
return NULL;
return iter->second;
}
-/* Send an error notice to all users, registered or not */
-void InspIRCd::SendError(const std::string &s)
-{
- for (LocalUserList::const_iterator i = this->Users->local_users.begin(); i != this->Users->local_users.end(); i++)
- {
- User* u = *i;
- if (u->registered == REG_ALL)
- {
- u->WriteServ("NOTICE %s :%s",u->nick.c_str(),s.c_str());
- }
- else
- {
- /* Unregistered connections receive ERROR, not a NOTICE */
- u->Write("ERROR :" + s);
- }
- }
-}
-
-/* return channel count */
-long InspIRCd::ChannelCount()
-{
- return chanlist->size();
-}
-
bool InspIRCd::IsValidMask(const std::string &mask)
{
const char* dest = mask.c_str();
@@ -190,7 +101,7 @@ bool InspIRCd::IsValidMask(const std::string &mask)
if (exclamation != 1 || atsign != 1)
return false;
- if (mask.length() > 250)
+ if (mask.length() > ServerInstance->Config->Limits.GetMaxMask())
return false;
return true;
@@ -216,7 +127,8 @@ void InspIRCd::StripColor(std::string &sentence)
else
seq = 0;
- if (seq || ((*i == 2) || (*i == 15) || (*i == 22) || (*i == 21) || (*i == 31)))
+ // Strip all control codes too except \001 for CTCP
+ if (seq || ((*i >= 0) && (*i < 32) && (*i != 1)))
i = sentence.erase(i);
else
++i;
@@ -234,19 +146,20 @@ void InspIRCd::ProcessColors(file_cache& input)
{
std::string character;
std::string replace;
- special_chars(const std::string &c, const std::string &r) : character(c), replace(r) { }
- }
-
- special[] = {
- special_chars("\\002", "\002"), // Bold
- special_chars("\\037", "\037"), // underline
- special_chars("\\003", "\003"), // Color
- special_chars("\\017", "\017"), // Stop colors
- special_chars("\\u", "\037"), // Alias for underline
- special_chars("\\b", "\002"), // Alias for Bold
- special_chars("\\x", "\017"), // Alias for stop
- special_chars("\\c", "\003"), // Alias for color
- special_chars("", "")
+ special_chars(const std::string& c, const std::string& r)
+ : character(c)
+ , replace(r)
+ {
+ }
+ } special[] = {
+ special_chars("\\b", "\x02"), // Bold
+ special_chars("\\c", "\x03"), // Color
+ special_chars("\\i", "\x1D"), // Italic
+ special_chars("\\m", "\x11"), // Monospace
+ special_chars("\\s", "\x1E"), // Strikethrough
+ special_chars("\\u", "\x1F"), // Underline
+ special_chars("\\x", "\x0F"), // Reset
+ special_chars("\\", "")
};
for(file_cache::iterator it = input.begin(), it_end = input.end(); it != it_end; it++)
@@ -281,47 +194,35 @@ void InspIRCd::ProcessColors(file_cache& input)
}
/* true for valid channel name, false else */
-bool IsChannelHandler::Call(const char *chname, size_t max)
+bool InspIRCd::DefaultIsChannel(const std::string& chname)
{
- const char *c = chname + 1;
+ if (chname.empty() || chname.length() > ServerInstance->Config->Limits.ChanMax)
+ return false;
- /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
- if (!chname || *chname != '#')
- {
+ if (chname[0] != '#')
return false;
- }
- while (*c)
+ for (std::string::const_iterator i = chname.begin()+1; i != chname.end(); ++i)
{
- switch (*c)
+ switch (*i)
{
case ' ':
case ',':
case 7:
return false;
}
-
- c++;
- }
-
- size_t len = c - chname;
- /* too long a name - note funky pointer arithmetic here. */
- if (len > max)
- {
- return false;
}
return true;
}
/* true for valid nickname, false else */
-bool IsNickHandler::Call(const char* n, size_t max)
+bool InspIRCd::DefaultIsNick(const std::string& n)
{
- if (!n || !*n)
+ if (n.empty() || n.length() > ServerInstance->Config->Limits.NickMax)
return false;
- unsigned int p = 0;
- for (const char* i = n; *i; i++, p++)
+ for (std::string::const_iterator i = n.begin(); i != n.end(); ++i)
{
if ((*i >= 'A') && (*i <= '}'))
{
@@ -329,7 +230,7 @@ bool IsNickHandler::Call(const char* n, size_t max)
continue;
}
- if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n))
+ if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i != n.begin()))
{
/* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */
continue;
@@ -339,17 +240,16 @@ bool IsNickHandler::Call(const char* n, size_t max)
return false;
}
- /* too long? or not */
- return (p <= max);
+ return true;
}
/* return true for good ident, false else */
-bool IsIdentHandler::Call(const char* n)
+bool InspIRCd::DefaultIsIdent(const std::string& n)
{
- if (!n || !*n)
+ if (n.empty())
return false;
- for (const char* i = n; *i; i++)
+ for (std::string::const_iterator i = n.begin(); i != n.end(); ++i)
{
if ((*i >= 'A') && (*i <= '}'))
{
@@ -367,36 +267,73 @@ bool IsIdentHandler::Call(const char* n)
return true;
}
-bool IsSIDHandler::Call(const std::string &str)
+bool InspIRCd::IsHost(const std::string& host)
{
- /* Returns true if the string given is exactly 3 characters long,
- * starts with a digit, and the other two characters are A-Z or digits
- */
- return ((str.length() == 3) && isdigit(str[0]) &&
- ((str[1] >= 'A' && str[1] <= 'Z') || isdigit(str[1])) &&
- ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2])));
-}
+ // Hostnames must be non-empty and shorter than the maximum hostname length.
+ if (host.empty() || host.length() > ServerInstance->Config->Limits.MaxHost)
+ return false;
-/* open the proper logfile */
-bool InspIRCd::OpenLog(char**, int)
-{
- if (!Config->cmdline.writelog) return true; // Skip opening default log if -nolog
+ unsigned int numdashes = 0;
+ unsigned int numdots = 0;
+ bool seendot = false;
+ const std::string::const_iterator hostend = host.end() - 1;
+ for (std::string::const_iterator iter = host.begin(); iter != host.end(); ++iter)
+ {
+ unsigned char chr = static_cast<unsigned char>(*iter);
+
+ // If the current character is a label separator.
+ if (chr == '.')
+ {
+ numdots++;
- if (Config->cmdline.startup_log.empty())
- Config->cmdline.startup_log = LOG_PATH "/startup.log";
- FILE* startup = fopen(Config->cmdline.startup_log.c_str(), "a+");
+ // Consecutive separators are not allowed and dashes can not exist at the start or end
+ // of labels and separators must only exist between labels.
+ if (seendot || numdashes || iter == host.begin() || iter == hostend)
+ return false;
+
+ seendot = true;
+ continue;
+ }
+
+ // If this point is reached then the character is not a dot.
+ seendot = false;
+
+ // If the current character is a dash.
+ if (chr == '-')
+ {
+ // Consecutive separators are not allowed and dashes can not exist at the start or end
+ // of labels and separators must only exist between labels.
+ if (seendot || numdashes >= 2 || iter == host.begin() || iter == hostend)
+ return false;
+
+ numdashes += 1;
+ continue;
+ }
+
+ // If this point is reached then the character is not a dash.
+ numdashes = 0;
+
+ // Alphanumeric characters are allowed at any position.
+ if ((chr >= '0' && chr <= '9') || (chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z'))
+ continue;
- if (!startup)
- {
return false;
}
- FileWriter* fw = new FileWriter(startup);
- FileLogStream *f = new FileLogStream((Config->cmdline.forcedebug ? DEBUG : DEFAULT), fw);
-
- this->Logs->AddLogType("*", f, true);
+ // Whilst simple hostnames (e.g. localhost) are valid we do not allow the server to use
+ // them to prevent issues with clients that differentiate between short client and server
+ // prefixes by checking whether the nickname contains a dot.
+ return numdots;
+}
- return true;
+bool InspIRCd::IsSID(const std::string &str)
+{
+ /* Returns true if the string given is exactly 3 characters long,
+ * starts with a digit, and the other two characters are A-Z or digits
+ */
+ return ((str.length() == 3) && isdigit(str[0]) &&
+ ((str[1] >= 'A' && str[1] <= 'Z') || isdigit(str[1])) &&
+ ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2])));
}
void InspIRCd::CheckRoot()
@@ -405,38 +342,16 @@ void InspIRCd::CheckRoot()
if (geteuid() == 0)
{
std::cout << "ERROR: You are running an irc server as root! DO NOT DO THIS!" << std::endl << std::endl;
- this->Logs->Log("STARTUP",DEFAULT,"Can't start as root");
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "Can't start as root");
Exit(EXIT_STATUS_ROOT);
}
#endif
}
-void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const std::string &text)
-{
- std::string copy_text = text;
-
- ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnWhoisLine, MOD_RESULT, (user, dest, numeric, copy_text));
-
- if (MOD_RESULT != MOD_RES_DENY)
- user->WriteServ("%d %s", numeric, copy_text.c_str());
-}
-
-void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const char* format, ...)
-{
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, format);
- vsnprintf(textbuffer, MAXBUF, format, argsPtr);
- va_end(argsPtr);
-
- this->SendWhoisLine(user, dest, numeric, std::string(textbuffer));
-}
-
/** Refactored by Brain, Jun 2009. Much faster with some clever O(1) array
* lookups and pointer maths.
*/
-long InspIRCd::Duration(const std::string &str)
+unsigned long InspIRCd::Duration(const std::string &str)
{
unsigned char multiplier = 0;
long total = 0;
@@ -476,31 +391,44 @@ long InspIRCd::Duration(const std::string &str)
return total + subtotal;
}
-bool InspIRCd::ULine(const std::string& sserver)
+std::string InspIRCd::Format(va_list& vaList, const char* formatString)
{
- if (sserver.empty())
- return true;
+ static std::vector<char> formatBuffer(1024);
+
+ while (true)
+ {
+ va_list dst;
+ va_copy(dst, vaList);
+
+ int vsnret = vsnprintf(&formatBuffer[0], formatBuffer.size(), formatString, dst);
+ va_end(dst);
+
+ if (vsnret > 0 && static_cast<unsigned>(vsnret) < formatBuffer.size())
+ {
+ break;
+ }
- return (Config->ulines.find(sserver.c_str()) != Config->ulines.end());
+ formatBuffer.resize(formatBuffer.size() * 2);
+ }
+
+ return std::string(&formatBuffer[0]);
}
-bool InspIRCd::SilentULine(const std::string& sserver)
+std::string InspIRCd::Format(const char* formatString, ...)
{
- std::map<irc::string,bool>::iterator n = Config->ulines.find(sserver.c_str());
- if (n != Config->ulines.end())
- return n->second;
- else
- return false;
+ std::string ret;
+ VAFORMAT(ret, formatString, formatString);
+ return ret;
}
-std::string InspIRCd::TimeString(time_t curtime)
+std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc)
{
#ifdef _WIN32
if (curtime < 0)
curtime = 0;
#endif
- struct tm* timeinfo = localtime(&curtime);
+ struct tm* timeinfo = utc ? gmtime(&curtime) : localtime(&curtime);
if (!timeinfo)
{
curtime = 0;
@@ -514,36 +442,24 @@ std::string InspIRCd::TimeString(time_t curtime)
else if (timeinfo->tm_year + 1900 < 1000)
timeinfo->tm_year = 0;
- return std::string(asctime(timeinfo),24);
-}
+ // This is the default format used by asctime without the terminating new line.
+ if (!format)
+ format = "%a %b %d %Y %H:%M:%S";
-// You should only pass a single character to this.
-void InspIRCd::AddExtBanChar(char c)
-{
- std::string &tok = Config->data005;
- std::string::size_type ebpos = tok.find(" EXTBAN=,");
+ char buffer[512];
+ if (!strftime(buffer, sizeof(buffer), format, timeinfo))
+ buffer[0] = '\0';
- if (ebpos == std::string::npos)
- {
- tok.append(" EXTBAN=,");
- tok.push_back(c);
- }
- else
- {
- ebpos += 9;
- while (isalpha(tok[ebpos]) && tok[ebpos] < c)
- ebpos++;
- tok.insert(ebpos, 1, c);
- }
+ return buffer;
}
-std::string InspIRCd::GenRandomStr(int length, bool printable)
+std::string InspIRCd::GenRandomStr(unsigned int length, bool printable)
{
char* buf = new char[length];
GenRandom(buf, length);
std::string rv;
rv.resize(length);
- for(int i=0; i < length; i++)
+ for(size_t i = 0; i < length; i++)
rv[i] = printable ? 0x3F + (buf[i] & 0x3F) : buf[i];
delete[] buf;
return rv;
@@ -559,10 +475,13 @@ unsigned long InspIRCd::GenRandomInt(unsigned long max)
}
// This is overridden by a higher-quality algorithm when SSL support is loaded
-void GenRandomHandler::Call(char *output, size_t max)
+void InspIRCd::DefaultGenRandom(char* output, size_t max)
{
- for(unsigned int i=0; i < max; i++)
-#ifdef _WIN32
+#if defined HAS_ARC4RANDOM_BUF
+ arc4random_buf(output, max);
+#else
+ for (unsigned int i = 0; i < max; ++i)
+# ifdef _WIN32
{
unsigned int uTemp;
if(rand_s(&uTemp) != 0)
@@ -570,32 +489,8 @@ void GenRandomHandler::Call(char *output, size_t max)
else
output[i] = uTemp;
}
-#else
+# else
output[i] = random();
+# endif
#endif
}
-
-ModResult OnCheckExemptionHandler::Call(User* user, Channel* chan, const std::string& restriction)
-{
- unsigned int mypfx = chan->GetPrefixValue(user);
- char minmode = 0;
- std::string current;
-
- irc::spacesepstream defaultstream(ServerInstance->Config->ConfValue("options")->getString("exemptchanops"));
-
- while (defaultstream.GetToken(current))
- {
- std::string::size_type pos = current.find(':');
- if (pos == std::string::npos)
- continue;
- if (current.substr(0,pos) == restriction)
- minmode = current[pos+1];
- }
-
- ModeHandler* mh = ServerInstance->Modes->FindMode(minmode, MODETYPE_CHANNEL);
- if (mh && mypfx >= mh->GetPrefixRank())
- return MOD_RES_ALLOW;
- if (mh || minmode == '*')
- return MOD_RES_DENY;
- return MOD_RES_PASSTHRU;
-}