Source code

Revision control

Copy as Markdown

Other Tools

/* 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 "nsComponentManagerUtils.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_SYNCRUNNABLEMETHOD4(ImapMailFolderSink, PercentProgress, nsIImapProtocol*,
nsACString 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& aBearerToken) {
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 = aBearerToken;
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