nsresult nsMsgCompose::ProcessSignature()

in mailnews/compose/src/nsMsgCompose.cpp [3845:4072]


nsresult nsMsgCompose::ProcessSignature(nsIMsgIdentity* identity, bool aQuoted,
                                        nsString* aMsgBody) {
  nsresult rv = NS_OK;

  // Now, we can get sort of fancy. This is the time we need to check
  // for all sorts of user defined stuff, like signatures and editor
  // types and the like!
  //
  //    user_pref(".....sig_file", "y:\\sig.html");
  //    user_pref(".....attach_signature", true);
  //    user_pref(".....htmlSigText", "unicode sig");
  //
  // Note: We will have intelligent signature behavior in that we
  // look at the signature file first...if the extension is .htm or
  // .html, we assume its HTML, otherwise, we assume it is plain text
  //
  // ...and that's not all! What we will also do now is look and see if
  // the file is an image file. If it is an image file, then we should
  // insert the correct HTML into the composer to have it work, but if we
  // are doing plain text compose, we should insert some sort of message
  // saying "Image Signature Omitted" or something (not done yet).
  //
  // If there's a sig pref, it will only be used if there is no sig file
  // defined, thus if attach_signature is checked, htmlSigText is ignored (bug
  // 324495). Plain-text signatures may or may not have a trailing line break
  // (bug 428040).

  bool attachFile = false;
  bool useSigFile = false;
  bool htmlSig = false;
  bool imageSig = false;
  nsAutoString sigData;
  nsAutoString sigOutput;
  int32_t reply_on_top = 0;
  bool sig_bottom = true;
  bool suppressSigSep = false;

  nsCOMPtr<nsIFile> sigFile;
  if (identity) {
    if (!CheckIncludeSignaturePrefs(identity)) return NS_OK;

    identity->GetReplyOnTop(&reply_on_top);
    identity->GetSigBottom(&sig_bottom);
    identity->GetSuppressSigSep(&suppressSigSep);

    rv = identity->GetAttachSignature(&attachFile);
    if (NS_SUCCEEDED(rv) && attachFile) {
      rv = identity->GetSignature(getter_AddRefs(sigFile));
      if (NS_SUCCEEDED(rv) && sigFile) {
        if (!sigFile->NativePath().IsEmpty()) {
          bool exists = false;
          sigFile->Exists(&exists);
          if (exists) {
            useSigFile = true;  // ok, there's a signature file

            // Now, most importantly, we need to figure out what the content
            // type is for this signature...if we can't, we assume text
            nsAutoCString sigContentType;
            nsresult rv2;  // don't want to clobber the other rv
            nsCOMPtr<nsIMIMEService> mimeFinder(
                do_GetService(NS_MIMESERVICE_CONTRACTID, &rv2));
            if (NS_SUCCEEDED(rv2)) {
              rv2 = mimeFinder->GetTypeFromFile(sigFile, sigContentType);
              if (NS_SUCCEEDED(rv2)) {
                if (StringBeginsWith(sigContentType, "image/"_ns,
                                     nsCaseInsensitiveCStringComparator))
                  imageSig = true;
                else if (sigContentType.Equals(
                             TEXT_HTML, nsCaseInsensitiveCStringComparator))
                  htmlSig = true;
              }
            }
          }
        }
      }
    }
  }

  // Unless signature to be attached from file, use preference value;
  // the htmlSigText value is always going to be treated as html if
  // the htmlSigFormat pref is true, otherwise it is considered text
  nsAutoString prefSigText;
  if (identity && !attachFile) identity->GetHtmlSigText(prefSigText);
  // Now, if they didn't even want to use a signature, we should
  // just return nicely.
  //
  if ((!useSigFile && prefSigText.IsEmpty()) || NS_FAILED(rv)) return NS_OK;

  static const char htmlBreak[] = "<br>";
  static const char dashes[] = "-- ";
  static const char htmlsigopen[] = "<div class=\"moz-signature\">";
  static const char htmlsigclose[] = "</div>"; /* XXX: Due to a bug in
                     4.x' HTML editor, it will not be able to
                     break this HTML sig, if quoted (for the user to
                     interleave a comment). */
  static const char _preopen[] = "<pre class=\"moz-signature\" cols=%d>";
  char* preopen;
  static const char preclose[] = "</pre>";

  int32_t wrapLength = 72;  // setup default value in case GetWrapLength failed
  GetWrapLength(&wrapLength);
  preopen = PR_smprintf(_preopen, wrapLength);
  if (!preopen) return NS_ERROR_OUT_OF_MEMORY;

  bool paragraphMode =
      mozilla::Preferences::GetBool("mail.compose.default_to_paragraph", false);

  if (imageSig) {
    // We have an image signature. If we're using the in HTML composer, we
    // should put in the appropriate HTML for inclusion, otherwise, do nothing.
    if (m_composeHTML) {
      if (!paragraphMode) sigOutput.AppendLiteral(htmlBreak);
      sigOutput.AppendLiteral(htmlsigopen);
      if ((mType == nsIMsgCompType::NewsPost || !suppressSigSep) &&
          (reply_on_top != 1 || sig_bottom || !aQuoted)) {
        sigOutput.AppendLiteral(dashes);
      }

      sigOutput.AppendLiteral(htmlBreak);
      sigOutput.AppendLiteral("<img src='");

      nsCOMPtr<nsIURI> fileURI;
      nsresult rv = NS_NewFileURI(getter_AddRefs(fileURI), sigFile);
      NS_ENSURE_SUCCESS(rv, rv);
      nsCString fileURL;
      fileURI->GetSpec(fileURL);

      nsString dataURL;
      rv = DataURLForFileURL(NS_ConvertUTF8toUTF16(fileURL), dataURL);
      if (NS_SUCCEEDED(rv)) {
        sigOutput.Append(dataURL);
      }
      sigOutput.AppendLiteral("' border=0>");
      sigOutput.AppendLiteral(htmlsigclose);
    }
  } else if (useSigFile) {
    // is this a text sig with an HTML editor?
    if ((m_composeHTML) && (!htmlSig)) {
      ConvertTextToHTML(sigFile, sigData);
    }
    // is this a HTML sig with a text window?
    else if ((!m_composeHTML) && (htmlSig)) {
      ConvertHTMLToText(sigFile, sigData);
    } else {                               // We have a match...
      LoadDataFromFile(sigFile, sigData);  // Get the data!
      ReplaceFileURLs(sigData);
    }
  }

  // if we have a prefSigText, append it to sigData.
  if (!prefSigText.IsEmpty()) {
    // set htmlSig if the pref is supposed to contain HTML code, defaults to
    // false
    rv = identity->GetHtmlSigFormat(&htmlSig);
    if (NS_FAILED(rv)) htmlSig = false;

    if (!m_composeHTML) {
      if (htmlSig) ConvertBufToPlainText(prefSigText, false, true, true);
      sigData.Append(prefSigText);
    } else {
      if (!htmlSig) {
        nsCString escapedUTF8;
        nsAppendEscapedHTML(NS_ConvertUTF16toUTF8(prefSigText), escapedUTF8);
        sigData.Append(NS_ConvertUTF8toUTF16(escapedUTF8));
      } else {
        ReplaceFileURLs(prefSigText);
        sigData.Append(prefSigText);
      }
    }
  }

  // post-processing for plain-text signatures to ensure we end in CR, LF, or
  // CRLF
  if (!htmlSig && !m_composeHTML) {
    int32_t sigLength = sigData.Length();
    if (sigLength > 0 && !(sigData.CharAt(sigLength - 1) == '\r') &&
        !(sigData.CharAt(sigLength - 1) == '\n'))
      sigData.AppendLiteral(CRLF);
  }

  // Now that sigData holds data...if any, append it to the body in a nice
  // looking manner
  if (!sigData.IsEmpty()) {
    if (m_composeHTML) {
      if (!paragraphMode) sigOutput.AppendLiteral(htmlBreak);

      if (htmlSig)
        sigOutput.AppendLiteral(htmlsigopen);
      else
        sigOutput.Append(NS_ConvertASCIItoUTF16(preopen));
    }

    if ((reply_on_top != 1 || sig_bottom || !aQuoted) &&
        sigData.Find(u"\r-- \r") < 0 && sigData.Find(u"\n-- \n") < 0 &&
        sigData.Find(u"\n-- \r") < 0) {
      nsDependentSubstring firstFourChars(sigData, 0, 4);

      if ((mType == nsIMsgCompType::NewsPost || !suppressSigSep) &&
          !(firstFourChars.EqualsLiteral("-- \n") ||
            firstFourChars.EqualsLiteral("-- \r"))) {
        sigOutput.AppendLiteral(dashes);

        if (!m_composeHTML || !htmlSig)
          sigOutput.AppendLiteral(CRLF);
        else if (m_composeHTML)
          sigOutput.AppendLiteral(htmlBreak);
      }
    }

    // add CRLF before signature for plain-text mode if signature comes before
    // quote
    if (!m_composeHTML && reply_on_top == 1 && !sig_bottom && aQuoted)
      sigOutput.AppendLiteral(CRLF);

    sigOutput.Append(sigData);

    if (m_composeHTML) {
      if (htmlSig)
        sigOutput.AppendLiteral(htmlsigclose);
      else
        sigOutput.AppendLiteral(preclose);
    }
  }

  aMsgBody->Append(sigOutput);
  PR_Free(preopen);
  return NS_OK;
}