Annotation of libaitwww/src/mime.c, revision 1.3.4.2

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