/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ /* mimeobj.c --- definition of the MimeObject class (see mimei.h) Created: Jamie Zawinski , 15-May-96. */ #include "rosetta.h" #include "mimeobj.h" #ifndef MOZILLA_30 /* Way to destroy any notions of modularity or class hierarchy, Terry! */ # include "mimetpla.h" # include "mimethtm.h" # include "mimecont.h" #endif /* !MOZILLA_30 */ MimeDefClass (MimeObject, MimeObjectClass, mimeObjectClass, NULL); static int MimeObject_initialize (MimeObject *); static void MimeObject_finalize (MimeObject *); static int MimeObject_parse_begin (MimeObject *); static int MimeObject_parse_buffer (char *, int32, MimeObject *); static int MimeObject_parse_line (char *, int32, MimeObject *); static int MimeObject_parse_eof (MimeObject *, XP_Bool); static int MimeObject_parse_end (MimeObject *, XP_Bool); static XP_Bool MimeObject_displayable_inline_p (MimeObjectClass *class, MimeHeaders *hdrs); #if defined(DEBUG) && defined(XP_UNIX) static int MimeObject_debug_print (MimeObject *, FILE *, int32 depth); #endif static int MimeObjectClassInitialize(MimeObjectClass *class) { XP_ASSERT(!class->class_initialized); class->initialize = MimeObject_initialize; class->finalize = MimeObject_finalize; class->parse_begin = MimeObject_parse_begin; class->parse_buffer = MimeObject_parse_buffer; class->parse_line = MimeObject_parse_line; class->parse_eof = MimeObject_parse_eof; class->parse_end = MimeObject_parse_end; class->displayable_inline_p = MimeObject_displayable_inline_p; #if defined(DEBUG) && defined(XP_UNIX) class->debug_print = MimeObject_debug_print; #endif return 0; } static int MimeObject_initialize (MimeObject *obj) { /* This is an abstract class; it shouldn't be directly instanciated. */ XP_ASSERT(obj->class != &mimeObjectClass); /* Set up the content-type and encoding. */ if (!obj->content_type && obj->headers) obj->content_type = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, TRUE, FALSE); if (!obj->encoding && obj->headers) obj->encoding = MimeHeaders_get (obj->headers, HEADER_CONTENT_TRANSFER_ENCODING, TRUE, FALSE); /* Special case to normalize some types and encodings to a canonical form. (These are nonstandard types/encodings which have been seen to appear in multiple forms; we normalize them so that things like looking up icons and extensions has consistent behavior for the receiver, regardless of the "alias" type that the sender used.) */ if (!obj->content_type) ; else if (!strcasecomp(obj->content_type, APPLICATION_UUENCODE2) || !strcasecomp(obj->content_type, APPLICATION_UUENCODE3) || !strcasecomp(obj->content_type, APPLICATION_UUENCODE4)) { XP_FREE(obj->content_type); obj->content_type = XP_STRDUP(APPLICATION_UUENCODE); } else if (!strcasecomp(obj->content_type, IMAGE_XBM2) || !strcasecomp(obj->content_type, IMAGE_XBM3)) { XP_FREE(obj->content_type); obj->content_type = XP_STRDUP(IMAGE_XBM); } if (!obj->encoding) ; else if (!strcasecomp(obj->encoding, ENCODING_UUENCODE2) || !strcasecomp(obj->encoding, ENCODING_UUENCODE3) || !strcasecomp(obj->encoding, ENCODING_UUENCODE4)) { XP_FREE(obj->encoding); obj->encoding = XP_STRDUP(ENCODING_UUENCODE); } else if (!strcasecomp(obj->encoding, ENCODING_COMPRESS2)) { XP_FREE(obj->encoding); obj->encoding = XP_STRDUP(ENCODING_COMPRESS); } else if (!strcasecomp(obj->encoding, ENCODING_GZIP2)) { XP_FREE(obj->encoding); obj->encoding = XP_STRDUP(ENCODING_GZIP); } return 0; } static void MimeObject_finalize (MimeObject *obj) { obj->class->parse_eof (obj, FALSE); obj->class->parse_end (obj, FALSE); if (obj->headers) { MimeHeaders_free(obj->headers); obj->headers = 0; } /* Should have been freed by parse_eof, but just in case... */ XP_ASSERT(!obj->ibuffer); XP_ASSERT(!obj->obuffer); FREEIF (obj->ibuffer); FREEIF (obj->obuffer); FREEIF(obj->content_type); FREEIF(obj->encoding); if (obj->options && obj->options->state) { XP_FREE(obj->options->state); obj->options->state = 0; } } static int MimeObject_parse_begin (MimeObject *obj) { XP_ASSERT (!obj->closed_p); /* If we haven't set up the state object yet, then this should be the outermost object... */ if (obj->options && !obj->options->state) { XP_ASSERT(!obj->headers); /* should be the outermost object. */ obj->options->state = XP_NEW(MimeParseStateObject); if (!obj->options->state) return MK_OUT_OF_MEMORY; XP_MEMSET(obj->options->state, 0, sizeof(*obj->options->state)); obj->options->state->root = obj; obj->options->state->separator_suppressed_p = TRUE; /* no first sep */ } /* Decide whether this object should be output or not... */ if (!obj->options || !obj->options->output_fn) obj->output_p = FALSE; else if (!obj->options->part_to_load) obj->output_p = TRUE; else { char *id = mime_part_address(obj); if (!id) return MK_OUT_OF_MEMORY; obj->output_p = !XP_STRCMP(id, obj->options->part_to_load); XP_FREE(id); } #ifndef MOZILLA_30 /* Way to destroy any notions of modularity or class hierarchy, Terry! */ if (obj->options && obj->options->nice_html_only_p) { if (!mime_subclass_p(obj->class, (MimeObjectClass*) &mimeInlineTextHTMLClass) && !mime_subclass_p(obj->class, (MimeObjectClass*) &mimeInlineTextPlainClass) && !mime_subclass_p(obj->class, (MimeObjectClass*) &mimeContainerClass)) { obj->output_p = FALSE; } } #endif /* !MOZILLA_30 */ return 0; } static int MimeObject_parse_buffer (char *buffer, int32 size, MimeObject *obj) { XP_ASSERT(!obj->closed_p); if (obj->closed_p) return -1; return XP_LineBuffer (buffer, size, &obj->ibuffer, &obj->ibuffer_size, &obj->ibuffer_fp, TRUE, ((int32 (*) (char *, uint32, void *)) /* This cast is to turn void into MimeObject */ obj->class->parse_line), obj); } static int MimeObject_parse_line (char *line, int32 length, MimeObject *obj) { /* This method should never be called. */ XP_ASSERT(0); return -1; } static int MimeObject_parse_eof (MimeObject *obj, XP_Bool abort_p) { if (obj->closed_p) return 0; XP_ASSERT(!obj->parsed_p); /* If there is still data in the ibuffer, that means that the last line of this part didn't end in a newline; so push it out anyway (this means that the parse_line method will be called with a string with no trailing newline, which isn't the usual case.) */ if (!abort_p && obj->ibuffer_fp > 0) { int status = obj->class->parse_line (obj->ibuffer, obj->ibuffer_fp, obj); obj->ibuffer_fp = 0; if (status < 0) { obj->closed_p = TRUE; return status; } } obj->closed_p = TRUE; return 0; } static int MimeObject_parse_end (MimeObject *obj, XP_Bool abort_p) { if (obj->parsed_p) { XP_ASSERT(obj->closed_p); return 0; } /* We won't be needing these buffers any more; nuke 'em. */ FREEIF(obj->ibuffer); obj->ibuffer_fp = 0; obj->ibuffer_size = 0; FREEIF(obj->obuffer); obj->obuffer_fp = 0; obj->obuffer_size = 0; obj->parsed_p = TRUE; return 0; } static XP_Bool MimeObject_displayable_inline_p (MimeObjectClass *class, MimeHeaders *hdrs) { XP_ASSERT(0); /* This method should never be called. */ return FALSE; } #if defined(DEBUG) && defined(XP_UNIX) static int MimeObject_debug_print (MimeObject *obj, FILE *stream, int32 depth) { int i; char *addr = mime_part_address(obj); for (i=0; i < depth; i++) fprintf(stream, " "); fprintf(stream, "<%s %s 0x%08X>\n", obj->class->class_name, addr ? addr : "???", (uint32) obj); FREEIF(addr); return 0; } #endif