File:  [ELWIX - Embedded LightWeight unIX -] / libaitwww / src / mime.c
Revision 1.5: download - view: text, annotated - select for diffs - revision graph
Thu May 30 09:25:35 2013 UTC (11 years ago) by misho
Branches: MAIN
CVS tags: www3_4, www3_3, www3_2, www3_1, WWW3_3, WWW3_2, WWW3_1, WWW3_0, HEAD
version 3.0

    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.5 2013/05/30 09:25:35 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, 2013
   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 = e_malloc(len + 1);
   72: 	if (!s) {
   73: 		www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
   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 = e_malloc(len + 1);
   90: 	if (!s) {
   91: 		www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
   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: 		ait_freeVar(&c->cgi_name);
  154: 		ait_freeVar(&c->cgi_value);
  155: 
  156: 		SLIST_REMOVE_HEAD(&m->mime_header, cgi_node);
  157: 		e_free(c);
  158: 	}
  159: }
  160: 
  161: static ait_val_t *
  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;
  167: 	ait_val_t *ret = NULL;
  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 = e_realloc(s, crlf - str + off + 1);
  177: 		if (!tmp) {
  178: 			www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
  179: 			e_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: 	ret = ait_makeVar(string, s);
  198: 	if (!ret)
  199: 		www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
  200: 	e_free(s);
  201: 
  202: 	return ret;
  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;
  335: 	const char *next = NULL;
  336: 
  337: 	if (!str | !bdtag) {
  338: 		www_SetErr(EINVAL, "String or boundary tag is NULL");
  339: 		return NULL;
  340: 	}
  341: 
  342: 	/* init MIME */
  343: 	mime = e_malloc(sizeof(mime_t));
  344: 	if (!mime) {
  345: 		www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
  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) {
  355: 		e_free(mime);
  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) {
  361: 		e_free(bd[0].iov_base);
  362: 		e_free(mime);
  363: 		return NULL;
  364: 	} else
  365: 		bd[1].iov_len = strlen(bd[1].iov_base);
  366: 
  367: 	/* check boundary tag */
  368: 	if (memcmp(str, strstr(bd[0].iov_base, "--"), strlen(strstr(bd[0].iov_base, "--")))) {
  369: 		www_SetErr(EFAULT, "Bad content data, not found boundary tag");
  370: 		e_free(bd[1].iov_base);
  371: 		e_free(bd[0].iov_base);
  372: 		e_free(mime);
  373: 		return NULL;
  374: 	} else {
  375: 		str += strlen(strstr(bd[0].iov_base, "--"));
  376: 		len -= strlen(strstr(bd[0].iov_base, "--"));
  377: 	}
  378: 
  379: 	while (len > 0) {
  380: 		m = e_malloc(sizeof(struct tagMIME));
  381: 		if (!m) {
  382: 			www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
  383: 			mime_close(&mime);
  384: 			e_free(bd[1].iov_base);
  385: 			e_free(bd[0].iov_base);
  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);
  398: 			e_free(bd[1].iov_base);
  399: 			e_free(bd[0].iov_base);
  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;
  422: 	/* LLVM static code analyzer said for this - unusable
  423: 	 *
  424: 	len -= bd[0].iov_len;
  425: 	*/
  426: 
  427: 	e_free(bd[1].iov_base);
  428: 	e_free(bd[0].iov_base);
  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)
  439: 		e_free(m->mime_body.iov_base);
  440: 	if (m->mime_prolog.iov_base)
  441: 		e_free(m->mime_prolog.iov_base);
  442: 	if (m->mime_epilog.iov_base)
  443: 		e_free(m->mime_epilog.iov_base);
  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);
  466: 		e_free(m);
  467: 	}
  468: 
  469: 	e_free(*mime);
  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) {
  503: 			www_SetErr(EFAULT, "Bad MIME format message");
  504: 			freeHeader(m);
  505: 			return -1;
  506: 		}
  507: 
  508: 		c = e_malloc(sizeof(struct tagCGI));
  509: 		if (!c) {
  510: 			www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
  511: 			freeHeader(m);
  512: 			return -1;
  513: 		}
  514: 		/* get name */
  515: 		c->cgi_name = ait_allocVar();
  516: 		if (!c->cgi_name) {
  517: 			www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
  518: 			e_free(c);
  519: 			freeHeader(m);
  520: 			return -1;
  521: 		} else
  522: 			AIT_SET_STRLCPY(c->cgi_name, str, colon - str + 1);
  523: 		/* get value */
  524: 		c->cgi_value = hdrValue(colon + 1, e - colon - 1, &str);
  525: 		if (!c->cgi_value) {
  526: 			free(c->cgi_name);
  527: 			free(c);
  528: 			freeHeader(m);
  529: 			return -1;
  530: 		}
  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: 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)
  557: 		if (!strcasecmp(AIT_GET_STR(c->cgi_name), name))
  558: 			return AIT_GET_STR(c->cgi_value);
  559: 
  560: 	return NULL;
  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: 	ait_val_t *v;
  578: 
  579: 	if (!m || !str || (ssize_t) len < 0) {
  580: 		www_SetErr(EINVAL, "Mime part, string is NULL or length is less 0");
  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 */
  590: 		m->mime_body.iov_base = e_malloc(len - (eoh - str) + 1);
  591: 		if (!m->mime_body.iov_base) {
  592: 			www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
  593: 			freeHeader(m);
  594: 			return -1;
  595: 		}
  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);
  602: 		if (!attr) {
  603: 			freeHeader(m);
  604: 			return -1;
  605: 		}
  606: 		v = www_getAttribute(attr, "boundary");
  607: 		bd.iov_base = bd_begin(AIT_GET_STR(v));
  608: 		bd.iov_len = strlen(bd.iov_base);
  609: 		eb = findtextpos(eoh, len - (eoh - str), bd.iov_base, bd.iov_len);
  610: 		e_free(bd.iov_base);
  611: 
  612: 		/* set prolog if exists */
  613: 		if (eb != eoh) {
  614: 			m->mime_prolog.iov_base = e_malloc(eb - eoh + 1);
  615: 			if (!m->mime_prolog.iov_base) {
  616: 				www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
  617: 				www_freeAttributes(&attr);
  618: 				freeHeader(m);
  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: 
  626: 		v = www_getAttribute(attr, "boundary");
  627: 		m->mime_attach = mime_parseMultiPart(eb + 1, len - (eb + 1 - str), 
  628: 				AIT_GET_STR(v), &eoh);
  629: 
  630: 		/* set epilog if exists */
  631: 		if (eoh - str < len) {
  632: 			m->mime_epilog.iov_base = e_malloc(len - (eoh - str) + 1);
  633: 			if (!m->mime_epilog.iov_base) {
  634: 				www_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
  635: 				www_freeAttributes(&attr);
  636: 				freeHeader(m);
  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: 		}
  644: 
  645: 		www_freeAttributes(&attr);
  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 */
  678: 	while (isspace((int) *s))
  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 */
  729: 	while (isspace((int) *s))
  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>