Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 • committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

View file

@ -0,0 +1,36 @@
# vim: set filetype=python:
# 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/.
SOURCES += [
'nsLocalMailFolder.cpp',
'nsLocalUndoTxn.cpp',
'nsLocalUtils.cpp',
'nsMailboxProtocol.cpp',
'nsMailboxServer.cpp',
'nsMailboxService.cpp',
'nsMailboxUrl.cpp',
'nsMsgBrkMBoxStore.cpp',
'nsMsgLocalStoreUtils.cpp',
'nsMsgMaildirStore.cpp',
'nsNoIncomingServer.cpp',
'nsNoneService.cpp',
'nsParseMailbox.cpp',
'nsPop3IncomingServer.cpp',
'nsPop3Protocol.cpp',
'nsPop3Service.cpp',
'nsPop3Sink.cpp',
'nsPop3URL.cpp',
'nsRssIncomingServer.cpp',
'nsRssService.cpp',
]
if CONFIG['MOZ_MOVEMAIL']:
SOURCES += [
'nsMovemailIncomingServer.cpp',
'nsMovemailService.cpp',
]
FINAL_LIBRARY = 'mail'

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,276 @@
/* -*- 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/. */
/**
Interface for representing Local Mail folders.
*/
#ifndef nsMsgLocalMailFolder_h__
#define nsMsgLocalMailFolder_h__
#include "mozilla/Attributes.h"
#include "nsMsgDBFolder.h" /* include the interface we are going to support */
#include "nsAutoPtr.h"
#include "nsICopyMessageListener.h"
#include "nsIFileStreams.h"
#include "nsIPop3IncomingServer.h" // need this for an interface ID
#include "nsMsgTxn.h"
#include "nsIMsgMessageService.h"
#include "nsIMsgParseMailMsgState.h"
#include "nsITransactionManager.h"
#include "nsIMsgLocalMailFolder.h"
#include "nsISeekableStream.h"
#include "nsIMutableArray.h"
#include "nsLocalUndoTxn.h"
#define COPY_BUFFER_SIZE 16384
class nsParseMailMessageState;
struct nsLocalMailCopyState
{
nsLocalMailCopyState();
virtual ~nsLocalMailCopyState();
nsCOMPtr <nsIOutputStream> m_fileStream;
nsCOMPtr<nsIMsgPluggableStore> m_msgStore;
nsCOMPtr<nsISupports> m_srcSupport;
/// Source nsIMsgDBHdr instances.
nsCOMPtr<nsIArray> m_messages;
/// Destination nsIMsgDBHdr instances.
nsCOMPtr<nsIMutableArray> m_destMessages;
RefPtr<nsLocalMoveCopyMsgTxn> m_undoMsgTxn;
nsCOMPtr<nsIMsgDBHdr> m_message; // current copy message
nsMsgMessageFlagType m_flags; // current copy message flags
RefPtr<nsParseMailMessageState> m_parseMsgState;
nsCOMPtr<nsIMsgCopyServiceListener> m_listener;
nsCOMPtr<nsIMsgWindow> m_msgWindow;
nsCOMPtr<nsIMsgDatabase> m_destDB;
// for displaying status;
nsCOMPtr <nsIMsgStatusFeedback> m_statusFeedback;
nsCOMPtr <nsIStringBundle> m_stringBundle;
int64_t m_lastProgressTime;
nsMsgKey m_curDstKey;
uint32_t m_curCopyIndex;
nsCOMPtr <nsIMsgMessageService> m_messageService;
/// The number of messages in m_messages.
uint32_t m_totalMsgCount;
char *m_dataBuffer;
uint32_t m_dataBufferSize;
uint32_t m_leftOver;
bool m_isMove;
bool m_isFolder; // isFolder move/copy
bool m_dummyEnvelopeNeeded;
bool m_copyingMultipleMessages;
bool m_fromLineSeen;
bool m_allowUndo;
bool m_writeFailed;
bool m_notifyFolderLoaded;
bool m_wholeMsgInStream;
nsCString m_newMsgKeywords;
nsCOMPtr <nsIMsgDBHdr> m_newHdr;
};
struct nsLocalFolderScanState
{
nsLocalFolderScanState();
~nsLocalFolderScanState();
nsCOMPtr<nsIInputStream> m_inputStream;
nsCOMPtr<nsISeekableStream> m_seekableStream;
nsCOMPtr<nsIMsgPluggableStore> m_msgStore;
nsCString m_header;
nsCString m_accountKey;
const char *m_uidl; // memory is owned by m_header
// false if we need a new input stream for each message
bool m_streamReusable;
};
class nsMsgLocalMailFolder : public nsMsgDBFolder,
public nsIMsgLocalMailFolder,
public nsICopyMessageListener
{
public:
nsMsgLocalMailFolder(void);
NS_DECL_NSICOPYMESSAGELISTENER
NS_DECL_NSIMSGLOCALMAILFOLDER
NS_DECL_NSIJUNKMAILCLASSIFICATIONLISTENER
NS_DECL_ISUPPORTS_INHERITED
// nsIRDFResource methods:
NS_IMETHOD Init(const char *aURI) override;
// nsIUrlListener methods
NS_IMETHOD OnStartRunningUrl(nsIURI * aUrl) override;
NS_IMETHOD OnStopRunningUrl(nsIURI * aUrl, nsresult aExitCode) override;
// nsIMsgFolder methods:
NS_IMETHOD GetSubFolders(nsISimpleEnumerator* *aResult) override;
NS_IMETHOD GetMsgDatabase(nsIMsgDatabase **aMsgDatabase) override;
NS_IMETHOD OnAnnouncerGoingAway(nsIDBChangeAnnouncer *instigator) override;
NS_IMETHOD GetMessages(nsISimpleEnumerator **result) override;
NS_IMETHOD UpdateFolder(nsIMsgWindow *aWindow) override;
NS_IMETHOD CreateSubfolder(const nsAString& folderName ,nsIMsgWindow *msgWindow) override;
NS_IMETHOD Compact(nsIUrlListener *aListener, nsIMsgWindow *aMsgWindow) override;
NS_IMETHOD CompactAll(nsIUrlListener *aListener, nsIMsgWindow *aMsgWindow, bool aCompactOfflineAlso) override;
NS_IMETHOD EmptyTrash(nsIMsgWindow *msgWindow, nsIUrlListener *aListener) override;
NS_IMETHOD Delete () override;
NS_IMETHOD DeleteSubFolders(nsIArray *folders, nsIMsgWindow *msgWindow) override;
NS_IMETHOD CreateStorageIfMissing(nsIUrlListener* urlListener) override;
NS_IMETHOD Rename (const nsAString& aNewName, nsIMsgWindow *msgWindow) override;
NS_IMETHOD RenameSubFolders (nsIMsgWindow *msgWindow, nsIMsgFolder *oldFolder) override;
NS_IMETHOD GetPrettyName(nsAString& prettyName) override; // Override of the base, for top-level mail folder
NS_IMETHOD SetPrettyName(const nsAString& aName) override;
NS_IMETHOD GetFolderURL(nsACString& url) override;
NS_IMETHOD GetManyHeadersToDownload(bool *retval) override;
NS_IMETHOD GetDeletable (bool *deletable) override;
NS_IMETHOD GetSizeOnDisk(int64_t *size) override;
NS_IMETHOD GetDBFolderInfoAndDB(nsIDBFolderInfo **folderInfo, nsIMsgDatabase **db) override;
NS_IMETHOD DeleteMessages(nsIArray *messages,
nsIMsgWindow *msgWindow, bool
deleteStorage, bool isMove,
nsIMsgCopyServiceListener* listener, bool allowUndo) override;
NS_IMETHOD CopyMessages(nsIMsgFolder *srcFolder, nsIArray* messages,
bool isMove, nsIMsgWindow *msgWindow,
nsIMsgCopyServiceListener* listener, bool isFolder, bool allowUndo) override;
NS_IMETHOD CopyFolder(nsIMsgFolder *srcFolder, bool isMoveFolder, nsIMsgWindow *msgWindow,
nsIMsgCopyServiceListener* listener) override;
NS_IMETHOD CopyFileMessage(nsIFile* aFile, nsIMsgDBHdr* msgToReplace,
bool isDraftOrTemplate,
uint32_t newMsgFlags,
const nsACString &aNewMsgKeywords,
nsIMsgWindow *msgWindow,
nsIMsgCopyServiceListener* listener) override;
NS_IMETHOD AddMessageDispositionState(nsIMsgDBHdr *aMessage, nsMsgDispositionState aDispositionFlag) override;
NS_IMETHOD MarkMessagesRead(nsIArray *aMessages, bool aMarkRead) override;
NS_IMETHOD MarkMessagesFlagged(nsIArray *aMessages, bool aMarkFlagged) override;
NS_IMETHOD MarkAllMessagesRead(nsIMsgWindow *aMsgWindow) override;
NS_IMETHOD MarkThreadRead(nsIMsgThread *thread) override;
NS_IMETHOD GetNewMessages(nsIMsgWindow *aWindow, nsIUrlListener *aListener) override;
NS_IMETHOD NotifyCompactCompleted() override;
NS_IMETHOD Shutdown(bool shutdownChildren) override;
NS_IMETHOD WriteToFolderCacheElem(nsIMsgFolderCacheElement *element) override;
NS_IMETHOD ReadFromFolderCacheElem(nsIMsgFolderCacheElement *element) override;
NS_IMETHOD GetName(nsAString& aName) override;
// Used when headers_only is TRUE
NS_IMETHOD DownloadMessagesForOffline(nsIArray *aMessages, nsIMsgWindow *aWindow) override;
NS_IMETHOD FetchMsgPreviewText(nsMsgKey *aKeysToFetch, uint32_t aNumKeys,
bool aLocalOnly, nsIUrlListener *aUrlListener,
bool *aAsyncResults) override;
NS_IMETHOD AddKeywordsToMessages(nsIArray *aMessages, const nsACString& aKeywords) override;
NS_IMETHOD RemoveKeywordsFromMessages(nsIArray *aMessages, const nsACString& aKeywords) override;
NS_IMETHOD GetIncomingServerType(nsACString& serverType) override;
protected:
virtual ~nsMsgLocalMailFolder();
nsresult CreateChildFromURI(const nsCString &uri, nsIMsgFolder **folder) override;
nsresult CopyFolderAcrossServer(nsIMsgFolder *srcFolder, nsIMsgWindow *msgWindow,nsIMsgCopyServiceListener* listener);
nsresult CreateSubFolders(nsIFile *path);
nsresult GetTrashFolder(nsIMsgFolder** trashFolder);
nsresult WriteStartOfNewMessage();
// CreateSubfolder, but without the nsIMsgFolderListener notification
nsresult CreateSubfolderInternal(const nsAString& folderName, nsIMsgWindow *msgWindow,
nsIMsgFolder **aNewFolder);
nsresult IsChildOfTrash(bool *result);
nsresult RecursiveSetDeleteIsMoveTrash(bool bVal);
nsresult ConfirmFolderDeletion(nsIMsgWindow *aMsgWindow, nsIMsgFolder *aFolder, bool *aResult);
nsresult DeleteMessage(nsISupports *message, nsIMsgWindow *msgWindow,
bool deleteStorage, bool commit);
nsresult GetDatabase() override;
// this will set mDatabase, if successful. It will also create a .msf file
// for an empty local mail folder. It will leave invalid DBs in place, and
// return an error.
nsresult OpenDatabase();
// copy message helper
nsresult DisplayMoveCopyStatusMsg();
nsresult CopyMessageTo(nsISupports *message, nsIMsgFolder *dstFolder,
nsIMsgWindow *msgWindow, bool isMove);
/**
* Checks if there's room in the target folder to copy message(s) into.
* If not, handles alerting the user, and sending the copy notifications.
*/
bool CheckIfSpaceForCopy(nsIMsgWindow *msgWindow,
nsIMsgFolder *srcFolder,
nsISupports *srcSupports,
bool isMove,
int64_t totalMsgSize);
// copy multiple messages at a time from this folder
nsresult CopyMessagesTo(nsIArray *messages, nsTArray<nsMsgKey> &keyArray,
nsIMsgWindow *aMsgWindow,
nsIMsgFolder *dstFolder,
bool isMove);
nsresult InitCopyState(nsISupports* aSupport, nsIArray* messages,
bool isMove, nsIMsgCopyServiceListener* listener, nsIMsgWindow *msgWindow, bool isMoveFolder, bool allowUndo);
nsresult InitCopyMsgHdrAndFileStream();
// preserve message metadata when moving or copying messages
void CopyPropertiesToMsgHdr(nsIMsgDBHdr *destHdr, nsIMsgDBHdr *srcHdr, bool isMove);
virtual nsresult CreateBaseMessageURI(const nsACString& aURI) override;
nsresult ChangeKeywordForMessages(nsIArray *aMessages, const nsACString& aKeyword, bool add);
bool GetDeleteFromServerOnMove();
void CopyHdrPropertiesWithSkipList(nsIMsgDBHdr *destHdr,
nsIMsgDBHdr *srcHdr,
const nsCString &skipList);
protected:
nsLocalMailCopyState *mCopyState; //We only allow one of these at a time
nsCString mType;
bool mHaveReadNameFromDB;
bool mInitialized;
bool mCheckForNewMessagesAfterParsing;
bool m_parsingFolder;
nsCOMPtr<nsIUrlListener> mReparseListener;
nsTArray<nsMsgKey> mSpamKeysToMove;
nsresult setSubfolderFlag(const nsAString& aFolderName, uint32_t flags);
// state variables for DownloadMessagesForOffline
// Do we notify the owning window of Delete's before or after
// Adding the new msg?
#define DOWNLOAD_NOTIFY_FIRST 1
#define DOWNLOAD_NOTIFY_LAST 2
#ifndef DOWNLOAD_NOTIFY_STYLE
#define DOWNLOAD_NOTIFY_STYLE DOWNLOAD_NOTIFY_FIRST
#endif
nsCOMArray<nsIMsgDBHdr> mDownloadMessages;
nsCOMPtr<nsIMsgWindow> mDownloadWindow;
nsMsgKey mDownloadSelectKey;
uint32_t mDownloadState;
#define DOWNLOAD_STATE_NONE 0
#define DOWNLOAD_STATE_INITED 1
#define DOWNLOAD_STATE_GOTMSG 2
#define DOWNLOAD_STATE_DIDSEL 3
#if DOWNLOAD_NOTIFY_STYLE == DOWNLOAD_NOTIFY_LAST
nsMsgKey mDownloadOldKey;
nsMsgKey mDownloadOldParent;
uint32_t mDownloadOldFlags;
#endif
};
#endif // nsMsgLocalMailFolder_h__

View file

@ -0,0 +1,560 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsIMsgHdr.h"
#include "nsLocalUndoTxn.h"
#include "nsImapCore.h"
#include "nsMsgImapCID.h"
#include "nsIImapService.h"
#include "nsIUrlListener.h"
#include "nsIMsgLocalMailFolder.h"
#include "nsIMsgMailSession.h"
#include "nsIMsgFolderNotificationService.h"
#include "nsThreadUtils.h"
#include "nsIMsgDatabase.h"
#include "nsIMutableArray.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsMsgUtils.h"
NS_IMPL_ISUPPORTS_INHERITED(nsLocalMoveCopyMsgTxn, nsMsgTxn, nsIFolderListener)
nsLocalMoveCopyMsgTxn::nsLocalMoveCopyMsgTxn() : m_srcIsImap4(false),
m_canUndelete(false)
{
}
nsLocalMoveCopyMsgTxn::~nsLocalMoveCopyMsgTxn()
{
}
nsresult
nsLocalMoveCopyMsgTxn::Init(nsIMsgFolder* srcFolder, nsIMsgFolder* dstFolder,
bool isMove)
{
nsresult rv;
rv = SetSrcFolder(srcFolder);
NS_ENSURE_SUCCESS(rv, rv);
rv = SetDstFolder(dstFolder);
NS_ENSURE_SUCCESS(rv, rv);
m_isMove = isMove;
mUndoFolderListener = nullptr;
nsCString protocolType;
rv = srcFolder->GetURI(protocolType);
protocolType.SetLength(protocolType.FindChar(':'));
if (MsgLowerCaseEqualsLiteral(protocolType, "imap"))
m_srcIsImap4 = true;
return nsMsgTxn::Init();
}
nsresult
nsLocalMoveCopyMsgTxn::GetSrcIsImap(bool *isImap)
{
*isImap = m_srcIsImap4;
return NS_OK;
}
nsresult
nsLocalMoveCopyMsgTxn::SetSrcFolder(nsIMsgFolder* srcFolder)
{
nsresult rv = NS_ERROR_NULL_POINTER;
if (srcFolder)
m_srcFolder = do_GetWeakReference(srcFolder, &rv);
return rv;
}
nsresult
nsLocalMoveCopyMsgTxn::SetDstFolder(nsIMsgFolder* dstFolder)
{
nsresult rv = NS_ERROR_NULL_POINTER;
if (dstFolder)
m_dstFolder = do_GetWeakReference(dstFolder, &rv);
return rv;
}
nsresult
nsLocalMoveCopyMsgTxn::AddSrcKey(nsMsgKey aKey)
{
m_srcKeyArray.AppendElement(aKey);
return NS_OK;
}
nsresult
nsLocalMoveCopyMsgTxn::AddSrcStatusOffset(uint32_t aStatusOffset)
{
m_srcStatusOffsetArray.AppendElement(aStatusOffset);
return NS_OK;
}
nsresult
nsLocalMoveCopyMsgTxn::AddDstKey(nsMsgKey aKey)
{
m_dstKeyArray.AppendElement(aKey);
return NS_OK;
}
nsresult
nsLocalMoveCopyMsgTxn::AddDstMsgSize(uint32_t msgSize)
{
m_dstSizeArray.AppendElement(msgSize);
return NS_OK;
}
nsresult
nsLocalMoveCopyMsgTxn::UndoImapDeleteFlag(nsIMsgFolder* folder,
nsTArray<nsMsgKey>& keyArray,
bool deleteFlag)
{
nsresult rv = NS_ERROR_FAILURE;
if (m_srcIsImap4)
{
nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIUrlListener> urlListener;
nsCString msgIds;
uint32_t i, count = keyArray.Length();
urlListener = do_QueryInterface(folder, &rv);
for (i=0; i < count; i++)
{
if (!msgIds.IsEmpty())
msgIds.Append(',');
msgIds.AppendInt((int32_t) keyArray[i]);
}
// This is to make sure that we are in the selected state
// when executing the imap url; we don't want to load the
// folder so use lite select to do the trick
rv = imapService->LiteSelectFolder(folder,
urlListener, nullptr, nullptr);
if (!deleteFlag)
rv =imapService->AddMessageFlags(folder,
urlListener, nullptr,
msgIds,
kImapMsgDeletedFlag,
true);
else
rv = imapService->SubtractMessageFlags(folder,
urlListener, nullptr,
msgIds,
kImapMsgDeletedFlag,
true);
if (NS_SUCCEEDED(rv) && m_msgWindow)
folder->UpdateFolder(m_msgWindow);
rv = NS_OK; // always return NS_OK to indicate that the src is imap
}
else
rv = NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsLocalMoveCopyMsgTxn::UndoTransaction()
{
nsresult rv;
nsCOMPtr<nsIMsgDatabase> dstDB;
nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgLocalMailFolder> dstlocalMailFolder = do_QueryReferent(m_dstFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
dstlocalMailFolder->GetDatabaseWOReparse(getter_AddRefs(dstDB));
if (!dstDB)
{
// This will listen for the db reparse finishing, and the corresponding
// FolderLoadedNotification. When it gets that, it will then call
// UndoTransactionInternal.
mUndoFolderListener = new nsLocalUndoFolderListener(this, dstFolder);
if (!mUndoFolderListener)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mUndoFolderListener);
nsCOMPtr<nsIMsgMailSession> mailSession =
do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = mailSession->AddFolderListener(mUndoFolderListener, nsIFolderListener::event);
NS_ENSURE_SUCCESS(rv,rv);
rv = dstFolder->GetMsgDatabase(getter_AddRefs(dstDB));
NS_ENSURE_SUCCESS(rv,rv);
}
else
rv = UndoTransactionInternal();
return rv;
}
nsresult
nsLocalMoveCopyMsgTxn::UndoTransactionInternal()
{
nsresult rv = NS_ERROR_FAILURE;
if (mUndoFolderListener)
{
nsCOMPtr<nsIMsgMailSession> mailSession =
do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = mailSession->RemoveFolderListener(mUndoFolderListener);
NS_ENSURE_SUCCESS(rv,rv);
NS_RELEASE(mUndoFolderListener);
mUndoFolderListener = nullptr;
}
nsCOMPtr<nsIMsgDatabase> srcDB;
nsCOMPtr<nsIMsgDatabase> dstDB;
nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = srcFolder->GetMsgDatabase(getter_AddRefs(srcDB));
if(NS_FAILED(rv)) return rv;
rv = dstFolder->GetMsgDatabase(getter_AddRefs(dstDB));
if (NS_FAILED(rv)) return rv;
uint32_t count = m_srcKeyArray.Length();
uint32_t i;
nsCOMPtr<nsIMsgDBHdr> oldHdr;
nsCOMPtr<nsIMsgDBHdr> newHdr;
// protect against a bogus undo txn without any source keys
// see bug #179856 for details
NS_ASSERTION(count, "no source keys");
if (!count)
return NS_ERROR_UNEXPECTED;
if (m_isMove)
{
if (m_srcIsImap4)
{
bool deleteFlag = true; //message has been deleted -we are trying to undo it
CheckForToggleDelete(srcFolder, m_srcKeyArray[0], &deleteFlag); //there could have been a toggle.
rv = UndoImapDeleteFlag(srcFolder, m_srcKeyArray, deleteFlag);
}
else if (m_canUndelete)
{
nsCOMPtr<nsIMutableArray> srcMessages =
do_CreateInstance(NS_ARRAY_CONTRACTID);
nsCOMPtr<nsIMutableArray> dstMessages =
do_CreateInstance(NS_ARRAY_CONTRACTID);
srcDB->StartBatch();
for (i = 0; i < count; i++)
{
rv = dstDB->GetMsgHdrForKey(m_dstKeyArray[i],
getter_AddRefs(oldHdr));
NS_ASSERTION(oldHdr, "fatal ... cannot get old msg header\n");
if (NS_SUCCEEDED(rv) && oldHdr)
{
rv = srcDB->CopyHdrFromExistingHdr(m_srcKeyArray[i],
oldHdr, true,
getter_AddRefs(newHdr));
NS_ASSERTION(newHdr,
"fatal ... cannot create new msg header\n");
if (NS_SUCCEEDED(rv) && newHdr)
{
newHdr->SetStatusOffset(m_srcStatusOffsetArray[i]);
srcDB->UndoDelete(newHdr);
srcMessages->AppendElement(newHdr, false);
// (we want to keep these two lists in sync)
dstMessages->AppendElement(oldHdr, false);
}
}
}
srcDB->EndBatch();
nsCOMPtr<nsIMsgFolderNotificationService>
notifier(do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID));
if (notifier)
{
// Remember that we're actually moving things back from the destination
// to the source!
notifier->NotifyMsgsMoveCopyCompleted(true, dstMessages,
srcFolder, srcMessages);
}
nsCOMPtr <nsIMsgLocalMailFolder> localFolder = do_QueryInterface(srcFolder);
if (localFolder)
localFolder->MarkMsgsOnPop3Server(srcMessages, POP3_NONE /*deleteMsgs*/);
}
else // undoing a move means moving the messages back.
{
nsCOMPtr<nsIMutableArray> dstMessages =
do_CreateInstance(NS_ARRAY_CONTRACTID);
m_numHdrsCopied = 0;
m_srcKeyArray.Clear();
for (i = 0; i < count; i++)
{
// GetMsgHdrForKey is not a test for whether the key exists, so check.
bool hasKey = false;
dstDB->ContainsKey(m_dstKeyArray[i], &hasKey);
nsCOMPtr<nsIMsgDBHdr> dstHdr;
if (hasKey)
dstDB->GetMsgHdrForKey(m_dstKeyArray[i], getter_AddRefs(dstHdr));
if (dstHdr)
{
nsCString messageId;
dstHdr->GetMessageId(getter_Copies(messageId));
dstMessages->AppendElement(dstHdr, false);
m_copiedMsgIds.AppendElement(messageId);
}
else
{
NS_WARNING("Cannot get old msg header");
}
}
if (m_copiedMsgIds.Length())
{
srcFolder->AddFolderListener(this);
m_undoing = true;
return srcFolder->CopyMessages(dstFolder, dstMessages,
true, nullptr, nullptr, false,
false);
}
else
{
// Nothing to do, probably because original messages were deleted.
NS_WARNING("Undo did not find any messages to move");
}
}
srcDB->SetSummaryValid(true);
}
dstDB->DeleteMessages(m_dstKeyArray.Length(), m_dstKeyArray.Elements(), nullptr);
dstDB->SetSummaryValid(true);
return rv;
}
NS_IMETHODIMP
nsLocalMoveCopyMsgTxn::RedoTransaction()
{
nsresult rv;
nsCOMPtr<nsIMsgDatabase> srcDB;
nsCOMPtr<nsIMsgDatabase> dstDB;
nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = srcFolder->GetMsgDatabase(getter_AddRefs(srcDB));
if(NS_FAILED(rv)) return rv;
rv = dstFolder->GetMsgDatabase(getter_AddRefs(dstDB));
if (NS_FAILED(rv)) return rv;
uint32_t count = m_srcKeyArray.Length();
uint32_t i;
nsCOMPtr<nsIMsgDBHdr> oldHdr;
nsCOMPtr<nsIMsgDBHdr> newHdr;
nsCOMPtr<nsIMutableArray> srcMessages = do_CreateInstance(NS_ARRAY_CONTRACTID);
nsCOMPtr <nsISupports> msgSupports;
for (i=0; i<count; i++)
{
rv = srcDB->GetMsgHdrForKey(m_srcKeyArray[i],
getter_AddRefs(oldHdr));
NS_ASSERTION(oldHdr, "fatal ... cannot get old msg header\n");
if (NS_SUCCEEDED(rv) && oldHdr)
{
msgSupports =do_QueryInterface(oldHdr);
srcMessages->AppendElement(msgSupports, false);
if (m_canUndelete)
{
rv = dstDB->CopyHdrFromExistingHdr(m_dstKeyArray[i],
oldHdr, true,
getter_AddRefs(newHdr));
NS_ASSERTION(newHdr, "fatal ... cannot get new msg header\n");
if (NS_SUCCEEDED(rv) && newHdr)
{
if (i < m_dstSizeArray.Length())
rv = newHdr->SetMessageSize(m_dstSizeArray[i]);
dstDB->UndoDelete(newHdr);
}
}
}
}
dstDB->SetSummaryValid(true);
if (m_isMove)
{
if (m_srcIsImap4)
{
// protect against a bogus undo txn without any source keys
// see bug #179856 for details
NS_ASSERTION(!m_srcKeyArray.IsEmpty(), "no source keys");
if (m_srcKeyArray.IsEmpty())
return NS_ERROR_UNEXPECTED;
bool deleteFlag = false; //message is un-deleted- we are trying to redo
CheckForToggleDelete(srcFolder, m_srcKeyArray[0], &deleteFlag); // there could have been a toggle
rv = UndoImapDeleteFlag(srcFolder, m_srcKeyArray, deleteFlag);
}
else if (m_canUndelete)
{
nsCOMPtr <nsIMsgLocalMailFolder> localFolder = do_QueryInterface(srcFolder);
if (localFolder)
localFolder->MarkMsgsOnPop3Server(srcMessages, POP3_DELETE /*deleteMsgs*/);
rv = srcDB->DeleteMessages(m_srcKeyArray.Length(), m_srcKeyArray.Elements(), nullptr);
srcDB->SetSummaryValid(true);
}
else
{
nsCOMPtr<nsIMsgDBHdr> srcHdr;
m_numHdrsCopied = 0;
m_dstKeyArray.Clear();
for (i = 0; i < count; i++)
{
srcDB->GetMsgHdrForKey(m_srcKeyArray[i], getter_AddRefs(srcHdr));
NS_ASSERTION(srcHdr, "fatal ... cannot get old msg header\n");
if (srcHdr)
{
nsCString messageId;
srcHdr->GetMessageId(getter_Copies(messageId));
m_copiedMsgIds.AppendElement(messageId);
}
}
dstFolder->AddFolderListener(this);
m_undoing = false;
return dstFolder->CopyMessages(srcFolder, srcMessages, true, nullptr,
nullptr, false, false);
}
}
return rv;
}
NS_IMETHODIMP nsLocalMoveCopyMsgTxn::OnItemAdded(nsIMsgFolder *parentItem, nsISupports *item)
{
nsCOMPtr<nsIMsgDBHdr> msgHdr(do_QueryInterface(item));
if (msgHdr)
{
nsresult rv;
nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(m_undoing ? m_srcFolder :
m_dstFolder, &rv);
NS_ENSURE_SUCCESS(rv,rv);
nsCString messageId;
msgHdr->GetMessageId(getter_Copies(messageId));
if (m_copiedMsgIds.Contains(messageId))
{
nsMsgKey msgKey;
msgHdr->GetMessageKey(&msgKey);
if (m_undoing)
m_srcKeyArray.AppendElement(msgKey);
else
m_dstKeyArray.AppendElement(msgKey);
if (++m_numHdrsCopied == m_copiedMsgIds.Length())
{
folder->RemoveFolderListener(this);
m_copiedMsgIds.Clear();
}
}
}
return NS_OK;
}
NS_IMETHODIMP nsLocalMoveCopyMsgTxn::OnItemRemoved(nsIMsgFolder *parentItem, nsISupports *item)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalMoveCopyMsgTxn::OnItemPropertyChanged(nsIMsgFolder *item, nsIAtom *property, const char *oldValue, const char *newValue)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalMoveCopyMsgTxn::OnItemIntPropertyChanged(nsIMsgFolder *item, nsIAtom *property, int64_t oldValue, int64_t newValue)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalMoveCopyMsgTxn::OnItemBoolPropertyChanged(nsIMsgFolder *item, nsIAtom *property, bool oldValue, bool newValue)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalMoveCopyMsgTxn::OnItemUnicharPropertyChanged(nsIMsgFolder *item, nsIAtom *property, const char16_t *oldValue, const char16_t *newValue)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalMoveCopyMsgTxn::OnItemPropertyFlagChanged(nsIMsgDBHdr *item, nsIAtom *property, uint32_t oldFlag, uint32_t newFlag)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalMoveCopyMsgTxn::OnItemEvent(nsIMsgFolder *aItem, nsIAtom *aEvent)
{
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsLocalUndoFolderListener, nsIFolderListener)
nsLocalUndoFolderListener::nsLocalUndoFolderListener(nsLocalMoveCopyMsgTxn *aTxn, nsIMsgFolder *aFolder)
{
mTxn = aTxn;
mFolder = aFolder;
}
nsLocalUndoFolderListener::~nsLocalUndoFolderListener()
{
}
NS_IMETHODIMP nsLocalUndoFolderListener::OnItemAdded(nsIMsgFolder *parentItem, nsISupports *item)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalUndoFolderListener::OnItemRemoved(nsIMsgFolder *parentItem, nsISupports *item)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalUndoFolderListener::OnItemPropertyChanged(nsIMsgFolder *item, nsIAtom *property, const char *oldValue, const char *newValue)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalUndoFolderListener::OnItemIntPropertyChanged(nsIMsgFolder *item, nsIAtom *property, int64_t oldValue, int64_t newValue)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalUndoFolderListener::OnItemBoolPropertyChanged(nsIMsgFolder *item, nsIAtom *property, bool oldValue, bool newValue)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalUndoFolderListener::OnItemUnicharPropertyChanged(nsIMsgFolder *item, nsIAtom *property, const char16_t *oldValue, const char16_t *newValue)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalUndoFolderListener::OnItemPropertyFlagChanged(nsIMsgDBHdr *item, nsIAtom *property, uint32_t oldFlag, uint32_t newFlag)
{
return NS_OK;
}
NS_IMETHODIMP nsLocalUndoFolderListener::OnItemEvent(nsIMsgFolder *aItem, nsIAtom *aEvent)
{
if (mTxn && mFolder && aItem == mFolder) {
bool isEqual = false;
aEvent->ScriptableEquals(NS_LITERAL_STRING("FolderLoaded"), &isEqual);
if (isEqual)
return mTxn->UndoTransactionInternal();
}
return NS_ERROR_FAILURE;
}

View file

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsLocalUndoTxn_h__
#define nsLocalUndoTxn_h__
#include "mozilla/Attributes.h"
#include "msgCore.h"
#include "nsIMsgFolder.h"
#include "nsMailboxService.h"
#include "nsMsgTxn.h"
#include "MailNewsTypes.h"
#include "nsTArray.h"
#include "nsCOMPtr.h"
#include "nsIUrlListener.h"
#include "nsIWeakReference.h"
#include "nsIWeakReferenceUtils.h"
class nsLocalUndoFolderListener;
class nsLocalMoveCopyMsgTxn : public nsIFolderListener, public nsMsgTxn
{
public:
nsLocalMoveCopyMsgTxn();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIFOLDERLISTENER
// overloading nsITransaction methods
NS_IMETHOD UndoTransaction(void) override;
NS_IMETHOD RedoTransaction(void) override;
// helper
nsresult AddSrcKey(nsMsgKey aKey);
nsresult AddSrcStatusOffset(uint32_t statusOffset);
nsresult AddDstKey(nsMsgKey aKey);
nsresult AddDstMsgSize(uint32_t msgSize);
nsresult SetSrcFolder(nsIMsgFolder* srcFolder);
nsresult GetSrcIsImap(bool *isImap);
nsresult SetDstFolder(nsIMsgFolder* dstFolder);
nsresult Init(nsIMsgFolder* srcFolder,
nsIMsgFolder* dstFolder, bool isMove);
nsresult UndoImapDeleteFlag(nsIMsgFolder* aFolder,
nsTArray<nsMsgKey>& aKeyArray,
bool deleteFlag);
nsresult UndoTransactionInternal();
// If the store using this undo transaction can "undelete" a message,
// it will call this function on the transaction; This makes undo/redo
// easy because message keys don't change after undo/redo. Otherwise,
// we need to adjust the src or dst keys after every undo/redo action
// to note the new keys.
void SetCanUndelete(bool canUndelete) {m_canUndelete = canUndelete;}
private:
virtual ~nsLocalMoveCopyMsgTxn();
nsWeakPtr m_srcFolder;
nsTArray<nsMsgKey> m_srcKeyArray; // used when src is local or imap
nsTArray<uint32_t> m_srcStatusOffsetArray; // used when src is local
nsWeakPtr m_dstFolder;
nsTArray<nsMsgKey> m_dstKeyArray;
bool m_isMove;
bool m_srcIsImap4;
bool m_canUndelete;
nsTArray<uint32_t> m_dstSizeArray;
bool m_undoing; // if false, re-doing
uint32_t m_numHdrsCopied;
nsTArray<nsCString> m_copiedMsgIds;
nsLocalUndoFolderListener *mUndoFolderListener;
};
class nsLocalUndoFolderListener : public nsIFolderListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIFOLDERLISTENER
nsLocalUndoFolderListener(nsLocalMoveCopyMsgTxn *aTxn, nsIMsgFolder *aFolder);
private:
virtual ~nsLocalUndoFolderListener();
nsLocalMoveCopyMsgTxn *mTxn;
nsIMsgFolder *mFolder;
};
#endif

View file

@ -0,0 +1,244 @@
/* -*- 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 "nsLocalUtils.h"
#include "nsIServiceManager.h"
#include "prsystem.h"
#include "nsCOMPtr.h"
#include "prmem.h"
// stuff for temporary root folder hack
#include "nsIMsgAccountManager.h"
#include "nsIMsgIncomingServer.h"
#include "nsIPop3IncomingServer.h"
#include "nsINoIncomingServer.h"
#include "nsMsgBaseCID.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsMsgUtils.h"
#include "nsNetCID.h"
// it would be really cool to:
// - cache the last hostname->path match
// - if no such server exists, behave like an old-style mailbox URL
// (i.e. return the mail.directory preference or something)
static nsresult
nsGetMailboxServer(const char *uriStr, nsIMsgIncomingServer** aResult)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIURL> aUrl = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
rv = aUrl->SetSpec(nsDependentCString(uriStr));
if (NS_FAILED(rv)) return rv;
// retrieve the AccountManager
nsCOMPtr<nsIMsgAccountManager> accountManager =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
// find all local mail "no servers" matching the given hostname
nsCOMPtr<nsIMsgIncomingServer> none_server;
aUrl->SetScheme(NS_LITERAL_CSTRING("none"));
// No unescaping of username or hostname done here.
// The unescaping is done inside of FindServerByURI
rv = accountManager->FindServerByURI(aUrl, false,
getter_AddRefs(none_server));
if (NS_SUCCEEDED(rv)) {
NS_ADDREF(*aResult = none_server);
return rv;
}
// if that fails, look for the rss hosts matching the given hostname
nsCOMPtr<nsIMsgIncomingServer> rss_server;
aUrl->SetScheme(NS_LITERAL_CSTRING("rss"));
rv = accountManager->FindServerByURI(aUrl, false,
getter_AddRefs(rss_server));
if (NS_SUCCEEDED(rv))
{
NS_ADDREF(*aResult = rss_server);
return rv;
}
#ifdef HAVE_MOVEMAIL
// find all movemail "servers" matching the given hostname
nsCOMPtr<nsIMsgIncomingServer> movemail_server;
aUrl->SetScheme(NS_LITERAL_CSTRING("movemail"));
rv = accountManager->FindServerByURI(aUrl, false,
getter_AddRefs(movemail_server));
if (NS_SUCCEEDED(rv)) {
NS_ADDREF(*aResult = movemail_server);
return rv;
}
#endif /* HAVE_MOVEMAIL */
// if that fails, look for the pop hosts matching the given hostname
nsCOMPtr<nsIMsgIncomingServer> server;
if (NS_FAILED(rv))
{
aUrl->SetScheme(NS_LITERAL_CSTRING("pop3"));
rv = accountManager->FindServerByURI(aUrl, false,
getter_AddRefs(server));
// if we can't find a pop server, maybe it's a local message
// in an imap hierarchy. look for an imap server.
if (NS_FAILED(rv))
{
aUrl->SetScheme(NS_LITERAL_CSTRING("imap"));
rv = accountManager->FindServerByURI(aUrl, false,
getter_AddRefs(server));
}
}
if (NS_SUCCEEDED(rv))
{
NS_ADDREF(*aResult = server);
return rv;
}
// if you fail after looking at all "pop3", "movemail" and "none" servers, you fail.
return rv;
}
static nsresult
nsLocalURI2Server(const char* uriStr,
nsIMsgIncomingServer ** aResult)
{
nsresult rv;
nsCOMPtr<nsIMsgIncomingServer> server;
rv = nsGetMailboxServer(uriStr, getter_AddRefs(server));
NS_IF_ADDREF(*aResult = server);
return rv;
}
// given rootURI and rootURI##folder, return on-disk path of folder
nsresult
nsLocalURI2Path(const char* rootURI, const char* uriStr,
nsCString& pathResult)
{
nsresult rv;
// verify that rootURI starts with "mailbox:/" or "mailbox-message:/"
if ((PL_strcmp(rootURI, kMailboxRootURI) != 0) &&
(PL_strcmp(rootURI, kMailboxMessageRootURI) != 0)) {
return NS_ERROR_FAILURE;
}
// verify that uristr starts with rooturi
nsAutoCString uri(uriStr);
if (uri.Find(rootURI) != 0)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIMsgIncomingServer> server;
rv = nsLocalURI2Server(uriStr, getter_AddRefs(server));
if (NS_FAILED(rv))
return rv;
// now ask the server what it's root is
// and begin pathResult with the mailbox root
nsCOMPtr<nsIFile> localPath;
rv = server->GetLocalPath(getter_AddRefs(localPath));
NS_ENSURE_SUCCESS(rv, rv);
nsCString localNativePath;
localPath->GetNativePath(localNativePath);
nsEscapeNativePath(localNativePath);
pathResult = localNativePath.get();
const char *curPos = uriStr + PL_strlen(rootURI);
if (curPos) {
// advance past hostname
while ((*curPos)=='/') curPos++;
while (*curPos && (*curPos)!='/') curPos++;
nsAutoCString newPath("");
// Unescape folder name
if (curPos) {
nsCString unescapedStr;
MsgUnescapeString(nsDependentCString(curPos), 0, unescapedStr);
NS_MsgCreatePathStringFromFolderURI(unescapedStr.get(), newPath, NS_LITERAL_CSTRING("none"));
} else
NS_MsgCreatePathStringFromFolderURI(curPos, newPath, NS_LITERAL_CSTRING("none"));
pathResult.Append('/');
pathResult.Append(newPath);
}
return NS_OK;
}
/* parses LocalMessageURI
* mailbox-message://folder1/folder2#123?header=none or
* mailbox-message://folder1/folder2#1234&part=1.2
*
* puts folder URI in folderURI (mailbox://folder1/folder2)
* message key number in key
*/
nsresult nsParseLocalMessageURI(const char* uri,
nsCString& folderURI,
nsMsgKey *key)
{
if(!key)
return NS_ERROR_NULL_POINTER;
nsAutoCString uriStr(uri);
int32_t keySeparator = uriStr.FindChar('#');
if(keySeparator != -1)
{
int32_t keyEndSeparator = MsgFindCharInSet(uriStr, "?&", keySeparator);
folderURI = StringHead(uriStr, keySeparator);
folderURI.Cut(7, 8); // cut out the -message part of mailbox-message:
nsAutoCString keyStr;
if (keyEndSeparator != -1)
keyStr = Substring(uriStr, keySeparator + 1,
keyEndSeparator - (keySeparator + 1));
else
keyStr = StringTail(uriStr, uriStr.Length() - (keySeparator + 1));
*key = msgKeyFromInt(ParseUint64Str(keyStr.get()));
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult nsBuildLocalMessageURI(const char *baseURI, nsMsgKey key, nsCString& uri)
{
// need to convert mailbox://hostname/.. to mailbox-message://hostname/..
uri.Append(baseURI);
uri.Append('#');
uri.AppendInt(key);
return NS_OK;
}
nsresult nsCreateLocalBaseMessageURI(const nsACString& baseURI, nsCString &baseMessageURI)
{
nsAutoCString tailURI(baseURI);
// chop off mailbox:/
if (tailURI.Find(kMailboxRootURI) == 0)
tailURI.Cut(0, PL_strlen(kMailboxRootURI));
baseMessageURI = kMailboxMessageRootURI;
baseMessageURI += tailURI;
return NS_OK;
}
void nsEscapeNativePath(nsCString& nativePath)
{
#if defined(XP_WIN)
nativePath.Insert('/', 0);
MsgReplaceChar(nativePath, '\\', '/');
#endif
}

View file

@ -0,0 +1,30 @@
/* -*- 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/. */
#ifndef NS_LOCALUTILS_H
#define NS_LOCALUTILS_H
#include "nsStringGlue.h"
#include "nsIMsgIncomingServer.h"
static const char kMailboxRootURI[] = "mailbox:/";
static const char kMailboxMessageRootURI[] = "mailbox-message:/";
nsresult
nsLocalURI2Path(const char* rootURI, const char* uriStr, nsCString& pathResult);
nsresult
nsParseLocalMessageURI(const char* uri, nsCString& folderURI, nsMsgKey *key);
nsresult
nsBuildLocalMessageURI(const char* baseURI, nsMsgKey key, nsCString& uri);
nsresult
nsCreateLocalBaseMessageURI(const nsACString& baseURI, nsCString &baseMessageURI);
void
nsEscapeNativePath(nsCString& nativePath);
#endif //NS_LOCALUTILS_H

View file

@ -0,0 +1,725 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsIOutputStream.h"
#include "nsIInputStreamPump.h"
#include "nsIMsgDatabase.h"
#include "nsIMsgHdr.h"
#include "nsMsgLineBuffer.h"
#include "nsMsgDBCID.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsICopyMsgStreamListener.h"
#include "nsMsgMessageFlags.h"
#include "prtime.h"
#include "mozilla/Logging.h"
#include "prerror.h"
#include "prprf.h"
#include "nspr.h"
PRLogModuleInfo *MAILBOX;
#include "nsIFileStreams.h"
#include "nsIStreamTransportService.h"
#include "nsIStreamConverterService.h"
#include "nsIIOService.h"
#include "nsNetUtil.h"
#include "nsMsgUtils.h"
#include "nsIMsgWindow.h"
#include "nsIMimeHeaders.h"
#include "nsIMsgPluggableStore.h"
#include "nsISeekableStream.h"
#include "nsIMsgMdnGenerator.h"
/* 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_lineStreamBuffer =nullptr;
// initialize the pr log if it hasn't been initialiezed already
if (!MAILBOX)
MAILBOX = PR_NewLogModule("MAILBOX");
}
nsMailboxProtocol::~nsMailboxProtocol()
{
// free our local state
delete m_lineStreamBuffer;
}
nsresult nsMailboxProtocol::OpenMultipleMsgTransport(uint64_t offset, int32_t size)
{
nsresult rv;
nsCOMPtr<nsIStreamTransportService> serv =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// XXX 64-bit
rv = serv->CreateInputTransport(m_multipleMsgMoveCopyStream, int64_t(offset),
int64_t(size), false,
getter_AddRefs(m_transport));
return rv;
}
nsresult nsMailboxProtocol::Initialize(nsIURI * aURL)
{
NS_PRECONDITION(aURL, "invalid URL passed into MAILBOX Protocol");
nsresult rv = NS_OK;
if (aURL)
{
rv = aURL->QueryInterface(NS_GET_IID(nsIMailboxUrl), (void **) getter_AddRefs(m_runningUrl));
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
{
// we need to specify a byte range to read in so we read in JUST the message we want.
rv = SetupMessageExtraction();
if (NS_FAILED(rv)) return rv;
uint32_t aMsgSize = 0;
rv = m_runningUrl->GetMessageSize(&aMsgSize);
NS_ASSERTION(NS_SUCCEEDED(rv), "oops....i messed something up");
SetContentLength(aMsgSize);
mailnewsUrl->SetMaxProgress(aMsgSize);
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)
{
rv = msgHdr->GetFolder(getter_AddRefs(folder));
if (NS_SUCCEEDED(rv) && folder)
{
nsCOMPtr<nsIInputStream> stream;
int64_t offset = 0;
bool reusable = false;
rv = folder->GetMsgInputStream(msgHdr, &reusable, 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 = aMsgSize;
// Save the stream for reuse, but only for multiple URLs.
if (reusable && RunningMultipleMsgUrl())
m_multipleMsgMoveCopyStream = stream;
else
reusable = false;
rv = sts->CreateInputTransport(stream, offset,
int64_t(aMsgSize), !reusable,
getter_AddRefs(m_transport));
m_socketIsOpen = false;
}
}
if (!folder) // must be a .eml file
rv = OpenFileSocket(aURL, 0, aMsgSize);
}
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 suppport the nsIStreamListener interface
////////////////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsMailboxProtocol::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
// 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...
m_mailboxParser->OnStartRequest(request, ctxt);
}
return nsMsgProtocol::OnStartRequest(request, ctxt);
}
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, nsISupports *ctxt, 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...
m_mailboxParser->OnStopRequest(request, ctxt, 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(ctxt, 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.get());
msgUrl->SetUri(uri.get());
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.
nsCOMPtr<nsISupports> urlSupports = do_QueryInterface(m_runningUrl);
//
// put us in a state where we are always notified of incoming data
//
m_transport = nullptr; // open new stream transport
m_inputStream = nullptr;
m_outputStream = nullptr;
if (m_multipleMsgMoveCopyStream)
{
rv = OpenMultipleMsgTransport(msgOffset, msgSize);
}
else
{
nsCOMPtr<nsIInputStream> stream;
bool reusable = false;
rv = msgFolder->GetMsgInputStream(nextMsg, &reusable,
getter_AddRefs(stream));
NS_ASSERTION(!reusable, "We thought streams were not reusable!");
if (NS_SUCCEEDED(rv))
{
// create input stream transport
nsCOMPtr<nsIStreamTransportService> sts =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
{
m_readCount = msgSize;
rv = sts->CreateInputTransport(stream, msgOffset,
int64_t(msgSize), true,
getter_AddRefs(m_transport));
}
}
}
if (NS_SUCCEEDED(rv))
{
if (!m_inputStream)
rv = m_transport->OpenInputStream(0, 0, 0, getter_AddRefs(m_inputStream));
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIInputStreamPump> pump;
rv = NS_NewInputStreamPump(getter_AddRefs(pump), m_inputStream);
if (NS_SUCCEEDED(rv)) {
rv = pump->AsyncRead(this, urlSupports);
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, mozilla::LogLevel::Info, ("Mailbox Done\n"));
// 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, ctxt, 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;
}
nsresult nsMailboxProtocol::SetupMessageExtraction()
{
// Determine the number of bytes we are going to need to read out of the
// mailbox url....
nsCOMPtr<nsIMsgDBHdr> msgHdr;
nsresult rv = NS_OK;
NS_ASSERTION(m_runningUrl, "Not running a url");
if (m_runningUrl)
{
uint32_t messageSize = 0;
m_runningUrl->GetMessageSize(&messageSize);
if (!messageSize)
{
nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(m_runningUrl, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = msgUrl->GetMessageHeader(getter_AddRefs(msgHdr));
if (NS_SUCCEEDED(rv) && msgHdr)
{
msgHdr->GetMessageSize(&messageSize);
m_runningUrl->SetMessageSize(messageSize);
msgHdr->GetMessageOffset(&m_msgOffset);
}
else
NS_ASSERTION(false, "couldn't get message header");
}
}
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)
{
nsCOMPtr <nsIURI> url = do_QueryInterface(m_runningUrl);
rv = m_mailboxParser->OnDataAvailable(nullptr, url, 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, m_channelContext, 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, m_channelContext,
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

View file

@ -0,0 +1,125 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsMailboxProtocol_h___
#define nsMailboxProtocol_h___
#include "mozilla/Attributes.h"
#include "nsMsgProtocol.h"
#include "nsCOMPtr.h"
#include "nsIFile.h"
#include "nsIChannel.h"
#include "nsIInputStreamPump.h"
#include "nsIOutputStream.h"
#include "nsIMailboxUrl.h"
// State Flags (Note, I use the word state in terms of storing
// state information about the connection (authentication, have we sent
// commands, etc. I do not intend it to refer to protocol state)
#define MAILBOX_PAUSE_FOR_READ 0x00000001 /* should we pause for the next read */
#define MAILBOX_MSG_PARSE_FIRST_LINE 0x00000002 /* have we read in the first line of the msg */
/* states of the machine
*/
typedef enum _MailboxStatesEnum {
MAILBOX_READ_FOLDER,
MAILBOX_FINISH_OPEN_FOLDER,
MAILBOX_OPEN_MESSAGE,
MAILBOX_OPEN_STREAM,
MAILBOX_READ_MESSAGE,
MAILBOX_COMPRESS_FOLDER,
MAILBOX_FINISH_COMPRESS_FOLDER,
MAILBOX_BACKGROUND,
MAILBOX_NULL,
MAILBOX_NULL2,
MAILBOX_DELIVER_QUEUED,
MAILBOX_FINISH_DELIVER_QUEUED,
MAILBOX_DONE,
MAILBOX_ERROR_DONE,
MAILBOX_FREE,
MAILBOX_COPY_MESSAGES,
MAILBOX_FINISH_COPY_MESSAGES
} MailboxStatesEnum;
class nsMsgLineStreamBuffer;
class nsMailboxProtocol : public nsMsgProtocol
{
public:
// Creating a protocol instance requires the URL which needs to be run AND it requires
// a transport layer.
nsMailboxProtocol(nsIURI * aURL);
virtual ~nsMailboxProtocol();
// initialization function given a new url and transport layer
nsresult Initialize(nsIURI * aURL);
// the consumer of the url might be something like an nsIDocShell....
virtual nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer) override;
////////////////////////////////////////////////////////////////////////////////////////
// we suppport the nsIStreamListener interface
////////////////////////////////////////////////////////////////////////////////////////
NS_IMETHOD OnStartRequest(nsIRequest *request, nsISupports *ctxt) override;
NS_IMETHOD OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult aStatus) override;
private:
nsCOMPtr<nsIMailboxUrl> m_runningUrl; // the nsIMailboxURL that is currently running
nsMailboxAction m_mailboxAction; // current mailbox action associated with this connnection...
uint64_t m_msgOffset;
// Event sink handles
nsCOMPtr<nsIStreamListener> m_mailboxParser;
// Local state for the current operation
nsMsgLineStreamBuffer * m_lineStreamBuffer; // used to efficiently extract lines from the incoming data stream
// Generic state information -- What state are we in? What state do we want to go to
// after the next response? What was the last response code? etc.
MailboxStatesEnum m_nextState;
MailboxStatesEnum m_initialState;
int64_t mCurrentProgress;
// can we just use the base class m_tempMsgFile?
nsCOMPtr<nsIFile> m_tempMessageFile;
nsCOMPtr<nsIOutputStream> m_msgFileOutputStream;
// this is used to hold the source mailbox file open when move/copying
// multiple messages.
nsCOMPtr<nsIInputStream> m_multipleMsgMoveCopyStream;
virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream,
uint64_t sourceOffset, uint32_t length) override;
virtual nsresult CloseSocket() override;
nsresult SetupMessageExtraction();
nsresult OpenMultipleMsgTransport(uint64_t offset, int32_t size);
bool RunningMultipleMsgUrl();
////////////////////////////////////////////////////////////////////////////////////////
// Protocol Methods --> This protocol is state driven so each protocol method is
// designed to re-act to the current "state". I've attempted to
// group them together based on functionality.
////////////////////////////////////////////////////////////////////////////////////////
// When parsing a mailbox folder in chunks, this protocol state reads in the current chunk
// and forwards it to the mailbox parser.
int32_t ReadFolderResponse(nsIInputStream * inputStream, uint64_t sourceOffset, uint32_t length);
int32_t ReadMessageResponse(nsIInputStream * inputStream, uint64_t sourceOffset, uint32_t length);
nsresult DoneReadingMessage();
////////////////////////////////////////////////////////////////////////////////////////
// End of Protocol Methods
////////////////////////////////////////////////////////////////////////////////////////
};
#endif // nsMailboxProtocol_h___

View file

@ -0,0 +1,33 @@
/**
* 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 "nsMailboxServer.h"
#include "nsLocalMailFolder.h"
NS_IMETHODIMP
nsMailboxServer::GetLocalStoreType(nsACString& type)
{
type.AssignLiteral("mailbox");
return NS_OK;
}
NS_IMETHODIMP
nsMailboxServer::GetLocalDatabaseType(nsACString& type)
{
type.AssignLiteral("mailbox");
return NS_OK;
}
nsresult
nsMailboxServer::CreateRootFolderFromUri(const nsCString &serverUri,
nsIMsgFolder **rootFolder)
{
nsMsgLocalMailFolder *newRootFolder = new nsMsgLocalMailFolder;
if (!newRootFolder)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*rootFolder = newRootFolder);
newRootFolder->Init(serverUri.get());
return NS_OK;
}

View file

@ -0,0 +1,22 @@
/**
* 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/. */
#ifndef nsMailboxServer_h__
#define nsMailboxServer_h__
#include "mozilla/Attributes.h"
#include "nsMsgIncomingServer.h"
class nsMailboxServer : public nsMsgIncomingServer
{
public:
NS_IMETHOD GetLocalStoreType(nsACString& type) override;
NS_IMETHOD GetLocalDatabaseType(nsACString& type) override;
protected:
virtual nsresult CreateRootFolderFromUri(const nsCString &serverUri,
nsIMsgFolder **rootFolder) override;
};
#endif

View file

@ -0,0 +1,677 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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" // precompiled header...
#include "nsCOMPtr.h"
#include "nsMailboxService.h"
#include "nsMailboxUrl.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsMailboxProtocol.h"
#include "nsIMsgDatabase.h"
#include "nsMsgDBCID.h"
#include "MailNewsTypes.h"
#include "nsTArray.h"
#include "nsLocalUtils.h"
#include "nsMsgLocalCID.h"
#include "nsMsgBaseCID.h"
#include "nsIDocShell.h"
#include "nsIPop3Service.h"
#include "nsMsgUtils.h"
#include "nsNetUtil.h"
#include "nsIDocShellLoadInfo.h"
#include "nsIWebNavigation.h"
#include "prprf.h"
#include "nsIMsgHdr.h"
#include "nsIFileURL.h"
#include "mozilla/RefPtr.h"
nsMailboxService::nsMailboxService()
{
mPrintingOperation = false;
}
nsMailboxService::~nsMailboxService()
{}
NS_IMPL_ISUPPORTS(nsMailboxService, nsIMailboxService, nsIMsgMessageService, nsIProtocolHandler, nsIMsgMessageFetchPartService)
nsresult nsMailboxService::ParseMailbox(nsIMsgWindow *aMsgWindow, nsIFile *aMailboxPath, nsIStreamListener *aMailboxParser,
nsIUrlListener * aUrlListener, nsIURI ** aURL)
{
NS_ENSURE_ARG_POINTER(aMailboxPath);
nsresult rv;
nsCOMPtr<nsIMailboxUrl> mailboxurl =
do_CreateInstance(NS_MAILBOXURL_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv) && mailboxurl)
{
nsCOMPtr<nsIMsgMailNewsUrl> url = do_QueryInterface(mailboxurl);
// okay now generate the url string
nsCString mailboxPath;
aMailboxPath->GetNativePath(mailboxPath);
nsAutoCString buf;
MsgEscapeURL(mailboxPath,
nsINetUtil::ESCAPE_URL_MINIMAL | nsINetUtil::ESCAPE_URL_FORCED, buf);
nsEscapeNativePath(buf);
url->SetUpdatingFolder(true);
url->SetMsgWindow(aMsgWindow);
nsAutoCString uriSpec("mailbox://");
uriSpec.Append(buf);
rv = url->SetSpec(uriSpec);
NS_ENSURE_SUCCESS(rv, rv);
mailboxurl->SetMailboxParser(aMailboxParser);
if (aUrlListener)
url->RegisterListener(aUrlListener);
rv = RunMailboxUrl(url, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
if (aURL)
{
*aURL = url;
NS_IF_ADDREF(*aURL);
}
}
return rv;
}
nsresult nsMailboxService::CopyMessage(const char * aSrcMailboxURI,
nsIStreamListener * aMailboxCopyHandler,
bool moveMessage,
nsIUrlListener * aUrlListener,
nsIMsgWindow *aMsgWindow,
nsIURI **aURL)
{
nsMailboxAction mailboxAction = nsIMailboxUrl::ActionMoveMessage;
if (!moveMessage)
mailboxAction = nsIMailboxUrl::ActionCopyMessage;
return FetchMessage(aSrcMailboxURI, aMailboxCopyHandler, aMsgWindow, aUrlListener, nullptr, mailboxAction, nullptr, aURL);
}
nsresult nsMailboxService::CopyMessages(uint32_t aNumKeys,
nsMsgKey* aMsgKeys,
nsIMsgFolder *srcFolder,
nsIStreamListener * aMailboxCopyHandler,
bool moveMessage,
nsIUrlListener * aUrlListener,
nsIMsgWindow *aMsgWindow,
nsIURI **aURL)
{
nsresult rv = NS_OK;
NS_ENSURE_ARG(srcFolder);
NS_ENSURE_ARG(aMsgKeys);
nsCOMPtr<nsIMailboxUrl> mailboxurl;
nsMailboxAction actionToUse = nsIMailboxUrl::ActionMoveMessage;
if (!moveMessage)
actionToUse = nsIMailboxUrl::ActionCopyMessage;
nsCOMPtr <nsIMsgDBHdr> msgHdr;
nsCOMPtr <nsIMsgDatabase> db;
srcFolder->GetMsgDatabase(getter_AddRefs(db));
if (db)
{
db->GetMsgHdrForKey(aMsgKeys[0], getter_AddRefs(msgHdr));
if (msgHdr)
{
nsCString uri;
srcFolder->GetUriForMsg(msgHdr, uri);
rv = PrepareMessageUrl(uri.get(), aUrlListener, actionToUse , getter_AddRefs(mailboxurl), aMsgWindow);
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIURI> url = do_QueryInterface(mailboxurl);
nsCOMPtr<nsIMsgMailNewsUrl> msgUrl (do_QueryInterface(url));
nsCOMPtr<nsIMailboxUrl> mailboxUrl (do_QueryInterface(url));
msgUrl->SetMsgWindow(aMsgWindow);
mailboxUrl->SetMoveCopyMsgKeys(aMsgKeys, aNumKeys);
rv = RunMailboxUrl(url, aMailboxCopyHandler);
}
}
}
if (aURL && mailboxurl)
CallQueryInterface(mailboxurl, aURL);
return rv;
}
nsresult nsMailboxService::FetchMessage(const char* aMessageURI,
nsISupports * aDisplayConsumer,
nsIMsgWindow * aMsgWindow,
nsIUrlListener * aUrlListener,
const char * aFileName, /* only used by open attachment... */
nsMailboxAction mailboxAction,
const char * aCharsetOverride,
nsIURI ** aURL)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMailboxUrl> mailboxurl;
nsMailboxAction actionToUse = mailboxAction;
nsCOMPtr<nsIURI> url;
nsCOMPtr<nsIMsgMailNewsUrl> msgUrl;
nsAutoCString uriString(aMessageURI);
if (!strncmp(aMessageURI, "file:", 5))
{
int64_t fileSize;
nsCOMPtr<nsIURI> fileUri;
rv = NS_NewURI(getter_AddRefs(fileUri), aMessageURI);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIFileURL> fileUrl = do_QueryInterface(fileUri, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIFile> file;
rv = fileUrl->GetFile(getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, rv);
file->GetFileSize(&fileSize);
uriString.Replace(0, 5, NS_LITERAL_CSTRING("mailbox:"));
uriString.Append(NS_LITERAL_CSTRING("&number=0"));
rv = NS_NewURI(getter_AddRefs(url), uriString);
NS_ENSURE_SUCCESS(rv, rv);
msgUrl = do_QueryInterface(url);
if (msgUrl)
{
msgUrl->SetMsgWindow(aMsgWindow);
nsCOMPtr <nsIMailboxUrl> mailboxUrl = do_QueryInterface(msgUrl, &rv);
mailboxUrl->SetMessageSize((uint32_t) fileSize);
nsCOMPtr <nsIMsgHeaderSink> headerSink;
// need to tell the header sink to capture some headers to create a fake db header
// so we can do reply to a .eml file or a rfc822 msg attachment.
if (aMsgWindow)
aMsgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
if (headerSink)
{
nsCOMPtr <nsIMsgDBHdr> dummyHeader;
headerSink->GetDummyMsgHeader(getter_AddRefs(dummyHeader));
if (dummyHeader)
dummyHeader->SetMessageSize((uint32_t) fileSize);
}
}
}
else
{
// this happens with forward inline of message/rfc822 attachment
// opened in a stand-alone msg window.
int32_t typeIndex = uriString.Find("&type=application/x-message-display");
if (typeIndex != -1)
{
uriString.Cut(typeIndex, sizeof("&type=application/x-message-display") - 1);
rv = NS_NewURI(getter_AddRefs(url), uriString.get());
mailboxurl = do_QueryInterface(url);
}
else
rv = PrepareMessageUrl(aMessageURI, aUrlListener, actionToUse , getter_AddRefs(mailboxurl), aMsgWindow);
if (NS_SUCCEEDED(rv))
{
url = do_QueryInterface(mailboxurl);
msgUrl = do_QueryInterface(url);
msgUrl->SetMsgWindow(aMsgWindow);
if (aFileName)
msgUrl->SetFileName(nsDependentCString(aFileName));
}
}
nsCOMPtr<nsIMsgI18NUrl> i18nurl(do_QueryInterface(msgUrl));
if (i18nurl)
i18nurl->SetCharsetOverRide(aCharsetOverride);
// instead of running the mailbox url like we used to, let's try to run the url in the docshell...
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aDisplayConsumer, &rv));
// if we were given a docShell, run the url in the docshell..otherwise just run it normally.
if (NS_SUCCEEDED(rv) && docShell)
{
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
// DIRTY LITTLE HACK --> if we are opening an attachment we want the docshell to
// treat this load as if it were a user click event. Then the dispatching stuff will be much
// happier.
if (mailboxAction == nsIMailboxUrl::ActionFetchPart)
{
docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadLink);
}
rv = docShell->LoadURI(url, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, false);
}
else
rv = RunMailboxUrl(url, aDisplayConsumer);
if (aURL && mailboxurl)
CallQueryInterface(mailboxurl, aURL);
return rv;
}
NS_IMETHODIMP nsMailboxService::FetchMimePart(nsIURI *aURI, const char *aMessageURI, nsISupports *aDisplayConsumer, nsIMsgWindow *aMsgWindow, nsIUrlListener *aUrlListener, nsIURI **aURL)
{
nsresult rv;
nsCOMPtr<nsIMsgMailNewsUrl> msgUrl (do_QueryInterface(aURI, &rv));
NS_ENSURE_SUCCESS(rv, rv);
msgUrl->SetMsgWindow(aMsgWindow);
// set up the url listener
if (aUrlListener)
msgUrl->RegisterListener(aUrlListener);
return RunMailboxUrl(msgUrl, aDisplayConsumer);
}
NS_IMETHODIMP nsMailboxService::DisplayMessage(const char* aMessageURI,
nsISupports * aDisplayConsumer,
nsIMsgWindow * aMsgWindow,
nsIUrlListener * aUrlListener,
const char * aCharsetOveride,
nsIURI ** aURL)
{
return FetchMessage(aMessageURI, aDisplayConsumer,
aMsgWindow,aUrlListener, nullptr,
nsIMailboxUrl::ActionFetchMessage, aCharsetOveride, aURL);
}
NS_IMETHODIMP
nsMailboxService::StreamMessage(const char *aMessageURI,
nsISupports *aConsumer,
nsIMsgWindow *aMsgWindow,
nsIUrlListener *aUrlListener,
bool /* aConvertData */,
const nsACString &aAdditionalHeader,
bool aLocalOnly,
nsIURI **aURL)
{
// The mailbox protocol object will look for "header=filter" or
// "header=attach" to decide if it wants to convert the data instead of
// using aConvertData. It turns out to be way too hard to pass aConvertData
// all the way over to the mailbox protocol object.
nsAutoCString aURIString(aMessageURI);
if (!aAdditionalHeader.IsEmpty())
{
aURIString.FindChar('?') == -1 ? aURIString += "?" : aURIString += "&";
aURIString += "header=";
aURIString += aAdditionalHeader;
}
return FetchMessage(aURIString.get(), aConsumer, aMsgWindow, aUrlListener, nullptr,
nsIMailboxUrl::ActionFetchMessage, nullptr, aURL);
}
NS_IMETHODIMP nsMailboxService::StreamHeaders(const char *aMessageURI,
nsIStreamListener *aConsumer,
nsIUrlListener *aUrlListener,
bool aLocalOnly,
nsIURI **aURL)
{
NS_ENSURE_ARG_POINTER(aMessageURI);
NS_ENSURE_ARG_POINTER(aConsumer);
nsAutoCString folderURI;
nsMsgKey msgKey;
nsCOMPtr<nsIMsgFolder> folder;
nsresult rv = DecomposeMailboxURI(aMessageURI, getter_AddRefs(folder), &msgKey);
if (msgKey == nsMsgKey_None)
return NS_MSG_MESSAGE_NOT_FOUND;
nsCOMPtr<nsIInputStream> inputStream;
int64_t messageOffset;
uint32_t messageSize;
rv = folder->GetOfflineFileStream(msgKey, &messageOffset, &messageSize, getter_AddRefs(inputStream));
NS_ENSURE_SUCCESS(rv, rv);
// GetOfflineFileStream returns NS_OK but null inputStream when there is an error getting the database
if (!inputStream)
return NS_ERROR_FAILURE;
return MsgStreamMsgHeaders(inputStream, aConsumer);
}
NS_IMETHODIMP nsMailboxService::IsMsgInMemCache(nsIURI *aUrl,
nsIMsgFolder *aFolder,
bool *aResult)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMailboxService::OpenAttachment(const char *aContentType,
const char *aFileName,
const char *aUrl,
const char *aMessageUri,
nsISupports *aDisplayConsumer,
nsIMsgWindow *aMsgWindow,
nsIUrlListener *aUrlListener)
{
nsCOMPtr <nsIURI> URL;
nsAutoCString urlString(aUrl);
urlString += "&type=";
urlString += aContentType;
urlString += "&filename=";
urlString += aFileName;
CreateStartupUrl(urlString.get(), getter_AddRefs(URL));
nsresult rv;
// try to run the url in the docshell...
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aDisplayConsumer, &rv));
// if we were given a docShell, run the url in the docshell..otherwise just run it normally.
if (NS_SUCCEEDED(rv) && docShell)
{
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
// DIRTY LITTLE HACK --> since we are opening an attachment we want the docshell to
// treat this load as if it were a user click event. Then the dispatching stuff will be much
// happier.
docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadLink);
return docShell->LoadURI(URL, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, false);
}
return RunMailboxUrl(URL, aDisplayConsumer);
}
NS_IMETHODIMP
nsMailboxService::SaveMessageToDisk(const char *aMessageURI,
nsIFile *aFile,
bool aAddDummyEnvelope,
nsIUrlListener *aUrlListener,
nsIURI **aURL,
bool canonicalLineEnding,
nsIMsgWindow *aMsgWindow)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMailboxUrl> mailboxurl;
rv = PrepareMessageUrl(aMessageURI, aUrlListener, nsIMailboxUrl::ActionSaveMessageToDisk, getter_AddRefs(mailboxurl), aMsgWindow);
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(mailboxurl);
if (msgUrl)
{
msgUrl->SetMessageFile(aFile);
msgUrl->SetAddDummyEnvelope(aAddDummyEnvelope);
msgUrl->SetCanonicalLineEnding(canonicalLineEnding);
}
nsCOMPtr<nsIURI> url = do_QueryInterface(mailboxurl);
rv = RunMailboxUrl(url);
}
if (aURL && mailboxurl)
CallQueryInterface(mailboxurl, aURL);
return rv;
}
NS_IMETHODIMP nsMailboxService::GetUrlForUri(const char *aMessageURI, nsIURI **aURL, nsIMsgWindow *aMsgWindow)
{
NS_ENSURE_ARG_POINTER(aURL);
if (!strncmp(aMessageURI, "file:", 5) || PL_strstr(aMessageURI, "type=application/x-message-display")
|| !strncmp(aMessageURI, "mailbox:", 8))
return NS_NewURI(aURL, aMessageURI);
nsresult rv = NS_OK;
nsCOMPtr<nsIMailboxUrl> mailboxurl;
rv = PrepareMessageUrl(aMessageURI, nullptr, nsIMailboxUrl::ActionFetchMessage, getter_AddRefs(mailboxurl), aMsgWindow);
if (NS_SUCCEEDED(rv) && mailboxurl)
rv = CallQueryInterface(mailboxurl, aURL);
return rv;
}
// Takes a mailbox url, this method creates a protocol instance and loads the url
// into the protocol instance.
nsresult nsMailboxService::RunMailboxUrl(nsIURI * aMailboxUrl, nsISupports * aDisplayConsumer)
{
// create a protocol instance to run the url..
nsresult rv = NS_OK;
nsMailboxProtocol * protocol = new nsMailboxProtocol(aMailboxUrl);
if (protocol)
{
rv = protocol->Initialize(aMailboxUrl);
if (NS_FAILED(rv))
{
delete protocol;
return rv;
}
NS_ADDREF(protocol);
rv = protocol->LoadUrl(aMailboxUrl, aDisplayConsumer);
NS_RELEASE(protocol); // after loading, someone else will have a ref cnt on the mailbox
}
return rv;
}
// This function takes a message uri, converts it into a file path & msgKey
// pair. It then turns that into a mailbox url object. It also registers a url
// listener if appropriate. AND it can take in a mailbox action and set that field
// on the returned url as well.
nsresult nsMailboxService::PrepareMessageUrl(const char * aSrcMsgMailboxURI, nsIUrlListener * aUrlListener,
nsMailboxAction aMailboxAction, nsIMailboxUrl ** aMailboxUrl,
nsIMsgWindow *msgWindow)
{
nsresult rv = CallCreateInstance(NS_MAILBOXURL_CONTRACTID, aMailboxUrl);
if (NS_SUCCEEDED(rv) && aMailboxUrl && *aMailboxUrl)
{
// okay now generate the url string
char * urlSpec;
nsAutoCString folderURI;
nsMsgKey msgKey;
nsCString folderPath;
const char *part = PL_strstr(aSrcMsgMailboxURI, "part=");
const char *header = PL_strstr(aSrcMsgMailboxURI, "header=");
rv = nsParseLocalMessageURI(aSrcMsgMailboxURI, folderURI, &msgKey);
NS_ENSURE_SUCCESS(rv,rv);
rv = nsLocalURI2Path(kMailboxRootURI, folderURI.get(), folderPath);
if (NS_SUCCEEDED(rv))
{
// set up the url spec and initialize the url with it.
nsAutoCString buf;
MsgEscapeURL(folderPath,
nsINetUtil::ESCAPE_URL_DIRECTORY | nsINetUtil::ESCAPE_URL_FORCED, buf);
if (mPrintingOperation)
urlSpec = PR_smprintf("mailbox://%s?number=%lu&header=print", buf.get(), msgKey);
else if (part)
urlSpec = PR_smprintf("mailbox://%s?number=%lu&%s", buf.get(), msgKey, part);
else if (header)
urlSpec = PR_smprintf("mailbox://%s?number=%lu&%s", buf.get(), msgKey, header);
else
urlSpec = PR_smprintf("mailbox://%s?number=%lu", buf.get(), msgKey);
nsCOMPtr <nsIMsgMailNewsUrl> url = do_QueryInterface(*aMailboxUrl);
rv = url->SetSpec(nsDependentCString(urlSpec));
NS_ENSURE_SUCCESS(rv, rv);
PR_smprintf_free(urlSpec);
(*aMailboxUrl)->SetMailboxAction(aMailboxAction);
// set up the url listener
if (aUrlListener)
rv = url->RegisterListener(aUrlListener);
url->SetMsgWindow(msgWindow);
nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(url);
if (msgUrl)
{
msgUrl->SetOriginalSpec(aSrcMsgMailboxURI);
msgUrl->SetUri(aSrcMsgMailboxURI);
}
} // if we got a url
} // if we got a url
return rv;
}
NS_IMETHODIMP nsMailboxService::GetScheme(nsACString &aScheme)
{
aScheme = "mailbox";
return NS_OK;
}
NS_IMETHODIMP nsMailboxService::GetDefaultPort(int32_t *aDefaultPort)
{
NS_ENSURE_ARG_POINTER(aDefaultPort);
*aDefaultPort = -1; // mailbox doesn't use a port!!!!!
return NS_OK;
}
NS_IMETHODIMP nsMailboxService::AllowPort(int32_t port, const char *scheme, bool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
// don't override anything.
*_retval = false;
return NS_OK;
}
NS_IMETHODIMP nsMailboxService::GetProtocolFlags(uint32_t *result)
{
NS_ENSURE_ARG_POINTER(result);
*result = URI_STD | URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT |
URI_DANGEROUS_TO_LOAD | URI_FORBIDS_COOKIE_ACCESS
#ifdef IS_ORIGIN_IS_FULL_SPEC_DEFINED
| ORIGIN_IS_FULL_SPEC
#endif
;
return NS_OK;
}
NS_IMETHODIMP nsMailboxService::NewURI(const nsACString &aSpec,
const char *aOriginCharset,
nsIURI *aBaseURI,
nsIURI **_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = 0;
nsresult rv;
nsCOMPtr<nsIURI> aMsgUri = do_CreateInstance(NS_MAILBOXURL_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// SetSpec calls below may fail if the mailbox url is of the form
// mailbox://<account>/<mailbox name>?... instead of
// mailbox://<path to folder>?.... This is the case for pop3 download urls.
// We know this, and the failure is harmless.
if (aBaseURI)
{
nsAutoCString newSpec;
rv = aBaseURI->Resolve(aSpec, newSpec);
NS_ENSURE_SUCCESS(rv, rv);
(void) aMsgUri->SetSpec(newSpec);
}
else
{
(void) aMsgUri->SetSpec(aSpec);
}
aMsgUri.swap(*_retval);
return rv;
}
NS_IMETHODIMP nsMailboxService::NewChannel(nsIURI *aURI, nsIChannel **_retval)
{
return NewChannel2(aURI, nullptr, _retval);
}
NS_IMETHODIMP nsMailboxService::NewChannel2(nsIURI *aURI,
nsILoadInfo *aLoadInfo,
nsIChannel **_retval)
{
NS_ENSURE_ARG_POINTER(aURI);
NS_ENSURE_ARG_POINTER(_retval);
nsresult rv = NS_OK;
nsAutoCString spec;
rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
if (spec.Find("?uidl=") >= 0 || spec.Find("&uidl=") >= 0)
{
nsCOMPtr<nsIProtocolHandler> handler =
do_GetService(NS_POP3SERVICE_CONTRACTID1, &rv);
if (NS_SUCCEEDED(rv))
{
nsCOMPtr <nsIURI> pop3Uri;
rv = handler->NewURI(spec, "" /* ignored */, aURI, getter_AddRefs(pop3Uri));
NS_ENSURE_SUCCESS(rv, rv);
return handler->NewChannel2(pop3Uri, aLoadInfo, _retval);
}
}
RefPtr<nsMailboxProtocol> protocol = new nsMailboxProtocol(aURI);
if (!protocol) {
return NS_ERROR_OUT_OF_MEMORY;
}
rv = protocol->Initialize(aURI);
NS_ENSURE_SUCCESS(rv, rv);
rv = protocol->SetLoadInfo(aLoadInfo);
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(protocol, _retval);
}
nsresult nsMailboxService::DisplayMessageForPrinting(const char* aMessageURI,
nsISupports * aDisplayConsumer,
nsIMsgWindow * aMsgWindow,
nsIUrlListener * aUrlListener,
nsIURI ** aURL)
{
mPrintingOperation = true;
nsresult rv = FetchMessage(aMessageURI, aDisplayConsumer, aMsgWindow,aUrlListener, nullptr,
nsIMailboxUrl::ActionFetchMessage, nullptr, aURL);
mPrintingOperation = false;
return rv;
}
NS_IMETHODIMP nsMailboxService::Search(nsIMsgSearchSession *aSearchSession, nsIMsgWindow *aMsgWindow, nsIMsgFolder *aMsgFolder, const char *aMessageUri)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsMailboxService::DecomposeMailboxURI(const char * aMessageURI, nsIMsgFolder ** aFolder, nsMsgKey *aMsgKey)
{
NS_ENSURE_ARG_POINTER(aMessageURI);
NS_ENSURE_ARG_POINTER(aFolder);
NS_ENSURE_ARG_POINTER(aMsgKey);
nsresult rv = NS_OK;
nsAutoCString folderURI;
rv = nsParseLocalMessageURI(aMessageURI, folderURI, aMsgKey);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr <nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1",&rv);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIRDFResource> res;
rv = rdf->GetResource(folderURI, getter_AddRefs(res));
NS_ENSURE_SUCCESS(rv,rv);
rv = res->QueryInterface(NS_GET_IID(nsIMsgFolder), (void **) aFolder);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
NS_IMETHODIMP
nsMailboxService::MessageURIToMsgHdr(const char *uri, nsIMsgDBHdr **_retval)
{
NS_ENSURE_ARG_POINTER(uri);
NS_ENSURE_ARG_POINTER(_retval);
nsresult rv = NS_OK;
nsCOMPtr<nsIMsgFolder> folder;
nsMsgKey msgKey;
rv = DecomposeMailboxURI(uri, getter_AddRefs(folder), &msgKey);
NS_ENSURE_SUCCESS(rv,rv);
rv = folder->GetMessageHeader(msgKey, _retval);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}

View file

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 4; 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/. */
#ifndef nsMailboxService_h___
#define nsMailboxService_h___
#include "nscore.h"
#include "nsISupports.h"
#include "nsIMailboxService.h"
#include "nsIMsgMessageService.h"
#include "nsIMailboxUrl.h"
#include "nsIURL.h"
#include "nsIUrlListener.h"
#include "nsIStreamListener.h"
#include "nsIFile.h"
#include "nsIProtocolHandler.h"
#include "nsIRDFService.h"
class nsMailboxService : public nsIMailboxService, public nsIMsgMessageService, public nsIMsgMessageFetchPartService, public nsIProtocolHandler
{
public:
nsMailboxService();
NS_DECL_ISUPPORTS
NS_DECL_NSIMAILBOXSERVICE
NS_DECL_NSIMSGMESSAGESERVICE
NS_DECL_NSIMSGMESSAGEFETCHPARTSERVICE
NS_DECL_NSIPROTOCOLHANDLER
protected:
virtual ~nsMailboxService();
bool mPrintingOperation;
// helper functions used by the service
nsresult PrepareMessageUrl(const char * aSrcMsgMailboxURI, nsIUrlListener * aUrlListener,
nsMailboxAction aMailboxAction, nsIMailboxUrl ** aMailboxUrl,
nsIMsgWindow *msgWindow);
nsresult RunMailboxUrl(nsIURI * aMailboxUrl, nsISupports * aDisplayConsumer = nullptr);
nsresult FetchMessage(const char* aMessageURI,
nsISupports * aDisplayConsumer,
nsIMsgWindow * aMsgWindow,
nsIUrlListener * aUrlListener,
const char * aFileName, /* only used by open attachment */
nsMailboxAction mailboxAction,
const char * aCharsetOverride,
nsIURI ** aURL);
nsresult DecomposeMailboxURI(const char * aMessageURI, nsIMsgFolder ** aFolder, nsMsgKey *aMsgKey);
};
#endif /* nsMailboxService_h___ */

View file

@ -0,0 +1,556 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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" // precompiled header...
#include "nsIURI.h"
#include "nsIMailboxUrl.h"
#include "nsMailboxUrl.h"
#include "nsStringGlue.h"
#include "nsLocalUtils.h"
#include "nsIMsgDatabase.h"
#include "nsMsgDBCID.h"
#include "nsMsgBaseCID.h"
#include "nsIMsgHdr.h"
#include "nsIMsgFolder.h"
#include "prprf.h"
#include "prmem.h"
#include "nsIMsgMailSession.h"
#include "nsNetUtil.h"
#include "nsIFileURL.h"
// this is totally lame and MUST be removed by M6
// the real fix is to attach the URI to the URL as it runs through netlib
// then grab it and use it on the other side
#include "nsCOMPtr.h"
#include "nsMsgBaseCID.h"
#include "nsIMsgAccountManager.h"
#include "nsMsgUtils.h"
#include "mozilla/Services.h"
// helper function for parsing the search field of a url
char * extractAttributeValue(const char * searchString, const char * attributeName);
nsMailboxUrl::nsMailboxUrl()
{
m_mailboxAction = nsIMailboxUrl::ActionParseMailbox;
m_filePath = nullptr;
m_messageID = nullptr;
m_messageKey = nsMsgKey_None;
m_messageSize = 0;
m_messageFile = nullptr;
m_addDummyEnvelope = false;
m_canonicalLineEnding = false;
m_curMsgIndex = 0;
}
nsMailboxUrl::~nsMailboxUrl()
{
PR_Free(m_messageID);
}
NS_IMPL_ADDREF_INHERITED(nsMailboxUrl, nsMsgMailNewsUrl)
NS_IMPL_RELEASE_INHERITED(nsMailboxUrl, nsMsgMailNewsUrl)
NS_INTERFACE_MAP_BEGIN(nsMailboxUrl)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMailboxUrl)
NS_INTERFACE_MAP_ENTRY(nsIMailboxUrl)
NS_INTERFACE_MAP_ENTRY(nsIMsgMessageUrl)
NS_INTERFACE_MAP_ENTRY(nsIMsgI18NUrl)
NS_INTERFACE_MAP_END_INHERITING(nsMsgMailNewsUrl)
////////////////////////////////////////////////////////////////////////////////////
// Begin nsIMailboxUrl specific support
////////////////////////////////////////////////////////////////////////////////////
nsresult nsMailboxUrl::SetMailboxParser(nsIStreamListener * aMailboxParser)
{
if (aMailboxParser)
m_mailboxParser = aMailboxParser;
return NS_OK;
}
nsresult nsMailboxUrl::GetMailboxParser(nsIStreamListener ** aConsumer)
{
NS_ENSURE_ARG_POINTER(aConsumer);
NS_IF_ADDREF(*aConsumer = m_mailboxParser);
return NS_OK;
}
nsresult nsMailboxUrl::SetMailboxCopyHandler(nsIStreamListener * aMailboxCopyHandler)
{
if (aMailboxCopyHandler)
m_mailboxCopyHandler = aMailboxCopyHandler;
return NS_OK;
}
nsresult nsMailboxUrl::GetMailboxCopyHandler(nsIStreamListener ** aMailboxCopyHandler)
{
NS_ENSURE_ARG_POINTER(aMailboxCopyHandler);
if (aMailboxCopyHandler)
{
*aMailboxCopyHandler = m_mailboxCopyHandler;
NS_IF_ADDREF(*aMailboxCopyHandler);
}
return NS_OK;
}
nsresult nsMailboxUrl::GetMessageKey(nsMsgKey* aMessageKey)
{
*aMessageKey = m_messageKey;
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::GetMessageSize(uint32_t * aMessageSize)
{
if (aMessageSize)
{
*aMessageSize = m_messageSize;
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
nsresult nsMailboxUrl::SetMessageSize(uint32_t aMessageSize)
{
m_messageSize = aMessageSize;
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::GetPrincipalSpec(nsACString& aPrincipalSpec)
{
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsURL;
QueryInterface(NS_GET_IID(nsIMsgMailNewsUrl), getter_AddRefs(mailnewsURL));
nsAutoCString spec;
mailnewsURL->GetSpecIgnoringRef(spec);
// mailbox: URLs contain a lot of query parts. We want need a normalised form:
// mailbox:///path/to/folder?number=nn.
// We also need to translate the second form mailbox://user@domain@server/folder?number=nn.
char* messageKey = extractAttributeValue(spec.get(), "number=");
// Strip any query part beginning with ? or /;
int32_t ind = spec.Find("/;");
if (ind != kNotFound)
spec.SetLength(ind);
ind = spec.FindChar('?');
if (ind != kNotFound)
spec.SetLength(ind);
// Check for format lacking absolute path.
if (spec.Find("///") == kNotFound) {
nsCString folderPath;
nsresult rv = nsLocalURI2Path(kMailboxRootURI, spec.get(), folderPath);
if (NS_SUCCEEDED (rv)) {
nsAutoCString buf;
MsgEscapeURL(folderPath,
nsINetUtil::ESCAPE_URL_DIRECTORY | nsINetUtil::ESCAPE_URL_FORCED, buf);
spec = NS_LITERAL_CSTRING("mailbox://") + buf;
}
}
spec += NS_LITERAL_CSTRING("?number=");
spec.Append(messageKey);
PR_Free(messageKey);
aPrincipalSpec.Assign(spec);
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::SetUri(const char * aURI)
{
mURI= aURI;
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::CloneInternal(uint32_t aRefHandlingMode,
const nsACString& newRef,
nsIURI **_retval)
{
nsresult rv = nsMsgMailNewsUrl::CloneInternal(aRefHandlingMode,
newRef, _retval);
NS_ENSURE_SUCCESS(rv, rv);
// also clone the mURI member, because GetUri below won't work if
// mURI isn't set due to nsIFile fun.
nsCOMPtr <nsIMsgMessageUrl> clonedUrl = do_QueryInterface(*_retval);
if (clonedUrl)
clonedUrl->SetUri(mURI.get());
return rv;
}
NS_IMETHODIMP nsMailboxUrl::GetUri(char ** aURI)
{
// if we have been given a uri to associate with this url, then use it
// otherwise try to reconstruct a URI on the fly....
if (!mURI.IsEmpty())
*aURI = ToNewCString(mURI);
else
{
if (m_filePath)
{
nsAutoCString baseUri;
nsresult rv;
nsCOMPtr<nsIMsgAccountManager> accountManager =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// we blow off errors here so that we can open attachments
// in .eml files.
(void) accountManager->FolderUriForPath(m_filePath, baseUri);
if (baseUri.IsEmpty()) {
rv = m_baseURL->GetSpec(baseUri);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCString baseMessageURI;
nsCreateLocalBaseMessageURI(baseUri, baseMessageURI);
nsAutoCString uriStr;
nsBuildLocalMessageURI(baseMessageURI.get(), m_messageKey, uriStr);
*aURI = ToNewCString(uriStr);
}
else
*aURI = nullptr;
}
return NS_OK;
}
nsresult nsMailboxUrl::GetMsgHdrForKey(nsMsgKey msgKey, nsIMsgDBHdr ** aMsgHdr)
{
nsresult rv = NS_OK;
if (aMsgHdr && m_filePath)
{
nsCOMPtr<nsIMsgDatabase> mailDBFactory;
nsCOMPtr<nsIMsgDatabase> mailDB;
nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
if (msgDBService)
rv = msgDBService->OpenMailDBFromFile(m_filePath, nullptr, false,
false, getter_AddRefs(mailDB));
if (NS_SUCCEEDED(rv) && mailDB) // did we get a db back?
rv = mailDB->GetMsgHdrForKey(msgKey, aMsgHdr);
else
{
nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
if (!msgWindow)
{
nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
}
// maybe this is .eml file we're trying to read. See if we can get a header from the header sink.
if (msgWindow)
{
nsCOMPtr<nsIMsgHeaderSink> headerSink;
msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
if (headerSink)
{
rv = headerSink->GetDummyMsgHeader(aMsgHdr);
if (NS_SUCCEEDED(rv))
{
int64_t fileSize = 0;
m_filePath->GetFileSize(&fileSize);
(*aMsgHdr)->SetMessageSize(fileSize);
}
}
}
}
}
else
rv = NS_ERROR_NULL_POINTER;
return rv;
}
NS_IMETHODIMP nsMailboxUrl::GetMessageHeader(nsIMsgDBHdr ** aMsgHdr)
{
if (m_dummyHdr)
{
NS_IF_ADDREF(*aMsgHdr = m_dummyHdr);
return NS_OK;
}
return GetMsgHdrForKey(m_messageKey, aMsgHdr);
}
NS_IMETHODIMP nsMailboxUrl::SetMessageHeader(nsIMsgDBHdr *aMsgHdr)
{
m_dummyHdr = aMsgHdr;
return NS_OK;
}
NS_IMPL_GETSET(nsMailboxUrl, AddDummyEnvelope, bool, m_addDummyEnvelope)
NS_IMPL_GETSET(nsMailboxUrl, CanonicalLineEnding, bool, m_canonicalLineEnding)
NS_IMETHODIMP
nsMailboxUrl::GetOriginalSpec(char **aSpec)
{
if (!aSpec || m_originalSpec.IsEmpty())
return NS_ERROR_NULL_POINTER;
*aSpec = ToNewCString(m_originalSpec);
return NS_OK;
}
NS_IMETHODIMP
nsMailboxUrl::SetOriginalSpec(const char *aSpec)
{
m_originalSpec = aSpec;
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::SetMessageFile(nsIFile * aFile)
{
m_messageFile = aFile;
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::GetMessageFile(nsIFile ** aFile)
{
// why don't we return an error for null aFile?
if (aFile)
NS_IF_ADDREF(*aFile = m_messageFile);
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::IsUrlType(uint32_t type, bool *isType)
{
NS_ENSURE_ARG(isType);
switch(type)
{
case nsIMsgMailNewsUrl::eCopy:
*isType = (m_mailboxAction == nsIMailboxUrl::ActionCopyMessage);
break;
case nsIMsgMailNewsUrl::eMove:
*isType = (m_mailboxAction == nsIMailboxUrl::ActionMoveMessage);
break;
case nsIMsgMailNewsUrl::eDisplay:
*isType = (m_mailboxAction == nsIMailboxUrl::ActionFetchMessage ||
m_mailboxAction == nsIMailboxUrl::ActionFetchPart);
break;
default:
*isType = false;
};
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////////
// End nsIMailboxUrl specific support
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// possible search part phrases include: MessageID=id&number=MessageKey
nsresult nsMailboxUrl::ParseSearchPart()
{
nsAutoCString searchPart;
nsresult rv = GetQuery(searchPart);
// add code to this function to decompose everything past the '?'.....
if (NS_SUCCEEDED(rv) && !searchPart.IsEmpty())
{
// the action for this mailbox must be a display message...
char * msgPart = extractAttributeValue(searchPart.get(), "part=");
if (msgPart) // if we have a part in the url then we must be fetching just the part.
m_mailboxAction = nsIMailboxUrl::ActionFetchPart;
else
m_mailboxAction = nsIMailboxUrl::ActionFetchMessage;
char * messageKey = extractAttributeValue(searchPart.get(), "number=");
m_messageID = extractAttributeValue(searchPart.get(),"messageid=");
if (messageKey)
m_messageKey = (nsMsgKey) ParseUint64Str(messageKey); // convert to a uint32_t...
PR_Free(msgPart);
PR_Free(messageKey);
}
else
m_mailboxAction = nsIMailboxUrl::ActionParseMailbox;
return rv;
}
// warning: don't assume when parsing the url that the protocol part is "news"...
nsresult nsMailboxUrl::ParseUrl()
{
GetFilePath(m_file);
ParseSearchPart();
// ### fix me.
// this hack is to avoid asserting on every local message loaded because the security manager
// is creating an empty "mailbox://" uri for every message.
if (m_file.Length() < 2)
m_filePath = nullptr;
else
{
nsCString fileUri("file://");
fileUri.Append(m_file);
nsresult rv;
nsCOMPtr<nsIIOService> ioService =
mozilla::services::GetIOService();
NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
nsCOMPtr <nsIURI> uri;
rv = ioService->NewURI(fileUri, nullptr, nullptr, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIFileURL> fileURL = do_QueryInterface(uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIFile> fileURLFile;
fileURL->GetFile(getter_AddRefs(fileURLFile));
m_filePath = do_QueryInterface(fileURLFile, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
GetPath(m_file);
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::SetSpec(const nsACString &aSpec)
{
nsresult rv = nsMsgMailNewsUrl::SetSpec(aSpec);
if (NS_SUCCEEDED(rv))
rv = ParseUrl();
return rv;
}
NS_IMETHODIMP nsMailboxUrl::SetQuery(const nsACString &aQuery)
{
nsresult rv = nsMsgMailNewsUrl::SetQuery(aQuery);
if (NS_SUCCEEDED(rv))
rv = ParseUrl();
return rv;
}
// takes a string like ?messageID=fooo&number=MsgKey and returns a new string
// containing just the attribute value. i.e you could pass in this string with
// an attribute name of messageID and I'll return fooo. Use PR_Free to delete
// this string...
// Assumption: attribute pairs in the string are separated by '&'.
char * extractAttributeValue(const char * searchString, const char * attributeName)
{
char * attributeValue = nullptr;
if (searchString && attributeName)
{
// search the string for attributeName
uint32_t attributeNameSize = PL_strlen(attributeName);
char * startOfAttribute = PL_strcasestr(searchString, attributeName);
if (startOfAttribute)
{
startOfAttribute += attributeNameSize; // skip over the attributeName
if (startOfAttribute) // is there something after the attribute name
{
char * endOfAttribute = startOfAttribute ? PL_strchr(startOfAttribute, '&') : nullptr;
nsDependentCString attributeValueStr;
if (startOfAttribute && endOfAttribute) // is there text after attribute value
attributeValueStr.Assign(startOfAttribute, endOfAttribute - startOfAttribute);
else // there is nothing left so eat up rest of line.
attributeValueStr.Assign(startOfAttribute);
// now unescape the string...
nsCString unescapedValue;
MsgUnescapeString(attributeValueStr, 0, unescapedValue);
attributeValue = PL_strdup(unescapedValue.get());
} // if we have a attribute value
} // if we have a attribute name
} // if we got non-null search string and attribute name values
return attributeValue;
}
// nsIMsgI18NUrl support
nsresult nsMailboxUrl::GetFolder(nsIMsgFolder **msgFolder)
{
// if we have a RDF URI, then try to get the folder for that URI and then ask the folder
// for it's charset....
nsCString uri;
GetUri(getter_Copies(uri));
NS_ENSURE_TRUE(!uri.IsEmpty(), NS_ERROR_FAILURE);
nsCOMPtr<nsIMsgDBHdr> msg;
GetMsgDBHdrFromURI(uri.get(), getter_AddRefs(msg));
if (!msg)
return NS_ERROR_FAILURE;
return msg->GetFolder(msgFolder);
}
NS_IMETHODIMP nsMailboxUrl::GetFolderCharset(char ** aCharacterSet)
{
NS_ENSURE_ARG_POINTER(aCharacterSet);
nsCOMPtr<nsIMsgFolder> folder;
nsresult rv = GetFolder(getter_AddRefs(folder));
// In cases where a file is not associated with a folder, for
// example standalone .eml files, failure is normal.
if (NS_FAILED(rv))
return rv;
nsCString tmpStr;
folder->GetCharset(tmpStr);
*aCharacterSet = ToNewCString(tmpStr);
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::GetFolderCharsetOverride(bool * aCharacterSetOverride)
{
nsCOMPtr<nsIMsgFolder> folder;
nsresult rv = GetFolder(getter_AddRefs(folder));
NS_ENSURE_SUCCESS(rv,rv);
NS_ENSURE_TRUE(folder, NS_ERROR_FAILURE);
folder->GetCharsetOverride(aCharacterSetOverride);
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::GetCharsetOverRide(char ** aCharacterSet)
{
if (!mCharsetOverride.IsEmpty())
*aCharacterSet = ToNewCString(mCharsetOverride);
else
*aCharacterSet = nullptr;
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::SetCharsetOverRide(const char * aCharacterSet)
{
mCharsetOverride = aCharacterSet;
return NS_OK;
}
/* void setMoveCopyMsgKeys (out nsMsgKey keysToFlag, in long numKeys); */
NS_IMETHODIMP nsMailboxUrl::SetMoveCopyMsgKeys(nsMsgKey *keysToFlag, int32_t numKeys)
{
m_keys.ReplaceElementsAt(0, m_keys.Length(), keysToFlag, numKeys);
if (!m_keys.IsEmpty() && m_messageKey == nsMsgKey_None)
m_messageKey = m_keys[0];
return NS_OK;
}
NS_IMETHODIMP nsMailboxUrl::GetMoveCopyMsgHdrForIndex(uint32_t msgIndex, nsIMsgDBHdr **msgHdr)
{
NS_ENSURE_ARG(msgHdr);
if (msgIndex < m_keys.Length())
{
nsMsgKey nextKey = m_keys[msgIndex];
return GetMsgHdrForKey(nextKey, msgHdr);
}
return NS_MSG_MESSAGE_NOT_FOUND;
}
NS_IMETHODIMP nsMailboxUrl::GetNumMoveCopyMsgs(uint32_t *numMsgs)
{
NS_ENSURE_ARG(numMsgs);
*numMsgs = m_keys.Length();
return NS_OK;
}

View file

@ -0,0 +1,110 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsMailboxUrl_h__
#define nsMailboxUrl_h__
#include "mozilla/Attributes.h"
#include "nsIMailboxUrl.h"
#include "nsMsgMailNewsUrl.h"
#include "nsIStreamListener.h"
#include "nsIFile.h"
#include "nsCOMPtr.h"
#include "MailNewsTypes.h"
#include "nsTArray.h"
class nsMailboxUrl : public nsIMailboxUrl, public nsMsgMailNewsUrl, public nsIMsgMessageUrl, public nsIMsgI18NUrl
{
public:
// nsIURI over-ride...
NS_IMETHOD SetSpec(const nsACString &aSpec) override;
NS_IMETHOD SetQuery(const nsACString &aQuery) override;
// from nsIMailboxUrl:
NS_IMETHOD SetMailboxParser(nsIStreamListener * aConsumer) override;
NS_IMETHOD GetMailboxParser(nsIStreamListener ** aConsumer) override;
NS_IMETHOD SetMailboxCopyHandler(nsIStreamListener * aConsumer) override;
NS_IMETHOD GetMailboxCopyHandler(nsIStreamListener ** aConsumer) override;
NS_IMETHOD GetMessageKey(nsMsgKey* aMessageKey) override;
NS_IMETHOD GetMessageSize(uint32_t *aMessageSize) override;
NS_IMETHOD SetMessageSize(uint32_t aMessageSize) override;
NS_IMETHOD GetMailboxAction(nsMailboxAction *result) override
{
NS_ENSURE_ARG_POINTER(result);
*result = m_mailboxAction;
return NS_OK;
}
NS_IMETHOD SetMailboxAction(nsMailboxAction aAction) override
{
m_mailboxAction = aAction;
return NS_OK;
}
NS_IMETHOD IsUrlType(uint32_t type, bool *isType) override;
NS_IMETHOD SetMoveCopyMsgKeys(nsMsgKey *keysToFlag, int32_t numKeys) override;
NS_IMETHOD GetMoveCopyMsgHdrForIndex(uint32_t msgIndex, nsIMsgDBHdr **msgHdr) override;
NS_IMETHOD GetNumMoveCopyMsgs(uint32_t *numMsgs) override;
NS_IMETHOD GetCurMoveCopyMsgIndex(uint32_t *result) override
{
NS_ENSURE_ARG_POINTER(result);
*result = m_curMsgIndex;
return NS_OK;
}
NS_IMETHOD SetCurMoveCopyMsgIndex(uint32_t aIndex) override
{
m_curMsgIndex = aIndex;
return NS_OK;
}
NS_IMETHOD GetFolder(nsIMsgFolder **msgFolder) override;
// nsIMsgMailNewsUrl override
NS_IMETHOD CloneInternal(uint32_t aRefHandlingMode,
const nsACString& newRef,
nsIURI **_retval) override;
// nsMailboxUrl
nsMailboxUrl();
NS_DECL_NSIMSGMESSAGEURL
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIMSGI18NURL
protected:
virtual ~nsMailboxUrl();
// protocol specific code to parse a url...
virtual nsresult ParseUrl();
nsresult GetMsgHdrForKey(nsMsgKey msgKey, nsIMsgDBHdr ** aMsgHdr);
// mailboxurl specific state
nsCOMPtr<nsIStreamListener> m_mailboxParser;
nsCOMPtr<nsIStreamListener> m_mailboxCopyHandler;
nsMailboxAction m_mailboxAction; // the action this url represents...parse mailbox, display messages, etc.
nsCOMPtr <nsIFile> m_filePath;
char *m_messageID;
uint32_t m_messageSize;
nsMsgKey m_messageKey;
nsCString m_file;
// This is currently only set when we're doing something with a .eml file.
// If that changes, we should change the name of this var.
nsCOMPtr<nsIMsgDBHdr> m_dummyHdr;
// used by save message to disk
nsCOMPtr<nsIFile> m_messageFile;
bool m_addDummyEnvelope;
bool m_canonicalLineEnding;
nsresult ParseSearchPart();
// for multiple msg move/copy
nsTArray<nsMsgKey> m_keys;
int32_t m_curMsgIndex;
// truncated message support
nsCString m_originalSpec;
nsCString mURI; // the RDF URI associated with this url.
nsCString mCharsetOverride; // used by nsIMsgI18NUrl...
};
#endif // nsMailboxUrl_h__

View file

@ -0,0 +1,178 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsMsgLocalCID.h"
#include "nsMsgFolderFlags.h"
#include "nsIMsgLocalMailFolder.h"
#include "nsIMovemailService.h"
#include "nsIFile.h"
#include "msgCore.h" // pre-compiled headers
#include "nsMovemailIncomingServer.h"
#include "nsServiceManagerUtils.h"
static NS_DEFINE_CID(kCMovemailServiceCID, NS_MOVEMAILSERVICE_CID);
NS_IMPL_ISUPPORTS_INHERITED(nsMovemailIncomingServer,
nsMsgIncomingServer,
nsIMovemailIncomingServer,
nsILocalMailIncomingServer)
nsMovemailIncomingServer::nsMovemailIncomingServer()
{
m_canHaveFilters = true;
}
nsMovemailIncomingServer::~nsMovemailIncomingServer()
{
}
NS_IMETHODIMP
nsMovemailIncomingServer::PerformBiff(nsIMsgWindow *aMsgWindow)
{
nsresult rv;
nsCOMPtr<nsIMovemailService> movemailService(do_GetService(
kCMovemailServiceCID, &rv));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIMsgFolder> inbox;
nsCOMPtr<nsIMsgFolder> rootMsgFolder;
nsCOMPtr<nsIUrlListener> urlListener;
rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
if(NS_SUCCEEDED(rv) && rootMsgFolder)
{
rootMsgFolder->GetFolderWithFlags(nsMsgFolderFlags::Inbox,
getter_AddRefs(inbox));
if (!inbox) return NS_ERROR_FAILURE;
}
SetPerformingBiff(true);
urlListener = do_QueryInterface(inbox);
bool downloadOnBiff = false;
rv = GetDownloadOnBiff(&downloadOnBiff);
if (downloadOnBiff)
{
nsCOMPtr <nsIMsgLocalMailFolder> localInbox = do_QueryInterface(inbox,
&rv);
if (localInbox && NS_SUCCEEDED(rv))
{
bool valid = false;
nsCOMPtr <nsIMsgDatabase> db;
rv = inbox->GetMsgDatabase(getter_AddRefs(db));
if (NS_SUCCEEDED(rv) && db)
{
rv = db->GetSummaryValid(&valid);
}
if (NS_SUCCEEDED(rv) && valid)
{
rv = movemailService->GetNewMail(aMsgWindow, urlListener, inbox,
this, nullptr);
}
else
{
bool isLocked;
inbox->GetLocked(&isLocked);
if (!isLocked)
{
rv = localInbox->ParseFolder(aMsgWindow, urlListener);
}
if (NS_SUCCEEDED(rv))
{
rv = localInbox->SetCheckForNewMessagesAfterParsing(true);
}
}
}
}
else
{
movemailService->CheckForNewMail(urlListener, inbox, this, nullptr);
}
return NS_OK;
}
NS_IMETHODIMP
nsMovemailIncomingServer::SetFlagsOnDefaultMailboxes()
{
nsCOMPtr<nsIMsgFolder> rootFolder;
nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgLocalMailFolder> localFolder =
do_QueryInterface(rootFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return localFolder->SetFlagsOnDefaultMailboxes(nsMsgFolderFlags::SpecialUse);
}
NS_IMETHODIMP nsMovemailIncomingServer::CreateDefaultMailboxes()
{
nsresult rv = CreateLocalFolder(NS_LITERAL_STRING("Inbox"));
NS_ENSURE_SUCCESS(rv, rv);
return CreateLocalFolder(NS_LITERAL_STRING("Trash"));
}
NS_IMETHODIMP
nsMovemailIncomingServer::GetNewMail(nsIMsgWindow *aMsgWindow,
nsIUrlListener *aUrlListener,
nsIMsgFolder *aMsgFolder,
nsIURI **aResult)
{
nsresult rv;
nsCOMPtr<nsIMovemailService> movemailService =
do_GetService(kCMovemailServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = movemailService->GetNewMail(aMsgWindow, aUrlListener,
aMsgFolder, this, aResult);
return rv;
}
NS_IMETHODIMP
nsMovemailIncomingServer::GetDownloadMessagesAtStartup(bool *getMessagesAtStartup)
{
NS_ENSURE_ARG_POINTER(getMessagesAtStartup);
*getMessagesAtStartup = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailIncomingServer::GetCanBeDefaultServer(bool *aCanBeDefaultServer)
{
NS_ENSURE_ARG_POINTER(aCanBeDefaultServer);
*aCanBeDefaultServer = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailIncomingServer::GetCanSearchMessages(bool *canSearchMessages)
{
NS_ENSURE_ARG_POINTER(canSearchMessages);
*canSearchMessages = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailIncomingServer::GetServerRequiresPasswordForBiff(bool *aServerRequiresPasswordForBiff)
{
NS_ENSURE_ARG_POINTER(aServerRequiresPasswordForBiff);
*aServerRequiresPasswordForBiff = false;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailIncomingServer::GetAccountManagerChrome(nsAString& aResult)
{
aResult.AssignLiteral("am-main.xul");
return NS_OK;
}

View file

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef __nsMovemailIncomingServer_h
#define __nsMovemailIncomingServer_h
#include "mozilla/Attributes.h"
#include "msgCore.h"
#include "nsIMovemailIncomingServer.h"
#include "nsILocalMailIncomingServer.h"
#include "nsMailboxServer.h"
/* get some implementation from nsMsgIncomingServer */
class nsMovemailIncomingServer : public nsMailboxServer,
public nsIMovemailIncomingServer,
public nsILocalMailIncomingServer
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIMOVEMAILINCOMINGSERVER
NS_DECL_NSILOCALMAILINCOMINGSERVER
nsMovemailIncomingServer();
NS_IMETHOD PerformBiff(nsIMsgWindow *aMsgWindow) override;
NS_IMETHOD GetDownloadMessagesAtStartup(bool *getMessages) override;
NS_IMETHOD GetCanBeDefaultServer(bool *canBeDefaultServer) override;
NS_IMETHOD GetCanSearchMessages(bool *canSearchMessages) override;
NS_IMETHOD GetServerRequiresPasswordForBiff(bool *aServerRequiresPasswordForBiff) override;
NS_IMETHOD GetAccountManagerChrome(nsAString& aResult) override;
private:
virtual ~nsMovemailIncomingServer();
};
#endif

View file

@ -0,0 +1,694 @@
/* -*- 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 <unistd.h> // for link(), used in spool-file locking
#include "prenv.h"
#include "private/pprio.h" // for our kernel-based locking
#include "nspr.h"
#include "msgCore.h" // precompiled header...
#include "nsMovemailService.h"
#include "nsIMovemailService.h"
#include "nsIMsgIncomingServer.h"
#include "nsIMovemailIncomingServer.h"
#include "nsIMsgProtocolInfo.h"
#include "nsParseMailbox.h"
#include "nsIMsgFolder.h"
#include "nsIPrompt.h"
#include "nsIFile.h"
#include "nsMailDirServiceDefs.h"
#include "nsMsgUtils.h"
#include "nsCOMPtr.h"
#include "nsMsgFolderFlags.h"
#include "nsILineInputStream.h"
#include "nsISeekableStream.h"
#include "nsNetUtil.h"
#include "nsAutoPtr.h"
#include "nsIStringBundle.h"
#include "nsIMsgPluggableStore.h"
#include "mozilla/Services.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "mozilla/Logging.h"
#if defined(PR_LOGGING)
//
// export NSPR_LOG_MODULES=Movemail:5
//
static PRLogModuleInfo *gMovemailLog = nullptr;
#define LOG(args) MOZ_LOG(gMovemailLog, mozilla::LogLevel::Debug, args)
#else
#define LOG(args)
#endif
#define PREF_MAIL_ROOT_MOVEMAIL "mail.root.movemail" // old - for backward compatibility only
#define PREF_MAIL_ROOT_MOVEMAIL_REL "mail.root.movemail-rel"
#define LOCK_SUFFIX ".lock"
#define MOZLOCK_SUFFIX ".mozlock"
const char * gDefaultSpoolPaths[] = {
"/var/spool/mail/",
"/usr/spool/mail/",
"/var/mail/",
"/usr/mail/"
};
#define NUM_DEFAULT_SPOOL_PATHS (sizeof(gDefaultSpoolPaths)/sizeof(gDefaultSpoolPaths[0]))
namespace {
class MOZ_STACK_CLASS SpoolLock
{
public:
/**
* Try to create a lock for the spool file while we operate on it.
*
* @param aSpoolName The path to the spool file.
* @param aSeconds The number of seconds to retry the locking.
* @param aMovemail The movemail service requesting the lock.
* @param aServer The nsIMsgIncomingServer requesting the lock.
*/
SpoolLock(nsACString *aSpoolPath, int aSeconds, nsMovemailService &aMovemail,
nsIMsgIncomingServer *aServer);
~SpoolLock();
bool isLocked();
private:
bool mLocked;
nsCString mSpoolName;
bool mUsingLockFile;
RefPtr<nsMovemailService> mOwningService;
nsCOMPtr<nsIMsgIncomingServer> mServer;
bool ObtainSpoolLock(unsigned int aSeconds);
bool YieldSpoolLock();
};
}
nsMovemailService::nsMovemailService()
{
#if defined(PR_LOGGING)
if (!gMovemailLog)
gMovemailLog = PR_NewLogModule("Movemail");
#endif
LOG(("nsMovemailService created: 0x%x\n", this));
}
nsMovemailService::~nsMovemailService()
{}
NS_IMPL_ISUPPORTS(nsMovemailService,
nsIMovemailService,
nsIMsgProtocolInfo)
NS_IMETHODIMP
nsMovemailService::CheckForNewMail(nsIUrlListener * aUrlListener,
nsIMsgFolder *inbox,
nsIMovemailIncomingServer *movemailServer,
nsIURI ** aURL)
{
nsresult rv = NS_OK;
LOG(("nsMovemailService::CheckForNewMail\n"));
return rv;
}
void
nsMovemailService::Error(const char* errorCode,
const char16_t **params,
uint32_t length)
{
if (!mMsgWindow) return;
nsCOMPtr<nsIPrompt> dialog;
nsresult rv = mMsgWindow->GetPromptDialog(getter_AddRefs(dialog));
if (NS_FAILED(rv))
return;
nsCOMPtr<nsIStringBundleService> bundleService =
mozilla::services::GetStringBundleService();
if (!bundleService)
return;
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle("chrome://messenger/locale/localMsgs.properties", getter_AddRefs(bundle));
if (NS_FAILED(rv))
return;
nsString errStr;
// Format the error string if necessary
if (params)
bundle->FormatStringFromName(NS_ConvertASCIItoUTF16(errorCode).get(),
params, length, getter_Copies(errStr));
else
bundle->GetStringFromName(NS_ConvertASCIItoUTF16(errorCode).get(),
getter_Copies(errStr));
if (!errStr.IsEmpty()) {
dialog->Alert(nullptr, errStr.get());
}
}
SpoolLock::SpoolLock(nsACString *aSpoolName, int aSeconds,
nsMovemailService &aMovemail,
nsIMsgIncomingServer *aServer)
: mLocked(false),
mSpoolName(*aSpoolName),
mOwningService(&aMovemail),
mServer(aServer)
{
if (!ObtainSpoolLock(aSeconds)) {
NS_ConvertUTF8toUTF16 lockFile(mSpoolName);
lockFile.AppendLiteral(LOCK_SUFFIX);
const char16_t* params[] = { lockFile.get() };
mOwningService->Error("movemailCantCreateLock", params, 1);
return;
}
mServer->SetServerBusy(true);
mLocked = true;
}
SpoolLock::~SpoolLock() {
if (mLocked && !YieldSpoolLock()) {
NS_ConvertUTF8toUTF16 lockFile(mSpoolName);
lockFile.AppendLiteral(LOCK_SUFFIX);
const char16_t* params[] = { lockFile.get() };
mOwningService->Error("movemailCantDeleteLock", params, 1);
}
mServer->SetServerBusy(false);
}
bool
SpoolLock::isLocked() {
return mLocked;
}
bool
SpoolLock::ObtainSpoolLock(unsigned int aSeconds /* number of seconds to retry */)
{
/*
* Locking procedures:
* If the directory is not writable, we want to use the appropriate system
* utilites to lock the file.
* If the directory is writable, we want to go through the create-and-link
* locking procedures to make it atomic for certain networked file systems.
* This involves creating a .mozlock file and attempting to hard-link it to
* the customary .lock file.
*/
nsCOMPtr<nsIFile> spoolFile;
nsresult rv = NS_NewNativeLocalFile(mSpoolName,
true,
getter_AddRefs(spoolFile));
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<nsIFile> directory;
rv = spoolFile->GetParent(getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, false);
rv = directory->IsWritable(&mUsingLockFile);
NS_ENSURE_SUCCESS(rv, false);
if (!mUsingLockFile) {
LOG(("Attempting to use kernel file lock"));
PRFileDesc *fd;
rv = spoolFile->OpenNSPRFileDesc(PR_RDWR, 0, &fd);
NS_ENSURE_SUCCESS(rv, false);
PRStatus lock_result;
unsigned int retry_count = 0;
do {
lock_result = PR_TLockFile(fd);
retry_count++;
LOG(("Attempt %d of %d to lock file", retry_count, aSeconds));
if (aSeconds > 0 && lock_result == PR_FAILURE) {
// pause 1sec, waiting for .lock to go away
PRIntervalTime sleepTime = 1000; // 1 second
PR_Sleep(sleepTime);
}
} while (lock_result == PR_FAILURE && retry_count < aSeconds);
LOG(("Lock result: %d", lock_result));
PR_Close(fd);
return lock_result == PR_SUCCESS;
}
// How to lock using files:
// step 1: create SPOOLNAME.mozlock
// 1a: can remove it if it already exists (probably crash-droppings)
// step 2: hard-link SPOOLNAME.mozlock to SPOOLNAME.lock for NFS atomicity
// 2a: if SPOOLNAME.lock is >60sec old then nuke it from orbit
// 2b: repeat step 2 until retry-count expired or hard-link succeeds
// step 3: remove SPOOLNAME.mozlock
// step 4: If step 2 hard-link failed, fail hard; we do not hold the lock
// DONE.
//
// (step 2a not yet implemented)
nsAutoCString mozlockstr(mSpoolName);
mozlockstr.AppendLiteral(MOZLOCK_SUFFIX);
nsAutoCString lockstr(mSpoolName);
lockstr.AppendLiteral(LOCK_SUFFIX);
// Create nsIFile for the spool.mozlock file
nsCOMPtr<nsIFile> tmplocfile;
rv = NS_NewNativeLocalFile(mozlockstr, true, getter_AddRefs(tmplocfile));
NS_ENSURE_SUCCESS(rv, false);
// THOUGHT: hmm, perhaps use MakeUnique to generate us a unique mozlock?
// ... perhaps not, MakeUnique implementation looks racey -- use mktemp()?
// step 1: create SPOOLNAME.mozlock
rv = tmplocfile->Create(nsIFile::NORMAL_FILE_TYPE, 0666);
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
// can't create our .mozlock file... game over already
LOG(("Failed to create file %s\n", mozlockstr.get()));
return false;
}
// step 2: hard-link .mozlock file to .lock file (this wackiness
// is necessary for non-racey locking on NFS-mounted spool dirs)
// n.b. XPCOM utilities don't support hard-linking yet, so we
// skip out to <unistd.h> and the POSIX interface for link()
int link_result = 0;
unsigned int retry_count = 0;
do {
link_result = link(mozlockstr.get(), lockstr.get());
retry_count++;
LOG(("Attempt %d of %d to create lock file", retry_count, aSeconds));
if (aSeconds > 0 && link_result == -1) {
// pause 1sec, waiting for .lock to go away
PRIntervalTime sleepTime = 1000; // 1 second
PR_Sleep(sleepTime);
}
} while (link_result == -1 && retry_count < aSeconds);
LOG(("Link result: %d", link_result));
// step 3: remove .mozlock file, in any case
rv = tmplocfile->Remove(false /* non-recursive */);
if (NS_FAILED(rv)) {
// Could not delete our .mozlock file... very unusual, but
// not fatal.
LOG(("Unable to delete %s", mozlockstr.get()));
}
// step 4: now we know whether we succeeded or failed
return link_result == 0;
}
/**
* Remove our mail-spool-file lock (n.b. we should only try this if
* we're the ones who made the lock in the first place! I.e. if mLocked is true.)
*/
bool
SpoolLock::YieldSpoolLock()
{
LOG(("YieldSpoolLock(%s)", mSpoolName.get()));
if (!mUsingLockFile) {
nsCOMPtr<nsIFile> spoolFile;
nsresult rv = NS_NewNativeLocalFile(mSpoolName,
true,
getter_AddRefs(spoolFile));
NS_ENSURE_SUCCESS(rv, false);
PRFileDesc *fd;
rv = spoolFile->OpenNSPRFileDesc(PR_RDWR, 0, &fd);
NS_ENSURE_SUCCESS(rv, false);
bool unlockSucceeded = PR_UnlockFile(fd) == PR_SUCCESS;
PR_Close(fd);
if (unlockSucceeded)
LOG(("YieldSpoolLock was successful."));
return unlockSucceeded;
}
nsAutoCString lockstr(mSpoolName);
lockstr.AppendLiteral(LOCK_SUFFIX);
nsresult rv;
// Create nsIFile for the spool.lock file
nsCOMPtr<nsIFile> locklocfile;
rv = NS_NewNativeLocalFile(lockstr, true, getter_AddRefs(locklocfile));
NS_ENSURE_SUCCESS(rv, false);
// Check if the lock file exists
bool exists;
rv = locklocfile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, false);
// Delete the file if it exists
if (exists) {
rv = locklocfile->Remove(false /* non-recursive */);
NS_ENSURE_SUCCESS(rv, false);
}
LOG(("YieldSpoolLock was successful."));
// Success.
return true;
}
static nsresult
LocateSpoolFile(nsACString & spoolPath)
{
bool isFile;
nsresult rv;
nsCOMPtr<nsIFile> spoolFile;
rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(spoolFile));
NS_ENSURE_SUCCESS(rv, rv);
char * mailEnv = PR_GetEnv("MAIL");
char * userEnv = PR_GetEnv("USER");
if (!userEnv)
userEnv = PR_GetEnv("USERNAME");
if (mailEnv) {
rv = spoolFile->InitWithNativePath(nsDependentCString(mailEnv));
NS_ENSURE_SUCCESS(rv, rv);
rv = spoolFile->IsFile(&isFile);
if (NS_SUCCEEDED(rv) && isFile)
spoolPath = mailEnv;
}
else if (userEnv) {
// Try to build the mailbox path from the username and a number
// of guessed spool directory paths.
nsAutoCString tmpPath;
uint32_t i;
for (i = 0; i < NUM_DEFAULT_SPOOL_PATHS; i++) {
tmpPath = gDefaultSpoolPaths[i];
tmpPath += userEnv;
rv = spoolFile->InitWithNativePath(tmpPath);
NS_ENSURE_SUCCESS(rv, rv);
rv = spoolFile->IsFile(&isFile);
if (NS_SUCCEEDED(rv) && isFile) {
spoolPath = tmpPath;
break;
}
}
}
return rv;
}
nsresult
nsMovemailService::GetNewMail(nsIMsgWindow *aMsgWindow,
nsIUrlListener* /* aUrlListener */,
nsIMsgFolder* /* aMsgFolder */,
nsIMovemailIncomingServer *aMovemailServer,
nsIURI ** /* aURL */)
{
LOG(("nsMovemailService::GetNewMail"));
NS_ENSURE_ARG_POINTER(aMovemailServer);
// It is OK if aMsgWindow is null.
mMsgWindow = aMsgWindow;
nsresult rv;
nsCOMPtr<nsIMsgIncomingServer> in_server =
do_QueryInterface(aMovemailServer, &rv);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && in_server,
NS_MSG_INVALID_OR_MISSING_SERVER);
// Attempt to locate the mail spool file
nsAutoCString spoolPath;
rv = in_server->GetCharValue("spoolDir", spoolPath);
if (NS_FAILED(rv) || spoolPath.IsEmpty())
rv = LocateSpoolFile(spoolPath);
if (NS_FAILED(rv) || spoolPath.IsEmpty()) {
Error("movemailSpoolFileNotFound", nullptr, 0);
return NS_ERROR_FAILURE;
}
NS_ConvertUTF8toUTF16 wideSpoolPath(spoolPath);
const char16_t* spoolPathString[] = { wideSpoolPath.get() };
// Create an input stream for the spool file
nsCOMPtr<nsIFile> spoolFile;
rv = NS_NewNativeLocalFile(spoolPath, true, getter_AddRefs(spoolFile));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInputStream> spoolInputStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(spoolInputStream), spoolFile);
if (NS_FAILED(rv)) {
Error("movemailCantOpenSpoolFile", spoolPathString, 1);
return rv;
}
// Get a line input interface for the spool file
nsCOMPtr<nsILineInputStream> lineInputStream =
do_QueryInterface(spoolInputStream, &rv);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && lineInputStream, rv);
nsCOMPtr<nsIMsgFolder> serverFolder;
nsCOMPtr<nsIMsgFolder> inbox;
rv = in_server->GetRootFolder(getter_AddRefs(serverFolder));
NS_ENSURE_SUCCESS(rv, rv);
rv = serverFolder->GetFolderWithFlags(nsMsgFolderFlags::Inbox,
getter_AddRefs(inbox));
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && inbox, rv);
nsCOMPtr<nsIMsgPluggableStore> msgStore;
rv = in_server->GetMsgStore(getter_AddRefs(msgStore));
NS_ENSURE_SUCCESS(rv, rv);
// create a new mail parser
RefPtr<nsParseNewMailState> newMailParser = new nsParseNewMailState;
// Try and obtain the lock for the spool file.
SpoolLock lock(&spoolPath, 5, *this, in_server);
if (!lock.isLocked())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIMsgDBHdr> newHdr;
nsCOMPtr<nsIOutputStream> outputStream;
// MIDDLE of the FUN : consume the mailbox data.
bool isMore = true;
nsAutoCString buffer;
uint32_t bytesWritten = 0;
while (isMore &&
NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore)))
{
// If first string is empty and we're now at EOF then abort parsing.
if (buffer.IsEmpty() && !isMore && !bytesWritten) {
LOG(("Empty spool file"));
break;
}
buffer.AppendLiteral(MSG_LINEBREAK);
if (isMore && StringBeginsWith(buffer, NS_LITERAL_CSTRING("From "))) {
// Finish previous header and message, if any.
if (newHdr) {
outputStream->Flush();
newMailParser->PublishMsgHeader(nullptr);
rv = msgStore->FinishNewMessage(outputStream, newHdr);
NS_ENSURE_SUCCESS(rv, rv);
newMailParser->Clear();
}
bool reusable;
rv = msgStore->GetNewMsgOutputStream(inbox, getter_AddRefs(newHdr),
&reusable, getter_AddRefs(outputStream));
NS_ENSURE_SUCCESS(rv, rv);
rv = newMailParser->Init(serverFolder, inbox,
nullptr, newHdr, outputStream);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!outputStream) {
// If we do not have outputStream here, something bad happened.
// We probably didn't find the proper message start delimiter "From "
// and are now reading in the middle of a message. Bail out.
Error("movemailCantParseSpool", spoolPathString, 1);
return NS_ERROR_UNEXPECTED;
}
newMailParser->HandleLine(buffer.BeginWriting(), buffer.Length());
rv = outputStream->Write(buffer.get(), buffer.Length(), &bytesWritten);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && (bytesWritten == buffer.Length()),
NS_ERROR_FAILURE);
// "From " lines delimit messages, start a new one here.
if (isMore && StringBeginsWith(buffer, NS_LITERAL_CSTRING("From "))) {
buffer.AssignLiteral("X-Mozilla-Status: 8000" MSG_LINEBREAK);
newMailParser->HandleLine(buffer.BeginWriting(), buffer.Length());
rv = outputStream->Write(buffer.get(), buffer.Length(), &bytesWritten);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && (bytesWritten == buffer.Length()),
NS_ERROR_FAILURE);
buffer.AssignLiteral("X-Mozilla-Status2: 00000000" MSG_LINEBREAK);
newMailParser->HandleLine(buffer.BeginWriting(), buffer.Length());
rv = outputStream->Write(buffer.get(), buffer.Length(), &bytesWritten);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && (bytesWritten == buffer.Length()),
NS_ERROR_FAILURE);
}
}
if (outputStream) {
outputStream->Flush();
newMailParser->PublishMsgHeader(nullptr);
newMailParser->OnStopRequest(nullptr, nullptr, NS_OK);
rv = msgStore->FinishNewMessage(outputStream, newHdr);
NS_ENSURE_SUCCESS(rv, rv);
outputStream->Close();
}
// Truncate the spool file as we parsed it successfully.
rv = spoolFile->SetFileSize(0);
if (NS_FAILED(rv)) {
Error("movemailCantTruncateSpoolFile", spoolPathString, 1);
}
LOG(("GetNewMail returning rv=%d", rv));
return rv;
}
NS_IMETHODIMP
nsMovemailService::SetDefaultLocalPath(nsIFile *aPath)
{
NS_ENSURE_ARG(aPath);
return NS_SetPersistentFile(PREF_MAIL_ROOT_MOVEMAIL_REL, PREF_MAIL_ROOT_MOVEMAIL, aPath);
}
NS_IMETHODIMP
nsMovemailService::GetDefaultLocalPath(nsIFile ** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = nullptr;
nsresult rv;
bool havePref;
nsCOMPtr<nsIFile> localFile;
rv = NS_GetPersistentFile(PREF_MAIL_ROOT_MOVEMAIL_REL,
PREF_MAIL_ROOT_MOVEMAIL,
NS_APP_MAIL_50_DIR,
havePref,
getter_AddRefs(localFile));
if (NS_FAILED(rv)) return rv;
bool exists;
rv = localFile->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists)
rv = localFile->Create(nsIFile::DIRECTORY_TYPE, 0775);
if (NS_FAILED(rv)) return rv;
if (!havePref || !exists) {
rv = NS_SetPersistentFile(PREF_MAIL_ROOT_MOVEMAIL_REL, PREF_MAIL_ROOT_MOVEMAIL, localFile);
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set root dir pref.");
}
NS_IF_ADDREF(*aResult = localFile);
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetServerIID(nsIID* *aServerIID)
{
*aServerIID = new nsIID(NS_GET_IID(nsIMovemailIncomingServer));
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetRequiresUsername(bool *aRequiresUsername)
{
NS_ENSURE_ARG_POINTER(aRequiresUsername);
*aRequiresUsername = false;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetPreflightPrettyNameWithEmailAddress(bool *aPreflightPrettyNameWithEmailAddress)
{
NS_ENSURE_ARG_POINTER(aPreflightPrettyNameWithEmailAddress);
*aPreflightPrettyNameWithEmailAddress = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetCanLoginAtStartUp(bool *aCanLoginAtStartUp)
{
NS_ENSURE_ARG_POINTER(aCanLoginAtStartUp);
*aCanLoginAtStartUp = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetCanDelete(bool *aCanDelete)
{
NS_ENSURE_ARG_POINTER(aCanDelete);
*aCanDelete = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetCanGetMessages(bool *aCanGetMessages)
{
NS_ENSURE_ARG_POINTER(aCanGetMessages);
*aCanGetMessages = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetCanGetIncomingMessages(bool *aCanGetIncomingMessages)
{
NS_ENSURE_ARG_POINTER(aCanGetIncomingMessages);
*aCanGetIncomingMessages = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetCanDuplicate(bool *aCanDuplicate)
{
NS_ENSURE_ARG_POINTER(aCanDuplicate);
*aCanDuplicate = false;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetDefaultDoBiff(bool *aDoBiff)
{
NS_ENSURE_ARG_POINTER(aDoBiff);
// by default, do biff for movemail
*aDoBiff = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetDefaultServerPort(bool isSecure, int32_t *aDefaultPort)
{
NS_ENSURE_ARG_POINTER(aDefaultPort);
*aDefaultPort = -1;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetShowComposeMsgLink(bool *showComposeMsgLink)
{
NS_ENSURE_ARG_POINTER(showComposeMsgLink);
*showComposeMsgLink = true;
return NS_OK;
}
NS_IMETHODIMP
nsMovemailService::GetFoldersCreatedAsync(bool *aAsyncCreation)
{
NS_ENSURE_ARG_POINTER(aAsyncCreation);
*aAsyncCreation = false;
return NS_OK;
}

View file

@ -0,0 +1,32 @@
/* -*- 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/. */
#ifndef nsMovemailService_h___
#define nsMovemailService_h___
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsIMovemailService.h"
#include "nsIMsgProtocolInfo.h"
#include "nsIMsgWindow.h"
class nsMovemailService : public nsIMsgProtocolInfo, public nsIMovemailService
{
public:
nsMovemailService();
NS_DECL_ISUPPORTS
NS_DECL_NSIMOVEMAILSERVICE
NS_DECL_NSIMSGPROTOCOLINFO
void Error(const char* errorCode, const char16_t **params, uint32_t length);
private:
virtual ~nsMovemailService();
nsCOMPtr<nsIMsgWindow> mMsgWindow;
};
#endif /* nsMovemailService_h___ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
/* -*- 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/. */
/**
Class for handling Berkeley Mailbox stores.
*/
#ifndef nsMsgBrkMboxStore_h__
#define nsMsgBrkMboxStore_h__
#include "nsMsgLocalStoreUtils.h"
#include "nsIFile.h"
#include "nsInterfaceHashtable.h"
#include "nsISeekableStream.h"
class nsMsgBrkMBoxStore final : public nsMsgLocalStoreUtils, nsIMsgPluggableStore
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGPLUGGABLESTORE
nsMsgBrkMBoxStore();
private:
~nsMsgBrkMBoxStore();
protected:
nsresult AddSubFolders(nsIMsgFolder *parent, nsCOMPtr<nsIFile> &path, bool deep);
nsresult CreateDirectoryForFolder(nsIFile *path);
nsresult GetOutputStream(nsIArray *aHdrArray,
nsCOMPtr<nsIOutputStream> &outputStream,
nsCOMPtr<nsISeekableStream> &seekableStream,
int64_t &restorePos);
void GetMailboxModProperties(nsIMsgFolder *aFolder,
int64_t *aSize, uint32_t *aDate);
void SetDBValid(nsIMsgDBHdr *aHdr);
// We don't want to keep re-opening an output stream when downloading
// multiple pop3 messages, or adjusting x-mozilla-status headers, so
// we cache output streams based on folder uri's. If the caller has closed
// the stream, we'll get a new one.
nsInterfaceHashtable<nsCStringHashKey, nsIOutputStream> m_outputStreams;
#ifdef _DEBUG
nsCOMPtr<nsIMsgFolder> m_streamOutstandingFolder;
#endif
};
#endif

View file

@ -0,0 +1,345 @@
/* -*- 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" // precompiled header...
#include "nsMsgLocalStoreUtils.h"
#include "nsIFile.h"
#include "nsIDBFolderInfo.h"
#include "nsIMsgDatabase.h"
#include "prprf.h"
#define EXTRA_SAFETY_SPACE 0x400000 // (4MiB)
nsMsgLocalStoreUtils::nsMsgLocalStoreUtils()
{
}
nsresult
nsMsgLocalStoreUtils::AddDirectorySeparator(nsIFile *path)
{
nsAutoString leafName;
path->GetLeafName(leafName);
leafName.AppendLiteral(FOLDER_SUFFIX);
return path->SetLeafName(leafName);
}
bool
nsMsgLocalStoreUtils::nsShouldIgnoreFile(nsAString& name)
{
char16_t firstChar = name.First();
if (firstChar == '.' || firstChar == '#' ||
name.CharAt(name.Length() - 1) == '~')
return true;
if (name.LowerCaseEqualsLiteral("msgfilterrules.dat") ||
name.LowerCaseEqualsLiteral("rules.dat") ||
name.LowerCaseEqualsLiteral("filterlog.html") ||
name.LowerCaseEqualsLiteral("junklog.html") ||
name.LowerCaseEqualsLiteral("rulesbackup.dat"))
return true;
// don't add summary files to the list of folders;
// don't add popstate files to the list either, or rules (sort.dat).
if (StringEndsWith(name, NS_LITERAL_STRING(".snm")) ||
name.LowerCaseEqualsLiteral("popstate.dat") ||
name.LowerCaseEqualsLiteral("sort.dat") ||
name.LowerCaseEqualsLiteral("mailfilt.log") ||
name.LowerCaseEqualsLiteral("filters.js") ||
StringEndsWith(name, NS_LITERAL_STRING(".toc")))
return true;
// ignore RSS data source files
if (name.LowerCaseEqualsLiteral("feeds.rdf") ||
name.LowerCaseEqualsLiteral("feeditems.rdf") ||
StringBeginsWith(name, NS_LITERAL_STRING("feeditems_error")))
return true;
// The .mozmsgs dir is for spotlight support
return (StringEndsWith(name, NS_LITERAL_STRING(".mozmsgs")) ||
StringEndsWith(name, NS_LITERAL_STRING(".sbd")) ||
StringEndsWith(name, NS_LITERAL_STRING(SUMMARY_SUFFIX)));
}
/**
* We're passed a stream positioned at the start of the message.
* We start reading lines, looking for x-mozilla-keys: headers; If we're
* adding the keyword and we find a header with the desired keyword already
* in it, we don't need to do anything. Likewise, if removing keyword and we
* don't find it,we don't need to do anything. Otherwise, if adding, we need
* to see if there's an x-mozilla-keys header with room for the new keyword.
* If so, we replace the corresponding number of spaces with the keyword.
* If no room, we can't do anything until the folder is compacted and another
* x-mozilla-keys header is added. In that case, we set a property
* on the header, which the compaction code will check.
* This is not true for maildir, however, since it won't require compaction.
*/
void
nsMsgLocalStoreUtils::ChangeKeywordsHelper(nsIMsgDBHdr *message,
uint64_t desiredOffset,
nsLineBuffer<char> *lineBuffer,
nsTArray<nsCString> &keywordArray,
bool aAdd,
nsIOutputStream *outputStream,
nsISeekableStream *seekableStream,
nsIInputStream *inputStream)
{
uint32_t bytesWritten;
for (uint32_t i = 0; i < keywordArray.Length(); i++)
{
nsAutoCString header;
nsAutoCString keywords;
bool done = false;
uint32_t len = 0;
nsAutoCString keywordToWrite(" ");
keywordToWrite.Append(keywordArray[i]);
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, desiredOffset);
// need to reset lineBuffer, which is cheaper than creating a new one.
lineBuffer->start = lineBuffer->end = lineBuffer->buf;
bool inKeywordHeader = false;
bool foundKeyword = false;
int64_t offsetToAddKeyword = 0;
bool more;
message->GetMessageSize(&len);
// loop through
while (!done)
{
int64_t lineStartPos;
seekableStream->Tell(&lineStartPos);
// we need to adjust the linestart pos by how much extra the line
// buffer has read from the stream.
lineStartPos -= (lineBuffer->end - lineBuffer->start);
// NS_ReadLine doesn't return line termination chars.
nsCString keywordHeaders;
nsresult rv = NS_ReadLine(inputStream, lineBuffer, keywordHeaders, &more);
if (NS_SUCCEEDED(rv))
{
if (keywordHeaders.IsEmpty())
break; // passed headers; no x-mozilla-keywords header; give up.
if (StringBeginsWith(keywordHeaders,
NS_LITERAL_CSTRING(HEADER_X_MOZILLA_KEYWORDS)))
inKeywordHeader = true;
else if (inKeywordHeader && (keywordHeaders.CharAt(0) == ' ' ||
keywordHeaders.CharAt(0) == '\t'))
; // continuation header line
else if (inKeywordHeader)
break;
else
continue;
uint32_t keywordHdrLength = keywordHeaders.Length();
int32_t startOffset, keywordLength;
// check if we have the keyword
if (MsgFindKeyword(keywordArray[i], keywordHeaders, &startOffset,
&keywordLength))
{
foundKeyword = true;
if (!aAdd) // if we're removing, remove it, and break;
{
keywordHeaders.Cut(startOffset, keywordLength);
for (int32_t j = keywordLength; j > 0; j--)
keywordHeaders.Append(' ');
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, lineStartPos);
outputStream->Write(keywordHeaders.get(), keywordHeaders.Length(),
&bytesWritten);
}
offsetToAddKeyword = 0;
// if adding and we already have the keyword, done
done = true;
break;
}
// argh, we need to check all the lines to see if we already have the
// keyword, but if we don't find it, we want to remember the line and
// position where we have room to add the keyword.
if (aAdd)
{
nsAutoCString curKeywordHdr(keywordHeaders);
// strip off line ending spaces.
curKeywordHdr.Trim(" ", false, true);
if (!offsetToAddKeyword && curKeywordHdr.Length() +
keywordToWrite.Length() < keywordHdrLength)
offsetToAddKeyword = lineStartPos + curKeywordHdr.Length();
}
}
}
if (aAdd && !foundKeyword)
{
if (!offsetToAddKeyword)
message->SetUint32Property("growKeywords", 1);
else
{
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET,
offsetToAddKeyword);
outputStream->Write(keywordToWrite.get(), keywordToWrite.Length(),
&bytesWritten);
}
}
}
}
nsresult
nsMsgLocalStoreUtils::UpdateFolderFlag(nsIMsgDBHdr *mailHdr, bool bSet,
nsMsgMessageFlagType flag,
nsIOutputStream *fileStream)
{
uint32_t statusOffset;
uint64_t msgOffset;
nsresult rv = mailHdr->GetStatusOffset(&statusOffset);
// This probably means there's no x-mozilla-status header, so
// we just ignore this.
if (NS_FAILED(rv) || (statusOffset == 0))
return NS_OK;
rv = mailHdr->GetMessageOffset(&msgOffset);
NS_ENSURE_SUCCESS(rv, rv);
uint64_t statusPos = msgOffset + statusOffset;
nsCOMPtr<nsISeekableStream> seekableStream(do_QueryInterface(fileStream, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, statusPos);
NS_ENSURE_SUCCESS(rv, rv);
char buf[50];
buf[0] = '\0';
nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(fileStream, &rv);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t bytesRead;
if (NS_SUCCEEDED(inputStream->Read(buf, X_MOZILLA_STATUS_LEN + 6,
&bytesRead)))
{
buf[bytesRead] = '\0';
if (strncmp(buf, X_MOZILLA_STATUS, X_MOZILLA_STATUS_LEN) == 0 &&
strncmp(buf + X_MOZILLA_STATUS_LEN, ": ", 2) == 0 &&
strlen(buf) >= X_MOZILLA_STATUS_LEN + 6)
{
uint32_t flags;
uint32_t bytesWritten;
(void)mailHdr->GetFlags(&flags);
if (!(flags & nsMsgMessageFlags::Expunged))
{
char *p = buf + X_MOZILLA_STATUS_LEN + 2;
nsresult errorCode = NS_OK;
flags = nsDependentCString(p).ToInteger(&errorCode, 16);
uint32_t curFlags;
(void)mailHdr->GetFlags(&curFlags);
flags = (flags & nsMsgMessageFlags::Queued) |
(curFlags & ~nsMsgMessageFlags::RuntimeOnly);
if (bSet)
flags |= flag;
else
flags &= ~flag;
}
else
{
flags &= ~nsMsgMessageFlags::RuntimeOnly;
}
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, statusPos);
// We are filing out x-mozilla-status flags here
PR_snprintf(buf, sizeof(buf), X_MOZILLA_STATUS_FORMAT,
flags & 0x0000FFFF);
int32_t lineLen = PL_strlen(buf);
uint64_t status2Pos = statusPos + lineLen;
fileStream->Write(buf, lineLen, &bytesWritten);
if (flag & 0xFFFF0000)
{
// Time to update x-mozilla-status2,
// first find it by finding end of previous line, see bug 234935.
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, status2Pos);
do
{
rv = inputStream->Read(buf, 1, &bytesRead);
status2Pos++;
} while (NS_SUCCEEDED(rv) && (*buf == '\n' || *buf == '\r'));
status2Pos--;
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, status2Pos);
if (NS_SUCCEEDED(inputStream->Read(buf, X_MOZILLA_STATUS2_LEN + 10,
&bytesRead)))
{
if (strncmp(buf, X_MOZILLA_STATUS2, X_MOZILLA_STATUS2_LEN) == 0 &&
strncmp(buf + X_MOZILLA_STATUS2_LEN, ": ", 2) == 0 &&
strlen(buf) >= X_MOZILLA_STATUS2_LEN + 10)
{
uint32_t dbFlags;
(void)mailHdr->GetFlags(&dbFlags);
dbFlags &= 0xFFFF0000;
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, status2Pos);
PR_snprintf(buf, sizeof(buf), X_MOZILLA_STATUS2_FORMAT, dbFlags);
fileStream->Write(buf, PL_strlen(buf), &bytesWritten);
}
}
}
}
else
{
#ifdef DEBUG
printf("Didn't find %s where expected at position %ld\n"
"instead, found %s.\n",
X_MOZILLA_STATUS, (long) statusPos, buf);
#endif
rv = NS_ERROR_FAILURE;
}
}
else
rv = NS_ERROR_FAILURE;
return rv;
}
/**
* Returns true if there is enough space on disk.
*
* @param aFile Any file in the message store that is on a logical
* disk volume so that it can be queried for disk space.
* @param aSpaceRequested The size of free space there must be on the disk
* to return true.
*/
bool
nsMsgLocalStoreUtils::DiskSpaceAvailableInStore(nsIFile *aFile, uint64_t aSpaceRequested)
{
int64_t diskFree;
nsresult rv = aFile->GetDiskSpaceAvailable(&diskFree);
if (NS_SUCCEEDED(rv)) {
#ifdef DEBUG
printf("GetDiskSpaceAvailable returned: %lld bytes\n", (long long)diskFree);
#endif
// When checking for disk space available, take into consideration
// possible database changes, therefore ask for a little more
// (EXTRA_SAFETY_SPACE) than what the requested size is. Also, due to disk
// sector sizes, allocation blocks, etc. The space "available" may be greater
// than the actual space usable.
return ((aSpaceRequested + EXTRA_SAFETY_SPACE) < (uint64_t) diskFree);
} else if (rv == NS_ERROR_NOT_IMPLEMENTED) {
// The call to GetDiskSpaceAvailable is not implemented!
// This will happen on certain platforms where GetDiskSpaceAvailable
// is not implemented. Since people on those platforms still need
// to download mail, we will simply bypass the disk-space check.
//
// We'll leave a debug message to warn people.
#ifdef DEBUG
printf("Call to GetDiskSpaceAvailable FAILED because it is not implemented!\n");
#endif
return true;
} else {
printf("Call to GetDiskSpaceAvailable FAILED!\n");
return false;
}
}
/**
* Resets forceReparse in the database.
*
* @param aMsgDb The database to reset.
*/
void
nsMsgLocalStoreUtils::ResetForceReparse(nsIMsgDatabase *aMsgDB)
{
if (aMsgDB)
{
nsCOMPtr<nsIDBFolderInfo> folderInfo;
aMsgDB->GetDBFolderInfo(getter_AddRefs(folderInfo));
if (folderInfo)
folderInfo->SetBooleanProperty("forceReparse", false);
}
}

View file

@ -0,0 +1,49 @@
/* -*- 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/. */
#ifndef nsMsgLocalStoreUtils_h__
#define nsMsgLocalStoreUtils_h__
#include "msgCore.h"
#include "nsIMsgPluggableStore.h"
#include "nsStringGlue.h"
#include "nsReadLine.h"
#include "nsISeekableStream.h"
#include "nsIMsgHdr.h"
#include "nsMsgLocalFolderHdrs.h"
#include "nsMailHeaders.h"
#include "nsMsgUtils.h"
#include "nsIOutputStream.h"
#include "nsMsgMessageFlags.h"
/**
* Utility Class for handling local mail stores. Berkeley Mailbox
* and MailDir stores inherit from this class to share some code.
*/
class nsMsgLocalStoreUtils
{
public:
nsMsgLocalStoreUtils();
static nsresult AddDirectorySeparator(nsIFile *path);
static bool nsShouldIgnoreFile(nsAString& name);
static void ChangeKeywordsHelper(nsIMsgDBHdr *message,
uint64_t desiredOffset,
nsLineBuffer<char> *lineBuffer,
nsTArray<nsCString> &keywordArray,
bool aAdd,
nsIOutputStream *outputStream,
nsISeekableStream *seekableStream,
nsIInputStream *inputStream);
static void ResetForceReparse(nsIMsgDatabase *aMsgDB);
nsresult UpdateFolderFlag(nsIMsgDBHdr *mailHdr, bool bSet,
nsMsgMessageFlagType flag,
nsIOutputStream *fileStream);
bool DiskSpaceAvailableInStore(nsIFile *aFile,
uint64_t aSpaceRequested);
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,38 @@
/* -*- 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/. */
/**
Class for handling Maildir stores.
*/
#ifndef nsMsgMaildirStore_h__
#define nsMsgMaildirStore_h__
#include "nsMsgLocalStoreUtils.h"
#include "nsIFile.h"
#include "nsMsgMessageFlags.h"
class nsMsgMaildirStore final : public nsMsgLocalStoreUtils, nsIMsgPluggableStore
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGPLUGGABLESTORE
nsMsgMaildirStore();
private:
~nsMsgMaildirStore();
protected:
nsresult GetDirectoryForFolder(nsIFile *path);
nsresult CreateDirectoryForFolder(nsIFile *path, bool aIsServer);
nsresult CreateMaildir(nsIFile *path);
nsresult AddSubFolders(nsIMsgFolder *parent, nsIFile *path, bool deep);
nsresult GetOutputStream(nsIMsgDBHdr *aHdr,
nsCOMPtr<nsIOutputStream> &aOutputStream);
};
#endif

View file

@ -0,0 +1,206 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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" // pre-compiled headers
#include "prmem.h"
#include "plstr.h"
#include "prprf.h"
#include "nsNoIncomingServer.h"
#include "nsMsgLocalCID.h"
#include "nsMsgFolderFlags.h"
#include "nsIMsgLocalMailFolder.h"
#include "nsIMsgMailSession.h"
#include "nsMsgBaseCID.h"
#include "nsIMsgAccountManager.h"
#include "nsIPop3IncomingServer.h"
#include "nsServiceManagerUtils.h"
#include "nsMsgUtils.h"
NS_IMPL_ISUPPORTS_INHERITED(nsNoIncomingServer,
nsMsgIncomingServer,
nsINoIncomingServer,
nsILocalMailIncomingServer)
nsNoIncomingServer::nsNoIncomingServer()
{
}
nsNoIncomingServer::~nsNoIncomingServer()
{
}
NS_IMETHODIMP
nsNoIncomingServer::GetLocalStoreType(nsACString& type)
{
type.AssignLiteral("mailbox");
return NS_OK;
}
NS_IMETHODIMP
nsNoIncomingServer::GetLocalDatabaseType(nsACString& type)
{
type.AssignLiteral("mailbox");
return NS_OK;
}
NS_IMETHODIMP
nsNoIncomingServer::GetAccountManagerChrome(nsAString& aResult)
{
aResult.AssignLiteral("am-serverwithnoidentities.xul");
return NS_OK;
}
NS_IMETHODIMP
nsNoIncomingServer::SetFlagsOnDefaultMailboxes()
{
nsCOMPtr<nsIMsgFolder> rootFolder;
nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgLocalMailFolder> localFolder =
do_QueryInterface(rootFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// None server may have an inbox if it's deferred to,
// or if it's the smart mailboxes account.
localFolder->SetFlagsOnDefaultMailboxes(nsMsgFolderFlags::SpecialUse);
return NS_OK;
}
// TODO: make this work with maildir message store, bug 890742.
NS_IMETHODIMP nsNoIncomingServer::CopyDefaultMessages(const char *folderNameOnDisk)
{
NS_ENSURE_ARG(folderNameOnDisk);
nsresult rv;
nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Get defaults directory for messenger files. MailSession service appends 'messenger' to the
// the app defaults folder and returns it. Locale will be added to the path, if there is one.
nsCOMPtr<nsIFile> defaultMessagesFile;
rv = mailSession->GetDataFilesDir("messenger", getter_AddRefs(defaultMessagesFile));
NS_ENSURE_SUCCESS(rv, rv);
// check if bin/defaults/messenger/<folderNameOnDisk>
// (or bin/defaults/messenger/<locale>/<folderNameOnDisk> if we had a locale provide) exists.
// it doesn't have to exist. if it doesn't, return
rv = defaultMessagesFile->AppendNative(nsDependentCString(folderNameOnDisk));
NS_ENSURE_SUCCESS(rv, rv);
bool exists;
rv = defaultMessagesFile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (!exists)
return NS_OK;
nsCOMPtr<nsIFile> parentDir;
rv = GetLocalPath(getter_AddRefs(parentDir));
NS_ENSURE_SUCCESS(rv, rv);
// check if parentDir/<folderNameOnDisk> exists
{
nsCOMPtr<nsIFile> testDir;
rv = parentDir->Clone(getter_AddRefs(testDir));
NS_ENSURE_SUCCESS(rv, rv);
rv = testDir->AppendNative(nsDependentCString(folderNameOnDisk));
NS_ENSURE_SUCCESS(rv, rv);
rv = testDir->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
}
// if it exists add to the end, else copy
if (exists)
{
#ifdef DEBUG
printf("append default %s (unimplemented)\n", folderNameOnDisk);
#endif
// todo for bug #1181 (the bug ID seems wrong...)
// open folderFile, seek to end
// read defaultMessagesFile, write to folderFile
}
else {
#ifdef DEBUG
printf("copy default %s\n",folderNameOnDisk);
#endif
rv = defaultMessagesFile->CopyTo(parentDir, EmptyString());
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
NS_IMETHODIMP nsNoIncomingServer::CreateDefaultMailboxes()
{
nsresult rv;
bool isHidden = false;
GetHidden(&isHidden);
if (isHidden)
return NS_OK;
// notice, no Inbox, unless we're deferred to...
bool isDeferredTo;
if (NS_SUCCEEDED(GetIsDeferredTo(&isDeferredTo)) && isDeferredTo)
{
rv = CreateLocalFolder(NS_LITERAL_STRING("Inbox"));
NS_ENSURE_SUCCESS(rv, rv);
}
rv = CreateLocalFolder(NS_LITERAL_STRING("Trash"));
NS_ENSURE_SUCCESS(rv, rv);
// copy the default templates into the Templates folder
rv = CopyDefaultMessages("Templates");
NS_ENSURE_SUCCESS(rv, rv);
return CreateLocalFolder(NS_LITERAL_STRING("Unsent Messages"));
}
NS_IMETHODIMP
nsNoIncomingServer::GetNewMail(nsIMsgWindow *aMsgWindow, nsIUrlListener *aUrlListener, nsIMsgFolder *aInbox, nsIURI **aResult)
{
nsCOMArray<nsIPop3IncomingServer> deferredServers;
nsresult rv = GetDeferredServers(this, deferredServers);
NS_ENSURE_SUCCESS(rv, rv);
if (!deferredServers.IsEmpty())
{
rv = deferredServers[0]->DownloadMailFromServers(deferredServers.Elements(),
deferredServers.Length(), aMsgWindow, aInbox, aUrlListener);
}
// listener might be counting on us to send a notification.
else if (aUrlListener)
aUrlListener->OnStopRunningUrl(nullptr, NS_OK);
return rv;
}
NS_IMETHODIMP
nsNoIncomingServer::GetCanSearchMessages(bool *canSearchMessages)
{
NS_ENSURE_ARG_POINTER(canSearchMessages);
*canSearchMessages = true;
return NS_OK;
}
NS_IMETHODIMP
nsNoIncomingServer::GetServerRequiresPasswordForBiff(bool *aServerRequiresPasswordForBiff)
{
NS_ENSURE_ARG_POINTER(aServerRequiresPasswordForBiff);
*aServerRequiresPasswordForBiff = false; // for local folders, we don't require a password
return NS_OK;
}
NS_IMETHODIMP
nsNoIncomingServer::GetSortOrder(int32_t* aSortOrder)
{
NS_ENSURE_ARG_POINTER(aSortOrder);
*aSortOrder = 200000000;
return NS_OK;
}

View file

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef __nsNoIncomingServer_h
#define __nsNoIncomingServer_h
#include "mozilla/Attributes.h"
#include "msgCore.h"
#include "nsINoIncomingServer.h"
#include "nsILocalMailIncomingServer.h"
#include "nsMsgIncomingServer.h"
#include "nsMailboxServer.h"
/* get some implementation from nsMsgIncomingServer */
class nsNoIncomingServer : public nsMailboxServer,
public nsINoIncomingServer,
public nsILocalMailIncomingServer
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSINOINCOMINGSERVER
NS_DECL_NSILOCALMAILINCOMINGSERVER
nsNoIncomingServer();
NS_IMETHOD GetLocalStoreType(nsACString& type) override;
NS_IMETHOD GetLocalDatabaseType(nsACString& type) override;
NS_IMETHOD GetCanSearchMessages(bool *canSearchMessages) override;
NS_IMETHOD GetServerRequiresPasswordForBiff(bool *aServerRequiresPasswordForBiff) override;
NS_IMETHOD GetAccountManagerChrome(nsAString& aResult) override;
NS_IMETHOD GetSortOrder(int32_t* aSortOrder) override;
private:
virtual ~nsNoIncomingServer();
};
#endif

View file

@ -0,0 +1,168 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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" // precompiled header...
#include "nsNoneService.h"
#include "nsINoIncomingServer.h"
#include "nsINoneService.h"
#include "nsIMsgProtocolInfo.h"
#include "nsMsgLocalCID.h"
#include "nsMsgBaseCID.h"
#include "nsIFile.h"
#include "nsCOMPtr.h"
#include "nsMsgUtils.h"
#include "nsIDirectoryService.h"
#include "nsMailDirServiceDefs.h"
#define PREF_MAIL_ROOT_NONE "mail.root.none" // old - for backward compatibility only
#define PREF_MAIL_ROOT_NONE_REL "mail.root.none-rel"
nsNoneService::nsNoneService()
{
}
nsNoneService::~nsNoneService()
{}
NS_IMPL_ISUPPORTS(nsNoneService, nsINoneService, nsIMsgProtocolInfo)
NS_IMETHODIMP
nsNoneService::SetDefaultLocalPath(nsIFile *aPath)
{
NS_ENSURE_ARG(aPath);
return NS_SetPersistentFile(PREF_MAIL_ROOT_NONE_REL, PREF_MAIL_ROOT_NONE, aPath);
}
NS_IMETHODIMP
nsNoneService::GetDefaultLocalPath(nsIFile ** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = nullptr;
bool havePref;
nsCOMPtr<nsIFile> localFile;
nsresult rv = NS_GetPersistentFile(PREF_MAIL_ROOT_NONE_REL,
PREF_MAIL_ROOT_NONE,
NS_APP_MAIL_50_DIR,
havePref,
getter_AddRefs(localFile));
if (NS_FAILED(rv)) return rv;
bool exists;
rv = localFile->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists)
rv = localFile->Create(nsIFile::DIRECTORY_TYPE, 0775);
if (NS_FAILED(rv)) return rv;
if (!havePref || !exists)
{
rv = NS_SetPersistentFile(PREF_MAIL_ROOT_NONE_REL, PREF_MAIL_ROOT_NONE, localFile);
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set root dir pref.");
}
NS_IF_ADDREF(*aResult = localFile);
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetServerIID(nsIID* *aServerIID)
{
*aServerIID = new nsIID(NS_GET_IID(nsINoIncomingServer));
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetRequiresUsername(bool *aRequiresUsername)
{
NS_ENSURE_ARG_POINTER(aRequiresUsername);
*aRequiresUsername = true;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetPreflightPrettyNameWithEmailAddress(bool *aPreflightPrettyNameWithEmailAddress)
{
NS_ENSURE_ARG_POINTER(aPreflightPrettyNameWithEmailAddress);
*aPreflightPrettyNameWithEmailAddress = true;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetCanLoginAtStartUp(bool *aCanLoginAtStartUp)
{
NS_ENSURE_ARG_POINTER(aCanLoginAtStartUp);
*aCanLoginAtStartUp = false;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetCanDelete(bool *aCanDelete)
{
NS_ENSURE_ARG_POINTER(aCanDelete);
*aCanDelete = false;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetCanDuplicate(bool *aCanDuplicate)
{
NS_ENSURE_ARG_POINTER(aCanDuplicate);
*aCanDuplicate = false;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetCanGetMessages(bool *aCanGetMessages)
{
NS_ENSURE_ARG_POINTER(aCanGetMessages);
*aCanGetMessages = false;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetCanGetIncomingMessages(bool *aCanGetIncomingMessages)
{
NS_ENSURE_ARG_POINTER(aCanGetIncomingMessages);
*aCanGetIncomingMessages = false;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetDefaultDoBiff(bool *aDoBiff)
{
NS_ENSURE_ARG_POINTER(aDoBiff);
// by default, don't do biff for "none" servers
*aDoBiff = false;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetDefaultServerPort(bool isSecure, int32_t *aDefaultPort)
{
NS_ENSURE_ARG_POINTER(aDefaultPort);
*aDefaultPort = -1;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetShowComposeMsgLink(bool *showComposeMsgLink)
{
NS_ENSURE_ARG_POINTER(showComposeMsgLink);
*showComposeMsgLink = false;
return NS_OK;
}
NS_IMETHODIMP
nsNoneService::GetFoldersCreatedAsync(bool *aAsyncCreation)
{
NS_ENSURE_ARG_POINTER(aAsyncCreation);
*aAsyncCreation = false;
return NS_OK;
}

View file

@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 4; 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/. */
#ifndef nsNoneService_h___
#define nsNoneService_h___
#include "nscore.h"
#include "nsIMsgProtocolInfo.h"
#include "nsINoneService.h"
class nsNoneService : public nsIMsgProtocolInfo, public nsINoneService
{
public:
nsNoneService();
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGPROTOCOLINFO
NS_DECL_NSINONESERVICE
private:
virtual ~nsNoneService();
};
#endif /* nsNoneService_h___ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,271 @@
/* -*- 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/. */
#ifndef nsParseMailbox_H
#define nsParseMailbox_H
#include "mozilla/Attributes.h"
#include "nsIURI.h"
#include "nsIMsgParseMailMsgState.h"
#include "nsIStreamListener.h"
#include "nsMsgLineBuffer.h"
#include "nsIMsgDatabase.h"
#include "nsIMsgHdr.h"
#include "nsIMsgStatusFeedback.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsIDBChangeListener.h"
#include "nsIWeakReference.h"
#include "nsIWeakReferenceUtils.h"
#include "nsIMsgWindow.h"
#include "nsImapMoveCoalescer.h"
#include "nsAutoPtr.h"
#include "nsStringGlue.h"
#include "nsIMsgFilterList.h"
#include "nsIMsgFilter.h"
#include "nsIMsgFilterHitNotify.h"
#include "nsIMsgFolderNotificationService.h"
#include "nsTArray.h"
class nsByteArray;
class nsOutputFileStream;
class nsIOFileStream;
class nsInputFileStream;
class nsIMsgFilter;
class MSG_FolderInfoMail;
class nsIMsgFilterList;
class nsIMsgFolder;
/* Used for the various things that parse RFC822 headers...
*/
typedef struct message_header
{
const char *value; /* The contents of a header (after ": ") */
int32_t length; /* The length of the data (it is not NULL-terminated.) */
} message_header;
// This object maintains the parse state for a single mail message.
class nsParseMailMessageState : public nsIMsgParseMailMsgState, public nsIDBChangeListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGPARSEMAILMSGSTATE
NS_DECL_NSIDBCHANGELISTENER
nsParseMailMessageState();
void Init(uint64_t fileposition);
virtual nsresult ParseFolderLine(const char *line, uint32_t lineLength);
virtual nsresult StartNewEnvelope(const char *line, uint32_t lineLength);
nsresult ParseHeaders();
nsresult FinalizeHeaders();
nsresult ParseEnvelope (const char *line, uint32_t line_size);
nsresult InternSubject (struct message_header *header);
static bool IsEnvelopeLine(const char *buf, int32_t buf_size);
nsCOMPtr<nsIMsgDBHdr> m_newMsgHdr; /* current message header we're building */
nsCOMPtr<nsIMsgDatabase> m_mailDB;
nsCOMPtr<nsIMsgDatabase> m_backupMailDB;
nsMailboxParseState m_state;
int64_t m_position;
uint64_t m_envelope_pos;
uint64_t m_headerstartpos;
nsMsgKey m_new_key; // DB key for the new header.
nsByteArray m_headers;
nsByteArray m_envelope;
struct message_header m_message_id;
struct message_header m_references;
struct message_header m_date;
struct message_header m_delivery_date;
struct message_header m_from;
struct message_header m_sender;
struct message_header m_newsgroups;
struct message_header m_subject;
struct message_header m_status;
struct message_header m_mozstatus;
struct message_header m_mozstatus2;
struct message_header m_in_reply_to;
struct message_header m_replyTo;
struct message_header m_content_type;
struct message_header m_bccList;
// Support for having multiple To or Cc header lines in a message
nsTArray<struct message_header*> m_toList;
nsTArray<struct message_header*> m_ccList;
struct message_header *GetNextHeaderInAggregate (nsTArray<struct message_header*> &list);
void GetAggregateHeader (nsTArray<struct message_header*> &list, struct message_header *);
void ClearAggregateHeader (nsTArray<struct message_header*> &list);
struct message_header m_envelope_from;
struct message_header m_envelope_date;
struct message_header m_priority;
struct message_header m_account_key;
struct message_header m_keywords;
// Mdn support
struct message_header m_mdn_original_recipient;
struct message_header m_return_path;
struct message_header m_mdn_dnt; /* MDN Disposition-Notification-To: header */
PRTime m_receivedTime;
uint16_t m_body_lines;
bool m_IgnoreXMozillaStatus;
// this enables extensions to add the values of particular headers to
// the .msf file as properties of nsIMsgHdr. It is initialized from a
// pref, mailnews.customDBHeaders
nsTArray<nsCString> m_customDBHeaders;
struct message_header *m_customDBHeaderValues;
nsCString m_receivedValue; // accumulated received header
protected:
virtual ~nsParseMailMessageState();
};
// This class is part of the mailbox parsing state machine
class nsMsgMailboxParser : public nsIStreamListener, public nsParseMailMessageState, public nsMsgLineBuffer
{
public:
nsMsgMailboxParser(nsIMsgFolder *);
nsMsgMailboxParser();
nsresult Init();
bool IsRunningUrl() { return m_urlInProgress;} // returns true if we are currently running a url and false otherwise...
NS_DECL_ISUPPORTS_INHERITED
////////////////////////////////////////////////////////////////////////////////////////
// we suppport the nsIStreamListener interface
////////////////////////////////////////////////////////////////////////////////////////
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
void SetDB (nsIMsgDatabase *mailDB) {m_mailDB = mailDB; }
// message socket libnet callbacks, which come through folder pane
nsresult ProcessMailboxInputStream(nsIURI* aURL, nsIInputStream *aIStream, uint32_t aLength);
virtual void DoneParsingFolder(nsresult status);
virtual void AbortNewHeader();
// for nsMsgLineBuffer
virtual nsresult HandleLine(const char *line, uint32_t line_length) override;
void UpdateDBFolderInfo();
void UpdateDBFolderInfo(nsIMsgDatabase *mailDB);
void UpdateStatusText(const char* stringName);
// Update the progress bar based on what we know.
virtual void UpdateProgressPercent ();
virtual void OnNewMessage(nsIMsgWindow *msgWindow);
protected:
virtual ~nsMsgMailboxParser();
nsCOMPtr<nsIMsgStatusFeedback> m_statusFeedback;
virtual int32_t PublishMsgHeader(nsIMsgWindow *msgWindow);
void FreeBuffers();
// data
nsString m_folderName;
nsCString m_inboxUri;
nsByteArray m_inputStream;
int32_t m_obuffer_size;
char *m_obuffer;
uint64_t m_graph_progress_total;
uint64_t m_graph_progress_received;
bool m_parsingDone;
PRTime m_startTime;
private:
// the following flag is used to determine when a url is currently being run. It is cleared on calls
// to ::StopBinding and it is set whenever we call Load on a url
bool m_urlInProgress;
nsWeakPtr m_folder;
void ReleaseFolderLock();
nsresult AcquireFolderLock();
};
class nsParseNewMailState : public nsMsgMailboxParser
, public nsIMsgFilterHitNotify
{
public:
nsParseNewMailState();
NS_DECL_ISUPPORTS_INHERITED
NS_IMETHOD FinishHeader() override;
nsresult Init(nsIMsgFolder *rootFolder, nsIMsgFolder *downloadFolder,
nsIMsgWindow *aMsgWindow, nsIMsgDBHdr *aHdr,
nsIOutputStream *aOutputStream);
virtual void DoneParsingFolder(nsresult status) override;
void DisableFilters() {m_disableFilters = true;}
NS_DECL_NSIMSGFILTERHITNOTIFY
nsOutputFileStream *GetLogFile();
virtual int32_t PublishMsgHeader(nsIMsgWindow *msgWindow) override;
void GetMsgWindow(nsIMsgWindow **aMsgWindow);
nsresult EndMsgDownload();
nsresult AppendMsgFromStream(nsIInputStream *fileStream, nsIMsgDBHdr *aHdr,
uint32_t length, nsIMsgFolder *destFolder);
virtual void ApplyFilters(bool *pMoved, nsIMsgWindow *msgWindow,
uint64_t msgOffset);
nsresult ApplyForwardAndReplyFilter(nsIMsgWindow *msgWindow);
virtual void OnNewMessage(nsIMsgWindow *msgWindow) override;
// this keeps track of how many messages we downloaded that
// aren't new - e.g., marked read, or moved to an other server.
int32_t m_numNotNewMessages;
protected:
virtual ~nsParseNewMailState();
virtual nsresult GetTrashFolder(nsIMsgFolder **pTrashFolder);
virtual nsresult MoveIncorporatedMessage(nsIMsgDBHdr *mailHdr,
nsIMsgDatabase *sourceDB,
nsIMsgFolder *destIFolder,
nsIMsgFilter *filter,
nsIMsgWindow *msgWindow);
virtual void MarkFilteredMessageRead(nsIMsgDBHdr *msgHdr);
virtual void MarkFilteredMessageUnread(nsIMsgDBHdr *msgHdr);
nsCOMPtr <nsIMsgFilterList> m_filterList;
nsCOMPtr <nsIMsgFilterList> m_deferredToServerFilterList;
nsCOMPtr <nsIMsgFolder> m_rootFolder;
nsCOMPtr <nsIMsgWindow> m_msgWindow;
nsCOMPtr <nsIMsgFolder> m_downloadFolder;
nsCOMPtr<nsIOutputStream> m_outputStream;
nsCOMArray <nsIMsgFolder> m_filterTargetFolders;
RefPtr<nsImapMoveCoalescer> m_moveCoalescer;
bool m_msgMovedByFilter;
bool m_msgCopiedByFilter;
bool m_disableFilters;
uint32_t m_ibuffer_fp;
char *m_ibuffer;
uint32_t m_ibuffer_size;
// used for applying move filters, because in the case of using a temporary
// download file, the offset/key in the msg hdr is not right.
uint64_t m_curHdrOffset;
// we have to apply the reply/forward filters in a second pass, after
// msg quarantining and moving to other local folders, so we remember the
// info we'll need to apply them with these vars.
// these need to be arrays in case we have multiple reply/forward filters.
nsTArray<nsCString> m_forwardTo;
nsTArray<nsCString> m_replyTemplateUri;
nsCOMPtr<nsIMsgDBHdr> m_msgToForwardOrReply;
nsCOMPtr<nsIMsgFilter> m_filter;
nsCOMPtr<nsIMsgRuleAction> m_ruleAction;
};
#endif

View file

@ -0,0 +1,744 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "prmem.h"
#include "plstr.h"
#include "prprf.h"
#include "nsCOMPtr.h"
#include "nsIStringBundle.h"
#include "nsIPop3IncomingServer.h"
#include "nsPop3IncomingServer.h"
#include "nsIPop3Service.h"
#include "nsMsgBaseCID.h"
#include "nsMsgLocalCID.h"
#include "nsMsgFolderFlags.h"
#include "nsPop3Protocol.h"
#include "nsAutoPtr.h"
#include "nsMsgKeyArray.h"
#include "nsIMsgLocalMailFolder.h"
#include "nsIMsgAccountManager.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsServiceManagerUtils.h"
#include "nsIMutableArray.h"
#include "nsMsgUtils.h"
#include "nsComponentManagerUtils.h"
#include "mozilla/Likely.h"
static NS_DEFINE_CID(kCPop3ServiceCID, NS_POP3SERVICE_CID);
class nsPop3GetMailChainer final : public nsIUrlListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIURLLISTENER
nsPop3GetMailChainer();
nsresult GetNewMailForServers(nsIPop3IncomingServer** servers, uint32_t count,
nsIMsgWindow *msgWindow,
nsIMsgFolder *folderToDownloadTo, nsIUrlListener *listener);
nsresult RunNextGetNewMail();
protected:
~nsPop3GetMailChainer();
nsCOMPtr <nsIMsgFolder> m_folderToDownloadTo;
nsCOMPtr <nsIMsgWindow> m_downloadingMsgWindow;
nsCOMArray<nsIPop3IncomingServer> m_serversToGetNewMailFor;
nsCOMPtr <nsIUrlListener> m_listener;
};
NS_IMPL_ISUPPORTS_INHERITED(nsPop3IncomingServer,
nsMsgIncomingServer,
nsIPop3IncomingServer,
nsILocalMailIncomingServer)
nsPop3IncomingServer::nsPop3IncomingServer()
{
m_capabilityFlags =
POP3_AUTH_MECH_UNDEFINED |
POP3_HAS_AUTH_USER | // should be always there
POP3_GURL_UNDEFINED |
POP3_UIDL_UNDEFINED |
POP3_TOP_UNDEFINED |
POP3_XTND_XLST_UNDEFINED;
m_canHaveFilters = true;
m_authenticated = false;
}
nsPop3IncomingServer::~nsPop3IncomingServer()
{
}
NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer,
LeaveMessagesOnServer,
"leave_on_server")
NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer,
HeadersOnly,
"headers_only")
NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer,
DeleteMailLeftOnServer,
"delete_mail_left_on_server")
NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer,
DotFix,
"dot_fix")
NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer,
DeleteByAgeFromServer,
"delete_by_age_from_server")
NS_IMPL_SERVERPREF_INT(nsPop3IncomingServer,
NumDaysToLeaveOnServer,
"num_days_to_leave_on_server")
NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer,
DeferGetNewMail,
"defer_get_new_mail")
NS_IMETHODIMP nsPop3IncomingServer::GetDeferredToAccount(nsACString& aRetVal)
{
nsresult rv = GetCharValue("deferred_to_account", aRetVal);
if (aRetVal.IsEmpty())
return rv;
// We need to repair broken profiles that defer to hidden or invalid servers,
// so find out if the deferred to account has a valid non-hidden server, and
// if not, defer to the local folders inbox.
nsCOMPtr<nsIMsgAccountManager> acctMgr =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID);
bool invalidAccount = true;
if (acctMgr)
{
nsCOMPtr<nsIMsgAccount> account;
nsCOMPtr<nsIMsgIncomingServer> server;
rv = acctMgr->GetAccount(aRetVal, getter_AddRefs(account));
if (account)
{
account->GetIncomingServer(getter_AddRefs(server));
if (server)
server->GetHidden(&invalidAccount);
}
if (invalidAccount)
{
nsCOMPtr<nsIMsgIncomingServer> localServer;
nsCOMPtr<nsIMsgAccount> localAccount;
rv = acctMgr->GetLocalFoldersServer(getter_AddRefs(localServer));
NS_ENSURE_SUCCESS(rv, rv);
// Try to copy any folders that have been stranded in the hidden account
// into the local folders account.
if (server)
{
nsCOMPtr<nsIMsgFolder> hiddenRootFolder;
nsCOMPtr<nsIMsgFolder> localFoldersRoot;
server->GetRootFolder(getter_AddRefs(hiddenRootFolder));
localServer->GetRootFolder(getter_AddRefs(localFoldersRoot));
if (hiddenRootFolder && localFoldersRoot)
{
// We're going to iterate over the folders in Local Folders-1,
// though I suspect only the Inbox will have messages. I don't
// think Sent Mail could end up here, but if any folders have
// messages, might as well copy them to the real Local Folders
// account.
nsCOMPtr<nsISimpleEnumerator> enumerator;
rv = hiddenRootFolder->GetSubFolders(getter_AddRefs(enumerator));
if (NS_SUCCEEDED(rv))
{
bool hasMore;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) &&
hasMore)
{
nsCOMPtr<nsISupports> item;
enumerator->GetNext(getter_AddRefs(item));
nsCOMPtr<nsIMsgFolder> subFolder(do_QueryInterface(item));
if (subFolder)
{
nsCOMPtr<nsIMsgDatabase> subFolderDB;
subFolder->GetMsgDatabase(getter_AddRefs(subFolderDB));
if (subFolderDB)
{
// Copy any messages in this sub-folder of the hidden
// account to the corresponding folder in Local Folders.
RefPtr<nsMsgKeyArray> keys = new nsMsgKeyArray;
rv = subFolderDB->ListAllKeys(keys);
nsCOMPtr<nsIMutableArray> hdrsToCopy(do_CreateInstance(NS_ARRAY_CONTRACTID));
MsgGetHeadersFromKeys(subFolderDB, keys->m_keys, hdrsToCopy);
uint32_t numHdrs = 0;
if (hdrsToCopy)
hdrsToCopy->GetLength(&numHdrs);
if (numHdrs)
{
// Look for a folder with the same name in Local Folders.
nsCOMPtr<nsIMsgFolder> dest;
nsString folderName;
subFolder->GetName(folderName);
localFoldersRoot->GetChildNamed(folderName,
getter_AddRefs(dest));
if (dest)
dest->CopyMessages(subFolder, hdrsToCopy, false,
nullptr, nullptr, false,false);
// Should we copy the folder if the dest doesn't exist?
}
}
}
}
}
}
}
rv = acctMgr->FindAccountForServer(localServer, getter_AddRefs(localAccount));
NS_ENSURE_SUCCESS(rv, rv);
if (!localAccount)
return NS_ERROR_NOT_AVAILABLE;
localAccount->GetKey(aRetVal);
// Can't call SetDeferredToAccount because it calls GetDeferredToAccount.
return SetCharValue("deferred_to_account", aRetVal);
}
}
return rv;
}
NS_IMETHODIMP nsPop3IncomingServer::SetDeferredToAccount(const nsACString& aAccountKey)
{
nsCString deferredToAccount;
GetDeferredToAccount(deferredToAccount);
m_rootMsgFolder = nullptr; // clear this so we'll recalculate it on demand.
//Notify listeners who listen to every folder
nsresult rv = SetCharValue("deferred_to_account", aAccountKey);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFolderListener> folderListenerManager =
do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIMsgFolder> rootFolder;
// use GetRootFolder, because that returns the real
// root, not the deferred to root.
rv = GetRootFolder(getter_AddRefs(rootFolder));
if (rootFolder)
{
// if isDeferred state has changed, send notification
if (aAccountKey.IsEmpty() != deferredToAccount.IsEmpty())
{
nsCOMPtr <nsIAtom> deferAtom = MsgGetAtom("isDeferred");
nsCOMPtr <nsIAtom> canFileAtom = MsgGetAtom("CanFileMessages");
folderListenerManager->OnItemBoolPropertyChanged(rootFolder, deferAtom,
!deferredToAccount.IsEmpty(), deferredToAccount.IsEmpty());
folderListenerManager->OnItemBoolPropertyChanged(rootFolder, canFileAtom,
deferredToAccount.IsEmpty(), !deferredToAccount.IsEmpty());
// this hack causes the account manager ds to send notifications to the
// xul content builder that make the changed acct appear or disappear
// from the folder pane and related menus.
nsCOMPtr<nsIMsgAccountManager> acctMgr =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID);
if (acctMgr)
{
acctMgr->NotifyServerUnloaded(this);
acctMgr->NotifyServerLoaded(this);
// check if this newly deferred to account is the local folders account
// and needs to have a newly created INBOX.
if (!aAccountKey.IsEmpty())
{
nsCOMPtr <nsIMsgAccount> account;
acctMgr->GetAccount(aAccountKey, getter_AddRefs(account));
if (account)
{
nsCOMPtr <nsIMsgIncomingServer> server;
account->GetIncomingServer(getter_AddRefs(server));
if (server)
{
nsCOMPtr <nsILocalMailIncomingServer> incomingLocalServer = do_QueryInterface(server);
if (incomingLocalServer)
{
nsCOMPtr <nsIMsgFolder> rootFolder;
rv = server->GetRootFolder(getter_AddRefs(rootFolder));
NS_ENSURE_SUCCESS(rv, rv);
// this will fail if it already exists, which is fine.
rootFolder->CreateSubfolder(NS_LITERAL_STRING("Inbox"), nullptr);
}
}
}
}
}
}
}
}
return rv;
}
//NS_IMPL_GETSET(nsPop3IncomingServer, Authenticated, bool, m_authenticated);
NS_IMETHODIMP nsPop3IncomingServer::GetAuthenticated(bool *aAuthenticated)
{
NS_ENSURE_ARG_POINTER(aAuthenticated);
*aAuthenticated = m_authenticated;
return NS_OK;
}
NS_IMETHODIMP nsPop3IncomingServer::SetAuthenticated(bool aAuthenticated)
{
m_authenticated = aAuthenticated;
return NS_OK;
}
nsresult
nsPop3IncomingServer::GetPop3CapabilityFlags(uint32_t *flags)
{
*flags = m_capabilityFlags;
return NS_OK;
}
nsresult
nsPop3IncomingServer::SetPop3CapabilityFlags(uint32_t flags)
{
m_capabilityFlags = flags;
return NS_OK;
}
NS_IMETHODIMP
nsPop3IncomingServer::GetRootMsgFolder(nsIMsgFolder **aRootMsgFolder)
{
NS_ENSURE_ARG_POINTER(aRootMsgFolder);
nsresult rv = NS_OK;
if (!m_rootMsgFolder)
{
nsCString deferredToAccount;
GetDeferredToAccount(deferredToAccount);
if (deferredToAccount.IsEmpty())
{
rv = CreateRootFolder();
m_rootMsgFolder = m_rootFolder;
}
else
{
nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr <nsIMsgAccount> account;
rv = accountManager->GetAccount(deferredToAccount, getter_AddRefs(account));
NS_ENSURE_SUCCESS(rv,rv);
if (account)
{
nsCOMPtr <nsIMsgIncomingServer> incomingServer;
rv = account->GetIncomingServer(getter_AddRefs(incomingServer));
NS_ENSURE_SUCCESS(rv,rv);
// make sure we're not deferred to ourself...
if (incomingServer && incomingServer != this)
rv = incomingServer->GetRootMsgFolder(getter_AddRefs(m_rootMsgFolder));
else
rv = NS_ERROR_FAILURE;
}
}
}
NS_IF_ADDREF(*aRootMsgFolder = m_rootMsgFolder);
return m_rootMsgFolder ? rv : NS_ERROR_FAILURE;
}
nsresult nsPop3IncomingServer::GetInbox(nsIMsgWindow *msgWindow, nsIMsgFolder **inbox)
{
NS_ENSURE_ARG_POINTER(inbox);
nsCOMPtr<nsIMsgFolder> rootFolder;
nsresult rv = GetRootMsgFolder(getter_AddRefs(rootFolder));
if(NS_SUCCEEDED(rv) && rootFolder)
{
rootFolder->GetFolderWithFlags(nsMsgFolderFlags::Inbox, inbox);
}
nsCOMPtr<nsIMsgLocalMailFolder> localInbox = do_QueryInterface(*inbox, &rv);
if (NS_SUCCEEDED(rv) && localInbox)
{
nsCOMPtr <nsIMsgDatabase> db;
rv = (*inbox)->GetMsgDatabase(getter_AddRefs(db));
if (NS_FAILED(rv))
{
(*inbox)->SetMsgDatabase(nullptr);
(void) localInbox->SetCheckForNewMessagesAfterParsing(true);
// this will cause a reparse of the mail folder.
localInbox->GetDatabaseWithReparse(nullptr, msgWindow, getter_AddRefs(db));
rv = NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE;
}
}
return rv;
}
NS_IMETHODIMP nsPop3IncomingServer::PerformBiff(nsIMsgWindow *aMsgWindow)
{
nsresult rv;
nsCOMPtr<nsIPop3Service> pop3Service(do_GetService(kCPop3ServiceCID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgFolder> inbox;
nsCOMPtr<nsIMsgFolder> rootMsgFolder;
nsCOMPtr<nsIUrlListener> urlListener;
rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
NS_ENSURE_TRUE(rootMsgFolder, NS_ERROR_FAILURE);
rootMsgFolder->GetFolderWithFlags(nsMsgFolderFlags::Inbox,
getter_AddRefs(inbox));
if (!inbox)
return NS_ERROR_FAILURE;
nsCOMPtr <nsIMsgIncomingServer> server;
inbox->GetServer(getter_AddRefs(server));
server->SetPerformingBiff(true);
urlListener = do_QueryInterface(inbox);
bool downloadOnBiff = false;
rv = GetDownloadOnBiff(&downloadOnBiff);
if (downloadOnBiff)
{
nsCOMPtr <nsIMsgLocalMailFolder> localInbox = do_QueryInterface(inbox, &rv);
if (localInbox && NS_SUCCEEDED(rv))
{
bool valid = false;
nsCOMPtr <nsIMsgDatabase> db;
rv = inbox->GetMsgDatabase(getter_AddRefs(db));
if (NS_SUCCEEDED(rv) && db)
rv = db->GetSummaryValid(&valid);
if (NS_SUCCEEDED(rv) && valid)
rv = pop3Service->GetNewMail(aMsgWindow, urlListener, inbox, this, nullptr);
else
{
bool isLocked;
inbox->GetLocked(&isLocked);
if (!isLocked)
rv = localInbox->GetDatabaseWithReparse(urlListener, aMsgWindow, getter_AddRefs(db));
if (NS_SUCCEEDED(rv))
rv = localInbox->SetCheckForNewMessagesAfterParsing(true);
}
}
}
else
rv = pop3Service->CheckForNewMail(aMsgWindow, urlListener, inbox, this, nullptr);
return NS_OK;
}
NS_IMETHODIMP
nsPop3IncomingServer::SetFlagsOnDefaultMailboxes()
{
nsCOMPtr<nsIMsgFolder> rootFolder;
nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgLocalMailFolder> localFolder = do_QueryInterface(rootFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// pop3 gets an inbox, but no queue (unsent messages)
localFolder->SetFlagsOnDefaultMailboxes(nsMsgFolderFlags::SpecialUse &
~nsMsgFolderFlags::Queue);
return NS_OK;
}
NS_IMETHODIMP nsPop3IncomingServer::CreateDefaultMailboxes()
{
nsresult rv = CreateLocalFolder(NS_LITERAL_STRING("Inbox"));
NS_ENSURE_SUCCESS(rv, rv);
return CreateLocalFolder(NS_LITERAL_STRING("Trash"));
}
// override this so we can say that deferred accounts can't have messages
// filed to them, which will remove them as targets of all the move/copy
// menu items.
NS_IMETHODIMP
nsPop3IncomingServer::GetCanFileMessagesOnServer(bool *aCanFileMessagesOnServer)
{
NS_ENSURE_ARG_POINTER(aCanFileMessagesOnServer);
nsCString deferredToAccount;
GetDeferredToAccount(deferredToAccount);
*aCanFileMessagesOnServer = deferredToAccount.IsEmpty();
return NS_OK;
}
NS_IMETHODIMP
nsPop3IncomingServer::GetCanCreateFoldersOnServer(bool *aCanCreateFoldersOnServer)
{
NS_ENSURE_ARG_POINTER(aCanCreateFoldersOnServer);
nsCString deferredToAccount;
GetDeferredToAccount(deferredToAccount);
*aCanCreateFoldersOnServer = deferredToAccount.IsEmpty();
return NS_OK;
}
NS_IMETHODIMP
nsPop3IncomingServer::VerifyLogon(nsIUrlListener *aUrlListener,
nsIMsgWindow *aMsgWindow, nsIURI **aURL)
{
nsresult rv;
nsCOMPtr<nsIPop3Service> pop3Service = do_GetService(kCPop3ServiceCID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
return pop3Service->VerifyLogon(this, aUrlListener, aMsgWindow, aURL);
}
NS_IMETHODIMP nsPop3IncomingServer::DownloadMailFromServers(nsIPop3IncomingServer** aServers,
uint32_t aCount,
nsIMsgWindow *aMsgWindow,
nsIMsgFolder *aFolder,
nsIUrlListener *aUrlListener)
{
nsPop3GetMailChainer *getMailChainer = new nsPop3GetMailChainer;
NS_ENSURE_TRUE(getMailChainer, NS_ERROR_OUT_OF_MEMORY);
getMailChainer->AddRef(); // this object owns itself and releases when done.
return getMailChainer->GetNewMailForServers(aServers, aCount, aMsgWindow, aFolder, aUrlListener);
}
NS_IMETHODIMP nsPop3IncomingServer::GetNewMail(nsIMsgWindow *aMsgWindow,
nsIUrlListener *aUrlListener,
nsIMsgFolder *aInbox,
nsIURI **aResult)
{
nsresult rv;
nsCOMPtr<nsIPop3Service> pop3Service = do_GetService(kCPop3ServiceCID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
return pop3Service->GetNewMail(aMsgWindow, aUrlListener, aInbox, this, aResult);
}
// user has clicked get new messages on this server. If other servers defer to this server,
// we need to get new mail for them. But if this server defers to an other server,
// I think we only get new mail for this server.
NS_IMETHODIMP
nsPop3IncomingServer::GetNewMessages(nsIMsgFolder *aFolder, nsIMsgWindow *aMsgWindow,
nsIUrlListener *aUrlListener)
{
nsresult rv;
nsCOMPtr<nsIPop3Service> pop3Service = do_GetService(kCPop3ServiceCID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr <nsIMsgFolder> inbox;
rv = GetInbox(aMsgWindow, getter_AddRefs(inbox));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIURI> url;
nsCOMPtr <nsIMsgIncomingServer> server;
nsCOMArray<nsIPop3IncomingServer> deferredServers;
nsCString deferredToAccount;
GetDeferredToAccount(deferredToAccount);
if (deferredToAccount.IsEmpty())
{
aFolder->GetServer(getter_AddRefs(server));
GetDeferredServers(server, deferredServers);
}
if (deferredToAccount.IsEmpty() && !deferredServers.IsEmpty())
{
nsPop3GetMailChainer *getMailChainer = new nsPop3GetMailChainer;
NS_ENSURE_TRUE(getMailChainer, NS_ERROR_OUT_OF_MEMORY);
getMailChainer->AddRef(); // this object owns itself and releases when done.
deferredServers.InsertElementAt(0, this);
return getMailChainer->GetNewMailForServers(deferredServers.Elements(),
deferredServers.Length(), aMsgWindow, inbox, aUrlListener);
}
if (m_runningProtocol)
return NS_MSG_FOLDER_BUSY;
return pop3Service->GetNewMail(aMsgWindow, aUrlListener, inbox, this, getter_AddRefs(url));
}
NS_IMETHODIMP
nsPop3IncomingServer::GetDownloadMessagesAtStartup(bool *getMessagesAtStartup)
{
NS_ENSURE_ARG_POINTER(getMessagesAtStartup);
// GetMessages is not automatically done for pop servers at startup.
// We need to trigger that action. Return true.
*getMessagesAtStartup = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3IncomingServer::GetCanBeDefaultServer(bool *canBeDefaultServer)
{
NS_ENSURE_ARG_POINTER(canBeDefaultServer);
*canBeDefaultServer = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3IncomingServer::GetCanSearchMessages(bool *canSearchMessages)
{
// this will return false if this server is deferred, which is what we want.
return GetCanFileMessagesOnServer(canSearchMessages);
}
NS_IMETHODIMP
nsPop3IncomingServer::CloseCachedConnections()
{
nsCOMPtr<nsIRequest> channel = do_QueryInterface(m_runningProtocol);
if (channel)
channel->Cancel(NS_ERROR_ABORT);
return NS_OK;
}
NS_IMETHODIMP
nsPop3IncomingServer::GetOfflineSupportLevel(int32_t *aSupportLevel)
{
NS_ENSURE_ARG_POINTER(aSupportLevel);
nsresult rv;
rv = GetIntValue("offline_support_level", aSupportLevel);
if (*aSupportLevel != OFFLINE_SUPPORT_LEVEL_UNDEFINED) return rv;
// set default value
*aSupportLevel = OFFLINE_SUPPORT_LEVEL_NONE;
return NS_OK;
}
NS_IMETHODIMP
nsPop3IncomingServer::SetRunningProtocol(nsIPop3Protocol *aProtocol)
{
NS_ASSERTION(!aProtocol || !m_runningProtocol, "overriding running protocol");
m_runningProtocol = aProtocol;
return NS_OK;
}
NS_IMETHODIMP nsPop3IncomingServer::GetRunningProtocol(nsIPop3Protocol **aProtocol)
{
NS_ENSURE_ARG_POINTER(aProtocol);
NS_IF_ADDREF(*aProtocol = m_runningProtocol);
return NS_OK;
}
NS_IMETHODIMP nsPop3IncomingServer::AddUidlToMark(const char *aUidl, int32_t aMark)
{
NS_ENSURE_ARG_POINTER(aUidl);
Pop3UidlEntry *uidlEntry = PR_NEWZAP(Pop3UidlEntry);
NS_ENSURE_TRUE(uidlEntry, NS_ERROR_OUT_OF_MEMORY);
uidlEntry->uidl = strdup(aUidl);
if (MOZ_UNLIKELY(!uidlEntry->uidl)) {
PR_Free(uidlEntry);
return NS_ERROR_OUT_OF_MEMORY;
}
uidlEntry->status = (aMark == POP3_DELETE) ? DELETE_CHAR :
(aMark == POP3_FETCH_BODY) ? FETCH_BODY : KEEP;
m_uidlsToMark.AppendElement(uidlEntry);
return NS_OK;
}
NS_IMETHODIMP nsPop3IncomingServer::MarkMessages()
{
nsresult rv;
if (m_runningProtocol)
rv = m_runningProtocol->MarkMessages(&m_uidlsToMark);
else
{
nsCString hostName;
nsCString userName;
nsCOMPtr<nsIFile> localPath;
GetLocalPath(getter_AddRefs(localPath));
GetHostName(hostName);
GetUsername(userName);
// do it all in one fell swoop
rv = nsPop3Protocol::MarkMsgForHost(hostName.get(), userName.get(), localPath, m_uidlsToMark);
}
uint32_t count = m_uidlsToMark.Length();
for (uint32_t i = 0; i < count; i++)
{
Pop3UidlEntry *ue = m_uidlsToMark[i];
PR_Free(ue->uidl);
PR_Free(ue);
}
m_uidlsToMark.Clear();
return rv;
}
NS_IMPL_ISUPPORTS(nsPop3GetMailChainer, nsIUrlListener)
nsPop3GetMailChainer::nsPop3GetMailChainer()
{
}
nsPop3GetMailChainer::~nsPop3GetMailChainer()
{
}
nsresult nsPop3GetMailChainer::GetNewMailForServers(nsIPop3IncomingServer** servers,
uint32_t count, nsIMsgWindow *msgWindow,
nsIMsgFolder *folderToDownloadTo, nsIUrlListener *listener)
{
NS_ENSURE_ARG_POINTER(folderToDownloadTo);
m_serversToGetNewMailFor.AppendElements(servers, count);
m_folderToDownloadTo = folderToDownloadTo;
m_downloadingMsgWindow = msgWindow;
m_listener = listener;
nsCOMPtr <nsIMsgDatabase> destFolderDB;
nsresult rv = folderToDownloadTo->GetMsgDatabase(getter_AddRefs(destFolderDB));
if (NS_FAILED(rv) || !destFolderDB)
{
nsCOMPtr <nsIMsgLocalMailFolder> localFolder = do_QueryInterface(folderToDownloadTo);
if (localFolder)
{
localFolder->GetDatabaseWithReparse(this, msgWindow, getter_AddRefs(destFolderDB));
return NS_OK;
}
}
return RunNextGetNewMail();
}
NS_IMETHODIMP
nsPop3GetMailChainer::OnStartRunningUrl(nsIURI *url)
{
return NS_OK;
}
NS_IMETHODIMP
nsPop3GetMailChainer::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode)
{
return RunNextGetNewMail();
}
nsresult nsPop3GetMailChainer::RunNextGetNewMail()
{
nsresult rv;
uint32_t numServersLeft = m_serversToGetNewMailFor.Count();
for (; numServersLeft > 0;)
{
nsCOMPtr<nsIPop3IncomingServer> popServer(m_serversToGetNewMailFor[0]);
m_serversToGetNewMailFor.RemoveObjectAt(0);
numServersLeft--;
if (popServer)
{
bool deferGetNewMail = false;
nsCOMPtr <nsIMsgIncomingServer> downloadingToServer;
m_folderToDownloadTo->GetServer(getter_AddRefs(downloadingToServer));
popServer->GetDeferGetNewMail(&deferGetNewMail);
nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(popServer);
nsCOMPtr<nsIPop3Protocol> protocol;
popServer->GetRunningProtocol(getter_AddRefs(protocol));
if ((deferGetNewMail || downloadingToServer == server) && !protocol)
{
// have to call routine that just gets mail for one server,
// and ignores deferred servers...
if (server)
{
nsCOMPtr <nsIURI> url;
nsCOMPtr<nsIPop3Service> pop3Service = do_GetService(kCPop3ServiceCID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
return pop3Service->GetNewMail(m_downloadingMsgWindow, this, m_folderToDownloadTo, popServer, getter_AddRefs(url));
}
}
}
}
rv = m_listener ? m_listener->OnStopRunningUrl(nullptr, NS_OK) : NS_OK;
Release(); // release ref to ourself.
return rv;
}

View file

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef __nsPop3IncomingServer_h
#define __nsPop3IncomingServer_h
#include "mozilla/Attributes.h"
#include "msgCore.h"
#include "nsIPop3IncomingServer.h"
#include "nsILocalMailIncomingServer.h"
#include "nsMsgIncomingServer.h"
#include "nsIPop3Protocol.h"
#include "nsIMsgWindow.h"
#include "nsMailboxServer.h"
/* get some implementation from nsMsgIncomingServer */
class nsPop3IncomingServer : public nsMailboxServer,
public nsIPop3IncomingServer,
public nsILocalMailIncomingServer
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIPOP3INCOMINGSERVER
NS_DECL_NSILOCALMAILINCOMINGSERVER
nsPop3IncomingServer();
NS_IMETHOD PerformBiff(nsIMsgWindow *aMsgWindow) override;
NS_IMETHOD GetDownloadMessagesAtStartup(bool *getMessages) override;
NS_IMETHOD GetCanBeDefaultServer(bool *canBeDefaultServer) override;
NS_IMETHOD GetCanSearchMessages(bool *canSearchMessages) override;
NS_IMETHOD GetOfflineSupportLevel(int32_t *aSupportLevel) override;
NS_IMETHOD CloseCachedConnections() override;
NS_IMETHOD GetRootMsgFolder(nsIMsgFolder **aRootMsgFolder) override;
NS_IMETHOD GetCanFileMessagesOnServer(bool *aCanFileMessagesOnServer) override;
NS_IMETHOD GetCanCreateFoldersOnServer(bool *aCanCreateFoldersOnServer) override;
NS_IMETHOD VerifyLogon(nsIUrlListener *aUrlListener, nsIMsgWindow *aMsgWindow,
nsIURI **aURL) override;
NS_IMETHOD GetNewMessages(nsIMsgFolder *aFolder, nsIMsgWindow *aMsgWindow,
nsIUrlListener *aUrlListener) override;
protected:
virtual ~nsPop3IncomingServer();
nsresult GetInbox(nsIMsgWindow *msgWindow, nsIMsgFolder **inbox);
private:
uint32_t m_capabilityFlags;
bool m_authenticated;
nsCOMPtr <nsIPop3Protocol> m_runningProtocol;
nsCOMPtr <nsIMsgFolder> m_rootMsgFolder;
nsTArray<Pop3UidlEntry*> m_uidlsToMark;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,402 @@
/* -*- 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/. */
#ifndef nsPop3Protocol_h__
#define nsPop3Protocol_h__
#include "mozilla/Attributes.h"
#include "nsIStreamListener.h"
#include "nsIOutputStream.h"
#include "nsIInputStream.h"
#include "nsIPop3URL.h"
#include "nsIPop3Sink.h"
#include "nsMsgLineBuffer.h"
#include "nsMsgProtocol.h"
#include "nsIPop3Protocol.h"
#include "MailNewsTypes.h"
#include "nsIStringBundle.h"
#include "nsIMsgStatusFeedback.h"
#include "nsIMsgFolder.h" // TO include biffState enum. Change to bool later...
#include "nsIAuthModule.h"
#include "nsITimer.h"
#include "nsIMsgAsyncPrompter.h"
#include "prerror.h"
#include "plhash.h"
#include "nsCOMPtr.h"
/* A more guaranteed way of making sure that we never get duplicate messages
is to always get each message's UIDL (if the server supports it)
and use these for storing up deletes which were not committed on the
server. Based on our experience, it looks like we do NOT need to
do this (it has performance tradeoffs, etc.). To turn it on, three
things need to happen: #define POP_ALWAYS_USE_UIDL_FOR_DUPLICATES, verify that
the uidl's are correctly getting added when the delete response is received,
and change the POP3_QUIT_RESPONSE state to flush the newly committed deletes. */
/*
* Cannot have the following line uncommented. It is defined.
* #ifdef POP_ALWAYS_USE_UIDL_FOR_DUPLICATES will always be evaluated
* as true.
*
#define POP_ALWAYS_USE_UIDL_FOR_DUPLICATES 0
*
*/
#define MK_OUT_OF_MEMORY -207
#define MK_POP3_PASSWORD_UNDEFINED -313
#define XP_NO_ANSWER 14401
#define XP_THE_PREVIOUSLY_ENTERED_PASSWORD_IS_INVALID_ETC 14405
#define XP_PASSWORD_FOR_POP3_USER 14590
#define OUTPUT_BUFFER_SIZE 8192 // maximum size of command string
/* structure to hold data pertaining to the active state of
* a transfer in progress.
*
*/
enum Pop3CapabilityEnum {
POP3_CAPABILITY_UNDEFINED = 0x00000000,
POP3_HAS_XSENDER = 0x00000001,
POP3_GURL_UNDEFINED = 0x00000002,
POP3_HAS_GURL = 0x00000004,
POP3_UIDL_UNDEFINED = 0x00000008,
POP3_HAS_UIDL = 0x00000010,
POP3_XTND_XLST_UNDEFINED = 0x00000020,
POP3_HAS_XTND_XLST = 0x00000040,
POP3_TOP_UNDEFINED = 0x00000080,
POP3_HAS_TOP = 0x00000100,
POP3_AUTH_MECH_UNDEFINED = 0x00000200,
POP3_HAS_AUTH_USER = 0x00000400,
POP3_HAS_AUTH_LOGIN = 0x00000800,
POP3_HAS_AUTH_PLAIN = 0x00001000,
POP3_HAS_AUTH_CRAM_MD5 = 0x00002000,
POP3_HAS_AUTH_APOP = 0x00004000,
POP3_HAS_AUTH_NTLM = 0x00008000,
POP3_HAS_AUTH_MSN = 0x00010000,
POP3_HAS_RESP_CODES = 0x00020000,
POP3_HAS_AUTH_RESP_CODE = 0x00040000,
POP3_HAS_STLS = 0x00080000,
POP3_HAS_AUTH_GSSAPI = 0x00100000
};
// TODO use value > 0?
#define POP3_HAS_AUTH_NONE 0
#define POP3_HAS_AUTH_ANY 0x00001C00
#define POP3_HAS_AUTH_ANY_SEC 0x0011E000
enum Pop3StatesEnum {
POP3_READ_PASSWORD, // 0
//
POP3_START_CONNECT, // 1
POP3_FINISH_CONNECT, // 2
POP3_WAIT_FOR_RESPONSE, // 3
POP3_WAIT_FOR_START_OF_CONNECTION_RESPONSE, // 4
POP3_SEND_USERNAME, // 5
POP3_SEND_PASSWORD, // 6
POP3_SEND_STAT, // 7
POP3_GET_STAT, // 8
POP3_SEND_LIST, // 9
POP3_GET_LIST, // 10
POP3_SEND_UIDL_LIST, // 11
POP3_GET_UIDL_LIST, // 12
POP3_SEND_XTND_XLST_MSGID, // 13
POP3_GET_XTND_XLST_MSGID, // 14
POP3_GET_MSG, // 15
POP3_SEND_TOP, // 16
POP3_TOP_RESPONSE, // 17
POP3_SEND_RETR, // 18
POP3_RETR_RESPONSE, // 19
POP3_SEND_DELE, // 20
POP3_DELE_RESPONSE, // 21
POP3_SEND_QUIT, // 22
POP3_DONE, // 23
POP3_ERROR_DONE, // 24
POP3_FREE, // 25
POP3_SEND_AUTH, // 26
POP3_AUTH_RESPONSE, // 27
POP3_SEND_CAPA, // 28
POP3_CAPA_RESPONSE, // 29
POP3_PROCESS_AUTH, // 30
POP3_NEXT_AUTH_STEP, // 31
POP3_AUTH_LOGIN, // 32
POP3_AUTH_LOGIN_RESPONSE, // 33
POP3_AUTH_NTLM, // 34
POP3_AUTH_NTLM_RESPONSE, // 35
POP3_SEND_XSENDER, // 36
POP3_XSENDER_RESPONSE, // 37
POP3_SEND_GURL, // 38
POP3_GURL_RESPONSE, // 39
POP3_QUIT_RESPONSE, // 40
POP3_TLS_RESPONSE, // 41
POP3_AUTH_GSSAPI, // 42
POP3_AUTH_GSSAPI_FIRST, // 43
POP3_AUTH_GSSAPI_STEP, // 44
/**
* Async wait to obtain the password and deal with the result.
* The *PREOBTAIN* states are used for where we try and get the password
* before we've initiated a connection to the server.
*/
POP3_OBTAIN_PASSWORD_EARLY, // 45
POP3_FINISH_OBTAIN_PASSWORD_EARLY, // 46
POP3_OBTAIN_PASSWORD_BEFORE_USERNAME, // 47
POP3_FINISH_OBTAIN_PASSWORD_BEFORE_USERNAME,// 48
POP3_OBTAIN_PASSWORD_BEFORE_PASSWORD, // 49
POP3_FINISH_OBTAIN_PASSWORD_BEFORE_PASSWORD // 50
};
#define KEEP 'k' /* If we want to keep this item on server. */
#define DELETE_CHAR 'd' /* If we want to delete this item. */
#define TOO_BIG 'b' /* item left on server because it was too big */
#define FETCH_BODY 'f' /* Fetch full body of a partial msg */
typedef struct Pop3UidlEntry { /* information about this message */
char* uidl;
char status; // KEEP=='k', DELETE='d' TOO_BIG='b' FETCH_BODY='f'
uint32_t dateReceived; // time message received, used for aging
} Pop3UidlEntry;
typedef struct Pop3UidlHost {
char* host;
char* user;
PLHashTable * hash;
Pop3UidlEntry* uidlEntries;
struct Pop3UidlHost* next;
} Pop3UidlHost;
typedef struct Pop3MsgInfo {
int32_t msgnum;
int32_t size;
char* uidl;
} Pop3MsgInfo;
typedef struct _Pop3ConData {
bool leave_on_server; /* Whether we're supposed to leave messages
on server. */
bool headers_only; /* Whether to just fetch headers on initial
downloads. */
int32_t size_limit; /* Leave messages bigger than this on the
server and only download a partial
message. */
uint32_t capability_flags; /* What capability this server has? */
Pop3StatesEnum next_state; /* the next state or action to be taken */
Pop3StatesEnum next_state_after_response;
bool pause_for_read; /* Pause now for next read? */
bool command_succeeded; /* did the last command succeed? */
bool list_done; /* did we get the complete list of msgIDs? */
int32_t first_msg;
uint32_t obuffer_size;
uint32_t obuffer_fp;
int32_t really_new_messages;
int32_t real_new_counter;
int32_t number_of_messages;
Pop3MsgInfo *msg_info; /* Message sizes and uidls (used only if we
are playing games that involve leaving
messages on the server). */
int32_t last_accessed_msg;
int32_t cur_msg_size;
bool truncating_cur_msg; /* are we using top and uidl? */
bool msg_del_started; /* True if MSG_BeginMailDel...
* called
*/
bool only_check_for_new_mail;
nsMsgBiffState biffstate; /* If just checking for, what the answer is. */
bool verify_logon; /* true if we're just seeing if we can logon */
void *msg_closure;
bool graph_progress_bytes_p; /* whether we should display info about
the bytes transferred (usually we
display info about the number of
messages instead.) */
Pop3UidlHost *uidlinfo;
PLHashTable *newuidl;
char *only_uidl; /* If non-NULL, then load only this UIDL. */
bool get_url;
bool seenFromHeader;
int32_t parsed_bytes;
int32_t pop3_size;
bool dot_fix;
bool assumed_end;
nsresult urlStatus;
} Pop3ConData;
// State Flags (Note, I use the word state in terms of storing
// state information about the connection (authentication, have we sent
// commands, etc. I do not intend it to refer to protocol state)
#define POP3_PAUSE_FOR_READ 0x00000001 /* should we pause for the next read */
#define POP3_PASSWORD_FAILED 0x00000002
#define POP3_STOPLOGIN 0x00000004 /* error loging in, so stop here */
#define POP3_AUTH_FAILURE 0x00000008 /* extended code said authentication failed */
class nsPop3Protocol : public nsMsgProtocol,
public nsIPop3Protocol,
public nsIMsgAsyncPromptListener
{
public:
nsPop3Protocol(nsIURI* aURL);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIPOP3PROTOCOL
NS_DECL_NSIMSGASYNCPROMPTLISTENER
nsresult Initialize(nsIURI * aURL);
virtual nsresult LoadUrl(nsIURI *aURL, nsISupports * aConsumer = nullptr) override;
void Cleanup();
const char* GetUsername() { return m_username.get(); }
void SetUsername(const char* name);
nsresult StartGetAsyncPassword(Pop3StatesEnum aNextState);
NS_IMETHOD OnTransportStatus(nsITransport *transport, nsresult status, int64_t progress, int64_t progressMax) override;
NS_IMETHOD OnStopRequest(nsIRequest *request, nsISupports * aContext, nsresult aStatus) override;
NS_IMETHOD Cancel(nsresult status) override;
static void MarkMsgInHashTable(PLHashTable *hashTable, const Pop3UidlEntry *uidl,
bool *changed);
static nsresult MarkMsgForHost(const char *hostName, const char *userName,
nsIFile *mailDirectory,
nsTArray<Pop3UidlEntry*> &UIDLArray);
private:
virtual ~nsPop3Protocol();
nsCString m_ApopTimestamp;
nsCOMPtr<nsIStringBundle> mLocalBundle;
nsCString m_username;
nsCString m_senderInfo;
nsCString m_commandResponse;
nsCString m_GSSAPICache;
// Used for asynchronous password prompts to store the password temporarily.
nsCString m_passwordResult;
// progress state information
void UpdateProgressPercent(int64_t totalDone, int64_t total);
void UpdateStatus(const char16_t *aStatusName);
void UpdateStatusWithString(const char16_t *aString);
nsresult FormatCounterString(const nsString &stringName,
uint32_t count1,
uint32_t count2,
nsString &resultString);
int32_t m_bytesInMsgReceived;
int64_t m_totalFolderSize;
int64_t m_totalDownloadSize; /* Number of bytes we're going to
download. Might be much less
than the total_folder_size. */
int64_t m_totalBytesReceived; // total # bytes received for the connection
virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream,
uint64_t sourceOffset, uint32_t length) override;
virtual int32_t Pop3SendData(const char * dataBuffer, bool aSuppressLogging = false);
virtual const char* GetType() override {return "pop3";}
nsCOMPtr<nsIURI> m_url;
nsCOMPtr<nsIPop3Sink> m_nsIPop3Sink;
nsCOMPtr<nsIPop3IncomingServer> m_pop3Server;
nsMsgLineStreamBuffer * m_lineStreamBuffer; // used to efficiently extract lines from the incoming data stream
Pop3ConData* m_pop3ConData;
void FreeMsgInfo();
void Abort();
bool m_tlsEnabled;
int32_t m_socketType;
bool m_password_already_sent;
bool m_needToRerunUrl;
void SetCapFlag(uint32_t flag);
void ClearCapFlag(uint32_t flag);
bool TestCapFlag(uint32_t flag);
uint32_t GetCapFlags();
void InitPrefAuthMethods(int32_t authMethodPrefValue);
nsresult ChooseAuthMethod();
void MarkAuthMethodAsFailed(int32_t failedAuthMethod);
void ResetAuthMethods();
int32_t m_prefAuthMethods; // set of capability flags for auth methods
int32_t m_failedAuthMethods; // ditto
int32_t m_currentAuthMethod; // exactly one capability flag, or 0
int32_t m_listpos;
nsresult HandleLine(char *line, uint32_t line_length);
nsresult GetApopTimestamp();
//////////////////////////////////////////////////////////////////////////////////////////
// Begin Pop3 protocol state handlers
//////////////////////////////////////////////////////////////////////////////////////////
int32_t WaitForStartOfConnectionResponse(nsIInputStream* inputStream,
uint32_t length);
int32_t WaitForResponse(nsIInputStream* inputStream,
uint32_t length);
int32_t Error(const char* err_code, const char16_t **params = nullptr,
uint32_t length = 0);
int32_t SendAuth();
int32_t AuthResponse(nsIInputStream* inputStream, uint32_t length);
int32_t SendCapa();
int32_t CapaResponse(nsIInputStream* inputStream, uint32_t length);
int32_t SendTLSResponse();
int32_t ProcessAuth();
int32_t NextAuthStep();
int32_t AuthLogin();
int32_t AuthLoginResponse();
int32_t AuthNtlm();
int32_t AuthNtlmResponse();
int32_t AuthGSSAPI();
int32_t AuthGSSAPIResponse(bool first);
int32_t SendUsername();
int32_t SendPassword();
int32_t SendStatOrGurl(bool sendStat);
int32_t SendStat();
int32_t GetStat();
int32_t SendGurl();
int32_t GurlResponse();
int32_t SendList();
int32_t GetList(nsIInputStream* inputStream, uint32_t length);
int32_t HandleNoUidListAvailable();
int32_t SendXtndXlstMsgid();
int32_t GetXtndXlstMsgid(nsIInputStream* inputStream, uint32_t length);
int32_t SendUidlList();
int32_t GetUidlList(nsIInputStream* inputStream, uint32_t length);
int32_t GetMsg();
int32_t SendTop();
int32_t SendXsender();
int32_t XsenderResponse();
int32_t SendRetr();
int32_t RetrResponse(nsIInputStream* inputStream, uint32_t length);
int32_t TopResponse(nsIInputStream* inputStream, uint32_t length);
int32_t SendDele();
int32_t DeleResponse();
int32_t CommitState(bool remove_last_entry);
Pop3StatesEnum GetNextPasswordObtainState();
nsresult RerunUrl();
};
#endif /* nsPop3Protocol_h__ */

View file

@ -0,0 +1,711 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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" // precompiled header...
#include "nsPop3Service.h"
#include "nsIMsgIncomingServer.h"
#include "nsIPop3IncomingServer.h"
#include "nsPop3URL.h"
#include "nsPop3Sink.h"
#include "nsPop3Protocol.h"
#include "nsMsgLocalCID.h"
#include "nsMsgBaseCID.h"
#include "nsCOMPtr.h"
#include "nsIMsgWindow.h"
#include "nsINetUtil.h"
#include "nsIRDFService.h"
#include "nsRDFCID.h"
#include "nsIDirectoryService.h"
#include "nsMailDirServiceDefs.h"
#include "prprf.h"
#include "nsMsgUtils.h"
#include "nsIMsgAccountManager.h"
#include "nsIMsgAccount.h"
#include "nsLocalMailFolder.h"
#include "nsIMailboxUrl.h"
#include "nsIPrompt.h"
#include "nsINetUtil.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/Services.h"
#define PREF_MAIL_ROOT_POP3 "mail.root.pop3" // old - for backward compatibility only
#define PREF_MAIL_ROOT_POP3_REL "mail.root.pop3-rel"
static NS_DEFINE_CID(kPop3UrlCID, NS_POP3URL_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
nsPop3Service::nsPop3Service()
{
}
nsPop3Service::~nsPop3Service()
{}
NS_IMPL_ISUPPORTS(nsPop3Service,
nsIPop3Service,
nsIProtocolHandler,
nsIMsgProtocolInfo)
NS_IMETHODIMP nsPop3Service::CheckForNewMail(nsIMsgWindow* aMsgWindow,
nsIUrlListener *aUrlListener,
nsIMsgFolder *aInbox,
nsIPop3IncomingServer *aPopServer,
nsIURI **aURL)
{
return GetMail(false /* don't download, just check */,
aMsgWindow, aUrlListener, aInbox, aPopServer, aURL);
}
nsresult nsPop3Service::GetNewMail(nsIMsgWindow *aMsgWindow,
nsIUrlListener *aUrlListener,
nsIMsgFolder *aInbox,
nsIPop3IncomingServer *aPopServer,
nsIURI **aURL)
{
return GetMail(true /* download */,
aMsgWindow, aUrlListener, aInbox, aPopServer, aURL);
}
nsresult nsPop3Service::GetMail(bool downloadNewMail,
nsIMsgWindow *aMsgWindow,
nsIUrlListener *aUrlListener,
nsIMsgFolder *aInbox,
nsIPop3IncomingServer *aPopServer,
nsIURI **aURL)
{
NS_ENSURE_ARG_POINTER(aInbox);
int32_t popPort = -1;
nsCOMPtr<nsIMsgIncomingServer> server;
nsCOMPtr<nsIURI> url;
server = do_QueryInterface(aPopServer);
NS_ENSURE_TRUE(server, NS_MSG_INVALID_OR_MISSING_SERVER);
nsCOMPtr<nsIMsgLocalMailFolder> destLocalFolder = do_QueryInterface(aInbox);
if (destLocalFolder)
{
// We don't know the needed size yet, so at least check
// if there is some free space (1MB) in the message store.
bool destFolderTooBig;
destLocalFolder->WarnIfLocalFileTooBig(aMsgWindow, 0xFFFF, &destFolderTooBig);
if (destFolderTooBig)
return NS_MSG_ERROR_WRITING_MAIL_FOLDER;
}
nsCString popHost;
nsCString popUser;
nsresult rv = server->GetHostName(popHost);
NS_ENSURE_SUCCESS(rv, rv);
if (popHost.IsEmpty())
return NS_MSG_INVALID_OR_MISSING_SERVER;
rv = server->GetPort(&popPort);
NS_ENSURE_SUCCESS(rv, rv);
rv = server->GetUsername(popUser);
NS_ENSURE_SUCCESS(rv, rv);
if (popUser.IsEmpty())
return NS_MSG_SERVER_USERNAME_MISSING;
nsCString escapedUsername;
MsgEscapeString(popUser, nsINetUtil::ESCAPE_XALPHAS, escapedUsername);
if (NS_SUCCEEDED(rv) && aPopServer)
{
// now construct a pop3 url...
// we need to escape the username because it may contain
// characters like / % or @
char * urlSpec = (downloadNewMail)
? PR_smprintf("pop3://%s@%s:%d", escapedUsername.get(), popHost.get(), popPort)
: PR_smprintf("pop3://%s@%s:%d/?check", escapedUsername.get(), popHost.get(), popPort);
rv = BuildPop3Url(urlSpec, aInbox, aPopServer, aUrlListener, getter_AddRefs(url), aMsgWindow);
PR_smprintf_free(urlSpec);
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ENSURE_TRUE(url, rv);
if (NS_SUCCEEDED(rv))
rv = RunPopUrl(server, url);
if (aURL) // we already have a ref count on pop3url...
NS_IF_ADDREF(*aURL = url);
return rv;
}
NS_IMETHODIMP nsPop3Service::VerifyLogon(nsIMsgIncomingServer *aServer,
nsIUrlListener *aUrlListener,
nsIMsgWindow *aMsgWindow,
nsIURI **aURL)
{
NS_ENSURE_ARG_POINTER(aServer);
nsCString popHost;
nsCString popUser;
int32_t popPort = -1;
nsresult rv = aServer->GetHostName(popHost);
NS_ENSURE_SUCCESS(rv, rv);
if (popHost.IsEmpty())
return NS_MSG_INVALID_OR_MISSING_SERVER;
rv = aServer->GetPort(&popPort);
NS_ENSURE_SUCCESS(rv, rv);
rv = aServer->GetUsername(popUser);
NS_ENSURE_SUCCESS(rv, rv);
if (popUser.IsEmpty())
return NS_MSG_SERVER_USERNAME_MISSING;
nsCString escapedUsername;
MsgEscapeString(popUser, nsINetUtil::ESCAPE_XALPHAS, escapedUsername);
nsCOMPtr<nsIPop3IncomingServer> popServer = do_QueryInterface(aServer, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// now construct a pop3 url...
// we need to escape the username because it may contain
// characters like / % or @
char *urlSpec = PR_smprintf("pop3://%s@%s:%d/?verifyLogon",
escapedUsername.get(), popHost.get(), popPort);
NS_ENSURE_TRUE(urlSpec, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIURI> url;
rv = BuildPop3Url(urlSpec, nullptr, popServer, aUrlListener,
getter_AddRefs(url), aMsgWindow);
PR_smprintf_free(urlSpec);
if (NS_SUCCEEDED(rv) && url)
{
rv = RunPopUrl(aServer, url);
if (NS_SUCCEEDED(rv) && aURL)
url.forget(aURL);
}
return rv;
}
nsresult nsPop3Service::BuildPop3Url(const char *urlSpec,
nsIMsgFolder *inbox,
nsIPop3IncomingServer *server,
nsIUrlListener *aUrlListener,
nsIURI **aUrl,
nsIMsgWindow *aMsgWindow)
{
nsresult rv;
nsPop3Sink *pop3Sink = new nsPop3Sink();
NS_ENSURE_TRUE(pop3Sink, NS_ERROR_OUT_OF_MEMORY);
pop3Sink->SetPopServer(server);
pop3Sink->SetFolder(inbox);
// now create a pop3 url and a protocol instance to run the url....
nsCOMPtr<nsIPop3URL> pop3Url = do_CreateInstance(kPop3UrlCID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
pop3Url->SetPop3Sink(pop3Sink);
rv = CallQueryInterface(pop3Url, aUrl);
NS_ENSURE_SUCCESS(rv,rv);
rv = (*aUrl)->SetSpec(nsDependentCString(urlSpec));
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsurl = do_QueryInterface(pop3Url);
if (mailnewsurl)
{
if (aUrlListener)
mailnewsurl->RegisterListener(aUrlListener);
if (aMsgWindow)
mailnewsurl->SetMsgWindow(aMsgWindow);
}
return rv;
}
nsresult nsPop3Service::RunPopUrl(nsIMsgIncomingServer *aServer, nsIURI *aUrlToRun)
{
NS_ENSURE_ARG_POINTER(aServer);
NS_ENSURE_ARG_POINTER(aUrlToRun);
nsCString userName;
// load up required server information
// we store the username unescaped in the server
// so there is no need to unescape it
nsresult rv = aServer->GetRealUsername(userName);
// find out if the server is busy or not...if the server is busy, we are
// *NOT* going to run the url
bool serverBusy = false;
rv = aServer->GetServerBusy(&serverBusy);
NS_ENSURE_SUCCESS(rv, rv);
if (!serverBusy)
{
RefPtr<nsPop3Protocol> protocol = new nsPop3Protocol(aUrlToRun);
if (protocol)
{
// the protocol stores the unescaped username, so there is no need to escape it.
protocol->SetUsername(userName.get());
rv = protocol->LoadUrl(aUrlToRun);
if (NS_FAILED(rv))
aServer->SetServerBusy(false);
}
}
else
{
nsCOMPtr<nsIMsgMailNewsUrl> url = do_QueryInterface(aUrlToRun);
if (url)
AlertServerBusy(url);
rv = NS_ERROR_FAILURE;
}
return rv;
}
NS_IMETHODIMP nsPop3Service::GetScheme(nsACString &aScheme)
{
aScheme.AssignLiteral("pop3");
return NS_OK;
}
NS_IMETHODIMP nsPop3Service::GetDefaultPort(int32_t *aDefaultPort)
{
NS_ENSURE_ARG_POINTER(aDefaultPort);
*aDefaultPort = nsIPop3URL::DEFAULT_POP3_PORT;
return NS_OK;
}
NS_IMETHODIMP nsPop3Service::AllowPort(int32_t port, const char *scheme, bool *_retval)
{
*_retval = true; // allow pop on any port
return NS_OK;
}
NS_IMETHODIMP nsPop3Service::GetDefaultDoBiff(bool *aDoBiff)
{
NS_ENSURE_ARG_POINTER(aDoBiff);
// by default, do biff for POP3 servers
*aDoBiff = true;
return NS_OK;
}
NS_IMETHODIMP nsPop3Service::GetProtocolFlags(uint32_t *result)
{
NS_ENSURE_ARG_POINTER(result);
*result = URI_NORELATIVE | URI_DANGEROUS_TO_LOAD | ALLOWS_PROXY |
URI_FORBIDS_COOKIE_ACCESS;
return NS_OK;
}
NS_IMETHODIMP nsPop3Service::NewURI(const nsACString &aSpec,
const char *aOriginCharset, // ignored
nsIURI *aBaseURI,
nsIURI **_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
nsAutoCString folderUri(aSpec);
nsCOMPtr<nsIRDFResource> resource;
int32_t offset = folderUri.FindChar('?');
if (offset != kNotFound)
folderUri.SetLength(offset);
const char *uidl = PL_strstr(nsCString(aSpec).get(), "uidl=");
NS_ENSURE_TRUE(uidl, NS_ERROR_FAILURE);
nsresult rv;
nsCOMPtr<nsIRDFService> rdfService(do_GetService(kRDFServiceCID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = rdfService->GetResource(folderUri, getter_AddRefs(resource));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(resource, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgIncomingServer> server;
nsLocalFolderScanState folderScanState;
nsCOMPtr<nsIMsgLocalMailFolder> localFolder = do_QueryInterface(folder);
nsCOMPtr<nsIMailboxUrl> mailboxUrl = do_QueryInterface(aBaseURI);
if (mailboxUrl && localFolder)
{
rv = localFolder->GetFolderScanState(&folderScanState);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgDBHdr> msgHdr;
nsMsgKey msgKey;
mailboxUrl->GetMessageKey(&msgKey);
folder->GetMessageHeader(msgKey, getter_AddRefs(msgHdr));
// we do this to get the account key
if (msgHdr)
localFolder->GetUidlFromFolder(&folderScanState, msgHdr);
if (!folderScanState.m_accountKey.IsEmpty())
{
nsCOMPtr<nsIMsgAccountManager> accountManager =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
if (accountManager)
{
nsCOMPtr<nsIMsgAccount> account;
accountManager->GetAccount(folderScanState.m_accountKey, getter_AddRefs(account));
if (account)
account->GetIncomingServer(getter_AddRefs(server));
}
}
}
if (!server)
rv = folder->GetServer(getter_AddRefs(server));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPop3IncomingServer> popServer = do_QueryInterface(server,&rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCString hostname;
nsCString username;
server->GetHostName(hostname);
server->GetUsername(username);
int32_t port;
server->GetPort(&port);
if (port == -1) port = nsIPop3URL::DEFAULT_POP3_PORT;
// we need to escape the username because it may contain
// characters like / % or @
nsCString escapedUsername;
MsgEscapeString(username, nsINetUtil::ESCAPE_XALPHAS, escapedUsername);
nsAutoCString popSpec("pop://");
popSpec += escapedUsername;
popSpec += "@";
popSpec += hostname;
popSpec += ":";
popSpec.AppendInt(port);
popSpec += "?";
popSpec += uidl;
nsCOMPtr<nsIUrlListener> urlListener = do_QueryInterface(folder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = BuildPop3Url(popSpec.get(), folder, popServer,
urlListener, _retval, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsurl = do_QueryInterface(*_retval, &rv);
if (NS_SUCCEEDED(rv))
{
// escape the username before we call SetUsername(). we do this because GetUsername()
// will unescape the username
mailnewsurl->SetUsername(escapedUsername);
}
nsCOMPtr<nsIPop3URL> popurl = do_QueryInterface(mailnewsurl, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString messageUri (aSpec);
if (!strncmp(messageUri.get(), "mailbox:", 8))
messageUri.Replace(0, 8, "mailbox-message:");
offset = messageUri.Find("?number=");
if (offset != kNotFound)
messageUri.Replace(offset, 8, "#");
offset = messageUri.FindChar('&');
if (offset != kNotFound)
messageUri.SetLength(offset);
popurl->SetMessageUri(messageUri.get());
nsCOMPtr<nsIPop3Sink> pop3Sink;
rv = popurl->GetPop3Sink(getter_AddRefs(pop3Sink));
NS_ENSURE_SUCCESS(rv, rv);
pop3Sink->SetBuildMessageUri(true);
return NS_OK;
}
void nsPop3Service::AlertServerBusy(nsIMsgMailNewsUrl *url)
{
nsresult rv;
nsCOMPtr<nsIStringBundleService> bundleService =
mozilla::services::GetStringBundleService();
if (!bundleService)
return;
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle("chrome://messenger/locale/localMsgs.properties", getter_AddRefs(bundle));
NS_ENSURE_SUCCESS_VOID(rv);
nsCOMPtr<nsIMsgWindow> msgWindow;
nsCOMPtr<nsIPrompt> dialog;
rv = url->GetMsgWindow(getter_AddRefs(msgWindow)); //it is ok to have null msgWindow, for example when biffing
if (NS_FAILED(rv) || !msgWindow)
return;
rv = msgWindow->GetPromptDialog(getter_AddRefs(dialog));
NS_ENSURE_SUCCESS_VOID(rv);
nsString accountName;
nsCOMPtr<nsIMsgIncomingServer> server;
rv = url->GetServer(getter_AddRefs(server));
NS_ENSURE_SUCCESS_VOID(rv);
rv = server->GetPrettyName(accountName);
NS_ENSURE_SUCCESS_VOID(rv);
const char16_t *params[] = { accountName.get() };
nsString alertString;
nsString dialogTitle;
bundle->FormatStringFromName(
u"pop3ServerBusy",
params, 1, getter_Copies(alertString));
bundle->FormatStringFromName(
u"pop3ErrorDialogTitle",
params, 1, getter_Copies(dialogTitle));
if (!alertString.IsEmpty())
dialog->Alert(dialogTitle.get(), alertString.get());
}
NS_IMETHODIMP nsPop3Service::NewChannel(nsIURI *aURI, nsIChannel **_retval)
{
return NewChannel2(aURI, nullptr, _retval);
}
NS_IMETHODIMP nsPop3Service::NewChannel2(nsIURI *aURI,
nsILoadInfo *aLoadInfo,
nsIChannel **_retval)
{
NS_ENSURE_ARG_POINTER(aURI);
nsresult rv;
nsCOMPtr<nsIMsgMailNewsUrl> url = do_QueryInterface(aURI, &rv);
nsCString realUserName;
if (NS_SUCCEEDED(rv) && url)
{
nsCOMPtr<nsIMsgIncomingServer> server;
url->GetServer(getter_AddRefs(server));
if (server)
{
// find out if the server is busy or not...if the server is busy, we are
// *NOT* going to run the url. The error code isn't quite right...
// We might want to put up an error right here.
bool serverBusy = false;
rv = server->GetServerBusy(&serverBusy);
if (serverBusy)
{
AlertServerBusy(url);
return NS_MSG_FOLDER_BUSY;
}
server->GetRealUsername(realUserName);
}
}
RefPtr<nsPop3Protocol> protocol = new nsPop3Protocol(aURI);
NS_ENSURE_TRUE(protocol, NS_ERROR_OUT_OF_MEMORY);
rv = protocol->Initialize(aURI);
NS_ENSURE_SUCCESS(rv, rv);
rv = protocol->SetLoadInfo(aLoadInfo);
NS_ENSURE_SUCCESS(rv, rv);
protocol->SetUsername(realUserName.get());
return CallQueryInterface(protocol, _retval);
}
NS_IMETHODIMP
nsPop3Service::SetDefaultLocalPath(nsIFile *aPath)
{
NS_ENSURE_ARG(aPath);
return NS_SetPersistentFile(PREF_MAIL_ROOT_POP3_REL, PREF_MAIL_ROOT_POP3, aPath);
}
NS_IMETHODIMP
nsPop3Service::GetDefaultLocalPath(nsIFile **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = nullptr;
bool havePref;
nsCOMPtr<nsIFile> localFile;
nsresult rv = NS_GetPersistentFile(PREF_MAIL_ROOT_POP3_REL,
PREF_MAIL_ROOT_POP3,
NS_APP_MAIL_50_DIR,
havePref,
getter_AddRefs(localFile));
NS_ENSURE_SUCCESS(rv, rv);
bool exists;
rv = localFile->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists)
rv = localFile->Create(nsIFile::DIRECTORY_TYPE, 0775);
NS_ENSURE_SUCCESS(rv, rv);
if (!havePref || !exists) {
rv = NS_SetPersistentFile(PREF_MAIL_ROOT_POP3_REL, PREF_MAIL_ROOT_POP3, localFile);
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set root dir pref.");
}
NS_IF_ADDREF(*aResult = localFile);
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetServerIID(nsIID **aServerIID)
{
*aServerIID = new nsIID(NS_GET_IID(nsIPop3IncomingServer));
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetRequiresUsername(bool *aRequiresUsername)
{
NS_ENSURE_ARG_POINTER(aRequiresUsername);
*aRequiresUsername = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetPreflightPrettyNameWithEmailAddress(bool *aPreflightPrettyNameWithEmailAddress)
{
NS_ENSURE_ARG_POINTER(aPreflightPrettyNameWithEmailAddress);
*aPreflightPrettyNameWithEmailAddress = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetCanLoginAtStartUp(bool *aCanLoginAtStartUp)
{
NS_ENSURE_ARG_POINTER(aCanLoginAtStartUp);
*aCanLoginAtStartUp = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetCanDelete(bool *aCanDelete)
{
NS_ENSURE_ARG_POINTER(aCanDelete);
*aCanDelete = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetCanDuplicate(bool *aCanDuplicate)
{
NS_ENSURE_ARG_POINTER(aCanDuplicate);
*aCanDuplicate = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetCanGetMessages(bool *aCanGetMessages)
{
NS_ENSURE_ARG_POINTER(aCanGetMessages);
*aCanGetMessages = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetCanGetIncomingMessages(bool *aCanGetIncomingMessages)
{
NS_ENSURE_ARG_POINTER(aCanGetIncomingMessages);
*aCanGetIncomingMessages = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetShowComposeMsgLink(bool *showComposeMsgLink)
{
NS_ENSURE_ARG_POINTER(showComposeMsgLink);
*showComposeMsgLink = true;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetFoldersCreatedAsync(bool *aAsyncCreation)
{
NS_ENSURE_ARG_POINTER(aAsyncCreation);
*aAsyncCreation = false;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::GetDefaultServerPort(bool isSecure, int32_t *aPort)
{
NS_ENSURE_ARG_POINTER(aPort);
if (!isSecure)
return GetDefaultPort(aPort);
*aPort = nsIPop3URL::DEFAULT_POP3S_PORT;
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::NotifyDownloadStarted(nsIMsgFolder *aFolder)
{
nsTObserverArray<nsCOMPtr<nsIPop3ServiceListener> >::ForwardIterator
iter(mListeners);
nsCOMPtr<nsIPop3ServiceListener> listener;
while (iter.HasMore()) {
listener = iter.GetNext();
listener->OnDownloadStarted(aFolder);
}
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::NotifyDownloadProgress(nsIMsgFolder *aFolder,
uint32_t aNumMessages,
uint32_t aNumTotalMessages)
{
nsTObserverArray<nsCOMPtr<nsIPop3ServiceListener> >::ForwardIterator
iter(mListeners);
nsCOMPtr<nsIPop3ServiceListener> listener;
while (iter.HasMore()) {
listener = iter.GetNext();
listener->OnDownloadProgress(aFolder, aNumMessages, aNumTotalMessages);
}
return NS_OK;
}
NS_IMETHODIMP
nsPop3Service::NotifyDownloadCompleted(nsIMsgFolder *aFolder,
uint32_t aNumMessages)
{
nsTObserverArray<nsCOMPtr<nsIPop3ServiceListener> >::ForwardIterator
iter(mListeners);
nsCOMPtr<nsIPop3ServiceListener> listener;
while (iter.HasMore()) {
listener = iter.GetNext();
listener->OnDownloadCompleted(aFolder, aNumMessages);
}
return NS_OK;
}
NS_IMETHODIMP nsPop3Service::AddListener(nsIPop3ServiceListener *aListener)
{
NS_ENSURE_ARG_POINTER(aListener);
mListeners.AppendElementUnlessExists(aListener);
return NS_OK;
}
NS_IMETHODIMP nsPop3Service::RemoveListener(nsIPop3ServiceListener *aListener)
{
NS_ENSURE_ARG_POINTER(aListener);
mListeners.RemoveElement(aListener);
return NS_OK;
}

View file

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 4; 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/. */
#ifndef nsPop3Service_h___
#define nsPop3Service_h___
#include "nscore.h"
#include "nsIPop3Service.h"
#include "nsIPop3URL.h"
#include "nsIUrlListener.h"
#include "nsIStreamListener.h"
#include "nsIProtocolHandler.h"
#include "nsIMsgProtocolInfo.h"
#include "nsTObserverArray.h"
class nsIMsgMailNewsUrl;
class nsPop3Service : public nsIPop3Service,
public nsIProtocolHandler,
public nsIMsgProtocolInfo
{
public:
nsPop3Service();
NS_DECL_ISUPPORTS
NS_DECL_NSIPOP3SERVICE
NS_DECL_NSIPROTOCOLHANDLER
NS_DECL_NSIMSGPROTOCOLINFO
protected:
virtual ~nsPop3Service();
nsresult GetMail(bool downloadNewMail,
nsIMsgWindow* aMsgWindow,
nsIUrlListener * aUrlListener,
nsIMsgFolder *inbox,
nsIPop3IncomingServer *popServer,
nsIURI ** aURL);
// convience function to make constructing of the pop3 url easier...
nsresult BuildPop3Url(const char * urlSpec, nsIMsgFolder *inbox,
nsIPop3IncomingServer *, nsIUrlListener * aUrlListener,
nsIURI ** aUrl, nsIMsgWindow *aMsgWindow);
nsresult RunPopUrl(nsIMsgIncomingServer * aServer, nsIURI * aUrlToRun);
void AlertServerBusy(nsIMsgMailNewsUrl *url);
nsTObserverArray<nsCOMPtr<nsIPop3ServiceListener> > mListeners;
};
#endif /* nsPop3Service_h___ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,78 @@
/* -*- 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/. */
#ifndef nsPop3Sink_h__
#define nsPop3Sink_h__
#include "nscore.h"
#include "nsIURL.h"
#include "nsIPop3Sink.h"
#include "nsIOutputStream.h"
#include "prmem.h"
#include "prio.h"
#include "plstr.h"
#include "prenv.h"
#include "nsIMsgFolder.h"
#include "nsAutoPtr.h"
#include "nsTArray.h"
#include "nsStringGlue.h"
class nsParseNewMailState;
class nsIMsgFolder;
struct partialRecord
{
partialRecord();
~partialRecord();
nsCOMPtr<nsIMsgDBHdr> m_msgDBHdr;
nsCString m_uidl;
};
class nsPop3Sink : public nsIPop3Sink
{
public:
nsPop3Sink();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIPOP3SINK
nsresult GetServerFolder(nsIMsgFolder **aFolder);
nsresult FindPartialMessages();
void CheckPartialMessages(nsIPop3Protocol *protocol);
static char* GetDummyEnvelope(void);
protected:
virtual ~nsPop3Sink();
nsresult WriteLineToMailbox(const nsACString& buffer);
nsresult ReleaseFolderLock();
nsresult HandleTempDownloadFailed(nsIMsgWindow *msgWindow);
bool m_authed;
nsCString m_accountUrl;
uint32_t m_biffState;
int32_t m_numNewMessages;
int32_t m_numNewMessagesInFolder;
int32_t m_numMsgsDownloaded;
bool m_senderAuthed;
nsCString m_outputBuffer;
nsCOMPtr<nsIPop3IncomingServer> m_popServer;
//Currently the folder we want to update about biff info
nsCOMPtr<nsIMsgFolder> m_folder;
RefPtr<nsParseNewMailState> m_newMailParser;
nsCOMPtr <nsIOutputStream> m_outFileStream; // the file we write to, which may be temporary
nsCOMPtr<nsIMsgPluggableStore> m_msgStore;
bool m_uidlDownload;
bool m_buildMessageUri;
bool m_downloadingToTempFile;
nsCOMPtr <nsIFile> m_tmpDownloadFile;
nsCOMPtr<nsIMsgWindow> m_window;
nsCString m_messageUri;
nsCString m_baseMessageUri;
nsCString m_origMessageUri;
nsCString m_accountKey;
nsTArray<partialRecord*> m_partialMsgsArray;
};
#endif

View file

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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" // precompiled header...
#include "nsIURL.h"
#include "nsPop3URL.h"
#include "nsPop3Protocol.h"
#include "nsStringGlue.h"
#include "prmem.h"
#include "plstr.h"
#include "prprf.h"
nsPop3URL::nsPop3URL(): nsMsgMailNewsUrl()
{
}
nsPop3URL::~nsPop3URL()
{
}
NS_IMPL_ISUPPORTS_INHERITED(nsPop3URL, nsMsgMailNewsUrl, nsIPop3URL)
////////////////////////////////////////////////////////////////////////////////////
// Begin nsIPop3URL specific support
////////////////////////////////////////////////////////////////////////////////////
nsresult nsPop3URL::SetPop3Sink(nsIPop3Sink* aPop3Sink)
{
if (aPop3Sink)
m_pop3Sink = aPop3Sink;
return NS_OK;
}
nsresult nsPop3URL::GetPop3Sink(nsIPop3Sink** aPop3Sink)
{
if (aPop3Sink)
{
*aPop3Sink = m_pop3Sink;
NS_IF_ADDREF(*aPop3Sink);
}
return NS_OK;
}
NS_IMETHODIMP
nsPop3URL::GetMessageUri(char ** aMessageUri)
{
if(!aMessageUri || m_messageUri.IsEmpty())
return NS_ERROR_NULL_POINTER;
*aMessageUri = ToNewCString(m_messageUri);
return NS_OK;
}
NS_IMETHODIMP
nsPop3URL::SetMessageUri(const char *aMessageUri)
{
if (aMessageUri)
m_messageUri = aMessageUri;
return NS_OK;
}

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsPop3URL_h__
#define nsPop3URL_h__
#include "nsIPop3URL.h"
#include "nsMsgMailNewsUrl.h"
#include "nsIMsgIncomingServer.h"
#include "nsCOMPtr.h"
class nsPop3URL : public nsIPop3URL, public nsMsgMailNewsUrl
{
public:
NS_DECL_NSIPOP3URL
nsPop3URL();
NS_DECL_ISUPPORTS_INHERITED
protected:
virtual ~nsPop3URL();
nsCString m_messageUri;
/* Pop3 specific event sinks */
nsCOMPtr<nsIPop3Sink> m_pop3Sink;
};
#endif // nsPop3URL_h__

View file

@ -0,0 +1,260 @@
/* 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 "nsIRssService.h"
#include "nsRssIncomingServer.h"
#include "nsMsgFolderFlags.h"
#include "nsINewsBlogFeedDownloader.h"
#include "nsMsgBaseCID.h"
#include "nsIFile.h"
#include "nsIMsgFolderNotificationService.h"
#include "nsIMsgLocalMailFolder.h"
#include "nsIDBFolderInfo.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsArrayUtils.h"
#include "nsMsgUtils.h"
nsrefcnt nsRssIncomingServer::gInstanceCount = 0;
NS_IMPL_ISUPPORTS_INHERITED(nsRssIncomingServer,
nsMsgIncomingServer,
nsIRssIncomingServer,
nsIMsgFolderListener,
nsILocalMailIncomingServer)
nsRssIncomingServer::nsRssIncomingServer()
{
m_canHaveFilters = true;
if (gInstanceCount == 0)
{
nsresult rv;
nsCOMPtr<nsIMsgFolderNotificationService> notifyService =
do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
notifyService->AddListener(this,
nsIMsgFolderNotificationService::folderAdded |
nsIMsgFolderNotificationService::folderDeleted |
nsIMsgFolderNotificationService::folderMoveCopyCompleted |
nsIMsgFolderNotificationService::folderRenamed);
}
gInstanceCount++;
}
nsRssIncomingServer::~nsRssIncomingServer()
{
gInstanceCount--;
if (gInstanceCount == 0)
{
nsresult rv;
nsCOMPtr<nsIMsgFolderNotificationService> notifyService =
do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
notifyService->RemoveListener(this);
}
}
nsresult nsRssIncomingServer::FillInDataSourcePath(const nsAString& aDataSourceName,
nsIFile ** aLocation)
{
nsresult rv;
// Get the local path for this server.
nsCOMPtr<nsIFile> localFile;
rv = GetLocalPath(getter_AddRefs(localFile));
NS_ENSURE_SUCCESS(rv, rv);
// Append the name of the subscriptions data source.
rv = localFile->Append(aDataSourceName);
NS_IF_ADDREF(*aLocation = localFile);
return rv;
}
// nsIRSSIncomingServer methods
NS_IMETHODIMP nsRssIncomingServer::GetSubscriptionsDataSourcePath(nsIFile ** aLocation)
{
return FillInDataSourcePath(NS_LITERAL_STRING("feeds.rdf"), aLocation);
}
NS_IMETHODIMP nsRssIncomingServer::GetFeedItemsDataSourcePath(nsIFile ** aLocation)
{
return FillInDataSourcePath(NS_LITERAL_STRING("feeditems.rdf"), aLocation);
}
NS_IMETHODIMP nsRssIncomingServer::CreateDefaultMailboxes()
{
// For Feeds, all we have is Trash.
return CreateLocalFolder(NS_LITERAL_STRING("Trash"));
}
NS_IMETHODIMP nsRssIncomingServer::SetFlagsOnDefaultMailboxes()
{
nsCOMPtr<nsIMsgFolder> rootFolder;
nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgLocalMailFolder> localFolder = do_QueryInterface(rootFolder, &rv);
NS_ENSURE_SUCCESS(rv, rv);
localFolder->SetFlagsOnDefaultMailboxes(nsMsgFolderFlags::Trash);
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::PerformBiff(nsIMsgWindow *aMsgWindow)
{
// Get the account root (server) folder and pass it on.
nsCOMPtr<nsIMsgFolder> rootRSSFolder;
GetRootMsgFolder(getter_AddRefs(rootRSSFolder));
nsCOMPtr<nsIUrlListener> urlListener = do_QueryInterface(rootRSSFolder);
nsresult rv;
bool isBiff = true;
nsCOMPtr<nsINewsBlogFeedDownloader> rssDownloader =
do_GetService("@mozilla.org/newsblog-feed-downloader;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rssDownloader->DownloadFeed(rootRSSFolder, urlListener, isBiff, aMsgWindow);
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::GetNewMail(nsIMsgWindow *aMsgWindow,
nsIUrlListener *aUrlListener,
nsIMsgFolder *aFolder,
nsIURI **_retval)
{
// Pass the selected folder on to the downloader.
NS_ENSURE_ARG_POINTER(aFolder);
nsresult rv;
bool isBiff = false;
nsCOMPtr<nsINewsBlogFeedDownloader> rssDownloader =
do_GetService("@mozilla.org/newsblog-feed-downloader;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rssDownloader->DownloadFeed(aFolder, aUrlListener, isBiff, aMsgWindow);
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::GetAccountManagerChrome(nsAString& aResult)
{
aResult.AssignLiteral("am-newsblog.xul");
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::GetOfflineSupportLevel(int32_t *aSupportLevel)
{
NS_ENSURE_ARG_POINTER(aSupportLevel);
*aSupportLevel = OFFLINE_SUPPORT_LEVEL_NONE;
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::GetSupportsDiskSpace(bool *aSupportsDiskSpace)
{
NS_ENSURE_ARG_POINTER(aSupportsDiskSpace);
*aSupportsDiskSpace = true;
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::GetServerRequiresPasswordForBiff(bool *aServerRequiresPasswordForBiff)
{
NS_ENSURE_ARG_POINTER(aServerRequiresPasswordForBiff);
// For Feed folders, we don't require a password.
*aServerRequiresPasswordForBiff = false;
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::GetCanSearchMessages(bool *canSearchMessages)
{
NS_ENSURE_ARG_POINTER(canSearchMessages);
*canSearchMessages = true;
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::MsgAdded(nsIMsgDBHdr *aMsg)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssIncomingServer::MsgsClassified(nsIArray *aMsgs,
bool aJunkProcessed,
bool aTraitProcessed)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssIncomingServer::MsgsDeleted(nsIArray *aMsgs)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssIncomingServer::MsgsMoveCopyCompleted(bool aMove,
nsIArray *aSrcMsgs,
nsIMsgFolder *aDestFolder,
nsIArray *aDestMsgs)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssIncomingServer::MsgKeyChanged(nsMsgKey aOldKey,
nsIMsgDBHdr *aNewHdr)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssIncomingServer::FolderAdded(nsIMsgFolder *aFolder)
{
// Nothing to do. Not necessary for new folder adds, as a new folder never
// has a subscription.
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::FolderDeleted(nsIMsgFolder *aFolder)
{
// Not necessary for folder deletes, which are move to Trash and handled by
// movecopy. Virtual folder or trash folder deletes send a folderdeleted,
// but these should have no subscriptions already.
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::FolderMoveCopyCompleted(bool aMove,
nsIMsgFolder *aSrcFolder,
nsIMsgFolder *aDestFolder)
{
return FolderChanged(aDestFolder, aSrcFolder, (aMove ? "move" : "copy"));
}
NS_IMETHODIMP nsRssIncomingServer::FolderRenamed(nsIMsgFolder *aOrigFolder,
nsIMsgFolder *aNewFolder)
{
return FolderChanged(aNewFolder, aOrigFolder, "rename");
}
NS_IMETHODIMP nsRssIncomingServer::ItemEvent(nsISupports *aItem,
const nsACString &aEvent,
nsISupports *aData)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsRssIncomingServer::FolderChanged(nsIMsgFolder *aFolder,
nsIMsgFolder *aOrigFolder,
const char *aAction)
{
if (!aFolder)
return NS_OK;
nsresult rv;
nsCOMPtr<nsINewsBlogFeedDownloader> rssDownloader =
do_GetService("@mozilla.org/newsblog-feed-downloader;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rssDownloader->UpdateSubscriptionsDS(aFolder, aOrigFolder, aAction);
return rv;
}
NS_IMETHODIMP
nsRssIncomingServer::GetSortOrder(int32_t* aSortOrder)
{
NS_ENSURE_ARG_POINTER(aSortOrder);
*aSortOrder = 400000000;
return NS_OK;
}

View file

@ -0,0 +1,43 @@
/* 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/. */
#ifndef __nsRssIncomingServer_h
#define __nsRssIncomingServer_h
#include "mozilla/Attributes.h"
#include "nsIRssIncomingServer.h"
#include "nsILocalMailIncomingServer.h"
#include "nsMsgIncomingServer.h"
#include "nsIMsgFolderListener.h"
#include "nsMailboxServer.h"
class nsRssIncomingServer : public nsMailboxServer,
public nsIRssIncomingServer,
public nsILocalMailIncomingServer,
public nsIMsgFolderListener
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIRSSINCOMINGSERVER
NS_DECL_NSILOCALMAILINCOMINGSERVER
NS_DECL_NSIMSGFOLDERLISTENER
NS_IMETHOD GetOfflineSupportLevel(int32_t *aSupportLevel) override;
NS_IMETHOD GetSupportsDiskSpace(bool *aSupportsDiskSpace) override;
NS_IMETHOD GetAccountManagerChrome(nsAString& aResult) override;
NS_IMETHOD PerformBiff(nsIMsgWindow *aMsgWindow) override;
NS_IMETHOD GetServerRequiresPasswordForBiff(bool *aServerRequiresPasswordForBiff) override;
NS_IMETHOD GetCanSearchMessages(bool *canSearchMessages) override;
NS_IMETHOD GetSortOrder(int32_t* aSortOrder) override;
nsRssIncomingServer();
protected:
virtual ~nsRssIncomingServer();
nsresult FolderChanged(nsIMsgFolder *aFolder, nsIMsgFolder *aOrigFolder, const char *aAction);
nsresult FillInDataSourcePath(const nsAString& aDataSourceName, nsIFile ** aLocation);
static nsrefcnt gInstanceCount;
};
#endif /* __nsRssIncomingServer_h */

View file

@ -0,0 +1,130 @@
/* 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 "nsRssService.h"
#include "nsIRssIncomingServer.h"
#include "nsCOMPtr.h"
#include "nsIFile.h"
#include "nsMailDirServiceDefs.h"
#include "nsIProperties.h"
#include "nsServiceManagerUtils.h"
nsRssService::nsRssService()
{
}
nsRssService::~nsRssService()
{
}
NS_IMPL_ISUPPORTS(nsRssService,
nsIRssService,
nsIMsgProtocolInfo)
NS_IMETHODIMP nsRssService::GetDefaultLocalPath(nsIFile * *aDefaultLocalPath)
{
NS_ENSURE_ARG_POINTER(aDefaultLocalPath);
*aDefaultLocalPath = nullptr;
nsCOMPtr<nsIFile> localFile;
nsCOMPtr<nsIProperties> dirService(do_GetService("@mozilla.org/file/directory_service;1"));
if (!dirService) return NS_ERROR_FAILURE;
dirService->Get(NS_APP_MAIL_50_DIR, NS_GET_IID(nsIFile), getter_AddRefs(localFile));
if (!localFile) return NS_ERROR_FAILURE;
bool exists;
nsresult rv = localFile->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists)
rv = localFile->Create(nsIFile::DIRECTORY_TYPE, 0775);
if (NS_FAILED(rv)) return rv;
NS_IF_ADDREF(*aDefaultLocalPath = localFile);
return NS_OK;
}
NS_IMETHODIMP nsRssService::SetDefaultLocalPath(nsIFile * aDefaultLocalPath)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssService::GetServerIID(nsIID * *aServerIID)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssService::GetRequiresUsername(bool *aRequiresUsername)
{
NS_ENSURE_ARG_POINTER(aRequiresUsername);
*aRequiresUsername = false;
return NS_OK;
}
NS_IMETHODIMP nsRssService::GetPreflightPrettyNameWithEmailAddress(bool *aPreflightPrettyNameWithEmailAddress)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssService::GetCanDelete(bool *aCanDelete)
{
NS_ENSURE_ARG_POINTER(aCanDelete);
*aCanDelete = true;
return NS_OK;
}
NS_IMETHODIMP nsRssService::GetCanLoginAtStartUp(bool *aCanLoginAtStartUp)
{
NS_ENSURE_ARG_POINTER(aCanLoginAtStartUp);
*aCanLoginAtStartUp = true;
return NS_OK;
}
NS_IMETHODIMP nsRssService::GetCanDuplicate(bool *aCanDuplicate)
{
NS_ENSURE_ARG_POINTER(aCanDuplicate);
*aCanDuplicate = true;
return NS_OK;
}
NS_IMETHODIMP nsRssService::GetDefaultServerPort(bool isSecure, int32_t *_retval)
{
*_retval = -1;
return NS_OK;
}
NS_IMETHODIMP nsRssService::GetCanGetMessages(bool *aCanGetMessages)
{
NS_ENSURE_ARG_POINTER(aCanGetMessages);
*aCanGetMessages = true;
return NS_OK;
}
NS_IMETHODIMP nsRssService::GetCanGetIncomingMessages(bool *aCanGetIncomingMessages)
{
NS_ENSURE_ARG_POINTER(aCanGetIncomingMessages);
*aCanGetIncomingMessages = true;
return NS_OK;
}
NS_IMETHODIMP nsRssService::GetDefaultDoBiff(bool *aDefaultDoBiff)
{
NS_ENSURE_ARG_POINTER(aDefaultDoBiff);
// by default, do biff for RSS feeds
*aDefaultDoBiff = true;
return NS_OK;
}
NS_IMETHODIMP nsRssService::GetShowComposeMsgLink(bool *aShowComposeMsgLink)
{
NS_ENSURE_ARG_POINTER(aShowComposeMsgLink);
*aShowComposeMsgLink = false;
return NS_OK;
}
NS_IMETHODIMP nsRssService::GetFoldersCreatedAsync(bool *aAsyncCreation)
{
NS_ENSURE_ARG_POINTER(aAsyncCreation);
*aAsyncCreation = false;
return NS_OK;
}

View file

@ -0,0 +1,25 @@
/* 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/. */
#ifndef nsRssService_h___
#define nsRssService_h___
#include "nsIRssService.h"
#include "nsIMsgProtocolInfo.h"
class nsRssService : public nsIMsgProtocolInfo, public nsIRssService
{
public:
nsRssService();
NS_DECL_ISUPPORTS
NS_DECL_NSIRSSSERVICE
NS_DECL_NSIMSGPROTOCOLINFO
private:
virtual ~nsRssService();
};
#endif /* nsRssService_h___ */