Example #1
0
static int
MimeMultipartRelated_initialize(MimeObject* obj)
{
  MimeMultipartRelated* relobj = (MimeMultipartRelated*) obj;
  relobj->base_url = MimeHeaders_get(obj->headers, HEADER_CONTENT_BASE,
                     false, false);
  /* rhp: need this for supporting Content-Location */
  if (!relobj->base_url)
  {
    relobj->base_url = MimeHeaders_get(obj->headers, HEADER_CONTENT_LOCATION,
      false, false);
  }
  /* rhp: need this for supporting Content-Location */

  /* I used to have code here to test if the type was text/html.  Then I
     added multipart/alternative as being OK, too.  Then I found that the
     VCard spec seems to talk about having the first part of a
     multipart/related be an application/directory.  At that point, I decided
     to punt.  We handle anything as the first part, and stomp on the HTML it
     generates to adjust tags to point into the other parts.  This probably
     works out to something reasonable in most cases. */

  relobj->hash = PL_NewHashTable(20, PL_HashString, PL_CompareStrings, PL_CompareValues,
                                (PLHashAllocOps *)NULL, NULL);

  if (!relobj->hash) return MIME_OUT_OF_MEMORY;

  relobj->input_file_stream = nullptr;
  relobj->output_file_stream = nullptr;

  return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(obj);
}
Example #2
0
// This is necessary to determine which charset to use for a reply/forward
char *
DetermineMailCharset(MimeMessage *msg)
{
  char          *retCharset = nsnull;

  if ( (msg) && (msg->hdrs) )
  {
    char *ct = MimeHeaders_get (msg->hdrs, HEADER_CONTENT_TYPE,
                                PR_FALSE, PR_FALSE);
    if (ct)
    {
      retCharset = MimeHeaders_get_parameter (ct, "charset", NULL, NULL);
      PR_Free(ct);
    }

    if (!retCharset)
    {
      // If we didn't find "Content-Type: ...; charset=XX" then look
      // for "X-Sun-Charset: XX" instead.  (Maybe this should be done
      // in MimeSunAttachmentClass, but it's harder there than here.)
      retCharset = MimeHeaders_get (msg->hdrs, HEADER_X_SUN_CHARSET,
                                    PR_FALSE, PR_FALSE);
    }
  }

  if (!retCharset)
    return strdup("ISO-8859-1");
  else
    return retCharset;
}
Example #3
0
static int
MimeExternalBody_debug_print (MimeObject *obj, PRFileDesc *stream, PRInt32 depth)
{
  MimeExternalBody *bod = (MimeExternalBody *) obj;
  int i;
  char *ct, *ct2;
  char *addr = mime_part_address(obj);

  if (obj->headers)
  ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
  if (bod->hdrs)
  ct2 = MimeHeaders_get (bod->hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);

  for (i=0; i < depth; i++)
  PR_Write(stream, "  ", 2);
/***
  fprintf(stream,
      "<%s %s\n"
      "\tcontent-type: %s\n"
      "\tcontent-type: %s\n"
      "\tBody:%s\n\t0x%08X>\n\n",
      obj->clazz->class_name,
      addr ? addr : "???",
      ct ? ct : "<none>",
      ct2 ? ct2 : "<none>",
      bod->body ? bod->body : "<none>",
      (PRUint32) obj);
***/
  PR_FREEIF(addr);
  PR_FREEIF(ct);
  PR_FREEIF(ct2);
  return 0;
}
Example #4
0
/* Pull the name out of some header or another.  Order is:
   Content-Disposition: XXX; filename=NAME (RFC 1521/1806)
   Content-Type: XXX; name=NAME (RFC 1341)
   Content-Name: NAME (no RFC, but seen to occur)
   X-Sun-Data-Name: NAME (no RFC, but used by MailTool)
 */
char *
MimeHeaders_get_name(MimeHeaders *hdrs, MimeDisplayOptions *opt)
{
  char *s = 0, *name = 0, *cvt = 0;
  char *charset = nullptr; // for RFC2231 support

  s = MimeHeaders_get(hdrs, HEADER_CONTENT_DISPOSITION, false, false);
  if (s)
  {
    name = MimeHeaders_get_parameter(s, HEADER_PARM_FILENAME, &charset, NULL);
    PR_Free(s);
  }

  if (! name)
  {
    s = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, false, false);
    if (s)
    {
      nsMemory::Free(charset);

      name = MimeHeaders_get_parameter(s, HEADER_PARM_NAME, &charset, NULL);
      PR_Free(s);
    }
  }

  if (! name)
    name = MimeHeaders_get (hdrs, HEADER_CONTENT_NAME, false, false);

  if (! name)
    name = MimeHeaders_get (hdrs, HEADER_X_SUN_DATA_NAME, false, false);

  if (name)
  {
    /* First remove continuation delimiters (CR+LF+space), then
       remove escape ('\\') characters, then attempt to decode
       mime-2 encoded-words. The latter two are done in
       mime_decode_filename.
    */
    MIME_StripContinuations(name);

    /* Argh. What we should do if we want to be robust is to decode qtext
       in all appropriate headers. Unfortunately, that would be too scary
       at this juncture. So just decode qtext/mime2 here. */
    cvt = mime_decode_filename(name, charset, opt);

    nsMemory::Free(charset);

    if (cvt && cvt != name)
    {
      PR_Free(name);
      name = cvt;
    }
  }

  return name;
}
Example #5
0
static int
MimeMultCMS_sig_init (void *crypto_closure,
            MimeObject *multipart_object,
            MimeHeaders *signature_hdrs)
{
  MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
  char *ct;
  int status = 0;
  nsresult rv;

  if (!signature_hdrs) {
    return -1;
  }

  ct = MimeHeaders_get (signature_hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);

  /* Verify that the signature object is of the right type. */
  if (!ct || /* is not a signature type */
             (PL_strcasecmp(ct, APPLICATION_XPKCS7_SIGNATURE) != 0
              && PL_strcasecmp(ct, APPLICATION_PKCS7_SIGNATURE) != 0)) {
    status = -1; /* #### error msg about bogus message */
  }
  PR_FREEIF(ct);
  if (status < 0) return status;

  data->sig_decoder_context = do_CreateInstance(NS_CMSDECODER_CONTRACTID, &rv);
  if (NS_FAILED(rv)) return 0;

  rv = data->sig_decoder_context->Start(nsnull, nsnull);
  if (NS_FAILED(rv)) {
    status = PR_GetError();
    if (status >= 0) status = -1;
  }
  return status;
}
nsresult nsMimeHeaders::ExtractHeader(const char *headerName, PRBool getAllOfThem, char **_retval)
{
  if (! mHeaders)
    return NS_ERROR_NOT_INITIALIZED;

  *_retval = MimeHeaders_get(mHeaders, headerName, PR_FALSE, getAllOfThem);
  return NS_OK;
}
Example #7
0
nsresult nsMimeHeaders::ExtractHeader(const char *headerName, bool getAllOfThem, char **_retval)
{
  NS_ENSURE_ARG_POINTER(_retval);
  NS_ENSURE_TRUE(mHeaders, NS_ERROR_NOT_INITIALIZED);

  *_retval = MimeHeaders_get(mHeaders, headerName, false, getAllOfThem);
  return NS_OK;
}
static int
MimeInlineTextHTMLSanitized_parse_begin (MimeObject *obj)
{
#ifdef DEBUG_BenB
printf("parse_begin\n");
#endif
  MimeInlineTextHTMLSanitized *textHTMLSan =
                                       (MimeInlineTextHTMLSanitized *) obj;
  textHTMLSan->complete_buffer = new nsString();
#ifdef DEBUG_BenB
printf(" B1\n");
printf(" cbp: %d\n", textHTMLSan->complete_buffer);
#endif
  int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
  if (status < 0)
    return status;
#ifdef DEBUG_BenB
printf(" B2\n");
#endif

  // charset
  /* honestly, I don't know how that charset stuff works in libmime.
     The part in mimethtm doesn't make much sense to me either.
     I'll just dump the charset we get in the mime headers into a
     HTML meta http-equiv.
     XXX Not sure, if that is correct, though. */
  char *content_type =
    (obj->headers
     ? MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE, false, false)
     : 0);
  if (content_type)
  {
    char* charset = MimeHeaders_get_parameter(content_type,
                                              HEADER_PARM_CHARSET,
                                              NULL, NULL);
    PR_Free(content_type);
    if (charset)
    {
      nsAutoCString charsetline(
        "\n<meta http-equiv=\"Context-Type\" content=\"text/html; charset=");
      charsetline += charset;
      charsetline += "\">\n";
      int status = MimeObject_write(obj,
                                    charsetline.get(),
                                    charsetline.Length(),
                                    true);
      PR_Free(charset);
      if (status < 0)
        return status;
    }
  }
#ifdef DEBUG_BenB
printf("/parse_begin\n");
#endif
  return 0;
}
Example #9
0
static bool
MimeThisIsStartPart(MimeObject *obj, MimeObject* child)
{
  bool rval = false;
  char *ct, *st, *cst;

  ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, false, false);
  st = (ct
        ? MimeHeaders_get_parameter(ct, HEADER_PARM_START, NULL, NULL)
        : 0);

  PR_FREEIF(ct);
  if (!st)
    return false;

  cst = MimeHeaders_get(child->headers, HEADER_CONTENT_ID, false, false);
  if (!cst)
    rval = false;
  else
  {
    char *tmp = cst;
    if (*tmp == '<')
    {
      int length;
      tmp++;
      length = strlen(tmp);
      if (length > 0 && tmp[length - 1] == '>')
      {
        tmp[length - 1] = '\0';
      }
    }

    rval = (!strcmp(st, tmp));
  }

  PR_FREEIF(st);
  PR_FREEIF(cst);
  return rval;
}
Example #10
0
static bool
MimeStartParamExists(MimeObject *obj, MimeObject* child)
{
  char *ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, false, false);
  char *st = (ct
              ? MimeHeaders_get_parameter(ct, HEADER_PARM_START, NULL, NULL)
              : 0);

  PR_FREEIF(ct);
  if (!st)
    return false;

  PR_FREEIF(st);
  return true;
}
Example #11
0
static int
MimeMultipart_initialize (MimeObject *object)
{
  MimeMultipart *mult = (MimeMultipart *) object;
  char *ct;

  /* This is an abstract class; it shouldn't be directly instantiated. */
  PR_ASSERT(object->clazz != (MimeObjectClass *) &mimeMultipartClass);

  ct = MimeHeaders_get (object->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
  mult->boundary = (ct
          ? MimeHeaders_get_parameter (ct, HEADER_PARM_BOUNDARY, NULL, NULL)
          : 0);
  PR_FREEIF(ct);
  mult->state = MimeMultipartPreamble;
  return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
}
static bool
MimeMultipartAlternative_display_part_p(MimeObject *self,
                    MimeHeaders *sub_hdrs)
{
  char *ct = MimeHeaders_get (sub_hdrs, HEADER_CONTENT_TYPE, true, false);
  if (!ct)
    return false;

  /* RFC 1521 says:
     Receiving user agents should pick and display the last format
     they are capable of displaying.  In the case where one of the
     alternatives is itself of type "multipart" and contains unrecognized
     sub-parts, the user agent may choose either to show that alternative,
     an earlier alternative, or both.

   Ugh.  If there is a multipart subtype of alternative, we simply show
   that, without descending into it to determine if any of its sub-parts
   are themselves unknown.
   */

  // prefer_plaintext pref
  nsIPrefBranch *prefBranch = GetPrefBranch(self->options);
  bool prefer_plaintext = false;
  if (prefBranch)
    prefBranch->GetBoolPref("mailnews.display.prefer_plaintext",
                            &prefer_plaintext);
  if (prefer_plaintext
      && self->options->format_out != nsMimeOutput::nsMimeMessageSaveAs
      && (!PL_strncasecmp(ct, "text/html", 9) ||
          !PL_strncasecmp(ct, "text/enriched", 13) ||
          !PL_strncasecmp(ct, "text/richtext", 13))
     )
    // if the user prefers plaintext and this is the "rich" (e.g. HTML) part...
  {
    return false;
  }

  MimeObjectClass *clazz = mime_find_class (ct, sub_hdrs, self->options, true);
  bool result = (clazz
          ? clazz->displayable_inline_p(clazz, sub_hdrs)
          : false);
  PR_FREEIF(ct);
  return result;
}
Example #13
0
static void*
MimePgpe_init(MimeObject *obj,
              int (*output_fn) (const char *buf, int32_t buf_size,
                                void *output_closure),
              void *output_closure)
{
  if (!(obj && obj->options && output_fn))
    return nullptr;

  MimePgpeData* data = new MimePgpeData();
  NS_ENSURE_TRUE(data, nullptr);

  data->self = obj;
  data->output_fn = output_fn;
  data->output_closure = output_closure;
  data->mimeDecrypt = nullptr;

  nsresult rv;
  data->mimeDecrypt = do_CreateInstance(NS_PGPMIMEPROXY_CONTRACTID, &rv);
  if (NS_FAILED(rv))
    return data;

  char *ct = MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE, false, false);

  rv = (ct ? data->mimeDecrypt->SetContentType(nsDependentCString(ct))
        : data->mimeDecrypt->SetContentType(EmptyCString()));

  PR_Free(ct);

  if (NS_FAILED(rv))
    return nullptr;

  mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure);
  nsIChannel *channel = msd->channel;

  nsCOMPtr<nsIURI> uri;
  if (channel)
    channel->GetURI(getter_AddRefs(uri));

  if (NS_FAILED(data->mimeDecrypt->SetMimeCallback(output_fn, output_closure, uri)))
    return nullptr;

  return data;
}
Example #14
0
static bool
MimeExternalBody_displayable_inline_p (MimeObjectClass *clazz,
                     MimeHeaders *hdrs)
{
  char *ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
  char *at = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL);
  bool inline_p = false;

  if (!at)
  ;
  else if (!PL_strcasecmp(at, "ftp") ||
       !PL_strcasecmp(at, "anon-ftp") ||
       !PL_strcasecmp(at, "local-file") ||
       !PL_strcasecmp(at, "mail-server") ||
       !PL_strcasecmp(at, "url"))
  inline_p = PR_TRUE;
#ifdef XP_UNIX
  else if (!PL_strcasecmp(at, "afs"))   /* only if there is a /afs/ directory */
  {
    nsCOMPtr <nsILocalFile> fs = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
    bool exists = false;
    if (fs)
    {
      fs->InitWithNativePath(NS_LITERAL_CSTRING("/afs/."));
      fs->Exists(&exists);
    }
    if  (!exists)
      return 0;

    inline_p = PR_TRUE;
  }
#endif /* XP_UNIX */

  PR_FREEIF(ct);
  PR_FREEIF(at);
  return inline_p;
}
Example #15
0
static int
MimeEncrypted_emit_buffered_child(MimeObject *obj)
{
  MimeEncrypted *enc = (MimeEncrypted *) obj;
  int status = 0;
  char *ct = 0;
  MimeObject *body;

  NS_ASSERTION(enc->crypto_closure, "1.2 <*****@*****.**> 01 Nov 2001 17:59");

  /* Emit some HTML saying whether the signature was cool.
	 But don't emit anything if in FO_QUOTE_MESSAGE mode.

	 Also, don't emit anything if the enclosed object is itself a signed
	 object -- in the case of an encrypted object which contains a signed
	 object, we only emit the HTML once (since the normal way of encrypting
	 and signing is to nest the signature inside the crypto envelope.)
   */
  if (enc->crypto_closure &&
	  obj->options &&
	  obj->options->headers != MimeHeadersCitation &&
	  obj->options->write_html_p &&
	  obj->options->output_fn)
	  // && !mime_crypto_object_p(enc->hdrs, PR_TRUE)) // XXX fix later XXX //
	{
    char *html;
#if 0 // XXX Fix this later XXX //
	  char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html
					(enc->crypto_closure));
	  if (!html) return -1; /* MK_OUT_OF_MEMORY? */
	  
    status = MimeObject_write(obj, html, nsCRT::strlen(html), PR_FALSE);
	  PR_FREEIF(html);
	  if (status < 0) return status;
#endif

	  /* Now that we have written out the crypto stamp, the outermost header
		 block is well and truly closed.  If this is in fact the outermost
		 message, then run the post_header_html_fn now.
	   */
	  if (obj->options &&
		  obj->options->state &&
		  obj->options->generate_post_header_html_fn &&
		  !obj->options->state->post_header_html_run_p)
		{
		  MimeHeaders *outer_headers = nsnull;
		  MimeObject *p;
		  for (p = obj; p->parent; p = p->parent)
			  outer_headers = p->headers;
		  NS_ASSERTION(obj->options->state->first_data_written_p, "1.2 <*****@*****.**> 01 Nov 2001 17:59");
		  html = obj->options->generate_post_header_html_fn(NULL,
													obj->options->html_closure,
															outer_headers);
		  obj->options->state->post_header_html_run_p = PR_TRUE;
		  if (html)
			{
        status = MimeObject_write(obj, html, strlen(html), PR_FALSE);
			  PR_FREEIF(html);
			  if (status < 0) return status;
			}
		}
	}
  else if (enc->crypto_closure &&
		   obj->options &&
	   obj->options->decrypt_p)
	{
	  /* Do this just to cause `mime_set_crypto_stamp' to be called, and to
		 cause the various `decode_error' and `verify_error' slots to be set:
		 we don't actually use the returned HTML, because we're not emitting
		 HTML.  It's maybe not such a good thing that the determination of
		 whether it was encrypted or not is tied up with generating HTML,
		 but oh well. */
	  char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html
					(enc->crypto_closure));
	  PR_FREEIF(html);
	}

  if (enc->hdrs)
	ct = MimeHeaders_get (enc->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);
  body = mime_create((ct ? ct : TEXT_PLAIN), enc->hdrs, obj->options);
  
#ifdef MIME_DRAFTS
  if (obj->options->decompose_file_p) {
	if (mime_typep (body, (MimeObjectClass*) &mimeMultipartClass) )
		obj->options->is_multipart_msg = PR_TRUE;
	else if (obj->options->decompose_file_init_fn)
		obj->options->decompose_file_init_fn(obj->options->stream_closure,
											 enc->hdrs);
  }
#endif /* MIME_DRAFTS */

  PR_FREEIF(ct);

  if (!body) return MIME_OUT_OF_MEMORY;
  status = ((MimeContainerClass *) obj->clazz)->add_child (obj, body);
  if (status < 0)
	{
	  mime_free(body);
	  return status;
	}

  /* Now that we've added this new object to our list of children,
	 start its parser going. */
  status = body->clazz->parse_begin(body);
  if (status < 0) return status;

  /* If this object (or the parent) is being output, then by definition
	 the child is as well.  (This is only necessary because this is such
	 a funny sort of container...)
   */
  if (!body->output_p &&
	  (obj->output_p ||
	   (obj->parent && obj->parent->output_p)))
	body->output_p = PR_TRUE;

  /* If the body is being written raw (not as HTML) then make sure to
	 write its headers as well. */
  if (body->output_p && obj->output_p && !obj->options->write_html_p)
	{
	  status = MimeObject_write(body, "", 0, PR_FALSE);  /* initialize */
	  if (status < 0) return status;
	  status = MimeHeaders_write_raw_headers(body->headers, obj->options,
											 PR_FALSE);
	  if (status < 0) return status;
	}

  if (enc->part_buffer)  /* part_buffer is 0 for 0-length encrypted data. */

#ifdef MIME_DRAFTS
    if (obj->options->decompose_file_p && !obj->options->is_multipart_msg)
		status = MimePartBufferRead(enc->part_buffer,
								/* The (nsresult (*) ...) cast is to turn the `void'
								   argument into `MimeObject'. */
								 ((nsresult (*) (const char *, PRInt32, void *))
								obj->options->decompose_file_output_fn),
								obj->options->stream_closure);
    else
#endif /* MIME_DRAFTS */

	status = MimePartBufferRead(enc->part_buffer,
								/* The (nsresult (*) ...) cast is to turn the `void'
								   argument into `MimeObject'. */
								 ((nsresult (*) (const char *, PRInt32, void *))
								 body->clazz->parse_buffer),
								body);
  if (status < 0) return status;

  /* The child has been fully processed.  Close it off.
   */
  status = body->clazz->parse_eof(body, PR_FALSE);
  if (status < 0) return status;

  status = body->clazz->parse_end(body, PR_FALSE);
  if (status < 0) return status;

#ifdef MIME_DRAFTS
  if (obj->options->decompose_file_p && !obj->options->is_multipart_msg)
	  obj->options->decompose_file_close_fn(obj->options->stream_closure);
#endif /* MIME_DRAFTS */

  /* Put out a separator after every encrypted object. */
  status = MimeObject_write_separator(obj);
  if (status < 0) return status;

  MimeEncrypted_cleanup (obj, PR_FALSE);

  return 0;
}
Example #16
0
static int
MimeMultipartSigned_emit_child (MimeObject *obj)
{
  MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;
  MimeMultipart *mult = (MimeMultipart *) obj;
  MimeContainer *cont = (MimeContainer *) obj;
  int status = 0;
  MimeObject *body;

  NS_ASSERTION(sig->crypto_closure, "no crypto closure");

  /* Emit some HTML saying whether the signature was cool.
   But don't emit anything if in FO_QUOTE_MESSAGE mode.
   */
  if (obj->options &&
    obj->options->headers != MimeHeadersCitation &&
    obj->options->write_html_p &&
    obj->options->output_fn &&
    obj->options->headers != MimeHeadersCitation &&
    sig->crypto_closure)
  {
    char *html = (((MimeMultipartSignedClass *) obj->clazz)
          ->crypto_generate_html (sig->crypto_closure));
#if 0 // XXX For the moment, no HTML output. Fix this XXX //
    if (!html) return -1; /* MIME_OUT_OF_MEMORY? */

    status = MimeObject_write(obj, html, strlen(html), false);
    PR_Free(html);
    if (status < 0) return status;
#endif

    /* Now that we have written out the crypto stamp, the outermost header
     block is well and truly closed.  If this is in fact the outermost
     message, then run the post_header_html_fn now.
     */
    if (obj->options &&
      obj->options->state &&
      obj->options->generate_post_header_html_fn &&
      !obj->options->state->post_header_html_run_p)
    {
      MimeHeaders *outer_headers=nsnull;
      MimeObject *p;
      for (p = obj; p->parent; p = p->parent)
      outer_headers = p->headers;
      NS_ASSERTION(obj->options->state->first_data_written_p,
                   "should have already written some data");
      html = obj->options->generate_post_header_html_fn(NULL,
                          obj->options->html_closure,
                              outer_headers);
      obj->options->state->post_header_html_run_p = true;
      if (html)
      {
        status = MimeObject_write(obj, html, strlen(html), false);
        PR_Free(html);
        if (status < 0) return status;
      }
    }
  }


  /* Oh, this is fairly nasty.  We're skipping over our "create child" method
   and using the one our superclass defines.  Perhaps instead we should add
   a new method on this class, and initialize that method to be the
   create_child method of the superclass.  Whatever.
   */


  /* The superclass method expects to find the headers for the part that it's
   to create in mult->hdrs, so ensure that they're there. */
  NS_ASSERTION(!mult->hdrs, "shouldn't already have hdrs for multipart");
  if (mult->hdrs) MimeHeaders_free(mult->hdrs);
  mult->hdrs = sig->body_hdrs;
  sig->body_hdrs = 0;

  /* Run the superclass create_child method.
   */
  status = (((MimeMultipartClass *)(&MIME_SUPERCLASS))->create_child(obj));
  if (status < 0) return status;

  // Notify the charset of the first part.
  if (obj->options && !(obj->options->override_charset)) {
    MimeObject *firstChild = ((MimeContainer*) obj)->children[0];
    char *disposition = MimeHeaders_get (firstChild->headers,
                                         HEADER_CONTENT_DISPOSITION, 
                                         true,
                                         false);
    // check if need to show as inline
    if (!disposition)
    {
      const char *content_type = firstChild->content_type;
      if (!PL_strcasecmp (content_type, TEXT_PLAIN) ||
          !PL_strcasecmp (content_type, TEXT_HTML) ||
          !PL_strcasecmp (content_type, TEXT_MDL) ||
          !PL_strcasecmp (content_type, MULTIPART_ALTERNATIVE) ||
          !PL_strcasecmp (content_type, MULTIPART_RELATED) ||
          !PL_strcasecmp (content_type, MESSAGE_NEWS) ||
          !PL_strcasecmp (content_type, MESSAGE_RFC822)) {
        char *ct = MimeHeaders_get(mult->hdrs, HEADER_CONTENT_TYPE, false, false);
        if (ct) {
          char *cset = MimeHeaders_get_parameter (ct, "charset", NULL, NULL);
          if (cset) {
            mimeEmitterUpdateCharacterSet(obj->options, cset);
            SetMailCharacterSetToMsgWindow(obj, cset);
            PR_Free(cset);
          }
          PR_Free(ct);
        }
      }
    }
  }
  
  // The js emitter wants to know about the newly created child.  Because
  //  MimeMultipartSigned dummies out its create_child operation, the logic
  //  in MimeMultipart_parse_line that would normally provide this notification
  //  does not get to fire.
  if (obj->options && obj->options->notify_nested_bodies) {
    MimeObject *kid = ((MimeContainer*) obj)->children[0];
    // The emitter is expecting the content type with parameters; not the fully
    //  parsed thing, so get it from raw.  (We do not do it in the charset
    //  notification block that just happened because it already has complex
    //  if-checks that do not jive with us.
    char *ct = MimeHeaders_get(mult->hdrs, HEADER_CONTENT_TYPE, false,
                               false);
    mimeEmitterAddHeaderField(obj->options, HEADER_CONTENT_TYPE,
                              ct ? ct : "text/plain");
    PR_Free(ct);
    
    char *part_path = mime_part_address(kid);
    if (part_path) {
      mimeEmitterAddHeaderField(obj->options,
                                "x-jsemitter-part-path",
                                part_path);
      PR_Free(part_path);
    }
  }

  /* Retrieve the child that it created.
   */
  NS_ASSERTION(cont->nchildren == 1, "should only have one child");
  if (cont->nchildren != 1)
    return -1;
  body = cont->children[0];
  NS_ASSERTION(body, "missing body");
  if (!body)
    return -1;

#ifdef MIME_DRAFTS
  if (body->options->decompose_file_p) {
    body->options->signed_p = true;
    if (!mime_typep(body, (MimeObjectClass*)&mimeMultipartClass) &&
    body->options->decompose_file_init_fn)
    body->options->decompose_file_init_fn ( body->options->stream_closure, body->headers );
  }
#endif /* MIME_DRAFTS */

  /* If there's no part_buffer, this is a zero-length signed message? */
  if (sig->part_buffer)
  {
#ifdef MIME_DRAFTS
    if (body->options->decompose_file_p &&
      !mime_typep(body, (MimeObjectClass*)&mimeMultipartClass)  &&
      body->options->decompose_file_output_fn)
      status = MimePartBufferRead (sig->part_buffer,
                 /* The (nsresult (*) ...) cast is to turn the
                  `void' argument into `MimeObject'. */
                 ((nsresult (*) (const char *, PRInt32, void *))
                 body->options->decompose_file_output_fn),
                 body->options->stream_closure);
    else
#endif /* MIME_DRAFTS */

    status = MimePartBufferRead (sig->part_buffer,
                 /* The (nsresult (*) ...) cast is to turn the
                  `void' argument into `MimeObject'. */
                 ((nsresult (*) (const char *, PRInt32, void *))
                body->clazz->parse_buffer),
                body);
    if (status < 0) return status;
  }

  MimeMultipartSigned_cleanup(obj, false);

  /* Done parsing. */
  status = body->clazz->parse_eof(body, false);
  if (status < 0) return status;
  status = body->clazz->parse_end(body, false);
  if (status < 0) return status;

#ifdef MIME_DRAFTS
  if (body->options->decompose_file_p &&
    !mime_typep(body, (MimeObjectClass*)&mimeMultipartClass)  &&
    body->options->decompose_file_close_fn)
    body->options->decompose_file_close_fn(body->options->stream_closure);
#endif /* MIME_DRAFTS */

  /* Put out a separator after every multipart/signed object. */
  status = MimeObject_write_separator(obj);
  if (status < 0) return status;

  return 0;
}
Example #17
0
static int
MimeMultipartSigned_parse_line (const char *line, PRInt32 length, MimeObject *obj)
{
  MimeMultipart *mult = (MimeMultipart *) obj;
  MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;
  MimeMultipartParseState old_state = mult->state;
  bool hash_line_p = true;
  bool no_headers_p = false;
  int status = 0;

  /* First do the parsing for normal multipart/ objects by handing it off to
   the superclass method.  This includes calling the create_child and
   close_child methods.
   */
  status = (((MimeObjectClass *)(&MIME_SUPERCLASS))
      ->parse_line (line, length, obj));
  if (status < 0) return status;

  /* The instance variable MimeMultipartClass->state tracks motion through
   the various stages of multipart/ parsing.  The instance variable
   MimeMultipartSigned->state tracks the difference between the first
   part (the body) and the second part (the signature.)  This second,
   more specific state variable is updated by noticing the transitions
   of the first, more general state variable.
   */
  if (old_state != mult->state)  /* there has been a state change */
  {
    switch (mult->state)
    {
    case MimeMultipartPreamble:
      PR_ASSERT(0);  /* can't move *in* to preamble state. */
      sig->state = MimeMultipartSignedPreamble;
      break;

    case MimeMultipartHeaders:
      /* If we're moving in to the Headers state, then that means
       that this line is the preceeding boundary string (and we
       should ignore it.)
       */
      hash_line_p = false;

      if (sig->state == MimeMultipartSignedPreamble)
      sig->state = MimeMultipartSignedBodyFirstHeader;
      else if (sig->state == MimeMultipartSignedBodyFirstLine ||
           sig->state == MimeMultipartSignedBodyLine)
      sig->state = MimeMultipartSignedSignatureHeaders;
      else if (sig->state == MimeMultipartSignedSignatureFirstLine ||
           sig->state == MimeMultipartSignedSignatureLine)
      sig->state = MimeMultipartSignedEpilogue;
      break;

    case MimeMultipartPartFirstLine:
      if (sig->state == MimeMultipartSignedBodyFirstHeader)
      {      
        sig->state = MimeMultipartSignedBodyFirstLine;
        no_headers_p = true;
      }
      else if (sig->state == MimeMultipartSignedBodyHeaders)
      sig->state = MimeMultipartSignedBodyFirstLine;
      else if (sig->state == MimeMultipartSignedSignatureHeaders)
      sig->state = MimeMultipartSignedSignatureFirstLine;
      else
      sig->state = MimeMultipartSignedEpilogue;
      break;

    case MimeMultipartPartLine:

      PR_ASSERT(sig->state == MimeMultipartSignedBodyFirstLine ||
          sig->state == MimeMultipartSignedBodyLine ||
          sig->state == MimeMultipartSignedSignatureFirstLine ||
          sig->state == MimeMultipartSignedSignatureLine);

      if (sig->state == MimeMultipartSignedBodyFirstLine)
      sig->state = MimeMultipartSignedBodyLine;
      else if (sig->state == MimeMultipartSignedSignatureFirstLine)
      sig->state = MimeMultipartSignedSignatureLine;
      break;

    case MimeMultipartEpilogue:
      sig->state = MimeMultipartSignedEpilogue;
      break;

    default:  /* bad state */
      NS_ERROR("bad state in MultipartSigned parse line");
      return -1;
      break;
    }
  }


  /* Perform multipart/signed-related actions on this line based on the state
   of the parser.
   */
  switch (sig->state)
  {
  case MimeMultipartSignedPreamble:
    /* Do nothing. */
    break;

  case MimeMultipartSignedBodyFirstLine:
    /* We have just moved out of the MimeMultipartSignedBodyHeaders
     state, so cache away the headers that apply only to the body part.
     */
    NS_ASSERTION(mult->hdrs, "null multipart hdrs");
    NS_ASSERTION(!sig->body_hdrs, "signed part shouldn't have already have body_hdrs");
    sig->body_hdrs = mult->hdrs;
    mult->hdrs = 0;

    /* fall through. */

  case MimeMultipartSignedBodyFirstHeader:
  case MimeMultipartSignedBodyHeaders:
  case MimeMultipartSignedBodyLine:

    if (!sig->crypto_closure)
    {
      /* Set error change */
      PR_SetError(0, 0);
      /* Initialize the signature verification library. */
      sig->crypto_closure = (((MimeMultipartSignedClass *) obj->clazz)
                 ->crypto_init) (obj);
      if (!sig->crypto_closure)
      {
        status = PR_GetError();
        NS_ASSERTION(status < 0, "got non-negative status");
        if (status >= 0)
          status = -1;
        return status;
      }
    }

    if (hash_line_p)
    {
      /* this is the first hashed line if this is the first header
       (that is, if it's the first line in the header state after
       a state change.)
       */
      bool first_line_p
      = (no_headers_p ||
         sig->state == MimeMultipartSignedBodyFirstHeader);

      if (sig->state == MimeMultipartSignedBodyFirstHeader)
      sig->state = MimeMultipartSignedBodyHeaders;

      /* The newline issues here are tricky, since both the newlines
       before and after the boundary string are to be considered part
       of the boundary: this is so that a part can be specified such
       that it does not end in a trailing newline.

       To implement this, we send a newline *before* each line instead
       of after, except for the first line, which is not preceeded by a
       newline.

       For purposes of cryptographic hashing, we always hash line
       breaks as CRLF -- the canonical, on-the-wire linebreaks, since
       we have no idea of knowing what line breaks were used on the
       originating system (SMTP rightly destroys that information.)
       */

      /* Remove the trailing newline... */
      if (length > 0 && line[length-1] == '\n') length--;
      if (length > 0 && line[length-1] == '\r') length--;

      PR_ASSERT(sig->crypto_closure);

      if (!first_line_p)
      {
        /* Push out a preceeding newline... */
        char nl[] = CRLF;
        status = (((MimeMultipartSignedClass *) obj->clazz)
            ->crypto_data_hash (nl, 2, sig->crypto_closure));
        if (status < 0) return status;
      }

      /* Now push out the line sans trailing newline. */
      if (length > 0)
      status = (((MimeMultipartSignedClass *) obj->clazz)
            ->crypto_data_hash (line,length, sig->crypto_closure));
      if (status < 0) return status;
    }
    break;

  case MimeMultipartSignedSignatureHeaders:

    if (sig->crypto_closure &&
      old_state != mult->state)
    {
      /* We have just moved out of the MimeMultipartSignedBodyLine
       state, so tell the signature verification library that we've
       reached the end of the signed data.
       */
      status = (((MimeMultipartSignedClass *) obj->clazz)
          ->crypto_data_eof) (sig->crypto_closure, false);
      if (status < 0) return status;
    }
    break;

  case MimeMultipartSignedSignatureFirstLine:
    /* We have just moved out of the MimeMultipartSignedSignatureHeaders
     state, so cache away the headers that apply only to the sig part.
     */
    PR_ASSERT(mult->hdrs);
    PR_ASSERT(!sig->sig_hdrs);
    sig->sig_hdrs = mult->hdrs;
    mult->hdrs = 0;


    /* If the signature block has an encoding, set up a decoder for it.
     (Similar logic is in MimeLeafClass->parse_begin.)
     */
    {
    MimeDecoderData *(*fn) (nsresult (*) (const char*, PRInt32,void*), void*) = 0;
    nsCString encoding;
    encoding.Adopt(MimeHeaders_get (sig->sig_hdrs,
                   HEADER_CONTENT_TRANSFER_ENCODING,
                   true, false));
    if (encoding.IsEmpty())
      ;
    else if (!PL_strcasecmp(encoding.get(), ENCODING_BASE64))
      fn = &MimeB64DecoderInit;
    else if (!PL_strcasecmp(encoding.get(), ENCODING_QUOTED_PRINTABLE))
    {
      sig->sig_decoder_data =
  MimeQPDecoderInit (((nsresult (*) (const char *, PRInt32, void *))
     (((MimeMultipartSignedClass *) obj->clazz)
          ->crypto_signature_hash)),
    sig->crypto_closure);
      if (!sig->sig_decoder_data)
  return MIME_OUT_OF_MEMORY;
    }
    else if (!PL_strcasecmp(encoding.get(), ENCODING_UUENCODE) ||
             !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE2) ||
             !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE3) ||
             !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE4))
      fn = &MimeUUDecoderInit;
    else if (!PL_strcasecmp(encoding.get(), ENCODING_YENCODE))
      fn = &MimeYDecoderInit;
    if (fn)
      {
      sig->sig_decoder_data =
        fn (((nsresult (*) (const char *, PRInt32, void *))
           (((MimeMultipartSignedClass *) obj->clazz)
          ->crypto_signature_hash)),
          sig->crypto_closure);
      if (!sig->sig_decoder_data)
        return MIME_OUT_OF_MEMORY;
      }
    }

    /* Show these headers to the crypto module. */
    if (hash_line_p)
    {
      status = (((MimeMultipartSignedClass *) obj->clazz)
          ->crypto_signature_init) (sig->crypto_closure,
                        obj, sig->sig_hdrs);
      if (status < 0) return status;
    }

    /* fall through. */

  case MimeMultipartSignedSignatureLine:
    if (hash_line_p)
    {
      /* Feed this line into the signature verification routines. */

      if (sig->sig_decoder_data)
      status = MimeDecoderWrite (sig->sig_decoder_data, line, length, nsnull);
      else
      status = (((MimeMultipartSignedClass *) obj->clazz)
            ->crypto_signature_hash (line, length,
                         sig->crypto_closure));
      if (status < 0) return status;
    }
    break;

  case MimeMultipartSignedEpilogue:
    /* Nothing special to do here. */
    break;

  default:  /* bad state */
    PR_ASSERT(0);
    return -1;
  }

  return status;
}
static int MimeInlineText_initializeCharset(MimeObject *obj)
{
  MimeInlineText  *text = (MimeInlineText *) obj;

  text->inputAutodetect = false;
  text->charsetOverridable = false;
  
  /* Figure out an appropriate charset for this object.
  */
  if (!text->charset && obj->headers)
  {
    if (obj->options && obj->options->override_charset)
    {
      text->charset = strdup(obj->options->default_charset);
    }
    else
    {
      char *ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE,
                                  false, false);
      if (ct)
      {
        text->charset = MimeHeaders_get_parameter (ct, "charset", NULL, NULL);
        PR_Free(ct);
      }
    
      if (!text->charset)
      {
        /* If we didn't find "Content-Type: ...; charset=XX" then look
           for "X-Sun-Charset: XX" instead.  (Maybe this should be done
           in MimeSunAttachmentClass, but it's harder there than here.)
         */
        text->charset = MimeHeaders_get (obj->headers,
                                          HEADER_X_SUN_CHARSET,
                                          false, false);
      }

      /* iMIP entities without an explicit charset parameter default to
       US-ASCII (RFC 2447, section 2.4). However, Microsoft Outlook generates
       UTF-8 but omits the charset parameter.
       When no charset is defined by the container (e.g. iMIP), iCalendar
       files default to UTF-8 (RFC 2445, section 4.1.4).
       */
      if (!text->charset &&
          obj->content_type &&
          !PL_strcasecmp(obj->content_type, TEXT_CALENDAR))
        text->charset = strdup("UTF-8");

      if (!text->charset)
      {
        nsresult res;
        
        text->charsetOverridable = true;

        nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &res)); 
        if (NS_SUCCEEDED(res))
        {
          nsCOMPtr<nsIPrefLocalizedString> str;
          if (NS_SUCCEEDED(prefBranch->GetComplexValue("intl.charset.detector", NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(str)))) {
            //only if we can get autodetector name correctly, do we set this to true
            text->inputAutodetect = true;
          }
        }
        
        if (obj->options && obj->options->default_charset)
          text->charset = strdup(obj->options->default_charset);
        else
        {
          if (NS_SUCCEEDED(res))
          {
            nsString value;
            NS_GetLocalizedUnicharPreferenceWithDefault(prefBranch, "mailnews.view_default_charset", EmptyString(), value);
            text->charset = ToNewUTF8String(value);
          }
          else
            text->charset = strdup("");
        }
      } 
    }
  }
  
  if (text->inputAutodetect)
  {
    //we need to prepare lineDam for charset detection
    text->lineDamBuffer = (char*)PR_Malloc(DAM_MAX_BUFFER_SIZE);
    text->lineDamPtrs = (char**)PR_Malloc(DAM_MAX_LINES*sizeof(char*));
    text->curDamOffset = 0;
    text->lastLineInDam = 0;
    if (!text->lineDamBuffer || !text->lineDamPtrs)
    {
      text->inputAutodetect = false;
      PR_FREEIF(text->lineDamBuffer);
      PR_FREEIF(text->lineDamPtrs);
    }
  }

  text->initializeCharset = true;

  return 0;
}
static char *
MimeMessage_partial_message_html(const char *data, void *closure,
                                 MimeHeaders *headers)
{
  MimeMessage *msg = (MimeMessage *)closure;
  nsAutoCString orig_url(data);
  char *uidl = MimeHeaders_get(headers, HEADER_X_UIDL, false, false);
  char *msgId = MimeHeaders_get(headers, HEADER_MESSAGE_ID, false,
                  false);
  char *msgIdPtr = PL_strchr(msgId, '<');

  int32_t pos = orig_url.Find("mailbox-message");
  if (pos != -1)
    orig_url.Cut(pos + 7, 8);

  pos = orig_url.FindChar('#');
  if (pos != -1)
    orig_url.Replace(pos, 1, "?number=", 8);

  if (msgIdPtr)
    msgIdPtr++;
  else
    msgIdPtr = msgId;
  char *gtPtr = PL_strchr(msgIdPtr, '>');
  if (gtPtr)
    *gtPtr = 0;

  bool msgBaseTruncated = (msg->bodyLength > MSG_LINEBREAK_LEN);

  nsCString partialMsgHtml;
  nsCString item;

  partialMsgHtml.AppendLiteral("<div style=\"margin: 1em auto; border: 1px solid black; width: 80%\">");
  partialMsgHtml.AppendLiteral("<div style=\"margin: 5px; padding: 10px; border: 1px solid gray; font-weight: bold; text-align: center;\">");

  partialMsgHtml.AppendLiteral("<span style=\"font-size: 120%;\">");
  if (msgBaseTruncated)
    item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_TRUNCATED")));
  else
    item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_NOT_DOWNLOADED")));
  partialMsgHtml += item;
  partialMsgHtml.AppendLiteral("</span><hr>");

  if (msgBaseTruncated)
    item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_TRUNCATED_EXPLANATION")));
  else
    item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_NOT_DOWNLOADED_EXPLANATION")));
  partialMsgHtml += item;
  partialMsgHtml.AppendLiteral("<br><br>");

  partialMsgHtml.AppendLiteral("<a href=\"");
  partialMsgHtml.Append(orig_url);

  if (msgIdPtr) {
    partialMsgHtml.AppendLiteral("&messageid=");

    MsgEscapeString(nsDependentCString(msgIdPtr), nsINetUtil::ESCAPE_URL_PATH,
                    item);

    partialMsgHtml.Append(item);
  }

  if (uidl) {
    partialMsgHtml.AppendLiteral("&uidl=");

    MsgEscapeString(nsDependentCString(uidl), nsINetUtil::ESCAPE_XALPHAS,
                    item);

    partialMsgHtml.Append(item);
  }

  partialMsgHtml.AppendLiteral("\">");
  item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_CLICK_FOR_REST")));
  partialMsgHtml += item;
  partialMsgHtml.AppendLiteral("</a>");

  partialMsgHtml.AppendLiteral("</div></div>");

  return ToNewCString(partialMsgHtml);
}
Example #20
0
static int
MimeMessage_write_headers_html (MimeObject *obj)
{
  MimeMessage     *msg = (MimeMessage *) obj;
  int             status;

#ifdef MOZ_SECURITY
  HG33391
#endif /* MOZ_SECURITY */

  if (!obj->options || !obj->options->output_fn)
    return 0;

  PR_ASSERT(obj->output_p && obj->options->write_html_p);

  // To support the no header option! Make sure we are not
  // suppressing headers on included email messages...
  if ( (obj->options->headers == MimeHeadersNone) &&
       (obj == obj->options->state->root) )
  {
    // Ok, we are going to kick the Emitter for a StartHeader
    // operation ONLY WHEN THE CHARSET OF THE ORIGINAL MESSAGE IS
    // NOT US-ASCII ("ISO-8859-1")
    //
    // This is only to notify the emitter of the charset of the
    // original message
    char    *mailCharset = DetermineMailCharset(msg);

    if ( (mailCharset) && (PL_strcasecmp(mailCharset, "US-ASCII")) &&
         (PL_strcasecmp(mailCharset, "ISO-8859-1")) )
      mimeEmitterUpdateCharacterSet(obj->options, mailCharset);
    PR_FREEIF(mailCharset);
    return 0;
  }

  if (!obj->options->state->first_data_written_p)
  {
    status = MimeObject_output_init (obj, TEXT_HTML);
    if (status < 0)
    {
      mimeEmitterEndHeader(obj->options);
      return status;
    }
    PR_ASSERT(obj->options->state->first_data_written_p);
  }

  // Start the header parsing by the emitter
  char *msgID = MimeHeaders_get (msg->hdrs, HEADER_MESSAGE_ID,
                                    PR_FALSE, PR_FALSE);
  PRBool outer_p = !obj->headers; /* is this the outermost message? */
  if (!outer_p && obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay &&
      obj->options->part_to_load)
  {
    //Maybe we are displaying a embedded message as outer part!
    char *id = mime_part_address(obj);
    if (id)
    {
      outer_p = !strcmp(id, obj->options->part_to_load);
      PR_Free(id);
    }
  }

  // Ok, we should really find out the charset of this part. We always
  // output UTF-8 for display, but the original charset is necessary for
  // reply and forward operations.
  //
  char    *mailCharset = DetermineMailCharset(msg);
  mimeEmitterStartHeader(obj->options,
                            outer_p,
                            (obj->options->headers == MimeHeadersOnly),
                            msgID,
                            mailCharset);

  // Change the default_charset by the charset of the original message
  // ONLY WHEN THE CHARSET OF THE ORIGINAL MESSAGE IS NOT US-ASCII
  // ("ISO-8859-1") and defailt_charset and mailCharset are different.
  if ( (mailCharset) && (PL_strcasecmp(mailCharset, "US-ASCII")) &&
       (PL_strcasecmp(mailCharset, "ISO-8859-1")) &&
       (PL_strcasecmp(obj->options->default_charset, mailCharset)) &&
       !obj->options->override_charset )
  {
    PR_FREEIF(obj->options->default_charset);
    obj->options->default_charset = strdup(mailCharset);
  }

  PR_FREEIF(msgID);
  PR_FREEIF(mailCharset);

#ifdef MOZ_SECURITY
    HG00919
#endif /* MOZ_SECURITY */

  status = MimeHeaders_write_all_headers (msg->hdrs, obj->options, PR_FALSE);
  if (status < 0)
  {
    mimeEmitterEndHeader(obj->options);
    return status;
  }

  if (msg->crypto_stamped_p)
  {
#ifdef MOZ_SECURITY
    HG11995
#endif /* MOZ_SECURITY */
  }
  else
  {
  /* If we're not writing a xlation stamp, and this is the outermost
  message, then now is the time to run the post_header_html_fn.
  (Otherwise, it will be run when the xlation-stamp is finally
  closed off, in MimeXlateed_emit_buffered_child() or
  MimeMultipartSigned_emit_child().)
     */
    if (obj->options &&
      obj->options->state &&
      obj->options->generate_post_header_html_fn &&
      !obj->options->state->post_header_html_run_p)
    {
      char *html = 0;
      PR_ASSERT(obj->options->state->first_data_written_p);
      html = obj->options->generate_post_header_html_fn(NULL,
                                          obj->options->html_closure,
                                          msg->hdrs);
      obj->options->state->post_header_html_run_p = PR_TRUE;
      if (html)
      {
        status = MimeObject_write(obj, html, strlen(html), PR_FALSE);
        PR_Free(html);
        if (status < 0)
        {
          mimeEmitterEndHeader(obj->options);
          return status;
        }
      }
    }
  }

  mimeEmitterEndHeader(obj->options);

  // rhp:
  // For now, we are going to parse the entire message, even if we are
  // only interested in headers...why? Well, because this is the only
  // way to build the attachment list. Now we will have the attachment
  // list in the output being created by the XML emitter. If we ever
  // want to go back to where we were before, just uncomment the conditional
  // and it will stop at header parsing.
  //
  // if (obj->options->headers == MimeHeadersOnly)
  //   return -1;
  // else

  return 0;
}
Example #21
0
static int
MimeMultipartRelated_parse_eof (MimeObject *obj, bool abort_p)
{
  /* OK, all the necessary data has been collected.  We now have to spew out
     the HTML.  We let it go through all the normal mechanisms (which
     includes content-encoding handling), and intercept the output data to do
     translation of the tags.  Whee. */
  MimeMultipartRelated *relobj = (MimeMultipartRelated *) obj;
  MimeContainer *cont = (MimeContainer *)obj;
  int status = 0;
  MimeObject *body;
  char* ct;
  const char* dct;

  status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
  if (status < 0) goto FAIL;

  if (!relobj->headobj) return 0;

  ct = (relobj->buffered_hdrs
      ? MimeHeaders_get (relobj->buffered_hdrs, HEADER_CONTENT_TYPE,
               true, false)
      : 0);
  dct = (((MimeMultipartClass *) obj->clazz)->default_part_type);

  relobj->real_output_fn = obj->options->output_fn;
  relobj->real_output_closure = obj->options->output_closure;

  obj->options->output_fn = mime_multipart_related_output_fn;
  obj->options->output_closure = obj;

  body = mime_create(((ct && *ct) ? ct : (dct ? dct : TEXT_HTML)),
             relobj->buffered_hdrs, obj->options);

  PR_FREEIF(ct);
  if (!body) {
    status = MIME_OUT_OF_MEMORY;
    goto FAIL;
  }
  // replace the existing head object with the new object
  for (int iChild = 0; iChild < cont->nchildren; iChild++) {
    if (cont->children[iChild] == relobj->headobj) {
      // cleanup of the headobj is performed explicitly in our finalizer now
      //  that it does not get cleaned up as a child.
      cont->children[iChild] = body;
      body->parent = obj;
      body->options = obj->options;
    }
  }

  if (!body->parent) {
    NS_WARNING("unexpected mime multipart related structure");
    goto FAIL;
  }

  body->dontShowAsAttachment = body->clazz->displayable_inline_p(body->clazz, body->headers);

#ifdef MIME_DRAFTS
  if ( obj->options &&
     obj->options->decompose_file_p &&
     obj->options->decompose_file_init_fn &&
     (relobj->file_buffer || relobj->head_buffer))
  {
    status = obj->options->decompose_file_init_fn ( obj->options->stream_closure,
                            relobj->buffered_hdrs );
    if (status < 0) return status;
  }
#endif /* MIME_DRAFTS */

  /* if the emitter wants to know about nested bodies, then it needs
     to know that we jumped back to this body part. */
  if (obj->options->notify_nested_bodies)
  {
    char *part_path = mime_part_address(body);
    if (part_path)
    {
      mimeEmitterAddHeaderField(obj->options,
                                "x-jsemitter-part-path",
                                part_path);
      PR_Free(part_path);
    }
  }

  /* Now that we've added this new object to our list of children,
     start its parser going. */
  status = body->clazz->parse_begin(body);
  if (status < 0) goto FAIL;

  if (relobj->head_buffer)
  {
    /* Read it out of memory. */
    PR_ASSERT(!relobj->file_buffer && !relobj->input_file_stream);

    status = body->clazz->parse_buffer(relobj->head_buffer,
                         relobj->head_buffer_fp,
                         body);
  }
  else if (relobj->file_buffer)
  {
    /* Read it off disk. */
    char *buf;
    int32_t buf_size = 10 * 1024;  /* 10k; tune this? */

    PR_ASSERT(relobj->head_buffer_size == 0 &&
          relobj->head_buffer_fp == 0);
    PR_ASSERT(relobj->file_buffer);
    if (!relobj->file_buffer)
    {
      status = -1;
      goto FAIL;
    }

    buf = (char *) PR_MALLOC(buf_size);
    if (!buf)
    {
      status = MIME_OUT_OF_MEMORY;
      goto FAIL;
    }

    // First, close the output file to open the input file!
    if (relobj->output_file_stream)
      relobj->output_file_stream->Close();

    nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(relobj->input_file_stream), relobj->file_buffer);
    if (NS_FAILED(rv))
    {
      PR_Free(buf);
      status = MIME_UNABLE_TO_OPEN_TMP_FILE;
      goto FAIL;
    }

    while(1)
    {
      uint32_t bytesRead = 0;
      rv = relobj->input_file_stream->Read(buf, buf_size - 1, &bytesRead);
      if (NS_FAILED(rv) || !bytesRead)
      {
        status = NS_FAILED(rv) ? -1 : 0;
        break;
      }
      else
      {
        /* It would be really nice to be able to yield here, and let
           some user events and other input sources get processed.
           Oh well. */

        status = body->clazz->parse_buffer(buf, bytesRead, body);
        if (status < 0) break;
      }
    }
    PR_Free(buf);
  }

  if (status < 0) goto FAIL;

  /* Done parsing. */
  status = body->clazz->parse_eof(body, false);
  if (status < 0) goto FAIL;
  status = body->clazz->parse_end(body, false);
  if (status < 0) goto FAIL;

FAIL:

#ifdef MIME_DRAFTS
  if ( obj->options &&
     obj->options->decompose_file_p &&
     obj->options->decompose_file_close_fn &&
     (relobj->file_buffer || relobj->head_buffer)) {
  status = obj->options->decompose_file_close_fn ( obj->options->stream_closure );
  if (status < 0) return status;
  }
#endif /* MIME_DRAFTS */

  obj->options->output_fn = relobj->real_output_fn;
  obj->options->output_closure = relobj->real_output_closure;

  return status;
}
Example #22
0
static int
MimeObject_initialize (MimeObject *obj)
{
  /* This is an abstract class; it shouldn't be directly instantiated. */
  NS_ASSERTION(obj->clazz != &mimeObjectClass, "should directly instantiate abstract class");

  /* Set up the content-type and encoding. */
  if (!obj->content_type && obj->headers)
  obj->content_type = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE,
                     PR_TRUE, PR_FALSE);
  if (!obj->encoding && obj->headers)
  obj->encoding = MimeHeaders_get (obj->headers,
                   HEADER_CONTENT_TRANSFER_ENCODING,
                   PR_TRUE, PR_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 || !*(obj->content_type))
  ;
  else if (!PL_strcasecmp(obj->content_type, APPLICATION_UUENCODE2) ||
       !PL_strcasecmp(obj->content_type, APPLICATION_UUENCODE3) ||
       !PL_strcasecmp(obj->content_type, APPLICATION_UUENCODE4))
  {
    PR_Free(obj->content_type);
    obj->content_type = strdup(APPLICATION_UUENCODE);
  }
  else if (!PL_strcasecmp(obj->content_type, IMAGE_XBM2) ||
       !PL_strcasecmp(obj->content_type, IMAGE_XBM3))
  {
    PR_Free(obj->content_type);
    obj->content_type = strdup(IMAGE_XBM);
  }
  else {
    // MIME-types are case-insenitive, but let's make it lower case internally
    // to avoid some hassle later down the road.
    nsCAutoString lowerCaseContentType;
    ToLowerCase(nsDependentCString(obj->content_type), lowerCaseContentType);
    PR_Free(obj->content_type);
    obj->content_type = ToNewCString(lowerCaseContentType);
  }

  if (!obj->encoding)
  ;
  else if (!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE2) ||
       !PL_strcasecmp(obj->encoding, ENCODING_UUENCODE3) ||
       !PL_strcasecmp(obj->encoding, ENCODING_UUENCODE4))
  {
    PR_Free(obj->encoding);
    obj->encoding = strdup(ENCODING_UUENCODE);
  }
  else if (!PL_strcasecmp(obj->encoding, ENCODING_COMPRESS2))
  {
    PR_Free(obj->encoding);
    obj->encoding = strdup(ENCODING_COMPRESS);
  }
  else if (!PL_strcasecmp(obj->encoding, ENCODING_GZIP2))
  {
    PR_Free(obj->encoding);
    obj->encoding = strdup(ENCODING_GZIP);
  }

  return 0;
}
Example #23
0
static int
MimeMessage_close_headers (MimeObject *obj)
{
  MimeMessage *msg = (MimeMessage *) obj;
  int status = 0;
  char *ct = 0;      /* Content-Type header */
  MimeObject *body;

  if (msg->hdrs)
  {
    PRBool outer_p = !obj->headers; /* is this the outermost message? */


#ifdef MIME_DRAFTS
    if (outer_p &&
      obj->options &&
          (obj->options->decompose_file_p || obj->options->caller_need_root_headers) &&
      obj->options->decompose_headers_info_fn)
    {
#ifdef ENABLE_SMIME
      if (obj->options->decrypt_p && !mime_crypto_object_p (msg->hdrs, PR_FALSE))
        obj->options->decrypt_p = PR_FALSE;
#endif /* ENABLE_SMIME */
      if (!obj->options->caller_need_root_headers || (obj == obj->options->state->root))
        status = obj->options->decompose_headers_info_fn (
                         obj->options->stream_closure,
                               msg->hdrs );
    }
#endif /* MIME_DRAFTS */


    /* If this is the outermost message, we need to run the
     `generate_header' callback.  This happens here instead of
     in `parse_begin', because it's only now that we've parsed
     our headers.  However, since this is the outermost message,
     we have yet to write any HTML, so that's fine.
     */
    if (outer_p &&
      obj->output_p &&
      obj->options &&
      obj->options->write_html_p &&
      obj->options->generate_header_html_fn)
    {
      int lstatus = 0;
      char *html = 0;

      /* The generate_header_html_fn might return HTML, so it's important
       that the output stream be set up with the proper type before we
       make the MimeObject_write() call below. */
      if (!obj->options->state->first_data_written_p)
      {
        lstatus = MimeObject_output_init (obj, TEXT_HTML);
        if (lstatus < 0) return lstatus;
        PR_ASSERT(obj->options->state->first_data_written_p);
      }

      html = obj->options->generate_header_html_fn(NULL,
                           obj->options->html_closure,
                             msg->hdrs);
      if (html)
      {
        lstatus = MimeObject_write(obj, html, strlen(html), PR_FALSE);
        PR_Free(html);
        if (lstatus < 0) return lstatus;
      }
    }


    /* Find the content-type of the body of this message.
     */
    {
    PRBool ok = PR_TRUE;
    char *mv = MimeHeaders_get (msg->hdrs, HEADER_MIME_VERSION,
                  PR_TRUE, PR_FALSE);

#ifdef REQUIRE_MIME_VERSION_HEADER
    /* If this is the outermost message, it must have a MIME-Version
       header with the value 1.0 for us to believe what might be in
       the Content-Type header.  If the MIME-Version header is not
       present, we must treat this message as untyped.
     */
    ok = (mv && !strcmp(mv, "1.0"));
#else
    /* #### actually, we didn't check this in Mozilla 2.0, and checking
       it now could cause some compatibility nonsense, so for now, let's
       just believe any Content-Type header we see.
     */
    ok = PR_TRUE;
#endif

    if (ok)
      {
      ct = MimeHeaders_get (msg->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);

      /* If there is no Content-Type header, but there is a MIME-Version
         header, then assume that this *is* in fact a MIME message.
         (I've seen messages with

          MIME-Version: 1.0
          Content-Transfer-Encoding: quoted-printable

         and no Content-Type, and we should treat those as being of type
         MimeInlineTextPlain rather than MimeUntypedText.)
       */
      if (mv && !ct)
        ct = strdup(TEXT_PLAIN);
      }

    PR_FREEIF(mv);  /* done with this now. */
    }

    /* If this message has a body which is encrypted and we're going to
       decrypt it (whithout converting it to HTML, since decrypt_p and
       write_html_p are never true at the same time)
    */
    if (obj->output_p &&
        obj->options &&
        obj->options->decrypt_p
#ifdef ENABLE_SMIME
        && !mime_crypto_object_p (msg->hdrs, PR_FALSE)
#endif /* ENABLE_SMIME */
        )
    {
      /* The body of this message is not an encrypted object, so we need
         to turn off the decrypt_p flag (to prevent us from s#$%ing the
         body of the internal object up into one.) In this case,
         our output will end up being identical to our input.
      */
      obj->options->decrypt_p = PR_FALSE;
    }

    /* Emit the HTML for this message's headers.  Do this before
     creating the object representing the body.
     */
    if (obj->output_p &&
      obj->options &&
      obj->options->write_html_p)
    {
      /* If citation headers are on, and this is not the outermost message,
       turn them off. */
      if (obj->options->headers == MimeHeadersCitation && !outer_p)
      obj->options->headers = MimeHeadersSome;

      /* Emit a normal header block. */
      status = MimeMessage_write_headers_html(obj);
      if (status < 0) return status;
    }
    else if (obj->output_p)
    {
      /* Dump the headers, raw. */
      status = MimeObject_write(obj, "", 0, PR_FALSE);  /* initialize */
      if (status < 0) return status;
      status = MimeHeaders_write_raw_headers(msg->hdrs, obj->options,
                         obj->options->decrypt_p);
      if (status < 0) return status;
    }

#ifdef XP_UNIX
    if (outer_p && obj->output_p)
    /* Kludge from mimehdrs.c */
    MimeHeaders_do_unix_display_hook_hack(msg->hdrs);
#endif /* XP_UNIX */
  }

  /* Never put out a separator after a message header block. */
  if (obj->options && obj->options->state)
  obj->options->state->separator_suppressed_p = PR_TRUE;

#ifdef MIME_DRAFTS
  if ( !obj->headers &&    /* outer most message header */
     obj->options &&
     obj->options->decompose_file_p &&
     ct )
  obj->options->is_multipart_msg = PL_strcasestr(ct, "multipart/") != NULL;
#endif /* MIME_DRAFTS */


  body = mime_create(ct, msg->hdrs, obj->options);

  PR_FREEIF(ct);
  if (!body) return MIME_OUT_OF_MEMORY;
  status = ((MimeContainerClass *) obj->clazz)->add_child (obj, body);
  if (status < 0)
  {
    mime_free(body);
    return status;
  }

  // Only do this if this is a Text Object!
  if ( mime_typep(body, (MimeObjectClass *) &mimeInlineTextClass) )
  {
    ((MimeInlineText *) body)->needUpdateMsgWinCharset = PR_TRUE;
  }

  /* Now that we've added this new object to our list of children,
   start its parser going. */
  status = body->clazz->parse_begin(body);
  if (status < 0) return status;

  // Now notify the emitter if this is the outer most message, unless
  // it is a part that is not the head of the message. If it's a part,
  // we need to figure out the content type/charset of the part
  //
  PRBool outer_p = !obj->headers;  /* is this the outermost message? */

  if ( outer_p &&
       (!obj->options->part_to_load || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay))
  {
    // call SetMailCharacterSetToMsgWindow() to set a menu charset
    if (mime_typep(body, (MimeObjectClass *) &mimeInlineTextClass))
    {
      MimeInlineText  *text = (MimeInlineText *) body;
      if (text && text->charset && *text->charset)
        SetMailCharacterSetToMsgWindow(body, text->charset);
    }

    char  *msgID = MimeHeaders_get (msg->hdrs, HEADER_MESSAGE_ID,
                                    PR_FALSE, PR_FALSE);

    const char  *outCharset = NULL;
    if (!obj->options->force_user_charset)  /* Only convert if the user prefs is false */
      outCharset = "UTF-8";

    mimeEmitterStartBody(obj->options, (obj->options->headers == MimeHeadersNone), msgID, outCharset);
    PR_FREEIF(msgID);

  // setting up truncated message html fotter function
  char *xmoz = MimeHeaders_get(msg->hdrs, HEADER_X_MOZILLA_STATUS, PR_FALSE,
                 PR_FALSE);
  if (xmoz)
  {
    PRUint32 flags = 0;
    char dummy = 0;
    if (sscanf(xmoz, " %lx %c", &flags, &dummy) == 1 &&
      flags & MSG_FLAG_PARTIAL)
    {
      obj->options->html_closure = obj;
      obj->options->generate_footer_html_fn =
        MimeMessage_partial_message_html;
    }
    PR_FREEIF(xmoz);
  }
  }

  return 0;
}
static int
MimeMultipartAlternative_display_cached_part(MimeObject *obj,
                                             MimeHeaders *hdrs,
                                             MimePartBufferData *buffer,
                                             bool do_display)
{
  int status;

  char *ct = (hdrs
        ? MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, true, false)
        : 0);
  const char *dct = (((MimeMultipartClass *) obj->clazz)->default_part_type);
  MimeObject *body;
  /** Don't pass in NULL as the content-type (this means that the
   * auto-uudecode-hack won't ever be done for subparts of a
   * multipart, but only for untyped children of message/rfc822.
   */
  const char *uct = (ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN);

  // We always want to display the cached part inline.
  body = mime_create(uct, hdrs, obj->options, true);
  PR_FREEIF(ct);
  if (!body) return MIME_OUT_OF_MEMORY;
  body->output_p = do_display;

  status = ((MimeContainerClass *) obj->clazz)->add_child(obj, body);
  if (status < 0)
  {
    mime_free(body);
    return status;
  }
  /* We need to muck around with the options to prevent output when
     do_display is false. More about this below. */
  /* add_child assigns body->options from obj->options, but that's
     just a pointer so if we muck with it in the child it'll modify
     the parent as well, which we definitely don't want. Therefore we
     need to make a copy. */
  body->options = new MimeDisplayOptions;
  *body->options = *obj->options;
  /* But we have to be careful about getting into a situation where
     memory could be double-freed. All of this is a gross abstraction
     violation which could be avoided if it were possible to tell
     parse_begin what output_p should be. */
  if (body->options->part_to_load)
    body->options->part_to_load = strdup(body->options->part_to_load);
  if (body->options->default_charset)
    body->options->default_charset = strdup(body->options->default_charset);
  
  /* parse_begin resets output_p. This is quite annoying. To convince
     it that we mean business, we set output_fn to null if we don't
     want output. */
  if (! do_display)
    body->options->output_fn = nullptr;

#ifdef MIME_DRAFTS
  /* if this object is a child of a multipart/related object, the parent is
     taking care of decomposing the whole part, don't need to do it at this level.
     However, we still have to call decompose_file_init_fn and decompose_file_close_fn
     in order to set the correct content-type. But don't call MimePartBufferRead
  */
  bool multipartRelatedChild = mime_typep(obj->parent,(MimeObjectClass*)&mimeMultipartRelatedClass);
  bool decomposeFile = do_display && obj->options &&
                  obj->options->decompose_file_p &&
                  obj->options->decompose_file_init_fn &&
                  !mime_typep(body, (MimeObjectClass *) &mimeMultipartClass);

  if (decomposeFile)
  {
    status = obj->options->decompose_file_init_fn (
                        obj->options->stream_closure, hdrs);
    if (status < 0) return status;
  }
#endif /* MIME_DRAFTS */

  /* Now that we've added this new object to our list of children,
   notify emitters and start its parser going. */
  MimeMultipart_notify_emitter(body);

  status = body->clazz->parse_begin(body);
  if (status < 0) return status;
  /* Now that parse_begin is done mucking with output_p, we can put
     body->options back to what it's supposed to be. Avoids a memory
     leak. */
  delete body->options;
  body->options = obj->options;

#ifdef MIME_DRAFTS
  if (decomposeFile && !multipartRelatedChild)
    status = MimePartBufferRead (buffer,
                  obj->options->decompose_file_output_fn,
                  obj->options->stream_closure);
  else
#endif /* MIME_DRAFTS */

  status = MimePartBufferRead (buffer,
                  /* The MimeConverterOutputCallback cast is to turn the
                   `void' argument into `MimeObject'. */
                  ((MimeConverterOutputCallback) body->clazz->parse_buffer),
                  body);

  if (status < 0) return status;

  /* Done parsing. */
  status = body->clazz->parse_eof(body, false);
  if (status < 0) return status;
  status = body->clazz->parse_end(body, false);
  if (status < 0) return status;

#ifdef MIME_DRAFTS
  if (decomposeFile)
  {
    status = obj->options->decompose_file_close_fn ( obj->options->stream_closure );
    if (status < 0) return status;
  }
#endif /* MIME_DRAFTS */

  return 0;
}
Example #25
0
static int
MimeMultipart_create_child(MimeObject *obj)
{
  MimeMultipart *mult = (MimeMultipart *) obj;
  int           status;
  char *ct = (mult->hdrs
        ? MimeHeaders_get (mult->hdrs, HEADER_CONTENT_TYPE,
                 PR_TRUE, PR_FALSE)
        : 0);
  const char *dct = (((MimeMultipartClass *) obj->clazz)->default_part_type);
  MimeObject *body = NULL;

  mult->state = MimeMultipartPartFirstLine;
  /* Don't pass in NULL as the content-type (this means that the
   auto-uudecode-hack won't ever be done for subparts of a
   multipart, but only for untyped children of message/rfc822.
   */
  body = mime_create(((ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN)),
           mult->hdrs, obj->options);
  PR_FREEIF(ct);
  if (!body) return MIME_OUT_OF_MEMORY;
  status = ((MimeContainerClass *) obj->clazz)->add_child(obj, body);
  if (status < 0)
  {
    mime_free(body);
    return status;
  }

#ifdef MIME_DRAFTS
  if ( obj->options && 
     obj->options->decompose_file_p &&
     obj->options->is_multipart_msg &&
     obj->options->decompose_file_init_fn )
  {
    if ( !mime_typep(obj,(MimeObjectClass*)&mimeMultipartRelatedClass) &&
           !mime_typep(obj,(MimeObjectClass*)&mimeMultipartAlternativeClass) &&
       !mime_typep(obj,(MimeObjectClass*)&mimeMultipartSignedClass) &&
#ifdef MIME_DETAIL_CHECK
       !mime_typep(body, (MimeObjectClass*)&mimeMultipartRelatedClass) &&
       !mime_typep(body, (MimeObjectClass*)&mimeMultipartAlternativeClass) &&
       !mime_typep(body,(MimeObjectClass*)&mimeMultipartSignedClass) 
#else
           /* bug 21869 -- due to the fact that we are not generating the
              correct mime class object for content-typ multipart/signed part
              the above check failed. to solve the problem in general and not
              to cause early temination when parsing message for opening as
              draft we can simply make sure that the child is not a multipart
              mime object. this way we could have a proper decomposing message
              part functions set correctly */
           !mime_typep(body, (MimeObjectClass*) &mimeMultipartClass)
#endif
    &&        ! (mime_typep(body, (MimeObjectClass*)&mimeExternalObjectClass) && !strcmp(body->content_type, "text/x-vcard"))
       )
    {
    status = obj->options->decompose_file_init_fn ( obj->options->stream_closure, mult->hdrs );
    if (status < 0) return status;
    }
  }
#endif /* MIME_DRAFTS */


  /* Now that we've added this new object to our list of children,
   start its parser going (if we want to display it.)
   */
  body->output_p = (((MimeMultipartClass *) obj->clazz)->output_child_p(obj, body));
  if (body->output_p)
  {  
    status = body->clazz->parse_begin(body);

#ifdef XP_MACOSX
    /* if we are saving an apple double attachment, we need to set correctly the conten type of the channel */
    if (mime_typep(obj, (MimeObjectClass *) &mimeMultipartAppleDoubleClass))
    {
      struct mime_stream_data *msd = (struct mime_stream_data *)body->options->stream_closure;
      if (!body->options->write_html_p && body->content_type && !PL_strcasecmp(body->content_type, APPLICATION_APPLEFILE))
      {
        if (msd && msd->channel)
          msd->channel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_APPLEFILE));
      }
    }
#endif

    if (status < 0) return status;
  }

  return 0;
}
Example #26
0
int
MimeHeaders_write_all_headers (MimeHeaders *hdrs, MimeDisplayOptions *opt, bool attachment)
{
  int status = 0;
  int i;
  bool wrote_any_p = false;

  NS_ASSERTION(hdrs, "1.1 <*****@*****.**> 19 Mar 1999 12:00");
  if (!hdrs)
    return -1;

  /* One shouldn't be trying to read headers when one hasn't finished
     parsing them yet... but this can happen if the message ended
     prematurely, and has no body at all (as opposed to a null body,
     which is more normal.)   So, if we try to read from the headers,
     let's assume that the headers are now finished.  If they aren't
     in fact finished, then a later attempt to write to them will assert.
   */
  if (!hdrs->done_p)
  {
    hdrs->done_p = true;
    status = MimeHeaders_build_heads_list(hdrs);
    if (status < 0) return 0;
  }

  char *charset = nullptr;
  if (opt->format_out == nsMimeOutput::nsMimeMessageSaveAs)
  {
    if (opt->override_charset)
      charset = PL_strdup(opt->default_charset);
    else
    {
      char *contentType = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, false, false);
      if (contentType)
        charset = MimeHeaders_get_parameter(contentType, HEADER_PARM_CHARSET, nullptr, nullptr);
      PR_FREEIF(contentType);
    }
  }

  for (i = 0; i < hdrs->heads_size; i++)
  {
    char *head = hdrs->heads[i];
    char *end = (i == hdrs->heads_size-1
                      ? hdrs->all_headers + hdrs->all_headers_fp
                      : hdrs->heads[i+1]);
    char *colon, *ocolon;
    char *contents = end;

    /* Hack for BSD Mailbox delimiter. */
    if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5))
    {
      /* For now, we don't really want this header to be output so
         we are going to just continue */
      continue;
      /* colon = head + 4; contents = colon + 1; */
    }
    else
    {
      /* Find the colon. */
      for (colon = head; colon < end && *colon != ':'; colon++)
        ;

        /* Back up over whitespace before the colon. */
        ocolon = colon;
        for (; colon > head && IS_SPACE(colon[-1]); colon--)
          ;

        contents = ocolon + 1;
    }

    /* Skip over whitespace after colon. */
    while (contents < end && IS_SPACE(*contents))
      contents++;

    /* Take off trailing whitespace... */
    while (end > contents && IS_SPACE(end[-1]))
      end--;

    nsCAutoString name(Substring(head, colon));
    nsCAutoString hdr_value;

    if ( (end - contents) > 0 )
    {
      hdr_value = Substring(contents, end);
    }

    // MW Fixme: more?
    bool convert_charset_only =
          MsgLowerCaseEqualsLiteral(name, "to") || MsgLowerCaseEqualsLiteral(name, "from") ||
          MsgLowerCaseEqualsLiteral(name, "cc") || MsgLowerCaseEqualsLiteral(name, "bcc") ||
          MsgLowerCaseEqualsLiteral(name, "reply-to") || MsgLowerCaseEqualsLiteral(name, "sender");
    MimeHeaders_convert_header_value(opt, hdr_value, convert_charset_only);
    // if we're saving as html, we need to convert headers from utf8 to message charset, if any
    if (opt->format_out == nsMimeOutput::nsMimeMessageSaveAs && charset)
    {
      nsCAutoString convertedStr;
      if (NS_SUCCEEDED(ConvertFromUnicode(charset, NS_ConvertUTF8toUTF16(hdr_value),
                       convertedStr)))
      {
        hdr_value = convertedStr;
      }
    }

    if (attachment)
      status = mimeEmitterAddAttachmentField(opt, name.get(), hdr_value.get());
    else
      status = mimeEmitterAddHeaderField(opt, name.get(), hdr_value.get());

    if (status < 0) return status;
    if (!wrote_any_p)
      wrote_any_p = (status > 0);
  }
  mimeEmitterAddAllHeaders(opt, hdrs->all_headers, hdrs->all_headers_fp);
  PR_FREEIF(charset);

  return 1;
}
Example #27
0
static char *
MimeMessage_partial_message_html(const char *data, void *closure,
                 MimeHeaders *headers)
{
  MimeMessage *msg = (MimeMessage *)closure;
  nsCAutoString orig_url(data);
  char *uidl = MimeHeaders_get(headers, HEADER_X_UIDL, PR_FALSE, PR_FALSE);
  char *msgId = MimeHeaders_get(headers, HEADER_MESSAGE_ID, PR_FALSE,
                  PR_FALSE);
  char *msgIdPtr = PL_strstr(msgId, "<");
  int msgBase;

  PRInt32 pos = orig_url.Find("mailbox-message");
  if (pos != -1)
    orig_url.Cut(pos + 7, 8);

  pos = orig_url.Find("#");
  if (pos != -1)
    orig_url.Replace(pos, 1, "?number=", 8);

  if (msgIdPtr)
    msgIdPtr++;
  else
    msgIdPtr = msgId;
  char *gtPtr = PL_strstr(msgIdPtr, ">");
  if (gtPtr)
    *gtPtr = 0;

  msgBase = (msg->bodyLength > MSG_LINEBREAK_LEN) ? MIME_MSG_PARTIAL_FMT_1 : MIME_MSG_PARTIAL_FMT2_1;

  nsCString partialMsgHtml;
  nsCString item;

  item.Adopt(MimeGetStringByID(msgBase));
  partialMsgHtml += item;

  item.Adopt(MimeGetStringByID(msgBase+1));
  partialMsgHtml += item;

  partialMsgHtml.Append(orig_url);

  if (msgIdPtr) {
    partialMsgHtml.AppendLiteral("&messageid=");

    MsgEscapeString(nsDependentCString(msgIdPtr), nsINetUtil::ESCAPE_URL_PATH,
                    item);

    partialMsgHtml.Append(item);
  }

  if (uidl) {
    partialMsgHtml.AppendLiteral("&uidl=");

    MsgEscapeString(nsDependentCString(uidl), nsINetUtil::ESCAPE_XALPHAS,
                    item);

    partialMsgHtml.Append(item);
  }

  item.Adopt(MimeGetStringByID(msgBase+2));
  partialMsgHtml += item;

  return ToNewCString(partialMsgHtml);
}
Example #28
0
static int
MimeExternalBody_parse_eof (MimeObject *obj, bool abort_p)
{
  int status = 0;
  MimeExternalBody *bod = (MimeExternalBody *) obj;

  if (obj->closed_p) return 0;

  /* Run parent method first, to flush out any buffered data. */
  status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
  if (status < 0) return status;

#ifdef XP_MACOSX
  if (obj->parent && mime_typep(obj->parent,
                                (MimeObjectClass*) &mimeMultipartAppleDoubleClass))
    goto done;
#endif /* XP_MACOSX */

  if (!abort_p &&
      obj->output_p &&
      obj->options &&
      obj->options->write_html_p)
  {
    bool all_headers_p = obj->options->headers == MimeHeadersAll;
    MimeDisplayOptions *newopt = obj->options;  /* copy it */

    char *ct = MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE,
                               PR_FALSE, PR_FALSE);
    char *at, *lexp, *size, *perm;
    char *url, *dir, *mode, *name, *site, *svr, *subj;
    char *h = 0, *lname = 0, *lurl = 0, *body = 0;
    MimeHeaders *hdrs = 0;

    if (!ct) return MIME_OUT_OF_MEMORY;

    at   = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL);
    lexp  = MimeHeaders_get_parameter(ct, "expiration", NULL, NULL);
    size = MimeHeaders_get_parameter(ct, "size", NULL, NULL);
    perm = MimeHeaders_get_parameter(ct, "permission", NULL, NULL);
    dir  = MimeHeaders_get_parameter(ct, "directory", NULL, NULL);
    mode = MimeHeaders_get_parameter(ct, "mode", NULL, NULL);
    name = MimeHeaders_get_parameter(ct, "name", NULL, NULL);
    site = MimeHeaders_get_parameter(ct, "site", NULL, NULL);
    svr  = MimeHeaders_get_parameter(ct, "server", NULL, NULL);
    subj = MimeHeaders_get_parameter(ct, "subject", NULL, NULL);
    url  = MimeHeaders_get_parameter(ct, "url", NULL, NULL);
    PR_FREEIF(ct);

    /* the *internal* content-type */
    ct = MimeHeaders_get(bod->hdrs, HEADER_CONTENT_TYPE,
                         PR_TRUE, PR_FALSE);
						 
    PRUint32 hlen = ((at ? strlen(at) : 0) +
                    (lexp ? strlen(lexp) : 0) +
                    (size ? strlen(size) : 0) +
                    (perm ? strlen(perm) : 0) +
                    (dir ? strlen(dir) : 0) +
                    (mode ? strlen(mode) : 0) +
                    (name ? strlen(name) : 0) +
                    (site ? strlen(site) : 0) +
                    (svr ? strlen(svr) : 0) +
                    (subj ? strlen(subj) : 0) +
                    (ct ? strlen(ct) : 0) +
                    (url ? strlen(url) : 0) + 100);
					
	h = (char *) PR_MALLOC(hlen);
    if (!h)
    {
      status = MIME_OUT_OF_MEMORY;
      goto FAIL;
    }

    /* If there's a URL parameter, remove all whitespace from it.
      (The URL parameter to one of these headers is stored with
       lines broken every 40 characters or less; it's assumed that
       all significant whitespace was URL-hex-encoded, and all the
       rest of it was inserted just to keep the lines short.)
      */
    if (url)
    {
      char *in, *out;
      for (in = url, out = url; *in; in++)
        if (!IS_SPACE(*in))
          *out++ = *in;
      *out = 0;
    }

    hdrs = MimeHeaders_new();
    if (!hdrs)
    {
      status = MIME_OUT_OF_MEMORY;
      goto FAIL;
    }

# define FROB(STR,VAR) \
    if (VAR) \
    { \
      PL_strncpyz(h, STR ": ", hlen); \
        PL_strcatn(h, hlen, VAR); \
          PL_strcatn(h, hlen, MSG_LINEBREAK); \
            status = MimeHeaders_parse_line(h, strlen(h), hdrs); \
              if (status < 0) goto FAIL; \
    }
    FROB("Access-Type",  at);
    FROB("URL",      url);
    FROB("Site",      site);
    FROB("Server",    svr);
    FROB("Directory",    dir);
    FROB("Name",      name);
    FROB("Type",      ct);
    FROB("Size",      size);
    FROB("Mode",      mode);
    FROB("Permission",  perm);
    FROB("Expiration",  lexp);
    FROB("Subject",    subj);
# undef FROB
    PL_strncpyz(h, MSG_LINEBREAK, hlen);
    status = MimeHeaders_parse_line(h, strlen(h), hdrs);
    if (status < 0) goto FAIL;

    lurl = MimeExternalBody_make_url(ct, at, lexp, size, perm, dir, mode,
                                     name, url, site, svr, subj, bod->body);
    if (lurl)
    {
      lname = MimeGetStringByID(MIME_MSG_LINK_TO_DOCUMENT);
    }
    else
    {
      lname = MimeGetStringByID(MIME_MSG_DOCUMENT_INFO);
      all_headers_p = PR_TRUE;
    }

    all_headers_p = PR_TRUE;  /* #### just do this all the time? */

    if (bod->body && all_headers_p)
    {
      char *s = bod->body;
      while (IS_SPACE(*s)) s++;
      if (*s)
      {
        char *s2;
        const char *pre = "<P><PRE>";
        const char *suf = "</PRE>";
        PRInt32 i;
        for(i = strlen(s)-1; i >= 0 && IS_SPACE(s[i]); i--)
          s[i] = 0;
        s2 = MsgEscapeHTML(s);
        if (!s2) goto FAIL;
        body = (char *) PR_MALLOC(strlen(pre) + strlen(s2) +
                                  strlen(suf) + 1);
        if (!body)
        {
          NS_Free(s2);
          goto FAIL;
        }
        PL_strcpy(body, pre);
        PL_strcat(body, s2);
        PL_strcat(body, suf);
      }
    }

    newopt->fancy_headers_p = PR_TRUE;
    newopt->headers = (all_headers_p ? MimeHeadersAll : MimeHeadersSome);

FAIL:
      if (hdrs)
        MimeHeaders_free(hdrs);
    PR_FREEIF(h);
    PR_FREEIF(lname);
    PR_FREEIF(lurl);
    PR_FREEIF(body);
    PR_FREEIF(ct);
    PR_FREEIF(at);
    PR_FREEIF(lexp);
    PR_FREEIF(size);
    PR_FREEIF(perm);
    PR_FREEIF(dir);
    PR_FREEIF(mode);
    PR_FREEIF(name);
    PR_FREEIF(url);
    PR_FREEIF(site);
    PR_FREEIF(svr);
    PR_FREEIF(subj);
  }

#ifdef XP_MACOSX
done:
#endif

    return status;
}
Example #29
0
static int
MimeInlineTextPlainFlowed_parse_begin (MimeObject *obj)
{
  int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
  if (status < 0) return status;

  status =  MimeObject_write(obj, "", 0, PR_TRUE); /* force out any separators... */
  if(status<0) return status;

  PRBool quoting = ( obj->options
    && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting ||
         obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting
       )       );  // The output will be inserted in the composer as quotation
  PRBool plainHTML = quoting || (obj->options &&
       obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs);
       // Just good(tm) HTML. No reliance on CSS.

  // Setup the data structure that is connected to the actual document
  // Saved in a linked list in case this is called with several documents
  // at the same time.
  /* This memory is freed when parse_eof is called. So it better be! */
  struct MimeInlineTextPlainFlowedExData *exdata =
    (MimeInlineTextPlainFlowedExData *)PR_MALLOC(sizeof(struct MimeInlineTextPlainFlowedExData));
  if(!exdata) return MIME_OUT_OF_MEMORY;

  MimeInlineTextPlainFlowed *text = (MimeInlineTextPlainFlowed *) obj;

  // Link it up.
  exdata->next = MimeInlineTextPlainFlowedExDataList;
  MimeInlineTextPlainFlowedExDataList = exdata;

  // Initialize data

  exdata->ownerobj = obj;
  exdata->inflow = PR_FALSE;
  exdata->quotelevel = 0;
  exdata->isSig = PR_FALSE;

  // check for DelSp=yes (RFC 3676)

  char *content_type_row =
    (obj->headers
     ? MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE)
     : 0);
  char *content_type_delsp =
    (content_type_row
     ? MimeHeaders_get_parameter(content_type_row, "delsp", NULL,NULL)
     : 0);
  ((MimeInlineTextPlainFlowed *)obj)->delSp = content_type_delsp && !PL_strcasecmp(content_type_delsp, "yes");
  PR_Free(content_type_delsp);
  PR_Free(content_type_row);

  // Get Prefs for viewing

  exdata->fixedwidthfont = PR_FALSE;
  //  Quotes
  text->mQuotedSizeSetting = 0;   // mail.quoted_size
  text->mQuotedStyleSetting = 0;  // mail.quoted_style
  text->mCitationColor = nsnull;  // mail.citation_color

  nsIPrefBranch *prefBranch = GetPrefBranch(obj->options);
  if (prefBranch)
  {
    prefBranch->GetIntPref("mail.quoted_size", &(text->mQuotedSizeSetting));
    prefBranch->GetIntPref("mail.quoted_style", &(text->mQuotedStyleSetting));
    prefBranch->GetCharPref("mail.citation_color", &(text->mCitationColor));
    nsresult rv = prefBranch->GetBoolPref("mail.fixed_width_messages",
                                          &(exdata->fixedwidthfont));
    NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get pref");
         // Check at least the success of one
  }

  // Get font
  // only used for viewing (!plainHTML)
  nsCAutoString fontstyle;
  nsCAutoString fontLang;     // langgroup of the font


  // generic font-family name ( -moz-fixed for fixed font and NULL for
  // variable font ) is sufficient now that bug 105199 has been fixed.

  if (exdata->fixedwidthfont)
    fontstyle = "font-family: -moz-fixed";

  if (nsMimeOutput::nsMimeMessageBodyDisplay == obj->options->format_out ||
      nsMimeOutput::nsMimeMessagePrintOutput == obj->options->format_out)
  {
    PRInt32 fontSize;       // default font size
    PRInt32 fontSizePercentage;   // size percentage
    nsresult rv = GetMailNewsFont(obj, exdata->fixedwidthfont,
                                  &fontSize, &fontSizePercentage, fontLang);
    if (NS_SUCCEEDED(rv))
    {
      if ( ! fontstyle.IsEmpty() ) {
        fontstyle += "; ";
      }
      fontstyle += "font-size: ";
      fontstyle.AppendInt(fontSize);
      fontstyle += "px;";
    }
  }

  // Opening <div>.
  if (!quoting)
       /* 4.x' editor can't break <div>s (e.g. to interleave comments).
          We'll add the class to the <blockquote type=cite> later. */
  {
    nsCAutoString openingDiv("<div class=\"moz-text-flowed\"");
    // We currently have to add formatting here. :-(
    if (!plainHTML && !fontstyle.IsEmpty())
    {
      openingDiv += " style=\"";
      openingDiv += fontstyle;
      openingDiv += '"';
    }
    if (!plainHTML && !fontLang.IsEmpty())
    {
      openingDiv += " lang=\"";
      openingDiv += fontLang;
      openingDiv += '\"';
    }
    openingDiv += ">";
    status = MimeObject_write(obj, openingDiv.get(), openingDiv.Length(), PR_FALSE);
    if (status < 0) return status;
  }

  return 0;
}
Example #30
0
static bool
MimeMultipartRelated_output_child_p(MimeObject *obj, MimeObject* child)
{
  MimeMultipartRelated *relobj = (MimeMultipartRelated *) obj;

  /* rhp - Changed from "if (relobj->head_loaded)" alone to support the
           start parameter
   */
  if (
       (relobj->head_loaded) ||
       (MimeStartParamExists(obj, child) && !MimeThisIsStartPart(obj, child))
     )
  {
    /* This is a child part.  Just remember the mapping between the URL
       it represents and the part-URL to get it back. */

    char* location = MimeHeaders_get(child->headers, HEADER_CONTENT_LOCATION,
                     false, false);
    if (!location) {
      char* tmp = MimeHeaders_get(child->headers, HEADER_CONTENT_ID,
                    false, false);
      if (tmp) {
        char* tmp2 = tmp;
        if (*tmp2 == '<') {
          int length;
          tmp2++;
          length = strlen(tmp2);
          if (length > 0 && tmp2[length - 1] == '>') {
            tmp2[length - 1] = '\0';
          }
        }
        location = PR_smprintf("cid:%s", tmp2);
        PR_Free(tmp);
      }
    }

    if (location) {
      char *absolute;
      char *base_url = MimeHeaders_get(child->headers, HEADER_CONTENT_BASE,
                       false, false);
      absolute = MakeAbsoluteURL(base_url ? base_url : relobj->base_url, location);

      PR_FREEIF(base_url);
      PR_Free(location);
      if (absolute) {
        nsCAutoString partnum;
        nsCAutoString imappartnum;
        partnum.Adopt(mime_part_address(child));
        if (!partnum.IsEmpty()) {
          if (obj->options->missing_parts)
          {
            char * imappart = mime_imap_part_address(child);
            if (imappart)
              imappartnum.Adopt(imappart);
          }

          /*
            AppleDouble part need special care: we need to output only the data fork part of it.
            The problem at this point is that we haven't yet decoded the children of the AppleDouble
            part therfore we will have to hope the datafork is the second one!
          */
          if (mime_typep(child, (MimeObjectClass *) &mimeMultipartAppleDoubleClass))
            partnum.Append(".2");

          char* part;
          if (!imappartnum.IsEmpty())
            part = mime_set_url_imap_part(obj->options->url, imappartnum.get(), partnum.get());
          else
          {
            char *no_part_url = nullptr;
            if (obj->options->part_to_load && obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay)
              no_part_url = mime_get_base_url(obj->options->url);
            if (no_part_url)
            {
              part = mime_set_url_part(no_part_url, partnum.get(), false);
              PR_Free(no_part_url);
            }
            else
              part = mime_set_url_part(obj->options->url, partnum.get(), false);
          }
          if (part)
          {
            char *name = MimeHeaders_get_name(child->headers, child->options);
            // let's stick the filename in the part so save as will work.
            if (name)
            {
              //char *savePart = part;
              //part = PR_smprintf("%s&filename=%s", savePart, name);
              //PR_Free(savePart);
              PR_Free(name);
            }
            char *temp = part;
            /* If there's a space in the url, escape the url.
               (This happens primarily on Windows and Unix.) */
            if (PL_strchr(part, ' ') || PL_strchr(part, '>') || PL_strchr(part, '%'))
              temp = escape_for_mrel_subst(part);
              MimeHashValue * value = new MimeHashValue(child, temp);
              PL_HashTableAdd(relobj->hash, absolute, value);

            /* rhp - If this part ALSO has a Content-ID we need to put that into
                     the hash table and this is what this code does
             */
            {
              char *tloc;
              char *tmp = MimeHeaders_get(child->headers, HEADER_CONTENT_ID, false, false);
              if (tmp)
              {
                char* tmp2 = tmp;
                if (*tmp2 == '<')
                {
                  int length;
                  tmp2++;
                  length = strlen(tmp2);
                  if (length > 0 && tmp2[length - 1] == '>')
                  {
                    tmp2[length - 1] = '\0';
                  }
                }

                tloc = PR_smprintf("cid:%s", tmp2);
                PR_Free(tmp);
                if (tloc)
                {
                  MimeHashValue *value;
                  value = (MimeHashValue*)PL_HashTableLookup(relobj->hash, tloc);

                  if (!value)
                  {
                    value = new MimeHashValue(child, temp);
                    PL_HashTableAdd(relobj->hash, tloc, value);
                  }
                  else
                    PR_smprintf_free(tloc);
                }
              }
            }
            /*  rhp - End of putting more stuff into the hash table */

              /* it's possible that temp pointer is the same than the part pointer,
                 therefore be carefull to not freeing twice the same pointer */
              if (temp && temp != part)
                PR_Free(temp);
              PR_Free(part);
            }
          }
        }
      }
  } else {
    /* Ah-hah!  We're the head object.  */
    char* base_url;
    relobj->head_loaded = true;
    relobj->headobj = child;
    relobj->buffered_hdrs = MimeHeaders_copy(child->headers);
    base_url = MimeHeaders_get(child->headers, HEADER_CONTENT_BASE,
                   false, false);
    /* rhp: need this for supporting Content-Location */
    if (!base_url)
    {
      base_url = MimeHeaders_get(child->headers, HEADER_CONTENT_LOCATION, false, false);
    }
    /* rhp: need this for supporting Content-Location */

    if (base_url) {
      /* If the head object has a base_url associated with it, use
         that instead of any base_url that may have been associated
         with the multipart/related. */
      PR_FREEIF(relobj->base_url);
      relobj->base_url = base_url;
    }
  }
  if (obj->options && !obj->options->write_html_p
#ifdef MIME_DRAFTS
    && !obj->options->decompose_file_p
#endif /* MIME_DRAFTS */
    )
    {
    return true;
    }

  return false;      /* Don't actually parse this child; we'll handle
                 all that at eof time. */
}