File:  [ELWIX - Embedded LightWeight unIX -] / libaitwww / src / mime.c
Revision 1.3: download - view: text, annotated - select for diffs - revision graph
Thu Mar 15 01:59:37 2012 UTC (12 years, 3 months ago) by misho
Branches: MAIN
CVS tags: www1_3, www1_2, WWW1_2, WWW1_1, HEAD
version 1.1

    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 2012/03/15 01:59:37 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(EFAULT, "Bad header format of MIME part");
  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 = NULL;
  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: 
  363: 	/* check boundary tag */
  364: 	if (memcmp(str, strstr(bd[0].iov_base, "--"), strlen(strstr(bd[0].iov_base, "--")))) {
  365: 		www_SetErr(EFAULT, "Bad content data, not found boundary tag");
  366: 		free(bd[1].iov_base);
  367: 		free(bd[0].iov_base);
  368: 		free(mime);
  369: 		return NULL;
  370: 	} else {
  371: 		str += strlen(strstr(bd[0].iov_base, "--"));
  372: 		len -= strlen(strstr(bd[0].iov_base, "--"));
  373: 	}
  374: 
  375: 	while (len > 0) {
  376: 		m = malloc(sizeof(struct tagMIME));
  377: 		if (!m) {
  378: 			LOGERR;
  379: 			mime_close(&mime);
  380: 			free(bd[1].iov_base);
  381: 			free(bd[0].iov_base);
  382: 			return NULL;
  383: 		} else {
  384: 			memset(m, 0, sizeof(struct tagMIME));
  385: 			SLIST_INIT(&m->mime_header);
  386: 		}
  387: 
  388: 		if (!(next = findtextpos(str, len, bd[0].iov_base, bd[0].iov_len)))
  389: 			next = findtextpos(str, len, bd[1].iov_base, bd[1].iov_len);
  390: 
  391: 		/* parse message between tags */
  392: 		if (mime_readPart(m, str, next - str)) {
  393: 			mime_close(&mime);
  394: 			free(bd[1].iov_base);
  395: 			free(bd[0].iov_base);
  396: 			return NULL;
  397: 		}
  398: 
  399: 		str += next - str;
  400: 		len -= next - str;
  401: 
  402: 		/* add to mime session */
  403: 		if (!old)
  404: 			SLIST_INSERT_HEAD(mime, m, mime_node);
  405: 		else
  406: 			SLIST_INSERT_AFTER(old, m, mime_node);
  407: 		old = m;
  408: 
  409: 		/* match part termination tag */
  410: 		if (!memcmp(str, bd[1].iov_base, bd[1].iov_len))
  411: 			break;
  412: 
  413: 		str += bd[0].iov_len;
  414: 		len -= bd[0].iov_len;
  415: 	}
  416: 
  417: 	str += bd[0].iov_len;
  418: 	/* LLVM static code analyzer said for this - unusable
  419: 	 *
  420: 	len -= bd[0].iov_len;
  421: 	*/
  422: 
  423: 	free(bd[1].iov_base);
  424: 	free(bd[0].iov_base);
  425: 
  426: 	if (end)
  427: 		*end = str;
  428: 	return mime;
  429: }
  430: 
  431: static inline void
  432: freeMIME(struct tagMIME * __restrict m)
  433: {
  434: 	if (m->mime_body.iov_base)
  435: 		free(m->mime_body.iov_base);
  436: 	if (m->mime_prolog.iov_base)
  437: 		free(m->mime_prolog.iov_base);
  438: 	if (m->mime_epilog.iov_base)
  439: 		free(m->mime_epilog.iov_base);
  440: 
  441: 	freeHeader(m);
  442: 	mime_close(&m->mime_attach);
  443: }
  444: 
  445: /*
  446:  * mime_close() - Close MIME session and free all resources
  447:  *
  448:  * @mime = Inited mime session
  449:  * return: none
  450:  */
  451: void
  452: mime_close(mime_t ** __restrict mime)
  453: {
  454: 	struct tagMIME *m;
  455: 
  456: 	if (!mime || !*mime)
  457: 		return;
  458: 
  459: 	while ((m = SLIST_FIRST(*mime))) {
  460: 		SLIST_REMOVE_HEAD(*mime, mime_node);
  461: 		freeMIME(m);
  462: 		free(m);
  463: 	}
  464: 
  465: 	free(*mime);
  466: 	*mime = NULL;
  467: }
  468: 
  469: /*
  470:  * mime_parseHeader() - Parse MIME header pairs
  471:  *
  472:  * @m = Mime part
  473:  * @str = String
  474:  * @len = String length
  475:  * @end = End of parsed part
  476:  * return: -1 error or 0 ok
  477:  */
  478: int
  479: mime_parseHeader(struct tagMIME * __restrict m, const char *str, size_t len, const char **end)
  480: {
  481: 	const char *e, *colon, *eoh;
  482: 	struct tagCGI *c, *old = NULL;
  483: 
  484: 	if (!m || !str) {
  485: 		www_SetErr(EINVAL, "Mime part or string is NULL");
  486: 		return -1;
  487: 	} else
  488: 		e = str + len;
  489: 
  490: 	while (str < e) {
  491: 		if (!memcmp(str, CRLF, strlen(CRLF))) {
  492: 			str += 2;
  493: 			break;
  494: 		}
  495: 
  496: 		colon = memchr(str, ':', e - str);
  497: 		eoh = findtextpos(str, e - str, CRLF, strlen(CRLF));
  498: 		if (!colon || !eoh || colon > eoh) {
  499: 			www_SetErr(EFAULT, "Bad MIME format message");
  500: 			freeHeader(m);
  501: 			return -1;
  502: 		}
  503: 
  504: 		c = malloc(sizeof(struct tagCGI));
  505: 		if (!c) {
  506: 			LOGERR;
  507: 			freeHeader(m);
  508: 			return -1;
  509: 		}
  510: 		/* get name */
  511: 		c->cgi_name = malloc(colon - str + 1);
  512: 		if (!c->cgi_name) {
  513: 			LOGERR;
  514: 			free(c);
  515: 			freeHeader(m);
  516: 			return -1;
  517: 		} else {
  518: 			memcpy(c->cgi_name, str, colon - str);
  519: 			c->cgi_name[colon - str] = 0;
  520: 		}
  521: 		/* get value */
  522: 		c->cgi_value = hdrValue(colon + 1, e - colon - 1, &str);
  523: 		if (!c->cgi_value) {
  524: 			free(c->cgi_name);
  525: 			free(c);
  526: 			freeHeader(m);
  527: 			return -1;
  528: 		}
  529: 
  530: 		if (!old)
  531: 			SLIST_INSERT_HEAD(&m->mime_header, c, cgi_node);
  532: 		else
  533: 			SLIST_INSERT_AFTER(old, c, cgi_node);
  534: 		old = c;
  535: 	}
  536: 
  537: 	if (end)
  538: 		*end = str;
  539: 	return 0;
  540: }
  541: 
  542: /*
  543:  * mime_getValue() - Get value from MIME header
  544:  *
  545:  * @m = Mime part
  546:  * @name = Header name
  547:  * return: NULL not found or !=NULL value
  548:  */
  549: inline const char *
  550: mime_getValue(struct tagMIME * __restrict m, const char *name)
  551: {
  552: 	struct tagCGI *c;
  553: 	const char *v = NULL;
  554: 
  555: 	SLIST_FOREACH(c, &m->mime_header, cgi_node)
  556: 		if (!strcasecmp(c->cgi_name, name)) {
  557: 			v = c->cgi_value;
  558: 			break;
  559: 		}
  560: 	return v;
  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;
  577: 
  578: 	if (!m || !str || (ssize_t) len < 0) {
  579: 		www_SetErr(EINVAL, "Mime part, string is NULL or length is less 0");
  580: 		return -1;
  581: 	}
  582: 
  583: 	if (mime_parseHeader(m, str, len, &eoh))
  584: 		return -1;
  585: 
  586: 	ct = mime_getValue(m, "content-type");
  587: 	if (!ct || www_cmptype(ct, "multipart")) {
  588: 		/* not multi part, assign like body element */
  589: 		m->mime_body.iov_base = malloc(len - (eoh - str) + 1);
  590: 		if (!m->mime_body.iov_base) {
  591: 			LOGERR;
  592: 			freeHeader(m);
  593: 			return -1;
  594: 		}
  595: 		memcpy(m->mime_body.iov_base, eoh, len - (eoh - str));
  596: 		((char*) m->mime_body.iov_base)[len - (eoh - str)] = 0;
  597: 		m->mime_body.iov_len = len - (eoh - str) + 1;
  598: 	} else {
  599: 		/* multi part */
  600: 		attr = www_parseAttributes(&ct);
  601: 		if (!attr) {
  602: 			freeHeader(m);
  603: 			return -1;
  604: 		}
  605: 		bd.iov_base = bd_begin(www_getAttribute(attr, "boundary"));
  606: 		bd.iov_len = strlen(bd.iov_base);
  607: 		eb = findtextpos(eoh, len - (eoh - str), bd.iov_base, bd.iov_len);
  608: 		free(bd.iov_base);
  609: 
  610: 		/* set prolog if exists */
  611: 		if (eb != eoh) {
  612: 			m->mime_prolog.iov_base = malloc(eb - eoh + 1);
  613: 			if (!m->mime_prolog.iov_base) {
  614: 				LOGERR;
  615: 				www_freeAttributes(&attr);
  616: 				freeHeader(m);
  617: 				return -1;
  618: 			}
  619: 			memcpy(m->mime_prolog.iov_base, eoh, eb - eoh);
  620: 			((char*) m->mime_prolog.iov_base)[eb - eoh] = 0;
  621: 			m->mime_prolog.iov_len = eb - eoh + 1;
  622: 		}
  623: 
  624: 		m->mime_attach = mime_parseMultiPart(eb + 1, len - (eb + 1 - str), 
  625: 				www_getAttribute(attr, "boundary"), &eoh);
  626: 
  627: 		/* set epilog if exists */
  628: 		if (eoh - str < len) {
  629: 			m->mime_epilog.iov_base = malloc(len - (eoh - str) + 1);
  630: 			if (!m->mime_epilog.iov_base) {
  631: 				LOGERR;
  632: 				www_freeAttributes(&attr);
  633: 				freeHeader(m);
  634: 				return -1;
  635: 			}
  636: 			memcpy(m->mime_epilog.iov_base, str, len - (eoh - str));
  637: 			((char*) m->mime_epilog.iov_base)[len - (eoh - str)] = 0;
  638: 			m->mime_epilog.iov_len = len - (eoh - str) + 1;
  639: 
  640: 		}
  641: 
  642: 		www_freeAttributes(&attr);
  643: 	}
  644: 
  645: 	return 0;
  646: }
  647: 
  648: /*
  649:  * mime_calcRawSize() - Calculate estimated memory for data from parsed MIME part
  650:  *
  651:  * @m = Mime part
  652:  * return: -1 error or >-1 data size in mime part
  653:  */
  654: int
  655: mime_calcRawSize(struct tagMIME * __restrict m)
  656: {
  657: 	const char *s;
  658: 	char *t;
  659: 	int len;
  660: 	register int i;
  661: 
  662: 	if (!m) {
  663: 		www_SetErr(EINVAL, "Mime part is NULL");
  664: 		return -1;
  665: 	}
  666: 
  667: 	/* no body */
  668: 	if (m->mime_body.iov_len < 1)
  669: 		return 0;
  670: 
  671: 	s = mime_getValue(m, "content-transfer-encoding");
  672: 	if (!s)
  673: 		return m->mime_body.iov_len;
  674: 	/* strip whitespaces */
  675: 	while (isspace(*s))
  676: 		s++;
  677: 	t = strchr(s, ';');
  678: 	len = t ? strlen(s) : t - s;
  679: 
  680: 	/* find proper encoding */
  681: 	for (i = 0; i < sizeof n_encode / sizeof *n_encode; i++)
  682: 		if (len == strlen(n_encode[i]) && !strncasecmp(s, n_encode[i], len))
  683: 			return m->mime_body.iov_len;
  684: 
  685: 	for (i = 0; i < sizeof encode / sizeof *encode; i++)
  686: 		if (len == strlen(encode[i].name) && !strncasecmp(s, encode[i].name, len))
  687: 			return m->mime_body.iov_len * encode[i].mul;
  688: 
  689: 	/* fail */
  690: 	return -1;
  691: }
  692: 
  693: /*
  694:  * mime_getRawData() - Get ready parsed data from MIME part body
  695:  *
  696:  * @m = Mime part
  697:  * @str = output data buffer
  698:  * @len = output data buffer length
  699:  * return: -1 error or >-1 data length in output buffer
  700:  */
  701: int
  702: mime_getRawData(struct tagMIME * __restrict m, char * __restrict str, int slen)
  703: {
  704: 	const char *s;
  705: 	char *t;
  706: 	int len;
  707: 	register int i;
  708: 
  709: 	if (!m || !str) {
  710: 		www_SetErr(EINVAL, "Mime part or string is NULL");
  711: 		return -1;
  712: 	}
  713: 
  714: 	/* no body */
  715: 	if (m->mime_body.iov_len < 1)
  716: 		return 0;
  717: 
  718: 	s = mime_getValue(m, "content-transfer-encoding");
  719: 	if (!s) {
  720: 		memcpy(str, m->mime_body.iov_base, m->mime_body.iov_len > (slen - 1) ? 
  721: 				slen - 1 : m->mime_body.iov_len);
  722: 		return m->mime_body.iov_len;
  723: 	}
  724: 
  725: 	/* strip whitespaces */
  726: 	while (isspace(*s))
  727: 		s++;
  728: 	t = strchr(s, ';');
  729: 	len = t ? strlen(s) : t - s;
  730: 
  731: 	/* decoding body */
  732: 	for (i = 0; i < sizeof encode / sizeof *encode; i++)
  733: 		if (len == strlen(encode[i].name) && !strncasecmp(s, encode[i].name, len))
  734: 			return encode[i].decode(m->mime_body.iov_base, 
  735: 					m->mime_body.iov_len, str);
  736: 
  737: 	/* fail */
  738: 	return -1;
  739: }

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