static char rcsid[] = "@(#)$Id: mpar_multipart.c,v 1.13 2006/05/07 08:35:31 hurtta Exp $"; /****************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.13 $ $State: Exp $ * * Author: Kari Hurtta (was hurtta+elm@ozone.FMI.FI) * * Some code based on mime_parse.c, which is * initially written by: Michael Elkins , 1995 * -- specially function mpar_multpart_parse() is based on function * multipart_parse() * *****************************************************************************/ #include "def_melib.h" #include "mpar_imp.h" #include "s_me.h" DEBUG_VAR(Debug,__FILE__,"mime"); #if ANSI_C #define S_(x) static x; #else #define S_(x) #endif #define MPAR_multipart_magic 0xFD03 struct mpar_multipart { unsigned short magic; /* MPAR_multipart_magic */ struct mimeinfo *parts; int part_count; }; S_(mpar_alloc mpar_multipart_alloc) static void mpar_multipart_alloc(D) struct mime_parser_data *D; { D->p.multipart = safe_malloc(sizeof (* (D->p.multipart))); /* bzero is defined on hdrs/defs.h */ bzero((void *)(D->p.multipart),sizeof (*(D->p.multipart))); D->p.multipart->magic = MPAR_multipart_magic; D->p.multipart->parts = NULL; D->p.multipart->part_count = 0; } S_(mpar_free mpar_multipart_free) static void mpar_multipart_free(D) struct mime_parser_data *D; { if (D->p.multipart) { if (D->p.multipart->magic != MPAR_multipart_magic) panic("MIME PARSER PANIC",__FILE__,__LINE__,"mpar_multipart_free", "Bad magic number",0); if (D->p.multipart->parts) { int i; for (i = 0; i < D->p.multipart->part_count; i++) { /* mime_t_clear will call mime_parser_free() if needed */ mime_t_clear(& (D->p.multipart->parts[i]));; } free(D->p.multipart->parts); D->p.multipart->parts = NULL; } D->p.multipart->part_count = 0; /* bzero is defined on hdrs/defs.h */ bzero((void *)(D->p.multipart),sizeof (*(D->p.multipart))); free(D->p.multipart); D->p.multipart = NULL; } } S_(mpar_parse mpar_multipart_parse) static int mpar_multipart_parse(D,s,defcharset,fp,header_error) struct mime_parser_data *D; struct mimeinfo *s; charset_t defcharset; FILE *fp; struct header_errors **header_error; { int ret = 1; /* Always succeed ... */ CONST char *boundary = NULL; int opts; int i; int blen = 0, len,last_pos; long end_offset, debug_pos; char buf[VERY_LONG_STRING]; char quess_boundary[STRING]; int ambiguous = 0; if (D->p.multipart->magic != MPAR_multipart_magic) panic("MIME PARSER PANIC",__FILE__,__LINE__,"mpar_multipart_parse", "Bad magic number",0); for (i = 0; i < D->p.multipart->part_count; i++) { /* mime_t_clear will call mime_parser_free() if needed */ mime_t_clear(& (D->p.multipart->parts[i]));; } D->p.multipart->part_count = 0; fseek (fp, s->offset, SEEK_SET); boundary = mime_get_boundary (s->TYPE_opts); opts = get_type_flags(s->TYPE); DPRINT(Debug,9,(&Debug, "mpar_multipart_parse- --> length=%d, boundary=%s\n", s->length, boundary ? boundary : "")); if (boundary) blen = strlen (boundary); end_offset = ftell (fp) + s->length; last_pos = ftell(fp); while ((debug_pos = ftell (fp)) < end_offset) { if ((len = mail_gets (buf, sizeof buf, fp)) == 0) break; DPRINT(Debug,49,(&Debug, "mpar_multipart_parse: Read %d bytes from %ld; last_pos=%d\n", len,debug_pos,last_pos)); if (buf[0] == '-' && buf[1] == '-' && (!boundary || strncmp (buf + 2, boundary, blen) == 0)) { header_list_ptr headers = NULL; long part_offset; long body_offset; /* If we matched to null boundary */ if (!boundary && len > 3) { int x; strnfcpy(quess_boundary,buf+2,len-2,sizeof quess_boundary, &x); if (x > 0 && quess_boundary[x-1] == '\n') { x--; quess_boundary[x] = '\0'; if (x > 0 && quess_boundary[x-1] == '\r') { x--; quess_boundary[x] = '\0'; } DPRINT(Debug,9,(&Debug, "mpar_multipart_parse: Quessing boundary: %Q, len=%d\n", quess_boundary,x)); boundary = quess_boundary; blen = x; lib_error(CATGETS(elm_msg_cat, MeSet, MeParseQuessMultipart, "Quessing multipart boundary")); } /* handle some ambiguous multipart boundary prefixes */ } else if (len > blen+2 && ' ' != buf[blen+2] && '-' != buf[blen+2] && '\t' != buf[blen+2] && '\r' != buf[blen+2] && '\n' != buf[blen+2]) { if (ambiguous++ == 0) lib_error(CATGETS(elm_msg_cat, MeSet, MeParseAmbiguousMultipart, "Ambiguous multipart boundary prefix")); goto noboundary; } /* Save the length of the previous part */ if (D->p.multipart->part_count > 0) { int idx = D->p.multipart->part_count-1; D->p.multipart->parts[idx].length = last_pos - D->p.multipart->parts[idx].offset; DPRINT(Debug,9,(&Debug, "mpar_multipart_parse: [%d] fixing length=%ld\n", idx, (long) D->p.multipart->parts[idx].length)); DPRINT(Debug,49,(&Debug, " : last_pos=%ld, offset=%ld\n", (long) last_pos, (long) D->p.multipart->parts[idx].offset)); } /* Check for the end boundary. */ if (buf[blen+2] == '-' && buf[blen+3] == '-') break; D->p.multipart->parts = safe_realloc(D->p.multipart->parts, (D->p.multipart->part_count+1) * sizeof (D->p.multipart->parts[0])); i = D->p.multipart->part_count++; mime_t_zero( & (D->p.multipart->parts[i])); part_offset = ftell (fp); headers = file_read_headers(fp,0); body_offset = ftell(fp); parse_mime_headers1(& (D->p.multipart->parts[i]), headers,part_offset, body_offset, opts,defcharset, header_error); delete_headers(&headers); if (!D->p.multipart->parts[i].TYPE) { DPRINT(Debug,1,(&Debug, "mpar_multipart_parse -- parse failure\n")); ret = 0; break; } DPRINT(Debug,9,(&Debug, "mpar_multipart_parse: (reading) [%d] content-type=%s/%s; flags=%d\n", i, get_major_type_name(D->p.multipart-> parts[i].TYPE), get_subtype_name(D->p.multipart->parts[i].TYPE), get_type_flags(D->p.multipart->parts[i].TYPE))); } noboundary: ; { /* mark position before CR LF */ int pos = ftell(fp); if (len > 1 && buf[len-2] == '\r' && buf[len-1] == '\n') last_pos = pos -2; else if (len > 0 && buf[len-1] == '\n') last_pos = pos -1; } } if (D->p.multipart->part_count > 0) { int idx = D->p.multipart->part_count-1; if (D->p.multipart->parts[idx].length != last_pos - D->p.multipart->parts[idx].offset) { D->p.multipart->parts[idx].length = last_pos - D->p.multipart->parts[idx].offset; DPRINT(Debug,9,(&Debug, "mpar_multipart_parse: fixing length=%ld (corrupted?)\n", (long) D->p.multipart->parts[idx].length)); lib_error(CATGETS(elm_msg_cat, MeSet, MeParseMultipartCorrupted, "Seems that multipart structure was corrupted.")); } } /* Now that we know what this message consists of, see if any of the * parts contain data that needs to be parsed. */ DPRINT(Debug,9,(&Debug, "mpar_multipart_parse: part count = %d\n", D->p.multipart->part_count)); for (i = 0; i < D->p.multipart->part_count; i++) { if (D->p.multipart->parts[i].magic != MIME_magic) mime_panic(__FILE__,__LINE__,"multipart_parse", "Bad magic number (array elem)"); if (!D->p.multipart->parts[i].TYPE) { DPRINT(Debug,9,(&Debug, "mpar_multipart_parse: (parsing) [%d] FAILED\n", i)); continue; } DPRINT(Debug,9,(&Debug, "mpar_multipart_parse: (parsing) [%d] content-type=%s/%s; flags=%d\n", i, get_major_type_name(D->p.multipart->parts[i].TYPE), get_subtype_name(D->p.multipart->parts[i].TYPE), get_type_flags(D->p.multipart->parts[i].TYPE))); /* PARSE PARTS */ mime_parser_parse(& (D->p.multipart->parts[i]),defcharset,fp, header_error); } /* Make sure to leave the stream at the end of the data since the * calling function might be assuming this. */ fseek (fp, end_offset, SEEK_SET); DPRINT(Debug,9,(&Debug, "mpar_multipart_parse=%d <-- DONE\n", ret)); return ret; } S_(mpar_subparts mpar_multipart_subparts) static int mpar_multipart_subparts(D) struct mime_parser_data *D; { if (D->p.multipart->magic != MPAR_multipart_magic) panic("MIME PARSER PANIC",__FILE__,__LINE__,"mpar_multipart_subparts", "Bad magic number",0); return D->p.multipart->part_count; } S_(mpar_index mpar_multipart_index) static struct mimeinfo *mpar_multipart_index(P,idx) struct mime_parser_data *P; int idx; { if (P->p.multipart->magic != MPAR_multipart_magic) panic("MIME PARSER PANIC",__FILE__,__LINE__,"mpar_multipart_index", "Bad magic number",0); if (idx < 0 || idx >= P->p.multipart->part_count) panic("MIME PARSER PANIC",__FILE__,__LINE__,"mpar_multipart_index", "Index out of range",0); return (& (P->p.multipart->parts[idx])); } S_(mpar_copy mpar_multipart_copy) static void mpar_multipart_copy(T,S) struct mime_parser_data *T; struct mime_parser_data *S; { int L,i; if (S->p.multipart->magic != MPAR_multipart_magic) panic("MIME PARSER PANIC",__FILE__,__LINE__,"mpar_multipart_copy", "Bad magic number",0); if (T->p.multipart->magic != MPAR_multipart_magic) panic("MIME PARSER PANIC",__FILE__,__LINE__,"mpar_multipart_copy", "Bad magic number",0); DPRINT(Debug,9,(&Debug, "mpar_multipart_copy: source %d parts -- resetting target %d parts\n", S->p.multipart->part_count, T->p.multipart->part_count )); for (i = 0; i < T->p.multipart->part_count; i++) mime_t_clear(& (T->p.multipart->parts[i])); L = S->p.multipart->part_count; if (L > 0) { DPRINT(Debug,9,(&Debug, "mpar_multipart_copy: Resizing target %d => %d\n", T->p.multipart->part_count,L)); T->p.multipart->parts = safe_realloc(T->p.multipart->parts, (L) * sizeof (T->p.multipart->parts[0])); DPRINT(Debug,9,(&Debug, "mpar_multipart_copy: resetting target %d - %d\n", T->p.multipart->part_count,L-1)); for (i = T->p.multipart->part_count; i < L; i++) mime_t_zero(& (T->p.multipart->parts[i])); DPRINT(Debug,9,(&Debug, "mpar_multipart_copy: Copying from source to target (%d parts)\n", L)); for (i = 0; i < L; i++) mime_t_copy(& (T->p.multipart->parts[i]), & (S->p.multipart->parts[i])); } T->p.multipart->part_count = L; DPRINT(Debug,9,(&Debug, "mpar_multipart_copy: target size = %d\n", T->p.multipart->part_count)); } static struct mime_parser multipart_PARSER = { mpar_multipart_alloc, mpar_multipart_free, mpar_multipart_parse, mpar_multipart_subparts, mpar_multipart_index, mpar_multipart_copy }; #if __GNUC__ #define MTH struct media_type_handle #define PARSER(A) handle_mime_parser, { parser_code: & A } #define CAST1 #else #define MTH struct COMPAT_media_type_handle #define PARSER(A) handle_mime_parser, (void *) & A #define CAST1 ( struct media_type_handle *) #endif static MTH multipart_parser_1 = { PARSER(multipart_PARSER) }; void register_multipart_parser() { register_mt_defhandler(MIME_TYPE_MULTIPART, CAST1 &multipart_parser_1); } /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */