/* tools.c - miscellaneous utility functions
* Copyright 2000-2004 srvx Development Team
*
- * This program is free software; you can redistribute it and/or modify
+ * This file is part of srvx.
+ *
+ * srvx 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. Important limitations are
- * listed in the COPYING file that accompanies this software.
+ * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, email srvx-maintainers@srvx.net.
+ * along with srvx; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
+#include "helpfile.h"
#include "log.h"
#include "nickserv.h"
#include "recdb.h"
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)
{
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)]
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;
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;
}
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;
}
}
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(irc_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
return 0;
if (!*text)
return 0;
- while (*text && (isalnum((char)*text) || strchr(".-?*", *text)))
+ while (*text && (isalnum((char)*text) || strchr(".-?*:", *text)))
text++;
return !*text;
}
*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;
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)
{
}
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;
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;
/* 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);