ref count body shells to fix crashes when doing mime parts on demand, r=neil, and a lot of whitespace cleanup bug 632011

This commit is contained in:
David Bienvenu 2011-05-31 08:41:52 -07:00
Родитель 3fbb6f9c85
Коммит a0349b43f3
6 изменённых файлов: 141 добавлений и 159 удалений

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

@ -47,7 +47,7 @@
#include "nsServiceManagerUtils.h"
// need to talk to Rich about this...
#define IMAP_EXTERNAL_CONTENT_HEADER "X-Mozilla-IMAP-Part"
#define IMAP_EXTERNAL_CONTENT_HEADER "X-Mozilla-IMAP-Part"
// imapbody.cpp
// Implementation of the nsIMAPBodyShell and associated classes
@ -70,7 +70,11 @@
///////////// nsIMAPBodyShell ////////////////////////////////////
nsIMAPBodyShell::nsIMAPBodyShell(nsImapProtocol *protocolConnection, nsIMAPBodypartMessage *message, PRUint32 UID, const char *folderName)
NS_IMPL_THREADSAFE_ISUPPORTS0(nsIMAPBodyShell)
nsIMAPBodyShell::nsIMAPBodyShell(nsImapProtocol *protocolConnection,
nsIMAPBodypartMessage *message, PRUint32 UID,
const char *folderName)
{
m_isValid = PR_FALSE;
m_isBeingGenerated = PR_FALSE;
@ -111,12 +115,9 @@ nsIMAPBodyShell::~nsIMAPBodyShell()
void nsIMAPBodyShell::SetIsValid(PRBool valid)
{
// if (!valid)
// PR_LOG(IMAP, out, ("BODYSHELL: Shell is invalid."));
m_isValid = valid;
}
PRBool nsIMAPBodyShell::GetShowAttachmentsInline()
{
if (!m_gotAttachmentPref)
@ -1252,17 +1253,15 @@ nsIMAPBodyShellCache::~nsIMAPBodyShellCache()
// least recently used one will be in slot 0.
PRBool nsIMAPBodyShellCache::EjectEntry()
{
if (m_shellList->Count() < 1)
return PR_FALSE;
if (m_shellList->Count() < 1)
return PR_FALSE;
nsIMAPBodyShell *removedShell = (nsIMAPBodyShell *) (m_shellList->ElementAt(0));
m_shellList->RemoveElementAt(0);
m_shellHash.Remove(removedShell->GetUID());
nsIMAPBodyShell *removedShell = (nsIMAPBodyShell *) (m_shellList->ElementAt(0));
m_shellList->RemoveElementAt(0);
m_shellHash.Remove(removedShell->GetUID());
return PR_TRUE;
return PR_TRUE;
}
void nsIMAPBodyShellCache::Clear()
@ -1270,53 +1269,49 @@ void nsIMAPBodyShellCache::Clear()
while (EjectEntry()) ;
}
PRBool nsIMAPBodyShellCache::AddShellToCache(nsIMAPBodyShell *shell)
PRBool nsIMAPBodyShellCache::AddShellToCache(nsIMAPBodyShell *shell)
{
// If it's already in the cache, then just return.
// This has the side-effect of re-ordering the LRU list
// to put this at the top, which is good, because it's what we want.
if (FindShellForUID(shell->GetUID(), shell->GetFolderName(), shell->GetContentModified()))
return PR_TRUE;
// If it's already in the cache, then just return.
// This has the side-effect of re-ordering the LRU list
// to put this at the top, which is good, because it's what we want.
if (FindShellForUID(shell->GetUID(), shell->GetFolderName(), shell->GetContentModified()))
return PR_TRUE;
// OK, so it's not in the cache currently.
// OK, so it's not in the cache currently.
// First, for safety sake, remove any entry with the given UID,
// just in case we have a collision between two messages in different
// folders with the same UID.
nsIMAPBodyShell *foundShell = nsnull;
m_shellHash.Get(shell->GetUID(), &foundShell);
if (foundShell)
{
m_shellHash.Remove(foundShell->GetUID());
m_shellList->RemoveElement(foundShell);
}
// First, for safety sake, remove any entry with the given UID,
// just in case we have a collision between two messages in different
// folders with the same UID.
nsRefPtr<nsIMAPBodyShell> foundShell;
m_shellHash.Get(shell->GetUID(), getter_AddRefs(foundShell));
if (foundShell)
{
m_shellHash.Remove(foundShell->GetUID());
m_shellList->RemoveElement(foundShell);
}
// Add the new one to the cache
m_shellList->AppendElement(shell);
m_shellHash.Put(shell->GetUID(), shell);
shell->SetIsCached(PR_TRUE);
// Add the new one to the cache
m_shellList->AppendElement(shell);
// while we're not over our size limit, eject entries
PRBool rv = PR_TRUE;
while (GetSize() > GetMaxSize())
{
rv = EjectEntry();
}
m_shellHash.Put(shell->GetUID(), shell);
shell->SetIsCached(PR_TRUE);
return rv;
// while we're not over our size limit, eject entries
PRBool rv = PR_TRUE;
while (GetSize() > GetMaxSize())
rv = EjectEntry();
return rv;
}
nsIMAPBodyShell *nsIMAPBodyShellCache::FindShellForUID(nsCString &UID, const char *mailboxName,
IMAP_ContentModifiedType modType)
{
nsIMAPBodyShell *foundShell = nsnull;
m_shellHash.Get(UID, &foundShell);
if (!foundShell)
return nsnull;
nsRefPtr<nsIMAPBodyShell> foundShell;
m_shellHash.Get(UID, getter_AddRefs(foundShell));
if (!foundShell)
return nsnull;
// Make sure the content-modified types are compatible.
// This allows us to work seamlessly while people switch between
// View Attachments Inline and View Attachments As Links.
@ -1325,28 +1320,18 @@ nsIMAPBodyShell *nsIMAPBodyShellCache::FindShellForUID(nsCString &UID, const cha
if (modType != foundShell->GetContentModified())
return nsnull;
// mailbox names must match also.
if (PL_strcmp(mailboxName, foundShell->GetFolderName()))
return nsnull;
// mailbox names must match also.
if (PL_strcmp(mailboxName, foundShell->GetFolderName()))
return nsnull;
// adjust the LRU stuff
m_shellList->RemoveElement(foundShell); // oh well, I suppose this defeats the performance gain of the hash if it actually is found
m_shellList->AppendElement(foundShell); // Adds to end
return foundShell;
// adjust the LRU stuff. This defeats the performance gain of the hash if
// it actually is found since this is linear.
m_shellList->RemoveElement(foundShell);
m_shellList->AppendElement(foundShell);// Adds to end
return foundShell;
}
nsIMAPBodyShell *nsIMAPBodyShellCache::FindShellForUID(PRUint32 UID, const char *mailboxName,
IMAP_ContentModifiedType modType)
{
nsCString uidString;
uidString.AppendInt(UID);
nsIMAPBodyShell *rv = FindShellForUID(uidString, mailboxName, modType);
return rv;
}
///////////// nsIMAPMessagePartID ////////////////////////////////////

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

@ -44,7 +44,7 @@ nsIMAPBodyShell and associated classes
#include "nsImapCore.h"
#include "nsStringGlue.h"
#include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsVoidArray.h"
class nsImapProtocol;
@ -233,41 +233,52 @@ class nsIMAPMessagePartIDArray;
// display. The MIME Shell has selected (inline) parts filled in, and leaves all others
// for on-demand retrieval through explicit part fetches.
class nsIMAPBodyShell
class nsIMAPBodyShell : public nsISupports
{
public:
nsIMAPBodyShell(nsImapProtocol *protocolConnection, nsIMAPBodypartMessage *message, PRUint32 UID, const char *folderName);
virtual ~nsIMAPBodyShell();
void SetConnection(nsImapProtocol *con) { m_protocolConnection = con; } // To be used after a shell is uncached
virtual PRBool GetIsValid() { return m_isValid; }
virtual void SetIsValid(PRBool valid);
NS_DECL_ISUPPORTS
nsIMAPBodyShell(nsImapProtocol *protocolConnection,
nsIMAPBodypartMessage *message, PRUint32 UID,
const char *folderName);
virtual ~nsIMAPBodyShell();
// To be used after a shell is uncached
void SetConnection(nsImapProtocol *con) { m_protocolConnection = con; }
virtual PRBool GetIsValid() { return m_isValid; }
virtual void SetIsValid(PRBool valid);
// Prefetch
void AddPrefetchToQueue(nsIMAPeFetchFields, const char *partNum); // Adds a message body part to the queue to be prefetched
// in a single, pipelined command
void FlushPrefetchQueue(); // Runs a single pipelined command which fetches all of the
// elements in the prefetch queue
void AdoptMessageHeaders(char *headers, const char *partNum); // Fills in buffer (and adopts storage) for header object
// partNum specifies the message part number to which the
// headers correspond. NULL indicates the top-level message
void AdoptMimeHeader(const char *partNum, char *mimeHeader); // Fills in buffer (and adopts storage) for MIME headers in appropriate object.
// If object can't be found, sets isValid to PR_FALSE.
// Prefetch
// Adds a message body part to the queue to be prefetched
// in a single, pipelined command
void AddPrefetchToQueue(nsIMAPeFetchFields, const char *partNum);
// Runs a single pipelined command which fetches all of the
// elements in the prefetch queue
void FlushPrefetchQueue();
// Fills in buffer (and adopts storage) for header object
// partNum specifies the message part number to which the
// headers correspond. NULL indicates the top-level message
void AdoptMessageHeaders(char *headers, const char *partNum);
// Fills in buffer (and adopts storage) for MIME headers in appropriate object.
// If object can't be found, sets isValid to PR_FALSE.
void AdoptMimeHeader(const char *partNum, char *mimeHeader);
// Generation
virtual PRInt32 Generate(char *partNum); // Streams out an HTML representation of this IMAP message, going along and
// fetching parts it thinks it needs, and leaving empty shells for the parts
// it doesn't.
// Returns number of bytes generated, or -1 if invalid.
// If partNum is not NULL, then this works to generates a MIME part that hasn't been downloaded yet
// and leaves out all other parts. By default, to generate a normal message, partNum should be NULL.
// Generation
// Streams out an HTML representation of this IMAP message, going along and
// fetching parts it thinks it needs, and leaving empty shells for the parts
// it doesn't.
// Returns number of bytes generated, or -1 if invalid.
// If partNum is not NULL, then this works to generates a MIME part that hasn't been downloaded yet
// and leaves out all other parts. By default, to generate a normal message, partNum should be NULL.
virtual PRInt32 Generate(char *partNum);
virtual PRBool GetShowAttachmentsInline(); // Returns TRUE if the user has the pref "Show Attachments Inline" set.
// Returns FALSE if the setting is "Show Attachments as Links"
PRBool PreflightCheckAllInline(); // Returns PR_TRUE if all parts are inline, PR_FALSE otherwise. Does not generate anything.
// Returns TRUE if the user has the pref "Show Attachments Inline" set.
// Returns FALSE if the setting is "Show Attachments as Links"
virtual PRBool GetShowAttachmentsInline();
// Returns PR_TRUE if all parts are inline, PR_FALSE otherwise. Does not generate anything.
PRBool PreflightCheckAllInline();
// Helpers
nsImapProtocol *GetConnection() { return m_protocolConnection; }
PRBool GetPseudoInterrupted();
PRBool GetPseudoInterrupted();
PRBool DeathSignalReceived();
nsCString &GetUID() { return m_UID; }
const char *GetFolderName() { return m_folderName; }
@ -282,9 +293,9 @@ public:
void SetContentModified(IMAP_ContentModifiedType modType) { m_contentModified = modType; }
protected:
nsIMAPBodypartMessage *m_message;
nsIMAPBodypartMessage *m_message;
nsIMAPMessagePartIDArray *m_prefetchQueue; // array of pipelined part prefetches. Ok, so it's not really a queue.
nsIMAPMessagePartIDArray *m_prefetchQueue; // array of pipelined part prefetches. Ok, so it's not really a queue.
PRBool m_isValid;
nsImapProtocol *m_protocolConnection; // Connection, for filling in parts
@ -297,8 +308,9 @@ protected:
PRBool m_cached; // Whether or not this shell is cached
PRBool m_generatingWholeMessage; // whether or not we are generating the whole (non-MPOD) message
// Set to PR_FALSE if we are generating by parts
IMAP_ContentModifiedType m_contentModified; // under what conditions the content has been modified.
// Either IMAP_CONTENT_MODIFIED_VIEW_INLINE or IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS
// under what conditions the content has been modified.
// Either IMAP_CONTENT_MODIFIED_VIEW_INLINE or IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS
IMAP_ContentModifiedType m_contentModified;
};
@ -315,35 +327,31 @@ protected:
class nsIMAPBodyShellCache
{
public:
static nsIMAPBodyShellCache *Create();
virtual ~nsIMAPBodyShellCache();
static nsIMAPBodyShellCache *Create();
virtual ~nsIMAPBodyShellCache();
PRBool AddShellToCache(nsIMAPBodyShell *shell); // Adds shell to cache, possibly ejecting
// another entry based on scheme in EjectEntry().
nsIMAPBodyShell *FindShellForUID(nsCString &UID, const char *mailboxName, IMAP_ContentModifiedType modType); // Looks up a shell in the cache given the message's UID.
nsIMAPBodyShell *FindShellForUID(PRUint32 UID, const char *mailboxName, IMAP_ContentModifiedType modType); // Looks up a shell in the cache given the message's UID.
// Returns the shell if found, NULL if not found.
// Adds shell to cache, possibly ejecting
// another entry based on scheme in EjectEntry().
PRBool AddShellToCache(nsIMAPBodyShell *shell);
// Looks up a shell in the cache given the message's UID.
nsIMAPBodyShell *FindShellForUID(nsCString &UID, const char *mailboxName,
IMAP_ContentModifiedType modType);
void Clear();
protected:
nsIMAPBodyShellCache();
PRBool EjectEntry(); // Chooses an entry to eject; deletes that entry; and ejects it from the cache,
// clearing up a new space. Returns PR_TRUE if it found an entry to eject, PR_FALSE otherwise.
PRUint32 GetSize() { return m_shellList->Count(); }
PRUint32 GetMaxSize() { return 20; }
protected:
nsVoidArray *m_shellList; // For maintenance
nsClassHashtable <nsCStringHashKey, nsIMAPBodyShell> m_shellHash; // For quick lookup based on UID
nsIMAPBodyShellCache();
// Chooses an entry to eject; deletes that entry; and ejects it from the
// cache, clearing up a new space. Returns PR_TRUE if it found an entry
// to eject, PR_FALSE otherwise.
PRBool EjectEntry();
PRUint32 GetSize() { return m_shellList->Count(); }
PRUint32 GetMaxSize() { return 20; }
nsVoidArray *m_shellList; // For maintenance
// For quick lookup based on UID
nsRefPtrHashtableMT <nsCStringHashKey, nsIMAPBodyShell> m_shellHash;
};
// MessagePartID and MessagePartIDArray are used for pipelining prefetches.
class nsIMAPMessagePartID

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

@ -730,17 +730,18 @@ NS_IMETHODIMP nsIMAPHostSessionList::AddShellToCacheForHost(const char *serverKe
}
NS_IMETHODIMP nsIMAPHostSessionList::FindShellInCacheForHost(const char *serverKey, const char *mailboxName, const char *UID,
IMAP_ContentModifiedType modType, nsIMAPBodyShell **shell)
IMAP_ContentModifiedType modType, nsIMAPBodyShell **shell)
{
nsCString uidString(UID);
nsCString uidString(UID);
PR_EnterMonitor(gCachedHostInfoMonitor);
nsIMAPHostInfo *host = FindHost(serverKey);
if (host)
if (host->fShellCache)
*shell = host->fShellCache->FindShellForUID(uidString, mailboxName, modType);
PR_ExitMonitor(gCachedHostInfoMonitor);
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
PR_EnterMonitor(gCachedHostInfoMonitor);
nsIMAPHostInfo *host = FindHost(serverKey);
if (host && host->fShellCache)
NS_IF_ADDREF(*shell = host->fShellCache->FindShellForUID(uidString,
mailboxName,
modType));
PR_ExitMonitor(gCachedHostInfoMonitor);
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
}
NS_IMETHODIMP

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

@ -433,6 +433,7 @@ nsImapProtocol::nsImapProtocol() : nsMsgProtocol(nsnull),
getter_Copies(customDBHeaders));
ParseString(customDBHeaders, ' ', mCustomDBHeaders);
prefBranch->GetBoolPref("mailnews.display.prefer_plaintext", &m_preferPlainText);
}
// ***** Thread support *****
@ -2583,9 +2584,10 @@ void nsImapProtocol::ProcessSelectedStateURL()
IMAP_CONTENT_MODIFIED_VIEW_INLINE :
IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS ;
nsIMAPBodyShell *foundShell = nsnull;
nsRefPtr<nsIMAPBodyShell> foundShell;
res = m_hostSessionList->FindShellInCacheForHost(GetImapServerKey(),
GetServerStateParser().GetSelectedMailboxName(), messageIdString.get(), modType, &foundShell);
GetServerStateParser().GetSelectedMailboxName(),
messageIdString.get(), modType, getter_AddRefs(foundShell));
if (!foundShell)
{
// The shell wasn't in the cache. Deal with this case later.
@ -2640,7 +2642,7 @@ void nsImapProtocol::ProcessSelectedStateURL()
// Before fetching the bodystructure, let's check our body shell cache to see if
// we already have it around.
nsIMAPBodyShell *foundShell = NULL;
nsRefPtr<nsIMAPBodyShell> foundShell;
IMAP_ContentModifiedType modType = GetShowAttachmentsInline() ?
IMAP_CONTENT_MODIFIED_VIEW_INLINE :
IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS ;
@ -2662,7 +2664,8 @@ void nsImapProtocol::ProcessSelectedStateURL()
if (bMessageIdsAreUids)
{
res = m_hostSessionList->FindShellInCacheForHost(GetImapServerKey(),
GetServerStateParser().GetSelectedMailboxName(), messageIdString.get(), modType, &foundShell);
GetServerStateParser().GetSelectedMailboxName(),
messageIdString.get(), modType, getter_AddRefs(foundShell));
if (foundShell)
{
Log("SHELL",NULL,"Loading message, using cached shell.");
@ -2702,7 +2705,6 @@ void nsImapProtocol::ProcessSelectedStateURL()
m_flagState->SetMessageFlags(index, flags);
}
}
}
}
break;

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

@ -76,7 +76,6 @@ nsImapServerResponseParser::nsImapServerResponseParser(nsImapProtocol &imapProto
fSelectedMailboxName(nsnull),
fIMAPstate(kNonAuthenticated),
fLastChunk(PR_FALSE),
m_shell(nsnull),
fServerConnection(imapProtocolConnection),
fHostSessionList(nsnull)
{
@ -471,12 +470,10 @@ void nsImapServerResponseParser::ProcessOkCommand(const char *commandToken)
|| fServerConnection.DeathSignalReceived())
{
// we were pseudointerrupted or interrupted
// if it's not in the cache, then we were (pseudo)interrupted while generating
// for the first time. Release it.
if (!m_shell->IsShellCached())
{
// if it's not in the cache, then we were (pseudo)interrupted while generating
// for the first time. Delete it.
delete m_shell;
}
m_shell = nsnull;
navCon->PseudoInterrupt(PR_FALSE);
}
else if (m_shell->GetIsValid())
@ -491,12 +488,6 @@ void nsImapServerResponseParser::ProcessOkCommand(const char *commandToken)
serverKey, m_shell);
}
}
else
{
// The shell isn't valid, so we don't cache it.
// Therefore, we have to destroy it here.
delete m_shell;
}
m_shell = nsnull;
}
}
@ -508,20 +499,14 @@ void nsImapServerResponseParser::ProcessBadCommand(const char *commandToken)
!PL_strcasecmp(commandToken, "AUTHENTICATE"))
fIMAPstate = kNonAuthenticated;
else if (!PL_strcasecmp(commandToken, "LOGOUT"))
fIMAPstate = kNonAuthenticated; // ??
fIMAPstate = kNonAuthenticated; // ??
else if (!PL_strcasecmp(commandToken, "SELECT") ||
!PL_strcasecmp(commandToken, "EXAMINE"))
fIMAPstate = kAuthenticated; // nothing selected
fIMAPstate = kAuthenticated; // nothing selected
else if (!PL_strcasecmp(commandToken, "CLOSE"))
fIMAPstate = kAuthenticated; // nothing selected
if (GetFillingInShell())
{
if (!m_shell->IsBeingGenerated())
{
delete m_shell;
m_shell = nsnull;
}
}
fIMAPstate = kAuthenticated; // nothing selected
if (GetFillingInShell() && !m_shell->IsBeingGenerated())
m_shell = nsnull;
}

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

@ -45,6 +45,7 @@
#include "MailNewsTypes.h"
#include "nsTArray.h"
#include "nsImapUtils.h"
#include "nsAutoPtr.h"
class nsIMAPNamespace;
class nsIMAPNamespaceList;
@ -289,7 +290,7 @@ private:
PRBool fLastChunk;
// points to the current body shell, if any
nsIMAPBodyShell *m_shell;
nsRefPtr<nsIMAPBodyShell> m_shell;
// The connection object
nsImapProtocol &fServerConnection;