diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mailnews/local/src/nsMailboxProtocol.cpp | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/mailnews/local/src/nsMailboxProtocol.cpp')
-rw-r--r-- | comm/mailnews/local/src/nsMailboxProtocol.cpp | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/comm/mailnews/local/src/nsMailboxProtocol.cpp b/comm/mailnews/local/src/nsMailboxProtocol.cpp new file mode 100644 index 0000000000..389de0a93e --- /dev/null +++ b/comm/mailnews/local/src/nsMailboxProtocol.cpp @@ -0,0 +1,657 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "msgCore.h" + +#include "nsMailboxProtocol.h" +#include "nscore.h" +#include "nsIInputStreamPump.h" +#include "nsIMsgHdr.h" +#include "nsMsgLineBuffer.h" +#include "nsIMsgMailNewsUrl.h" +#include "nsIMsgFolder.h" +#include "nsICopyMessageStreamListener.h" +#include "prtime.h" +#include "mozilla/Logging.h" +#include "mozilla/SlicedInputStream.h" +#include "prerror.h" +#include "prprf.h" +#include "nspr.h" +#include "nsIStreamTransportService.h" +#include "nsIStreamConverterService.h" +#include "nsNetUtil.h" +#include "nsMsgUtils.h" +#include "nsIMsgWindow.h" +#include "nsISeekableStream.h" +#include "nsStreamUtils.h" + +using namespace mozilla; + +static LazyLogModule MAILBOX("Mailbox"); + +/* the output_buffer_size must be larger than the largest possible line + * 2000 seems good for news + * + * jwz: I increased this to 4k since it must be big enough to hold the + * entire button-bar HTML, and with the new "mailto" format, that can + * contain arbitrarily long header fields like "references". + * + * fortezza: proxy auth is huge, buffer increased to 8k (sigh). + */ +#define OUTPUT_BUFFER_SIZE (4096 * 2) + +nsMailboxProtocol::nsMailboxProtocol(nsIURI* aURI) + : nsMsgProtocol(aURI), + m_mailboxAction(nsIMailboxUrl::ActionParseMailbox), + m_nextState(MAILBOX_UNINITIALIZED), + m_initialState(MAILBOX_UNINITIALIZED), + mCurrentProgress(0) {} + +nsMailboxProtocol::~nsMailboxProtocol() {} + +nsresult nsMailboxProtocol::OpenMultipleMsgTransport(uint64_t offset, + int64_t size) { + nsresult rv; + + nsCOMPtr<nsIStreamTransportService> serv = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIInputStream> clonedStream; + nsCOMPtr<nsIInputStream> replacementStream; + rv = NS_CloneInputStream(m_multipleMsgMoveCopyStream, + getter_AddRefs(clonedStream), + getter_AddRefs(replacementStream)); + NS_ENSURE_SUCCESS(rv, rv); + if (replacementStream) { + // If m_multipleMsgMoveCopyStream is not clonable, NS_CloneInputStream + // will clone it using a pipe. In order to keep the copy alive and working, + // we have to replace the original stream with the replacement. + m_multipleMsgMoveCopyStream = replacementStream.forget(); + } + // XXX 64-bit + // This can be called with size == -1 which means "read as much as we can". + // We pass this on as UINT64_MAX, which is in fact uint64_t(-1). + RefPtr<SlicedInputStream> slicedStream = new SlicedInputStream( + clonedStream.forget(), offset, size == -1 ? UINT64_MAX : uint64_t(size)); + // Always close the sliced stream when done, we still have the original. + rv = serv->CreateInputTransport(slicedStream, true, + getter_AddRefs(m_transport)); + + return rv; +} + +nsresult nsMailboxProtocol::Initialize(nsIURI* aURL) { + NS_ASSERTION(aURL, "invalid URL passed into MAILBOX Protocol"); + nsresult rv = NS_OK; + if (aURL) { + m_runningUrl = do_QueryInterface(aURL, &rv); + if (NS_SUCCEEDED(rv) && m_runningUrl) { + nsCOMPtr<nsIMsgWindow> window; + rv = m_runningUrl->GetMailboxAction(&m_mailboxAction); + // clear stopped flag on msg window, because we care. + nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_runningUrl); + if (mailnewsUrl) { + mailnewsUrl->GetMsgWindow(getter_AddRefs(window)); + if (window) window->SetStopped(false); + } + + if (m_mailboxAction == nsIMailboxUrl::ActionParseMailbox) { + // Set the length of the file equal to the max progress + nsCOMPtr<nsIFile> file; + GetFileFromURL(aURL, getter_AddRefs(file)); + if (file) { + int64_t fileSize = 0; + file->GetFileSize(&fileSize); + mailnewsUrl->SetMaxProgress(fileSize); + } + + rv = + OpenFileSocket(aURL, 0, -1 /* read in all the bytes in the file */); + } else { + if (RunningMultipleMsgUrl()) { + // if we're running multiple msg url, we clear the event sink because + // the multiple msg urls will handle setting the progress. + mProgressEventSink = nullptr; + } + + nsCOMPtr<nsIMsgMessageUrl> msgUrl = + do_QueryInterface(m_runningUrl, &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIMsgFolder> folder; + nsCOMPtr<nsIMsgDBHdr> msgHdr; + rv = msgUrl->GetMessageHeader(getter_AddRefs(msgHdr)); + if (NS_SUCCEEDED(rv) && msgHdr) { + uint32_t msgSize = 0; + msgHdr->GetMessageSize(&msgSize); + m_runningUrl->SetMessageSize(msgSize); + + SetContentLength(msgSize); + mailnewsUrl->SetMaxProgress(msgSize); + + rv = msgHdr->GetFolder(getter_AddRefs(folder)); + if (NS_SUCCEEDED(rv) && folder) { + nsCOMPtr<nsIInputStream> stream; + int64_t offset = 0; + rv = folder->GetMsgInputStream(msgHdr, getter_AddRefs(stream)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsISeekableStream> seekableStream( + do_QueryInterface(stream, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + seekableStream->Tell(&offset); + // create input stream transport + nsCOMPtr<nsIStreamTransportService> sts = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + m_readCount = msgSize; + + RefPtr<SlicedInputStream> slicedStream = new SlicedInputStream( + stream.forget(), offset, uint64_t(msgSize)); + // Always close the sliced stream when done, we still have the + // original. + rv = sts->CreateInputTransport(slicedStream, true, + getter_AddRefs(m_transport)); + + m_socketIsOpen = false; + } + } + if (!folder) { // must be a .eml file + rv = OpenFileSocket(aURL, 0, -1); + } + } + NS_ASSERTION(NS_SUCCEEDED(rv), "oops....i messed something up"); + } + } + } + + m_lineStreamBuffer = new nsMsgLineStreamBuffer(OUTPUT_BUFFER_SIZE, true); + + m_nextState = MAILBOX_READ_FOLDER; + m_initialState = MAILBOX_READ_FOLDER; + mCurrentProgress = 0; + + // do we really need both? + m_tempMessageFile = m_tempMsgFile; + return rv; +} + +///////////////////////////////////////////////////////////////////////////////////////////// +// we support the nsIStreamListener interface +//////////////////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP nsMailboxProtocol::OnStartRequest(nsIRequest* request) { + // extract the appropriate event sinks from the url and initialize them in our + // protocol data the URL should be queried for a nsINewsURL. If it doesn't + // support a news URL interface then we have an error. + if (m_nextState == MAILBOX_READ_FOLDER && m_mailboxParser) { + // we need to inform our mailbox parser that it's time to start... + // NOTE: `request` here will be an nsInputStreamPump, but our callbacks + // are expecting to be able to QI to a `nsIChannel` to get the URI. + // So we pass `this`. See Bug 1528662. + m_mailboxParser->OnStartRequest(this); + } + return nsMsgProtocol::OnStartRequest(request); +} + +bool nsMailboxProtocol::RunningMultipleMsgUrl() { + if (m_mailboxAction == nsIMailboxUrl::ActionCopyMessage || + m_mailboxAction == nsIMailboxUrl::ActionMoveMessage) { + uint32_t numMoveCopyMsgs; + nsresult rv = m_runningUrl->GetNumMoveCopyMsgs(&numMoveCopyMsgs); + if (NS_SUCCEEDED(rv) && numMoveCopyMsgs > 1) return true; + } + return false; +} + +// stop binding is a "notification" informing us that the stream associated with +// aURL is going away. +NS_IMETHODIMP nsMailboxProtocol::OnStopRequest(nsIRequest* request, + nsresult aStatus) { + nsresult rv; + if (m_nextState == MAILBOX_READ_FOLDER && m_mailboxParser) { + // we need to inform our mailbox parser that there is no more incoming + // data... NOTE: `request` here will be an nsInputStreamPump, but our + // callbacks are expecting to be able to QI to a `nsIChannel` to get the + // URI. So we pass `this`. See Bug 1528662. + m_mailboxParser->OnStopRequest(this, aStatus); + } else if (m_nextState == MAILBOX_READ_MESSAGE) { + DoneReadingMessage(); + } + // I'm not getting cancel status - maybe the load group still has the status. + bool stopped = false; + if (m_runningUrl) { + nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_runningUrl); + if (mailnewsUrl) { + nsCOMPtr<nsIMsgWindow> window; + mailnewsUrl->GetMsgWindow(getter_AddRefs(window)); + if (window) window->GetStopped(&stopped); + } + + if (!stopped && NS_SUCCEEDED(aStatus) && + (m_mailboxAction == nsIMailboxUrl::ActionCopyMessage || + m_mailboxAction == nsIMailboxUrl::ActionMoveMessage)) { + uint32_t numMoveCopyMsgs; + uint32_t curMoveCopyMsgIndex; + rv = m_runningUrl->GetNumMoveCopyMsgs(&numMoveCopyMsgs); + if (NS_SUCCEEDED(rv) && numMoveCopyMsgs > 0) { + m_runningUrl->GetCurMoveCopyMsgIndex(&curMoveCopyMsgIndex); + if (++curMoveCopyMsgIndex < numMoveCopyMsgs) { + if (!mSuppressListenerNotifications && m_channelListener) { + nsCOMPtr<nsICopyMessageStreamListener> listener = + do_QueryInterface(m_channelListener, &rv); + if (listener) { + listener->EndCopy(mailnewsUrl, aStatus); + listener->StartMessage(); // start next message. + } + } + m_runningUrl->SetCurMoveCopyMsgIndex(curMoveCopyMsgIndex); + nsCOMPtr<nsIMsgDBHdr> nextMsg; + rv = m_runningUrl->GetMoveCopyMsgHdrForIndex(curMoveCopyMsgIndex, + getter_AddRefs(nextMsg)); + if (NS_SUCCEEDED(rv) && nextMsg) { + uint32_t msgSize = 0; + nsCOMPtr<nsIMsgFolder> msgFolder; + nextMsg->GetFolder(getter_AddRefs(msgFolder)); + NS_ASSERTION( + msgFolder, + "couldn't get folder for next msg in multiple msg local copy"); + if (msgFolder) { + nsCString uri; + msgFolder->GetUriForMsg(nextMsg, uri); + nsCOMPtr<nsIMsgMessageUrl> msgUrl = + do_QueryInterface(m_runningUrl); + if (msgUrl) { + msgUrl->SetOriginalSpec(uri); + msgUrl->SetUri(uri); + + uint64_t msgOffset; + nextMsg->GetMessageOffset(&msgOffset); + nextMsg->GetMessageSize(&msgSize); + // now we have to seek to the right position in the file and + // basically re-initialize the transport with the correct + // message size. then, we have to make sure the url keeps + // running somehow. + // + // put us in a state where we are always notified of incoming + // data + // + m_transport = nullptr; // open new stream transport + m_outputStream = nullptr; + + if (m_multipleMsgMoveCopyStream) { + rv = OpenMultipleMsgTransport(msgOffset, msgSize); + } else { + nsCOMPtr<nsIInputStream> stream; + rv = msgFolder->GetMsgInputStream(nextMsg, + getter_AddRefs(stream)); + if (NS_SUCCEEDED(rv)) { + // create input stream transport + nsCOMPtr<nsIStreamTransportService> sts = do_GetService( + NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); + + if (NS_SUCCEEDED(rv)) { + m_readCount = msgSize; + RefPtr<SlicedInputStream> slicedStream = + new SlicedInputStream(stream.forget(), msgOffset, + uint64_t(msgSize)); + rv = sts->CreateInputTransport( + slicedStream, true, getter_AddRefs(m_transport)); + } + } + } + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIInputStream> stream; + rv = m_transport->OpenInputStream(0, 0, 0, + getter_AddRefs(stream)); + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIInputStreamPump> pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), + stream.forget()); + if (NS_SUCCEEDED(rv)) { + rv = pump->AsyncRead(this); + if (NS_SUCCEEDED(rv)) m_request = pump; + } + } + } + + NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncRead failed"); + if (m_loadGroup) + m_loadGroup->RemoveRequest(static_cast<nsIRequest*>(this), + nullptr, aStatus); + m_socketIsOpen = true; // mark the channel as open + return aStatus; + } + } + } + } else { + } + } + } + } + // and we want to mark ourselves for deletion or some how inform our protocol + // manager that we are available for another url if there is one. + + // mscott --> maybe we should set our state to done because we don't run + // multiple urls in a mailbox protocol connection.... + m_nextState = MAILBOX_DONE; + + // the following is for smoke test purposes. QA is looking at this "Mailbox + // Done" string which is printed out to the console and determining if the + // mail app loaded up correctly...obviously this solution is not very good so + // we should look at something better, but don't remove this line before + // talking to me (mscott) and mailnews QA.... + + MOZ_LOG(MAILBOX, LogLevel::Info, ("Mailbox Done")); + + // when on stop binding is called, we as the protocol are done...let's close + // down the connection releasing all of our interfaces. It's important to + // remember that this on stop binding call is coming from netlib so they are + // never going to ping us again with on data available. This means we'll never + // be going through the Process loop... + + if (m_multipleMsgMoveCopyStream) { + m_multipleMsgMoveCopyStream->Close(); + m_multipleMsgMoveCopyStream = nullptr; + } + nsMsgProtocol::OnStopRequest(request, aStatus); + return CloseSocket(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +// End of nsIStreamListenerSupport +////////////////////////////////////////////////////////////////////////////////////////////// + +nsresult nsMailboxProtocol::DoneReadingMessage() { + nsresult rv = NS_OK; + // and close the article file if it was open.... + + if (m_mailboxAction == nsIMailboxUrl::ActionSaveMessageToDisk && + m_msgFileOutputStream) + rv = m_msgFileOutputStream->Close(); + + return rv; +} + +///////////////////////////////////////////////////////////////////////////////////////////// +// Begin protocol state machine functions... +////////////////////////////////////////////////////////////////////////////////////////////// + +nsresult nsMailboxProtocol::LoadUrl(nsIURI* aURL, nsISupports* aConsumer) { + nsresult rv = NS_OK; + // if we were already initialized with a consumer, use it... + nsCOMPtr<nsIStreamListener> consumer = do_QueryInterface(aConsumer); + if (consumer) m_channelListener = consumer; + + if (aURL) { + m_runningUrl = do_QueryInterface(aURL); + if (m_runningUrl) { + // find out from the url what action we are supposed to perform... + rv = m_runningUrl->GetMailboxAction(&m_mailboxAction); + + bool convertData = false; + + // need to check if we're fetching an rfc822 part in order to + // quote a message. + if (m_mailboxAction == nsIMailboxUrl::ActionFetchMessage) { + nsCOMPtr<nsIMsgMailNewsUrl> msgUrl = + do_QueryInterface(m_runningUrl, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString queryStr; + rv = msgUrl->GetQuery(queryStr); + NS_ENSURE_SUCCESS(rv, rv); + + // check if this is a filter plugin requesting the message. + // in that case, set up a text converter + convertData = (queryStr.Find("header=filter") != -1 || + queryStr.Find("header=attach") != -1); + } else if (m_mailboxAction == nsIMailboxUrl::ActionFetchPart) { + // when fetching a part, we need to insert a converter into the listener + // chain order to force just the part out of the message. Our channel + // listener is the consumer we'll pass in to AsyncConvertData. + convertData = true; + consumer = m_channelListener; + } + if (convertData) { + nsCOMPtr<nsIStreamConverterService> streamConverter = + do_GetService("@mozilla.org/streamConverters;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIStreamListener> conversionListener; + nsCOMPtr<nsIChannel> channel; + QueryInterface(NS_GET_IID(nsIChannel), getter_AddRefs(channel)); + + rv = streamConverter->AsyncConvertData( + "message/rfc822", "*/*", consumer, channel, + getter_AddRefs(m_channelListener)); + } + + if (NS_SUCCEEDED(rv)) { + switch (m_mailboxAction) { + case nsIMailboxUrl::ActionParseMailbox: + // extract the mailbox parser.. + rv = + m_runningUrl->GetMailboxParser(getter_AddRefs(m_mailboxParser)); + m_nextState = MAILBOX_READ_FOLDER; + break; + case nsIMailboxUrl::ActionSaveMessageToDisk: + // ohhh, display message already writes a msg to disk (as part of a + // hack) so we can piggy back off of that!! We just need to change + // m_tempMessageFile to be the name of our save message to disk + // file. Since save message to disk urls are run without a docshell + // to display the msg into, we won't be trying to display the + // message after we write it to disk... + { + nsCOMPtr<nsIMsgMessageUrl> messageUrl = + do_QueryInterface(m_runningUrl, &rv); + if (NS_SUCCEEDED(rv)) { + messageUrl->GetMessageFile(getter_AddRefs(m_tempMessageFile)); + rv = MsgNewBufferedFileOutputStream( + getter_AddRefs(m_msgFileOutputStream), m_tempMessageFile, + -1, 00600); + NS_ENSURE_SUCCESS(rv, rv); + + bool addDummyEnvelope = false; + messageUrl->GetAddDummyEnvelope(&addDummyEnvelope); + if (addDummyEnvelope) + SetFlag(MAILBOX_MSG_PARSE_FIRST_LINE); + else + ClearFlag(MAILBOX_MSG_PARSE_FIRST_LINE); + } + } + m_nextState = MAILBOX_READ_MESSAGE; + break; + case nsIMailboxUrl::ActionCopyMessage: + case nsIMailboxUrl::ActionMoveMessage: + case nsIMailboxUrl::ActionFetchMessage: + ClearFlag(MAILBOX_MSG_PARSE_FIRST_LINE); + m_nextState = MAILBOX_READ_MESSAGE; + break; + case nsIMailboxUrl::ActionFetchPart: + m_nextState = MAILBOX_READ_MESSAGE; + break; + default: + break; + } + } + + rv = nsMsgProtocol::LoadUrl(aURL, m_channelListener); + + } // if we received an MAILBOX url... + } // if we received a url! + + return rv; +} + +int32_t nsMailboxProtocol::ReadFolderResponse(nsIInputStream* inputStream, + uint64_t sourceOffset, + uint32_t length) { + // okay we are doing a folder read in 8K chunks of a mail folder.... + // this is almost too easy....we can just forward the data in this stream on + // to our folder parser object!!! + + nsresult rv = NS_OK; + mCurrentProgress += length; + + if (m_mailboxParser) { + rv = m_mailboxParser->OnDataAvailable( + nullptr, inputStream, sourceOffset, + length); // let the parser deal with it... + } + if (NS_FAILED(rv)) { + m_nextState = MAILBOX_ERROR_DONE; // drop out of the loop.... + return -1; + } + + // now wait for the next 8K chunk to come in..... + SetFlag(MAILBOX_PAUSE_FOR_READ); + + // leave our state alone so when the next chunk of the mailbox comes in we + // jump to this state and repeat....how does this process end? Well when the + // file is done being read in, core net lib will issue an ::OnStopRequest to + // us...we'll use that as our sign to drop out of this state and to close the + // protocol instance... + + return 0; +} + +int32_t nsMailboxProtocol::ReadMessageResponse(nsIInputStream* inputStream, + uint64_t sourceOffset, + uint32_t length) { + char* line = nullptr; + uint32_t status = 0; + nsresult rv = NS_OK; + mCurrentProgress += length; + + // if we are doing a move or a copy, forward the data onto the copy handler... + // if we want to display the message then parse the incoming data... + + if (m_channelListener) { + // just forward the data we read in to the listener... + rv = m_channelListener->OnDataAvailable(this, inputStream, sourceOffset, + length); + } else { + bool pauseForMoreData = false; + bool canonicalLineEnding = false; + nsCOMPtr<nsIMsgMessageUrl> msgurl = do_QueryInterface(m_runningUrl); + + if (msgurl) msgurl->GetCanonicalLineEnding(&canonicalLineEnding); + + while ((line = m_lineStreamBuffer->ReadNextLine(inputStream, status, + pauseForMoreData)) && + !pauseForMoreData) { + /* When we're sending this line to a converter (ie, + it's a message/rfc822) use the local line termination + convention, not CRLF. This makes text articles get + saved with the local line terminators. Since SMTP + and NNTP mandate the use of CRLF, it is expected that + the local system will convert that to the local line + terminator as it is read. + */ + // mscott - the firstline hack is aimed at making sure we don't write + // out the dummy header when we are trying to display the message. + // The dummy header is the From line with the date tag on it. + if (m_msgFileOutputStream && TestFlag(MAILBOX_MSG_PARSE_FIRST_LINE)) { + uint32_t count = 0; + rv = m_msgFileOutputStream->Write(line, PL_strlen(line), &count); + if (NS_FAILED(rv)) break; + + if (canonicalLineEnding) + rv = m_msgFileOutputStream->Write(CRLF, 2, &count); + else + rv = m_msgFileOutputStream->Write(MSG_LINEBREAK, MSG_LINEBREAK_LEN, + &count); + + if (NS_FAILED(rv)) break; + } else + SetFlag(MAILBOX_MSG_PARSE_FIRST_LINE); + PR_Free(line); + } + PR_Free(line); + } + + SetFlag(MAILBOX_PAUSE_FOR_READ); // wait for more data to become available... + if (mProgressEventSink && m_runningUrl) { + int64_t maxProgress; + nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl(do_QueryInterface(m_runningUrl)); + mailnewsUrl->GetMaxProgress(&maxProgress); + mProgressEventSink->OnProgress(this, mCurrentProgress, maxProgress); + } + + if (NS_FAILED(rv)) return -1; + + return 0; +} + +/* + * returns negative if the transfer is finished or error'd out + * + * returns zero or more if the transfer needs to be continued. + */ +nsresult nsMailboxProtocol::ProcessProtocolState(nsIURI* url, + nsIInputStream* inputStream, + uint64_t offset, + uint32_t length) { + nsresult rv = NS_OK; + int32_t status = 0; + ClearFlag(MAILBOX_PAUSE_FOR_READ); /* already paused; reset */ + + while (!TestFlag(MAILBOX_PAUSE_FOR_READ)) { + switch (m_nextState) { + case MAILBOX_READ_MESSAGE: + if (inputStream == nullptr) + SetFlag(MAILBOX_PAUSE_FOR_READ); + else + status = ReadMessageResponse(inputStream, offset, length); + break; + case MAILBOX_READ_FOLDER: + if (inputStream == nullptr) + SetFlag(MAILBOX_PAUSE_FOR_READ); // wait for file socket to read in + // the next chunk... + else + status = ReadFolderResponse(inputStream, offset, length); + break; + case MAILBOX_DONE: + case MAILBOX_ERROR_DONE: { + nsCOMPtr<nsIMsgMailNewsUrl> anotherUrl = + do_QueryInterface(m_runningUrl); + rv = m_nextState == MAILBOX_DONE ? NS_OK : NS_ERROR_FAILURE; + anotherUrl->SetUrlState(false, rv); + m_nextState = MAILBOX_FREE; + } break; + + case MAILBOX_FREE: + // MAILBOX is a one time use connection so kill it if we get here... + CloseSocket(); + return rv; /* final end */ + + default: /* should never happen !!! */ + m_nextState = MAILBOX_ERROR_DONE; + break; + } + + /* check for errors during load and call error + * state if found + */ + if (status < 0 && m_nextState != MAILBOX_FREE) { + m_nextState = MAILBOX_ERROR_DONE; + /* don't exit! loop around again and do the free case */ + ClearFlag(MAILBOX_PAUSE_FOR_READ); + } + } /* while(!MAILBOX_PAUSE_FOR_READ) */ + + return rv; +} + +nsresult nsMailboxProtocol::CloseSocket() { + // how do you force a release when closing the connection?? + nsMsgProtocol::CloseSocket(); + m_runningUrl = nullptr; + m_mailboxParser = nullptr; + return NS_OK; +} + +// vim: ts=2 sw=2 |