home *** CD-ROM | disk | FTP | other *** search
- /* -*- 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.
- */
-
- /* mimeunty.h --- definition of the MimeUntypedText class (see mimei.h)
- Created: Jamie Zawinski <jwz@netscape.com>, 15-May-96.
- */
-
- #include "mimeunty.h"
-
- #define MIME_SUPERCLASS mimeContainerClass
- MimeDefClass(MimeUntypedText, MimeUntypedTextClass,
- mimeUntypedTextClass, &MIME_SUPERCLASS);
-
- static int MimeUntypedText_initialize (MimeObject *);
- static void MimeUntypedText_finalize (MimeObject *);
- static int MimeUntypedText_parse_begin (MimeObject *);
- static int MimeUntypedText_parse_line (char *, int32, MimeObject *);
-
- static int MimeUntypedText_open_subpart (MimeObject *obj,
- MimeUntypedTextSubpartType ttype,
- const char *type,
- const char *enc,
- const char *name,
- const char *desc);
- static int MimeUntypedText_close_subpart (MimeObject *obj);
-
- static XP_Bool MimeUntypedText_uu_begin_line_p(const char *line, int32 length,
- MimeDisplayOptions *opt,
- char **type_ret,
- char **name_ret);
- static XP_Bool MimeUntypedText_uu_end_line_p(const char *line, int32 length);
-
- static XP_Bool MimeUntypedText_binhex_begin_line_p(const char *line,
- int32 length,
- MimeDisplayOptions *opt);
- static XP_Bool MimeUntypedText_binhex_end_line_p(const char *line,
- int32 length);
-
- static int
- MimeUntypedTextClassInitialize(MimeUntypedTextClass *class)
- {
- MimeObjectClass *oclass = (MimeObjectClass *) class;
- XP_ASSERT(!oclass->class_initialized);
- oclass->initialize = MimeUntypedText_initialize;
- oclass->finalize = MimeUntypedText_finalize;
- oclass->parse_begin = MimeUntypedText_parse_begin;
- oclass->parse_line = MimeUntypedText_parse_line;
- return 0;
- }
-
-
- static int
- MimeUntypedText_initialize (MimeObject *object)
- {
- return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
- }
-
- static void
- MimeUntypedText_finalize (MimeObject *object)
- {
- MimeUntypedText *uty = (MimeUntypedText *) object;
-
- if (uty->open_hdrs)
- {
- /* Oops, those shouldn't still be here... */
- MimeHeaders_free(uty->open_hdrs);
- uty->open_hdrs = 0;
- }
-
- /* What about the open_subpart? We're gonna have to assume that it
- is also on the MimeContainer->children list, and will get cleaned
- up by that class. */
-
- ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
- }
-
- static int
- MimeUntypedText_parse_begin (MimeObject *obj)
- {
- return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
- }
-
- static int
- MimeUntypedText_parse_line (char *line, int32 length, MimeObject *obj)
- {
- MimeUntypedText *uty = (MimeUntypedText *) obj;
- int status = 0;
- char *name = 0, *type = 0;
- XP_Bool begin_line_p = FALSE;
-
- XP_ASSERT(line && *line);
- if (!line || !*line) return -1;
-
- /* If we're supposed to write this object, but aren't supposed to convert
- it to HTML, simply pass it through unaltered. */
- if (obj->output_p &&
- obj->options &&
- !obj->options->write_html_p &&
- obj->options->output_fn)
- return MimeObject_write(obj, line, length, TRUE);
-
-
- /* Open a new sub-part if this line demands it.
- */
- if (line[0] == 'b' &&
- MimeUntypedText_uu_begin_line_p(line, length, obj->options,
- &type, &name))
- {
- /* Close the old part and open a new one. */
- status = MimeUntypedText_open_subpart (obj,
- MimeUntypedTextSubpartTypeUUE,
- type, ENCODING_UUENCODE,
- name, NULL);
- FREEIF(name);
- FREEIF(type);
- if (status < 0) return status;
- begin_line_p = TRUE;
- }
-
- else if (line[0] == '(' && line[1] == 'T' &&
- MimeUntypedText_binhex_begin_line_p(line, length, obj->options))
- {
- /* Close the old part and open a new one. */
- status = MimeUntypedText_open_subpart (obj,
- MimeUntypedTextSubpartTypeBinhex,
- APPLICATION_BINHEX, NULL,
- NULL, NULL);
- if (status < 0) return status;
- begin_line_p = TRUE;
- }
-
- /* Open a text/plain sub-part if there is no sub-part open.
- */
- if (!uty->open_subpart)
- {
- XP_ASSERT(!begin_line_p);
- status = MimeUntypedText_open_subpart (obj,
- MimeUntypedTextSubpartTypeText,
- TEXT_PLAIN, NULL, NULL, NULL);
- XP_ASSERT(uty->open_subpart);
- if (!uty->open_subpart) return -1;
- if (status < 0) return status;
- }
-
- /* Hand this line to the currently-open sub-part.
- */
- status = uty->open_subpart->class->parse_buffer(line, length,
- uty->open_subpart);
- if (status < 0) return status;
-
- /* Close this sub-part if this line demands it.
- */
- if (begin_line_p)
- ;
- else if (line[0] == 'e' &&
- uty->type == MimeUntypedTextSubpartTypeUUE &&
- MimeUntypedText_uu_end_line_p(line, length))
- {
- status = MimeUntypedText_close_subpart (obj);
- if (status < 0) return status;
- XP_ASSERT(!uty->open_subpart);
- }
- else if (uty->type == MimeUntypedTextSubpartTypeBinhex &&
- MimeUntypedText_binhex_end_line_p(line, length))
- {
- status = MimeUntypedText_close_subpart (obj);
- if (status < 0) return status;
- XP_ASSERT(!uty->open_subpart);
- }
-
- return 0;
- }
-
-
- static int
- MimeUntypedText_close_subpart (MimeObject *obj)
- {
- MimeUntypedText *uty = (MimeUntypedText *) obj;
- int status;
-
- if (uty->open_subpart)
- {
- status = uty->open_subpart->class->parse_eof(uty->open_subpart, FALSE);
- uty->open_subpart = 0;
-
- XP_ASSERT(uty->open_hdrs);
- if (uty->open_hdrs)
- {
- MimeHeaders_free(uty->open_hdrs);
- uty->open_hdrs = 0;
- }
- uty->type = MimeUntypedTextSubpartTypeText;
- if (status < 0) return status;
-
- /* Never put out a separator between sub-parts of UntypedText.
- (This bypasses the rule that text/plain subparts always
- have separators before and after them.)
- */
- if (obj->options && obj->options->state)
- obj->options->state->separator_suppressed_p = TRUE;
- }
-
- XP_ASSERT(!uty->open_hdrs);
- return 0;
- }
-
- static int
- MimeUntypedText_open_subpart (MimeObject *obj,
- MimeUntypedTextSubpartType ttype,
- const char *type,
- const char *enc,
- const char *name,
- const char *desc)
- {
- MimeUntypedText *uty = (MimeUntypedText *) obj;
- int status = 0;
- char *h = 0;
-
- if (!type || !*type || !strcasecomp(type, UNKNOWN_CONTENT_TYPE))
- type = APPLICATION_OCTET_STREAM;
- if (enc && !*enc)
- enc = 0;
- if (desc && !*desc)
- desc = 0;
- if (name && !*name)
- name = 0;
-
- if (uty->open_subpart)
- {
- status = MimeUntypedText_close_subpart (obj);
- if (status < 0) return status;
- }
- XP_ASSERT(!uty->open_subpart);
- XP_ASSERT(!uty->open_hdrs);
-
- /* To make one of these implicitly-typed sub-objects, we make up a fake
- header block, containing only the minimum number of MIME headers needed.
- We could do most of this (Type and Encoding) by making a null header
- block, and simply setting obj->content_type and obj->encoding; but making
- a fake header block is better for two reasons: first, it means that
- something will actually be displayed when in `Show All Headers' mode;
- and second, it's the only way to communicate the filename parameter,
- aside from adding a new slot to MimeObject (which is something to be
- avoided when possible.)
- */
-
- uty->open_hdrs = MimeHeaders_new();
- if (!uty->open_hdrs) return MK_OUT_OF_MEMORY;
-
- h = (char *) XP_ALLOC(XP_STRLEN(type) +
- (enc ? XP_STRLEN(enc) : 0) +
- (desc ? XP_STRLEN(desc) : 0) +
- (name ? XP_STRLEN(name) : 0) +
- 100);
- if (!h) return MK_OUT_OF_MEMORY;
-
- XP_STRCPY(h, HEADER_CONTENT_TYPE ": ");
- XP_STRCAT(h, type);
- XP_STRCAT(h, LINEBREAK);
- status = MimeHeaders_parse_line(h, XP_STRLEN(h), uty->open_hdrs);
- if (status < 0) goto FAIL;
-
- if (enc)
- {
- XP_STRCPY(h, HEADER_CONTENT_TRANSFER_ENCODING ": ");
- XP_STRCAT(h, enc);
- XP_STRCAT(h, LINEBREAK);
- status = MimeHeaders_parse_line(h, XP_STRLEN(h), uty->open_hdrs);
- if (status < 0) goto FAIL;
- }
-
- if (desc)
- {
- XP_STRCPY(h, HEADER_CONTENT_DESCRIPTION ": ");
- XP_STRCAT(h, desc);
- XP_STRCAT(h, LINEBREAK);
- status = MimeHeaders_parse_line(h, XP_STRLEN(h), uty->open_hdrs);
- if (status < 0) goto FAIL;
- }
- if (name)
- {
- XP_STRCPY(h, HEADER_CONTENT_DISPOSITION ": inline; filename=\"");
- XP_STRCAT(h, name);
- XP_STRCAT(h, "\"" LINEBREAK);
- status = MimeHeaders_parse_line(h, XP_STRLEN(h), uty->open_hdrs);
- if (status < 0) goto FAIL;
- }
-
- /* push out a blank line. */
- XP_STRCPY(h, LINEBREAK);
- status = MimeHeaders_parse_line(h, XP_STRLEN(h), uty->open_hdrs);
- if (status < 0) goto FAIL;
-
-
- /* Create a child... */
- {
- XP_Bool horrid_kludge = (obj->options && obj->options->state &&
- obj->options->state->first_part_written_p);
- if (horrid_kludge)
- obj->options->state->first_part_written_p = FALSE;
-
- uty->open_subpart = mime_create(type, uty->open_hdrs, obj->options);
-
- if (horrid_kludge)
- obj->options->state->first_part_written_p = TRUE;
-
- if (!uty->open_subpart)
- {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
- }
-
- /* Add it to the list... */
- status = ((MimeContainerClass *) obj->class)->add_child(obj,
- uty->open_subpart);
- if (status < 0)
- {
- mime_free(uty->open_subpart);
- uty->open_subpart = 0;
- goto FAIL;
- }
-
- /* And start its parser going. */
- status = uty->open_subpart->class->parse_begin(uty->open_subpart);
- if (status < 0)
- {
- /* MimeContainer->finalize will take care of shutting it down now. */
- uty->open_subpart = 0;
- goto FAIL;
- }
-
- uty->type = ttype;
-
- FAIL:
- FREEIF(h);
-
- if (status < 0 && uty->open_hdrs)
- {
- MimeHeaders_free(uty->open_hdrs);
- uty->open_hdrs = 0;
- }
-
- return status;
- }
-
- static XP_Bool
- MimeUntypedText_uu_begin_line_p(const char *line, int32 length,
- MimeDisplayOptions *opt,
- char **type_ret, char **name_ret)
- {
- const char *s;
- char *name = 0;
- char *type = 0;
-
- if (type_ret) *type_ret = 0;
- if (name_ret) *name_ret = 0;
-
- if (XP_STRNCMP (line, "begin ", 6)) return FALSE;
- /* ...then three or four octal digits. */
- s = line + 6;
- if (*s < '0' || *s > '7') return FALSE;
- s++;
- if (*s < '0' || *s > '7') return FALSE;
- s++;
- if (*s < '0' || *s > '7') return FALSE;
- s++;
- if (*s == ' ')
- s++;
- else
- {
- if (*s < '0' || *s > '7') return FALSE;
- s++;
- if (*s != ' ') return FALSE;
- }
-
- while (XP_IS_SPACE(*s))
- s++;
-
- name = (char *) XP_ALLOC(((line+length)-s) + 1);
- if (!name) return FALSE; /* grr... */
- XP_MEMCPY(name, s, (line+length)-s);
- name[(line+length)-s] = 0;
-
- /* take off newline. */
- if (name[XP_STRLEN(name)-1] == LF) name[XP_STRLEN(name)-1] = 0;
- if (name[XP_STRLEN(name)-1] == CR) name[XP_STRLEN(name)-1] = 0;
-
- /* Now try and figure out a type.
- */
- if (opt && opt->file_type_fn)
- type = opt->file_type_fn(name, opt->stream_closure);
- else
- type = 0;
-
- if (name_ret)
- *name_ret = name;
- else
- FREEIF(name);
-
- if (type_ret)
- *type_ret = type;
- else
- FREEIF(type);
-
- return TRUE;
- }
-
- static XP_Bool
- MimeUntypedText_uu_end_line_p(const char *line, int32 length)
- {
- #if 0
- /* A strictly conforming uuencode end line. */
- return (line[0] == 'e' &&
- line[1] == 'n' &&
- line[2] == 'd' &&
- (line[3] == 0 || XP_IS_SPACE(line[3])));
- #else
- /* ...but, why don't we accept any line that begins with the three
- letters "END" in any case: I've seen lots of partial messages
- that look like
-
- BEGIN----- Cut Here-----
- begin 644 foo.gif
- Mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- Mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- Mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- END------- Cut Here-----
-
- so let's be lenient here. (This is only for the untyped-text-plain
- case -- the uudecode parser itself is strict.)
- */
- return (line[0] == ' ' ||
- line[0] == '\t' ||
- ((line[0] == 'e' || line[0] == 'E') &&
- (line[1] == 'n' || line[1] == 'N') &&
- (line[2] == 'd' || line[2] == 'D')));
- #endif
- }
-
-
- #define BINHEX_MAGIC "(This file must be converted with BinHex 4.0)"
- #define BINHEX_MAGIC_LEN 45
-
- static XP_Bool
- MimeUntypedText_binhex_begin_line_p(const char *line, int32 length,
- MimeDisplayOptions *opt)
- {
- if (length <= BINHEX_MAGIC_LEN)
- return FALSE;
-
- while(length > 0 && XP_IS_SPACE(line[length-1]))
- length--;
-
- if (length != BINHEX_MAGIC_LEN)
- return FALSE;
-
- if (!XP_STRNCMP(line, BINHEX_MAGIC, BINHEX_MAGIC_LEN))
- return TRUE;
- else
- return FALSE;
- }
-
- static XP_Bool
- MimeUntypedText_binhex_end_line_p(const char *line, int32 length)
- {
- if (length > 0 && line[length-1] == LF) length--;
- if (length > 0 && line[length-1] == CR) length--;
-
- if (length != 0 && length != 64)
- return TRUE;
- else
- return FALSE;
- }
-