diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mailnews/imap/src/nsSyncRunnableHelpers.cpp | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/mailnews/imap/src/nsSyncRunnableHelpers.cpp')
-rw-r--r-- | comm/mailnews/imap/src/nsSyncRunnableHelpers.cpp | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/comm/mailnews/imap/src/nsSyncRunnableHelpers.cpp b/comm/mailnews/imap/src/nsSyncRunnableHelpers.cpp new file mode 100644 index 0000000000..14028fef03 --- /dev/null +++ b/comm/mailnews/imap/src/nsSyncRunnableHelpers.cpp @@ -0,0 +1,596 @@ +/* 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 "nsImapCore.h" +#include "nsIMsgMailNewsUrl.h" +#include "nsIMsgIncomingServer.h" +#include "nsIMsgWindow.h" +#include "nsIImapMailFolderSink.h" + +#include "mozilla/ClearOnShutdown.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() + : mozilla::Runnable("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_SYNCRUNNABLEMETHOD4(StreamListener, OnDataAvailable, nsIRequest*, + nsIInputStream*, uint64_t, uint32_t) + +NS_SYNCRUNNABLEMETHOD1(StreamListener, OnStartRequest, nsIRequest*) + +NS_SYNCRUNNABLEMETHOD2(StreamListener, OnStopRequest, nsIRequest*, 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_SYNCRUNNABLEMETHOD4(ImapMailFolderSink, SetFolderQuotaData, uint32_t, + const nsACString&, uint64_t, uint64_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_SYNCRUNNABLEMETHOD3(ImapMailFolderSink, GetMsgHdrsToDownload, bool*, + int32_t*, nsTArray<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_SYNCRUNNABLEMETHOD5(ImapMailFolderSink, PercentProgress, nsIImapProtocol*, + nsACString const&, nsAString const&, 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_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, + nsAString&) +NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SyncGetPassword, nsAString&) +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, nsAString&) +NS_SYNCRUNNABLEMETHOD1(ImapServerSink, RemoveServerConnection, nsIImapProtocol*) +NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetServerShuttingDown, bool*) +NS_SYNCRUNNABLEMETHOD1(ImapServerSink, ResetServerConnection, const nsACString&) +NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SetServerDoingLsub, bool) +NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SetServerUtf8AcceptEnabled, bool) + +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("OAuth2ThreadHelper::mOAuth2Support", + 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( + "OAuth2ThreadHelper::SupportsOAuth2", this, &OAuth2ThreadHelper::Init); + nsresult rv = NS_DispatchToMainThread(runInit); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + 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("OAuth2ThreadHelper::GetXOAuth2String", this, + &OAuth2ThreadHelper::Connect); + nsresult rv = NS_DispatchToMainThread(runInit); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + mMonitor.Wait(); + + nsCOMPtr<nsIRunnable> shutdownNotify = NS_NewRunnableFunction( + "GetXOAuth2StringShutdownNotifier", [self = RefPtr(this)]() { + mozilla::RunOnShutdown([self]() { + // Notify anyone waiting that we're done. + self->mMonitor.Notify(); + }); + }); + rv = NS_DispatchToMainThread(shutdownNotify.forget()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + // 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& aOAuth2String) { + 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"); + mOAuth2String = aOAuth2String; + 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 |