Bug #73819 --> hook imap and news up to the new memory cache.

r/sr=sspitzer,bienvenu
This commit is contained in:
mscott%netscape.com 2001-04-13 03:48:37 +00:00
Родитель f77df37354
Коммит c6ef67e961
17 изменённых файлов: 512 добавлений и 299 удалений

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

@ -30,7 +30,7 @@ interface nsIMsgIncomingServer;
interface nsIMsgWindow;
interface nsILoadGroup;
interface nsIMsgSearchSession;
interface nsICachedNetData;
interface nsICacheEntryDescriptor;
[scriptable, uuid(6CFFCEB0-CB8C-11d2-8065-006008128C4E)]
interface nsIMsgMailNewsUrl : nsIURL {
@ -72,7 +72,7 @@ interface nsIMsgMailNewsUrl : nsIURL {
attribute boolean msgIsInLocalCache;
attribute boolean suppressErrorMsgs; // used to avoid displaying biff error messages
attribute nsICachedNetData memCacheEntry;
attribute nsICacheEntryDescriptor memCacheEntry;
const unsigned long eCopy = 0;
const unsigned long eMove = 1;
@ -98,8 +98,8 @@ interface nsIMsgMessageUrl : nsISupports {
// used by imap, pop and nntp in order to implement save message to disk
attribute nsIFileSpec messageFile;
attribute boolean AddDummyEnvelope;
attribute boolean canonicalLineEnding;
attribute string originalSpec;
attribute boolean canonicalLineEnding;
attribute string originalSpec;
};
//////////////////////////////////////////////////////////////////////////////////

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

@ -34,7 +34,6 @@
#include "nsIWebProgressListener.h"
#include "nsIInterfaceRequestor.h"
#include "nsIIOService.h"
#include "nsINetDataCacheManager.h"
#include "nsNetCID.h"
static NS_DEFINE_CID(kUrlListenerManagerCID, NS_URLLISTENERMANAGER_CID);
@ -605,36 +604,17 @@ NS_IMETHODIMP nsMsgMailNewsUrl::SetFilePath(const char *i_DirFile)
return m_baseURL->SetFilePath(i_DirFile);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetMemCacheEntry(nsICachedNetData *memCacheEntry)
NS_IMETHODIMP nsMsgMailNewsUrl::SetMemCacheEntry(nsICacheEntryDescriptor *memCacheEntry)
{
m_memCacheEntry = memCacheEntry;
return NS_OK;
}
NS_IMETHODIMP nsMsgMailNewsUrl:: GetMemCacheEntry(nsICachedNetData **memCacheEntry)
NS_IMETHODIMP nsMsgMailNewsUrl:: GetMemCacheEntry(nsICacheEntryDescriptor **memCacheEntry)
{
NS_ENSURE_ARG(memCacheEntry);
nsresult rv = NS_OK;
if (!m_memCacheEntry)
{
nsCOMPtr<nsINetDataCacheManager> cacheManager = do_GetService(NS_NETWORK_CACHE_MANAGER_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv) && cacheManager)
{
// Retrieve an existing cache entry or create a new one if none exists for the
// given URL.
nsXPIDLCString urlCString;
// eventually we are going to want to use the url spec - the query/ref part 'cause that doesn't
// distinguish urls.......
GetSpec(getter_Copies(urlCString));
// for now, truncate of the query part so we don't duplicate urls in the cache...
char * anchor = PL_strrchr(urlCString, '?');
if (anchor)
*anchor = '\0';
rv = cacheManager->GetCachedNetData(urlCString, 0, 0, nsINetDataCacheManager::BYPASS_PERSISTENT_CACHE,
getter_AddRefs(m_memCacheEntry));
}
}
if (m_memCacheEntry)
{
*memCacheEntry = m_memCacheEntry;
@ -645,6 +625,6 @@ NS_IMETHODIMP nsMsgMailNewsUrl:: GetMemCacheEntry(nsICachedNetData **memCacheEnt
*memCacheEntry = nsnull;
return NS_ERROR_NULL_POINTER;
}
return rv;
}

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

@ -18,6 +18,7 @@
* Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*/
#ifndef nsMsgMailNewsUrl_h___
@ -34,7 +35,8 @@
#include "nsIURL.h"
#include "nsILoadGroup.h"
#include "nsIMsgSearchSession.h"
#include "nsICachedNetData.h"
#include "nsICacheEntryDescriptor.h"
///////////////////////////////////////////////////////////////////////////////////
// Okay, I found that all of the mail and news url interfaces needed to support
// several common interfaces (in addition to those provided through nsIURI).
@ -64,7 +66,7 @@ protected:
nsCOMPtr<nsIMsgWindow> m_msgWindow;
nsCOMPtr<nsILoadGroup> m_loadGroup;
nsCOMPtr<nsIMsgSearchSession> m_searchSession;
nsCOMPtr<nsICachedNetData> m_memCacheEntry;
nsCOMPtr<nsICacheEntryDescriptor> m_memCacheEntry;
char *m_errorMessage;
PRBool m_runningUrl;
PRBool m_updatingFolder;

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

@ -27,13 +27,13 @@
#include "nsIMailboxSpec.idl"
interface nsIMsgMailNewsUrl;
interface nsIImapMockChannel;
typedef long ImapOnlineCopyState;
[scriptable, uuid(5f7484b0-68b4-11d3-a53e-0060b0fc04b7)]
interface ImapOnlineCopyStateType
{
interface ImapOnlineCopyStateType
{
const long kInProgress = 0;
const long kSuccessfulCopy = 1;
const long kSuccessfulMove = 2;
@ -44,34 +44,32 @@ typedef long ImapOnlineCopyState;
const long kInterruptedState = 7;
const long kFailedCopy = 8;
const long kFailedMove = 9;
};
};
[scriptable, uuid(3b2dd7e0-e72c-11d2-ab7b-00805f8ac968)]
interface nsIImapMailFolderSink : nsISupports {
attribute boolean folderNeedsACLListed;
attribute boolean folderNeedsSubscribing;
attribute boolean folderNeedsAdded;
attribute boolean folderNeedsACLListed;
attribute boolean folderNeedsSubscribing;
attribute boolean folderNeedsAdded;
attribute boolean folderVerifiedOnline;
string GetOnlineDelimiter();
// Tell mail master about the newly selected mailbox
void UpdateImapMailboxInfo(in nsIImapProtocol aProtocol,
string GetOnlineDelimiter();
// Tell mail master about the newly selected mailbox
void UpdateImapMailboxInfo(in nsIImapProtocol aProtocol,
in nsIMailboxSpec aSpec);
void UpdateImapMailboxStatus(in nsIImapProtocol aProtocol,
in nsIMailboxSpec aSpec);
void UpdateImapMailboxStatus(in nsIImapProtocol aProtocol,
in nsIMailboxSpec aSpec);
void ChildDiscoverySucceeded(in nsIImapProtocol aProtocol) ;
void PromptUserForSubscribeUpdatePath(in nsIImapProtocol aProtocol,
out boolean aBool) ;
void SetupHeaderParseStream(in nsIImapProtocol aProtocol, in unsigned long size, in string content_type, in nsIMailboxSpec boxSpec);
void ChildDiscoverySucceeded(in nsIImapProtocol aProtocol) ;
void PromptUserForSubscribeUpdatePath(in nsIImapProtocol aProtocol,
out boolean aBool) ;
void SetupHeaderParseStream(in nsIImapProtocol aProtocol, in unsigned long size, in string content_type, in nsIMailboxSpec boxSpec);
void ParseAdoptedHeaderLine(in nsIImapProtocol aProtocol, in string messageLine, in unsigned long msgKey) ;
void NormalEndHeaderParseStream(in nsIImapProtocol aProtocol);
void AbortHeaderParseStream(in nsIImapProtocol aProtocol) ;
void OnlineCopyCompleted(in nsIImapProtocol aProtocol, in ImapOnlineCopyState aCopyState);
void ParseAdoptedHeaderLine(in nsIImapProtocol aProtocol, in string messageLine, in unsigned long msgKey) ;
void NormalEndHeaderParseStream(in nsIImapProtocol aProtocol);
void AbortHeaderParseStream(in nsIImapProtocol aProtocol) ;
void OnlineCopyCompleted(in nsIImapProtocol aProtocol, in ImapOnlineCopyState aCopyState);
void StartMessage(in nsIMsgMailNewsUrl aUrl);
void EndMessage(in nsIMsgMailNewsUrl aUrl, in nsMsgKey uidOfMessage);
@ -82,4 +80,5 @@ interface nsIImapMailFolderSink : nsISupports {
// are only released / destroyed from the UI thread.
void PrepareToReleaseUrl(in nsIMsgMailNewsUrl aUrl);
void ReleaseUrl();
void CloseMockChannel(in nsIImapMockChannel aChannel);
};

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

@ -40,6 +40,7 @@ interface nsIEventQueue;
interface nsIMsgFolder;
interface nsIMsgWindow;
interface nsIImapIncomingServer;
interface nsICacheSession;
[scriptable, uuid(18236127-FA1D-11d3-98BA-001083010E9B)]
@ -224,4 +225,6 @@ interface nsIImapService : nsISupports
void playbackAllOfflineOperations(in nsIMsgWindow aMsgWindow, in nsIUrlListener aListener);
void downloadAllOffineImapFolders(in nsIMsgWindow aMsgWindow, in nsIUrlListener aListener);
readonly attribute nsICacheSession cacheSession;
};

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

@ -65,9 +65,7 @@
#include "nsIPrompt.h"
#include "nsIWindowWatcher.h"
// for the memory cache...
#include "nsINetDataCacheManager.h"
#include "nsINetDataCache.h"
#include "nsICachedNetData.h"
#include "nsICacheEntryDescriptor.h"
#include "nsImapUrl.h"
#include "nsFileStream.h"
@ -475,10 +473,8 @@ nsImapIncomingServer::LoadNextQueuedUrl(PRBool *aResult)
while (cnt > 0 && !urlRun && keepGoing)
{
nsCOMPtr<nsISupports>
aSupport(getter_AddRefs(m_urlQueue->ElementAt(0)));
nsCOMPtr<nsIImapUrl>
aImapUrl(do_QueryInterface(aSupport, &rv));
nsCOMPtr<nsISupports> aSupport(getter_AddRefs(m_urlQueue->ElementAt(0)));
nsCOMPtr<nsIImapUrl> aImapUrl(do_QueryInterface(aSupport, &rv));
nsCOMPtr<nsIMsgMailNewsUrl> aMailNewsUrl(do_QueryInterface(aSupport, &rv));
if (aImapUrl)
@ -487,9 +483,9 @@ nsImapIncomingServer::LoadNextQueuedUrl(PRBool *aResult)
if (NS_SUCCEEDED(aImapUrl->GetMockChannel(getter_AddRefs(mockChannel))) && mockChannel)
{
nsCOMPtr<nsIRequest> request = do_QueryInterface(mockChannel);
nsCOMPtr<nsIRequest> request = do_QueryInterface(mockChannel);
if (!request)
return NS_ERROR_FAILURE;
return NS_ERROR_FAILURE;
request->GetStatus(&rv);
if (!NS_SUCCEEDED(rv))
{
@ -500,10 +496,10 @@ nsImapIncomingServer::LoadNextQueuedUrl(PRBool *aResult)
if (aMailNewsUrl)
{
nsCOMPtr<nsICachedNetData> cacheEntry;
nsCOMPtr<nsICacheEntryDescriptor> cacheEntry;
res = aMailNewsUrl->GetMemCacheEntry(getter_AddRefs(cacheEntry));
if (NS_SUCCEEDED(res) && cacheEntry)
cacheEntry->Delete();
cacheEntry->Doom();
}
}
}
@ -511,14 +507,11 @@ nsImapIncomingServer::LoadNextQueuedUrl(PRBool *aResult)
// between the place we set it and here.
if (NS_SUCCEEDED(rv))
{
nsISupports *aConsumer =
(nsISupports*)m_urlConsumers.ElementAt(0);
nsISupports *aConsumer = (nsISupports*)m_urlConsumers.ElementAt(0);
NS_IF_ADDREF(aConsumer);
nsCOMPtr <nsIImapProtocol> protocolInstance ;
rv = CreateImapConnection(nsnull, aImapUrl,
getter_AddRefs(protocolInstance));
rv = CreateImapConnection(nsnull, aImapUrl, getter_AddRefs(protocolInstance));
if (NS_SUCCEEDED(rv) && protocolInstance)
{
nsCOMPtr<nsIURI> url = do_QueryInterface(aImapUrl, &rv);

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

@ -70,6 +70,7 @@
#include "nsImapOfflineSync.h"
#include "nsIMsgAccountManager.h"
#include "nsQuickSort.h"
#include "nsIImapMockChannel.h"
static NS_DEFINE_CID(kMsgAccountManagerCID, NS_MSGACCOUNTMANAGER_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
@ -3416,6 +3417,13 @@ nsImapMailFolder::ReleaseUrl()
return NS_OK;
}
NS_IMETHODIMP
nsImapMailFolder::CloseMockChannel(nsIImapMockChannel * aChannel)
{
aChannel->Close();
return NS_OK;
}
NS_IMETHODIMP
nsImapMailFolder::BeginMessageUpload()
{

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

@ -59,7 +59,8 @@
#include "nsIDNSService.h"
#include "nsIMsgHdr.h"
// for the memory cache...
#include "nsICachedNetData.h"
#include "nsICacheEntryDescriptor.h"
#include "nsICacheSession.h"
#include "nsCOMPtr.h"
PRLogModuleInfo *IMAP;
@ -90,6 +91,7 @@ static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CI
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID);
#define OUTPUT_BUFFER_SIZE (4096*2) // mscott - i should be able to remove this if I can use nsMsgLineBuffer???
@ -637,7 +639,7 @@ nsresult nsImapProtocol::SetupWithUrl(nsIURI * aURL, nsISupports* aConsumer)
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_runningUrl);
if (mailnewsUrl)
{
nsCOMPtr<nsICachedNetData> cacheEntry;
nsCOMPtr<nsICacheEntryDescriptor> cacheEntry;
mailnewsUrl->GetMemCacheEntry(getter_AddRefs(cacheEntry));
if (cacheEntry)
cacheEntry->SetSecurityInfo(securityInfo);
@ -654,7 +656,10 @@ void nsImapProtocol::ReleaseUrlState()
{
if (m_mockChannel)
{
m_mockChannel->Close();
if (m_imapMailFolderSink)
m_imapMailFolderSink->CloseMockChannel(m_mockChannel);
else
m_mockChannel->Close();
m_mockChannel = null_nsCOMPtr();
}
if (m_runningUrl)
@ -6790,6 +6795,7 @@ NS_INTERFACE_MAP_BEGIN(nsImapMockChannel)
NS_INTERFACE_MAP_ENTRY(nsIImapMockChannel)
NS_INTERFACE_MAP_ENTRY(nsIChannel)
NS_INTERFACE_MAP_ENTRY(nsIRequest)
NS_INTERFACE_MAP_ENTRY(nsICacheListener)
NS_INTERFACE_MAP_END_THREADSAFE
@ -6807,8 +6813,10 @@ nsImapMockChannel::~nsImapMockChannel()
NS_IMETHODIMP nsImapMockChannel::Close()
{
m_channelListener = null_nsCOMPtr();
return NS_OK;
m_channelListener = null_nsCOMPtr();
mCacheRequest = null_nsCOMPtr();
m_url = null_nsCOMPtr();
return NS_OK;
}
NS_IMETHODIMP nsImapMockChannel::GetProgressEventSink(nsIProgressEventSink ** aProgressEventSink)
@ -6885,18 +6893,18 @@ NS_IMETHODIMP nsImapMockChannel::SetURI(nsIURI* aURI)
if (!aURI)
printf("Clearing URI\n");
#endif
if (m_url)
if (m_url)
{
// if we don't have a progress event sink yet, get it from the url for now...
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_url);
if (mailnewsUrl && !mProgressEventSink)
{
// if we don't have a progress event sink yet, get it from the url for now...
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_url);
if (mailnewsUrl && !mProgressEventSink)
{
nsCOMPtr<nsIMsgStatusFeedback> statusFeedback;
mailnewsUrl->GetStatusFeedback(getter_AddRefs(statusFeedback));
mProgressEventSink = do_QueryInterface(statusFeedback);
}
nsCOMPtr<nsIMsgStatusFeedback> statusFeedback;
mailnewsUrl->GetStatusFeedback(getter_AddRefs(statusFeedback));
mProgressEventSink = do_QueryInterface(statusFeedback);
}
return NS_OK;
}
return NS_OK;
}
NS_IMETHODIMP nsImapMockChannel::Open(nsIInputStream **_retval)
@ -6905,70 +6913,100 @@ NS_IMETHODIMP nsImapMockChannel::Open(nsIInputStream **_retval)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsImapMockChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
NS_IMETHODIMP
nsImapMockChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry, nsCacheAccessMode access, nsresult status)
{
nsCOMPtr<nsICachedNetData> cacheEntry;
PRUint32 contentLength = 0;
PRBool partialFlag = PR_FALSE;
// set the stream listener and then load the url
m_channelContext = ctxt;
m_channelListener = listener;
nsresult rv = NS_OK;
nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(m_url);
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_url, &rv);
if (NS_FAILED(rv)) return rv;
// look to see if this url should be added to the memory cache..
PRBool useMemoryCache = PR_FALSE;
mailnewsUrl->GetAddToMemoryCache(&useMemoryCache);
rv = mailnewsUrl->GetMemCacheEntry(getter_AddRefs(cacheEntry));
if (NS_SUCCEEDED(rv) && cacheEntry)
if (NS_SUCCEEDED(status))
{
PRBool updateInProgress;
cacheEntry->GetPartialFlag(&partialFlag);
cacheEntry->GetUpdateInProgress(&updateInProgress);
cacheEntry->GetStoredContentLength(&contentLength);
// only try to update the cache entry if it isn't being used.
// We always want to try to write to the cache entry if we can
if (!updateInProgress)
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_url, &rv);
mailnewsUrl->SetMemCacheEntry(entry);
// if we have write access then insert a "stream T" into the flow so data
// gets written to both
if (access & nsICache::ACCESS_WRITE && !(access & nsICache::ACCESS_READ))
{
// now we need to figure out if the entry is new / or partially unfinished...
// this determines if we are going to USE the cache entry for reading the data
// vs. if we need to write data into the cache entry...
if (!contentLength || partialFlag)
// we're going to fill up this cache entry,
rv = cacheEntry->InterceptAsyncRead(listener, 0, getter_AddRefs(m_channelListener));
entry->MarkValid();
// use a stream listener Tee to force data into the cache and to our current channel listener...
nsCOMPtr<nsIStreamListener> newListener;
nsCOMPtr<nsIStreamListenerTee> tee = do_CreateInstance(kStreamListenerTeeCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsITransport> transport;
rv = entry->GetTransport(getter_AddRefs(transport));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIOutputStream> out;
rv = transport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(out));
NS_ENSURE_SUCCESS(rv, rv);
rv = tee->Init(m_channelListener, out);
m_channelListener = do_QueryInterface(tee);
NS_ENSURE_SUCCESS(rv, rv);
}
}
// now, determine if we should be loading from the cache or if we have
// to really load the msg with a protocol connection...
if (cacheEntry && contentLength > 0 && !partialFlag)
{
PRUint32 annotationLength = 0;
char *annotation = nsnull;
rv = cacheEntry->GetAnnotation("ContentModified", &annotationLength, &annotation);
if (NS_SUCCEEDED(rv) && annotationLength == nsCRT::strlen("Not Modified")
&& annotation && !nsCRT::strncmp(annotation, "Not Modified", annotationLength))
else
{
nsCOMPtr<nsIChannel> cacheChannel;
rv = cacheEntry->NewChannel(m_loadGroup, getter_AddRefs(cacheChannel));
rv = ReadFromMemCache(entry);
if (access & nsICache::ACCESS_WRITE)
entry->MarkValid();
if (NS_SUCCEEDED(rv)) return NS_OK; // kick out if reading from the cache succeeded...
}
} // if we got a valid entry back from the cache...
// if reading from the cache failed or if we are writing into the cache, default to ReadFromImapConnection.
return ReadFromImapConnection();
}
nsresult nsImapMockChannel::OpenCacheEntry()
{
nsresult rv = NS_OK;
// get the cache session from our imap service...
nsCOMPtr<nsIImapService> imapService = do_GetService(kCImapService, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsICacheSession> cacheSession;
rv = imapService->GetCacheSession(getter_AddRefs(cacheSession));
NS_ENSURE_SUCCESS(rv, rv);
// Open a cache entry with key = url
nsXPIDLCString urlSpec;
m_url->GetSpec(getter_Copies(urlSpec));
// for now, truncate of the query part so we don't duplicate urls in the cache...
char * anchor = PL_strrchr(urlSpec, '?');
if (anchor)
*anchor = '\0';
return cacheSession->AsyncOpenCacheEntry(urlSpec, nsICache::ACCESS_READ_WRITE, this);
}
nsresult nsImapMockChannel::ReadFromMemCache(nsICacheEntryDescriptor *entry)
{
NS_ENSURE_ARG(entry);
PRUint32 annotationLength = 0;
nsXPIDLCString annotation;
nsresult rv = NS_OK;
rv = entry->GetMetaDataElement("ContentModified", getter_Copies(annotation));
if (NS_SUCCEEDED(rv) && (annotation.get()))
{
annotationLength = nsCRT::strlen(annotation.get());
if (annotationLength == nsCRT::strlen("Not Modified") && !nsCRT::strncmp(annotation, "Not Modified", annotationLength))
{
nsCOMPtr<nsITransport> cacheTransport;
rv = entry->GetTransport(getter_AddRefs(cacheTransport));
if (NS_SUCCEEDED(rv))
{
// if we are going to read from the cache, then create a mock stream listener class and use it
nsImapCacheStreamListener * cacheListener = new nsImapCacheStreamListener();
NS_ADDREF(cacheListener);
SetupPartExtractor(imapUrl, m_channelListener);
cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this));
rv = cacheChannel->AsyncOpen(cacheListener, m_channelContext);
rv = cacheTransport->AsyncRead(cacheListener, m_channelContext, 0, PRUint32(-1), 0, getter_AddRefs(mCacheRequest));
NS_RELEASE(cacheListener);
if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return
{
nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(m_url);
// if the msg is unread, we should mark it read on the server. This lets
// the code running this url we're loading from the cache, if it cares.
imapUrl->SetMsgLoadingFromCache(PR_TRUE);
@ -6979,15 +7017,58 @@ NS_IMETHODIMP nsImapMockChannel::AsyncOpen(nsIStreamListener *listener, nsISuppo
// be sure to set the cache entry's security info status as our security info status...
nsCOMPtr<nsISupports> securityInfo;
cacheEntry->GetSecurityInfo(getter_AddRefs(securityInfo));
entry->GetSecurityInfo(getter_AddRefs(securityInfo));
SetSecurityInfo(securityInfo);
return rv;
}
}
}
}
return NS_OK;
} // if AsyncRead succeeded.
} // if get transport succeeded
} // if contnet is not modified
else
rv = NS_ERROR_FAILURE; // content is modified so return an error so we try to open it the old fashioned way
} // if we got an annotation
return rv;
}
// the requested url isn't in any of our caches so create an imap connection
// to process it.
nsresult nsImapMockChannel::ReadFromImapConnection()
{
nsresult rv = NS_OK;
nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(m_url);
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_url);
// okay, add the mock channel to the load group..
imapUrl->AddChannelToLoadGroup();
// loading the url consists of asking the server to add the url to it's imap event queue....
nsCOMPtr<nsIMsgIncomingServer> server;
rv = mailnewsUrl->GetServer(getter_AddRefs(server));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIImapIncomingServer> imapServer (do_QueryInterface(server, &rv));
NS_ENSURE_SUCCESS(rv, rv);
// Assume AsyncRead is always called from the UI thread.....
nsCOMPtr<nsIEventQueue> queue;
// get the Event Queue for this thread...
nsCOMPtr<nsIEventQueueService> pEventQService (do_GetService(kEventQueueServiceCID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
NS_ENSURE_SUCCESS(rv, rv);
rv = imapServer->GetImapConnectionAndLoadUrl(queue, imapUrl, nsnull);
return rv;
}
// for messages stored in our offline cache, we have special code to handle that...
// If it's in the local cache, we return true and we can abort the download because
// this method does the rest of the work.
PRBool nsImapMockChannel::ReadFromLocalCache()
{
nsresult rv = NS_OK;
nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(m_url);
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_url, &rv);
// check if msg is in local cache.
PRBool useLocalCache = PR_FALSE;
mailnewsUrl->GetMsgIsInLocalCache(&useLocalCache);
if (useLocalCache)
@ -6998,7 +7079,7 @@ NS_IMETHODIMP nsImapMockChannel::AsyncOpen(nsIStreamListener *listener, nsISuppo
rv = imapUrl->GetImapFolder(getter_AddRefs(folder));
if (folder && NS_SUCCEEDED(rv))
{
// we want to create a file channel and read the msg from there.
// we want to create a file channel and read the msg from there.
nsCOMPtr<nsITransport> fileChannel;
nsMsgKey msgKey = atoi(messageIdString);
PRUint32 size, offset;
@ -7007,17 +7088,15 @@ NS_IMETHODIMP nsImapMockChannel::AsyncOpen(nsIStreamListener *listener, nsISuppo
// folder sink?) We also need to set the transfer offset to the message offset
if (fileChannel && NS_SUCCEEDED(rv))
{
// dougt - This may break the ablity to "cancel" a read from offline mail reading.
// fileChannel->SetLoadGroup(m_loadGroup);
// dougt - This may break the ablity to "cancel" a read from offline mail reading.
// fileChannel->SetLoadGroup(m_loadGroup);
// force the url to remove its reference on the mock channel...this is to solve
// a nasty reference counting problem...
imapUrl->SetMockChannel(nsnull);
// if we are going to read from the cache, then create a mock stream listener class and use it
nsImapCacheStreamListener * cacheListener = new nsImapCacheStreamListener();
NS_ADDREF(cacheListener);
SetupPartExtractor(imapUrl, m_channelListener);
cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this));
nsCOMPtr<nsIRequest> request;
rv = fileChannel->AsyncRead(cacheListener, m_channelContext, offset, size, 0, getter_AddRefs(request));
@ -7028,37 +7107,40 @@ NS_IMETHODIMP nsImapMockChannel::AsyncOpen(nsIStreamListener *listener, nsISuppo
// if the msg is unread, we should mark it read on the server. This lets
// the code running this url we're loading from the cache, if it cares.
imapUrl->SetMsgLoadingFromCache(PR_TRUE);
return rv;
return PR_TRUE;
}
}
}
}
} // if we got an offline file transport
} // if we got the folder for this url
} // if use local cache
SetupPartExtractor(imapUrl, m_channelListener);
// okay, add the mock channel to the load group..
imapUrl->AddChannelToLoadGroup();
// loading the url consists of asking the server to add the url to it's imap event queue....
nsCOMPtr<nsIMsgIncomingServer> server;
rv = mailnewsUrl->GetServer(getter_AddRefs(server));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIImapIncomingServer> imapServer;
imapServer = do_QueryInterface(server, &rv);
if (NS_FAILED(rv)) return rv;
// Assume AsyncRead is always called from the UI thread.....
nsCOMPtr<nsIEventQueue> queue;
// get the Event Queue for this thread...
NS_WITH_SERVICE(nsIEventQueueService, pEventQService,kEventQueueServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
if (NS_FAILED(rv)) return rv;
rv = imapServer->GetImapConnectionAndLoadUrl(queue, imapUrl, nsnull);
return rv;
return PR_FALSE;
}
nsresult nsImapMockChannel::SetupPartExtractor(nsIImapUrl * aUrl, nsIStreamListener * aConsumer)
NS_IMETHODIMP nsImapMockChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
{
nsresult rv = NS_OK;
// set the stream listener and then load the url
m_channelContext = ctxt;
m_channelListener = listener;
nsCOMPtr<nsIImapUrl> imapUrl (do_QueryInterface(m_url));
SetupPartExtractorListener(imapUrl, m_channelListener);
if (ReadFromLocalCache())
return NS_OK;
// okay, it's not in the local cache, now check the memory cache...
rv = OpenCacheEntry();
// if for some reason open cache entry failed then just default to opening an imap connection for the url
if (NS_FAILED(rv))
return ReadFromImapConnection();
else
return NS_OK;
}
nsresult nsImapMockChannel::SetupPartExtractorListener(nsIImapUrl * aUrl, nsIStreamListener * aConsumer)
{
// if the url we are loading refers to a specific part then we need
// libmime to extract that part from the message for us.
@ -7071,7 +7153,7 @@ nsresult nsImapMockChannel::SetupPartExtractor(nsIImapUrl * aUrl, nsIStreamListe
{
nsCOMPtr<nsIStreamListener> newConsumer;
converter->AsyncConvertData(NS_LITERAL_STRING("message/rfc822").get(), NS_LITERAL_STRING("*/*").get(),
aConsumer, this, getter_AddRefs(newConsumer));
aConsumer, NS_STATIC_CAST(nsIChannel *, this), getter_AddRefs(newConsumer));
if (newConsumer)
m_channelListener = newConsumer;
}

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

@ -63,6 +63,7 @@
#include "nsXPIDLString.h"
#include "nsIMsgWindow.h"
#include "nsIMsgLogonRedirector.h"
#include "nsICacheListener.h"
class nsIMAPMessagePartIDArray;
class nsIMsgIncomingServer;
@ -578,7 +579,9 @@ private:
//
// Threading concern: This class lives entirely in the UI thread.
class nsImapMockChannel : public nsIImapMockChannel
class nsICacheEntryDescriptor;
class nsImapMockChannel : public nsIImapMockChannel, public nsICacheListener
{
public:
@ -586,6 +589,7 @@ public:
NS_DECL_NSIIMAPMOCKCHANNEL
NS_DECL_NSICHANNEL
NS_DECL_NSIREQUEST
NS_DECL_NSICACHELISTENER
nsImapMockChannel();
virtual ~nsImapMockChannel();
@ -610,9 +614,17 @@ protected:
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsISupports> mOwner;
nsCOMPtr<nsISupports> mSecurityInfo;
nsCOMPtr<nsIRequest> mCacheRequest; // the request associated with a read from the cache
nsCString m_ContentType;
nsresult SetupPartExtractor(nsIImapUrl * aUrl, nsIStreamListener * aConsumer);
// cache related helper methods
nsresult OpenCacheEntry(); // makes a request to the cache service for a cache entry for a url
PRBool ReadFromLocalCache(); // attempts to read the url out of our local (offline) cache....
nsresult ReadFromImapConnection(); // creates a new imap connection to read the url
nsresult ReadFromMemCache(nsICacheEntryDescriptor *entry); // attempts to read the url out of our memory cache
// we end up daisy chaining multiple nsIStreamListeners into the load process.
nsresult SetupPartExtractorListener(nsIImapUrl * aUrl, nsIStreamListener * aConsumer);
};
#endif // nsImapProtocol_h___

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

@ -59,12 +59,16 @@
#include "nsImapOfflineSync.h"
#include "nsIMsgHdr.h"
#include "nsMsgUtils.h"
#include "nsICacheService.h"
#include "nsNetCID.h"
#define PREF_MAIL_ROOT_IMAP "mail.root.imap"
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kImapUrlCID, NS_IMAPURL_CID);
static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
static const char *sequenceString = "SEQUENCE";
@ -410,7 +414,7 @@ NS_IMETHODIMP nsImapService::FetchMimePart(nsIURI *aURI, const char *aMessageURI
rv = nsParseImapMessageURI(aMessageURI, folderURI, &key, getter_Copies(mimePart));
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(aURI);
@ -3321,3 +3325,21 @@ nsImapService::DownloadAllOffineImapFolders(nsIMsgWindow *aMsgWindow, nsIUrlList
return NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsImapService::GetCacheSession(nsICacheSession **result)
{
nsresult rv = NS_OK;
if (!mCacheSession)
{
nsCOMPtr<nsICacheService> serv = do_GetService(kCacheServiceCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = serv->CreateSession("IMAP-memory-only", nsICache::STORE_IN_MEMORY, nsICache::STREAM_BASED, getter_AddRefs(mCacheSession));
NS_ENSURE_SUCCESS(rv, rv);
rv = mCacheSession->SetDoomEntriesIfExpired(PR_FALSE);
}
*result = mCacheSession;
NS_IF_ADDREF(*result);
return rv;
}

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

@ -31,6 +31,8 @@
#include "nsIProtocolHandler.h"
#include "nsIMsgProtocolInfo.h"
#include "nsICacheSession.h"
class nsIImapHostSessionList;
class nsCString;
class nsIImapUrl;
@ -110,6 +112,8 @@ protected:
PRBool mPrintingOperation; // Flag for printing operations
// handle to the cache session for imap.....
nsCOMPtr<nsICacheSession> mCacheSession;
};
#endif /* nsImapService_h___ */

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

@ -42,7 +42,7 @@
#include "nsXPIDLString.h"
#include "nsAutoLock.h"
#include "nsIMAPNamespace.h"
#include "nsICachedNetData.h"
#include "nsICacheEntryDescriptor.h"
// rdf stuff is needed to get the charset from the imap folder associated with the url.
#include "nsIRDFService.h"
#include "rdf.h"
@ -1001,7 +1001,7 @@ NS_IMETHODIMP nsImapUrl::SetAllowContentChange(PRBool allowContentChange)
NS_IMETHODIMP nsImapUrl::SetContentModified(nsImapContentModifiedType contentModified)
{
m_contentModified = contentModified;
nsCOMPtr<nsICachedNetData> cacheEntry;
nsCOMPtr<nsICacheEntryDescriptor> cacheEntry;
nsresult res = GetMemCacheEntry(getter_AddRefs(cacheEntry));
if (NS_SUCCEEDED(res) && cacheEntry)
{
@ -1021,7 +1021,7 @@ NS_IMETHODIMP nsImapUrl::SetContentModified(nsImapContentModifiedType contentMod
contentModifiedAnnotation = "Force Content Not Modified";
break;
}
cacheEntry->SetAnnotation("ContentModified", nsCRT::strlen(contentModifiedAnnotation), contentModifiedAnnotation);
cacheEntry->SetMetaDataElement("ContentModified", contentModifiedAnnotation);
}
return NS_OK;
}

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

@ -32,6 +32,7 @@ interface nsISupportsArray;
interface nsIFileSpec;
interface nsIMsgWindow;
interface nsIMsgFolder;
interface nsICacheSession;
[scriptable, uuid(4C9F90E0-E19B-11d2-806E-006008128C4E)]
interface nsINntpService : nsISupports {
@ -55,5 +56,7 @@ interface nsINntpService : nsISupports {
* can handle news_message:// and news://
*/
void decomposeNewsURI(in string uri, out nsIMsgFolder folder, out nsMsgKey key);
};
// handle to the cache session used by news....
readonly attribute nsICacheSession cacheSession;
};

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

@ -78,7 +78,10 @@
#include "nsIDocShell.h"
// for the memory cache...
#include "nsICachedNetData.h"
#include "nsICacheEntryDescriptor.h"
#include "nsICacheSession.h"
#include "nsIStreamListener.h"
#include "nsNetCID.h"
#include "nsIPref.h"
@ -160,6 +163,7 @@ static NS_DEFINE_CID(kCMsgMailSessionCID, NS_MSGMAILSESSION_CID);
static NS_DEFINE_CID(kCMsgAccountManagerCID, NS_MSGACCOUNTMANAGER_CID);
static NS_DEFINE_CID(kPrefServiceCID,NS_PREF_CID);
static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID);
typedef struct _cancelInfoEntry {
char *from;
@ -414,8 +418,9 @@ NS_IMPL_ADDREF_INHERITED(nsNNTPProtocol, nsMsgProtocol)
NS_IMPL_RELEASE_INHERITED(nsNNTPProtocol, nsMsgProtocol)
NS_INTERFACE_MAP_BEGIN(nsNNTPProtocol)
NS_INTERFACE_MAP_ENTRY(nsINNTPProtocol)
NS_INTERFACE_MAP_ENTRY(nsINNTPProtocol)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
NS_INTERFACE_MAP_ENTRY(nsICacheListener)
NS_INTERFACE_MAP_END_INHERITING(nsMsgProtocol)
nsNNTPProtocol::nsNNTPProtocol(nsIURI * aURL, nsIMsgWindow *aMsgWindow)
@ -656,7 +661,7 @@ NS_IMETHODIMP nsNNTPProtocol::LoadNewsUrl(nsIURI * aURL, nsISupports * aConsumer
nsCOMPtr<nsINntpUrl> newsUrl (do_QueryInterface(aURL));
newsUrl->GetNewsAction(&m_newsAction);
SetupPartExtractor(m_channelListener);
SetupPartExtractorListener(m_channelListener);
return LoadUrl(aURL, aConsumer);
}
@ -748,7 +753,7 @@ nsNntpCacheStreamListener::OnDataAvailable(nsIRequest *request, nsISupports * aC
return mListener->OnDataAvailable(ourRequest, aCtxt, aInStream, aSourceOffset, aCount);
}
nsresult nsNNTPProtocol::SetupPartExtractor(nsIStreamListener * aConsumer)
nsresult nsNNTPProtocol::SetupPartExtractorListener(nsIStreamListener * aConsumer)
{
if (m_newsAction == nsINntpUrl::ActionFetchPart)
{
@ -769,6 +774,165 @@ nsresult nsNNTPProtocol::SetupPartExtractor(nsIStreamListener * aConsumer)
return NS_OK;
}
nsresult nsNNTPProtocol::ReadFromMemCache(nsICacheEntryDescriptor *entry)
{
NS_ENSURE_ARG(entry);
nsCOMPtr<nsITransport> cacheTransport;
nsresult rv = entry->GetTransport(getter_AddRefs(cacheTransport));
if (NS_SUCCEEDED(rv))
{
nsNntpCacheStreamListener * cacheListener = new nsNntpCacheStreamListener();
NS_ADDREF(cacheListener);
SetLoadGroup(m_loadGroup);
m_typeWanted = ARTICLE_WANTED;
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_runningURL);
cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this), mailnewsUrl);
nsCOMPtr<nsIRequest> request;
rv = cacheTransport->AsyncRead(cacheListener, m_channelContext, 0, PRUint32(-1), 0, getter_AddRefs(request));
NS_RELEASE(cacheListener);
MarkCurrentMsgRead();
if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return
{
// we're not calling nsMsgProtocol::AsyncRead(), which calls nsNNTPProtocol::LoadUrl, so we need to take care of some stuff it does.
m_ContentType = "";
m_channelListener = nsnull;
return rv;
}
}
return rv;
}
nsresult nsNNTPProtocol::ReadFromNewsConnection()
{
return nsMsgProtocol::AsyncOpen(m_channelListener, m_channelContext);
}
// for messages stored in our offline cache, we have special code to handle that...
// If it's in the local cache, we return true and we can abort the download because
// this method does the rest of the work.
PRBool nsNNTPProtocol::ReadFromLocalCache()
{
PRBool msgIsInLocalCache = PR_FALSE;
nsresult rv = NS_OK;
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_runningURL);
mailnewsUrl->GetMsgIsInLocalCache(&msgIsInLocalCache);
if (msgIsInLocalCache)
{
nsXPIDLCString group;
nsXPIDLCString commandSpecificData;
rv = ParseURL(m_url, getter_Copies(group), &m_messageID, getter_Copies(commandSpecificData));
nsCOMPtr <nsIMsgFolder> folder = do_QueryInterface(m_newsFolder);
if (folder && NS_SUCCEEDED(rv))
{
// we want to create a file channel and read the msg from there.
nsCOMPtr<nsITransport> fileChannel;
PRUint32 offset=0, size=0;
rv = folder->GetOfflineFileTransport(m_key, &offset, &size, getter_AddRefs(fileChannel));
// get the file channel from the folder, somehow (through the message or
// folder sink?) We also need to set the transfer offset to the message offset
if (fileChannel && NS_SUCCEEDED(rv))
{
// dougt - This may break the ablity to "cancel" a read from offline mail reading.
// fileChannel->SetLoadGroup(m_loadGroup);
m_typeWanted = ARTICLE_WANTED;
nsNntpCacheStreamListener * cacheListener = new nsNntpCacheStreamListener();
NS_ADDREF(cacheListener);
cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this), mailnewsUrl);
nsCOMPtr<nsIRequest> request;
rv = fileChannel->AsyncRead(cacheListener, m_channelContext, offset, size, 0, getter_AddRefs(request));
NS_RELEASE(cacheListener);
MarkCurrentMsgRead();
if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return
{
m_ContentType = "";
m_channelListener = nsnull;
return PR_TRUE;
}
}
}
}
return PR_FALSE;
}
NS_IMETHODIMP
nsNNTPProtocol::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry, nsCacheAccessMode access, nsresult status)
{
nsresult rv = NS_OK;
if (NS_SUCCEEDED(status))
{
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_runningURL, &rv);
mailnewsUrl->SetMemCacheEntry(entry);
// if we have write access then insert a "stream T" into the flow so data
// gets written to both
if (access & nsICache::ACCESS_WRITE && !(access & nsICache::ACCESS_READ))
{
entry->MarkValid();
// use a stream listener Tee to force data into the cache and to our current channel listener...
nsCOMPtr<nsIStreamListener> newListener;
nsCOMPtr<nsIStreamListenerTee> tee = do_CreateInstance(kStreamListenerTeeCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsITransport> transport;
rv = entry->GetTransport(getter_AddRefs(transport));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIOutputStream> out;
rv = transport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(out));
NS_ENSURE_SUCCESS(rv, rv);
rv = tee->Init(m_channelListener, out);
m_channelListener = do_QueryInterface(tee);
NS_ENSURE_SUCCESS(rv, rv);
}
else
{
rv = ReadFromMemCache(entry);
if (access & nsICache::ACCESS_WRITE)
entry->MarkValid();
if (NS_SUCCEEDED(rv)) return NS_OK; // kick out if reading from the cache succeeded...
}
} // if we got a valid entry back from the cache...
// if reading from the cache failed or if we are writing into the cache, default to ReadFromImapConnection.
return ReadFromNewsConnection();
}
nsresult nsNNTPProtocol::OpenCacheEntry()
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_runningURL, &rv);
// get the cache session from our nntp service...
nsCOMPtr <nsINntpService> nntpService = do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsICacheSession> cacheSession;
rv = nntpService->GetCacheSession(getter_AddRefs(cacheSession));
NS_ENSURE_SUCCESS(rv, rv);
// Open a cache entry with key = url
nsXPIDLCString urlSpec;
mailnewsUrl->GetSpec(getter_Copies(urlSpec));
// for now, truncate of the query part so we don't duplicate urls in the cache...
char * anchor = PL_strrchr(urlSpec, '?');
if (anchor)
*anchor = '\0';
return cacheSession->AsyncOpenCacheEntry(urlSpec, nsICache::ACCESS_READ_WRITE, this);
}
NS_IMETHODIMP nsNNTPProtocol::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
{
nsresult rv;
@ -782,110 +946,12 @@ NS_IMETHODIMP nsNNTPProtocol::AsyncOpen(nsIStreamListener *listener, nsISupports
// the memory cache or the local msg cache.
if (mailnewsUrl && (m_newsAction == nsINntpUrl::ActionFetchArticle || m_newsAction == nsINntpUrl::ActionFetchPart))
{
nsCOMPtr<nsICachedNetData> cacheEntry;
PRUint32 contentLength = 0;
PRBool partialFlag = PR_FALSE;
PRBool msgIsInLocalCache;
SetupPartExtractor(m_channelListener);
SetupPartExtractorListener(m_channelListener);
if (ReadFromLocalCache())
return NS_OK;
mailnewsUrl->GetMsgIsInLocalCache(&msgIsInLocalCache);
if (msgIsInLocalCache)
{
nsXPIDLCString group;
nsXPIDLCString commandSpecificData;
rv = ParseURL(m_url, getter_Copies(group), &m_messageID, getter_Copies(commandSpecificData));
nsCOMPtr <nsIMsgFolder> folder = do_QueryInterface(m_newsFolder);
if (folder && NS_SUCCEEDED(rv))
{
// we want to create a file channel and read the msg from there.
nsCOMPtr<nsITransport> fileChannel;
PRUint32 offset=0, size=0;
rv = folder->GetOfflineFileTransport(m_key, &offset, &size, getter_AddRefs(fileChannel));
// get the file channel from the folder, somehow (through the message or
// folder sink?) We also need to set the transfer offset to the message offset
if (fileChannel && NS_SUCCEEDED(rv))
{
// dougt - This may break the ablity to "cancel" a read from offline mail reading.
// fileChannel->SetLoadGroup(m_loadGroup);
m_typeWanted = ARTICLE_WANTED;
nsNntpCacheStreamListener * cacheListener = new nsNntpCacheStreamListener();
NS_ADDREF(cacheListener);
cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this), mailnewsUrl);
nsCOMPtr<nsIRequest> request;
rv = fileChannel->AsyncRead(cacheListener, m_channelContext, offset, size, 0, getter_AddRefs(request));
NS_RELEASE(cacheListener);
MarkCurrentMsgRead();
if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return
{
m_ContentType = "";
m_channelListener = nsnull;
return NS_OK;
}
}
}
}
// look to see if this url should be added to the memory cache..
PRBool useMemoryCache = PR_FALSE;
mailnewsUrl->GetAddToMemoryCache(&useMemoryCache);
rv = mailnewsUrl->GetMemCacheEntry(getter_AddRefs(cacheEntry));
if (NS_SUCCEEDED(rv) && cacheEntry)
{
PRBool updateInProgress;
m_typeWanted = ARTICLE_WANTED;
cacheEntry->GetPartialFlag(&partialFlag);
cacheEntry->GetUpdateInProgress(&updateInProgress);
cacheEntry->GetStoredContentLength(&contentLength);
// only try to update the cache entry if it isn't being used.
// We always want to try to write to the cache entry if we can
if (!updateInProgress)
{
// now we need to figure out if the entry is new / or partially unfinished...
// this determines if we are going to USE the cache entry for reading the data
// vs. if we need to write data into the cache entry...
if (!contentLength || partialFlag)
{
// we're going to fill up this cache entry,
// do we have a listener here?
nsIStreamListener *anotherListener = m_channelListener;
rv = cacheEntry->InterceptAsyncRead(anotherListener, 0, getter_AddRefs(m_channelListener));
nsCOMPtr<nsIRequest> request;
if (NS_SUCCEEDED(rv))
return nsMsgProtocol::AsyncOpen(m_channelListener, ctxt);
}
}
}
// now, determine if we should be loading from the cache or if we have
// to really load the msg with a protocol connection...
if (cacheEntry && contentLength > 0 && !partialFlag)
{
nsCOMPtr<nsIChannel> cacheChannel;
rv = cacheEntry->NewChannel(m_loadGroup, getter_AddRefs(cacheChannel));
if (NS_SUCCEEDED(rv))
{
nsNntpCacheStreamListener * cacheListener = new nsNntpCacheStreamListener();
NS_ADDREF(cacheListener);
SetLoadGroup(m_loadGroup);
m_typeWanted = ARTICLE_WANTED;
cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this), mailnewsUrl);
nsCOMPtr<nsIRequest> request;
rv = cacheChannel->AsyncOpen(cacheListener, m_channelContext);
NS_RELEASE(cacheListener);
MarkCurrentMsgRead();
if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return
{
// we're not calling nsMsgProtocol::AsyncRead(), which calls nsNNTPProtocol::LoadUrl, so we need to take care of some stuff it does.
m_ContentType = "";
m_channelListener = nsnull;
return rv;
}
}
}
rv = OpenCacheEntry();
if (NS_SUCCEEDED(rv)) return NS_OK; // if this didn't return an error then jump out now...
}
nsCOMPtr<nsIRequest> parentRequest;

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

@ -46,6 +46,7 @@
#include "nsIStringBundle.h"
#include "nsITimer.h"
#include "nsITimerCallback.h"
#include "nsICacheListener.h"
// this is only needed as long as our libmime hack is in place
#include "prio.h"
@ -145,11 +146,14 @@ NEWS_FREE,
NEWS_FINISHED
} StatesEnum;
class nsNNTPProtocol : public nsINNTPProtocol, public nsITimerCallback, public nsMsgProtocol
class nsICacheEntryDescriptor;
class nsNNTPProtocol : public nsINNTPProtocol, public nsITimerCallback, public nsICacheListener, public nsMsgProtocol
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSINNTPPROTOCOL
NS_DECL_NSICACHELISTENER
// nsITimerCallback interfaces
NS_IMETHOD_(void) Notify(nsITimer *timer);
@ -170,7 +174,6 @@ public:
nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer);
private:
nsresult SetupPartExtractor(nsIStreamListener * aConsumer);
// over-rides from nsMsgProtocol
virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream,
PRUint32 sourceOffset, PRUint32 length);
@ -392,21 +395,28 @@ private:
void SetProgressBarPercent(PRUint32 aProgress, PRUint32 aProgressMax);
nsresult SetProgressStatus(const PRUnichar *aMessage);
nsresult SetCheckingForNewNewsStatus(PRInt32 current, PRInt32 total);
nsresult MarkCurrentMsgRead(); // marks the message corresponding to the currently running url read.
nsresult SetCheckingForNewNewsStatus(PRInt32 current, PRInt32 total);
nsresult MarkCurrentMsgRead(); // marks the message corresponding to the currently running url read.
nsresult InitializeNewsFolderFromUri(const char *uri);
void TimerCallback();
nsCOMPtr <nsIInputStream> mInputStream;
nsCOMPtr <nsITimer> mUpdateTimer;
nsCOMPtr <nsITimer> mUpdateTimer;
nsresult AlertError(PRInt32 errorCode, const char *text);
PRInt32 mBytesReceived;
PRInt32 mBytesReceivedSinceLastStatusUpdate;
PRTime m_startTime;
PRInt32 mNumGroupsListed;
nsMsgKey m_key;
PRInt32 mBytesReceivedSinceLastStatusUpdate;
PRTime m_startTime;
PRInt32 mNumGroupsListed;
nsMsgKey m_key;
nsresult SetCurrentGroup(); /* sets m_currentGroup. should be called after doing a successful GROUP command */
nsresult CleanupNewsgroupList(); /* cleans up m_newsgroupList, and set it to null */
nsresult SetCurrentGroup(); /* sets m_currentGroup. should be called after doing a successful GROUP command */
nsresult CleanupNewsgroupList(); /* cleans up m_newsgroupList, and set it to null */
// cache related helper methods
nsresult OpenCacheEntry(); // makes a request to the cache service for a cache entry for a url
PRBool ReadFromLocalCache(); // attempts to read the url out of our local (offline) cache....
nsresult ReadFromNewsConnection(); // creates a new news connection to read the url
nsresult ReadFromMemCache(nsICacheEntryDescriptor *entry); // attempts to read the url out of our memory cache
nsresult SetupPartExtractorListener(nsIStreamListener * aConsumer);
};
NS_BEGIN_EXTERN_C

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

@ -59,6 +59,9 @@
#include "nsIPrompt.h"
#include "nsIRDFService.h"
#include "nsNewsDownloader.h"
#include "nsICacheService.h"
#include "nsNetCID.h"
#undef GetPort // XXX Windows!
#undef SetPort // XXX Windows!
@ -70,6 +73,7 @@ static NS_DEFINE_CID(kCPrefServiceCID, NS_PREF_CID);
static NS_DEFINE_CID(kMsgAccountManagerCID, NS_MSGACCOUNTMANAGER_CID);
static NS_DEFINE_CID(kMessengerMigratorCID, NS_MESSENGERMIGRATOR_CID);
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
nsNntpService::nsNntpService()
{
@ -361,7 +365,12 @@ NS_IMETHODIMP nsNntpService::OpenAttachment(const char *aContentType,
nsCOMPtr<nsIURI> url;
nsresult rv = NS_OK;
NewURI(aUrl, nsnull, getter_AddRefs(url));
nsCAutoString newsUrl;
newsUrl = aUrl;
newsUrl += "&type=";
newsUrl += aContentType;
NewURI(newsUrl, nsnull, getter_AddRefs(url));
if (NS_SUCCEEDED(rv) && url)
{
@ -1537,3 +1546,20 @@ nsNntpService::DownloadNewsgroupsForOffline(nsIMsgWindow *aMsgWindow, nsIUrlList
return rv;
}
NS_IMETHODIMP nsNntpService::GetCacheSession(nsICacheSession **result)
{
nsresult rv = NS_OK;
if (!mCacheSession)
{
nsCOMPtr<nsICacheService> serv = do_GetService(kCacheServiceCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = serv->CreateSession("NNTP-memory-only", nsICache::STORE_IN_MEMORY, nsICache::STREAM_BASED, getter_AddRefs(mCacheSession));
NS_ENSURE_SUCCESS(rv, rv);
rv = mCacheSession->SetDoomEntriesIfExpired(PR_FALSE);
}
*result = mCacheSession;
NS_IF_ADDREF(*result);
return rv;
}

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

@ -36,6 +36,7 @@
#include "nsICmdLineHandler.h"
#include "nsCOMPtr.h"
#include "nsIContentHandler.h"
#include "nsICacheSession.h"
class nsIURI;
class nsIUrlListener;
@ -46,7 +47,7 @@ class nsNntpService : public nsINntpService,
public nsIProtocolHandler,
public nsIMsgProtocolInfo,
public nsICmdLineHandler,
public nsIContentHandler
public nsIContentHandler
{
public:
@ -87,6 +88,8 @@ protected:
PRBool mPrintingOperation; // Flag for printing operations
PRBool mOpenAttachmentOperation; // Flag for opening attachments
PRBool mCopyingOperation;
nsCOMPtr<nsICacheSession> mCacheSession; // the cache session used by news
};
#endif /* nsNntpService_h___ */