summaryrefslogtreecommitdiff
path: root/src/misc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/misc.cpp')
-rw-r--r--src/misc.cpp1562
1 files changed, 1562 insertions, 0 deletions
diff --git a/src/misc.cpp b/src/misc.cpp
new file mode 100644
index 000000000..22ea81432
--- /dev/null
+++ b/src/misc.cpp
@@ -0,0 +1,1562 @@
+
+/* Miscellaneous routines.
+ *
+ * (C) 2003-2010 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#include "services.h"
+#include "language.h"
+#include "hashcomp.h" // If this gets added to services.h or someplace else later, remove it from here -- CyberBotX
+
+/* Cheaper than isspace() or isblank() */
+#define issp(c) ((c) == 32)
+
+struct arc4_stream {
+ uint8 i;
+ uint8 j;
+ uint8 s[256];
+} rs;
+
+/*************************************************************************/
+
+/** Check if a file exists
+ * @param filename The file
+ * @return true if the file exists, false if it doens't
+ */
+bool IsFile(const std::string &filename)
+{
+ struct stat fileinfo;
+ if (!stat(filename.c_str(), &fileinfo))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * toupper: Like the ANSI functions, but make sure we return an
+ * int instead of a (signed) char.
+ * @param c Char
+ * @return int
+ */
+int toupper(char c)
+{
+ if (islower(c)) {
+ return static_cast<int>(c) - ('a' - 'A');
+ } else {
+ return static_cast<int>(c);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * tolower: Like the ANSI functions, but make sure we return an
+ * int instead of a (signed) char.
+ * @param c Char
+ * @return int
+ */
+int tolower(char c)
+{
+ if (isupper(c)) {
+ return static_cast<int>(c) + ('a' - 'A');
+ } else {
+ return static_cast<int>(c);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Simple function to convert binary data to hex.
+ * Taken from hybrid-ircd ( http://ircd-hybrid.com/ )
+ */
+void binary_to_hex(unsigned char *bin, char *hex, int length)
+{
+ static const char trans[] = "0123456789ABCDEF";
+ int i;
+
+ for (i = 0; i < length; i++) {
+ hex[i << 1] = trans[bin[i] >> 4];
+ hex[(i << 1) + 1] = trans[bin[i] & 0xf];
+ }
+
+ hex[i << 1] = '\0';
+}
+
+
+/*************************************************************************/
+
+/**
+ * strscpy: Copy at most len-1 characters from a string to a buffer, and
+ * add a null terminator after the last character copied.
+ * @param d Buffer to copy into
+ * @param s Data to copy int
+ * @param len Length of data
+ * @return updated buffer
+ */
+char *strscpy(char *d, const char *s, size_t len)
+{
+ char *d_orig = d;
+
+ if (!len) {
+ return d;
+ }
+ while (--len && (*d++ = *s++));
+ *d = '\0';
+ return d_orig;
+}
+
+/*************************************************************************/
+
+/**
+ * stristr: Search case-insensitively for string s2 within string s1,
+ * returning the first occurrence of s2 or NULL if s2 was not
+ * found.
+ * @param s1 String 1
+ * @param s2 String 2
+ * @return first occurrence of s2
+ */
+const char *stristr(const char *s1, const char *s2)
+{
+ register const char *s = s1, *d = s2;
+
+ while (*s1) {
+ if (tolower(*s1) == tolower(*d)) {
+ s1++;
+ d++;
+ if (*d == 0)
+ return s;
+ } else {
+ s = ++s1;
+ d = s2;
+ }
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+
+/**
+ * strnrepl: Replace occurrences of `old' with `new' in string `s'. Stop
+ * replacing if a replacement would cause the string to exceed
+ * `size' bytes (including the null terminator). Return the
+ * string.
+ * @param s String
+ * @param size size of s
+ * @param old character to replace
+ * @param newstr character to replace with
+ * @return updated s
+ */
+char *strnrepl(char *s, int32 size, const char *old, const char *newstr)
+{
+ char *ptr = s;
+ int32 left = strlen(s);
+ int32 avail = size - (left + 1);
+ int32 oldlen = strlen(old);
+ int32 newlen = strlen(newstr);
+ int32 diff = newlen - oldlen;
+
+ while (left >= oldlen) {
+ if (strncmp(ptr, old, oldlen) != 0) {
+ left--;
+ ptr++;
+ continue;
+ }
+ if (diff > avail)
+ break;
+ if (diff != 0)
+ memmove(ptr + oldlen + diff, ptr + oldlen, left + 1 - oldlen);
+ strncpy(ptr, newstr, newlen);
+ ptr += newlen;
+ left -= oldlen;
+ }
+ return s;
+}
+
+/*************************************************************************/
+
+/**
+ * merge_args: Take an argument count and argument vector and merge them
+ * into a single string in which each argument is separated by
+ * a space.
+ * @param int Number of Args
+ * @param argv Array
+ * @return string of the merged array
+ */
+const char *merge_args(int argc, const char **argv)
+{
+ int i;
+ static char s[4096];
+ char *t;
+
+ t = s;
+ for (i = 0; i < argc; i++)
+ t += snprintf(t, sizeof(s) - (t - s), "%s%s", *argv++,
+ (i < argc - 1) ? " " : "");
+ return s;
+}
+
+/*
+ * XXX: temporary "safe" version to avoid casting, it's still ugly.
+ */
+const char *merge_args(int argc, char **argv)
+{
+ int i;
+ static char s[4096];
+ char *t;
+
+ t = s;
+ for (i = 0; i < argc; i++)
+ t += snprintf(t, sizeof(s) - (t - s), "%s%s", *argv++,
+ (i < argc - 1) ? " " : "");
+ return s;
+}
+
+/*************************************************************************/
+
+NumberList::NumberList(const std::string &list)
+{
+ char *error;
+ commasepstream sep(list);
+ std::string token;
+
+ sep.GetToken(token);
+ if (token.empty())
+ token = list;
+ do
+ {
+ char *h = strchr(token.c_str(), '-');
+
+ if (!h)
+ {
+ unsigned num = strtol(token.c_str(), &error, 10);
+ if (*error == '\0')
+ {
+ numbers.insert(num);
+ }
+ else
+ {
+ if (!this->InvalidRange(list))
+ {
+ delete this;
+ return;
+ }
+ }
+ }
+ else
+ {
+ char *error2;
+ *h++ = '\0';
+ unsigned num1 = strtol(token.c_str(), &error, 10);
+ unsigned num2 = strtol(h, &error2, 10);
+ if (*error == '\0' && *error2 == '\0')
+ {
+ for (unsigned i = num1; i <= num2; ++i)
+ {
+ numbers.insert(i);
+ }
+ }
+ else
+ {
+ if (!this->InvalidRange(list))
+ {
+ delete this;
+ return;
+ }
+ }
+ }
+ } while (sep.GetToken(token));
+}
+
+NumberList::~NumberList()
+{
+}
+
+void NumberList::Process()
+{
+ for (std::set<unsigned>::reverse_iterator it = numbers.rbegin(); it != numbers.rend(); ++it)
+ {
+ this->HandleNumber(*it);
+ }
+
+ delete this;
+}
+
+void NumberList::HandleNumber(unsigned)
+{
+}
+
+bool NumberList::InvalidRange(const std::string &)
+{
+ return true;
+}
+
+/**
+ * dotime: Return the number of seconds corresponding to the given time
+ * string. If the given string does not represent a valid time,
+ * return -1.
+ *
+ * A time string is either a plain integer (representing a number
+ * of seconds), or an integer followed by one of these characters:
+ * "s" (seconds), "m" (minutes), "h" (hours), or "d" (days).
+ * @param s String to convert
+ * @return time_t
+ */
+time_t dotime(const char *s)
+{
+ int amount;
+
+ if (!s || !*s) {
+ return -1;
+ }
+
+ amount = strtol(s, const_cast<char **>(&s), 10);
+ if (*s) {
+ switch (*s) {
+ case 's':
+ return amount;
+ case 'm':
+ return amount * 60;
+ case 'h':
+ return amount * 3600;
+ case 'd':
+ return amount * 86400;
+ case 'w':
+ return amount * 86400 * 7;
+ case 'y':
+ return amount * 86400 * 365;
+ default:
+ return -1;
+ }
+ } else {
+ return amount;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Expresses in a string the period of time represented by a given amount
+ * of seconds (with days/hours/minutes).
+ * @param na Nick Alias
+ * @param buf buffer to store result into
+ * @param bufsize Size of the buffer
+ * @param seconds time in seconds
+ * @return buffer
+ */
+const char *duration(NickCore *nc, char *buf, int bufsize, time_t seconds)
+{
+ int days = 0, hours = 0, minutes = 0;
+ int need_comma = 0;
+
+ char buf2[64], *end;
+ const char *comma = getstring(nc, COMMA_SPACE);
+
+ /* We first calculate everything */
+ days = seconds / 86400;
+ seconds -= (days * 86400);
+ hours = seconds / 3600;
+ seconds -= (hours * 3600);
+ minutes = seconds / 60;
+
+ if (!days && !hours && !minutes) {
+ snprintf(buf, bufsize,
+ getstring(nc,
+ (seconds <=
+ 1 ? DURATION_SECOND : DURATION_SECONDS)),
+ seconds);
+ } else {
+ end = buf;
+ if (days) {
+ snprintf(buf2, sizeof(buf2),
+ getstring(nc,
+ (days == 1 ? DURATION_DAY : DURATION_DAYS)),
+ days);
+ end += snprintf(end, bufsize - (end - buf), "%s", buf2);
+ need_comma = 1;
+ }
+ if (hours) {
+ snprintf(buf2, sizeof(buf2),
+ getstring(nc,
+ (hours ==
+ 1 ? DURATION_HOUR : DURATION_HOURS)),
+ hours);
+ end +=
+ snprintf(end, bufsize - (end - buf), "%s%s",
+ (need_comma ? comma : ""), buf2);
+ need_comma = 1;
+ }
+ if (minutes) {
+ snprintf(buf2, sizeof(buf2),
+ getstring(nc,
+ (minutes ==
+ 1 ? DURATION_MINUTE : DURATION_MINUTES)),
+ minutes);
+ end +=
+ snprintf(end, bufsize - (end - buf), "%s%s",
+ (need_comma ? comma : ""), buf2);
+ need_comma = 1;
+ }
+ }
+
+ return buf;
+}
+
+/*************************************************************************/
+
+/**
+ * Generates a human readable string of type "expires in ..."
+ * @param na Nick Alias
+ * @param buf buffer to store result into
+ * @param bufsize Size of the buffer
+ * @param seconds time in seconds
+ * @return buffer
+ */
+const char *expire_left(NickCore *nc, char *buf, int len, time_t expires)
+{
+ time_t now = time(NULL);
+
+ if (!expires) {
+ strlcpy(buf, getstring(nc, NO_EXPIRE), len);
+ } else if (expires <= now) {
+ strlcpy(buf, getstring(nc, EXPIRES_SOON), len);
+ } else {
+ time_t diff = expires - now + 59;
+
+ if (diff >= 86400) {
+ int days = diff / 86400;
+ snprintf(buf, len,
+ getstring(nc, (days == 1) ? EXPIRES_1D : EXPIRES_D),
+ days);
+ } else {
+ if (diff <= 3600) {
+ int minutes = diff / 60;
+ snprintf(buf, len,
+ getstring(nc,
+ (minutes ==
+ 1) ? EXPIRES_1M : EXPIRES_M), minutes);
+ } else {
+ int hours = diff / 3600, minutes;
+ diff -= (hours * 3600);
+ minutes = diff / 60;
+ snprintf(buf, len,
+ getstring(nc,
+ ((hours == 1
+ && minutes ==
+ 1) ? EXPIRES_1H1M : ((hours == 1
+ && minutes !=
+ 1) ? EXPIRES_1HM
+ : ((hours != 1
+ && minutes ==
+ 1) ?
+ EXPIRES_H1M :
+ EXPIRES_HM)))),
+ hours, minutes);
+ }
+ }
+ }
+
+ return buf;
+}
+
+
+/*************************************************************************/
+
+/**
+ * Validate the host
+ * shortname = ( letter / digit ) *( letter / digit / "-" ) *( letter / digit )
+ * hostname = shortname *( "." shortname )
+ * ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
+ * @param host = string to check
+ * @param type = format, 1 = ip4addr, 2 = hostname
+ * @return 1 if a host is valid, 0 if it isnt.
+ */
+int doValidHost(const char *host, int type)
+{
+ int idx = 0;
+ int len = 0;
+ int sec_len = 0;
+ int dots = 1;
+ if (type != 1 && type != 2) {
+ return 0;
+ }
+ if (!host) {
+ return 0;
+ }
+
+ len = strlen(host);
+
+ if (len > Config.HostLen) {
+ return 0;
+ }
+
+ switch (type) {
+ case 1:
+ for (idx = 0; idx < len; idx++) {
+ if (isdigit(host[idx])) {
+ if (sec_len < 3) {
+ sec_len++;
+ } else {
+ return 0;
+ }
+ } else {
+ if (idx == 0) {
+ return 0;
+ } /* cant start with a non-digit */
+ if (host[idx] != '.') {
+ return 0;
+ } /* only . is a valid non-digit */
+ if (sec_len > 3) {
+ return 0;
+ } /* sections cant be more than 3 digits */
+ sec_len = 0;
+ dots++;
+ }
+ }
+ if (dots != 4) {
+ return 0;
+ }
+ break;
+ case 2:
+ dots = 0;
+ for (idx = 0; idx < len; idx++) {
+ if (!isalnum(host[idx])) {
+ if (idx == 0) {
+ return 0;
+ }
+ if ((host[idx] != '.') && (host[idx] != '-')) {
+ return 0;
+ }
+ if (host[idx] == '.') {
+ dots++;
+ }
+ }
+ }
+ if (host[len - 1] == '.') {
+ return 0;
+ }
+ /**
+ * Ultimate3 dosnt like a non-dotted hosts at all, nor does unreal,
+ * so just dont allow them.
+ **/
+ if (dots == 0) {
+ return 0;
+ }
+
+ break;
+ }
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Front end to doValidHost
+ * @param host = string to check
+ * @param type = format, 1 = ip4addr, 2 = hostname
+ * @return 1 if a host is valid, 0 if it isnt.
+ */
+int isValidHost(const char *host, int type)
+{
+ int status = 0;
+ if (type == 3) {
+ if (!(status = doValidHost(host, 1))) {
+ status = doValidHost(host, 2);
+ }
+ } else {
+ status = doValidHost(host, type);
+ }
+ return status;
+}
+
+/*************************************************************************/
+
+/**
+ * Valid character check
+ * @param c Character to check
+ * @return 1 if a host is valid, 0 if it isnt.
+ */
+int isvalidchar(const char c)
+{
+ if (((c >= 'A') && (c <= 'Z')) ||
+ ((c >= 'a') && (c <= 'z')) ||
+ ((c >= '0') && (c <= '9')) || (c == '.') || (c == '-'))
+ return 1;
+ else
+ return 0;
+}
+
+
+/*************************************************************************/
+
+/**
+ * Get the token
+ * @param str String to search in
+ * @param dilim Character to search for
+ * @param token_number the token number
+ * @return token
+ */
+char *myStrGetToken(const char *str, const char dilim, int token_number)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ char *substring = NULL;
+ if (!str) {
+ return NULL;
+ }
+ len = strlen(str);
+ for (idx = 0; idx <= len; idx++) {
+ if ((str[idx] == dilim) || (idx == len)) {
+ if (counter == token_number) {
+ substring = myStrSubString(str, start_pos, idx);
+ counter++;
+ } else {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ }
+ return substring;
+}
+
+/*************************************************************************/
+
+/**
+ * Get the token only
+ * @param str String to search in
+ * @param dilim Character to search for
+ * @param token_number the token number
+ * @return token
+ */
+char *myStrGetOnlyToken(const char *str, const char dilim,
+ int token_number)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ char *substring = NULL;
+ if (!str) {
+ return NULL;
+ }
+ len = strlen(str);
+ for (idx = 0; idx <= len; idx++) {
+ if (str[idx] == dilim) {
+ if (counter == token_number) {
+ if (str[idx] == '\r')
+ substring = myStrSubString(str, start_pos, idx - 1);
+ else
+ substring = myStrSubString(str, start_pos, idx);
+ counter++;
+ } else {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ }
+ return substring;
+}
+
+/*************************************************************************/
+
+/**
+ * Get the Remaining tokens
+ * @param str String to search in
+ * @param dilim Character to search for
+ * @param token_number the token number
+ * @return token
+ */
+char *myStrGetTokenRemainder(const char *str, const char dilim,
+ int token_number)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ char *substring = NULL;
+ if (!str) {
+ return NULL;
+ }
+ len = strlen(str);
+
+ for (idx = 0; idx <= len; idx++) {
+ if ((str[idx] == dilim) || (idx == len)) {
+ if (counter == token_number) {
+ substring = myStrSubString(str, start_pos, len);
+ counter++;
+ } else {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ }
+ return substring;
+}
+
+/*************************************************************************/
+
+/**
+ * Get the string between point A and point B
+ * @param str String to search in
+ * @param start Point A
+ * @param end Point B
+ * @return the string in between
+ */
+char *myStrSubString(const char *src, int start, int end)
+{
+ char *substring = NULL;
+ int len, idx;
+ if (!src) {
+ return NULL;
+ }
+ len = strlen(src);
+ if (((start >= 0) && (end <= len)) && (end > start)) {
+ substring = new char[(end - start) + 1];
+ for (idx = 0; idx <= end - start; idx++) {
+ substring[idx] = src[start + idx];
+ }
+ substring[end - start] = '\0';
+ }
+ return substring;
+}
+
+/*************************************************************************/
+
+/**
+ * Clean up the buffer for extra spaces
+ * @param str to clean up
+ * @return void
+ */
+void doCleanBuffer(char *str)
+{
+ char *in, *out;
+ char ch;
+
+ if (!str) {
+ return;
+ }
+
+ in = str;
+ out = str;
+
+ while (issp(ch = *in++));
+ if (ch != '\0')
+ for (;;) {
+ *out++ = ch;
+ ch = *in++;
+ if (ch == '\0')
+ break;
+ if (!issp(ch))
+ continue;
+ while (issp(ch = *in++));
+ if (ch == '\0')
+ break;
+ *out++ = ' ';
+ }
+ *out = ch; /* == '\0' */
+}
+
+/*************************************************************************/
+
+/**
+ * Kill the user to enforce the sqline
+ * @param nick to kill
+ * @param killer whom is doing the killing
+ * @return void
+ */
+void EnforceQlinedNick(const std::string &nick, const char *killer)
+{
+ User *u2;
+
+ if ((u2 = finduser(nick))) {
+ Alog() << "Killed Q-lined nick: " << u2->GetMask();
+ kill_user(killer, u2->nick.c_str(), "This nick is reserved for Services. Please use a non Q-Lined nick.");
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Is the given nick a network service
+ * @param nick to check
+ * @param int Check if botserv bots
+ * @return int
+ */
+int nickIsServices(const char *tempnick, int bot)
+{
+ int found = 0;
+ char *s, *nick;
+
+ if (!tempnick) {
+ return found;
+ }
+
+ nick = sstrdup(tempnick);
+
+ s = strchr(nick, '@');
+ if (s) {
+ *s++ = 0;
+ if (stricmp(s, Config.ServerName) != 0) {
+ delete [] nick;
+ return found;
+ }
+ }
+
+ if (Config.s_NickServ && (stricmp(nick, Config.s_NickServ) == 0))
+ found++;
+ else if (Config.s_ChanServ && (stricmp(nick, Config.s_ChanServ) == 0))
+ found++;
+ else if (Config.s_HostServ && (stricmp(nick, Config.s_HostServ) == 0))
+ found++;
+ else if (Config.s_MemoServ && (stricmp(nick, Config.s_MemoServ) == 0))
+ found++;
+ else if (Config.s_BotServ && (stricmp(nick, Config.s_BotServ) == 0))
+ found++;
+ else if (Config.s_OperServ && (stricmp(nick, Config.s_OperServ) == 0))
+ found++;
+ else if (Config.s_GlobalNoticer && (stricmp(nick, Config.s_GlobalNoticer) == 0))
+ found++;
+ else if (Config.s_BotServ && bot)
+ {
+ for (botinfo_map::const_iterator it = BotList.begin(); it != BotList.end(); ++it)
+ {
+ BotInfo *bi = it->second;
+
+ ci::string ci_bi_nick(bi->nick.c_str());
+ if (ci_bi_nick == nick)
+ {
+ found++;
+ break;
+ }
+ }
+ }
+
+ /* Somehow, something tells me we should free this :) -GD */
+ delete [] nick;
+
+ return found;
+}
+
+/*************************************************************************/
+
+/**
+ * arc4 init
+ * @return void
+ */
+static void arc4_init()
+{
+ int n;
+ for (n = 0; n < 256; n++)
+ rs.s[n] = n;
+ rs.i = 0;
+ rs.j = 0;
+}
+
+/*************************************************************************/
+
+/**
+ * arc4 addrandom
+ * @param data
+ * @param dalen Data Length
+ * @return void
+ */
+static void arc4_addrandom(void *dat, int datlen)
+{
+ int n;
+ uint8 si;
+
+ rs.i--;
+ for (n = 0; n < 256; n++) {
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si + (static_cast<unsigned char *>(dat))[n % datlen]);
+ rs.s[rs.i] = rs.s[rs.j];
+ rs.s[rs.j] = si;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * random init
+ * @return void
+ */
+void rand_init()
+{
+#ifndef _WIN32
+ int n, fd;
+#endif
+ struct {
+#ifndef _WIN32
+ struct timeval nowt; /* time */
+ char rnd[32]; /* /dev/urandom */
+#else
+ MEMORYSTATUS mstat; /* memory status */
+ struct _timeb nowt; /* time */
+#endif
+ } rdat;
+
+ arc4_init();
+
+ /* Grab OS specific "random" data */
+#ifndef _WIN32
+ /* unix/bsd: time */
+ gettimeofday(&rdat.nowt, NULL);
+ /* unix/bsd: /dev/urandom */
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd) {
+ n = read(fd, &rdat.rnd, sizeof(rdat.rnd));
+ close(fd);
+ }
+#else
+ /* win32: time */
+ _ftime(&rdat.nowt);
+ /* win32: memory status */
+ GlobalMemoryStatus(&rdat.mstat);
+#endif
+
+ arc4_addrandom(&rdat, sizeof(rdat));
+}
+
+/*************************************************************************/
+
+/**
+ * Setup the random numbers
+ * @return void
+ */
+void add_entropy_userkeys()
+{
+ arc4_addrandom(&Config.UserKey1, sizeof(Config.UserKey1));
+ arc4_addrandom(&Config.UserKey2, sizeof(Config.UserKey2));
+ arc4_addrandom(&Config.UserKey3, sizeof(Config.UserKey3));
+ /* UserKey3 is also used in mysql_rand() */
+}
+
+/*************************************************************************/
+
+/**
+ * Get the random numbers 8 byte deep
+ * @return char
+ */
+unsigned char getrandom8()
+{
+ unsigned char si, sj;
+
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si);
+ sj = rs.s[rs.j];
+ rs.s[rs.i] = sj;
+ rs.s[rs.j] = si;
+ return (rs.s[(si + sj) & 0xff]);
+}
+
+/*************************************************************************/
+
+/**
+ * Get the random numbers 16 byte deep
+ * @return char
+ */
+uint16 getrandom16()
+{
+ uint16 val;
+
+ val = getrandom8() << 8;
+ val |= getrandom8();
+ return val;
+}
+
+/*************************************************************************/
+
+/**
+ * Get the random numbers 32 byte deep
+ * @return char
+ */
+uint32 getrandom32()
+{
+ uint32 val;
+
+ val = getrandom8() << 24;
+ val |= getrandom8() << 16;
+ val |= getrandom8() << 8;
+ val |= getrandom8();
+ return val;
+}
+
+/*************************************************************************/
+
+/**
+ * Number of tokens in a string
+ * @param str String
+ * @param dilim Dilimiter
+ * @return number of tokens
+ */
+int myNumToken(const char *str, const char dilim)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ if (!str) {
+ return 0;
+ }
+ len = strlen(str);
+ for (idx = 0; idx <= len; idx++) {
+ if ((str[idx] == dilim) || (idx == len)) {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ return counter;
+}
+
+/*************************************************************************/
+
+/**
+ * Resolve a host to an IP
+ * @param host to convert
+ * @return ip address
+ */
+char *host_resolve(char *host)
+{
+ struct hostent *hentp = NULL;
+ uint32 ip = INADDR_NONE;
+ char ipbuf[16];
+ char *ipreturn;
+ struct in_addr addr;
+
+ ipreturn = NULL;
+
+ hentp = gethostbyname(host);
+
+ if (hentp) {
+ memcpy(&ip, hentp->h_addr, sizeof(hentp->h_length));
+ addr.s_addr = ip;
+ ntoa(addr, ipbuf, sizeof(ipbuf));
+ ipreturn = sstrdup(ipbuf);
+ Alog(LOG_DEBUG) << "resolved " << host << " to " << ipbuf;
+ return ipreturn;
+ } else {
+ return ipreturn;
+ }
+}
+
+/*************************************************************************/
+
+/** Build a string list from a source string
+ * @param src The source string
+ * @return a list of strings
+ */
+std::list<std::string> BuildStringList(const std::string &src)
+{
+ spacesepstream tokens(src);
+ std::string token;
+ std::list<std::string> Ret;
+
+ while (tokens.GetToken(token))
+ Ret.push_back(token);
+
+ return Ret;
+}
+
+std::list<ci::string> BuildStringList(const ci::string &src)
+{
+ spacesepstream tokens(src);
+ ci::string token;
+ std::list<ci::string> Ret;
+
+ while (tokens.GetToken(token))
+ Ret.push_back(token);
+
+ return Ret;
+}
+
+std::vector<std::string> BuildStringVector(const std::string &src)
+{
+ spacesepstream tokens(src);
+ std::string token;
+ std::vector<std::string> Ret;
+
+ while (tokens.GetToken(token))
+ Ret.push_back(token);
+
+ return Ret;
+}
+
+/*************************************************************************/
+
+/**
+ * Change an unsigned string to a signed string, overwriting the original
+ * string.
+ * @param input string
+ * @return output string, same as input string.
+ */
+
+char *str_signed(unsigned char *str)
+{
+ char *nstr;
+
+ nstr = reinterpret_cast<char *>(str);
+ while (*str) {
+ *nstr = static_cast<char>(*str);
+ str++;
+ nstr++;
+ }
+
+ return nstr;
+}
+
+/**
+ * Strip the mode prefix from the given string.
+ * Useful for using the modes stored in things like ircd->ownerset etc..
+ **/
+
+char *stripModePrefix(const char *str)
+{
+ if (str && ((*str == '+') || (*str == '-'))) {
+ return sstrdup(str + 1);
+ }
+ return NULL;
+}
+
+/* Equivalent to inet_ntoa */
+
+void ntoa(struct in_addr addr, char *ipaddr, int len)
+{
+ unsigned char *bytes = reinterpret_cast<unsigned char *>(&addr.s_addr);
+ snprintf(ipaddr, len, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2],
+ bytes[3]);
+}
+
+/*
+* strlcat and strlcpy were ripped from openssh 2.5.1p2
+* They had the following Copyright info:
+*
+*
+* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz, dlen;
+
+ while (n-- != 0 && *d != '\0')
+ d++;
+
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return (dlen + strlen(s));
+
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+
+ s++;
+ }
+
+ *d = '\0';
+ return dlen + (s - src); /* count does not include NUL */
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ }
+ while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++);
+ }
+
+ return s - src - 1; /* count does not include NUL */
+}
+#endif
+
+
+
+
+#ifdef _WIN32
+char *GetWindowsVersion()
+{
+ OSVERSIONINFOEX osvi;
+ BOOL bOsVersionInfoEx;
+ char buf[BUFSIZE];
+ char *extra;
+ char *cputype;
+ SYSTEM_INFO si;
+
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ ZeroMemory(&si, sizeof(SYSTEM_INFO));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (!GetVersionEx((OSVERSIONINFO *) & osvi)) {
+ return sstrdup("");
+ }
+ }
+ GetSystemInfo(&si);
+
+ /* Determine CPU type 32 or 64 */
+ if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) {
+ cputype = sstrdup(" 64-bit");
+ } else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL ) {
+ cputype = sstrdup(" 32-bit");
+ } else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 ) {
+ cputype = sstrdup(" Itanium 64-bit");
+ } else {
+ cputype = sstrdup(" ");
+ }
+
+ switch (osvi.dwPlatformId) {
+ /* test for the Windows NT product family. */
+ case VER_PLATFORM_WIN32_NT:
+ /* Windows Vista or Windows Server 2008 */
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) {
+ if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+ extra = sstrdup("Enterprise Edition");
+ } else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+ extra = sstrdup("Datacenter Edition");
+ } else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
+ extra = sstrdup("Home Premium/Basic");
+ } else {
+ extra = sstrdup(" ");
+ }
+ if (osvi.wProductType & VER_NT_WORKSTATION) {
+ snprintf(buf, sizeof(buf), "Microsoft Windows Vista %s%s",
+ cputype, extra);
+ } else {
+ snprintf(buf, sizeof(buf), "Microsoft Windows Server 2008 %s%s",
+ cputype, extra);
+ }
+ delete [] extra;
+ }
+ /* Windows 2003 or Windows XP Pro 64 */
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
+ if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+ extra = sstrdup("Datacenter Edition");
+ } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+ extra = sstrdup("Enterprise Edition");
+#ifdef VER_SUITE_COMPUTE_SERVER
+ } else if (osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER) {
+ extra = sstrdup("Compute Cluster Edition");
+#endif
+ } else if (osvi.wSuiteMask == VER_SUITE_BLADE) {
+ extra = sstrdup("Web Edition");
+ } else {
+ extra = sstrdup("Standard Edition");
+ }
+ if ( osvi.wProductType & VER_NT_WORKSTATION && si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
+ snprintf(buf, sizeof(buf), "Windows XP Professional x64 Edition %s",
+ extra);
+ } else {
+ snprintf(buf, sizeof(buf),
+ "Microsoft Windows Server 2003 Family %s%s", cputype, extra);
+ }
+ delete [] extra;
+ }
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
+ if (osvi.wSuiteMask & VER_SUITE_EMBEDDEDNT) {
+ extra = sstrdup("Embedded");
+ } else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
+ extra = sstrdup("Home Edition");
+ } else {
+ extra = sstrdup(" ");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows XP %s", extra);
+ delete [] extra;
+ }
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
+ if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+ extra = sstrdup("Datacenter Server");
+ } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+ extra = sstrdup("Advanced Server");
+ } else {
+ extra = sstrdup("Server");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows 2000 %s", extra);
+ delete [] extra;
+ }
+ if (osvi.dwMajorVersion <= 4) {
+ if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+ extra = sstrdup("Server 4.0, Enterprise Edition");
+ } else {
+ extra = sstrdup("Server 4.0");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows NT %s", extra);
+ delete [] extra;
+ }
+ case VER_PLATFORM_WIN32_WINDOWS:
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
+ if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') {
+ extra = sstrdup("OSR2");
+ } else {
+ extra = sstrdup(" ");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows 95 %s", extra);
+ delete [] extra;
+ }
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
+ if (osvi.szCSDVersion[1] == 'A') {
+ extra = sstrdup("SE");
+ } else {
+ extra = sstrdup(" ");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows 98 %s", extra);
+ delete [] extra;
+ }
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
+ snprintf(buf, sizeof(buf),
+ "Microsoft Windows Millennium Edition");
+ }
+ }
+ delete [] cputype;
+ return sstrdup(buf);
+}
+
+int SupportedWindowsVersion()
+{
+ OSVERSIONINFOEX osvi;
+ BOOL bOsVersionInfoEx;
+
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (!GetVersionEx((OSVERSIONINFO *) & osvi)) {
+ return 0;
+ }
+ }
+
+ switch (osvi.dwPlatformId) {
+ /* test for the Windows NT product family. */
+ case VER_PLATFORM_WIN32_NT:
+ /* win nt4 */
+ if (osvi.dwMajorVersion <= 4) {
+ return 0;
+ }
+ /* the rest */
+ return 1;
+ /* win95 win98 winME */
+ case VER_PLATFORM_WIN32_WINDOWS:
+ return 0;
+ }
+ return 0;
+}
+
+#endif
+
+
+/*************************************************************************/
+/* This 2 functions were originally found in Bahamut */
+
+/**
+ * Turn a cidr value into a netmask
+ * @param cidr CIDR value
+ * @return Netmask value
+ */
+uint32 cidr_to_netmask(uint16 cidr)
+{
+ if (cidr == 0)
+ return 0;
+
+ return (0xFFFFFFFF - (1 << (32 - cidr)) + 1);
+}
+
+/**
+ * Turn a netmask into a cidr value
+ * @param mask Netmask
+ * @return CIDR value
+ */
+uint16 netmask_to_cidr(uint32 mask)
+{
+ int tmp = 0;
+
+ while (!(mask & (1 << tmp)) && (tmp < 32))
+ tmp++;
+
+ return (32 - tmp);
+}
+
+/*************************************************************************/
+
+/**
+ * Check if the given string is some sort of wildcard
+ * @param str String to check
+ * @return 1 for wildcard, 0 for anything else
+ */
+int str_is_wildcard(const char *str)
+{
+ while (*str) {
+ if ((*str == '*') || (*str == '?'))
+ return 1;
+ str++;
+ }
+
+ return 0;
+}
+
+/**
+ * Check if the given string is a pure wildcard
+ * @param str String to check
+ * @return 1 for pure wildcard, 0 for anything else
+ */
+int str_is_pure_wildcard(const char *str)
+{
+ while (*str) {
+ if (*str != '*')
+ return 0;
+ str++;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Check if the given string is an IP, and return the IP.
+ * @param str String to check
+ * @return The IP, if one found. 0 if none.
+ */
+uint32 str_is_ip(char *str)
+{
+ int i;
+ int octets[4] = { -1, -1, -1, -1 };
+ char *s = str;
+ uint32 ip;
+
+ for (i = 0; i < 4; i++) {
+ octets[i] = strtol(s, &s, 10);
+ /* Bail out if the octet is invalid or wrongly terminated */
+ if ((octets[i] < 0) || (octets[i] > 255)
+ || ((i < 3) && (*s != '.')))
+ return 0;
+ if (i < 3)
+ s++;
+ }
+
+ /* Fill the IP - the dirty way */
+ ip = octets[3];
+ ip += octets[2] * 256;
+ ip += octets[1] * 65536;
+ ip += octets[0] * 16777216;
+
+ return ip;
+}
+
+/*************************************************************************/
+
+/**
+ * Check if the given string is an IP or CIDR mask, and fill the given
+ * ip/cidr params if so.
+ * @param str String to check
+ * @param ip The ipmask to fill when a CIDR is found
+ * @param mask The CIDR mask to fill when a CIDR is found
+ * @param host Displayed host
+ * @return 1 for IP/CIDR, 0 for anything else
+ */
+int str_is_cidr(char *str, uint32 * ip, uint32 * mask, char **host)
+{
+ int i;
+ int octets[4] = { -1, -1, -1, -1 };
+ char *s = str;
+ char buf[512];
+ uint16 cidr;
+
+ for (i = 0; i < 4; i++) {
+ octets[i] = strtol(s, &s, 10);
+ /* Bail out if the octet is invalid or wrongly terminated */
+ if ((octets[i] < 0) || (octets[i] > 255)
+ || ((i < 3) && (*s != '.')))
+ return 0;
+ if (i < 3)
+ s++;
+ }
+
+ /* Fill the IP - the dirty way */
+ *ip = octets[3];
+ *ip += octets[2] * 256;
+ *ip += octets[1] * 65536;
+ *ip += octets[0] * 16777216;
+
+ if (*s == '/') {
+ s++;
+ /* There's a CIDR mask here! */
+ cidr = strtol(s, &s, 10);
+ /* Bail out if the CIDR is invalid or the string isn't done yet */
+ if ((cidr > 32) || (*s))
+ return 0;
+ } else {
+ /* No CIDR mask here - use 32 so the whole ip will be matched */
+ cidr = 32;
+ }
+
+ *mask = cidr_to_netmask(cidr);
+ /* Apply the mask to avoid 255.255.255.255/8 bans */
+ *ip &= *mask;
+
+ /* Refill the octets to fill the host */
+ octets[0] = (*ip & 0xFF000000) / 16777216;
+ octets[1] = (*ip & 0x00FF0000) / 65536;
+ octets[2] = (*ip & 0x0000FF00) / 256;
+ octets[3] = (*ip & 0x000000FF);
+
+ if (cidr == 32)
+ snprintf(buf, 512, "%d.%d.%d.%d", octets[0], octets[1], octets[2],
+ octets[3]);
+ else
+ snprintf(buf, 512, "%d.%d.%d.%d/%d", octets[0], octets[1],
+ octets[2], octets[3], cidr);
+
+ *host = sstrdup(buf);
+
+ return 1;
+}
+
+/* EOF */