Annotation of win32/gnome/gmime-x.x.x/gmime-param.c, revision 1.1

1.1     ! paf         1: /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
        !             2: /*
        !             3:  *  Authors: Jeffrey Stedfast <fejj@helixcode.com>
        !             4:  *
        !             5:  *  Copyright 2000 Helix Code, Inc. (www.helixcode.com)
        !             6:  *
        !             7:  *  This program is free software; you can redistribute it and/or modify
        !             8:  *  it under the terms of the GNU General Public License as published by
        !             9:  *  the Free Software Foundation; either version 2 of the License, or
        !            10:  *  (at your option) any later version.
        !            11:  *
        !            12:  *  This program is distributed in the hope that it will be useful,
        !            13:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            15:  *  GNU General Public License for more details.
        !            16:  *
        !            17:  *  You should have received a copy of the GNU General Public License
        !            18:  *  along with this program; if not, write to the Free Software
        !            19:  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
        !            20:  *
        !            21:  */
        !            22: 
        !            23: #ifdef HAVE_CONFIG_H
        !            24: #include <config.h>
        !            25: #endif
        !            26: 
        !            27: #include <string.h>
        !            28: #include <ctype.h>
        !            29: #include <errno.h>
        !            30: 
        !            31: #ifdef HAVE_ALLOCA_H
        !            32: #include <alloca.h>
        !            33: #endif
        !            34: 
        !            35: #include "gmime-param.h"
        !            36: #include "gmime-table-private.h"
        !            37: #include "gmime-charset.h"
        !            38: #include "gmime-utils.h"
        !            39: #include "gmime-iconv.h"
        !            40: #include "gmime-iconv-utils.h"
        !            41: 
        !            42: #include "strlib.h"
        !            43: 
        !            44: //#define d(x) x
        !            45: #define d(x)
        !            46: #define w(x)
        !            47: 
        !            48: extern int gmime_interfaces_utf8;
        !            49: 
        !            50: static unsigned char tohex[16] = {
        !            51:        '0', '1', '2', '3', '4', '5', '6', '7',
        !            52:        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
        !            53: };
        !            54: 
        !            55: 
        !            56: /**
        !            57:  * g_mime_param_new: Create a new MIME Param object
        !            58:  * @name: parameter name
        !            59:  * @value: parameter value
        !            60:  *
        !            61:  * Creates a new GMimeParam node with name @name and value @value.
        !            62:  *
        !            63:  * Returns a new paramter structure.
        !            64:  **/
        !            65: GMimeParam *
        !            66: g_mime_param_new (const char *name, const char *value)
        !            67: {
        !            68:        GMimeParam *param;
        !            69:        
        !            70:        param = g_new (GMimeParam, 1);
        !            71:        
        !            72:        param->next = NULL;
        !            73:        param->name = g_strdup (name);
        !            74:        param->value = g_strdup (value);
        !            75:        
        !            76:        return param;
        !            77: }
        !            78: 
        !            79: 
        !            80: #define HEXVAL(c) (isdigit (c) ? (c) - '0' : tolower (c) - 'a' + 10)
        !            81: 
        !            82: static size_t
        !            83: hex_decode (const unsigned char *in, size_t len, unsigned char *out)
        !            84: {
        !            85:        register const unsigned char *inptr;
        !            86:        register unsigned char *outptr;
        !            87:        const unsigned char *inend;
        !            88:        
        !            89:        inptr = in;
        !            90:        inend = in + len;
        !            91:        
        !            92:        outptr = out;
        !            93:        
        !            94:        while (inptr < inend) {
        !            95:                if (*inptr == '%') {
        !            96:                        if (isxdigit (inptr[1]) && isxdigit (inptr[2])) {
        !            97:                                *outptr++ = HEXVAL (inptr[1]) * 16 + HEXVAL (inptr[2]);
        !            98:                                inptr += 3;
        !            99:                        } else
        !           100:                                *outptr++ = *inptr++;
        !           101:                } else
        !           102:                        *outptr++ = *inptr++;
        !           103:        }
        !           104:        
        !           105:        *outptr = '\0';
        !           106:        
        !           107:        return outptr - out;
        !           108: }
        !           109: 
        !           110: /* an rfc2184 encoded string looks something like:
        !           111:  * us-ascii'en'This%20is%20even%20more%20
        !           112:  */
        !           113: static char *
        !           114: rfc2184_decode (const char *in, size_t len)
        !           115: {
        !           116:        const char *inptr = in;
        !           117:        const char *inend = in + len;
        !           118:        const char *charset = NULL;
        !           119:        char *decoded = NULL;
        !           120:        char *charenc;
        !           121:        
        !           122:        /* skips to the end of the charset / beginning of the locale */
        !           123:        inptr = memchr (inptr, '\'', len);
        !           124:        if (!inptr)
        !           125:                return NULL;
        !           126:        
        !           127:        /* save the charset */
        !           128:        len = inptr - in;
        !           129:        charenc = alloca (len + 1);
        !           130:        memcpy (charenc, in, len);
        !           131:        charenc[len] = '\0';
        !           132:        charset = charenc;
        !           133:        
        !           134:        /* skip to the end of the locale */
        !           135:        inptr = memchr (inptr + 1, '\'', (unsigned int) (inend - inptr - 1));
        !           136:        if (!inptr)
        !           137:                return NULL;
        !           138:        
        !           139:        inptr++;
        !           140:        if (inptr < inend) {
        !           141:                len = inend - inptr;
        !           142:                if (gmime_interfaces_utf8 && strcasecmp (charset, "UTF-8") != 0) {
        !           143:                        char *udecoded;
        !           144:                        iconv_t cd;
        !           145:                        
        !           146:                        decoded = alloca (len + 1);
        !           147:                        len = hex_decode (inptr, len, decoded);
        !           148:                        
        !           149:                        cd = g_mime_iconv_open ("UTF-8", charset);
        !           150:                        if (cd == (iconv_t) -1) {
        !           151:                                d(g_warning ("Cannot convert from %s to UTF-8, param display may "
        !           152:                                             "be corrupt: %s", charset, g_strerror (errno)));
        !           153:                                charset = g_mime_charset_locale_name ();
        !           154:                                cd = g_mime_iconv_open ("UTF-8", charset);
        !           155:                                if (cd == (iconv_t) -1)
        !           156:                                        return NULL;
        !           157:                        }
        !           158:                        
        !           159:                        udecoded = g_mime_iconv_strndup (cd, decoded, len);
        !           160:                        g_mime_iconv_close (cd);
        !           161:                        
        !           162:                        if (!udecoded) {
        !           163:                                d(g_warning ("Failed to convert \"%.*s\" to UTF-8, display may be "
        !           164:                                             "corrupt: %s", len, decoded, g_strerror (errno)));
        !           165:                        }
        !           166:                        
        !           167:                        decoded = udecoded;
        !           168:                } else {
        !           169:                        decoded = g_malloc (len + 1);
        !           170:                        hex_decode (inptr, len, decoded);
        !           171:                }
        !           172:        }
        !           173:        
        !           174:        return decoded;
        !           175: }
        !           176: 
        !           177: static void
        !           178: decode_lwsp (const char **in)
        !           179: {
        !           180:        const char *inptr = *in;
        !           181:        
        !           182:        while (*inptr && (*inptr == '(' || is_lwsp (*inptr))) {
        !           183:                while (*inptr && is_lwsp (*inptr))
        !           184:                        inptr++;
        !           185:                
        !           186:                /* skip over any comments */
        !           187:                if (*inptr == '(') {
        !           188:                        int depth = 1;
        !           189:                        
        !           190:                        inptr++;
        !           191:                        while (*inptr && depth) {
        !           192:                                if (*inptr == '\\' && *(inptr + 1))
        !           193:                                        inptr++;
        !           194:                                else if (*inptr == '(')
        !           195:                                        depth++;
        !           196:                                else if (*inptr == ')')
        !           197:                                        depth--;
        !           198:                                
        !           199:                                inptr++;
        !           200:                        }
        !           201:                }
        !           202:        }
        !           203:        
        !           204:        *in = inptr;
        !           205: }
        !           206: 
        !           207: static int
        !           208: decode_int (const char **in)
        !           209: {
        !           210:        const char *inptr = *in;
        !           211:        int n = 0;
        !           212:        
        !           213:        decode_lwsp (&inptr);
        !           214:        
        !           215:        while (isdigit ((int) *inptr)) {
        !           216:                n = n * 10 + (*inptr - '0');
        !           217:                inptr++;
        !           218:        }
        !           219:        
        !           220:        *in = inptr;
        !           221:        
        !           222:        return n;
        !           223: }
        !           224: 
        !           225: static char *
        !           226: decode_quoted_string (const char **in)
        !           227: {
        !           228:        const char *start, *inptr = *in;
        !           229:        char *out = NULL;
        !           230:        
        !           231:        decode_lwsp (&inptr);
        !           232:        if (*inptr == '"') {
        !           233:                start = inptr++;
        !           234:                
        !           235:                while (*inptr && *inptr != '"') {
        !           236:                        if (*inptr++ == '\\')
        !           237:                                inptr++;
        !           238:                }
        !           239:                
        !           240:                if (*inptr == '"') {
        !           241:                        start++;
        !           242:                        out = g_strndup (start, (unsigned int) (inptr - start));
        !           243:                        inptr++;
        !           244:                } else {
        !           245:                        /* string wasn't properly quoted */
        !           246:                        out = g_strndup (start, (unsigned int) (inptr - start));
        !           247:                }
        !           248:        }
        !           249:        
        !           250:        *in = inptr;
        !           251:        
        !           252:        return out;
        !           253: }
        !           254: 
        !           255: static char *
        !           256: decode_token (const char **in)
        !           257: {
        !           258:        const char *inptr = *in;
        !           259:        const char *start;
        !           260:        
        !           261:        decode_lwsp (&inptr);
        !           262:        
        !           263:        start = inptr;
        !           264:        while (is_ttoken (*inptr))
        !           265:                inptr++;
        !           266:        if (inptr > start) {
        !           267:                *in = inptr;
        !           268:                return g_strndup (start, (unsigned int) (inptr - start));
        !           269:        } else {
        !           270:                return NULL;
        !           271:        }
        !           272: }
        !           273: 
        !           274: static char *
        !           275: decode_value (const char **in)
        !           276: {
        !           277:        const char *inptr = *in;
        !           278:        
        !           279:        decode_lwsp (&inptr);
        !           280:        
        !           281:        if (*inptr == '"') {
        !           282:                return decode_quoted_string (in);
        !           283:        } else if (is_ttoken (*inptr)) {
        !           284:                return decode_token (in);
        !           285:        }
        !           286:        
        !           287:        return NULL;
        !           288: }
        !           289: 
        !           290: /* This function is basically the same as decode_token()
        !           291:  * except that it will not accept *'s which have a special
        !           292:  * meaning for rfc2184 params */
        !           293: static char *
        !           294: decode_param_token (const char **in)
        !           295: {
        !           296:        const char *inptr = *in;
        !           297:        const char *start;
        !           298:        
        !           299:        decode_lwsp (&inptr);
        !           300:        
        !           301:        start = inptr;
        !           302:        while (is_ttoken (*inptr) && *inptr != '*')
        !           303:                inptr++;
        !           304:        if (inptr > start) {
        !           305:                *in = inptr;
        !           306:                return g_strndup (start, (unsigned int) (inptr - start));
        !           307:        } else {
        !           308:                return NULL;
        !           309:        }
        !           310: }
        !           311: 
        !           312: static gboolean
        !           313: decode_rfc2184_param (const char **in, char **paramp, int *part, gboolean *value_is_encoded)
        !           314: {
        !           315:        gboolean is_rfc2184 = FALSE;
        !           316:        const char *inptr = *in;
        !           317:        char *param;
        !           318:        
        !           319:        *value_is_encoded = FALSE;
        !           320:        *part = -1;
        !           321:        
        !           322:        param = decode_param_token (&inptr);
        !           323:        
        !           324:        decode_lwsp (&inptr);
        !           325:        
        !           326:        if (*inptr == '*') {
        !           327:                is_rfc2184 = TRUE;
        !           328:                inptr++;
        !           329:                
        !           330:                decode_lwsp (&inptr);
        !           331:                if (*inptr == '=') {
        !           332:                        /* form := param*=value */
        !           333:                        if (value_is_encoded)
        !           334:                                *value_is_encoded = TRUE;
        !           335:                } else {
        !           336:                        /* form := param*#=value or param*#*=value */
        !           337:                        *part = decode_int (&inptr);
        !           338:                        
        !           339:                        decode_lwsp (&inptr);
        !           340:                        if (*inptr == '*') {
        !           341:                                /* form := param*#*=value */
        !           342:                                if (value_is_encoded)
        !           343:                                        *value_is_encoded = TRUE;
        !           344:                                inptr++;
        !           345:                                decode_lwsp (&inptr);
        !           346:                        }
        !           347:                }
        !           348:        }
        !           349:        
        !           350:        if (paramp)
        !           351:                *paramp = param;
        !           352:        
        !           353:        if (param)
        !           354:                *in = inptr;
        !           355:        
        !           356:        return is_rfc2184;
        !           357: }
        !           358: 
        !           359: static int
        !           360: decode_param (const char **in, char **paramp, char **valuep, gboolean *is_rfc2184_param)
        !           361: {
        !           362:        gboolean is_rfc2184_encoded = FALSE;
        !           363:        gboolean is_rfc2184 = FALSE;
        !           364:        gboolean valid_utf8 = FALSE;
        !           365:        const char *inptr = *in;
        !           366:        char *param, *value = NULL;
        !           367:        int rfc2184_part = -1;
        !           368:        
        !           369:        *is_rfc2184_param = FALSE;
        !           370:        
        !           371:        is_rfc2184 = decode_rfc2184_param (&inptr, &param, &rfc2184_part,
        !           372:                                           &is_rfc2184_encoded);
        !           373:        
        !           374:        if (*inptr == '=') {
        !           375:                inptr++;
        !           376:                value = decode_value (&inptr);
        !           377:                
        !           378:                if (is_rfc2184) {
        !           379:                        /* We have ourselves an rfc2184 parameter */
        !           380:                        if (rfc2184_part == -1) {
        !           381:                                /* rfc2184 allows the value to be broken into
        !           382:                                 * multiple parts - this isn't one of them so
        !           383:                                 * it is safe to decode it.
        !           384:                                 */
        !           385:                                char *val;
        !           386:                                
        !           387:                                val = rfc2184_decode (value, strlen (value));
        !           388:                                if (val) {
        !           389:                                        valid_utf8 = TRUE;
        !           390:                                        g_free (value);
        !           391:                                        value = val;
        !           392:                                }
        !           393:                        } else {
        !           394:                                /* Since we are expecting to find the rest of
        !           395:                                 * this paramter value later, let our caller know.
        !           396:                                 */
        !           397:                                *is_rfc2184_param = TRUE;
        !           398:                        }
        !           399:                } else if (value && !strncmp (value, "=?", 2)) {
        !           400:                        /* We have a broken param value that is rfc2047 encoded.
        !           401:                         * Since both Outlook and Netscape/Mozilla do this, we
        !           402:                         * should handle this case.
        !           403:                         */
        !           404:                        char *val;
        !           405:                        
        !           406:                        val = g_mime_utils_8bit_header_decode (value);
        !           407:                        if (val) {
        !           408:                                valid_utf8 = TRUE;
        !           409:                                g_free (value);
        !           410:                                value = val;
        !           411:                        }
        !           412:                } else {
        !           413:                        if (gmime_interfaces_utf8)
        !           414:                                valid_utf8 = !g_mime_utils_text_is_8bit (value, strlen (value));
        !           415:                }
        !           416:        }
        !           417:        
        !           418:        if (gmime_interfaces_utf8 && value && !valid_utf8) {
        !           419:                /* A (broken) mailer has sent us an unencoded 8bit value.
        !           420:                 * Attempt to save it by assuming it's in the user's
        !           421:                 * locale and converting to UTF-8 */
        !           422:                char *buf;
        !           423:                
        !           424:                buf = g_mime_iconv_locale_to_utf8 (value);
        !           425:                if (buf) {
        !           426:                        g_free (value);
        !           427:                        value = buf;
        !           428:                } else {
        !           429:                        d(g_warning ("Failed to convert %s param value (\"%s\") to UTF-8: %s",
        !           430:                                     param, value, g_strerror (errno)));
        !           431:                }
        !           432:        }
        !           433:        
        !           434:        if (param && value) {
        !           435:                *paramp = param;
        !           436:                *valuep = value;
        !           437:                *in = inptr;
        !           438:                return 0;
        !           439:        } else {
        !           440:                g_free (param);
        !           441:                g_free (value);
        !           442:                return 1;
        !           443:        }
        !           444: }
        !           445: 
        !           446: static GMimeParam *
        !           447: decode_param_list (const char **in)
        !           448: {
        !           449:        const char *inptr = *in;
        !           450:        GMimeParam *head = NULL, *tail = NULL;
        !           451:        gboolean last_was_rfc2184 = FALSE;
        !           452:        gboolean is_rfc2184 = FALSE;
        !           453:        
        !           454:        decode_lwsp (&inptr);
        !           455:        
        !           456:        do {
        !           457:                GMimeParam *param = NULL;
        !           458:                char *name, *value;
        !           459:                
        !           460:                /* invalid format? */
        !           461:                if (decode_param (&inptr, &name, &value, &is_rfc2184) != 0) {
        !           462:                        if (*inptr == ';') {
        !           463:                                continue;
        !           464:                        }
        !           465:                        break;
        !           466:                }
        !           467:                
        !           468:                if (is_rfc2184 && tail && !strcasecmp (name, tail->name)) {
        !           469:                        /* rfc2184 allows a parameter to be broken into multiple parts
        !           470:                         * and it looks like we've found one. Append this value to the
        !           471:                         * last value.
        !           472:                         */
        !           473:                        GString *gvalue;
        !           474:                        
        !           475:                        gvalue = g_string_new (tail->value);
        !           476:                        g_string_append (gvalue, value);
        !           477:                        g_free (tail->value);
        !           478:                        g_free (value);
        !           479:                        g_free (name);
        !           480:                        
        !           481:                        tail->value = gvalue->str;
        !           482:                        g_string_free (gvalue, FALSE);
        !           483:                } else {
        !           484:                        if (last_was_rfc2184) {
        !           485:                                /* We've finished gathering the values for the last param
        !           486:                                 * so it is now safe to decode it.
        !           487:                                 */
        !           488:                                char *val;
        !           489:                                
        !           490:                                val = rfc2184_decode (tail->value, strlen (tail->value));
        !           491:                                if (val) {
        !           492:                                        g_free (tail->value);
        !           493:                                        tail->value = val;
        !           494:                                }
        !           495:                        }
        !           496:                        
        !           497:                        param = g_new (GMimeParam, 1);
        !           498:                        param->next = NULL;
        !           499:                        param->name = name;
        !           500:                        param->value = value;
        !           501:                        
        !           502:                        if (head == NULL)
        !           503:                                head = param;
        !           504:                        if (tail)
        !           505:                                tail->next = param;
        !           506:                        tail = param;
        !           507:                }
        !           508:                
        !           509:                last_was_rfc2184 = is_rfc2184;
        !           510:                
        !           511:                decode_lwsp (&inptr);
        !           512:        } while (*inptr++ == ';');
        !           513:        
        !           514:        if (last_was_rfc2184) {
        !           515:                /* We've finished gathering the values for the last param
        !           516:                 * so it is now safe to decode it.
        !           517:                 */
        !           518:                char *val;
        !           519:                
        !           520:                val = rfc2184_decode (tail->value, strlen (tail->value));
        !           521:                if (val) {
        !           522:                        g_free (tail->value);
        !           523:                        tail->value = val;
        !           524:                }
        !           525:        }
        !           526:        
        !           527:        *in = inptr;
        !           528:        
        !           529:        return head;
        !           530: }
        !           531: 
        !           532: 
        !           533: /**
        !           534:  * g_mime_param_new_from_string: Create a new MIME Param object
        !           535:  * @string: input string
        !           536:  *
        !           537:  * Creates a parameter list based on the input string.
        !           538:  *
        !           539:  * Returns a GMimeParam structure based on @string.
        !           540:  **/
        !           541: GMimeParam *
        !           542: g_mime_param_new_from_string (const char *string)
        !           543: {
        !           544:        g_return_val_if_fail (string != NULL, NULL);
        !           545:        
        !           546:        return decode_param_list (&string);
        !           547: }
        !           548: 
        !           549: 
        !           550: /**
        !           551:  * g_mime_param_destroy: Destroy the MIME Param
        !           552:  * @param: Mime param list to destroy
        !           553:  *
        !           554:  * Releases all memory used by this mime param back to the Operating
        !           555:  * System.
        !           556:  **/
        !           557: void
        !           558: g_mime_param_destroy (GMimeParam *param)
        !           559: {
        !           560:        GMimeParam *next;
        !           561:        
        !           562:        while (param) {
        !           563:                next = param->next;
        !           564:                g_free (param->name);
        !           565:                g_free (param->value);
        !           566:                g_free (param);
        !           567:                param = next;
        !           568:        }
        !           569: }
        !           570: 
        !           571: 
        !           572: /**
        !           573:  * g_mime_param_append:
        !           574:  * @params: param list
        !           575:  * @name: new param name
        !           576:  * @value: new param value
        !           577:  *
        !           578:  * Appends a new parameter with name @name and value @value to the
        !           579:  * parameter list @params.
        !           580:  *
        !           581:  * Returns a param list with the new param of name @name and value
        !           582:  * @value appended to the list of params @params.
        !           583:  **/
        !           584: GMimeParam *
        !           585: g_mime_param_append (GMimeParam *params, const char *name, const char *value)
        !           586: {
        !           587:        GMimeParam *param, *p;
        !           588:        
        !           589:        g_return_val_if_fail (name != NULL, params);
        !           590:        g_return_val_if_fail (value != NULL, params);
        !           591:        
        !           592:        param = g_mime_param_new (name, value);
        !           593:        if (params) {
        !           594:                p = params;
        !           595:                while (p->next)
        !           596:                        p = p->next;
        !           597:                p->next = param;
        !           598:        } else
        !           599:                params = param;
        !           600:        
        !           601:        return params;
        !           602: }
        !           603: 
        !           604: 
        !           605: /**
        !           606:  * g_mime_param_append_param:
        !           607:  * @params: param list
        !           608:  * @param: param to append
        !           609:  *
        !           610:  * Appends @param to the param list @params.
        !           611:  *
        !           612:  * Returns a param list with the new param @param appended to the list
        !           613:  * of params @params.
        !           614:  **/
        !           615: GMimeParam *
        !           616: g_mime_param_append_param (GMimeParam *params, GMimeParam *param)
        !           617: {
        !           618:        GMimeParam *p;
        !           619:        
        !           620:        g_return_val_if_fail (param != NULL, params);
        !           621:        
        !           622:        if (params) {
        !           623:                p = params;
        !           624:                while (p->next)
        !           625:                        p = p->next;
        !           626:                p->next = param;
        !           627:        } else
        !           628:                params = param;
        !           629:        
        !           630:        return params;
        !           631: }
        !           632: 
        !           633: /* FIXME: I wrote this in a quick & dirty fasion - it may not be 100% correct */
        !           634: static char *
        !           635: encode_param (const unsigned char *in, gboolean *encoded)
        !           636: {
        !           637:        register const unsigned char *inptr;
        !           638:        unsigned char *outbuf = NULL;
        !           639:        iconv_t cd = (iconv_t) -1;
        !           640:        const char *charset = NULL;
        !           641:        char *outstr;
        !           642:        GString *out;
        !           643:        
        !           644:        *encoded = FALSE;
        !           645:        
        !           646:        for (inptr = in; *inptr && inptr - in < GMIME_FOLD_LEN; inptr++)
        !           647:                if (*inptr > 127)
        !           648:                        break;
        !           649:        
        !           650:        if (*inptr == '\0')
        !           651:                return g_strdup (in);
        !           652:        
        !           653:        if (*inptr > 127) {
        !           654:                if (gmime_interfaces_utf8)
        !           655:                        charset = g_mime_charset_best (in, strlen (in));
        !           656:                else
        !           657:                        charset = g_mime_charset_locale_name ();
        !           658:        }
        !           659:        
        !           660:        if (!charset)
        !           661:                charset = "iso-8859-1";
        !           662:        
        !           663:        if (gmime_interfaces_utf8) {
        !           664:                if (strcasecmp (charset, "UTF-8") != 0)
        !           665:                        cd = g_mime_iconv_open (charset, "UTF-8");
        !           666:                
        !           667:                if (cd == (iconv_t) -1)
        !           668:                        charset = "UTF-8";
        !           669:        }
        !           670:        
        !           671:        if (cd != (iconv_t) -1) {
        !           672:                outbuf = g_mime_iconv_strdup (cd, in);
        !           673:                g_mime_iconv_close (cd);
        !           674:                inptr = outbuf;
        !           675:        } else {
        !           676:                inptr = in;
        !           677:        }
        !           678:        
        !           679:        /* FIXME: set the 'language' as well, assuming we can get that info...? */
        !           680:        out = g_string_new ("");
        !           681:        g_string_sprintfa (out, "%s''", charset);
        !           682:        
        !           683:        while (inptr && *inptr) {
        !           684:                unsigned char c = *inptr++;
        !           685:                
        !           686:                /* FIXME: make sure that '\'', '*', and ';' are also encoded */
        !           687:                
        !           688:                if (c > 127) {
        !           689:                        g_string_sprintfa (out, "%%%c%c", tohex[(c >> 4) & 0xf], tohex[c & 0xf]);
        !           690:                } else if (is_lwsp (c) || !(gmime_special_table[c] & IS_ESAFE)) {
        !           691:                        g_string_sprintfa (out, "%%%c%c", tohex[(c >> 4) & 0xf], tohex[c & 0xf]);
        !           692:                } else {
        !           693:                        g_string_append_c (out, c);
        !           694:                }
        !           695:        }
        !           696:        
        !           697:        g_free (outbuf);
        !           698:        
        !           699:        outstr = out->str;
        !           700:        g_string_free (out, FALSE);
        !           701:        *encoded = TRUE;
        !           702:        
        !           703:        return outstr;
        !           704: }
        !           705: 
        !           706: static void
        !           707: g_string_append_len_quoted (GString *out, const char *in, size_t len)
        !           708: {
        !           709:        const char *inptr;
        !           710:        
        !           711:        g_string_append_c (out, '"');
        !           712:        
        !           713:        for (inptr = in; *inptr; inptr++) {
        !           714:                if ((*inptr == '"') || *inptr == '\\')
        !           715:                        g_string_append_c (out, '\\');
        !           716:                
        !           717:                g_string_append_c (out, *inptr);
        !           718:        }
        !           719:        
        !           720:        g_string_append_c (out, '"');
        !           721: }
        !           722: /*
        !           723: static void
        !           724: g_string_append_len (GString *out, const char *in, size_t len)
        !           725: {
        !           726:        char *buf;
        !           727:        
        !           728:        buf = alloca (len + 1);
        !           729:        strlcpy (buf, in, len);
        !           730:        
        !           731:        g_string_append (out, buf);
        !           732: }
        !           733: */
        !           734: static void
        !           735: param_list_format (GString *out, GMimeParam *param, gboolean fold)
        !           736: {
        !           737:        int used = out->len;
        !           738:        
        !           739:        while (param) {
        !           740:                gboolean encoded = FALSE;
        !           741:                gboolean quote = FALSE;
        !           742:                unsigned nlen, vlen;
        !           743:                int here = out->len;
        !           744:                char *value;
        !           745:                
        !           746:                if (!param->value) {
        !           747:                        param = param->next;
        !           748:                        continue;
        !           749:                }
        !           750:                
        !           751:                value = encode_param (param->value, &encoded);
        !           752:                if (!value) {
        !           753:                        w(g_warning ("appending parameter %s=%s violates rfc2184",
        !           754:                                     param->name, param->value));
        !           755:                        value = g_strdup (param->value);
        !           756:                }
        !           757:                
        !           758:                if (!encoded) {
        !           759:                        char *ch;
        !           760:                        
        !           761:                        for (ch = value; *ch; ch++) {
        !           762:                                if (is_tspecial (*ch) || is_lwsp (*ch))
        !           763:                                        break;
        !           764:                        }
        !           765:                        
        !           766:                        quote = ch && *ch;
        !           767:                }
        !           768:                
        !           769:                nlen = strlen (param->name);
        !           770:                vlen = strlen (value);
        !           771:                
        !           772:                if (used + nlen + vlen > GMIME_FOLD_LEN - 8) {
        !           773:                        if (fold)
        !           774:                                g_string_append (out, ";\n\t");
        !           775:                        else
        !           776:                                g_string_append (out, "; ");
        !           777:                        
        !           778:                        here = out->len;
        !           779:                        used = 0;
        !           780:                } else
        !           781:                        out = g_string_append (out, "; ");
        !           782:                
        !           783:                if (nlen + vlen > GMIME_FOLD_LEN - 10) {
        !           784:                        /* we need to do special rfc2184 parameter wrapping */
        !           785:                        int maxlen = GMIME_FOLD_LEN - (nlen + 10);
        !           786:                        char *inptr, *inend;
        !           787:                        int i = 0;
        !           788:                        
        !           789:                        inptr = value;
        !           790:                        inend = value + vlen;
        !           791:                        
        !           792:                        while (inptr < inend) {
        !           793:                                char *ptr = inptr + MIN (inend - inptr, maxlen);
        !           794:                                
        !           795:                                if (encoded && ptr < inend) {
        !           796:                                        /* be careful not to break an encoded char (ie %20) */
        !           797:                                        char *q = ptr;
        !           798:                                        int j = 2;
        !           799:                                        
        !           800:                                        for ( ; j > 0 && q > inptr && *q != '%'; j--, q--);
        !           801:                                        if (*q == '%')
        !           802:                                                ptr = q;
        !           803:                                }
        !           804:                                
        !           805:                                if (i != 0) {
        !           806:                                        if (fold)
        !           807:                                                g_string_append (out, ";\n\t");
        !           808:                                        else
        !           809:                                                g_string_append (out, "; ");
        !           810:                                        
        !           811:                                        here = out->len;
        !           812:                                        used = 0;
        !           813:                                }
        !           814:                                
        !           815:                                g_string_sprintfa (out, "%s*%d%s=", param->name, i++, encoded ? "*" : "");
        !           816:                                if (encoded || !quote)
        !           817:                                        g_string_append_len (out, inptr, (unsigned) (ptr - inptr));
        !           818:                                else
        !           819:                                        g_string_append_len_quoted (out, inptr, (unsigned) (ptr - inptr));
        !           820:                                
        !           821:                                d(printf ("wrote: %s\n", out->str + here));
        !           822:                                
        !           823:                                used += (out->len - here);
        !           824:                                
        !           825:                                inptr = ptr;
        !           826:                        }
        !           827:                } else {
        !           828:                        g_string_sprintfa (out, "%s%s=", param->name, encoded ? "*" : "");
        !           829:                        
        !           830:                        if (encoded || !quote)
        !           831:                                g_string_append_len (out, value, vlen);
        !           832:                        else
        !           833:                                g_string_append_len_quoted (out, value, vlen);
        !           834:                        
        !           835:                        used += (out->len - here);
        !           836:                }
        !           837:                
        !           838:                g_free (value);
        !           839:                
        !           840:                param = param->next;
        !           841:        }
        !           842: }
        !           843: 
        !           844: 
        !           845: /**
        !           846:  * g_mime_param_write_to_string:
        !           847:  * @param: MIME Param list
        !           848:  * @fold: specifies whether or not to fold headers
        !           849:  * @string: output string
        !           850:  *
        !           851:  * Assumes the output string contains only the Content-* header and
        !           852:  * it's immediate value.
        !           853:  *
        !           854:  * Writes the params out to the string @string.
        !           855:  **/
        !           856: void
        !           857: g_mime_param_write_to_string (GMimeParam *param, gboolean fold, GString *string)
        !           858: {
        !           859:        g_return_if_fail (string != NULL);
        !           860:        
        !           861:        param_list_format (string, param, fold);
        !           862: }

E-mail: