Bug 324495 - "put signature editing in UI (rather than select a file)" [r=Neil,sr=bienvenu,ui-review=clarkbw]
authorrsx11m <rsx11m.pub@gmail.com>
Wed, 15 Apr 2009 09:11:08 +0100
changeset 2390 12e923a82a10fb16e9a638898e140d5bc3ae2d2f
parent 2389 2ba40cd789ec6db3626049253632b9f9cf3c84aa
child 2391 5c061c0df29c605d05eff2f3025abd715f0e6c50
push idunknown
push userunknown
push dateunknown
reviewersNeil, bienvenu
bugs324495
Bug 324495 - "put signature editing in UI (rather than select a file)" [r=Neil,sr=bienvenu,ui-review=clarkbw]
mail/locales/en-US/chrome/messenger/am-main.dtd
mail/themes/gnomestripe/mail/accountManage.css
mail/themes/pinstripe/mail/accountManage.css
mail/themes/qute/mail/accountManage.css
mailnews/base/prefs/resources/content/am-addressing.js
mailnews/base/prefs/resources/content/am-addressingOverlay.xul
mailnews/base/prefs/resources/content/am-identity-edit.js
mailnews/base/prefs/resources/content/am-identity-edit.xul
mailnews/base/prefs/resources/content/am-main.xul
mailnews/base/public/nsIMsgIdentity.idl
mailnews/base/util/nsMsgIdentity.cpp
mailnews/compose/src/nsMsgCompose.cpp
suite/locales/en-US/chrome/common/help/mail_help.xhtml
suite/locales/en-US/chrome/mailnews/pref/am-main.dtd
suite/themes/classic/messenger/accountManage.css
suite/themes/modern/messenger/accountManage.css
--- a/mail/locales/en-US/chrome/messenger/am-main.dtd
+++ b/mail/locales/en-US/chrome/messenger/am-main.dtd
@@ -8,18 +8,22 @@
 <!ENTITY name.label "Your Name:">
 <!ENTITY name.accesskey "Y">
 <!ENTITY email.label "Email Address:">
 <!ENTITY email.accesskey "E">
 <!ENTITY replyTo.label "Reply-to Address:">
 <!ENTITY replyTo.accesskey "s">
 <!ENTITY organization.label "Organization:">
 <!ENTITY organization.accesskey "O">
-<!ENTITY signature.label "Attach this signature:">
-<!ENTITY signature.accesskey "t">
+<!ENTITY signatureText.label "Signature text:">
+<!ENTITY signatureText.accesskey "x">
+<!ENTITY signatureHtml.label "Use HTML (e.g., &lt;b&gt;bold&lt;/b&gt;)">
+<!ENTITY signatureHtml.accesskey "L">
+<!ENTITY signatureFile.label "Attach the signature from a file instead (text, HTML, or image):">
+<!ENTITY signatureFile.accesskey "t">
 <!ENTITY edit.label "Edit…">
 <!ENTITY choose.label "Choose…">
 <!ENTITY choose.accesskey "C">
 <!ENTITY editVCard.label "Edit Card…">
 <!ENTITY editVCard.accesskey "d">
 <!-- LOCALIZATION NOTE (attachVCard.label) : do not translate "vCard" in below line -->
 <!ENTITY attachVCard.label "Attach my vCard to messages">
 <!ENTITY attachVCard.accesskey "v">
--- a/mail/themes/gnomestripe/mail/accountManage.css
+++ b/mail/themes/gnomestripe/mail/accountManage.css
@@ -56,16 +56,20 @@
 .selectForOfflineUseButton {
   list-style-image: url("chrome://communicator/skin/icons/offline.png");
 }
 
 .selectForOfflineUseButton > .button-box > .button-icon {
   margin: 0 4px;
 }
 
+.signatureBox {
+  font-family: -moz-fixed;
+}
+
 treechildren::-moz-tree-cell-text(isDefaultServer-true) {
   font-weight: bold;
 }
 
 /* ::::: SMTP Server Panel :::::: */
 
 .smtpServerListItem {
   -moz-padding-start: 3px;
--- a/mail/themes/pinstripe/mail/accountManage.css
+++ b/mail/themes/pinstripe/mail/accountManage.css
@@ -48,16 +48,20 @@
 .specialFolderPickerGrid {
   -moz-margin-start: 20px;
 }
 
 .fccReplyFollowsParent {
   -moz-margin-start: 20px;
 }
 
+.signatureBox {
+  font-family: -moz-fixed;
+}
+
 #am-main-title, dialogheader {
   display: none;
 }
 
 .dialog-button[dlgtype="help"] {
   display: none;
 }
 
--- a/mail/themes/qute/mail/accountManage.css
+++ b/mail/themes/qute/mail/accountManage.css
@@ -56,16 +56,20 @@
 .selectForOfflineUseButton {
   list-style-image: url("chrome://communicator/skin/icons/offline.png");
 }
 
 .selectForOfflineUseButton > .button-box > .button-icon {
   margin: 0 4px;
 }
 
+.signatureBox {
+  font-family: -moz-fixed;
+}
+
 treechildren::-moz-tree-cell-text(isDefaultServer-true) {
   font-weight: bold;
 }
 
 /* ::::: SMTP Server Panel :::::: */
 
 .smtpServerListItem {
   -moz-padding-start: 3px;
--- a/mailnews/base/prefs/resources/content/am-addressing.js
+++ b/mailnews/base/prefs/resources/content/am-addressing.js
@@ -97,17 +97,18 @@ function enabling()
 
 function quoteEnabling()
 {
   var quotebox = document.getElementById("thenBox");
   var placebox = document.getElementById("placeBox");
   var quotecheck = document.getElementById("identity.autoQuote");
 
   if (quotecheck.checked && !quotecheck.disabled &&
-      document.getElementById("identity.attachSignature").checked &&
+      (document.getElementById("identity.attachSignature").checked ||
+       (document.getElementById("identity.htmlSigText").value.length > 0)) &&
       (document.getElementById("identity.replyOnTop").value == 1)) {
     placebox.firstChild.removeAttribute("disabled");
     placebox.lastChild.removeAttribute("disabled");
   }
   else {
     placebox.firstChild.setAttribute("disabled", "true");
     placebox.lastChild.setAttribute("disabled", "true");
   }
--- a/mailnews/base/prefs/resources/content/am-addressingOverlay.xul
+++ b/mailnews/base/prefs/resources/content/am-addressingOverlay.xul
@@ -46,16 +46,19 @@
 
   <script type="application/x-javascript" src="chrome://messenger/content/am-addressing.js"/>
 
   <vbox flex="1" id="compositionAndAddressing">
     <stringbundle id="bundle_addressBook" src="chrome://messenger/locale/addressbook/addressBook.properties"/>
     <checkbox hidden="true" wsm_persist="true" id="identity.attachSignature"
           pref="true" preftype="bool" prefattribute="value"
           prefstring="mail.identity.%identitykey%.attach_signature"/>
+    <textbox hidden="true" wsm_persist="true" id="identity.htmlSigText"
+          pref="true" preftype="string" prefattribute="value"
+          prefstring="mail.identity.%identitykey%.htmlSigText"/>
 
     <groupbox>
       <caption label="&compositionGroupTitle.label;"/>
       <hbox align="center">
         <checkbox wsm_persist="true" id="identity.composeHtml" label="&useHtml.label;"
                   accesskey="&useHtml.accesskey;"
                   prefattribute="value"
                   prefstring="mail.identity.%identitykey%.compose_html"/>
--- a/mailnews/base/prefs/resources/content/am-identity-edit.js
+++ b/mailnews/base/prefs/resources/content/am-identity-edit.js
@@ -62,16 +62,18 @@ function initIdentityValues(identity)
 {
   if (identity)
   {
     document.getElementById('identity.fullName').value = identity.fullName;
     document.getElementById('identity.email').value = identity.email;
     document.getElementById('identity.replyTo').value = identity.replyTo;
     document.getElementById('identity.organization').value = identity.organization;
     document.getElementById('identity.attachSignature').checked = identity.attachSignature;
+    document.getElementById('identity.htmlSigText').value = identity.htmlSigText;
+    document.getElementById('identity.htmlSigFormat').checked = identity.htmlSigFormat;
 
     if (identity.signature)
       document.getElementById('identity.signature').value = identity.signature.path;
 
     document.getElementById('identity.attachVCard').checked = identity.attachVCard;
     document.getElementById('identity.escapedVCard').value = identity.escapedVCard;
   }
 
@@ -183,16 +185,18 @@ function saveIdentitySettings(identity)
 {
   if (identity)
   {
     identity.fullName = document.getElementById('identity.fullName').value;
     identity.email = document.getElementById('identity.email').value;
     identity.replyTo = document.getElementById('identity.replyTo').value;
     identity.organization = document.getElementById('identity.organization').value;
     identity.attachSignature = document.getElementById('identity.attachSignature').checked;
+    identity.htmlSigText = document.getElementById('identity.htmlSigText').value;
+    identity.htmlSigFormat = document.getElementById('identity.htmlSigFormat').checked;
 
     identity.attachVCard = document.getElementById('identity.attachVCard').checked;
     identity.escapedVCard = document.getElementById('identity.escapedVCard').value;
     identity.smtpServerKey = document.getElementById('identity.smtpServerKey').value;
 
     var attachSignaturePath = document.getElementById('identity.signature').value;
     identity.signature = null; // this is important so we don't accidentally inherit the default
     
@@ -283,28 +287,42 @@ function GetSigFolder()
     }
   }
   catch (ex) {
       dump("failed to get signature folder..\n");
   }
   return sigFolder;
 }
 
+// Signature textbox is active unless option to select from file is checked.
 // If a signature is need to be attached, the associated items which
 // displays the absolute path to the signature (in a textbox) and the way
 // to select a new signature file (a button) are enabled. Otherwise, they
 // are disabled. Check to see if the attachSignature is locked to block
 // broadcasting events.
 function setupSignatureItems()
 { 
   var signature = document.getElementById("identity.signature");
   var browse = document.getElementById("identity.sigbrowsebutton");
+  var htmlSigText = document.getElementById("identity.htmlSigText");
+  var htmlSigFormat = document.getElementById("identity.htmlSigFormat");
   var attachSignature = document.getElementById("identity.attachSignature");
   var checked = attachSignature.checked;
 
+  if (checked)
+  {
+    htmlSigText.setAttribute("disabled", "true");
+    htmlSigFormat.setAttribute("disabled", "true");
+  }
+  else
+  {
+    htmlSigText.removeAttribute("disabled");
+    htmlSigFormat.removeAttribute("disabled");
+  }
+
   if (checked && !getAccountValueIsLocked(signature))
     signature.removeAttribute("disabled");
   else
     signature.setAttribute("disabled", "true");
 
   if (checked && !getAccountValueIsLocked(browse))
     browse.removeAttribute("disabled");
   else
--- a/mailnews/base/prefs/resources/content/am-identity-edit.xul
+++ b/mailnews/base/prefs/resources/content/am-identity-edit.xul
@@ -1,11 +1,12 @@
 <?xml version="1.0"?>
 
 <?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
+<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
 
 <!-- ***** BEGIN LICENSE BLOCK *****
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at
  http://www.mozilla.org/MPL/
@@ -102,24 +103,31 @@
             <row align="center">
               <label value="&replyTo.label;" control="identity.replyTo" accesskey="&replyTo.accesskey;"/>
               <textbox id="identity.replyTo" class="uri-element"/>
             </row>
             <row align="center">
               <label value="&organization.label;" control="identity.organization" accesskey="&organization.accesskey;"/>
               <textbox id="identity.organization"/>
             </row>
+            <separator class="thin"/>
+            <row align="center">
+              <label value="&signatureText.label;" control="identity.htmlSigText" accesskey="&signatureText.accesskey;"/>
+              <checkbox id="identity.htmlSigFormat" label="&signatureHtml.label;" accesskey="&signatureHtml.accesskey;"/>
+            </row>
           </rows>
         </grid>
-    
-        <separator class="thin"/>
+
+        <hbox align="center" class="indent">
+          <textbox id="identity.htmlSigText" flex="1" multiline="true" wrap="off" rows="4" class="signatureBox"/>
+        </hbox>
 
         <hbox align="center">
-          <checkbox id="identity.attachSignature" label="&signature.label;" flex="1"
-                    accesskey="&signature.accesskey;"
+          <checkbox id="identity.attachSignature" label="&signatureFile.label;" flex="1"
+                    accesskey="&signatureFile.accesskey;"
                     oncommand="setupSignatureItems();"/>
         </hbox>
 
         <hbox align="center" class="indent">
           <textbox id="identity.signature" datatype="nsILocalFile" flex="1" name="identity.signature"
                    aria-labelledby="identity.attachSignature"
                    observes="broadcaster_attachSignature" class="uri-element"/>
           <button class="push" name="browse" label="&choose.label;"
--- a/mailnews/base/prefs/resources/content/am-main.xul
+++ b/mailnews/base/prefs/resources/content/am-main.xul
@@ -56,24 +56,34 @@
                      prefstring="mail.identity.%identitykey%.reply_to" class="uri-element"/>
           </row>
           <row align="center">
             <label value="&organization.label;" control="identity.organization"
                    accesskey="&organization.accesskey;"/>
             <textbox wsm_persist="true" id="identity.organization"
                      prefstring="mail.identity.%identitykey%.organization"/>
           </row>
+          <separator class="thin"/>
+          <row align="center">
+            <label value="&signatureText.label;" control="identity.htmlSigText" accesskey="&signatureText.accesskey;"/>
+            <checkbox wsm_persist="true" id="identity.htmlSigFormat" label="&signatureHtml.label;"
+                      prefattribute="value" accesskey="&signatureHtml.accesskey;"
+                      prefstring="mail.identity.%identitykey%.htmlSigFormat"/>
+          </row>
         </rows>
       </grid>
-      
-      <separator class="thin"/>
+
+      <hbox align="center" class="indent">
+        <textbox wsm_persist="true" id="identity.htmlSigText" multiline="true" wrap="off" rows="4" flex="1"
+                 prefstring="mail.identity.%identitykey%.htmlSigText" class="signatureBox"/>
+      </hbox>
 
       <hbox align="center">
-        <checkbox wsm_persist="true" id="identity.attachSignature" label="&signature.label;" flex="1"
-                  accesskey="&signature.accesskey;"
+        <checkbox wsm_persist="true" id="identity.attachSignature" label="&signatureFile.label;" flex="1"
+                  accesskey="&signatureFile.accesskey;"
                   oncommand="setupSignatureItems();"
                   prefattribute="value"
                   prefstring="mail.identity.%identitykey%.attach_signature"/>
       </hbox>
 
       <hbox align="center" class="indent">
         <textbox wsm_persist="true" id="identity.signature" datatype="nsILocalFile" flex="1" name="identity.signature"
                  aria-labelledby="identity.attachSignature"
--- a/mailnews/base/public/nsIMsgIdentity.idl
+++ b/mailnews/base/public/nsIMsgIdentity.idl
@@ -44,17 +44,17 @@
  * for a given person.
  * each identity is identified by a key, which is the <id> string in
  * the identity preferences, such as in
  * mail.identity.<id>.replyTo
  *
  */
 
 
-[scriptable, uuid(ca17fc07-f842-4ea1-936c-3a2756f99531)]
+[scriptable, uuid(592d1e34-acab-4817-8247-0299fdc55204)]
 interface nsIMsgIdentity : nsISupports {
   /* internal preferences ID */
   attribute ACString key;
 
   /*
    *overriding display name for this identity. if this pref is not set
    * then this will return some composed string from the fullname and email
    */
@@ -85,20 +85,24 @@ interface nsIMsgIdentity : nsISupports {
   attribute boolean autoQuote;
 
   /* what should our quoting preference be? */
   attribute long replyOnTop;
 
   /* what should our signature be at the end of the quoted text when replying above it? */
   attribute boolean sigBottom;
 
-  /* the current signature */
+  /* the current signature if read from file */
   attribute nsILocalFile signature;
   attribute long signatureDate;
 
+  /* text (format=false) or HTML (format=true) signature if set by preference */
+  attribute AString htmlSigText;
+  attribute boolean htmlSigFormat;
+
   attribute ACString escapedVCard;
 
   attribute boolean doFcc;
   /// URI for the fcc (Sent) folder
   attribute ACString fccFolder;
   attribute boolean fccReplyFollowsParent;
   
   /**
--- a/mailnews/base/util/nsMsgIdentity.cpp
+++ b/mailnews/base/util/nsMsgIdentity.cpp
@@ -169,16 +169,18 @@ NS_IMPL_IDPREF_STR(EscapedVCard, "escape
 NS_IMPL_IDPREF_STR(SmtpServerKey, "smtpServer")
 NS_IMPL_IDPREF_WSTR(FullName, "fullName")
 NS_IMPL_IDPREF_STR(Email, "useremail")
 NS_IMPL_IDPREF_STR(ReplyTo, "reply_to")
 NS_IMPL_IDPREF_WSTR(Organization, "organization")
 NS_IMPL_IDPREF_BOOL(ComposeHtml, "compose_html")
 NS_IMPL_IDPREF_BOOL(AttachVCard, "attach_vcard")
 NS_IMPL_IDPREF_BOOL(AttachSignature, "attach_signature")
+NS_IMPL_IDPREF_WSTR(HtmlSigText, "htmlSigText")
+NS_IMPL_IDPREF_BOOL(HtmlSigFormat, "htmlSigFormat")
 
 NS_IMPL_IDPREF_BOOL(AutoQuote, "auto_quote")
 NS_IMPL_IDPREF_INT(ReplyOnTop, "reply_on_top")
 NS_IMPL_IDPREF_BOOL(SigBottom, "sig_bottom")
 
 NS_IMPL_IDPREF_INT(SignatureDate,"sig_date")
 
 NS_IMPL_IDPREF_BOOL(DoFcc, "fcc")
@@ -556,16 +558,18 @@ nsMsgIdentity::Copy(nsIMsgIdentity *iden
     COPY_IDENTITY_STR_VALUE(identity,GetDraftFolder,SetDraftFolder)
     COPY_IDENTITY_STR_VALUE(identity,GetArchiveFolder,SetArchiveFolder)
     COPY_IDENTITY_STR_VALUE(identity,GetFccFolder,SetFccFolder)
     COPY_IDENTITY_BOOL_VALUE(identity,GetFccReplyFollowsParent,
                              SetFccReplyFollowsParent)
     COPY_IDENTITY_STR_VALUE(identity,GetStationeryFolder,SetStationeryFolder)
     COPY_IDENTITY_BOOL_VALUE(identity,GetAttachSignature,SetAttachSignature)
     COPY_IDENTITY_FILE_VALUE(identity,GetSignature,SetSignature)
+    COPY_IDENTITY_WSTR_VALUE(identity,GetHtmlSigText,SetHtmlSigText)
+    COPY_IDENTITY_BOOL_VALUE(identity,GetHtmlSigFormat,SetHtmlSigFormat)
     COPY_IDENTITY_BOOL_VALUE(identity,GetAutoQuote,SetAutoQuote)
     COPY_IDENTITY_INT_VALUE(identity,GetReplyOnTop,SetReplyOnTop)
     COPY_IDENTITY_BOOL_VALUE(identity,GetSigBottom,SetSigBottom)
     COPY_IDENTITY_INT_VALUE(identity,GetSignatureDate,SetSignatureDate)
     COPY_IDENTITY_BOOL_VALUE(identity,GetAttachVCard,SetAttachVCard)
     COPY_IDENTITY_STR_VALUE(identity,GetEscapedVCard,SetEscapedVCard)
     COPY_IDENTITY_STR_VALUE(identity,GetSmtpServerKey,SetSmtpServerKey)
     return NS_OK;
--- a/mailnews/compose/src/nsMsgCompose.cpp
+++ b/mailnews/compose/src/nsMsgCompose.cpp
@@ -2182,17 +2182,17 @@ QuotingOutputStreamListener::QuotingOutp
       mIdentity->GetReplyOnTop(&reply_on_top);
       if (reply_on_top == 1)
       {
         // add one newline if a signature comes before the quote, two otherwise
         PRBool sig_bottom = PR_TRUE;
         PRBool useSigFile = PR_FALSE;
         nsString prefSigText;
         mIdentity->GetSigBottom(&sig_bottom);
-        mIdentity->GetUnicharAttribute("htmlSigText", prefSigText);
+        mIdentity->GetHtmlSigText(prefSigText);
         rv = mIdentity->GetAttachSignature(&useSigFile);
         if (!sig_bottom && ((NS_SUCCEEDED(rv) && useSigFile) || !prefSigText.IsEmpty()))
           mCitePrefix.AppendLiteral("\n");
         else
           mCitePrefix.AppendLiteral("\n\n");
       }
 
 
@@ -3918,32 +3918,32 @@ nsMsgCompose::ProcessSignature(nsIMsgIde
   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("...sigText", "unicode sig");
+  //    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.
+  // saying "Image Signature Omitted" or something (not done yet).
   //
-  // If there's a sig pref, we will append its text after the sig file contents - we don't
-  // expect many users to use both, but when they do, I think it the pref text is more
-  // likely to be centrally controlled by MCD or a custom installation, and thus will
-  // be more general, and thus should probably go after the user's sig file.
+  // 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).
+
   nsCAutoString sigNativePath;
   PRBool        useSigFile = PR_FALSE;
   PRBool        htmlSig = PR_FALSE;
   PRBool        imageSig = PR_FALSE;
   nsAutoString  sigData;
   nsAutoString sigOutput;
   PRInt32      reply_on_top = 0;
   PRBool       sig_bottom = PR_TRUE;
@@ -3982,20 +3982,22 @@ nsMsgCompose::ProcessSignature(nsIMsgIde
               }
             }
           }
         }
       }
     }
   }
 
+  // Unless a signature file is given, use preference value;
   // the pref sig is always going to be treated as html
+  // if any <> tag is found, otherwise it is considered text
   nsString prefSigText;
-  if (identity)
-    identity->GetUnicharAttribute("htmlSigText", prefSigText);
+  if (identity && !useSigFile)
+    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[] = "-- ";
@@ -4039,48 +4041,59 @@ nsMsgCompose::ProcessSignature(nsIMsgIde
     // 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!
-    // post-processing for plain-text signatures to ensure we end in CR, LF, or CRLF
-    if (!htmlSig && !m_composeHTML)
-    {
-      PRInt32 sigLength = sigData.Length();
-      if (sigLength > 0 && !(sigData.CharAt(sigLength - 1) == '\r')
-                        && !(sigData.CharAt(sigLength - 1) == '\n'))
-        sigData.AppendLiteral(CRLF);
-    }
   }
 
   // if we have a prefSigText, append it to sigData.
   if (!prefSigText.IsEmpty())
   {
-    // insert a line between the sig file and the pref sig text, if there was a sig file.
-    if (!sigData.IsEmpty())
-    {
-      if (m_composeHTML)
-        sigOutput.AppendLiteral(htmlBreak);
-      else
-        sigOutput.AppendLiteral(CRLF);
-    }
+    // set htmlSig if the pref is supposed to contain HTML code, defaults to false
+    rv = identity->GetHtmlSigFormat(&htmlSig);
+    if (NS_FAILED(rv))
+      htmlSig = PR_FALSE;
 
     if (!m_composeHTML)
     {
-      ConvertBufToPlainText(prefSigText, PR_FALSE);
+      if (htmlSig)
+        ConvertBufToPlainText(prefSigText, PR_FALSE);
       sigData.Append(prefSigText);
     }
     else
     {
-      sigData.Append(prefSigText);
+      if (!htmlSig)
+      {
+        PRUnichar* escaped = nsEscapeHTML2(prefSigText.get());
+        if (escaped)
+        {
+          sigData.Append(escaped);
+          NS_Free(escaped);
+        }
+        else
+          sigData.Append(prefSigText);
+      }
+      else
+        sigData.Append(prefSigText);
     }
   }
+
+  // post-processing for plain-text signatures to ensure we end in CR, LF, or CRLF
+  if (!htmlSig && !m_composeHTML)
+  {
+    PRInt32 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)
     {
       sigOutput.AppendLiteral(htmlBreak);
       if (htmlSig)
--- a/suite/locales/en-US/chrome/common/help/mail_help.xhtml
+++ b/suite/locales/en-US/chrome/common/help/mail_help.xhtml
@@ -245,17 +245,17 @@
 <p>To view or change information for an existing mail or newsgroup account,
   begin from the Mail window:</p>
 
 <ol>
   <li>Open the Edit menu and choose Mail &amp; Newsgroups Account Settings. You
     see the Mail &amp; Newsgroups Account Settings dialog box.</li>
   <li>Click the account name in the left-hand side of the Account Settings
     dialog box. You see information about the account, such as your email
-    address and signature file, in the right side of the dialog box.</li>
+    address and signature, in the right side of the dialog box.</li>
   <li>Click any of these items beneath the name of an account to see the
     corresponding settings:
     <ul>
       <li><strong>Server Settings</strong>: The settings available depend on
         the type of server (IMAP, POP, or newsgroup server). For more
         information, see <a href="#server_settings">Mail &amp; Newsgroups
         Account Settings - Server Settings</a>.
 
@@ -3494,34 +3494,38 @@ to filter unwanted mail, and how phishin
     <li><a href="#outgoing_server">Outgoing Server (SMTP)</a></li>
   </ul>
 </div>
 
 <h2 id="account_settings">Mail &amp; Newsgroups Account Settings - Account
   Settings</h2>
 
 <p>This section describes how to view or change your Account Settings, such as
-  your user name, reply-to address, and signature file. If you are not already
+  your user name, reply-to address, and signature. If you are not already
   viewing the Account Settings, begin from the Mail window:</p>
 
 <ol>
   <li>Open the Edit menu and choose Mail &amp; Newsgroups Account Settings. You
     see the Mail &amp; Newsgroups Account Settings dialog box.</li>
   <li>Select the name of the account to display the Account Settings
     panel.</li>
 </ol>
 
 <ul>
   <li><strong>Account Name</strong>: The name for this account.</li>
   <li><strong>Identity</strong>: Stores your name, email address, reply-to
     address (only if different from your email address), and organization
     (optional).</li>
-  <li><strong>Attach this signature</strong>: Lets you choose the signature
-    file (in text or HTML format) you want to attach to your outgoing messages.
-    Click Choose to locate the signature file (optional).</li>
+  <li><strong>Signature text</strong>: If you want to attach a signature to all
+    outgoing messages, type its text into this box. Check <strong>Use HTML</strong>
+    to enable HTML code, e.g., &lt;b&gt;bold&lt;/b&gt; (optional).</li>
+  <li><strong>Attach the signature from a file instead</strong>: Lets you choose
+    to attach the signature from a file (in text, HTML, or image format) rather
+    than entering its text. Checking this option overrides any text entered into
+    the signature box. Click Choose to locate the signature file (optional).</li>
   <li><strong>Attach my vCard to messages</strong>: Lets you choose if your
     vCard should be attached to your outgoing messages. Click Edit Card to edit
     the card information (optional).</li>
 </ul>
 
 <p>[<a href="#mail_and_newsgroups_account_settings">Return to beginning of
   section</a>]</p>
 
--- a/suite/locales/en-US/chrome/mailnews/pref/am-main.dtd
+++ b/suite/locales/en-US/chrome/mailnews/pref/am-main.dtd
@@ -8,18 +8,22 @@
 <!ENTITY name.label "Your Name:">
 <!ENTITY name.accesskey "Y">
 <!ENTITY email.label "Email Address:">
 <!ENTITY email.accesskey "E">
 <!ENTITY replyTo.label "Reply-to Address:">
 <!ENTITY replyTo.accesskey "s">
 <!ENTITY organization.label "Organization:">
 <!ENTITY organization.accesskey "O">
-<!ENTITY signature.label "Attach this signature:">
-<!ENTITY signature.accesskey "t">
+<!ENTITY signatureText.label "Signature text:">
+<!ENTITY signatureText.accesskey "x">
+<!ENTITY signatureHtml.label "Use HTML">
+<!ENTITY signatureHtml.accesskey "L">
+<!ENTITY signatureFile.label "Attach the signature from a file instead:">
+<!ENTITY signatureFile.accesskey "t">
 <!ENTITY choose.label "Choose…">
 <!ENTITY choose.accesskey "C">
 <!ENTITY editVCard.label "Edit Card…">
 <!ENTITY editVCard.accesskey "d">
 <!-- LOCALIZATION NOTE (attachVCard.label) : do not translate "vCard" in below line -->
 <!ENTITY attachVCard.label "Attach my vCard to messages">
 <!ENTITY attachVCard.accesskey "v">
 
--- a/suite/themes/classic/messenger/accountManage.css
+++ b/suite/themes/classic/messenger/accountManage.css
@@ -57,16 +57,20 @@
   list-style-image: url("chrome://communicator/skin/icons/offline.gif");
 }
 
 .selectForOfflineUseButton > .button-box > .button-icon {
   -moz-margin-start: 4px;
   -moz-margin-end: 4px;
 }
 
+.signatureBox {
+  font-family: -moz-fixed;
+}
+
 treechildren::-moz-tree-cell-text(isDefaultServer-true) {
   font-weight: bold;
 }
 
 /* ::::: SMTP Server Panel :::::: */
 
 .smtpServerListItem {
   -moz-padding-start: 3px;
--- a/suite/themes/modern/messenger/accountManage.css
+++ b/suite/themes/modern/messenger/accountManage.css
@@ -57,16 +57,20 @@
   list-style-image: url("chrome://communicator/skin/icons/offline.gif");
 }
 
 .selectForOfflineUseButton > .button-box > .button-icon {
   -moz-margin-start: 4px;
   -moz-margin-end: 4px;
 }
 
+.signatureBox {
+  font-family: -moz-fixed;
+}
+
 treechildren::-moz-tree-cell-text(isDefaultServer-true) {
   font-weight: bold;
 }
 
 /* ::::: SMTP Server Panel :::::: */
 
 .smtpServerListItem {
   -moz-padding-start: 3px;