fix 169271 when displaying an imap message with parts, and falling back to fetching the whole msg because the parts are inline, store the msg for offline use if we would have stored it for offline use but for the parts, sr=mscott

This commit is contained in:
bienvenu%nventure.com 2004-05-20 23:28:49 +00:00
parent aa21b1c3e4
commit 688a4e589c
10 changed files with 170 additions and 137 deletions

View File

@ -105,7 +105,6 @@ interface nsIImapIncomingServer : nsISupports {
in boolean forceAllFolders,
in boolean performingBiff);
attribute boolean doingLsub;
void allowFolderConversion(out boolean allowConversion);
void convertFolderName(in string originalName, out wstring convertedName);
void hideFolderName(in string originalName, out boolean hideFolder);

View File

@ -113,7 +113,8 @@ interface nsIImapUrl : nsISupports
attribute nsISupports copyState;
attribute nsIFileSpec msgFileSpec;
attribute nsIImapMockChannel mockChannel;
attribute boolean shouldStoreMsgOffline; // set to true if we should store the msg for offline use if we can,
// i.e., we're not doing mime parts on demand.
void addChannelToLoadGroup();
void removeChannel(in nsresult aStatus);

View File

@ -274,7 +274,7 @@ PRInt32 nsIMAPBodyShell::Generate(char *partNum)
PRUint32 messageSize = m_protocolConnection->GetMessageSize(GetUID().get(), PR_TRUE);
m_protocolConnection->SetContentModified(IMAP_CONTENT_NOT_MODIFIED); // So that when we cache it, we know we have the whole message
if (!DeathSignalReceived())
m_protocolConnection->FetchTryChunking(GetUID().get(), kEveryThingRFC822, PR_TRUE, NULL, messageSize, PR_TRUE);
m_protocolConnection->FallbackToFetchWholeMsg(GetUID().get(), messageSize);
contentLength = (PRInt32) messageSize; // ugh
}
else

View File

@ -713,24 +713,24 @@ NS_IMETHODIMP nsIMAPHostSessionList::FlushUncommittedNamespacesForHost(const cha
// Returns NULL if there is no personal namespace on the given host
NS_IMETHODIMP nsIMAPHostSessionList::GetOnlineInboxPathForHost(const char *serverKey, nsString &result)
{
PR_EnterMonitor(gCachedHostInfoMonitor);
nsIMAPHostInfo *host = FindHost(serverKey);
if (host)
{
nsIMAPNamespace *ns = NULL;
ns = host->fNamespaceList->GetDefaultNamespaceOfType(kPersonalNamespace);
if (ns)
{
result.AssignWithConversion(ns->GetPrefix());
result.Append(NS_LITERAL_STRING("INBOX"));
}
}
else
{
result.SetLength(0);
}
PR_ExitMonitor(gCachedHostInfoMonitor);
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
PR_EnterMonitor(gCachedHostInfoMonitor);
nsIMAPHostInfo *host = FindHost(serverKey);
if (host)
{
nsIMAPNamespace *ns = NULL;
ns = host->fNamespaceList->GetDefaultNamespaceOfType(kPersonalNamespace);
if (ns)
{
result.AssignWithConversion(ns->GetPrefix());
result.Append(NS_LITERAL_STRING("INBOX"));
}
}
else
{
result.SetLength(0);
}
PR_ExitMonitor(gCachedHostInfoMonitor);
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
}
NS_IMETHODIMP nsIMAPHostSessionList::GetShouldAlwaysListInboxForHost(const char* /*serverKey*/, PRBool &result)

View File

@ -2751,6 +2751,18 @@ void nsImapProtocol::FetchMsgAttribute(const char * messageIds, const char *attr
// this routine is used to fetch a message or messages, or headers for a
// message...
void nsImapProtocol::FallbackToFetchWholeMsg(const char *messageId, PRUint32 messageSize)
{
if (m_imapMessageSink && m_runningUrl)
{
PRBool shouldStoreMsgOffline;
m_runningUrl->GetShouldStoreMsgOffline(&shouldStoreMsgOffline);
if (shouldStoreMsgOffline)
m_imapMessageSink->SetNotifyDownloadedLines(PR_TRUE);
}
FetchTryChunking(messageId, kEveryThingRFC822, PR_TRUE, NULL, messageSize, PR_TRUE);
}
void
nsImapProtocol::FetchMessage(const char * messageIds,
nsIMAPeFetchFields whatToFetch,

View File

@ -231,6 +231,7 @@ public:
PRUint32 downloadSize,
PRBool tryChunking);
virtual void PipelinedFetchMessageParts(nsCString &uid, nsIMAPMessagePartIDArray *parts);
void FallbackToFetchWholeMsg(const char *messageId, PRUint32 messageSize);
// used when streaming a message fetch
virtual nsresult BeginMessageDownLoad(PRUint32 totalSize, // for user, headers and body

View File

@ -182,7 +182,7 @@ void nsImapServerResponseParser::IncrementNumberOfTaggedResponsesExpected(const
void nsImapServerResponseParser::InitializeState()
{
fProcessingTaggedResponse = PR_FALSE;
fCurrentCommandFailed = PR_FALSE;
fCurrentCommandFailed = PR_FALSE;
}
void nsImapServerResponseParser::ParseIMAPServerResponse(const char *currentCommand, PRBool aIgnoreBadAndNOResponses)
@ -2461,10 +2461,10 @@ void nsImapServerResponseParser::acl_data()
void nsImapServerResponseParser::mime_data()
{
if (PL_strstr(fNextToken, "MIME"))
mime_header_data();
else
mime_part_data();
if (PL_strstr(fNextToken, "MIME"))
mime_header_data();
else
mime_part_data();
}
// mime_header_data should not be streamed out; rather, it should be
@ -2474,103 +2474,103 @@ void nsImapServerResponseParser::mime_data()
// we can construct the final output stream.
void nsImapServerResponseParser::mime_header_data()
{
char *partNumber = PL_strdup(fNextToken);
if (partNumber)
{
char *start = partNumber+5, *end = partNumber+5; // 5 == nsCRT::strlen("BODY[")
while (ContinueParse() && end && *end != 'M' && *end != 'm')
{
end++;
}
if (end && (*end == 'M' || *end == 'm'))
{
*(end-1) = 0;
fNextToken = GetNextToken();
char *mimeHeaderData = CreateAstring(); // is it really this simple?
fNextToken = GetNextToken();
if (m_shell)
{
m_shell->AdoptMimeHeader(start, mimeHeaderData);
}
}
else
{
SetSyntaxError(PR_TRUE);
}
PR_Free(partNumber); // partNumber is not adopted by the body shell.
}
else
{
HandleMemoryFailure();
}
char *partNumber = PL_strdup(fNextToken);
if (partNumber)
{
char *start = partNumber+5, *end = partNumber+5; // 5 == nsCRT::strlen("BODY[")
while (ContinueParse() && end && *end != 'M' && *end != 'm')
{
end++;
}
if (end && (*end == 'M' || *end == 'm'))
{
*(end-1) = 0;
fNextToken = GetNextToken();
char *mimeHeaderData = CreateAstring(); // is it really this simple?
fNextToken = GetNextToken();
if (m_shell)
{
m_shell->AdoptMimeHeader(start, mimeHeaderData);
}
}
else
{
SetSyntaxError(PR_TRUE);
}
PR_Free(partNumber); // partNumber is not adopted by the body shell.
}
else
{
HandleMemoryFailure();
}
}
// Actual mime parts are filled in on demand (either from shell generation
// or from explicit user download), so we need to stream these out.
void nsImapServerResponseParser::mime_part_data()
{
char *checkOriginToken = PL_strdup(fNextToken);
if (checkOriginToken)
{
PRUint32 origin = 0;
PRBool originFound = PR_FALSE;
char *whereStart = PL_strchr(checkOriginToken, '<');
if (whereStart)
{
char *whereEnd = PL_strchr(whereStart, '>');
if (whereEnd)
{
*whereEnd = 0;
whereStart++;
origin = atoi(whereStart);
originFound = PR_TRUE;
}
}
PR_Free(checkOriginToken);
fNextToken = GetNextToken();
msg_fetch_content(originFound, origin, MESSAGE_RFC822); // keep content type as message/rfc822, even though the
// MIME part might not be, because then libmime will
// still handle and decode it.
}
else
HandleMemoryFailure();
char *checkOriginToken = PL_strdup(fNextToken);
if (checkOriginToken)
{
PRUint32 origin = 0;
PRBool originFound = PR_FALSE;
char *whereStart = PL_strchr(checkOriginToken, '<');
if (whereStart)
{
char *whereEnd = PL_strchr(whereStart, '>');
if (whereEnd)
{
*whereEnd = 0;
whereStart++;
origin = atoi(whereStart);
originFound = PR_TRUE;
}
}
PR_Free(checkOriginToken);
fNextToken = GetNextToken();
msg_fetch_content(originFound, origin, MESSAGE_RFC822); // keep content type as message/rfc822, even though the
// MIME part might not be, because then libmime will
// still handle and decode it.
}
else
HandleMemoryFailure();
}
// FETCH BODYSTRUCTURE parser
// After exit, set fNextToken and fCurrentLine to the right things
void nsImapServerResponseParser::bodystructure_data()
{
fNextToken = GetNextToken();
// separate it out first
if (fNextToken && *fNextToken == '(') // It has to start with an open paren.
{
char *buf = CreateParenGroup();
if (ContinueParse())
{
if (!buf)
HandleMemoryFailure();
else
{
// Looks like we have what might be a valid BODYSTRUCTURE response.
// Try building the shell from it here.
m_shell = new nsIMAPBodyShell(&fServerConnection, buf, CurrentResponseUID(), GetSelectedMailboxName());
/*
if (m_shell)
{
if (!m_shell->GetIsValid())
{
SetSyntaxError(PR_TRUE);
}
}
*/
PR_Free(buf);
}
}
}
else
SetSyntaxError(PR_TRUE);
fNextToken = GetNextToken();
// separate it out first
if (fNextToken && *fNextToken == '(') // It has to start with an open paren.
{
char *buf = CreateParenGroup();
if (ContinueParse())
{
if (!buf)
HandleMemoryFailure();
else
{
// Looks like we have what might be a valid BODYSTRUCTURE response.
// Try building the shell from it here.
m_shell = new nsIMAPBodyShell(&fServerConnection, buf, CurrentResponseUID(), GetSelectedMailboxName());
/*
if (m_shell)
{
if (!m_shell->GetIsValid())
{
SetSyntaxError(PR_TRUE);
}
}
*/
PR_Free(buf);
}
}
}
else
SetSyntaxError(PR_TRUE);
}
void nsImapServerResponseParser::quota_data()

View File

@ -560,6 +560,9 @@ NS_IMETHODIMP nsImapService::DisplayMessage(const char* aMessageURI,
{
// whenever we are displaying a message, we want to add it to the memory cache..
imapUrl->SetFetchPartsOnDemand(PR_TRUE);
// if we happen to fetch the whole message, note in the url
// whether we want to store this message offline.
imapUrl->SetShouldStoreMsgOffline(shouldStoreMsgOffline);
shouldStoreMsgOffline = PR_FALSE; // if we're fetching by parts, don't store offline
msgurl->SetAddToMemoryCache(PR_FALSE);
}
@ -833,6 +836,9 @@ NS_IMETHODIMP nsImapService::Search(nsIMsgSearchSession *aSearchSession, nsIMsgW
GetFolderName(aMsgFolder, getter_Copies(folderName));
nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(imapUrl);
if (!aMsgWindow)
mailNewsUrl->SetSuppressErrorMsgs(PR_TRUE);
urlSpec.Append("/search>UID>");
urlSpec.Append(char(hierarchySeparator));
urlSpec.Append((const char *) folderName);

View File

@ -88,6 +88,7 @@ nsImapUrl::nsImapUrl()
m_allowContentChange = PR_TRUE; // assume we can do MPOD.
m_fetchPartsOnDemand = PR_FALSE; // but assume we're not doing it :-)
m_msgLoadingFromCache = PR_FALSE;
m_shouldStoreMsgOffline = PR_FALSE;
m_externalLinkUrl = PR_TRUE; // we'll start this at true, and set it false in nsImapService::CreateStartOfImapUrl
m_contentModified = IMAP_CONTENT_NOT_MODIFIED;
m_validUrl = PR_TRUE; // assume the best.
@ -346,10 +347,10 @@ NS_IMETHODIMP nsImapUrl::CreateSearchCriteriaString(char ** aResult)
{
// this method should only be called from the imap thread...
// o.t. add lock protection..
if (nsnull == aResult || !m_searchCriteriaString)
return NS_ERROR_NULL_POINTER;
if (nsnull == aResult || !m_searchCriteriaString)
return NS_ERROR_NULL_POINTER;
*aResult = nsCRT::strdup(m_searchCriteriaString);
return NS_OK;
return NS_OK;
}
// this method gets called from the UI thread and the imap thread
@ -357,30 +358,30 @@ NS_IMETHODIMP nsImapUrl::CreateListOfMessageIdsString(char ** aResult)
{
nsAutoCMonitor mon(this);
nsCAutoString newStr;
if (nsnull == aResult || !m_listOfMessageIds)
return NS_ERROR_NULL_POINTER;
if (nsnull == aResult || !m_listOfMessageIds)
return NS_ERROR_NULL_POINTER;
PRInt32 bytesToCopy = strlen(m_listOfMessageIds);
// mime may have glommed a "&part=" for a part download
// we return the entire message and let mime extract
// the part. Pop and news work this way also.
// this algorithm truncates the "&part" string.
char *currentChar = m_listOfMessageIds;
while (*currentChar && (*currentChar != '?'))
currentChar++;
if (*currentChar == '?')
bytesToCopy = currentChar - m_listOfMessageIds;
// we should also strip off anything after "/;section="
// since that can specify an IMAP MIME part
char *wherePart = PL_strstr(m_listOfMessageIds, "/;section=");
if (wherePart)
bytesToCopy = PR_MIN(bytesToCopy, wherePart - m_listOfMessageIds);
newStr.Assign(m_listOfMessageIds, bytesToCopy);
// mime may have glommed a "&part=" for a part download
// we return the entire message and let mime extract
// the part. Pop and news work this way also.
// this algorithm truncates the "&part" string.
char *currentChar = m_listOfMessageIds;
while (*currentChar && (*currentChar != '?'))
currentChar++;
if (*currentChar == '?')
bytesToCopy = currentChar - m_listOfMessageIds;
// we should also strip off anything after "/;section="
// since that can specify an IMAP MIME part
char *wherePart = PL_strstr(m_listOfMessageIds, "/;section=");
if (wherePart)
bytesToCopy = PR_MIN(bytesToCopy, wherePart - m_listOfMessageIds);
newStr.Assign(m_listOfMessageIds, bytesToCopy);
*aResult = ToNewCString(newStr);
return NS_OK;
return NS_OK;
}
NS_IMETHODIMP nsImapUrl::GetCommand(char **result)
@ -1132,7 +1133,7 @@ NS_IMETHODIMP nsImapUrl::SetAllowContentChange(PRBool allowContentChange)
NS_IMETHODIMP nsImapUrl::SetContentModified(nsImapContentModifiedType contentModified)
{
m_contentModified = contentModified;
m_contentModified = contentModified;
nsCOMPtr<nsICacheEntryDescriptor> cacheEntry;
nsresult res = GetMemCacheEntry(getter_AddRefs(cacheEntry));
if (NS_SUCCEEDED(res) && cacheEntry)
@ -1612,3 +1613,15 @@ NS_IMETHODIMP nsImapUrl::SetCharsetOverRide(const char * aCharacterSet)
return NS_OK;
}
NS_IMETHODIMP nsImapUrl::GetShouldStoreMsgOffline(PRBool *aShouldStoreMsgOffline)
{
NS_ENSURE_ARG_POINTER(aShouldStoreMsgOffline);
*aShouldStoreMsgOffline = m_shouldStoreMsgOffline;
return NS_OK;
}
NS_IMETHODIMP nsImapUrl::SetShouldStoreMsgOffline(PRBool aShouldStoreMsgOffline)
{
m_shouldStoreMsgOffline = aShouldStoreMsgOffline;
return NS_OK;
}

View File

@ -125,6 +125,7 @@ protected:
PRPackedBool m_fetchPartsOnDemand; // if PR_TRUE, we should fetch leave parts on server.
PRPackedBool m_msgLoadingFromCache; // if PR_TRUE, we might need to mark read on server
PRPackedBool m_externalLinkUrl; // if PR_TRUE, we're running this url because the user
PRPackedBool m_shouldStoreMsgOffline;
nsImapContentModifiedType m_contentModified;
PRInt32 m_discoveryDepth;