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, ¶m, &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: