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 26 2006-09-20 18:02:06Z spb $
28 #include "sprintf_irc.h"
30 #include "irc_string.h"
49 * myctime - This is like standard ctime()-function, but it zaps away
50 * the newline from the end of that string. Also, it takes
51 * the time value as parameter, instead of pointer to it.
52 * Note that it is necessary to copy the string to alternate
53 * buffer (who knows how ctime() implements it, maybe it statically
54 * has newline there and never 'refreshes' it -- zapping that
55 * might break things in other places...)
58 * Thu Nov 24 18:22:48 1986
66 strcpy(buf
, ctime(&value
));
67 if((p
= strchr(buf
, '\n')) != NULL
)
74 * clean_string - clean up a string possibly containing garbage
76 * *sigh* Before the kiddies find this new and exciting way of
77 * annoying opers, lets clean up what is sent to local opers
81 clean_string(char *dest
, const unsigned char *src
, size_t len
)
87 if(dest
== NULL
|| src
== NULL
)
90 len
-= 3; /* allow for worst case, '^A\0' */
92 while(*src
&& (len
> 0))
94 if(*src
& 0x80) /* if high bit is set */
99 else if(!IsPrint(*src
)) /* if NOT printable */
103 *d
++ = 0x40 + *src
; /* turn it into a printable */
115 * strip_tabs(dst, src, length)
117 * Copies src to dst, while converting all \t (tabs) into spaces.
119 * NOTE: jdc: I have a gut feeling there's a faster way to do this.
122 strip_tabs(char *dest
, const unsigned char *src
, size_t len
)
125 /* Sanity check; we don't want anything nasty... */
129 if(dest
== NULL
|| src
== NULL
)
132 while(*src
&& (len
> 0))
136 *d
++ = ' '; /* Translate the tab into a space */
140 *d
++ = *src
; /* Copy src to dst */
145 *d
= '\0'; /* Null terminate, thanks and goodbye */
150 * strtoken - walk through a string of tokens, using a set of separators
155 strtoken(char **save
, char *str
, const char *fs
)
157 char *pos
= *save
; /* keep last position across calls */
161 pos
= str
; /* new string scan */
163 while(pos
&& *pos
&& strchr(fs
, *pos
) != NULL
)
164 ++pos
; /* skip leading separators */
167 return (pos
= *save
= NULL
); /* string contains only sep's */
169 tmp
= pos
; /* now, keep position of the token */
171 while(*pos
&& strchr(fs
, *pos
) == NULL
)
172 ++pos
; /* skip content of the token */
175 *pos
++ = '\0'; /* remove first sep after the token */
177 pos
= NULL
; /* end of string */
183 static const char base64_table
[] =
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 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
187 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
188 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
191 static const char base64_pad
= '=';
193 static const short base64_reverse_table
[256] = {
194 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
195 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
196 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
197 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
198 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
199 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
200 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
201 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -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 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
209 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
213 ircd_base64_encode(const unsigned char *str
, int length
)
215 const unsigned char *current
= str
;
217 unsigned char *result
;
219 if ((length
+ 2) < 0 || ((length
+ 2) / 3) >= (1 << (sizeof(int) * 8 - 2))) {
223 result
= MyMalloc(((length
+ 2) / 3) * 5);
228 *p
++ = base64_table
[current
[0] >> 2];
229 *p
++ = base64_table
[((current
[0] & 0x03) << 4) + (current
[1] >> 4)];
230 *p
++ = base64_table
[((current
[1] & 0x0f) << 2) + (current
[2] >> 6)];
231 *p
++ = base64_table
[current
[2] & 0x3f];
238 *p
++ = base64_table
[current
[0] >> 2];
240 *p
++ = base64_table
[((current
[0] & 0x03) << 4) + (current
[1] >> 4)];
241 *p
++ = base64_table
[(current
[1] & 0x0f) << 2];
244 *p
++ = base64_table
[(current
[0] & 0x03) << 4];
254 ircd_base64_decode(const unsigned char *str
, int length
, int *ret
)
256 const unsigned char *current
= str
;
257 int ch
, i
= 0, j
= 0, k
;
258 unsigned char *result
;
260 result
= MyMalloc(length
+ 1);
262 while ((ch
= *current
++) != '\0' && length
-- > 0) {
263 if (ch
== base64_pad
) break;
265 ch
= base64_reverse_table
[ch
];
266 if (ch
< 0) continue;
273 result
[j
++] |= ch
>> 4;
274 result
[j
] = (ch
& 0x0f) << 4;
277 result
[j
++] |= ch
>>2;
278 result
[j
] = (ch
& 0x03) << 6;
289 if (ch
== base64_pad
) {
309 * From: Thomas Helvey <tomh@inxpress.net>
311 static const char *IpQuadTab
[] = {
312 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
313 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
314 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
315 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
316 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
317 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
318 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
319 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
320 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
321 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
322 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
323 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
324 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
325 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
326 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
327 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
328 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
329 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
330 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
331 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
332 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
333 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
334 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
335 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
336 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
337 "250", "251", "252", "253", "254", "255"
341 * inetntoa - in_addr to string
342 * changed name to remove collision possibility and
343 * so behaviour is guaranteed to take a pointer arg.
345 * inet_ntoa -- returned the dotted notation of a given
348 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
352 inetntoa(const char *in
)
356 const unsigned char *a
= (const unsigned char *) in
;
379 * Copyright (c) 1996-1999 by Internet Software Consortium.
381 * Permission to use, copy, modify, and distribute this software for any
382 * purpose with or without fee is hereby granted, provided that the above
383 * copyright notice and this permission notice appear in all copies.
385 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
386 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
387 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
388 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
389 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
390 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
391 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
395 #define SPRINTF(x) ((size_t)ircsprintf x)
398 * WARNING: Don't even consider trying to compile this on a system where
399 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
402 static const char *inet_ntop4(const u_char
* src
, char *dst
, unsigned int size
);
404 static const char *inet_ntop6(const u_char
* src
, char *dst
, unsigned int size
);
408 * inet_ntop4(src, dst, size)
409 * format an IPv4 address
413 * (1) uses no statics
414 * (2) takes a u_char* not an in_addr as input
419 inet_ntop4(const unsigned char *src
, char *dst
, unsigned int size
)
423 return strcpy(dst
, inetntoa((const char *) src
));
427 * inet_ntop6(src, dst, size)
428 * convert IPv6 binary address into presentation (printable) format
434 inet_ntop6(const unsigned char *src
, char *dst
, unsigned int size
)
437 * Note that int32_t and int16_t need only be "at least" large enough
438 * to contain a value of the specified size. On some systems, like
439 * Crays, there is no such thing as an integer variable with 16 bits.
440 * Keep this in mind if you think this function should have been coded
441 * to use pointer overlays. All the world's not a VAX.
443 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp
;
449 u_int words
[IN6ADDRSZ
/ INT16SZ
];
454 * Copy the input (bytewise) array into a wordwise array.
455 * Find the longest run of 0x00's in src[] for :: shorthanding.
457 memset(words
, '\0', sizeof words
);
458 for(i
= 0; i
< IN6ADDRSZ
; i
+= 2)
459 words
[i
/ 2] = (src
[i
] << 8) | src
[i
+ 1];
462 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
467 cur
.base
= i
, cur
.len
= 1;
475 if(best
.base
== -1 || cur
.len
> best
.len
)
483 if(best
.base
== -1 || cur
.len
> best
.len
)
486 if(best
.base
!= -1 && best
.len
< 2)
493 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
495 /* Are we inside the best run of 0x00's? */
496 if(best
.base
!= -1 && i
>= best
.base
&& i
< (best
.base
+ best
.len
))
506 /* Are we following an initial run of 0x00s or any real hex? */
509 /* Is this address an encapsulated IPv4? */
510 if(i
== 6 && best
.base
== 0 &&
511 (best
.len
== 6 || (best
.len
== 5 && words
[5] == 0xffff)))
513 if(!inet_ntop4(src
+ 12, tp
, sizeof tmp
- (tp
- tmp
)))
518 tp
+= SPRINTF((tp
, "%x", words
[i
]));
520 /* Was it a trailing run of 0x00's? */
521 if(best
.base
!= -1 && (best
.base
+ best
.len
) == (IN6ADDRSZ
/ INT16SZ
))
526 * Check for overflow, copy, and we're done.
529 if((unsigned int) (tp
- tmp
) > size
)
533 return strcpy(dst
, tmp
);
538 inetpton_sock(const char *src
, struct sockaddr
*dst
)
540 if(inetpton(AF_INET
, src
, &((struct sockaddr_in
*) dst
)->sin_addr
))
542 ((struct sockaddr_in
*) dst
)->sin_port
= 0;
543 ((struct sockaddr_in
*) dst
)->sin_family
= AF_INET
;
544 SET_SS_LEN(*((struct irc_sockaddr_storage
*) dst
), sizeof(struct sockaddr_in
));
548 else if(inetpton(AF_INET6
, src
, &((struct sockaddr_in6
*) dst
)->sin6_addr
))
550 ((struct sockaddr_in6
*) dst
)->sin6_port
= 0;
551 ((struct sockaddr_in6
*) dst
)->sin6_family
= AF_INET6
;
552 SET_SS_LEN(*((struct irc_sockaddr_storage
*) dst
), sizeof(struct sockaddr_in6
));
560 inetntop_sock(struct sockaddr
*src
, char *dst
, unsigned int size
)
562 switch (src
->sa_family
)
565 return (inetntop(AF_INET
, &((struct sockaddr_in
*) src
)->sin_addr
, dst
, size
));
569 return (inetntop(AF_INET6
, &((struct sockaddr_in6
*) src
)->sin6_addr
, dst
, size
));
579 * inetntop(af, src, dst, size)
580 * convert a network format address to presentation format.
582 * pointer to presentation format address (`dst'), or NULL (see errno).
587 inetntop(int af
, const void *src
, char *dst
, unsigned int size
)
592 return (inet_ntop4(src
, dst
, size
));
595 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr
*) src
) ||
596 IN6_IS_ADDR_V4COMPAT((const struct in6_addr
*) src
))
598 ((const unsigned char *)
599 &((const struct in6_addr
*) src
)->s6_addr
[12], dst
, size
));
601 return (inet_ntop6(src
, dst
, size
));
612 * WARNING: Don't even consider trying to compile this on a system where
613 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
617 * inetpton(af, src, dst)
618 * convert from presentation format (which usually means ASCII printable)
619 * to network format (which is usually some kind of binary format).
621 * 1 if the address was valid for the specified address family
622 * 0 if the address wasn't valid (`dst' is untouched in this case)
623 * -1 if some other error occurred (`dst' is untouched in this case, too)
629 * inet_pton4(src, dst)
630 * like inet_aton() but without all the hexadecimal and shorthand.
632 * 1 if `src' is a valid dotted quad, else 0.
634 * does not touch `dst' unless it's returning 1.
643 int saw_digit
, octets
, ch
;
644 u_char tmp
[INADDRSZ
], *tp
;
649 while((ch
= *src
++) != '\0')
652 if(ch
>= '0' && ch
<= '9')
654 u_int
new = *tp
* 10 + (ch
- '0');
666 else if(ch
== '.' && saw_digit
)
678 memcpy(dst
, tmp
, INADDRSZ
);
684 * inet_pton6(src, dst)
685 * convert presentation level address to network order binary form.
687 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
689 * (1) does not touch `dst' unless it's returning 1.
690 * (2) :: in a full address is silently ignored.
692 * inspired by Mark Andrews.
702 static const char xdigits
[] = "0123456789abcdef";
703 u_char tmp
[IN6ADDRSZ
], *tp
, *endp
, *colonp
;
708 tp
= memset(tmp
, '\0', IN6ADDRSZ
);
709 endp
= tp
+ IN6ADDRSZ
;
711 /* Leading :: requires some special handling. */
718 while((ch
= tolower(*src
++)) != '\0')
722 pch
= strchr(xdigits
, ch
);
726 val
|= (pch
- xdigits
);
742 else if(*src
== '\0')
746 if(tp
+ INT16SZ
> endp
)
748 *tp
++ = (u_char
) (val
>> 8) & 0xff;
749 *tp
++ = (u_char
) val
& 0xff;
754 if(*src
!= '\0' && ch
== '.')
756 if(((tp
+ INADDRSZ
) <= endp
) && inet_pton4(curtok
, tp
) > 0)
760 break; /* '\0' was seen by inet_pton4(). */
769 if(tp
+ INT16SZ
> endp
)
771 *tp
++ = (u_char
) (val
>> 8) & 0xff;
772 *tp
++ = (u_char
) val
& 0xff;
777 * Since some memmove()'s erroneously fail to handle
778 * overlapping regions, we'll do the shift by hand.
780 const int n
= tp
- colonp
;
785 for(i
= 1; i
<= n
; i
++)
787 endp
[-i
] = colonp
[n
- i
];
794 memcpy(dst
, tmp
, IN6ADDRSZ
);
799 inetpton(af
, src
, dst
)
807 return (inet_pton4(src
, dst
));
810 /* Somebody might have passed as an IPv4 address this is sick but it works */
811 if(inet_pton4(src
, dst
))
814 ircsprintf(tmp
, "::ffff:%s", src
);
815 return (inet_pton6(tmp
, dst
));
818 return (inet_pton6(src
, dst
));
827 * strlcat and strlcpy were ripped from openssh 2.5.1p2
828 * They had the following Copyright info:
831 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
832 * All rights reserved.
834 * Redistribution and use in source and binary forms, with or without
835 * modification, are permitted provided that the following conditions
837 * 1. Redistributions of source code must retain the above copyright
838 * notice, this list of conditions and the following disclaimer.
839 * 2. Redistributions in binary form must reproduce the above copyright
840 * notice, this list of conditions and the following disclaimer in the
841 * documentation and/or other materials provided with the distribution.
842 * 3. The name of the author may not be used to endorse or promote products
843 * derived from this software without specific prior written permission.
845 * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
846 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
847 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
848 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
849 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
850 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
851 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
852 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
853 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
854 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
861 strlcat(char *dst
, const char *src
, size_t siz
)
865 size_t n
= siz
, dlen
;
867 while(n
-- != 0 && *d
!= '\0')
873 return (dlen
+ strlen(s
));
884 return (dlen
+ (s
- src
)); /* count does not include NUL */
890 strlcpy(char *dst
, const char *src
, size_t siz
)
895 /* Copy as many bytes as will fit */
896 if(n
!= 0 && --n
!= 0)
900 if((*d
++ = *s
++) == 0)
905 /* Not enough room in dst, add NUL and traverse rest of src */
909 *d
= '\0'; /* NUL-terminate dst */
914 return (s
- src
- 1); /* count does not include NUL */
919 strip_colour(char *string
)
923 char *last_non_space
= NULL
;
924 /* c is source, c2 is target */
934 if(c
[1] == ',' && isdigit(c
[2]))
960 *last_non_space
= '\0';