Bug 199809 Memory leak in notification handler in nsMsgSendLater. r=Neil,sr=bienvenu
This commit is contained in:
Родитель
648628a054
Коммит
9fa201cbe4
|
@ -88,9 +88,6 @@ nsMsgSendLater::nsMsgSendLater()
|
|||
mMessage = nsnull;
|
||||
mLeftoverBuffer = nsnull;
|
||||
|
||||
mListenerArray = nsnull;
|
||||
mListenerArrayCount = 0;
|
||||
|
||||
m_to = nsnull;
|
||||
m_bcc = nsnull;
|
||||
m_fcc = nsnull;
|
||||
|
@ -1122,93 +1119,54 @@ nsMsgSendLater::GetMsgWindow(nsIMsgWindow **aMsgWindow)
|
|||
NS_IMETHODIMP
|
||||
nsMsgSendLater::AddListener(nsIMsgSendLaterListener *aListener)
|
||||
{
|
||||
if ( (mListenerArrayCount > 0) || mListenerArray )
|
||||
{
|
||||
++mListenerArrayCount;
|
||||
mListenerArray = (nsIMsgSendLaterListener **)
|
||||
PR_Realloc(*mListenerArray, sizeof(nsIMsgSendLaterListener *) * mListenerArrayCount);
|
||||
if (!mListenerArray)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
else
|
||||
{
|
||||
mListenerArray[mListenerArrayCount - 1] = aListener;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mListenerArrayCount = 1;
|
||||
mListenerArray = (nsIMsgSendLaterListener **) PR_Malloc(sizeof(nsIMsgSendLaterListener *) * mListenerArrayCount);
|
||||
if (!mListenerArray)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
memset(mListenerArray, 0, (sizeof(nsIMsgSendLaterListener *) * mListenerArrayCount));
|
||||
|
||||
mListenerArray[0] = aListener;
|
||||
NS_ADDREF(mListenerArray[0]);
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ENSURE_ARG_POINTER(aListener);
|
||||
mListenerArray.AppendElement(aListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgSendLater::RemoveListener(nsIMsgSendLaterListener *aListener)
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i=0; i<mListenerArrayCount; i++)
|
||||
if (mListenerArray[i] == aListener)
|
||||
{
|
||||
NS_RELEASE(mListenerArray[i]);
|
||||
mListenerArray[i] = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
NS_ENSURE_ARG_POINTER(aListener);
|
||||
return mListenerArray.RemoveElement(aListener) ? NS_OK : NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
#define NOTIFY_LISTENERS(propertyfunc_, params_) \
|
||||
PR_BEGIN_MACRO \
|
||||
nsTObserverArray<nsCOMPtr<nsIMsgSendLaterListener> >::ForwardIterator iter(mListenerArray); \
|
||||
nsCOMPtr<nsIMsgSendLaterListener> listener; \
|
||||
while (iter.HasMore()) { \
|
||||
listener = iter.GetNext(); \
|
||||
listener->propertyfunc_ params_; \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsMsgSendLater::NotifyListenersOnStartSending(PRUint32 aTotalMessageCount)
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i=0; i<mListenerArrayCount; i++)
|
||||
if (mListenerArray[i] != nsnull)
|
||||
mListenerArray[i]->OnStartSending(aTotalMessageCount);
|
||||
|
||||
return NS_OK;
|
||||
NOTIFY_LISTENERS(OnStartSending, (aTotalMessageCount));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMsgSendLater::NotifyListenersOnProgress(PRUint32 aCurrentMessage, PRUint32 aTotalMessage)
|
||||
void
|
||||
nsMsgSendLater::NotifyListenersOnProgress(PRUint32 aCurrentMessage,
|
||||
PRUint32 aTotalMessage)
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i=0; i<mListenerArrayCount; i++)
|
||||
if (mListenerArray[i] != nsnull)
|
||||
mListenerArray[i]->OnProgress(aCurrentMessage, aTotalMessage);
|
||||
|
||||
return NS_OK;
|
||||
NOTIFY_LISTENERS(OnProgress, (aCurrentMessage, aTotalMessage));
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsMsgSendLater::NotifyListenersOnStatus(const PRUnichar *aMsg)
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i=0; i<mListenerArrayCount; i++)
|
||||
if (mListenerArray[i] != nsnull)
|
||||
mListenerArray[i]->OnStatus(aMsg);
|
||||
|
||||
return NS_OK;
|
||||
NOTIFY_LISTENERS(OnStatus, (aMsg));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMsgSendLater::NotifyListenersOnStopSending(nsresult aStatus, const PRUnichar *aMsg,
|
||||
PRUint32 aTotalTried, PRUint32 aSuccessful)
|
||||
void
|
||||
nsMsgSendLater::NotifyListenersOnStopSending(nsresult aStatus,
|
||||
const PRUnichar *aMsg,
|
||||
PRUint32 aTotalTried,
|
||||
PRUint32 aSuccessful)
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i=0; i<mListenerArrayCount; i++)
|
||||
if (mListenerArray[i] != nsnull)
|
||||
mListenerArray[i]->OnStopSending(aStatus, aMsg, aTotalTried, aSuccessful);
|
||||
|
||||
return NS_OK;
|
||||
NOTIFY_LISTENERS(OnStopSending, (aStatus, aMsg, aTotalTried, aSuccessful));
|
||||
}
|
||||
|
||||
// XXX todo
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "nsIMsgSendLaterListener.h"
|
||||
#include "nsIMsgSendLater.h"
|
||||
#include "nsIMsgWindow.h"
|
||||
#include "nsTObserverArray.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// This is the listener class for the send operation. We have to create this class
|
||||
|
@ -104,11 +105,12 @@ public:
|
|||
nsresult BuildNewBuffer(const char* aBuf, PRUint32 aCount, PRUint32 *totalBufSize);
|
||||
|
||||
// methods for listener array processing...
|
||||
nsresult NotifyListenersOnStartSending(PRUint32 aTotalMessageCount);
|
||||
nsresult NotifyListenersOnProgress(PRUint32 aCurrentMessage, PRUint32 aTotalMessage);
|
||||
nsresult NotifyListenersOnStatus(const PRUnichar *aMsg);
|
||||
nsresult NotifyListenersOnStopSending(nsresult aStatus, const PRUnichar *aMsg,
|
||||
PRUint32 aTotalTried, PRUint32 aSuccessful);
|
||||
void NotifyListenersOnStartSending(PRUint32 aTotalMessageCount);
|
||||
void NotifyListenersOnProgress(PRUint32 aCurrentMessage,
|
||||
PRUint32 aTotalMessage);
|
||||
void NotifyListenersOnStatus(const PRUnichar *aMsg);
|
||||
void NotifyListenersOnStopSending(nsresult aStatus, const PRUnichar *aMsg,
|
||||
PRUint32 aTotalTried, PRUint32 aSuccessful);
|
||||
|
||||
// counters and things for enumeration
|
||||
PRUint32 mTotalSentSuccessfully;
|
||||
|
@ -122,8 +124,7 @@ public:
|
|||
private:
|
||||
nsresult GetIdentityFromKey(const char *aKey, nsIMsgIdentity **aIdentity);
|
||||
|
||||
nsIMsgSendLaterListener **mListenerArray;
|
||||
PRInt32 mListenerArrayCount;
|
||||
nsTObserverArray<nsCOMPtr<nsIMsgSendLaterListener> > mListenerArray;
|
||||
|
||||
nsCOMPtr<nsIMsgDBHdr> mMessage;
|
||||
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/**
|
||||
* Protocol tests for SMTP.
|
||||
*
|
||||
* This test verifies:
|
||||
* - Sending a message to an SMTP server (which is also covered elsewhere).
|
||||
* - Correct reception of the message by the SMTP server.
|
||||
* - Correct saving of the message to the sent folder.
|
||||
*
|
||||
* Originally written to test bug 429891 where saving to the sent folder was
|
||||
* mangling the message.
|
||||
*/
|
||||
var type = null;
|
||||
var test = null;
|
||||
var server;
|
||||
var sentFolder;
|
||||
var transaction;
|
||||
var originalData;
|
||||
var finished = false;
|
||||
var identity = null;
|
||||
var testFile = do_get_file("../mailnews/compose/test/unit/data/429891_testcase.eml");
|
||||
|
||||
const kSender = "from@invalid.com";
|
||||
const kTo = "invalid@invalid.com";
|
||||
|
||||
// This listener handles the post-sending of the actual message and checks the
|
||||
// sequence and ensures the data is correct.
|
||||
function msll() {
|
||||
}
|
||||
|
||||
msll.prototype = {
|
||||
// nsIMsgSendLaterListener
|
||||
OnStartSending: function (aTotal) {
|
||||
},
|
||||
OnProgress: function (aCurrentMessage, aTotal) {
|
||||
},
|
||||
OnStatus: function (aMsg) {
|
||||
},
|
||||
OnStopSending: function (aStatus, aMsg, aTotal, aSuccessful) {
|
||||
do_test_finished();
|
||||
print("msll onStopSending\n");
|
||||
try {
|
||||
do_check_eq(aStatus, 0);
|
||||
|
||||
do_check_transaction(transaction,
|
||||
["EHLO test",
|
||||
"MAIL FROM:<" + kSender + "> SIZE=" + originalData.length,
|
||||
"RCPT TO:<" + kTo + ">",
|
||||
"DATA"]);
|
||||
|
||||
// Compare data file to what the server received
|
||||
do_check_eq(originalData, server._handler.post);
|
||||
|
||||
// Now wait till the copy is finished for the sent message
|
||||
do_test_pending();
|
||||
} catch (e) {
|
||||
do_throw(e);
|
||||
} finally {
|
||||
server.stop();
|
||||
|
||||
var thread = gThreadManager.currentThread;
|
||||
while (thread.hasPendingEvents())
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// This listener is used to find out when the copying of the message to the
|
||||
// unsent message folder is completed, and hence can fire off the actual
|
||||
// sending of the message.
|
||||
function copyListener() {
|
||||
}
|
||||
|
||||
copyListener.prototype = {
|
||||
// nsIMsgSendListener
|
||||
onStartSending: function (aMsgID, aMsgSize) {
|
||||
},
|
||||
onProgress: function (aMsgID, aProgress, aProgressMax) {
|
||||
},
|
||||
onStatus: function (aMsgID, aMsg) {
|
||||
},
|
||||
onStopSending: function (aMsgID, aStatus, aMsg, aReturnFile) {
|
||||
},
|
||||
onGetDraftFolderURI: function (aFolderURI) {
|
||||
},
|
||||
onSendNotPerformed: function (aMsgID, aStatus) {
|
||||
},
|
||||
|
||||
// nsIMsgCopyServiceListener
|
||||
OnStartCopy: function () {
|
||||
},
|
||||
OnProgress: function (aProgress, aProgressMax) {
|
||||
},
|
||||
SetMessageKey: function (aKey) {
|
||||
},
|
||||
GetMessageId: function (aMessageId) {
|
||||
},
|
||||
OnStopCopy: function (aStatus) {
|
||||
do_test_finished();
|
||||
|
||||
try {
|
||||
do_check_eq(aStatus, 0);
|
||||
|
||||
var msgSendLater = Cc["@mozilla.org/messengercompose/sendlater;1"]
|
||||
.createInstance(Ci.nsIMsgSendLater);
|
||||
|
||||
let folder = msgSendLater.getUnsentMessagesFolder(identity);
|
||||
|
||||
// Check we have a message in the unsent message folder
|
||||
do_check_eq(folder.getTotalMessages(false), 1);
|
||||
|
||||
// Now do a comparison of what is in the sent mail folder
|
||||
var fileData = loadFileToString(folder.filePath);
|
||||
|
||||
// Skip the headers etc that mailnews adds
|
||||
var pos = fileData.indexOf("From:");
|
||||
do_check_neq(pos, -1);
|
||||
|
||||
fileData = fileData.substr(pos);
|
||||
|
||||
// Check the data is matching.
|
||||
do_check_eq(originalData, fileData);
|
||||
|
||||
do_test_pending();
|
||||
do_timeout(sendMessageLater(), 0);
|
||||
} catch (e) {
|
||||
do_throw(e);
|
||||
} finally {
|
||||
server.stop();
|
||||
|
||||
var thread = gThreadManager.currentThread;
|
||||
while (thread.hasPendingEvents())
|
||||
thread.processNextEvent(true);
|
||||
|
||||
finished = true;
|
||||
}
|
||||
},
|
||||
|
||||
// QueryInterface
|
||||
QueryInterface: function (iid) {
|
||||
if (iid.equals(Ci.nsIMsgSendListener) ||
|
||||
iid.equals(Ci.nsIMsgCopyServiceListener) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
|
||||
Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// This function does the actual send later
|
||||
function sendMessageLater()
|
||||
{
|
||||
do_test_finished();
|
||||
|
||||
// Set up the SMTP server.
|
||||
server = setupServerDaemon();
|
||||
|
||||
type = "sendMessageLater";
|
||||
|
||||
// Handle the server in a try/catch/finally loop so that we always will stop
|
||||
// the server if something fails.
|
||||
try {
|
||||
// Start the fake SMTP server
|
||||
server.start(SMTP_PORT);
|
||||
|
||||
// A test to check that we are sending files correctly, including checking
|
||||
// what the server receives and what we output.
|
||||
test = "sendMessageLater";
|
||||
|
||||
var msgSendLater = Cc["@mozilla.org/messengercompose/sendlater;1"]
|
||||
.createInstance(Ci.nsIMsgSendLater);
|
||||
|
||||
var messageListener = new msll();
|
||||
|
||||
msgSendLater.AddListener(messageListener);
|
||||
|
||||
// Send the unsent message
|
||||
msgSendLater.SendUnsentMessages(identity);
|
||||
|
||||
server.performTest();
|
||||
|
||||
transaction = server.playTransaction();
|
||||
|
||||
do_timeout(10000, "if (!finished) do_throw('Notifications of message send/copy not received');");
|
||||
|
||||
do_test_pending();
|
||||
|
||||
} catch (e) {
|
||||
do_throw(e);
|
||||
} finally {
|
||||
server.stop();
|
||||
|
||||
var thread = gThreadManager.currentThread;
|
||||
while (thread.hasPendingEvents())
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// Test file - for bug 429891
|
||||
originalData = loadFileToString(testFile);
|
||||
|
||||
Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch)
|
||||
.setBoolPref("mail.really_delete_draft", false);
|
||||
|
||||
// Ensure we have a local mail account, an normal account and appropriate
|
||||
// servers and identities.
|
||||
loadLocalMailAccount();
|
||||
|
||||
var acctMgr = Cc["@mozilla.org/messenger/account-manager;1"]
|
||||
.getService(Ci.nsIMsgAccountManager);
|
||||
acctMgr.setSpecialFolders();
|
||||
|
||||
var account = acctMgr.createAccount();
|
||||
incomingServer = acctMgr.createIncomingServer("test", "localhost", "pop3");
|
||||
|
||||
var smtpServer = getBasicSmtpServer();
|
||||
identity = getSmtpIdentity(kSender, smtpServer);
|
||||
|
||||
account.addIdentity(identity);
|
||||
account.defaultIdentity = identity;
|
||||
account.incomingServer = incomingServer;
|
||||
|
||||
sentFolder = gLocalIncomingServer.rootMsgFolder.addSubfolder("Sent");
|
||||
|
||||
do_check_eq(identity.doFcc, true);
|
||||
|
||||
// Now prepare to actually "send" the message later, i.e. dump it in the
|
||||
// unsent messages folder.
|
||||
|
||||
var compFields = Cc["@mozilla.org/messengercompose/composefields;1"]
|
||||
.createInstance(Ci.nsIMsgCompFields);
|
||||
|
||||
compFields.from = identity.email;
|
||||
compFields.to = kTo;
|
||||
|
||||
var cl = new copyListener(true);
|
||||
|
||||
var msgSend = Cc["@mozilla.org/messengercompose/send;1"]
|
||||
.createInstance(Ci.nsIMsgSend);
|
||||
|
||||
msgSend.sendMessageFile(identity, "", compFields, testFile,
|
||||
false, false, Ci.nsIMsgSend.nsMsgQueueForLater,
|
||||
null, cl, null, null);
|
||||
|
||||
// Now we wait till we get copy notification of completion.
|
||||
do_test_pending();
|
||||
}
|
Загрузка…
Ссылка в новой задаче