/* ** ** Copyright (C) 1993 Swedish University Network (SUNET) ** ** ** This program is developed by UDAC, Uppsala University by commission ** of the Swedish University Network (SUNET). ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITTNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ** ** Martin.Wendel@its.uu.se ** Torbjorn.Wictorin@its.uu.se ** ** ITS ** P.O. Box 887 ** S-751 08 Uppsala ** Sweden ** */ #include "emil.h" /* * int * parse_message(inbuf, message) * * Parse message and divide into a hierarchical structure of message parts. * */ int parse_mime_message(struct message *m) { struct data *inbuf; static int not_first = 0; /* Initialize inbuf */ inbuf = (struct data *)m->sd; #ifdef DEBUG if (edebug) fprintf(stderr, "+ Parsing (MIME) body part %d at level %d and offset %lu.\n", inbuf->count, m->level, inbuf->offset); #endif /* Exit on empty input */ if (inbuf->size == 0 || (inbuf->end <= inbuf->offset)) { #ifdef DEBUG if (edebug) fprintf(stderr, "*** Empty input (failed).\n"); #endif logger(LOG_ERR, "parse_message: Empty input"); return(NOK); } if (not_first) { /* Check header if possible */ if (!m->headerdone && (m->sd->format != RFC822 || m->level == 0)) if (check_header(m) != OK) return(NOK); } else not_first = 1; /* Body starts here */ inbuf->bodystart = inbuf->offset; inbuf->linestart = inbuf->loffset; /* If Multipart create a child and run parse_message * on the child. * If MIME Multipart define the end boundary as end of * current data. If Mailtool Multipart define end according * to the lines field. Else leave end undefined. */ if (inbuf->encoding == EMULTI) { int status; if ((status = parse_mime_multi(m)) == OK) { #ifdef DEBUG if (edebug) fprintf(stderr, "+ Marked up (MIME) multipart %d at level %d starting at %lu and ending at %lu.\n", inbuf->count, m->level, inbuf->bodystart, inbuf->bodyend); #endif return(OK); } if (status == NOK) { #ifdef DEBUG if (edebug) fprintf(stderr, "+ MIME body part %d at level %d failed.\n", inbuf->count, m->level); #endif return(NOK); } } else { if (m->sd->bodyend == 0) m->sd->bodyend = m->sd->end; } if (check_encoding(m) != OK) m->sd->encoding = E7BIT; return(OK); } int parse_mime_multi(struct message *m) { struct data *childbuf, *inbuf; struct message *childm; #ifdef DEBUG if (edebug) fprintf(stderr, "+ parse_mime_multi\n"); #endif inbuf = (struct data *)m->sd; /* Find end of part if prematured by an end boundary (MIME) */ if (m->sd->endbound != NULL) set_end_by_boundary(m, m->sd->endbound); else { /* Body end is end of data */ inbuf->bodyend = inbuf->end; inbuf->lineend = inbuf->lend; } /* Copy off a child */ childm = (struct message *)copy_mstruct(m, 0); /* Set more child data */ childbuf = childm->sd; childm->level = m->level + 1; childm->parent = m; childm->bigsib = childm; /* Loop back */ childbuf->end = (inbuf->bodyend != 0) ? inbuf->bodyend: inbuf->end; childbuf->lend = (inbuf->lineend != 0) ? inbuf->lineend: inbuf->lend; childbuf->offset = inbuf->bodystart; if (parse_mime_siblings(childm) == OK) { m->child = childm; #ifdef DEBUG if (edebug) fprintf(stderr, " *parse_mime_multi: success, multipart OK\n"); #endif return(OK); } else { /* Erroneous multipart, set type to text instead and * run test check below */ #ifdef DEBUG if (edebug) fprintf(stderr, " *parse_mime_multi: failed, set type to TEXT\n"); #endif m->sd->encoding = E7BIT; m->sd->type = NEWSTR("TEXT"); check_bits(m->sd); return(FAIL); } } int parse_mime_siblings(struct message *m) { struct data *inbuf, *sibbuf; struct message *sibm; inbuf = m->sd; #ifdef DEBUG if (edebug) fprintf(stderr, "+ parse_mime_siblings\n"); #endif /* Parse child */ /* If this is a body part in a multipart with startbound set * find the start of this body part */ if (m->parent != NULL && m->parent->sd->startbound != NULL) { if (move_past_boundary(m, m->parent->sd->startbound) != OK) return(NOK); } /* If multipart, find end of bodypart */ if (m->parent != NULL && m->parent->sd->startbound != NULL) set_end_by_boundary(m, m->parent->sd->startbound); parse_mime_message(m); #ifdef DEBUG if (edebug) fprintf(stderr, "+ Marked up (MIME) body part %d at level %d starting at %lu and ending at %lu.\n", inbuf->count, m->level, inbuf->bodystart, inbuf->bodyend); #endif /* FIX */ if (m->sd->encoding == EMULTI && m->sd->endbound != NULL) { int tttt; move_past_boundary(m, m->sd->endbound); for (;;) { tttt = getline(m->sd); #ifdef DEBUG if (edebug) fprintf(stderr," getline = %d\n", tttt); #endif if (tttt == 1) { inbuf->offset += tttt; inbuf->loffset += 1; continue; } if (tttt == 2 && *(m->sd->contents + m->sd->offset) == '\r') { inbuf->offset += tttt; inbuf->loffset += 1; continue; } break; } } else /* END_FIX */ m->sd->offset = m->sd->bodyend; if (getline(m->sd) == 0) return(OK); if (m->sd->offset < m->sd->end) { /* Allocate siblings data sructure */ sibm = (struct message *)copy_mstruct(m, 0); sibbuf = sibm->sd; sibbuf->end = inbuf->end; sibbuf->lend = inbuf->lend; sibbuf->offset = inbuf->bodyend; sibm->bigsib = m->bigsib; sibm->level = m->level; sibm->parent = m->parent; /* Run Sibling */ if (parse_mime_siblings(sibm) == OK) { #ifdef DEBUG if (edebug) fprintf(stderr, "* sibling ended at offset %lu\n", sibbuf->offset); #endif m->sibling = sibm; if (m->parent) m->parent->children += 1; return(OK); } else return(NOK); /* Successful return from current part */ return(OK); } return(OK); }