Bug #388353 --> displaying a mail message leaks a jsContext.

mailnews urls should use weak references for the msg window and the status feedback object

sr=bienvenu


git-svn-id: svn://10.0.0.236/trunk@230081 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
scott%scott-macgregor.org
2007-07-17 00:04:04 +00:00
parent 4c4da3ab97
commit 970f6f6644
7 changed files with 111 additions and 145 deletions

View File

@@ -53,66 +53,63 @@ interface nsIMsgFolder;
interface nsIMsgHeaderSink;
interface nsIMsgDBHdr;
[scriptable, uuid(0f9fb55c-f9ac-4501-af93-d4a7f23f82fb)]
[scriptable, uuid(2FB327C2-00A3-4e3f-8CD6-93BED40BD621)]
interface nsIMsgMailNewsUrl : nsIURL {
///////////////////////////////////////////////////////////////////////////////
// Eventually we'd like to push this type of functionality up into nsIURI.
// The idea is to allow the "application" (the part of the code which wants to
// run a url in order to perform some action) to register itself as a listener
// on url. As a url listener, the app will be informed when the url begins to run
// and when the url is finished.
////////////////////////////////////////////////////////////////////////////////
void RegisterListener (in nsIUrlListener aUrlListener);
void UnRegisterListener (in nsIUrlListener aUrlListener);
///////////////////////////////////////////////////////////////////////////////
// Eventually we'd like to push this type of functionality up into nsIURI.
// The idea is to allow the "application" (the part of the code which wants to
// run a url in order to perform some action) to register itself as a listener
// on url. As a url listener, the app will be informed when the url begins to run
// and when the url is finished.
////////////////////////////////////////////////////////////////////////////////
void RegisterListener (in nsIUrlListener aUrlListener);
void UnRegisterListener (in nsIUrlListener aUrlListener);
readonly attribute nsIURI baseURI;
// Eventually this will be removed and replaced with calls to nsIMsgStatusFeedback
attribute string errorMessage;
readonly attribute nsIURI baseURI;
// if you really want to know what the current state of the url is (running or not
// running) you should look into becoming a urlListener...
void SetUrlState(in boolean runningUrl, in nsresult aStatusCode);
void GetUrlState(out boolean runningUrl);
// if you really want to know what the current state of the url is (running or not
// running) you should look into becoming a urlListener...
void SetUrlState(in boolean runningUrl, in nsresult aStatusCode);
void GetUrlState(out boolean runningUrl);
readonly attribute nsIMsgIncomingServer server;
attribute nsIMsgFolder folder;
readonly attribute nsIMsgIncomingServer server;
attribute nsIMsgFolder folder;
// the ownership model for msg feedback
attribute nsIMsgStatusFeedback statusFeedback;
attribute nsIMsgStatusFeedback statusFeedback;
attribute nsIMsgWindow msgWindow;
attribute nsIMsgWindow msgWindow;
// current mime headers if reading message
attribute nsIMimeHeaders mimeHeaders;
// current mime headers if reading message
attribute nsIMimeHeaders mimeHeaders;
// the load group is computed from the msgWindow
readonly attribute nsILoadGroup loadGroup;
// the load group is computed from the msgWindow
readonly attribute nsILoadGroup loadGroup;
// search session, if we're running a search.
attribute nsIMsgSearchSession searchSession;
attribute boolean updatingFolder;
attribute boolean addToMemoryCache;
attribute boolean msgIsInLocalCache;
attribute boolean suppressErrorMsgs; // used to avoid displaying biff error messages
// search session, if we're running a search.
attribute nsIMsgSearchSession searchSession;
attribute boolean updatingFolder;
attribute boolean addToMemoryCache;
attribute boolean msgIsInLocalCache;
attribute boolean suppressErrorMsgs; // used to avoid displaying biff error messages
attribute nsICacheEntryDescriptor memCacheEntry;
// if we want mime to cache images fetched by this message, set this cache session.
attribute nsICacheSession imageCacheSession;
// hold onto this cache entry until url goes away. This is used by mime to keep
// images cached until the url is deleted so we don't get entries evicted
// before we've used them. We need to be sure this doesn't introduce
// circular references or the url will never get freed.
void cacheCacheEntry(in nsICacheEntryDescriptor cacheEntry);
void removeCacheEntry(in nsICacheEntryDescriptor cacheEntry);
const unsigned long eCopy = 0;
const unsigned long eMove = 1;
const unsigned long eDisplay = 2;
boolean IsUrlType(in unsigned long type);
nsIStreamListener getSaveAsListener(in boolean addDummyEnvelope, in nsIFile aFile);
attribute nsICacheEntryDescriptor memCacheEntry;
// if we want mime to cache images fetched by this message, set this cache session.
attribute nsICacheSession imageCacheSession;
// hold onto this cache entry until url goes away. This is used by mime to keep
// images cached until the url is deleted so we don't get entries evicted
// before we've used them. We need to be sure this doesn't introduce
// circular references or the url will never get freed.
void cacheCacheEntry(in nsICacheEntryDescriptor cacheEntry);
void removeCacheEntry(in nsICacheEntryDescriptor cacheEntry);
const unsigned long eCopy = 0;
const unsigned long eMove = 1;
const unsigned long eDisplay = 2;
boolean IsUrlType(in unsigned long type);
nsIStreamListener getSaveAsListener(in boolean addDummyEnvelope, in nsIFile aFile);
// typically the header sink is tied to the nsIMsgWindow, but in certain circumstances, a consumer
// may chose to provide its own header sink for this url
attribute nsIMsgHeaderSink msgHeaderSink;
// typically the header sink is tied to the nsIMsgWindow, but in certain circumstances, a consumer
// may chose to provide its own header sink for this url
attribute nsIMsgHeaderSink msgHeaderSink;
};
//////////////////////////////////////////////////////////////////////////////////
@@ -132,12 +129,11 @@ interface nsIMsgMessageUrl : nsISupports {
attribute string uri;
// used by imap, pop and nntp in order to implement save message to disk
attribute nsIFile messageFile;
attribute boolean AddDummyEnvelope;
attribute boolean AddDummyEnvelope;
attribute boolean canonicalLineEnding;
attribute string originalSpec;
// a message db header for that message.
readonly attribute nsIMsgDBHdr messageHeader;
};
//////////////////////////////////////////////////////////////////////////////////
@@ -149,10 +145,10 @@ interface nsIMsgMessageUrl : nsISupports {
[scriptable, uuid(D71E0785-2862-11d4-98C1-001083010E9B)]
interface nsIMsgI18NUrl : nsISupports {
// the charset associated with a folder for this url.....
readonly attribute string folderCharset;
readonly attribute boolean folderCharsetOverride;
// the charsetOverRide is a charset the user may have specified via the menu for
// a particular message
attribute string charsetOverRide;
// the charset associated with a folder for this url.....
readonly attribute string folderCharset;
readonly attribute boolean folderCharsetOverride;
// the charsetOverRide is a charset the user may have specified via the menu for
// a particular message
attribute string charsetOverRide;
};

View File

@@ -55,6 +55,7 @@ NS_INTERFACE_MAP_BEGIN(nsMsgProgress)
NS_INTERFACE_MAP_ENTRY(nsIMsgStatusFeedback)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END_THREADSAFE

View File

@@ -48,7 +48,8 @@
#include "nsIStringBundle.h"
#include "nsWeakReference.h"
class nsMsgProgress : public nsIMsgProgress, public nsIMsgStatusFeedback, public nsIProgressEventSink
class nsMsgProgress : public nsIMsgProgress, public nsIMsgStatusFeedback, public nsIProgressEventSink,
public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS

View File

@@ -148,18 +148,6 @@ nsresult nsMsgMailNewsUrl::UnRegisterListener (nsIUrlListener * aUrlListener)
return NS_OK;
}
nsresult nsMsgMailNewsUrl::SetErrorMessage (const char * errorMessage)
{
// functionality has been moved to nsIMsgStatusFeedback
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsMsgMailNewsUrl::GetErrorMessage (char ** errorMessage)
{
// functionality has been moved to nsIMsgStatusFeedback
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetServer(nsIMsgIncomingServer ** aIncomingServer)
{
// mscott --> we could cache a copy of the server here....but if we did, we run
@@ -208,54 +196,49 @@ NS_IMETHODIMP nsMsgMailNewsUrl::GetServer(nsIMsgIncomingServer ** aIncomingServe
return rv;
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetStatusFeedback(nsIMsgStatusFeedback *aMsgFeedback)
{
if (aMsgFeedback)
m_statusFeedback = do_QueryInterface(aMsgFeedback);
return NS_OK;
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetMsgWindow(nsIMsgWindow **aMsgWindow)
{
NS_ENSURE_ARG_POINTER(aMsgWindow);
*aMsgWindow = nsnull;
// note: it is okay to return a null msg window and not return an error
// it's possible the url really doesn't have msg window
*aMsgWindow = m_msgWindow;
NS_IF_ADDREF(*aMsgWindow);
nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
msgWindow.swap(*aMsgWindow);
return NS_OK;
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetMsgWindow(nsIMsgWindow *aMsgWindow)
{
if (aMsgWindow)
m_msgWindow = do_QueryInterface(aMsgWindow);
m_msgWindowWeak = do_GetWeakReference(aMsgWindow);
return NS_OK;
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetStatusFeedback(nsIMsgStatusFeedback **aMsgFeedback)
{
nsresult rv = NS_OK;
// note: it is okay to return a null status feedback and not return an error
// it's possible the url really doesn't have status feedback
if (!m_statusFeedback)
*aMsgFeedback = nsnull;
if (!m_statusFeedbackWeak)
{
if(m_msgWindow)
{
m_msgWindow->GetStatusFeedback(getter_AddRefs(m_statusFeedback));
}
}
if (aMsgFeedback)
{
*aMsgFeedback = m_statusFeedback;
NS_IF_ADDREF(*aMsgFeedback);
nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
if (msgWindow)
msgWindow->GetStatusFeedback(aMsgFeedback);
}
else
rv = NS_ERROR_NULL_POINTER;
return rv;
{
nsCOMPtr<nsIMsgStatusFeedback> statusFeedback(do_QueryReferent(m_statusFeedbackWeak));
statusFeedback.swap(*aMsgFeedback);
}
return *aMsgFeedback ? NS_OK : NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetStatusFeedback(nsIMsgStatusFeedback *aMsgFeedback)
{
if (aMsgFeedback)
m_statusFeedbackWeak = do_GetWeakReference(aMsgFeedback);
return NS_OK;
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetLoadGroup(nsILoadGroup **aLoadGroup)
@@ -265,37 +248,14 @@ NS_IMETHODIMP nsMsgMailNewsUrl::GetLoadGroup(nsILoadGroup **aLoadGroup)
// it's possible the url really doesn't have load group
if (!m_loadGroup)
{
if (m_msgWindow)
nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
if (msgWindow)
{
// XXXbz This is really weird... why are we getting some
// random loadgroup we're not really a part of?
nsCOMPtr<nsIDocShell> docShell;
m_msgWindow->GetRootDocShell(getter_AddRefs(docShell));
#if 0 // since we're not going through the doc loader for most mail/news urls,
//, this code isn't useful
// but I can imagine it could be useful at some point.
// load group needs status feedback set, since it's
// not the main window load group.
nsCOMPtr<nsIMsgStatusFeedback> statusFeedback;
m_msgWindow->GetStatusFeedback(getter_AddRefs(statusFeedback));
if (statusFeedback)
{
nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(docShell));
nsCOMPtr<nsIWebProgressListener> webProgressListener(do_QueryInterface(statusFeedback));
// register our status feedback object
if (statusFeedback && docShell)
{
webProgressListener = do_QueryInterface(statusFeedback);
webProgress->AddProgressListener(webProgressListener,
nsIWebProgress::NOTIFY_ALL);
}
}
#endif
m_loadGroup = do_GetInterface(docShell);
// XXXbz This is really weird... why are we getting some
// random loadgroup we're not really a part of?
nsCOMPtr<nsIDocShell> docShell;
msgWindow->GetRootDocShell(getter_AddRefs(docShell));
m_loadGroup = do_GetInterface(docShell);
}
}
@@ -580,11 +540,12 @@ NS_IMETHODIMP nsMsgMailNewsUrl::Clone(nsIURI **_retval)
NS_ENSURE_SUCCESS(rv, rv);
// add the msg window to the cloned url
if (m_msgWindow)
nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
if (msgWindow)
{
nsCOMPtr<nsIMsgMailNewsUrl> msgMailNewsUrl = do_QueryInterface(*_retval, &rv);
NS_ENSURE_SUCCESS(rv, rv);
msgMailNewsUrl->SetMsgWindow(m_msgWindow);
msgMailNewsUrl->SetMsgWindow(msgWindow);
}
return rv;

View File

@@ -55,6 +55,7 @@
#include "nsICacheSession.h"
#include "nsISupportsArray.h"
#include "nsIMimeMiscStatus.h"
#include "nsWeakReference.h"
///////////////////////////////////////////////////////////////////////////////////
// Okay, I found that all of the mail and news url interfaces needed to support
@@ -84,8 +85,8 @@ protected:
virtual const char * GetUserName() = 0;
nsCOMPtr<nsIURL> m_baseURL;
nsCOMPtr<nsIMsgStatusFeedback> m_statusFeedback;
nsCOMPtr<nsIMsgWindow> m_msgWindow;
nsWeakPtr m_statusFeedbackWeak;
nsWeakPtr m_msgWindowWeak;
nsCOMPtr<nsILoadGroup> m_loadGroup;
nsCOMPtr<nsIMimeHeaders> mMimeHeaders;
nsCOMPtr<nsIMsgSearchSession> m_searchSession;

View File

@@ -121,26 +121,29 @@ NS_IMETHODIMP nsImapUrl::SetMsgWindow(nsIMsgWindow *aMsgWindow)
{
if (aMsgWindow)
{
m_msgWindow = do_QueryInterface(aMsgWindow);
nsMsgMailNewsUrl::SetMsgWindow(aMsgWindow);
if (m_mockChannel) {
m_mockChannel->SetURI(this);
nsCOMPtr<nsIDocShell> msgDocShell;
m_msgWindow->GetRootDocShell(getter_AddRefs(msgDocShell));
if (msgDocShell) {
nsCOMPtr <nsIProgressEventSink> prevEventSink;
m_mockChannel->GetProgressEventSink(getter_AddRefs(prevEventSink));
nsCOMPtr<nsIInterfaceRequestor> docIR(do_QueryInterface(msgDocShell));
m_mockChannel->SetNotificationCallbacks(docIR);
// we want to use our existing event sink.
if (prevEventSink)
m_mockChannel->SetProgressEventSink(prevEventSink);
nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
if (msgWindow)
{
msgWindow->GetRootDocShell(getter_AddRefs(msgDocShell));
if (msgDocShell) {
nsCOMPtr <nsIProgressEventSink> prevEventSink;
m_mockChannel->GetProgressEventSink(getter_AddRefs(prevEventSink));
nsCOMPtr<nsIInterfaceRequestor> docIR(do_QueryInterface(msgDocShell));
m_mockChannel->SetNotificationCallbacks(docIR);
// we want to use our existing event sink.
if (prevEventSink)
m_mockChannel->SetProgressEventSink(prevEventSink);
}
}
}
}
return NS_OK;
}
nsImapUrl::~nsImapUrl()
{
PR_FREEIF(m_listOfMessageIds);

View File

@@ -228,17 +228,20 @@ nsresult nsMailboxUrl::GetMsgHdrForKey(nsMsgKey msgKey, nsIMsgDBHdr ** aMsgHdr)
rv = mailDB->GetMsgHdrForKey(msgKey, aMsgHdr);
else
{
if (!m_msgWindow)
nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
if (!msgWindow)
{
nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
mailSession->GetTopmostMsgWindow(getter_AddRefs(m_msgWindow));
mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
SetMsgWindow(msgWindow);
}
// maybe this is .eml file we're trying to read. See if we can get a header from the header sink.
if (m_msgWindow)
if (msgWindow)
{
nsCOMPtr <nsIMsgHeaderSink> headerSink;
m_msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
if (headerSink)
return headerSink->GetDummyMsgHeader(aMsgHdr);
}