Пример #1
0
/* Pull the name out of some header or another.  Order is:
   Content-Disposition: XXX; filename=NAME (RFC 1521/1806)
   Content-Type: XXX; name=NAME (RFC 1341)
   Content-Name: NAME (no RFC, but seen to occur)
   X-Sun-Data-Name: NAME (no RFC, but used by MailTool)
 */
char *
MimeHeaders_get_name(MimeHeaders *hdrs, MimeDisplayOptions *opt)
{
  char *s = 0, *name = 0, *cvt = 0;
  char *charset = nullptr; // for RFC2231 support

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

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

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

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

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

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

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

    nsMemory::Free(charset);

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

  return name;
}
Пример #2
0
// This is necessary to determine which charset to use for a reply/forward
char *
DetermineMailCharset(MimeMessage *msg)
{
  char          *retCharset = nsnull;

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

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

  if (!retCharset)
    return strdup("ISO-8859-1");
  else
    return retCharset;
}
Пример #3
0
static int
MimeInlineTextHTMLSanitized_parse_begin (MimeObject *obj)
{
#ifdef DEBUG_BenB
printf("parse_begin\n");
#endif
  MimeInlineTextHTMLSanitized *textHTMLSan =
                                       (MimeInlineTextHTMLSanitized *) obj;
  textHTMLSan->complete_buffer = new nsString();
#ifdef DEBUG_BenB
printf(" B1\n");
printf(" cbp: %d\n", textHTMLSan->complete_buffer);
#endif
  int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
  if (status < 0)
    return status;
#ifdef DEBUG_BenB
printf(" B2\n");
#endif

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

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

  PR_FREEIF(st);
  return true;
}
Пример #5
0
static int
MimeMultipart_initialize (MimeObject *object)
{
  MimeMultipart *mult = (MimeMultipart *) object;
  char *ct;

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

  ct = MimeHeaders_get (object->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
  mult->boundary = (ct
          ? MimeHeaders_get_parameter (ct, HEADER_PARM_BOUNDARY, NULL, NULL)
          : 0);
  PR_FREEIF(ct);
  mult->state = MimeMultipartPreamble;
  return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
}
Пример #6
0
static bool
MimeThisIsStartPart(MimeObject *obj, MimeObject* child)
{
  bool rval = false;
  char *ct, *st, *cst;

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

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

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

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

  PR_FREEIF(st);
  PR_FREEIF(cst);
  return rval;
}
Пример #7
0
static bool
MimeExternalBody_displayable_inline_p (MimeObjectClass *clazz,
                     MimeHeaders *hdrs)
{
  char *ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
  char *at = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL);
  bool inline_p = false;

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

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

  PR_FREEIF(ct);
  PR_FREEIF(at);
  return inline_p;
}
Пример #8
0
static int
MimeInlineTextPlainFlowed_parse_begin (MimeObject *obj)
{
  int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
  if (status < 0) return status;

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

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

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

  MimeInlineTextPlainFlowed *text = (MimeInlineTextPlainFlowed *) obj;

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

  // Initialize data

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

  // check for DelSp=yes (RFC 3676)

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

  // Get Prefs for viewing

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

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

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


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

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

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

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

  return 0;
}
Пример #9
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;
}
Пример #10
0
static int MimeInlineText_initializeCharset(MimeObject *obj)
{
  MimeInlineText  *text = (MimeInlineText *) obj;

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

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

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

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

  text->initializeCharset = true;

  return 0;
}
Пример #11
0
int
MimeHeaders_write_all_headers (MimeHeaders *hdrs, MimeDisplayOptions *opt, bool attachment)
{
  int status = 0;
  int i;
  bool wrote_any_p = false;

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

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

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

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

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

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

        contents = ocolon + 1;
    }

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

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

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

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

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

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

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

  return 1;
}
Пример #12
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;
}
Пример #13
0
static int
MimeMessage_close_headers (MimeObject *obj)
{
  MimeMessage *msg = (MimeMessage *) obj;
  int status = 0;
  char *ct = 0;      /* Content-Type header */
  MimeObject *body;

  // Do a proper decoding of the munged subject.
  if (obj->headers && msg->hdrs && msg->grabSubject && obj->headers->munged_subject) {
    // nsMsgI18NConvertToUnicode wants nsAStrings...
    nsDependentCString orig(obj->headers->munged_subject);
    nsAutoString dest;
    // First, get the Content-Type, then extract the charset="whatever" part of
    // it.
    nsCString charset;
    nsCString contentType;
    contentType.Adopt(MimeHeaders_get(msg->hdrs, HEADER_CONTENT_TYPE, false, false));
    if (!contentType.IsEmpty())
      charset.Adopt(MimeHeaders_get_parameter(contentType.get(), "charset", nullptr, nullptr));

    // If we've got a charset, use nsMsgI18NConvertToUnicode to magically decode
    // the munged subject.
    if (!charset.IsEmpty()) {
      nsresult rv = nsMsgI18NConvertToUnicode(charset.get(), orig, dest);
      // If we managed to convert the string, replace munged_subject with the
      // UTF8 version of it, otherwise, just forget about it (maybe there was an
      // improperly encoded string in there).
      PR_Free(obj->headers->munged_subject);
      if (NS_SUCCEEDED(rv))
        obj->headers->munged_subject = ToNewUTF8String(dest);
      else
        obj->headers->munged_subject = nullptr;
    } else {
      PR_Free(obj->headers->munged_subject);
      obj->headers->munged_subject = nullptr;
    }
  }

  if (msg->hdrs)
  {
    bool 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, false))
        obj->options->decrypt_p = 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), false);
        PR_Free(html);
        if (lstatus < 0) return lstatus;
      }
    }


    /* Find the content-type of the body of this message.
     */
    {
    bool ok = true;
    char *mv = MimeHeaders_get (msg->hdrs, HEADER_MIME_VERSION,
                  true, 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 = true;
#endif

    if (ok)
      {
      ct = MimeHeaders_get (msg->hdrs, HEADER_CONTENT_TYPE, true, 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, 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 = 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, 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 = 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 = 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
  //
  bool outer_p = !obj->headers;  /* is this the outermost message? */

  if ( (outer_p || obj->options->notify_nested_bodies) &&
       (!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,
                                    false, 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, false,
                 false);
  if (xmoz)
  {
    uint32_t flags = 0;
    char dummy = 0;
    if (sscanf(xmoz, " %x %c", &flags, &dummy) == 1 &&
      flags & nsMsgMessageFlags::Partial)
    {
      obj->options->html_closure = obj;
      obj->options->generate_footer_html_fn =
        MimeMessage_partial_message_html;
    }
    PR_FREEIF(xmoz);
  }
  }

  return 0;
}
Пример #14
0
void
nsEnigMimeListener::ParseHeader(const char* header, PRUint32 count)
{

  //DEBUG_LOG(("nsEnigMimeListener::ParseHeader: header='%s'\n", header));

  if (!header || (count <= 0) )
    return;

  // Create header string
  nsCAutoString headerStr(header, count);

  //DEBUG_LOG(("nsEnigMimeListener::ParseHeader: header='%s'\n", headerStr.get()));
  PRInt32 colonOffset;
  colonOffset = headerStr.FindChar(':');
  if (colonOffset < 0)
    return;

  // Null header key not allowed
  if (colonOffset == 0)
    return;

  // Extract header key (not case-sensitive)
  nsCAutoString headerKey = (nsCString) nsDependentCSubstring (headerStr, 0, colonOffset);
  ToLowerCase(headerKey);


  // Extract header value, trimming leading/trailing whitespace
  nsCAutoString buf = (nsCString) nsDependentCSubstring (headerStr, colonOffset+1, headerStr.Length() - colonOffset);
  buf.Trim(" ", PR_TRUE, PR_TRUE);

  //DEBUG_LOG(("nsEnigMimeListener::ParseHeader: '%s': %s\n", headerKey.get(), buf.get()));

  PRInt32 semicolonOffset = buf.FindChar(';');

  nsCString headerValue;
  if (semicolonOffset < 0) {
    // No parameters
    headerValue = ((nsCString)buf).get();

  } else {
    // Extract value to left of parameters
    headerValue = nsDependentCSubstring (buf, 0, semicolonOffset);
  }

  // Trim leading and trailing spaces in header value
  headerValue.Trim(" ", PR_TRUE, PR_TRUE);

  if (headerKey.Equals("content-type")) {
    mContentType = headerValue;

    DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentType=%s\n",
               mContentType.get()));

    if (!buf.IsEmpty()) {
      char *charset  = MimeHeaders_get_parameter(buf.get(),
                              HEADER_PARM_CHARSET, NULL, NULL);
      char *boundary = MimeHeaders_get_parameter(buf.get(),
                              HEADER_PARM_BOUNDARY, NULL, NULL);
      char *protocol = MimeHeaders_get_parameter(buf.get(),
                              PARAM_PROTOCOL, NULL, NULL);
      char *micalg   = MimeHeaders_get_parameter(buf.get(),
                               PARAM_MICALG, NULL, NULL);

      if (charset)
        mContentCharset = charset;

      if (boundary)
        mContentBoundary = boundary;

      if (protocol)
        mContentProtocol = protocol;

      if (micalg)
        mContentMicalg = micalg;

      PR_FREEIF(charset);
      PR_FREEIF(boundary);
      PR_FREEIF(protocol);
      PR_FREEIF(micalg);

      DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentCharset=%s\n",
                 mContentCharset.get()));

      DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentBoundary=%s\n",
                 mContentBoundary.get()));

      DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentProtocol=%s\n",
                 mContentProtocol.get()));

      DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentMicalg=%s\n",
                 mContentMicalg.get()));
    }

  } else if (headerKey.Equals("content-transfer-encoding")) {
    mContentEncoding = buf;
    ToLowerCase(mContentEncoding);

    DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentEncoding=%s\n",
               mContentEncoding.get()));

  } else if (headerKey.Equals("content-disposition")) {
    mContentDisposition = buf;

    DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentDisposition=%s\n",
               mContentDisposition.get()));

  } else if (headerKey.Equals("content-length")) {
    nsresult status;
    PRInt32 value = headerValue.ToInteger(&status);

    if (NS_SUCCEEDED(status))
      mContentLength = value;

    DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContenLengtht=%d\n",
               mContentLength));
  }

  return;
}
Пример #15
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;
}
Пример #16
0
static void *
MimeMultCMS_init (MimeObject *obj)
{
  MimeHeaders *hdrs = obj->headers;
  MimeMultCMSdata *data = 0;
  char *ct, *micalg;
  PRInt16 hash_type;
  nsresult rv;

  ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
  if (!ct) return 0; /* #### bogus message?  out of memory? */
  micalg = MimeHeaders_get_parameter (ct, PARAM_MICALG, NULL, NULL);
  PR_Free(ct);
  ct = 0;
  if (!micalg) return 0; /* #### bogus message?  out of memory? */

  if (!PL_strcasecmp(micalg, PARAM_MICALG_MD5) ||
      !PL_strcasecmp(micalg, PARAM_MICALG_MD5_2))
    hash_type = nsICryptoHash::MD5;
  else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA1) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_2) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_3) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_4) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_5))
    hash_type = nsICryptoHash::SHA1;
  else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA256) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA256_2) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA256_3))
    hash_type = nsICryptoHash::SHA256;
  else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA384) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA384_2) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA384_3))
    hash_type = nsICryptoHash::SHA384;
  else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA512) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA512_2) ||
       !PL_strcasecmp(micalg, PARAM_MICALG_SHA512_3))
    hash_type = nsICryptoHash::SHA512;
  else if (!PL_strcasecmp(micalg, PARAM_MICALG_MD2))
    hash_type = nsICryptoHash::MD2;
  else
    hash_type = -1;

  PR_Free(micalg);
  micalg = 0;

  if (hash_type == -1) return 0; /* #### bogus message? */

  data = new MimeMultCMSdata;
  if (!data)
    return 0;

  data->self = obj;
  data->hash_type = hash_type;

  data->data_hash_context = do_CreateInstance("@mozilla.org/security/hash;1", &rv);
  if (NS_FAILED(rv))
  {
    delete data;
    return 0;
  }

  rv = data->data_hash_context->Init(data->hash_type);
  if (NS_FAILED(rv))
  {
    delete data;
    return 0;
  }

  PR_SetError(0,0);

  data->parent_holds_stamp_p =
  (obj->parent && mime_crypto_stamped_p(obj->parent));

  data->parent_is_encrypted_p =
  (obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent));

  /* If the parent of this object is a crypto-blob, then it's the grandparent
   who would have written out the headers and prepared for a stamp...
   (This s##t s$%#s.)
   */
  if (data->parent_is_encrypted_p &&
    !data->parent_holds_stamp_p &&
    obj->parent && obj->parent->parent)
  data->parent_holds_stamp_p =
    mime_crypto_stamped_p (obj->parent->parent);

  mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure);
  if (msd)
  {
    nsIChannel *channel = msd->channel;  // note the lack of ref counting...
    if (channel)
    {
      nsCOMPtr<nsIURI> uri;
      nsCOMPtr<nsIMsgWindow> msgWindow;
      nsCOMPtr<nsIMsgHeaderSink> headerSink;
      nsCOMPtr<nsIMsgMailNewsUrl> msgurl;
      nsCOMPtr<nsISupports> securityInfo;
      channel->GetURI(getter_AddRefs(uri));
      if (uri)
      {
        nsCAutoString urlSpec;
        rv = uri->GetSpec(urlSpec);

        // We only want to update the UI if the current mime transaction
        // is intended for display.
        // If the current transaction is intended for background processing,
        // we can learn that by looking at the additional header=filter
        // string contained in the URI.
        //
        // If we find something, we do not set smimeHeaderSink,
        // which will prevent us from giving UI feedback.
        //
        // If we do not find header=filter, we assume the result of the
        // processing will be shown in the UI.

        if (!strstr(urlSpec.get(), "?header=filter") &&
            !strstr(urlSpec.get(), "&header=filter")&&
            !strstr(urlSpec.get(), "?header=attach") &&
            !strstr(urlSpec.get(), "&header=attach"))
        {
          msgurl = do_QueryInterface(uri);
          if (msgurl)
            msgurl->GetMsgWindow(getter_AddRefs(msgWindow));
          if (msgWindow)
            msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
          if (headerSink)
            headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));
          if (securityInfo)
            data->smimeHeaderSink = do_QueryInterface(securityInfo);
         }
       }
    } // if channel
  } // if msd

  return data;
}