зеркало из https://github.com/mozilla/gecko-dev.git
306 строки
8.4 KiB
C
306 строки
8.4 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.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 <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
|