Bug 409458 - nsIMsgFolder.AddFolderListener should hold a reference to the listener. r=standard8,neil,darktrojan,jorgk

This commit is contained in:
Hiroyuki Ikezoe 2018-08-30 15:42:58 +12:00
Родитель 210561200a
Коммит 2329776de1
6 изменённых файлов: 129 добавлений и 53 удалений

Просмотреть файл

@ -0,0 +1,45 @@
/*
* Test that adding nsIFolderListener in js does not cause any crash.
*/
ChromeUtils.import("resource:///modules/MailServices.jsm");
load("../../../resources/logHelper.js");
load("../../../resources/asyncTestUtils.js");
load("../../../resources/messageModifier.js");
load("../../../resources/messageGenerator.js");
load("../../../resources/messageInjection.js");
var folderListener = {
OnItemAdded: function() {},
OnItemRemoved: function() {},
OnItemPropertyChanged: function() {},
OnItemIntPropertyChanged: function() {},
OnItemBoolPropertyChanged: function() {},
OnItemUnicharPropertyChanged: function() {},
OnItemPropertyFlagChanged: function() {},
OnItemEvent: function() {},
}
var targetFolder;
var tests = [
function setup() {
gMessageGenerator = new MessageGenerator();
configure_message_injection({mode: "local"});
targetFolder = make_empty_folder();
targetFolder.AddFolderListener(folderListener);
registerCleanupFunction(function() {
targetFolder.RemoveFolderListener(folderListener);
});
},
async function create_new_message() {
let [msgSet] = make_new_sets_in_folder(targetFolder, [{count: 1}]);
await wait_for_message_injection();
}
];
function run_test() {
async_run_tests(tests);
}

Просмотреть файл

@ -78,3 +78,4 @@ skip-if = true # See bug 1418063.
[test_testsuite_fakeserverAuth.js]
[test_viewSortByAddresses.js]
[test_formatFileSize.js]
[test_nsIFolderListener.js]

Просмотреть файл

@ -4929,16 +4929,25 @@ NS_IMETHODIMP nsMsgDBFolder::CopyDataDone()
return NS_OK;
}
#define NOTIFY_LISTENERS(propertyfunc_, params_) \
PR_BEGIN_MACRO \
nsTObserverArray<nsCOMPtr<nsIFolderListener>>::ForwardIterator iter(mListeners); \
nsCOMPtr<nsIFolderListener> listener; \
while (iter.HasMore()) { \
listener = iter.GetNext(); \
listener->propertyfunc_ params_; \
} \
PR_END_MACRO
NS_IMETHODIMP
nsMsgDBFolder::NotifyPropertyChanged(const nsACString &aProperty,
const nsACString& aOldValue,
const nsACString& aNewValue)
{
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mListeners, nsIFolderListener,
OnItemPropertyChanged,
(this, aProperty,
nsCString(aOldValue).get(),
nsCString(aNewValue).get()));
NOTIFY_LISTENERS(OnItemPropertyChanged,
(this, aProperty,
nsCString(aOldValue).get(),
nsCString(aNewValue).get()));
// Notify listeners who listen to every folder
nsresult rv;
@ -4955,11 +4964,10 @@ nsMsgDBFolder::NotifyUnicharPropertyChanged(const nsACString &aProperty,
const nsAString& aOldValue,
const nsAString& aNewValue)
{
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mListeners, nsIFolderListener,
OnItemUnicharPropertyChanged,
(this, aProperty,
nsString(aOldValue).get(),
nsString(aNewValue).get()));
NOTIFY_LISTENERS(OnItemUnicharPropertyChanged,
(this, aProperty,
nsString(aOldValue).get(),
nsString(aNewValue).get()));
// Notify listeners who listen to every folder
nsresult rv;
@ -4982,9 +4990,8 @@ nsMsgDBFolder::NotifyIntPropertyChanged(const nsACString &aProperty, int64_t aOl
aProperty.Equals(kTotalUnreadMessages)))
return NS_OK;
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mListeners, nsIFolderListener,
OnItemIntPropertyChanged,
(this, aProperty, aOldValue, aNewValue));
NOTIFY_LISTENERS(OnItemIntPropertyChanged,
(this, aProperty, aOldValue, aNewValue));
// Notify listeners who listen to every folder
nsresult rv;
@ -4999,9 +5006,8 @@ NS_IMETHODIMP
nsMsgDBFolder::NotifyBoolPropertyChanged(const nsACString &aProperty,
bool aOldValue, bool aNewValue)
{
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mListeners, nsIFolderListener,
OnItemBoolPropertyChanged,
(this, aProperty, aOldValue, aNewValue));
NOTIFY_LISTENERS(OnItemBoolPropertyChanged,
(this, aProperty, aOldValue, aNewValue));
// Notify listeners who listen to every folder
nsresult rv;
@ -5016,9 +5022,8 @@ NS_IMETHODIMP
nsMsgDBFolder::NotifyPropertyFlagChanged(nsIMsgDBHdr *aItem, const nsACString &aProperty,
uint32_t aOldValue, uint32_t aNewValue)
{
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mListeners, nsIFolderListener,
OnItemPropertyFlagChanged,
(aItem, aProperty, aOldValue, aNewValue));
NOTIFY_LISTENERS(OnItemPropertyFlagChanged,
(aItem, aProperty, aOldValue, aNewValue));
// Notify listeners who listen to every folder
nsresult rv;
@ -5036,9 +5041,8 @@ NS_IMETHODIMP nsMsgDBFolder::NotifyItemAdded(nsISupports *aItem)
if (!notify)
return NS_OK;
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mListeners, nsIFolderListener,
OnItemAdded,
(this, aItem));
NOTIFY_LISTENERS(OnItemAdded,
(this, aItem));
// Notify listeners who listen to every folder
nsresult rv;
@ -5050,9 +5054,8 @@ NS_IMETHODIMP nsMsgDBFolder::NotifyItemAdded(nsISupports *aItem)
nsresult nsMsgDBFolder::NotifyItemRemoved(nsISupports *aItem)
{
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mListeners, nsIFolderListener,
OnItemRemoved,
(this, aItem));
NOTIFY_LISTENERS(OnItemRemoved,
(this, aItem));
// Notify listeners who listen to every folder
nsresult rv;
@ -5064,9 +5067,8 @@ nsresult nsMsgDBFolder::NotifyItemRemoved(nsISupports *aItem)
nsresult nsMsgDBFolder::NotifyFolderEvent(const nsACString &aEvent)
{
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mListeners, nsIFolderListener,
OnItemEvent,
(this, aEvent));
NOTIFY_LISTENERS(OnItemEvent,
(this, aEvent));
//Notify listeners who listen to every folder
nsresult rv;

Просмотреть файл

@ -214,8 +214,7 @@ protected:
bool mNotifyCountChanges;
int64_t mExpungedBytes;
nsCOMArray<nsIMsgFolder> mSubFolders;
// This can't be refcounted due to ownsership issues
nsTObserverArray<nsIFolderListener*> mListeners;
nsTObserverArray<nsCOMPtr<nsIFolderListener>> mListeners;
bool mInitializedFromCache;
nsISupports *mSemaphoreHolder; // set when the folder is being written to

Просмотреть файл

@ -117,12 +117,13 @@ nsMsgSendLater::Init()
// Subscribe to the unsent messages folder
// XXX This code should be set up for multiple unsent folders, however we
// don't support that at the moment, so for now just assume one folder.
rv = GetUnsentMessagesFolder(nullptr, getter_AddRefs(mMessageFolder));
nsCOMPtr<nsIMsgFolder> folder;
rv = GetUnsentMessagesFolder(nullptr, getter_AddRefs(folder));
// There doesn't have to be a nsMsgQueueForLater flagged folder.
if (NS_FAILED(rv) || !mMessageFolder)
if (NS_FAILED(rv) || !folder)
return NS_OK;
rv = mMessageFolder->AddFolderListener(this);
rv = folder->AddFolderListener(this);
NS_ENSURE_SUCCESS(rv, rv);
// XXX may want to send messages X seconds after startup if there are any.
@ -164,8 +165,12 @@ nsMsgSendLater::Observe(nsISupports *aSubject, const char* aTopic,
nsresult rv;
if (mMessageFolder)
{
rv = mMessageFolder->RemoveFolderListener(this);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(mMessageFolder, &rv);
if (folder)
{
rv = folder->RemoveFolderListener(this);
NS_ENSURE_SUCCESS(rv, rv);
}
}
// Now remove ourselves from the observer service as well.
@ -610,7 +615,9 @@ nsMsgSendLater::StartNextMailFileSend(nsresult prevStatus)
return NS_ERROR_UNEXPECTED;
nsCString messageURI;
mMessageFolder->GetUriForMsg(mMessage, messageURI);
nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(mMessageFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
folder->GetUriForMsg(mMessage, messageURI);
rv = nsMsgCreateTempFile("nsqmail.tmp", getter_AddRefs(mTempFile));
NS_ENSURE_SUCCESS(rv, rv);
@ -657,12 +664,21 @@ nsMsgSendLater::StartNextMailFileSend(nsresult prevStatus)
}
NS_IMETHODIMP
nsMsgSendLater::GetUnsentMessagesFolder(nsIMsgIdentity *aIdentity, nsIMsgFolder **folder)
nsMsgSendLater::GetUnsentMessagesFolder(nsIMsgIdentity *aIdentity, nsIMsgFolder **aFolder)
{
nsCString uri;
GetFolderURIFromUserPrefs(nsIMsgSend::nsMsgQueueForLater, aIdentity, uri);
return LocateMessageFolder(aIdentity, nsIMsgSend::nsMsgQueueForLater,
uri.get(), folder);
nsresult rv = NS_OK;
nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(mMessageFolder);
if (!folder) {
nsCString uri;
GetFolderURIFromUserPrefs(nsIMsgSend::nsMsgQueueForLater, aIdentity, uri);
rv = LocateMessageFolder(aIdentity, nsIMsgSend::nsMsgQueueForLater, uri.get(), getter_AddRefs(folder));
mMessageFolder = do_GetWeakReference(folder);
if (!mMessageFolder)
return NS_ERROR_FAILURE;
}
if (folder)
folder.forget(aFolder);
return rv;
}
NS_IMETHODIMP
@ -689,16 +705,19 @@ nsMsgSendLater::HasUnsentMessages(nsIMsgIdentity *aIdentity, bool *aResult)
// don't support that at the moment, so for now just assume one folder.
if (!mMessageFolder)
{
rv = GetUnsentMessagesFolder(nullptr, getter_AddRefs(mMessageFolder));
nsCOMPtr<nsIMsgFolder> folder;
rv = GetUnsentMessagesFolder(nullptr, getter_AddRefs(folder));
// There doesn't have to be a nsMsgQueueForLater flagged folder.
if (NS_FAILED(rv) || !mMessageFolder)
if (NS_FAILED(rv) || !folder)
return NS_OK;
}
rv = ReparseDBIfNeeded(nullptr);
NS_ENSURE_SUCCESS(rv, rv);
int32_t totalMessages;
rv = mMessageFolder->GetTotalMessages(false, &totalMessages);
nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(mMessageFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = folder->GetTotalMessages(false, &totalMessages);
NS_ENSURE_SUCCESS(rv, rv);
*aResult = totalMessages > 0;
@ -741,7 +760,7 @@ nsresult nsMsgSendLater::ReparseDBIfNeeded(nsIUrlListener *aListener)
// there are unsent messages, the db will be up to date.
nsCOMPtr<nsIMsgDatabase> unsentDB;
nsresult rv;
nsCOMPtr<nsIMsgLocalMailFolder> locFolder(do_QueryInterface(mMessageFolder, &rv));
nsCOMPtr<nsIMsgLocalMailFolder> locFolder(do_QueryReferent(mMessageFolder, &rv));
NS_ENSURE_SUCCESS(rv, rv);
return locFolder->GetDatabaseWithReparse(aListener, nullptr,
getter_AddRefs(unsentDB));
@ -767,9 +786,10 @@ nsMsgSendLater::InternalSendMessages(bool aUserInitiated,
// don't support that at the moment, so for now just assume one folder.
if (!mMessageFolder)
{
rv = GetUnsentMessagesFolder(nullptr,
getter_AddRefs(mMessageFolder));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgFolder> folder;
rv = GetUnsentMessagesFolder(nullptr, getter_AddRefs(folder));
if (NS_FAILED(rv) || !folder)
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIMsgDatabase> unsentDB;
// Remember these in case we need to reparse the db.
@ -780,7 +800,9 @@ nsMsgSendLater::InternalSendMessages(bool aUserInitiated,
mIdentity = nullptr; // don't hold onto the identity since we're a service.
nsCOMPtr<nsISimpleEnumerator> enumerator;
rv = mMessageFolder->GetMessages(getter_AddRefs(enumerator));
nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(mMessageFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = folder->GetMessages(getter_AddRefs(enumerator));
NS_ENSURE_SUCCESS(rv, rv);
// copy all the elements in the enumerator into our isupports array....
@ -886,8 +908,11 @@ nsMsgSendLater::DeleteCurrentMessage()
msgArray->InsertElementAt(mMessage, 0);
nsresult res = mMessageFolder->DeleteMessages(msgArray, nullptr, true, false, nullptr, false /*allowUndo*/);
if (NS_FAILED(res))
nsresult rv;
nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(mMessageFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = folder->DeleteMessages(msgArray, nullptr, true, false, nullptr, false /*allowUndo*/);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
// Null out the message so we don't try and delete it again.
@ -1313,8 +1338,11 @@ nsMsgSendLater::EndSendMessages(nsresult aStatus, const char16_t *aMsg,
// Clear out our array of messages.
mMessagesToSend.Clear();
nsresult rv;
nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(mMessageFolder, &rv);
NS_ENSURE_SUCCESS(rv,);
// We don't need to keep hold of the database now we've finished sending.
(void)mMessageFolder->SetMsgDatabase(nullptr);
(void)folder->SetMsgDatabase(nullptr);
// or the enumerator, temp file or output stream
mEnumerator = nullptr;

Просмотреть файл

@ -17,6 +17,7 @@
#include "nsITimer.h"
#include "nsCOMPtr.h"
#include "nsIMsgShutdown.h"
#include "nsWeakPtr.h"
////////////////////////////////////////////////////////////////////////////////////
// This is the listener class for the send operation. We have to create this class
@ -94,7 +95,7 @@ public:
uint32_t mTotalSendCount;
nsCOMArray<nsIMsgDBHdr> mMessagesToSend;
nsCOMPtr<nsISimpleEnumerator> mEnumerator;
nsCOMPtr<nsIMsgFolder> mMessageFolder;
nsWeakPtr mMessageFolder;
nsCOMPtr<nsIMsgStatusFeedback> mFeedback;
// Private Information