예제 #1
0
static int MimeUntypedText_close_subpart(MimeObject *obj) {
  MimeUntypedText *uty = (MimeUntypedText *)obj;
  int status;

  if (uty->open_subpart) {
    status = uty->open_subpart->clazz->parse_eof(uty->open_subpart, false);
    uty->open_subpart = 0;

    PR_ASSERT(uty->open_hdrs);
    if (uty->open_hdrs) {
      MimeHeaders_free(uty->open_hdrs);
      uty->open_hdrs = 0;
    }
    uty->type = MimeUntypedTextSubpartTypeText;
    if (status < 0) return status;

    /* Never put out a separator between sub-parts of UntypedText.
     (This bypasses the rule that text/plain subparts always
     have separators before and after them.)
     */
    if (obj->options && obj->options->state)
      obj->options->state->separator_suppressed_p = true;
  }

  PR_ASSERT(!uty->open_hdrs);
  return 0;
}
예제 #2
0
static void
MimeEncrypted_cleanup (MimeObject *obj, PRBool finalizing_p)
{
  MimeEncrypted *enc = (MimeEncrypted *) obj;

  if (enc->part_buffer)
	{
	  MimePartBufferDestroy(enc->part_buffer);
	  enc->part_buffer = 0;
	}

  if (finalizing_p && enc->crypto_closure)
	{
	  /* Don't free these until this object is really going away -- keep them
		 around for the lifetime of the MIME object, so that we can get at the
		 security info of sub-parts of the currently-displayed message. */
	  ((MimeEncryptedClass *) obj->clazz)->crypto_free (enc->crypto_closure);
	  enc->crypto_closure = 0;
	}

  /* (Duplicated from MimeLeaf, see comments in mimecryp.h.)
	 Free the decoder data, if it's still around. */
  if (enc->decoder_data)
	{
	  MimeDecoderDestroy(enc->decoder_data, PR_TRUE);
	  enc->decoder_data = 0;
	}

  if (enc->hdrs)
	{
	  MimeHeaders_free(enc->hdrs);
	  enc->hdrs = 0;
	}
}
예제 #3
0
static void
MimeObject_finalize (MimeObject *obj)
{
  obj->clazz->parse_eof (obj, PR_FALSE);
  obj->clazz->parse_end (obj, PR_FALSE);

  if (obj->headers)
  {
    MimeHeaders_free(obj->headers);
    obj->headers = 0;
  }

  /* Should have been freed by parse_eof, but just in case... */
  NS_ASSERTION(!obj->ibuffer, "buffer not freed");
  NS_ASSERTION(!obj->obuffer, "buffer not freed");
  PR_FREEIF (obj->ibuffer);
  PR_FREEIF (obj->obuffer);

  PR_FREEIF(obj->content_type);
  PR_FREEIF(obj->encoding);

  if (obj->options && obj->options->state)
  {
    delete obj->options->state;
    obj->options->state = nsnull;
  }
}
예제 #4
0
static int
MimeMultipartSigned_close_child (MimeObject *obj)
{
  /* The close_child method on MimeMultipartSigned doesn't actually do
   anything to the children list, since the create_child method also
   doesn't do anything.
   */
  MimeMultipart *mult = (MimeMultipart *) obj;
  MimeContainer *cont = (MimeContainer *) obj;
  MimeMultipartSigned *msig = (MimeMultipartSigned *) obj;

  if (msig->part_buffer)
  /* Closes the tmp file, if there is one: doesn't free the part_buffer. */
  MimePartBufferClose(msig->part_buffer);

  if (mult->hdrs)  /* duplicated from MimeMultipart_close_child, ugh. */
  {
    MimeHeaders_free(mult->hdrs);
    mult->hdrs = 0;
  }

  /* Should be no kids yet. */
  PR_ASSERT(cont->nchildren == 0);
  if (cont->nchildren != 0) return -1;

  return 0;
}
예제 #5
0
static void
MimeMessage_finalize (MimeObject *object)
{
  MimeMessage *msg = (MimeMessage *)object;
  if (msg->hdrs)
  MimeHeaders_free(msg->hdrs);
  msg->hdrs = 0;
  ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
}
예제 #6
0
nsresult nsMimeHeaders::Initialize(const char * aAllHeaders, PRInt32 allHeadersSize)
{
  /* just in case we want to reuse the object, cleanup...*/
  if (mHeaders)
    MimeHeaders_free(mHeaders);

  mHeaders = MimeHeaders_new();
  if (mHeaders)
    return MimeHeaders_parse_line(aAllHeaders, allHeadersSize, mHeaders);

  return NS_ERROR_OUT_OF_MEMORY;
}
예제 #7
0
static void
MimeExternalBody_finalize (MimeObject *object)
{
  MimeExternalBody *bod = (MimeExternalBody *) object;
  if (bod->hdrs)
  {
    MimeHeaders_free(bod->hdrs);
    bod->hdrs = 0;
  }
  PR_FREEIF(bod->body);

  ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
}
예제 #8
0
static void
MimeMultipart_finalize (MimeObject *object)
{
  MimeMultipart *mult = (MimeMultipart *) object;

  object->clazz->parse_eof(object, PR_FALSE);

  PR_FREEIF(mult->boundary);
  if (mult->hdrs)
  MimeHeaders_free(mult->hdrs);
  mult->hdrs = 0;
  ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
}
예제 #9
0
static void
MimeMultipartSigned_cleanup (MimeObject *obj, bool finalizing_p)
{
  MimeMultipart *mult = (MimeMultipart *) obj; /* #58075.  Fix suggested by jwz */
  MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;
  if (sig->part_buffer)
  {
    MimePartBufferDestroy(sig->part_buffer);
    sig->part_buffer = 0;
  }
  if (sig->body_hdrs)
  {
    MimeHeaders_free (sig->body_hdrs);
    sig->body_hdrs = 0;
  }
  if (sig->sig_hdrs)
  {
    MimeHeaders_free (sig->sig_hdrs);
    sig->sig_hdrs = 0;
  }

  mult->state = MimeMultipartEpilogue;  /* #58075.  Fix suggested by jwz */
  sig->state = MimeMultipartSignedEpilogue;

  if (finalizing_p && sig->crypto_closure) {
    /* Don't free these until this object is really going away -- keep them
       around for the lifetime of the MIME object, so that we can get at the
       security info of sub-parts of the currently-displayed message. */
    ((MimeMultipartSignedClass *) obj->clazz)->crypto_free (sig->crypto_closure);
     sig->crypto_closure = 0;
  }

  if (sig->sig_decoder_data)
  {
    MimeDecoderDestroy(sig->sig_decoder_data, true);
    sig->sig_decoder_data = 0;
  }
}
예제 #10
0
static void
MimeMultipartAlternative_cleanup(MimeObject *obj)
{
  MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  int32_t i;

  for (i = 0; i < malt->pending_parts; i++) {
    MimeHeaders_free(malt->buffered_hdrs[i]);
    MimePartBufferDestroy(malt->part_buffers[i]);
  }
  PR_FREEIF(malt->buffered_hdrs);
  PR_FREEIF(malt->part_buffers);
  malt->pending_parts = 0;
}
예제 #11
0
static void MimeUntypedText_finalize(MimeObject *object) {
  MimeUntypedText *uty = (MimeUntypedText *)object;

  if (uty->open_hdrs) {
    /* Oops, those shouldn't still be here... */
    MimeHeaders_free(uty->open_hdrs);
    uty->open_hdrs = 0;
  }

  /* What about the open_subpart?  We're going to have to assume that it
   is also on the MimeContainer->children list, and will get cleaned
   up by that class. */

  ((MimeObjectClass *)&MIME_SUPERCLASS)->finalize(object);
}
예제 #12
0
static int
MimeMultipartAlternative_close_child(MimeObject *obj)
{
  MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  MimeMultipart *mult = (MimeMultipart *) obj;

  /* PR_ASSERT(malt->part_buffer);      Some Mac brokenness trips this...
  if (!malt->part_buffer) return -1; */

  if (malt->pending_parts)
    MimePartBufferClose(malt->part_buffers[malt->pending_parts-1]);

  /* PR_ASSERT(mult->hdrs);         I expect the Mac trips this too */

  if (mult->hdrs) {
    MimeHeaders_free(mult->hdrs);
    mult->hdrs = 0;
  }

  return 0;
}
예제 #13
0
nsMimeHeaders::~nsMimeHeaders()
{
  if (mHeaders)
    MimeHeaders_free(mHeaders);
}
예제 #14
0
static int
MimeMultipart_close_child(MimeObject *object)
{
  MimeMultipart *mult = (MimeMultipart *) object;
  MimeContainer *cont = (MimeContainer *) object;

  if (!mult->hdrs)
  return 0;

  MimeHeaders_free(mult->hdrs);
  mult->hdrs = 0;

  NS_ASSERTION(cont->nchildren > 0, "badly formed mime message");
  if (cont->nchildren > 0)
  {
    MimeObject *kid = cont->children[cont->nchildren-1];
    // If we have a child and it has not already been closed, process it.
    // The kid would be already be closed if we encounter a multipart section
    // that did not have a fully delineated header block.  No header block means
    // no creation of a new child, but the termination case still happens and
    // we still end up here.  Obviously, we don't want to close the child a
    // second time and the best thing we can do is nothing.
    if (kid && !kid->closed_p)
    {
      int status;
      status = kid->clazz->parse_eof(kid, PR_FALSE);
      if (status < 0) return status;
      status = kid->clazz->parse_end(kid, PR_FALSE);
      if (status < 0) return status;

#ifdef MIME_DRAFTS
      if ( object->options &&
         object->options->decompose_file_p &&
         object->options->is_multipart_msg &&
         object->options->decompose_file_close_fn ) 
      {
        if ( !mime_typep(object,(MimeObjectClass*)&mimeMultipartRelatedClass) &&
           !mime_typep(object,(MimeObjectClass*)&mimeMultipartAlternativeClass) &&
           !mime_typep(object,(MimeObjectClass*)&mimeMultipartSignedClass) &&
#ifdef MIME_DETAIL_CHECK
           !mime_typep(kid,(MimeObjectClass*)&mimeMultipartRelatedClass) &&
           !mime_typep(kid,(MimeObjectClass*)&mimeMultipartAlternativeClass) &&
           !mime_typep(kid,(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(kid,(MimeObjectClass*) &mimeMultipartClass)
#endif
                                  && !(mime_typep(kid, (MimeObjectClass*)&mimeExternalObjectClass) && !strcmp(kid->content_type, "text/x-vcard"))
           )
        {
          status = object->options->decompose_file_close_fn ( object->options->stream_closure );
          if (status < 0) return status;
        }
      }
#endif /* MIME_DRAFTS */

    }
  }
  return 0;
}
예제 #15
0
static int MimeUntypedText_open_subpart(MimeObject *obj,
                                        MimeUntypedTextSubpartType ttype,
                                        const char *type, const char *enc,
                                        const char *name, const char *desc) {
  MimeUntypedText *uty = (MimeUntypedText *)obj;
  int status = 0;
  char *h = 0;

  if (!type || !*type || !PL_strcasecmp(type, UNKNOWN_CONTENT_TYPE))
    type = APPLICATION_OCTET_STREAM;
  if (enc && !*enc) enc = 0;
  if (desc && !*desc) desc = 0;
  if (name && !*name) name = 0;

  if (uty->open_subpart) {
    status = MimeUntypedText_close_subpart(obj);
    if (status < 0) return status;
  }
  NS_ASSERTION(!uty->open_subpart, "no open subpart");
  NS_ASSERTION(!uty->open_hdrs, "no open headers");

  /* To make one of these implicitly-typed sub-objects, we make up a fake
   header block, containing only the minimum number of MIME headers needed.
   We could do most of this (Type and Encoding) by making a null header
   block, and simply setting obj->content_type and obj->encoding; but making
   a fake header block is better for two reasons: first, it means that
   something will actually be displayed when in `Show All Headers' mode;
   and second, it's the only way to communicate the filename parameter,
   aside from adding a new slot to MimeObject (which is something to be
   avoided when possible.)
   */

  uty->open_hdrs = MimeHeaders_new();
  if (!uty->open_hdrs) return MIME_OUT_OF_MEMORY;

  uint32_t hlen = strlen(type) + (enc ? strlen(enc) : 0) +
                  (desc ? strlen(desc) : 0) + (name ? strlen(name) : 0) + 100;
  h = (char *)PR_MALLOC(hlen);
  if (!h) return MIME_OUT_OF_MEMORY;

  PL_strncpyz(h, HEADER_CONTENT_TYPE ": ", hlen);
  PL_strcatn(h, hlen, type);
  PL_strcatn(h, hlen, MSG_LINEBREAK);
  status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
  if (status < 0) goto FAIL;

  if (enc) {
    PL_strncpyz(h, HEADER_CONTENT_TRANSFER_ENCODING ": ", hlen);
    PL_strcatn(h, hlen, enc);
    PL_strcatn(h, hlen, MSG_LINEBREAK);
    status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
    if (status < 0) goto FAIL;
  }

  if (desc) {
    PL_strncpyz(h, HEADER_CONTENT_DESCRIPTION ": ", hlen);
    PL_strcatn(h, hlen, desc);
    PL_strcatn(h, hlen, MSG_LINEBREAK);
    status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
    if (status < 0) goto FAIL;
  }
  if (name) {
    PL_strncpyz(h, HEADER_CONTENT_DISPOSITION ": inline; filename=\"", hlen);
    PL_strcatn(h, hlen, name);
    PL_strcatn(h, hlen, "\"" MSG_LINEBREAK);
    status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
    if (status < 0) goto FAIL;
  }

  /* push out a blank line. */
  PL_strncpyz(h, MSG_LINEBREAK, hlen);
  status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
  if (status < 0) goto FAIL;

  /* Create a child... */
  {
    bool horrid_kludge = (obj->options && obj->options->state &&
                          obj->options->state->first_part_written_p);
    if (horrid_kludge) obj->options->state->first_part_written_p = false;

    uty->open_subpart = mime_create(type, uty->open_hdrs, obj->options);

    if (horrid_kludge) obj->options->state->first_part_written_p = true;

    if (!uty->open_subpart) {
      status = MIME_OUT_OF_MEMORY;
      goto FAIL;
    }
  }

  /* Add it to the list... */
  status =
      ((MimeContainerClass *)obj->clazz)->add_child(obj, uty->open_subpart);
  if (status < 0) {
    mime_free(uty->open_subpart);
    uty->open_subpart = 0;
    goto FAIL;
  }

  /* And start its parser going. */
  status = uty->open_subpart->clazz->parse_begin(uty->open_subpart);
  if (status < 0) {
    /* MimeContainer->finalize will take care of shutting it down now. */
    uty->open_subpart = 0;
    goto FAIL;
  }

  uty->type = ttype;

FAIL:
  PR_FREEIF(h);

  if (status < 0 && uty->open_hdrs) {
    MimeHeaders_free(uty->open_hdrs);
    uty->open_hdrs = 0;
  }

  return status;
}
예제 #16
0
static int
MimeMultipartAlternative_flush_children(MimeObject *obj,
                                        bool finished,
                                        bool next_is_displayable)
{
  /*
    Possible states:

    1. Cache contains nothing: do nothing.

    2. Finished, and the cache contains one displayable body followed
       by zero or more non-displayable bodies:

    3. Finished, and the cache contains one non-displayable body:
       create it with output off.

    4. Not finished, and the cache contains one displayable body
       followed by zero or more non-displayable bodies, and the new
       body we're about to create is displayable: create all cached
       bodies with output off.

    5. Not finished, and the cache contains one displayable body
       followed by zero or more non-displayable bodies, and the new
       body we're about to create is non-displayable: do nothing.

    6. Not finished, and the cache contains one non-displayable body:
       create it with output off.
  */
  MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
  bool have_displayable, do_flush, do_display;

  /* Case 1 */
  if (! malt->pending_parts)
    return 0;

  have_displayable =
    MimeMultipartAlternative_display_part_p(obj, malt->buffered_hdrs[0]);
  
  if (finished && have_displayable) {
    /* Case 2 */
    do_flush = true;
    do_display = true;
  }
  else if (finished && ! have_displayable) {
    /* Case 3 */
    do_flush = true;
    do_display = false;
  }
  else if (! finished && have_displayable && next_is_displayable) {
    /* Case 4 */
    do_flush = true;
    do_display = false;
  }
  else if (! finished && have_displayable && ! next_is_displayable) {
    /* Case 5 */
    do_flush = false;
    do_display = false;
  }
  else if (! finished && ! have_displayable) {
    /* Case 6 */
    do_flush = true;
    do_display = false;
  }
  else {
    NS_ERROR("mimemalt.cpp: logic error in flush_children");
    return -1;
  }
  
  if (do_flush) {
    int32_t i;
    for (i = 0; i < malt->pending_parts; i++) {
      MimeMultipartAlternative_display_cached_part(obj,
                                                   malt->buffered_hdrs[i],
                                                   malt->part_buffers[i],
                                                   do_display && (i == 0));
      MimeHeaders_free(malt->buffered_hdrs[i]);
      MimePartBufferDestroy(malt->part_buffers[i]);
    }
    malt->pending_parts = 0;
  }
  return 0;
}
예제 #17
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;
}
예제 #18
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;
}
예제 #19
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;
}