source: lib/misc.c @ f06894d

Last change on this file since f06894d was 51fdc45, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-09-17T15:56:16Z

add_cr() is not used anymore, and HTML entity handling got UTFized some time
ago already, so no need for that FIXME comment.

  • Property mode set to 100644
File size: 10.3 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2006 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/*
8 * Various utility functions. Some are copied from Gaim to support the
9 * IM-modules, most are from BitlBee.
10 *
11 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
12 *                          (and possibly other members of the Gaim team)
13 * Copyright 2002-2006 Wilmer van der Gaast <wilmer@gaast.net>
14 */
15
16/*
17  This program is free software; you can redistribute it and/or modify
18  it under the terms of the GNU General Public License as published by
19  the Free Software Foundation; either version 2 of the License, or
20  (at your option) any later version.
21
22  This program is distributed in the hope that it will be useful,
23  but WITHOUT ANY WARRANTY; without even the implied warranty of
24  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  GNU General Public License for more details.
26
27  You should have received a copy of the GNU General Public License with
28  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
29  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
30  Suite 330, Boston, MA  02111-1307  USA
31*/
32
33#define BITLBEE_CORE
34#include "nogaim.h"
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <ctype.h>
39#include <glib.h>
40#include <time.h>
41
42void strip_linefeed(gchar *text)
43{
44        int i, j;
45        gchar *text2 = g_malloc(strlen(text) + 1);
46
47        for (i = 0, j = 0; text[i]; i++)
48                if (text[i] != '\r')
49                        text2[j++] = text[i];
50        text2[j] = '\0';
51
52        strcpy(text, text2);
53        g_free(text2);
54}
55
56char *normalize(const char *s)
57{
58        static char buf[BUF_LEN];
59        char *t, *u;
60        int x = 0;
61
62        g_return_val_if_fail((s != NULL), NULL);
63
64        u = t = g_strdup(s);
65
66        strcpy(t, s);
67        g_strdown(t);
68
69        while (*t && (x < BUF_LEN - 1)) {
70                if (*t != ' ') {
71                        buf[x] = *t;
72                        x++;
73                }
74                t++;
75        }
76        buf[x] = '\0';
77        g_free(u);
78        return buf;
79}
80
81time_t get_time(int year, int month, int day, int hour, int min, int sec)
82{
83        struct tm tm;
84
85        tm.tm_year = year - 1900;
86        tm.tm_mon = month - 1;
87        tm.tm_mday = day;
88        tm.tm_hour = hour;
89        tm.tm_min = min;
90        tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60;
91        return mktime(&tm);
92}
93
94typedef struct htmlentity
95{
96        char code[7];
97        char is[3];
98} htmlentity_t;
99
100static const htmlentity_t ent[] =
101{
102        { "lt",     "<" },
103        { "gt",     ">" },
104        { "amp",    "&" },
105        { "quot",   "\"" },
106        { "aacute", "á" },
107        { "eacute", "é" },
108        { "iacute", "é" },
109        { "oacute", "ó" },
110        { "uacute", "ú" },
111        { "agrave", "à" },
112        { "egrave", "è" },
113        { "igrave", "ì" },
114        { "ograve", "ò" },
115        { "ugrave", "ù" },
116        { "acirc",  "â" },
117        { "ecirc",  "ê" },
118        { "icirc",  "î" },
119        { "ocirc",  "ô" },
120        { "ucirc",  "û" },
121        { "auml",   "ä" },
122        { "euml",   "ë" },
123        { "iuml",   "ï" },
124        { "ouml",   "ö" },
125        { "uuml",   "ü" },
126        { "nbsp",   " " },
127        { "",        ""  }
128};
129
130void strip_html( char *in )
131{
132        char *start = in;
133        char *out = g_malloc( strlen( in ) + 1 );
134        char *s = out, *cs;
135        int i, matched;
136       
137        memset( out, 0, strlen( in ) + 1 );
138       
139        while( *in )
140        {
141                if( *in == '<' && ( isalpha( *(in+1) ) || *(in+1) == '/' ) )
142                {
143                        /* If in points at a < and in+1 points at a letter or a slash, this is probably
144                           a HTML-tag. Try to find a closing > and continue there. If the > can't be
145                           found, assume that it wasn't a HTML-tag after all. */
146                       
147                        cs = in;
148                       
149                        while( *in && *in != '>' )
150                                in ++;
151                       
152                        if( *in )
153                        {
154                                if( g_strncasecmp( cs+1, "br", 2) == 0 )
155                                        *(s++) = '\n';
156                                in ++;
157                        }
158                        else
159                        {
160                                in = cs;
161                                *(s++) = *(in++);
162                        }
163                }
164                else if( *in == '&' )
165                {
166                        cs = ++in;
167                        while( *in && isalpha( *in ) )
168                                in ++;
169                       
170                        if( *in == ';' ) in ++;
171                        matched = 0;
172                       
173                        for( i = 0; *ent[i].code; i ++ )
174                                if( g_strncasecmp( ent[i].code, cs, strlen( ent[i].code ) ) == 0 )
175                                {
176                                        int j;
177                                       
178                                        for( j = 0; ent[i].is[j]; j ++ )
179                                                *(s++) = ent[i].is[j];
180                                       
181                                        matched = 1;
182                                        break;
183                                }
184
185                        /* None of the entities were matched, so return the string */
186                        if( !matched )
187                        {
188                                in = cs - 1;
189                                *(s++) = *(in++);
190                        }
191                }
192                else
193                {
194                        *(s++) = *(in++);
195                }
196        }
197       
198        strcpy( start, out );
199        g_free( out );
200}
201
202char *escape_html( const char *html )
203{
204        const char *c = html;
205        GString *ret;
206        char *str;
207       
208        if( html == NULL )
209                return( NULL );
210       
211        ret = g_string_new( "" );
212       
213        while( *c )
214        {
215                switch( *c )
216                {
217                        case '&':
218                                ret = g_string_append( ret, "&amp;" );
219                                break;
220                        case '<':
221                                ret = g_string_append( ret, "&lt;" );
222                                break;
223                        case '>':
224                                ret = g_string_append( ret, "&gt;" );
225                                break;
226                        case '"':
227                                ret = g_string_append( ret, "&quot;" );
228                                break;
229                        default:
230                                ret = g_string_append_c( ret, *c );
231                }
232                c ++;
233        }
234       
235        str = ret->str;
236        g_string_free( ret, FALSE );
237        return( str );
238}
239
240void info_string_append(GString *str, char *newline, char *name, char *value)
241{
242        if( value && value[0] )
243                g_string_sprintfa( str, "%s%s: %s", newline, name, value );
244}
245
246/* Decode%20a%20file%20name                                             */
247void http_decode( char *s )
248{
249        char *t;
250        int i, j, k;
251       
252        t = g_new( char, strlen( s ) + 1 );
253       
254        for( i = j = 0; s[i]; i ++, j ++ )
255        {
256                if( s[i] == '%' )
257                {
258                        if( sscanf( s + i + 1, "%2x", &k ) )
259                        {
260                                t[j] = k;
261                                i += 2;
262                        }
263                        else
264                        {
265                                *t = 0;
266                                break;
267                        }
268                }
269                else
270                {
271                        t[j] = s[i];
272                }
273        }
274        t[j] = 0;
275       
276        strcpy( s, t );
277        g_free( t );
278}
279
280/* Warning: This one explodes the string. Worst-cases can make the string 3x its original size! */
281/* This fuction is safe, but make sure you call it safely as well! */
282void http_encode( char *s )
283{
284        char *t;
285        int i, j;
286       
287        t = g_strdup( s );
288       
289        for( i = j = 0; t[i]; i ++, j ++ )
290        {
291                /* if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) */
292                if( !isalnum( t[i] ) )
293                {
294                        sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] );
295                        j += 2;
296                }
297                else
298                {
299                        s[j] = t[i];
300                }
301        }
302        s[j] = 0;
303       
304        g_free( t );
305}
306
307/* Strip newlines from a string. Modifies the string passed to it. */ 
308char *strip_newlines( char *source )
309{
310        int i; 
311
312        for( i = 0; source[i] != '\0'; i ++ )
313                if( source[i] == '\n' || source[i] == '\r' )
314                        source[i] = ' ';
315       
316        return source;
317}
318
319#ifdef IPV6
320/* Wrap an IPv4 address into IPv6 space. Not thread-safe... */
321char *ipv6_wrap( char *src )
322{
323        static char dst[64];
324        int i;
325       
326        for( i = 0; src[i]; i ++ )
327                if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' )
328                        break;
329       
330        /* Hmm, it's not even an IP... */
331        if( src[i] )
332                return src;
333       
334        g_snprintf( dst, sizeof( dst ), "::ffff:%s", src );
335       
336        return dst;
337}
338
339/* Unwrap an IPv4 address into IPv6 space. Thread-safe, because it's very simple. :-) */
340char *ipv6_unwrap( char *src )
341{
342        int i;
343       
344        if( g_strncasecmp( src, "::ffff:", 7 ) != 0 )
345                return src;
346       
347        for( i = 7; src[i]; i ++ )
348                if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' )
349                        break;
350       
351        /* Hmm, it's not even an IP... */
352        if( src[i] )
353                return src;
354       
355        return ( src + 7 );
356}
357#endif
358
359/* Convert from one charset to another.
360   
361   from_cs, to_cs: Source and destination charsets
362   src, dst: Source and destination strings
363   size: Size if src. 0 == use strlen(). strlen() is not reliable for UNICODE/UTF16 strings though.
364   maxbuf: Maximum number of bytes to write to dst
365   
366   Returns the number of bytes written to maxbuf or -1 on an error.
367*/
368signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf )
369{
370        GIConv cd;
371        size_t res;
372        size_t inbytesleft, outbytesleft;
373        char *inbuf = src;
374        char *outbuf = dst;
375       
376        cd = g_iconv_open( to_cs, from_cs );
377        if( cd == (GIConv) -1 )
378                return( -1 );
379       
380        inbytesleft = size ? size : strlen( src );
381        outbytesleft = maxbuf - 1;
382        res = g_iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft );
383        *outbuf = '\0';
384        g_iconv_close( cd );
385       
386        if( res == (size_t) -1 )
387                return( -1 );
388        else
389                return( outbuf - dst );
390}
391
392/* A pretty reliable random number generator. Tries to use the /dev/random
393   devices first, and falls back to the random number generator from libc
394   when it fails. Opens randomizer devices with O_NONBLOCK to make sure a
395   lack of entropy won't halt BitlBee. */
396void random_bytes( unsigned char *buf, int count )
397{
398        static int use_dev = -1;
399       
400        /* Actually this probing code isn't really necessary, is it? */
401        if( use_dev == -1 )
402        {
403                if( access( "/dev/random", R_OK ) == 0 || access( "/dev/urandom", R_OK ) == 0 )
404                        use_dev = 1;
405                else
406                {
407                        use_dev = 0;
408                        srand( ( getpid() << 16 ) ^ time( NULL ) );
409                }
410        }
411       
412        if( use_dev )
413        {
414                int fd;
415               
416                /* At least on Linux, /dev/random can block if there's not
417                   enough entropy. We really don't want that, so if it can't
418                   give anything, use /dev/urandom instead. */
419                if( ( fd = open( "/dev/random", O_RDONLY | O_NONBLOCK ) ) >= 0 )
420                        if( read( fd, buf, count ) == count )
421                        {
422                                close( fd );
423                                return;
424                        }
425                close( fd );
426               
427                /* urandom isn't supposed to block at all, but just to be
428                   sure. If it blocks, we'll disable use_dev and use the libc
429                   randomizer instead. */
430                if( ( fd = open( "/dev/urandom", O_RDONLY | O_NONBLOCK ) ) >= 0 )
431                        if( read( fd, buf, count ) == count )
432                        {
433                                close( fd );
434                                return;
435                        }
436                close( fd );
437               
438                /* If /dev/random blocks once, we'll still try to use it
439                   again next time. If /dev/urandom also fails for some
440                   reason, stick with libc during this session. */
441               
442                use_dev = 0;
443                srand( ( getpid() << 16 ) ^ time( NULL ) );
444        }
445       
446        if( !use_dev )
447        {
448                int i;
449               
450                /* Possibly the LSB of rand() isn't very random on some
451                   platforms. Seems okay on at least Linux and OSX though. */
452                for( i = 0; i < count; i ++ )
453                        buf[i] = rand() & 0xff;
454        }
455}
456
457int is_bool( char *value )
458{
459        if( *value == 0 )
460                return 0;
461       
462        if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) )
463                return 1;
464        if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) )
465                return 1;
466       
467        while( *value )
468                if( !isdigit( *value ) )
469                        return 0;
470                else
471                        value ++;
472       
473        return 1;
474}
475
476int bool2int( char *value )
477{
478        int i;
479       
480        if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) )
481                return 1;
482        if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) )
483                return 0;
484       
485        if( sscanf( value, "%d", &i ) == 1 )
486                return i;
487       
488        return 0;
489}
Note: See TracBrowser for help on using the repository browser.