Make match_ircglob() work more like the ircd.
[srvx.git] / src / tools.c
index 4b852615c8bef349086e2c852e4cc557cdba5997..934c04372297ae56233e673ac4ac055bacd522dc 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
 
+#include "helpfile.h"
 #include "log.h"
 #include "nickserv.h"
 #include "recdb.h"
@@ -115,7 +116,8 @@ split_line(char *line, int irc_colon, int argv_size, char *argv[])
     int argc = 0;
     int n;
     while (*line && (argc < argv_size)) {
-       while (*line == ' ') *line++ = 0;
+       while (*line == ' ')
+            *line++ = 0;
        if (*line == ':' && irc_colon && argc > 0) {
            /* the rest is a single parameter */
            argv[argc++] = line + 1;
@@ -126,14 +128,14 @@ split_line(char *line, int irc_colon, int argv_size, char *argv[])
        argv[argc++] = line;
        if (argc >= argv_size)
             break;
-       while (*line != ' ' && *line) line++;
+       while (*line != ' ' && *line)
+            line++;
     }
 #ifdef NDEBUG
     n = 0;
 #else
-    for (n=argc; n<argv_size; n++) {
+    for (n=argc; n<argv_size; n++)
         argv[n] = (char*)0xFEEDBEEF;
-    }
 #endif
     return argc;
 }
@@ -243,63 +245,57 @@ 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++)
+            return 0;
+        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;
     }
 }
 
@@ -332,20 +328,22 @@ user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick
     if (!match_ircglob(user->ident, glob))
         return 0;
     glob = marker + 1;
-    /* Now check the host part */
-    if (isdigit(*glob) && !glob[strspn(glob, "0123456789./*?")]) {
-        /* Looks like an IP-based mask */
-        return match_ircglob(inet_ntoa(user->ip), glob);
-    } else {
-        /* The host part of the mask isn't IP-based */
-        if (hidden_host_suffix && user->handle_info) {
-            char hidden_host[HOSTLEN+1];
-            snprintf(hidden_host, sizeof(hidden_host), "%s.%s", user->handle_info->handle, hidden_host_suffix);
-            if (match_ircglob(hidden_host, glob))
-                return 1;
-        }
-        return match_ircglob(user->hostname, glob);
-    }
+    /* 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;
+    /* Check for an account match. */
+    if (hidden_host_suffix && user->handle_info) {
+        char hidden_host[HOSTLEN+1];
+        snprintf(hidden_host, sizeof(hidden_host), "%s.%s", user->handle_info->handle, hidden_host_suffix);
+        if (match_ircglob(hidden_host, glob))
+            return 1;
+    }
+    /* None of the above; could only be a hostname match. */
+    return match_ircglob(user->hostname, glob);
 }
 
 int
@@ -374,7 +372,7 @@ is_gline(const char *text)
         return 0;
     if (!*text)
         return 0;
-    while (*text && (isalnum((char)*text) || strchr(".-?*", *text)))
+    while (*text && (isalnum((char)*text) || strchr(".-?*:", *text)))
         text++;
     return !*text;
 }
@@ -401,9 +399,9 @@ split_ircmask(char *text, char **nick, char **ident, char **host)
     *text = 0;
     if (ident)
         *ident = start;
-    
+
     start = ++text;
-    while (*text && (isalnum((char)*text) || strchr(".-?*", *text)))
+    while (*text && (isalnum((char)*text) || strchr(".-?*:", *text)))
         text++;
     if (host)
         *host = start;
@@ -642,25 +640,29 @@ unsplit_string(char *set[], unsigned int max, char *dest)
 }
 
 char *
-intervalString2(char *output, time_t interval, int brief)
+intervalString(char *output, time_t interval, struct handle_info *hi)
 {
     static const struct {
-        const char *name;
+        const char *msg_single;
+        const char *msg_plural;
         long length;
     } unit[] = {
-        { "year", 365 * 24 * 60 * 60 },
-        { "week",   7 * 24 * 60 * 60 },
-        { "day",        24 * 60 * 60 },
-        { "hour",            60 * 60 },
-        { "minute",               60 },
-        { "second",                1 }
+        { "MSG_YEAR",   "MSG_YEARS", 365 * 24 * 60 * 60 },
+        { "MSG_WEEK",   "MSG_WEEKS",   7 * 24 * 60 * 60 },
+        { "MSG_DAY",    "MSG_DAYS",        24 * 60 * 60 },
+        { "MSG_HOUR",   "MSG_HOURS",            60 * 60 },
+        { "MSG_MINUTE", "MSG_MINUTES",               60 },
+        { "MSG_SECOND", "MSG_SECONDS",                1 }
     };
+    struct language *lang;
+    const char *msg;
     unsigned int type, words, pos, count;
 
+    lang = hi ? hi->language : lang_C;
     if(!interval)
     {
-       strcpy(output, brief ? "0s" : "0 seconds");
-       return output;
+        msg = language_find_message(lang, "MSG_0_SECONDS");
+       return strcpy(output, msg);
     }
 
     for (type = 0, words = pos = 0;
@@ -671,15 +673,15 @@ intervalString2(char *output, time_t interval, int brief)
         count = interval / unit[type].length;
         interval = interval % unit[type].length;
 
-        if (brief)
-            pos += sprintf(output + pos, "%d%c", count, unit[type].name[0]);
-        else if (words == 1)
-            pos += sprintf(output + pos, " and %d %s", count, unit[type].name);
+        if (words++ == 1) {
+            msg = language_find_message(lang, "MSG_AND");
+            pos += sprintf(output + pos, " %s ", msg);
+        }
+        if (count == 1)
+            msg = language_find_message(lang, unit[type].msg_single);
         else
-            pos += sprintf(output + pos, "%d %s", count, unit[type].name);
-        if (count != 1)
-            output[pos++] = 's';
-        words++;
+            msg = language_find_message(lang, unit[type].msg_plural);
+        pos += sprintf(output + pos, "%d %s", count, msg);
     }
 
     output[pos] = 0;
@@ -738,7 +740,7 @@ string_buffer_append_vprintf(struct string_buffer *buf, const char *fmt, va_list
         /* pre-C99 behavior; double buffer size until it is big enough */
         va_end(working);
         VA_COPY(working, args);
-        while ((ret = vsnprintf(buf->list + buf->used, buf->size, fmt, working)) == -1) {
+        while ((ret = vsnprintf(buf->list + buf->used, buf->size - buf->used, fmt, working)) <= 0) {
             buf->size += len;
             buf->list = realloc(buf->list, buf->size);
             va_end(working);