diff options
Diffstat (limited to 'mailnews/imap/src/nsSyncRunnableHelpers.cpp')
-rw-r--r-- | mailnews/imap/src/nsSyncRunnableHelpers.cpp | 600 |
1 files changed, 600 insertions, 0 deletions
diff --git a/mailnews/imap/src/nsSyncRunnableHelpers.cpp b/mailnews/imap/src/nsSyncRunnableHelpers.cpp new file mode 100644 index 000000000..ec547eb91 --- /dev/null +++ b/mailnews/imap/src/nsSyncRunnableHelpers.cpp @@ -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 |