gecko-dev/lib/libmime/mimeobj.c

310 lines
8.5 KiB
C

/* -*- 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.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/* mimeobj.c --- definition of the MimeObject class (see mimei.h)
Created: Jamie Zawinski <jwz@netscape.com>, 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