Beispiel #1
0
static int
MimeMessage_add_child (MimeObject *parent, MimeObject *child)
{
  MimeContainer *cont = (MimeContainer *) parent;
  PR_ASSERT(parent && child);
  if (!parent || !child) return -1;

  /* message/rfc822 containers can only have one child. */
  PR_ASSERT(cont->nchildren == 0);
  if (cont->nchildren != 0) return -1;

#ifdef MIME_DRAFTS
  if ( parent->options &&
     parent->options->decompose_file_p &&
     ! parent->options->is_multipart_msg &&
     ! mime_typep(child, (MimeObjectClass*) &mimeEncryptedClass) &&
     parent->options->decompose_file_init_fn ) {
  int status = 0;
  status = parent->options->decompose_file_init_fn (
                        parent->options->stream_closure,
                        ((MimeMessage*)parent)->hdrs );
  if ( status < 0 ) return status;
  }
#endif /* MIME_DRAFTS */

  return ((MimeContainerClass*)&MIME_SUPERCLASS)->add_child (parent, child);
}
Beispiel #2
0
static MimeMultipartBoundaryType
MimeMultipart_check_boundary(MimeObject *obj, const char *line, PRInt32 length)
{
  MimeMultipart *mult = (MimeMultipart *) obj;
  PRInt32 blen;
  PRBool term_p;

  if (!mult->boundary ||
    line[0] != '-' ||
    line[1] != '-')
  return MimeMultipartBoundaryTypeNone;

  /* This is a candidate line to be a boundary.  Check it out... */
  blen = strlen(mult->boundary);
  term_p = PR_FALSE;

  /* strip trailing whitespace (including the newline.) */
  while(length > 2 && IS_SPACE(line[length-1]))
  length--;

  /* Could this be a terminating boundary? */
  if (length == blen + 4 &&
    line[length-1] == '-' &&
    line[length-2] == '-')
  {
    term_p = PR_TRUE;
  }

  //looks like we have a separator but first, we need to check it's not for one of the part's children.
  MimeContainer *cont = (MimeContainer *) obj;
  if (cont->nchildren > 0)
  {
    MimeObject *kid = cont->children[cont->nchildren-1];
    if (kid)
      if (mime_typep(kid, (MimeObjectClass*) &mimeMultipartClass))
      {
        //Don't ask the kid to check the boundary if it has already detected a Teminator
        MimeMultipart *mult = (MimeMultipart *) kid;
        if (mult->state != MimeMultipartEpilogue)
          if (MimeMultipart_check_boundary(kid, line, length) != MimeMultipartBoundaryTypeNone)
            return MimeMultipartBoundaryTypeNone;
      }
  }

  if (term_p)
    length -= 2;

  if (blen == length-2 && !strncmp(line+2, mult->boundary, length-2))
    return (term_p
      ? MimeMultipartBoundaryTypeTerminator
      : MimeMultipartBoundaryTypeSeparator);
  else
    return MimeMultipartBoundaryTypeNone;
}
Beispiel #3
0
bool MimeEncryptedCMS_encrypted_p (MimeObject *obj)
{
  bool encrypted;

  if (!obj) return false;
  if (mime_typep(obj, (MimeObjectClass *) &mimeEncryptedCMSClass))
  {
    MimeEncrypted *enc = (MimeEncrypted *) obj;
    MimeCMSdata *data = (MimeCMSdata *) enc->crypto_closure;
    if (!data || !data->content_info) return false;
                data->content_info->ContentIsEncrypted(&encrypted);
          return encrypted;
  }
  return false;
}
Beispiel #4
0
static int
MimeMessage_parse_eof (MimeObject *obj, PRBool abort_p)
{
  int status;
  PRBool outer_p;
  MimeMessage *msg = (MimeMessage *)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;

  outer_p = !obj->headers;  /* is this the outermost message? */

  // Hack for messages with truncated headers (bug 244722)
  // If there is no empty line in a message, the parser can't figure out where
  // the headers end, causing parsing to hang. So we insert an extra newline
  // to keep it happy. This is OK, since a message without any empty lines is
  // broken anyway...
  if(outer_p && msg->hdrs && ! msg->hdrs->done_p) {
    MimeMessage_parse_line("\n", 1, obj);
  }

  // Once we get to the end of parsing the message, we will notify
  // the emitter that we are done the the body.

  // Mark the end of the mail body if we are actually emitting the
  // body of the message (i.e. not Header ONLY)
  if (outer_p && obj->options && obj->options->write_html_p)
  {
    if (obj->options->generate_footer_html_fn)
    {
      mime_stream_data *msd =
        (mime_stream_data *) obj->options->stream_closure;
      if (msd)
      {
        char *html = obj->options->generate_footer_html_fn
          (msd->orig_url_name, obj->options->html_closure, msg->hdrs);
        if (html)
        {
          int lstatus = MimeObject_write(obj, html,
                         strlen(html),
                         PR_FALSE);
          PR_Free(html);
          if (lstatus < 0) return lstatus;
        }
      }
    }
    if ((!obj->options->part_to_load  || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay) &&
      obj->options->headers != MimeHeadersOnly)
      mimeEmitterEndBody(obj->options);
  }

#ifdef MIME_DRAFTS
  if ( obj->options &&
     obj->options->decompose_file_p &&
     obj->options->done_parsing_outer_headers &&
     ! obj->options->is_multipart_msg &&
     ! mime_typep(obj, (MimeObjectClass*) &mimeEncryptedClass) &&
     obj->options->decompose_file_close_fn ) {
  status = obj->options->decompose_file_close_fn (
                         obj->options->stream_closure );

  if ( status < 0 ) return status;
  }
#endif /* MIME_DRAFTS */


  /* Put out a separator after every message/rfc822 object. */
  if (!abort_p && !outer_p)
  {
    status = MimeObject_write_separator(obj);
    if (status < 0) return status;
  }

  return 0;
}
Beispiel #5
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;
}
Beispiel #6
0
static int
MimeMessage_parse_line (const char *aLine, PRInt32 aLength, MimeObject *obj)
{
  const char * line = aLine;
  PRInt32 length = aLength;

  MimeMessage *msg = (MimeMessage *) obj;
  int status = 0;

  PR_ASSERT(line && *line);
  if (!line || !*line) return -1;

#ifdef MOZ_SECURITY
  HG11013
#endif /* MOZ_SECURITY */

  if (msg->grabSubject)
  {
    if ( (!PL_strncasecmp(line, "Subject: ", 9)) && (obj->parent) )
    {
      if ( (obj->headers) && (!obj->headers->munged_subject) )
      {
        obj->headers->munged_subject = (char *) PL_strndup(line + 9, length - 9);
        char *tPtr = obj->headers->munged_subject;
        while (*tPtr)
        {
          if ( (*tPtr == '\r') || (*tPtr == '\n') )
          {
            *tPtr = '\0';
            break;
          }
          tPtr++;
        }
      }
    }
  }

  /* If we already have a child object, then we're done parsing headers,
   and all subsequent lines get passed to the inferior object without
   further processing by us.  (Our parent will stop feeding us lines
   when this MimeMessage part is out of data.)
   */
  if (msg->container.nchildren)
  {
    MimeObject *kid = msg->container.children[0];
    PRBool nl;
    PR_ASSERT(kid);
    if (!kid) return -1;

          msg->bodyLength += length;

    /* Don't allow MimeMessage objects to not end in a newline, since it
     would be inappropriate for any following part to appear on the same
     line as the last line of the message.

     #### This assumes that the only time the `parse_line' method is
     called with a line that doesn't end in a newline is when that line
     is the last line.
     */
    nl = (length > 0 && (line[length-1] == '\r' || line[length-1] == '\n'));

#ifdef MIME_DRAFTS
    if ( !mime_typep (kid, (MimeObjectClass*) &mimeMessageClass) &&
       obj->options &&
       obj->options->decompose_file_p &&
       ! obj->options->is_multipart_msg &&
       obj->options->decompose_file_output_fn )
    {
      if (!obj->options->decrypt_p) {
        //if we are processing a flowed plain text line, we need to remove any stuffed space
        if (length > 0 && ' ' == *line && mime_typep(kid, (MimeObjectClass *)&mimeInlineTextPlainFlowedClass))
        {
          line ++;
          length --;
        }
        status = obj->options->decompose_file_output_fn (line,
                                 length,
                           obj->options->stream_closure);
        if (status < 0) return status;
        if (!nl) {
        status = obj->options->decompose_file_output_fn (MSG_LINEBREAK,
                                 MSG_LINEBREAK_LEN,
                           obj->options->stream_closure);
        if (status < 0) return status;
        }
        return status;
      }
    }
#endif /* MIME_DRAFTS */


    if (nl)
    return kid->clazz->parse_buffer (line, length, kid);
    else
    {
      /* Hack a newline onto the end. */
      char *s = (char *)PR_MALLOC(length + MSG_LINEBREAK_LEN + 1);
      if (!s) return MIME_OUT_OF_MEMORY;
      memcpy(s, line, length);
      PL_strncpyz(s + length, MSG_LINEBREAK, MSG_LINEBREAK_LEN);
      status = kid->clazz->parse_buffer (s, length + MSG_LINEBREAK_LEN, kid);
      PR_Free(s);
      return status;
    }
  }

  /* Otherwise we don't yet have a child object, which means we're not
   done parsing our headers yet.
   */
  if (!msg->hdrs)
  {
    msg->hdrs = MimeHeaders_new();
    if (!msg->hdrs) return MIME_OUT_OF_MEMORY;
  }

#ifdef MIME_DRAFTS
  if ( obj->options &&
       obj->options->decompose_file_p &&
       ! obj->options->is_multipart_msg &&
       obj->options->done_parsing_outer_headers &&
       obj->options->decompose_file_output_fn )
  {
    status =  obj->options->decompose_file_output_fn( line, length,
                                                      obj->options->stream_closure );
    if (status < 0)
      return status;
  }
#endif /* MIME_DRAFTS */

  status = MimeHeaders_parse_line(line, length, msg->hdrs);
  if (status < 0) return status;

  /* If this line is blank, we're now done parsing headers, and should
   examine our content-type to create our "body" part.
   */
  if (*line == '\r' || *line == '\n')
  {
    status = MimeMessage_close_headers(obj);
    if (status < 0) return status;
  }

  return 0;
}
Beispiel #7
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;
}
Beispiel #8
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;
}
static int 
MimeInlineText_convert_and_parse_line(char *line, int32_t length, MimeObject *obj)
{
  int status;
  char *converted = 0;
  int32_t converted_len = 0;
  
  MimeInlineText *text = (MimeInlineText *) obj;

  //in case of charset autodetection, charset can be override by meta charset
  if (text->charsetOverridable) {
    if (mime_typep(obj, (MimeObjectClass *) &mimeInlineTextHTMLClass))
    {
      MimeInlineTextHTML  *textHTML = (MimeInlineTextHTML *) obj;
      if (textHTML->charset && 
          *textHTML->charset &&
          strcmp(textHTML->charset, text->charset))
      {
        //if meta tag specified charset is different from our detected result, use meta charset.
        //but we don't want to redo previous lines
        MIME_get_unicode_decoder(textHTML->charset, getter_AddRefs(text->inputDecoder));
        PR_FREEIF(text->charset);
        text->charset = strdup(textHTML->charset);

        //update MsgWindow charset if we are instructed to do so
        if (text->needUpdateMsgWinCharset && *text->charset)
          SetMailCharacterSetToMsgWindow(obj, text->charset);
      }
    }
  }

  //initiate decoder if not yet
  if (text->inputDecoder == nullptr)
    MIME_get_unicode_decoder(text->charset, getter_AddRefs(text->inputDecoder));
  // If no decoder found, use ""UTF-8"", that will map most non-US-ASCII chars as invalid
  // A pure-ASCII only decoder would be better, but there is none
  if (text->inputDecoder == nullptr)
    MIME_get_unicode_decoder("UTF-8", getter_AddRefs(text->inputDecoder));
  if (text->utf8Encoder == nullptr)
    MIME_get_unicode_encoder("UTF-8", getter_AddRefs(text->utf8Encoder));

  bool useInputCharsetConverter = obj->options->m_inputCharsetToUnicodeDecoder && !PL_strcasecmp(text->charset, obj->options->charsetForCachedInputDecoder.get());

  if (useInputCharsetConverter)
    status = obj->options->charset_conversion_fn(line, length,
                         text->charset,
                         "UTF-8",
                         &converted,
                         &converted_len,
                         obj->options->stream_closure, obj->options->m_inputCharsetToUnicodeDecoder,
                       obj->options->m_unicodeToUTF8Encoder);
  else
    status = obj->options->charset_conversion_fn(line, length,
                         text->charset,
                       "UTF-8",
                         &converted,
                         &converted_len,
                         obj->options->stream_closure, (nsIUnicodeDecoder*)text->inputDecoder,
                         (nsIUnicodeEncoder*)text->utf8Encoder);

  if (status < 0)
  {
    PR_FREEIF(converted);
    return status;
  }

  if (converted)
  {
    line = converted;
    length = converted_len;
  }

  /* Now that the line has been converted, call the subclass's parse_line
   method with the decoded data. */
  status = obj->clazz->parse_line(line, length, obj);
  PR_FREEIF(converted);

  return status;
}
Beispiel #10
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. */
}
Beispiel #11
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;
}
Beispiel #12
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;
}
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;
}
Beispiel #14
0
static int
MimeMultipart_parse_child_line (MimeObject *obj, const char *line, PRInt32 length,
                PRBool first_line_p)
{
  MimeContainer *cont = (MimeContainer *) obj;
  int status;
  MimeObject *kid;

  PR_ASSERT(cont->nchildren > 0);
  if (cont->nchildren <= 0)
  return -1;

  kid = cont->children[cont->nchildren-1];
  PR_ASSERT(kid);
  if (!kid) return -1;

#ifdef MIME_DRAFTS
  if ( obj->options &&
     obj->options->decompose_file_p &&
     obj->options->is_multipart_msg && 
     obj->options->decompose_file_output_fn ) 
  {
  if (!mime_typep(obj,(MimeObjectClass*)&mimeMultipartAlternativeClass) &&
    !mime_typep(obj,(MimeObjectClass*)&mimeMultipartRelatedClass) &&
    !mime_typep(obj,(MimeObjectClass*)&mimeMultipartSignedClass) &&
#ifdef MIME_DETAIL_CHECK
    !mime_typep(kid,(MimeObjectClass*)&mimeMultipartAlternativeClass) &&
    !mime_typep(kid,(MimeObjectClass*)&mimeMultipartRelatedClass) &&
    !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"))
    )
    return obj->options->decompose_file_output_fn (line, length, obj->options->stream_closure);
  }
#endif /* MIME_DRAFTS */

  /* 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.
   */

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

  if (!first_line_p)
  {
    /* Push out a preceeding newline... */
    char nl[] = MSG_LINEBREAK;
    status = kid->clazz->parse_buffer (nl, MSG_LINEBREAK_LEN, kid);
    if (status < 0) return status;
  }

  /* Now push out the line sans trailing newline. */
  return kid->clazz->parse_buffer (line, length, kid);
}
Beispiel #15
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;
}
Beispiel #16
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;
}