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>