diff options
Diffstat (limited to 'lib/misc.c')
| -rw-r--r-- | lib/misc.c | 521 | 
1 files changed, 521 insertions, 0 deletions
| diff --git a/lib/misc.c b/lib/misc.c new file mode 100644 index 00000000..17599946 --- /dev/null +++ b/lib/misc.c @@ -0,0 +1,521 @@ +  /********************************************************************\ +  * BitlBee -- An IRC to other IM-networks gateway                     * +  *                                                                    * +  * Copyright 2002-2006 Wilmer van der Gaast and others                * +  \********************************************************************/ + +/* + * Various utility functions. Some are copied from Gaim to support the + * IM-modules, most are from BitlBee. + * + * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> + *                          (and possibly other members of the Gaim team) + * Copyright 2002-2006 Wilmer van der Gaast <wilmer@gaast.net> + */ + +/* +  This program is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published by +  the Free Software Foundation; either version 2 of the License, or +  (at your option) any later version. + +  This program is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License with +  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; +  if not, write to the Free Software Foundation, Inc., 59 Temple Place, +  Suite 330, Boston, MA  02111-1307  USA +*/ + +#define BITLBEE_CORE +#include "nogaim.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <glib.h> +#include <time.h> + +void strip_linefeed(gchar *text) +{ +	int i, j; +	gchar *text2 = g_malloc(strlen(text) + 1); + +	for (i = 0, j = 0; text[i]; i++) +		if (text[i] != '\r') +			text2[j++] = text[i]; +	text2[j] = '\0'; + +	strcpy(text, text2); +	g_free(text2); +} + +char *add_cr(char *text) +{ +	char *ret = NULL; +	int count = 0, j; +	unsigned int i; + +	if (text[0] == '\n') +		count++; +	for (i = 1; i < strlen(text); i++) +		if (text[i] == '\n' && text[i - 1] != '\r') +			count++; + +	if (count == 0) +		return g_strdup(text); + +	ret = g_malloc0(strlen(text) + count + 1); + +	i = 0; j = 0; +	if (text[i] == '\n') +		ret[j++] = '\r'; +	ret[j++] = text[i++]; +	for (; i < strlen(text); i++) { +		if (text[i] == '\n' && text[i - 1] != '\r') +			ret[j++] = '\r'; +		ret[j++] = text[i]; +	} + +	return ret; +} + +char *normalize(const char *s) +{ +	static char buf[BUF_LEN]; +	char *t, *u; +	int x = 0; + +	g_return_val_if_fail((s != NULL), NULL); + +	u = t = g_strdup(s); + +	strcpy(t, s); +	g_strdown(t); + +	while (*t && (x < BUF_LEN - 1)) { +		if (*t != ' ') { +			buf[x] = *t; +			x++; +		} +		t++; +	} +	buf[x] = '\0'; +	g_free(u); +	return buf; +} + +time_t get_time(int year, int month, int day, int hour, int min, int sec) +{ +	struct tm tm; + +	tm.tm_year = year - 1900; +	tm.tm_mon = month - 1; +	tm.tm_mday = day; +	tm.tm_hour = hour; +	tm.tm_min = min; +	tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; +	return mktime(&tm); +} + +typedef struct htmlentity +{ +	char code[8]; +	char is[4]; +} htmlentity_t; + +/* FIXME: This is ISO8859-1(5) centric, so might cause problems with other charsets. */ + +static const htmlentity_t ent[] = +{ +	{ "lt",     "<" }, +	{ "gt",     ">" }, +	{ "amp",    "&" }, +	{ "quot",   "\"" }, +	{ "aacute", "á" }, +	{ "eacute", "é" }, +	{ "iacute", "é" }, +	{ "oacute", "ó" }, +	{ "uacute", "ú" }, +	{ "agrave", "à" }, +	{ "egrave", "è" }, +	{ "igrave", "ì" }, +	{ "ograve", "ò" }, +	{ "ugrave", "ù" }, +	{ "acirc",  "â" }, +	{ "ecirc",  "ê" }, +	{ "icirc",  "î" }, +	{ "ocirc",  "ô" }, +	{ "ucirc",  "û" }, +	{ "auml",   "ä" }, +	{ "euml",   "ë" }, +	{ "iuml",   "ï" }, +	{ "ouml",   "ö" }, +	{ "uuml",   "ü" }, +	{ "nbsp",   " " }, +	{ "",        ""  } +}; + +void strip_html( char *in ) +{ +	char *start = in; +	char *out = g_malloc( strlen( in ) + 1 ); +	char *s = out, *cs; +	int i, matched; +	 +	memset( out, 0, strlen( in ) + 1 ); +	 +	while( *in ) +	{ +		if( *in == '<' && ( isalpha( *(in+1) ) || *(in+1) == '/' ) ) +		{ +			/* If in points at a < and in+1 points at a letter or a slash, this is probably +			   a HTML-tag. Try to find a closing > and continue there. If the > can't be +			   found, assume that it wasn't a HTML-tag after all. */ +			 +			cs = in; +			 +			while( *in && *in != '>' ) +				in ++; +			 +			if( *in ) +			{ +				if( g_strncasecmp( cs+1, "br", 2) == 0 ) +					*(s++) = '\n'; +				in ++; +			} +			else +			{ +				in = cs; +				*(s++) = *(in++); +			} +		} +		else if( *in == '&' ) +		{ +			cs = ++in; +			while( *in && isalpha( *in ) ) +				in ++; +			 +			if( *in == ';' ) in ++; +			matched = 0; +			 +			for( i = 0; *ent[i].code; i ++ ) +				if( g_strncasecmp( ent[i].code, cs, strlen( ent[i].code ) ) == 0 ) +				{ +					int j; +					 +					for( j = 0; ent[i].is[j]; j ++ ) +						*(s++) = ent[i].is[j]; +					 +					matched = 1; +					break; +				} + +			/* None of the entities were matched, so return the string */ +			if( !matched ) +			{ +				in = cs - 1; +				*(s++) = *(in++); +			} +		} +		else +		{ +			*(s++) = *(in++); +		} +	} +	 +	strcpy( start, out ); +	g_free( out ); +} + +char *escape_html( const char *html ) +{ +	const char *c = html; +	GString *ret; +	char *str; +	 +	if( html == NULL ) +		return( NULL ); +	 +	ret = g_string_new( "" ); +	 +	while( *c ) +	{ +		switch( *c ) +		{ +			case '&': +				ret = g_string_append( ret, "&" ); +				break; +			case '<': +				ret = g_string_append( ret, "<" ); +				break; +			case '>': +				ret = g_string_append( ret, ">" ); +				break; +			case '"': +				ret = g_string_append( ret, """ ); +				break; +			default: +				ret = g_string_append_c( ret, *c ); +		} +		c ++; +	} +	 +	str = ret->str; +	g_string_free( ret, FALSE ); +	return( str ); +} + +void info_string_append(GString *str, char *newline, char *name, char *value) +{ +	if( value && value[0] ) +		g_string_sprintfa( str, "%s%s: %s", newline, name, value ); +} + +/* Decode%20a%20file%20name						*/ +void http_decode( char *s ) +{ +	char *t; +	int i, j, k; +	 +	t = g_new( char, strlen( s ) + 1 ); +	 +	for( i = j = 0; s[i]; i ++, j ++ ) +	{ +		if( s[i] == '%' ) +		{ +			if( sscanf( s + i + 1, "%2x", &k ) ) +			{ +				t[j] = k; +				i += 2; +			} +			else +			{ +				*t = 0; +				break; +			} +		} +		else +		{ +			t[j] = s[i]; +		} +	} +	t[j] = 0; +	 +	strcpy( s, t ); +	g_free( t ); +} + +/* Warning: This one explodes the string. Worst-cases can make the string 3x its original size! */ +/* This fuction is safe, but make sure you call it safely as well! */ +void http_encode( char *s ) +{ +	char *t; +	int i, j; +	 +	t = g_strdup( s ); +	 +	for( i = j = 0; t[i]; i ++, j ++ ) +	{ +		/* if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) */ +		if( !isalnum( t[i] ) ) +		{ +			sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] ); +			j += 2; +		} +		else +		{ +			s[j] = t[i]; +		} +	} +	s[j] = 0; +	 +	g_free( t ); +} + +/* Strip newlines from a string. Modifies the string passed to it. */  +char *strip_newlines( char *source ) +{ +	int i;	 + +	for( i = 0; source[i] != '\0'; i ++ ) +		if( source[i] == '\n' || source[i] == '\r' ) +			source[i] = ' '; +	 +	return source; +} + +#ifdef IPV6 +/* Wrap an IPv4 address into IPv6 space. Not thread-safe... */ +char *ipv6_wrap( char *src ) +{ +	static char dst[64]; +	int i; +	 +	for( i = 0; src[i]; i ++ ) +		if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) +			break; +	 +	/* Hmm, it's not even an IP... */ +	if( src[i] ) +		return src; +	 +	g_snprintf( dst, sizeof( dst ), "::ffff:%s", src ); +	 +	return dst; +} + +/* Unwrap an IPv4 address into IPv6 space. Thread-safe, because it's very simple. :-) */ +char *ipv6_unwrap( char *src ) +{ +	int i; +	 +	if( g_strncasecmp( src, "::ffff:", 7 ) != 0 ) +		return src; +	 +	for( i = 7; src[i]; i ++ ) +		if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) +			break; +	 +	/* Hmm, it's not even an IP... */ +	if( src[i] ) +		return src; +	 +	return ( src + 7 ); +} +#endif + +/* Convert from one charset to another. +    +   from_cs, to_cs: Source and destination charsets +   src, dst: Source and destination strings +   size: Size if src. 0 == use strlen(). strlen() is not reliable for UNICODE/UTF16 strings though. +   maxbuf: Maximum number of bytes to write to dst +    +   Returns the number of bytes written to maxbuf or -1 on an error. +*/ +signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ) +{ +	GIConv cd; +	size_t res; +	size_t inbytesleft, outbytesleft; +	char *inbuf = src; +	char *outbuf = dst; +	 +	cd = g_iconv_open( to_cs, from_cs ); +	if( cd == (GIConv) -1 ) +		return( -1 ); +	 +	inbytesleft = size ? size : strlen( src ); +	outbytesleft = maxbuf - 1; +	res = g_iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); +	*outbuf = '\0'; +	g_iconv_close( cd ); +	 +	if( res == (size_t) -1 ) +		return( -1 ); +	else +		return( outbuf - dst ); +} + +/* A pretty reliable random number generator. Tries to use the /dev/random +   devices first, and falls back to the random number generator from libc +   when it fails. Opens randomizer devices with O_NONBLOCK to make sure a +   lack of entropy won't halt BitlBee. */ +void random_bytes( unsigned char *buf, int count ) +{ +	static int use_dev = -1; +	 +	/* Actually this probing code isn't really necessary, is it? */ +	if( use_dev == -1 ) +	{ +		if( access( "/dev/random", R_OK ) == 0 || access( "/dev/urandom", R_OK ) == 0 ) +			use_dev = 1; +		else +		{ +			use_dev = 0; +			srand( ( getpid() << 16 ) ^ time( NULL ) ); +		} +	} +	 +	if( use_dev ) +	{ +		int fd; +		 +		/* At least on Linux, /dev/random can block if there's not +		   enough entropy. We really don't want that, so if it can't +		   give anything, use /dev/urandom instead. */ +		if( ( fd = open( "/dev/random", O_RDONLY | O_NONBLOCK ) ) >= 0 ) +			if( read( fd, buf, count ) == count ) +			{ +				close( fd ); +				return; +			} +		close( fd ); +		 +		/* urandom isn't supposed to block at all, but just to be +		   sure. If it blocks, we'll disable use_dev and use the libc +		   randomizer instead. */ +		if( ( fd = open( "/dev/urandom", O_RDONLY | O_NONBLOCK ) ) >= 0 ) +			if( read( fd, buf, count ) == count ) +			{ +				close( fd ); +				return; +			} +		close( fd ); +		 +		/* If /dev/random blocks once, we'll still try to use it +		   again next time. If /dev/urandom also fails for some +		   reason, stick with libc during this session. */ +		 +		use_dev = 0; +		srand( ( getpid() << 16 ) ^ time( NULL ) ); +	} +	 +	if( !use_dev ) +	{ +		int i; +		 +		/* Possibly the LSB of rand() isn't very random on some +		   platforms. Seems okay on at least Linux and OSX though. */ +		for( i = 0; i < count; i ++ ) +			buf[i] = rand() & 0xff; +	} +} + +int is_bool( char *value ) +{ +	if( *value == 0 ) +		return 0; +	 +	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) +		return 1; +	if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) +		return 1; +	 +	while( *value ) +		if( !isdigit( *value ) ) +			return 0; +		else +			value ++; +	 +	return 1; +} + +int bool2int( char *value ) +{ +	int i; +	 +	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) +		return 1; +	if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) +		return 0; +	 +	if( sscanf( value, "%d", &i ) == 1 ) +		return i; +	 +	return 0; +} | 
