mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-25 18:07:31 +09:00
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
This commit is contained in:
parent
23e0d82436
commit
e400f4130a
1564 changed files with 510348 additions and 0 deletions
36
mailnews/local/src/moz.build
Normal file
36
mailnews/local/src/moz.build
Normal 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'
|
||||
|
||||
3852
mailnews/local/src/nsLocalMailFolder.cpp
Normal file
3852
mailnews/local/src/nsLocalMailFolder.cpp
Normal file
File diff suppressed because it is too large
Load diff
276
mailnews/local/src/nsLocalMailFolder.h
Normal file
276
mailnews/local/src/nsLocalMailFolder.h
Normal 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__
|
||||
560
mailnews/local/src/nsLocalUndoTxn.cpp
Normal file
560
mailnews/local/src/nsLocalUndoTxn.cpp
Normal 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;
|
||||
}
|
||||
86
mailnews/local/src/nsLocalUndoTxn.h
Normal file
86
mailnews/local/src/nsLocalUndoTxn.h
Normal 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
|
||||
244
mailnews/local/src/nsLocalUtils.cpp
Normal file
244
mailnews/local/src/nsLocalUtils.cpp
Normal 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
|
||||
}
|
||||
30
mailnews/local/src/nsLocalUtils.h
Normal file
30
mailnews/local/src/nsLocalUtils.h
Normal 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
|
||||
725
mailnews/local/src/nsMailboxProtocol.cpp
Normal file
725
mailnews/local/src/nsMailboxProtocol.cpp
Normal 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
|
||||
125
mailnews/local/src/nsMailboxProtocol.h
Normal file
125
mailnews/local/src/nsMailboxProtocol.h
Normal 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___
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
33
mailnews/local/src/nsMailboxServer.cpp
Normal file
33
mailnews/local/src/nsMailboxServer.cpp
Normal 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;
|
||||
}
|
||||
22
mailnews/local/src/nsMailboxServer.h
Normal file
22
mailnews/local/src/nsMailboxServer.h
Normal 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
|
||||
677
mailnews/local/src/nsMailboxService.cpp
Normal file
677
mailnews/local/src/nsMailboxService.cpp
Normal 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;
|
||||
}
|
||||
57
mailnews/local/src/nsMailboxService.h
Normal file
57
mailnews/local/src/nsMailboxService.h
Normal 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___ */
|
||||
556
mailnews/local/src/nsMailboxUrl.cpp
Normal file
556
mailnews/local/src/nsMailboxUrl.cpp
Normal 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;
|
||||
}
|
||||
110
mailnews/local/src/nsMailboxUrl.h
Normal file
110
mailnews/local/src/nsMailboxUrl.h
Normal 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__
|
||||
178
mailnews/local/src/nsMovemailIncomingServer.cpp
Normal file
178
mailnews/local/src/nsMovemailIncomingServer.cpp
Normal 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;
|
||||
}
|
||||
40
mailnews/local/src/nsMovemailIncomingServer.h
Normal file
40
mailnews/local/src/nsMovemailIncomingServer.h
Normal 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
|
||||
694
mailnews/local/src/nsMovemailService.cpp
Normal file
694
mailnews/local/src/nsMovemailService.cpp
Normal 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;
|
||||
}
|
||||
32
mailnews/local/src/nsMovemailService.h
Normal file
32
mailnews/local/src/nsMovemailService.h
Normal 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___ */
|
||||
1124
mailnews/local/src/nsMsgBrkMBoxStore.cpp
Normal file
1124
mailnews/local/src/nsMsgBrkMBoxStore.cpp
Normal file
File diff suppressed because it is too large
Load diff
50
mailnews/local/src/nsMsgBrkMBoxStore.h
Normal file
50
mailnews/local/src/nsMsgBrkMBoxStore.h
Normal 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
|
||||
345
mailnews/local/src/nsMsgLocalStoreUtils.cpp
Normal file
345
mailnews/local/src/nsMsgLocalStoreUtils.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
49
mailnews/local/src/nsMsgLocalStoreUtils.h
Normal file
49
mailnews/local/src/nsMsgLocalStoreUtils.h
Normal 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
|
||||
1453
mailnews/local/src/nsMsgMaildirStore.cpp
Normal file
1453
mailnews/local/src/nsMsgMaildirStore.cpp
Normal file
File diff suppressed because it is too large
Load diff
38
mailnews/local/src/nsMsgMaildirStore.h
Normal file
38
mailnews/local/src/nsMsgMaildirStore.h
Normal 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
|
||||
206
mailnews/local/src/nsNoIncomingServer.cpp
Normal file
206
mailnews/local/src/nsNoIncomingServer.cpp
Normal 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;
|
||||
}
|
||||
|
||||
41
mailnews/local/src/nsNoIncomingServer.h
Normal file
41
mailnews/local/src/nsNoIncomingServer.h
Normal 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
|
||||
168
mailnews/local/src/nsNoneService.cpp
Normal file
168
mailnews/local/src/nsNoneService.cpp
Normal 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;
|
||||
}
|
||||
28
mailnews/local/src/nsNoneService.h
Normal file
28
mailnews/local/src/nsNoneService.h
Normal 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___ */
|
||||
2624
mailnews/local/src/nsParseMailbox.cpp
Normal file
2624
mailnews/local/src/nsParseMailbox.cpp
Normal file
File diff suppressed because it is too large
Load diff
271
mailnews/local/src/nsParseMailbox.h
Normal file
271
mailnews/local/src/nsParseMailbox.h
Normal 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
|
||||
744
mailnews/local/src/nsPop3IncomingServer.cpp
Normal file
744
mailnews/local/src/nsPop3IncomingServer.cpp
Normal 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;
|
||||
}
|
||||
57
mailnews/local/src/nsPop3IncomingServer.h
Normal file
57
mailnews/local/src/nsPop3IncomingServer.h
Normal 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
|
||||
4176
mailnews/local/src/nsPop3Protocol.cpp
Normal file
4176
mailnews/local/src/nsPop3Protocol.cpp
Normal file
File diff suppressed because it is too large
Load diff
402
mailnews/local/src/nsPop3Protocol.h
Normal file
402
mailnews/local/src/nsPop3Protocol.h
Normal 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__ */
|
||||
711
mailnews/local/src/nsPop3Service.cpp
Normal file
711
mailnews/local/src/nsPop3Service.cpp
Normal 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;
|
||||
}
|
||||
52
mailnews/local/src/nsPop3Service.h
Normal file
52
mailnews/local/src/nsPop3Service.h
Normal 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___ */
|
||||
1026
mailnews/local/src/nsPop3Sink.cpp
Normal file
1026
mailnews/local/src/nsPop3Sink.cpp
Normal file
File diff suppressed because it is too large
Load diff
78
mailnews/local/src/nsPop3Sink.h
Normal file
78
mailnews/local/src/nsPop3Sink.h
Normal 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
|
||||
63
mailnews/local/src/nsPop3URL.cpp
Normal file
63
mailnews/local/src/nsPop3URL.cpp
Normal 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;
|
||||
}
|
||||
30
mailnews/local/src/nsPop3URL.h
Normal file
30
mailnews/local/src/nsPop3URL.h
Normal 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__
|
||||
260
mailnews/local/src/nsRssIncomingServer.cpp
Normal file
260
mailnews/local/src/nsRssIncomingServer.cpp
Normal 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;
|
||||
}
|
||||
43
mailnews/local/src/nsRssIncomingServer.h
Normal file
43
mailnews/local/src/nsRssIncomingServer.h
Normal 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 */
|
||||
130
mailnews/local/src/nsRssService.cpp
Normal file
130
mailnews/local/src/nsRssService.cpp
Normal 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;
|
||||
}
|
||||
25
mailnews/local/src/nsRssService.h
Normal file
25
mailnews/local/src/nsRssService.h
Normal 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___ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue