fix save as in news while offline by using common save as listener r=navin, sr=sspitzer 159988

This commit is contained in:
bienvenu%netscape.com 2002-08-10 17:13:44 +00:00
Родитель f90e0cdffb
Коммит a3d081ccb0
6 изменённых файлов: 230 добавлений и 275 удалений

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

@ -48,6 +48,8 @@ interface nsIMsgSearchSession;
interface nsICacheEntryDescriptor;
interface nsICacheSession;
interface nsIMimeHeaders;
interface nsIStreamListener;
[scriptable, uuid(6CFFCEB0-CB8C-11d2-8065-006008128C4E)]
interface nsIMsgMailNewsUrl : nsIURL {
///////////////////////////////////////////////////////////////////////////////
@ -101,6 +103,7 @@ interface nsIMsgMailNewsUrl : nsIURL {
const unsigned long eMove = 1;
const unsigned long eDisplay = 2;
boolean IsUrlType(in unsigned long type);
nsIStreamListener getSaveAsListener(in boolean addDummyEnvelope, in nsIFileSpec aFileSpec);
};
//////////////////////////////////////////////////////////////////////////////////
@ -115,12 +118,12 @@ interface nsIMsgMailNewsUrl : nsIURL {
[scriptable, uuid(02338DD2-E7B9-11d2-8070-006008128C4E)]
interface nsIMsgMessageUrl : nsISupports {
// get and set the RDF URI associated with the url. Note, not all urls have
// had uri's set on them so be prepared to handle cases where this string is empty.
attribute string uri;
// used by imap, pop and nntp in order to implement save message to disk
attribute nsIFileSpec messageFile;
attribute boolean AddDummyEnvelope;
// get and set the RDF URI associated with the url. Note, not all urls have
// had uri's set on them so be prepared to handle cases where this string is empty.
attribute string uri;
// 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;
};

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

@ -53,6 +53,11 @@
#include "nsIIOService.h"
#include "nsNetCID.h"
#include "nsEscape.h"
#include "nsIStreamListener.h"
#include "nsIOutputStream.h"
#include "nsIInputStream.h"
#include "nsIFileSpec.h"
#include <time.h>
static NS_DEFINE_CID(kUrlListenerManagerCID, NS_URLLISTENERMANAGER_CID);
static NS_DEFINE_CID(kStandardUrlCID, NS_STANDARDURL_CID);
@ -802,3 +807,192 @@ NS_IMETHODIMP nsMsgMailNewsUrl::SetMimeHeaders(nsIMimeHeaders *mimeHeaders)
mMimeHeaders = mimeHeaders;
return NS_OK;
}
#define SAVE_BUF_SIZE 8192
class nsMsgSaveAsListener : public nsIStreamListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
nsMsgSaveAsListener(nsIFileSpec *aFileSpec, PRBool addDummyEnvelope);
virtual ~nsMsgSaveAsListener();
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(nsMsgSaveAsListener, nsIStreamListener)
nsMsgSaveAsListener::nsMsgSaveAsListener(nsIFileSpec *aFileSpec, PRBool addDummyEnvelope)
{
m_outputFile = aFileSpec;
m_writtenData = PR_FALSE;
m_addDummyEnvelope = addDummyEnvelope;
m_leftOver = 0;
NS_INIT_REFCNT();
}
nsMsgSaveAsListener::~nsMsgSaveAsListener()
{
}
NS_IMETHODIMP nsMsgSaveAsListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
return NS_OK;
}
NS_IMETHODIMP
nsMsgSaveAsListener::OnStopRequest(nsIRequest *request, nsISupports * aCtxt, nsresult aStatus)
{
if (m_outputStream)
{
m_outputStream->Flush();
m_outputStream->Close();
}
if (m_outputFile)
m_outputFile->CloseStream();
return NS_OK;
}
NS_IMETHODIMP nsMsgSaveAsListener::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_strchr(start, '\r');
if (!end)
end = PL_strchr(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_strchr(start, '\r');
if (!end)
end = PL_strchr(start, '\n');
if (start && !end)
{
m_leftOver -= (start - m_dataBuffer);
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 nsMsgSaveAsListener::SetupMsgWriteStream(nsIFileSpec *aFileSpec, PRBool addDummyEnvelope)
{
nsresult rv = NS_ERROR_FAILURE;
// if the file already exists, delete it.
// do this before we get the outputstream
nsFileSpec fileSpec;
aFileSpec->GetFileSpec(&fileSpec);
fileSpec.Delete(PR_FALSE);
rv = aFileSpec->GetOutputStream(getter_AddRefs(m_outputStream));
NS_ENSURE_SUCCESS(rv,rv);
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_IMETHODIMP nsMsgMailNewsUrl::GetSaveAsListener(PRBool addDummyEnvelope,
nsIFileSpec *aFileSpec, nsIStreamListener **aSaveListener)
{
NS_ENSURE_ARG_POINTER(aSaveListener);
nsMsgSaveAsListener *saveAsListener = new nsMsgSaveAsListener(aFileSpec, addDummyEnvelope);
return saveAsListener->QueryInterface(NS_GET_IID(nsIStreamListener), (void **) aSaveListener);
}

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

@ -98,7 +98,6 @@
#include "nsIWindowWatcher.h"
#include "nsImapProtocol.h"
#include "nsIMsgMailSession.h"
#include <time.h>
#define PREF_MAIL_ROOT_IMAP "mail.root.imap"
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
@ -115,184 +114,6 @@ 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()
{
}
NS_IMETHODIMP nsImapSaveAsListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
return NS_OK;
}
NS_IMETHODIMP
nsImapSaveAsListener::OnStopRequest(nsIRequest *request, nsISupports * aCtxt, nsresult aStatus)
{
if (m_outputStream)
{
m_outputStream->Flush();
m_outputStream->Close();
}
if (m_outputFile)
m_outputFile->CloseStream();
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);
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;
// if the file already exists, delete it.
// do this before we get the outputstream
nsFileSpec fileSpec;
aFileSpec->GetFileSpec(&fileSpec);
fileSpec.Delete(PR_FALSE);
rv = aFileSpec->GetOutputStream(getter_AddRefs(m_outputStream));
NS_ENSURE_SUCCESS(rv,rv);
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_INTERFACE6(nsImapService,
@ -1132,7 +953,8 @@ NS_IMETHODIMP nsImapService::SaveMessageToDisk(const char *aMessageURI,
if (mailnewsUrl)
mailnewsUrl->SetMsgIsInLocalCache(hasMsgOffline);
nsImapSaveAsListener *saveAsListener = new nsImapSaveAsListener(aFile, aAddDummyEnvelope);
nsCOMPtr <nsIStreamListener> saveAsListener;
mailnewsUrl->GetSaveAsListener(aAddDummyEnvelope, aFile, getter_AddRefs(saveAsListener));
return FetchMessage(imapUrl, nsIImapUrl::nsImapSaveMessageToDisk, folder, imapMessageSink, aMsgWindow, aURL, saveAsListener, msgKey, PR_TRUE);
}

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

@ -530,7 +530,8 @@ NS_IMETHODIMP nsNNTPProtocol::Initialize(nsIURI * aURL, nsIMsgWindow *aMsgWindow
mailnewsUrl->SetMsgWindow(aMsgWindow);
m_runningURL->GetNewsAction(&m_newsAction);
if (m_newsAction == nsINntpUrl::ActionFetchArticle || m_newsAction == nsINntpUrl::ActionFetchPart) {
if (m_newsAction == nsINntpUrl::ActionFetchArticle || m_newsAction == nsINntpUrl::ActionFetchPart
|| m_newsAction == nsINntpUrl::ActionSaveMessageToDisk) {
PRBool msgIsInLocalCache = PR_FALSE;
mailnewsUrl->GetMsgIsInLocalCache(&msgIsInLocalCache);
if (msgIsInLocalCache)
@ -963,7 +964,8 @@ NS_IMETHODIMP nsNNTPProtocol::AsyncOpen(nsIStreamListener *listener, nsISupports
m_runningURL->GetNewsAction(&m_newsAction);
// first, check if this is a message load that should come from either
// the memory cache or the local msg cache.
if (mailnewsUrl && (m_newsAction == nsINntpUrl::ActionFetchArticle || m_newsAction == nsINntpUrl::ActionFetchPart))
if (mailnewsUrl && (m_newsAction == nsINntpUrl::ActionFetchArticle || m_newsAction == nsINntpUrl::ActionFetchPart
|| m_newsAction == nsINntpUrl::ActionSaveMessageToDisk))
{
SetupPartExtractorListener(m_channelListener);
@ -2488,54 +2490,6 @@ PRInt32 nsNNTPProtocol::BeginArticle()
// TODO: return on failure?
}
if (m_newsAction == nsINntpUrl::ActionSaveMessageToDisk)
{
// get the file involved from the url
nsCOMPtr<nsIFileSpec> msgSpec;
nsCOMPtr<nsIMsgMessageUrl> msgurl = do_QueryInterface(m_runningURL);
msgurl->GetMessageFile(getter_AddRefs(msgSpec));
nsFileSpec fileSpec;
if (msgSpec)
{
msgSpec->GetFileSpec(&fileSpec);
fileSpec.Delete(PR_FALSE);
nsCOMPtr <nsISupports> supports;
NS_NewIOFileStream(getter_AddRefs(supports), fileSpec,
PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 00700);
nsresult rv;
m_tempArticleStream = do_QueryInterface(supports, &rv);
NS_ASSERTION(NS_SUCCEEDED(rv) && m_tempArticleStream,"failed to get article stream");
if (NS_FAILED(rv) || !m_tempArticleStream) return -1;
PRBool needDummyHeaders = PR_FALSE;
msgurl->GetAddDummyEnvelope(&needDummyHeaders);
if (needDummyHeaders)
{
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_tempArticleStream->Write(result.get(), result.Length(),
&writeCount);
result = "X-Mozilla-Status: 0001";
result += MSG_LINEBREAK;
m_tempArticleStream->Write(result.get(), result.Length(),
&writeCount);
result = "X-Mozilla-Status2: 00000000";
result += MSG_LINEBREAK;
m_tempArticleStream->Write(result.get(), result.Length(),
&writeCount);
}
}
}
m_nextState = NNTP_READ_ARTICLE;
return 0;
@ -2675,10 +2629,6 @@ PRInt32 nsNNTPProtocol::ReadArticle(nsIInputStream * inputStream, PRUint32 lengt
else
m_nextState = NEWS_DONE;
// and close the article file if it was open....
if (m_tempArticleStream)
m_tempArticleStream->Close();
ClearFlag(NNTP_PAUSE_FOR_READ);
}
else
@ -2699,32 +2649,6 @@ PRInt32 nsNNTPProtocol::ReadArticle(nsIInputStream * inputStream, PRUint32 lengt
ParseHeaderForCancel(outputBuffer);
}
if (m_tempArticleStream)
{
PRUint32 count = 0;
m_tempArticleStream->Write(outputBuffer, PL_strlen(outputBuffer), &count);
/* 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.
*/
// ** jto - in the case of save message to the stationary file if the
// message is to be uploaded to the imap server we need to end the
// line with canonical line endings, i.e., CRLF
nsCOMPtr<nsIMsgMessageUrl> msgurl = do_QueryInterface(m_runningURL);
PRBool canonicalLineEnding = PR_FALSE;
if (msgurl)
msgurl->GetCanonicalLineEnding(&canonicalLineEnding);
if (canonicalLineEnding)
m_tempArticleStream->Write(CRLF, PL_strlen(CRLF), &count);
else
m_tempArticleStream->Write(MSG_LINEBREAK, PL_strlen(MSG_LINEBREAK), &count);
}
}
}

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

@ -204,8 +204,6 @@ private:
static PRBool CheckIfAuthor(nsISupports *aElement, void *data);
nsCOMPtr<nsIOutputStream> m_tempArticleStream;
nsCOMPtr <nsINNTPNewsgroupList> m_newsgroupList;
nsCOMPtr <nsINNTPArticleList> m_articleList;

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

@ -157,21 +157,35 @@ nsNntpService::SaveMessageToDisk(const char *aMessageURI,
nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(url);
if (msgUrl) {
msgUrl->SetMessageFile(aFile);
// msgUrl->SetMessageFile(aFile);
msgUrl->SetAddDummyEnvelope(aAddDummyEnvelope);
msgUrl->SetCanonicalLineEnding(canonicalLineEnding);
}
rv = RunNewsUrl(url, nsnull, nsnull);
NS_ENSURE_SUCCESS(rv,rv);
PRBool hasMsgOffline = PR_FALSE;
if (aURL)
nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(url);
if (folder)
{
*aURL = url;
NS_IF_ADDREF(*aURL);
nsCOMPtr <nsIMsgNewsFolder> newsFolder = do_QueryInterface(folder);
if (newsFolder)
{
if (mailNewsUrl)
{
folder->HasMsgOffline(key, &hasMsgOffline);
mailNewsUrl->SetMsgIsInLocalCache(hasMsgOffline);
}
}
}
return rv;
if (mailNewsUrl)
{
nsCOMPtr <nsIStreamListener> saveAsListener;
mailNewsUrl->GetSaveAsListener(aAddDummyEnvelope, aFile, getter_AddRefs(saveAsListener));
rv = DisplayMessage(aMessageURI, saveAsListener, /* nsIMsgWindow *aMsgWindow */nsnull, aUrlListener, nsnull /*aCharsetOverride */, aURL);
}
return rv;
}