X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/182dd032e9ea762dcd8df317ba21cb9e9130fa88..0f3e9cfc4b5d0f13085c975e10c0e6c4c8e5fbc3:/src/tools.c diff --git a/src/tools.c b/src/tools.c index 9a273d3..a46ed50 100644 --- a/src/tools.c +++ b/src/tools.c @@ -1,7 +1,7 @@ /* 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 * it under the terms of the GNU General Public License as published by @@ -245,70 +245,146 @@ 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; } } extern const char *hidden_host_suffix; +/* 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) +{ + return(match_ircglob("abcdefghijklmnopqrstuv!frcmbghilnrtoasde@apdic.yfa.dsfsdaffsdasfdasfd.abcdefghijklmnopqrstuvwxyz.asdfasfdfsdsfdasfda.ydfbe", mask)); +} + +int user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick) +{ + /* 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 */ +} + int -user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick) +user_matches_glob_broken(struct userNode *user, const char *orig_glob, int include_nick) { char *glob, *marker; char *setident = NULL, *sethostname = NULL; // sethost - reed/apples @@ -343,24 +419,24 @@ user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick if (!match_ircglob(user->ident, glob) && (IsSetHost(user) && !match_ircglob(setident, 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 (IsSetHost(user) && match_ircglob(sethostname, glob)) - return 1; - if (IsFakeHost(user) && match_ircglob(user->fakehost, glob)) - return 1; - 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; + if (IsSetHost(user) && match_ircglob(sethostname, 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 @@ -389,7 +465,22 @@ 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; +} + +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; } @@ -418,7 +509,7 @@ split_ircmask(char *text, char **nick, char **ident, char **host) *ident = start; start = ++text; - while (*text && (isalnum((char)*text) || strchr(".-?*", *text))) + while (*text && (isalnum((char)*text) || strchr(".-?*:", *text))) text++; if (host) *host = start; @@ -513,7 +604,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; @@ -523,6 +614,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) { @@ -692,13 +787,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; @@ -757,7 +852,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); @@ -854,3 +949,82 @@ tools_cleanup(void) free(str_tab.list[ii]); free(str_tab.list); } + +/* mysep() is my answer to the strtok/strsep + * issue. strsep is nice but doesn't skip + * multiple dilimiters, which can really + * offset tokens and cause huge corruption + * so this function will use strsep but + * act like strtok in that sense. + */ +char *mysep(char **sepstr, char *delim) +{ + static char *retstr; + + if(!*sepstr || !**sepstr) + return(NULL); + + do + { + retstr = strsep(sepstr, delim); + }while (retstr && !(*retstr)); + + return(retstr); +} + +char *time2str(time_t thetime) +{ + char *buf, *tmp; + + buf = ctime(&thetime); + tmp = (char *)strchr(buf, '\n'); + *tmp = '\0'; + 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