in mail/base/content/mailCommon.js [458:719]
isCommandEnabled(command) {
const type = typeof this._isCallbackEnabled[command];
if (type == "function") {
return this._isCallbackEnabled[command]();
} else if (type == "boolean") {
return this._isCallbackEnabled[command];
}
const hasIdentities = MailServices.accounts.allIdentities.length;
switch (command) {
case "cmd_newMessage":
return hasIdentities;
case "cmd_searchMessages":
// TODO: This shouldn't be here, or should return false if there are no accounts.
return true;
case "cmd_space":
case "cmd_manageTags":
return true;
}
if (!gViewWrapper?.dbView) {
return false;
}
const isDummyMessage = !gViewWrapper.isSynthetic && !gFolder;
if (["cmd_goBack", "cmd_goForward"].includes(command)) {
const activeMessageHistory = (
window.messageBrowser?.contentWindow ?? window
).messageHistory;
const relPos = command === "cmd_goBack" ? -1 : 1;
if (relPos === -1 && activeMessageHistory.canPop(0)) {
return !isDummyMessage;
}
return !isDummyMessage && activeMessageHistory.canPop(relPos);
}
if (command in this._navigationCommands) {
return !isDummyMessage;
}
const numSelectedMessages = isDummyMessage
? 1
: Number(gDBView?.numSelected);
// Evaluate these properties only if needed, not once for each command.
const folder = () => {
if (gFolder) {
return gFolder;
}
if (gDBView?.numSelected >= 1) {
return gDBView.hdrForFirstSelectedMessage?.folder;
}
return null;
};
const isNewsgroup = () =>
folder()?.isSpecialFolder(Ci.nsMsgFolderFlags.Newsgroup, true);
const canMove = () =>
numSelectedMessages >= 1 &&
(folder()?.canDeleteMessages || gViewWrapper.isSynthetic) &&
!gViewWrapper.isExpandedGroupedByHeaderAtIndex(
gDBView.viewIndexForFirstSelectedMsg
);
switch (command) {
case "cmd_cancel":
if (numSelectedMessages == 1 && isNewsgroup()) {
// Ensure author of message matches own identity
const author = gDBView.hdrForFirstSelectedMessage.mime2DecodedAuthor;
return MailServices.accounts
.getIdentitiesForServer(folder().server)
.some(id => id.fullAddress == author);
}
return false;
case "cmd_openConversation":
return (
// This (instead of numSelectedMessages) is necessary to be able to
// also open a collapsed thread in conversation.
gDBView.selection.count == 1 &&
ConversationOpener.isMessageIndexed(
gDBView.hdrForFirstSelectedMessage
)
);
case "cmd_replylist":
if (
!mailContextMenu.selectionIsOverridden &&
hasIdentities &&
numSelectedMessages == 1
) {
return (window.messageBrowser?.contentWindow ?? window)
.currentHeaderData?.["list-post"];
}
return false;
case "cmd_viewPageSource":
return numSelectedMessages > 0;
case "cmd_saveAsTemplate":
return numSelectedMessages == 1 && !isDummyMessage;
case "cmd_reply":
case "cmd_replySender":
case "cmd_replyall":
case "cmd_forward":
case "cmd_forwardInline":
case "cmd_forwardAttachment":
case "cmd_redirect":
case "cmd_editAsNew":
return (
hasIdentities &&
(numSelectedMessages == 1 ||
(numSelectedMessages > 1 &&
// Exclude collapsed threads.
numSelectedMessages == gDBView.selection.count))
);
case "cmd_copyMessage":
case "cmd_saveAsFile":
return numSelectedMessages >= 1;
case "cmd_openMessage":
return (
(location.href == "about:3pane" ||
parent.location.href == "about:3pane") &&
numSelectedMessages >= 1 &&
!isDummyMessage
);
case "cmd_tag":
case "cmd_tag1":
case "cmd_tag2":
case "cmd_tag3":
case "cmd_tag4":
case "cmd_tag5":
case "cmd_tag6":
case "cmd_tag7":
case "cmd_tag8":
case "cmd_tag9":
case "cmd_addTag":
case "cmd_removeTags":
case "cmd_toggleTag":
case "cmd_toggleRead":
case "cmd_markAsFlagged":
case "cmd_applyFiltersToSelection":
return numSelectedMessages >= 1 && !isDummyMessage;
case "cmd_copyDecryptedTo": {
let showDecrypt = numSelectedMessages > 1;
if (numSelectedMessages == 1 && !isDummyMessage) {
const msgURI = gDBView.URIForFirstSelectedMessage;
if (msgURI) {
showDecrypt = gEncryptedURIService.isEncrypted(msgURI);
}
}
return showDecrypt;
}
case "cmd_editDraftMsg":
return (
numSelectedMessages >= 1 &&
folder()?.isSpecialFolder(Ci.nsMsgFolderFlags.Drafts, true)
);
case "cmd_newMsgFromTemplate":
case "cmd_editTemplateMsg":
return (
numSelectedMessages >= 1 &&
folder()?.isSpecialFolder(Ci.nsMsgFolderFlags.Templates, true)
);
case "cmd_replyGroup":
return (
isNewsgroup() ||
(window.messageBrowser?.contentWindow ?? window).currentHeaderData
?.newsgroups
);
case "cmd_markAsRead":
return (
numSelectedMessages >= 1 &&
!isDummyMessage &&
gViewWrapper.dbView.getSelectedMsgHdrs().some(msg => !msg.isRead)
);
case "cmd_markAsUnread":
return (
numSelectedMessages >= 1 &&
!isDummyMessage &&
gViewWrapper.dbView.getSelectedMsgHdrs().some(msg => msg.isRead)
);
case "cmd_markThreadAsRead": {
if (numSelectedMessages == 0 || isDummyMessage) {
return false;
}
const sel = gViewWrapper.dbView.selection;
for (let i = 0; i < sel.getRangeCount(); i++) {
const start = {};
const end = {};
sel.getRangeAt(i, start, end);
for (let j = start.value; j <= end.value; j++) {
if (
gViewWrapper.dbView.getThreadContainingIndex(j)
.numUnreadChildren > 0
) {
return true;
}
}
}
return false;
}
case "cmd_markReadByDate":
case "cmd_markAllRead":
return gDBView?.msgFolder?.getNumUnread(false) > 0;
case "cmd_markAsJunk":
case "cmd_markAsNotJunk":
return this._getViewCommandStatus(Ci.nsMsgViewCommandType.junk);
case "cmd_archive":
return (
!isDummyMessage &&
MessageArchiver.canArchive(
gDBView.getSelectedMsgHdrs(),
gViewWrapper.isSingleFolder
)
);
case "cmd_moveMessage": {
return canMove();
}
case "cmd_moveToFolderAgain": {
// Disable "Move to <folder> Again" for news and other read only
// folders since we can't really move messages from there - only copy.
let canMoveAgain = numSelectedMessages >= 1;
if (Services.prefs.getBoolPref("mail.last_msg_movecopy_was_move")) {
canMoveAgain = canMove() && !isNewsgroup();
}
if (canMoveAgain) {
const targetURI = Services.prefs.getStringPref(
"mail.last_msg_movecopy_target_uri"
);
canMoveAgain = targetURI && MailUtils.getExistingFolder(targetURI);
}
return !!canMoveAgain;
}
case "cmd_deleteMessage":
return canMove();
case "cmd_shiftDeleteMessage":
return this._getViewCommandStatus(
Ci.nsMsgViewCommandType.deleteNoTrash
);
case "cmd_createFilterFromMenu":
return (
numSelectedMessages == 1 &&
!isDummyMessage &&
folder()?.server.canHaveFilters
);
case "cmd_watchThread": {
if (gViewWrapper?.showGroupedBySort) {
return false;
}
const enabledObj = {};
const checkStatusObj = {};
gViewWrapper.dbView.getCommandStatus(
Ci.nsMsgViewCommandType.toggleThreadWatched,
enabledObj,
checkStatusObj
);
return enabledObj.value;
}
case "cmd_applyFilters": {
return this._getViewCommandStatus(Ci.nsMsgViewCommandType.applyFilters);
}
}
return false;
},