]> jfr.im git - irc/rqf/shadowircd.git/blob - src/irc_string.c
strlcat -> rb_strlcat
[irc/rqf/shadowircd.git] / src / irc_string.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * irc_string.c: IRC string functions.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id: irc_string.c 678 2006-02-03 20:25:01Z jilles $
25 */
26
27 #include "stdinc.h"
28 #include "sprintf_irc.h"
29 #include "irc_string.h"
30 #include "client.h"
31 #include "setup.h"
32
33 #ifndef INADDRSZ
34 #define INADDRSZ 4
35 #endif
36
37 #ifdef RB_IPV6
38 #ifndef IN6ADDRSZ
39 #define IN6ADDRSZ 16
40 #endif
41 #endif
42
43 #ifndef INT16SZ
44 #define INT16SZ 2
45 #endif
46 /*
47 * myctime - This is like standard ctime()-function, but it zaps away
48 * the newline from the end of that string. Also, it takes
49 * the time value as parameter, instead of pointer to it.
50 * Note that it is necessary to copy the string to alternate
51 * buffer (who knows how ctime() implements it, maybe it statically
52 * has newline there and never 'refreshes' it -- zapping that
53 * might break things in other places...)
54 *
55 *
56 * Thu Nov 24 18:22:48 1986
57 */
58 const char *
59 myctime(time_t value)
60 {
61 static char buf[32];
62 char *p;
63
64 strcpy(buf, ctime(&value));
65 if((p = strchr(buf, '\n')) != NULL)
66 *p = '\0';
67 return buf;
68 }
69
70
71 /*
72 * clean_string - clean up a string possibly containing garbage
73 *
74 * *sigh* Before the kiddies find this new and exciting way of
75 * annoying opers, lets clean up what is sent to local opers
76 * -Dianora
77 */
78 char *
79 clean_string(char *dest, const unsigned char *src, size_t len)
80 {
81 char *d = dest;
82 s_assert(0 != dest);
83 s_assert(0 != src);
84
85 if(dest == NULL || src == NULL)
86 return NULL;
87
88 len -= 3; /* allow for worst case, '^A\0' */
89
90 while(*src && (len > 0))
91 {
92 if(*src & 0x80) /* if high bit is set */
93 {
94 *d++ = '.';
95 --len;
96 }
97 else if(!IsPrint(*src)) /* if NOT printable */
98 {
99 *d++ = '^';
100 --len;
101 *d++ = 0x40 + *src; /* turn it into a printable */
102 }
103 else
104 *d++ = *src;
105 ++src;
106 --len;
107 }
108 *d = '\0';
109 return dest;
110 }
111
112 /*
113 * strip_tabs(dst, src, length)
114 *
115 * Copies src to dst, while converting all \t (tabs) into spaces.
116 *
117 * NOTE: jdc: I have a gut feeling there's a faster way to do this.
118 */
119 char *
120 strip_tabs(char *dest, const unsigned char *src, size_t len)
121 {
122 char *d = dest;
123 /* Sanity check; we don't want anything nasty... */
124 s_assert(0 != dest);
125 s_assert(0 != src);
126
127 if(dest == NULL || src == NULL)
128 return NULL;
129
130 while(*src && (len > 0))
131 {
132 if(*src == '\t')
133 {
134 *d++ = ' '; /* Translate the tab into a space */
135 }
136 else
137 {
138 *d++ = *src; /* Copy src to dst */
139 }
140 ++src;
141 --len;
142 }
143 *d = '\0'; /* Null terminate, thanks and goodbye */
144 return dest;
145 }
146
147 /*
148 * strtoken - walk through a string of tokens, using a set of separators
149 * argv 9/90
150 *
151 */
152 char *
153 strtoken(char **save, char *str, const char *fs)
154 {
155 char *pos = *save; /* keep last position across calls */
156 char *tmp;
157
158 if(str)
159 pos = str; /* new string scan */
160
161 while(pos && *pos && strchr(fs, *pos) != NULL)
162 ++pos; /* skip leading separators */
163
164 if(!pos || !*pos)
165 return (pos = *save = NULL); /* string contains only sep's */
166
167 tmp = pos; /* now, keep position of the token */
168
169 while(*pos && strchr(fs, *pos) == NULL)
170 ++pos; /* skip content of the token */
171
172 if(*pos)
173 *pos++ = '\0'; /* remove first sep after the token */
174 else
175 pos = NULL; /* end of string */
176
177 *save = pos;
178 return tmp;
179 }
180
181 static const char base64_table[] =
182 { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
183 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
184 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
185 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
186 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
187 };
188
189 static const char base64_pad = '=';
190
191 static const short base64_reverse_table[256] = {
192 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
193 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
194 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
195 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
196 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
197 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
198 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
199 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
200 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
201 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
202 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
203 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
204 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
205 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
206 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
207 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
208 };
209
210 /*
211 * From: Thomas Helvey <tomh@inxpress.net>
212 */
213 static const char *IpQuadTab[] = {
214 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
215 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
216 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
217 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
218 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
219 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
220 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
221 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
222 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
223 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
224 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
225 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
226 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
227 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
228 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
229 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
230 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
231 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
232 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
233 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
234 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
235 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
236 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
237 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
238 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
239 "250", "251", "252", "253", "254", "255"
240 };
241
242 /*
243 * inetntoa - in_addr to string
244 * changed name to remove collision possibility and
245 * so behaviour is guaranteed to take a pointer arg.
246 * -avalon 23/11/92
247 * inet_ntoa -- returned the dotted notation of a given
248 * internet number
249 * argv 11/90).
250 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
251 */
252
253 const char *
254 inetntoa(const char *in)
255 {
256 static char buf[16];
257 char *bufptr = buf;
258 const unsigned char *a = (const unsigned char *) in;
259 const char *n;
260
261 n = IpQuadTab[*a++];
262 while(*n)
263 *bufptr++ = *n++;
264 *bufptr++ = '.';
265 n = IpQuadTab[*a++];
266 while(*n)
267 *bufptr++ = *n++;
268 *bufptr++ = '.';
269 n = IpQuadTab[*a++];
270 while(*n)
271 *bufptr++ = *n++;
272 *bufptr++ = '.';
273 n = IpQuadTab[*a];
274 while(*n)
275 *bufptr++ = *n++;
276 *bufptr = '\0';
277 return buf;
278 }
279
280 /*
281 * Copyright (c) 1996-1999 by Internet Software Consortium.
282 *
283 * Permission to use, copy, modify, and distribute this software for any
284 * purpose with or without fee is hereby granted, provided that the above
285 * copyright notice and this permission notice appear in all copies.
286 *
287 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
288 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
289 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
290 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
291 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
292 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
293 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
294 * SOFTWARE.
295 */
296
297 #define SPRINTF(x) ((size_t)rb_sprintf x)
298
299 /*
300 * WARNING: Don't even consider trying to compile this on a system where
301 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
302 */
303
304 static const char *inet_ntop4(const u_char * src, char *dst, unsigned int size);
305 #ifdef RB_IPV6
306 static const char *inet_ntop6(const u_char * src, char *dst, unsigned int size);
307 #endif
308
309 /* const char *
310 * inet_ntop4(src, dst, size)
311 * format an IPv4 address
312 * return:
313 * `dst' (as a const)
314 * notes:
315 * (1) uses no statics
316 * (2) takes a u_char* not an in_addr as input
317 * author:
318 * Paul Vixie, 1996.
319 */
320 static const char *
321 inet_ntop4(const unsigned char *src, char *dst, unsigned int size)
322 {
323 if(size < 16)
324 return NULL;
325 return strcpy(dst, inetntoa((const char *) src));
326 }
327
328 /* const char *
329 * inet_ntop6(src, dst, size)
330 * convert IPv6 binary address into presentation (printable) format
331 * author:
332 * Paul Vixie, 1996.
333 */
334 #ifdef RB_IPV6
335 static const char *
336 inet_ntop6(const unsigned char *src, char *dst, unsigned int size)
337 {
338 /*
339 * Note that int32_t and int16_t need only be "at least" large enough
340 * to contain a value of the specified size. On some systems, like
341 * Crays, there is no such thing as an integer variable with 16 bits.
342 * Keep this in mind if you think this function should have been coded
343 * to use pointer overlays. All the world's not a VAX.
344 */
345 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
346 struct
347 {
348 int base, len;
349 }
350 best, cur;
351 u_int words[IN6ADDRSZ / INT16SZ];
352 int i;
353
354 /*
355 * Preprocess:
356 * Copy the input (bytewise) array into a wordwise array.
357 * Find the longest run of 0x00's in src[] for :: shorthanding.
358 */
359 memset(words, '\0', sizeof words);
360 for(i = 0; i < IN6ADDRSZ; i += 2)
361 words[i / 2] = (src[i] << 8) | src[i + 1];
362 best.base = -1;
363 cur.base = -1;
364 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
365 {
366 if(words[i] == 0)
367 {
368 if(cur.base == -1)
369 cur.base = i, cur.len = 1;
370 else
371 cur.len++;
372 }
373 else
374 {
375 if(cur.base != -1)
376 {
377 if(best.base == -1 || cur.len > best.len)
378 best = cur;
379 cur.base = -1;
380 }
381 }
382 }
383 if(cur.base != -1)
384 {
385 if(best.base == -1 || cur.len > best.len)
386 best = cur;
387 }
388 if(best.base != -1 && best.len < 2)
389 best.base = -1;
390
391 /*
392 * Format the result.
393 */
394 tp = tmp;
395 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
396 {
397 /* Are we inside the best run of 0x00's? */
398 if(best.base != -1 && i >= best.base && i < (best.base + best.len))
399 {
400 if(i == best.base)
401 {
402 if(i == 0)
403 *tp++ = '0';
404 *tp++ = ':';
405 }
406 continue;
407 }
408 /* Are we following an initial run of 0x00s or any real hex? */
409 if(i != 0)
410 *tp++ = ':';
411 /* Is this address an encapsulated IPv4? */
412 if(i == 6 && best.base == 0 &&
413 (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
414 {
415 if(!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
416 return (NULL);
417 tp += strlen(tp);
418 break;
419 }
420 tp += SPRINTF((tp, "%x", words[i]));
421 }
422 /* Was it a trailing run of 0x00's? */
423 if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
424 *tp++ = ':';
425 *tp++ = '\0';
426
427 /*
428 * Check for overflow, copy, and we're done.
429 */
430
431 if((unsigned int) (tp - tmp) > size)
432 {
433 return (NULL);
434 }
435 return strcpy(dst, tmp);
436 }
437 #endif
438
439 int
440 inetpton_sock(const char *src, struct sockaddr *dst)
441 {
442 if(inetpton(AF_INET, src, &((struct sockaddr_in *) dst)->sin_addr))
443 {
444 ((struct sockaddr_in *) dst)->sin_port = 0;
445 ((struct sockaddr_in *) dst)->sin_family = AF_INET;
446 SET_SS_LEN((struct rb_sockaddr_storage *) dst, sizeof(struct sockaddr_in));
447 return 1;
448 }
449 #ifdef RB_IPV6
450 else if(inetpton(AF_INET6, src, &((struct sockaddr_in6 *) dst)->sin6_addr))
451 {
452 ((struct sockaddr_in6 *) dst)->sin6_port = 0;
453 ((struct sockaddr_in6 *) dst)->sin6_family = AF_INET6;
454 SET_SS_LEN((struct rb_sockaddr_storage *) dst, sizeof(struct sockaddr_in6));
455 return 1;
456 }
457 #endif
458 return 0;
459 }
460
461 const char *
462 inetntop_sock(struct sockaddr *src, char *dst, unsigned int size)
463 {
464 switch (src->sa_family)
465 {
466 case AF_INET:
467 return (inetntop(AF_INET, &((struct sockaddr_in *) src)->sin_addr, dst, size));
468 break;
469 #ifdef RB_IPV6
470 case AF_INET6:
471 return (inetntop(AF_INET6, &((struct sockaddr_in6 *) src)->sin6_addr, dst, size));
472 break;
473 #endif
474 default:
475 return NULL;
476 break;
477 }
478 }
479
480 /* char *
481 * inetntop(af, src, dst, size)
482 * convert a network format address to presentation format.
483 * return:
484 * pointer to presentation format address (`dst'), or NULL (see errno).
485 * author:
486 * Paul Vixie, 1996.
487 */
488 const char *
489 inetntop(int af, const void *src, char *dst, unsigned int size)
490 {
491 switch (af)
492 {
493 case AF_INET:
494 return (inet_ntop4(src, dst, size));
495 #ifdef RB_IPV6
496 case AF_INET6:
497 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr *) src) ||
498 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *) src))
499 return (inet_ntop4
500 ((const unsigned char *)
501 &((const struct in6_addr *) src)->s6_addr[12], dst, size));
502 else
503 return (inet_ntop6(src, dst, size));
504
505
506 #endif
507 default:
508 return (NULL);
509 }
510 /* NOTREACHED */
511 }
512
513 /*
514 * WARNING: Don't even consider trying to compile this on a system where
515 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
516 */
517
518 /* int
519 * inetpton(af, src, dst)
520 * convert from presentation format (which usually means ASCII printable)
521 * to network format (which is usually some kind of binary format).
522 * return:
523 * 1 if the address was valid for the specified address family
524 * 0 if the address wasn't valid (`dst' is untouched in this case)
525 * -1 if some other error occurred (`dst' is untouched in this case, too)
526 * author:
527 * Paul Vixie, 1996.
528 */
529
530 /* int
531 * inet_pton4(src, dst)
532 * like inet_aton() but without all the hexadecimal and shorthand.
533 * return:
534 * 1 if `src' is a valid dotted quad, else 0.
535 * notice:
536 * does not touch `dst' unless it's returning 1.
537 * author:
538 * Paul Vixie, 1996.
539 */
540 static int
541 inet_pton4(src, dst)
542 const char *src;
543 u_char *dst;
544 {
545 int saw_digit, octets, ch;
546 u_char tmp[INADDRSZ], *tp;
547
548 saw_digit = 0;
549 octets = 0;
550 *(tp = tmp) = 0;
551 while((ch = *src++) != '\0')
552 {
553
554 if(ch >= '0' && ch <= '9')
555 {
556 u_int new = *tp * 10 + (ch - '0');
557
558 if(new > 255)
559 return (0);
560 *tp = new;
561 if(!saw_digit)
562 {
563 if(++octets > 4)
564 return (0);
565 saw_digit = 1;
566 }
567 }
568 else if(ch == '.' && saw_digit)
569 {
570 if(octets == 4)
571 return (0);
572 *++tp = 0;
573 saw_digit = 0;
574 }
575 else
576 return (0);
577 }
578 if(octets < 4)
579 return (0);
580 memcpy(dst, tmp, INADDRSZ);
581 return (1);
582 }
583
584 #ifdef RB_IPV6
585 /* int
586 * inet_pton6(src, dst)
587 * convert presentation level address to network order binary form.
588 * return:
589 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
590 * notice:
591 * (1) does not touch `dst' unless it's returning 1.
592 * (2) :: in a full address is silently ignored.
593 * credit:
594 * inspired by Mark Andrews.
595 * author:
596 * Paul Vixie, 1996.
597 */
598
599 static int
600 inet_pton6(src, dst)
601 const char *src;
602 u_char *dst;
603 {
604 static const char xdigits[] = "0123456789abcdef";
605 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
606 const char *curtok;
607 int ch, saw_xdigit;
608 u_int val;
609
610 tp = memset(tmp, '\0', IN6ADDRSZ);
611 endp = tp + IN6ADDRSZ;
612 colonp = NULL;
613 /* Leading :: requires some special handling. */
614 if(*src == ':')
615 if(*++src != ':')
616 return (0);
617 curtok = src;
618 saw_xdigit = 0;
619 val = 0;
620 while((ch = tolower(*src++)) != '\0')
621 {
622 const char *pch;
623
624 pch = strchr(xdigits, ch);
625 if(pch != NULL)
626 {
627 val <<= 4;
628 val |= (pch - xdigits);
629 if(val > 0xffff)
630 return (0);
631 saw_xdigit = 1;
632 continue;
633 }
634 if(ch == ':')
635 {
636 curtok = src;
637 if(!saw_xdigit)
638 {
639 if(colonp)
640 return (0);
641 colonp = tp;
642 continue;
643 }
644 else if(*src == '\0')
645 {
646 return (0);
647 }
648 if(tp + INT16SZ > endp)
649 return (0);
650 *tp++ = (u_char) (val >> 8) & 0xff;
651 *tp++ = (u_char) val & 0xff;
652 saw_xdigit = 0;
653 val = 0;
654 continue;
655 }
656 if(*src != '\0' && ch == '.')
657 {
658 if(((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
659 {
660 tp += INADDRSZ;
661 saw_xdigit = 0;
662 break; /* '\0' was seen by inet_pton4(). */
663 }
664 }
665 else
666 continue;
667 return (0);
668 }
669 if(saw_xdigit)
670 {
671 if(tp + INT16SZ > endp)
672 return (0);
673 *tp++ = (u_char) (val >> 8) & 0xff;
674 *tp++ = (u_char) val & 0xff;
675 }
676 if(colonp != NULL)
677 {
678 /*
679 * Since some memmove()'s erroneously fail to handle
680 * overlapping regions, we'll do the shift by hand.
681 */
682 const int n = tp - colonp;
683 int i;
684
685 if(tp == endp)
686 return (0);
687 for(i = 1; i <= n; i++)
688 {
689 endp[-i] = colonp[n - i];
690 colonp[n - i] = 0;
691 }
692 tp = endp;
693 }
694 if(tp != endp)
695 return (0);
696 memcpy(dst, tmp, IN6ADDRSZ);
697 return (1);
698 }
699 #endif
700 int
701 inetpton(af, src, dst)
702 int af;
703 const char *src;
704 void *dst;
705 {
706 switch (af)
707 {
708 case AF_INET:
709 return (inet_pton4(src, dst));
710 #ifdef RB_IPV6
711 case AF_INET6:
712 /* Somebody might have passed as an IPv4 address this is sick but it works */
713 if(inet_pton4(src, dst))
714 {
715 char tmp[HOSTIPLEN];
716 rb_sprintf(tmp, "::ffff:%s", src);
717 return (inet_pton6(tmp, dst));
718 }
719 else
720 return (inet_pton6(src, dst));
721 #endif
722 default:
723 return (-1);
724 }
725 /* NOTREACHED */
726 }
727
728 char *
729 strip_colour(char *string)
730 {
731 char *c = string;
732 char *c2 = string;
733 char *last_non_space = NULL;
734 /* c is source, c2 is target */
735 for(; c && *c; c++)
736 switch (*c)
737 {
738 case 3:
739 if(isdigit(c[1]))
740 {
741 c++;
742 if(isdigit(c[1]))
743 c++;
744 if(c[1] == ',' && isdigit(c[2]))
745 {
746 c += 2;
747 if(isdigit(c[1]))
748 c++;
749 }
750 }
751 break;
752 case 2:
753 case 6:
754 case 7:
755 case 22:
756 case 23:
757 case 27:
758 case 31:
759 break;
760 case 32:
761 *c2++ = *c;
762 break;
763 default:
764 *c2++ = *c;
765 last_non_space = c2;
766 break;
767 }
768 *c2 = '\0';
769 if(last_non_space)
770 *last_non_space = '\0';
771 return string;
772 }