source: util.c @ 41ca004

Last change on this file since 41ca004 was e27661d, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-03-31T17:55:47Z

Finished the iconv() fix. Instead of doing it every time something goes from
or to the IM-modules, it's now just done with everything that goes between
BitlBee and the user. Incomparably more efficient/reliable. Plus some more
cleanups. It compiles, can't test it for real yet. ;-)

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