source: lib/misc.c @ df1694b

Last change on this file since df1694b was df1694b, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-06-25T12:15:42Z

Moving all generic files to lib/ instead of having some in / and some in
protocols/, and adding RC4 code.

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