source: util.c @ c2fa827

Last change on this file since c2fa827 was 574af7e, checked in by Jelmer Vernooij <jelmer@…>, at 2006-05-25T23:20:54Z

Require GLib 2

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