Annotation of libaitwww/src/mime.c, revision 1.4.6.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 $
1.4.6.1 ! misho 6: * $Id: mime.c,v 1.4 2012/08/01 00:40:41 misho Exp $
1.1 misho 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:
1.4.6.1 ! misho 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
1.1 misho 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:
49:
50: static int decode_quoted(char *, int, char *);
51: static int decode_base64(char *, int, char *);
52:
53: static const char *n_encode[] = { "7bit", "8bit", "binary" };
54: static struct _tagEncode {
55: char *name;
56: float mul;
57:
58: int (*decode)(char *, int, char *);
59: } encode[] = {
60: { "quoted-printable", 1, decode_quoted },
61: { "base64", (float) 3 / 4, decode_base64 }
62: };
63:
64:
65: static inline char *
66: bd_begin(const char *str)
67: {
68: char *s;
69: int len = strlen(str) + 6;
70:
1.4.6.1 ! misho 71: s = e_malloc(len + 1);
1.1 misho 72: if (!s) {
1.4.6.1 ! misho 73: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.1 misho 74: return NULL;
75: } else {
76: snprintf(s, len + 1, "\r\n--%s\r\n", str);
77: s[len] = 0;
78: }
79:
80: return s;
81: }
82:
83: static inline char *
84: bd_end(const char *str)
85: {
86: char *s;
87: int len = strlen(str) + 8;
88:
1.4.6.1 ! misho 89: s = e_malloc(len + 1);
1.1 misho 90: if (!s) {
1.4.6.1 ! misho 91: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.1 misho 92: return NULL;
93: } else {
94: snprintf(s, len + 1, "\r\n--%s--\r\n", str);
95: s[len] = 0;
96: }
97:
98: return s;
99: }
100:
101: static u_int
102: powmod(int x, int y, int q)
103: {
104: u_int ret = 1;
105:
106: while (y) {
107: if (y & 1)
108: ret = ((unsigned long long)ret * x) % q;
109: x = (unsigned long long) x * x % q;
110: y = y / 2;
111: }
112: return ret;
113: }
114:
115: static const char *
116: findtextpos(const char *T, size_t tlen, const char *P, size_t plen)
117: {
118: const u_int q = 4294967291u;
119: const u_int d = 256;
120: u_int hash, p = 0, t = 0;
121: register int i;
122:
123: hash = powmod(d, plen - 1, q);
124:
125: /* calculate initial hash tags */
126: for (i = 0; i < plen; i++) {
127: p = (d * p + P[i]) % q;
128: t = (d * t + T[i]) % q;
129: }
130:
131: tlen -= plen;
132: for (i = 0; i <= tlen; i++) {
133: if (p == t) {
134: /* match pattern */
135: if (!memcmp(P, T + i, plen))
136: return T + i;
137: }
138:
139: /* rehashing */
140: if (i < tlen)
141: t = (d * (t - T[i] * hash) + T[i + plen]) % q;
142: }
143:
144: return NULL;
145: }
146:
147: static inline void
148: freeHeader(struct tagMIME * __restrict m)
149: {
150: struct tagCGI *c;
151:
152: while ((c = SLIST_FIRST(&m->mime_header))) {
1.4.6.1 ! misho 153: ait_freeVar(&c->cgi_name);
! 154: ait_freeVar(&c->cgi_value);
1.4 misho 155:
1.1 misho 156: SLIST_REMOVE_HEAD(&m->mime_header, cgi_node);
1.4.6.1 ! misho 157: e_free(c);
1.1 misho 158: }
159: }
160:
1.4 misho 161: static ait_val_t *
1.1 misho 162: hdrValue(const char *str, size_t len, const char **end)
163: {
164: const char *e, *crlf = NULL;
165: char *tmp, *s = NULL;
166: int off = 0;
1.4 misho 167: ait_val_t *ret = NULL;
1.1 misho 168:
169: e = str + len;
170: while (str < e) {
1.2 misho 171: if (!(crlf = findtextpos(str, e - str, CRLF, strlen(CRLF)))) {
1.3 misho 172: www_SetErr(EFAULT, "Bad header format of MIME part");
1.1 misho 173: return NULL;
174: }
175:
1.4.6.1 ! misho 176: tmp = e_realloc(s, crlf - str + off + 1);
1.1 misho 177: if (!tmp) {
1.4.6.1 ! misho 178: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
! 179: e_free(s);
1.1 misho 180: return NULL;
181: } else
182: s = tmp;
183:
184: memcpy(s + off, str, crlf - str);
185: s[crlf - str + off] = 0;
186: off += crlf - str;
187:
188: /* if is multi part header value */
189: tmp = (char*) crlf + strlen(CRLF);
190: if (*tmp == ' ' || *tmp == '\t')
191: str = ++tmp;
192: else
193: break;
194: }
195:
196: *end = crlf + strlen(CRLF);
1.4.6.1 ! misho 197: ret = ait_makeVar(string, s);
1.4 misho 198: if (!ret)
1.4.6.1 ! misho 199: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
! 200: e_free(s);
1.4 misho 201:
202: return ret;
1.1 misho 203: }
204:
205: static inline int
206: hexdigit(char a)
207: {
208: if (a >= '0' && a <= '9')
209: return a - '0';
210: if (a >= 'a' && a <= 'f')
211: return a - 'a' + 10;
212: if (a >= 'A' && a <= 'F')
213: return a - 'A' + 10;
214: /* error!!! */
215: return -1;
216: }
217:
218: static int
219: decode_quoted(char *in, int len, char *out)
220: {
221: register int i, cx;
222:
223: for (i = cx = 0; i < len; i++)
224: if (in[i] == '=') {
225: /* special handling */
226: i++;
227: if ((in[i] >= '0' && in[i] <= '9') ||
228: (in[i] >= 'A' && in[i] <= 'F') ||
229: (in[i] >= 'a' && in[i] <= 'f')) {
230: /* encoding a special char */
231: *out++ = hexdigit(in[i]) << 4 | hexdigit(in[i+ 1]);
232: cx++;
233: } else
234: i += strlen(CRLF);
235: } else {
236: *out++ = in[i++];
237: cx++;
238: }
239:
240: return cx;
241: }
242:
243: static int
244: decode_base64(char *in, int len, char *out)
245: {
246: register int cx, i, j;
247: int bits, eqc;
248:
249: for (cx = i = eqc = bits = 0; i < len && !eqc; bits = 0) {
250: for (j = 0; i < len && j < 4; i++) {
251: switch (in[i]) {
252: case 'A': case 'B': case 'C': case 'D': case 'E':
253: case 'F': case 'G': case 'H': case 'I': case 'J':
254: case 'K': case 'L': case 'M': case 'N': case 'O':
255: case 'P': case 'Q': case 'R': case 'S': case 'T':
256: case 'U': case 'V': case 'W': case 'X': case 'Y':
257: case 'Z':
258: bits = (bits << 6) | (in[i] - 'A');
259: j++;
260: break;
261: case 'a': case 'b': case 'c': case 'd': case 'e':
262: case 'f': case 'g': case 'h': case 'i': case 'j':
263: case 'k': case 'l': case 'm': case 'n': case 'o':
264: case 'p': case 'q': case 'r': case 's': case 't':
265: case 'u': case 'v': case 'w': case 'x': case 'y':
266: case 'z':
267: bits = (bits << 6) | (in[i] - 'a' + 26);
268: j++;
269: break;
270: case '0': case '1': case '2': case '3': case '4':
271: case '5': case '6': case '7': case '8': case '9':
272: bits = (bits << 6) | (in[i] - '0' + 52);
273: j++;
274: break;
275: case '+':
276: bits = (bits << 6) | 62;
277: j++;
278: break;
279: case '/':
280: bits = (bits << 6) | 63;
281: j++;
282: break;
283: case '=':
284: bits <<= 6;
285: j++;
286: eqc++;
287: break;
288: default:
289: break;
290: }
291: }
292:
293: if (!j && i >= len)
294: continue;
295:
296: switch (eqc) {
297: case 0:
298: *out++ = (bits >> 16) & 0xff;
299: *out++ = (bits >> 8) & 0xff;
300: *out++ = bits & 0xff;
301: cx += 3;
302: break;
303: case 1:
304: *out++ = (bits >> 16) & 0xff;
305: *out++ = (bits >> 8) & 0xff;
306: cx += 2;
307: break;
308: case 2:
309: *out++ = (bits >> 16) & 0xff;
310: cx += 1;
311: break;
312: }
313: }
314:
315: return cx;
316: }
317:
318: /* ------------------------------------------------------------------ */
319:
320: /*
321: * mime_parseMultiPart() - Parse multi part MIME message
322: *
323: * @str = String
324: * @len = String length
325: * @bd = Boundary tag
326: * @end = End of parsed part
327: * return: NULL error or !=NULL allocated MIME session
328: */
329: mime_t *
330: mime_parseMultiPart(const char *str, size_t len, const char *bdtag, const char **end)
331: {
332: mime_t *mime = NULL;
333: struct iovec bd[2];
334: struct tagMIME *m, *old = NULL;
1.2 misho 335: const char *next = NULL;
1.1 misho 336:
337: if (!str | !bdtag) {
338: www_SetErr(EINVAL, "String or boundary tag is NULL");
339: return NULL;
340: }
341:
342: /* init MIME */
1.4.6.1 ! misho 343: mime = e_malloc(sizeof(mime_t));
1.1 misho 344: if (!mime) {
1.4.6.1 ! misho 345: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.1 misho 346: return NULL;
347: } else {
348: memset(mime, 0, sizeof(mime_t));
349: SLIST_INIT(mime);
350: }
351:
352: /* prepare boundary format */
353: bd[0].iov_base = bd_begin(bdtag);
354: if (!bd[0].iov_base) {
1.4.6.1 ! misho 355: e_free(mime);
1.1 misho 356: return NULL;
357: } else
358: bd[0].iov_len = strlen(bd[0].iov_base);
359: bd[1].iov_base = bd_end(bdtag);
360: if (!bd[1].iov_base) {
1.4.6.1 ! misho 361: e_free(bd[0].iov_base);
! 362: e_free(mime);
1.1 misho 363: return NULL;
364: } else
365: bd[1].iov_len = strlen(bd[1].iov_base);
1.2 misho 366:
367: /* check boundary tag */
1.1 misho 368: if (memcmp(str, strstr(bd[0].iov_base, "--"), strlen(strstr(bd[0].iov_base, "--")))) {
1.3 misho 369: www_SetErr(EFAULT, "Bad content data, not found boundary tag");
1.4.6.1 ! misho 370: e_free(bd[1].iov_base);
! 371: e_free(bd[0].iov_base);
! 372: e_free(mime);
1.1 misho 373: return NULL;
374: } else {
375: str += strlen(strstr(bd[0].iov_base, "--"));
376: len -= strlen(strstr(bd[0].iov_base, "--"));
377: }
378:
1.2 misho 379: while (len > 0) {
1.4.6.1 ! misho 380: m = e_malloc(sizeof(struct tagMIME));
1.1 misho 381: if (!m) {
1.4.6.1 ! misho 382: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.1 misho 383: mime_close(&mime);
1.4.6.1 ! misho 384: e_free(bd[1].iov_base);
! 385: e_free(bd[0].iov_base);
1.1 misho 386: return NULL;
387: } else {
388: memset(m, 0, sizeof(struct tagMIME));
389: SLIST_INIT(&m->mime_header);
390: }
391:
392: if (!(next = findtextpos(str, len, bd[0].iov_base, bd[0].iov_len)))
393: next = findtextpos(str, len, bd[1].iov_base, bd[1].iov_len);
394:
395: /* parse message between tags */
396: if (mime_readPart(m, str, next - str)) {
397: mime_close(&mime);
1.4.6.1 ! misho 398: e_free(bd[1].iov_base);
! 399: e_free(bd[0].iov_base);
1.1 misho 400: return NULL;
401: }
402:
403: str += next - str;
404: len -= next - str;
405:
406: /* add to mime session */
407: if (!old)
408: SLIST_INSERT_HEAD(mime, m, mime_node);
409: else
410: SLIST_INSERT_AFTER(old, m, mime_node);
411: old = m;
412:
413: /* match part termination tag */
414: if (!memcmp(str, bd[1].iov_base, bd[1].iov_len))
415: break;
416:
417: str += bd[0].iov_len;
418: len -= bd[0].iov_len;
419: }
420:
421: str += bd[0].iov_len;
1.2 misho 422: /* LLVM static code analyzer said for this - unusable
423: *
1.1 misho 424: len -= bd[0].iov_len;
1.2 misho 425: */
426:
1.4.6.1 ! misho 427: e_free(bd[1].iov_base);
! 428: e_free(bd[0].iov_base);
1.1 misho 429:
430: if (end)
431: *end = str;
432: return mime;
433: }
434:
435: static inline void
436: freeMIME(struct tagMIME * __restrict m)
437: {
438: if (m->mime_body.iov_base)
1.4.6.1 ! misho 439: e_free(m->mime_body.iov_base);
1.1 misho 440: if (m->mime_prolog.iov_base)
1.4.6.1 ! misho 441: e_free(m->mime_prolog.iov_base);
1.1 misho 442: if (m->mime_epilog.iov_base)
1.4.6.1 ! misho 443: e_free(m->mime_epilog.iov_base);
1.1 misho 444:
445: freeHeader(m);
446: mime_close(&m->mime_attach);
447: }
448:
449: /*
450: * mime_close() - Close MIME session and free all resources
451: *
452: * @mime = Inited mime session
453: * return: none
454: */
455: void
456: mime_close(mime_t ** __restrict mime)
457: {
458: struct tagMIME *m;
459:
460: if (!mime || !*mime)
461: return;
462:
463: while ((m = SLIST_FIRST(*mime))) {
464: SLIST_REMOVE_HEAD(*mime, mime_node);
465: freeMIME(m);
1.4.6.1 ! misho 466: e_free(m);
1.1 misho 467: }
468:
1.4.6.1 ! misho 469: e_free(*mime);
1.1 misho 470: *mime = NULL;
471: }
472:
473: /*
474: * mime_parseHeader() - Parse MIME header pairs
475: *
476: * @m = Mime part
477: * @str = String
478: * @len = String length
479: * @end = End of parsed part
480: * return: -1 error or 0 ok
481: */
482: int
483: mime_parseHeader(struct tagMIME * __restrict m, const char *str, size_t len, const char **end)
484: {
485: const char *e, *colon, *eoh;
486: struct tagCGI *c, *old = NULL;
487:
488: if (!m || !str) {
489: www_SetErr(EINVAL, "Mime part or string is NULL");
490: return -1;
491: } else
492: e = str + len;
493:
494: while (str < e) {
495: if (!memcmp(str, CRLF, strlen(CRLF))) {
496: str += 2;
497: break;
498: }
499:
500: colon = memchr(str, ':', e - str);
501: eoh = findtextpos(str, e - str, CRLF, strlen(CRLF));
502: if (!colon || !eoh || colon > eoh) {
1.3 misho 503: www_SetErr(EFAULT, "Bad MIME format message");
1.1 misho 504: freeHeader(m);
505: return -1;
506: }
507:
1.4.6.1 ! misho 508: c = e_malloc(sizeof(struct tagCGI));
1.1 misho 509: if (!c) {
1.4.6.1 ! misho 510: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.1 misho 511: freeHeader(m);
512: return -1;
513: }
514: /* get name */
1.4.6.1 ! misho 515: c->cgi_name = ait_allocVar();
1.1 misho 516: if (!c->cgi_name) {
1.4.6.1 ! misho 517: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
! 518: e_free(c);
1.1 misho 519: freeHeader(m);
520: return -1;
1.4 misho 521: } else
522: AIT_SET_STRLCPY(c->cgi_name, str, colon - str + 1);
1.1 misho 523: /* get value */
524: c->cgi_value = hdrValue(colon + 1, e - colon - 1, &str);
1.2 misho 525: if (!c->cgi_value) {
526: free(c->cgi_name);
527: free(c);
528: freeHeader(m);
529: return -1;
530: }
1.1 misho 531:
532: if (!old)
533: SLIST_INSERT_HEAD(&m->mime_header, c, cgi_node);
534: else
535: SLIST_INSERT_AFTER(old, c, cgi_node);
536: old = c;
537: }
538:
539: if (end)
540: *end = str;
541: return 0;
542: }
543:
544: /*
545: * mime_getValue() - Get value from MIME header
546: *
547: * @m = Mime part
548: * @name = Header name
549: * return: NULL not found or !=NULL value
550: */
551: inline const char *
552: mime_getValue(struct tagMIME * __restrict m, const char *name)
553: {
554: struct tagCGI *c;
555:
556: SLIST_FOREACH(c, &m->mime_header, cgi_node)
1.4 misho 557: if (!strcasecmp(AIT_GET_STR(c->cgi_name), name))
558: return AIT_GET_STR(c->cgi_value);
559:
560: return NULL;
1.1 misho 561: }
562:
563: /*
564: * mime_readPart() Read and parse MIME part
565: *
566: * @m = Mime part
567: * @str = String
568: * @len = String length
569: * return: -1 error or 0 ok
570: */
571: int
572: mime_readPart(struct tagMIME * __restrict m, const char *str, size_t len)
573: {
574: const char *eoh, *ct, *eb;
575: cgi_t *attr;
576: struct iovec bd;
1.4 misho 577: ait_val_t *v;
1.1 misho 578:
1.2 misho 579: if (!m || !str || (ssize_t) len < 0) {
580: www_SetErr(EINVAL, "Mime part, string is NULL or length is less 0");
1.1 misho 581: return -1;
582: }
583:
584: if (mime_parseHeader(m, str, len, &eoh))
585: return -1;
586:
587: ct = mime_getValue(m, "content-type");
588: if (!ct || www_cmptype(ct, "multipart")) {
589: /* not multi part, assign like body element */
1.4.6.1 ! misho 590: m->mime_body.iov_base = e_malloc(len - (eoh - str) + 1);
1.2 misho 591: if (!m->mime_body.iov_base) {
1.4.6.1 ! misho 592: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.2 misho 593: freeHeader(m);
594: return -1;
595: }
1.1 misho 596: memcpy(m->mime_body.iov_base, eoh, len - (eoh - str));
597: ((char*) m->mime_body.iov_base)[len - (eoh - str)] = 0;
598: m->mime_body.iov_len = len - (eoh - str) + 1;
599: } else {
600: /* multi part */
601: attr = www_parseAttributes(&ct);
1.2 misho 602: if (!attr) {
603: freeHeader(m);
1.1 misho 604: return -1;
1.2 misho 605: }
1.4 misho 606: v = www_getAttribute(attr, "boundary");
607: bd.iov_base = bd_begin(AIT_GET_STR(v));
1.1 misho 608: bd.iov_len = strlen(bd.iov_base);
609: eb = findtextpos(eoh, len - (eoh - str), bd.iov_base, bd.iov_len);
1.4.6.1 ! misho 610: e_free(bd.iov_base);
1.1 misho 611:
612: /* set prolog if exists */
613: if (eb != eoh) {
1.4.6.1 ! misho 614: m->mime_prolog.iov_base = e_malloc(eb - eoh + 1);
1.1 misho 615: if (!m->mime_prolog.iov_base) {
1.4.6.1 ! misho 616: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.1 misho 617: www_freeAttributes(&attr);
1.2 misho 618: freeHeader(m);
1.1 misho 619: return -1;
620: }
621: memcpy(m->mime_prolog.iov_base, eoh, eb - eoh);
622: ((char*) m->mime_prolog.iov_base)[eb - eoh] = 0;
623: m->mime_prolog.iov_len = eb - eoh + 1;
624: }
625:
1.4 misho 626: v = www_getAttribute(attr, "boundary");
1.1 misho 627: m->mime_attach = mime_parseMultiPart(eb + 1, len - (eb + 1 - str),
1.4 misho 628: AIT_GET_STR(v), &eoh);
1.1 misho 629:
630: /* set epilog if exists */
631: if (eoh - str < len) {
1.4.6.1 ! misho 632: m->mime_epilog.iov_base = e_malloc(len - (eoh - str) + 1);
1.1 misho 633: if (!m->mime_epilog.iov_base) {
1.4.6.1 ! misho 634: www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.1 misho 635: www_freeAttributes(&attr);
1.2 misho 636: freeHeader(m);
1.1 misho 637: return -1;
638: }
639: memcpy(m->mime_epilog.iov_base, str, len - (eoh - str));
640: ((char*) m->mime_epilog.iov_base)[len - (eoh - str)] = 0;
641: m->mime_epilog.iov_len = len - (eoh - str) + 1;
642:
643: }
1.2 misho 644:
645: www_freeAttributes(&attr);
1.1 misho 646: }
647:
648: return 0;
649: }
650:
651: /*
652: * mime_calcRawSize() - Calculate estimated memory for data from parsed MIME part
653: *
654: * @m = Mime part
655: * return: -1 error or >-1 data size in mime part
656: */
657: int
658: mime_calcRawSize(struct tagMIME * __restrict m)
659: {
660: const char *s;
661: char *t;
662: int len;
663: register int i;
664:
665: if (!m) {
666: www_SetErr(EINVAL, "Mime part is NULL");
667: return -1;
668: }
669:
670: /* no body */
671: if (m->mime_body.iov_len < 1)
672: return 0;
673:
674: s = mime_getValue(m, "content-transfer-encoding");
675: if (!s)
676: return m->mime_body.iov_len;
677: /* strip whitespaces */
1.4 misho 678: while (isspace((int) *s))
1.1 misho 679: s++;
680: t = strchr(s, ';');
681: len = t ? strlen(s) : t - s;
682:
683: /* find proper encoding */
684: for (i = 0; i < sizeof n_encode / sizeof *n_encode; i++)
685: if (len == strlen(n_encode[i]) && !strncasecmp(s, n_encode[i], len))
686: return m->mime_body.iov_len;
687:
688: for (i = 0; i < sizeof encode / sizeof *encode; i++)
689: if (len == strlen(encode[i].name) && !strncasecmp(s, encode[i].name, len))
690: return m->mime_body.iov_len * encode[i].mul;
691:
692: /* fail */
693: return -1;
694: }
695:
696: /*
697: * mime_getRawData() - Get ready parsed data from MIME part body
698: *
699: * @m = Mime part
700: * @str = output data buffer
701: * @len = output data buffer length
702: * return: -1 error or >-1 data length in output buffer
703: */
704: int
705: mime_getRawData(struct tagMIME * __restrict m, char * __restrict str, int slen)
706: {
707: const char *s;
708: char *t;
709: int len;
710: register int i;
711:
712: if (!m || !str) {
713: www_SetErr(EINVAL, "Mime part or string is NULL");
714: return -1;
715: }
716:
717: /* no body */
718: if (m->mime_body.iov_len < 1)
719: return 0;
720:
721: s = mime_getValue(m, "content-transfer-encoding");
722: if (!s) {
723: memcpy(str, m->mime_body.iov_base, m->mime_body.iov_len > (slen - 1) ?
724: slen - 1 : m->mime_body.iov_len);
725: return m->mime_body.iov_len;
726: }
727:
728: /* strip whitespaces */
1.4 misho 729: while (isspace((int) *s))
1.1 misho 730: s++;
731: t = strchr(s, ';');
732: len = t ? strlen(s) : t - s;
733:
734: /* decoding body */
735: for (i = 0; i < sizeof encode / sizeof *encode; i++)
736: if (len == strlen(encode[i].name) && !strncasecmp(s, encode[i].name, len))
737: return encode[i].decode(m->mime_body.iov_base,
738: m->mime_body.iov_len, str);
739:
740: /* fail */
741: return -1;
742: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>