зеркало из https://github.com/mozilla/gecko-dev.git
2130 строки
60 KiB
C++
2130 строки
60 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape 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/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
*/
|
|
#include "nsCOMPtr.h"
|
|
#include "nsMsgCompose.h"
|
|
#include "nsIScriptGlobalObject.h"
|
|
#include "nsIDOMNode.h"
|
|
#include "nsIDOMNodeList.h"
|
|
#include "nsIDOMHTMLInputElement.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsMsgI18N.h"
|
|
#include "nsMsgCompCID.h"
|
|
#include "nsMsgSend.h"
|
|
#include "nsIMessenger.h" //temporary!
|
|
#include "nsIMessage.h" //temporary!
|
|
#include "nsMsgQuote.h"
|
|
#include "nsIPref.h"
|
|
#include "nsIDocumentEncoder.h" // for editor output flags
|
|
#include "nsXPIDLString.h"
|
|
#include "nsIMsgHeaderParser.h"
|
|
#include "nsMsgCompUtils.h"
|
|
#include "nsMsgComposeStringBundle.h"
|
|
#include "nsSpecialSystemDirectory.h"
|
|
#include "nsMsgSend.h"
|
|
#include "nsMsgCreate.h"
|
|
#include "nsMailHeaders.h"
|
|
#include "nsMsgPrompts.h"
|
|
#include "nsMimeTypes.h"
|
|
#include "nsICharsetConverterManager.h"
|
|
#include "nsTextFormatter.h"
|
|
#include "nsIEditor.h"
|
|
#include "nsIHTMLEditor.h"
|
|
#include "nsIDOMSelection.h"
|
|
#include "nsIDOMNode.h"
|
|
#include "nsEscape.h"
|
|
#include "plstr.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsIRDFService.h"
|
|
#include "nsRDFCID.h"
|
|
#include "nsAbBaseCID.h"
|
|
#include "nsIAddrDatabase.h"
|
|
#include "nsIAddrBookSession.h"
|
|
|
|
// Defines....
|
|
static NS_DEFINE_CID(kMsgQuoteCID, NS_MSGQUOTE_CID);
|
|
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
|
|
static NS_DEFINE_CID(kHeaderParserCID, NS_MSGHEADERPARSER_CID);
|
|
static NS_DEFINE_CID(kAddrBookSessionCID, NS_ADDRBOOKSESSION_CID);
|
|
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
|
static NS_DEFINE_CID(kAddressBookDBCID, NS_ADDRDATABASE_CID);
|
|
static NS_DEFINE_CID(kMsgRecipientArrayCID, NS_MSGRECIPIENTARRAY_CID);
|
|
|
|
static PRInt32 GetReplyOnTop()
|
|
{
|
|
PRInt32 reply_on_top = 1;
|
|
nsresult rv;
|
|
NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv);
|
|
if (NS_SUCCEEDED(rv))
|
|
prefs->GetIntPref("mailnews.reply_on_top", &reply_on_top);
|
|
return reply_on_top;
|
|
}
|
|
|
|
static nsresult RemoveDuplicateAddresses(const char * addresses, const char * anothersAddresses, PRBool removeAliasesToMe, char** newAddress)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIMsgHeaderParser> parser = do_GetService(kHeaderParserCID);;
|
|
if (parser)
|
|
rv= parser->RemoveDuplicateAddresses(msgCompHeaderInternalCharset(), addresses, anothersAddresses, removeAliasesToMe, newAddress);
|
|
else
|
|
rv = NS_ERROR_FAILURE;
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
nsMsgCompose::nsMsgCompose()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
|
|
mEntityConversionDone = PR_FALSE;
|
|
mQuotingToFollow = PR_FALSE;
|
|
mWhatHolder = 1;
|
|
mQuoteURI = "";
|
|
mDocumentListener = nsnull;
|
|
mMsgSend = nsnull;
|
|
m_sendListener = nsnull;
|
|
m_window = nsnull;
|
|
m_webShell = nsnull;
|
|
m_webShellWin = nsnull;
|
|
m_editor = nsnull;
|
|
mQuoteStreamListener=nsnull;
|
|
m_compFields = new nsMsgCompFields;
|
|
NS_IF_ADDREF(m_compFields);
|
|
mType = nsIMsgCompType::New;
|
|
|
|
// Get the default charset from pref, use this as a mail charset.
|
|
char * default_mail_charset = nsMsgI18NGetDefaultMailCharset();
|
|
if (default_mail_charset)
|
|
{
|
|
m_compFields->SetCharacterSet(default_mail_charset);
|
|
PR_Free(default_mail_charset);
|
|
}
|
|
|
|
m_composeHTML = PR_FALSE;
|
|
}
|
|
|
|
|
|
nsMsgCompose::~nsMsgCompose()
|
|
{
|
|
if (mDocumentListener)
|
|
{
|
|
mDocumentListener->SetComposeObj(nsnull);
|
|
NS_RELEASE(mDocumentListener);
|
|
}
|
|
NS_IF_RELEASE(m_sendListener);
|
|
NS_IF_RELEASE(m_compFields);
|
|
NS_IF_RELEASE(mQuoteStreamListener);
|
|
}
|
|
|
|
/* the following macro actually implement addref, release and query interface for our component. */
|
|
NS_IMPL_ISUPPORTS(nsMsgCompose, NS_GET_IID(nsMsgCompose));
|
|
|
|
//
|
|
// Once we are here, convert the data which we know to be UTF-8 to UTF-16
|
|
// for insertion into the editor
|
|
//
|
|
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
|
|
|
|
nsresult
|
|
TranslateLineEndings(nsString &aString)
|
|
{
|
|
PRUnichar *transBuf = nsnull;
|
|
|
|
// First, do sanity checking...if aString doesn't have
|
|
// any CR's, then there is no reason to call this rest
|
|
// of this
|
|
if (aString.FindChar(CR) < 0)
|
|
return NS_OK;
|
|
|
|
transBuf = aString.ToNewUnicode();
|
|
if (transBuf)
|
|
{
|
|
DoLineEndingConJobUnicode(transBuf, aString.Length());
|
|
aString.SetString(transBuf);
|
|
PR_FREEIF(transBuf);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParent, PRInt32 &aOffset)
|
|
{
|
|
NS_ASSERTION((aChild && aParent), "bad args");
|
|
nsresult result = NS_ERROR_NULL_POINTER;
|
|
if (aChild && aParent)
|
|
{
|
|
nsCOMPtr<nsIDOMNodeList> childNodes;
|
|
result = aParent->GetChildNodes(getter_AddRefs(childNodes));
|
|
if ((NS_SUCCEEDED(result)) && (childNodes))
|
|
{
|
|
PRInt32 i=0;
|
|
for ( ; NS_SUCCEEDED(result); i++)
|
|
{
|
|
nsCOMPtr<nsIDOMNode> childNode;
|
|
result = childNodes->Item(i, getter_AddRefs(childNode));
|
|
if ((NS_SUCCEEDED(result)) && (childNode))
|
|
{
|
|
if (childNode.get()==aChild)
|
|
{
|
|
aOffset = i;
|
|
break;
|
|
}
|
|
}
|
|
else if (!childNode)
|
|
result = NS_ERROR_NULL_POINTER;
|
|
}
|
|
}
|
|
else if (!childNodes)
|
|
result = NS_ERROR_NULL_POINTER;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
GetNodeLocation(nsIDOMNode *inChild, nsCOMPtr<nsIDOMNode> *outParent, PRInt32 *outOffset)
|
|
{
|
|
NS_ASSERTION((inChild && outParent && outOffset), "bad args");
|
|
nsresult result = NS_ERROR_NULL_POINTER;
|
|
if (inChild && outParent && outOffset)
|
|
{
|
|
result = inChild->GetParentNode(getter_AddRefs(*outParent));
|
|
if ( (NS_SUCCEEDED(result)) && (*outParent) )
|
|
{
|
|
result = GetChildOffset(inChild, *outParent, *outOffset);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
nsresult nsMsgCompose::ConvertAndLoadComposeWindow(nsIEditorShell *aEditorShell, nsString aPrefix, nsString aBuf,
|
|
nsString aSignature, PRBool aQuoted, PRBool aHTMLEditor)
|
|
{
|
|
// First, get the nsIEditor interface for future use
|
|
nsCOMPtr<nsIEditor> editor;
|
|
nsIDOMNode *nodeInserted = nsnull;
|
|
|
|
aEditorShell->GetEditor(getter_AddRefs(editor));
|
|
|
|
TranslateLineEndings(aPrefix);
|
|
TranslateLineEndings(aBuf);
|
|
TranslateLineEndings(aSignature);
|
|
|
|
if (editor)
|
|
editor->EnableUndo(PR_FALSE);
|
|
|
|
// Ok - now we need to figure out the charset of the aBuf we are going to send
|
|
// into the editor shell. There are I18N calls to sniff the data and then we need
|
|
// to call the new routine in the editor that will allow us to send in the charset
|
|
//
|
|
|
|
// Now, insert it into the editor...
|
|
if ( (aQuoted) )
|
|
{
|
|
if (!aPrefix.IsEmpty())
|
|
{
|
|
if (aHTMLEditor)
|
|
aEditorShell->InsertSource(aPrefix.GetUnicode());
|
|
else
|
|
aEditorShell->InsertText(aPrefix.GetUnicode());
|
|
}
|
|
|
|
if (!aBuf.IsEmpty())
|
|
{
|
|
aEditorShell->InsertAsQuotation(aBuf.GetUnicode(), &nodeInserted);
|
|
}
|
|
|
|
if (!aSignature.IsEmpty())
|
|
{
|
|
if (aHTMLEditor)
|
|
aEditorShell->InsertSource(aSignature.GetUnicode());
|
|
else
|
|
aEditorShell->InsertText(aSignature.GetUnicode());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (aHTMLEditor)
|
|
{
|
|
if (!aBuf.IsEmpty())
|
|
aEditorShell->InsertSource(aBuf.GetUnicode());
|
|
if (!aSignature.IsEmpty())
|
|
aEditorShell->InsertSource(aSignature.GetUnicode());
|
|
}
|
|
else
|
|
{
|
|
if (!aBuf.IsEmpty())
|
|
aEditorShell->InsertText(aBuf.GetUnicode());
|
|
|
|
if (!aSignature.IsEmpty())
|
|
aEditorShell->InsertText(aSignature.GetUnicode());
|
|
}
|
|
}
|
|
|
|
if (editor)
|
|
{
|
|
switch (GetReplyOnTop())
|
|
{
|
|
// This should set the cursor after the body but before the sig
|
|
case 0 :
|
|
{
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
|
if (!htmlEditor)
|
|
{
|
|
editor->BeginningOfDocument();
|
|
break;
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMSelection> selection = nsnull;
|
|
nsCOMPtr<nsIDOMNode> parent = nsnull;
|
|
PRInt32 offset;
|
|
nsresult rv;
|
|
|
|
// get parent and offset of mailcite
|
|
rv = GetNodeLocation(nodeInserted, &parent, &offset);
|
|
if ( NS_FAILED(rv) || (!parent) )
|
|
{
|
|
editor->BeginningOfDocument();
|
|
break;
|
|
}
|
|
|
|
// get selection
|
|
editor->GetSelection(getter_AddRefs(selection));
|
|
if (!selection)
|
|
{
|
|
editor->BeginningOfDocument();
|
|
break;
|
|
}
|
|
|
|
// place selection after mailcite
|
|
selection->Collapse(parent, offset+1);
|
|
|
|
// insert a break at current selection
|
|
htmlEditor->InsertBreak();
|
|
|
|
// i'm not sure if you need to move the selection back to before the
|
|
// break. expirement.
|
|
selection->Collapse(parent, offset+1);
|
|
|
|
break;
|
|
}
|
|
|
|
case 2 :
|
|
{
|
|
editor->SelectAll();
|
|
break;
|
|
}
|
|
|
|
// This should set the cursor to the top!
|
|
default : editor->BeginningOfDocument(); break;
|
|
}
|
|
}
|
|
|
|
NotifyStateListeners(nsMsgCompose::eComposeFieldsReady);
|
|
if (editor)
|
|
editor->EnableUndo(PR_TRUE);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgCompose::SetQuotingToFollow(PRBool aVal)
|
|
{
|
|
mQuotingToFollow = aVal;
|
|
return NS_OK;
|
|
}
|
|
|
|
PRBool
|
|
nsMsgCompose::QuotingToFollow(void)
|
|
{
|
|
return mQuotingToFollow;
|
|
}
|
|
|
|
nsresult nsMsgCompose::Initialize(nsIDOMWindow *aWindow,
|
|
const PRUnichar *originalMsgURI,
|
|
MSG_ComposeType type,
|
|
MSG_ComposeFormat format,
|
|
nsIMsgCompFields *compFields,
|
|
nsIMsgIdentity *identity)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
m_identity = identity;
|
|
|
|
if (aWindow)
|
|
{
|
|
m_window = aWindow;
|
|
nsCOMPtr<nsIScriptGlobalObject> globalObj(do_QueryInterface(aWindow));
|
|
if (!globalObj)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIDocShell> docShell;
|
|
globalObj->GetDocShell(getter_AddRefs(docShell));
|
|
nsCOMPtr<nsIWebShell> webShell(do_QueryInterface(docShell));
|
|
if (!webShell)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
m_webShell = webShell;
|
|
|
|
nsCOMPtr<nsIWebShellContainer> webShellContainer;
|
|
m_webShell->GetContainer(*getter_AddRefs(webShellContainer));
|
|
if (!webShellContainer)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIWebShellWindow> webShellWin = do_QueryInterface(webShellContainer, &rv);
|
|
m_webShellWin = webShellWin;
|
|
}
|
|
|
|
switch (format)
|
|
{
|
|
case nsIMsgCompFormat::HTML : m_composeHTML = PR_TRUE; break;
|
|
case nsIMsgCompFormat::PlainText : m_composeHTML = PR_FALSE; break;
|
|
default :
|
|
/* ask the identity which compose to use */
|
|
if (m_identity) m_identity->GetComposeHtml(&m_composeHTML);
|
|
break;
|
|
|
|
}
|
|
|
|
CreateMessage(originalMsgURI, type, format, compFields);
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult nsMsgCompose::SetDocumentCharset(const PRUnichar *charset)
|
|
{
|
|
// Set charset, this will be used for the MIME charset labeling.
|
|
m_compFields->SetCharacterSet(nsCAutoString(charset));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgCompose::RegisterStateListener(nsIMsgComposeStateListener *stateListener)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (!stateListener)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
if (!mStateListeners)
|
|
{
|
|
rv = NS_NewISupportsArray(getter_AddRefs(mStateListeners));
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
nsCOMPtr<nsISupports> iSupports = do_QueryInterface(stateListener, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// note that this return value is really a PRBool, so be sure to use
|
|
// NS_SUCCEEDED or NS_FAILED to check it.
|
|
return mStateListeners->AppendElement(iSupports);
|
|
}
|
|
|
|
nsresult nsMsgCompose::UnregisterStateListener(nsIMsgComposeStateListener *stateListener)
|
|
{
|
|
if (!stateListener)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
// otherwise, see if it exists in our list
|
|
if (!mStateListeners)
|
|
return (nsresult)PR_FALSE; // yeah, this sucks, but I'm emulating the behaviour of
|
|
// nsISupportsArray::RemoveElement()
|
|
|
|
nsCOMPtr<nsISupports> iSupports = do_QueryInterface(stateListener, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// note that this return value is really a PRBool, so be sure to use
|
|
// NS_SUCCEEDED or NS_FAILED to check it.
|
|
return mStateListeners->RemoveElement(iSupports);
|
|
}
|
|
|
|
nsresult nsMsgCompose::_SendMsg(MSG_DeliverMode deliverMode,
|
|
nsIMsgIdentity *identity,
|
|
const PRUnichar *callback)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (m_compFields && identity)
|
|
{
|
|
// Pref values are supposed to be stored as UTF-8, so no conversion
|
|
nsXPIDLCString email;
|
|
nsXPIDLString fullName;
|
|
nsXPIDLCString replyTo;
|
|
nsXPIDLString organization;
|
|
|
|
identity->GetEmail(getter_Copies(email));
|
|
identity->GetFullName(getter_Copies(fullName));
|
|
identity->GetReplyTo(getter_Copies(replyTo));
|
|
identity->GetOrganization(getter_Copies(organization));
|
|
|
|
char * sender = nsnull;
|
|
nsCOMPtr<nsIMsgHeaderParser> parser = do_GetService(kHeaderParserCID);
|
|
if (parser) {
|
|
// convert to UTF8 before passing to MakeFullAddress
|
|
nsAutoString fullNameStr(fullName);
|
|
char *fullNameUTF8 = fullNameStr.ToNewUTF8String();
|
|
parser->MakeFullAddress(nsnull, fullNameUTF8, email, &sender);
|
|
nsCRT::free(fullNameUTF8);
|
|
}
|
|
|
|
if (!sender)
|
|
m_compFields->SetFrom(email);
|
|
else
|
|
m_compFields->SetFrom(sender);
|
|
PR_FREEIF(sender);
|
|
|
|
//Set the reply-to only if the user have not specified one in the message
|
|
const char * reply = m_compFields->GetReplyTo();
|
|
if (reply == nsnull || *reply == 0)
|
|
m_compFields->SetReplyTo(replyTo);
|
|
m_compFields->SetOrganization(organization);
|
|
|
|
#if defined(DEBUG_ducarroz) || defined(DEBUG_seth_)
|
|
printf("----------------------------\n");
|
|
printf("-- Sending Mail Message --\n");
|
|
printf("----------------------------\n");
|
|
printf("from: %s\n", m_compFields->GetFrom());
|
|
printf("To: %s Cc: %s Bcc: %s\n", m_compFields->GetTo(), m_compFields->GetCc(), m_compFields->GetBcc());
|
|
printf("Newsgroups: %s\n", m_compFields->GetNewsgroups());
|
|
printf("Subject: %s \nMsg: %s\n", m_compFields->GetSubject(), m_compFields->GetBody());
|
|
printf("Attachments: %s\n",m_compFields->GetAttachments());
|
|
printf("----------------------------\n");
|
|
#endif //DEBUG
|
|
|
|
nsMsgComposeAndSend *tMsgComp = new nsMsgComposeAndSend();
|
|
if (!tMsgComp)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
mMsgSend = do_QueryInterface( tMsgComp );
|
|
if (mMsgSend)
|
|
{
|
|
PRBool newBody = PR_FALSE;
|
|
char *bodyString = (char *)m_compFields->GetBody();
|
|
PRInt32 bodyLength;
|
|
char *attachment1_type = TEXT_HTML; // we better be "text/html" at this point
|
|
|
|
mMsgSend->SetWebShell(m_webShell);
|
|
|
|
if (!mEntityConversionDone)
|
|
{
|
|
// Convert body to mail charset
|
|
char *outCString;
|
|
nsString aCharset = m_compFields->GetCharacterSet();
|
|
|
|
if ( aCharset != "")
|
|
{
|
|
// Apply entity conversion then convert to a mail charset.
|
|
char charset[65];
|
|
rv = nsMsgI18NSaveAsCharset(attachment1_type, aCharset.ToCString(charset, 65),
|
|
nsString(bodyString).GetUnicode(), &outCString);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
bodyString = outCString;
|
|
newBody = PR_TRUE;
|
|
mEntityConversionDone = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
bodyLength = PL_strlen(bodyString);
|
|
|
|
// Create the listener for the send operation...
|
|
m_sendListener = new nsMsgComposeSendListener();
|
|
if (!m_sendListener)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
NS_ADDREF(m_sendListener);
|
|
// set this object for use on completion...
|
|
m_sendListener->SetComposeObj(this);
|
|
m_sendListener->SetDeliverMode(deliverMode);
|
|
nsIMsgSendListener **tArray = m_sendListener->CreateListenerArray();
|
|
if (!tArray)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("Error creating listener array.\n");
|
|
#endif
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
// If we are composing HTML, then this should be sent as
|
|
// multipart/related which means we pass the editor into the
|
|
// backend...if not, just pass nsnull
|
|
//
|
|
nsIEditorShell *tEditor = nsnull;
|
|
|
|
if (m_composeHTML)
|
|
{
|
|
tEditor = m_editor;
|
|
}
|
|
else
|
|
tEditor = nsnull;
|
|
|
|
rv = mMsgSend->CreateAndSendMessage(
|
|
tEditor,
|
|
identity,
|
|
m_compFields,
|
|
PR_FALSE, // PRBool digest_p,
|
|
PR_FALSE, // PRBool dont_deliver_p,
|
|
(nsMsgDeliverMode)deliverMode, // nsMsgDeliverMode mode,
|
|
nsnull, // nsIMessage *msgToReplace,
|
|
m_composeHTML?TEXT_HTML:TEXT_PLAIN, // const char *attachment1_type,
|
|
bodyString, // const char *attachment1_body,
|
|
bodyLength, // PRUint32 attachment1_body_length,
|
|
nsnull, // const struct nsMsgAttachmentData *attachments,
|
|
nsnull, // const struct nsMsgAttachedFile *preloaded_attachments,
|
|
nsnull, // nsMsgSendPart *relatedPart,
|
|
tArray); // listener array
|
|
|
|
// Cleanup converted body...
|
|
if (newBody)
|
|
PR_FREEIF(bodyString);
|
|
|
|
PR_Free(tArray);
|
|
}
|
|
else
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
else
|
|
rv = NS_ERROR_NOT_INITIALIZED;
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
/*TODO, don't close the window but just hide it, we will close it later when we receive a call back from the BE
|
|
if (nsnull != mScriptContext) {
|
|
const char* url = "";
|
|
PRBool isUndefined = PR_FALSE;
|
|
nsString rVal;
|
|
|
|
mScriptContext->EvaluateString(mScript, url, 0, rVal, &isUndefined);
|
|
CloseWindow();
|
|
}
|
|
else // If we don't have a JS callback, then close the window by default!
|
|
*/
|
|
// rhp:
|
|
// We shouldn't close the window if we are just saving a draft or a template
|
|
// so do this check
|
|
if ( (deliverMode != nsMsgSaveAsDraft) && (deliverMode != nsMsgSaveAsTemplate) )
|
|
ShowWindow(PR_FALSE);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult nsMsgCompose::SendMsg(MSG_DeliverMode deliverMode,
|
|
nsIMsgIdentity *identity,
|
|
const PRUnichar *callback)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (m_editor && m_compFields && !m_composeHTML)
|
|
{
|
|
const char contentType[] = "text/plain";
|
|
nsAutoString msgBody;
|
|
PRUnichar *bodyText = NULL;
|
|
nsAutoString format(contentType);
|
|
PRUint32 flags = nsIDocumentEncoder::OutputFormatted;
|
|
|
|
nsresult rv2;
|
|
NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv2);
|
|
if (NS_SUCCEEDED(rv2)) {
|
|
PRBool sendflowed;
|
|
rv2=prefs->GetBoolPref("mailnews.send_plaintext_flowed", &sendflowed);
|
|
if(!(NS_SUCCEEDED(rv2) && !sendflowed))
|
|
// Unless explicitly forbidden...
|
|
flags |= nsIDocumentEncoder::OutputFormatFlowed;
|
|
}
|
|
|
|
if (!mEntityConversionDone)
|
|
{
|
|
rv = m_editor->GetContentsAs(format.GetUnicode(), flags, &bodyText);
|
|
|
|
if (NS_SUCCEEDED(rv) && NULL != bodyText)
|
|
{
|
|
msgBody = bodyText;
|
|
nsAllocator::Free(bodyText);
|
|
|
|
// Convert body to mail charset not to utf-8 (because we don't manipulate body text)
|
|
char *outCString = NULL;
|
|
rv = nsMsgI18NSaveAsCharset(contentType, m_compFields->GetCharacterSet(),
|
|
msgBody.GetUnicode(), &outCString);
|
|
if (NS_SUCCEEDED(rv) && NULL != outCString)
|
|
{
|
|
mEntityConversionDone = PR_TRUE;
|
|
m_compFields->SetBody(outCString);
|
|
PR_Free(outCString);
|
|
}
|
|
else
|
|
m_compFields->SetBody(nsCAutoString(msgBody));
|
|
}
|
|
}
|
|
}
|
|
|
|
rv = _SendMsg(deliverMode, identity, callback);
|
|
if (NS_FAILED(rv))
|
|
{
|
|
ShowWindow(PR_TRUE);
|
|
if (rv != NS_ERROR_BUT_DONT_SHOW_ALERT)
|
|
nsMsgDisplayMessageByID(rv);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsMsgCompose::SendMsgEx(MSG_DeliverMode deliverMode,
|
|
nsIMsgIdentity *identity,
|
|
const PRUnichar *addrTo, const PRUnichar *addrCc,
|
|
const PRUnichar *addrBcc, const PRUnichar *newsgroup,
|
|
const PRUnichar *subject, const PRUnichar *body,
|
|
const PRUnichar *callback)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (m_compFields && identity)
|
|
{
|
|
nsAutoString aCharset(msgCompHeaderInternalCharset());
|
|
char *outCString;
|
|
|
|
// Convert fields to UTF-8
|
|
if (NS_SUCCEEDED(ConvertFromUnicode(aCharset, addrTo, &outCString)))
|
|
{
|
|
m_compFields->SetTo(outCString);
|
|
PR_Free(outCString);
|
|
}
|
|
else
|
|
m_compFields->SetTo(nsCAutoString(addrTo));
|
|
|
|
if (NS_SUCCEEDED(ConvertFromUnicode(aCharset, addrCc, &outCString)))
|
|
{
|
|
m_compFields->SetCc(outCString);
|
|
PR_Free(outCString);
|
|
}
|
|
else
|
|
m_compFields->SetCc(nsCAutoString(addrCc));
|
|
|
|
if (NS_SUCCEEDED(ConvertFromUnicode(aCharset, addrBcc, &outCString)))
|
|
{
|
|
m_compFields->SetBcc(outCString);
|
|
PR_Free(outCString);
|
|
}
|
|
else
|
|
m_compFields->SetBcc(nsCAutoString(addrBcc));
|
|
|
|
if (NS_SUCCEEDED(ConvertFromUnicode(aCharset, newsgroup, &outCString)))
|
|
{
|
|
m_compFields->SetNewsgroups(outCString);
|
|
PR_Free(outCString);
|
|
}
|
|
else
|
|
m_compFields->SetNewsgroups(nsCAutoString(newsgroup));
|
|
|
|
if (NS_SUCCEEDED(ConvertFromUnicode(aCharset, subject, &outCString)))
|
|
{
|
|
m_compFields->SetSubject(outCString);
|
|
PR_Free(outCString);
|
|
}
|
|
else
|
|
m_compFields->SetSubject(nsCAutoString(subject));
|
|
|
|
// Convert body to mail charset not to utf-8 (because we don't manipulate body text)
|
|
aCharset.SetString(m_compFields->GetCharacterSet());
|
|
if (NS_SUCCEEDED(ConvertFromUnicode(aCharset, body, &outCString)))
|
|
{
|
|
m_compFields->SetBody(outCString);
|
|
PR_Free(outCString);
|
|
}
|
|
else
|
|
m_compFields->SetBody(nsCAutoString(body));
|
|
|
|
rv = _SendMsg(deliverMode, identity, callback);
|
|
}
|
|
else
|
|
rv = NS_ERROR_NOT_INITIALIZED;
|
|
|
|
if (NS_FAILED(rv))
|
|
{
|
|
ShowWindow(PR_TRUE);
|
|
if (rv != NS_ERROR_BUT_DONT_SHOW_ALERT)
|
|
nsMsgDisplayMessageByID(rv);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
nsresult nsMsgCompose::CloseWindow()
|
|
{
|
|
if (m_webShellWin)
|
|
{
|
|
m_editor = nsnull; /* m_editor will be destroyed during the Close Window. Set it to null to */
|
|
/* be sure we wont use it anymore. */
|
|
nsIWebShellWindow *saveWin = m_webShellWin;
|
|
m_webShellWin = nsnull;
|
|
saveWin->Close();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgCompose::ShowWindow(PRBool show)
|
|
{
|
|
if (m_webShellWin)
|
|
{
|
|
m_webShellWin->Show(show);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgCompose::GetEditor(nsIEditorShell * *aEditor)
|
|
{
|
|
*aEditor = m_editor;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgCompose::SetEditor(nsIEditorShell * aEditor)
|
|
{
|
|
// First, store the editor shell.
|
|
m_editor = aEditor;
|
|
|
|
//
|
|
// Now this routine will create a listener for state changes
|
|
// in the editor and set us as the compose object of interest.
|
|
//
|
|
mDocumentListener = new nsMsgDocumentStateListener();
|
|
if (!mDocumentListener)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
mDocumentListener->SetComposeObj(this);
|
|
NS_ADDREF(mDocumentListener);
|
|
|
|
// Make sure we setup to listen for editor state changes...
|
|
m_editor->RegisterDocumentStateListener(mDocumentListener);
|
|
|
|
// Now, lets init the editor here!
|
|
// Just get a blank editor started...
|
|
m_editor->LoadUrl(nsAutoString("about:blank").GetUnicode());
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgCompose::GetDomWindow(nsIDOMWindow * *aDomWindow)
|
|
{
|
|
*aDomWindow = m_window;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult nsMsgCompose::GetCompFields(nsIMsgCompFields * *aCompFields)
|
|
{
|
|
*aCompFields = (nsIMsgCompFields*)m_compFields;
|
|
NS_IF_ADDREF(*aCompFields);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult nsMsgCompose::GetComposeHTML(PRBool *aComposeHTML)
|
|
{
|
|
*aComposeHTML = m_composeHTML;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult nsMsgCompose::GetWrapLength(PRInt32 *aWrapLength)
|
|
{
|
|
nsresult rv;
|
|
NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return prefs->GetIntPref("mailnews.wraplength", aWrapLength);
|
|
}
|
|
|
|
nsresult nsMsgCompose::CreateMessage(const PRUnichar * originalMsgURI,
|
|
MSG_ComposeType type,
|
|
MSG_ComposeFormat format,
|
|
nsIMsgCompFields * compFields)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
mType = type;
|
|
if (compFields)
|
|
{
|
|
if (m_compFields)
|
|
rv = m_compFields->Copy(compFields);
|
|
return rv;
|
|
}
|
|
|
|
/* In case of forwarding multiple messages, originalMsgURI will contains several URI separated by a comma. */
|
|
/* we need to extract only the first URI*/
|
|
nsAutoString firstURI(originalMsgURI);
|
|
PRInt32 offset = firstURI.FindChar(',');
|
|
if (offset >= 0)
|
|
firstURI.Truncate(offset);
|
|
|
|
nsCOMPtr<nsIMessage> message = getter_AddRefs(GetIMessageFromURI(firstURI.GetUnicode()));
|
|
if ((NS_SUCCEEDED(rv)) && message)
|
|
{
|
|
nsXPIDLCString subject;
|
|
nsAutoString subjectStr("");
|
|
nsAutoString aCharset("");
|
|
nsAutoString decodedString;
|
|
nsAutoString encodedCharset; // we don't use this
|
|
char *aCString = nsnull;
|
|
|
|
rv = message->GetCharSet(&aCharset);
|
|
if (NS_FAILED(rv)) return rv;
|
|
rv = message->GetSubject(getter_Copies(subject));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
switch (type)
|
|
{
|
|
default: break;
|
|
case nsIMsgCompType::Reply :
|
|
case nsIMsgCompType::ReplyAll:
|
|
{
|
|
mQuotingToFollow = PR_TRUE;
|
|
// get an original charset, used for a label, UTF-8 is used for the internal processing
|
|
if (!aCharset.Equals(""))
|
|
m_compFields->SetCharacterSet(nsCAutoString(aCharset));
|
|
|
|
subjectStr += "Re: ";
|
|
subjectStr += subject;
|
|
if (NS_SUCCEEDED(rv = nsMsgI18NDecodeMimePartIIStr(subjectStr, encodedCharset, decodedString)))
|
|
m_compFields->SetSubject(decodedString.GetUnicode());
|
|
else
|
|
m_compFields->SetSubject(subjectStr.GetUnicode());
|
|
|
|
nsXPIDLCString author;
|
|
rv = message->GetAuthor(getter_Copies(author));
|
|
if (NS_FAILED(rv)) return rv;
|
|
m_compFields->SetTo(author);
|
|
|
|
nsString authorStr(author);
|
|
if (NS_SUCCEEDED(rv = nsMsgI18NDecodeMimePartIIStr(authorStr, encodedCharset, decodedString)))
|
|
if (NS_SUCCEEDED(rv = ConvertFromUnicode(msgCompHeaderInternalCharset(), decodedString, &aCString)))
|
|
{
|
|
m_compFields->SetTo(aCString);
|
|
PR_Free(aCString);
|
|
}
|
|
|
|
if (type == nsIMsgCompType::ReplyAll)
|
|
{
|
|
nsXPIDLCString recipients;
|
|
rv = message->GetRecipients(getter_Copies(recipients));
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsAutoString recipStr(recipients);
|
|
CleanUpRecipients(recipStr);
|
|
|
|
nsXPIDLCString ccList;
|
|
rv = message->GetCcList(getter_Copies(ccList));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsAutoString ccListStr(ccList);
|
|
CleanUpRecipients(ccListStr);
|
|
if (recipStr.Length() > 0 && ccListStr.Length() > 0)
|
|
recipStr += ", ";
|
|
recipStr += ccListStr;
|
|
m_compFields->SetCc(nsCAutoString(recipStr));
|
|
|
|
if (NS_SUCCEEDED(rv = nsMsgI18NDecodeMimePartIIStr(recipStr, encodedCharset, decodedString)))
|
|
if (NS_SUCCEEDED(rv = ConvertFromUnicode(msgCompHeaderInternalCharset(), decodedString, &aCString)))
|
|
{
|
|
char * resultStr = nsnull;
|
|
nsCString addressToBeRemoved = m_compFields->GetTo();
|
|
|
|
if (m_identity)
|
|
{
|
|
nsXPIDLCString email;
|
|
m_identity->GetEmail(getter_Copies(email));
|
|
addressToBeRemoved += ", ";
|
|
addressToBeRemoved += NS_CONST_CAST(char*, (const char *)email);
|
|
}
|
|
rv= RemoveDuplicateAddresses(aCString, (char *)addressToBeRemoved, PR_TRUE, &resultStr);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
PR_Free(aCString);
|
|
aCString = resultStr;
|
|
}
|
|
|
|
m_compFields->SetCc(aCString);
|
|
PR_Free(aCString);
|
|
}
|
|
}
|
|
|
|
// Setup quoting callbacks for later...
|
|
mWhatHolder = 1;
|
|
mQuoteURI = originalMsgURI;
|
|
|
|
break;
|
|
}
|
|
case nsIMsgCompType::ForwardAsAttachment:
|
|
{
|
|
|
|
if (!aCharset.Equals(""))
|
|
m_compFields->SetCharacterSet(nsCAutoString(aCharset));
|
|
|
|
subjectStr += "[Fwd: ";
|
|
subjectStr += subject;
|
|
subjectStr += "]";
|
|
|
|
if (NS_SUCCEEDED(rv = nsMsgI18NDecodeMimePartIIStr(subjectStr, encodedCharset, decodedString)))
|
|
m_compFields->SetSubject(decodedString.GetUnicode());
|
|
else
|
|
m_compFields->SetSubject(subjectStr.GetUnicode());
|
|
|
|
// Setup quoting callbacks for later...
|
|
mQuotingToFollow = PR_FALSE; //We don't need to quote the original message.
|
|
m_compFields->SetAttachments(originalMsgURI);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// THIS IS THE CLASS THAT IS THE STREAM CONSUMER OF THE HTML OUPUT
|
|
// FROM LIBMIME. THIS IS FOR QUOTING
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
QuotingOutputStreamListener::~QuotingOutputStreamListener()
|
|
{
|
|
if (mComposeObj)
|
|
NS_RELEASE(mComposeObj);
|
|
}
|
|
|
|
QuotingOutputStreamListener::QuotingOutputStreamListener(const PRUnichar * originalMsgURI,
|
|
PRBool quoteHeaders,
|
|
nsIMsgIdentity *identity)
|
|
{
|
|
mComposeObj = nsnull;
|
|
mQuoteHeaders = quoteHeaders;
|
|
mIdentity = identity;
|
|
|
|
// For the built message body...
|
|
mMsgBody = "";
|
|
mCitePrefix = "";
|
|
mSignature = "";
|
|
|
|
nsCOMPtr<nsIMessage> originalMsg = getter_AddRefs(GetIMessageFromURI(originalMsgURI));
|
|
if (originalMsg && !quoteHeaders)
|
|
{
|
|
nsresult rv;
|
|
nsAutoString author;
|
|
rv = originalMsg->GetMime2DecodedAuthor(&author);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
char * authorName = nsnull;
|
|
nsCOMPtr<nsIMsgHeaderParser> parser = do_GetService(kHeaderParserCID);
|
|
|
|
if (parser)
|
|
{
|
|
nsAutoString aCharset(msgCompHeaderInternalCharset());
|
|
char * utf8Author = nsnull;
|
|
rv = ConvertFromUnicode(aCharset, author, &utf8Author);
|
|
if (NS_SUCCEEDED(rv) && utf8Author)
|
|
{
|
|
rv = parser->ExtractHeaderAddressName(nsCAutoString(aCharset), utf8Author, &authorName);
|
|
if (NS_SUCCEEDED(rv))
|
|
rv = ConvertToUnicode(aCharset, authorName, author);
|
|
}
|
|
|
|
if (!utf8Author || NS_FAILED(rv))
|
|
{
|
|
rv = parser->ExtractHeaderAddressName(nsnull, nsCAutoString(author), &authorName);
|
|
if (NS_SUCCEEDED(rv))
|
|
author = authorName;
|
|
}
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
if (GetReplyOnTop() == 1)
|
|
mCitePrefix.Append("<br><br>");
|
|
|
|
mCitePrefix.Append(author);
|
|
mCitePrefix.Append(" wrote:<br><html>");
|
|
}
|
|
if (authorName)
|
|
PL_strfree(authorName);
|
|
PR_FREEIF(utf8Author);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mCitePrefix.IsEmpty())
|
|
mCitePrefix.Append("<br><br>--- Original Message ---<br><html>");
|
|
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsresult
|
|
QuotingOutputStreamListener::ConvertToPlainText()
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
rv += ConvertBufToPlainText(mCitePrefix);
|
|
rv += ConvertBufToPlainText(mMsgBody);
|
|
rv += ConvertBufToPlainText(mSignature);
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP QuotingOutputStreamListener::OnStartRequest(nsIChannel * /* aChannel */, nsISupports * /* ctxt */)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP QuotingOutputStreamListener::OnStopRequest(nsIChannel *aChannel, nsISupports * /* ctxt */, nsresult status, const PRUnichar * /* errorMsg */)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mComposeObj)
|
|
{
|
|
MSG_ComposeType type = mComposeObj->GetMessageType();
|
|
|
|
if (mHeaders && (type == nsIMsgCompType::Reply || type == nsIMsgCompType::ReplyAll))
|
|
{
|
|
nsIMsgCompFields *compFields = nsnull;
|
|
mComposeObj->GetCompFields(&compFields); //GetCompFields will addref, you need to release when your are done with it
|
|
if (compFields)
|
|
{
|
|
nsAutoString aCharset(msgCompHeaderInternalCharset());
|
|
nsAutoString replyTo;
|
|
nsAutoString newgroups;
|
|
nsAutoString followUpTo;
|
|
nsAutoString messageId;
|
|
nsAutoString references;
|
|
char *outCString = nsnull;
|
|
PRUnichar emptyUnichar = 0;
|
|
PRBool toChanged = PR_FALSE;
|
|
|
|
mHeaders->ExtractHeader(HEADER_REPLY_TO, PR_FALSE, &outCString);
|
|
if (outCString)
|
|
{
|
|
// Convert fields to UTF-8
|
|
ConvertToUnicode(aCharset, outCString, replyTo);
|
|
PR_FREEIF(outCString);
|
|
}
|
|
|
|
mHeaders->ExtractHeader(HEADER_NEWSGROUPS, PR_FALSE, &outCString);
|
|
if (outCString)
|
|
{
|
|
// Convert fields to UTF-8
|
|
ConvertToUnicode(aCharset, outCString, newgroups);
|
|
PR_FREEIF(outCString);
|
|
}
|
|
|
|
mHeaders->ExtractHeader(HEADER_FOLLOWUP_TO, PR_FALSE, &outCString);
|
|
if (outCString)
|
|
{
|
|
// Convert fields to UTF-8
|
|
ConvertToUnicode(aCharset, outCString, followUpTo);
|
|
PR_FREEIF(outCString);
|
|
}
|
|
|
|
mHeaders->ExtractHeader(HEADER_MESSAGE_ID, PR_FALSE, &outCString);
|
|
if (outCString)
|
|
{
|
|
// Convert fields to UTF-8
|
|
ConvertToUnicode(aCharset, outCString, messageId);
|
|
PR_FREEIF(outCString);
|
|
}
|
|
|
|
mHeaders->ExtractHeader(HEADER_REFERENCES, PR_FALSE, &outCString);
|
|
if (outCString)
|
|
{
|
|
// Convert fields to UTF-8
|
|
ConvertToUnicode(aCharset, outCString, references);
|
|
PR_FREEIF(outCString);
|
|
}
|
|
|
|
if (! replyTo.IsEmpty())
|
|
{
|
|
compFields->SetTo(replyTo.GetUnicode());
|
|
toChanged = PR_TRUE;
|
|
}
|
|
|
|
if (! newgroups.IsEmpty())
|
|
{
|
|
compFields->SetNewsgroups(newgroups.GetUnicode());
|
|
if (type == nsIMsgCompType::Reply)
|
|
compFields->SetTo(&emptyUnichar);
|
|
}
|
|
|
|
if (! followUpTo.IsEmpty())
|
|
{
|
|
compFields->SetNewsgroups(followUpTo.GetUnicode());
|
|
if (type == nsIMsgCompType::Reply)
|
|
compFields->SetTo(&emptyUnichar);
|
|
}
|
|
|
|
if (! references.IsEmpty())
|
|
references += ' ';
|
|
references += messageId;
|
|
compFields->SetReferences(references.GetUnicode());
|
|
|
|
if (toChanged)
|
|
{
|
|
//Remove duplicate addresses between TO && CC
|
|
char * resultStr;
|
|
nsMsgCompFields* _compFields = (nsMsgCompFields*)compFields;
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
rv= RemoveDuplicateAddresses(_compFields->GetCc(), _compFields->GetTo(), PR_FALSE, &resultStr);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
_compFields->SetCc(resultStr);
|
|
PR_Free(resultStr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ok, if we are here, we need to see if a charset was tagged
|
|
// on this channel. If there WAS, then this charset needs to
|
|
// override the default charset that is set in compFields. This
|
|
// is the case where you are replying to a message that has a
|
|
// non US-ASCII charset. You are supposed to reply in that charset.
|
|
//
|
|
char *contentType = nsnull;
|
|
if (NS_SUCCEEDED(aChannel->GetContentType(&contentType)) && contentType)
|
|
{
|
|
char *workContentType = nsCRT::strdup(contentType);
|
|
if (workContentType)
|
|
{
|
|
char *ptr = PL_strstr(workContentType, "charset=");
|
|
if (ptr)
|
|
{
|
|
ptr += nsCRT::strlen("charset=");
|
|
if (*ptr == '"')
|
|
ptr++;
|
|
|
|
char *ptr2 = ptr;
|
|
while (*ptr2)
|
|
{
|
|
if ( (*ptr2 == ' ') || (*ptr2 == ';') || (*ptr2 == '"'))
|
|
{
|
|
*ptr2 = '\0';
|
|
break;
|
|
}
|
|
|
|
++ptr2;
|
|
}
|
|
|
|
compFields->SetCharacterSet(nsString(ptr).GetUnicode());
|
|
}
|
|
|
|
PR_FREEIF(workContentType);
|
|
}
|
|
|
|
PR_FREEIF(contentType);
|
|
}
|
|
|
|
NS_RELEASE(compFields);
|
|
}
|
|
}
|
|
|
|
mMsgBody += "</html>";
|
|
|
|
// Now we have an HTML representation of the quoted message.
|
|
// If we are in plain text mode, we need to convert this to plain
|
|
// text before we try to insert it into the editor. If we don't, we
|
|
// just get lots of HTML text in the message...not good.
|
|
//
|
|
PRBool composeHTML = PR_TRUE;
|
|
mComposeObj->GetComposeHTML(&composeHTML);
|
|
if (!composeHTML)
|
|
ConvertToPlainText();
|
|
|
|
//
|
|
// Ok, now we have finished quoting so we should load this into the editor
|
|
// window.
|
|
//
|
|
PRBool compHTML = PR_FALSE;
|
|
mComposeObj->GetComposeHTML(&compHTML);
|
|
|
|
mComposeObj->ProcessSignature(mIdentity, &mSignature);
|
|
|
|
nsIEditorShell *editor = nsnull;
|
|
if (NS_SUCCEEDED(mComposeObj->GetEditor(&editor)) && editor)
|
|
{
|
|
mComposeObj->ConvertAndLoadComposeWindow(editor, mCitePrefix, mMsgBody, mSignature, PR_TRUE, compHTML);
|
|
}
|
|
}
|
|
|
|
NS_IF_RELEASE(mComposeObj); //We are done with it, therefore release it.
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP QuotingOutputStreamListener::OnDataAvailable(nsIChannel * /* aChannel */,
|
|
nsISupports *ctxt, nsIInputStream *inStr,
|
|
PRUint32 sourceOffset, PRUint32 count)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
if (!inStr)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
char *newBuf = (char *)PR_Malloc(count + 1);
|
|
if (!newBuf)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
PRUint32 numWritten = 0;
|
|
rv = inStr->Read(newBuf, count, &numWritten);
|
|
if (rv == NS_BASE_STREAM_WOULD_BLOCK)
|
|
rv = NS_OK;
|
|
newBuf[numWritten] = '\0';
|
|
if (NS_SUCCEEDED(rv) && numWritten > 0)
|
|
{
|
|
PRUnichar *u = nsnull;
|
|
nsAutoString fmt("%s");
|
|
|
|
u = nsTextFormatter::smprintf(fmt.GetUnicode(), newBuf); // this converts UTF-8 to UCS-2
|
|
if (u)
|
|
{
|
|
PRInt32 newLen = nsCRT::strlen(u);
|
|
mMsgBody.Append(u, newLen);
|
|
PR_FREEIF(u);
|
|
}
|
|
else
|
|
mMsgBody.Append(newBuf, numWritten);
|
|
}
|
|
|
|
PR_FREEIF(newBuf);
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
QuotingOutputStreamListener::SetComposeObj(nsMsgCompose *obj)
|
|
{
|
|
mComposeObj = obj;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
QuotingOutputStreamListener::SetMimeHeaders(nsIMimeHeaders * headers)
|
|
{
|
|
mHeaders = headers;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(QuotingOutputStreamListener, NS_GET_IID(nsIStreamListener));
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// END OF QUOTING LISTENER
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
MSG_ComposeType nsMsgCompose::GetMessageType()
|
|
{
|
|
return mType;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgCompose::QuoteOriginalMessage(const PRUnichar *originalMsgURI, PRInt32 what) // New template
|
|
{
|
|
nsresult rv;
|
|
|
|
mQuotingToFollow = PR_FALSE;
|
|
|
|
nsAutoString tmpURI(originalMsgURI);
|
|
|
|
// Create a mime parser (nsIStreamConverter)!
|
|
rv = nsComponentManager::CreateInstance(kMsgQuoteCID,
|
|
NULL, NS_GET_IID(nsIMsgQuote),
|
|
(void **) getter_AddRefs(mQuote));
|
|
if (NS_FAILED(rv) || !mQuote)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// Create the consumer output stream.. this will receive all the HTML from libmime
|
|
mQuoteStreamListener =
|
|
new QuotingOutputStreamListener(originalMsgURI, what != 1, m_identity);
|
|
|
|
if (!mQuoteStreamListener)
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("Failed to create mQuoteStreamListener\n");
|
|
#endif
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
NS_ADDREF(mQuoteStreamListener);
|
|
|
|
NS_ADDREF(this);
|
|
mQuoteStreamListener->SetComposeObj(this);
|
|
|
|
rv = mQuote->QuoteMessage(originalMsgURI, what != 1, mQuoteStreamListener);
|
|
return rv;
|
|
}
|
|
|
|
//CleanUpRecipient will remove un-necesary "<>" when a recipient as an address without name
|
|
void nsMsgCompose::CleanUpRecipients(nsString& recipients)
|
|
{
|
|
// TODO...
|
|
PRInt16 i;
|
|
PRBool startANewRecipient = PR_TRUE;
|
|
PRBool removeBracket = PR_FALSE;
|
|
nsAutoString newRecipient;
|
|
PRUnichar aChar;
|
|
|
|
for (i = 0; i < recipients.Length(); i ++)
|
|
{
|
|
aChar = recipients[i];
|
|
switch (aChar)
|
|
{
|
|
case '<' :
|
|
if (startANewRecipient)
|
|
removeBracket = PR_TRUE;
|
|
else
|
|
newRecipient += aChar;
|
|
startANewRecipient = PR_FALSE;
|
|
break;
|
|
|
|
case '>' :
|
|
if (removeBracket)
|
|
removeBracket = PR_FALSE;
|
|
else
|
|
newRecipient += aChar;
|
|
break;
|
|
|
|
case ' ' :
|
|
newRecipient += aChar;
|
|
break;
|
|
|
|
case ',' :
|
|
newRecipient += aChar;
|
|
startANewRecipient = PR_TRUE;
|
|
removeBracket = PR_FALSE;
|
|
break;
|
|
|
|
default :
|
|
newRecipient += aChar;
|
|
startANewRecipient = PR_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
recipients = newRecipient;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is the listener class for both the send operation and the copy operation.
|
|
// We have to create this class to listen for message send completion and deal with
|
|
// failures in both send and copy operations
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
NS_IMPL_ADDREF(nsMsgComposeSendListener)
|
|
NS_IMPL_RELEASE(nsMsgComposeSendListener)
|
|
|
|
nsIMsgSendListener ** nsMsgComposeSendListener::CreateListenerArray()
|
|
{
|
|
nsIMsgSendListener **tArray = (nsIMsgSendListener **)PR_Malloc(sizeof(nsIMsgSendListener *) * 2);
|
|
if (!tArray)
|
|
return nsnull;
|
|
nsCRT::memset(tArray, 0, sizeof(nsIMsgSendListener *) * 2);
|
|
tArray[0] = this;
|
|
return tArray;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMsgComposeSendListener::QueryInterface(const nsIID &aIID, void** aInstancePtr)
|
|
{
|
|
if (NULL == aInstancePtr)
|
|
return NS_ERROR_NULL_POINTER;
|
|
*aInstancePtr = NULL;
|
|
|
|
if (aIID.Equals(NS_GET_IID(nsIMsgSendListener)))
|
|
{
|
|
*aInstancePtr = (nsIMsgSendListener *) this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(NS_GET_IID(nsIMsgCopyServiceListener)))
|
|
{
|
|
*aInstancePtr = (nsIMsgCopyServiceListener *) this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
nsMsgComposeSendListener::nsMsgComposeSendListener(void)
|
|
{
|
|
mComposeObj = nsnull;
|
|
mDeliverMode = 0;
|
|
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsMsgComposeSendListener::~nsMsgComposeSendListener(void)
|
|
{
|
|
}
|
|
|
|
nsresult nsMsgComposeSendListener::SetComposeObj(nsMsgCompose *obj)
|
|
{
|
|
mComposeObj = obj;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgComposeSendListener::SetDeliverMode(MSG_DeliverMode deliverMode)
|
|
{
|
|
mDeliverMode = deliverMode;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgComposeSendListener::OnStartSending(const char *aMsgID, PRUint32 aMsgSize)
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("nsMsgComposeSendListener::OnStartSending()\n");
|
|
#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgComposeSendListener::OnProgress(const char *aMsgID, PRUint32 aProgress, PRUint32 aProgressMax)
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("nsMsgComposeSendListener::OnProgress()\n");
|
|
#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgComposeSendListener::OnStatus(const char *aMsgID, const PRUnichar *aMsg)
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("nsMsgComposeSendListener::OnStatus()\n");
|
|
#endif
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgComposeSendListener::OnStopSending(const char *aMsgID, nsresult aStatus, const PRUnichar *aMsg,
|
|
nsIFileSpec *returnFileSpec)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mComposeObj)
|
|
{
|
|
if (NS_SUCCEEDED(aStatus))
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("nsMsgComposeSendListener: Success on the message send operation!\n");
|
|
#endif
|
|
nsIMsgCompFields *compFields = nsnull;
|
|
mComposeObj->GetCompFields(&compFields); //GetCompFields will addref, you need to release when your are done with it
|
|
|
|
// Close the window ONLY if we are not going to do a save operation
|
|
PRUnichar *fieldsFCC = nsnull;
|
|
if (NS_SUCCEEDED(compFields->GetFcc(&fieldsFCC)))
|
|
{
|
|
if (fieldsFCC && *fieldsFCC)
|
|
{
|
|
if (nsCRT::strcasecmp(fieldsFCC, "nocopy://") == 0)
|
|
mComposeObj->CloseWindow();
|
|
}
|
|
}
|
|
else
|
|
mComposeObj->CloseWindow(); // if we fail on the simple GetFcc call, close the window to be safe and avoid
|
|
// windows hanging around to prevent the app from exiting.
|
|
|
|
NS_IF_RELEASE(compFields);
|
|
}
|
|
else
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("nsMsgComposeSendListener: the message send operation failed!\n");
|
|
#endif
|
|
mComposeObj->ShowWindow(PR_TRUE);
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgComposeSendListener::OnStartCopy()
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("nsMsgComposeSendListener::OnStartCopy()\n");
|
|
#endif
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgComposeSendListener::OnProgress(PRUint32 aProgress, PRUint32 aProgressMax)
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("nsMsgComposeSendListener::OnProgress() - COPY\n");
|
|
#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgComposeSendListener::OnStopCopy(nsresult aStatus)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mComposeObj)
|
|
{
|
|
// Ok, if we are here, we are done with the send/copy operation so
|
|
// we have to do something with the window....SHOW if failed, Close
|
|
// if succeeded
|
|
if (NS_SUCCEEDED(aStatus))
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("nsMsgComposeSendListener: Success on the message copy operation!\n");
|
|
#endif
|
|
// We should only close the window if we are done. Things like templates
|
|
// and drafts aren't done so their windows should stay open
|
|
if ( (mDeliverMode != nsMsgSaveAsDraft) && (mDeliverMode != nsMsgSaveAsTemplate) )
|
|
mComposeObj->CloseWindow();
|
|
}
|
|
else
|
|
{
|
|
#ifdef NS_DEBUG
|
|
printf("nsMsgComposeSendListener: the message copy operation failed!\n");
|
|
#endif
|
|
mComposeObj->ShowWindow(PR_TRUE);
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgComposeSendListener::SetMessageKey(PRUint32 aMessageKey)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgComposeSendListener::GetMessageId(nsCString* aMessageId)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is a class that will allow us to listen to state changes in the Ender
|
|
// compose window. This is important since we must wait until we are told Ender
|
|
// is ready before we do various quoting operations
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
NS_IMPL_ISUPPORTS(nsMsgDocumentStateListener, NS_GET_IID(nsIDocumentStateListener));
|
|
|
|
nsMsgDocumentStateListener::nsMsgDocumentStateListener(void)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mComposeObj = nsnull;
|
|
}
|
|
|
|
nsMsgDocumentStateListener::~nsMsgDocumentStateListener(void)
|
|
{
|
|
}
|
|
|
|
void
|
|
nsMsgDocumentStateListener::SetComposeObj(nsMsgCompose *obj)
|
|
{
|
|
mComposeObj = obj;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgDocumentStateListener::NotifyDocumentCreated(void)
|
|
{
|
|
// Ok, now the document has been loaded, so we are ready to setup
|
|
// the compose window and let the user run hog wild!
|
|
|
|
// Now, do the appropriate startup operation...signature only
|
|
// or quoted message and signature...
|
|
if ( mComposeObj->QuotingToFollow() )
|
|
return mComposeObj->BuildQuotedMessageAndSignature();
|
|
else
|
|
return mComposeObj->BuildBodyMessageAndSignature();
|
|
}
|
|
|
|
nsresult
|
|
nsMsgDocumentStateListener::NotifyDocumentWillBeDestroyed(void)
|
|
{
|
|
if (mComposeObj)
|
|
mComposeObj->m_editor = nsnull; /* m_editor will be destroyed. Set it to null to */
|
|
/* be sure we wont use it anymore. */
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgDocumentStateListener::NotifyDocumentStateChanged(PRBool nowDirty)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgCompose::ConvertHTMLToText(nsFileSpec& aSigFile, nsString &aSigData)
|
|
{
|
|
nsresult rv;
|
|
nsAutoString origBuf;
|
|
|
|
rv = LoadDataFromFile(aSigFile, origBuf);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
ConvertBufToPlainText(origBuf);
|
|
aSigData = origBuf;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgCompose::ConvertTextToHTML(nsFileSpec& aSigFile, nsString &aSigData)
|
|
{
|
|
nsresult rv;
|
|
nsAutoString origBuf;
|
|
|
|
rv = LoadDataFromFile(aSigFile, origBuf);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
aSigData.Append(origBuf);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgCompose::LoadDataFromFile(nsFileSpec& fSpec, nsString &sigData)
|
|
{
|
|
PRInt32 readSize;
|
|
char *readBuf;
|
|
|
|
nsInputFileStream tempFile(fSpec);
|
|
if (!tempFile.is_open())
|
|
return NS_MSG_ERROR_WRITING_FILE;
|
|
|
|
readSize = fSpec.GetFileSize();
|
|
readBuf = (char *)PR_Malloc(readSize + 1);
|
|
if (!readBuf)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
nsCRT::memset(readBuf, 0, readSize + 1);
|
|
|
|
readSize = tempFile.read(readBuf, readSize);
|
|
tempFile.close();
|
|
|
|
sigData = readBuf;
|
|
PR_FREEIF(readBuf);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgCompose::BuildQuotedMessageAndSignature(void)
|
|
{
|
|
//
|
|
// This should never happen...if it does, just bail out...
|
|
//
|
|
if (!m_editor)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// We will fire off the quote operation and wait for it to
|
|
// finish before we actually do anything with Ender...
|
|
return QuoteOriginalMessage(mQuoteURI.GetUnicode(), mWhatHolder);
|
|
}
|
|
|
|
//
|
|
// This will process the signature file for the user. This method
|
|
// will always append the results to the mMsgBody member variable.
|
|
//
|
|
nsresult
|
|
nsMsgCompose::ProcessSignature(nsIMsgIdentity *identity, nsString *aMsgBody)
|
|
{
|
|
nsresult rv;
|
|
|
|
// 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(".....signature_file", "y:\\sig.html");
|
|
// user_pref(".....use_signature_file", true);
|
|
//
|
|
// 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
|
|
//
|
|
nsAutoString urlStr;
|
|
nsCOMPtr<nsIFileSpec> sigFileSpec;
|
|
PRBool useSigFile = PR_FALSE;
|
|
PRBool htmlSig = PR_FALSE;
|
|
nsAutoString sigData = "";
|
|
|
|
if (identity)
|
|
{
|
|
rv = identity->GetAttachSignature(&useSigFile);
|
|
if (NS_SUCCEEDED(rv) && useSigFile)
|
|
{
|
|
identity->GetSignature(getter_AddRefs(sigFileSpec));
|
|
}
|
|
}
|
|
|
|
// Now, if they didn't even want to use a signature, we should
|
|
// just return nicely.
|
|
//
|
|
if ((!useSigFile) || (!sigFileSpec))
|
|
return NS_OK;
|
|
|
|
nsFileSpec testSpec;
|
|
sigFileSpec->GetFileSpec(&testSpec);
|
|
|
|
// If this file doesn't really exist, just bail!
|
|
if (!testSpec.Exists())
|
|
return NS_OK;
|
|
|
|
// Once we get here, we need to figure out if we have the correct file
|
|
// type for the editor.
|
|
//
|
|
nsFileURL sigFilePath(testSpec);
|
|
char *fileExt = nsMsgGetExtensionFromFileURL(nsAutoString(sigFilePath));
|
|
|
|
if ( (fileExt) && (*fileExt) )
|
|
{
|
|
htmlSig = ( (!PL_strcasecmp(fileExt, "HTM")) || (!PL_strcasecmp(fileExt, "HTML")) );
|
|
PR_FREEIF(fileExt);
|
|
}
|
|
|
|
// is this a text sig with an HTML editor?
|
|
if ( (m_composeHTML) && (!htmlSig) )
|
|
ConvertTextToHTML(testSpec, sigData);
|
|
// is this a HTML sig with a text window?
|
|
else if ( (!m_composeHTML) && (htmlSig) )
|
|
ConvertHTMLToText(testSpec, sigData);
|
|
else // We have a match...
|
|
LoadDataFromFile(testSpec, sigData); // Get the data!
|
|
|
|
// Now that sigData holds data...if any, append it to the body in a nice
|
|
// looking manner
|
|
//
|
|
char *htmlBreak = "<BR>";
|
|
char *dashes = "--";
|
|
if (sigData != "")
|
|
{
|
|
if (m_composeHTML)
|
|
{
|
|
aMsgBody->Append(htmlBreak);
|
|
if (!htmlSig)
|
|
{
|
|
aMsgBody->Append("<pre>");
|
|
aMsgBody->Append(CRLF);
|
|
}
|
|
}
|
|
else
|
|
aMsgBody->Append(CRLF);
|
|
|
|
aMsgBody->Append(dashes);
|
|
|
|
if ( (!m_composeHTML) || ((m_composeHTML) && (!htmlSig)) )
|
|
aMsgBody->Append(CRLF);
|
|
else if (m_composeHTML)
|
|
aMsgBody->Append(htmlBreak);
|
|
|
|
aMsgBody->Append(sigData);
|
|
|
|
if ( (m_composeHTML) && (!htmlSig) )
|
|
aMsgBody->Append("</pre>");
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMsgCompose::BuildBodyMessageAndSignature()
|
|
{
|
|
PRUnichar *bod = nsnull;
|
|
nsresult rv;
|
|
|
|
//
|
|
// This should never happen...if it does, just bail out...
|
|
//
|
|
if (!m_editor)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
//
|
|
// Now, we have the body so we can just blast it into the
|
|
// composition editor window.
|
|
//
|
|
m_compFields->GetBody(&bod);
|
|
|
|
nsAutoString tSignature = "";
|
|
/* Some time we want to add a signature and sometime we wont. Let's figure that now...*/
|
|
PRBool addSignature;
|
|
switch (mType)
|
|
{
|
|
case nsIMsgCompType::New :
|
|
case nsIMsgCompType::Reply : /* should not append! but just in case */
|
|
case nsIMsgCompType::ReplyAll : /* should not append! but just in case */
|
|
case nsIMsgCompType::ForwardAsAttachment : /* should not append! but just in case */
|
|
case nsIMsgCompType::ForwardInline :
|
|
case nsIMsgCompType::NewsPost :
|
|
addSignature = PR_TRUE;
|
|
break;
|
|
|
|
case nsIMsgCompType::Draft :
|
|
case nsIMsgCompType::Template :
|
|
addSignature = PR_FALSE;
|
|
break;
|
|
|
|
case nsIMsgCompType::MailToUrl :
|
|
addSignature = !(bod && *bod != 0);
|
|
break;
|
|
|
|
default :
|
|
addSignature = PR_FALSE;
|
|
break;
|
|
}
|
|
if (addSignature)
|
|
ProcessSignature(m_identity, &tSignature);
|
|
if (m_editor)
|
|
{
|
|
if (bod)
|
|
rv = ConvertAndLoadComposeWindow(m_editor, "", bod, tSignature, PR_FALSE, m_composeHTML);
|
|
else
|
|
rv = ConvertAndLoadComposeWindow(m_editor, "", "", tSignature, PR_FALSE, m_composeHTML);
|
|
}
|
|
|
|
PR_FREEIF(bod);
|
|
return rv;
|
|
}
|
|
|
|
nsresult nsMsgCompose::NotifyStateListeners(TStateListenerNotification aNotificationType)
|
|
{
|
|
if (!mStateListeners)
|
|
return NS_OK; // maybe there just aren't any.
|
|
|
|
PRUint32 numListeners;
|
|
nsresult rv = mStateListeners->Count(&numListeners);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
PRUint32 i;
|
|
switch (aNotificationType)
|
|
{
|
|
case eComposeFieldsReady:
|
|
for (i = 0; i < numListeners;i++)
|
|
{
|
|
nsCOMPtr<nsISupports> iSupports = getter_AddRefs(mStateListeners->ElementAt(i));
|
|
nsCOMPtr<nsIMsgComposeStateListener> thisListener = do_QueryInterface(iSupports);
|
|
if (thisListener)
|
|
{
|
|
rv = thisListener->NotifyComposeFieldsReady();
|
|
if (NS_FAILED(rv))
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
NS_NOTREACHED("Unknown notification");
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult nsMsgCompose::AttachmentPrettyName(const PRUnichar* url, PRUnichar** _retval)
|
|
{
|
|
nsCAutoString unescapeULR = url;
|
|
nsUnescape(unescapeULR);
|
|
if (unescapeULR.IsEmpty())
|
|
{
|
|
*_retval = nsCRT::strdup(url);
|
|
return NS_OK;
|
|
}
|
|
|
|
if (PL_strncasestr(unescapeULR, "file:", 5))
|
|
{
|
|
nsFileURL fileUrl(url);
|
|
nsFileSpec fileSpec(fileUrl);
|
|
char * leafName = fileSpec.GetLeafName();
|
|
if (leafName && *leafName)
|
|
{
|
|
nsAutoString tempStr;
|
|
nsresult rv = ConvertToUnicode(msgCompFileSystemCharset(), leafName, tempStr);
|
|
if (NS_FAILED(rv))
|
|
tempStr = leafName;
|
|
*_retval = tempStr.ToNewUnicode();
|
|
nsCRT::free(leafName);
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
if (PL_strncasestr(unescapeULR, "http:", 5))
|
|
{
|
|
nsAutoString tempStr = &unescapeULR.mBuffer[7];
|
|
*_retval = tempStr.ToNewUnicode();
|
|
return NS_OK;
|
|
}
|
|
|
|
*_retval = nsCRT::strdup(url);
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult OpenAddressBook(const char * dbName, nsIAddrDatabase** aDatabase, nsIAbDirectory** aDirectory)
|
|
{
|
|
if (!aDatabase || !aDirectory)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult rv = NS_OK;
|
|
nsFileSpec* dbPath = nsnull;
|
|
|
|
NS_WITH_SERVICE(nsIAddrBookSession, abSession, kAddrBookSessionCID, &rv);
|
|
if(NS_SUCCEEDED(rv))
|
|
abSession->GetUserProfileDirectory(&dbPath);
|
|
|
|
if (dbPath)
|
|
{
|
|
(*dbPath) += dbName;
|
|
|
|
NS_WITH_SERVICE(nsIAddrDatabase, addrDBFactory, kAddressBookDBCID, &rv);
|
|
|
|
if (NS_SUCCEEDED(rv) && addrDBFactory)
|
|
rv = addrDBFactory->Open(dbPath, PR_TRUE, aDatabase, PR_TRUE);
|
|
}
|
|
NS_WITH_SERVICE(nsIRDFService, rdfService, kRDFServiceCID, &rv);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
nsCOMPtr <nsIRDFResource> resource;
|
|
nsCAutoString path("abdirectory://");
|
|
path += dbName;
|
|
rv = rdfService->GetResource(path, getter_AddRefs(resource));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
// query interface
|
|
rv = resource->QueryInterface(nsIAbDirectory::GetIID(), (void **)aDirectory);
|
|
return rv;
|
|
}
|
|
|
|
nsresult nsMsgCompose::GetNoHtmlRecipients(const PRUnichar *recipients, PRUnichar **_retval)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
*_retval = nsnull;
|
|
PRInt32 j;
|
|
PRInt32 i;
|
|
PRInt32 nbrRecipients;
|
|
nsXPIDLString emailAddr;
|
|
|
|
nsAutoString recipientStr;
|
|
if (recipients != nsnull)
|
|
recipientStr = recipients;
|
|
else
|
|
{
|
|
recipientStr += m_compFields->GetTo();
|
|
recipientStr += ',';
|
|
recipientStr += m_compFields->GetCc();
|
|
recipientStr += ',';
|
|
recipientStr += m_compFields->GetBcc();
|
|
}
|
|
|
|
/*ducarroz: for now, I've hardcoded the addressbook DBs we are looking in it, will do much better later! */
|
|
PRInt32 nbrOfAddrbook = 2;
|
|
const char addrbookName[2][20] = {"abook.mab", "history.mab"};
|
|
|
|
nsCOMPtr<nsIMsgRecipientArray> array;
|
|
nsCOMPtr<nsIMsgRecipientArray> noHTMLArray;
|
|
rv = nsComponentManager::CreateInstance(kMsgRecipientArrayCID,
|
|
NULL, NS_GET_IID(nsIMsgRecipientArray),
|
|
(void **) getter_AddRefs(noHTMLArray));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
rv = m_compFields->SplitRecipients(recipientStr.GetUnicode(), PR_TRUE, getter_AddRefs(array));
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
nsCOMPtr<nsIAddrDatabase> abDataBase;
|
|
nsCOMPtr<nsIAbDirectory> abDirectory;
|
|
nsCOMPtr <nsIAbCard> existingCard;
|
|
|
|
for (j = 0; j < nbrOfAddrbook; j++)
|
|
{
|
|
array->GetCount(&nbrRecipients);
|
|
if (nbrRecipients == 0)
|
|
break;
|
|
|
|
rv = OpenAddressBook(addrbookName[j], getter_AddRefs(abDataBase), getter_AddRefs(abDirectory));
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
|
|
for (i = 0; i < nbrRecipients; i ++)
|
|
{
|
|
rv = array->StringAt(i, getter_Copies(emailAddr));
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
nsCAutoString emailStr(emailAddr);
|
|
|
|
rv = abDataBase->GetCardForEmailAddress(abDirectory, emailStr, getter_AddRefs(existingCard));
|
|
if (NS_SUCCEEDED(rv) && existingCard)
|
|
{
|
|
PRBool bPlainText;
|
|
rv = existingCard->GetSendPlainText(&bPlainText);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
PRBool aBool;
|
|
if (bPlainText)
|
|
{
|
|
//this guy doesn't want/support HTML message, move it in the noHTML array.
|
|
noHTMLArray->AppendString(emailAddr, &aBool);
|
|
}
|
|
array->RemoveStringAt(i, &aBool);
|
|
if (aBool)
|
|
{
|
|
nbrRecipients --;
|
|
i --;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (abDataBase)
|
|
abDataBase->Close(PR_FALSE);
|
|
}
|
|
}
|
|
|
|
//now, build the result
|
|
recipientStr = "";
|
|
noHTMLArray->GetCount(&nbrRecipients);
|
|
for (i = 0; i < nbrRecipients; i ++)
|
|
{
|
|
if (! recipientStr.IsEmpty())
|
|
recipientStr += ',';
|
|
noHTMLArray->StringAt(i, getter_Copies(emailAddr));
|
|
recipientStr += emailAddr;
|
|
}
|
|
//Remaining recipients which do not have an entry in the AB are considered as non HTML compliant
|
|
array->GetCount(&nbrRecipients);
|
|
for (i = 0; i < nbrRecipients; i ++)
|
|
{
|
|
if (! recipientStr.IsEmpty())
|
|
recipientStr += ',';
|
|
array->StringAt(i, getter_Copies(emailAddr));
|
|
recipientStr += emailAddr;
|
|
}
|
|
*_retval = recipientStr.ToNewUnicode();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgCompose::GetNoHtmlNewsgroups(const PRUnichar *newsgroups, PRUnichar **_retval)
|
|
{
|
|
//FIX ME: write me
|
|
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
|
|
*_retval = nsnull;
|
|
return rv;
|
|
}
|