]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/tools.c
Fixing small bug in x3.conf.example
[irc/evilnet/x3.git] / src / tools.c
index 85912a61c63caf9b554ec00eb3610686362b8a53..3ff571b04c37ac9bde386aaf701f3fd493f22cd2 100644 (file)
@@ -1,9 +1,9 @@
 /* tools.c - miscellaneous utility functions
  * Copyright 2000-2004 srvx Development Team
  *
- * This file is part of srvx.
+ * 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
  * (at your option) any later version.
@@ -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,6 +88,271 @@ 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) {
+        unsigned int 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)]
@@ -245,156 +520,81 @@ 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;
+        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)
 {
     char *glob, *marker;
-    char *setident = NULL, *sethostname = NULL; // sethost - reed/apples
 
     /* Make a writable copy of the glob */
     glob = alloca(strlen(orig_glob)+1);
     strcpy(glob, orig_glob);
     /* 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,28 +603,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;
+        return 1;
+
+    /* 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];
@@ -432,6 +625,14 @@ user_matches_glob_broken(struct userNode *user, const char *orig_glob, int inclu
         if (match_ircglob(hidden_host, 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);
 }
@@ -467,6 +668,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)
 {
@@ -586,7 +802,7 @@ TypeLength(char type)
 {
     switch (type) {
     case 'y': return 365*24*60*60;
-    case 'M': return 31*24*60*60;
+    case 'M': return 30*24*60*60;
     case 'w': return 7*24*60*60;
     case 'd': return 24*60*60;
     case 'h': return 60*60;
@@ -596,6 +812,10 @@ TypeLength(char type)
     }
 }
 
+/* This function is not entirely accurate as it does not take into account leap units
+ * or varying months. TODO: use proper dateadd functions to calculate real seconds
+ * from now for the units (eg 1M should be give us seconds till todays date next month)
+ */
 unsigned long
 ParseInterval(const char *interval)
 {
@@ -644,74 +864,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)
 {
@@ -765,13 +917,13 @@ intervalString(char *output, time_t interval, struct handle_info *hi)
 
         if (words++ == 1) {
             msg = language_find_message(lang, "MSG_AND");
-            pos += sprintf(output + pos, " %s ", msg);
+            pos += sprintf(output + pos, "%s ", msg);
         }
         if (count == 1)
             msg = language_find_message(lang, unit[type].msg_single);
         else
             msg = language_find_message(lang, unit[type].msg_plural);
-        pos += sprintf(output + pos, "%d %s", count, msg);
+        pos += sprintf(output + pos, "%d%s", count, msg);
     }
 
     output[pos] = 0;
@@ -933,7 +1085,7 @@ tools_cleanup(void)
  * multiple dilimiters, which can really
  * offset tokens and cause huge corruption
  * so this function will use strsep but
- * act like strtok in that sence.
+ * act like strtok in that sense.
  */
 char *mysep(char **sepstr, char *delim)
 {
@@ -960,3 +1112,49 @@ 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;
+}
+