Annotation of libaitwww/src/mime.c, revision 1.1
1.1 ! misho 1: /*************************************************************************
! 2: * (C) 2012 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
! 3: * by Michael Pounov <misho@elwix.org>
! 4: *
! 5: * $Author: misho $
! 6: * $Id: array.c,v 1.7 2012/02/02 21:32:42 misho Exp $
! 7: *
! 8: **************************************************************************
! 9: The ELWIX and AITNET software is distributed under the following
! 10: terms:
! 11:
! 12: All of the documentation and software included in the ELWIX and AITNET
! 13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
! 14:
! 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
! 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
! 17:
! 18: Redistribution and use in source and binary forms, with or without
! 19: modification, are permitted provided that the following conditions
! 20: are met:
! 21: 1. Redistributions of source code must retain the above copyright
! 22: notice, this list of conditions and the following disclaimer.
! 23: 2. Redistributions in binary form must reproduce the above copyright
! 24: notice, this list of conditions and the following disclaimer in the
! 25: documentation and/or other materials provided with the distribution.
! 26: 3. All advertising materials mentioning features or use of this software
! 27: must display the following acknowledgement:
! 28: This product includes software developed by Michael Pounov <misho@elwix.org>
! 29: ELWIX - Embedded LightWeight unIX and its contributors.
! 30: 4. Neither the name of AITNET nor the names of its contributors
! 31: may be used to endorse or promote products derived from this software
! 32: without specific prior written permission.
! 33:
! 34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
! 35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 44: SUCH DAMAGE.
! 45: */
! 46: #include "global.h"
! 47: #include "mime.h"
! 48: #include "tools.h"
! 49:
! 50:
! 51: static int decode_quoted(char *, int, char *);
! 52: static int decode_base64(char *, int, char *);
! 53:
! 54: static const char *n_encode[] = { "7bit", "8bit", "binary" };
! 55: static struct _tagEncode {
! 56: char *name;
! 57: float mul;
! 58:
! 59: int (*decode)(char *, int, char *);
! 60: } encode[] = {
! 61: { "quoted-printable", 1, decode_quoted },
! 62: { "base64", (float) 3 / 4, decode_base64 }
! 63: };
! 64:
! 65:
! 66: static inline char *
! 67: bd_begin(const char *str)
! 68: {
! 69: char *s;
! 70: int len = strlen(str) + 6;
! 71:
! 72: s = malloc(len + 1);
! 73: if (!s) {
! 74: LOGERR;
! 75: return NULL;
! 76: } else {
! 77: snprintf(s, len + 1, "\r\n--%s\r\n", str);
! 78: s[len] = 0;
! 79: }
! 80:
! 81: return s;
! 82: }
! 83:
! 84: static inline char *
! 85: bd_end(const char *str)
! 86: {
! 87: char *s;
! 88: int len = strlen(str) + 8;
! 89:
! 90: s = malloc(len + 1);
! 91: if (!s) {
! 92: LOGERR;
! 93: return NULL;
! 94: } else {
! 95: snprintf(s, len + 1, "\r\n--%s--\r\n", str);
! 96: s[len] = 0;
! 97: }
! 98:
! 99: return s;
! 100: }
! 101:
! 102: static u_int
! 103: powmod(int x, int y, int q)
! 104: {
! 105: u_int ret = 1;
! 106:
! 107: while (y) {
! 108: if (y & 1)
! 109: ret = ((unsigned long long)ret * x) % q;
! 110: x = (unsigned long long) x * x % q;
! 111: y = y / 2;
! 112: }
! 113: return ret;
! 114: }
! 115:
! 116: static const char *
! 117: findtextpos(const char *T, size_t tlen, const char *P, size_t plen)
! 118: {
! 119: const u_int q = 4294967291u;
! 120: const u_int d = 256;
! 121: u_int hash, p = 0, t = 0;
! 122: register int i;
! 123:
! 124: hash = powmod(d, plen - 1, q);
! 125:
! 126: /* calculate initial hash tags */
! 127: for (i = 0; i < plen; i++) {
! 128: p = (d * p + P[i]) % q;
! 129: t = (d * t + T[i]) % q;
! 130: }
! 131:
! 132: tlen -= plen;
! 133: for (i = 0; i <= tlen; i++) {
! 134: if (p == t) {
! 135: /* match pattern */
! 136: if (!memcmp(P, T + i, plen))
! 137: return T + i;
! 138: }
! 139:
! 140: /* rehashing */
! 141: if (i < tlen)
! 142: t = (d * (t - T[i] * hash) + T[i + plen]) % q;
! 143: }
! 144:
! 145: return NULL;
! 146: }
! 147:
! 148: static inline void
! 149: freeHeader(struct tagMIME * __restrict m)
! 150: {
! 151: struct tagCGI *c;
! 152:
! 153: while ((c = SLIST_FIRST(&m->mime_header))) {
! 154: if (c->cgi_name)
! 155: free(c->cgi_name);
! 156: if (c->cgi_value)
! 157: free(c->cgi_value);
! 158: SLIST_REMOVE_HEAD(&m->mime_header, cgi_node);
! 159: free(c);
! 160: }
! 161: }
! 162:
! 163: static char *
! 164: hdrValue(const char *str, size_t len, const char **end)
! 165: {
! 166: const char *e, *crlf = NULL;
! 167: char *tmp, *s = NULL;
! 168: int off = 0;
! 169:
! 170: e = str + len;
! 171: while (str < e) {
! 172: if ((crlf = findtextpos(str, e - str, CRLF, strlen(CRLF)))) {
! 173: www_SetErr(EBADMSG, "Bad MIME format message");
! 174: return NULL;
! 175: }
! 176:
! 177: tmp = realloc(s, crlf - str + off + 1);
! 178: if (!tmp) {
! 179: LOGERR;
! 180: free(s);
! 181: return NULL;
! 182: } else
! 183: s = tmp;
! 184:
! 185: memcpy(s + off, str, crlf - str);
! 186: s[crlf - str + off] = 0;
! 187: off += crlf - str;
! 188:
! 189: /* if is multi part header value */
! 190: tmp = (char*) crlf + strlen(CRLF);
! 191: if (*tmp == ' ' || *tmp == '\t')
! 192: str = ++tmp;
! 193: else
! 194: break;
! 195: }
! 196:
! 197: *end = crlf + strlen(CRLF);
! 198: return s;
! 199: }
! 200:
! 201: static inline int
! 202: hexdigit(char a)
! 203: {
! 204: if (a >= '0' && a <= '9')
! 205: return a - '0';
! 206: if (a >= 'a' && a <= 'f')
! 207: return a - 'a' + 10;
! 208: if (a >= 'A' && a <= 'F')
! 209: return a - 'A' + 10;
! 210: /* error!!! */
! 211: return -1;
! 212: }
! 213:
! 214: static int
! 215: decode_quoted(char *in, int len, char *out)
! 216: {
! 217: register int i, cx;
! 218:
! 219: for (i = cx = 0; i < len; i++)
! 220: if (in[i] == '=') {
! 221: /* special handling */
! 222: i++;
! 223: if ((in[i] >= '0' && in[i] <= '9') ||
! 224: (in[i] >= 'A' && in[i] <= 'F') ||
! 225: (in[i] >= 'a' && in[i] <= 'f')) {
! 226: /* encoding a special char */
! 227: *out++ = hexdigit(in[i]) << 4 | hexdigit(in[i+ 1]);
! 228: cx++;
! 229: } else
! 230: i += strlen(CRLF);
! 231: } else {
! 232: *out++ = in[i++];
! 233: cx++;
! 234: }
! 235:
! 236: return cx;
! 237: }
! 238:
! 239: static int
! 240: decode_base64(char *in, int len, char *out)
! 241: {
! 242: register int cx, i, j;
! 243: int bits, eqc;
! 244:
! 245: for (cx = i = eqc = bits = 0; i < len && !eqc; bits = 0) {
! 246: for (j = 0; i < len && j < 4; i++) {
! 247: switch (in[i]) {
! 248: case 'A': case 'B': case 'C': case 'D': case 'E':
! 249: case 'F': case 'G': case 'H': case 'I': case 'J':
! 250: case 'K': case 'L': case 'M': case 'N': case 'O':
! 251: case 'P': case 'Q': case 'R': case 'S': case 'T':
! 252: case 'U': case 'V': case 'W': case 'X': case 'Y':
! 253: case 'Z':
! 254: bits = (bits << 6) | (in[i] - 'A');
! 255: j++;
! 256: break;
! 257: case 'a': case 'b': case 'c': case 'd': case 'e':
! 258: case 'f': case 'g': case 'h': case 'i': case 'j':
! 259: case 'k': case 'l': case 'm': case 'n': case 'o':
! 260: case 'p': case 'q': case 'r': case 's': case 't':
! 261: case 'u': case 'v': case 'w': case 'x': case 'y':
! 262: case 'z':
! 263: bits = (bits << 6) | (in[i] - 'a' + 26);
! 264: j++;
! 265: break;
! 266: case '0': case '1': case '2': case '3': case '4':
! 267: case '5': case '6': case '7': case '8': case '9':
! 268: bits = (bits << 6) | (in[i] - '0' + 52);
! 269: j++;
! 270: break;
! 271: case '+':
! 272: bits = (bits << 6) | 62;
! 273: j++;
! 274: break;
! 275: case '/':
! 276: bits = (bits << 6) | 63;
! 277: j++;
! 278: break;
! 279: case '=':
! 280: bits <<= 6;
! 281: j++;
! 282: eqc++;
! 283: break;
! 284: default:
! 285: break;
! 286: }
! 287: }
! 288:
! 289: if (!j && i >= len)
! 290: continue;
! 291:
! 292: switch (eqc) {
! 293: case 0:
! 294: *out++ = (bits >> 16) & 0xff;
! 295: *out++ = (bits >> 8) & 0xff;
! 296: *out++ = bits & 0xff;
! 297: cx += 3;
! 298: break;
! 299: case 1:
! 300: *out++ = (bits >> 16) & 0xff;
! 301: *out++ = (bits >> 8) & 0xff;
! 302: cx += 2;
! 303: break;
! 304: case 2:
! 305: *out++ = (bits >> 16) & 0xff;
! 306: cx += 1;
! 307: break;
! 308: }
! 309: }
! 310:
! 311: return cx;
! 312: }
! 313:
! 314: /* ------------------------------------------------------------------ */
! 315:
! 316: /*
! 317: * mime_parseMultiPart() - Parse multi part MIME message
! 318: *
! 319: * @str = String
! 320: * @len = String length
! 321: * @bd = Boundary tag
! 322: * @end = End of parsed part
! 323: * return: NULL error or !=NULL allocated MIME session
! 324: */
! 325: mime_t *
! 326: mime_parseMultiPart(const char *str, size_t len, const char *bdtag, const char **end)
! 327: {
! 328: mime_t *mime = NULL;
! 329: struct iovec bd[2];
! 330: struct tagMIME *m, *old = NULL;
! 331: const char *next;
! 332:
! 333: if (!str | !bdtag) {
! 334: www_SetErr(EINVAL, "String or boundary tag is NULL");
! 335: return NULL;
! 336: }
! 337:
! 338: /* init MIME */
! 339: mime = malloc(sizeof(mime_t));
! 340: if (!mime) {
! 341: LOGERR;
! 342: return NULL;
! 343: } else {
! 344: memset(mime, 0, sizeof(mime_t));
! 345: SLIST_INIT(mime);
! 346: }
! 347:
! 348: /* prepare boundary format */
! 349: bd[0].iov_base = bd_begin(bdtag);
! 350: if (!bd[0].iov_base) {
! 351: free(mime);
! 352: return NULL;
! 353: } else
! 354: bd[0].iov_len = strlen(bd[0].iov_base);
! 355: bd[1].iov_base = bd_end(bdtag);
! 356: if (!bd[1].iov_base) {
! 357: free(bd[0].iov_base);
! 358: free(mime);
! 359: return NULL;
! 360: } else
! 361: bd[1].iov_len = strlen(bd[1].iov_base);
! 362: if (memcmp(str, strstr(bd[0].iov_base, "--"), strlen(strstr(bd[0].iov_base, "--")))) {
! 363: www_SetErr(EBADMSG, "Bad content data, not found boundary tag");
! 364: free(bd[1].iov_base);
! 365: free(bd[0].iov_base);
! 366: free(mime);
! 367: return NULL;
! 368: } else {
! 369: str += strlen(strstr(bd[0].iov_base, "--"));
! 370: len -= strlen(strstr(bd[0].iov_base, "--"));
! 371: }
! 372:
! 373: while (42) {
! 374: m = malloc(sizeof(struct tagMIME));
! 375: if (!m) {
! 376: LOGERR;
! 377: mime_close(&mime);
! 378: free(bd[1].iov_base);
! 379: free(bd[0].iov_base);
! 380: return NULL;
! 381: } else {
! 382: memset(m, 0, sizeof(struct tagMIME));
! 383: SLIST_INIT(&m->mime_header);
! 384: }
! 385:
! 386: if (!(next = findtextpos(str, len, bd[0].iov_base, bd[0].iov_len)))
! 387: next = findtextpos(str, len, bd[1].iov_base, bd[1].iov_len);
! 388:
! 389: /* parse message between tags */
! 390: if (mime_readPart(m, str, next - str)) {
! 391: mime_close(&mime);
! 392: free(bd[1].iov_base);
! 393: free(bd[0].iov_base);
! 394: return NULL;
! 395: }
! 396:
! 397: str += next - str;
! 398: len -= next - str;
! 399:
! 400: /* add to mime session */
! 401: if (!old)
! 402: SLIST_INSERT_HEAD(mime, m, mime_node);
! 403: else
! 404: SLIST_INSERT_AFTER(old, m, mime_node);
! 405: old = m;
! 406:
! 407: /* match part termination tag */
! 408: if (!memcmp(str, bd[1].iov_base, bd[1].iov_len))
! 409: break;
! 410:
! 411: str += bd[0].iov_len;
! 412: len -= bd[0].iov_len;
! 413: }
! 414:
! 415: str += bd[0].iov_len;
! 416: len -= bd[0].iov_len;
! 417:
! 418: if (end)
! 419: *end = str;
! 420: return mime;
! 421: }
! 422:
! 423: static inline void
! 424: freeMIME(struct tagMIME * __restrict m)
! 425: {
! 426: if (m->mime_body.iov_base)
! 427: free(m->mime_body.iov_base);
! 428: if (m->mime_prolog.iov_base)
! 429: free(m->mime_prolog.iov_base);
! 430: if (m->mime_epilog.iov_base)
! 431: free(m->mime_epilog.iov_base);
! 432:
! 433: freeHeader(m);
! 434: mime_close(&m->mime_attach);
! 435: }
! 436:
! 437: /*
! 438: * mime_close() - Close MIME session and free all resources
! 439: *
! 440: * @mime = Inited mime session
! 441: * return: none
! 442: */
! 443: void
! 444: mime_close(mime_t ** __restrict mime)
! 445: {
! 446: struct tagMIME *m;
! 447:
! 448: if (!mime || !*mime)
! 449: return;
! 450:
! 451: while ((m = SLIST_FIRST(*mime))) {
! 452: SLIST_REMOVE_HEAD(*mime, mime_node);
! 453: freeMIME(m);
! 454: free(m);
! 455: }
! 456:
! 457: free(*mime);
! 458: *mime = NULL;
! 459: }
! 460:
! 461: /*
! 462: * mime_parseHeader() - Parse MIME header pairs
! 463: *
! 464: * @m = Mime part
! 465: * @str = String
! 466: * @len = String length
! 467: * @end = End of parsed part
! 468: * return: -1 error or 0 ok
! 469: */
! 470: int
! 471: mime_parseHeader(struct tagMIME * __restrict m, const char *str, size_t len, const char **end)
! 472: {
! 473: const char *e, *colon, *eoh;
! 474: struct tagCGI *c, *old = NULL;
! 475:
! 476: if (!m || !str) {
! 477: www_SetErr(EINVAL, "Mime part or string is NULL");
! 478: return -1;
! 479: } else
! 480: e = str + len;
! 481:
! 482: while (str < e) {
! 483: if (!memcmp(str, CRLF, strlen(CRLF))) {
! 484: str += 2;
! 485: break;
! 486: }
! 487:
! 488: colon = memchr(str, ':', e - str);
! 489: eoh = findtextpos(str, e - str, CRLF, strlen(CRLF));
! 490: if (!colon || !eoh || colon > eoh) {
! 491: www_SetErr(EBADMSG, "Bad MIME format message");
! 492: freeHeader(m);
! 493: return -1;
! 494: }
! 495:
! 496: c = malloc(sizeof(struct tagCGI));
! 497: if (!c) {
! 498: LOGERR;
! 499: freeHeader(m);
! 500: return -1;
! 501: }
! 502: /* get name */
! 503: c->cgi_name = malloc(colon - str + 1);
! 504: if (!c->cgi_name) {
! 505: LOGERR;
! 506: free(c);
! 507: freeHeader(m);
! 508: return -1;
! 509: } else {
! 510: memcpy(c->cgi_name, str, colon - str);
! 511: c->cgi_name[colon - str] = 0;
! 512: }
! 513: /* get value */
! 514: c->cgi_value = hdrValue(colon + 1, e - colon - 1, &str);
! 515:
! 516: if (!old)
! 517: SLIST_INSERT_HEAD(&m->mime_header, c, cgi_node);
! 518: else
! 519: SLIST_INSERT_AFTER(old, c, cgi_node);
! 520: old = c;
! 521: }
! 522:
! 523: if (end)
! 524: *end = str;
! 525: return 0;
! 526: }
! 527:
! 528: /*
! 529: * mime_getValue() - Get value from MIME header
! 530: *
! 531: * @m = Mime part
! 532: * @name = Header name
! 533: * return: NULL not found or !=NULL value
! 534: */
! 535: inline const char *
! 536: mime_getValue(struct tagMIME * __restrict m, const char *name)
! 537: {
! 538: struct tagCGI *c;
! 539: const char *v = NULL;
! 540:
! 541: SLIST_FOREACH(c, &m->mime_header, cgi_node)
! 542: if (!strcmp(c->cgi_name, name)) {
! 543: v = c->cgi_value;
! 544: break;
! 545: }
! 546: return v;
! 547: }
! 548:
! 549: /*
! 550: * mime_readPart() Read and parse MIME part
! 551: *
! 552: * @m = Mime part
! 553: * @str = String
! 554: * @len = String length
! 555: * return: -1 error or 0 ok
! 556: */
! 557: int
! 558: mime_readPart(struct tagMIME * __restrict m, const char *str, size_t len)
! 559: {
! 560: const char *eoh, *ct, *eb;
! 561: cgi_t *attr;
! 562: struct iovec bd;
! 563:
! 564: if (!m || !str) {
! 565: www_SetErr(EINVAL, "Mime part or string is NULL");
! 566: return -1;
! 567: }
! 568:
! 569: if (mime_parseHeader(m, str, len, &eoh))
! 570: return -1;
! 571:
! 572: ct = mime_getValue(m, "content-type");
! 573: if (!ct || www_cmptype(ct, "multipart")) {
! 574: /* not multi part, assign like body element */
! 575: m->mime_body.iov_base = malloc(len - (eoh - str) + 1);
! 576: memcpy(m->mime_body.iov_base, eoh, len - (eoh - str));
! 577: ((char*) m->mime_body.iov_base)[len - (eoh - str)] = 0;
! 578: m->mime_body.iov_len = len - (eoh - str) + 1;
! 579: } else {
! 580: /* multi part */
! 581: attr = www_parseAttributes(&ct);
! 582: if (!attr)
! 583: return -1;
! 584: bd.iov_base = bd_begin(www_getAttribute(attr, "boundary"));
! 585: bd.iov_len = strlen(bd.iov_base);
! 586: eb = findtextpos(eoh, len - (eoh - str), bd.iov_base, bd.iov_len);
! 587: free(bd.iov_base);
! 588:
! 589: /* set prolog if exists */
! 590: if (eb != eoh) {
! 591: m->mime_prolog.iov_base = malloc(eb - eoh + 1);
! 592: if (!m->mime_prolog.iov_base) {
! 593: LOGERR;
! 594: www_freeAttributes(&attr);
! 595: return -1;
! 596: }
! 597: memcpy(m->mime_prolog.iov_base, eoh, eb - eoh);
! 598: ((char*) m->mime_prolog.iov_base)[eb - eoh] = 0;
! 599: m->mime_prolog.iov_len = eb - eoh + 1;
! 600: }
! 601:
! 602: m->mime_attach = mime_parseMultiPart(eb + 1, len - (eb + 1 - str),
! 603: www_getAttribute(attr, "boundary"), &eoh);
! 604:
! 605: /* set epilog if exists */
! 606: if (eoh - str < len) {
! 607: m->mime_epilog.iov_base = malloc(len - (eoh - str) + 1);
! 608: if (!m->mime_epilog.iov_base) {
! 609: LOGERR;
! 610: www_freeAttributes(&attr);
! 611: return -1;
! 612: }
! 613: memcpy(m->mime_epilog.iov_base, str, len - (eoh - str));
! 614: ((char*) m->mime_epilog.iov_base)[len - (eoh - str)] = 0;
! 615: m->mime_epilog.iov_len = len - (eoh - str) + 1;
! 616:
! 617: }
! 618: }
! 619:
! 620: www_freeAttributes(&attr);
! 621: return 0;
! 622: }
! 623:
! 624: /*
! 625: * mime_calcRawSize() - Calculate estimated memory for data from parsed MIME part
! 626: *
! 627: * @m = Mime part
! 628: * return: -1 error or >-1 data size in mime part
! 629: */
! 630: int
! 631: mime_calcRawSize(struct tagMIME * __restrict m)
! 632: {
! 633: const char *s;
! 634: char *t;
! 635: int len;
! 636: register int i;
! 637:
! 638: if (!m) {
! 639: www_SetErr(EINVAL, "Mime part is NULL");
! 640: return -1;
! 641: }
! 642:
! 643: /* no body */
! 644: if (m->mime_body.iov_len < 1)
! 645: return 0;
! 646:
! 647: s = mime_getValue(m, "content-transfer-encoding");
! 648: if (!s)
! 649: return m->mime_body.iov_len;
! 650: /* strip whitespaces */
! 651: while (isspace(*s))
! 652: s++;
! 653: t = strchr(s, ';');
! 654: len = t ? strlen(s) : t - s;
! 655:
! 656: /* find proper encoding */
! 657: for (i = 0; i < sizeof n_encode / sizeof *n_encode; i++)
! 658: if (len == strlen(n_encode[i]) && !strncasecmp(s, n_encode[i], len))
! 659: return m->mime_body.iov_len;
! 660:
! 661: for (i = 0; i < sizeof encode / sizeof *encode; i++)
! 662: if (len == strlen(encode[i].name) && !strncasecmp(s, encode[i].name, len))
! 663: return m->mime_body.iov_len * encode[i].mul;
! 664:
! 665: /* fail */
! 666: return -1;
! 667: }
! 668:
! 669: /*
! 670: * mime_getRawData() - Get ready parsed data from MIME part body
! 671: *
! 672: * @m = Mime part
! 673: * @str = output data buffer
! 674: * @len = output data buffer length
! 675: * return: -1 error or >-1 data length in output buffer
! 676: */
! 677: int
! 678: mime_getRawData(struct tagMIME * __restrict m, char * __restrict str, int slen)
! 679: {
! 680: const char *s;
! 681: char *t;
! 682: int len;
! 683: register int i;
! 684:
! 685: if (!m || !str) {
! 686: www_SetErr(EINVAL, "Mime part or string is NULL");
! 687: return -1;
! 688: }
! 689:
! 690: /* no body */
! 691: if (m->mime_body.iov_len < 1)
! 692: return 0;
! 693:
! 694: s = mime_getValue(m, "content-transfer-encoding");
! 695: if (!s) {
! 696: memcpy(str, m->mime_body.iov_base, m->mime_body.iov_len > (slen - 1) ?
! 697: slen - 1 : m->mime_body.iov_len);
! 698: return m->mime_body.iov_len;
! 699: }
! 700:
! 701: /* strip whitespaces */
! 702: while (isspace(*s))
! 703: s++;
! 704: t = strchr(s, ';');
! 705: len = t ? strlen(s) : t - s;
! 706:
! 707: /* decoding body */
! 708: for (i = 0; i < sizeof encode / sizeof *encode; i++)
! 709: if (len == strlen(encode[i].name) && !strncasecmp(s, encode[i].name, len))
! 710: return encode[i].decode(m->mime_body.iov_base,
! 711: m->mime_body.iov_len, str);
! 712:
! 713: /* fail */
! 714: return -1;
! 715: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>