]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/tools.c
Fix for a couple of crash bugs
[irc/evilnet/x3.git] / src / tools.c
index d9fd7c0e9cd49fbb0fbfb18794a16ea0b9265e3b..357c1c7c3f6eb35a6c66d4957988947115c932f6 100644 (file)
@@ -3,9 +3,9 @@
  *
  * This file is part of x3.
  *
- * srvx is free software; you can redistribute it and/or modify
+ * x3 is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -50,13 +50,23 @@ static const unsigned char convert2n[256] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0, 
+  52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
    0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
   15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
    0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
   41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0
 };
 
+static const unsigned char ctype[256] = {
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
+   0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
 unsigned long int
 base64toint(const char* s, int count)
 {
@@ -78,12 +88,289 @@ const char* inttobase64(char* buf, unsigned int v, unsigned int count)
   return buf;
 }
 
+unsigned int
+irc_ntop(char *output, unsigned int out_size, const irc_in_addr_t *addr)
+{
+    static const char hexdigits[] = "0123456789abcdef";
+    unsigned int pos;
+
+    assert(output);
+    assert(addr);
+
+    if (irc_in_addr_is_ipv4(*addr)) {
+        unsigned int ip4;
+
+        ip4 = (ntohs(addr->in6[6]) << 16) | ntohs(addr->in6[7]);
+        pos = snprintf(output, out_size, "%u.%u.%u.%u", (ip4 >> 24), (ip4 >> 16) & 255, (ip4 >> 8) & 255, ip4 & 255);
+   } else {
+        unsigned int part, max_start, max_zeros, curr_zeros, ii;
+
+        /* Find longest run of zeros. */
+        for (max_start = max_zeros = curr_zeros = ii = 0; ii < 8; ++ii) {
+            if (!addr->in6[ii])
+                curr_zeros++;
+            else if (curr_zeros > max_zeros) {
+                max_start = ii - curr_zeros;
+                max_zeros = curr_zeros;
+                curr_zeros = 0;
+            }
+        }
+        if (curr_zeros > max_zeros) {
+            max_start = ii - curr_zeros;
+            max_zeros = curr_zeros;
+        }
+
+        /* Print out address. */
+#define APPEND(CH) do { if (pos < out_size) output[pos] = (CH); pos++; } while (0)
+        for (pos = 0, ii = 0; ii < 8; ++ii) {
+            if ((max_zeros > 0) && (ii == max_start)) {
+                if (ii == 0)
+                    APPEND(':');
+                APPEND(':');
+                ii += max_zeros - 1;
+                continue;
+            }
+            part = ntohs(addr->in6[ii]);
+            if (part >= 0x1000)
+                APPEND(hexdigits[part >> 12]);
+            if (part >= 0x100)
+                APPEND(hexdigits[(part >> 8) & 15]);
+            if (part >= 0x10)
+                APPEND(hexdigits[(part >> 4) & 15]);
+            APPEND(hexdigits[part & 15]);
+            if (ii < 7)
+                APPEND(':');
+        }
+#undef APPEND
+        output[pos < out_size ? pos : out_size - 1] = '\0';
+    }
+
+    return pos;
+}
+
+unsigned int
+irc_ntop_mask(char *output, unsigned int out_size, const irc_in_addr_t *addr, unsigned char bits)
+{
+    char base_addr[IRC_NTOP_MAX_SIZE];
+    int len;
+
+    if (bits >= 128)
+        return irc_ntop(output, out_size, addr);
+    if (!irc_ntop(base_addr, sizeof(base_addr), addr))
+        return 0;
+    len = snprintf(output, out_size, "%s/%d", base_addr, bits);
+    if ((unsigned int)len >= out_size)
+        return 0;
+    return len;
+}
+
+static unsigned int
+irc_pton_ip4(const char *input, unsigned char *pbits, uint32_t *output)
+{
+    unsigned int dots = 0, pos = 0, part = 0, ip = 0, bits = 32;
+
+    /* Intentionally no support for bizarre IPv4 formats (plain
+     * integers, octal or hex components) -- only vanilla dotted
+     * decimal quads, optionally with trailing /nn.
+     */
+    if (input[0] == '.')
+        return 0;
+    while (1) switch (input[pos]) {
+    default:
+        if (dots < 3)
+            return 0;
+    out:
+        ip |= part << (24 - 8 * dots++);
+        *output = htonl(ip);
+        if (pbits)
+            *pbits = bits;
+        return pos;
+    case '.':
+        if (input[++pos] == '.')
+            return 0;
+        ip |= part << (24 - 8 * dots++);
+        part = 0;
+        if (input[pos] == '*') {
+            while (input[++pos] == '*') ;
+            if (input[pos] != '\0')
+                return 0;
+            if (pbits)
+                *pbits = dots * 8;
+            *output = htonl(ip);
+            return pos;
+        }
+        break;
+    case '/':
+        if (!pbits || !isdigit(input[pos + 1]))
+            return 0;
+        for (bits = 0; isdigit(input[++pos]); )
+            bits = bits * 10 + input[pos] - '0';
+        if (bits > 32)
+            return 0;
+        goto out;
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+        part = part * 10 + input[pos++] - '0';
+        if (part > 255)
+            return 0;
+        break;
+    }
+}
+
+unsigned int
+irc_pton(irc_in_addr_t *addr, unsigned char *bits, const char *input)
+{
+    const char *part_start = NULL;
+    char *colon;
+    char *dot;
+    unsigned int part = 0, pos = 0, ii = 0, cpos = 8;
+
+    assert(input);
+    memset(addr, 0, sizeof(*addr));
+    colon = strchr(input, ':');
+    dot = strchr(input, '.');
+
+    if (colon && (!dot || (dot > colon))) {
+        /* Parse IPv6, possibly like ::127.0.0.1.
+         * This is pretty straightforward; the only trick is borrowed
+         * from Paul Vixie (BIND): when it sees a "::" continue as if
+         * it were a single ":", but note where it happened, and fill
+         * with zeros afterwards.
+         */
+        if (input[pos] == ':') {
+            if ((input[pos+1] != ':') || (input[pos+2] == ':'))
+                return 0;
+            cpos = 0;
+            pos += 2;
+            part_start = input + pos;
+        }
+        while (ii < 8) switch (input[pos]) {
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+            part = (part << 4) | (ctype[(unsigned char)input[pos++]] & 15);
+            if (part > 0xffff)
+                return 0;
+            break;
+        case ':':
+            part_start = input + ++pos;
+            if (input[pos] == '.')
+                return 0;
+            addr->in6[ii++] = htons(part);
+            part = 0;
+            if (input[pos] == ':') {
+                if (cpos < 8)
+                    return 0;
+                cpos = ii;
+            }
+            break;
+        case '.': {
+            uint32_t ip4;
+            unsigned int len;
+            len = irc_pton_ip4(part_start, bits, &ip4);
+            if (!len || (ii > 6))
+                return 0;
+            memcpy(addr->in6 + ii, &ip4, sizeof(ip4));
+            if (bits)
+                *bits += 96;
+            ii += 2;
+            pos = part_start + len - input;
+            goto finish;
+        }
+        case '/':
+            if (!bits || !isdigit(input[pos + 1]))
+                return 0;
+            addr->in6[ii++] = htons(part);
+            for (part = 0; isdigit(input[++pos]); )
+                part = part * 10 + input[pos] - '0';
+            if (part > 128)
+                return 0;
+            *bits = part;
+            goto finish;
+        case '*':
+            while (input[++pos] == '*') ;
+            if (input[pos] != '\0' || cpos < 8)
+                return 0;
+            if (bits)
+                *bits = ii * 16;
+            return pos;
+        default:
+            addr->in6[ii++] = htons(part);
+            if (cpos == 8 && ii < 8)
+                return 0;
+            if (bits)
+                *bits = 128;
+            goto finish;
+        }
+    finish:
+        /* Shift stuff after "::" up and fill middle with zeros. */
+        if (cpos < 8) {
+            unsigned int jj;
+            for (jj = 0; jj < ii - cpos; jj++)
+                addr->in6[7 - jj] = addr->in6[ii - jj - 1];
+            for (jj = 0; jj < 8 - ii; jj++)
+                addr->in6[cpos + jj] = 0;
+        }
+    } else if (dot) {
+        uint32_t ip4;
+        pos = irc_pton_ip4(input, bits, &ip4);
+        if (pos) {
+            addr->in6[5] = htons(65535);
+            addr->in6[6] = htons(ntohl(ip4) >> 16);
+            addr->in6[7] = htons(ntohl(ip4) & 65535);
+            if (bits)
+                *bits += 96;
+        }
+    } else if (input[0] == '*') {
+        while (input[++pos] == '*') ;
+        if (input[pos] != '\0')
+            return 0;
+        if (bits)
+            *bits = 0;
+    }
+    return pos;
+}
+
+const char *irc_ntoa(const irc_in_addr_t *addr)
+{
+    static char ntoa[IRC_NTOP_MAX_SIZE];
+    irc_ntop(ntoa, sizeof(ntoa), addr);
+    return ntoa;
+}
+
+unsigned int
+irc_check_mask(const irc_in_addr_t *check, const irc_in_addr_t *mask, unsigned char bits)
+{
+    unsigned int ii;
+
+    for (ii = 0; (ii < 8) && (bits > 16); bits -= 16, ++ii)
+        if (check->in6[ii] != mask->in6[ii])
+            return 0;
+    if (ii < 8 && bits > 0
+        && (ntohs(check->in6[ii] ^ mask->in6[ii]) >> (16 - bits)))
+        return 0;
+    return 1;
+}
+
 static char irc_tolower[256];
 #undef tolower
 #define tolower(X) irc_tolower[(unsigned char)(X)]
 
+void
+irc_strtolower(char *str) {
+    char *p;
+    for(p = str;*p;p++) {
+       *p = tolower(*p);
+    }
+}
+
 int
 irccasecmp(const char *stra, const char *strb) {
+    if (!stra)
+      return -1;
+    if (!strb)
+      return 1;
     while (*stra && (tolower(*stra) == tolower(*strb)))
         stra++, strb++;
     return tolower(*stra) - tolower(*strb);
@@ -110,6 +397,14 @@ irccasestr(const char *haystack, const char *needle) {
     return NULL;
 }
 
+char *
+ircstrlower(char *str) {
+    size_t ii;
+    for (ii = 0; str[ii] != '\0'; ++ii)
+        str[ii] = tolower(str[ii]);
+    return str;
+}
+
 int
 split_line(char *line, int irc_colon, int argv_size, char *argv[])
 {
@@ -245,156 +540,213 @@ int mmatch(const char *old_mask, const char *new_mask)
 int
 match_ircglob(const char *text, const char *glob)
 {
-    unsigned int star_p, q_cnt;
-    while (1) {
-       switch (*glob) {
-       case 0:
-           return !*text;
-        case '\\':
-            glob++;
-            /* intentionally not tolower(...) so people can force
-             * capitalization, or we can overload \ in the future */
-            if (*text++ != *glob++)
-                return 0;
-            break;
-       case '*':
-        case '?':
-            star_p = q_cnt = 0;
-            do {
-                if (*glob == '*')
-                    star_p = 1;
-                else if (*glob == '?')
-                    q_cnt++;
-                else
-                    break;
-                glob++;
-            } while (1);
-            while (q_cnt) {
-                if (!*text++)
-                    return 0;
-                q_cnt--;
-            }
-            if (star_p) {
-                /* if this is the last glob character, it will match any text */
-                if (!*glob)
-                    return 1;
-                /* Thanks to the loop above, we know that the next
-                 * character is a normal character.  So just look for
-                 * the right character.
-                 */
-                for (; *text; text++) {
-                    if ((tolower(*text) == tolower(*glob))
-                        && match_ircglob(text+1, glob+1)) {
-                        return 1;
-                    }
-                }
-                return 0;
-            }
-            /* if !star_p, fall through to normal character case,
-             * first checking to see if ?s carried us to the end */
-            if (!*glob && !*text)
+    const char *m = glob, *n = text;
+    const char *m_tmp = glob, *n_tmp = text;
+    int star_p;
+
+    for (;;) switch (*m) {
+    case '\0':
+        if (!*n)
+            return 1;
+    backtrack:
+        if (m_tmp == glob)
+            return 0;
+        m = m_tmp;
+        n = ++n_tmp;
+        if (!*n)
+            return 0;
+        break;
+    case '\\':
+        m++;
+        /* allow escaping to force capitalization */
+        if (*m++ != *n++)
+            goto backtrack;
+        break;
+    case '*': case '?':
+        for (star_p = 0; ; m++) {
+            if (*m == '*')
+                star_p = 1;
+            else if (*m == '?') {
+                if (!*n++)
+                    goto backtrack;
+            } else break;
+        }
+        if (star_p) {
+            if (!*m)
                 return 1;
-       default:
-           if (!*text)
-                return 0;
-           while (*text && *glob && *glob != '*' && *glob != '?' && *glob != '\\') {
-               if (tolower(*text++) != tolower(*glob++))
+            else if (*m == '\\') {
+                m_tmp = ++m;
+                if (!*m)
                     return 0;
-           }
-       }
+                for (n_tmp = n; *n && *n != *m; n++) ;
+            } else {
+                m_tmp = m;
+                for (n_tmp = n; *n && tolower(*n) != tolower(*m); n++) ;
+            }
+        }
+        /* and fall through */
+    default:
+        if (!*n)
+            return *m == '\0';
+        if (tolower(*m) != tolower(*n))
+            goto backtrack;
+        m++;
+        n++;
+        break;
     }
 }
 
 extern const char *hidden_host_suffix;
 
-int user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick)
+/* Prevent *@* *@** *@*a* type masks, while allowing anything else. This is the best way iv found to detect 
+ * a global matching mask; if it matches this string, it'll match almost anything :) */
+int is_overmask(char *mask)
 {
-    /* A new glob function, the old one had many false positives.
-     * look at IsSetHost(user) etc and include_nick, build a nick!user@host string
-     * from user and save it in a variable. Compare with match_ircglob() and 
-     * return the results. Match any of the possible user@host combos (ugh) -Rubin
-     */
-    char *matchstr_user;
-    char *matchstr_host;
-    char *matchstr_full = NULL;
-
-    if(IsSetHost(user))   /* S: line sethosts */
-    {
-        /* Grab host and user from sethost instead of real host */
-        char *buff;
-        buff = alloca(strlen(user->sethost) + 1);
-        strcpy(buff, user->sethost);
-        matchstr_user = mysep(&buff, "@");
-        matchstr_host = mysep(&buff, "@");
-
-        matchstr_full = alloca(strlen(user->nick) + strlen(matchstr_user) + strlen(matchstr_host) + 4);
-        if(include_nick)
-            sprintf(matchstr_full, "%s!%s@%s", user->nick, matchstr_user, matchstr_host);
-        else
-            sprintf(matchstr_full, "%s@%s", matchstr_user, matchstr_host);
-        if(match_ircglob(matchstr_full, orig_glob))
-            return(1);
-    }
-    else if(IsFakeHost(user))  /* Fakehost */
-    {
-        matchstr_full = alloca(strlen(user->nick) + strlen(user->ident) + strlen(user->fakehost) + 4);
-        if(include_nick)
-            sprintf(matchstr_full, "%s!%s@%s", user->nick, user->ident, user->fakehost);
-        else
-            sprintf(matchstr_full, "%s@%s", user->ident, user->fakehost);
-        if(match_ircglob(matchstr_full, orig_glob))
-            return(1);
-    }
-    else if(hidden_host_suffix && user->handle_info)  /* name.users.network.org  host */
-    {
-        matchstr_host = alloca(strlen(user->handle_info->handle) + strlen(hidden_host_suffix) + 2);
-        sprintf(matchstr_host, "%s.%s", user->handle_info->handle, hidden_host_suffix);
-        matchstr_user = user->ident;
-
-        matchstr_full = alloca(strlen(user->nick) + strlen(user->ident) + strlen(matchstr_host) + 4);
-        if(include_nick)
-            sprintf(matchstr_full, "%s!%s@%s", user->nick, user->ident, matchstr_host);
-        else
-            sprintf(matchstr_full, "%s@%s", user->ident, matchstr_host);
-        if(match_ircglob(matchstr_full, orig_glob))
-            return(1);
-    }
-
-    /* Check normal hostname */
-    matchstr_full = alloca(strlen(user->nick) + strlen(user->ident) + strlen(user->hostname) + 4);
-    if(include_nick)
-        sprintf(matchstr_full, "%s!%s@%s", user->nick, user->ident, user->hostname);
-    else
-        sprintf(matchstr_full, "%s@%s", user->ident, user->hostname);
-    if(match_ircglob(matchstr_full, orig_glob))
-            return(1);
-
-    /* Check IP hostname (could skip this if same as above?)*/
-    matchstr_host = inet_ntoa(user->ip);
-    matchstr_full = alloca(strlen(user->nick) + strlen(user->ident) + strlen(matchstr_host) + 4);
-    if(include_nick)
-        sprintf(matchstr_full, "%s!%s@%s", user->nick, user->ident, matchstr_host);
-    else
-        sprintf(matchstr_full, "%s@%s", user->ident, matchstr_host);
-    if(match_ircglob(matchstr_full, orig_glob))
-            return(1);
-
-    return(0); /* Didnt match anything */
+    return(match_ircglob("abcdefghijklmnopqrstuv!frcmbghilnrtoasde@apdic.yfa.dsfsdaffsdasfdasfd.abcdefghijklmnopqrstuvwxyz.asdfasfdfsdsfdasfda.ydfbe", mask));
 }
 
 int
-user_matches_glob_broken(struct userNode *user, const char *orig_glob, int include_nick)
+user_matches_glob(struct userNode *user, const char *orig_glob, int flags, int shared)
 {
-    char *glob, *marker;
-    char *setident = NULL, *sethostname = NULL; // sethost - reed/apples
+    char *tmpglob, *glob, *marker;
+    char exttype = 0;
+    int extreverse = 0, is_extended = 0, match = 0, banned = 0;
+    unsigned int count, n;
+    struct modeNode *mn;
+    struct chanNode *channel;
+    struct banNode *ban;
 
     /* Make a writable copy of the glob */
     glob = alloca(strlen(orig_glob)+1);
     strcpy(glob, orig_glob);
+
+    /* Extended bans */
+    tmpglob = alloca(strlen(orig_glob)+1);
+    tmpglob = strdup(orig_glob);
+
+    if (*tmpglob == '~') {
+        tmpglob++; /* get rid of the ~ */
+
+        if (*tmpglob == '!') {
+            extreverse = 1;
+            tmpglob++; /* get rid of the ! */
+        }
+
+        exttype = *tmpglob;
+        tmpglob++; /* get rid of the type */
+
+        if (*tmpglob == ':') {
+            is_extended = 1;
+            tmpglob++; /* get rid of the : */
+            glob = strdup(tmpglob);
+        }
+    }
+
+    if (is_extended) {
+        log_module(MAIN_LOG, LOG_DEBUG, "Extended ban. T (%c) R (%d) M (%s)", exttype, extreverse, glob);
+        switch (exttype) {
+            case 'a':
+                if (user->handle_info) {
+                    if (extreverse) {
+                        if (0 != strcasecmp(glob, user->handle_info->handle))
+                            return 1;
+                    } else {
+                        if (0 == strcasecmp(glob, user->handle_info->handle))
+                            return 1;
+                    }
+                } else {
+                    if (extreverse)
+                        return 1;
+                }
+                return match_ircglob(user->hostname, glob);
+            case 'c':
+                if (!strstr(glob, "#"))
+                    return -1;
+
+                if (extreverse) {
+                    for (n=count=0; n<user->channels.used; n++) {
+                        mn = user->channels.list[n];
+                        match = 0;
+
+                        if (*glob == '#') {
+                            if (0 == strcasecmp(glob, mn->channel->name))
+                                match = 1;
+                        } else {
+                            if (0 == strcasecmp(glob+1, mn->channel->name)) {
+                                if ((*glob == '@') && (mn->modes & MODE_CHANOP))
+                                    match = 1;
+                                else if ((*glob == '%') && (mn->modes & MODE_HALFOP))
+                                    match = 1;
+                                else if ((*glob == '+') && (mn->modes & MODE_VOICE))
+                                    match = 1;
+                             }
+                        }
+
+                        if (match == 0)
+                            banned = 1;
+                        else {
+                            banned = 0;
+                            break;
+                        }
+                    }
+                } else {
+                    for (n=count=0; n<user->channels.used; n++) {
+                        mn = user->channels.list[n];
+                        match = 0;
+
+                        if (*glob == '#') {
+                            if (0 == strcasecmp(glob, mn->channel->name))
+                                match = 1;
+                        } else {
+                            if (0 == strcasecmp(glob+1, mn->channel->name)) {
+                                if ((*glob == '@') && (mn->modes & MODE_CHANOP))
+                                    match = 1;
+                                else if ((*glob == '%') && (mn->modes & MODE_HALFOP))
+                                    match = 1;
+                                else if ((*glob == '+') && (mn->modes & MODE_VOICE))
+                                    match = 1;
+                             }
+                        }
+
+                        if (match == 1)
+                            banned = 1;
+                    }
+                }
+
+                if (banned)
+                    return 1;
+                else
+                    return match_ircglob(user->hostname, glob);
+            case 'j':
+                 if (shared == 0) {
+                     if (*glob != '#')
+                         return -1;
+                     if ((channel = GetChannel(glob))) {
+                         for (n = 0; n < channel->banlist.used; n++) {
+                             ban = channel->banlist.list[n];
+                             if (user_matches_glob(user, ban->ban, flags, 1))
+                                 return 1;
+                         }
+                     }
+                 }
+                 return match_ircglob(user->hostname, glob);
+            case 'n': /* this is handled ircd side */
+                return match_ircglob(user->hostname, glob);
+            case 'q': /* this is handled ircd side */
+                return match_ircglob(user->hostname, glob);
+            case 't': /* this is handled ircd side */
+                return match_ircglob(user->hostname, glob);
+            case 'R': /* this is handled ircd side */
+                return match_ircglob(user->hostname, glob);
+            default:
+                return -1;
+        }
+    }
+
     /* Check the nick, if it's present */
-    if (include_nick) {
+    if (flags & MATCH_USENICK) {
         if (!(marker = strchr(glob, '!'))) {
-            log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include a '!'", user->nick, orig_glob, include_nick);
+            log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include a '!'", user->nick, orig_glob, flags);
             return 0;
         }
         *marker = 0;
@@ -403,30 +755,21 @@ user_matches_glob_broken(struct userNode *user, const char *orig_glob, int inclu
     }
     /* Check the ident */
     if (!(marker = strchr(glob, '@'))) {
-        log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include an '@'", user->nick, orig_glob, include_nick);
+        log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include an '@'", user->nick, orig_glob, flags);
         return 0;
     }
     *marker = 0;
-
-    // sethost - reed/apples
-    if (IsSetHost(user)) {
-      setident = alloca(strcspn(user->sethost, "@")+2);
-      safestrncpy(setident, user->sethost, strcspn(user->sethost, "@")+1);
-      sethostname = strchr(user->sethost, '@') + 1;
-    }
-
-    if (!match_ircglob(user->ident, glob) && (IsSetHost(user) && !match_ircglob(setident, glob)))
-       return 0;
+    if (!match_ircglob(user->ident, glob))
+        return 0;
     glob = marker + 1;
-    /* If it might be an IP glob, test that. */
-    if (!glob[strspn(glob, "0123456789./*?")]
-        && match_ircglob(inet_ntoa(user->ip), glob))
-        return 1;
     /* Check for a fakehost match. */
     if (IsFakeHost(user) && match_ircglob(user->fakehost, glob))
         return 1;
-    if (IsSetHost(user) && match_ircglob(sethostname, glob))
+
+    /* Check for a sethost (S:lines) */
+    if (IsSetHost(user) && match_ircglob(user->sethost, glob))
         return 1;
+
     /* Check for an account match. */
     if (hidden_host_suffix && user->handle_info) {
         char hidden_host[HOSTLEN+1];
@@ -434,6 +777,23 @@ user_matches_glob_broken(struct userNode *user, const char *orig_glob, int inclu
         if (match_ircglob(hidden_host, glob))
             return 1;
     }
+
+    /* Match crypt hostname */
+    if (match_ircglob(user->crypthost, glob))
+        return 1;
+
+    /* Match crypt IP */
+    if (match_ircglob(user->cryptip, glob))
+        return 1;
+
+    /* If only matching the visible hostnames, bail early. */
+    if ((flags & MATCH_VISIBLE) && IsHiddenHost(user)
+        && (IsFakeHost(user) || (hidden_host_suffix && user->handle_info)))
+        return 0;
+    /* If it might be an IP glob, test that. */
+    if (!glob[strspn(glob, "0123456789./*?")]
+        && match_ircglob(irc_ntoa(&user->ip), glob))
+        return 1;
     /* None of the above; could only be a hostname match. */
     return match_ircglob(user->hostname, glob);
 }
@@ -441,6 +801,27 @@ user_matches_glob_broken(struct userNode *user, const char *orig_glob, int inclu
 int
 is_ircmask(const char *text)
 {
+    char *tmptext;
+
+    if (*text == '~') {
+        tmptext = alloca(strlen(text)+1);
+        tmptext = strdup(text);
+
+       tmptext++; /* get rid of the ~ */
+
+        if (*tmptext == '!')
+            tmptext++; /* get rid of the ! if it exists */
+
+        tmptext++; /* get rid of the ext ban type */
+
+        if (*tmptext == ':') {
+            tmptext++; /* get rid of the : */
+            while (*tmptext && !isspace((char)*tmptext))
+                tmptext++;  /* get rid of the rest */
+            return !*tmptext;
+        }
+    }
+
     while (*text && (isalnum((char)*text) || strchr("-_[]|\\`^{}?*", *text)))
         text++;
     if (*text++ != '!')
@@ -469,6 +850,21 @@ is_gline(const char *text)
     return !*text;
 }
 
+int
+is_shun(const char *text)
+{
+    if (*text == '@')
+        return 0;
+    text += strcspn(text, "@!% \t\r\n");
+    if (*text++ != '@')
+        return 0;
+    if (!*text)
+        return 0;
+    while (*text && (isalnum((char)*text) || strchr(".-?*:", *text)))
+        text++;
+    return !*text;
+}
+
 int
 split_ircmask(char *text, char **nick, char **ident, char **host)
 {
@@ -611,12 +1007,14 @@ ParseInterval(const char *interval)
 
     /* process the string, resetting the count if we find a unit character */
     while ((c = *interval++)) {
-       if (isdigit((int)c)) {
-           partial = partial*10 + c - '0';
-       } else {
-           seconds += TypeLength(c) * partial;
-           partial = 0;
-       }
+        if (isdigit((int)c)) {
+            partial = partial*10 + c - '0';
+        } else if (strchr("yMwdhms", c)) {
+            seconds += TypeLength(c) * partial;
+            partial = 0;
+        } else {
+            return 0;
+        }
     }
     /* assume the last chunk is seconds (the normal case) */
     return seconds + partial;
@@ -650,74 +1048,6 @@ ParseVolume(const char *volume)
     return accum + partial;
 }
 
-int
-parse_ipmask(const char *str, struct in_addr *addr, unsigned long *mask)
-{
-    int accum, pos;
-    unsigned long t_a, t_m;
-
-    t_a = t_m = pos = 0;
-    if (addr)
-        addr->s_addr = htonl(t_a);
-    if (mask)
-        *mask = t_m;
-    while (*str) {
-        if (!isdigit(*str))
-            return 0;
-        accum = 0;
-        do {
-            accum = (accum * 10) + *str++ - '0';
-        } while (isdigit(*str));
-        if (accum > 255)
-            return 0;
-        t_a = (t_a << 8) | accum;
-        t_m = (t_m << 8) | 255;
-        pos += 8;
-        if (*str == '.') {
-            str++;
-            while (*str == '*') {
-                str++;
-                if (*str == '.') {
-                    t_a <<= 8;
-                    t_m <<= 8;
-                    pos += 8;
-                    str++;
-                } else if (*str == 0) {
-                    t_a <<= 32 - pos;
-                    t_m <<= 32 - pos;
-                    pos = 32;
-                    goto out;
-                } else
-                    return 0;
-            }
-        } else if (*str == '/') {
-            int start = pos;
-            accum = 0;
-            do {
-                accum = (accum * 10) + *str++ - '0';
-            } while (isdigit(*str));
-            while (pos < start+accum && pos < 32) {
-                t_a = (t_a << 1) | 0;
-                t_m = (t_m << 1) | 1;
-                pos++;
-            }
-            if (pos != start+accum)
-                return 0;
-        } else if (*str == 0)
-            break;
-        else
-            return 0;
-    }
-out:
-    if (pos != 32)
-        return 0;
-    if (addr)
-        addr->s_addr = htonl(t_a);
-    if (mask)
-        *mask = t_m;
-    return 1;
-}
-
 char *
 unsplit_string(char *set[], unsigned int max, char *dest)
 {
@@ -956,6 +1286,23 @@ char *mysep(char **sepstr, char *delim)
   return(retstr);
 }
 
+/* Mallocing snprintf *
+ *
+ * If it overruns size, it will simply be safely truncated.
+ */
+char *
+x3_msnprintf(const int size, const char *format, ...)
+{
+    va_list ap;
+    char* buff = calloc(sizeof(char *), size+1);
+
+    va_start(ap, format);
+    vsnprintf(buff, size, format, ap);
+    va_end(ap);
+    buff = realloc(buff, strlen(buff) + 1);
+    return buff;
+}
+
 char *time2str(time_t thetime)
 {
     char *buf, *tmp;
@@ -966,3 +1313,171 @@ char *time2str(time_t thetime)
     return(buf);
 }
 
+char* x3_strtok(char **save, char *str, char *fs)
+{
+  char *pos = *save;            /* keep last position across calls */
+  char *tmp;
+
+  if (str)
+    pos = str;                  /* new string scan */
+
+  while (pos && *pos && strchr(fs, *pos) != NULL)
+    pos++;                      /* skip leading separators */
+
+  if (!pos || !*pos)
+    return (pos = *save = NULL);        /* string contains only sep's */
+
+  tmp = pos;                    /* now, keep position of the token */
+
+  while (*pos && strchr(fs, *pos) == NULL)
+    pos++;                      /* skip content of the token */
+
+  if (*pos)
+    *pos++ = '\0';              /* remove first sep after the token */
+  else
+    pos = NULL;                 /* end of string */
+
+  *save = pos;
+  return (tmp);
+}
+
+int valid_email(const char *email)
+{
+    unsigned int i;
+    for (i=0;i<strlen(email);i++)
+    {
+        if(!isalnum(email[i]) &&
+               email[i] != '.' &&
+               email[i] != '@' &&
+               email[i] != '-' &&
+               email[i] != '+' &&
+               email[i] != '_' )
+            return false;
+    }
+    if(strchr(email, '@') == NULL)
+        return false;
+    return true;
+}
+
+/*
+ * Create a string of form "foo!bar@fubar" given foo, bar and fubar
+ * as the parameters.  If NULL, they become "*".
+ */
+#define NUH_BUFSIZE    (NICKLEN + USERLEN + HOSTLEN + 10)
+static char *make_nick_user_host(char *namebuf, const char *nick,
+                                const char *name, const char *host)
+{
+  snprintf(namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
+  return namebuf;
+}
+
+/*
+ * pretty_mask
+ *
+ * by Carlo Wood (Run), 05 Oct 1998.
+ *
+ * Canonify a mask.
+ *
+ * When the nick is longer then NICKLEN, it is cut off (its an error of course).
+ * When the user name or host name are too long (USERLEN and HOSTLEN
+ * respectively) then they are cut off at the start with a '*'.
+ *
+ * The following transformations are made:
+ *
+ * 1)   xxx             -> nick!*@*
+ * 2)   xxx.xxx         -> *!*@host
+ * 3)   xxx!yyy         -> nick!user@*
+ * 4)   xxx@yyy         -> *!user@host
+ * 5)   xxx!yyy@zzz     -> nick!user@host
+ */
+char *pretty_mask(char *mask)
+{
+  static char star[2] = { '*', 0 };
+  static char retmask[NUH_BUFSIZE] = "";
+  char *last_dot = NULL;
+  char *ptr = NULL;
+
+  /* Case 1: default */
+  char *nick = mask;
+  char *user = star;
+  char *host = star;
+
+  /* Do a _single_ pass through the characters of the mask: */
+  for (ptr = mask; *ptr; ++ptr)
+  {
+    if (*ptr == '!')
+    {
+      /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
+      user = ++ptr;
+      host = star;
+    }
+    else if (*ptr == '@')
+    {
+      /* Case 4: Found last '@' (without finding a '!' yet) */
+      nick = star;
+      user = mask;
+      host = ++ptr;
+    }
+    else if (*ptr == '.')
+    {
+      /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
+      last_dot = ptr;
+      continue;
+    }
+    else
+      continue;
+    for (; *ptr; ++ptr)
+    {
+      if (*ptr == '@')
+      {
+        /* Case 4 or 5: Found last '@' */
+        host = ptr + 1;
+      }
+    }
+    break;
+  }
+  if (user == star && last_dot)
+  {
+    /* Case 2: */
+    nick = star;
+    user = star;
+    host = mask;
+  }
+  /* Check lengths */
+  if (nick != star)
+  {
+    char *nick_end = (user != star) ? user - 1 : ptr;
+    if (nick_end - nick > NICKLEN)
+      nick[NICKLEN] = 0;
+    *nick_end = 0;
+  }
+  if (user != star)
+  {
+    char *user_end = (host != star) ? host - 1 : ptr;
+    if (user_end - user > USERLEN)
+    {
+      user = user_end - USERLEN;
+      *user = '*';
+    }
+    *user_end = 0;
+  }
+  if (host != star && ptr - host > HOSTLEN)
+  {
+    host = ptr - HOSTLEN;
+    *host = '*';
+  }
+  return make_nick_user_host(retmask, nick, user, host);
+}
+
+int str_is_number(const char *str)
+{
+    char *ptr;
+    int ret = false;
+    for(ptr = (char *)str;*ptr;ptr++) {
+        if((*ptr >= '0' && *ptr <= '9') || *ptr == '-')
+            ret = true;
+        else
+            return false;
+    }
+    return ret;
+}