mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-26 02:17:34 +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
33
mailnews/imap/src/moz.build
Normal file
33
mailnews/imap/src/moz.build
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# 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/.
|
||||
|
||||
EXPORTS += [
|
||||
'nsImapCore.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'nsAutoSyncManager.cpp',
|
||||
'nsAutoSyncState.cpp',
|
||||
'nsIMAPBodyShell.cpp',
|
||||
'nsImapFlagAndUidState.cpp',
|
||||
'nsIMAPGenericParser.cpp',
|
||||
'nsIMAPHostSessionList.cpp',
|
||||
'nsImapIncomingServer.cpp',
|
||||
'nsImapMailFolder.cpp',
|
||||
'nsIMAPNamespace.cpp',
|
||||
'nsImapOfflineSync.cpp',
|
||||
'nsImapProtocol.cpp',
|
||||
'nsImapSearchResults.cpp',
|
||||
'nsImapServerResponseParser.cpp',
|
||||
'nsImapService.cpp',
|
||||
'nsImapStringBundle.cpp',
|
||||
'nsImapUndoTxn.cpp',
|
||||
'nsImapUrl.cpp',
|
||||
'nsImapUtils.cpp',
|
||||
'nsSyncRunnableHelpers.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'mail'
|
||||
|
||||
1412
mailnews/imap/src/nsAutoSyncManager.cpp
Normal file
1412
mailnews/imap/src/nsAutoSyncManager.cpp
Normal file
File diff suppressed because it is too large
Load diff
265
mailnews/imap/src/nsAutoSyncManager.h
Normal file
265
mailnews/imap/src/nsAutoSyncManager.h
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/* 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 nsAutoSyncManager_h__
|
||||
#define nsAutoSyncManager_h__
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIUrlListener.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsIAutoSyncManager.h"
|
||||
#include "nsIAutoSyncMsgStrategy.h"
|
||||
#include "nsIAutoSyncFolderStrategy.h"
|
||||
#include "prtime.h"
|
||||
|
||||
class nsImapMailFolder;
|
||||
class nsIMsgDBHdr;
|
||||
class nsIIdleService;
|
||||
class nsIMsgFolder;
|
||||
|
||||
/* Auto-Sync
|
||||
*
|
||||
* Background:
|
||||
* it works only with offline imap folders. "autosync_offline_stores" pref
|
||||
* enables/disables auto-sync mechanism. Note that setting "autosync_offline_stores"
|
||||
* to false, or setting folder to not-offline doesn't stop synchronization
|
||||
* process for already queued folders.
|
||||
*
|
||||
* Auto-Sync policy:
|
||||
* o It kicks in during system idle time, and tries to download as much messages
|
||||
* as possible based on given folder and message prioritization strategies/rules.
|
||||
* Default folder prioritization strategy dictates to sort the folders based on the
|
||||
* following order: INBOX > DRAFTS > SUBFOLDERS > TRASH.
|
||||
* Similarly, default message prioritization strategy dictates to download the most
|
||||
* recent and smallest message first. Also, by sorting the messages by size in the
|
||||
* queue, it tries to maximize the number of messages downloaded.
|
||||
* o It downloads the messages in groups. Default groups size is defined by |kDefaultGroupSize|.
|
||||
* o It downloads the messages larger than the group size one-by-one.
|
||||
* o If new messages arrive when not idle, it downloads the messages that do fit into
|
||||
* |kFirstGroupSizeLimit| size limit immediately, without waiting for idle time, unless there is
|
||||
* a sibling (a folder owned by the same imap server) in stDownloadInProgress state in the q
|
||||
* o If new messages arrive when idle, it downloads all the messages without any restriction.
|
||||
* o If new messages arrive into a folder while auto-sync is downloading other messages of the
|
||||
* same folder, it simply puts the new messages into the folder's download queue, and
|
||||
* re-prioritize the messages. That behavior makes sure that the high priority
|
||||
* (defined by the message strategy) get downloaded first always.
|
||||
* o If new messages arrive into a folder while auto-sync is downloading messages of a lower
|
||||
* priority folder, auto-sync switches the folders in the queue and starts downloading the
|
||||
* messages of the higher priority folder next time it downloads a message group.
|
||||
* o Currently there is no way to stop/pause/cancel a message download. The smallest
|
||||
* granularity is the message group size.
|
||||
* o Auto-Sync manager periodically (kAutoSyncFreq) checks folder for existing messages
|
||||
* w/o bodies. It persists the last time the folder is checked in the local database of the
|
||||
* folder. We call this process 'Discovery'. This process is asynchronous and processes
|
||||
* |kNumberOfHeadersToProcess| number of headers at each cycle. Since it works on local data,
|
||||
* it doesn't consume lots of system resources, it does its job fast.
|
||||
* o Discovery is necessary especially when the user makes a transition from not-offline
|
||||
* to offline mode.
|
||||
* o Update frequency is defined by nsMsgIncomingServer::BiffMinutes.
|
||||
*
|
||||
* Error Handling:
|
||||
* o if the user moves/deletes/filters all messages of a folder already queued, auto-sync
|
||||
* deals with that situation by skipping the folder in question, and continuing with the
|
||||
* next in chain.
|
||||
* o If the message size is zero, auto-sync ignores the message.
|
||||
* o If the download of the message group fails for some reason, auto-sync tries to
|
||||
* download the same group |kGroupRetryCount| times. If it still fails, continues with the
|
||||
* next group of messages.
|
||||
*
|
||||
* Download Model:
|
||||
* Parallel model should be used with the imap servers that do not have any "max number of sessions
|
||||
* per IP" limit, and when the bandwidth is significantly large.
|
||||
*
|
||||
* How it really works:
|
||||
* The AutoSyncManager gets an idle notification. First it processes any
|
||||
* folders in the discovery queue (which means it schedules message download
|
||||
* for any messages it previously determined it should download). Then it sets
|
||||
* a timer, and in the timer callback, it processes the update q, by calling
|
||||
* InitiateAutoSync on the first folder in the update q.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default strategy implementation to prioritize messages in the download queue.
|
||||
*/
|
||||
class nsDefaultAutoSyncMsgStrategy final : public nsIAutoSyncMsgStrategy
|
||||
{
|
||||
static const uint32_t kFirstPassMessageSize = 60U*1024U; // 60K
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIAUTOSYNCMSGSTRATEGY
|
||||
|
||||
nsDefaultAutoSyncMsgStrategy();
|
||||
|
||||
private:
|
||||
~nsDefaultAutoSyncMsgStrategy();
|
||||
};
|
||||
|
||||
/**
|
||||
* Default strategy implementation to prioritize folders in the download queue.
|
||||
*/
|
||||
class nsDefaultAutoSyncFolderStrategy final : public nsIAutoSyncFolderStrategy
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIAUTOSYNCFOLDERSTRATEGY
|
||||
|
||||
nsDefaultAutoSyncFolderStrategy();
|
||||
|
||||
private:
|
||||
~nsDefaultAutoSyncFolderStrategy();
|
||||
};
|
||||
|
||||
// see the end of the page for auto-sync internals
|
||||
|
||||
/**
|
||||
* Manages background message download operations for offline imap folders.
|
||||
*/
|
||||
class nsAutoSyncManager final : public nsIObserver,
|
||||
public nsIUrlListener,
|
||||
public nsIAutoSyncManager
|
||||
{
|
||||
static const PRTime kAutoSyncFreq = 60UL * (PR_USEC_PER_SEC * 60UL); // 1hr
|
||||
static const uint32_t kDefaultUpdateInterval = 10UL; // 10min
|
||||
static const int32_t kTimerIntervalInMs = 400;
|
||||
static const uint32_t kNumberOfHeadersToProcess = 250U;
|
||||
// enforced size of the first group that will be downloaded before idle time
|
||||
static const uint32_t kFirstGroupSizeLimit = 60U*1024U /* 60K */;
|
||||
static const int32_t kIdleTimeInSec = 10;
|
||||
static const uint32_t kGroupRetryCount = 3;
|
||||
|
||||
enum IdleState { systemIdle, appIdle, notIdle };
|
||||
enum UpdateState { initiated, completed };
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIURLLISTENER
|
||||
NS_DECL_NSIAUTOSYNCMANAGER
|
||||
|
||||
nsAutoSyncManager();
|
||||
|
||||
private:
|
||||
~nsAutoSyncManager();
|
||||
|
||||
void SetIdleState(IdleState st);
|
||||
IdleState GetIdleState() const;
|
||||
nsresult StartIdleProcessing();
|
||||
nsresult AutoUpdateFolders();
|
||||
void ScheduleFolderForOfflineDownload(nsIAutoSyncState *aAutoSyncStateObj);
|
||||
nsresult DownloadMessagesForOffline(nsIAutoSyncState *aAutoSyncStateObj, uint32_t aSizeLimit = 0);
|
||||
nsresult HandleDownloadErrorFor(nsIAutoSyncState *aAutoSyncStateObj, const nsresult error);
|
||||
|
||||
// Helper methods for priority Q operations
|
||||
static
|
||||
void ChainFoldersInQ(const nsCOMArray<nsIAutoSyncState> &aQueue,
|
||||
nsCOMArray<nsIAutoSyncState> &aChainedQ);
|
||||
static
|
||||
nsIAutoSyncState* SearchQForSibling(const nsCOMArray<nsIAutoSyncState> &aQueue,
|
||||
nsIAutoSyncState *aAutoSyncStateObj, int32_t aStartIdx, int32_t *aIndex = nullptr);
|
||||
static
|
||||
bool DoesQContainAnySiblingOf(const nsCOMArray<nsIAutoSyncState> &aQueue,
|
||||
nsIAutoSyncState *aAutoSyncStateObj, const int32_t aState,
|
||||
int32_t *aIndex = nullptr);
|
||||
static
|
||||
nsIAutoSyncState* GetNextSibling(const nsCOMArray<nsIAutoSyncState> &aQueue,
|
||||
nsIAutoSyncState *aAutoSyncStateObj, int32_t *aIndex = nullptr);
|
||||
static
|
||||
nsIAutoSyncState* GetHighestPrioSibling(const nsCOMArray<nsIAutoSyncState> &aQueue,
|
||||
nsIAutoSyncState *aAutoSyncStateObj, int32_t *aIndex = nullptr);
|
||||
|
||||
/// timer to process existing keys and updates
|
||||
void InitTimer();
|
||||
static void TimerCallback(nsITimer *aTimer, void *aClosure);
|
||||
void StopTimer();
|
||||
void StartTimerIfNeeded();
|
||||
|
||||
/// pref helpers
|
||||
uint32_t GetUpdateIntervalFor(nsIAutoSyncState *aAutoSyncStateObj);
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIAutoSyncMsgStrategy> mMsgStrategyImpl;
|
||||
nsCOMPtr<nsIAutoSyncFolderStrategy> mFolderStrategyImpl;
|
||||
// contains the folders that will be downloaded on background
|
||||
nsCOMArray<nsIAutoSyncState> mPriorityQ;
|
||||
// contains the folders that will be examined for existing headers and
|
||||
// adds the headers we don't have offline into the autosyncState
|
||||
// object's download queue.
|
||||
nsCOMArray<nsIAutoSyncState> mDiscoveryQ;
|
||||
// contains the folders that will be checked for new messages with STATUS,
|
||||
// and if there are any, we'll call UpdateFolder on them.
|
||||
nsCOMArray<nsIAutoSyncState> mUpdateQ;
|
||||
// this is the update state for the current folder.
|
||||
UpdateState mUpdateState;
|
||||
|
||||
// This is set if auto sync has been completely paused.
|
||||
bool mPaused;
|
||||
// This is set if we've finished startup and should start
|
||||
// paying attention to idle notifications.
|
||||
bool mStartupDone;
|
||||
|
||||
private:
|
||||
uint32_t mGroupSize;
|
||||
IdleState mIdleState;
|
||||
int32_t mDownloadModel;
|
||||
nsCOMPtr<nsIIdleService> mIdleService;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsTObserverArray<nsCOMPtr<nsIAutoSyncMgrListener> > mListeners;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
How queues inter-relate:
|
||||
|
||||
nsAutoSyncState has an internal priority queue to store messages waiting to be
|
||||
downloaded. nsAutoSyncMsgStrategy object determines the order in this queue,
|
||||
nsAutoSyncManager uses this queue to manage downloads. Two events cause a
|
||||
change in this queue:
|
||||
|
||||
1) nsImapMailFolder::HeaderFetchCompleted: is triggered when TB notices that
|
||||
there are pending messages on the server -- via IDLE command from the server,
|
||||
via explicit select from the user, or via automatic Update during idle time. If
|
||||
it turns out that there are pending messages on the server, it adds them into
|
||||
nsAutoSyncState's download queue.
|
||||
|
||||
2) nsAutoSyncState::ProcessExistingHeaders: is triggered for every imap folder
|
||||
every hour or so (see kAutoSyncFreq). nsAutoSyncManager uses an internal queue called Discovery
|
||||
queue to keep track of this task. The purpose of ProcessExistingHeaders()
|
||||
method is to check existing headers of a given folder in batches and discover
|
||||
the messages without bodies, in asynchronous fashion. This process is
|
||||
sequential, one and only one folder at any given time, very similar to
|
||||
indexing. Again, if it turns out that the folder in hand has messages w/o
|
||||
bodies, ProcessExistingHeaders adds them into nsAutoSyncState's download queue.
|
||||
|
||||
Any change in nsAutoSyncState's download queue, notifies nsAutoSyncManager and
|
||||
nsAutoSyncManager puts the requesting nsAutoSyncState into its internal
|
||||
priority queue (called mPriorityQ) -- if the folder is not already there.
|
||||
nsAutoSyncFolderStrategy object determines the order in this queue. This queue
|
||||
is processed in two modes: chained and parallel.
|
||||
|
||||
i) Chained: One folder per imap server any given time. Folders owned by
|
||||
different imap servers are simultaneous.
|
||||
|
||||
ii) Parallel: All folders at the same time, using all cached-connections -
|
||||
a.k.a 'Folders gone wild' mode.
|
||||
|
||||
The order the folders are added into the mPriorityQ doesn't matter since every
|
||||
time a batch completed for an imap server, nsAutoSyncManager adjusts the order.
|
||||
So, lets say that updating a sub-folder starts downloading message immediately,
|
||||
when an higher priority folder is added into the queue, nsAutoSyncManager
|
||||
switches to this higher priority folder instead of processing the next group of
|
||||
messages of the lower priority one. Setting group size too high might delay
|
||||
this switch at worst.
|
||||
|
||||
And finally, Update queue helps nsAutoSyncManager to keep track of folders
|
||||
waiting to be updated. With the latest change, we update one and only one
|
||||
folder at any given time. Default frequency of updating is 10 min (kDefaultUpdateInterval).
|
||||
We add folders into the update queue during idle time, if they are not in mPriorityQ already.
|
||||
|
||||
*/
|
||||
765
mailnews/imap/src/nsAutoSyncState.cpp
Normal file
765
mailnews/imap/src/nsAutoSyncState.cpp
Normal file
|
|
@ -0,0 +1,765 @@
|
|||
/* 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 "nsAutoSyncState.h"
|
||||
#include "nsImapMailFolder.h"
|
||||
#include "nsMsgImapCID.h"
|
||||
#include "nsIMsgMailNewsUrl.h"
|
||||
#include "nsMsgKeyArray.h"
|
||||
#include "nsIMsgWindow.h"
|
||||
#include "nsIMsgMailSession.h"
|
||||
#include "nsMsgFolderFlags.h"
|
||||
#include "nsIAutoSyncManager.h"
|
||||
#include "nsIAutoSyncMsgStrategy.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
extern PRLogModuleInfo *gAutoSyncLog;
|
||||
|
||||
MsgStrategyComparatorAdaptor::MsgStrategyComparatorAdaptor(nsIAutoSyncMsgStrategy* aStrategy,
|
||||
nsIMsgFolder *aFolder, nsIMsgDatabase *aDatabase) : mStrategy(aStrategy), mFolder(aFolder),
|
||||
mDatabase(aDatabase)
|
||||
{
|
||||
}
|
||||
|
||||
/** @return True if the elements are equals; false otherwise. */
|
||||
bool MsgStrategyComparatorAdaptor::Equals(const nsMsgKey& a, const nsMsgKey& b) const
|
||||
{
|
||||
nsCOMPtr<nsIMsgDBHdr> hdrA;
|
||||
nsCOMPtr<nsIMsgDBHdr> hdrB;
|
||||
|
||||
mDatabase->GetMsgHdrForKey(a, getter_AddRefs(hdrA));
|
||||
mDatabase->GetMsgHdrForKey(b, getter_AddRefs(hdrB));
|
||||
|
||||
if (hdrA && hdrB)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
nsAutoSyncStrategyDecisionType decision = nsAutoSyncStrategyDecisions::Same;
|
||||
|
||||
nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(mFolder);
|
||||
if (mStrategy)
|
||||
rv = mStrategy->Sort(folder, hdrA, hdrB, &decision);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return (decision == nsAutoSyncStrategyDecisions::Same);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @return True if (a < b); false otherwise. */
|
||||
bool MsgStrategyComparatorAdaptor::LessThan(const nsMsgKey& a, const nsMsgKey& b) const
|
||||
{
|
||||
nsCOMPtr<nsIMsgDBHdr> hdrA;
|
||||
nsCOMPtr<nsIMsgDBHdr> hdrB;
|
||||
|
||||
mDatabase->GetMsgHdrForKey(a, getter_AddRefs(hdrA));
|
||||
mDatabase->GetMsgHdrForKey(b, getter_AddRefs(hdrB));
|
||||
|
||||
if (hdrA && hdrB)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
nsAutoSyncStrategyDecisionType decision = nsAutoSyncStrategyDecisions::Same;
|
||||
|
||||
nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(mFolder);
|
||||
if (mStrategy)
|
||||
rv = mStrategy->Sort(folder, hdrA, hdrB, &decision);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return (decision == nsAutoSyncStrategyDecisions::Lower);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoSyncState::nsAutoSyncState(nsImapMailFolder *aOwnerFolder, PRTime aLastSyncTime)
|
||||
: mSyncState(stCompletedIdle), mOffset(0U), mLastOffset(0U), mLastServerTotal(0),
|
||||
mLastServerRecent(0), mLastServerUnseen(0), mLastNextUID(0),
|
||||
mLastSyncTime(aLastSyncTime), mLastUpdateTime(0UL), mProcessPointer(0U),
|
||||
mIsDownloadQChanged(false), mRetryCounter(0U)
|
||||
{
|
||||
mOwnerFolder = do_GetWeakReference(static_cast<nsIMsgImapMailFolder*>(aOwnerFolder));
|
||||
}
|
||||
|
||||
nsAutoSyncState::~nsAutoSyncState()
|
||||
{
|
||||
}
|
||||
|
||||
// TODO:XXXemre should be implemented when we start
|
||||
// doing space management
|
||||
nsresult nsAutoSyncState::ManageStorageSpace()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsAutoSyncState::PlaceIntoDownloadQ(const nsTArray<nsMsgKey> &aMsgKeyList)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (!aMsgKeyList.IsEmpty())
|
||||
{
|
||||
nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIMsgDatabase> database;
|
||||
rv = folder->GetMsgDatabase(getter_AddRefs(database));
|
||||
if (!database)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsCOMPtr<nsIAutoSyncMsgStrategy> msgStrategy;
|
||||
autoSyncMgr->GetMsgStrategy(getter_AddRefs(msgStrategy));
|
||||
|
||||
// increase the array size
|
||||
mDownloadQ.SetCapacity(mDownloadQ.Length() + aMsgKeyList.Length());
|
||||
|
||||
// remove excluded messages
|
||||
int32_t elemCount = aMsgKeyList.Length();
|
||||
for (int32_t idx = 0; idx < elemCount; idx++)
|
||||
{
|
||||
nsCOMPtr<nsIMsgDBHdr> hdr;
|
||||
bool containsKey;
|
||||
database->ContainsKey(aMsgKeyList[idx], &containsKey);
|
||||
if (!containsKey)
|
||||
continue;
|
||||
rv = database->GetMsgHdrForKey(aMsgKeyList[idx], getter_AddRefs(hdr));
|
||||
if(!hdr)
|
||||
continue; // can't get message header, continue with the next one
|
||||
|
||||
bool doesFit = true;
|
||||
rv = autoSyncMgr->DoesMsgFitDownloadCriteria(hdr, &doesFit);
|
||||
if (NS_SUCCEEDED(rv) && !mDownloadSet.Contains(aMsgKeyList[idx]) && doesFit)
|
||||
{
|
||||
bool excluded = false;
|
||||
if (msgStrategy)
|
||||
{
|
||||
rv = msgStrategy->IsExcluded(folder, hdr, &excluded);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !excluded)
|
||||
{
|
||||
mIsDownloadQChanged = true;
|
||||
mDownloadSet.PutEntry(aMsgKeyList[idx]);
|
||||
mDownloadQ.AppendElement(aMsgKeyList[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}//endfor
|
||||
|
||||
if (mIsDownloadQChanged)
|
||||
{
|
||||
LogOwnerFolderName("Download Q is created for ");
|
||||
LogQWithSize(mDownloadQ, 0);
|
||||
rv = autoSyncMgr->OnDownloadQChanged(this);
|
||||
}
|
||||
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsAutoSyncState::SortQueueBasedOnStrategy(nsTArray<nsMsgKey> &aQueue)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIMsgDatabase> database;
|
||||
rv = folder->GetMsgDatabase(getter_AddRefs(database));
|
||||
if (!database)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIAutoSyncMsgStrategy> msgStrategy;
|
||||
rv = autoSyncMgr->GetMsgStrategy(getter_AddRefs(msgStrategy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MsgStrategyComparatorAdaptor strategyComp(msgStrategy, folder, database);
|
||||
aQueue.Sort(strategyComp);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// This method is a hack to prioritize newly inserted messages,
|
||||
// without changing the size of the queue. It is required since
|
||||
// we cannot sort ranges in nsTArray.
|
||||
nsresult nsAutoSyncState::SortSubQueueBasedOnStrategy(nsTArray<nsMsgKey> &aQueue,
|
||||
uint32_t aStartingOffset)
|
||||
{
|
||||
NS_ASSERTION(aStartingOffset < aQueue.Length(), "*** Starting offset is out of range");
|
||||
|
||||
// Copy already downloaded messages into a temporary queue,
|
||||
// we want to exclude them from the sort.
|
||||
nsTArray<nsMsgKey> tmpQ;
|
||||
tmpQ.AppendElements(aQueue.Elements(), aStartingOffset);
|
||||
|
||||
// Remove already downloaded messages and sort the resulting queue
|
||||
aQueue.RemoveElementsAt(0, aStartingOffset);
|
||||
|
||||
nsresult rv = SortQueueBasedOnStrategy(aQueue);
|
||||
|
||||
// copy excluded messages back
|
||||
aQueue.InsertElementsAt(0, tmpQ);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::GetNextGroupOfMessages(uint32_t aSuggestedGroupSizeLimit,
|
||||
uint32_t *aActualGroupSize,
|
||||
nsIMutableArray **aMessagesList)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aMessagesList);
|
||||
NS_ENSURE_ARG_POINTER(aActualGroupSize);
|
||||
|
||||
*aActualGroupSize = 0;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIMsgDatabase> database;
|
||||
folder->GetMsgDatabase(getter_AddRefs(database));
|
||||
|
||||
nsCOMPtr<nsIMutableArray> group = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||
if (database)
|
||||
{
|
||||
if (!mDownloadQ.IsEmpty())
|
||||
{
|
||||
// sort the download queue if new items are added since the last time
|
||||
if (mIsDownloadQChanged)
|
||||
{
|
||||
// we want to sort only pending messages. mOffset is
|
||||
// the position of the first pending message in the download queue
|
||||
rv = (mOffset > 0)
|
||||
? SortSubQueueBasedOnStrategy(mDownloadQ, mOffset)
|
||||
: SortQueueBasedOnStrategy(mDownloadQ);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mIsDownloadQChanged = false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t msgCount = mDownloadQ.Length();
|
||||
uint32_t idx = mOffset;
|
||||
|
||||
nsCOMPtr<nsIAutoSyncMsgStrategy> msgStrategy;
|
||||
autoSyncMgr->GetMsgStrategy(getter_AddRefs(msgStrategy));
|
||||
|
||||
for (; idx < msgCount; idx++)
|
||||
{
|
||||
bool containsKey = false;
|
||||
database->ContainsKey(mDownloadQ[idx], &containsKey);
|
||||
if (!containsKey)
|
||||
{
|
||||
mDownloadSet.RemoveEntry(mDownloadQ[idx]);
|
||||
mDownloadQ.RemoveElementAt(idx--);
|
||||
msgCount--;
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsIMsgDBHdr> qhdr;
|
||||
database->GetMsgHdrForKey(mDownloadQ[idx], getter_AddRefs(qhdr));
|
||||
if(!qhdr)
|
||||
continue; //maybe deleted, skip it!
|
||||
|
||||
// ensure that we don't have this message body offline already,
|
||||
// possible if the user explicitly selects this message prior
|
||||
// to auto-sync kicks in
|
||||
bool hasMessageOffline;
|
||||
folder->HasMsgOffline(mDownloadQ[idx], &hasMessageOffline);
|
||||
if (hasMessageOffline)
|
||||
continue;
|
||||
|
||||
// this check point allows msg strategy function
|
||||
// to do last minute decisions based on the current
|
||||
// state of TB such as the size of the message store etc.
|
||||
if (msgStrategy)
|
||||
{
|
||||
bool excluded = false;
|
||||
if (NS_SUCCEEDED(msgStrategy->IsExcluded(folder, qhdr, &excluded)) && excluded)
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t msgSize;
|
||||
qhdr->GetMessageSize(&msgSize);
|
||||
// ignore 0 byte messages; the imap parser asserts when we try
|
||||
// to download them, and there's no point anyway.
|
||||
if (!msgSize)
|
||||
continue;
|
||||
|
||||
if (!*aActualGroupSize && msgSize >= aSuggestedGroupSizeLimit)
|
||||
{
|
||||
*aActualGroupSize = msgSize;
|
||||
group->AppendElement(qhdr, false);
|
||||
idx++;
|
||||
break;
|
||||
}
|
||||
else if ((*aActualGroupSize) + msgSize > aSuggestedGroupSizeLimit)
|
||||
break;
|
||||
else
|
||||
{
|
||||
group->AppendElement(qhdr, false);
|
||||
*aActualGroupSize += msgSize;
|
||||
}
|
||||
}// endfor
|
||||
|
||||
mLastOffset = mOffset;
|
||||
mOffset = idx;
|
||||
}
|
||||
|
||||
LogOwnerFolderName("Next group of messages to be downloaded.");
|
||||
LogQWithSize(group.get(), 0);
|
||||
} //endif
|
||||
|
||||
// return it to the caller
|
||||
NS_IF_ADDREF(*aMessagesList = group);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Usually called by nsAutoSyncManager when the last sync time is expired.
|
||||
*/
|
||||
NS_IMETHODIMP nsAutoSyncState::ProcessExistingHeaders(uint32_t aNumOfHdrsToProcess, uint32_t *aLeftToProcess)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aLeftToProcess);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIMsgDatabase> database;
|
||||
rv = folder->GetMsgDatabase(getter_AddRefs(database));
|
||||
if (!database)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// create a queue to process existing headers for the first time
|
||||
if (mExistingHeadersQ.IsEmpty())
|
||||
{
|
||||
RefPtr<nsMsgKeyArray> keys = new nsMsgKeyArray;
|
||||
rv = database->ListAllKeys(keys);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
keys->Sort();
|
||||
mExistingHeadersQ.AppendElements(keys->m_keys);
|
||||
mProcessPointer = 0;
|
||||
}
|
||||
|
||||
// process the existing headers and find the messages not downloaded yet
|
||||
uint32_t lastIdx = mProcessPointer;
|
||||
nsTArray<nsMsgKey> msgKeys;
|
||||
uint32_t keyCount = mExistingHeadersQ.Length();
|
||||
for (; mProcessPointer < (lastIdx + aNumOfHdrsToProcess) && mProcessPointer < keyCount; mProcessPointer++)
|
||||
{
|
||||
bool hasMessageOffline;
|
||||
folder->HasMsgOffline(mExistingHeadersQ[mProcessPointer], &hasMessageOffline);
|
||||
if (!hasMessageOffline)
|
||||
msgKeys.AppendElement(mExistingHeadersQ[mProcessPointer]);
|
||||
}
|
||||
if (!msgKeys.IsEmpty())
|
||||
{
|
||||
nsCString folderName;
|
||||
folder->GetURI(folderName);
|
||||
MOZ_LOG(gAutoSyncLog, LogLevel::Debug,
|
||||
("%d messages will be added into the download q of folder %s\n",
|
||||
msgKeys.Length(), folderName.get()));
|
||||
|
||||
rv = PlaceIntoDownloadQ(msgKeys);
|
||||
if (NS_FAILED(rv))
|
||||
mProcessPointer = lastIdx;
|
||||
}
|
||||
|
||||
*aLeftToProcess = keyCount - mProcessPointer;
|
||||
|
||||
// cleanup if we are done processing
|
||||
if (0 == *aLeftToProcess)
|
||||
{
|
||||
mLastSyncTime = PR_Now();
|
||||
mExistingHeadersQ.Clear();
|
||||
mProcessPointer = 0;
|
||||
folder->SetMsgDatabase(nullptr);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nsAutoSyncState::OnNewHeaderFetchCompleted(const nsTArray<nsMsgKey> &aMsgKeyList)
|
||||
{
|
||||
SetLastUpdateTime(PR_Now());
|
||||
if (!aMsgKeyList.IsEmpty())
|
||||
PlaceIntoDownloadQ(aMsgKeyList);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::UpdateFolder()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIUrlListener> autoSyncMgrListener = do_QueryInterface(autoSyncMgr, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
SetState(nsAutoSyncState::stUpdateIssued);
|
||||
return imapFolder->UpdateFolderWithListener(nullptr, autoSyncMgrListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::OnStartRunningUrl(nsIURI* aUrl)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// if there is a problem to start the download, set rv with the
|
||||
// corresponding error code. In that case, AutoSyncManager is going to
|
||||
// set the autosync state to nsAutoSyncState::stReadyToDownload
|
||||
// to resume downloading another time
|
||||
|
||||
// TODO: is there a way to make sure that download started without
|
||||
// problem through nsIURI interface?
|
||||
|
||||
nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return autoSyncMgr->OnDownloadStarted(this, rv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::OnStopRunningUrl(nsIURI* aUrl, nsresult aExitCode)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIUrlListener> autoSyncMgrListener = do_QueryInterface(autoSyncMgr, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mSyncState == stStatusIssued)
|
||||
{
|
||||
nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int32_t serverTotal, serverUnseen, serverRecent, serverNextUID;
|
||||
imapFolder->GetServerTotal(&serverTotal);
|
||||
imapFolder->GetServerUnseen(&serverUnseen);
|
||||
imapFolder->GetServerRecent(&serverRecent);
|
||||
imapFolder->GetServerNextUID(&serverNextUID);
|
||||
if (serverNextUID != mLastNextUID || serverTotal != mLastServerTotal ||
|
||||
serverUnseen != mLastServerUnseen || serverRecent != mLastServerRecent)
|
||||
{
|
||||
nsCString folderName;
|
||||
ownerFolder->GetURI(folderName);
|
||||
MOZ_LOG(gAutoSyncLog, LogLevel::Debug,
|
||||
("folder %s status changed serverNextUID = %lx lastNextUID = %lx\n", folderName.get(),
|
||||
serverNextUID, mLastNextUID));
|
||||
MOZ_LOG(gAutoSyncLog, LogLevel::Debug,
|
||||
("serverTotal = %lx lastServerTotal = %lx serverRecent = %lx lastServerRecent = %lx\n",
|
||||
serverTotal, mLastServerTotal, serverRecent, mLastServerRecent));
|
||||
SetServerCounts(serverTotal, serverRecent, serverUnseen, serverNextUID);
|
||||
SetState(nsAutoSyncState::stUpdateIssued);
|
||||
return imapFolder->UpdateFolderWithListener(nullptr, autoSyncMgrListener);
|
||||
}
|
||||
else
|
||||
{
|
||||
ownerFolder->SetMsgDatabase(nullptr);
|
||||
// nothing more to do.
|
||||
SetState(nsAutoSyncState::stCompletedIdle);
|
||||
// autoSyncMgr needs this notification, so manufacture it.
|
||||
return autoSyncMgrListener->OnStopRunningUrl(nullptr, NS_OK);
|
||||
}
|
||||
}
|
||||
//XXXemre how we recover from this error?
|
||||
rv = ownerFolder->ReleaseSemaphore(ownerFolder);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "*** Cannot release folder semaphore");
|
||||
|
||||
nsCOMPtr<nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(aUrl);
|
||||
if (mailUrl)
|
||||
rv = mailUrl->UnRegisterListener(this);
|
||||
|
||||
return autoSyncMgr->OnDownloadCompleted(this, aExitCode);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::GetState(int32_t *aState)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aState);
|
||||
*aState = mSyncState;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const char *stateStrings[] = {"idle", "status issued", "update needed",
|
||||
"update issued", "downloading",
|
||||
"ready to download"};
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::SetState(int32_t aState)
|
||||
{
|
||||
mSyncState = aState;
|
||||
if (aState == stCompletedIdle)
|
||||
{
|
||||
ResetDownloadQ();
|
||||
//tell folder to let go of its cached msg db pointer
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMsgMailSession> session =
|
||||
do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv) && session)
|
||||
{
|
||||
nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool folderOpen;
|
||||
uint32_t folderFlags;
|
||||
ownerFolder->GetFlags(&folderFlags);
|
||||
session->IsFolderOpenInWindow(ownerFolder, &folderOpen);
|
||||
if (!folderOpen && ! (folderFlags & nsMsgFolderFlags::Inbox))
|
||||
ownerFolder->SetMsgDatabase(nullptr);
|
||||
}
|
||||
}
|
||||
nsCString logStr("Sync State set to ");
|
||||
logStr.Append(stateStrings[aState]);
|
||||
logStr.Append(" for ");
|
||||
LogOwnerFolderName(logStr.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::TryCurrentGroupAgain(uint32_t aRetryCount)
|
||||
{
|
||||
SetState(stReadyToDownload);
|
||||
|
||||
nsresult rv;
|
||||
if (++mRetryCounter > aRetryCount)
|
||||
{
|
||||
ResetRetryCounter();
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
else
|
||||
rv = Rollback();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::ResetRetryCounter()
|
||||
{
|
||||
mRetryCounter = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::GetPendingMessageCount(int32_t *aMsgCount)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aMsgCount);
|
||||
*aMsgCount = mDownloadQ.Length() - mOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::GetTotalMessageCount(int32_t *aMsgCount)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aMsgCount);
|
||||
*aMsgCount = mDownloadQ.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::GetOwnerFolder(nsIMsgFolder **aFolder)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFolder);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_IF_ADDREF(*aFolder = ownerFolder);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::Rollback()
|
||||
{
|
||||
mOffset = mLastOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::ResetDownloadQ()
|
||||
{
|
||||
mOffset = mLastOffset = 0;
|
||||
mDownloadSet.Clear();
|
||||
mDownloadQ.Clear();
|
||||
mDownloadQ.Compact();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the given folder is owned by the same imap server
|
||||
* or not.
|
||||
*/
|
||||
NS_IMETHODIMP nsAutoSyncState::IsSibling(nsIAutoSyncState *aAnotherStateObj, bool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = false;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMsgFolder> folderA, folderB;
|
||||
|
||||
rv = GetOwnerFolder(getter_AddRefs(folderA));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = aAnotherStateObj->GetOwnerFolder(getter_AddRefs(folderB));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsCOMPtr <nsIMsgIncomingServer> serverA, serverB;
|
||||
rv = folderA->GetServer(getter_AddRefs(serverA));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = folderB->GetServer(getter_AddRefs(serverB));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
bool isSibling;
|
||||
rv = serverA->Equals(serverB, &isSibling);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
*aResult = isSibling;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::DownloadMessagesForOffline(nsIArray *aMessagesList)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aMessagesList);
|
||||
|
||||
uint32_t count;
|
||||
nsresult rv = aMessagesList->GetLength(&count);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsAutoCString messageIds;
|
||||
nsTArray<nsMsgKey> msgKeys;
|
||||
|
||||
rv = nsImapMailFolder::BuildIdsAndKeyArray(aMessagesList, messageIds, msgKeys);
|
||||
if (NS_FAILED(rv) || messageIds.IsEmpty())
|
||||
return rv;
|
||||
|
||||
// acquire semaphore for offline store. If it fails, we won't download
|
||||
nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = folder->AcquireSemaphore(folder);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString folderName;
|
||||
folder->GetURI(folderName);
|
||||
MOZ_LOG(gAutoSyncLog, LogLevel::Debug, ("downloading %s for %s", messageIds.get(),
|
||||
folderName.get()));
|
||||
// start downloading
|
||||
rv = imapService->DownloadMessagesForOffline(messageIds,
|
||||
folder,
|
||||
this,
|
||||
nullptr);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
SetState(stDownloadInProgress);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::GetLastSyncTime(PRTime *aLastSyncTime)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aLastSyncTime);
|
||||
*aLastSyncTime = mLastSyncTime;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsAutoSyncState::SetLastSyncTimeInSec(int32_t aLastSyncTime)
|
||||
{
|
||||
mLastSyncTime = ((PRTime)aLastSyncTime * PR_USEC_PER_SEC);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::GetLastUpdateTime(PRTime *aLastUpdateTime)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aLastUpdateTime);
|
||||
*aLastUpdateTime = mLastUpdateTime;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAutoSyncState::SetLastUpdateTime(PRTime aLastUpdateTime)
|
||||
{
|
||||
mLastUpdateTime = aLastUpdateTime;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsAutoSyncState::SetServerCounts(int32_t total, int32_t recent,
|
||||
int32_t unseen, int32_t nextUID)
|
||||
{
|
||||
mLastServerTotal = total;
|
||||
mLastServerRecent = recent;
|
||||
mLastServerUnseen = unseen;
|
||||
mLastNextUID = nextUID;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAutoSyncState, nsIAutoSyncState, nsIUrlListener)
|
||||
|
||||
|
||||
void nsAutoSyncState::LogQWithSize(nsTArray<nsMsgKey>& q, uint32_t toOffset)
|
||||
{
|
||||
nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder);
|
||||
if (ownerFolder)
|
||||
{
|
||||
nsCOMPtr<nsIMsgDatabase> database;
|
||||
ownerFolder->GetMsgDatabase(getter_AddRefs(database));
|
||||
|
||||
uint32_t x = q.Length();
|
||||
while (x > toOffset && database)
|
||||
{
|
||||
x--;
|
||||
nsCOMPtr<nsIMsgDBHdr> h;
|
||||
database->GetMsgHdrForKey(q[x], getter_AddRefs(h));
|
||||
uint32_t s;
|
||||
if (h)
|
||||
{
|
||||
h->GetMessageSize(&s);
|
||||
MOZ_LOG(gAutoSyncLog, LogLevel::Debug,
|
||||
("Elem #%d, size: %u bytes\n", x+1, s));
|
||||
}
|
||||
else
|
||||
MOZ_LOG(gAutoSyncLog, LogLevel::Debug, ("unable to get header for key %ul", q[x]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsAutoSyncState::LogQWithSize(nsIMutableArray *q, uint32_t toOffset)
|
||||
{
|
||||
nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder);
|
||||
if (ownerFolder)
|
||||
{
|
||||
nsCOMPtr<nsIMsgDatabase> database;
|
||||
ownerFolder->GetMsgDatabase(getter_AddRefs(database));
|
||||
|
||||
uint32_t x;
|
||||
q->GetLength(&x);
|
||||
while (x > toOffset && database)
|
||||
{
|
||||
x--;
|
||||
nsCOMPtr<nsIMsgDBHdr> h;
|
||||
q->QueryElementAt(x, NS_GET_IID(nsIMsgDBHdr),
|
||||
getter_AddRefs(h));
|
||||
uint32_t s;
|
||||
if (h)
|
||||
{
|
||||
h->GetMessageSize(&s);
|
||||
MOZ_LOG(gAutoSyncLog, LogLevel::Debug,
|
||||
("Elem #%d, size: %u bytes\n", x+1, s));
|
||||
}
|
||||
else
|
||||
MOZ_LOG(gAutoSyncLog, LogLevel::Debug, ("null header in q at index %ul", x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsAutoSyncState::LogOwnerFolderName(const char *s)
|
||||
{
|
||||
nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder);
|
||||
if (ownerFolder)
|
||||
{
|
||||
nsCString folderName;
|
||||
ownerFolder->GetURI(folderName);
|
||||
MOZ_LOG(gAutoSyncLog, LogLevel::Debug,
|
||||
("*** %s Folder: %s ***\n", s, folderName.get()));
|
||||
}
|
||||
}
|
||||
107
mailnews/imap/src/nsAutoSyncState.h
Normal file
107
mailnews/imap/src/nsAutoSyncState.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/* 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 nsAutoSyncState_h__
|
||||
#define nsAutoSyncState_h__
|
||||
|
||||
#include "MailNewsTypes.h"
|
||||
#include "nsIAutoSyncState.h"
|
||||
#include "nsIAutoSyncManager.h"
|
||||
#include "nsIUrlListener.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsTArray.h"
|
||||
#include "prlog.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
|
||||
class nsImapMailFolder;
|
||||
class nsIAutoSyncMsgStrategy;
|
||||
class nsIMsgDatabase;
|
||||
|
||||
/**
|
||||
* An adaptor class to make msg strategy nsTArray.Sort()
|
||||
* compatible.
|
||||
*/
|
||||
class MsgStrategyComparatorAdaptor
|
||||
{
|
||||
public:
|
||||
MsgStrategyComparatorAdaptor(nsIAutoSyncMsgStrategy* aStrategy,
|
||||
nsIMsgFolder *aFolder, nsIMsgDatabase *aDatabase);
|
||||
|
||||
/** @return True if the elements are equals; false otherwise. */
|
||||
bool Equals(const nsMsgKey& a, const nsMsgKey& b) const;
|
||||
|
||||
/** @return True if (a < b); false otherwise. */
|
||||
bool LessThan(const nsMsgKey& a, const nsMsgKey& b) const;
|
||||
|
||||
private:
|
||||
MsgStrategyComparatorAdaptor();
|
||||
|
||||
private:
|
||||
nsIAutoSyncMsgStrategy *mStrategy;
|
||||
nsIMsgFolder *mFolder;
|
||||
nsIMsgDatabase *mDatabase;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Facilitates auto-sync capabilities for imap folders.
|
||||
*/
|
||||
class nsAutoSyncState final : public nsIAutoSyncState, public nsIUrlListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIAUTOSYNCSTATE
|
||||
NS_DECL_NSIURLLISTENER
|
||||
|
||||
nsAutoSyncState(nsImapMailFolder *aOwnerFolder, PRTime aLastSyncTime = 0UL);
|
||||
|
||||
/// Called by owner folder when new headers are fetched from the server
|
||||
void OnNewHeaderFetchCompleted(const nsTArray<nsMsgKey> &aMsgKeyList);
|
||||
|
||||
/// Sets the last sync time in lower precision (seconds)
|
||||
void SetLastSyncTimeInSec(int32_t aLastSyncTime);
|
||||
|
||||
/// Manages storage space for auto-sync operations
|
||||
nsresult ManageStorageSpace();
|
||||
|
||||
void SetServerCounts(int32_t total, int32_t recent, int32_t unseen,
|
||||
int32_t nextUID);
|
||||
|
||||
private:
|
||||
~nsAutoSyncState();
|
||||
|
||||
nsresult PlaceIntoDownloadQ(const nsTArray<nsMsgKey> &aMsgKeyList);
|
||||
nsresult SortQueueBasedOnStrategy(nsTArray<nsMsgKey> &aQueue);
|
||||
nsresult SortSubQueueBasedOnStrategy(nsTArray<nsMsgKey> &aQueue,
|
||||
uint32_t aStartingOffset);
|
||||
|
||||
void LogOwnerFolderName(const char *s);
|
||||
void LogQWithSize(nsTArray<nsMsgKey>& q, uint32_t toOffset = 0);
|
||||
void LogQWithSize(nsIMutableArray *q, uint32_t toOffset = 0);
|
||||
|
||||
private:
|
||||
int32_t mSyncState;
|
||||
nsWeakPtr mOwnerFolder;
|
||||
uint32_t mOffset;
|
||||
uint32_t mLastOffset;
|
||||
|
||||
// used to tell if the Server counts have changed.
|
||||
int32_t mLastServerTotal;
|
||||
int32_t mLastServerRecent;
|
||||
int32_t mLastServerUnseen;
|
||||
int32_t mLastNextUID;
|
||||
|
||||
PRTime mLastSyncTime;
|
||||
PRTime mLastUpdateTime;
|
||||
uint32_t mProcessPointer;
|
||||
bool mIsDownloadQChanged;
|
||||
uint32_t mRetryCounter;
|
||||
nsTHashtable<nsUint32HashKey> mDownloadSet;
|
||||
nsTArray<nsMsgKey> mDownloadQ;
|
||||
nsTArray<nsMsgKey> mExistingHeadersQ;
|
||||
};
|
||||
|
||||
#endif
|
||||
1333
mailnews/imap/src/nsIMAPBodyShell.cpp
Normal file
1333
mailnews/imap/src/nsIMAPBodyShell.cpp
Normal file
File diff suppressed because it is too large
Load diff
361
mailnews/imap/src/nsIMAPBodyShell.h
Normal file
361
mailnews/imap/src/nsIMAPBodyShell.h
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/*
|
||||
nsIMAPBodyShell and associated classes
|
||||
*/
|
||||
|
||||
#ifndef IMAPBODY_H
|
||||
#define IMAPBODY_H
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsImapCore.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsImapProtocol;
|
||||
|
||||
typedef enum _nsIMAPBodypartType {
|
||||
IMAP_BODY_MESSAGE_RFC822,
|
||||
IMAP_BODY_MESSAGE_HEADER,
|
||||
IMAP_BODY_LEAF,
|
||||
IMAP_BODY_MULTIPART
|
||||
} nsIMAPBodypartType;
|
||||
|
||||
class nsIMAPBodyShell;
|
||||
class nsIMAPBodypartMessage;
|
||||
|
||||
class nsIMAPBodypart
|
||||
{
|
||||
public:
|
||||
// Construction
|
||||
virtual bool GetIsValid() { return m_isValid; }
|
||||
virtual void SetIsValid(bool valid);
|
||||
virtual nsIMAPBodypartType GetType() = 0;
|
||||
|
||||
// Generation
|
||||
// Generates an HTML representation of this part. Returns content length generated, -1 if failed.
|
||||
virtual int32_t Generate(nsIMAPBodyShell *aShell, bool /*stream*/, bool /* prefetch */) { return -1; }
|
||||
virtual void AdoptPartDataBuffer(char *buf); // Adopts storage for part data buffer. If NULL, sets isValid to false.
|
||||
virtual void AdoptHeaderDataBuffer(char *buf); // Adopts storage for header data buffer. If NULL, sets isValid to false.
|
||||
virtual bool ShouldFetchInline(nsIMAPBodyShell *aShell) { return true; } // returns true if this part should be fetched inline for generation.
|
||||
virtual bool PreflightCheckAllInline(nsIMAPBodyShell *aShell) { return true; }
|
||||
|
||||
virtual bool ShouldExplicitlyFetchInline();
|
||||
virtual bool ShouldExplicitlyNotFetchInline();
|
||||
virtual bool IsLastTextPart(const char *partNumberString) {return true;}
|
||||
|
||||
protected:
|
||||
// If stream is false, simply returns the content length that will be generated
|
||||
// the body of the part itself
|
||||
virtual int32_t GeneratePart(nsIMAPBodyShell *aShell, bool stream, bool prefetch);
|
||||
// the MIME headers of the part
|
||||
virtual int32_t GenerateMIMEHeader(nsIMAPBodyShell *aShell, bool stream, bool prefetch);
|
||||
// Generates the MIME boundary wrapper for this part.
|
||||
virtual int32_t GenerateBoundary(nsIMAPBodyShell *aShell, bool stream, bool prefetch, bool lastBoundary);
|
||||
// lastBoundary indicates whether or not this should be the boundary for the
|
||||
// final MIME part of the multipart message.
|
||||
// Generates (possibly empty) filling for a part that won't be filled in inline.
|
||||
virtual int32_t GenerateEmptyFilling(nsIMAPBodyShell *aShell, bool stream, bool prefetch);
|
||||
|
||||
// Part Numbers / Hierarchy
|
||||
public:
|
||||
virtual char *GetPartNumberString() { return m_partNumberString; }
|
||||
virtual nsIMAPBodypart *FindPartWithNumber(const char *partNum); // Returns the part object with the given number
|
||||
virtual nsIMAPBodypart *GetParentPart() { return m_parentPart; } // Returns the parent of this part.
|
||||
// We will define a part of type message/rfc822 to be the
|
||||
// parent of its body and header.
|
||||
// A multipart is a parent of its child parts.
|
||||
// All other leafs do not have children.
|
||||
|
||||
// Other / Helpers
|
||||
public:
|
||||
virtual ~nsIMAPBodypart();
|
||||
virtual nsIMAPBodypartMessage *GetnsIMAPBodypartMessage() { return NULL; }
|
||||
|
||||
const char *GetBodyType() { return m_bodyType; }
|
||||
const char *GetBodySubType() { return m_bodySubType; }
|
||||
void SetBoundaryData(char *boundaryData) { m_boundaryData = boundaryData; }
|
||||
|
||||
protected:
|
||||
virtual void QueuePrefetchMIMEHeader(nsIMAPBodyShell *aShell);
|
||||
//virtual void PrefetchMIMEHeader(); // Initiates a prefetch for the MIME header of this part.
|
||||
nsIMAPBodypart(char *partNumber, nsIMAPBodypart *parentPart);
|
||||
|
||||
protected:
|
||||
bool m_isValid; // If this part is valid.
|
||||
char *m_partNumberString; // string representation of this part's full-hierarchy number. Define 0 to be the top-level message
|
||||
char *m_partData; // data for this part. NULL if not filled in yet.
|
||||
char *m_headerData; // data for this part's MIME header. NULL if not filled in yet.
|
||||
char *m_boundaryData; // MIME boundary for this part
|
||||
int32_t m_partLength;
|
||||
int32_t m_contentLength; // Total content length which will be Generate()'d. -1 if not filled in yet.
|
||||
nsIMAPBodypart *m_parentPart; // Parent of this part
|
||||
|
||||
// Fields - Filled in from parsed BODYSTRUCTURE response (as well as others)
|
||||
char *m_contentType; // constructed from m_bodyType and m_bodySubType
|
||||
char *m_bodyType;
|
||||
char *m_bodySubType;
|
||||
char *m_bodyID;
|
||||
char *m_bodyDescription;
|
||||
char *m_bodyEncoding;
|
||||
// we ignore extension data for now
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Message headers
|
||||
// A special type of nsIMAPBodypart
|
||||
// These may be headers for the top-level message,
|
||||
// or any body part of type message/rfc822.
|
||||
class nsIMAPMessageHeaders : public nsIMAPBodypart
|
||||
{
|
||||
public:
|
||||
nsIMAPMessageHeaders(char *partNum, nsIMAPBodypart *parentPart);
|
||||
virtual nsIMAPBodypartType GetType() override;
|
||||
// Generates an HTML representation of this part. Returns content length generated, -1 if failed.
|
||||
virtual int32_t Generate(nsIMAPBodyShell *aShell, bool stream,
|
||||
bool prefetch) override;
|
||||
virtual bool ShouldFetchInline(nsIMAPBodyShell *aShell) override;
|
||||
virtual void QueuePrefetchMessageHeaders(nsIMAPBodyShell *aShell);
|
||||
};
|
||||
|
||||
|
||||
class nsIMAPBodypartMultipart : public nsIMAPBodypart
|
||||
{
|
||||
public:
|
||||
nsIMAPBodypartMultipart(char *partNum, nsIMAPBodypart *parentPart);
|
||||
virtual nsIMAPBodypartType GetType() override;
|
||||
virtual ~nsIMAPBodypartMultipart();
|
||||
virtual bool ShouldFetchInline(nsIMAPBodyShell *aShell) override;
|
||||
virtual bool PreflightCheckAllInline(nsIMAPBodyShell *aShell) override;
|
||||
// Generates an HTML representation of this part. Returns content length generated, -1 if failed.
|
||||
virtual int32_t Generate(nsIMAPBodyShell *aShell, bool stream,
|
||||
bool prefetch) override;
|
||||
// Returns the part object with the given number
|
||||
virtual nsIMAPBodypart *FindPartWithNumber(const char *partNum
|
||||
) override;
|
||||
virtual bool IsLastTextPart(const char *partNumberString) override;
|
||||
void AppendPart(nsIMAPBodypart *part) { m_partList->AppendElement(part); }
|
||||
void SetBodySubType(char *bodySubType);
|
||||
|
||||
protected:
|
||||
nsTArray<nsIMAPBodypart*> *m_partList; // An ordered list of top-level body parts for this shell
|
||||
};
|
||||
|
||||
|
||||
// The name "leaf" is somewhat misleading, since a part of type message/rfc822 is technically
|
||||
// a leaf, even though it can contain other parts within it.
|
||||
class nsIMAPBodypartLeaf : public nsIMAPBodypart
|
||||
{
|
||||
public:
|
||||
nsIMAPBodypartLeaf(char *partNum, nsIMAPBodypart *parentPart, char *bodyType,
|
||||
char *bodySubType, char *bodyID, char *bodyDescription,
|
||||
char *bodyEncoding, int32_t partLength,
|
||||
bool preferPlainText);
|
||||
virtual nsIMAPBodypartType GetType() override;
|
||||
// Generates an HTML representation of this part. Returns content length generated, -1 if failed.
|
||||
virtual int32_t Generate(nsIMAPBodyShell *aShell, bool stream, bool prefetch) override;
|
||||
// returns true if this part should be fetched inline for generation.
|
||||
virtual bool ShouldFetchInline(nsIMAPBodyShell *aShell) override;
|
||||
virtual bool PreflightCheckAllInline(nsIMAPBodyShell *aShell) override;
|
||||
private:
|
||||
bool mPreferPlainText;
|
||||
};
|
||||
|
||||
|
||||
class nsIMAPBodypartMessage : public nsIMAPBodypartLeaf
|
||||
{
|
||||
public:
|
||||
nsIMAPBodypartMessage(char *partNum, nsIMAPBodypart *parentPart,
|
||||
bool topLevelMessage, char *bodyType,
|
||||
char *bodySubType, char *bodyID,
|
||||
char *bodyDescription, char *bodyEncoding,
|
||||
int32_t partLength, bool preferPlainText);
|
||||
void SetBody(nsIMAPBodypart *body);
|
||||
virtual nsIMAPBodypartType GetType() override;
|
||||
virtual ~nsIMAPBodypartMessage();
|
||||
virtual int32_t Generate(nsIMAPBodyShell *aShell, bool stream,
|
||||
bool prefetch) override;
|
||||
virtual bool ShouldFetchInline(nsIMAPBodyShell *aShell) override;
|
||||
virtual bool PreflightCheckAllInline(nsIMAPBodyShell *aShell) override;
|
||||
// Returns the part object with the given number
|
||||
virtual nsIMAPBodypart *FindPartWithNumber(const char *partNum
|
||||
) override;
|
||||
void AdoptMessageHeaders(char *headers); // Fills in buffer (and adopts storage) for header object
|
||||
// partNum specifies the message part number to which the
|
||||
// headers correspond. NULL indicates the top-level message
|
||||
virtual nsIMAPBodypartMessage *GetnsIMAPBodypartMessage() override { return this; }
|
||||
virtual bool GetIsTopLevelMessage() { return m_topLevelMessage; }
|
||||
|
||||
protected:
|
||||
nsIMAPMessageHeaders *m_headers; // Every body shell should have headers
|
||||
nsIMAPBodypart *m_body;
|
||||
bool m_topLevelMessage; // Whether or not this is the top-level message
|
||||
|
||||
};
|
||||
|
||||
|
||||
class nsIMAPMessagePartIDArray;
|
||||
|
||||
// We will refer to a Body "Shell" as a hierarchical object representation of a parsed BODYSTRUCTURE
|
||||
// response. A shell contains representations of Shell "Parts." A Body Shell can undergo essentially
|
||||
// two operations: Construction and Generation.
|
||||
// Shell Construction occurs from a parsed a BODYSTRUCTURE response, split into empty parts.
|
||||
// Shell Generation generates a "MIME Shell" of the message and streams it to libmime for
|
||||
// display. The MIME Shell has selected (inline) parts filled in, and leaves all others
|
||||
// for on-demand retrieval through explicit part fetches.
|
||||
|
||||
class nsIMAPBodyShell : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
nsIMAPBodyShell(nsImapProtocol *protocolConnection,
|
||||
nsIMAPBodypartMessage *message, uint32_t UID,
|
||||
const char *folderName);
|
||||
// To be used after a shell is uncached
|
||||
void SetConnection(nsImapProtocol *con) { m_protocolConnection = con; }
|
||||
virtual bool GetIsValid() { return m_isValid; }
|
||||
virtual void SetIsValid(bool valid);
|
||||
|
||||
// Prefetch
|
||||
// Adds a message body part to the queue to be prefetched
|
||||
// in a single, pipelined command
|
||||
void AddPrefetchToQueue(nsIMAPeFetchFields, const char *partNum);
|
||||
// Runs a single pipelined command which fetches all of the
|
||||
// elements in the prefetch queue
|
||||
void FlushPrefetchQueue();
|
||||
// Fills in buffer (and adopts storage) for header object
|
||||
// partNum specifies the message part number to which the
|
||||
// headers correspond. NULL indicates the top-level message
|
||||
void AdoptMessageHeaders(char *headers, const char *partNum);
|
||||
// Fills in buffer (and adopts storage) for MIME headers in appropriate object.
|
||||
// If object can't be found, sets isValid to false.
|
||||
void AdoptMimeHeader(const char *partNum, char *mimeHeader);
|
||||
|
||||
// Generation
|
||||
// Streams out an HTML representation of this IMAP message, going along and
|
||||
// fetching parts it thinks it needs, and leaving empty shells for the parts
|
||||
// it doesn't.
|
||||
// Returns number of bytes generated, or -1 if invalid.
|
||||
// If partNum is not NULL, then this works to generates a MIME part that hasn't been downloaded yet
|
||||
// and leaves out all other parts. By default, to generate a normal message, partNum should be NULL.
|
||||
virtual int32_t Generate(char *partNum);
|
||||
|
||||
// Returns TRUE if the user has the pref "Show Attachments Inline" set.
|
||||
// Returns FALSE if the setting is "Show Attachments as Links"
|
||||
virtual bool GetShowAttachmentsInline();
|
||||
// Returns true if all parts are inline, false otherwise. Does not generate anything.
|
||||
bool PreflightCheckAllInline();
|
||||
|
||||
// Helpers
|
||||
nsImapProtocol *GetConnection() { return m_protocolConnection; }
|
||||
bool GetPseudoInterrupted();
|
||||
bool DeathSignalReceived();
|
||||
nsCString &GetUID() { return m_UID; }
|
||||
const char *GetFolderName() { return m_folderName; }
|
||||
char *GetGeneratingPart() { return m_generatingPart; }
|
||||
// Returns true if this is in the process of being generated,
|
||||
// so we don't re-enter
|
||||
bool IsBeingGenerated() { return m_isBeingGenerated; }
|
||||
bool IsShellCached() { return m_cached; }
|
||||
void SetIsCached(bool isCached) { m_cached = isCached; }
|
||||
bool GetGeneratingWholeMessage() { return m_generatingWholeMessage; }
|
||||
IMAP_ContentModifiedType GetContentModified() { return m_contentModified; }
|
||||
void SetContentModified(IMAP_ContentModifiedType modType) { m_contentModified = modType; }
|
||||
protected:
|
||||
virtual ~nsIMAPBodyShell();
|
||||
|
||||
nsIMAPBodypartMessage *m_message;
|
||||
|
||||
nsIMAPMessagePartIDArray *m_prefetchQueue; // array of pipelined part prefetches. Ok, so it's not really a queue.
|
||||
|
||||
bool m_isValid;
|
||||
nsImapProtocol *m_protocolConnection; // Connection, for filling in parts
|
||||
nsCString m_UID; // UID of this message
|
||||
char *m_folderName; // folder that contains this message
|
||||
char *m_generatingPart; // If a specific part is being generated, this is it. Otherwise, NULL.
|
||||
bool m_isBeingGenerated; // true if this body shell is in the process of being generated
|
||||
bool m_gotAttachmentPref; // Whether or not m_showAttachmentsInline has been initialized
|
||||
bool m_showAttachmentsInline; // Whether or not we should display attachment inline
|
||||
bool m_cached; // Whether or not this shell is cached
|
||||
bool m_generatingWholeMessage; // whether or not we are generating the whole (non-MPOD) message
|
||||
// Set to false if we are generating by parts
|
||||
// under what conditions the content has been modified.
|
||||
// Either IMAP_CONTENT_MODIFIED_VIEW_INLINE or IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS
|
||||
IMAP_ContentModifiedType m_contentModified;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// This class caches shells, so we don't have to always go and re-fetch them.
|
||||
// This does not cache any of the filled-in inline parts; those are cached individually
|
||||
// in the libnet memory cache. (ugh, how will we do that?)
|
||||
// Since we'll only be retrieving shells for messages over a given size, and since the
|
||||
// shells themselves won't be very large, this cache will not grow very big (relatively)
|
||||
// and should handle most common usage scenarios.
|
||||
|
||||
// A body cache is associated with a given host, spanning folders.
|
||||
// It should pay attention to UIDVALIDITY.
|
||||
|
||||
class nsIMAPBodyShellCache
|
||||
{
|
||||
public:
|
||||
static nsIMAPBodyShellCache *Create();
|
||||
virtual ~nsIMAPBodyShellCache();
|
||||
|
||||
// Adds shell to cache, possibly ejecting
|
||||
// another entry based on scheme in EjectEntry().
|
||||
bool AddShellToCache(nsIMAPBodyShell *shell);
|
||||
// Looks up a shell in the cache given the message's UID.
|
||||
nsIMAPBodyShell *FindShellForUID(nsCString &UID, const char *mailboxName,
|
||||
IMAP_ContentModifiedType modType);
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
nsIMAPBodyShellCache();
|
||||
// Chooses an entry to eject; deletes that entry; and ejects it from the
|
||||
// cache, clearing up a new space. Returns true if it found an entry
|
||||
// to eject, false otherwise.
|
||||
bool EjectEntry();
|
||||
uint32_t GetSize() { return m_shellList->Length(); }
|
||||
uint32_t GetMaxSize() { return 20; }
|
||||
nsTArray<nsIMAPBodyShell*> *m_shellList; // For maintenance
|
||||
// For quick lookup based on UID
|
||||
nsRefPtrHashtable <nsCStringHashKey, nsIMAPBodyShell> m_shellHash;
|
||||
};
|
||||
|
||||
// MessagePartID and MessagePartIDArray are used for pipelining prefetches.
|
||||
|
||||
class nsIMAPMessagePartID
|
||||
{
|
||||
public:
|
||||
nsIMAPMessagePartID(nsIMAPeFetchFields fields, const char *partNumberString);
|
||||
nsIMAPeFetchFields GetFields() { return m_fields; }
|
||||
const char *GetPartNumberString() { return m_partNumberString; }
|
||||
|
||||
protected:
|
||||
const char *m_partNumberString;
|
||||
nsIMAPeFetchFields m_fields;
|
||||
};
|
||||
|
||||
|
||||
class nsIMAPMessagePartIDArray : public nsTArray<nsIMAPMessagePartID*> {
|
||||
public:
|
||||
nsIMAPMessagePartIDArray();
|
||||
~nsIMAPMessagePartIDArray();
|
||||
|
||||
void RemoveAndFreeAll();
|
||||
uint32_t GetNumParts() { return Length(); }
|
||||
nsIMAPMessagePartID *GetPart(uint32_t i)
|
||||
{
|
||||
NS_ASSERTION(i < Length(), "invalid message part #");
|
||||
return ElementAt(i);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // IMAPBODY_H
|
||||
484
mailnews/imap/src/nsIMAPGenericParser.cpp
Normal file
484
mailnews/imap/src/nsIMAPGenericParser.cpp
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
/* -*- 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" // for pre-compiled headers
|
||||
|
||||
#include "nsImapCore.h"
|
||||
#include "nsImapProtocol.h"
|
||||
#include "nsIMAPGenericParser.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
////////////////// nsIMAPGenericParser /////////////////////////
|
||||
|
||||
|
||||
nsIMAPGenericParser::nsIMAPGenericParser() :
|
||||
fNextToken(nullptr),
|
||||
fCurrentLine(nullptr),
|
||||
fLineOfTokens(nullptr),
|
||||
fStartOfLineOfTokens(nullptr),
|
||||
fCurrentTokenPlaceHolder(nullptr),
|
||||
fAtEndOfLine(false),
|
||||
fParserState(stateOK)
|
||||
{
|
||||
}
|
||||
|
||||
nsIMAPGenericParser::~nsIMAPGenericParser()
|
||||
{
|
||||
PR_FREEIF( fCurrentLine );
|
||||
PR_FREEIF( fStartOfLineOfTokens);
|
||||
}
|
||||
|
||||
void nsIMAPGenericParser::HandleMemoryFailure()
|
||||
{
|
||||
SetConnected(false);
|
||||
}
|
||||
|
||||
void nsIMAPGenericParser::ResetLexAnalyzer()
|
||||
{
|
||||
PR_FREEIF( fCurrentLine );
|
||||
PR_FREEIF( fStartOfLineOfTokens );
|
||||
|
||||
fNextToken = fCurrentLine = fLineOfTokens = fStartOfLineOfTokens = fCurrentTokenPlaceHolder = nullptr;
|
||||
fAtEndOfLine = false;
|
||||
}
|
||||
|
||||
bool nsIMAPGenericParser::LastCommandSuccessful()
|
||||
{
|
||||
return fParserState == stateOK;
|
||||
}
|
||||
|
||||
void nsIMAPGenericParser::SetSyntaxError(bool error, const char *msg)
|
||||
{
|
||||
if (error)
|
||||
fParserState |= stateSyntaxErrorFlag;
|
||||
else
|
||||
fParserState &= ~stateSyntaxErrorFlag;
|
||||
NS_ASSERTION(!error, "syntax error in generic parser");
|
||||
}
|
||||
|
||||
void nsIMAPGenericParser::SetConnected(bool connected)
|
||||
{
|
||||
if (connected)
|
||||
fParserState &= ~stateDisconnectedFlag;
|
||||
else
|
||||
fParserState |= stateDisconnectedFlag;
|
||||
}
|
||||
|
||||
void nsIMAPGenericParser::skip_to_CRLF()
|
||||
{
|
||||
while (Connected() && !fAtEndOfLine)
|
||||
AdvanceToNextToken();
|
||||
}
|
||||
|
||||
// fNextToken initially should point to
|
||||
// a string after the initial open paren ("(")
|
||||
// After this call, fNextToken points to the
|
||||
// first character after the matching close
|
||||
// paren. Only call AdvanceToNextToken() to get the NEXT
|
||||
// token after the one returned in fNextToken.
|
||||
void nsIMAPGenericParser::skip_to_close_paren()
|
||||
{
|
||||
int numberOfCloseParensNeeded = 1;
|
||||
while (ContinueParse())
|
||||
{
|
||||
// go through fNextToken, account for nested parens
|
||||
const char *loc;
|
||||
for (loc = fNextToken; loc && *loc; loc++)
|
||||
{
|
||||
if (*loc == '(')
|
||||
numberOfCloseParensNeeded++;
|
||||
else if (*loc == ')')
|
||||
{
|
||||
numberOfCloseParensNeeded--;
|
||||
if (numberOfCloseParensNeeded == 0)
|
||||
{
|
||||
fNextToken = loc + 1;
|
||||
if (!fNextToken || !*fNextToken)
|
||||
AdvanceToNextToken();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (*loc == '{' || *loc == '"') {
|
||||
// quoted or literal
|
||||
fNextToken = loc;
|
||||
char *a = CreateString();
|
||||
PR_FREEIF(a);
|
||||
break; // move to next token
|
||||
}
|
||||
}
|
||||
if (ContinueParse())
|
||||
AdvanceToNextToken();
|
||||
}
|
||||
}
|
||||
|
||||
void nsIMAPGenericParser::AdvanceToNextToken()
|
||||
{
|
||||
if (!fCurrentLine || fAtEndOfLine)
|
||||
AdvanceToNextLine();
|
||||
if (Connected())
|
||||
{
|
||||
if (!fStartOfLineOfTokens)
|
||||
{
|
||||
// this is the first token of the line; setup tokenizer now
|
||||
fStartOfLineOfTokens = PL_strdup(fCurrentLine);
|
||||
if (!fStartOfLineOfTokens)
|
||||
{
|
||||
HandleMemoryFailure();
|
||||
return;
|
||||
}
|
||||
fLineOfTokens = fStartOfLineOfTokens;
|
||||
fCurrentTokenPlaceHolder = fStartOfLineOfTokens;
|
||||
}
|
||||
fNextToken = NS_strtok(WHITESPACE, &fCurrentTokenPlaceHolder);
|
||||
if (!fNextToken)
|
||||
{
|
||||
fAtEndOfLine = true;
|
||||
fNextToken = CRLF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsIMAPGenericParser::AdvanceToNextLine()
|
||||
{
|
||||
PR_FREEIF( fCurrentLine );
|
||||
PR_FREEIF( fStartOfLineOfTokens);
|
||||
|
||||
bool ok = GetNextLineForParser(&fCurrentLine);
|
||||
if (!ok)
|
||||
{
|
||||
SetConnected(false);
|
||||
fStartOfLineOfTokens = nullptr;
|
||||
fLineOfTokens = nullptr;
|
||||
fCurrentTokenPlaceHolder = nullptr;
|
||||
fAtEndOfLine = true;
|
||||
fNextToken = CRLF;
|
||||
}
|
||||
else if (!fCurrentLine)
|
||||
{
|
||||
HandleMemoryFailure();
|
||||
}
|
||||
else
|
||||
{
|
||||
fNextToken = nullptr;
|
||||
// determine if there are any tokens (without calling AdvanceToNextToken);
|
||||
// otherwise we are already at end of line
|
||||
NS_ASSERTION(strlen(WHITESPACE) == 3, "assume 3 chars of whitespace");
|
||||
char *firstToken = fCurrentLine;
|
||||
while (*firstToken && (*firstToken == WHITESPACE[0] ||
|
||||
*firstToken == WHITESPACE[1] || *firstToken == WHITESPACE[2]))
|
||||
firstToken++;
|
||||
fAtEndOfLine = (*firstToken == '\0');
|
||||
}
|
||||
}
|
||||
|
||||
// advances |fLineOfTokens| by |bytesToAdvance| bytes
|
||||
void nsIMAPGenericParser::AdvanceTokenizerStartingPoint(int32_t bytesToAdvance)
|
||||
{
|
||||
NS_PRECONDITION(bytesToAdvance>=0, "bytesToAdvance must not be negative");
|
||||
if (!fStartOfLineOfTokens)
|
||||
{
|
||||
AdvanceToNextToken(); // the tokenizer was not yet initialized, do it now
|
||||
if (!fStartOfLineOfTokens)
|
||||
return;
|
||||
}
|
||||
|
||||
if(!fStartOfLineOfTokens)
|
||||
return;
|
||||
// The last call to AdvanceToNextToken() cleared the token separator to '\0'
|
||||
// iff |fCurrentTokenPlaceHolder|. We must recover this token separator now.
|
||||
if (fCurrentTokenPlaceHolder)
|
||||
{
|
||||
int endTokenOffset = fCurrentTokenPlaceHolder - fStartOfLineOfTokens - 1;
|
||||
if (endTokenOffset >= 0)
|
||||
fStartOfLineOfTokens[endTokenOffset] = fCurrentLine[endTokenOffset];
|
||||
}
|
||||
|
||||
NS_ASSERTION(bytesToAdvance + (fLineOfTokens-fStartOfLineOfTokens) <=
|
||||
(int32_t)strlen(fCurrentLine), "cannot advance beyond end of fLineOfTokens");
|
||||
fLineOfTokens += bytesToAdvance;
|
||||
fCurrentTokenPlaceHolder = fLineOfTokens;
|
||||
}
|
||||
|
||||
// RFC3501: astring = 1*ASTRING-CHAR / string
|
||||
// string = quoted / literal
|
||||
// This function leaves us off with fCurrentTokenPlaceHolder immediately after
|
||||
// the end of the Astring. Call AdvanceToNextToken() to get the token after it.
|
||||
char *nsIMAPGenericParser::CreateAstring()
|
||||
{
|
||||
if (*fNextToken == '{')
|
||||
return CreateLiteral(); // literal
|
||||
else if (*fNextToken == '"')
|
||||
return CreateQuoted(); // quoted
|
||||
else
|
||||
return CreateAtom(true); // atom
|
||||
}
|
||||
|
||||
// Create an atom
|
||||
// This function does not advance the parser.
|
||||
// Call AdvanceToNextToken() to get the next token after the atom.
|
||||
// RFC3501: atom = 1*ATOM-CHAR
|
||||
// ASTRING-CHAR = ATOM-CHAR / resp-specials
|
||||
// ATOM-CHAR = <any CHAR except atom-specials>
|
||||
// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards /
|
||||
// quoted-specials / resp-specials
|
||||
// list-wildcards = "%" / "*"
|
||||
// quoted-specials = DQUOTE / "\"
|
||||
// resp-specials = "]"
|
||||
// "Characters are 7-bit US-ASCII unless otherwise specified." [RFC3501, 1.2.]
|
||||
char *nsIMAPGenericParser::CreateAtom(bool isAstring)
|
||||
{
|
||||
char *rv = PL_strdup(fNextToken);
|
||||
if (!rv)
|
||||
{
|
||||
HandleMemoryFailure();
|
||||
return nullptr;
|
||||
}
|
||||
// We wish to stop at the following characters (in decimal ascii)
|
||||
// 1-31 (CTL), 32 (SP), 34 '"', 37 '%', 40-42 "()*", 92 '\\', 123 '{'
|
||||
// also, ']' is only allowed in astrings
|
||||
char *last = rv;
|
||||
char c = *last;
|
||||
while ((c > 42 || c == 33 || c == 35 || c == 36 || c == 38 || c == 39)
|
||||
&& c != '\\' && c != '{' && (isAstring || c != ']'))
|
||||
c = *++last;
|
||||
if (rv == last) {
|
||||
SetSyntaxError(true, "no atom characters found");
|
||||
PL_strfree(rv);
|
||||
return nullptr;
|
||||
}
|
||||
if (*last)
|
||||
{
|
||||
// not the whole token was consumed
|
||||
*last = '\0';
|
||||
AdvanceTokenizerStartingPoint((fNextToken - fLineOfTokens) + (last-rv));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// CreateNilString return either NULL (for "NIL") or a string
|
||||
// Call with fNextToken pointing to the thing which we think is the nilstring.
|
||||
// This function leaves us off with fCurrentTokenPlaceHolder immediately after
|
||||
// the end of the string.
|
||||
// Regardless of type, call AdvanceToNextToken() to get the token after it.
|
||||
// RFC3501: nstring = string / nil
|
||||
// nil = "NIL"
|
||||
char *nsIMAPGenericParser::CreateNilString()
|
||||
{
|
||||
if (!PL_strncasecmp(fNextToken, "NIL", 3))
|
||||
{
|
||||
// check if there is text after "NIL" in fNextToken,
|
||||
// equivalent handling as in CreateQuoted
|
||||
if (fNextToken[3])
|
||||
AdvanceTokenizerStartingPoint((fNextToken - fLineOfTokens) + 3);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return CreateString();
|
||||
}
|
||||
|
||||
|
||||
// Create a string, which can either be quoted or literal,
|
||||
// but not an atom.
|
||||
// This function leaves us off with fCurrentTokenPlaceHolder immediately after
|
||||
// the end of the String. Call AdvanceToNextToken() to get the token after it.
|
||||
char *nsIMAPGenericParser::CreateString()
|
||||
{
|
||||
if (*fNextToken == '{')
|
||||
{
|
||||
char *rv = CreateLiteral(); // literal
|
||||
return (rv);
|
||||
}
|
||||
else if (*fNextToken == '"')
|
||||
{
|
||||
char *rv = CreateQuoted(); // quoted
|
||||
return (rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSyntaxError(true, "string does not start with '{' or '\"'");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// This function sets fCurrentTokenPlaceHolder immediately after the end of the
|
||||
// closing quote. Call AdvanceToNextToken() to get the token after it.
|
||||
// QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> /
|
||||
// "\" quoted_specials
|
||||
// TEXT_CHAR ::= <any CHAR except CR and LF>
|
||||
// quoted_specials ::= <"> / "\"
|
||||
// Note that according to RFC 1064 and RFC 2060, CRs and LFs are not allowed
|
||||
// inside a quoted string. It is sufficient to read from the current line only.
|
||||
char *nsIMAPGenericParser::CreateQuoted(bool /*skipToEnd*/)
|
||||
{
|
||||
// one char past opening '"'
|
||||
char *currentChar = fCurrentLine + (fNextToken - fStartOfLineOfTokens) + 1;
|
||||
|
||||
int escapeCharsCut = 0;
|
||||
nsCString returnString(currentChar);
|
||||
int charIndex;
|
||||
for (charIndex = 0; returnString.CharAt(charIndex) != '"'; charIndex++)
|
||||
{
|
||||
if (!returnString.CharAt(charIndex))
|
||||
{
|
||||
SetSyntaxError(true, "no closing '\"' found in quoted");
|
||||
return nullptr;
|
||||
}
|
||||
else if (returnString.CharAt(charIndex) == '\\')
|
||||
{
|
||||
// eat the escape character, but keep the escaped character
|
||||
returnString.Cut(charIndex, 1);
|
||||
escapeCharsCut++;
|
||||
}
|
||||
}
|
||||
// +2 because of the start and end quotes
|
||||
AdvanceTokenizerStartingPoint((fNextToken - fLineOfTokens) +
|
||||
charIndex + escapeCharsCut + 2);
|
||||
|
||||
returnString.SetLength(charIndex);
|
||||
return ToNewCString(returnString);
|
||||
}
|
||||
|
||||
|
||||
// This function leaves us off with fCurrentTokenPlaceHolder immediately after
|
||||
// the end of the literal string. Call AdvanceToNextToken() to get the token
|
||||
// after the literal string.
|
||||
// RFC3501: literal = "{" number "}" CRLF *CHAR8
|
||||
// ; Number represents the number of CHAR8s
|
||||
// CHAR8 = %x01-ff
|
||||
// ; any OCTET except NUL, %x00
|
||||
char *nsIMAPGenericParser::CreateLiteral()
|
||||
{
|
||||
int32_t numberOfCharsInMessage = atoi(fNextToken + 1);
|
||||
uint32_t numBytes = numberOfCharsInMessage + 1;
|
||||
NS_ASSERTION(numBytes, "overflow!");
|
||||
if (!numBytes)
|
||||
return nullptr;
|
||||
char *returnString = (char *)PR_Malloc(numBytes);
|
||||
if (!returnString)
|
||||
{
|
||||
HandleMemoryFailure();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int32_t currentLineLength = 0;
|
||||
int32_t charsReadSoFar = 0;
|
||||
int32_t bytesToCopy = 0;
|
||||
while (charsReadSoFar < numberOfCharsInMessage)
|
||||
{
|
||||
AdvanceToNextLine();
|
||||
if (!ContinueParse())
|
||||
break;
|
||||
|
||||
currentLineLength = strlen(fCurrentLine);
|
||||
bytesToCopy = (currentLineLength > numberOfCharsInMessage - charsReadSoFar ?
|
||||
numberOfCharsInMessage - charsReadSoFar : currentLineLength);
|
||||
NS_ASSERTION(bytesToCopy, "zero-length line?");
|
||||
memcpy(returnString + charsReadSoFar, fCurrentLine, bytesToCopy);
|
||||
charsReadSoFar += bytesToCopy;
|
||||
}
|
||||
|
||||
if (ContinueParse())
|
||||
{
|
||||
if (currentLineLength == bytesToCopy)
|
||||
{
|
||||
// We have consumed the entire line.
|
||||
// Consider the input "{4}\r\n" "L1\r\n" " A2\r\n" which is read
|
||||
// line-by-line. Reading an Astring, this should result in "L1\r\n".
|
||||
// Note that the second line is "L1\r\n", where the "\r\n" is part of
|
||||
// the literal. Hence, we now read the next line to ensure that the
|
||||
// next call to AdvanceToNextToken() leads to fNextToken=="A2" in our
|
||||
// example.
|
||||
AdvanceToNextLine();
|
||||
}
|
||||
else
|
||||
AdvanceTokenizerStartingPoint(bytesToCopy);
|
||||
}
|
||||
|
||||
returnString[charsReadSoFar] = 0;
|
||||
return returnString;
|
||||
}
|
||||
|
||||
|
||||
// Call this to create a buffer containing all characters within
|
||||
// a given set of parentheses.
|
||||
// Call this with fNextToken[0]=='(', that is, the open paren
|
||||
// of the group.
|
||||
// It will allocate and return all characters up to and including the corresponding
|
||||
// closing paren, and leave the parser in the right place afterwards.
|
||||
char *nsIMAPGenericParser::CreateParenGroup()
|
||||
{
|
||||
NS_ASSERTION(fNextToken[0] == '(', "we don't have a paren group!");
|
||||
|
||||
int numOpenParens = 0;
|
||||
AdvanceTokenizerStartingPoint(fNextToken - fLineOfTokens);
|
||||
|
||||
// Build up a buffer containing the paren group.
|
||||
nsCString returnString;
|
||||
char *parenGroupStart = fCurrentTokenPlaceHolder;
|
||||
NS_ASSERTION(parenGroupStart[0] == '(', "we don't have a paren group (2)!");
|
||||
while (*fCurrentTokenPlaceHolder)
|
||||
{
|
||||
if (*fCurrentTokenPlaceHolder == '{') // literal
|
||||
{
|
||||
// Ensure it is a properly formatted literal.
|
||||
NS_ASSERTION(!strcmp("}\r\n", fCurrentTokenPlaceHolder + strlen(fCurrentTokenPlaceHolder) - 3), "not a literal");
|
||||
|
||||
// Append previous characters and the "{xx}\r\n" to buffer.
|
||||
returnString.Append(parenGroupStart);
|
||||
|
||||
// Append literal itself.
|
||||
AdvanceToNextToken();
|
||||
if (!ContinueParse())
|
||||
break;
|
||||
char *lit = CreateLiteral();
|
||||
NS_ASSERTION(lit, "syntax error or out of memory");
|
||||
if (!lit)
|
||||
break;
|
||||
returnString.Append(lit);
|
||||
PR_Free(lit);
|
||||
if (!ContinueParse())
|
||||
break;
|
||||
parenGroupStart = fCurrentTokenPlaceHolder;
|
||||
}
|
||||
else if (*fCurrentTokenPlaceHolder == '"') // quoted
|
||||
{
|
||||
// Append the _escaped_ version of the quoted string:
|
||||
// just skip it (because the quoted string must be on the same line).
|
||||
AdvanceToNextToken();
|
||||
if (!ContinueParse())
|
||||
break;
|
||||
char *q = CreateQuoted();
|
||||
if (!q)
|
||||
break;
|
||||
PR_Free(q);
|
||||
if (!ContinueParse())
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Append this character to the buffer.
|
||||
char c = *fCurrentTokenPlaceHolder++;
|
||||
if (c == '(')
|
||||
numOpenParens++;
|
||||
else if (c == ')')
|
||||
{
|
||||
numOpenParens--;
|
||||
if (numOpenParens == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numOpenParens != 0 || !ContinueParse())
|
||||
{
|
||||
SetSyntaxError(true, "closing ')' not found in paren group");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
returnString.Append(parenGroupStart, fCurrentTokenPlaceHolder - parenGroupStart);
|
||||
AdvanceToNextToken();
|
||||
return ToNewCString(returnString);
|
||||
}
|
||||
|
||||
76
mailnews/imap/src/nsIMAPGenericParser.h
Normal file
76
mailnews/imap/src/nsIMAPGenericParser.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/*
|
||||
nsIMAPGenericParser is the base parser class used by the server parser and body shell parser
|
||||
*/
|
||||
|
||||
#ifndef nsIMAPGenericParser_H
|
||||
#define nsIMAPGenericParser_H
|
||||
|
||||
#include "nsImapCore.h"
|
||||
|
||||
#define WHITESPACE " \015\012" // token delimiter
|
||||
|
||||
|
||||
class nsIMAPGenericParser
|
||||
{
|
||||
|
||||
public:
|
||||
nsIMAPGenericParser();
|
||||
virtual ~nsIMAPGenericParser();
|
||||
|
||||
// Add any specific stuff in the derived class
|
||||
virtual bool LastCommandSuccessful();
|
||||
|
||||
bool SyntaxError() { return (fParserState & stateSyntaxErrorFlag) != 0; }
|
||||
bool ContinueParse() { return fParserState == stateOK; }
|
||||
bool Connected() { return !(fParserState & stateDisconnectedFlag); }
|
||||
void SetConnected(bool error);
|
||||
|
||||
protected:
|
||||
|
||||
// This is a pure virtual member which must be overridden in the derived class
|
||||
// for each different implementation of a nsIMAPGenericParser.
|
||||
// For instance, one implementation (the nsIMAPServerState) might get the next line
|
||||
// from an open socket, whereas another implementation might just get it from a buffer somewhere.
|
||||
// This fills in nextLine with the buffer, and returns true if everything is OK.
|
||||
// Returns false if there was some error encountered. In that case, we reset the parser.
|
||||
virtual bool GetNextLineForParser(char **nextLine) = 0;
|
||||
|
||||
virtual void HandleMemoryFailure();
|
||||
void skip_to_CRLF();
|
||||
void skip_to_close_paren();
|
||||
char *CreateString();
|
||||
char *CreateAstring();
|
||||
char *CreateNilString();
|
||||
char *CreateLiteral();
|
||||
char *CreateAtom(bool isAstring = false);
|
||||
char *CreateQuoted(bool skipToEnd = true);
|
||||
char *CreateParenGroup();
|
||||
virtual void SetSyntaxError(bool error, const char *msg);
|
||||
|
||||
void AdvanceToNextToken();
|
||||
void AdvanceToNextLine();
|
||||
void AdvanceTokenizerStartingPoint(int32_t bytesToAdvance);
|
||||
void ResetLexAnalyzer();
|
||||
|
||||
protected:
|
||||
// use with care
|
||||
const char *fNextToken;
|
||||
char *fCurrentLine;
|
||||
char *fLineOfTokens;
|
||||
char *fStartOfLineOfTokens;
|
||||
char *fCurrentTokenPlaceHolder;
|
||||
bool fAtEndOfLine;
|
||||
|
||||
private:
|
||||
enum nsIMAPGenericParserState { stateOK = 0,
|
||||
stateSyntaxErrorFlag = 0x1,
|
||||
stateDisconnectedFlag = 0x2 };
|
||||
uint32_t fParserState;
|
||||
};
|
||||
|
||||
#endif
|
||||
701
mailnews/imap/src/nsIMAPHostSessionList.cpp
Normal file
701
mailnews/imap/src/nsIMAPHostSessionList.cpp
Normal file
|
|
@ -0,0 +1,701 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "msgCore.h"
|
||||
#include "nsIMAPHostSessionList.h"
|
||||
#include "nsIMAPBodyShell.h"
|
||||
#include "nsIMAPNamespace.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsIImapIncomingServer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIMsgIncomingServer.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsMsgUtils.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
nsIMAPHostInfo::nsIMAPHostInfo(const char *serverKey,
|
||||
nsIImapIncomingServer *server)
|
||||
{
|
||||
fServerKey = serverKey;
|
||||
NS_ASSERTION(server, "*** Fatal null imap incoming server...\n");
|
||||
server->GetServerDirectory(fOnlineDir);
|
||||
fNextHost = NULL;
|
||||
fCachedPassword = NULL;
|
||||
fCapabilityFlags = kCapabilityUndefined;
|
||||
fHierarchyDelimiters = NULL;
|
||||
#ifdef DEBUG_bienvenu1
|
||||
fHaveWeEverDiscoveredFolders = true; // try this, see what bad happens - we'll need to
|
||||
// figure out a way to make new accounts have it be false
|
||||
#else
|
||||
fHaveWeEverDiscoveredFolders = false; // try this, see what bad happens
|
||||
#endif
|
||||
fCanonicalOnlineSubDir = NULL;
|
||||
fNamespaceList = nsIMAPNamespaceList::CreatensIMAPNamespaceList();
|
||||
fUsingSubscription = true;
|
||||
server->GetUsingSubscription(&fUsingSubscription);
|
||||
fOnlineTrashFolderExists = false;
|
||||
fShouldAlwaysListInbox = true;
|
||||
fShellCache = nsIMAPBodyShellCache::Create();
|
||||
fPasswordVerifiedOnline = false;
|
||||
fDeleteIsMoveToTrash = true;
|
||||
fShowDeletedMessages = false;
|
||||
fGotNamespaces = false;
|
||||
fHaveAdminURL = false;
|
||||
fNamespacesOverridable = true;
|
||||
server->GetOverrideNamespaces(&fNamespacesOverridable);
|
||||
fTempNamespaceList = nsIMAPNamespaceList::CreatensIMAPNamespaceList();
|
||||
}
|
||||
|
||||
nsIMAPHostInfo::~nsIMAPHostInfo()
|
||||
{
|
||||
PR_Free(fCachedPassword);
|
||||
PR_Free(fHierarchyDelimiters);
|
||||
delete fNamespaceList;
|
||||
delete fTempNamespaceList;
|
||||
delete fShellCache;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsIMAPHostSessionList,
|
||||
nsIImapHostSessionList,
|
||||
nsIObserver,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
|
||||
nsIMAPHostSessionList::nsIMAPHostSessionList()
|
||||
{
|
||||
gCachedHostInfoMonitor = PR_NewMonitor(/* "accessing-hostlist-monitor"*/);
|
||||
fHostInfoList = nullptr;
|
||||
}
|
||||
|
||||
nsIMAPHostSessionList::~nsIMAPHostSessionList()
|
||||
{
|
||||
ResetAll();
|
||||
PR_DestroyMonitor(gCachedHostInfoMonitor);
|
||||
}
|
||||
|
||||
nsresult nsIMAPHostSessionList::Init()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
NS_ENSURE_TRUE(observerService, NS_ERROR_UNEXPECTED);
|
||||
observerService->AddObserver(this, "profile-before-change", true);
|
||||
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
|
||||
{
|
||||
if (!strcmp(aTopic, "profile-before-change"))
|
||||
ResetAll();
|
||||
else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
NS_ENSURE_TRUE(observerService, NS_ERROR_UNEXPECTED);
|
||||
observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
||||
observerService->RemoveObserver(this, "profile-before-change");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIMAPHostInfo *nsIMAPHostSessionList::FindHost(const char *serverKey)
|
||||
{
|
||||
nsIMAPHostInfo *host;
|
||||
|
||||
// ### should also check userName here, if NON NULL
|
||||
for (host = fHostInfoList; host; host = host->fNextHost)
|
||||
{
|
||||
if (host->fServerKey.Equals(serverKey, nsCaseInsensitiveCStringComparator()))
|
||||
return host;
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
// reset any cached connection info - delete the lot of 'em
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::ResetAll()
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *nextHost = NULL;
|
||||
for (nsIMAPHostInfo *host = fHostInfoList; host; host = nextHost)
|
||||
{
|
||||
nextHost = host->fNextHost;
|
||||
delete host;
|
||||
}
|
||||
fHostInfoList = NULL;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIMAPHostSessionList::AddHostToList(const char *serverKey,
|
||||
nsIImapIncomingServer *server)
|
||||
{
|
||||
nsIMAPHostInfo *newHost=NULL;
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
if (!FindHost(serverKey))
|
||||
{
|
||||
// stick it on the front
|
||||
newHost = new nsIMAPHostInfo(serverKey, server);
|
||||
if (newHost)
|
||||
{
|
||||
newHost->fNextHost = fHostInfoList;
|
||||
fHostInfoList = newHost;
|
||||
}
|
||||
}
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (newHost == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetPasswordForHost(const char *serverKey, nsString &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
CopyASCIItoUTF16(nsDependentCString(host->fCachedPassword), result);
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetPasswordForHost(const char *serverKey, const char *password)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
{
|
||||
PR_FREEIF(host->fCachedPassword);
|
||||
if (password)
|
||||
host->fCachedPassword = NS_strdup(password);
|
||||
}
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetPasswordVerifiedOnline(const char *serverKey)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fPasswordVerifiedOnline = true;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetPasswordVerifiedOnline(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fPasswordVerifiedOnline;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetOnlineDirForHost(const char *serverKey,
|
||||
nsString &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
CopyASCIItoUTF16(host->fOnlineDir, result);
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetOnlineDirForHost(const char *serverKey,
|
||||
const char *onlineDir)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
{
|
||||
if (onlineDir)
|
||||
host->fOnlineDir = onlineDir;
|
||||
}
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetDeleteIsMoveToTrashForHost(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fDeleteIsMoveToTrash;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetShowDeletedMessagesForHost(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fShowDeletedMessages;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetDeleteIsMoveToTrashForHost(const char *serverKey, bool isMoveToTrash)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fDeleteIsMoveToTrash = isMoveToTrash;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetShowDeletedMessagesForHost(const char *serverKey, bool showDeletedMessages)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fShowDeletedMessages = showDeletedMessages;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetGotNamespacesForHost(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fGotNamespaces;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetGotNamespacesForHost(const char *serverKey, bool gotNamespaces)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fGotNamespaces = gotNamespaces;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetHostIsUsingSubscription(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fUsingSubscription;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetHostIsUsingSubscription(const char *serverKey, bool usingSubscription)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fUsingSubscription = usingSubscription;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetHostHasAdminURL(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fHaveAdminURL;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetHostHasAdminURL(const char *serverKey, bool haveAdminURL)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fHaveAdminURL = haveAdminURL;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetHaveWeEverDiscoveredFoldersForHost(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fHaveWeEverDiscoveredFolders;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetHaveWeEverDiscoveredFoldersForHost(const char *serverKey, bool discovered)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fHaveWeEverDiscoveredFolders = discovered;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetOnlineTrashFolderExistsForHost(const char *serverKey, bool exists)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fOnlineTrashFolderExists = exists;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetOnlineTrashFolderExistsForHost(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fOnlineTrashFolderExists;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::AddNewNamespaceForHost(const char *serverKey, nsIMAPNamespace *ns)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fNamespaceList->AddNewNamespace(ns);
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetNamespaceFromPrefForHost(const char *serverKey,
|
||||
const char *namespacePref, EIMAPNamespaceType nstype)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
{
|
||||
if (namespacePref)
|
||||
{
|
||||
int numNamespaces = host->fNamespaceList->UnserializeNamespaces(namespacePref, nullptr, 0);
|
||||
char **prefixes = (char**) PR_CALLOC(numNamespaces * sizeof(char*));
|
||||
if (prefixes)
|
||||
{
|
||||
int len = host->fNamespaceList->UnserializeNamespaces(namespacePref, prefixes, numNamespaces);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char *thisns = prefixes[i];
|
||||
char delimiter = '/'; // a guess
|
||||
if (PL_strlen(thisns) >= 1)
|
||||
delimiter = thisns[PL_strlen(thisns)-1];
|
||||
nsIMAPNamespace *ns = new nsIMAPNamespace(nstype, thisns, delimiter, true);
|
||||
if (ns)
|
||||
host->fNamespaceList->AddNewNamespace(ns);
|
||||
PR_FREEIF(thisns);
|
||||
}
|
||||
PR_Free(prefixes);
|
||||
}
|
||||
}
|
||||
}
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetNamespaceForMailboxForHost(const char *serverKey, const char *mailbox_name, nsIMAPNamespace * &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fNamespaceList->GetNamespaceForMailbox(mailbox_name);
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::ClearPrefsNamespacesForHost(const char *serverKey)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fNamespaceList->ClearNamespaces(true, false, true);
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::ClearServerAdvertisedNamespacesForHost(const char *serverKey)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fNamespaceList->ClearNamespaces(false, true, true);
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetDefaultNamespaceOfTypeForHost(const char *serverKey, EIMAPNamespaceType type, nsIMAPNamespace * &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fNamespaceList->GetDefaultNamespaceOfType(type);
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetNamespacesOverridableForHost(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fNamespacesOverridable;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetNamespacesOverridableForHost(const char *serverKey, bool overridable)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fNamespacesOverridable = overridable;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetNumberOfNamespacesForHost(const char *serverKey, uint32_t &result)
|
||||
{
|
||||
int32_t intResult = 0;
|
||||
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
intResult = host->fNamespaceList->GetNumberOfNamespaces();
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
NS_ASSERTION(intResult >= 0, "negative number of namespaces");
|
||||
result = (uint32_t) intResult;
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetNamespaceNumberForHost(const char *serverKey, int32_t n, nsIMAPNamespace * &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
result = host->fNamespaceList->GetNamespaceNumber(n);
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsIMAPHostSessionList::SetNamespacesPrefForHost(nsIImapIncomingServer *aHost,
|
||||
EIMAPNamespaceType type,
|
||||
const char *pref)
|
||||
{
|
||||
if (type == kPersonalNamespace)
|
||||
aHost->SetPersonalNamespace(nsDependentCString(pref));
|
||||
else if (type == kPublicNamespace)
|
||||
aHost->SetPublicNamespace(nsDependentCString(pref));
|
||||
else if (type == kOtherUsersNamespace)
|
||||
aHost->SetOtherUsersNamespace(nsDependentCString(pref));
|
||||
else
|
||||
NS_ASSERTION(false, "bogus namespace type");
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
// do we need this? What should we do about the master thing?
|
||||
// Make sure this is running in the Mozilla thread when called
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::CommitNamespacesForHost(nsIImapIncomingServer *aHost)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aHost);
|
||||
nsCString serverKey;
|
||||
nsCOMPtr <nsIMsgIncomingServer> incomingServer = do_QueryInterface(aHost);
|
||||
if (!incomingServer)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsresult rv = incomingServer->GetKey(serverKey);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey.get());
|
||||
if (host)
|
||||
{
|
||||
host->fGotNamespaces = true; // so we only issue NAMESPACE once per host per session.
|
||||
EIMAPNamespaceType type = kPersonalNamespace;
|
||||
for (int i = 1; i <= 3; i++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case 1:
|
||||
type = kPersonalNamespace;
|
||||
break;
|
||||
case 2:
|
||||
type = kPublicNamespace;
|
||||
break;
|
||||
case 3:
|
||||
type = kOtherUsersNamespace;
|
||||
break;
|
||||
default:
|
||||
type = kPersonalNamespace;
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t numInNS = host->fNamespaceList->GetNumberOfNamespaces(type);
|
||||
if (numInNS == 0)
|
||||
SetNamespacesPrefForHost(aHost, type, "");
|
||||
else if (numInNS >= 1)
|
||||
{
|
||||
char *pref = PR_smprintf("");
|
||||
for (int count = 1; count <= numInNS; count++)
|
||||
{
|
||||
nsIMAPNamespace *ns = host->fNamespaceList->GetNamespaceNumber(count, type);
|
||||
if (ns)
|
||||
{
|
||||
if (count > 1)
|
||||
{
|
||||
// append the comma
|
||||
char *tempPref = PR_smprintf("%s,",pref);
|
||||
PR_FREEIF(pref);
|
||||
pref = tempPref;
|
||||
}
|
||||
char *tempPref = PR_smprintf("%s\"%s\"",pref,ns->GetPrefix());
|
||||
PR_FREEIF(pref);
|
||||
pref = tempPref;
|
||||
}
|
||||
}
|
||||
if (pref)
|
||||
{
|
||||
SetNamespacesPrefForHost(aHost, type, pref);
|
||||
PR_Free(pref);
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear, but don't delete the entries in, the temp namespace list
|
||||
host->fTempNamespaceList->ClearNamespaces(true, true, false);
|
||||
|
||||
// Now reset all of libmsg's namespace references.
|
||||
// Did I mention this needs to be running in the mozilla thread?
|
||||
aHost->ResetNamespaceReferences();
|
||||
}
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::FlushUncommittedNamespacesForHost(const char *serverKey, bool &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fTempNamespaceList->ClearNamespaces(true, true, true);
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// Returns NULL if there is no personal namespace on the given host
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetOnlineInboxPathForHost(const char *serverKey, nsString &result)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
{
|
||||
nsIMAPNamespace *ns = NULL;
|
||||
ns = host->fNamespaceList->GetDefaultNamespaceOfType(kPersonalNamespace);
|
||||
if (ns)
|
||||
{
|
||||
CopyASCIItoUTF16(nsDependentCString(ns->GetPrefix()), result);
|
||||
result.AppendLiteral("INBOX");
|
||||
}
|
||||
}
|
||||
else
|
||||
result.Truncate();
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::GetShouldAlwaysListInboxForHost(const char* /*serverKey*/, bool &result)
|
||||
{
|
||||
result = true;
|
||||
|
||||
/*
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
ret = host->fShouldAlwaysListInbox;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
*/
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetShouldAlwaysListInboxForHost(const char *serverKey, bool shouldList)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
host->fShouldAlwaysListInbox = shouldList;
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::SetNamespaceHierarchyDelimiterFromMailboxForHost(const char *serverKey, const char *boxName, char delimiter)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
{
|
||||
nsIMAPNamespace *ns = host->fNamespaceList->GetNamespaceForMailbox(boxName);
|
||||
if (ns && !ns->GetIsDelimiterFilledIn())
|
||||
ns->SetDelimiter(delimiter, true);
|
||||
}
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host) ? NS_OK : NS_ERROR_ILLEGAL_VALUE ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::AddShellToCacheForHost(const char *serverKey, nsIMAPBodyShell *shell)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host)
|
||||
{
|
||||
if (host->fShellCache)
|
||||
{
|
||||
if (!host->fShellCache->AddShellToCache(shell))
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
else
|
||||
rv = NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIMAPHostSessionList::FindShellInCacheForHost(const char *serverKey, const char *mailboxName, const char *UID,
|
||||
IMAP_ContentModifiedType modType, nsIMAPBodyShell **shell)
|
||||
{
|
||||
nsCString uidString(UID);
|
||||
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host && host->fShellCache)
|
||||
NS_IF_ADDREF(*shell = host->fShellCache->FindShellForUID(uidString,
|
||||
mailboxName,
|
||||
modType));
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIMAPHostSessionList::ClearShellCacheForHost(const char *serverKey)
|
||||
{
|
||||
PR_EnterMonitor(gCachedHostInfoMonitor);
|
||||
nsIMAPHostInfo *host = FindHost(serverKey);
|
||||
if (host && host->fShellCache)
|
||||
host->fShellCache->Clear();
|
||||
PR_ExitMonitor(gCachedHostInfoMonitor);
|
||||
return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
|
||||
}
|
||||
|
||||
135
mailnews/imap/src/nsIMAPHostSessionList.h
Normal file
135
mailnews/imap/src/nsIMAPHostSessionList.h
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* -*- 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 _nsIMAPHostSessionList_H_
|
||||
#define _nsIMAPHostSessionList_H_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsImapCore.h"
|
||||
#include "nsIIMAPHostSessionList.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nspr.h"
|
||||
|
||||
class nsIMAPNamespaceList;
|
||||
class nsIImapIncomingServer;
|
||||
|
||||
class nsIMAPHostInfo
|
||||
{
|
||||
public:
|
||||
friend class nsIMAPHostSessionList;
|
||||
|
||||
nsIMAPHostInfo(const char *serverKey, nsIImapIncomingServer *server);
|
||||
~nsIMAPHostInfo();
|
||||
protected:
|
||||
nsCString fServerKey;
|
||||
char *fCachedPassword;
|
||||
nsCString fOnlineDir;
|
||||
nsIMAPHostInfo *fNextHost;
|
||||
eIMAPCapabilityFlags fCapabilityFlags;
|
||||
char *fHierarchyDelimiters;// string of top-level hierarchy delimiters
|
||||
bool fHaveWeEverDiscoveredFolders;
|
||||
char *fCanonicalOnlineSubDir;
|
||||
nsIMAPNamespaceList *fNamespaceList, *fTempNamespaceList;
|
||||
bool fNamespacesOverridable;
|
||||
bool fUsingSubscription;
|
||||
bool fOnlineTrashFolderExists;
|
||||
bool fShouldAlwaysListInbox;
|
||||
bool fHaveAdminURL;
|
||||
bool fPasswordVerifiedOnline;
|
||||
bool fDeleteIsMoveToTrash;
|
||||
bool fShowDeletedMessages;
|
||||
bool fGotNamespaces;
|
||||
nsIMAPBodyShellCache *fShellCache;
|
||||
};
|
||||
|
||||
// this is an interface to a linked list of host info's
|
||||
class nsIMAPHostSessionList : public nsIImapHostSessionList, public nsIObserver, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsIMAPHostSessionList();
|
||||
nsresult Init();
|
||||
// Host List
|
||||
NS_IMETHOD AddHostToList(const char *serverKey,
|
||||
nsIImapIncomingServer *server) override;
|
||||
NS_IMETHOD ResetAll() override;
|
||||
|
||||
// Capabilities
|
||||
NS_IMETHOD GetHostHasAdminURL(const char *serverKey, bool &result) override;
|
||||
NS_IMETHOD SetHostHasAdminURL(const char *serverKey, bool hasAdminUrl) override;
|
||||
// Subscription
|
||||
NS_IMETHOD GetHostIsUsingSubscription(const char *serverKey, bool &result) override;
|
||||
NS_IMETHOD SetHostIsUsingSubscription(const char *serverKey, bool usingSubscription) override;
|
||||
|
||||
// Passwords
|
||||
NS_IMETHOD GetPasswordForHost(const char *serverKey, nsString &result) override;
|
||||
NS_IMETHOD SetPasswordForHost(const char *serverKey, const char *password) override;
|
||||
NS_IMETHOD GetPasswordVerifiedOnline(const char *serverKey, bool &result) override;
|
||||
NS_IMETHOD SetPasswordVerifiedOnline(const char *serverKey) override;
|
||||
|
||||
// OnlineDir
|
||||
NS_IMETHOD GetOnlineDirForHost(const char *serverKey,
|
||||
nsString &result) override;
|
||||
NS_IMETHOD SetOnlineDirForHost(const char *serverKey,
|
||||
const char *onlineDir) override;
|
||||
|
||||
// Delete is move to trash folder
|
||||
NS_IMETHOD GetDeleteIsMoveToTrashForHost(const char *serverKey, bool &result) override;
|
||||
NS_IMETHOD SetDeleteIsMoveToTrashForHost(const char *serverKey, bool isMoveToTrash) override;
|
||||
// imap delete model (or not)
|
||||
NS_IMETHOD GetShowDeletedMessagesForHost(const char *serverKey, bool &result) override;
|
||||
NS_IMETHOD SetShowDeletedMessagesForHost(const char *serverKey, bool showDeletedMessages) override;
|
||||
|
||||
// Get namespaces
|
||||
NS_IMETHOD GetGotNamespacesForHost(const char *serverKey, bool &result) override;
|
||||
NS_IMETHOD SetGotNamespacesForHost(const char *serverKey, bool gotNamespaces) override;
|
||||
// Folders
|
||||
NS_IMETHOD SetHaveWeEverDiscoveredFoldersForHost(const char *serverKey, bool discovered) override;
|
||||
NS_IMETHOD GetHaveWeEverDiscoveredFoldersForHost(const char *serverKey, bool &result) override;
|
||||
|
||||
// Trash Folder
|
||||
NS_IMETHOD SetOnlineTrashFolderExistsForHost(const char *serverKey, bool exists) override;
|
||||
NS_IMETHOD GetOnlineTrashFolderExistsForHost(const char *serverKey, bool &result) override;
|
||||
|
||||
// INBOX
|
||||
NS_IMETHOD GetOnlineInboxPathForHost(const char *serverKey, nsString &result) override;
|
||||
NS_IMETHOD GetShouldAlwaysListInboxForHost(const char *serverKey, bool &result) override;
|
||||
NS_IMETHOD SetShouldAlwaysListInboxForHost(const char *serverKey, bool shouldList) override;
|
||||
|
||||
// Namespaces
|
||||
NS_IMETHOD GetNamespaceForMailboxForHost(const char *serverKey, const char *mailbox_name, nsIMAPNamespace *&result) override;
|
||||
NS_IMETHOD SetNamespaceFromPrefForHost(const char *serverKey, const char *namespacePref, EIMAPNamespaceType type) override;
|
||||
NS_IMETHOD AddNewNamespaceForHost(const char *serverKey, nsIMAPNamespace *ns) override;
|
||||
NS_IMETHOD ClearServerAdvertisedNamespacesForHost(const char *serverKey) override;
|
||||
NS_IMETHOD ClearPrefsNamespacesForHost(const char *serverKey) override;
|
||||
NS_IMETHOD GetDefaultNamespaceOfTypeForHost(const char *serverKey, EIMAPNamespaceType type, nsIMAPNamespace *&result) override;
|
||||
NS_IMETHOD SetNamespacesOverridableForHost(const char *serverKey, bool overridable) override;
|
||||
NS_IMETHOD GetNamespacesOverridableForHost(const char *serverKey,bool &result) override;
|
||||
NS_IMETHOD GetNumberOfNamespacesForHost(const char *serverKey, uint32_t &result) override;
|
||||
NS_IMETHOD GetNamespaceNumberForHost(const char *serverKey, int32_t n, nsIMAPNamespace * &result) override;
|
||||
// ### dmb hoo boy, how are we going to do this?
|
||||
NS_IMETHOD CommitNamespacesForHost(nsIImapIncomingServer *host) override;
|
||||
NS_IMETHOD FlushUncommittedNamespacesForHost(const char *serverKey, bool &result) override;
|
||||
|
||||
// Hierarchy Delimiters
|
||||
NS_IMETHOD SetNamespaceHierarchyDelimiterFromMailboxForHost(const char *serverKey, const char *boxName, char delimiter) override;
|
||||
|
||||
// Message Body Shells
|
||||
NS_IMETHOD AddShellToCacheForHost(const char *serverKey, nsIMAPBodyShell *shell) override;
|
||||
NS_IMETHOD FindShellInCacheForHost(const char *serverKey, const char *mailboxName, const char *UID, IMAP_ContentModifiedType modType, nsIMAPBodyShell **result) override;
|
||||
NS_IMETHOD ClearShellCacheForHost(const char *serverKey) override;
|
||||
PRMonitor *gCachedHostInfoMonitor;
|
||||
nsIMAPHostInfo *fHostInfoList;
|
||||
protected:
|
||||
virtual ~nsIMAPHostSessionList();
|
||||
nsresult SetNamespacesPrefForHost(nsIImapIncomingServer *aHost,
|
||||
EIMAPNamespaceType type,
|
||||
const char *pref);
|
||||
nsIMAPHostInfo *FindHost(const char *serverKey);
|
||||
};
|
||||
#endif
|
||||
650
mailnews/imap/src/nsIMAPNamespace.cpp
Normal file
650
mailnews/imap/src/nsIMAPNamespace.cpp
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
/* -*- 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" // for pre-compiled headers
|
||||
|
||||
#include "nsImapCore.h"
|
||||
#include "nsIMAPNamespace.h"
|
||||
#include "nsImapProtocol.h"
|
||||
#include "nsMsgImapCID.h"
|
||||
#include "nsImapUrl.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
//////////////////// nsIMAPNamespace /////////////////////////////////////////////////////////////
|
||||
|
||||
static NS_DEFINE_CID(kCImapHostSessionListCID, NS_IIMAPHOSTSESSIONLIST_CID);
|
||||
|
||||
nsIMAPNamespace::nsIMAPNamespace(EIMAPNamespaceType type, const char *prefix, char delimiter, bool from_prefs)
|
||||
{
|
||||
m_namespaceType = type;
|
||||
m_prefix = PL_strdup(prefix);
|
||||
m_fromPrefs = from_prefs;
|
||||
|
||||
m_delimiter = delimiter;
|
||||
m_delimiterFilledIn = !m_fromPrefs; // if it's from the prefs, we can't be sure about the delimiter until we list it.
|
||||
}
|
||||
|
||||
nsIMAPNamespace::~nsIMAPNamespace()
|
||||
{
|
||||
PR_FREEIF(m_prefix);
|
||||
}
|
||||
|
||||
void nsIMAPNamespace::SetDelimiter(char delimiter, bool delimiterFilledIn)
|
||||
{
|
||||
m_delimiter = delimiter;
|
||||
m_delimiterFilledIn = delimiterFilledIn;
|
||||
}
|
||||
|
||||
// returns -1 if this box is not part of this namespace,
|
||||
// or the length of the prefix if it is part of this namespace
|
||||
int nsIMAPNamespace::MailboxMatchesNamespace(const char *boxname)
|
||||
{
|
||||
if (!boxname) return -1;
|
||||
|
||||
// If the namespace is part of the boxname
|
||||
if (!m_prefix || !*m_prefix)
|
||||
return 0;
|
||||
|
||||
if (PL_strstr(boxname, m_prefix) == boxname)
|
||||
return PL_strlen(m_prefix);
|
||||
|
||||
// If the boxname is part of the prefix
|
||||
// (Used for matching Personal mailbox with Personal/ namespace, etc.)
|
||||
if (PL_strstr(m_prefix, boxname) == m_prefix)
|
||||
return PL_strlen(boxname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
nsIMAPNamespaceList *nsIMAPNamespaceList::CreatensIMAPNamespaceList()
|
||||
{
|
||||
nsIMAPNamespaceList *rv = new nsIMAPNamespaceList();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsIMAPNamespaceList::nsIMAPNamespaceList()
|
||||
{
|
||||
}
|
||||
|
||||
int nsIMAPNamespaceList::GetNumberOfNamespaces()
|
||||
{
|
||||
return m_NamespaceList.Length();
|
||||
}
|
||||
|
||||
|
||||
nsresult nsIMAPNamespaceList::InitFromString(const char *nameSpaceString, EIMAPNamespaceType nstype)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (nameSpaceString)
|
||||
{
|
||||
int numNamespaces = UnserializeNamespaces(nameSpaceString, nullptr, 0);
|
||||
char **prefixes = (char**) PR_CALLOC(numNamespaces * sizeof(char*));
|
||||
if (prefixes)
|
||||
{
|
||||
int len = UnserializeNamespaces(nameSpaceString, prefixes, numNamespaces);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char *thisns = prefixes[i];
|
||||
char delimiter = '/'; // a guess
|
||||
if (PL_strlen(thisns) >= 1)
|
||||
delimiter = thisns[PL_strlen(thisns)-1];
|
||||
nsIMAPNamespace *ns = new nsIMAPNamespace(nstype, thisns, delimiter, true);
|
||||
if (ns)
|
||||
AddNewNamespace(ns);
|
||||
PR_FREEIF(thisns);
|
||||
}
|
||||
PR_Free(prefixes);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsIMAPNamespaceList::OutputToString(nsCString &string)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int nsIMAPNamespaceList::GetNumberOfNamespaces(EIMAPNamespaceType type)
|
||||
{
|
||||
int nodeIndex = 0, count = 0;
|
||||
for (nodeIndex = m_NamespaceList.Length() - 1; nodeIndex >= 0; nodeIndex--)
|
||||
{
|
||||
nsIMAPNamespace *nspace = m_NamespaceList.ElementAt(nodeIndex);
|
||||
if (nspace->GetType() == type)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int nsIMAPNamespaceList::AddNewNamespace(nsIMAPNamespace *ns)
|
||||
{
|
||||
// If the namespace is from the NAMESPACE response, then we should see if there
|
||||
// are any namespaces previously set by the preferences, or the default namespace. If so, remove these.
|
||||
|
||||
if (!ns->GetIsNamespaceFromPrefs())
|
||||
{
|
||||
int nodeIndex;
|
||||
// iterate backwards because we delete elements
|
||||
for (nodeIndex = m_NamespaceList.Length() - 1; nodeIndex >= 0; nodeIndex--)
|
||||
{
|
||||
nsIMAPNamespace *nspace = m_NamespaceList.ElementAt(nodeIndex);
|
||||
// if we find existing namespace(s) that matches the
|
||||
// new one, we'll just remove the old ones and let the
|
||||
// new one get added when we've finished checking for
|
||||
// matching namespaces or namespaces that came from prefs.
|
||||
if (nspace &&
|
||||
(nspace->GetIsNamespaceFromPrefs() ||
|
||||
(!PL_strcmp(ns->GetPrefix(), nspace->GetPrefix()) &&
|
||||
ns->GetType() == nspace->GetType() &&
|
||||
ns->GetDelimiter() == nspace->GetDelimiter())))
|
||||
{
|
||||
m_NamespaceList.RemoveElementAt(nodeIndex);
|
||||
delete nspace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new namespace to the list. This must come after the removing code,
|
||||
// or else we could never add the initial kDefaultNamespace type to the list.
|
||||
m_NamespaceList.AppendElement(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// chrisf - later, fix this to know the real concept of "default" namespace of a given type
|
||||
nsIMAPNamespace *nsIMAPNamespaceList::GetDefaultNamespaceOfType(EIMAPNamespaceType type)
|
||||
{
|
||||
nsIMAPNamespace *rv = 0, *firstOfType = 0;
|
||||
|
||||
int nodeIndex, count = m_NamespaceList.Length();
|
||||
for (nodeIndex= 0; nodeIndex < count && !rv; nodeIndex++)
|
||||
{
|
||||
nsIMAPNamespace *ns = m_NamespaceList.ElementAt(nodeIndex);
|
||||
if (ns->GetType() == type)
|
||||
{
|
||||
if (!firstOfType)
|
||||
firstOfType = ns;
|
||||
if (!(*(ns->GetPrefix())))
|
||||
{
|
||||
// This namespace's prefix is ""
|
||||
// Therefore it is the default
|
||||
rv = ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!rv)
|
||||
rv = firstOfType;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsIMAPNamespaceList::~nsIMAPNamespaceList()
|
||||
{
|
||||
ClearNamespaces(true, true, true);
|
||||
}
|
||||
|
||||
// ClearNamespaces removes and deletes the namespaces specified, and if there are no namespaces left,
|
||||
void nsIMAPNamespaceList::ClearNamespaces(bool deleteFromPrefsNamespaces, bool deleteServerAdvertisedNamespaces, bool reallyDelete)
|
||||
{
|
||||
int nodeIndex;
|
||||
|
||||
// iterate backwards because we delete elements
|
||||
for (nodeIndex = m_NamespaceList.Length() - 1; nodeIndex >= 0; nodeIndex--)
|
||||
{
|
||||
nsIMAPNamespace *ns = m_NamespaceList.ElementAt(nodeIndex);
|
||||
if (ns->GetIsNamespaceFromPrefs())
|
||||
{
|
||||
if (deleteFromPrefsNamespaces)
|
||||
{
|
||||
m_NamespaceList.RemoveElementAt(nodeIndex);
|
||||
if (reallyDelete)
|
||||
delete ns;
|
||||
}
|
||||
}
|
||||
else if (deleteServerAdvertisedNamespaces)
|
||||
{
|
||||
m_NamespaceList.RemoveElementAt(nodeIndex);
|
||||
if (reallyDelete)
|
||||
delete ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsIMAPNamespace *nsIMAPNamespaceList::GetNamespaceNumber(int nodeIndex)
|
||||
{
|
||||
NS_ASSERTION(nodeIndex >= 0 && nodeIndex < GetNumberOfNamespaces(), "invalid IMAP namespace node index");
|
||||
if (nodeIndex < 0) nodeIndex = 0;
|
||||
|
||||
// XXX really could be just ElementAt; that's why we have the assertion
|
||||
return m_NamespaceList.SafeElementAt(nodeIndex);
|
||||
}
|
||||
|
||||
nsIMAPNamespace *nsIMAPNamespaceList::GetNamespaceNumber(int nodeIndex, EIMAPNamespaceType type)
|
||||
{
|
||||
int nodeCount, count = 0;
|
||||
for (nodeCount = m_NamespaceList.Length() - 1; nodeCount >= 0; nodeCount--)
|
||||
{
|
||||
nsIMAPNamespace *nspace = m_NamespaceList.ElementAt(nodeCount);
|
||||
if (nspace->GetType() == type)
|
||||
{
|
||||
count++;
|
||||
if (count == nodeIndex)
|
||||
return nspace;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIMAPNamespace *nsIMAPNamespaceList::GetNamespaceForMailbox(const char *boxname)
|
||||
{
|
||||
// We want to find the LONGEST substring that matches the beginning of this mailbox's path.
|
||||
// This accounts for nested namespaces (i.e. "Public/" and "Public/Users/")
|
||||
|
||||
// Also, we want to match the namespace's mailbox to that namespace also:
|
||||
// The Personal box will match the Personal/ namespace, etc.
|
||||
|
||||
// these lists shouldn't be too long (99% chance there won't be more than 3 or 4)
|
||||
// so just do a linear search
|
||||
|
||||
int lengthMatched = -1;
|
||||
int currentMatchedLength = -1;
|
||||
nsIMAPNamespace *rv = nullptr;
|
||||
int nodeIndex = 0;
|
||||
|
||||
if (!PL_strcasecmp(boxname, "INBOX"))
|
||||
return GetDefaultNamespaceOfType(kPersonalNamespace);
|
||||
|
||||
for (nodeIndex = m_NamespaceList.Length() - 1; nodeIndex >= 0; nodeIndex--)
|
||||
{
|
||||
nsIMAPNamespace *nspace = m_NamespaceList.ElementAt(nodeIndex);
|
||||
currentMatchedLength = nspace->MailboxMatchesNamespace(boxname);
|
||||
if (currentMatchedLength > lengthMatched)
|
||||
{
|
||||
rv = nspace;
|
||||
lengthMatched = currentMatchedLength;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#define SERIALIZER_SEPARATORS ","
|
||||
|
||||
/**
|
||||
* If len is one, copies the first element of prefixes into serializedNamespaces.
|
||||
* If len > 1, copies len strings from prefixes into serializedNamespaces
|
||||
* as a comma-separated list of quoted strings.
|
||||
*/
|
||||
nsresult nsIMAPNamespaceList::SerializeNamespaces(char **prefixes, int len,
|
||||
nsCString &serializedNamespaces)
|
||||
{
|
||||
if (len <= 0)
|
||||
return NS_OK;
|
||||
|
||||
if (len == 1)
|
||||
{
|
||||
serializedNamespaces.Assign(prefixes[0]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
serializedNamespaces.AppendLiteral(",");
|
||||
|
||||
serializedNamespaces.AppendLiteral("\"");
|
||||
serializedNamespaces.Append(prefixes[i]);
|
||||
serializedNamespaces.AppendLiteral("\"");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* str is the string which needs to be unserialized.
|
||||
If prefixes is NULL, simply returns the number of namespaces in str. (len is ignored)
|
||||
If prefixes is not NULL, it should be an array of length len which is to be filled in
|
||||
with newly-allocated string. Returns the number of strings filled in.
|
||||
*/
|
||||
int nsIMAPNamespaceList::UnserializeNamespaces(const char *str, char **prefixes, int len)
|
||||
{
|
||||
if (!str)
|
||||
return 0;
|
||||
if (!prefixes)
|
||||
{
|
||||
if (str[0] != '"')
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
int count = 0;
|
||||
char *ourstr = PL_strdup(str);
|
||||
char *origOurStr = ourstr;
|
||||
if (ourstr)
|
||||
{
|
||||
char *token = NS_strtok(SERIALIZER_SEPARATORS, &ourstr );
|
||||
while (token != nullptr)
|
||||
{
|
||||
token = NS_strtok(SERIALIZER_SEPARATORS, &ourstr );
|
||||
count++;
|
||||
}
|
||||
PR_Free(origOurStr);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((str[0] != '"') && (len >= 1))
|
||||
{
|
||||
prefixes[0] = PL_strdup(str);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = 0;
|
||||
char *ourstr = PL_strdup(str);
|
||||
char *origOurStr = ourstr;
|
||||
if (ourstr)
|
||||
{
|
||||
char *token = NS_strtok(SERIALIZER_SEPARATORS, &ourstr );
|
||||
while ((count < len) && (token != nullptr))
|
||||
{
|
||||
|
||||
char *current = PL_strdup(token), *where = current;
|
||||
if (where[0] == '"')
|
||||
where++;
|
||||
if (where[PL_strlen(where)-1] == '"')
|
||||
where[PL_strlen(where)-1] = 0;
|
||||
prefixes[count] = PL_strdup(where);
|
||||
PR_FREEIF(current);
|
||||
token = NS_strtok(SERIALIZER_SEPARATORS, &ourstr );
|
||||
count++;
|
||||
}
|
||||
PR_Free(origOurStr);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
char *nsIMAPNamespaceList::AllocateCanonicalFolderName(const char *onlineFolderName, char delimiter)
|
||||
{
|
||||
char *canonicalPath = nullptr;
|
||||
if (delimiter)
|
||||
canonicalPath = nsImapUrl::ReplaceCharsInCopiedString(onlineFolderName, delimiter , '/');
|
||||
else
|
||||
canonicalPath = PL_strdup(onlineFolderName);
|
||||
|
||||
// eat any escape characters for escaped dir separators
|
||||
if (canonicalPath)
|
||||
{
|
||||
char *currentEscapeSequence = strstr(canonicalPath, "\\/");
|
||||
while (currentEscapeSequence)
|
||||
{
|
||||
strcpy(currentEscapeSequence, currentEscapeSequence+1);
|
||||
currentEscapeSequence = strstr(currentEscapeSequence+1, "\\/");
|
||||
}
|
||||
}
|
||||
|
||||
return canonicalPath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
GetFolderNameWithoutNamespace takes as input a folder name
|
||||
in canonical form, and the namespace for the given folder. It returns an allocated
|
||||
string of the folder's path with the namespace string stripped out. For instance,
|
||||
when passed the folder Folders/a/b where the namespace is "Folders/", it will return
|
||||
"a/b". Similarly, if the folder name is "#news/comp/mail/imap" in canonical form,
|
||||
with a real delimiter of "." and a namespace of "#news.", it will return "comp/mail/imap".
|
||||
The return value is always in canonical form.
|
||||
*/
|
||||
char* nsIMAPNamespaceList::GetFolderNameWithoutNamespace(nsIMAPNamespace *namespaceForFolder, const char *canonicalFolderName)
|
||||
{
|
||||
NS_ASSERTION(canonicalFolderName, "null folder name");
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(namespaceForFolder || !PL_strcasecmp(canonicalFolderName, "INBOX"), "need namespace or INBOX");
|
||||
#endif
|
||||
|
||||
char *retFolderName = nullptr;
|
||||
|
||||
if (!PL_strcasecmp(canonicalFolderName, "INBOX"))
|
||||
return PL_strdup(canonicalFolderName);
|
||||
|
||||
// convert the canonical path to the online path
|
||||
char *convertedFolderName = nsIMAPNamespaceList::AllocateServerFolderName(canonicalFolderName, namespaceForFolder->GetDelimiter());
|
||||
if (convertedFolderName)
|
||||
{
|
||||
char *beginFolderPath = nullptr;
|
||||
if (strlen(convertedFolderName) <= strlen(namespaceForFolder->GetPrefix()))
|
||||
beginFolderPath = convertedFolderName;
|
||||
else
|
||||
beginFolderPath = convertedFolderName + strlen(namespaceForFolder->GetPrefix());
|
||||
NS_ASSERTION(beginFolderPath, "empty folder path");
|
||||
retFolderName = nsIMAPNamespaceList::AllocateCanonicalFolderName(beginFolderPath, namespaceForFolder->GetDelimiter());
|
||||
PR_Free(convertedFolderName);
|
||||
}
|
||||
|
||||
NS_ASSERTION(retFolderName, "returning null folder name");
|
||||
return retFolderName;
|
||||
}
|
||||
|
||||
|
||||
nsIMAPNamespace* nsIMAPNamespaceList::GetNamespaceForFolder(const char *hostName,
|
||||
const char *canonicalFolderName,
|
||||
char delimiter)
|
||||
{
|
||||
if (!hostName || !canonicalFolderName)
|
||||
return nullptr;
|
||||
|
||||
nsIMAPNamespace *resultNamespace = nullptr;
|
||||
nsresult rv;
|
||||
char *convertedFolderName = nsIMAPNamespaceList::AllocateServerFolderName(canonicalFolderName, delimiter);
|
||||
|
||||
if (convertedFolderName)
|
||||
{
|
||||
|
||||
nsCOMPtr<nsIImapHostSessionList> hostSessionList =
|
||||
do_GetService(kCImapHostSessionListCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return nullptr;
|
||||
hostSessionList->GetNamespaceForMailboxForHost(hostName, convertedFolderName, resultNamespace);
|
||||
PR_Free(convertedFolderName);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(false, "couldn't get converted folder name");
|
||||
}
|
||||
|
||||
return resultNamespace;
|
||||
}
|
||||
|
||||
/* static */
|
||||
char *nsIMAPNamespaceList::AllocateServerFolderName(const char *canonicalFolderName, char delimiter)
|
||||
{
|
||||
if (delimiter)
|
||||
return nsImapUrl::ReplaceCharsInCopiedString(canonicalFolderName, '/', delimiter);
|
||||
else
|
||||
return NS_strdup(canonicalFolderName);
|
||||
}
|
||||
|
||||
/*
|
||||
GetFolderOwnerNameFromPath takes as inputs a folder name
|
||||
in canonical form, and a namespace for that folder.
|
||||
The namespace MUST be of type kOtherUsersNamespace, hence the folder MUST be
|
||||
owned by another user. This function extracts the folder owner's name from the
|
||||
canonical name of the folder, and returns an allocated copy of that owner's name
|
||||
*/
|
||||
/* static */
|
||||
char *nsIMAPNamespaceList::GetFolderOwnerNameFromPath(nsIMAPNamespace *namespaceForFolder, const char *canonicalFolderName)
|
||||
{
|
||||
if (!namespaceForFolder || !canonicalFolderName)
|
||||
{
|
||||
NS_ASSERTION(false,"null namespace or canonical folder name");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *rv = nullptr;
|
||||
|
||||
// convert the canonical path to the online path
|
||||
char *convertedFolderName = AllocateServerFolderName(canonicalFolderName, namespaceForFolder->GetDelimiter());
|
||||
if (convertedFolderName)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(strlen(convertedFolderName) > strlen(namespaceForFolder->GetPrefix()), "server folder name invalid");
|
||||
#endif
|
||||
if (strlen(convertedFolderName) > strlen(namespaceForFolder->GetPrefix()))
|
||||
{
|
||||
char *owner = convertedFolderName + strlen(namespaceForFolder->GetPrefix());
|
||||
NS_ASSERTION(owner, "couldn't find folder owner");
|
||||
char *nextDelimiter = strchr(owner, namespaceForFolder->GetDelimiter());
|
||||
// if !nextDelimiter, then the path is of the form Shared/Users/chrisf (no subfolder)
|
||||
if (nextDelimiter)
|
||||
{
|
||||
*nextDelimiter = 0;
|
||||
}
|
||||
rv = PL_strdup(owner);
|
||||
}
|
||||
PR_Free(convertedFolderName);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(false, "couldn't allocate server folder name");
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
GetFolderIsNamespace returns TRUE if the given folder is the folder representing
|
||||
a namespace.
|
||||
*/
|
||||
|
||||
bool nsIMAPNamespaceList::GetFolderIsNamespace(const char *hostName,
|
||||
const char *canonicalFolderName,
|
||||
char delimiter,nsIMAPNamespace *namespaceForFolder)
|
||||
{
|
||||
NS_ASSERTION(namespaceForFolder, "null namespace");
|
||||
|
||||
bool rv = false;
|
||||
|
||||
const char *prefix = namespaceForFolder->GetPrefix();
|
||||
NS_ASSERTION(prefix, "namespace has no prefix");
|
||||
if (!prefix || !*prefix) // empty namespace prefix
|
||||
return false;
|
||||
|
||||
char *convertedFolderName = AllocateServerFolderName(canonicalFolderName, delimiter);
|
||||
if (convertedFolderName)
|
||||
{
|
||||
bool lastCharIsDelimiter = (prefix[strlen(prefix) - 1] == delimiter);
|
||||
|
||||
if (lastCharIsDelimiter)
|
||||
{
|
||||
rv = ((strncmp(convertedFolderName, prefix, strlen(convertedFolderName)) == 0) &&
|
||||
(strlen(convertedFolderName) == strlen(prefix) - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = (strcmp(convertedFolderName, prefix) == 0);
|
||||
}
|
||||
|
||||
PR_Free(convertedFolderName);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(false, "couldn't allocate server folder name");
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
SuggestHierarchySeparatorForNamespace takes a namespace from libmsg
|
||||
and a hierarchy delimiter. If the namespace has not been filled in from
|
||||
online NAMESPACE command yet, it fills in the suggested delimiter to be
|
||||
used from then on (until it is overridden by an online response).
|
||||
*/
|
||||
|
||||
void nsIMAPNamespaceList::SuggestHierarchySeparatorForNamespace(nsIMAPNamespace *namespaceForFolder, char delimiterFromFolder)
|
||||
{
|
||||
NS_ASSERTION(namespaceForFolder, "need namespace");
|
||||
if (namespaceForFolder && !namespaceForFolder->GetIsDelimiterFilledIn())
|
||||
namespaceForFolder->SetDelimiter(delimiterFromFolder, false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
GenerateFullFolderNameWithDefaultNamespace takes a folder name in canonical form,
|
||||
converts it to online form, allocates a string to contain the full online server name
|
||||
including the namespace prefix of the default namespace of the given type, in the form:
|
||||
PR_smprintf("%s%s", prefix, onlineServerName) if there is a NULL owner
|
||||
PR_smprintf("%s%s%c%s", prefix, owner, delimiter, onlineServerName) if there is an owner
|
||||
It then converts this back to canonical form and returns it (allocated) to libmsg.
|
||||
It returns NULL if there is no namespace of the given type.
|
||||
If nsUsed is not passed in as NULL, then *nsUsed is filled in and returned; it is the
|
||||
namespace used for generating the folder name.
|
||||
*/
|
||||
char *nsIMAPNamespaceList::GenerateFullFolderNameWithDefaultNamespace(const char *hostName,
|
||||
const char *canonicalFolderName,
|
||||
const char *owner,
|
||||
EIMAPNamespaceType nsType,
|
||||
nsIMAPNamespace **nsUsed)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIImapHostSessionList> hostSession =
|
||||
do_GetService(kCImapHostSessionListCID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
nsIMAPNamespace *ns;
|
||||
char *fullFolderName = nullptr;
|
||||
rv = hostSession->GetDefaultNamespaceOfTypeForHost(hostName, nsType, ns);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
if (ns)
|
||||
{
|
||||
if (nsUsed)
|
||||
*nsUsed = ns;
|
||||
const char *prefix = ns->GetPrefix();
|
||||
char *convertedFolderName = AllocateServerFolderName(canonicalFolderName, ns->GetDelimiter());
|
||||
if (convertedFolderName)
|
||||
{
|
||||
char *convertedReturnName = nullptr;
|
||||
if (owner)
|
||||
{
|
||||
convertedReturnName = PR_smprintf("%s%s%c%s", prefix, owner, ns->GetDelimiter(), convertedFolderName);
|
||||
}
|
||||
else
|
||||
{
|
||||
convertedReturnName = PR_smprintf("%s%s", prefix, convertedFolderName);
|
||||
}
|
||||
|
||||
if (convertedReturnName)
|
||||
{
|
||||
fullFolderName = AllocateCanonicalFolderName(convertedReturnName, ns->GetDelimiter());
|
||||
PR_Free(convertedReturnName);
|
||||
}
|
||||
PR_Free(convertedFolderName);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(false, "couldn't allocate server folder name");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Could not find other users namespace on the given host
|
||||
NS_WARNING("couldn't find namespace for given host");
|
||||
}
|
||||
return (fullFolderName);
|
||||
}
|
||||
|
||||
87
mailnews/imap/src/nsIMAPNamespace.h
Normal file
87
mailnews/imap/src/nsIMAPNamespace.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- 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 _nsIMAPNamespace_H_
|
||||
#define _nsIMAPNamespace_H_
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIMAPNamespace
|
||||
{
|
||||
|
||||
public:
|
||||
nsIMAPNamespace(EIMAPNamespaceType type, const char *prefix, char delimiter, bool from_prefs);
|
||||
|
||||
~nsIMAPNamespace();
|
||||
|
||||
EIMAPNamespaceType GetType() { return m_namespaceType; }
|
||||
const char * GetPrefix() { return m_prefix; }
|
||||
char GetDelimiter() { return m_delimiter; }
|
||||
void SetDelimiter(char delimiter, bool delimiterFilledIn);
|
||||
bool GetIsDelimiterFilledIn() { return m_delimiterFilledIn; }
|
||||
bool GetIsNamespaceFromPrefs() { return m_fromPrefs; }
|
||||
|
||||
// returns -1 if this box is not part of this namespace,
|
||||
// or the length of the prefix if it is part of this namespace
|
||||
int MailboxMatchesNamespace(const char *boxname);
|
||||
|
||||
protected:
|
||||
EIMAPNamespaceType m_namespaceType;
|
||||
char *m_prefix;
|
||||
char m_delimiter;
|
||||
bool m_fromPrefs;
|
||||
bool m_delimiterFilledIn;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// represents an array of namespaces for a given host
|
||||
class nsIMAPNamespaceList
|
||||
{
|
||||
public:
|
||||
~nsIMAPNamespaceList();
|
||||
|
||||
static nsIMAPNamespaceList *CreatensIMAPNamespaceList();
|
||||
|
||||
nsresult InitFromString(const char *nameSpaceString, EIMAPNamespaceType nstype);
|
||||
nsresult OutputToString(nsCString &OutputString);
|
||||
int UnserializeNamespaces(const char *str, char **prefixes, int len);
|
||||
nsresult SerializeNamespaces(char **prefixes, int len, nsCString &serializedNamespace);
|
||||
|
||||
void ClearNamespaces(bool deleteFromPrefsNamespaces, bool deleteServerAdvertisedNamespaces, bool reallyDelete);
|
||||
int GetNumberOfNamespaces();
|
||||
int GetNumberOfNamespaces(EIMAPNamespaceType);
|
||||
nsIMAPNamespace *GetNamespaceNumber(int nodeIndex);
|
||||
nsIMAPNamespace *GetNamespaceNumber(int nodeIndex, EIMAPNamespaceType);
|
||||
|
||||
nsIMAPNamespace *GetDefaultNamespaceOfType(EIMAPNamespaceType type);
|
||||
int AddNewNamespace(nsIMAPNamespace *ns);
|
||||
nsIMAPNamespace *GetNamespaceForMailbox(const char *boxname);
|
||||
static nsIMAPNamespace* GetNamespaceForFolder(const char *hostName,
|
||||
const char *canonicalFolderName,
|
||||
char delimiter);
|
||||
static bool GetFolderIsNamespace(const char *hostName,
|
||||
const char *canonicalFolderName,
|
||||
char delimiter,nsIMAPNamespace *namespaceForFolder);
|
||||
static char* GetFolderNameWithoutNamespace(nsIMAPNamespace *namespaceForFolder, const char *canonicalFolderName);
|
||||
static char *AllocateServerFolderName(const char *canonicalFolderName, char delimiter);
|
||||
static char *GetFolderOwnerNameFromPath(nsIMAPNamespace *namespaceForFolder, const char *canonicalFolderName);
|
||||
static char *AllocateCanonicalFolderName(const char *onlineFolderName, char delimiter);
|
||||
static void SuggestHierarchySeparatorForNamespace(nsIMAPNamespace *namespaceForFolder, char delimiterFromFolder);
|
||||
static char *GenerateFullFolderNameWithDefaultNamespace(const char *hostName,
|
||||
const char *canonicalFolderName,
|
||||
const char *owner,
|
||||
EIMAPNamespaceType nsType,
|
||||
nsIMAPNamespace **nsUsed);
|
||||
|
||||
protected:
|
||||
nsIMAPNamespaceList(); // use CreatensIMAPNamespaceList to create one
|
||||
|
||||
nsTArray<nsIMAPNamespace*> m_NamespaceList;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
188
mailnews/imap/src/nsImapCore.h
Normal file
188
mailnews/imap/src/nsImapCore.h
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/* -*- 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 _nsImapCore_H_
|
||||
#define _nsImapCore_H_
|
||||
|
||||
#include "MailNewsTypes.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsIMailboxSpec.h"
|
||||
#include "nsIImapFlagAndUidState.h"
|
||||
|
||||
class nsIMAPNamespace;
|
||||
class nsImapProtocol;
|
||||
class nsImapFlagAndUidState;
|
||||
|
||||
/* imap message flags */
|
||||
typedef uint16_t imapMessageFlagsType;
|
||||
|
||||
/* used for communication between imap thread and event sinks */
|
||||
#define kNoFlags 0x00 /* RFC flags */
|
||||
#define kMarked 0x01
|
||||
#define kUnmarked 0x02
|
||||
#define kNoinferiors 0x04
|
||||
#define kNoselect 0x08
|
||||
#define kImapTrash 0x10 /* Navigator flag */
|
||||
#define kJustExpunged 0x20 /* This update is a post expunge url update. */
|
||||
#define kPersonalMailbox 0x40 /* this mailbox is in the personal namespace */
|
||||
#define kPublicMailbox 0x80 /* this mailbox is in the public namespace */
|
||||
#define kOtherUsersMailbox 0x100 /* this mailbox is in the other users' namespace */
|
||||
#define kNameSpace 0x200 /* this mailbox IS a namespace */
|
||||
#define kNewlyCreatedFolder 0x400 /* this folder was just created */
|
||||
#define kImapDrafts 0x800 /* XLIST says this is the drafts folder */
|
||||
#define kImapSpam 0x1000 /* XLIST says this is the spam folder */
|
||||
#define kImapSent 0x2000 /* XLIST says this is the sent folder */
|
||||
#define kImapInbox 0x4000 /* XLIST says this is the INBOX folder */
|
||||
#define kImapAllMail 0x8000 /* XLIST says this is AllMail (GMail) */
|
||||
#define kImapXListTrash 0x10000 /* XLIST says this is the trash */
|
||||
#define kNonExistent 0x20000 /* RFC 5258, LIST-EXTENDED */
|
||||
#define kSubscribed 0x40000 /* RFC 5258, LIST-EXTENDED */
|
||||
#define kRemote 0x80000 /* RFC 5258, LIST-EXTENDED */
|
||||
#define kHasChildren 0x100000 /* RFC 5258, LIST-EXTENDED */
|
||||
#define kHasNoChildren 0x200000 /* RFC 5258, LIST-EXTENDED */
|
||||
#define kImapArchive 0x400000 /* RFC 5258, LIST-EXTENDED */
|
||||
|
||||
/* flags for individual messages */
|
||||
/* currently the ui only offers \Seen and \Flagged */
|
||||
#define kNoImapMsgFlag 0x0000
|
||||
#define kImapMsgSeenFlag 0x0001
|
||||
#define kImapMsgAnsweredFlag 0x0002
|
||||
#define kImapMsgFlaggedFlag 0x0004
|
||||
#define kImapMsgDeletedFlag 0x0008
|
||||
#define kImapMsgDraftFlag 0x0010
|
||||
#define kImapMsgRecentFlag 0x0020
|
||||
#define kImapMsgForwardedFlag 0x0040 /* Not always supported, check mailbox folder */
|
||||
#define kImapMsgMDNSentFlag 0x0080 /* Not always supported. check mailbox folder */
|
||||
#define kImapMsgCustomKeywordFlag 0x0100 /* this msg has a custom keyword */
|
||||
#define kImapMsgLabelFlags 0x0E00 /* supports 5 labels only supported if the folder supports keywords */
|
||||
#define kImapMsgSupportMDNSentFlag 0x2000
|
||||
#define kImapMsgSupportForwardedFlag 0x4000
|
||||
/**
|
||||
* We use a separate xlist trash flag so we can prefer the GMail trash
|
||||
* over an existing Trash folder we may have created.
|
||||
*/
|
||||
#define kImapMsgSupportUserFlag 0x8000
|
||||
/* This seems to be the most cost effective way of
|
||||
* piggying back the server support user flag info.
|
||||
*/
|
||||
|
||||
/* if a url creator does not know the hierarchyDelimiter, use this */
|
||||
#define kOnlineHierarchySeparatorUnknown '^'
|
||||
#define kOnlineHierarchySeparatorNil '|'
|
||||
|
||||
#define IMAP_URL_TOKEN_SEPARATOR ">"
|
||||
#define kUidUnknown -1
|
||||
// Special initial value meaning ACLs need to be loaded from DB.
|
||||
#define kAclInvalid ((uint32_t) -1)
|
||||
|
||||
// this has to do with Mime Parts on Demand. It used to live in net.h
|
||||
// I'm not sure where this will live, but here is OK temporarily
|
||||
typedef enum {
|
||||
IMAP_CONTENT_NOT_MODIFIED = 0,
|
||||
IMAP_CONTENT_MODIFIED_VIEW_INLINE,
|
||||
IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS,
|
||||
IMAP_CONTENT_FORCE_CONTENT_NOT_MODIFIED
|
||||
} IMAP_ContentModifiedType;
|
||||
|
||||
// I think this should really go in an imap.h equivalent file
|
||||
typedef enum {
|
||||
kPersonalNamespace = 0,
|
||||
kOtherUsersNamespace,
|
||||
kPublicNamespace,
|
||||
kDefaultNamespace,
|
||||
kUnknownNamespace
|
||||
} EIMAPNamespaceType;
|
||||
|
||||
|
||||
/**
|
||||
* IMAP server feature, mostly CAPABILITY responses
|
||||
*
|
||||
* one of the cap flags below
|
||||
*/
|
||||
typedef uint64_t eIMAPCapabilityFlag;
|
||||
/**
|
||||
* IMAP server features, mostly CAPABILITY responses
|
||||
*
|
||||
* any set of the cap flags below, i.e.
|
||||
* i.e. 0, 1 or more |eIMAPCapabilityFlag|.
|
||||
*/
|
||||
typedef uint64_t eIMAPCapabilityFlags;
|
||||
|
||||
const eIMAPCapabilityFlag kCapabilityUndefined = 0x00000000;
|
||||
const eIMAPCapabilityFlag kCapabilityDefined = 0x00000001;
|
||||
const eIMAPCapabilityFlag kHasAuthLoginCapability = 0x00000002; /* AUTH LOGIN (not the same as kHasAuthOldLoginCapability) */
|
||||
const eIMAPCapabilityFlag kHasAuthOldLoginCapability = 0x00000004; /* original IMAP login method */
|
||||
const eIMAPCapabilityFlag kHasXSenderCapability = 0x00000008;
|
||||
const eIMAPCapabilityFlag kIMAP4Capability = 0x00000010; /* RFC1734 */
|
||||
const eIMAPCapabilityFlag kIMAP4rev1Capability = 0x00000020; /* RFC2060 */
|
||||
const eIMAPCapabilityFlag kIMAP4other = 0x00000040; /* future rev?? */
|
||||
const eIMAPCapabilityFlag kNoHierarchyRename = 0x00000080; /* no hierarchy rename */
|
||||
const eIMAPCapabilityFlag kACLCapability = 0x00000100; /* ACL extension */
|
||||
const eIMAPCapabilityFlag kNamespaceCapability = 0x00000200; /* IMAP4 Namespace Extension */
|
||||
const eIMAPCapabilityFlag kHasIDCapability = 0x00000400; /* client user agent id extension */
|
||||
const eIMAPCapabilityFlag kXServerInfoCapability = 0x00000800; /* XSERVERINFO extension for admin urls */
|
||||
const eIMAPCapabilityFlag kHasAuthPlainCapability = 0x00001000; /* new form of auth plain base64 login */
|
||||
const eIMAPCapabilityFlag kUidplusCapability = 0x00002000; /* RFC 2359 UIDPLUS extension */
|
||||
const eIMAPCapabilityFlag kLiteralPlusCapability = 0x00004000; /* RFC 2088 LITERAL+ extension */
|
||||
const eIMAPCapabilityFlag kAOLImapCapability = 0x00008000; /* aol imap extensions */
|
||||
const eIMAPCapabilityFlag kHasLanguageCapability = 0x00010000; /* language extensions */
|
||||
const eIMAPCapabilityFlag kHasCRAMCapability = 0x00020000; /* CRAM auth extension */
|
||||
const eIMAPCapabilityFlag kQuotaCapability = 0x00040000; /* RFC 2087 quota extension */
|
||||
const eIMAPCapabilityFlag kHasIdleCapability = 0x00080000; /* RFC 2177 idle extension */
|
||||
const eIMAPCapabilityFlag kHasAuthNTLMCapability = 0x00100000; /* AUTH NTLM extension */
|
||||
const eIMAPCapabilityFlag kHasAuthMSNCapability = 0x00200000; /* AUTH MSN extension */
|
||||
const eIMAPCapabilityFlag kHasStartTLSCapability =0x00400000; /* STARTTLS support */
|
||||
const eIMAPCapabilityFlag kHasAuthNoneCapability = 0x00800000; /* needs no login */
|
||||
const eIMAPCapabilityFlag kHasAuthGssApiCapability = 0x01000000; /* GSSAPI AUTH */
|
||||
const eIMAPCapabilityFlag kHasCondStoreCapability = 0x02000000; /* RFC 3551 CondStore extension */
|
||||
const eIMAPCapabilityFlag kHasEnableCapability = 0x04000000; /* RFC 5161 ENABLE extension */
|
||||
const eIMAPCapabilityFlag kHasXListCapability = 0x08000000; /* XLIST extension */
|
||||
const eIMAPCapabilityFlag kHasCompressDeflateCapability = 0x10000000; /* RFC 4978 COMPRESS extension */
|
||||
const eIMAPCapabilityFlag kHasAuthExternalCapability = 0x20000000; /* RFC 2222 SASL AUTH EXTERNAL */
|
||||
const eIMAPCapabilityFlag kHasMoveCapability = 0x40000000; /* Proposed MOVE RFC */
|
||||
const eIMAPCapabilityFlag kHasHighestModSeqCapability = 0x80000000; /* Subset of RFC 3551 */
|
||||
// above are 32bit; below start the uint64_t bits 33-64
|
||||
const eIMAPCapabilityFlag kHasListExtendedCapability = 0x100000000LL; /* RFC 5258 */
|
||||
const eIMAPCapabilityFlag kHasSpecialUseCapability = 0x200000000LL; /* RFC 6154: Sent, Draft etc. folders */
|
||||
const eIMAPCapabilityFlag kGmailImapCapability = 0x400000000LL; /* X-GM-EXT-1 capability extension for gmail */
|
||||
const eIMAPCapabilityFlag kHasXOAuth2Capability = 0x800000000LL; /* AUTH XOAUTH2 extension */
|
||||
|
||||
|
||||
// this used to be part of the connection object class - maybe we should move it into
|
||||
// something similar
|
||||
typedef enum {
|
||||
kEveryThingRFC822,
|
||||
kEveryThingRFC822Peek,
|
||||
kHeadersRFC822andUid,
|
||||
kUid,
|
||||
kFlags,
|
||||
kRFC822Size,
|
||||
kRFC822HeadersOnly,
|
||||
kMIMEPart,
|
||||
kMIMEHeader,
|
||||
kBodyStart
|
||||
} nsIMAPeFetchFields;
|
||||
|
||||
typedef struct _utf_name_struct {
|
||||
bool toUtf7Imap;
|
||||
unsigned char *sourceString;
|
||||
unsigned char *convertedString;
|
||||
} utf_name_struct;
|
||||
|
||||
typedef struct _ProgressInfo {
|
||||
char16_t *message;
|
||||
int32_t currentProgress;
|
||||
int32_t maxProgress;
|
||||
} ProgressInfo;
|
||||
|
||||
typedef enum {
|
||||
eContinue,
|
||||
eContinueNew,
|
||||
eListMyChildren,
|
||||
eNewServerDirectory,
|
||||
eCancelled
|
||||
} EMailboxDiscoverStatus;
|
||||
|
||||
#endif
|
||||
321
mailnews/imap/src/nsImapFlagAndUidState.cpp
Normal file
321
mailnews/imap/src/nsImapFlagAndUidState.cpp
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
/* -*- 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" // for pre-compiled headers
|
||||
|
||||
#include "nsImapCore.h"
|
||||
#include "nsImapFlagAndUidState.h"
|
||||
#include "nsMsgUtils.h"
|
||||
#include "prcmon.h"
|
||||
#include "nspr.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsImapFlagAndUidState, nsIImapFlagAndUidState)
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::GetNumberOfMessages(int32_t *result)
|
||||
{
|
||||
if (!result)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
*result = fUids.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::GetUidOfMessage(int32_t zeroBasedIndex, uint32_t *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
PR_CEnterMonitor(this);
|
||||
*aResult = fUids.SafeElementAt(zeroBasedIndex, nsMsgKey_None);
|
||||
PR_CExitMonitor(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::GetMessageFlags(int32_t zeroBasedIndex, uint16_t *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = fFlags.SafeElementAt(zeroBasedIndex, kNoImapMsgFlag);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::SetMessageFlags(int32_t zeroBasedIndex, unsigned short flags)
|
||||
{
|
||||
if (zeroBasedIndex < (int32_t)fUids.Length())
|
||||
fFlags[zeroBasedIndex] = flags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::GetNumberOfRecentMessages(int32_t *result)
|
||||
{
|
||||
if (!result)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PR_CEnterMonitor(this);
|
||||
uint32_t counter = 0;
|
||||
int32_t numUnseenMessages = 0;
|
||||
|
||||
for (counter = 0; counter < fUids.Length(); counter++)
|
||||
{
|
||||
if (fFlags[counter] & kImapMsgRecentFlag)
|
||||
numUnseenMessages++;
|
||||
}
|
||||
PR_CExitMonitor(this);
|
||||
|
||||
*result = numUnseenMessages;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::GetPartialUIDFetch(bool *aPartialUIDFetch)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPartialUIDFetch);
|
||||
*aPartialUIDFetch = fPartialUIDFetch;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* amount to expand for imap entry flags when we need more */
|
||||
|
||||
nsImapFlagAndUidState::nsImapFlagAndUidState(int32_t numberOfMessages)
|
||||
: fUids(numberOfMessages),
|
||||
fFlags(numberOfMessages),
|
||||
m_customFlagsHash(10),
|
||||
m_customAttributesHash(10),
|
||||
mLock("nsImapFlagAndUidState.mLock")
|
||||
{
|
||||
fSupportedUserFlags = 0;
|
||||
fNumberDeleted = 0;
|
||||
fPartialUIDFetch = true;
|
||||
}
|
||||
|
||||
nsImapFlagAndUidState::~nsImapFlagAndUidState()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImapFlagAndUidState::OrSupportedUserFlags(uint16_t flags)
|
||||
{
|
||||
fSupportedUserFlags |= flags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImapFlagAndUidState::GetSupportedUserFlags(uint16_t *aFlags)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFlags);
|
||||
*aFlags = fSupportedUserFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// we need to reset our flags, (re-read all) but chances are the memory allocation needed will be
|
||||
// very close to what we were already using
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::Reset()
|
||||
{
|
||||
PR_CEnterMonitor(this);
|
||||
fNumberDeleted = 0;
|
||||
m_customFlagsHash.Clear();
|
||||
fUids.Clear();
|
||||
fFlags.Clear();
|
||||
fPartialUIDFetch = true;
|
||||
PR_CExitMonitor(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// Remove (expunge) a message from our array, since now it is gone for good
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::ExpungeByIndex(uint32_t msgIndex)
|
||||
{
|
||||
// protect ourselves in case the server gave us an index key of -1 or 0
|
||||
if ((int32_t) msgIndex <= 0)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
if ((uint32_t) fUids.Length() < msgIndex)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
PR_CEnterMonitor(this);
|
||||
msgIndex--; // msgIndex is 1-relative
|
||||
if (fFlags[msgIndex] & kImapMsgDeletedFlag) // see if we already had counted this one as deleted
|
||||
fNumberDeleted--;
|
||||
fUids.RemoveElementAt(msgIndex);
|
||||
fFlags.RemoveElementAt(msgIndex);
|
||||
PR_CExitMonitor(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// adds to sorted list, protects against duplicates and going past array bounds.
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::AddUidFlagPair(uint32_t uid, imapMessageFlagsType flags, uint32_t zeroBasedIndex)
|
||||
{
|
||||
if (uid == nsMsgKey_None) // ignore uid of -1
|
||||
return NS_OK;
|
||||
// check for potential overflow in buffer size for uid array
|
||||
if (zeroBasedIndex > 0x3FFFFFFF)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
PR_CEnterMonitor(this);
|
||||
// make sure there is room for this pair
|
||||
if (zeroBasedIndex >= fUids.Length())
|
||||
{
|
||||
int32_t sizeToGrowBy = zeroBasedIndex - fUids.Length() + 1;
|
||||
fUids.InsertElementsAt(fUids.Length(), sizeToGrowBy, 0);
|
||||
fFlags.InsertElementsAt(fFlags.Length(), sizeToGrowBy, 0);
|
||||
}
|
||||
|
||||
fUids[zeroBasedIndex] = uid;
|
||||
fFlags[zeroBasedIndex] = flags;
|
||||
if (flags & kImapMsgDeletedFlag)
|
||||
fNumberDeleted++;
|
||||
PR_CExitMonitor(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::GetNumberOfDeletedMessages(int32_t *numDeletedMessages)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(numDeletedMessages);
|
||||
*numDeletedMessages = NumberOfDeletedMessages();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t nsImapFlagAndUidState::NumberOfDeletedMessages()
|
||||
{
|
||||
return fNumberDeleted;
|
||||
}
|
||||
|
||||
// since the uids are sorted, start from the back (rb)
|
||||
|
||||
uint32_t nsImapFlagAndUidState::GetHighestNonDeletedUID()
|
||||
{
|
||||
uint32_t msgIndex = fUids.Length();
|
||||
do
|
||||
{
|
||||
if (msgIndex <= 0)
|
||||
return(0);
|
||||
msgIndex--;
|
||||
if (fUids[msgIndex] && !(fFlags[msgIndex] & kImapMsgDeletedFlag))
|
||||
return fUids[msgIndex];
|
||||
}
|
||||
while (msgIndex > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Has the user read the last message here ? Used when we first open the inbox to see if there
|
||||
// really is new mail there.
|
||||
|
||||
bool nsImapFlagAndUidState::IsLastMessageUnseen()
|
||||
{
|
||||
uint32_t msgIndex = fUids.Length();
|
||||
|
||||
if (msgIndex <= 0)
|
||||
return false;
|
||||
msgIndex--;
|
||||
// if last message is deleted, it was probably filtered the last time around
|
||||
if (fUids[msgIndex] && (fFlags[msgIndex] & (kImapMsgSeenFlag | kImapMsgDeletedFlag)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// find a message flag given a key with non-recursive binary search, since some folders
|
||||
// may have thousand of messages, once we find the key set its index, or the index of
|
||||
// where the key should be inserted
|
||||
|
||||
imapMessageFlagsType nsImapFlagAndUidState::GetMessageFlagsFromUID(uint32_t uid, bool *foundIt, int32_t *ndx)
|
||||
{
|
||||
PR_CEnterMonitor(this);
|
||||
*ndx = (int32_t) fUids.IndexOfFirstElementGt(uid) - 1;
|
||||
*foundIt = *ndx >= 0 && fUids[*ndx] == uid;
|
||||
imapMessageFlagsType retFlags = (*foundIt) ? fFlags[*ndx] : kNoImapMsgFlag;
|
||||
PR_CExitMonitor(this);
|
||||
return retFlags;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::AddUidCustomFlagPair(uint32_t uid, const char *customFlag)
|
||||
{
|
||||
if (!customFlag)
|
||||
return NS_OK;
|
||||
|
||||
MutexAutoLock mon(mLock);
|
||||
nsCString ourCustomFlags;
|
||||
nsCString oldValue;
|
||||
if (m_customFlagsHash.Get(uid, &oldValue))
|
||||
{
|
||||
// We'll store multiple keys as space-delimited since space is not
|
||||
// a valid character in a keyword. First, we need to look for the
|
||||
// customFlag in the existing flags;
|
||||
nsDependentCString customFlagString(customFlag);
|
||||
int32_t existingCustomFlagPos = oldValue.Find(customFlagString);
|
||||
uint32_t customFlagLen = customFlagString.Length();
|
||||
while (existingCustomFlagPos != kNotFound)
|
||||
{
|
||||
// if existing flags ends with this exact flag, or flag + ' '
|
||||
// and the flag is at the beginning of the string or there is ' ' + flag
|
||||
// then we have this flag already;
|
||||
if (((oldValue.Length() == existingCustomFlagPos + customFlagLen) ||
|
||||
(oldValue.CharAt(existingCustomFlagPos + customFlagLen) == ' ')) &&
|
||||
((existingCustomFlagPos == 0) ||
|
||||
(oldValue.CharAt(existingCustomFlagPos - 1) == ' ')))
|
||||
return NS_OK;
|
||||
// else, advance to next flag
|
||||
existingCustomFlagPos = MsgFind(oldValue, customFlagString, false, existingCustomFlagPos + customFlagLen);
|
||||
}
|
||||
ourCustomFlags.Assign(oldValue);
|
||||
ourCustomFlags.AppendLiteral(" ");
|
||||
ourCustomFlags.Append(customFlag);
|
||||
m_customFlagsHash.Remove(uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ourCustomFlags.Assign(customFlag);
|
||||
}
|
||||
m_customFlagsHash.Put(uid, ourCustomFlags);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::GetCustomFlags(uint32_t uid, char **customFlags)
|
||||
{
|
||||
MutexAutoLock mon(mLock);
|
||||
nsCString value;
|
||||
if (m_customFlagsHash.Get(uid, &value))
|
||||
{
|
||||
*customFlags = NS_strdup(value.get());
|
||||
return (*customFlags) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
*customFlags = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::ClearCustomFlags(uint32_t uid)
|
||||
{
|
||||
MutexAutoLock mon(mLock);
|
||||
m_customFlagsHash.Remove(uid);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::SetCustomAttribute(uint32_t aUid,
|
||||
const nsACString &aCustomAttributeName,
|
||||
const nsACString &aCustomAttributeValue)
|
||||
{
|
||||
nsCString key;
|
||||
key.AppendInt((int64_t)aUid);
|
||||
key.Append(aCustomAttributeName);
|
||||
nsCString value;
|
||||
value.Assign(aCustomAttributeValue);
|
||||
m_customAttributesHash.Put(key, value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapFlagAndUidState::GetCustomAttribute(uint32_t aUid,
|
||||
const nsACString &aCustomAttributeName,
|
||||
nsACString &aCustomAttributeValue)
|
||||
{
|
||||
nsCString key;
|
||||
key.AppendInt((int64_t)aUid);
|
||||
key.Append(aCustomAttributeName);
|
||||
nsCString val;
|
||||
m_customAttributesHash.Get(key, &val);
|
||||
aCustomAttributeValue.Assign(val);
|
||||
return NS_OK;
|
||||
}
|
||||
55
mailnews/imap/src/nsImapFlagAndUidState.h
Normal file
55
mailnews/imap/src/nsImapFlagAndUidState.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- 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 nsImapFlagAndUidState_h___
|
||||
#define nsImapFlagAndUidState_h___
|
||||
|
||||
#include "MailNewsTypes.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIImapFlagAndUidState.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
const int32_t kImapFlagAndUidStateSize = 100;
|
||||
|
||||
#include "nsBaseHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
class nsImapFlagAndUidState : public nsIImapFlagAndUidState
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
nsImapFlagAndUidState(int numberOfMessages);
|
||||
|
||||
NS_DECL_NSIIMAPFLAGANDUIDSTATE
|
||||
|
||||
int32_t NumberOfDeletedMessages();
|
||||
|
||||
imapMessageFlagsType GetMessageFlagsFromUID(uint32_t uid, bool *foundIt, int32_t *ndx);
|
||||
|
||||
bool IsLastMessageUnseen(void);
|
||||
bool GetPartialUIDFetch() {return fPartialUIDFetch;}
|
||||
void SetPartialUIDFetch(bool isPartial) {fPartialUIDFetch = isPartial;}
|
||||
uint32_t GetHighestNonDeletedUID();
|
||||
uint16_t GetSupportedUserFlags() { return fSupportedUserFlags; }
|
||||
|
||||
private:
|
||||
virtual ~nsImapFlagAndUidState();
|
||||
|
||||
nsTArray<nsMsgKey> fUids;
|
||||
nsTArray<imapMessageFlagsType> fFlags;
|
||||
// Hash table, mapping uids to extra flags
|
||||
nsDataHashtable<nsUint32HashKey, nsCString> m_customFlagsHash;
|
||||
// Hash table, mapping UID+customAttributeName to customAttributeValue.
|
||||
nsDataHashtable<nsCStringHashKey, nsCString> m_customAttributesHash;
|
||||
uint16_t fSupportedUserFlags;
|
||||
int32_t fNumberDeleted;
|
||||
bool fPartialUIDFetch;
|
||||
mozilla::Mutex mLock;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
3382
mailnews/imap/src/nsImapIncomingServer.cpp
Normal file
3382
mailnews/imap/src/nsImapIncomingServer.cpp
Normal file
File diff suppressed because it is too large
Load diff
137
mailnews/imap/src/nsImapIncomingServer.h
Normal file
137
mailnews/imap/src/nsImapIncomingServer.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/* -*- 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 __nsImapIncomingServer_h
|
||||
#define __nsImapIncomingServer_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "msgCore.h"
|
||||
#include "nsIImapIncomingServer.h"
|
||||
#include "nsMsgIncomingServer.h"
|
||||
#include "nsIImapServerSink.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsISubscribableServer.h"
|
||||
#include "nsIUrlListener.h"
|
||||
#include "nsIMsgImapMailFolder.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
class nsIRDFService;
|
||||
|
||||
/* get some implementation from nsMsgIncomingServer */
|
||||
class nsImapIncomingServer : public nsMsgIncomingServer,
|
||||
public nsIImapIncomingServer,
|
||||
public nsIImapServerSink,
|
||||
public nsISubscribableServer,
|
||||
public nsIUrlListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
nsImapIncomingServer();
|
||||
|
||||
// overriding nsMsgIncomingServer methods
|
||||
NS_IMETHOD SetKey(const nsACString& aKey) override; // override nsMsgIncomingServer's implementation...
|
||||
NS_IMETHOD GetLocalStoreType(nsACString& type) override;
|
||||
NS_IMETHOD GetLocalDatabaseType(nsACString& type) override;
|
||||
|
||||
NS_DECL_NSIIMAPINCOMINGSERVER
|
||||
NS_DECL_NSIIMAPSERVERSINK
|
||||
NS_DECL_NSISUBSCRIBABLESERVER
|
||||
NS_DECL_NSIURLLISTENER
|
||||
|
||||
NS_IMETHOD PerformBiff(nsIMsgWindow *aMsgWindow) override;
|
||||
NS_IMETHOD PerformExpand(nsIMsgWindow *aMsgWindow) override;
|
||||
NS_IMETHOD CloseCachedConnections() override;
|
||||
NS_IMETHOD GetConstructedPrettyName(nsAString& retval) override;
|
||||
NS_IMETHOD GetCanBeDefaultServer(bool *canBeDefaultServer) override;
|
||||
NS_IMETHOD GetCanCompactFoldersOnServer(bool *canCompactFoldersOnServer
|
||||
) override;
|
||||
NS_IMETHOD GetCanUndoDeleteOnServer(bool *canUndoDeleteOnServer) override;
|
||||
NS_IMETHOD GetCanSearchMessages(bool *canSearchMessages) override;
|
||||
NS_IMETHOD GetCanEmptyTrashOnExit(bool *canEmptyTrashOnExit) override;
|
||||
NS_IMETHOD GetOfflineSupportLevel(int32_t *aSupportLevel) override;
|
||||
NS_IMETHOD GeneratePrettyNameForMigration(nsAString& aPrettyName) override;
|
||||
NS_IMETHOD GetSupportsDiskSpace(bool *aSupportsDiskSpace) override;
|
||||
NS_IMETHOD GetCanCreateFoldersOnServer(bool *aCanCreateFoldersOnServer
|
||||
) override;
|
||||
NS_IMETHOD GetCanFileMessagesOnServer(bool *aCanFileMessagesOnServer
|
||||
) override;
|
||||
NS_IMETHOD GetFilterScope(nsMsgSearchScopeValue *filterScope) override;
|
||||
NS_IMETHOD GetSearchScope(nsMsgSearchScopeValue *searchScope) override;
|
||||
NS_IMETHOD GetServerRequiresPasswordForBiff(bool *aServerRequiresPasswordForBiff
|
||||
) override;
|
||||
NS_IMETHOD OnUserOrHostNameChanged(const nsACString& oldName,
|
||||
const nsACString& newName,
|
||||
bool hostnameChanged) override;
|
||||
NS_IMETHOD GetNumIdleConnections(int32_t *aNumIdleConnections);
|
||||
NS_IMETHOD ForgetSessionPassword() override;
|
||||
NS_IMETHOD GetMsgFolderFromURI(nsIMsgFolder *aFolderResource,
|
||||
const nsACString& aURI,
|
||||
nsIMsgFolder **aFolder) override;
|
||||
NS_IMETHOD SetSocketType(int32_t aSocketType) override;
|
||||
NS_IMETHOD VerifyLogon(nsIUrlListener *aUrlListener, nsIMsgWindow *aMsgWindow,
|
||||
nsIURI **aURL) override;
|
||||
|
||||
protected:
|
||||
virtual ~nsImapIncomingServer();
|
||||
nsresult GetFolder(const nsACString& name, nsIMsgFolder** pFolder);
|
||||
virtual nsresult CreateRootFolderFromUri(const nsCString &serverUri,
|
||||
nsIMsgFolder **rootFolder) override;
|
||||
nsresult ResetFoldersToUnverified(nsIMsgFolder *parentFolder);
|
||||
void GetUnverifiedSubFolders(nsIMsgFolder *parentFolder,
|
||||
nsCOMArray<nsIMsgImapMailFolder> &aFoldersArray);
|
||||
void GetUnverifiedFolders(nsCOMArray<nsIMsgImapMailFolder> &aFolderArray);
|
||||
nsresult DeleteNonVerifiedFolders(nsIMsgFolder *parentFolder);
|
||||
bool NoDescendentsAreVerified(nsIMsgFolder *parentFolder);
|
||||
bool AllDescendentsAreNoSelect(nsIMsgFolder *parentFolder);
|
||||
|
||||
nsresult GetStringBundle();
|
||||
static nsresult AlertUser(const nsAString& aString, nsIMsgMailNewsUrl *aUrl);
|
||||
|
||||
private:
|
||||
nsresult SubscribeToFolder(const char16_t *aName, bool subscribe);
|
||||
nsresult GetImapConnection(nsIImapUrl* aImapUrl,
|
||||
nsIImapProtocol** aImapConnection);
|
||||
nsresult CreateProtocolInstance(nsIImapProtocol ** aImapConnection);
|
||||
nsresult CreateHostSpecificPrefName(const char *prefPrefix, nsAutoCString &prefName);
|
||||
|
||||
nsresult DoomUrlIfChannelHasError(nsIImapUrl *aImapUrl, bool *urlDoomed);
|
||||
bool ConnectionTimeOut(nsIImapProtocol* aImapConnection);
|
||||
nsresult GetFormattedStringFromName(const nsAString& aValue, const char* aName, nsAString& aResult);
|
||||
nsresult GetPrefForServerAttribute(const char *prefSuffix, bool *prefValue);
|
||||
bool CheckSpecialFolder(nsIRDFService *rdf, nsCString &folderUri,
|
||||
uint32_t folderFlag, nsCString &existingUri);
|
||||
|
||||
nsCOMArray<nsIImapProtocol> m_connectionCache;
|
||||
nsCOMArray<nsIImapUrl> m_urlQueue;
|
||||
nsCOMPtr<nsIStringBundle> m_stringBundle;
|
||||
nsCOMArray<nsIMsgFolder> m_subscribeFolders; // used to keep folder resources around while subscribe UI is up.
|
||||
nsCOMArray<nsIMsgImapMailFolder> m_foldersToStat; // folders to check for new mail with Status
|
||||
nsTArray<nsISupports*> m_urlConsumers;
|
||||
eIMAPCapabilityFlags m_capability;
|
||||
nsCString m_manageMailAccountUrl;
|
||||
bool m_userAuthenticated;
|
||||
bool mDoingSubscribeDialog;
|
||||
bool mDoingLsub;
|
||||
bool m_shuttingDown;
|
||||
|
||||
mozilla::Mutex mLock;
|
||||
// subscribe dialog stuff
|
||||
nsresult AddFolderToSubscribeDialog(const char *parentUri, const char *uri,const char *folderName);
|
||||
nsCOMPtr <nsISubscribableServer> mInner;
|
||||
nsresult EnsureInner();
|
||||
nsresult ClearInner();
|
||||
|
||||
// Utility function for checking folder existence
|
||||
nsresult GetExistingMsgFolder(const nsACString& aURI,
|
||||
nsACString& folderUriWithNamespace,
|
||||
bool& namespacePrefixAdded,
|
||||
bool caseInsensitive,
|
||||
nsIMsgFolder **aFolder);
|
||||
};
|
||||
|
||||
#endif
|
||||
9868
mailnews/imap/src/nsImapMailFolder.cpp
Normal file
9868
mailnews/imap/src/nsImapMailFolder.cpp
Normal file
File diff suppressed because it is too large
Load diff
550
mailnews/imap/src/nsImapMailFolder.h
Normal file
550
mailnews/imap/src/nsImapMailFolder.h
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
/* -*- 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 nsImapMailFolder_h__
|
||||
#define nsImapMailFolder_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsImapCore.h"
|
||||
#include "nsMsgDBFolder.h"
|
||||
#include "nsIImapMailFolderSink.h"
|
||||
#include "nsIImapMessageSink.h"
|
||||
#include "nsICopyMessageListener.h"
|
||||
#include "nsIImapService.h"
|
||||
#include "nsIUrlListener.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIImapIncomingServer.h" // we need this for its IID
|
||||
#include "nsIMsgParseMailMsgState.h"
|
||||
#include "nsITransactionManager.h"
|
||||
#include "nsImapUndoTxn.h"
|
||||
#include "nsIMsgMessageService.h"
|
||||
#include "nsIMsgFilterHitNotify.h"
|
||||
#include "nsIMsgFilterList.h"
|
||||
#include "prmon.h"
|
||||
#include "nsIMsgImapMailFolder.h"
|
||||
#include "nsIMsgLocalMailFolder.h"
|
||||
#include "nsIMsgThread.h"
|
||||
#include "nsIImapMailFolderSink.h"
|
||||
#include "nsIImapServerSink.h"
|
||||
#include "nsIMsgFilterPlugin.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsAutoSyncState.h"
|
||||
#include "nsIRequestObserver.h"
|
||||
|
||||
class nsImapMoveCoalescer;
|
||||
class nsIMsgIdentity;
|
||||
class nsIMsgOfflineImapOperation;
|
||||
|
||||
#define COPY_BUFFER_SIZE 16384
|
||||
|
||||
#define NS_IMAPMAILCOPYSTATE_IID \
|
||||
{ 0xb64534f0, 0x3d53, 0x11d3, \
|
||||
{ 0xac, 0x2a, 0x00, 0x80, 0x5f, 0x8a, 0xc9, 0x68 } }
|
||||
|
||||
class nsImapMailCopyState: public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMAPMAILCOPYSTATE_IID)
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
nsImapMailCopyState();
|
||||
|
||||
nsCOMPtr<nsISupports> m_srcSupport; // source file spec or folder
|
||||
nsCOMPtr<nsIArray> m_messages; // array of source messages
|
||||
RefPtr<nsImapMoveCopyMsgTxn> m_undoMsgTxn; // undo object with this copy operation
|
||||
nsCOMPtr<nsIMsgDBHdr> m_message; // current message to be copied
|
||||
nsCOMPtr<nsIMsgCopyServiceListener> m_listener; // listener of this copy
|
||||
// operation
|
||||
nsCOMPtr<nsIFile> m_tmpFile; // temp file spec for copy operation
|
||||
nsCOMPtr<nsIMsgWindow> m_msgWindow; // msg window for copy operation
|
||||
|
||||
nsCOMPtr<nsIMsgMessageService> m_msgService; // source folder message service; can
|
||||
// be Nntp, Mailbox, or Imap
|
||||
bool m_isMove; // is a move
|
||||
bool m_selectedState; // needs to be in selected state; append msg
|
||||
bool m_isCrossServerOp; // are we copying between imap servers?
|
||||
uint32_t m_curIndex; // message index to the message array which we are
|
||||
// copying
|
||||
uint32_t m_totalCount;// total count of messages we have to do
|
||||
uint32_t m_unreadCount; // num unread messages we're moving
|
||||
bool m_streamCopy;
|
||||
char *m_dataBuffer; // temporary buffer for this copy operation
|
||||
nsCOMPtr<nsIOutputStream> m_msgFileStream; // temporary file (processed mail)
|
||||
uint32_t m_dataBufferSize;
|
||||
uint32_t m_leftOver;
|
||||
bool m_allowUndo;
|
||||
bool m_eatLF;
|
||||
uint32_t m_newMsgFlags; // only used if there's no m_message
|
||||
nsCString m_newMsgKeywords; // ditto
|
||||
// If the server supports UIDPLUS, this is the UID for the append,
|
||||
// if we're doing an append.
|
||||
nsMsgKey m_appendUID;
|
||||
|
||||
private:
|
||||
virtual ~nsImapMailCopyState();
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsImapMailCopyState, NS_IMAPMAILCOPYSTATE_IID)
|
||||
|
||||
// ACLs for this folder.
|
||||
// Generally, we will try to always query this class when performing
|
||||
// an operation on the folder.
|
||||
// If the server doesn't support ACLs, none of this data will be filled in.
|
||||
// Therefore, we can assume that if we look up ourselves and don't find
|
||||
// any info (and also look up "anyone") then we have full rights, that is, ACLs don't exist.
|
||||
class nsImapMailFolder;
|
||||
|
||||
#define IMAP_ACL_READ_FLAG 0x0000001 /* SELECT, CHECK, FETCH, PARTIAL, SEARCH, COPY from folder */
|
||||
#define IMAP_ACL_STORE_SEEN_FLAG 0x0000002 /* STORE SEEN flag */
|
||||
#define IMAP_ACL_WRITE_FLAG 0x0000004 /* STORE flags other than SEEN and DELETED */
|
||||
#define IMAP_ACL_INSERT_FLAG 0x0000008 /* APPEND, COPY into folder */
|
||||
#define IMAP_ACL_POST_FLAG 0x0000010 /* Can I send mail to the submission address for folder? */
|
||||
#define IMAP_ACL_CREATE_SUBFOLDER_FLAG 0x0000020 /* Can I CREATE a subfolder of this folder? */
|
||||
#define IMAP_ACL_DELETE_FLAG 0x0000040 /* STORE DELETED flag */
|
||||
#define IMAP_ACL_ADMINISTER_FLAG 0x0000080 /* perform SETACL */
|
||||
#define IMAP_ACL_RETRIEVED_FLAG 0x0000100 /* ACL info for this folder has been initialized */
|
||||
#define IMAP_ACL_EXPUNGE_FLAG 0x0000200 // can EXPUNGE or do implicit EXPUNGE on CLOSE
|
||||
#define IMAP_ACL_DELETE_FOLDER 0x0000400 // can DELETE/RENAME folder
|
||||
|
||||
class nsMsgIMAPFolderACL
|
||||
{
|
||||
public:
|
||||
nsMsgIMAPFolderACL(nsImapMailFolder *folder);
|
||||
~nsMsgIMAPFolderACL();
|
||||
|
||||
bool SetFolderRightsForUser(const nsACString& userName, const nsACString& rights);
|
||||
|
||||
public:
|
||||
|
||||
// generic for any user, although we might not use them in
|
||||
// DO NOT use these for looking up information about the currently authenticated user.
|
||||
// (There are some different checks and defaults we do).
|
||||
// Instead, use the functions below, GetICan....()
|
||||
bool GetCanUserLookupFolder(const nsACString& userName); // Is folder visible to LIST/LSUB?
|
||||
bool GetCanUserReadFolder(const nsACString& userName); // SELECT, CHECK, FETCH, PARTIAL, SEARCH, COPY from folder?
|
||||
bool GetCanUserStoreSeenInFolder(const nsACString& userName); // STORE SEEN flag?
|
||||
bool GetCanUserWriteFolder(const nsACString& userName); // STORE flags other than SEEN and DELETED?
|
||||
bool GetCanUserInsertInFolder(const nsACString& userName); // APPEND, COPY into folder?
|
||||
bool GetCanUserPostToFolder(const nsACString& userName); // Can I send mail to the submission address for folder?
|
||||
bool GetCanUserCreateSubfolder(const nsACString& userName); // Can I CREATE a subfolder of this folder?
|
||||
bool GetCanUserDeleteInFolder(const nsACString& userName); // STORE DELETED flag, perform EXPUNGE?
|
||||
bool GetCanUserAdministerFolder(const nsACString& userName); // perform SETACL?
|
||||
|
||||
// Functions to find out rights for the currently authenticated user.
|
||||
|
||||
bool GetCanILookupFolder(); // Is folder visible to LIST/LSUB?
|
||||
bool GetCanIReadFolder(); // SELECT, CHECK, FETCH, PARTIAL, SEARCH, COPY from folder?
|
||||
bool GetCanIStoreSeenInFolder(); // STORE SEEN flag?
|
||||
bool GetCanIWriteFolder(); // STORE flags other than SEEN and DELETED?
|
||||
bool GetCanIInsertInFolder(); // APPEND, COPY into folder?
|
||||
bool GetCanIPostToFolder(); // Can I send mail to the submission address for folder?
|
||||
bool GetCanICreateSubfolder(); // Can I CREATE a subfolder of this folder?
|
||||
bool GetCanIDeleteInFolder(); // STORE DELETED flag?
|
||||
bool GetCanIAdministerFolder(); // perform SETACL?
|
||||
bool GetCanIExpungeFolder(); // perform EXPUNGE?
|
||||
|
||||
bool GetDoIHaveFullRightsForFolder(); // Returns TRUE if I have full rights on this folder (all of the above return TRUE)
|
||||
|
||||
bool GetIsFolderShared(); // We use this to see if the ACLs think a folder is shared or not.
|
||||
// We will define "Shared" in 5.0 to mean:
|
||||
// At least one user other than the currently authenticated user has at least one
|
||||
// explicitly-listed ACL right on that folder.
|
||||
|
||||
// Returns a newly allocated string describing these rights
|
||||
nsresult CreateACLRightsString(nsAString& rightsString);
|
||||
|
||||
nsresult GetRightsStringForUser(const nsACString& userName, nsCString &rights);
|
||||
|
||||
nsresult GetOtherUsers(nsIUTF8StringEnumerator** aResult);
|
||||
|
||||
protected:
|
||||
bool GetFlagSetInRightsForUser(const nsACString& userName, char flag, bool defaultIfNotFound);
|
||||
void BuildInitialACLFromCache();
|
||||
void UpdateACLCache();
|
||||
|
||||
protected:
|
||||
nsDataHashtable <nsCStringHashKey, nsCString> m_rightsHash; // Hash table, mapping username strings to rights strings.
|
||||
nsImapMailFolder *m_folder;
|
||||
int32_t m_aclCount;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates parameters required to playback offline ops
|
||||
* on given folder.
|
||||
*/
|
||||
struct nsPlaybackRequest
|
||||
{
|
||||
explicit nsPlaybackRequest(nsImapMailFolder *srcFolder, nsIMsgWindow *msgWindow)
|
||||
: SrcFolder(srcFolder), MsgWindow(msgWindow)
|
||||
{
|
||||
}
|
||||
nsImapMailFolder *SrcFolder;
|
||||
nsCOMPtr<nsIMsgWindow> MsgWindow;
|
||||
};
|
||||
|
||||
class nsImapMailFolder : public nsMsgDBFolder,
|
||||
public nsIMsgImapMailFolder,
|
||||
public nsIImapMailFolderSink,
|
||||
public nsIImapMessageSink,
|
||||
public nsICopyMessageListener,
|
||||
public nsIMsgFilterHitNotify
|
||||
{
|
||||
static const uint32_t PLAYBACK_TIMER_INTERVAL_IN_MS = 500;
|
||||
public:
|
||||
nsImapMailFolder();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIMsgFolder methods:
|
||||
NS_IMETHOD GetSubFolders(nsISimpleEnumerator **aResult) override;
|
||||
|
||||
NS_IMETHOD GetMessages(nsISimpleEnumerator* *result) override;
|
||||
NS_IMETHOD UpdateFolder(nsIMsgWindow *aWindow) override;
|
||||
|
||||
NS_IMETHOD CreateSubfolder(const nsAString& folderName,nsIMsgWindow *msgWindow ) override;
|
||||
NS_IMETHOD AddSubfolder(const nsAString& aName, nsIMsgFolder** aChild) override;
|
||||
NS_IMETHODIMP CreateStorageIfMissing(nsIUrlListener* urlListener) 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 CopyDataToOutputStreamForAppend(nsIInputStream *aIStream,
|
||||
int32_t aLength, nsIOutputStream *outputStream) override;
|
||||
NS_IMETHOD CopyDataDone() override;
|
||||
NS_IMETHOD Delete () override;
|
||||
NS_IMETHOD Rename (const nsAString& newName, nsIMsgWindow *msgWindow) override;
|
||||
NS_IMETHOD RenameSubFolders(nsIMsgWindow *msgWindow, nsIMsgFolder *oldFolder) override;
|
||||
NS_IMETHOD GetNoSelect(bool *aResult) override;
|
||||
|
||||
NS_IMETHOD GetPrettyName(nsAString& prettyName) override; // Override of the base, for top-level mail folder
|
||||
|
||||
NS_IMETHOD GetFolderURL(nsACString& url) override;
|
||||
|
||||
NS_IMETHOD UpdateSummaryTotals(bool force) override;
|
||||
|
||||
NS_IMETHOD GetDeletable (bool *deletable) override;
|
||||
|
||||
NS_IMETHOD GetSizeOnDisk(int64_t *size) override;
|
||||
|
||||
NS_IMETHOD GetCanCreateSubfolders(bool *aResult) override;
|
||||
NS_IMETHOD GetCanSubscribe(bool *aResult) override;
|
||||
|
||||
NS_IMETHOD ApplyRetentionSettings() override;
|
||||
|
||||
NS_IMETHOD AddMessageDispositionState(nsIMsgDBHdr *aMessage, nsMsgDispositionState aDispositionFlag) override;
|
||||
NS_IMETHOD MarkMessagesRead(nsIArray *messages, bool markRead) override;
|
||||
NS_IMETHOD MarkAllMessagesRead(nsIMsgWindow *aMsgWindow) override;
|
||||
NS_IMETHOD MarkMessagesFlagged(nsIArray *messages, bool markFlagged) override;
|
||||
NS_IMETHOD MarkThreadRead(nsIMsgThread *thread) override;
|
||||
NS_IMETHOD SetLabelForMessages(nsIArray *aMessages, nsMsgLabelValue aLabel) override;
|
||||
NS_IMETHOD SetJunkScoreForMessages(nsIArray *aMessages, const nsACString& aJunkScore) override;
|
||||
NS_IMETHOD DeleteSubFolders(nsIArray *folders, nsIMsgWindow *msgWindow) override;
|
||||
NS_IMETHOD ReadFromFolderCacheElem(nsIMsgFolderCacheElement *element) override;
|
||||
NS_IMETHOD WriteToFolderCacheElem(nsIMsgFolderCacheElement *element) 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 isMove, nsIMsgWindow *msgWindow,
|
||||
nsIMsgCopyServiceListener* listener) override;
|
||||
NS_IMETHOD CopyFileMessage(nsIFile* file,
|
||||
nsIMsgDBHdr* msgToReplace,
|
||||
bool isDraftOrTemplate,
|
||||
uint32_t aNewMsgFlags,
|
||||
const nsACString &aNewMsgKeywords,
|
||||
nsIMsgWindow *msgWindow,
|
||||
nsIMsgCopyServiceListener* listener) override;
|
||||
NS_IMETHOD GetNewMessages(nsIMsgWindow *aWindow, nsIUrlListener *aListener) override;
|
||||
|
||||
NS_IMETHOD GetFilePath(nsIFile** aPathName) override;
|
||||
NS_IMETHOD SetFilePath(nsIFile * aPath) override;
|
||||
|
||||
NS_IMETHOD Shutdown(bool shutdownChildren) override;
|
||||
|
||||
NS_IMETHOD DownloadMessagesForOffline(nsIArray *messages, nsIMsgWindow *msgWindow) override;
|
||||
|
||||
NS_IMETHOD DownloadAllForOffline(nsIUrlListener *listener, nsIMsgWindow *msgWindow) override;
|
||||
NS_IMETHOD GetCanFileMessages(bool *aCanFileMessages) override;
|
||||
NS_IMETHOD GetCanDeleteMessages(bool *aCanDeleteMessages) 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 NotifyCompactCompleted() override;
|
||||
|
||||
// overrides nsMsgDBFolder::HasMsgOffline()
|
||||
NS_IMETHOD HasMsgOffline(nsMsgKey msgKey, bool *_retval) override;
|
||||
// overrides nsMsgDBFolder::GetOfflineFileStream()
|
||||
NS_IMETHOD GetOfflineFileStream(nsMsgKey msgKey, int64_t *offset, uint32_t *size, nsIInputStream **aFileStream) override;
|
||||
|
||||
NS_DECL_NSIMSGIMAPMAILFOLDER
|
||||
NS_DECL_NSIIMAPMAILFOLDERSINK
|
||||
NS_DECL_NSIIMAPMESSAGESINK
|
||||
NS_DECL_NSICOPYMESSAGELISTENER
|
||||
|
||||
// nsIUrlListener methods
|
||||
NS_IMETHOD OnStartRunningUrl(nsIURI * aUrl) override;
|
||||
NS_IMETHOD OnStopRunningUrl(nsIURI * aUrl, nsresult aExitCode) override;
|
||||
|
||||
NS_DECL_NSIMSGFILTERHITNOTIFY
|
||||
NS_DECL_NSIJUNKMAILCLASSIFICATIONLISTENER
|
||||
|
||||
NS_IMETHOD IsCommandEnabled(const nsACString& command, bool *result) override;
|
||||
NS_IMETHOD SetFilterList(nsIMsgFilterList *aMsgFilterList) override;
|
||||
NS_IMETHOD GetCustomIdentity(nsIMsgIdentity **aIdentity) override;
|
||||
|
||||
/**
|
||||
* This method is used to locate a folder where a msg could be present, not just
|
||||
* the folder where the message first arrives, this method searches for the existence
|
||||
* of msg in all the folders/labels that we retrieve from X-GM-LABELS also.
|
||||
* overrides nsMsgDBFolder::GetOfflineMsgFolder()
|
||||
* @param msgKey key of the msg for which we are trying to get the folder;
|
||||
* @param aMsgFolder required folder;
|
||||
*/
|
||||
NS_IMETHOD GetOfflineMsgFolder(nsMsgKey msgKey, nsIMsgFolder **aMsgFolder) override;
|
||||
|
||||
NS_IMETHOD GetIncomingServerType(nsACString& serverType) override;
|
||||
|
||||
nsresult AddSubfolderWithPath(nsAString& name, nsIFile *dbPath, nsIMsgFolder **child, bool brandNew = false);
|
||||
nsresult MoveIncorporatedMessage(nsIMsgDBHdr *mailHdr,
|
||||
nsIMsgDatabase *sourceDB,
|
||||
const nsACString& destFolder,
|
||||
nsIMsgFilter *filter,
|
||||
nsIMsgWindow *msgWindow);
|
||||
|
||||
// send notification to copy service listener.
|
||||
nsresult OnCopyCompleted(nsISupports *srcSupport, nsresult exitCode);
|
||||
|
||||
static nsresult AllocateUidStringFromKeys(nsMsgKey *keys, uint32_t numKeys, nsCString &msgIds);
|
||||
static nsresult BuildIdsAndKeyArray(nsIArray* messages, nsCString& msgIds, nsTArray<nsMsgKey>& keyArray);
|
||||
|
||||
// these might end up as an nsIImapMailFolder attribute.
|
||||
nsresult SetSupportedUserFlags(uint32_t userFlags);
|
||||
nsresult GetSupportedUserFlags(uint32_t *userFlags);
|
||||
|
||||
// Find the start of a range of msgKeys that can hold srcCount headers.
|
||||
nsresult FindOpenRange(nsMsgKey &fakeBase, uint32_t srcCount);
|
||||
|
||||
protected:
|
||||
virtual ~nsImapMailFolder();
|
||||
// Helper methods
|
||||
|
||||
virtual nsresult CreateChildFromURI(const nsCString &uri, nsIMsgFolder **folder) override;
|
||||
void FindKeysToAdd(const nsTArray<nsMsgKey> &existingKeys, nsTArray<nsMsgKey>
|
||||
&keysToFetch, uint32_t &numNewUnread, nsIImapFlagAndUidState *flagState);
|
||||
void FindKeysToDelete(const nsTArray<nsMsgKey> &existingKeys, nsTArray<nsMsgKey>
|
||||
&keysToFetch, nsIImapFlagAndUidState *flagState, uint32_t boxFlags);
|
||||
void PrepareToAddHeadersToMailDB(nsIImapProtocol* aProtocol);
|
||||
void TweakHeaderFlags(nsIImapProtocol* aProtocol, nsIMsgDBHdr *tweakMe);
|
||||
|
||||
nsresult SyncFlags(nsIImapFlagAndUidState *flagState);
|
||||
nsresult HandleCustomFlags(nsMsgKey uidOfMessage, nsIMsgDBHdr *dbHdr,
|
||||
uint16_t userFlags, nsCString& keywords);
|
||||
nsresult NotifyMessageFlagsFromHdr(nsIMsgDBHdr *dbHdr, nsMsgKey msgKey,
|
||||
uint32_t flags);
|
||||
|
||||
nsresult SetupHeaderParseStream(uint32_t size, const nsACString& content_type, nsIMailboxSpec *boxSpec);
|
||||
nsresult ParseAdoptedHeaderLine(const char *messageLine, nsMsgKey msgKey);
|
||||
nsresult NormalEndHeaderParseStream(nsIImapProtocol *aProtocol, nsIImapUrl *imapUrl);
|
||||
|
||||
void EndOfflineDownload();
|
||||
|
||||
/**
|
||||
* At the end of a file-to-folder copy operation, copy the file to the
|
||||
* offline store and/or add to the message database, (if needed).
|
||||
*
|
||||
* @param srcFile file containing the message key
|
||||
* @param msgKey key to use for the new messages
|
||||
*/
|
||||
nsresult CopyFileToOfflineStore(nsIFile *srcFile, nsMsgKey msgKey);
|
||||
|
||||
nsresult MarkMessagesImapDeleted(nsTArray<nsMsgKey> *keyArray, bool deleted, nsIMsgDatabase *db);
|
||||
|
||||
// Notifies imap autosync that it should update this folder when it
|
||||
// gets a chance.
|
||||
void NotifyHasPendingMsgs();
|
||||
void UpdatePendingCounts();
|
||||
void SetIMAPDeletedFlag(nsIMsgDatabase *mailDB, const nsTArray<nsMsgKey> &msgids, bool markDeleted);
|
||||
virtual bool ShowDeletedMessages();
|
||||
virtual bool DeleteIsMoveToTrash();
|
||||
nsresult GetFolder(const nsACString& name, nsIMsgFolder **pFolder);
|
||||
nsresult GetTrashFolder(nsIMsgFolder **pTrashFolder);
|
||||
bool TrashOrDescendentOfTrash(nsIMsgFolder* folder);
|
||||
static bool ShouldCheckAllFolders(nsIImapIncomingServer *imapServer);
|
||||
nsresult GetServerKey(nsACString& serverKey);
|
||||
nsresult DisplayStatusMsg(nsIImapUrl *aImapUrl, const nsAString& msg);
|
||||
|
||||
//nsresult RenameLocal(const char *newName);
|
||||
nsresult AddDirectorySeparator(nsIFile *path);
|
||||
nsresult CreateSubFolders(nsIFile *path);
|
||||
nsresult GetDatabase() override;
|
||||
|
||||
nsresult GetFolderOwnerUserName(nsACString& userName);
|
||||
nsIMAPNamespace *GetNamespaceForFolder();
|
||||
void SetNamespaceForFolder(nsIMAPNamespace *ns);
|
||||
|
||||
nsMsgIMAPFolderACL * GetFolderACL();
|
||||
nsresult CreateACLRightsStringForFolder(nsAString& rightsString);
|
||||
nsresult GetBodysToDownload(nsTArray<nsMsgKey> *keysOfMessagesToDownload);
|
||||
// Uber message copy service
|
||||
nsresult CopyMessagesWithStream(nsIMsgFolder* srcFolder,
|
||||
nsIArray* messages,
|
||||
bool isMove,
|
||||
bool isCrossServerOp,
|
||||
nsIMsgWindow *msgWindow,
|
||||
nsIMsgCopyServiceListener* listener, bool allowUndo);
|
||||
nsresult CopyStreamMessage(nsIMsgDBHdr* message, nsIMsgFolder* dstFolder,
|
||||
nsIMsgWindow *msgWindow, bool isMove);
|
||||
nsresult InitCopyState(nsISupports* srcSupport,
|
||||
nsIArray* messages,
|
||||
bool isMove,
|
||||
bool selectedState,
|
||||
bool acrossServers,
|
||||
uint32_t newMsgFlags,
|
||||
const nsACString &newMsgKeywords,
|
||||
nsIMsgCopyServiceListener* listener,
|
||||
nsIMsgWindow *msgWindow,
|
||||
bool allowUndo);
|
||||
nsresult GetMoveCoalescer();
|
||||
nsresult PlaybackCoalescedOperations();
|
||||
virtual nsresult CreateBaseMessageURI(const nsACString& aURI) override;
|
||||
// offline-ish methods
|
||||
nsresult GetClearedOriginalOp(nsIMsgOfflineImapOperation *op, nsIMsgOfflineImapOperation **originalOp, nsIMsgDatabase **originalDB);
|
||||
nsresult GetOriginalOp(nsIMsgOfflineImapOperation *op, nsIMsgOfflineImapOperation **originalOp, nsIMsgDatabase **originalDB);
|
||||
nsresult CopyMessagesOffline(nsIMsgFolder* srcFolder,
|
||||
nsIArray* messages,
|
||||
bool isMove,
|
||||
nsIMsgWindow *msgWindow,
|
||||
nsIMsgCopyServiceListener* listener);
|
||||
void SetPendingAttributes(nsIArray* messages, bool aIsMove);
|
||||
|
||||
nsresult CopyOfflineMsgBody(nsIMsgFolder *srcFolder, nsIMsgDBHdr *destHdr,
|
||||
nsIMsgDBHdr *origHdr, nsIInputStream *inputStream,
|
||||
nsIOutputStream *outputStream);
|
||||
|
||||
void GetTrashFolderName(nsAString &aFolderName);
|
||||
bool ShowPreviewText();
|
||||
|
||||
// Pseudo-Offline operation playback timer
|
||||
static void PlaybackTimerCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
nsresult CreatePlaybackTimer();
|
||||
|
||||
// Allocate and initialize associated auto-sync state object.
|
||||
void InitAutoSyncState();
|
||||
|
||||
bool m_initialized;
|
||||
bool m_haveDiscoveredAllFolders;
|
||||
nsCOMPtr<nsIMsgParseMailMsgState> m_msgParser;
|
||||
nsCOMPtr<nsIMsgFilterList> m_filterList;
|
||||
nsCOMPtr<nsIMsgFilterPlugin> m_filterPlugin; // XXX should be a list
|
||||
// used with filter plugins to know when we've finished classifying and can playback moves
|
||||
bool m_msgMovedByFilter;
|
||||
nsImapMoveCoalescer *m_moveCoalescer; // strictly owned by the nsImapMailFolder
|
||||
nsCOMPtr<nsIMutableArray> m_junkMessagesToMarkAsRead;
|
||||
/// list of keys to be moved to the junk folder
|
||||
nsTArray<nsMsgKey> mSpamKeysToMove;
|
||||
/// the junk destination folder
|
||||
nsCOMPtr<nsIMsgFolder> mSpamFolder;
|
||||
nsMsgKey m_curMsgUid;
|
||||
uint32_t m_uidValidity;
|
||||
|
||||
// These three vars are used to store counts from STATUS or SELECT command
|
||||
// They include deleted messages, so they can differ from the generic
|
||||
// folder total and unread counts.
|
||||
int32_t m_numServerRecentMessages;
|
||||
int32_t m_numServerUnseenMessages;
|
||||
int32_t m_numServerTotalMessages;
|
||||
// if server supports UIDNEXT, we store it here.
|
||||
int32_t m_nextUID;
|
||||
|
||||
int32_t m_nextMessageByteLength;
|
||||
nsCOMPtr<nsIUrlListener> m_urlListener;
|
||||
bool m_urlRunning;
|
||||
|
||||
// undo move/copy transaction support
|
||||
RefPtr<nsMsgTxn> m_pendingUndoTxn;
|
||||
RefPtr<nsImapMailCopyState> m_copyState;
|
||||
char m_hierarchyDelimiter;
|
||||
int32_t m_boxFlags;
|
||||
nsCString m_onlineFolderName;
|
||||
nsCString m_ownerUserName; // username of the "other user," as in
|
||||
// "Other Users' Mailboxes"
|
||||
|
||||
nsCString m_adminUrl; // url to run to set admin privileges for this folder
|
||||
nsIMAPNamespace *m_namespace;
|
||||
bool m_verifiedAsOnlineFolder;
|
||||
bool m_explicitlyVerify; // whether or not we need to explicitly verify this through LIST
|
||||
bool m_folderIsNamespace;
|
||||
bool m_folderNeedsSubscribing;
|
||||
bool m_folderNeedsAdded;
|
||||
bool m_folderNeedsACLListed;
|
||||
bool m_performingBiff;
|
||||
bool m_folderQuotaCommandIssued;
|
||||
bool m_folderQuotaDataIsValid;
|
||||
bool m_updatingFolder;
|
||||
// These two vars are used to keep track of compaction state so we can know
|
||||
// when to send a done notification.
|
||||
bool m_compactingOfflineStore;
|
||||
bool m_expunging;
|
||||
bool m_applyIncomingFilters; // apply filters to this folder, even if not the inbox
|
||||
nsMsgIMAPFolderACL *m_folderACL;
|
||||
uint32_t m_aclFlags;
|
||||
uint32_t m_supportedUserFlags;
|
||||
|
||||
// determines if we are on GMail server
|
||||
bool m_isGmailServer;
|
||||
// offline imap support
|
||||
bool m_downloadingFolderForOfflineUse;
|
||||
bool m_filterListRequiresBody;
|
||||
|
||||
// auto-sync (automatic message download) support
|
||||
RefPtr<nsAutoSyncState> m_autoSyncStateObj;
|
||||
|
||||
// Quota support
|
||||
nsCString m_folderQuotaRoot;
|
||||
uint32_t m_folderQuotaUsedKB;
|
||||
uint32_t m_folderQuotaMaxKB;
|
||||
|
||||
// Pseudo-Offline Playback support
|
||||
nsPlaybackRequest *m_pendingPlaybackReq;
|
||||
nsCOMPtr<nsITimer> m_playbackTimer;
|
||||
nsTArray<RefPtr<nsImapMoveCopyMsgTxn> > m_pendingOfflineMoves;
|
||||
// hash table of mapping between messageids and message keys
|
||||
// for pseudo hdrs.
|
||||
nsDataHashtable<nsCStringHashKey, nsMsgKey> m_pseudoHdrs;
|
||||
|
||||
nsTArray<nsMsgKey> m_keysToFetch;
|
||||
uint32_t m_totalKeysToFetch;
|
||||
|
||||
/**
|
||||
* delete if appropriate local storage for messages in this folder
|
||||
*
|
||||
* @parm aMessages array (of nsIMsgDBHdr) of messages to delete
|
||||
* (or an array of message keys)
|
||||
* @parm aSrcFolder the folder containing the messages (optional)
|
||||
*/
|
||||
void DeleteStoreMessages(nsIArray* aMessages);
|
||||
void DeleteStoreMessages(nsTArray<nsMsgKey> &aMessages);
|
||||
static void DeleteStoreMessages(nsTArray<nsMsgKey> &aMessages, nsIMsgFolder* aFolder);
|
||||
};
|
||||
#endif
|
||||
1292
mailnews/imap/src/nsImapOfflineSync.cpp
Normal file
1292
mailnews/imap/src/nsImapOfflineSync.cpp
Normal file
File diff suppressed because it is too large
Load diff
92
mailnews/imap/src/nsImapOfflineSync.h
Normal file
92
mailnews/imap/src/nsImapOfflineSync.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/* -*- 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 _nsImapOfflineSync_H_
|
||||
#define _nsImapOfflineSync_H_
|
||||
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIMsgDatabase.h"
|
||||
#include "nsIUrlListener.h"
|
||||
#include "nsIMsgOfflineImapOperation.h"
|
||||
#include "nsIMsgWindow.h"
|
||||
#include "nsIMsgFolder.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIDBChangeListener.h"
|
||||
|
||||
class nsImapOfflineSync : public nsIUrlListener,
|
||||
public nsIMsgCopyServiceListener,
|
||||
public nsIDBChangeListener {
|
||||
public: // set to one folder to playback one folder only
|
||||
nsImapOfflineSync(nsIMsgWindow *window, nsIUrlListener *listener,
|
||||
nsIMsgFolder *singleFolderOnly = nullptr,
|
||||
bool isPseudoOffline = false);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIURLLISTENER
|
||||
NS_DECL_NSIMSGCOPYSERVICELISTENER
|
||||
NS_DECL_NSIDBCHANGELISTENER
|
||||
virtual nsresult ProcessNextOperation(); // this kicks off playback
|
||||
|
||||
int32_t GetCurrentUIDValidity();
|
||||
void SetCurrentUIDValidity(int32_t uidvalidity) { mCurrentUIDValidity = uidvalidity; }
|
||||
|
||||
void SetPseudoOffline(bool pseudoOffline) {m_pseudoOffline = pseudoOffline;}
|
||||
bool ProcessingStaleFolderUpdate() { return m_singleFolderToUpdate != nullptr; }
|
||||
|
||||
bool CreateOfflineFolder(nsIMsgFolder *folder);
|
||||
void SetWindow(nsIMsgWindow *window);
|
||||
protected:
|
||||
virtual ~nsImapOfflineSync();
|
||||
|
||||
bool CreateOfflineFolders();
|
||||
bool DestFolderOnSameServer(nsIMsgFolder *destFolder);
|
||||
bool AdvanceToNextServer();
|
||||
bool AdvanceToNextFolder();
|
||||
void AdvanceToFirstIMAPFolder();
|
||||
void DeleteAllOfflineOpsForCurrentDB();
|
||||
void ClearCurrentOps();
|
||||
// Clears m_currentDB, and unregister listener.
|
||||
void ClearDB();
|
||||
void ProcessFlagOperation(nsIMsgOfflineImapOperation *currentOp);
|
||||
void ProcessKeywordOperation(nsIMsgOfflineImapOperation *op);
|
||||
void ProcessMoveOperation(nsIMsgOfflineImapOperation *currentOp);
|
||||
void ProcessCopyOperation(nsIMsgOfflineImapOperation *currentOp);
|
||||
void ProcessEmptyTrash();
|
||||
void ProcessAppendMsgOperation(nsIMsgOfflineImapOperation *currentOp,
|
||||
nsOfflineImapOperationType opType);
|
||||
|
||||
nsCOMPtr <nsIMsgFolder> m_currentFolder;
|
||||
nsCOMPtr <nsIMsgFolder> m_singleFolderToUpdate;
|
||||
nsCOMPtr <nsIMsgWindow> m_window;
|
||||
nsCOMPtr <nsIArray> m_allServers;
|
||||
nsCOMPtr <nsIArray> m_allFolders;
|
||||
nsCOMPtr <nsIMsgIncomingServer> m_currentServer;
|
||||
nsCOMPtr <nsISimpleEnumerator> m_serverEnumerator;
|
||||
nsCOMPtr <nsIFile> m_curTempFile;
|
||||
|
||||
nsTArray<nsMsgKey> m_CurrentKeys;
|
||||
nsCOMArray<nsIMsgOfflineImapOperation> m_currentOpsToClear;
|
||||
uint32_t m_KeyIndex;
|
||||
nsCOMPtr <nsIMsgDatabase> m_currentDB;
|
||||
nsCOMPtr <nsIUrlListener> m_listener;
|
||||
int32_t mCurrentUIDValidity;
|
||||
int32_t mCurrentPlaybackOpType; // kFlagsChanged -> kMsgCopy -> kMsgMoved
|
||||
bool m_mailboxupdatesStarted;
|
||||
bool m_mailboxupdatesFinished;
|
||||
bool m_pseudoOffline; // for queueing online events in offline db
|
||||
bool m_createdOfflineFolders;
|
||||
|
||||
};
|
||||
|
||||
class nsImapOfflineDownloader : public nsImapOfflineSync
|
||||
{
|
||||
public:
|
||||
nsImapOfflineDownloader(nsIMsgWindow *window, nsIUrlListener *listener);
|
||||
virtual ~nsImapOfflineDownloader();
|
||||
virtual nsresult ProcessNextOperation() override; // this kicks off download
|
||||
};
|
||||
|
||||
#endif
|
||||
10046
mailnews/imap/src/nsImapProtocol.cpp
Normal file
10046
mailnews/imap/src/nsImapProtocol.cpp
Normal file
File diff suppressed because it is too large
Load diff
764
mailnews/imap/src/nsImapProtocol.h
Normal file
764
mailnews/imap/src/nsImapProtocol.h
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
/* -*- 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 nsImapProtocol_h___
|
||||
#define nsImapProtocol_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIImapProtocol.h"
|
||||
#include "nsIImapUrl.h"
|
||||
|
||||
#include "nsMsgProtocol.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsImapCore.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsIInputStreamPump.h"
|
||||
|
||||
// imap event sinks
|
||||
#include "nsIImapMailFolderSink.h"
|
||||
#include "nsIImapServerSink.h"
|
||||
#include "nsIImapMessageSink.h"
|
||||
|
||||
// UI Thread proxy helper
|
||||
#include "nsIImapProtocolSink.h"
|
||||
|
||||
#include "nsImapServerResponseParser.h"
|
||||
#include "nsImapFlagAndUidState.h"
|
||||
#include "nsIMAPNamespace.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#include "nsMsgLineBuffer.h" // we need this to use the nsMsgLineStreamBuffer helper class...
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIMsgIncomingServer.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIImapMockChannel.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIImapIncomingServer.h"
|
||||
#include "nsIMsgWindow.h"
|
||||
#include "nsIImapHeaderXferInfo.h"
|
||||
#include "nsMsgLineBuffer.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIMsgFolder.h"
|
||||
#include "nsIMsgAsyncPrompter.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsSyncRunnableHelpers.h"
|
||||
#include "nsICacheEntryOpenCallback.h"
|
||||
|
||||
class nsIMAPMessagePartIDArray;
|
||||
class nsIMsgIncomingServer;
|
||||
class nsIPrefBranch;
|
||||
class nsIMAPMailboxInfo;
|
||||
|
||||
#define kDownLoadCacheSize 16000 // was 1536 - try making it bigger
|
||||
|
||||
|
||||
typedef struct _msg_line_info {
|
||||
const char *adoptedMessageLine;
|
||||
uint32_t uidOfMessage;
|
||||
} msg_line_info;
|
||||
|
||||
|
||||
class nsMsgImapLineDownloadCache : public nsIImapHeaderInfo, public nsByteArray
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIMAPHEADERINFO
|
||||
nsMsgImapLineDownloadCache();
|
||||
uint32_t CurrentUID();
|
||||
uint32_t SpaceAvailable();
|
||||
bool CacheEmpty();
|
||||
|
||||
msg_line_info *GetCurrentLineInfo();
|
||||
|
||||
private:
|
||||
virtual ~nsMsgImapLineDownloadCache();
|
||||
|
||||
msg_line_info *fLineInfo;
|
||||
int32_t m_msgSize;
|
||||
};
|
||||
|
||||
#define kNumHdrsToXfer 10
|
||||
|
||||
class nsMsgImapHdrXferInfo : public nsIImapHeaderXferInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIMAPHEADERXFERINFO
|
||||
nsMsgImapHdrXferInfo();
|
||||
void ResetAll(); // reset HeaderInfos for re-use
|
||||
void ReleaseAll(); // release HeaderInfos (frees up memory)
|
||||
// this will return null if we're full, in which case the client code
|
||||
// should transfer the headers and retry.
|
||||
nsIImapHeaderInfo *StartNewHdr();
|
||||
// call when we've finished adding lines to current hdr
|
||||
void FinishCurrentHdr();
|
||||
private:
|
||||
virtual ~nsMsgImapHdrXferInfo();
|
||||
nsCOMArray<nsIImapHeaderInfo> m_hdrInfos;
|
||||
int32_t m_nextFreeHdrInfo;
|
||||
};
|
||||
|
||||
// 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)
|
||||
// Use these flags in conjunction with SetFlag/TestFlag/ClearFlag instead
|
||||
// of creating PRBools for everything....
|
||||
|
||||
#define IMAP_RECEIVED_GREETING 0x00000001 /* should we pause for the next read */
|
||||
#define IMAP_CONNECTION_IS_OPEN 0x00000004 /* is the connection currently open? */
|
||||
#define IMAP_WAITING_FOR_DATA 0x00000008
|
||||
#define IMAP_CLEAN_UP_URL_STATE 0x00000010 // processing clean up url state
|
||||
#define IMAP_ISSUED_LANGUAGE_REQUEST 0x00000020 // make sure we only issue the language request once per connection...
|
||||
#define IMAP_ISSUED_COMPRESS_REQUEST 0x00000040 // make sure we only request compression once
|
||||
|
||||
class nsImapProtocol : public nsIImapProtocol,
|
||||
public nsIRunnable,
|
||||
public nsIInputStreamCallback,
|
||||
public nsSupportsWeakReference,
|
||||
public nsMsgProtocol,
|
||||
public nsIImapProtocolSink,
|
||||
public nsIMsgAsyncPromptListener
|
||||
{
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||
nsImapProtocol();
|
||||
|
||||
virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream,
|
||||
uint64_t sourceOffset, uint32_t length) override;
|
||||
|
||||
// nsIRunnable method
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// we support the nsIImapProtocol interface
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
NS_DECL_NSIIMAPPROTOCOL
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// we support the nsIImapProtocolSink interface
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
NS_DECL_NSIIMAPPROTOCOLSINK
|
||||
|
||||
NS_DECL_NSIMSGASYNCPROMPTLISTENER
|
||||
|
||||
// message id string utilities.
|
||||
uint32_t CountMessagesInIdString(const char *idString);
|
||||
static bool HandlingMultipleMessages(const nsCString &messageIdString);
|
||||
// escape slashes and double quotes in username/passwords for insecure login.
|
||||
static void EscapeUserNamePasswordString(const char *strToEscape, nsCString *resultStr);
|
||||
|
||||
// used to start fetching a message.
|
||||
void GetShouldDownloadAllHeaders(bool *aResult);
|
||||
void GetArbitraryHeadersToDownload(nsCString &aResult);
|
||||
virtual void AdjustChunkSize();
|
||||
virtual void FetchMessage(const nsCString &messageIds,
|
||||
nsIMAPeFetchFields whatToFetch,
|
||||
const char *fetchModifier = nullptr,
|
||||
uint32_t startByte = 0, uint32_t numBytes = 0,
|
||||
char *part = 0);
|
||||
void FetchTryChunking(const nsCString &messageIds,
|
||||
nsIMAPeFetchFields whatToFetch,
|
||||
bool idIsUid,
|
||||
char *part,
|
||||
uint32_t downloadSize,
|
||||
bool tryChunking);
|
||||
virtual void PipelinedFetchMessageParts(nsCString &uid, nsIMAPMessagePartIDArray *parts);
|
||||
void FallbackToFetchWholeMsg(const nsCString &messageId, uint32_t messageSize);
|
||||
// used when streaming a message fetch
|
||||
virtual nsresult BeginMessageDownLoad(uint32_t totalSize, // for user, headers and body
|
||||
const char *contentType); // some downloads are header only
|
||||
virtual void HandleMessageDownLoadLine(const char *line, bool isPartialLine, char *lineCopy=nullptr);
|
||||
virtual void NormalMessageEndDownload();
|
||||
virtual void AbortMessageDownLoad();
|
||||
virtual void PostLineDownLoadEvent(const char *line, uint32_t uid);
|
||||
void FlushDownloadCache();
|
||||
|
||||
virtual void SetMailboxDiscoveryStatus(EMailboxDiscoverStatus status);
|
||||
virtual EMailboxDiscoverStatus GetMailboxDiscoveryStatus();
|
||||
|
||||
virtual void ProcessMailboxUpdate(bool handlePossibleUndo);
|
||||
// Send log output...
|
||||
void Log(const char *logSubName, const char *extraInfo, const char *logData);
|
||||
static void LogImapUrl(const char *logMsg, nsIImapUrl *imapUrl);
|
||||
// Comment from 4.5: We really need to break out the thread synchronizer from the
|
||||
// connection class...Not sure what this means
|
||||
bool GetPseudoInterrupted();
|
||||
void PseudoInterrupt(bool the_interrupt);
|
||||
|
||||
uint32_t GetMessageSize(const char * messageId, bool idsAreUids);
|
||||
bool GetSubscribingNow();
|
||||
|
||||
bool DeathSignalReceived();
|
||||
void ResetProgressInfo();
|
||||
void SetActive(bool active);
|
||||
bool GetActive();
|
||||
|
||||
bool GetShowAttachmentsInline();
|
||||
|
||||
// Sets whether or not the content referenced by the current ActiveEntry has been modified.
|
||||
// Used for MIME parts on demand.
|
||||
void SetContentModified(IMAP_ContentModifiedType modified);
|
||||
bool GetShouldFetchAllParts();
|
||||
bool GetIgnoreExpunges() {return m_ignoreExpunges;}
|
||||
// Generic accessors required by the imap parser
|
||||
char * CreateNewLineFromSocket();
|
||||
nsresult GetConnectionStatus();
|
||||
void SetConnectionStatus(nsresult status);
|
||||
|
||||
// Cleanup the connection and shutdown the thread.
|
||||
void TellThreadToDie();
|
||||
|
||||
const nsCString& GetImapHostName(); // return the host name from the url for the
|
||||
// current connection
|
||||
const nsCString& GetImapUserName(); // return the user name from the identity
|
||||
const char* GetImapServerKey(); // return the user name from the incoming server;
|
||||
|
||||
// state set by the imap parser...
|
||||
void NotifyMessageFlags(imapMessageFlagsType flags, const nsACString &keywords,
|
||||
nsMsgKey key, uint64_t highestModSeq);
|
||||
void NotifySearchHit(const char * hitLine);
|
||||
|
||||
// Event handlers for the imap parser.
|
||||
void DiscoverMailboxSpec(nsImapMailboxSpec * adoptedBoxSpec);
|
||||
void AlertUserEventUsingName(const char* aMessageId);
|
||||
void AlertUserEvent(const char * message);
|
||||
void AlertUserEventFromServer(const char * aServerEvent);
|
||||
|
||||
void ProgressEventFunctionUsingName(const char* aMsgId);
|
||||
void ProgressEventFunctionUsingNameWithString(const char* aMsgName, const char *
|
||||
aExtraInfo);
|
||||
void PercentProgressUpdateEvent(char16_t *message, int64_t currentProgress, int64_t maxProgress);
|
||||
void ShowProgress();
|
||||
|
||||
// utility function calls made by the server
|
||||
|
||||
void Copy(const char * messageList, const char *destinationMailbox,
|
||||
bool idsAreUid);
|
||||
void Search(const char * searchCriteria, bool useUID,
|
||||
bool notifyHit = true);
|
||||
// imap commands issued by the parser
|
||||
void Store(const nsCString &aMessageList, const char * aMessageData, bool
|
||||
aIdsAreUid);
|
||||
void ProcessStoreFlags(const nsCString &messageIds,
|
||||
bool idsAreUids,
|
||||
imapMessageFlagsType flags,
|
||||
bool addFlags);
|
||||
void IssueUserDefinedMsgCommand(const char *command, const char * messageList);
|
||||
void FetchMsgAttribute(const nsCString &messageIds, const nsCString &attribute);
|
||||
void Expunge();
|
||||
void UidExpunge(const nsCString &messageSet);
|
||||
void Close(bool shuttingDown = false, bool waitForResponse = true);
|
||||
void Check();
|
||||
void SelectMailbox(const char *mailboxName);
|
||||
// more imap commands
|
||||
void Logout(bool shuttingDown = false, bool waitForResponse = true);
|
||||
void Noop();
|
||||
void XServerInfo();
|
||||
void Netscape();
|
||||
void XMailboxInfo(const char *mailboxName);
|
||||
void XAOL_Option(const char *option);
|
||||
void MailboxData();
|
||||
void GetMyRightsForFolder(const char *mailboxName);
|
||||
void Bodystructure(const nsCString &messageId, bool idIsUid);
|
||||
void PipelinedFetchMessageParts(const char *uid, nsIMAPMessagePartIDArray *parts);
|
||||
|
||||
|
||||
// this function does not ref count!!! be careful!!!
|
||||
nsIImapUrl *GetCurrentUrl() {return m_runningUrl;}
|
||||
|
||||
// acl and namespace stuff
|
||||
// notifies libmsg that we have a new personal/default namespace that we're using
|
||||
void CommitNamespacesForHostEvent();
|
||||
// notifies libmsg that we have new capability data for the current host
|
||||
void CommitCapability();
|
||||
|
||||
// Adds a set of rights for a given user on a given mailbox on the current host.
|
||||
// if userName is NULL, it means "me," or MYRIGHTS.
|
||||
// rights is a single string of rights, as specified by RFC2086, the IMAP ACL extension.
|
||||
void AddFolderRightsForUser(const char *mailboxName, const char *userName, const char *rights);
|
||||
// Clears all rights for the current folder, for all users.
|
||||
void ClearAllFolderRights();
|
||||
void RefreshFolderACLView(const char *mailboxName, nsIMAPNamespace *nsForMailbox);
|
||||
|
||||
nsresult SetFolderAdminUrl(const char *mailboxName);
|
||||
void HandleMemoryFailure();
|
||||
void HandleCurrentUrlError();
|
||||
|
||||
// UIDPLUS extension
|
||||
void SetCopyResponseUid(const char* msgIdString);
|
||||
|
||||
// Quota support
|
||||
void UpdateFolderQuotaData(nsCString& aQuotaRoot, uint32_t aUsed, uint32_t aMax);
|
||||
|
||||
bool GetPreferPlainText() { return m_preferPlainText; }
|
||||
|
||||
int32_t GetCurFetchSize() { return m_curFetchSize; }
|
||||
|
||||
const nsString &GetEmptyMimePartString() { return m_emptyMimePartString; }
|
||||
private:
|
||||
virtual ~nsImapProtocol();
|
||||
// the following flag is used to determine when a url is currently being run. It is cleared when we
|
||||
// finish processng a url and it is set whenever we call Load on a url
|
||||
bool m_urlInProgress;
|
||||
nsCOMPtr<nsIImapUrl> m_runningUrl; // the nsIImapURL that is currently running
|
||||
nsImapAction m_imapAction; // current imap action associated with this connnection...
|
||||
|
||||
nsCString m_hostName;
|
||||
nsCString m_userName;
|
||||
nsCString m_serverKey;
|
||||
nsCString m_realHostName;
|
||||
char *m_dataOutputBuf;
|
||||
nsMsgLineStreamBuffer * m_inputStreamBuffer;
|
||||
uint32_t m_allocatedSize; // allocated size
|
||||
uint32_t m_totalDataSize; // total data size
|
||||
uint32_t m_curReadIndex; // current read index
|
||||
nsCString m_trashFolderName;
|
||||
|
||||
// Ouput stream for writing commands to the socket
|
||||
nsCOMPtr<nsISocketTransport> m_transport;
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> m_channelInputStream;
|
||||
nsCOMPtr<nsIAsyncOutputStream> m_channelOutputStream;
|
||||
nsCOMPtr<nsIImapMockChannel> m_mockChannel; // this is the channel we should forward to people
|
||||
uint32_t m_bytesToChannel;
|
||||
bool m_fetchingWholeMessage;
|
||||
//nsCOMPtr<nsIRequest> mAsyncReadRequest; // we're going to cancel this when we're done with the conn.
|
||||
|
||||
|
||||
// ******* Thread support *******
|
||||
nsCOMPtr<nsIThread> m_iThread;
|
||||
PRThread *m_thread;
|
||||
mozilla::ReentrantMonitor m_dataAvailableMonitor; // used to notify the arrival of data from the server
|
||||
mozilla::ReentrantMonitor m_urlReadyToRunMonitor; // used to notify the arrival of a new url to be processed
|
||||
mozilla::ReentrantMonitor m_pseudoInterruptMonitor;
|
||||
mozilla::ReentrantMonitor m_dataMemberMonitor;
|
||||
mozilla::ReentrantMonitor m_threadDeathMonitor;
|
||||
mozilla::ReentrantMonitor m_waitForBodyIdsMonitor;
|
||||
mozilla::ReentrantMonitor m_fetchBodyListMonitor;
|
||||
mozilla::ReentrantMonitor m_passwordReadyMonitor;
|
||||
mozilla::Mutex mLock;
|
||||
// If we get an async password prompt, this is where the UI thread
|
||||
// stores the password, before notifying the imap thread of the password
|
||||
// via the m_passwordReadyMonitor.
|
||||
nsCString m_password;
|
||||
// Set to the result of nsImapServer::PromptPassword
|
||||
nsresult m_passwordStatus;
|
||||
|
||||
bool m_imapThreadIsRunning;
|
||||
void ImapThreadMainLoop(void);
|
||||
nsresult m_connectionStatus;
|
||||
nsCString m_connectionType;
|
||||
|
||||
bool m_nextUrlReadyToRun;
|
||||
nsWeakPtr m_server;
|
||||
|
||||
RefPtr<ImapMailFolderSinkProxy> m_imapMailFolderSink;
|
||||
RefPtr<ImapMessageSinkProxy> m_imapMessageSink;
|
||||
RefPtr<ImapServerSinkProxy> m_imapServerSink;
|
||||
RefPtr<ImapProtocolSinkProxy> m_imapProtocolSink;
|
||||
|
||||
// helper function to setup imap sink interface proxies
|
||||
nsresult SetupSinkProxy();
|
||||
// End thread support stuff
|
||||
|
||||
bool GetDeleteIsMoveToTrash();
|
||||
bool GetShowDeletedMessages();
|
||||
nsCString m_currentCommand;
|
||||
nsImapServerResponseParser m_parser;
|
||||
nsImapServerResponseParser& GetServerStateParser() { return m_parser; }
|
||||
|
||||
void HandleIdleResponses();
|
||||
virtual bool ProcessCurrentURL();
|
||||
void EstablishServerConnection();
|
||||
virtual void ParseIMAPandCheckForNewMail(const char* commandString =
|
||||
nullptr, bool ignoreBadNOResponses = false);
|
||||
// biff
|
||||
void PeriodicBiff();
|
||||
void SendSetBiffIndicatorEvent(nsMsgBiffState newState);
|
||||
bool CheckNewMail();
|
||||
|
||||
// folder opening and listing header functions
|
||||
void FolderHeaderDump(uint32_t *msgUids, uint32_t msgCount);
|
||||
void FolderMsgDump(uint32_t *msgUids, uint32_t msgCount, nsIMAPeFetchFields fields);
|
||||
void FolderMsgDumpLoop(uint32_t *msgUids, uint32_t msgCount, nsIMAPeFetchFields fields);
|
||||
void WaitForPotentialListOfBodysToFetch(uint32_t **msgIdList, uint32_t &msgCount);
|
||||
void HeaderFetchCompleted();
|
||||
void UploadMessageFromFile(nsIFile* file, const char* mailboxName, PRTime date,
|
||||
imapMessageFlagsType flags, nsCString &keywords);
|
||||
|
||||
// mailbox name utilities.
|
||||
void CreateEscapedMailboxName(const char *rawName, nsCString &escapedName);
|
||||
void SetupMessageFlagsString(nsCString & flagString,
|
||||
imapMessageFlagsType flags,
|
||||
uint16_t userFlags);
|
||||
|
||||
// body fetching listing data
|
||||
bool m_fetchBodyListIsNew;
|
||||
uint32_t m_fetchBodyCount;
|
||||
uint32_t *m_fetchBodyIdList;
|
||||
|
||||
// initialization function given a new url and transport layer
|
||||
nsresult SetupWithUrl(nsIURI * aURL, nsISupports* aConsumer);
|
||||
void ReleaseUrlState(bool rerunningUrl); // release any state that is stored on a per action basis.
|
||||
/**
|
||||
* Last ditch effort to run the url without using an imap connection.
|
||||
* If it turns out that we don't need to run the url at all (e.g., we're
|
||||
* trying to download a single message for offline use and it has already
|
||||
* been downloaded, this function will send the appropriate notifications.
|
||||
*
|
||||
* @returns true if the url has been run locally, or doesn't need to be run.
|
||||
*/
|
||||
bool TryToRunUrlLocally(nsIURI *aURL, nsISupports *aConsumer);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Communication methods --> Reading and writing protocol
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SendData not only writes the NULL terminated data in dataBuffer to our output stream
|
||||
// but it also informs the consumer that the data has been written to the stream.
|
||||
// aSuppressLogging --> set to true if you wish to suppress logging for this particular command.
|
||||
// this is useful for making sure we don't log authenication information like the user's password (which was
|
||||
// encoded anyway), but still we shouldn't add that information to the log.
|
||||
nsresult SendData(const char * dataBuffer, bool aSuppressLogging = false) override;
|
||||
|
||||
// state ported over from 4.5
|
||||
bool m_pseudoInterrupted;
|
||||
bool m_active;
|
||||
bool m_folderNeedsSubscribing;
|
||||
bool m_folderNeedsACLRefreshed;
|
||||
|
||||
bool m_threadShouldDie;
|
||||
|
||||
// use to prevent re-entering TellThreadToDie.
|
||||
bool m_inThreadShouldDie;
|
||||
// if the UI thread has signalled the IMAP thread to die, and the
|
||||
// connection has timed out, this will be set to FALSE.
|
||||
bool m_safeToCloseConnection;
|
||||
|
||||
nsImapFlagAndUidState *m_flagState;
|
||||
nsMsgBiffState m_currentBiffState;
|
||||
// manage the IMAP server command tags
|
||||
// 11 = enough memory for the decimal representation of MAX_UINT + trailing nul
|
||||
char m_currentServerCommandTag[11];
|
||||
uint32_t m_currentServerCommandTagNumber;
|
||||
void IncrementCommandTagNumber();
|
||||
const char *GetServerCommandTag();
|
||||
|
||||
void StartTLS();
|
||||
|
||||
// login related methods.
|
||||
nsresult GetPassword(nsCString &password, bool aNewPasswordRequested);
|
||||
void InitPrefAuthMethods(int32_t authMethodPrefValue,
|
||||
nsIMsgIncomingServer *aServer);
|
||||
nsresult ChooseAuthMethod();
|
||||
void MarkAuthMethodAsFailed(eIMAPCapabilityFlags failedAuthMethod);
|
||||
void ResetAuthMethods();
|
||||
|
||||
// All of these methods actually issue protocol
|
||||
void Capability(); // query host for capabilities.
|
||||
void ID(); // send RFC 2971 app info to server
|
||||
void EnableCondStore();
|
||||
void StartCompressDeflate();
|
||||
nsresult BeginCompressing();
|
||||
void Language(); // set the language on the server if it supports it
|
||||
void Namespace();
|
||||
void InsecureLogin(const char *userName, const nsCString &password);
|
||||
nsresult AuthLogin(const char *userName, const nsCString &password, eIMAPCapabilityFlag flag);
|
||||
void ProcessAuthenticatedStateURL();
|
||||
void ProcessAfterAuthenticated();
|
||||
void ProcessSelectedStateURL();
|
||||
bool TryToLogon();
|
||||
|
||||
// Process Authenticated State Url used to be one giant if statement. I've broken out a set of actions
|
||||
// based on the imap action passed into the url. The following functions are imap protocol handlers for
|
||||
// each action. They are called by ProcessAuthenticatedStateUrl.
|
||||
void OnLSubFolders();
|
||||
void OnAppendMsgFromFile();
|
||||
|
||||
char *GetFolderPathString(); // OK to call from UI thread
|
||||
|
||||
char * OnCreateServerSourceFolderPathString();
|
||||
char * OnCreateServerDestinationFolderPathString();
|
||||
nsresult CreateServerSourceFolderPathString(char **result);
|
||||
void OnCreateFolder(const char * aSourceMailbox);
|
||||
void OnEnsureExistsFolder(const char * aSourceMailbox);
|
||||
void OnSubscribe(const char * aSourceMailbox);
|
||||
void OnUnsubscribe(const char * aSourceMailbox);
|
||||
void RefreshACLForFolderIfNecessary(const char * mailboxName);
|
||||
void RefreshACLForFolder(const char * aSourceMailbox);
|
||||
void GetACLForFolder(const char *aMailboxName);
|
||||
void OnRefreshAllACLs();
|
||||
void OnListFolder(const char * aSourceMailbox, bool aBool);
|
||||
void OnStatusForFolder(const char * sourceMailbox);
|
||||
void OnDeleteFolder(const char * aSourceMailbox);
|
||||
void OnRenameFolder(const char * aSourceMailbox);
|
||||
void OnMoveFolderHierarchy(const char * aSourceMailbox);
|
||||
void DeleteFolderAndMsgs(const char * aSourceMailbox);
|
||||
void RemoveMsgsAndExpunge();
|
||||
void FindMailboxesIfNecessary();
|
||||
void CreateMailbox(const char *mailboxName);
|
||||
void DeleteMailbox(const char *mailboxName);
|
||||
void RenameMailbox(const char *existingName, const char *newName);
|
||||
void RemoveHierarchyDelimiter(nsCString &mailboxName);
|
||||
bool CreateMailboxRespectingSubscriptions(const char *mailboxName);
|
||||
bool DeleteMailboxRespectingSubscriptions(const char *mailboxName);
|
||||
bool RenameMailboxRespectingSubscriptions(const char *existingName,
|
||||
const char *newName,
|
||||
bool reallyRename);
|
||||
// notify the fe that a folder was deleted
|
||||
void FolderDeleted(const char *mailboxName);
|
||||
// notify the fe that a folder creation failed
|
||||
void FolderNotCreated(const char *mailboxName);
|
||||
// notify the fe that a folder was deleted
|
||||
void FolderRenamed(const char *oldName,
|
||||
const char *newName);
|
||||
|
||||
bool FolderIsSelected(const char *mailboxName);
|
||||
|
||||
bool MailboxIsNoSelectMailbox(const char *mailboxName);
|
||||
nsCString CreatePossibleTrashName(const char *prefix);
|
||||
bool FolderNeedsACLInitialized(const char *folderName);
|
||||
void DiscoverMailboxList();
|
||||
void DiscoverAllAndSubscribedBoxes();
|
||||
void MailboxDiscoveryFinished();
|
||||
void NthLevelChildList(const char *onlineMailboxPrefix, int32_t depth);
|
||||
// LIST SUBSCRIBED command (from RFC 5258) crashes some servers. so we need to
|
||||
// identify those servers
|
||||
bool GetListSubscribedIsBrokenOnServer();
|
||||
bool IsExtraSelectNeeded();
|
||||
void Lsub(const char *mailboxPattern, bool addDirectoryIfNecessary);
|
||||
void List(const char *mailboxPattern, bool addDirectoryIfNecessary,
|
||||
bool useXLIST = false);
|
||||
void Subscribe(const char *mailboxName);
|
||||
void Unsubscribe(const char *mailboxName);
|
||||
void Idle();
|
||||
void EndIdle(bool waitForResponse = true);
|
||||
// Some imap servers include the mailboxName following the dir-separator in the list of
|
||||
// subfolders of the mailboxName. In fact, they are the same. So we should decide if
|
||||
// we should delete such subfolder and provide feedback if the delete operation succeed.
|
||||
bool DeleteSubFolders(const char* aMailboxName, bool & aDeleteSelf);
|
||||
bool RenameHierarchyByHand(const char *oldParentMailboxName,
|
||||
const char *newParentMailboxName);
|
||||
bool RetryUrl();
|
||||
|
||||
nsresult GlobalInitialization(nsIPrefBranch *aPrefBranch);
|
||||
nsresult Configure(int32_t TooFastTime, int32_t IdealTime,
|
||||
int32_t ChunkAddSize, int32_t ChunkSize, int32_t ChunkThreshold,
|
||||
bool FetchByChunks);
|
||||
nsresult GetMsgWindow(nsIMsgWindow ** aMsgWindow);
|
||||
// End Process AuthenticatedState Url helper methods
|
||||
|
||||
virtual char const *GetType() override {return "imap";}
|
||||
|
||||
// Quota support
|
||||
void GetQuotaDataIfSupported(const char *aBoxName);
|
||||
|
||||
// CondStore support - true if server supports it, and the user hasn't disabled it.
|
||||
bool UseCondStore();
|
||||
// false if pref "mail.server.serverxxx.use_condstore" is false;
|
||||
bool m_useCondStore;
|
||||
// COMPRESS=DEFLATE support - true if server supports it, and the user hasn't disabled it.
|
||||
bool UseCompressDeflate();
|
||||
// false if pref "mail.server.serverxxx.use_compress_deflate" is false;
|
||||
bool m_useCompressDeflate;
|
||||
// these come from the nsIDBFolderInfo in the msgDatabase and
|
||||
// are initialized in nsImapProtocol::SetupWithUrl.
|
||||
uint64_t mFolderLastModSeq;
|
||||
int32_t mFolderTotalMsgCount;
|
||||
uint32_t mFolderHighestUID;
|
||||
uint32_t mFolderNumDeleted;
|
||||
|
||||
bool m_isGmailServer;
|
||||
nsTArray<nsCString> mCustomDBHeaders;
|
||||
nsTArray<nsCString> mCustomHeaders;
|
||||
bool m_trackingTime;
|
||||
PRTime m_startTime;
|
||||
PRTime m_endTime;
|
||||
PRTime m_lastActiveTime;
|
||||
int32_t m_tooFastTime;
|
||||
int32_t m_idealTime;
|
||||
int32_t m_chunkAddSize;
|
||||
int32_t m_chunkStartSize;
|
||||
bool m_fetchByChunks;
|
||||
bool m_sendID;
|
||||
int32_t m_curFetchSize;
|
||||
bool m_ignoreExpunges;
|
||||
eIMAPCapabilityFlags m_prefAuthMethods; // set of capability flags (in nsImapCore.h) for auth methods
|
||||
eIMAPCapabilityFlags m_failedAuthMethods; // ditto
|
||||
eIMAPCapabilityFlag m_currentAuthMethod; // exactly one capability flag, or 0
|
||||
int32_t m_socketType;
|
||||
int32_t m_chunkSize;
|
||||
int32_t m_chunkThreshold;
|
||||
RefPtr<nsMsgImapLineDownloadCache> m_downloadLineCache;
|
||||
RefPtr<nsMsgImapHdrXferInfo> m_hdrDownloadCache;
|
||||
nsCOMPtr <nsIImapHeaderInfo> m_curHdrInfo;
|
||||
// mapping between mailboxes and the corresponding folder flags
|
||||
nsDataHashtable<nsCStringHashKey, int32_t> m_standardListMailboxes;
|
||||
// mapping between special xlist mailboxes and the corresponding folder flags
|
||||
nsDataHashtable<nsCStringHashKey, int32_t> m_specialXListMailboxes;
|
||||
|
||||
|
||||
nsIImapHostSessionList * m_hostSessionList;
|
||||
|
||||
bool m_fromHeaderSeen;
|
||||
|
||||
// these settings allow clients to override various pieces of the connection info from the url
|
||||
bool m_overRideUrlConnectionInfo;
|
||||
|
||||
nsCString m_logonHost;
|
||||
nsCString m_logonCookie;
|
||||
int16_t m_logonPort;
|
||||
|
||||
nsString mAcceptLanguages;
|
||||
|
||||
// progress stuff
|
||||
void SetProgressString(const char* stringName);
|
||||
|
||||
nsString m_progressString;
|
||||
nsCString m_progressStringName;
|
||||
int32_t m_progressIndex;
|
||||
int32_t m_progressCount;
|
||||
nsCString m_lastProgressStringName;
|
||||
int32_t m_lastPercent;
|
||||
int64_t m_lastProgressTime;
|
||||
|
||||
bool m_notifySearchHit;
|
||||
bool m_checkForNewMailDownloadsHeaders;
|
||||
bool m_needNoop;
|
||||
bool m_idle;
|
||||
bool m_useIdle;
|
||||
int32_t m_noopCount;
|
||||
bool m_autoSubscribe, m_autoUnsubscribe, m_autoSubscribeOnOpen;
|
||||
bool m_closeNeededBeforeSelect;
|
||||
bool m_retryUrlOnError;
|
||||
bool m_preferPlainText;
|
||||
nsCString m_forceSelectValue;
|
||||
bool m_forceSelect;
|
||||
|
||||
int32_t m_uidValidity; // stored uid validity for the selected folder.
|
||||
|
||||
enum EMailboxHierarchyNameState {
|
||||
kNoOperationInProgress,
|
||||
kDiscoverBaseFolderInProgress,
|
||||
kDiscoverTrashFolderInProgress,
|
||||
kDeleteSubFoldersInProgress,
|
||||
kListingForInfoOnly,
|
||||
kListingForInfoAndDiscovery,
|
||||
kDiscoveringNamespacesOnly,
|
||||
kXListing,
|
||||
kListingForFolderFlags,
|
||||
kListingForCreate
|
||||
};
|
||||
EMailboxHierarchyNameState m_hierarchyNameState;
|
||||
EMailboxDiscoverStatus m_discoveryStatus;
|
||||
nsTArray<nsIMAPMailboxInfo*> m_listedMailboxList;
|
||||
nsTArray<char*> * m_deletableChildren;
|
||||
uint32_t m_flagChangeCount;
|
||||
PRTime m_lastCheckTime;
|
||||
|
||||
bool CheckNeeded();
|
||||
|
||||
nsString m_emptyMimePartString;
|
||||
|
||||
RefPtr<mozilla::mailnews::OAuth2ThreadHelper> mOAuth2Support;
|
||||
};
|
||||
|
||||
// This small class is a "mock" channel because it is a mockery of the imap channel's implementation...
|
||||
// it's a light weight channel that we can return to necko when they ask for a channel on a url before
|
||||
// we actually have an imap protocol instance around which can run the url. Please see my comments in
|
||||
// nsIImapMockChannel.idl for more details..
|
||||
//
|
||||
// Threading concern: This class lives entirely in the UI thread.
|
||||
|
||||
class nsICacheEntry;
|
||||
|
||||
class nsImapMockChannel : public nsIImapMockChannel
|
||||
, public nsICacheEntryOpenCallback
|
||||
, public nsITransportEventSink
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
friend class nsImapProtocol;
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIMAPMOCKCHANNEL
|
||||
NS_DECL_NSICHANNEL
|
||||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSICACHEENTRYOPENCALLBACK
|
||||
NS_DECL_NSITRANSPORTEVENTSINK
|
||||
|
||||
nsImapMockChannel();
|
||||
static nsresult Create (const nsIID& iid, void **result);
|
||||
nsresult RunOnStopRequestFailure();
|
||||
|
||||
protected:
|
||||
virtual ~nsImapMockChannel();
|
||||
nsCOMPtr <nsIURI> m_url;
|
||||
|
||||
nsCOMPtr<nsIURI> m_originalUrl;
|
||||
nsCOMPtr<nsILoadGroup> m_loadGroup;
|
||||
nsCOMPtr<nsILoadInfo> m_loadInfo;
|
||||
nsCOMPtr<nsIStreamListener> m_channelListener;
|
||||
nsISupports * m_channelContext;
|
||||
nsresult m_cancelStatus;
|
||||
nsLoadFlags mLoadFlags;
|
||||
nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
|
||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||
nsCOMPtr<nsIRequest> mCacheRequest; // the request associated with a read from the cache
|
||||
nsCString mContentType;
|
||||
nsCString mCharset;
|
||||
nsWeakPtr mProtocol;
|
||||
|
||||
bool mChannelClosed;
|
||||
bool mReadingFromCache;
|
||||
bool mTryingToReadPart;
|
||||
int64_t mContentLength;
|
||||
|
||||
// cache related helper methods
|
||||
nsresult OpenCacheEntry(); // makes a request to the cache service for a cache entry for a url
|
||||
bool ReadFromLocalCache(); // attempts to read the url out of our local (offline) cache....
|
||||
nsresult ReadFromImapConnection(); // creates a new imap connection to read the url
|
||||
nsresult ReadFromMemCache(nsICacheEntry *entry); // attempts to read the url out of our memory cache
|
||||
nsresult NotifyStartEndReadFromCache(bool start);
|
||||
|
||||
// we end up daisy chaining multiple nsIStreamListeners into the load process.
|
||||
nsresult SetupPartExtractorListener(nsIImapUrl * aUrl, nsIStreamListener * aConsumer);
|
||||
};
|
||||
|
||||
// This class contains the name of a mailbox and whether or not
|
||||
// its children have been listed.
|
||||
class nsIMAPMailboxInfo
|
||||
{
|
||||
public:
|
||||
nsIMAPMailboxInfo(const nsACString &aName, char aDelimiter);
|
||||
virtual ~nsIMAPMailboxInfo();
|
||||
|
||||
void SetChildrenListed(bool childrenListed);
|
||||
bool GetChildrenListed();
|
||||
const nsACString& GetMailboxName();
|
||||
char GetDelimiter();
|
||||
|
||||
protected:
|
||||
nsCString mMailboxName;
|
||||
bool mChildrenListed;
|
||||
char mDelimiter;
|
||||
};
|
||||
|
||||
#endif // nsImapProtocol_h___
|
||||
92
mailnews/imap/src/nsImapSearchResults.cpp
Normal file
92
mailnews/imap/src/nsImapSearchResults.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/* -*- 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" // for pre-compiled headers
|
||||
|
||||
#include "nsImapCore.h"
|
||||
#include "nsImapSearchResults.h"
|
||||
#include "prmem.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
nsImapSearchResultSequence::nsImapSearchResultSequence()
|
||||
{
|
||||
}
|
||||
|
||||
nsImapSearchResultSequence *nsImapSearchResultSequence::CreateSearchResultSequence()
|
||||
{
|
||||
return new nsImapSearchResultSequence;
|
||||
}
|
||||
|
||||
void nsImapSearchResultSequence::Clear(void)
|
||||
{
|
||||
int32_t i = Length();
|
||||
while (0 <= --i)
|
||||
{
|
||||
char* string = ElementAt(i);
|
||||
PR_Free(string);
|
||||
}
|
||||
nsTArray<char*>::Clear();
|
||||
}
|
||||
|
||||
nsImapSearchResultSequence::~nsImapSearchResultSequence()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
void nsImapSearchResultSequence::ResetSequence()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void nsImapSearchResultSequence::AddSearchResultLine(const char *searchLine)
|
||||
{
|
||||
// The first add becomes node 2. Fix this.
|
||||
char *copiedSequence = PL_strdup(searchLine + 9); // 9 == "* SEARCH "
|
||||
|
||||
if (copiedSequence) // if we can't allocate this then the search won't hit
|
||||
AppendElement(copiedSequence);
|
||||
}
|
||||
|
||||
|
||||
nsImapSearchResultIterator::nsImapSearchResultIterator(nsImapSearchResultSequence &sequence) :
|
||||
fSequence(sequence)
|
||||
{
|
||||
ResetIterator();
|
||||
}
|
||||
|
||||
nsImapSearchResultIterator::~nsImapSearchResultIterator()
|
||||
{
|
||||
}
|
||||
|
||||
void nsImapSearchResultIterator::ResetIterator()
|
||||
{
|
||||
fSequenceIndex = 0;
|
||||
fCurrentLine = (char *) fSequence.SafeElementAt(fSequenceIndex);
|
||||
fPositionInCurrentLine = fCurrentLine;
|
||||
}
|
||||
|
||||
int32_t nsImapSearchResultIterator::GetNextMessageNumber()
|
||||
{
|
||||
int32_t returnValue = 0;
|
||||
if (fPositionInCurrentLine)
|
||||
{
|
||||
returnValue = atoi(fPositionInCurrentLine);
|
||||
|
||||
// eat the current number
|
||||
while (isdigit(*++fPositionInCurrentLine))
|
||||
;
|
||||
|
||||
if (*fPositionInCurrentLine == 0xD) // found CR, no more digits on line
|
||||
{
|
||||
fCurrentLine = (char *) fSequence.SafeElementAt(++fSequenceIndex);
|
||||
fPositionInCurrentLine = fCurrentLine;
|
||||
}
|
||||
else // eat the space
|
||||
fPositionInCurrentLine++;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
42
mailnews/imap/src/nsImapSearchResults.h
Normal file
42
mailnews/imap/src/nsImapSearchResults.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- 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 nsImapSearchResults_h___
|
||||
#define nsImapSearchResults_h___
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsImapSearchResultSequence : public nsTArray<char*>
|
||||
{
|
||||
public:
|
||||
virtual ~nsImapSearchResultSequence();
|
||||
static nsImapSearchResultSequence *CreateSearchResultSequence();
|
||||
|
||||
virtual void AddSearchResultLine(const char *searchLine);
|
||||
virtual void ResetSequence();
|
||||
void Clear();
|
||||
|
||||
friend class nsImapSearchResultIterator;
|
||||
private:
|
||||
nsImapSearchResultSequence();
|
||||
};
|
||||
|
||||
class nsImapSearchResultIterator {
|
||||
public:
|
||||
nsImapSearchResultIterator(nsImapSearchResultSequence &sequence);
|
||||
virtual ~nsImapSearchResultIterator();
|
||||
|
||||
void ResetIterator();
|
||||
int32_t GetNextMessageNumber(); // returns 0 at end of list
|
||||
private:
|
||||
nsImapSearchResultSequence &fSequence;
|
||||
int32_t fSequenceIndex;
|
||||
char *fCurrentLine;
|
||||
char *fPositionInCurrentLine;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
3360
mailnews/imap/src/nsImapServerResponseParser.cpp
Normal file
3360
mailnews/imap/src/nsImapServerResponseParser.cpp
Normal file
File diff suppressed because it is too large
Load diff
269
mailnews/imap/src/nsImapServerResponseParser.h
Normal file
269
mailnews/imap/src/nsImapServerResponseParser.h
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
/* -*- 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 _nsIMAPServerResponseParser_H_
|
||||
#define _nsIMAPServerResponseParser_H_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIMAPHostSessionList.h"
|
||||
#include "nsImapSearchResults.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "MailNewsTypes.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsImapUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
class nsIMAPNamespace;
|
||||
class nsIMAPNamespaceList;
|
||||
class nsIMAPBodyShell;
|
||||
class nsIMAPBodypart;
|
||||
class nsImapSearchResultIterator;
|
||||
class nsImapFlagAndUidState;
|
||||
class nsCString;
|
||||
|
||||
#include "nsIMAPGenericParser.h"
|
||||
|
||||
class nsImapServerResponseParser : public nsIMAPGenericParser
|
||||
{
|
||||
public:
|
||||
nsImapServerResponseParser(nsImapProtocol &imapConnection);
|
||||
virtual ~nsImapServerResponseParser();
|
||||
|
||||
// Overridden from the base parser class
|
||||
virtual bool LastCommandSuccessful() override;
|
||||
virtual void HandleMemoryFailure() override;
|
||||
|
||||
// aignoreBadAndNOResponses --> don't throw a error dialog if this command results in a NO or Bad response
|
||||
// from the server..in other words the command is "exploratory" and we don't really care if it succeeds or fails.
|
||||
// This value is typically FALSE for almost all cases.
|
||||
virtual void ParseIMAPServerResponse(const char *aCurrentCommand,
|
||||
bool aIgnoreBadAndNOResponses,
|
||||
char *aGreetingWithCapability = NULL);
|
||||
virtual void InitializeState();
|
||||
bool CommandFailed();
|
||||
void SetCommandFailed(bool failed);
|
||||
|
||||
enum eIMAPstate {
|
||||
kNonAuthenticated,
|
||||
kAuthenticated,
|
||||
kFolderSelected
|
||||
} ;
|
||||
|
||||
virtual eIMAPstate GetIMAPstate();
|
||||
virtual bool WaitingForMoreClientInput() { return fWaitingForMoreClientInput; }
|
||||
const char *GetSelectedMailboxName(); // can be NULL
|
||||
|
||||
// if we get a PREAUTH greeting from the server, initialize the parser to begin in
|
||||
// the kAuthenticated state
|
||||
void PreauthSetAuthenticatedState();
|
||||
|
||||
// these functions represent the state of the currently selected
|
||||
// folder
|
||||
bool CurrentFolderReadOnly();
|
||||
int32_t NumberOfMessages();
|
||||
int32_t NumberOfRecentMessages();
|
||||
int32_t NumberOfUnseenMessages();
|
||||
int32_t FolderUID();
|
||||
uint32_t CurrentResponseUID();
|
||||
uint32_t HighestRecordedUID();
|
||||
void SetCurrentResponseUID(uint32_t uid);
|
||||
bool IsNumericString(const char *string);
|
||||
uint32_t SizeOfMostRecentMessage();
|
||||
void SetTotalDownloadSize(int32_t newSize) { fTotalDownloadSize = newSize; }
|
||||
|
||||
nsImapSearchResultIterator *CreateSearchResultIterator();
|
||||
void ResetSearchResultSequence() {fSearchResults->ResetSequence();}
|
||||
|
||||
// create a struct mailbox_spec from our info, used in
|
||||
// libmsg c interface
|
||||
nsImapMailboxSpec *CreateCurrentMailboxSpec(const char *mailboxName = nullptr);
|
||||
|
||||
// Resets the flags state.
|
||||
void ResetFlagInfo();
|
||||
|
||||
// set this to false if you don't want to alert the user to server
|
||||
// error messages
|
||||
void SetReportingErrors(bool reportThem) { fReportingErrors=reportThem;}
|
||||
bool GetReportingErrors() { return fReportingErrors; }
|
||||
|
||||
eIMAPCapabilityFlags GetCapabilityFlag() { return fCapabilityFlag; }
|
||||
void SetCapabilityFlag(eIMAPCapabilityFlags capability) {fCapabilityFlag = capability;}
|
||||
bool ServerHasIMAP4Rev1Capability() { return ((fCapabilityFlag & kIMAP4rev1Capability) != 0); }
|
||||
bool ServerHasACLCapability() { return ((fCapabilityFlag & kACLCapability) != 0); }
|
||||
bool ServerHasNamespaceCapability() { return ((fCapabilityFlag & kNamespaceCapability) != 0); }
|
||||
bool ServerIsNetscape3xServer() { return fServerIsNetscape3xServer; }
|
||||
bool ServerHasServerInfo() {return ((fCapabilityFlag & kXServerInfoCapability) != 0); }
|
||||
bool ServerIsAOLServer() {return ((fCapabilityFlag & kAOLImapCapability) != 0); }
|
||||
void SetFetchingFlags(bool aFetchFlags) { fFetchingAllFlags = aFetchFlags;}
|
||||
void ResetCapabilityFlag() ;
|
||||
|
||||
nsCString& GetMailAccountUrl() { return fMailAccountUrl; }
|
||||
const char *GetXSenderInfo() { return fXSenderInfo; }
|
||||
void FreeXSenderInfo() { PR_FREEIF(fXSenderInfo); }
|
||||
nsCString& GetManageListsUrl() { return fManageListsUrl; }
|
||||
nsCString& GetManageFiltersUrl() {return fManageFiltersUrl;}
|
||||
const char *GetManageFolderUrl() {return fFolderAdminUrl;}
|
||||
nsCString &GetServerID() {return fServerIdResponse;}
|
||||
|
||||
// Call this when adding a pipelined command to the session
|
||||
void IncrementNumberOfTaggedResponsesExpected(const char *newExpectedTag);
|
||||
|
||||
// Interrupt a Fetch, without really Interrupting (through netlib)
|
||||
bool GetLastFetchChunkReceived();
|
||||
void ClearLastFetchChunkReceived();
|
||||
virtual uint16_t SupportsUserFlags() { return fSupportsUserDefinedFlags; }
|
||||
virtual uint16_t SettablePermanentFlags() { return fSettablePermanentFlags;}
|
||||
void SetFlagState(nsIImapFlagAndUidState *state);
|
||||
bool GetDownloadingHeaders();
|
||||
bool GetFillingInShell();
|
||||
void UseCachedShell(nsIMAPBodyShell *cachedShell);
|
||||
void SetHostSessionList(nsIImapHostSessionList *aHostSession);
|
||||
char *fAuthChallenge; // the challenge returned by the server in
|
||||
//response to authenticate using CRAM-MD5 or NTLM
|
||||
bool fCondStoreEnabled;
|
||||
bool fUseModSeq; // can use mod seq for currently selected folder
|
||||
uint64_t fHighestModSeq;
|
||||
|
||||
protected:
|
||||
virtual void flags();
|
||||
virtual void envelope_data();
|
||||
virtual void xaolenvelope_data();
|
||||
virtual void parse_address(nsAutoCString &addressLine);
|
||||
virtual void internal_date();
|
||||
virtual nsresult BeginMessageDownload(const char *content_type);
|
||||
|
||||
virtual void response_data();
|
||||
virtual void resp_text();
|
||||
virtual void resp_cond_state(bool isTagged);
|
||||
virtual void text_mime2();
|
||||
virtual void text();
|
||||
virtual void parse_folder_flags();
|
||||
virtual void enable_data();
|
||||
virtual void language_data();
|
||||
virtual void authChallengeResponse_data();
|
||||
virtual void resp_text_code();
|
||||
virtual void response_done();
|
||||
virtual void response_tagged();
|
||||
virtual void response_fatal();
|
||||
virtual void resp_cond_bye();
|
||||
virtual void id_data();
|
||||
virtual void mailbox_data();
|
||||
virtual void numeric_mailbox_data();
|
||||
virtual void capability_data();
|
||||
virtual void xserverinfo_data();
|
||||
virtual void xmailboxinfo_data();
|
||||
virtual void namespace_data();
|
||||
virtual void myrights_data(bool unsolicited);
|
||||
virtual void acl_data();
|
||||
virtual void bodystructure_data();
|
||||
nsIMAPBodypart *bodystructure_part(char *partNum, nsIMAPBodypart *parentPart);
|
||||
nsIMAPBodypart *bodystructure_leaf(char *partNum, nsIMAPBodypart *parentPart);
|
||||
nsIMAPBodypart *bodystructure_multipart(char *partNum, nsIMAPBodypart *parentPart);
|
||||
virtual void mime_data();
|
||||
virtual void mime_part_data();
|
||||
virtual void mime_header_data();
|
||||
virtual void quota_data();
|
||||
virtual void msg_fetch();
|
||||
virtual void msg_obsolete();
|
||||
virtual void msg_fetch_headers(const char *partNum);
|
||||
virtual void msg_fetch_content(bool chunk, int32_t origin, const char *content_type);
|
||||
virtual bool msg_fetch_quoted();
|
||||
virtual bool msg_fetch_literal(bool chunk, int32_t origin);
|
||||
virtual void mailbox_list(bool discoveredFromLsub);
|
||||
virtual void mailbox(nsImapMailboxSpec *boxSpec);
|
||||
|
||||
virtual void ProcessOkCommand(const char *commandToken);
|
||||
virtual void ProcessBadCommand(const char *commandToken);
|
||||
virtual void PreProcessCommandToken(const char *commandToken,
|
||||
const char *currentCommand);
|
||||
virtual void PostProcessEndOfLine();
|
||||
|
||||
// Overridden from the nsIMAPGenericParser, to retrieve the next line
|
||||
// from the open socket.
|
||||
virtual bool GetNextLineForParser(char **nextLine) override;
|
||||
// overriden to do logging
|
||||
virtual void SetSyntaxError(bool error, const char *msg = nullptr) override;
|
||||
|
||||
private:
|
||||
bool fCurrentCommandFailed;
|
||||
bool fReportingErrors;
|
||||
|
||||
|
||||
bool fCurrentFolderReadOnly;
|
||||
bool fCurrentLineContainedFlagInfo;
|
||||
bool fFetchingAllFlags;
|
||||
bool fWaitingForMoreClientInput;
|
||||
// Is the server a Netscape 3.x Messaging Server?
|
||||
bool fServerIsNetscape3xServer;
|
||||
bool fDownloadingHeaders;
|
||||
bool fCurrentCommandIsSingleMessageFetch;
|
||||
bool fGotPermanentFlags;
|
||||
imapMessageFlagsType fSavedFlagInfo;
|
||||
nsTArray<nsCString> fCustomFlags;
|
||||
|
||||
uint16_t fSupportsUserDefinedFlags;
|
||||
uint16_t fSettablePermanentFlags;
|
||||
|
||||
int32_t fFolderUIDValidity;
|
||||
int32_t fNumberOfUnseenMessages;
|
||||
int32_t fNumberOfExistingMessages;
|
||||
int32_t fNumberOfRecentMessages;
|
||||
uint32_t fCurrentResponseUID;
|
||||
uint32_t fHighestRecordedUID;
|
||||
// used to handle server that sends msg size after headers
|
||||
uint32_t fReceivedHeaderOrSizeForUID;
|
||||
int32_t fSizeOfMostRecentMessage;
|
||||
int32_t fTotalDownloadSize;
|
||||
|
||||
int32_t fStatusUnseenMessages;
|
||||
int32_t fStatusRecentMessages;
|
||||
uint32_t fStatusNextUID;
|
||||
uint32_t fStatusExistingMessages;
|
||||
|
||||
int fNumberOfTaggedResponsesExpected;
|
||||
|
||||
char *fCurrentCommandTag;
|
||||
|
||||
nsCString fZeroLengthMessageUidString;
|
||||
|
||||
char *fSelectedMailboxName;
|
||||
|
||||
nsImapSearchResultSequence *fSearchResults;
|
||||
|
||||
nsCOMPtr <nsIImapFlagAndUidState> fFlagState; // NOT owned by us, it's a copy, do not destroy
|
||||
|
||||
eIMAPstate fIMAPstate;
|
||||
|
||||
eIMAPCapabilityFlags fCapabilityFlag;
|
||||
nsCString fMailAccountUrl;
|
||||
char *fNetscapeServerVersionString;
|
||||
char *fXSenderInfo; /* changed per message download */
|
||||
char *fLastAlert; /* used to avoid displaying the same alert over and over */
|
||||
char *fMsgID; /* MessageID for Gmail only (X-GM-MSGID) */
|
||||
char *fThreadID; /* ThreadID for Gmail only (X-GM-THRID) */
|
||||
char *fLabels; /* Labels for Gmail only (X-GM-LABELS) [will include parens, removed while passing to hashTable ]*/
|
||||
nsCString fManageListsUrl;
|
||||
nsCString fManageFiltersUrl;
|
||||
char *fFolderAdminUrl;
|
||||
nsCString fServerIdResponse; // RFC
|
||||
|
||||
int32_t fFetchResponseIndex;
|
||||
|
||||
// used for aborting a fetch stream when we're pseudo-Interrupted
|
||||
int32_t numberOfCharsInThisChunk;
|
||||
int32_t charsReadSoFar;
|
||||
bool fLastChunk;
|
||||
|
||||
// points to the current body shell, if any
|
||||
RefPtr<nsIMAPBodyShell> m_shell;
|
||||
|
||||
// The connection object
|
||||
nsImapProtocol &fServerConnection;
|
||||
|
||||
nsIImapHostSessionList *fHostSessionList;
|
||||
nsTArray<nsMsgKey> fCopyResponseKeyArray;
|
||||
};
|
||||
|
||||
#endif
|
||||
3400
mailnews/imap/src/nsImapService.cpp
Normal file
3400
mailnews/imap/src/nsImapService.cpp
Normal file
File diff suppressed because it is too large
Load diff
123
mailnews/imap/src/nsImapService.h
Normal file
123
mailnews/imap/src/nsImapService.h
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/* -*- 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 nsImapService_h___
|
||||
#define nsImapService_h___
|
||||
|
||||
#include "nsIImapService.h"
|
||||
#include "nsIMsgMessageService.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIMsgProtocolInfo.h"
|
||||
#include "nsIContentHandler.h"
|
||||
#include "nsICacheStorage.h"
|
||||
|
||||
class nsIImapHostSessionList;
|
||||
class nsCString;
|
||||
class nsIImapUrl;
|
||||
class nsIMsgFolder;
|
||||
class nsIMsgStatusFeedback;
|
||||
class nsIMsgIncomingServer;
|
||||
|
||||
class nsImapService : public nsIImapService,
|
||||
public nsIMsgMessageService,
|
||||
public nsIMsgMessageFetchPartService,
|
||||
public nsIProtocolHandler,
|
||||
public nsIMsgProtocolInfo,
|
||||
public nsIContentHandler
|
||||
{
|
||||
public:
|
||||
nsImapService();
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIMSGPROTOCOLINFO
|
||||
NS_DECL_NSIIMAPSERVICE
|
||||
NS_DECL_NSIMSGMESSAGESERVICE
|
||||
NS_DECL_NSIPROTOCOLHANDLER
|
||||
NS_DECL_NSIMSGMESSAGEFETCHPARTSERVICE
|
||||
NS_DECL_NSICONTENTHANDLER
|
||||
|
||||
protected:
|
||||
virtual ~nsImapService();
|
||||
char GetHierarchyDelimiter(nsIMsgFolder *aMsgFolder);
|
||||
|
||||
nsresult GetFolderName(nsIMsgFolder *aImapFolder, nsACString &aFolderName);
|
||||
|
||||
// This is called by both FetchMessage and StreamMessage
|
||||
nsresult GetMessageFromUrl(nsIImapUrl *aImapUrl,
|
||||
nsImapAction aImapAction,
|
||||
nsIMsgFolder *aImapMailFolder,
|
||||
nsIImapMessageSink *aImapMessage,
|
||||
nsIMsgWindow *aMsgWindow,
|
||||
nsISupports *aDisplayConsumer,
|
||||
bool aConvertDataToText,
|
||||
nsIURI **aURL);
|
||||
|
||||
nsresult CreateStartOfImapUrl(const nsACString &aImapURI, // a RDF URI for the current message/folder, can be empty
|
||||
nsIImapUrl **imapUrl,
|
||||
nsIMsgFolder *aImapFolder,
|
||||
nsIUrlListener *aUrlListener,
|
||||
nsACString &urlSpec,
|
||||
char &hierarchyDelimiter);
|
||||
|
||||
nsresult GetImapConnectionAndLoadUrl(nsIImapUrl *aImapUrl,
|
||||
nsISupports *aConsumer,
|
||||
nsIURI **aURL);
|
||||
|
||||
nsresult SetImapUrlSink(nsIMsgFolder *aMsgFolder, nsIImapUrl *aImapUrl);
|
||||
|
||||
nsresult FetchMimePart(nsIImapUrl *aImapUrl,
|
||||
nsImapAction aImapAction,
|
||||
nsIMsgFolder *aImapMailFolder,
|
||||
nsIImapMessageSink *aImapMessage,
|
||||
nsIURI **aURL,
|
||||
nsISupports *aDisplayConsumer,
|
||||
const nsACString &messageIdentifierList,
|
||||
const nsACString &mimePart);
|
||||
|
||||
nsresult FolderCommand(nsIMsgFolder *imapMailFolder,
|
||||
nsIUrlListener *urlListener,
|
||||
const char *aCommand,
|
||||
nsImapAction imapAction,
|
||||
nsIMsgWindow *msgWindow,
|
||||
nsIURI **url);
|
||||
|
||||
nsresult ChangeFolderSubscription(nsIMsgFolder *folder,
|
||||
const nsAString &folderName,
|
||||
const char *aCommand,
|
||||
nsIUrlListener *urlListener,
|
||||
nsIURI **url);
|
||||
|
||||
nsresult DiddleFlags(nsIMsgFolder *aImapMailFolder,
|
||||
nsIUrlListener *aUrlListener,
|
||||
nsIURI **aURL,
|
||||
const nsACString &messageIdentifierList,
|
||||
const char *howToDiddle,
|
||||
imapMessageFlagsType flags,
|
||||
bool messageIdsAreUID);
|
||||
|
||||
nsresult OfflineAppendFromFile(nsIFile *aFile,
|
||||
nsIURI *aUrl,
|
||||
nsIMsgFolder *aDstFolder,
|
||||
const nsACString &messageId, // to be replaced
|
||||
bool inSelectedState, // needs to be in
|
||||
nsIUrlListener *aListener,
|
||||
nsIURI **aURL,
|
||||
nsISupports *aCopyState);
|
||||
|
||||
nsresult GetServerFromUrl(nsIImapUrl *aImapUrl, nsIMsgIncomingServer **aServer);
|
||||
|
||||
// just a little helper method...maybe it should be a macro? which helps break down a imap message uri
|
||||
// into the folder and message key equivalents
|
||||
nsresult DecomposeImapURI(const nsACString &aMessageURI, nsIMsgFolder **aFolder, nsACString &msgKey);
|
||||
nsresult DecomposeImapURI(const nsACString &aMessageURI, nsIMsgFolder **aFolder, nsMsgKey *msgKey);
|
||||
|
||||
|
||||
nsCOMPtr<nsICacheStorage> mCacheStorage;
|
||||
bool mPrintingOperation; // Flag for printing operations
|
||||
};
|
||||
|
||||
#endif /* nsImapService_h___ */
|
||||
42
mailnews/imap/src/nsImapStringBundle.cpp
Normal file
42
mailnews/imap/src/nsImapStringBundle.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- 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 "prprf.h"
|
||||
#include "prmem.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsImapStringBundle.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#define IMAP_MSGS_URL "chrome://messenger/locale/imapMsgs.properties"
|
||||
|
||||
extern "C"
|
||||
nsresult
|
||||
IMAPGetStringByName(const char* stringName, char16_t **aString)
|
||||
{
|
||||
nsCOMPtr <nsIStringBundle> sBundle;
|
||||
nsresult rv = IMAPGetStringBundle(getter_AddRefs(sBundle));
|
||||
if (NS_SUCCEEDED(rv) && sBundle)
|
||||
rv = sBundle->GetStringFromName(NS_ConvertASCIItoUTF16(stringName).get(),
|
||||
aString);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
IMAPGetStringBundle(nsIStringBundle **aBundle)
|
||||
{
|
||||
nsresult rv=NS_OK;
|
||||
nsCOMPtr<nsIStringBundleService> stringService =
|
||||
mozilla::services::GetStringBundleService();
|
||||
if (!stringService) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIStringBundle> stringBundle;
|
||||
rv = stringService->CreateBundle(IMAP_MSGS_URL, getter_AddRefs(stringBundle));
|
||||
*aBundle = stringBundle;
|
||||
NS_IF_ADDREF(*aBundle);
|
||||
return rv;
|
||||
}
|
||||
17
mailnews/imap/src/nsImapStringBundle.h
Normal file
17
mailnews/imap/src/nsImapStringBundle.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/* 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 _nsImapStringBundle_H__
|
||||
#define _nsImapStringBundle_H__
|
||||
|
||||
#include "nsIStringBundle.h"
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
nsresult IMAPGetStringByName(const char* stringName, char16_t **aString);
|
||||
nsresult IMAPGetStringBundle(nsIStringBundle **aBundle);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif /* _nsImapStringBundle_H__ */
|
||||
751
mailnews/imap/src/nsImapUndoTxn.cpp
Normal file
751
mailnews/imap/src/nsImapUndoTxn.cpp
Normal file
|
|
@ -0,0 +1,751 @@
|
|||
/* -*- 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" // for precompiled headers
|
||||
#include "nsMsgImapCID.h"
|
||||
#include "nsIMsgHdr.h"
|
||||
#include "nsImapUndoTxn.h"
|
||||
#include "nsIIMAPHostSessionList.h"
|
||||
#include "nsIMsgIncomingServer.h"
|
||||
#include "nsImapMailFolder.h"
|
||||
#include "nsIDBFolderInfo.h"
|
||||
#include "nsIMsgDatabase.h"
|
||||
#include "nsMsgUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
nsImapMoveCopyMsgTxn::nsImapMoveCopyMsgTxn() :
|
||||
m_idsAreUids(false), m_isMove(false), m_srcIsPop3(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsImapMoveCopyMsgTxn::Init(nsIMsgFolder* srcFolder, nsTArray<nsMsgKey>* srcKeyArray,
|
||||
const char* srcMsgIdString, nsIMsgFolder* dstFolder,
|
||||
bool idsAreUids, bool isMove)
|
||||
{
|
||||
m_srcMsgIdString = srcMsgIdString;
|
||||
m_idsAreUids = idsAreUids;
|
||||
m_isMove = isMove;
|
||||
m_srcFolder = do_GetWeakReference(srcFolder);
|
||||
m_dstFolder = do_GetWeakReference(dstFolder);
|
||||
m_srcKeyArray = *srcKeyArray;
|
||||
m_dupKeyArray = *srcKeyArray;
|
||||
nsCString uri;
|
||||
nsresult rv = srcFolder->GetURI(uri);
|
||||
nsCString protocolType(uri);
|
||||
protocolType.SetLength(protocolType.FindChar(':'));
|
||||
nsCOMPtr<nsIMsgDatabase> srcDB;
|
||||
rv = srcFolder->GetMsgDatabase(getter_AddRefs(srcDB));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
uint32_t i, count = m_srcKeyArray.Length();
|
||||
nsCOMPtr<nsIMsgDBHdr> srcHdr;
|
||||
nsCOMPtr<nsIMsgDBHdr> copySrcHdr;
|
||||
nsCString messageId;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
rv = srcDB->GetMsgHdrForKey(m_srcKeyArray[i],
|
||||
getter_AddRefs(srcHdr));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
// ** jt -- only do this for mailbox protocol
|
||||
if (MsgLowerCaseEqualsLiteral(protocolType, "mailbox"))
|
||||
{
|
||||
m_srcIsPop3 = true;
|
||||
uint32_t msgSize;
|
||||
rv = srcHdr->GetMessageSize(&msgSize);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
m_srcSizeArray.AppendElement(msgSize);
|
||||
if (isMove)
|
||||
{
|
||||
rv = srcDB->CopyHdrFromExistingHdr(nsMsgKey_None, srcHdr, false,
|
||||
getter_AddRefs(copySrcHdr));
|
||||
nsMsgKey pseudoKey = nsMsgKey_None;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
copySrcHdr->GetMessageKey(&pseudoKey);
|
||||
m_srcHdrs.AppendObject(copySrcHdr);
|
||||
}
|
||||
m_dupKeyArray[i] = pseudoKey;
|
||||
}
|
||||
}
|
||||
srcHdr->GetMessageId(getter_Copies(messageId));
|
||||
m_srcMessageIds.AppendElement(messageId);
|
||||
}
|
||||
}
|
||||
return nsMsgTxn::Init();
|
||||
}
|
||||
|
||||
nsImapMoveCopyMsgTxn::~nsImapMoveCopyMsgTxn()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(nsImapMoveCopyMsgTxn, nsMsgTxn, nsIUrlListener)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImapMoveCopyMsgTxn::UndoTransaction(void)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool finishInOnStopRunningUrl = false;
|
||||
|
||||
if (m_isMove || !m_dstFolder)
|
||||
{
|
||||
if (m_srcIsPop3)
|
||||
{
|
||||
rv = UndoMailboxDelete();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
|
||||
if (NS_FAILED(rv) || !srcFolder)
|
||||
return rv;
|
||||
nsCOMPtr<nsIUrlListener> srcListener = do_QueryInterface(srcFolder, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
m_onStopListener = do_GetWeakReference(srcListener);
|
||||
|
||||
// ** make sure we are in the selected state; use lite select
|
||||
// folder so we won't hit performance hard
|
||||
rv = imapService->LiteSelectFolder(srcFolder, srcListener, nullptr, nullptr);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
bool deletedMsgs = true; //default is true unless imapDelete model
|
||||
nsMsgImapDeleteModel deleteModel;
|
||||
rv = GetImapDeleteModel(srcFolder, &deleteModel);
|
||||
|
||||
// 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;
|
||||
|
||||
if (!m_srcMsgIdString.IsEmpty())
|
||||
{
|
||||
if (NS_SUCCEEDED(rv) && deleteModel == nsMsgImapDeleteModels::IMAPDelete)
|
||||
CheckForToggleDelete(srcFolder, m_srcKeyArray[0], &deletedMsgs);
|
||||
|
||||
if (deletedMsgs)
|
||||
rv = imapService->SubtractMessageFlags(srcFolder,
|
||||
this, nullptr,
|
||||
m_srcMsgIdString,
|
||||
kImapMsgDeletedFlag,
|
||||
m_idsAreUids);
|
||||
else
|
||||
rv = imapService->AddMessageFlags(srcFolder,
|
||||
srcListener, nullptr,
|
||||
m_srcMsgIdString,
|
||||
kImapMsgDeletedFlag,
|
||||
m_idsAreUids);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
finishInOnStopRunningUrl = true;
|
||||
if (deleteModel != nsMsgImapDeleteModels::IMAPDelete)
|
||||
rv = imapService->GetHeaders(srcFolder, srcListener, nullptr,
|
||||
m_srcMsgIdString, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!finishInOnStopRunningUrl && !m_dstMsgIdString.IsEmpty())
|
||||
{
|
||||
nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
|
||||
if (NS_FAILED(rv) || !dstFolder)
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIUrlListener> dstListener;
|
||||
|
||||
dstListener = do_QueryInterface(dstFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// ** make sure we are in the selected state; use lite select folder
|
||||
// so we won't potentially download a bunch of headers.
|
||||
rv = imapService->LiteSelectFolder(dstFolder,
|
||||
dstListener, nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = imapService->AddMessageFlags(dstFolder, dstListener,
|
||||
nullptr, m_dstMsgIdString,
|
||||
kImapMsgDeletedFlag, m_idsAreUids);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImapMoveCopyMsgTxn::RedoTransaction(void)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (m_isMove || !m_dstFolder)
|
||||
{
|
||||
if (m_srcIsPop3)
|
||||
{
|
||||
rv = RedoMailboxDelete();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
else if (!m_srcMsgIdString.IsEmpty())
|
||||
{
|
||||
nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
|
||||
if (NS_FAILED(rv) || !srcFolder)
|
||||
return rv;
|
||||
nsCOMPtr<nsIUrlListener> srcListener = do_QueryInterface(srcFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool deletedMsgs = false; //default will be false unless imapDeleteModel;
|
||||
nsMsgImapDeleteModel deleteModel;
|
||||
rv = GetImapDeleteModel(srcFolder, &deleteModel);
|
||||
|
||||
// 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;
|
||||
|
||||
if (NS_SUCCEEDED(rv) && deleteModel == nsMsgImapDeleteModels::IMAPDelete)
|
||||
rv = CheckForToggleDelete(srcFolder, m_srcKeyArray[0], &deletedMsgs);
|
||||
|
||||
// Make sure we are in the selected state; use lite select
|
||||
// folder so performance won't suffer.
|
||||
rv = imapService->LiteSelectFolder(srcFolder, srcListener, nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (deletedMsgs)
|
||||
{
|
||||
rv = imapService->SubtractMessageFlags(srcFolder,
|
||||
srcListener, nullptr,
|
||||
m_srcMsgIdString,
|
||||
kImapMsgDeletedFlag,
|
||||
m_idsAreUids);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = imapService->AddMessageFlags(srcFolder,
|
||||
srcListener, nullptr, m_srcMsgIdString,
|
||||
kImapMsgDeletedFlag, m_idsAreUids);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_dstMsgIdString.IsEmpty())
|
||||
{
|
||||
nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
|
||||
if (NS_FAILED(rv) || !dstFolder) return rv;
|
||||
|
||||
nsCOMPtr<nsIUrlListener> dstListener;
|
||||
|
||||
dstListener = do_QueryInterface(dstFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// ** make sure we are in the selected state; use lite select
|
||||
// folder so we won't hit performance hard
|
||||
rv = imapService->LiteSelectFolder(dstFolder, dstListener, nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = imapService->SubtractMessageFlags(dstFolder,
|
||||
dstListener, nullptr,
|
||||
m_dstMsgIdString,
|
||||
kImapMsgDeletedFlag,
|
||||
m_idsAreUids);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsMsgImapDeleteModel deleteModel;
|
||||
rv = GetImapDeleteModel(dstFolder, &deleteModel);
|
||||
if (NS_FAILED(rv) || deleteModel == nsMsgImapDeleteModels::MoveToTrash)
|
||||
{
|
||||
rv = imapService->GetHeaders(dstFolder, dstListener,
|
||||
nullptr, m_dstMsgIdString, true);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsImapMoveCopyMsgTxn::SetCopyResponseUid(const char* aMsgIdString)
|
||||
{
|
||||
if (!aMsgIdString) return NS_ERROR_NULL_POINTER;
|
||||
m_dstMsgIdString = aMsgIdString;
|
||||
if (m_dstMsgIdString.Last() == ']')
|
||||
{
|
||||
int32_t len = m_dstMsgIdString.Length();
|
||||
m_dstMsgIdString.SetLength(len - 1);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsImapMoveCopyMsgTxn::GetSrcKeyArray(nsTArray<nsMsgKey>& srcKeyArray)
|
||||
{
|
||||
srcKeyArray = m_srcKeyArray;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsImapMoveCopyMsgTxn::AddDstKey(nsMsgKey aKey)
|
||||
{
|
||||
if (!m_dstMsgIdString.IsEmpty())
|
||||
m_dstMsgIdString.Append(",");
|
||||
m_dstMsgIdString.AppendInt((int32_t) aKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsImapMoveCopyMsgTxn::UndoMailboxDelete()
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
// ** jt -- only do this for mailbox protocol
|
||||
if (m_srcIsPop3)
|
||||
{
|
||||
nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
|
||||
if (NS_FAILED(rv) || !srcFolder) return rv;
|
||||
|
||||
nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
|
||||
if (NS_FAILED(rv) || !dstFolder) return rv;
|
||||
|
||||
nsCOMPtr<nsIMsgDatabase> srcDB;
|
||||
nsCOMPtr<nsIMsgDatabase> dstDB;
|
||||
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;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
oldHdr = m_srcHdrs[i];
|
||||
NS_ASSERTION(oldHdr, "fatal ... cannot get old msg header\n");
|
||||
rv = srcDB->CopyHdrFromExistingHdr(m_srcKeyArray[i],
|
||||
oldHdr,true,
|
||||
getter_AddRefs(newHdr));
|
||||
NS_ASSERTION(newHdr, "fatal ... cannot create new header\n");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && newHdr)
|
||||
{
|
||||
if (i < m_srcSizeArray.Length())
|
||||
newHdr->SetMessageSize(m_srcSizeArray[i]);
|
||||
srcDB->UndoDelete(newHdr);
|
||||
}
|
||||
}
|
||||
srcDB->SetSummaryValid(true);
|
||||
return NS_OK; // always return NS_OK
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsImapMoveCopyMsgTxn::RedoMailboxDelete()
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (m_srcIsPop3)
|
||||
{
|
||||
nsCOMPtr<nsIMsgDatabase> srcDB;
|
||||
nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
|
||||
if (NS_FAILED(rv) || !srcFolder) return rv;
|
||||
rv = srcFolder->GetMsgDatabase(getter_AddRefs(srcDB));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
srcDB->DeleteMessages(m_srcKeyArray.Length(), m_srcKeyArray.Elements(), nullptr);
|
||||
srcDB->SetSummaryValid(true);
|
||||
}
|
||||
return NS_OK; // always return NS_OK
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsImapMoveCopyMsgTxn::GetImapDeleteModel(nsIMsgFolder *aFolder, nsMsgImapDeleteModel *aDeleteModel)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMsgIncomingServer> server;
|
||||
if (!aFolder)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
rv = aFolder->GetServer(getter_AddRefs(server));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIImapIncomingServer> imapServer = do_QueryInterface(server, &rv);
|
||||
if (NS_SUCCEEDED(rv) && imapServer)
|
||||
rv = imapServer->GetDeleteModel(aDeleteModel);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMoveCopyMsgTxn::OnStartRunningUrl(nsIURI *aUrl)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMoveCopyMsgTxn::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode)
|
||||
{
|
||||
nsCOMPtr<nsIUrlListener> urlListener = do_QueryReferent(m_onStopListener);
|
||||
if (urlListener)
|
||||
urlListener->OnStopRunningUrl(aUrl, aExitCode);
|
||||
|
||||
nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(aUrl);
|
||||
if (imapUrl)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsImapAction imapAction;
|
||||
imapUrl->GetImapAction(&imapAction);
|
||||
nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (imapAction == nsIImapUrl::nsImapSubtractMsgFlags)
|
||||
{
|
||||
int32_t extraStatus;
|
||||
imapUrl->GetExtraStatus(&extraStatus);
|
||||
if (extraStatus != nsIImapUrl::ImapStatusNone)
|
||||
{
|
||||
// If subtracting the deleted flag didn't work, try
|
||||
// moving the message back from the target folder to the src folder
|
||||
if (!m_dstMsgIdString.IsEmpty())
|
||||
imapService->OnlineMessageCopy(dstFolder,
|
||||
m_dstMsgIdString,
|
||||
srcFolder,
|
||||
true,
|
||||
true,
|
||||
nullptr, /* listener */
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
else
|
||||
{
|
||||
// server doesn't support COPYUID, so we're going to update the dest
|
||||
// folder, and when that's done, use the db to find the messages
|
||||
// to move back, looking them up by message-id.
|
||||
nsCOMPtr<nsIMsgImapMailFolder> imapDest = do_QueryInterface(dstFolder);
|
||||
if (imapDest)
|
||||
imapDest->UpdateFolderWithListener(nullptr, this);
|
||||
}
|
||||
}
|
||||
else if (!m_dstMsgIdString.IsEmpty())
|
||||
{
|
||||
nsCOMPtr<nsIUrlListener> dstListener;
|
||||
|
||||
dstListener = do_QueryInterface(dstFolder, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// ** make sure we are in the selected state; use lite select folder
|
||||
// so we won't potentially download a bunch of headers.
|
||||
rv = imapService->LiteSelectFolder(dstFolder, dstListener, nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = imapService->AddMessageFlags(dstFolder, dstListener,
|
||||
nullptr, m_dstMsgIdString,
|
||||
kImapMsgDeletedFlag, m_idsAreUids);
|
||||
}
|
||||
}
|
||||
else if (imapAction == nsIImapUrl::nsImapSelectFolder)
|
||||
{
|
||||
// Now we should have the headers from the dest folder.
|
||||
// Look them up and move them back to the source folder.
|
||||
uint32_t count = m_srcMessageIds.Length();
|
||||
uint32_t i;
|
||||
nsCString messageId;
|
||||
nsTArray<nsMsgKey> dstKeys;
|
||||
nsCOMPtr<nsIMsgDatabase> destDB;
|
||||
nsCOMPtr<nsIMsgDBHdr> dstHdr;
|
||||
|
||||
rv = dstFolder->GetMsgDatabase(getter_AddRefs(destDB));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
rv = destDB->GetMsgHdrForMessageID(m_srcMessageIds[i].get(), getter_AddRefs(dstHdr));
|
||||
if (NS_SUCCEEDED(rv) && dstHdr)
|
||||
{
|
||||
nsMsgKey dstKey;
|
||||
dstHdr->GetMessageKey(&dstKey);
|
||||
dstKeys.AppendElement(dstKey);
|
||||
}
|
||||
}
|
||||
if (dstKeys.Length())
|
||||
{
|
||||
nsAutoCString uids;
|
||||
nsImapMailFolder::AllocateUidStringFromKeys(dstKeys.Elements(), dstKeys.Length(), uids);
|
||||
rv = imapService->OnlineMessageCopy(dstFolder, uids, srcFolder,
|
||||
true, true, nullptr,
|
||||
nullptr, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsImapOfflineTxn::nsImapOfflineTxn(nsIMsgFolder* srcFolder, nsTArray<nsMsgKey>* srcKeyArray,
|
||||
const char *srcMsgIdString, nsIMsgFolder* dstFolder,
|
||||
bool isMove, nsOfflineImapOperationType opType,
|
||||
nsCOMArray<nsIMsgDBHdr> &srcHdrs)
|
||||
{
|
||||
Init(srcFolder, srcKeyArray, srcMsgIdString, dstFolder, true,
|
||||
isMove);
|
||||
|
||||
m_opType = opType;
|
||||
m_flags = 0;
|
||||
m_addFlags = false;
|
||||
if (opType == nsIMsgOfflineImapOperation::kDeletedMsg)
|
||||
{
|
||||
nsCOMPtr<nsIMsgDatabase> srcDB;
|
||||
nsCOMPtr<nsIDBFolderInfo> folderInfo;
|
||||
|
||||
nsresult rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(srcDB));
|
||||
if (NS_SUCCEEDED(rv) && srcDB)
|
||||
{
|
||||
nsMsgKey pseudoKey;
|
||||
nsCOMPtr <nsIMsgDBHdr> copySrcHdr;
|
||||
|
||||
// Imap protocols have conflated key/UUID so we cannot use
|
||||
// auto key with them.
|
||||
nsCString protocolType;
|
||||
srcFolder->GetURI(protocolType);
|
||||
protocolType.SetLength(protocolType.FindChar(':'));
|
||||
for (int32_t i = 0; i < srcHdrs.Count(); i++)
|
||||
{
|
||||
if (protocolType.EqualsLiteral("imap"))
|
||||
{
|
||||
srcDB->GetNextPseudoMsgKey(&pseudoKey);
|
||||
pseudoKey--;
|
||||
}
|
||||
else
|
||||
{
|
||||
pseudoKey = nsMsgKey_None;
|
||||
}
|
||||
rv = srcDB->CopyHdrFromExistingHdr(pseudoKey, srcHdrs[i], false, getter_AddRefs(copySrcHdr));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
copySrcHdr->GetMessageKey(&pseudoKey);
|
||||
m_srcHdrs.AppendObject(copySrcHdr);
|
||||
}
|
||||
m_dupKeyArray[i] = pseudoKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_srcHdrs.AppendObjects(srcHdrs);
|
||||
}
|
||||
|
||||
nsImapOfflineTxn::~nsImapOfflineTxn()
|
||||
{
|
||||
}
|
||||
|
||||
// Open the database and find the key for the offline operation that we want to
|
||||
// undo, then remove it from the database, we also hold on to this
|
||||
// data for a redo operation.
|
||||
NS_IMETHODIMP nsImapOfflineTxn::UndoTransaction(void)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
|
||||
if (NS_FAILED(rv) || !srcFolder)
|
||||
return rv;
|
||||
nsCOMPtr <nsIMsgOfflineImapOperation> op;
|
||||
nsCOMPtr <nsIDBFolderInfo> folderInfo;
|
||||
nsCOMPtr <nsIMsgDatabase> srcDB;
|
||||
nsCOMPtr <nsIMsgDatabase> destDB;
|
||||
|
||||
rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(srcDB));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
switch (m_opType)
|
||||
{
|
||||
case nsIMsgOfflineImapOperation::kMsgMoved:
|
||||
case nsIMsgOfflineImapOperation::kMsgCopy:
|
||||
case nsIMsgOfflineImapOperation::kAddedHeader:
|
||||
case nsIMsgOfflineImapOperation::kFlagsChanged:
|
||||
case nsIMsgOfflineImapOperation::kDeletedMsg:
|
||||
{
|
||||
if (m_srcHdrs.IsEmpty())
|
||||
{
|
||||
NS_ASSERTION(false, "No msg header to apply undo.");
|
||||
break;
|
||||
}
|
||||
nsCOMPtr<nsIMsgDBHdr> firstHdr = m_srcHdrs[0];
|
||||
nsMsgKey hdrKey;
|
||||
firstHdr->GetMessageKey(&hdrKey);
|
||||
rv = srcDB->GetOfflineOpForKey(hdrKey, false, getter_AddRefs(op));
|
||||
bool offlineOpPlayedBack = true;
|
||||
if (NS_SUCCEEDED(rv) && op)
|
||||
{
|
||||
op->GetPlayingBack(&offlineOpPlayedBack);
|
||||
srcDB->RemoveOfflineOp(op);
|
||||
op = nullptr;
|
||||
}
|
||||
if (!WeAreOffline() && offlineOpPlayedBack)
|
||||
{
|
||||
// couldn't find offline op - it must have been played back already
|
||||
// so we should undo the transaction online.
|
||||
return nsImapMoveCopyMsgTxn::UndoTransaction();
|
||||
}
|
||||
|
||||
if (!firstHdr)
|
||||
break;
|
||||
nsMsgKey msgKey;
|
||||
if (m_opType == nsIMsgOfflineImapOperation::kAddedHeader)
|
||||
{
|
||||
for (int32_t i = 0; i < m_srcHdrs.Count(); i++)
|
||||
{
|
||||
m_srcHdrs[i]->GetMessageKey(&msgKey);
|
||||
nsCOMPtr<nsIMsgDBHdr> mailHdr;
|
||||
rv = srcDB->GetMsgHdrForKey(msgKey, getter_AddRefs(mailHdr));
|
||||
if (mailHdr)
|
||||
srcDB->DeleteHeader(mailHdr, nullptr, false, false);
|
||||
}
|
||||
srcDB->Commit(true);
|
||||
}
|
||||
else if (m_opType == nsIMsgOfflineImapOperation::kDeletedMsg)
|
||||
{
|
||||
for (int32_t i = 0; i < m_srcHdrs.Count(); i++)
|
||||
{
|
||||
nsCOMPtr<nsIMsgDBHdr> undeletedHdr = m_srcHdrs[i];
|
||||
m_srcHdrs[i]->GetMessageKey(&msgKey);
|
||||
if (undeletedHdr)
|
||||
{
|
||||
nsCOMPtr<nsIMsgDBHdr> newHdr;
|
||||
srcDB->CopyHdrFromExistingHdr (msgKey, undeletedHdr, true, getter_AddRefs(newHdr));
|
||||
}
|
||||
}
|
||||
srcDB->Close(true);
|
||||
srcFolder->SummaryChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case nsIMsgOfflineImapOperation::kMsgMarkedDeleted:
|
||||
{
|
||||
nsMsgKey msgKey;
|
||||
for (int32_t i = 0; i < m_srcHdrs.Count(); i++)
|
||||
{
|
||||
m_srcHdrs[i]->GetMessageKey(&msgKey);
|
||||
srcDB->MarkImapDeleted(msgKey, false, nullptr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
srcDB->Close(true);
|
||||
srcFolder->SummaryChanged();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapOfflineTxn::RedoTransaction(void)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
|
||||
if (NS_FAILED(rv) || !srcFolder)
|
||||
return rv;
|
||||
nsCOMPtr <nsIMsgOfflineImapOperation> op;
|
||||
nsCOMPtr <nsIDBFolderInfo> folderInfo;
|
||||
nsCOMPtr <nsIMsgDatabase> srcDB;
|
||||
nsCOMPtr <nsIMsgDatabase> destDB;
|
||||
rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(srcDB));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
switch (m_opType)
|
||||
{
|
||||
case nsIMsgOfflineImapOperation::kMsgMoved:
|
||||
case nsIMsgOfflineImapOperation::kMsgCopy:
|
||||
for (int32_t i = 0; i < m_srcHdrs.Count(); i++)
|
||||
{
|
||||
nsMsgKey hdrKey;
|
||||
m_srcHdrs[i]->GetMessageKey(&hdrKey);
|
||||
rv = srcDB->GetOfflineOpForKey(hdrKey, false, getter_AddRefs(op));
|
||||
if (NS_SUCCEEDED(rv) && op)
|
||||
{
|
||||
nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
|
||||
if (dstFolder)
|
||||
{
|
||||
nsCString folderURI;
|
||||
dstFolder->GetURI(folderURI);
|
||||
|
||||
if (m_opType == nsIMsgOfflineImapOperation::kMsgMoved)
|
||||
op->SetDestinationFolderURI(folderURI.get()); // offline move
|
||||
if (m_opType == nsIMsgOfflineImapOperation::kMsgCopy)
|
||||
{
|
||||
op->SetOperation(nsIMsgOfflineImapOperation::kMsgMoved);
|
||||
op->AddMessageCopyOperation(folderURI.get()); // offline copy
|
||||
}
|
||||
dstFolder->SummaryChanged();
|
||||
}
|
||||
}
|
||||
else if (!WeAreOffline())
|
||||
{
|
||||
// couldn't find offline op - it must have been played back already
|
||||
// so we should redo the transaction online.
|
||||
return nsImapMoveCopyMsgTxn::RedoTransaction();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case nsIMsgOfflineImapOperation::kAddedHeader:
|
||||
{
|
||||
nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
|
||||
rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(destDB));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (int32_t i = 0; i < m_srcHdrs.Count(); i++)
|
||||
{
|
||||
nsCOMPtr<nsIMsgDBHdr> restoreHdr;
|
||||
nsMsgKey msgKey;
|
||||
m_srcHdrs[i]->GetMessageKey(&msgKey);
|
||||
destDB->CopyHdrFromExistingHdr (msgKey, m_srcHdrs[i], true, getter_AddRefs(restoreHdr));
|
||||
rv = destDB->GetOfflineOpForKey(msgKey, true, getter_AddRefs(op));
|
||||
if (NS_SUCCEEDED(rv) && op)
|
||||
{
|
||||
nsCString folderURI;
|
||||
srcFolder->GetURI(folderURI);
|
||||
op->SetSourceFolderURI(folderURI.get());
|
||||
}
|
||||
}
|
||||
dstFolder->SummaryChanged();
|
||||
destDB->Close(true);
|
||||
}
|
||||
break;
|
||||
case nsIMsgOfflineImapOperation::kDeletedMsg:
|
||||
for (int32_t i = 0; i < m_srcHdrs.Count(); i++)
|
||||
{
|
||||
nsMsgKey msgKey;
|
||||
m_srcHdrs[i]->GetMessageKey(&msgKey);
|
||||
srcDB->DeleteMessage(msgKey, nullptr, true);
|
||||
}
|
||||
break;
|
||||
case nsIMsgOfflineImapOperation::kMsgMarkedDeleted:
|
||||
for (int32_t i = 0; i < m_srcHdrs.Count(); i++)
|
||||
{
|
||||
nsMsgKey msgKey;
|
||||
m_srcHdrs[i]->GetMessageKey(&msgKey);
|
||||
srcDB->MarkImapDeleted(msgKey, true, nullptr);
|
||||
}
|
||||
break;
|
||||
case nsIMsgOfflineImapOperation::kFlagsChanged:
|
||||
for (int32_t i = 0; i < m_srcHdrs.Count(); i++)
|
||||
{
|
||||
nsMsgKey msgKey;
|
||||
m_srcHdrs[i]->GetMessageKey(&msgKey);
|
||||
rv = srcDB->GetOfflineOpForKey(msgKey, true, getter_AddRefs(op));
|
||||
if (NS_SUCCEEDED(rv) && op)
|
||||
{
|
||||
imapMessageFlagsType newMsgFlags;
|
||||
op->GetNewFlags(&newMsgFlags);
|
||||
if (m_addFlags)
|
||||
op->SetFlagOperation(newMsgFlags | m_flags);
|
||||
else
|
||||
op->SetFlagOperation(newMsgFlags & ~m_flags);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
srcDB->Close(true);
|
||||
srcDB = nullptr;
|
||||
srcFolder->SummaryChanged();
|
||||
return NS_OK;
|
||||
}
|
||||
92
mailnews/imap/src/nsImapUndoTxn.h
Normal file
92
mailnews/imap/src/nsImapUndoTxn.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/* -*- 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 nsImapUndoTxn_h__
|
||||
#define nsImapUndoTxn_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIMsgFolder.h"
|
||||
#include "nsImapCore.h"
|
||||
#include "nsIImapService.h"
|
||||
#include "nsIImapIncomingServer.h"
|
||||
#include "nsIUrlListener.h"
|
||||
#include "nsMsgTxn.h"
|
||||
#include "MailNewsTypes.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIMsgOfflineImapOperation.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
class nsImapMoveCopyMsgTxn : public nsMsgTxn, nsIUrlListener
|
||||
{
|
||||
public:
|
||||
|
||||
nsImapMoveCopyMsgTxn();
|
||||
nsImapMoveCopyMsgTxn(nsIMsgFolder* srcFolder, nsTArray<nsMsgKey>* srcKeyArray,
|
||||
const char* srcMsgIdString, nsIMsgFolder* dstFolder,
|
||||
bool isMove);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIURLLISTENER
|
||||
|
||||
NS_IMETHOD UndoTransaction(void) override;
|
||||
NS_IMETHOD RedoTransaction(void) override;
|
||||
|
||||
// helper
|
||||
nsresult SetCopyResponseUid(const char *msgIdString);
|
||||
nsresult GetSrcKeyArray(nsTArray<nsMsgKey>& srcKeyArray);
|
||||
void GetSrcMsgIds(nsCString &srcMsgIds) {srcMsgIds = m_srcMsgIdString;}
|
||||
nsresult AddDstKey(nsMsgKey aKey);
|
||||
nsresult UndoMailboxDelete();
|
||||
nsresult RedoMailboxDelete();
|
||||
nsresult Init(nsIMsgFolder* srcFolder, nsTArray<nsMsgKey>* srcKeyArray,
|
||||
const char* srcMsgIdString, nsIMsgFolder* dstFolder,
|
||||
bool idsAreUids, bool isMove);
|
||||
|
||||
protected:
|
||||
virtual ~nsImapMoveCopyMsgTxn();
|
||||
|
||||
nsWeakPtr m_srcFolder;
|
||||
nsCOMArray<nsIMsgDBHdr> m_srcHdrs;
|
||||
nsTArray<nsMsgKey> m_dupKeyArray;
|
||||
nsTArray<nsMsgKey> m_srcKeyArray;
|
||||
nsTArray<nsCString> m_srcMessageIds;
|
||||
nsCString m_srcMsgIdString;
|
||||
nsWeakPtr m_dstFolder;
|
||||
nsCString m_dstMsgIdString;
|
||||
bool m_idsAreUids;
|
||||
bool m_isMove;
|
||||
bool m_srcIsPop3;
|
||||
nsTArray<uint32_t> m_srcSizeArray;
|
||||
// this is used when we chain urls for imap undo, since "this" needs
|
||||
// to be the listener, but the folder may need to also be notified.
|
||||
nsWeakPtr m_onStopListener;
|
||||
|
||||
nsresult GetImapDeleteModel(nsIMsgFolder* aFolder, nsMsgImapDeleteModel *aDeleteModel);
|
||||
};
|
||||
|
||||
class nsImapOfflineTxn : public nsImapMoveCopyMsgTxn
|
||||
{
|
||||
public:
|
||||
nsImapOfflineTxn(nsIMsgFolder* srcFolder, nsTArray<nsMsgKey>* srcKeyArray,
|
||||
const char* srcMsgIdString,
|
||||
nsIMsgFolder* dstFolder,
|
||||
bool isMove,
|
||||
nsOfflineImapOperationType opType,
|
||||
nsCOMArray<nsIMsgDBHdr> &srcHdrs);
|
||||
|
||||
NS_IMETHOD UndoTransaction(void) override;
|
||||
NS_IMETHOD RedoTransaction(void) override;
|
||||
void SetAddFlags(bool addFlags) {m_addFlags = addFlags;}
|
||||
void SetFlags(uint32_t flags) {m_flags = flags;}
|
||||
protected:
|
||||
virtual ~nsImapOfflineTxn();
|
||||
nsOfflineImapOperationType m_opType;
|
||||
// these two are used to undo flag changes, which we don't currently do.
|
||||
bool m_addFlags;
|
||||
uint32_t m_flags;
|
||||
};
|
||||
#endif
|
||||
1563
mailnews/imap/src/nsImapUrl.cpp
Normal file
1563
mailnews/imap/src/nsImapUrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
133
mailnews/imap/src/nsImapUrl.h
Normal file
133
mailnews/imap/src/nsImapUrl.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/* -*- 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 nsImapUrl_h___
|
||||
#define nsImapUrl_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIImapUrl.h"
|
||||
#include "nsIImapMockChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsMsgMailNewsUrl.h"
|
||||
#include "nsIMsgIncomingServer.h"
|
||||
#include "nsIImapMailFolderSink.h"
|
||||
#include "nsIImapServerSink.h"
|
||||
#include "nsIImapMessageSink.h"
|
||||
|
||||
#include "nsWeakPtr.h"
|
||||
#include "nsIFile.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
class nsImapUrl : public nsIImapUrl, public nsMsgMailNewsUrl, public nsIMsgMessageUrl, public nsIMsgI18NUrl
|
||||
{
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIURI override
|
||||
NS_IMETHOD SetSpec(const nsACString &aSpec) override;
|
||||
NS_IMETHOD SetQuery(const nsACString &aQuery) override;
|
||||
NS_IMETHOD CloneInternal(uint32_t aRefHandlingMode,
|
||||
const nsACString& newRef, nsIURI **_retval) override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// we support the nsIImapUrl interface
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
NS_DECL_NSIIMAPURL
|
||||
|
||||
// nsIMsgMailNewsUrl overrides
|
||||
NS_IMETHOD IsUrlType(uint32_t type, bool *isType) override;
|
||||
NS_IMETHOD GetFolder(nsIMsgFolder **aFolder) override;
|
||||
NS_IMETHOD SetFolder(nsIMsgFolder *aFolder) override;
|
||||
// nsIMsgMessageUrl
|
||||
NS_DECL_NSIMSGMESSAGEURL
|
||||
NS_DECL_NSIMSGI18NURL
|
||||
|
||||
// nsImapUrl
|
||||
nsImapUrl();
|
||||
|
||||
static nsresult ConvertToCanonicalFormat(const char *folderName, char onlineDelimiter, char **resultingCanonicalPath);
|
||||
static nsresult EscapeSlashes(const char *sourcePath, char **resultPath);
|
||||
static nsresult UnescapeSlashes(char *path);
|
||||
static char * ReplaceCharsInCopiedString(const char *stringToCopy, char oldChar, char newChar);
|
||||
|
||||
protected:
|
||||
virtual ~nsImapUrl();
|
||||
virtual nsresult ParseUrl();
|
||||
|
||||
char *m_listOfMessageIds;
|
||||
|
||||
// handle the imap specific parsing
|
||||
void ParseImapPart(char *imapPartOfUrl);
|
||||
|
||||
void ParseFolderPath(char **resultingCanonicalPath);
|
||||
void ParseSearchCriteriaString();
|
||||
void ParseUidChoice();
|
||||
void ParseMsgFlags();
|
||||
void ParseListOfMessageIds();
|
||||
void ParseCustomMsgFetchAttribute();
|
||||
void ParseNumBytes();
|
||||
|
||||
nsresult GetMsgFolder(nsIMsgFolder **msgFolder);
|
||||
|
||||
char *m_sourceCanonicalFolderPathSubString;
|
||||
char *m_destinationCanonicalFolderPathSubString;
|
||||
char *m_tokenPlaceHolder;
|
||||
char *m_urlidSubString;
|
||||
char m_onlineSubDirSeparator;
|
||||
char *m_searchCriteriaString; // should we use m_search, or is this special?
|
||||
nsCString m_command; // for custom commands
|
||||
nsCString m_msgFetchAttribute; // for fetching custom msg attributes
|
||||
nsCString m_customAttributeResult; // for fetching custom msg attributes
|
||||
nsCString m_customCommandResult; // custom command response
|
||||
nsCString m_customAddFlags; // these two are for setting and clearing custom flags
|
||||
nsCString m_customSubtractFlags;
|
||||
int32_t m_numBytesToFetch; // when doing a msg body preview, how many bytes to read
|
||||
bool m_validUrl;
|
||||
bool m_runningUrl;
|
||||
bool m_idsAreUids;
|
||||
bool m_mimePartSelectorDetected;
|
||||
bool m_allowContentChange; // if false, we can't use Mime parts on demand
|
||||
bool m_fetchPartsOnDemand; // if true, we should fetch leave parts on server.
|
||||
bool m_msgLoadingFromCache; // if true, we might need to mark read on server
|
||||
bool m_externalLinkUrl; // if true, we're running this url because the user
|
||||
// True if the fetch results should be put in the offline store.
|
||||
bool m_storeResultsOffline;
|
||||
bool m_storeOfflineOnFallback;
|
||||
bool m_localFetchOnly;
|
||||
bool m_rerunningUrl; // first attempt running this failed with connection error; retrying
|
||||
bool m_moreHeadersToDownload;
|
||||
nsImapContentModifiedType m_contentModified;
|
||||
|
||||
int32_t m_extraStatus;
|
||||
|
||||
nsCString m_userName;
|
||||
nsCString m_serverKey;
|
||||
// event sinks
|
||||
imapMessageFlagsType m_flags;
|
||||
nsImapAction m_imapAction;
|
||||
|
||||
nsWeakPtr m_imapFolder;
|
||||
nsWeakPtr m_imapMailFolderSink;
|
||||
nsWeakPtr m_imapMessageSink;
|
||||
|
||||
nsWeakPtr m_imapServerSink;
|
||||
|
||||
// online message copy support; i don't have a better solution yet
|
||||
nsCOMPtr <nsISupports> m_copyState; // now, refcounted.
|
||||
nsCOMPtr<nsIFile> m_file;
|
||||
nsWeakPtr m_channelWeakPtr;
|
||||
|
||||
// used by save message to disk
|
||||
nsCOMPtr<nsIFile> m_messageFile;
|
||||
bool m_addDummyEnvelope;
|
||||
bool m_canonicalLineEnding; // CRLF
|
||||
|
||||
nsCString mURI; // the RDF URI associated with this url.
|
||||
nsCString mCharsetOverride; // used by nsIMsgI18NUrl...
|
||||
mozilla::Mutex mLock;
|
||||
};
|
||||
|
||||
#endif /* nsImapUrl_h___ */
|
||||
373
mailnews/imap/src/nsImapUtils.cpp
Normal file
373
mailnews/imap/src/nsImapUtils.cpp
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
/* -*- 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 "nsImapUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "prsystem.h"
|
||||
#include "prprf.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
// stuff for temporary root folder hack
|
||||
#include "nsIMsgAccountManager.h"
|
||||
#include "nsIMsgIncomingServer.h"
|
||||
#include "nsIImapIncomingServer.h"
|
||||
#include "nsMsgBaseCID.h"
|
||||
#include "nsImapCore.h"
|
||||
#include "nsMsgUtils.h"
|
||||
#include "nsImapFlagAndUidState.h"
|
||||
#include "nsIMAPNamespace.h"
|
||||
#include "nsIImapFlagAndUidState.h"
|
||||
|
||||
nsresult
|
||||
nsImapURI2FullName(const char* rootURI, const char* hostName, const char* uriStr,
|
||||
char **name)
|
||||
{
|
||||
nsAutoCString uri(uriStr);
|
||||
nsAutoCString fullName;
|
||||
if (uri.Find(rootURI) != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
fullName = Substring(uri, strlen(rootURI));
|
||||
uri = fullName;
|
||||
int32_t hostStart = uri.Find(hostName);
|
||||
if (hostStart <= 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
fullName = Substring(uri, hostStart);
|
||||
uri = fullName;
|
||||
int32_t hostEnd = uri.FindChar('/');
|
||||
if (hostEnd <= 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
fullName = Substring(uri, hostEnd + 1);
|
||||
if (fullName.IsEmpty())
|
||||
return NS_ERROR_FAILURE;
|
||||
*name = ToNewCString(fullName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* parses ImapMessageURI */
|
||||
nsresult nsParseImapMessageURI(const char* uri, nsCString& folderURI, uint32_t *key, char **part)
|
||||
{
|
||||
if(!key)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsAutoCString uriStr(uri);
|
||||
int32_t folderEnd = -1;
|
||||
// imap-message uri's can have imap:// url strings tacked on the end,
|
||||
// e.g., when opening/saving attachments. We don't want to look for '#'
|
||||
// in that part of the uri, if the attachment name contains '#',
|
||||
// so check for that here.
|
||||
if (StringBeginsWith(uriStr, NS_LITERAL_CSTRING("imap-message")))
|
||||
folderEnd = uriStr.Find("imap://");
|
||||
|
||||
int32_t keySeparator = MsgRFindChar(uriStr, '#', folderEnd);
|
||||
if(keySeparator != -1)
|
||||
{
|
||||
int32_t keyEndSeparator = MsgFindCharInSet(uriStr, "/?&", keySeparator);
|
||||
nsAutoString folderPath;
|
||||
folderURI = StringHead(uriStr, keySeparator);
|
||||
folderURI.Cut(4, 8); // cut out the _message part of imap-message:
|
||||
// folder uri's don't have fully escaped usernames.
|
||||
int32_t atPos = folderURI.FindChar('@');
|
||||
if (atPos != -1)
|
||||
{
|
||||
nsCString unescapedName, escapedName;
|
||||
int32_t userNamePos = folderURI.Find("//") + 2;
|
||||
uint32_t origUserNameLen = atPos - userNamePos;
|
||||
if (NS_SUCCEEDED(MsgUnescapeString(Substring(folderURI, userNamePos,
|
||||
origUserNameLen),
|
||||
0, unescapedName)))
|
||||
{
|
||||
// Re-escape the username, matching the way we do it in uris, not the
|
||||
// way necko escapes urls. See nsMsgIncomingServer::GetServerURI.
|
||||
MsgEscapeString(unescapedName, nsINetUtil::ESCAPE_XALPHAS, escapedName);
|
||||
folderURI.Replace(userNamePos, origUserNameLen, escapedName);
|
||||
}
|
||||
}
|
||||
nsAutoCString keyStr;
|
||||
if (keyEndSeparator != -1)
|
||||
keyStr = Substring(uriStr, keySeparator + 1, keyEndSeparator - (keySeparator + 1));
|
||||
else
|
||||
keyStr = Substring(uriStr, keySeparator + 1);
|
||||
|
||||
*key = strtoul(keyStr.get(), nullptr, 10);
|
||||
|
||||
if (part && keyEndSeparator != -1)
|
||||
{
|
||||
int32_t partPos = MsgFind(uriStr, "part=", false, keyEndSeparator);
|
||||
if (partPos != -1)
|
||||
{
|
||||
*part = ToNewCString(Substring(uriStr, keyEndSeparator));
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsBuildImapMessageURI(const char *baseURI, uint32_t key, nsCString& uri)
|
||||
{
|
||||
uri.Append(baseURI);
|
||||
uri.Append('#');
|
||||
uri.AppendInt(key);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsCreateImapBaseMessageURI(const nsACString& baseURI, nsCString &baseMessageURI)
|
||||
{
|
||||
nsAutoCString tailURI(baseURI);
|
||||
// chop off imap:/
|
||||
if (tailURI.Find(kImapRootURI) == 0)
|
||||
tailURI.Cut(0, PL_strlen(kImapRootURI));
|
||||
baseMessageURI = kImapMessageRootURI;
|
||||
baseMessageURI += tailURI;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsImapMailboxSpec definition
|
||||
NS_IMPL_ISUPPORTS(nsImapMailboxSpec, nsIMailboxSpec)
|
||||
|
||||
nsImapMailboxSpec::nsImapMailboxSpec()
|
||||
{
|
||||
mFolder_UIDVALIDITY = 0;
|
||||
mHighestModSeq = 0;
|
||||
mNumOfMessages = 0;
|
||||
mNumOfUnseenMessages = 0;
|
||||
mNumOfRecentMessages = 0;
|
||||
mNextUID = 0;
|
||||
|
||||
mBoxFlags = 0;
|
||||
mSupportedUserFlags = 0;
|
||||
|
||||
mHierarchySeparator = '\0';
|
||||
|
||||
mFolderSelected = false;
|
||||
mDiscoveredFromLsub = false;
|
||||
|
||||
mOnlineVerified = false;
|
||||
mNamespaceForFolder = nullptr;
|
||||
}
|
||||
|
||||
nsImapMailboxSpec::~nsImapMailboxSpec()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, Folder_UIDVALIDITY, int32_t, mFolder_UIDVALIDITY)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, HighestModSeq, uint64_t, mHighestModSeq)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, NumMessages, int32_t, mNumOfMessages)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, NumUnseenMessages, int32_t, mNumOfUnseenMessages)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, NumRecentMessages, int32_t, mNumOfRecentMessages)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, NextUID, int32_t, mNextUID)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, HierarchyDelimiter, char, mHierarchySeparator)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, FolderSelected, bool, mFolderSelected)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, DiscoveredFromLsub, bool, mDiscoveredFromLsub)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, OnlineVerified, bool, mOnlineVerified)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, SupportedUserFlags, uint32_t, mSupportedUserFlags)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, Box_flags, uint32_t, mBoxFlags)
|
||||
NS_IMPL_GETSET(nsImapMailboxSpec, NamespaceForFolder, nsIMAPNamespace *, mNamespaceForFolder)
|
||||
|
||||
NS_IMETHODIMP nsImapMailboxSpec::GetAllocatedPathName(nsACString &aAllocatedPathName)
|
||||
{
|
||||
aAllocatedPathName = mAllocatedPathName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMailboxSpec::SetAllocatedPathName(const nsACString &aAllocatedPathName)
|
||||
{
|
||||
mAllocatedPathName = aAllocatedPathName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMailboxSpec::GetUnicharPathName(nsAString &aUnicharPathName)
|
||||
{
|
||||
aUnicharPathName = aUnicharPathName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMailboxSpec::SetUnicharPathName(const nsAString &aUnicharPathName)
|
||||
{
|
||||
mUnicharPathName = aUnicharPathName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMailboxSpec::GetHostName(nsACString &aHostName)
|
||||
{
|
||||
aHostName = mHostName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMailboxSpec::SetHostName(const nsACString &aHostName)
|
||||
{
|
||||
mHostName = aHostName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMailboxSpec::GetFlagState(nsIImapFlagAndUidState ** aFlagState)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFlagState);
|
||||
NS_IF_ADDREF(*aFlagState = mFlagState);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMailboxSpec::SetFlagState(nsIImapFlagAndUidState * aFlagState)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFlagState);
|
||||
mFlagState = aFlagState;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsImapMailboxSpec& nsImapMailboxSpec::operator= (const nsImapMailboxSpec& aCopy)
|
||||
{
|
||||
mFolder_UIDVALIDITY = aCopy.mFolder_UIDVALIDITY;
|
||||
mHighestModSeq = aCopy.mHighestModSeq;
|
||||
mNumOfMessages = aCopy.mNumOfMessages;
|
||||
mNumOfUnseenMessages = aCopy.mNumOfUnseenMessages;
|
||||
mNumOfRecentMessages = aCopy.mNumOfRecentMessages;
|
||||
|
||||
mBoxFlags = aCopy.mBoxFlags;
|
||||
mSupportedUserFlags = aCopy.mSupportedUserFlags;
|
||||
|
||||
mAllocatedPathName.Assign(aCopy.mAllocatedPathName);
|
||||
mUnicharPathName.Assign(aCopy.mUnicharPathName);
|
||||
mHostName.Assign(aCopy.mHostName);
|
||||
|
||||
mFlagState = aCopy.mFlagState;
|
||||
mNamespaceForFolder = aCopy.mNamespaceForFolder;
|
||||
|
||||
mFolderSelected = aCopy.mFolderSelected;
|
||||
mDiscoveredFromLsub = aCopy.mDiscoveredFromLsub;
|
||||
|
||||
mOnlineVerified = aCopy.mOnlineVerified;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// use the flagState to determine if the gaps in the msgUids correspond to gaps in the mailbox,
|
||||
// in which case we can still use ranges. If flagState is null, we won't do this.
|
||||
void AllocateImapUidString(uint32_t *msgUids, uint32_t &msgCount,
|
||||
nsImapFlagAndUidState *flagState, nsCString &returnString)
|
||||
{
|
||||
uint32_t startSequence = (msgCount > 0) ? msgUids[0] : 0xFFFFFFFF;
|
||||
uint32_t curSequenceEnd = startSequence;
|
||||
uint32_t total = msgCount;
|
||||
int32_t curFlagStateIndex = -1;
|
||||
|
||||
// a partial fetch flag state doesn't help us, so don't use it.
|
||||
if (flagState && flagState->GetPartialUIDFetch())
|
||||
flagState = nullptr;
|
||||
|
||||
|
||||
for (uint32_t keyIndex = 0; keyIndex < total; keyIndex++)
|
||||
{
|
||||
uint32_t curKey = msgUids[keyIndex];
|
||||
uint32_t nextKey = (keyIndex + 1 < total) ? msgUids[keyIndex + 1] : 0xFFFFFFFF;
|
||||
bool lastKey = (nextKey == 0xFFFFFFFF);
|
||||
|
||||
if (lastKey)
|
||||
curSequenceEnd = curKey;
|
||||
|
||||
if (!lastKey)
|
||||
{
|
||||
if (nextKey == curSequenceEnd + 1)
|
||||
{
|
||||
curSequenceEnd = nextKey;
|
||||
curFlagStateIndex++;
|
||||
continue;
|
||||
}
|
||||
if (flagState)
|
||||
{
|
||||
if (curFlagStateIndex == -1)
|
||||
{
|
||||
bool foundIt;
|
||||
flagState->GetMessageFlagsFromUID(curSequenceEnd, &foundIt, &curFlagStateIndex);
|
||||
if (!foundIt)
|
||||
{
|
||||
NS_WARNING("flag state missing key");
|
||||
// The start of this sequence is missing from flag state, so move
|
||||
// on to the next key.
|
||||
curFlagStateIndex = -1;
|
||||
curSequenceEnd = startSequence = nextKey;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
curFlagStateIndex++;
|
||||
uint32_t nextUidInFlagState;
|
||||
nsresult rv = flagState->GetUidOfMessage(curFlagStateIndex, &nextUidInFlagState);
|
||||
if (NS_SUCCEEDED(rv) && nextUidInFlagState == nextKey)
|
||||
{
|
||||
curSequenceEnd = nextKey;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (curSequenceEnd > startSequence)
|
||||
{
|
||||
returnString.AppendInt((int64_t) startSequence);
|
||||
returnString += ':';
|
||||
returnString.AppendInt((int64_t) curSequenceEnd);
|
||||
startSequence = nextKey;
|
||||
curSequenceEnd = startSequence;
|
||||
curFlagStateIndex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
startSequence = nextKey;
|
||||
curSequenceEnd = startSequence;
|
||||
returnString.AppendInt((int64_t) msgUids[keyIndex]);
|
||||
curFlagStateIndex = -1;
|
||||
}
|
||||
// check if we've generated too long a string - if there's no flag state,
|
||||
// it means we just need to go ahead and generate a too long string
|
||||
// because the calling code won't handle breaking up the strings.
|
||||
if (flagState && returnString.Length() > 950)
|
||||
{
|
||||
msgCount = keyIndex;
|
||||
break;
|
||||
}
|
||||
// If we are not the last item then we need to add the comma
|
||||
// but it's important we do it here, after the length check
|
||||
if (!lastKey)
|
||||
returnString += ',';
|
||||
}
|
||||
}
|
||||
|
||||
void ParseUidString(const char *uidString, nsTArray<nsMsgKey> &keys)
|
||||
{
|
||||
// This is in the form <id>,<id>, or <id1>:<id2>
|
||||
if (!uidString)
|
||||
return;
|
||||
|
||||
char curChar = *uidString;
|
||||
bool isRange = false;
|
||||
uint32_t curToken;
|
||||
uint32_t saveStartToken = 0;
|
||||
|
||||
for (const char *curCharPtr = uidString; curChar && *curCharPtr;)
|
||||
{
|
||||
const char *currentKeyToken = curCharPtr;
|
||||
curChar = *curCharPtr;
|
||||
while (curChar != ':' && curChar != ',' && curChar != '\0')
|
||||
curChar = *curCharPtr++;
|
||||
|
||||
// we don't need to null terminate currentKeyToken because strtoul
|
||||
// stops at non-numeric chars.
|
||||
curToken = strtoul(currentKeyToken, nullptr, 10);
|
||||
if (isRange)
|
||||
{
|
||||
while (saveStartToken < curToken)
|
||||
keys.AppendElement(saveStartToken++);
|
||||
}
|
||||
keys.AppendElement(curToken);
|
||||
isRange = (curChar == ':');
|
||||
if (isRange)
|
||||
saveStartToken = curToken + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void AppendUid(nsCString &msgIds, uint32_t uid)
|
||||
{
|
||||
char buf[20];
|
||||
PR_snprintf(buf, sizeof(buf), "%u", uid);
|
||||
msgIds.Append(buf);
|
||||
}
|
||||
77
mailnews/imap/src/nsImapUtils.h
Normal file
77
mailnews/imap/src/nsImapUtils.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- 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_IMAPUTILS_H
|
||||
#define NS_IMAPUTILS_H
|
||||
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsIMsgIncomingServer.h"
|
||||
#include "MailNewsTypes.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIMailboxSpec.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsImapFlagAndUidState;
|
||||
class nsImapProtocol;
|
||||
|
||||
static const char kImapRootURI[] = "imap:/";
|
||||
static const char kImapMessageRootURI[] = "imap-message:/";
|
||||
static const char kModSeqPropertyName[] = "highestModSeq";
|
||||
static const char kHighestRecordedUIDPropertyName[] = "highestRecordedUID";
|
||||
static const char kDeletedHdrCountPropertyName[] = "numDeletedHeaders";
|
||||
|
||||
extern nsresult
|
||||
nsImapURI2FullName(const char* rootURI, const char* hostname, const char* uriStr,
|
||||
char **name);
|
||||
|
||||
extern nsresult
|
||||
nsParseImapMessageURI(const char* uri, nsCString& folderURI, uint32_t *key, char **part);
|
||||
|
||||
extern nsresult
|
||||
nsBuildImapMessageURI(const char *baseURI, uint32_t key, nsCString& uri);
|
||||
|
||||
extern nsresult
|
||||
nsCreateImapBaseMessageURI(const nsACString& baseURI, nsCString& baseMessageURI);
|
||||
|
||||
void AllocateImapUidString(uint32_t *msgUids, uint32_t &msgCount, nsImapFlagAndUidState *flagState, nsCString &returnString);
|
||||
void ParseUidString(const char *uidString, nsTArray<nsMsgKey> &keys);
|
||||
void AppendUid(nsCString &msgIds, uint32_t uid);
|
||||
|
||||
class nsImapMailboxSpec : public nsIMailboxSpec
|
||||
{
|
||||
public:
|
||||
nsImapMailboxSpec();
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIMAILBOXSPEC
|
||||
|
||||
nsImapMailboxSpec& operator= (const nsImapMailboxSpec& aCopy);
|
||||
|
||||
nsCOMPtr<nsIImapFlagAndUidState> mFlagState;
|
||||
nsIMAPNamespace *mNamespaceForFolder;
|
||||
|
||||
uint32_t mBoxFlags;
|
||||
uint32_t mSupportedUserFlags;
|
||||
int32_t mFolder_UIDVALIDITY;
|
||||
uint64_t mHighestModSeq;
|
||||
int32_t mNumOfMessages;
|
||||
int32_t mNumOfUnseenMessages;
|
||||
int32_t mNumOfRecentMessages;
|
||||
int32_t mNextUID;
|
||||
nsCString mAllocatedPathName;
|
||||
nsCString mHostName;
|
||||
nsString mUnicharPathName;
|
||||
char mHierarchySeparator;
|
||||
bool mFolderSelected;
|
||||
bool mDiscoveredFromLsub;
|
||||
bool mOnlineVerified;
|
||||
|
||||
nsImapProtocol *mConnection; // do we need this? It seems evil
|
||||
|
||||
private:
|
||||
virtual ~nsImapMailboxSpec();
|
||||
};
|
||||
|
||||
#endif //NS_IMAPUTILS_H
|
||||
600
mailnews/imap/src/nsSyncRunnableHelpers.cpp
Normal file
600
mailnews/imap/src/nsSyncRunnableHelpers.cpp
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
/* 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 "nsSyncRunnableHelpers.h"
|
||||
#include "nsIMsgMailNewsUrl.h"
|
||||
#include "nsIMsgWindow.h"
|
||||
#include "nsImapMailFolder.h"
|
||||
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(StreamListenerProxy, nsIStreamListener)
|
||||
NS_IMPL_ISUPPORTS(ImapMailFolderSinkProxy, nsIImapMailFolderSink)
|
||||
NS_IMPL_ISUPPORTS(ImapServerSinkProxy, nsIImapServerSink)
|
||||
NS_IMPL_ISUPPORTS(ImapMessageSinkProxy,
|
||||
nsIImapMessageSink)
|
||||
NS_IMPL_ISUPPORTS(ImapProtocolSinkProxy,
|
||||
nsIImapProtocolSink)
|
||||
namespace {
|
||||
|
||||
// Traits class for a reference type, specialized for parameters which are
|
||||
// already references.
|
||||
template<typename T>
|
||||
struct RefType
|
||||
{
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct RefType<nsAString&>
|
||||
{
|
||||
typedef nsAString& type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct RefType<const nsAString&>
|
||||
{
|
||||
typedef const nsAString& type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct RefType<nsACString&>
|
||||
{
|
||||
typedef nsACString& type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct RefType<const nsACString&>
|
||||
{
|
||||
typedef const nsACString& type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct RefType<const nsIID&>
|
||||
{
|
||||
typedef const nsIID& type;
|
||||
};
|
||||
|
||||
class SyncRunnableBase : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
nsresult Result() {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
mozilla::Monitor& Monitor() {
|
||||
return mMonitor;
|
||||
}
|
||||
|
||||
protected:
|
||||
SyncRunnableBase()
|
||||
: mResult(NS_ERROR_UNEXPECTED)
|
||||
, mMonitor("SyncRunnableBase")
|
||||
{ }
|
||||
|
||||
nsresult mResult;
|
||||
mozilla::Monitor mMonitor;
|
||||
};
|
||||
|
||||
template<typename Receiver>
|
||||
class SyncRunnable0 : public SyncRunnableBase
|
||||
{
|
||||
public:
|
||||
typedef nsresult (NS_STDCALL Receiver::*ReceiverMethod)();
|
||||
|
||||
SyncRunnable0(Receiver* receiver, ReceiverMethod method)
|
||||
: mReceiver(receiver)
|
||||
, mMethod(method)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mResult = (mReceiver->*mMethod)();
|
||||
mozilla::MonitorAutoLock(mMonitor).Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
Receiver* mReceiver;
|
||||
ReceiverMethod mMethod;
|
||||
};
|
||||
|
||||
|
||||
template<typename Receiver, typename Arg1>
|
||||
class SyncRunnable1 : public SyncRunnableBase
|
||||
{
|
||||
public:
|
||||
typedef nsresult (NS_STDCALL Receiver::*ReceiverMethod)(Arg1);
|
||||
typedef typename RefType<Arg1>::type Arg1Ref;
|
||||
|
||||
SyncRunnable1(Receiver* receiver, ReceiverMethod method,
|
||||
Arg1Ref arg1)
|
||||
: mReceiver(receiver)
|
||||
, mMethod(method)
|
||||
, mArg1(arg1)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mResult = (mReceiver->*mMethod)(mArg1);
|
||||
mozilla::MonitorAutoLock(mMonitor).Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
Receiver* mReceiver;
|
||||
ReceiverMethod mMethod;
|
||||
Arg1Ref mArg1;
|
||||
};
|
||||
|
||||
template<typename Receiver, typename Arg1, typename Arg2>
|
||||
class SyncRunnable2 : public SyncRunnableBase
|
||||
{
|
||||
public:
|
||||
typedef nsresult (NS_STDCALL Receiver::*ReceiverMethod)(Arg1, Arg2);
|
||||
typedef typename RefType<Arg1>::type Arg1Ref;
|
||||
typedef typename RefType<Arg2>::type Arg2Ref;
|
||||
|
||||
SyncRunnable2(Receiver* receiver, ReceiverMethod method,
|
||||
Arg1Ref arg1, Arg2Ref arg2)
|
||||
: mReceiver(receiver)
|
||||
, mMethod(method)
|
||||
, mArg1(arg1)
|
||||
, mArg2(arg2)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mResult = (mReceiver->*mMethod)(mArg1, mArg2);
|
||||
mozilla::MonitorAutoLock(mMonitor).Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
Receiver* mReceiver;
|
||||
ReceiverMethod mMethod;
|
||||
Arg1Ref mArg1;
|
||||
Arg2Ref mArg2;
|
||||
};
|
||||
|
||||
template<typename Receiver, typename Arg1, typename Arg2, typename Arg3>
|
||||
class SyncRunnable3 : public SyncRunnableBase
|
||||
{
|
||||
public:
|
||||
typedef nsresult (NS_STDCALL Receiver::*ReceiverMethod)(Arg1, Arg2, Arg3);
|
||||
typedef typename RefType<Arg1>::type Arg1Ref;
|
||||
typedef typename RefType<Arg2>::type Arg2Ref;
|
||||
typedef typename RefType<Arg3>::type Arg3Ref;
|
||||
|
||||
SyncRunnable3(Receiver* receiver, ReceiverMethod method,
|
||||
Arg1Ref arg1, Arg2Ref arg2, Arg3Ref arg3)
|
||||
: mReceiver(receiver)
|
||||
, mMethod(method)
|
||||
, mArg1(arg1)
|
||||
, mArg2(arg2)
|
||||
, mArg3(arg3)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mResult = (mReceiver->*mMethod)(mArg1, mArg2, mArg3);
|
||||
mozilla::MonitorAutoLock(mMonitor).Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
Receiver* mReceiver;
|
||||
ReceiverMethod mMethod;
|
||||
Arg1Ref mArg1;
|
||||
Arg2Ref mArg2;
|
||||
Arg3Ref mArg3;
|
||||
};
|
||||
|
||||
template<typename Receiver, typename Arg1, typename Arg2, typename Arg3,
|
||||
typename Arg4>
|
||||
class SyncRunnable4 : public SyncRunnableBase
|
||||
{
|
||||
public:
|
||||
typedef nsresult (NS_STDCALL Receiver::*ReceiverMethod)(Arg1, Arg2, Arg3, Arg4);
|
||||
typedef typename RefType<Arg1>::type Arg1Ref;
|
||||
typedef typename RefType<Arg2>::type Arg2Ref;
|
||||
typedef typename RefType<Arg3>::type Arg3Ref;
|
||||
typedef typename RefType<Arg4>::type Arg4Ref;
|
||||
|
||||
SyncRunnable4(Receiver* receiver, ReceiverMethod method,
|
||||
Arg1Ref arg1, Arg2Ref arg2, Arg3Ref arg3, Arg4Ref arg4)
|
||||
: mReceiver(receiver)
|
||||
, mMethod(method)
|
||||
, mArg1(arg1)
|
||||
, mArg2(arg2)
|
||||
, mArg3(arg3)
|
||||
, mArg4(arg4)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mResult = (mReceiver->*mMethod)(mArg1, mArg2, mArg3, mArg4);
|
||||
mozilla::MonitorAutoLock(mMonitor).Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
Receiver* mReceiver;
|
||||
ReceiverMethod mMethod;
|
||||
Arg1Ref mArg1;
|
||||
Arg2Ref mArg2;
|
||||
Arg3Ref mArg3;
|
||||
Arg4Ref mArg4;
|
||||
};
|
||||
|
||||
template<typename Receiver, typename Arg1, typename Arg2, typename Arg3,
|
||||
typename Arg4, typename Arg5>
|
||||
class SyncRunnable5 : public SyncRunnableBase
|
||||
{
|
||||
public:
|
||||
typedef nsresult (NS_STDCALL Receiver::*ReceiverMethod)(Arg1, Arg2, Arg3, Arg4, Arg5);
|
||||
typedef typename RefType<Arg1>::type Arg1Ref;
|
||||
typedef typename RefType<Arg2>::type Arg2Ref;
|
||||
typedef typename RefType<Arg3>::type Arg3Ref;
|
||||
typedef typename RefType<Arg4>::type Arg4Ref;
|
||||
typedef typename RefType<Arg5>::type Arg5Ref;
|
||||
|
||||
SyncRunnable5(Receiver* receiver, ReceiverMethod method,
|
||||
Arg1Ref arg1, Arg2Ref arg2, Arg3Ref arg3, Arg4Ref arg4, Arg5Ref arg5)
|
||||
: mReceiver(receiver)
|
||||
, mMethod(method)
|
||||
, mArg1(arg1)
|
||||
, mArg2(arg2)
|
||||
, mArg3(arg3)
|
||||
, mArg4(arg4)
|
||||
, mArg5(arg5)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mResult = (mReceiver->*mMethod)(mArg1, mArg2, mArg3, mArg4, mArg5);
|
||||
mozilla::MonitorAutoLock(mMonitor).Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
Receiver* mReceiver;
|
||||
ReceiverMethod mMethod;
|
||||
Arg1Ref mArg1;
|
||||
Arg2Ref mArg2;
|
||||
Arg3Ref mArg3;
|
||||
Arg4Ref mArg4;
|
||||
Arg5Ref mArg5;
|
||||
};
|
||||
|
||||
nsresult
|
||||
DispatchSyncRunnable(SyncRunnableBase* r)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
r->Run();
|
||||
}
|
||||
else {
|
||||
mozilla::MonitorAutoLock lock(r->Monitor());
|
||||
nsresult rv = NS_DispatchToMainThread(r);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
lock.Wait();
|
||||
}
|
||||
return r->Result();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#define NS_SYNCRUNNABLEMETHOD0(iface, method) \
|
||||
NS_IMETHODIMP iface##Proxy::method() { \
|
||||
RefPtr<SyncRunnableBase> r = \
|
||||
new SyncRunnable0<nsI##iface> \
|
||||
(mReceiver, &nsI##iface::method); \
|
||||
return DispatchSyncRunnable(r); \
|
||||
}
|
||||
|
||||
|
||||
#define NS_SYNCRUNNABLEMETHOD1(iface, method, \
|
||||
arg1) \
|
||||
NS_IMETHODIMP iface##Proxy::method(arg1 a1) { \
|
||||
RefPtr<SyncRunnableBase> r = \
|
||||
new SyncRunnable1<nsI##iface, arg1> \
|
||||
(mReceiver, &nsI##iface::method, a1); \
|
||||
return DispatchSyncRunnable(r); \
|
||||
}
|
||||
|
||||
#define NS_SYNCRUNNABLEMETHOD2(iface, method, \
|
||||
arg1, arg2) \
|
||||
NS_IMETHODIMP iface##Proxy::method(arg1 a1, arg2 a2) { \
|
||||
RefPtr<SyncRunnableBase> r = \
|
||||
new SyncRunnable2<nsI##iface, arg1, arg2> \
|
||||
(mReceiver, &nsI##iface::method, a1, a2); \
|
||||
return DispatchSyncRunnable(r); \
|
||||
}
|
||||
|
||||
#define NS_SYNCRUNNABLEMETHOD3(iface, method, \
|
||||
arg1, arg2, arg3) \
|
||||
NS_IMETHODIMP iface##Proxy::method(arg1 a1, arg2 a2, arg3 a3) { \
|
||||
RefPtr<SyncRunnableBase> r = \
|
||||
new SyncRunnable3<nsI##iface, arg1, arg2, arg3> \
|
||||
(mReceiver, &nsI##iface::method, \
|
||||
a1, a2, a3); \
|
||||
return DispatchSyncRunnable(r); \
|
||||
}
|
||||
|
||||
#define NS_SYNCRUNNABLEMETHOD4(iface, method, \
|
||||
arg1, arg2, arg3, arg4) \
|
||||
NS_IMETHODIMP iface##Proxy::method(arg1 a1, arg2 a2, arg3 a3, arg4 a4) { \
|
||||
RefPtr<SyncRunnableBase> r = \
|
||||
new SyncRunnable4<nsI##iface, arg1, arg2, arg3, arg4> \
|
||||
(mReceiver, &nsI##iface::method, \
|
||||
a1, a2, a3, a4); \
|
||||
return DispatchSyncRunnable(r); \
|
||||
}
|
||||
|
||||
#define NS_SYNCRUNNABLEMETHOD5(iface, method, \
|
||||
arg1, arg2, arg3, arg4, arg5) \
|
||||
NS_IMETHODIMP iface##Proxy::method(arg1 a1, arg2 a2, arg3 a3, arg4 a4, arg5 a5) { \
|
||||
RefPtr<SyncRunnableBase> r = \
|
||||
new SyncRunnable5<nsI##iface, arg1, arg2, arg3, arg4, arg5> \
|
||||
(mReceiver, &nsI##iface::method, \
|
||||
a1, a2, a3, a4, a5); \
|
||||
return DispatchSyncRunnable(r); \
|
||||
}
|
||||
|
||||
#define NS_SYNCRUNNABLEATTRIBUTE(iface, attribute, \
|
||||
type) \
|
||||
NS_IMETHODIMP iface##Proxy::Get##attribute(type *a1) { \
|
||||
RefPtr<SyncRunnableBase> r = \
|
||||
new SyncRunnable1<nsI##iface, type *> \
|
||||
(mReceiver, &nsI##iface::Get##attribute, a1); \
|
||||
return DispatchSyncRunnable(r); \
|
||||
} \
|
||||
NS_IMETHODIMP iface##Proxy::Set##attribute(type a1) { \
|
||||
RefPtr<SyncRunnableBase> r = \
|
||||
new SyncRunnable1<nsI##iface, type> \
|
||||
(mReceiver, &nsI##iface::Set##attribute, a1); \
|
||||
return DispatchSyncRunnable(r); \
|
||||
}
|
||||
|
||||
|
||||
#define NS_NOTIMPLEMENTED \
|
||||
{ NS_RUNTIMEABORT("Not implemented"); return NS_ERROR_UNEXPECTED; }
|
||||
|
||||
NS_SYNCRUNNABLEMETHOD5(StreamListener, OnDataAvailable,
|
||||
nsIRequest *, nsISupports *, nsIInputStream *, uint64_t, uint32_t)
|
||||
|
||||
NS_SYNCRUNNABLEMETHOD2(StreamListener, OnStartRequest,
|
||||
nsIRequest *, nsISupports *)
|
||||
|
||||
NS_SYNCRUNNABLEMETHOD3(StreamListener, OnStopRequest,
|
||||
nsIRequest *, nsISupports *, nsresult)
|
||||
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapProtocolSink, GetUrlWindow, nsIMsgMailNewsUrl *,
|
||||
nsIMsgWindow **)
|
||||
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapProtocolSink, CloseStreams)
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapProtocolSink, SetupMainThreadProxies)
|
||||
|
||||
NS_SYNCRUNNABLEATTRIBUTE(ImapMailFolderSink, FolderNeedsACLListed, bool)
|
||||
NS_SYNCRUNNABLEATTRIBUTE(ImapMailFolderSink, FolderNeedsSubscribing, bool)
|
||||
NS_SYNCRUNNABLEATTRIBUTE(ImapMailFolderSink, FolderNeedsAdded, bool)
|
||||
NS_SYNCRUNNABLEATTRIBUTE(ImapMailFolderSink, AclFlags, uint32_t)
|
||||
NS_SYNCRUNNABLEATTRIBUTE(ImapMailFolderSink, UidValidity, int32_t)
|
||||
NS_SYNCRUNNABLEATTRIBUTE(ImapMailFolderSink, FolderQuotaCommandIssued, bool)
|
||||
NS_SYNCRUNNABLEMETHOD3(ImapMailFolderSink, SetFolderQuotaData, const nsACString &, uint32_t, uint32_t)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapMailFolderSink, GetShouldDownloadAllHeaders, bool *)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapMailFolderSink, GetOnlineDelimiter, char *)
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapMailFolderSink, OnNewIdleMessages)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, UpdateImapMailboxStatus, nsIImapProtocol *, nsIMailboxSpec *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, UpdateImapMailboxInfo, nsIImapProtocol *, nsIMailboxSpec *)
|
||||
NS_SYNCRUNNABLEMETHOD4(ImapMailFolderSink, GetMsgHdrsToDownload, bool *, int32_t *, uint32_t *, nsMsgKey **)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, ParseMsgHdrs, nsIImapProtocol *, nsIImapHeaderXferInfo *)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapMailFolderSink, AbortHeaderParseStream, nsIImapProtocol *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, OnlineCopyCompleted, nsIImapProtocol *, ImapOnlineCopyState)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapMailFolderSink, StartMessage, nsIMsgMailNewsUrl *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, EndMessage, nsIMsgMailNewsUrl *, nsMsgKey)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, NotifySearchHit, nsIMsgMailNewsUrl *, const char *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, CopyNextStreamMessage, bool, nsISupports *)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapMailFolderSink, CloseMockChannel, nsIImapMockChannel *)
|
||||
NS_SYNCRUNNABLEMETHOD5(ImapMailFolderSink, SetUrlState, nsIImapProtocol *, nsIMsgMailNewsUrl *,
|
||||
bool, bool, nsresult)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapMailFolderSink, ReleaseUrlCacheEntry, nsIMsgMailNewsUrl *)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapMailFolderSink, HeaderFetchCompleted, nsIImapProtocol *)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapMailFolderSink, SetBiffStateAndUpdate, int32_t)
|
||||
NS_SYNCRUNNABLEMETHOD3(ImapMailFolderSink, ProgressStatusString, nsIImapProtocol*, const char*, const char16_t *)
|
||||
NS_SYNCRUNNABLEMETHOD4(ImapMailFolderSink, PercentProgress, nsIImapProtocol*, const char16_t *, int64_t, int64_t)
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapMailFolderSink, ClearFolderRights)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, SetCopyResponseUid, const char *, nsIImapUrl *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, SetAppendMsgUid, nsMsgKey, nsIImapUrl *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMailFolderSink, GetMessageId, nsIImapUrl *, nsACString &)
|
||||
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMessageSink, SetupMsgWriteStream, nsIFile *, bool)
|
||||
NS_SYNCRUNNABLEMETHOD3(ImapMessageSink, ParseAdoptedMsgLine, const char *, nsMsgKey, nsIImapUrl *)
|
||||
NS_SYNCRUNNABLEMETHOD4(ImapMessageSink, NormalEndMsgWriteStream, nsMsgKey, bool, nsIImapUrl *, int32_t)
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapMessageSink, AbortMsgWriteStream)
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapMessageSink, BeginMessageUpload)
|
||||
NS_SYNCRUNNABLEMETHOD4(ImapMessageSink, NotifyMessageFlags, uint32_t, const nsACString &, nsMsgKey, uint64_t)
|
||||
NS_SYNCRUNNABLEMETHOD3(ImapMessageSink, NotifyMessageDeleted, const char *, bool, const char *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMessageSink, GetMessageSizeFromDB, const char *, uint32_t *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapMessageSink, SetContentModified, nsIImapUrl *, nsImapContentModifiedType)
|
||||
NS_SYNCRUNNABLEMETHOD4(ImapMessageSink, GetCurMoveCopyMessageInfo, nsIImapUrl *, PRTime *, nsACString &, uint32_t *)
|
||||
|
||||
NS_SYNCRUNNABLEMETHOD4(ImapServerSink, PossibleImapMailbox, const nsACString &, char, int32_t, bool *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, FolderNeedsACLInitialized, const nsACString &, bool *)
|
||||
NS_SYNCRUNNABLEMETHOD3(ImapServerSink, AddFolderRights, const nsACString &, const nsACString &, const nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, RefreshFolderRights, const nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapServerSink, DiscoveryDone)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, OnlineFolderDelete, const nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, OnlineFolderCreateFailed, const nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD3(ImapServerSink, OnlineFolderRename, nsIMsgWindow *, const nsACString &, const nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, FolderIsNoSelect, const nsACString &, bool *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, SetFolderAdminURL, const nsACString &, const nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, FolderVerifiedOnline, const nsACString &, bool *)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SetCapability, eIMAPCapabilityFlags)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SetServerID, const nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, LoadNextQueuedUrl, nsIImapProtocol *, bool *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, PrepareToRetryUrl, nsIImapUrl *, nsIImapMockChannel **)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SuspendUrl, nsIImapUrl *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, RetryUrl, nsIImapUrl *, nsIImapMockChannel *)
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapServerSink, AbortQueuedUrls)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, GetImapStringByName, const char*, nsAString &)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, PromptLoginFailed, nsIMsgWindow *, int32_t *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, FEAlert, const nsAString &, nsIMsgMailNewsUrl *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, FEAlertWithName, const char*, nsIMsgMailNewsUrl *)
|
||||
NS_SYNCRUNNABLEMETHOD2(ImapServerSink, FEAlertFromServer, const nsACString &, nsIMsgMailNewsUrl *)
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapServerSink, CommitNamespaces)
|
||||
NS_SYNCRUNNABLEMETHOD3(ImapServerSink, AsyncGetPassword, nsIImapProtocol *, bool, nsACString &)
|
||||
NS_SYNCRUNNABLEATTRIBUTE(ImapServerSink, UserAuthenticated, bool)
|
||||
NS_SYNCRUNNABLEMETHOD3(ImapServerSink, SetMailServerUrls, const nsACString &, const nsACString &, const nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetArbitraryHeaders, nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD0(ImapServerSink, ForgetPassword)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetShowAttachmentsInline, bool *)
|
||||
NS_SYNCRUNNABLEMETHOD3(ImapServerSink, CramMD5Hash, const char *, const char *, char **)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetLoginUsername, nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, UpdateTrySTARTTLSPref, bool)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetOriginalUsername, nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetServerKey, nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetServerPassword, nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, RemoveServerConnection, nsIImapProtocol *)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetServerShuttingDown, bool *)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, ResetServerConnection, const nsACString &)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SetServerDoingLsub, bool)
|
||||
NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SetServerForceSelect, const nsACString &)
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
namespace mailnews {
|
||||
|
||||
NS_IMPL_ISUPPORTS(OAuth2ThreadHelper, msgIOAuth2ModuleListener)
|
||||
|
||||
OAuth2ThreadHelper::OAuth2ThreadHelper(nsIMsgIncomingServer *aServer)
|
||||
: mMonitor("OAuth thread lock"),
|
||||
mServer(aServer)
|
||||
{
|
||||
}
|
||||
|
||||
OAuth2ThreadHelper::~OAuth2ThreadHelper()
|
||||
{
|
||||
if (mOAuth2Support)
|
||||
{
|
||||
NS_ReleaseOnMainThread(mOAuth2Support.forget());
|
||||
}
|
||||
}
|
||||
|
||||
bool OAuth2ThreadHelper::SupportsOAuth2()
|
||||
{
|
||||
// Acquire a lock early, before reading anything. Guarantees memory visibility
|
||||
// issues.
|
||||
MonitorAutoLock lockGuard(mMonitor);
|
||||
|
||||
// If we don't have a server, we can't init, and therefore, we don't support
|
||||
// OAuth2.
|
||||
if (!mServer)
|
||||
return false;
|
||||
|
||||
// If we have this, then we support OAuth2.
|
||||
if (mOAuth2Support)
|
||||
return true;
|
||||
|
||||
// Initialize. This needs to be done on-main-thread: if we're off that thread,
|
||||
// synchronously dispatch to the main thread.
|
||||
if (NS_IsMainThread())
|
||||
{
|
||||
MonitorAutoUnlock lockGuard(mMonitor);
|
||||
Init();
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runInit =
|
||||
NewRunnableMethod(this, &OAuth2ThreadHelper::Init);
|
||||
NS_DispatchToMainThread(runInit);
|
||||
mMonitor.Wait();
|
||||
}
|
||||
|
||||
// After synchronously initializing, if we didn't get an object, then we don't
|
||||
// support XOAuth2.
|
||||
return mOAuth2Support != nullptr;
|
||||
}
|
||||
|
||||
void OAuth2ThreadHelper::GetXOAuth2String(nsACString &base64Str)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "This method cannot run on the main thread");
|
||||
|
||||
// Acquire a lock early, before reading anything. Guarantees memory visibility
|
||||
// issues.
|
||||
MonitorAutoLock lockGuard(mMonitor);
|
||||
|
||||
// Umm... what are you trying to do?
|
||||
if (!mOAuth2Support)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIRunnable> runInit =
|
||||
NewRunnableMethod(this, &OAuth2ThreadHelper::Connect);
|
||||
NS_DispatchToMainThread(runInit);
|
||||
mMonitor.Wait();
|
||||
|
||||
// Now we either have the string, or we failed (in which case the string is
|
||||
// empty).
|
||||
base64Str = mOAuth2String;
|
||||
}
|
||||
|
||||
void OAuth2ThreadHelper::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Can't touch JS off-main-thread");
|
||||
MonitorAutoLock lockGuard(mMonitor);
|
||||
|
||||
// Create the OAuth2 helper module and initialize it. If the preferences are
|
||||
// not set up on this server, we don't support OAuth2, and we nullify our
|
||||
// members to indicate this.
|
||||
mOAuth2Support = do_CreateInstance(MSGIOAUTH2MODULE_CONTRACTID);
|
||||
if (mOAuth2Support)
|
||||
{
|
||||
bool supportsOAuth = false;
|
||||
mOAuth2Support->InitFromMail(mServer, &supportsOAuth);
|
||||
if (!supportsOAuth)
|
||||
mOAuth2Support = nullptr;
|
||||
}
|
||||
|
||||
// There is now no longer any need for the server. Kill it now--this helps
|
||||
// prevent us from maintaining a refcount cycle.
|
||||
mServer = nullptr;
|
||||
|
||||
// Notify anyone waiting that we're done.
|
||||
mMonitor.Notify();
|
||||
}
|
||||
|
||||
void OAuth2ThreadHelper::Connect()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Can't touch JS off-main-thread");
|
||||
MOZ_ASSERT(mOAuth2Support, "Should not be here if no OAuth2 support");
|
||||
|
||||
// OK to delay lock since mOAuth2Support is only written on main thread.
|
||||
nsresult rv = mOAuth2Support->Connect(true, this);
|
||||
// If the method failed, we'll never get a callback, so notify the monitor
|
||||
// immediately so that IMAP can react.
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
MonitorAutoLock lockGuard(mMonitor);
|
||||
mMonitor.Notify();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult OAuth2ThreadHelper::OnSuccess(const nsACString &aAccessToken)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Can't touch JS off-main-thread");
|
||||
MonitorAutoLock lockGuard(mMonitor);
|
||||
|
||||
MOZ_ASSERT(mOAuth2Support, "Should not be here if no OAuth2 support");
|
||||
mOAuth2Support->BuildXOAuth2String(mOAuth2String);
|
||||
mMonitor.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult OAuth2ThreadHelper::OnFailure(nsresult aError)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Can't touch JS off-main-thread");
|
||||
MonitorAutoLock lockGuard(mMonitor);
|
||||
|
||||
mOAuth2String.Truncate();
|
||||
mMonitor.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mailnews
|
||||
} // namespace mozilla
|
||||
146
mailnews/imap/src/nsSyncRunnableHelpers.h
Normal file
146
mailnews/imap/src/nsSyncRunnableHelpers.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/* 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 nsSyncRunnableHelpers_h
|
||||
#define nsSyncRunnableHelpers_h
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "msgIOAuth2Module.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIImapMailFolderSink.h"
|
||||
#include "nsIImapServerSink.h"
|
||||
#include "nsIImapProtocolSink.h"
|
||||
#include "nsIImapMessageSink.h"
|
||||
|
||||
// The classes in this file proxy method calls to the main thread
|
||||
// synchronously. The main thread must not block on this thread, or a
|
||||
// deadlock condition can occur.
|
||||
|
||||
class StreamListenerProxy final : public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
StreamListenerProxy(nsIStreamListener* receiver)
|
||||
: mReceiver(receiver)
|
||||
{ }
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
private:
|
||||
~StreamListenerProxy() {
|
||||
NS_ReleaseOnMainThread(mReceiver.forget());
|
||||
}
|
||||
nsCOMPtr<nsIStreamListener> mReceiver;
|
||||
};
|
||||
|
||||
class ImapMailFolderSinkProxy final : public nsIImapMailFolderSink
|
||||
{
|
||||
public:
|
||||
ImapMailFolderSinkProxy(nsIImapMailFolderSink* receiver)
|
||||
: mReceiver(receiver)
|
||||
{
|
||||
NS_ASSERTION(receiver, "Don't allow receiver is nullptr");
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIMAPMAILFOLDERSINK
|
||||
|
||||
private:
|
||||
~ImapMailFolderSinkProxy() {
|
||||
NS_ReleaseOnMainThread(mReceiver.forget());
|
||||
}
|
||||
nsCOMPtr<nsIImapMailFolderSink> mReceiver;
|
||||
};
|
||||
|
||||
class ImapServerSinkProxy final : public nsIImapServerSink
|
||||
{
|
||||
public:
|
||||
ImapServerSinkProxy(nsIImapServerSink* receiver)
|
||||
: mReceiver(receiver)
|
||||
{ }
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIMAPSERVERSINK
|
||||
|
||||
private:
|
||||
~ImapServerSinkProxy() {
|
||||
NS_ReleaseOnMainThread(mReceiver.forget());
|
||||
}
|
||||
nsCOMPtr<nsIImapServerSink> mReceiver;
|
||||
};
|
||||
|
||||
|
||||
class ImapMessageSinkProxy final : public nsIImapMessageSink
|
||||
{
|
||||
public:
|
||||
ImapMessageSinkProxy(nsIImapMessageSink* receiver)
|
||||
: mReceiver(receiver)
|
||||
{ }
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIMAPMESSAGESINK
|
||||
|
||||
private:
|
||||
~ImapMessageSinkProxy() {
|
||||
NS_ReleaseOnMainThread(mReceiver.forget());
|
||||
}
|
||||
nsCOMPtr<nsIImapMessageSink> mReceiver;
|
||||
};
|
||||
|
||||
class ImapProtocolSinkProxy final : public nsIImapProtocolSink
|
||||
{
|
||||
public:
|
||||
ImapProtocolSinkProxy(nsIImapProtocolSink* receiver)
|
||||
: mReceiver(receiver)
|
||||
{ }
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIMAPPROTOCOLSINK
|
||||
|
||||
private:
|
||||
~ImapProtocolSinkProxy() {
|
||||
NS_ReleaseOnMainThread(mReceiver.forget());
|
||||
}
|
||||
nsCOMPtr<nsIImapProtocolSink> mReceiver;
|
||||
};
|
||||
|
||||
class msgIOAuth2Module;
|
||||
class nsIMsgIncomingServer;
|
||||
class nsIVariant;
|
||||
class nsIWritableVariant;
|
||||
|
||||
namespace mozilla {
|
||||
namespace mailnews {
|
||||
|
||||
class OAuth2ThreadHelper final : public msgIOAuth2ModuleListener
|
||||
{
|
||||
public:
|
||||
OAuth2ThreadHelper(nsIMsgIncomingServer *aServer);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MSGIOAUTH2MODULELISTENER
|
||||
|
||||
bool SupportsOAuth2();
|
||||
void GetXOAuth2String(nsACString &base64Str);
|
||||
|
||||
private:
|
||||
~OAuth2ThreadHelper();
|
||||
void Init();
|
||||
void Connect();
|
||||
|
||||
Monitor mMonitor;
|
||||
nsCOMPtr<msgIOAuth2Module> mOAuth2Support;
|
||||
nsCOMPtr<nsIMsgIncomingServer> mServer;
|
||||
nsCString mOAuth2String;
|
||||
};
|
||||
|
||||
} // namespace mailnews
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // nsSyncRunnableHelpers_h
|
||||
Loading…
Add table
Add a link
Reference in a new issue