fix saving as template imap message while offline r=sspitzer, sr=mscott 81690

This commit is contained in:
bienvenu%netscape.com 2001-08-13 23:56:54 +00:00
Родитель f801f480c9
Коммит 89fdd48706
9 изменённых файлов: 251 добавлений и 124 удалений

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

@ -78,7 +78,9 @@ interface nsIImapMailFolderSink : nsISupports {
// these two hokey methods are needed so we can try to make sure the imap url is released
// on the UI thread. This in turn ensures that the objects the imap url holds on to
// are only released / destroyed from the UI thread.
void PrepareToReleaseUrl(in nsIMsgMailNewsUrl aUrl);
void ReleaseUrl();
void CloseMockChannel(in nsIImapMockChannel aChannel);
void prepareToReleaseUrl(in nsIMsgMailNewsUrl aUrl);
void releaseUrl();
void closeMockChannel(in nsIImapMockChannel aChannel);
void setUrlState(in nsIImapProtocol aProtocol, in nsIMsgMailNewsUrl aUrl, in boolean isRunning, in nsresult status);
};

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

@ -72,10 +72,6 @@ public:
NS_IMETHOD CopyNextStreamMessage(nsIImapProtocol* aProtocol,
nsIImapUrl * aUrl,
PRBool copySucceeded) = 0;
NS_IMETHOD SetUrlState(nsIImapProtocol* aProtocol,
nsIMsgMailNewsUrl* aUrl,
PRBool isRunning,
nsresult statusCode) = 0;
};

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

@ -256,11 +256,6 @@ public:
NS_IMETHOD CopyNextStreamMessage(nsIImapProtocol* aProtocol,
nsIImapUrl * aUrl,
PRBool copySucceeded);
NS_IMETHOD SetUrlState(nsIImapProtocol* aProtocol,
nsIMsgMailNewsUrl* aUrl,
PRBool isRunning,
nsresult statusCode);
NS_IMETHOD MatchName(nsString *name, PRBool *matches);
// nsIMsgFilterHitNotification method(s)
NS_IMETHOD ApplyFilterHit(nsIMsgFilter *filter, PRBool *applyMore);

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

@ -1052,11 +1052,10 @@ PRBool nsImapProtocol::ProcessCurrentURL()
mailnewsurl->GetSpec(getter_Copies(urlSpec));
printf("processing url %s\n", (const char *) urlSpec);
#endif
if (NS_SUCCEEDED(rv) && mailnewsurl && m_imapMiscellaneousSink)
if (NS_SUCCEEDED(rv) && mailnewsurl && m_imapMailFolderSink)
{
m_imapMiscellaneousSink->SetUrlState(this, mailnewsurl, PR_TRUE,
m_imapMailFolderSink->SetUrlState(this, mailnewsurl, PR_TRUE,
NS_OK);
WaitForFEEventCompletion();
}
// if we are set up as a channel, we should notify our channel listener that we are starting...
@ -1135,14 +1134,13 @@ PRBool nsImapProtocol::ProcessCurrentURL()
else if (!logonFailed)
HandleCurrentUrlError();
if (mailnewsurl && m_imapMiscellaneousSink)
if (mailnewsurl && m_imapMailFolderSink)
{
rv = GetServerStateParser().LastCommandSuccessful() ? NS_OK :
NS_ERROR_FAILURE;
m_imapMiscellaneousSink->SetUrlState(this, mailnewsurl, PR_FALSE,
m_imapMailFolderSink->SetUrlState(this, mailnewsurl, PR_FALSE,
rv); // we are done with this
// url.
WaitForFEEventCompletion();
}
else
NS_ASSERTION(PR_FALSE, "missing url or sink");
@ -6845,14 +6843,41 @@ nsImapMockChannel::nsImapMockChannel()
m_cancelStatus = NS_OK;
mLoadFlags = 0;
mChannelClosed = PR_FALSE;
mReadingFromCache = PR_FALSE;
}
nsImapMockChannel::~nsImapMockChannel()
{
// if we're offline, we may not get to close the channel correctly.
// we need to do this to send the url state change notification in
// the case of mem and disk cache reads.
if (!mChannelClosed)
Close();
}
nsresult nsImapMockChannel::NotifyStartEndReadFromCache(PRBool start)
{
nsresult rv = NS_OK;
mReadingFromCache = start;
nsCOMPtr <nsIImapUrl> imapUrl = do_QueryInterface(m_url, &rv);
if (imapUrl)
{
nsCOMPtr <nsIImapMailFolderSink> folderSink;
rv = imapUrl->GetImapMailFolderSink(getter_AddRefs(folderSink));
if (folderSink)
{
nsCOMPtr <nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(m_url);
rv = folderSink->SetUrlState(nsnull /* we don't know the protocol */, mailUrl, start, NS_OK);
}
}
return rv;
}
NS_IMETHODIMP nsImapMockChannel::Close()
{
if (mReadingFromCache)
NotifyStartEndReadFromCache(PR_FALSE);
m_channelListener = null_nsCOMPtr();
mCacheRequest = null_nsCOMPtr();
m_url = null_nsCOMPtr();
@ -6997,10 +7022,12 @@ nsImapMockChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry, nsCache
else
{
rv = ReadFromMemCache(entry);
NotifyStartEndReadFromCache(PR_TRUE);
if (access & nsICache::ACCESS_WRITE)
entry->MarkValid();
if (NS_SUCCEEDED(rv)) return NS_OK; // kick out if reading from the cache succeeded...
mailnewsUrl->SetMemCacheEntry(nsnull); // we aren't going to be reading from the cache
}
} // if we got a valid entry back from the cache...
@ -7187,7 +7214,10 @@ NS_IMETHODIMP nsImapMockChannel::AsyncOpen(nsIStreamListener *listener, nsISuppo
SetupPartExtractorListener(imapUrl, m_channelListener);
if (ReadFromLocalCache())
{
(void) NotifyStartEndReadFromCache(PR_TRUE);
return NS_OK;
}
nsImapAction imapAction;
imapUrl->GetImapAction(&imapAction);

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

@ -586,14 +586,14 @@ class nsImapMockChannel : public nsIImapMockChannel, public nsICacheListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_ISUPPORTS
NS_DECL_NSIIMAPMOCKCHANNEL
NS_DECL_NSICHANNEL
NS_DECL_NSIREQUEST
NS_DECL_NSICACHELISTENER
nsImapMockChannel();
virtual ~nsImapMockChannel();
virtual ~nsImapMockChannel();
static nsresult Create (const nsIID& iid, void **result);
protected:
@ -619,12 +619,13 @@ protected:
nsCString m_ContentType;
PRBool mChannelClosed;
PRBool mReadingFromCache;
// 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
nsresult NotifyStartEndReadFromCache(PRBool start);
// we end up daisy chaining multiple nsIStreamListeners into the load process.
nsresult SetupPartExtractorListener(nsIImapUrl * aUrl, nsIStreamListener * aConsumer);

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

@ -675,37 +675,6 @@ nsImapMiscellaneousSinkProxy::CopyNextStreamMessage(nsIImapProtocol* aProtocol,
return res;
}
NS_IMETHODIMP
nsImapMiscellaneousSinkProxy::SetUrlState(nsIImapProtocol* aProtocol,
nsIMsgMailNewsUrl* aUrl,
PRBool isRunning,
nsresult statusCode)
{
nsresult res = NS_OK;
NS_PRECONDITION (aUrl, "Oops... null url");
if(!aUrl)
return NS_ERROR_NULL_POINTER;
NS_ASSERTION (m_protocol == aProtocol, "Ooh ooh, wrong protocol");
if (PR_GetCurrentThread() == m_thread)
{
SetUrlStateProxyEvent *ev =
new SetUrlStateProxyEvent(this, aUrl, isRunning, statusCode);
if(nsnull == ev)
res = NS_ERROR_OUT_OF_MEMORY;
else
{
ev->SetNotifyCompletion(PR_TRUE);
ev->PostEvent(m_eventQueue);
}
}
else
{
res = m_realImapMiscellaneousSink->SetUrlState(aProtocol, aUrl,
isRunning, statusCode);
}
return res;
}
///
@ -1292,27 +1261,3 @@ CopyNextStreamMessageProxyEvent::HandleEvent()
return res;
}
SetUrlStateProxyEvent::SetUrlStateProxyEvent(
nsImapMiscellaneousSinkProxy* aProxy, nsIMsgMailNewsUrl* aUrl,
PRBool isRunning, nsresult statusCode) :
nsImapMiscellaneousSinkProxyEvent(aProxy), m_isRunning(isRunning),
m_status(statusCode)
{
NS_ASSERTION (aUrl, "Oops... a null url");
m_url = do_QueryInterface(aUrl);
}
SetUrlStateProxyEvent::~SetUrlStateProxyEvent()
{
}
NS_IMETHODIMP
SetUrlStateProxyEvent::HandleEvent()
{
nsresult res = m_proxy->m_realImapMiscellaneousSink->SetUrlState(
m_proxy->m_protocol, m_url, m_isRunning, m_status);
if (m_notifyCompletion)
m_proxy->m_protocol->NotifyFEEventCompletion();
return res;
}

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

@ -123,11 +123,6 @@ public:
nsIImapUrl * aUrl,
PRBool copySucceeded);
NS_IMETHOD SetUrlState(nsIImapProtocol* aProtocol,
nsIMsgMailNewsUrl* aUrl,
PRBool isRunning,
nsresult statusCode);
nsIImapMiscellaneousSink* m_realImapMiscellaneousSink;
};
@ -339,16 +334,4 @@ struct CopyNextStreamMessageProxyEvent : public nsImapMiscellaneousSinkProxyEven
PRBool m_copySucceeded;
};
struct SetUrlStateProxyEvent : public nsImapMiscellaneousSinkProxyEvent
{
SetUrlStateProxyEvent(nsImapMiscellaneousSinkProxy* aProxy,
nsIMsgMailNewsUrl* aUrl, PRBool isRunning,
nsresult statusCode);
virtual ~SetUrlStateProxyEvent();
NS_IMETHOD HandleEvent();
nsCOMPtr<nsIMsgMailNewsUrl> m_url;
PRBool m_isRunning;
nsresult m_status;
};
#endif

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

@ -69,6 +69,8 @@
#include "nsIMsgParseMailMsgState.h"
#include "nsMsgLineBuffer.h"
#include "nsMsgLocalCID.h"
#include "nsIOutputStream.h"
#include "xp_core.h"
#define PREF_MAIL_ROOT_IMAP "mail.root.imap"
@ -86,6 +88,176 @@ static PRBool gInitialized = PR_FALSE;
static PRInt32 gMIMEOnDemandThreshold = 15000;
static PRBool gMIMEOnDemand = PR_FALSE;
#define SAVE_BUF_SIZE 8192
class nsImapSaveAsListener : public nsIStreamListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
nsImapSaveAsListener(nsIFileSpec *aFileSpec, PRBool addDummyEnvelope);
virtual ~nsImapSaveAsListener();
nsresult SetupMsgWriteStream(nsIFileSpec *aFileSpec, PRBool addDummyEnvelope);
protected:
nsCOMPtr<nsIOutputStream> m_outputStream;
nsCOMPtr<nsIFileSpec> m_outputFile;
PRBool m_addDummyEnvelope;
PRBool m_writtenData;
PRUint32 m_leftOver;
char m_dataBuffer[SAVE_BUF_SIZE+1]; // temporary buffer for this save operation
};
NS_IMPL_ISUPPORTS1(nsImapSaveAsListener, nsIStreamListener)
nsImapSaveAsListener::nsImapSaveAsListener(nsIFileSpec *aFileSpec, PRBool addDummyEnvelope)
{
m_outputFile = aFileSpec;
m_writtenData = PR_FALSE;
m_addDummyEnvelope = addDummyEnvelope;
m_leftOver = 0;
NS_INIT_REFCNT();
}
nsImapSaveAsListener::~nsImapSaveAsListener()
{
if (m_outputStream)
{
m_outputStream->Flush();
m_outputStream->Close();
}
}
NS_IMETHODIMP nsImapSaveAsListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
return NS_OK;
}
NS_IMETHODIMP
nsImapSaveAsListener::OnStopRequest(nsIRequest *request, nsISupports * aCtxt, nsresult aStatus)
{
return NS_OK;
}
NS_IMETHODIMP nsImapSaveAsListener::OnDataAvailable(nsIRequest* request,
nsISupports* aSupport,
nsIInputStream* inStream,
PRUint32 srcOffset,
PRUint32 count)
{
nsresult rv;
PRUint32 available;
rv = inStream->Available(&available);
if (!m_writtenData)
{
m_writtenData = PR_TRUE;
rv = SetupMsgWriteStream(m_outputFile, m_addDummyEnvelope);
NS_ENSURE_SUCCESS(rv, rv);
}
PRUint32 readCount, maxReadCount = SAVE_BUF_SIZE - m_leftOver;
PRUint32 writeCount;
char *start, *end;
PRUint32 linebreak_len = 0;
while (count > 0)
{
if (count < (PRInt32) maxReadCount)
maxReadCount = count;
rv = inStream->Read(m_dataBuffer + m_leftOver,
maxReadCount,
&readCount);
if (NS_FAILED(rv)) return rv;
m_leftOver += readCount;
m_dataBuffer[m_leftOver] = '\0';
start = m_dataBuffer;
end = PL_strstr(start, "\r");
if (!end)
end = PL_strstr(start, "\n");
else if (*(end+1) == nsCRT::LF && linebreak_len == 0)
linebreak_len = 2;
if (linebreak_len == 0) // not initialize yet
linebreak_len = 1;
count -= readCount;
maxReadCount = SAVE_BUF_SIZE - m_leftOver;
if (!end && count > (PRInt32) maxReadCount)
// must be a very very long line; sorry cannot handle it
return NS_ERROR_FAILURE;
while (start && end)
{
if (PL_strncasecmp(start, "X-Mozilla-Status:", 17) &&
PL_strncasecmp(start, "X-Mozilla-Status2:", 18) &&
PL_strncmp(start, "From - ", 7))
{
rv = m_outputStream->Write(start, end-start, &writeCount);
rv = m_outputStream->Write(CRLF, 2, &writeCount);
}
start = end+linebreak_len;
if (start >= m_dataBuffer + m_leftOver)
{
maxReadCount = SAVE_BUF_SIZE;
m_leftOver = 0;
break;
}
end = PL_strstr(start, "\r");
if (!end)
end = PL_strstr(start, "\n");
if (start && !end)
{
m_leftOver -= (start - m_dataBuffer);
nsCRT::memcpy(m_dataBuffer, start,
m_leftOver+1); // including null
maxReadCount = SAVE_BUF_SIZE - m_leftOver;
}
}
if (NS_FAILED(rv)) return rv;
}
return rv;
// rv = m_outputStream->WriteFrom(inStream, PR_MIN(available, count), &bytesWritten);
}
nsresult nsImapSaveAsListener::SetupMsgWriteStream(nsIFileSpec *aFileSpec, PRBool addDummyEnvelope)
{
nsresult rv = NS_ERROR_FAILURE;
rv = aFileSpec->GetOutputStream(getter_AddRefs(m_outputStream));
nsFileSpec fileSpec;
aFileSpec->GetFileSpec(&fileSpec);
fileSpec.Delete(PR_FALSE);
if (m_outputStream && addDummyEnvelope)
{
nsCAutoString result;
char *ct;
PRUint32 writeCount;
time_t now = time ((time_t*) 0);
ct = ctime(&now);
ct[24] = 0;
result = "From - ";
result += ct;
result += MSG_LINEBREAK;
m_outputStream->Write(result.get(), result.Length(),
&writeCount);
result = "X-Mozilla-Status: 0001";
result += MSG_LINEBREAK;
m_outputStream->Write(result.get(), result.Length(),
&writeCount);
result = "X-Mozilla-Status2: 00000000";
result += MSG_LINEBREAK;
m_outputStream->Write(result.get(), result.Length(),
&writeCount);
}
return rv;
}
NS_IMPL_THREADSAFE_ADDREF(nsImapService);
NS_IMPL_THREADSAFE_RELEASE(nsImapService);
NS_IMPL_QUERY_INTERFACE5(nsImapService,
@ -912,7 +1084,7 @@ NS_IMETHODIMP nsImapService::SaveMessageToDisk(const char *aMessageURI,
folder->HasMsgOffline(atoi(msgKey), &hasMsgOffline);
nsCAutoString urlSpec;
PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
rv = CreateStartOfImapUrl(aMessageURI, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator);
if (NS_SUCCEEDED(rv))
{
@ -928,7 +1100,9 @@ NS_IMETHODIMP nsImapService::SaveMessageToDisk(const char *aMessageURI,
if (mailnewsUrl)
mailnewsUrl->SetMsgIsInLocalCache(hasMsgOffline);
return FetchMessage(imapUrl, nsIImapUrl::nsImapSaveMessageToDisk, folder, imapMessageSink, aMsgWindow, aURL, nsnull, msgKey, PR_TRUE);
nsImapSaveAsListener *saveAsListener = new nsImapSaveAsListener(aFile, aAddDummyEnvelope);
return FetchMessage(imapUrl, nsIImapUrl::nsImapSaveMessageToDisk, folder, imapMessageSink, aMsgWindow, aURL, saveAsListener, msgKey, PR_TRUE);
}
return rv;
@ -946,7 +1120,7 @@ nsImapService::FetchMessage(nsIImapUrl * aImapUrl,
nsIImapMessageSink * aImapMessage,
nsIMsgWindow *aMsgWindow,
nsIURI ** aURL,
nsISupports * aDisplayConsumer,
nsISupports * aDisplayConsumer,
const char *messageIdentifierList,
PRBool messageIdsAreUID)
{
@ -993,16 +1167,16 @@ nsImapService::FetchMessage(nsIImapUrl * aImapUrl,
PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
urlSpec.Append("fetch>");
urlSpec.Append(messageIdsAreUID ? uidString : sequenceString);
urlSpec.Append(">");
urlSpec.AppendWithConversion(hierarchySeparator);
urlSpec.Append("fetch>");
urlSpec.Append(messageIdsAreUID ? uidString : sequenceString);
urlSpec.Append(">");
urlSpec.AppendWithConversion(hierarchySeparator);
nsXPIDLCString folderName;
GetFolderName(aImapMailFolder, getter_Copies(folderName));
urlSpec.Append((const char *) folderName);
urlSpec.Append(">");
urlSpec.Append(messageIdentifierList);
nsXPIDLCString folderName;
GetFolderName(aImapMailFolder, getter_Copies(folderName));
urlSpec.Append((const char *) folderName);
urlSpec.Append(">");
urlSpec.Append(messageIdentifierList);
// rhp: If we are displaying this message for the purpose of printing, we
// need to append the header=print option.
@ -1010,28 +1184,28 @@ nsImapService::FetchMessage(nsIImapUrl * aImapUrl,
if (mPrintingOperation)
urlSpec.Append("?header=print");
// mscott - this cast to a char * is okay...there's a bug in the XPIDL
// compiler that is preventing in string parameters from showing up as
// const char *. hopefully they will fix it soon.
rv = url->SetSpec(urlSpec.get());
// mscott - this cast to a char * is okay...there's a bug in the XPIDL
// compiler that is preventing in string parameters from showing up as
// const char *. hopefully they will fix it soon.
rv = url->SetSpec(urlSpec.get());
rv = aImapUrl->SetImapAction(aImapAction);
rv = aImapUrl->SetImapAction(aImapAction);
if (aImapMailFolder && aDisplayConsumer)
{
nsCOMPtr<nsIMsgIncomingServer> aMsgIncomingServer;
rv = aImapMailFolder->GetServer(getter_AddRefs(aMsgIncomingServer));
if (NS_SUCCEEDED(rv) && aMsgIncomingServer)
{
PRBool interrupted;
nsCOMPtr<nsIImapIncomingServer>
aImapServer(do_QueryInterface(aMsgIncomingServer, &rv));
if (NS_SUCCEEDED(rv) && aImapServer)
aImapServer->PseudoInterruptMsgLoad(aImapUrl, &interrupted);
}
nsCOMPtr<nsIMsgIncomingServer> aMsgIncomingServer;
rv = aImapMailFolder->GetServer(getter_AddRefs(aMsgIncomingServer));
if (NS_SUCCEEDED(rv) && aMsgIncomingServer)
{
PRBool interrupted;
nsCOMPtr<nsIImapIncomingServer>
aImapServer(do_QueryInterface(aMsgIncomingServer, &rv));
if (NS_SUCCEEDED(rv) && aImapServer)
aImapServer->PseudoInterruptMsgLoad(aImapUrl, &interrupted);
}
}
// if the display consumer is a docshell, then we should run the url in the docshell.
// otherwise, it should be a stream listener....so open a channel using AsyncRead
// and the provided stream listener....
// if the display consumer is a docshell, then we should run the url in the docshell.
// otherwise, it should be a stream listener....so open a channel using AsyncRead
// and the provided stream listener....
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aDisplayConsumer, &rv));
if (NS_SUCCEEDED(rv) && docShell)

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

@ -195,7 +195,8 @@ NS_IMETHODIMP nsImapUrl::GetImapMailFolderSink(nsIImapMailFolderSink **
aImapMailFolderSink)
{
NS_ENSURE_ARG_POINTER(aImapMailFolderSink);
NS_ENSURE_ARG_POINTER(m_imapMailFolderSink);
if (!m_imapMailFolderSink)
return NS_ERROR_NULL_POINTER; // no assert, so don't use NS_ENSURE_POINTER.
nsCOMPtr<nsIImapMailFolderSink> folderSink = do_QueryReferent(m_imapMailFolderSink);
*aImapMailFolderSink = folderSink;