/[svn]/vendor/ircservices-5.1.24/misc.c
ViewVC logotype

Annotation of /vendor/ircservices-5.1.24/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3389 - (hide annotations)
Fri Apr 25 14:12:15 2014 UTC (6 years, 3 months ago) by michael
File MIME type: text/x-chdr
File size: 36080 byte(s)
- Imported ircservices-5.1.24

1 michael 3389 /* Miscellaneous routines.
2     *
3     * IRC Services is copyright (c) 1996-2009 Andrew Church.
4     * E-mail: <achurch@achurch.org>
5     * Parts written by Andrew Kempe and others.
6     * This program is free but copyrighted software; see the file GPL.txt for
7     * details.
8     */
9    
10     #include "services.h"
11    
12     #ifdef CONVERT_DB
13     # undef log
14     # define log(...) fprintf(stderr, __VA_ARGS__)
15     #endif
16    
17     /*************************************************************************/
18    
19     /* Table used by irc_tolower(). This table follows the RFC 1459
20     * requirement that [ \ ] and { | } be considered equivalent. Protocols
21     * which do not follow this requirement should modify the table
22     * accordingly.
23     */
24    
25     unsigned char irc_lowertable[256] = {
26     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
27     0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
28     0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
29     0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
30     0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
31     0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
32     0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
33     0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
34    
35     0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
36     0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
37     0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
38     0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x5E,0x5F,
39     0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
40     0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
41     0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
42     0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
43    
44     0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
45     0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
46     0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
47     0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
48     0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
49     0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
50     0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
51     0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
52    
53     0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
54     0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
55     0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
56     0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
57     0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
58     0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
59     0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
60     0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
61     };
62    
63    
64     /*************************************************************************/
65    
66     /* irc_tolower: Like toupper/tolower, but for nicknames and channel names;
67     * the RFC requires that '[' and '{', '\' and '|', ']' and '}'
68     * be pairwise equivalent in such names. Declared inline for
69     * irc_str[n]icmp()'s benefit.
70     */
71    
72     #undef irc_tolower
73     inline unsigned char irc_tolower(char c)
74     {
75     return irc_lowertable[(uint8)c];
76     }
77    
78     /*************************************************************************/
79    
80     /* irc_str[n]icmp: Like str[n]icmp, but for nicknames and channel names. */
81    
82     int irc_stricmp(const char *s1, const char *s2)
83     {
84     register char c1, c2;
85    
86     while ((c1 = (char)irc_tolower(*s1)) == (c2 = (char)irc_tolower(*s2))) {
87     if (c1 == 0)
88     return 0;
89     s1++;
90     s2++;
91     }
92     return c1<c2 ? -1 : 1;
93     }
94    
95     int irc_strnicmp(const char *s1, const char *s2, int max)
96     {
97     register char c1, c2;
98    
99     if (max <= 0)
100     return 0;
101     while ((c1 = (char)irc_tolower(*s1)) == (c2 = (char)irc_tolower(*s2))) {
102     if (c1 == 0 || --max <= 0)
103     return 0;
104     s1++;
105     s2++;
106     }
107     return c1<c2 ? -1 : 1;
108     }
109    
110     /*************************************************************************/
111    
112     /* strscpy: Copy at most len-1 characters from a string to a buffer, and
113     * add a null terminator after the last character copied.
114     * The `strbcpy(d,s)' variant (defined as a macro in extern.h)
115     * assumes `d' is a character array and uses sizeof(d) as the
116     * `len' parameter.
117     */
118    
119     char *strscpy(char *d, const char *s, size_t len)
120     {
121     char *d_orig = d;
122    
123     if (!len)
124     return d;
125     while (--len && (*d++ = *s++))
126     ;
127     *d = 0;
128     return d_orig;
129     }
130    
131     /*************************************************************************/
132    
133     /* strmove: Like strcpy(), but handles overlapping regions of memory
134     * properly. The str*() analog of memmove().
135     */
136    
137     char *strmove(char *d, const char *s)
138     {
139     memmove(d, s, strlen(s)+1);
140     return d;
141     }
142    
143     /*************************************************************************/
144    
145     /* stristr: Search case-insensitively for string s2 within string s1,
146     * returning the first occurrence of s2 or NULL if s2 was not
147     * found.
148     */
149    
150     char *stristr(const char *s1, const char *s2)
151     {
152     register const char *s = s1, *d = s2;
153    
154     while (*s1) {
155     if (tolower(*s1) == tolower(*d)) {
156     s1++;
157     d++;
158     if (*d == 0)
159     return (char *)s;
160     } else {
161     s = ++s1;
162     d = s2;
163     }
164     }
165     return NULL;
166     }
167    
168     /*************************************************************************/
169    
170     /* strupper, strlower: Convert a string to upper or lower case.
171     */
172    
173     char *strupper(char *s)
174     {
175     char *t = s;
176     while (*t) {
177     *t = toupper(*t);
178     t++;
179     }
180     return s;
181     }
182    
183     char *strlower(char *s)
184     {
185     char *t = s;
186     while (*t) {
187     *t = tolower(*t);
188     t++;
189     }
190     return s;
191     }
192    
193     /*************************************************************************/
194    
195     /* strnrepl: Replace occurrences of `old' with `new' in string `s'. Stop
196     * replacing if a replacement would cause the string to exceed
197     * `size' bytes (including the null terminator). Return the
198     * string.
199     */
200    
201     char *strnrepl(char *s, int32 size, const char *old, const char *new)
202     {
203     char *ptr = s;
204     int32 left = strlen(s);
205     int32 avail = size - (left+1);
206     int32 oldlen = strlen(old);
207     int32 newlen = strlen(new);
208     int32 diff = newlen - oldlen;
209    
210     if (avail < 0) /* silly parameter */
211     avail = 0;
212     while (left >= oldlen) {
213     if (strncmp(ptr, old, oldlen) != 0) {
214     left--;
215     ptr++;
216     continue;
217     }
218     if (diff > avail)
219     break;
220     if (diff != 0)
221     memmove(ptr+oldlen+diff, ptr+oldlen, left+1);
222     strncpy(ptr, new, newlen);
223     ptr += newlen;
224     left -= oldlen;
225     }
226     return s;
227     }
228    
229     /*************************************************************************/
230    
231     /* strtok_remaining: Return the result of strtok(NULL, "") with any
232     * leading or trailing whitespace discarded. If nothing
233     * but whitespace is left, return NULL.
234     */
235    
236     char *strtok_remaining(void)
237     {
238     char *s = strtok(NULL, ""), *t;
239     if (s) {
240     while (isspace(*s))
241     s++;
242     t = s + strlen(s)-1;
243     while (t >= s && isspace(*t))
244     *t-- = 0;
245     if (!*s)
246     return NULL;
247     }
248     return s;
249     }
250    
251     /*************************************************************************/
252     /*************************************************************************/
253    
254     /* merge_args: Take an argument count and argument vector and merge them
255     * into a single string in which each argument is separated by
256     * a space. The returned string is stored in a static buffer
257     * which will be overwritten on the next call.
258     */
259    
260     char *merge_args(int argc, char **argv)
261     {
262     int i;
263     static char s[4096];
264     char *t;
265    
266     t = s;
267     for (i = 0; i < argc; i++) {
268     t += snprintf(t, sizeof(s)-(t-s), "%s%s", *argv++,
269     (i<argc-1) ? " " : "");
270     }
271     return s;
272     }
273    
274     /*************************************************************************/
275     /*************************************************************************/
276    
277     /* match_wild: Attempt to match a string to a pattern which might contain
278     * '*' or '?' wildcards. Return 1 if the string matches the
279     * pattern, 0 if not.
280     */
281    
282     static int do_match_wild(const char *pattern, const char *str, int docase)
283     {
284     char c;
285     const char *s;
286    
287     /* Sanity-check pointer parameters */
288    
289     if (pattern == NULL) {
290     log("BUG or corrupted database: pattern == NULL in do_match_wild())");
291     return 0;
292     }
293     if (str == NULL) {
294     log("BUG or corrupted database: str == NULL in do_match_wild())");
295     return 0;
296     }
297    
298     /* This loop is guaranteed to terminate, either by *pattern == 0 (the
299     * end of the pattern string) or a trailing '*' (or "*???..."). */
300    
301     for (;;) {
302     switch (c = *pattern++) {
303     case 0:
304     if (!*str)
305     return 1;
306     return 0;
307     case '?':
308     if (!*str)
309     return 0;
310     str++;
311     break;
312     case '*':
313     while (*pattern == '?') {
314     if (!*str)
315     return 0;
316     str++; /* skip a character for each '?' */
317     pattern++;
318     }
319     if (!*pattern)
320     return 1; /* trailing '*' matches everything else */
321     s = str;
322     while (*s) {
323     if ((docase ? (*s==*pattern) : (tolower(*s)==tolower(*pattern)))
324     && do_match_wild(pattern+1, s+1, docase))
325     return 1;
326     s++;
327     }
328     break;
329     default:
330     if (docase ? (*str != c) : (tolower(*str) != tolower(c)))
331     return 0;
332     str++;
333     break;
334     } /* switch */
335     }
336     /* not reached */
337     }
338    
339    
340     int match_wild(const char *pattern, const char *str)
341     {
342     return do_match_wild(pattern, str, 1);
343     }
344    
345     int match_wild_nocase(const char *pattern, const char *str)
346     {
347     return do_match_wild(pattern, str, 0);
348     }
349    
350     /*************************************************************************/
351     /*************************************************************************/
352    
353     /* Tables used by valid_nick() and valid_chan(). These tables follow the
354     * RFC 1459 definitions; protocols with different definitions should modify
355     * the table accordingly:
356     * Bit 0 (0x01) = valid as a first character
357     * Bit 1 (0x02) = valid as a subsequent character
358     * Bit 2 (0x04) = valid as byte 1 of a 2-byte character
359     * Bit 3 (0x08) = valid as byte 2 of a 2-byte character
360     * valid_{nick,chan}_table[0] should never be modified.
361     *
362     * 2-byte characters are handled by setting bits 2 and 3 on the appropriate
363     * single-byte entries (0x80-0xFF), then setting bits 0 and/or 1 on 2-byte
364     * entries (0x0100-0xFFFF) as needed, where the first byte of the character
365     * is the upper 8 bits of the array index and the second byte is the lower
366     * 8 bits.
367     *
368     * Note: The grammar for nicknames in RFC 1459 excludes '|', but this
369     * contradicts an earlier statement that '|' and '\' are to be considered
370     * equivalent when comparing nicknames. On the other hand, the reference
371     * server code (at least as far back as version 2.6.2, September 1991)
372     * allows anything from 'A' to '}', and allows all specials other than '-'
373     * at the beginning of a nick as well. We consider the RFC to be in error
374     * and go by the reference implementation.
375     */
376    
377     unsigned char valid_nick_table[0x10000] = {
378     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,
379     0,0,0,0,0,0,0,0, 0,0,0,0,0,2,0,0, 2,2,2,2,2,2,2,2, 2,2,0,0,0,0,0,0,
380     0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,
381     3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,0,
382     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,
383     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,
384     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,
385     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,
386     };
387    
388     unsigned char valid_chan_table[0x10000] = {
389     0,2,2,2,2,2,2,0, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
390     0,2,2,3,2,2,3,2, 2,2,2,2,0,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
391     2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
392     2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
393     2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
394     2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
395     2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
396     2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
397     };
398    
399     /*************************************************************************/
400    
401     /* valid_nick, valid_chan: Check whether the given string is a valid
402     * nickname or channel name, ignoring length.
403     * Returns nonzero if valid, zero if not.
404     */
405    
406     static int valid_nickchan(const char *str, const unsigned char *table)
407     {
408     int first = 1; /* First character? */
409     int mbsave = 0; /* First byte of a 2-byte character */
410    
411     while (*str) {
412     int ch = *(const unsigned char *)str++;
413     if (mbsave) {
414     if (!(table[ch] & 8))
415     return 0;
416     ch |= mbsave<<8;
417     mbsave = 0;
418     } else if (table[ch] & 4) {
419     mbsave = ch;
420     continue;
421     }
422     if (!(table[ch] & (first ? 1 : 2)))
423     return 0;
424     first = 0;
425     }
426     return 1;
427     }
428    
429     int valid_nick(const char *str) {return valid_nickchan(str, valid_nick_table);}
430     int valid_chan(const char *str) {return valid_nickchan(str, valid_chan_table);}
431    
432     /*************************************************************************/
433    
434     /* Check whether the given string is a valid domain name, according to RFC
435     * rules:
436     * - Contains only letters, digits, hyphens, and periods (dots).
437     * - Begins with a letter or digit.
438     * - Has a letter or digit after every dot (except for a trailing dot).
439     * - Is no more than DOMAIN_MAXLEN characters long.
440     * - Has no more than DOMPART_MAXLEN characters between periods.
441     * - Has at least one character and does not end with a dot. (not RFC)
442     */
443    
444     #define DOMAIN_MAXLEN 255
445     #define DOMPART_MAXLEN 63
446    
447     int valid_domain(const char *str)
448     {
449     const char *s;
450     int i;
451     static const char valid_domain_chars[] =
452     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.";
453    
454     if (!*str)
455     return 0;
456     if (str[strspn(str,valid_domain_chars)] != 0)
457     return 0;
458     s = str;
459     while (s-str < DOMAIN_MAXLEN && *s) {
460     if (*s == '-' || *s == '.')
461     return 0;
462     i = strcspn(s, ".");
463     if (i > DOMPART_MAXLEN)
464     return 0;
465     s += i;
466     if (*s)
467     s++;
468     }
469     if (s-str > DOMAIN_MAXLEN || *s)
470     return 0;
471     if (s[-1] == '.')
472     return 0;
473     return 1;
474     }
475    
476     /*************************************************************************/
477    
478     /* Check whether the given string is a valid E-mail address. A valid
479     * E-mail address:
480     * - Contains none of the following characters:
481     * + control characters (\000-\037)
482     * + space (\040)
483     * + vertical bar ('|') (because some mailers try to pipe with it)
484     * + RFC-822 specials, except [ ] @ .
485     * - Contains exactly one '@', which may not be the first character.
486     * - Contains a valid domain name or an IP address in square brackets
487     * after the '@'.
488     * - Does not contain [ or ] except when used with an IP address as above.
489     */
490    
491     int valid_email(const char *str)
492     {
493     const unsigned char *s;
494     const char *atmark;
495    
496     for (s = (const unsigned char *)str; *s; s++) {
497     if (*s <= '\040') // 040 == 0x20 == ' '
498     return 0;
499     if (strchr("|,:;\\\"()<>", *s))
500     return 0;
501     }
502    
503     /* Find the @, and abort if there isn't one */
504     atmark = strchr(str, '@');
505     if (!atmark || atmark == str)
506     return 0;
507     atmark++;
508    
509     /* Don't allow [] in username */
510     s = (const unsigned char *)strpbrk(str, "[]");
511     if (s && (const char *)s < atmark)
512     return 0;
513    
514     /* Check for a [1.2.3.4] type of domain */
515     if (*atmark == '[') {
516     unsigned char ipstr[16];
517     const char *bracket = strchr(atmark+1, ']');
518     int len = bracket - (atmark+1);
519     /* Valid IP addresses have no more than 15 characters */
520     if (len <= 15 && !bracket[1]) {
521     strncpy((char *)ipstr, atmark+1, len);
522     ipstr[len] = 0;
523     /* Use pack_ip() to see if it's a valid address */
524     if (pack_ip((const char *)ipstr))
525     return 1;
526     }
527     }
528    
529     /* Don't allow [] in domains except for the above case */
530     if (strpbrk(atmark, "[]"))
531     return 0;
532    
533     /* Valid domain names cannot contain '@' so we just check valid_domain().
534     * Also prohibit domains without dots. */
535     return strchr(atmark, '.') && valid_domain(atmark);
536     }
537    
538     /*************************************************************************/
539    
540     /* Check whether the given string is a valid URL. A valid URL:
541     * - Contains neither control characters (\000-\037) nor spaces (\040).
542     * - Contains a series of letters followed by "://" followed by a valid
543     * domain name, possibly followed by a : and a numeric port number in
544     * the range 1-65535, followed either by a slash and possibly more text
545     * or by nothing.
546     */
547    
548     int valid_url(const char *str)
549     {
550     const unsigned char *s, *colon, *host;
551     static const char letters[] =
552     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
553     char domainbuf[DOMAIN_MAXLEN+1];
554    
555     for (s = (const unsigned char *)str; *s; s++) {
556     if (*s <= '\040') // 040 == 0x20 == ' '
557     return 0;
558     }
559     s = (const unsigned char *)strstr(str, "://");
560     if (!s)
561     return 0; /* No "://" */
562     if (strspn(str, letters) != s - (const unsigned char *)str)
563     return 0; /* Protocol has non-alphabetic characters */
564     host = s+3;
565     colon = (const unsigned char *)strchr((const char *)host, ':');
566     /* s will eventually point to the expected end of the host string */
567     s = host + strcspn((const char *)host, "/");
568     /* Make sure the port is valid if present. */
569     if (colon && colon < s) {
570     int port = (int)atolsafe((const char *)colon+1, 1, 65535);
571     if (port < 1)
572     return 0; /* Invalid port number or non-numeric characters */
573     s = colon;
574     }
575     /* The string from host through s-1 must be a valid domain name.
576     * Check length (must be >=1, <=DOMAIN_MAXLEN), then copy into
577     * temporary buffer and check. Also discard domain names without
578     * dots in them. */
579     if (s-host < 1 || s-host > DOMAIN_MAXLEN)
580     return 0;
581     memcpy(domainbuf, host, s-host);
582     domainbuf[s-host] = 0;
583     return strchr(domainbuf, '.') && valid_domain(domainbuf);
584     }
585    
586     /*************************************************************************/
587    
588     /* Check whether the given E-mail address is rejected by a RejectEmail
589     * configuration directive.
590     */
591    
592     int rejected_email(const char *email)
593     {
594     int i;
595    
596     if (!email) {
597     return 0;
598     }
599     ARRAY_FOREACH (i, RejectEmail) {
600     if (match_wild_nocase(RejectEmail[i], email)) {
601     return 1;
602     }
603     }
604     return 0;
605     }
606    
607     /*************************************************************************/
608     /*************************************************************************/
609    
610     /* time_msec: Return the current time to millisecond resolution. */
611    
612     uint32 time_msec(void)
613     {
614     #if HAVE_GETTIMEOFDAY
615     struct timeval tv;
616     gettimeofday(&tv, NULL);
617     return tv.tv_sec*1000 + tv.tv_usec/1000;
618     #else
619     return time(NULL) * 1000;
620     #endif
621     }
622    
623     /*************************************************************************/
624    
625     /* strtotime: Convert a string into a time_t. Essentially the same as
626     * strtol(), but assumes base 10 and returns a time_t.
627     */
628    
629     time_t strtotime(const char *str, char **endptr)
630     {
631     time_t t = 0;
632    
633     while (*str >= '0' && *str <= '9') {
634     if (t > MAX_TIME_T/10 || MAX_TIME_T - t*10 < *str-'0') {
635     t = MAX_TIME_T;
636     errno = ERANGE;
637     } else {
638     t = t*10 + *str-'0';
639     }
640     str++;
641     }
642     if (endptr)
643     *endptr = (char *)str;
644     return t;
645     }
646    
647     /*************************************************************************/
648    
649     /* dotime: Return the number of seconds corresponding to the given time
650     * string. If the given string does not represent a valid time,
651     * return -1.
652     *
653     * A time string is either a plain integer (representing a number
654     * of seconds), an integer followed by one of these characters:
655     * "s" (seconds), "m" (minutes), "h" (hours), or "d" (days), or a
656     * sequence of such integer-character pairs (without separators,
657     * e.g. "1h30m").
658     */
659    
660     int dotime(const char *s)
661     {
662     int amount;
663    
664     amount = strtol(s, (char **)&s, 10);
665     if (*s) {
666     char c = *s++;
667     int rest = dotime(s);
668     if (rest < 0)
669     return -1;
670     switch (c) {
671     case 's': return rest + amount;
672     case 'm': return rest + amount*60;
673     case 'h': return rest + amount*3600;
674     case 'd': return rest + amount*86400;
675     default : return -1;
676     }
677     } else {
678     return amount;
679     }
680     }
681    
682     /*************************************************************************/
683     /*************************************************************************/
684    
685     /* Translate an IPv4 dotted-quad address into binary (4 bytes). Returns
686     * NULL if the given string is not in dotted-quad format or `ipaddr' is
687     * NULL. The returned buffer is static and will be overwritten on
688     * subsequent calls.
689     */
690    
691     uint8 *pack_ip(const char *ipaddr)
692     {
693     static uint8 ipbuf[4];
694     const char *s, *s2;
695     int i;
696     long tmp;
697    
698     if (!ipaddr)
699     return NULL;
700     s = ipaddr;
701     for (i = 0; i < 4; i++) {
702     if (i > 0 && *s++ != '.')
703     return NULL;
704     if (isspace(*s)) /* because strtol() will skip whitespace */
705     return NULL;
706     tmp = strtol(s, (char **)&s2, 10);
707     if (s2 == s || tmp < 0 || tmp > 255)
708     return NULL;
709     ipbuf[i] = (uint8)tmp;
710     s = s2;
711     }
712     if (*s)
713     return NULL;
714     return ipbuf;
715     }
716    
717     /*************************************************************************/
718    
719     /* Translate a 4-byte binary IPv4 to its dotted-quad (ASCII) representation.
720     * Always succeeds and always returns a null-terminated string <= 15
721     * characters in length, unless `ip' is NULL, in which case the function
722     * returns NULL. The returned buffer is static and will be overwritten on
723     * subsequent calls.
724     */
725    
726     char *unpack_ip(const uint8 *ip)
727     {
728     static char ipbuf[16];
729    
730     if (!ip)
731     return NULL;
732     snprintf(ipbuf, sizeof(ipbuf), "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
733     return ipbuf;
734     }
735    
736     /*************************************************************************/
737    
738     /* Translate an IPv6 ASCII address into binary (16 bytes). Return NULL if
739     * the given string is not in IPv6 format or `ipaddr' is NULL. The
740     * returned buffer is static and will be overwritten on subsequent calls.
741     */
742    
743     uint8 *pack_ip6(const char *ipaddr)
744     {
745     static uint8 ipbuf[16];
746     int words[8];
747     int wordnum;
748     const char *s, *t;
749     int i;
750    
751     if (!ipaddr)
752     return NULL;
753    
754     /* Parse the address into 16-bit words */
755     s = ipaddr;
756     wordnum = 0;
757     if (*s == ':') {
758     words[wordnum++] = 0;
759     s++;
760     }
761     while (*s) {
762     if (wordnum >= 8) {
763     /* too many words, abort */
764     return NULL;
765     }
766     if (*s == ':') {
767     /* mark "::" with a -1 */
768     words[wordnum++] = -1;
769     s++;
770     } else {
771     words[wordnum++] = (int)strtol(s, (char **)&t, 16);
772     if (*t && *t != ':') {
773     /* invalid syntax */
774     return NULL;
775     }
776     if (*t) {
777     t++; /* skip past delimiter */
778     if (!*t) {
779     /* trailing ":", convert to :0000 */
780     if (wordnum >= 8)
781     return NULL;
782     words[wordnum++] = 0;
783     }
784     }
785     s = t;
786     }
787     }
788    
789     /* Expand "::" into as many zeros as needed, and make sure there
790     * aren't multiple occurrences of "::" */
791     for (i = 0; i < wordnum; i++) {
792     if (words[i] == -1)
793     break;
794     }
795     if (i < wordnum) { /* found a "::" */
796     int j, offset;
797     for (j = i+1; j < wordnum; j++) {
798     if (words[j] == -1) {
799     /* multiple "::" */
800     return NULL;
801     }
802     }
803     offset = 8-wordnum;
804     for (j = 7; j >= i; j--) {
805     if (j-offset > i)
806     words[j] = words[j-offset];
807     else
808     words[j] = 0;
809     }
810     wordnum = 8;
811     }
812    
813     /* Make sure we have exactly 8 words */
814     if (wordnum != 8)
815     return NULL;
816    
817     /* Convert to binary and return */
818     for (i = 0; i < 8; i++) {
819     ipbuf[i*2 ] = words[i] >> 8;
820     ipbuf[i*2+1] = words[i] & 255;
821     }
822     return ipbuf;
823     }
824    
825     /*************************************************************************/
826    
827     /* Translate a 16-byte binary IPv6 address to its ASCII representation.
828     * Always succeeds and always returns a null-terminated string <= 39
829     * characters in length, unless `ip' is NULL, in which case the function
830     * returns NULL. The returned buffer is static and will be overwritten on
831     * subsequent calls.
832     *
833     * The address string returned by this function will always use 4-digit
834     * hexadecimal numbers for each word in the address, but will omit all-zero
835     * words when possible.
836     */
837    
838     char *unpack_ip6(const uint8 *ip)
839     {
840     static char ipbuf[40];
841     char *out, *s;
842     int i;
843    
844     if (!ip)
845     return NULL;
846    
847     out = ipbuf;
848     for (i = 0; i < 8; i++) {
849     /* Skip 0000 at beginning or end */
850     if ((i != 0 && i != 7) || ip[i*2] || ip[i*2+1]) {
851     out += snprintf(out, sizeof(ipbuf)-(out-ipbuf), "%02X%02X",
852     ip[i*2], ip[i*2+1]);
853     }
854     if (i != 7)
855     *out++ = ':';
856     }
857     if ((s = strstr(ipbuf,":0000:")) != NULL) {
858     /* Compress zeros */
859     memmove(s+1, s+5, strlen(s+5)+1);
860     s++;
861     while (strncmp(s,":0000:",6) == 0)
862     memmove(s, s+5, strlen(s+5)+1);
863     }
864     return ipbuf;
865     }
866    
867     /*************************************************************************/
868     /*************************************************************************/
869    
870     /* Encode buffer `in' of size `insize' to buffer `out' of size `outsize'
871     * using base64, appending a trailing null. Returns the number of bytes
872     * required by the encoded string. (The amount of space needed to store
873     * the encoded string can be found with encode_base64(...,NULL,0).)
874     * Returns -1 if the input or output buffer is NULL (except when the
875     * corresponding size is zero) or if the input or output size is negative.
876     * If `out' is too small to hold the entire encoded string, it will contain
877     * the first `outsize'-1 bytes of the encoded string followed by a null.
878     */
879    
880     static const char base64_chars[] =
881     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
882    
883     int encode_base64(const void *in, int insize, char *out, int outsize)
884     {
885     int required = ((insize+2)/3*4)+1;
886     const uint8 *inp = in;
887     int inpos, outpos;
888    
889     if (insize < 0 || outsize < 0)
890     return -1;
891     if (outsize == 0)
892     return required;
893     if (!out)
894     return -1;
895     if (insize == 0) {
896     /* outsize is at least 1 */
897     *out = 0;
898     return 1;
899     }
900     if (!in)
901     return -1;
902    
903     outsize--; /* leave room for trailing \0 */
904    
905     /* Actually do the encoding */
906     outpos = 0;
907     for (inpos = 0; inpos < insize; inpos += 3) {
908     uint8 i0, i1, i2;
909     char o0, o1, o2, o3;
910     i0 = inp[inpos];
911     o0 = base64_chars[i0>>2];
912     if (inpos+1 < insize) {
913     i1 = inp[inpos+1];
914     o1 = base64_chars[(i0&3)<<4 | i1>>4];
915     if (inpos+2 < insize) {
916     i2 = inp[inpos+2];
917     o2 = base64_chars[(i1&15)<<2 | i2>>6];
918     o3 = base64_chars[i2&63];
919     } else {
920     o2 = base64_chars[(i1&15)<<2];
921     o3 = '=';
922     }
923     } else {
924     o1 = base64_chars[(i0&3)<<4];
925     o2 = '=';
926     o3 = '=';
927     }
928     if (outpos < outsize)
929     out[outpos++] = o0;
930     if (outpos < outsize)
931     out[outpos++] = o1;
932     if (outpos < outsize)
933     out[outpos++] = o2;
934     if (outpos < outsize)
935     out[outpos++] = o3;
936     }
937    
938     /* Terminate the string and return; outpos is constrained above to
939     * still be within the buffer (remember that outsize was decremented
940     * before the loop) */
941     out[outpos] = 0;
942     return required;
943     }
944    
945     /*************************************************************************/
946    
947     /* Decode base64-encoded string `in' (null-terminated) to buffer `out' of
948     * size `outsize'. Returns the number of bytes required by the decoded
949     * data. (The amount of space needed to store the decoded data can be
950     * found with decode_base64(...,NULL,0).) Returns -1 if the input string
951     * is NULL, or if the output buffer is NULL (except when the size is zero)
952     * or the size is negative. If `out' is too small to hold all of the
953     * decoded data, it will contain the first `outsize' bytes.
954     */
955    
956     static const char base64_array[256] = {
957     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 0x00 */
958     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
959     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
960     52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
961     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 0x40 */
962     15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
963     -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
964     41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
965     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 0x80 */
966     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
967     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
968     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
969     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 0xC0 */
970     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
971     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
972     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
973     };
974    
975     int decode_base64(const char *in, void *out, int outsize)
976     {
977     uint8 *outp = out;
978     int outpos;
979    
980     if (!in || outsize < 0)
981     return -1;
982    
983     outpos = 0;
984     while (*in) {
985     int i0, i1, i2, i3;
986     i0 = *in++;
987     if (*in) {
988     i1 = *in++;
989     if (*in) {
990     i2 = *in++;
991     if (*in) {
992     i3 = *in++;
993     } else {
994     i3 = 0;
995     }
996     } else {
997     i2 = 0;
998     i3 = 0;
999     }
1000     } else {
1001     i1 = 0;
1002     i2 = 0;
1003     i3 = 0;
1004     }
1005     i0 = base64_array[(int)i0 & 255];
1006     i1 = base64_array[(int)i1 & 255];
1007     i2 = base64_array[(int)i2 & 255];
1008     i3 = base64_array[(int)i3 & 255];
1009     if (i0 < 0 || i1 < 0)
1010     break;
1011     /* Only store if buffer space is available; increment outpos anyway
1012     * to keep track of total space required (for return value) */
1013     if (outpos < outsize)
1014     outp[outpos] = i0<<2 | i1>>4;
1015     outpos++;
1016     if (i2 < 0)
1017     break;
1018     if (outpos < outsize)
1019     outp[outpos] = (i1&15)<<4 | i2>>2;
1020     outpos++;
1021     if (i3 < 0)
1022     break;
1023     if (outpos < outsize)
1024     outp[outpos] = (i2&3)<<6 | i3;
1025     outpos++;
1026     }
1027    
1028     return outpos;
1029     }
1030    
1031     /*************************************************************************/
1032     /*************************************************************************/
1033    
1034     /* Process a string containing a number/range list in the form
1035     * "n1[-n2][,n3[-n4]]...", calling a caller-specified routine for each
1036     * number in the list. If the callback returns -1, stop immediately.
1037     * Returns the sum of all nonnegative return values from the callback.
1038     * If `count_ret' is non-NULL, *count_ret will be set to the total number
1039     * of times the callback was called.
1040     *
1041     * The number list will never contain duplicates and will always be sorted
1042     * ascendingly. This means the callback routines don't have to worry about
1043     * being called twice for the same index. -TheShadow
1044     * Also, the only values accepted are 0-65536 (inclusive), to avoid someone
1045     * giving us 0-2^31 and causing freezes or out-of-memory. Numbers outside
1046     * this range will be ignored.
1047     *
1048     * The callback should be of type range_callback_t, which is defined as:
1049     * int (*range_callback_t)(User *u, int num, va_list args)
1050     */
1051    
1052     int process_numlist(const char *numstr, int *count_ret,
1053     range_callback_t callback, ...)
1054     {
1055     int n1, n2, min, max, i;
1056     int retval = 0;
1057     int numcount = 0;
1058     va_list args;
1059     static uint8 numflag[65536/8+1]; /* 1 bit per index 0-65536 inclusive */
1060    
1061     memset(numflag, 0, sizeof(numflag));
1062     min = 65536;
1063     max = 0;
1064     va_start(args, callback);
1065    
1066     /* This algorithm ignores invalid characters, ignores a dash
1067     * when it precedes a comma, and ignores everything from the
1068     * end of a valid number or range to the next comma or null.
1069     */
1070     while (*numstr) {
1071     n1 = n2 = strtol(numstr, (char **)&numstr, 10);
1072     numstr += strcspn(numstr, "0123456789,-");
1073     if (*numstr == '-') {
1074     numstr++;
1075     numstr += strcspn(numstr, "0123456789,");
1076     if (isdigit(*numstr)) {
1077     n2 = strtol(numstr, (char **)&numstr, 10);
1078     numstr += strcspn(numstr, "0123456789,-");
1079     }
1080     }
1081     if (n1 < 0)
1082     n1 = 0;
1083     if (n2 > 65536)
1084     n2 = 65536;
1085     if (n1 < min)
1086     min = n1;
1087     if (n2 > max)
1088     max = n2;
1089     while (n1 <= n2) {
1090     if ((n1&7) == 0 && n1+7 <= n2) {
1091     /* Set a whole byte at once */
1092     numflag[n1>>3] = 0xFF;
1093     n1 += 8;
1094     } else {
1095     /* Set just a single bit */
1096     numflag[n1>>3] |= 1 << (n1&7);
1097     n1++;
1098     }
1099     }
1100     numstr += strcspn(numstr, ",");
1101     if (*numstr)
1102     numstr++;
1103     }
1104    
1105     /* Now call the callback routine for each index. */
1106     numcount = 0;
1107     for (i = min; i <= max; i++) {
1108     va_list args_copy;
1109     int res;
1110     if (!(numflag[i>>3] & (1 << (i&7))))
1111     continue;
1112     numcount++;
1113     va_copy(args_copy, args);
1114     res = callback(i, args_copy);
1115     va_end(args_copy);
1116     if (res < 0)
1117     break;
1118     retval += res;
1119     }
1120    
1121     va_end(args);
1122     if (count_ret)
1123     *count_ret = numcount;
1124     return retval;
1125     }
1126    
1127     /*************************************************************************/
1128     /*************************************************************************/
1129    
1130     /* atolsafe: Convert a string in base 10 to a long int, ensuring that the
1131     * string contains no invalid characters and that the result is
1132     * within a specified range (>=min && <=max). Returns min-1 on
1133     * error. errno is set to EINVAL if the string is not a valid
1134     * number, ERANGE if the value is outside the range [min..max],
1135     * and left unmodified otherwise.
1136     */
1137    
1138     long atolsafe(const char *s, long min, long max)
1139     {
1140     int errno_save = errno;
1141     long v;
1142    
1143     if (!s || !*s)
1144     return min-1;
1145     errno = 0;
1146     v = strtol(s, (char **)&s, 10);
1147     if (*s) {
1148     errno = EINVAL;
1149     return min-1;
1150     }
1151     if (errno == ERANGE || v < min || v > max) {
1152     errno = ERANGE;
1153     return min-1;
1154     }
1155     errno = errno_save;
1156     return v;
1157     }
1158    
1159     /*************************************************************************/
1160    
1161     /*
1162     * Local variables:
1163     * c-file-style: "stroustrup"
1164     * c-file-offsets: ((case-label . *) (statement-case-intro . *))
1165     * indent-tabs-mode: nil
1166     * End:
1167     *
1168     * vim: expandtab shiftwidth=4:
1169     */

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28