source: lib/misc.c @ 1719464

Last change on this file since 1719464 was 1719464, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-06-28T14:47:05Z

Added random_bytes() function for better/more reliable randomization and
moved set_eval_ops() to a slightly more suitable place.

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