X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/2aef5f4b9017263e6890dc2f72969cc1dcc7b2b6..b6f98d33f1bc450e7d67f320fe59c29cc76be741:/src/tools.c diff --git a/src/tools.c b/src/tools.c index 296041b..afaed60 100644 --- a/src/tools.c +++ b/src/tools.c @@ -1,11 +1,11 @@ /* 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 + * 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,81 +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; +/* 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) +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; nchannels.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; nchannels.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; @@ -328,44 +755,74 @@ user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick } /* 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; - /* 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); + /* Check for a fakehost match. */ + if (IsFakeHost(user) && match_ircglob(user->fakehost, glob)) + 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]; + snprintf(hidden_host, sizeof(hidden_host), "%s.%s", user->handle_info->handle, hidden_host_suffix); + 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) || + user->crypthost || user->cryptip)) + 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); } 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++ != '!') @@ -389,7 +846,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 +890,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 +985,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 +995,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) { @@ -532,12 +1008,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; @@ -571,74 +1049,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) { @@ -692,13 +1102,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 +1167,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); @@ -860,7 +1270,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) { @@ -877,3 +1287,198 @@ 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; + + 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 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; +}