Bug 1211292 - Return Promise in nsIMsgSend and nsIMsgCompose. r=mkmelin

This commit is contained in:
Ping Chen 2020-10-16 13:36:07 +03:00
Родитель ff34fa3e57
Коммит 9632f42ffd
17 изменённых файлов: 124 добавлений и 135 удалений

Просмотреть файл

@ -4553,7 +4553,7 @@ function GenericSendMessage(msgType) {
* GenericSendMessage, or if GenericSendMessage was interrupted by your code.
* @param msgType nsIMsgCompDeliverMode of the operation.
*/
function CompleteGenericSendMessage(msgType) {
async function CompleteGenericSendMessage(msgType) {
// hook for extra compose pre-processing
Services.obs.notifyObservers(window, "mail:composeOnSend");
@ -4606,7 +4606,7 @@ function CompleteGenericSendMessage(msgType) {
}
msgWindow.domWindow = window;
msgWindow.rootDocShell.allowAuth = true;
gMsgCompose.SendMsg(
await gMsgCompose.sendMsg(
msgType,
getCurrentIdentity(),
getCurrentAccountKey(),

Просмотреть файл

@ -114,7 +114,7 @@ interface nsIMsgCompose : nsIMsgSendListener {
void UnregisterStateListener(in nsIMsgComposeStateListener stateListener);
/* ... */
void SendMsg(in MSG_DeliverMode deliverMode, in nsIMsgIdentity identity, in string accountKey, in nsIMsgWindow aMsgWindow, in nsIMsgProgress progress);
Promise sendMsg(in MSG_DeliverMode deliverMode, in nsIMsgIdentity identity, in string accountKey, in nsIMsgWindow aMsgWindow, in nsIMsgProgress progress);
/**
* After all Compose preparations are complete, send the prepared message to
@ -125,9 +125,9 @@ interface nsIMsgCompose : nsIMsgSendListener {
* @param identity The message identity.
* @param accountKey The message account key.
*/
void sendMsgToServer(in MSG_DeliverMode deliverMode,
in nsIMsgIdentity identity,
in string accountKey);
Promise sendMsgToServer(in MSG_DeliverMode deliverMode,
in nsIMsgIdentity identity,
in string accountKey);
/* ... */
void CloseWindow();

Просмотреть файл

@ -194,8 +194,6 @@ interface nsIMsgSend : nsISupports
* @param aMsgToReplace e.g., when saving a draft over an old draft. May be 0
* @param aBodyType content type of message body
* @param aBody message body text (should have native line endings)
* @param aAttachments Array of nsIMsgAttachmentData
* @param aPreloadedAttachments Array of nsIMsgAttachedFile
* @param aParentWindow compose window; may be null.
* @param aProgress where to send progress info; may be null.
* @param aListener optional listener for send progress
@ -203,24 +201,22 @@ interface nsIMsgSend : nsISupports
* @param aOriginalMsgURI may be null.
* @param aType see nsIMsgComposeParams.idl
*/
void createAndSendMessage(in nsIEditor aEditor,
in nsIMsgIdentity aUserIdentity,
in string aAccountKey,
in nsIMsgCompFields aFields,
in boolean aIsDigest,
in boolean aDontDeliver,
in nsMsgDeliverMode aMode,
in nsIMsgDBHdr aMsgToReplace,
in string aBodyType,
in ACString aBody,
in nsIArray aAttachments,
in nsIArray aPreloadedAttachments,
in mozIDOMWindowProxy aParentWindow,
in nsIMsgProgress aProgress,
in nsIMsgSendListener aListener,
in AString aPassword,
in AUTF8String aOriginalMsgURI,
in MSG_ComposeType aType);
Promise createAndSendMessage(in nsIEditor aEditor,
in nsIMsgIdentity aUserIdentity,
in string aAccountKey,
in nsIMsgCompFields aFields,
in boolean aIsDigest,
in boolean aDontDeliver,
in nsMsgDeliverMode aMode,
in nsIMsgDBHdr aMsgToReplace,
in string aBodyType,
in ACString aBody,
in mozIDOMWindowProxy aParentWindow,
in nsIMsgProgress aProgress,
in nsIMsgSendListener aListener,
in AString aPassword,
in AUTF8String aOriginalMsgURI,
in MSG_ComposeType aType);
/**
* Creates a file containing an rfc822 message, using the passed information.
@ -264,7 +260,7 @@ interface nsIMsgSend : nsISupports
* @param aDeleteSendFileOnCompletion
* Set to true if you want the send file deleted once
* the message has been sent.
* @param aDigest_p If this is a multipart message, this param
* @param aDigest If this is a multipart message, this param
* specifies whether the message is in digest or mixed
* format.
* @param aMode The delivery mode for sending the message (see
@ -282,18 +278,18 @@ interface nsIMsgSend : nsISupports
* @param aPassword Pass this in to prevent a dialog if the password
* is needed for secure transmission.
*/
void sendMessageFile(in nsIMsgIdentity aUserIdentity,
in string aAccountKey,
in nsIMsgCompFields aFields,
in nsIFile aSendIFile,
in boolean aDeleteSendFileOnCompletion,
in boolean aDigest_p,
in nsMsgDeliverMode aMode,
in nsIMsgDBHdr aMsgToReplace,
in nsIMsgSendListener aListener,
in nsIMsgStatusFeedback aStatusFeedback,
in wstring aPassword
);
Promise sendMessageFile(in nsIMsgIdentity aUserIdentity,
in string aAccountKey,
in nsIMsgCompFields aFields,
in nsIFile aSendIFile,
in boolean aDeleteSendFileOnCompletion,
in boolean aDigest,
in nsMsgDeliverMode aMode,
in nsIMsgDBHdr aMsgToReplace,
in nsIMsgSendListener aListener,
in nsIMsgStatusFeedback aStatusFeedback,
in wstring aPassword
);
/* Abort current send/save operation */
void abort();

Просмотреть файл

@ -31,7 +31,7 @@ MessageSend.prototype = {
QueryInterface: ChromeUtils.generateQI(["nsIMsgSend"]),
classID: Components.ID("{028b9c1e-8d0a-4518-80c2-842e07846eaa}"),
createAndSendMessage(
async createAndSendMessage(
editor,
userIdentity,
accountKey,
@ -42,8 +42,6 @@ MessageSend.prototype = {
msgToReplace,
bodyType,
body,
attachments,
preloadedAttachments,
parentWindow,
progress,
listener,
@ -108,11 +106,15 @@ MessageSend.prototype = {
this._messageKey = nsMsgKey_None;
// nsMsgCompose will do some cleanups depending if the return value of
// createAndSendMessage is not 0, this required createAndSendMessage to run
// synchonously.
// TODO: update nsIMsgSend.idl to return Promise.
this._runPromise(this._createAndSendMessage());
// Create a local file from MimeMessage, then pass it to _deliverMessage.
this._setStatusMessage(
this._composeBundle.GetStringFromName("creatingMailMessage")
);
let messageFile = await this._message.createMessageFile();
this._setStatusMessage(
this._composeBundle.GetStringFromName("assemblingMessageDone")
);
return this._deliverMessage(messageFile);
},
sendMessageFile(
@ -165,7 +167,7 @@ MessageSend.prototype = {
// nsMsgKey_None from MailNewsTypes.h.
this._messageKey = 0xffffffff;
this._runPromise(this._deliverMessage(messageFile));
return this._deliverMessage(messageFile);
},
abort() {
@ -482,20 +484,6 @@ MessageSend.prototype = {
return this._sendReport;
},
/**
* Create a local file from MimeMessage, then pass it to _deliverMessage.
*/
async _createAndSendMessage() {
this._setStatusMessage(
this._composeBundle.GetStringFromName("creatingMailMessage")
);
let messageFile = await this._message.createMessageFile();
this._setStatusMessage(
this._composeBundle.GetStringFromName("assemblingMessageDone")
);
return this._deliverMessage(messageFile);
},
_setStatusMessage(msg) {
if (this._sendProgress) {
this._sendProgress.onStatusChange(null, null, Cr.NS_OK, msg);
@ -965,18 +953,6 @@ MessageSend.prototype = {
new TextEncoder().encode(bodyText)
);
},
/**
* A wrapper of MsgUtils.syncPromise to run a promise synchonously.
* @param {Promise} promise - the promise to run
*/
_runPromise(promise) {
let e = MsgUtils.syncPromise(promise);
if (e && e.result != 0) {
this._sendReport.setError(Ci.nsIMsgSendReport.process_Current, e, false);
throw Components.Exception("_runPromise failed", e.result);
}
},
};
/**

Просмотреть файл

@ -1049,34 +1049,4 @@ var MsgUtils = {
.split("?")[0]
.split("#")[0];
},
/**
* Synchronize a promise: wait synchonously until a promise has completed and
* return the value that the promise returned. This is a temporary workaround,
* avoid using it if possible.
* TODO: remove this hack by returning Promise in nsIMsgSend.idl.
* @param {Promise} promise - the promise to wait for
*
* @return {Variant} whatever the promise returns
*/
syncPromise(promise) {
let inspector = Cc["@mozilla.org/jsinspector;1"].createInstance(
Ci.nsIJSInspector
);
let res = null;
promise
.then(gotResult => {
res = gotResult;
inspector.exitNestedEventLoop();
})
.catch(gotResult => {
console.log("syncPromise failed result: %o", gotResult);
res = gotResult;
inspector.exitNestedEventLoop();
});
inspector.enterNestedEventLoop(0);
return res;
},
};

Просмотреть файл

@ -70,6 +70,7 @@
#include "mozilla/dom/HTMLAnchorElement.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/Utf8.h"
#include "nsStreamConverter.h"
#include "nsIObserverService.h"
@ -1090,8 +1091,8 @@ NS_IMETHODIMP nsMsgCompose::RemoveMsgSendListener(
NS_IMETHODIMP
nsMsgCompose::SendMsgToServer(MSG_DeliverMode deliverMode,
nsIMsgIdentity* identity,
const char* accountKey) {
nsIMsgIdentity* identity, const char* accountKey,
Promise** aPromise) {
nsresult rv = NS_OK;
// clear saved message id if sending, so we don't send out the same
@ -1182,20 +1183,19 @@ nsMsgCompose::SendMsgToServer(MSG_DeliverMode deliverMode,
//
nsCOMPtr<nsIMsgSendListener> sendListener =
do_QueryInterface(composeSendListener);
RefPtr<mozilla::dom::Promise> promise;
rv = mMsgSend->CreateAndSendMessage(
m_composeHTML ? m_editor.get() : nullptr, identity, accountKey,
m_compFields, false, false, (nsMsgDeliverMode)deliverMode, nullptr,
m_composeHTML ? TEXT_HTML : TEXT_PLAIN, bodyString, nullptr, nullptr,
m_window, mProgress, sendListener, mSmtpPassword, mOriginalMsgURI,
mType);
m_composeHTML ? TEXT_HTML : TEXT_PLAIN, bodyString, m_window,
mProgress, sendListener, mSmtpPassword, mOriginalMsgURI, mType,
getter_AddRefs(promise));
promise.forget(aPromise);
} else
rv = NS_ERROR_FAILURE;
} else
rv = NS_ERROR_NOT_INITIALIZED;
if (NS_FAILED(rv))
NotifyStateListeners(nsIMsgComposeNotificationType::ComposeProcessDone, rv);
return rv;
}
@ -1203,7 +1203,8 @@ NS_IMETHODIMP nsMsgCompose::SendMsg(MSG_DeliverMode deliverMode,
nsIMsgIdentity* identity,
const char* accountKey,
nsIMsgWindow* aMsgWindow,
nsIMsgProgress* progress) {
nsIMsgProgress* progress,
Promise** aPromise) {
NS_ENSURE_TRUE(m_compFields, NS_ERROR_NOT_INITIALIZED);
nsresult rv = NS_OK;
nsCOMPtr<nsIPrompt> prompt;
@ -1346,8 +1347,12 @@ NS_IMETHODIMP nsMsgCompose::SendMsg(MSG_DeliverMode deliverMode,
// Save the identity being sent for later use.
m_identity = identity;
rv = SendMsgToServer(deliverMode, identity, accountKey);
if (NS_FAILED(rv)) {
RefPtr<mozilla::dom::Promise> promise;
rv = SendMsgToServer(deliverMode, identity, accountKey,
getter_AddRefs(promise));
auto handleFailure = [&](nsresult rv) {
NotifyStateListeners(nsIMsgComposeNotificationType::ComposeProcessDone, rv);
nsCOMPtr<nsIMsgSendReport> sendReport;
if (mMsgSend) mMsgSend->GetSendReport(getter_AddRefs(sendReport));
if (sendReport) {
@ -1373,8 +1378,14 @@ NS_IMETHODIMP nsMsgCompose::SendMsg(MSG_DeliverMode deliverMode,
break;
}
}
if (progress) progress->CloseProgressDialog(true);
if (mProgress) mProgress->CloseProgressDialog(true);
};
if (promise) {
new DomPromiseListener(
promise, [](JSContext*, JS::Handle<JS::Value>) {}, handleFailure);
promise.forget(aPromise);
} else if (NS_FAILED(rv)) {
handleFailure(rv);
}
return rv;

Просмотреть файл

@ -746,8 +746,9 @@ NS_IMETHODIMP nsMsgTemplateReplyHelper::OnStopRunningUrl(nsIURI* aUrl,
rv = pMsgCompose->Initialize(pMsgComposeParams, parentWindow, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<mozilla::dom::Promise> promise;
return pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, mIdentity, nullptr,
nullptr, nullptr);
nullptr, nullptr, getter_AddRefs(promise));
}
NS_IMETHODIMP
@ -1013,8 +1014,9 @@ nsMsgComposeService::ForwardMessage(const nsAString& forwardTo,
rv = pMsgCompose->Initialize(pMsgComposeParams, parentWindow, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<mozilla::dom::Promise> promise;
rv = pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, identity, nullptr,
nullptr, nullptr);
nullptr, nullptr, getter_AddRefs(promise));
NS_ENSURE_SUCCESS(rv, rv);
// nsMsgCompose::ProcessReplyFlags usually takes care of marking messages

Просмотреть файл

@ -3647,10 +3647,10 @@ nsMsgComposeAndSend::CreateAndSendMessage(
nsIMsgCompFields* fields, bool digest_p, bool dont_deliver_p,
nsMsgDeliverMode mode, nsIMsgDBHdr* msgToReplace,
const char* attachment1_type, const nsACString& attachment1_body,
nsIArray* attachments, nsIArray* preloaded_attachments,
mozIDOMWindowProxy* parentWindow, nsIMsgProgress* progress,
nsIMsgSendListener* aListener, const nsAString& password,
const nsACString& aOriginalMsgURI, MSG_ComposeType aType) {
const nsACString& aOriginalMsgURI, MSG_ComposeType aType,
Promise** aPromise) {
nsCOMPtr<nsIMsgSend> kungFuDeathGrip(this);
nsresult rv;
@ -3667,13 +3667,27 @@ nsMsgComposeAndSend::CreateAndSendMessage(
rv = Init(aUserIdentity, aAccountKey, (nsMsgCompFields*)fields, nullptr,
digest_p, dont_deliver_p, mode, msgToReplace, attachment1_type,
attachment1_body, attachments, preloaded_attachments, password,
aOriginalMsgURI, aType);
attachment1_body, nullptr, nullptr, password, aOriginalMsgURI,
aType);
if (NS_FAILED(rv) && mSendReport)
mSendReport->SetError(nsIMsgSendReport::process_Current, rv, false);
return rv;
nsCOMPtr<nsIGlobalObject> global =
xpc::NativeGlobal(xpc::PrivilegedJunkScope());
ErrorResult er;
RefPtr<Promise> retPromise = Promise::Create(global, er);
nsresult rv2 = er.StealNSResult();
NS_ENSURE_SUCCESS(rv2, rv2);
if (NS_SUCCEEDED(rv)) {
retPromise->MaybeResolve(0);
} else {
retPromise->MaybeReject(rv);
}
retPromise.forget(aPromise);
return rv2;
}
NS_IMETHODIMP
@ -3712,7 +3726,8 @@ nsresult nsMsgComposeAndSend::SendMessageFile(
nsIMsgCompFields* fields, nsIFile* sendIFile,
bool deleteSendFileOnCompletion, bool digest_p, nsMsgDeliverMode mode,
nsIMsgDBHdr* msgToReplace, nsIMsgSendListener* aListener,
nsIMsgStatusFeedback* aStatusFeedback, const char16_t* password) {
nsIMsgStatusFeedback* aStatusFeedback, const char16_t* password,
Promise** aPromise) {
NS_ENSURE_ARG_POINTER(fields);
NS_ENSURE_ARG_POINTER(sendIFile);
@ -3748,6 +3763,20 @@ nsresult nsMsgComposeAndSend::SendMessageFile(
if (NS_FAILED(rv) && mSendReport)
mSendReport->SetError(nsIMsgSendReport::process_Current, rv, false);
nsCOMPtr<nsIGlobalObject> global =
xpc::NativeGlobal(xpc::PrivilegedJunkScope());
ErrorResult er;
RefPtr<Promise> retPromise = Promise::Create(global, er);
nsresult rv2 = er.StealNSResult();
NS_ENSURE_SUCCESS(rv2, rv2);
if (NS_SUCCEEDED(rv)) {
retPromise->MaybeResolve(0);
} else {
retPromise->MaybeReject(rv);
}
retPromise.forget(aPromise);
return rv;
}

Просмотреть файл

@ -29,6 +29,7 @@
#include "nsIMsgLocalMailFolder.h"
#include "nsIMsgDatabase.h"
#include "nsMsgMessageFlags.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/Services.h"
#include "nsArrayUtils.h"
@ -502,6 +503,7 @@ nsresult nsMsgSendLater::CompleteMailFileSend() {
// Create the listener for the send operation...
RefPtr<SendOperationListener> sendListener = new SendOperationListener(this);
RefPtr<mozilla::dom::Promise> promise;
rv = pMsgSend->SendMessageFile(
identity, mAccountKey,
compFields, // nsIMsgCompFields *fields,
@ -510,7 +512,7 @@ nsresult nsMsgSendLater::CompleteMailFileSend() {
false, // bool digest_p,
nsIMsgSend::nsMsgSendUnsent, // nsMsgDeliverMode mode,
nullptr, // nsIMsgDBHdr *msgToReplace,
sendListener, mFeedback, nullptr);
sendListener, mFeedback, nullptr, getter_AddRefs(promise));
return rv;
}

Просмотреть файл

@ -225,7 +225,7 @@ function richCreateMessage(
progressListener.reject = reject;
});
progress.registerListener(progressListener);
msgCompose.SendMsg(
msgCompose.sendMsg(
Ci.nsIMsgSend.nsMsgSaveAsDraft,
identity,
account ? account.key : "",

Просмотреть файл

@ -158,8 +158,6 @@ function send_message_later(aMessageHeaderKeys, aStatus) {
"bodyText\n",
null,
null,
null,
null,
copyListener,
null,
"",

Просмотреть файл

@ -52,7 +52,7 @@ function sendMessage(fieldParams, identity, opts = {}, attachments = []) {
progressListener.reject = reject;
});
progress.registerListener(progressListener);
msgCompose.SendMsg(
msgCompose.sendMsg(
Ci.nsIMsgSend.nsMsgDeliverNow,
identity,
"",

Просмотреть файл

@ -120,7 +120,7 @@ add_task(async function() {
do_test_pending();
gMsgCompose.SendMsg(
gMsgCompose.sendMsg(
Ci.nsIMsgSend.nsMsgSaveAsDraft,
identity,
"",

Просмотреть файл

@ -82,7 +82,7 @@ function* saveDraft() {
Ci.nsIMsgProgress
);
progress.registerListener(progressListener);
msgCompose.SendMsg(
msgCompose.sendMsg(
Ci.nsIMsgSend.nsMsgSaveAsDraft,
identity,
"",

Просмотреть файл

@ -59,7 +59,7 @@ function* saveDraft() {
Ci.nsIMsgProgress
);
progress.registerListener(progressListener);
msgCompose.SendMsg(
msgCompose.sendMsg(
Ci.nsIMsgSend.nsMsgSaveAsDraft,
identity,
"",

Просмотреть файл

@ -36,6 +36,7 @@
#include "nsThreadUtils.h"
#include "nsMsgUtils.h"
#include "nsNetUtil.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Services.h"
#include "nsIArray.h"
@ -335,9 +336,11 @@ nsresult nsMapiHook::BlindSendMail(unsigned long aSession,
NS_ENSURE_SUCCESS(rv, rv);
// If we're in offline mode, we'll need to queue it for later.
RefPtr<mozilla::dom::Promise> promise;
rv = pMsgCompose->SendMsg(WeAreOffline() ? nsIMsgSend::nsMsgQueueForLater
: nsIMsgSend::nsMsgDeliverNow,
pMsgId, nullptr, nullptr, nullptr);
pMsgId, nullptr, nullptr, nullptr,
getter_AddRefs(promise));
NS_ENSURE_SUCCESS(rv, rv);
// We need to wait to make sure that we only return when the send is

Просмотреть файл

@ -48,6 +48,7 @@
#include "nsIMsgAccountManager.h"
#include "nsMsgBaseCID.h"
#include "modmimee.h" // for MimeConverterOutputCallback
#include "mozilla/dom/Promise.h"
#include "mozilla/mailnews/MimeHeaderParser.h"
using namespace mozilla::mailnews;
@ -286,8 +287,9 @@ nsresult ForwardMsgInline(nsIMsgCompFields* compFields,
rv = pMsgCompose->Initialize(pMsgComposeParams, nullptr, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<mozilla::dom::Promise> promise;
rv = pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, identity, nullptr,
nullptr, nullptr);
nullptr, nullptr, getter_AddRefs(promise));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIMsgFolder> origFolder;
origMsgHdr->GetFolder(getter_AddRefs(origFolder));