File:  [ELWIX - Embedded LightWeight unIX -] / libaitwww / src / mime.c
Revision 1.3.4.1: download - view: text, annotated - select for diffs - revision graph
Tue Jul 31 11:56:16 2012 UTC (11 years, 11 months ago) by misho
Branches: www1_3
Diff to: branchpoint 1.3: preferred, unified
remove header

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>