]>
jfr.im git - solanum.git/blob - src/irc_string.c
2 * ircd-ratbox: A slightly useful ircd.
3 * irc_string.c: IRC string functions.
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
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.
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.
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
24 * $Id: irc_string.c 678 2006-02-03 20:25:01Z jilles $
28 #include "sprintf_irc.h"
29 #include "irc_string.h"
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...)
56 * Thu Nov 24 18:22:48 1986
64 strcpy(buf
, ctime(&value
));
65 if((p
= strchr(buf
, '\n')) != NULL
)
72 * clean_string - clean up a string possibly containing garbage
74 * *sigh* Before the kiddies find this new and exciting way of
75 * annoying opers, lets clean up what is sent to local opers
79 clean_string(char *dest
, const unsigned char *src
, size_t len
)
85 if(dest
== NULL
|| src
== NULL
)
88 len
-= 3; /* allow for worst case, '^A\0' */
90 while(*src
&& (len
> 0))
92 if(*src
& 0x80) /* if high bit is set */
97 else if(!IsPrint(*src
)) /* if NOT printable */
101 *d
++ = 0x40 + *src
; /* turn it into a printable */
113 * strip_tabs(dst, src, length)
115 * Copies src to dst, while converting all \t (tabs) into spaces.
117 * NOTE: jdc: I have a gut feeling there's a faster way to do this.
120 strip_tabs(char *dest
, const unsigned char *src
, size_t len
)
123 /* Sanity check; we don't want anything nasty... */
127 if(dest
== NULL
|| src
== NULL
)
130 while(*src
&& (len
> 0))
134 *d
++ = ' '; /* Translate the tab into a space */
138 *d
++ = *src
; /* Copy src to dst */
143 *d
= '\0'; /* Null terminate, thanks and goodbye */
148 * strtoken - walk through a string of tokens, using a set of separators
153 strtoken(char **save
, char *str
, const char *fs
)
155 char *pos
= *save
; /* keep last position across calls */
159 pos
= str
; /* new string scan */
161 while(pos
&& *pos
&& strchr(fs
, *pos
) != NULL
)
162 ++pos
; /* skip leading separators */
165 return (pos
= *save
= NULL
); /* string contains only sep's */
167 tmp
= pos
; /* now, keep position of the token */
169 while(*pos
&& strchr(fs
, *pos
) == NULL
)
170 ++pos
; /* skip content of the token */
173 *pos
++ = '\0'; /* remove first sep after the token */
175 pos
= NULL
; /* end of string */
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'
189 static const char base64_pad
= '=';
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
211 ircd_base64_encode(const unsigned char *str
, int length
)
213 const unsigned char *current
= str
;
215 unsigned char *result
;
217 if ((length
+ 2) < 0 || ((length
+ 2) / 3) >= (1 << (sizeof(int) * 8 - 2))) {
221 result
= rb_malloc(((length
+ 2) / 3) * 5);
226 *p
++ = base64_table
[current
[0] >> 2];
227 *p
++ = base64_table
[((current
[0] & 0x03) << 4) + (current
[1] >> 4)];
228 *p
++ = base64_table
[((current
[1] & 0x0f) << 2) + (current
[2] >> 6)];
229 *p
++ = base64_table
[current
[2] & 0x3f];
236 *p
++ = base64_table
[current
[0] >> 2];
238 *p
++ = base64_table
[((current
[0] & 0x03) << 4) + (current
[1] >> 4)];
239 *p
++ = base64_table
[(current
[1] & 0x0f) << 2];
242 *p
++ = base64_table
[(current
[0] & 0x03) << 4];
252 ircd_base64_decode(const unsigned char *str
, int length
, int *ret
)
254 const unsigned char *current
= str
;
255 int ch
, i
= 0, j
= 0, k
;
256 unsigned char *result
;
258 result
= rb_malloc(length
+ 1);
260 while ((ch
= *current
++) != '\0' && length
-- > 0) {
261 if (ch
== base64_pad
) break;
263 ch
= base64_reverse_table
[ch
];
264 if (ch
< 0) continue;
271 result
[j
++] |= ch
>> 4;
272 result
[j
] = (ch
& 0x0f) << 4;
275 result
[j
++] |= ch
>>2;
276 result
[j
] = (ch
& 0x03) << 6;
287 if (ch
== base64_pad
) {
307 * From: Thomas Helvey <tomh@inxpress.net>
309 static const char *IpQuadTab
[] = {
310 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
311 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
312 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
313 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
314 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
315 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
316 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
317 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
318 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
319 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
320 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
321 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
322 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
323 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
324 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
325 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
326 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
327 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
328 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
329 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
330 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
331 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
332 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
333 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
334 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
335 "250", "251", "252", "253", "254", "255"
339 * inetntoa - in_addr to string
340 * changed name to remove collision possibility and
341 * so behaviour is guaranteed to take a pointer arg.
343 * inet_ntoa -- returned the dotted notation of a given
346 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
350 inetntoa(const char *in
)
354 const unsigned char *a
= (const unsigned char *) in
;
377 * Copyright (c) 1996-1999 by Internet Software Consortium.
379 * Permission to use, copy, modify, and distribute this software for any
380 * purpose with or without fee is hereby granted, provided that the above
381 * copyright notice and this permission notice appear in all copies.
383 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
384 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
385 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
386 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
387 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
388 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
389 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
393 #define SPRINTF(x) ((size_t)rb_sprintf x)
396 * WARNING: Don't even consider trying to compile this on a system where
397 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
400 static const char *inet_ntop4(const u_char
* src
, char *dst
, unsigned int size
);
402 static const char *inet_ntop6(const u_char
* src
, char *dst
, unsigned int size
);
406 * inet_ntop4(src, dst, size)
407 * format an IPv4 address
411 * (1) uses no statics
412 * (2) takes a u_char* not an in_addr as input
417 inet_ntop4(const unsigned char *src
, char *dst
, unsigned int size
)
421 return strcpy(dst
, inetntoa((const char *) src
));
425 * inet_ntop6(src, dst, size)
426 * convert IPv6 binary address into presentation (printable) format
432 inet_ntop6(const unsigned char *src
, char *dst
, unsigned int size
)
435 * Note that int32_t and int16_t need only be "at least" large enough
436 * to contain a value of the specified size. On some systems, like
437 * Crays, there is no such thing as an integer variable with 16 bits.
438 * Keep this in mind if you think this function should have been coded
439 * to use pointer overlays. All the world's not a VAX.
441 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp
;
447 u_int words
[IN6ADDRSZ
/ INT16SZ
];
452 * Copy the input (bytewise) array into a wordwise array.
453 * Find the longest run of 0x00's in src[] for :: shorthanding.
455 memset(words
, '\0', sizeof words
);
456 for(i
= 0; i
< IN6ADDRSZ
; i
+= 2)
457 words
[i
/ 2] = (src
[i
] << 8) | src
[i
+ 1];
460 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
465 cur
.base
= i
, cur
.len
= 1;
473 if(best
.base
== -1 || cur
.len
> best
.len
)
481 if(best
.base
== -1 || cur
.len
> best
.len
)
484 if(best
.base
!= -1 && best
.len
< 2)
491 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
493 /* Are we inside the best run of 0x00's? */
494 if(best
.base
!= -1 && i
>= best
.base
&& i
< (best
.base
+ best
.len
))
504 /* Are we following an initial run of 0x00s or any real hex? */
507 /* Is this address an encapsulated IPv4? */
508 if(i
== 6 && best
.base
== 0 &&
509 (best
.len
== 6 || (best
.len
== 5 && words
[5] == 0xffff)))
511 if(!inet_ntop4(src
+ 12, tp
, sizeof tmp
- (tp
- tmp
)))
516 tp
+= SPRINTF((tp
, "%x", words
[i
]));
518 /* Was it a trailing run of 0x00's? */
519 if(best
.base
!= -1 && (best
.base
+ best
.len
) == (IN6ADDRSZ
/ INT16SZ
))
524 * Check for overflow, copy, and we're done.
527 if((unsigned int) (tp
- tmp
) > size
)
531 return strcpy(dst
, tmp
);
536 inetpton_sock(const char *src
, struct sockaddr
*dst
)
538 if(inetpton(AF_INET
, src
, &((struct sockaddr_in
*) dst
)->sin_addr
))
540 ((struct sockaddr_in
*) dst
)->sin_port
= 0;
541 ((struct sockaddr_in
*) dst
)->sin_family
= AF_INET
;
542 SET_SS_LEN((struct rb_sockaddr_storage
*) dst
, sizeof(struct sockaddr_in
));
546 else if(inetpton(AF_INET6
, src
, &((struct sockaddr_in6
*) dst
)->sin6_addr
))
548 ((struct sockaddr_in6
*) dst
)->sin6_port
= 0;
549 ((struct sockaddr_in6
*) dst
)->sin6_family
= AF_INET6
;
550 SET_SS_LEN((struct rb_sockaddr_storage
*) dst
, sizeof(struct sockaddr_in6
));
558 inetntop_sock(struct sockaddr
*src
, char *dst
, unsigned int size
)
560 switch (src
->sa_family
)
563 return (inetntop(AF_INET
, &((struct sockaddr_in
*) src
)->sin_addr
, dst
, size
));
567 return (inetntop(AF_INET6
, &((struct sockaddr_in6
*) src
)->sin6_addr
, dst
, size
));
577 * inetntop(af, src, dst, size)
578 * convert a network format address to presentation format.
580 * pointer to presentation format address (`dst'), or NULL (see errno).
585 inetntop(int af
, const void *src
, char *dst
, unsigned int size
)
590 return (inet_ntop4(src
, dst
, size
));
593 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr
*) src
) ||
594 IN6_IS_ADDR_V4COMPAT((const struct in6_addr
*) src
))
596 ((const unsigned char *)
597 &((const struct in6_addr
*) src
)->s6_addr
[12], dst
, size
));
599 return (inet_ntop6(src
, dst
, size
));
610 * WARNING: Don't even consider trying to compile this on a system where
611 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
615 * inetpton(af, src, dst)
616 * convert from presentation format (which usually means ASCII printable)
617 * to network format (which is usually some kind of binary format).
619 * 1 if the address was valid for the specified address family
620 * 0 if the address wasn't valid (`dst' is untouched in this case)
621 * -1 if some other error occurred (`dst' is untouched in this case, too)
627 * inet_pton4(src, dst)
628 * like inet_aton() but without all the hexadecimal and shorthand.
630 * 1 if `src' is a valid dotted quad, else 0.
632 * does not touch `dst' unless it's returning 1.
641 int saw_digit
, octets
, ch
;
642 u_char tmp
[INADDRSZ
], *tp
;
647 while((ch
= *src
++) != '\0')
650 if(ch
>= '0' && ch
<= '9')
652 u_int
new = *tp
* 10 + (ch
- '0');
664 else if(ch
== '.' && saw_digit
)
676 memcpy(dst
, tmp
, INADDRSZ
);
682 * inet_pton6(src, dst)
683 * convert presentation level address to network order binary form.
685 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
687 * (1) does not touch `dst' unless it's returning 1.
688 * (2) :: in a full address is silently ignored.
690 * inspired by Mark Andrews.
700 static const char xdigits
[] = "0123456789abcdef";
701 u_char tmp
[IN6ADDRSZ
], *tp
, *endp
, *colonp
;
706 tp
= memset(tmp
, '\0', IN6ADDRSZ
);
707 endp
= tp
+ IN6ADDRSZ
;
709 /* Leading :: requires some special handling. */
716 while((ch
= tolower(*src
++)) != '\0')
720 pch
= strchr(xdigits
, ch
);
724 val
|= (pch
- xdigits
);
740 else if(*src
== '\0')
744 if(tp
+ INT16SZ
> endp
)
746 *tp
++ = (u_char
) (val
>> 8) & 0xff;
747 *tp
++ = (u_char
) val
& 0xff;
752 if(*src
!= '\0' && ch
== '.')
754 if(((tp
+ INADDRSZ
) <= endp
) && inet_pton4(curtok
, tp
) > 0)
758 break; /* '\0' was seen by inet_pton4(). */
767 if(tp
+ INT16SZ
> endp
)
769 *tp
++ = (u_char
) (val
>> 8) & 0xff;
770 *tp
++ = (u_char
) val
& 0xff;
775 * Since some memmove()'s erroneously fail to handle
776 * overlapping regions, we'll do the shift by hand.
778 const int n
= tp
- colonp
;
783 for(i
= 1; i
<= n
; i
++)
785 endp
[-i
] = colonp
[n
- i
];
792 memcpy(dst
, tmp
, IN6ADDRSZ
);
797 inetpton(af
, src
, dst
)
805 return (inet_pton4(src
, dst
));
808 /* Somebody might have passed as an IPv4 address this is sick but it works */
809 if(inet_pton4(src
, dst
))
812 rb_sprintf(tmp
, "::ffff:%s", src
);
813 return (inet_pton6(tmp
, dst
));
816 return (inet_pton6(src
, dst
));
825 * strlcat and strlcpy were ripped from openssh 2.5.1p2
826 * They had the following Copyright info:
829 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
830 * All rights reserved.
832 * Redistribution and use in source and binary forms, with or without
833 * modification, are permitted provided that the following conditions
835 * 1. Redistributions of source code must retain the above copyright
836 * notice, this list of conditions and the following disclaimer.
837 * 2. Redistributions in binary form must reproduce the above copyright
838 * notice, this list of conditions and the following disclaimer in the
839 * documentation and/or other materials provided with the distribution.
840 * 3. The name of the author may not be used to endorse or promote products
841 * derived from this software without specific prior written permission.
843 * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
844 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
845 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
846 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
847 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
848 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
849 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
850 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
851 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
852 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
859 strlcat(char *dst
, const char *src
, size_t siz
)
863 size_t n
= siz
, dlen
;
865 while(n
-- != 0 && *d
!= '\0')
871 return (dlen
+ strlen(s
));
882 return (dlen
+ (s
- src
)); /* count does not include NUL */
888 strlcpy(char *dst
, const char *src
, size_t siz
)
893 /* Copy as many bytes as will fit */
894 if(n
!= 0 && --n
!= 0)
898 if((*d
++ = *s
++) == 0)
903 /* Not enough room in dst, add NUL and traverse rest of src */
907 *d
= '\0'; /* NUL-terminate dst */
912 return (s
- src
- 1); /* count does not include NUL */
917 strip_colour(char *string
)
921 char *last_non_space
= NULL
;
922 /* c is source, c2 is target */
932 if(c
[1] == ',' && isdigit(c
[2]))
958 *last_non_space
= '\0';