ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/misc.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (9 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 36080 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# Content
1 /* 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 */