source: util.c @ db28304

Last change on this file since db28304 was 0a69d7b, checked in by Jelmer Vernooij <jelmer@…>, at 2006-05-25T09:53:53Z

Use iconv from GLib if available

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