示例#1
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;
}
示例#2
0
static int
MimeMessage_debug_print (MimeObject *obj, PRFileDesc *stream, PRInt32 depth)
{
  MimeMessage *msg = (MimeMessage *) obj;
  char *addr = mime_part_address(obj);
  int i;
  for (i=0; i < depth; i++)
  PR_Write(stream, "  ", 2);
/*
  fprintf(stream, "<%s %s%s 0x%08X>\n",
      obj->clazz->class_name,
      addr ? addr : "???",
      (msg->container.nchildren == 0 ? " (no body)" : ""),
      (PRUint32) msg);
*/
  PR_FREEIF(addr);

#if 0
  if (msg->hdrs)
  {
    char *s;

    depth++;

# define DUMP(HEADER) \
    for (i=0; i < depth; i++)                        \
        PR_Write(stream, "  ", 2);                        \
    s = MimeHeaders_get (msg->hdrs, HEADER, PR_FALSE, PR_TRUE);
/**
    \
    PR_Write(stream, HEADER ": %s\n", s ? s : "");              \
**/

    PR_FREEIF(s)

      DUMP(HEADER_SUBJECT);
      DUMP(HEADER_DATE);
      DUMP(HEADER_FROM);
      DUMP(HEADER_TO);
      /* DUMP(HEADER_CC); */
      DUMP(HEADER_NEWSGROUPS);
      DUMP(HEADER_MESSAGE_ID);
# undef DUMP

    PR_Write(stream, "\n", 1);
  }
#endif

  PR_ASSERT(msg->container.nchildren <= 1);
  if (msg->container.nchildren == 1)
  {
    MimeObject *kid = msg->container.children[0];
    int status = kid->clazz->debug_print (kid, stream, depth+1);
    if (status < 0) return status;
  }
  return 0;
}
示例#3
0
static int
MimeObject_debug_print (MimeObject *obj, PRFileDesc *stream, PRInt32 depth)
{
  int i;
  char *addr = mime_part_address(obj);
  for (i=0; i < depth; i++)
  PR_Write(stream, "  ", 2);
/*
  fprintf(stream, "<%s %s 0x%08X>\n", obj->clazz->class_name,
      addr ? addr : "???",
      (PRUint32) obj);
*/
  PR_FREEIF(addr);
  return 0;
}
示例#4
0
static int
MimeMultipart_debug_print (MimeObject *obj, PRFileDesc *stream, PRInt32 depth)
{
  /*  MimeMultipart *mult = (MimeMultipart *) obj; */
  MimeContainer *cont = (MimeContainer *) obj;
  char *addr = mime_part_address(obj);
  int i;
  for (i=0; i < depth; i++)
  PR_Write(stream, "  ", 2);
/**
  fprintf(stream, "<%s %s (%d kid%s) boundary=%s 0x%08X>\n",
      obj->clazz->class_name,
      addr ? addr : "???",
      cont->nchildren, (cont->nchildren == 1 ? "" : "s"),
      (mult->boundary ? mult->boundary : "(none)"),
      (PRUint32) mult);
**/
  PR_FREEIF(addr);

/*
  if (cont->nchildren > 0)
  fprintf(stream, "\n");
 */

  for (i = 0; i < cont->nchildren; i++)
  {
    MimeObject *kid = cont->children[i];
    int status = kid->clazz->debug_print (kid, stream, depth+1);
    if (status < 0) return status;
  }

/*
  if (cont->nchildren > 0)
  fprintf(stream, "\n");
 */

  return 0;
}
示例#5
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;
}
示例#6
0
static int
MimeInlineImage_parse_begin (MimeObject *obj)
{
  MimeInlineImage *img = (MimeInlineImage *) obj;
  MimeInlineImageClass *clazz;

  int status;

  status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
  if (status < 0) return status;

  if (!obj->output_p) return 0;

  if (!obj->options || !obj->options->output_fn ||
      // don't bother processing if the consumer doesn't want us
      //  gunking the body up.
      obj->options->write_pure_bodies)
    return 0;

  clazz = (MimeInlineImageClass *) obj->clazz;

  if (obj->options &&
    obj->options->image_begin &&
    obj->options->write_html_p &&
    obj->options->image_write_buffer)
  {
    char *html, *part, *image_url;
    const char *ct;

    part = mime_part_address(obj);
    if (!part) return MIME_OUT_OF_MEMORY;

      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)
        {
          image_url = mime_set_url_part(no_part_url, part, true);
          PR_Free(no_part_url);
        }
        else
          image_url = mime_set_url_part(obj->options->url, part, true);

    if (!image_url)
    {
      PR_Free(part);
      return MIME_OUT_OF_MEMORY;
    }
    PR_Free(part);

    ct = obj->content_type;
    if (!ct) ct = IMAGE_GIF;  /* Can't happen?  Close enough. */

    // Fill in content type and attachment name here.
    nsCAutoString url_with_filename(image_url);
    url_with_filename += "&type=";
    url_with_filename += ct;
    char * filename = MimeHeaders_get_name ( obj->headers, obj->options );
    if (filename)
    {
      nsCString escapedName;
      MsgEscapeString(nsDependentCString(filename), nsINetUtil::ESCAPE_URL_PATH,
                      escapedName);
      url_with_filename += "&filename=";
      url_with_filename += escapedName;
      PR_Free(filename);
    }

    // We need to separate images with HR's...
    MimeObject_write_separator(obj);

    img->image_data =
      obj->options->image_begin(url_with_filename.get(), ct, obj->options->stream_closure);
    PR_Free(image_url);

    if (!img->image_data) return MIME_OUT_OF_MEMORY;

    html = obj->options->make_image_html(img->image_data);
    if (!html) return MIME_OUT_OF_MEMORY;

    status = MimeObject_write(obj, html, strlen(html), true);
    PR_Free(html);
    if (status < 0) return status;
  }

  //
  // Now we are going to see if we should set the content type in the
  // URI for the url being run...
  //
  if (obj->options && obj->options->stream_closure && obj->content_type)
  {
    mime_stream_data  *msd = (mime_stream_data *) (obj->options->stream_closure);
    if ( (msd) && (msd->channel) )
    {
      msd->channel->SetContentType(nsDependentCString(obj->content_type));
    }
  }

  return 0;
}
示例#7
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;
}
示例#8
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;
}
示例#9
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. */
}
示例#10
0
static int
MimeObject_parse_begin (MimeObject *obj)
{
  NS_ASSERTION (!obj->closed_p, "object shouldn't be already closed");

  /* If we haven't set up the state object yet, then this should be
   the outermost object... */
  if (obj->options && !obj->options->state)
  {
    NS_ASSERTION(!obj->headers, "headers should be null");  /* should be the outermost object. */

    obj->options->state = new MimeParseStateObject;
    if (!obj->options->state) return MIME_OUT_OF_MEMORY;
    obj->options->state->root = obj;
    obj->options->state->separator_suppressed_p = PR_TRUE; /* no first sep */
    const char *delParts = PL_strcasestr(obj->options->url, "&del=");
    const char *detachLocations = PL_strcasestr(obj->options->url, "&detachTo=");
    if (delParts)
    {
      const char *delEnd = PL_strcasestr(delParts + 1, "&");
      if (!delEnd)
        delEnd = delParts + strlen(delParts);
      ParseString(Substring(delParts + 5, delEnd), ',', obj->options->state->partsToStrip);
    }
    if (detachLocations)
    {
      detachLocations += 10; // advance past "&detachTo="
      ParseString(nsDependentCString(detachLocations), ',', obj->options->state->detachToFiles);
    }
  }

  /* Decide whether this object should be output or not... */
  if (!obj->options || !obj->options->output_fn
    /* if we are decomposing the message in files and processing a multipart object,
       we must not output it without parsing it first */
     || (obj->options->decompose_file_p && obj->options->decompose_file_output_fn &&
      mime_typep(obj, (MimeObjectClass*) &mimeMultipartClass))
    )
    obj->output_p = PR_FALSE;
  else if (!obj->options->part_to_load)
    obj->output_p = PR_TRUE;
  else
  {
    char *id = mime_part_address(obj);
    if (!id) return MIME_OUT_OF_MEMORY;

      // We need to check if a part is the subpart of the part to load.
      // If so and this is a raw or body display output operation, then
      // we should mark the part for subsequent output.
      //

      // First, check for an exact match
      obj->output_p = !strcmp(id, obj->options->part_to_load);
      if (!obj->output_p && (obj->options->format_out == nsMimeOutput::nsMimeMessageRaw ||
             obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay
             || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach))
    {
        // Then, check for subpart
        unsigned int partlen = strlen(obj->options->part_to_load);
        obj->output_p = (strlen(id) >= partlen + 2) && (id[partlen] == '.') &&
            !strncmp(id, obj->options->part_to_load, partlen);
      }

    PR_Free(id);
  }

  return 0;
}
示例#11
0
static int
MimeExternalObject_parse_begin (MimeObject *obj)
{
  int status;

  status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
  if (status < 0) return status;

  // If we're writing this object, and we're doing it in raw form, then
  // now is the time to inform the backend what the type of this data is.
  //
  if (obj->output_p &&
    obj->options &&
    !obj->options->write_html_p &&
    !obj->options->state->first_data_written_p)
  {
    status = MimeObject_output_init(obj, 0);
    if (status < 0) return status;
    NS_ASSERTION(obj->options->state->first_data_written_p, "1.1 <*****@*****.**> 19 Mar 1999 12:00");
  }

  //
  // If we're writing this object as HTML, do all the work now -- just write
  // out a table with a link in it.  (Later calls to the `parse_buffer' method
  // will simply discard the data of the object itself.)
  //
  if (obj->options &&
      obj->output_p &&
      obj->options->write_html_p &&
      obj->options->output_fn)
  {
    MimeDisplayOptions newopt = *obj->options;  // copy it
    char *id = 0;
    char *id_url = 0;
    char *id_name = 0;
    nsCString id_imap;
    PRBool all_headers_p = obj->options->headers == MimeHeadersAll;

    id = mime_part_address (obj);
    if (obj->options->missing_parts)
      id_imap.Adopt(mime_imap_part_address (obj));
    if (! id) return MIME_OUT_OF_MEMORY;

    if (obj->options && obj->options->url)
    {
      const char *url = obj->options->url;
      if (!id_imap.IsEmpty() && id)
      {
        // if this is an IMAP part.
        id_url = mime_set_url_imap_part(url, id_imap.get(), id);
      }
      else
      {
        // This is just a normal MIME part as usual.
        id_url = mime_set_url_part(url, id, PR_TRUE);
      }
      if (!id_url)
      {
        PR_Free(id);
        return MIME_OUT_OF_MEMORY;
      }
    }
    if (!strcmp (id, "0"))
    {
      PR_Free(id);
      id = MimeGetStringByID(MIME_MSG_ATTACHMENT);
    }
    else
    {
      const char *p = "Part ";
      PRUint32 slen = strlen(p) + strlen(id) + 1;
      char *s = (char *)PR_MALLOC(slen);
      if (!s)
      {
        PR_Free(id);
        PR_Free(id_url);
        return MIME_OUT_OF_MEMORY;
      }
      // we have a valid id
      if (id)
        id_name = mime_find_suggested_name_of_part(id, obj);
      PL_strncpyz(s, p, slen);
      PL_strcatn(s, slen, id);
      PR_Free(id);
      id = s;
    }

    if (all_headers_p &&
    // Don't bother showing all headers on this part if it's the only
    // part in the message: in that case, we've already shown these
    // headers.
    obj->options->state &&
    obj->options->state->root == obj->parent)
    all_headers_p = PR_FALSE;

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

/******
RICHIE SHERRY
GOTTA STILL DO THIS FOR QUOTING!
     status = MimeHeaders_write_attachment_box (obj->headers, &newopt,
                                                 obj->content_type,
                                                 obj->encoding,
                                                 id_name? id_name : id, id_url, 0)
*****/

    // obj->options really owns the storage for this.
    newopt.part_to_load = nsnull;
    newopt.default_charset = nsnull;
    PR_FREEIF(id);
    PR_FREEIF(id_url);
    PR_FREEIF(id_name);
    if (status < 0) return status;
  }

  return 0;
}
示例#12
0
static int
MimeMultipart_parse_line (const char *line, PRInt32 length, MimeObject *obj)
{
  MimeMultipart *mult = (MimeMultipart *) obj;
  int status = 0;
  MimeMultipartBoundaryType boundary;

  NS_ASSERTION(line && *line, "empty line in multipart parse_line");
  if (!line || !*line) return -1;

  NS_ASSERTION(!obj->closed_p, "obj shouldn't already be closed");
  if (obj->closed_p) return -1;

  /* If we're supposed to write this object, but aren't supposed to convert
     it to HTML, simply pass it through unaltered. */
  if (obj->output_p &&
    obj->options &&
    !obj->options->write_html_p &&
    obj->options->output_fn
          && obj->options->format_out != nsMimeOutput::nsMimeMessageAttach)
  return MimeObject_write(obj, line, length, PR_TRUE);


  if (mult->state == MimeMultipartEpilogue)  /* already done */
    boundary = MimeMultipartBoundaryTypeNone;
  else
    boundary = ((MimeMultipartClass *)obj->clazz)->check_boundary(obj, line,
                                                                  length);

  if (boundary == MimeMultipartBoundaryTypeTerminator ||
    boundary == MimeMultipartBoundaryTypeSeparator)
  {
  /* Match!  Close the currently-open part, move on to the next
     state, and discard this line.
   */
    PRBool endOfPart = (mult->state != MimeMultipartPreamble);
    if (endOfPart)
      status = ((MimeMultipartClass *)obj->clazz)->close_child(obj);
    if (status < 0) return status;
    
    if (boundary == MimeMultipartBoundaryTypeTerminator)
      mult->state = MimeMultipartEpilogue;
    else
    {
      mult->state = MimeMultipartHeaders;
      
      /* Reset the header parser for this upcoming part. */
      NS_ASSERTION(!mult->hdrs, "mult->hdrs should be null here");
      if (mult->hdrs)
        MimeHeaders_free(mult->hdrs);
      mult->hdrs = MimeHeaders_new();
      if (!mult->hdrs)
        return MIME_OUT_OF_MEMORY;
      if (obj->options && obj->options->state &&
          obj->options->state->partsToStrip.Length() > 0)
      {
        nsCAutoString newPart(mime_part_address(obj));
        MimeContainer *container = (MimeContainer*) obj; 
        newPart.Append('.');
        newPart.AppendInt(container->nchildren + 1);
        obj->options->state->strippingPart = PR_FALSE;
        // check if this is a sub-part of a part we're stripping.
        for (PRUint32 partIndex = 0; partIndex < obj->options->state->partsToStrip.Length(); partIndex++)
        {
          nsCString &curPartToStrip = obj->options->state->partsToStrip[partIndex];
          if (newPart.Find(curPartToStrip) == 0 && (newPart.Length() == curPartToStrip.Length() || newPart.CharAt(curPartToStrip.Length()) == '.'))
          {
            obj->options->state->strippingPart = PR_TRUE;
            if (partIndex < obj->options->state->detachToFiles.Length())
              obj->options->state->detachedFilePath = obj->options->state->detachToFiles[partIndex];
            break;
          }
        }
      }
    }
    
    // if stripping out attachments, write the boundary line. Otherwise, return
    // to ignore it.
    if (obj->options && obj->options->format_out == nsMimeOutput::nsMimeMessageAttach)
    {
      // Because MimeMultipart_parse_child_line strips out the 
      // the CRLF of the last line before the end of a part, we need to add that
      // back in here.
      if (endOfPart)
        MimeWriteAString(obj, NS_LITERAL_CSTRING(MSG_LINEBREAK));

      status = MimeObject_write(obj, line, length, PR_TRUE);
    }
    return 0;
  }

  /* Otherwise, this isn't a boundary string.  So do whatever it is we
   should do with this line (parse it as a header, feed it to the
   child part, ignore it, etc.) */

  switch (mult->state)
  {
    case MimeMultipartPreamble:
    case MimeMultipartEpilogue:
      /* Ignore this line. */
      break;

    case MimeMultipartHeaders:
    /* Parse this line as a header for the sub-part. */
    {
      status = MimeHeaders_parse_line(line, length, mult->hdrs);
      if (status < 0) return status;
      
      // If this line is blank, we're now done parsing headers, and should
      // now examine the content-type to create this "body" part.
      //
      if (*line == '\r' || *line == '\n')
      {
        if (obj->options && obj->options->state &&
            obj->options->state->strippingPart)
        {
          PRBool detachingPart = obj->options->state->detachedFilePath.Length() > 0;

          nsCAutoString fileName;
          fileName.Adopt(MimeHeaders_get_name(mult->hdrs, obj->options));
          if (detachingPart)
          {
            char *contentType = MimeHeaders_get(mult->hdrs, "Content-Type", PR_FALSE, PR_FALSE);
            if (contentType)
            {
              MimeWriteAString(obj, NS_LITERAL_CSTRING("Content-Type: "));
              MimeWriteAString(obj, nsDependentCString(contentType));
              PR_Free(contentType);
            }
            MimeWriteAString(obj, NS_LITERAL_CSTRING(MSG_LINEBREAK));
            MimeWriteAString(obj, NS_LITERAL_CSTRING("Content-Disposition: attachment; filename=\""));
            MimeWriteAString(obj, fileName);
            MimeWriteAString(obj, NS_LITERAL_CSTRING("\""MSG_LINEBREAK));
            MimeWriteAString(obj, NS_LITERAL_CSTRING("X-Mozilla-External-Attachment-URL: "));
            MimeWriteAString(obj, obj->options->state->detachedFilePath);
            MimeWriteAString(obj, NS_LITERAL_CSTRING(MSG_LINEBREAK));
            MimeWriteAString(obj, NS_LITERAL_CSTRING("X-Mozilla-Altered: AttachmentDetached; date=\""));
          }
          else
          {
            nsCAutoString header("Content-Type: text/x-moz-deleted; name=\"Deleted: ");
            header.Append(fileName);
            status = MimeWriteAString(obj, header);
            if (status < 0) 
              return status;
            status = MimeWriteAString(obj, NS_LITERAL_CSTRING("\""MSG_LINEBREAK"Content-Transfer-Encoding: 8bit"MSG_LINEBREAK));
            MimeWriteAString(obj, NS_LITERAL_CSTRING("Content-Disposition: inline; filename=\"Deleted: "));
            MimeWriteAString(obj, fileName);
            MimeWriteAString(obj, NS_LITERAL_CSTRING("\""MSG_LINEBREAK"X-Mozilla-Altered: AttachmentDeleted; date=\""));
          }
          nsCString result;
          char timeBuffer[128];
          PRExplodedTime now;
          PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &now);
          PR_FormatTimeUSEnglish(timeBuffer, sizeof(timeBuffer),
                                 "%a %b %d %H:%M:%S %Y",
                                 &now);
          MimeWriteAString(obj, nsDependentCString(timeBuffer));
          MimeWriteAString(obj, NS_LITERAL_CSTRING("\""MSG_LINEBREAK));
          MimeWriteAString(obj, NS_LITERAL_CSTRING(MSG_LINEBREAK"You deleted an attachment from this message. The original MIME headers for the attachment were:"MSG_LINEBREAK));
          MimeHeaders_write_raw_headers(mult->hdrs, obj->options, PR_FALSE);
        }
        status = ((MimeMultipartClass *) obj->clazz)->create_child(obj);
        if (status < 0) return status;
        NS_ASSERTION(mult->state != MimeMultipartHeaders,
                     "mult->state shouldn't be MimeMultipartHeaders");

        // Ok, at this point, we need to examine the headers and see if there
        // is a special charset (i.e. non US-ASCII) for this message. If so, 
        // we need to tell the emitter that this is the case for use in in any
        // possible reply or forward operation.
        //
        PRBool isBody = PR_FALSE;
        PRBool isAlternative = PR_FALSE;

        MimeContainer *container = (MimeContainer*) obj; 
        // check if we're stripping the part of this newly created child.
        if (container->children && container->nchildren > 0)
        {
          MimeObject *kid = container->children[container->nchildren-1];
          if (kid->output_p)
            kid->output_p = !(obj->options && obj->options->state &&
                              obj->options->state->strippingPart);
        }
        if (container->children && container->nchildren == 1)
        {
          PRBool isAlternativeOrRelated = PR_FALSE;
          isBody = MimeObjectChildIsMessageBody(obj, &isAlternativeOrRelated);

          // MimeObjectChildIsMessageBody returns false for "multipart/related"
          // but we want to use the first part charset if that's a body.
          // I don't want to change the behavior of MimeObjectChildIsMessageBody
          // which is used by other places, so do the body check here.
          if (!isBody && 
              isAlternativeOrRelated &&
              mime_subclass_p(obj->clazz, (MimeObjectClass*) &mimeMultipartRelatedClass))
          {
            MimeObject *firstChild = container->children[0];
            char *disposition = MimeHeaders_get (firstChild->headers,
                                                 HEADER_CONTENT_DISPOSITION, 
                                                 PR_TRUE,
                                                 PR_FALSE);
            if (!disposition)
            {
              if (!PL_strcasecmp (firstChild->content_type, TEXT_PLAIN) ||
                  !PL_strcasecmp (firstChild->content_type, TEXT_HTML) ||
                  !PL_strcasecmp (firstChild->content_type, TEXT_MDL) ||
                  !PL_strcasecmp (firstChild->content_type, MULTIPART_ALTERNATIVE) ||
                  !PL_strcasecmp (firstChild->content_type, MULTIPART_RELATED) ||
                  !PL_strcasecmp (firstChild->content_type, MESSAGE_NEWS) ||
                  !PL_strcasecmp (firstChild->content_type, MESSAGE_RFC822))
                isBody = PR_TRUE;
            }
          }
        }
        else 
          isAlternative = mime_subclass_p(obj->clazz, (MimeObjectClass*) &mimeMultipartAlternativeClass);

        // If "multipart/alternative" or the first part is a message body
        // then we should check for a charset and notify the emitter  
        // if one exists.
        if (obj->options &&
            ((isAlternative && mult->state != MimeMultipartSkipPartLine) ||
             isBody || obj->options->notify_nested_bodies))
        {
          {
            char *ct = MimeHeaders_get(mult->hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
            if (ct)
            {
              if (obj->options->notify_nested_bodies)
                mimeEmitterAddHeaderField(obj->options, HEADER_CONTENT_TYPE,
                                          ct);
             char *cset = MimeHeaders_get_parameter (ct, "charset", NULL, NULL);
             if (cset)
             {
                mimeEmitterUpdateCharacterSet(obj->options, cset);
                if (!(obj->options->override_charset))
                  // Also set this charset to msgWindow
                  SetMailCharacterSetToMsgWindow(obj, cset);
              }

              PR_FREEIF(ct);
              PR_FREEIF(cset);
            }
            // no content type means text/plain.
            else if (obj->options->notify_nested_bodies)
            {
              mimeEmitterAddHeaderField(obj->options, HEADER_CONTENT_TYPE,
                                        "text/plain");
            }
            if (obj->options->notify_nested_bodies && container->nchildren)
            {
              MimeObject *kid = container->children[container->nchildren-1];
              char *part_path = mime_part_address(kid);
              if (part_path)
              {
                mimeEmitterAddHeaderField(obj->options,
                                          "x-jsemitter-part-path",
                                          part_path);
                PR_Free(part_path);
              }
            }
          }
        }
      }
      break;
    }

    case MimeMultipartPartFirstLine:
      /* Hand this line off to the sub-part. */
      status = (((MimeMultipartClass *) obj->clazz)->parse_child_line(obj,
                                                  line, length, PR_TRUE));
      if (status < 0) return status;
      mult->state = MimeMultipartPartLine;
      break;

    case MimeMultipartPartLine:
      /* Hand this line off to the sub-part. */
      status = (((MimeMultipartClass *) obj->clazz)->parse_child_line(obj,
                  line, length, PR_FALSE));
      if (status < 0) return status;
      break;

    case MimeMultipartSkipPartLine:
      /* we are skipping that part, therefore just ignore the line */
      break;

    default:
      NS_ERROR("unexpected state in parse line");
      return -1;
  }

  if (obj->options &&
      obj->options->format_out == nsMimeOutput::nsMimeMessageAttach &&
      (!(obj->options->state && obj->options->state->strippingPart) &&
      mult->state != MimeMultipartPartLine))
      return MimeObject_write(obj, line, length, PR_FALSE);
  return 0;
}