RetroZilla/mailnews/base/resources/content/mailCommands.js
2015-10-20 23:03:22 -04:00

757 lines
25 KiB
JavaScript

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function DoRDFCommand(dataSource, command, srcArray, argumentArray)
{
var commandResource = RDF.GetResource(command);
if (commandResource) {
try {
if (!argumentArray)
argumentArray = Components.classes["@mozilla.org/supports-array;1"]
.createInstance(Components.interfaces.nsISupportsArray);
if (argumentArray)
argumentArray.AppendElement(msgWindow);
dataSource.DoCommand(srcArray, commandResource, argumentArray);
}
catch(e) {
if (command == "http://home.netscape.com/NC-rdf#NewFolder") {
throw(e); // so that the dialog does not automatically close.
}
dump("Exception : In mail commands" + e + "\n");
}
}
}
function GetNewMessages(selectedFolders, server, compositeDataSource)
{
var numFolders = selectedFolders.length;
if (numFolders > 0)
{
var msgFolder = selectedFolders[0];
// Whenever we do get new messages, clear the old new messages.
if (msgFolder)
{
var nsIMsgFolder = Components.interfaces.nsIMsgFolder;
msgFolder.biffState = nsIMsgFolder.nsMsgBiffState_NoMail;
msgFolder.clearNewMessages();
}
if (compositeDataSource)
{
var folderResource = msgFolder.QueryInterface(Components.interfaces.nsIRDFResource);
var folderArray = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
folderArray.AppendElement(folderResource);
var serverArray = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
serverArray.AppendElement(server);
DoRDFCommand(compositeDataSource, "http://home.netscape.com/NC-rdf#GetNewMessages", folderArray, serverArray);
}
}
else {
dump("Nothing was selected\n");
}
}
function getBestIdentity(identities, optionalHint)
{
var identity = null;
var identitiesCount = identities.Count();
try
{
// if we have more than one identity and a hint to help us pick one
if (identitiesCount > 1 && optionalHint) {
// normalize case on the optional hint to improve our chances of finding a match
optionalHint = optionalHint.toLowerCase();
var id;
// iterate over all of the identities
var tempID;
for (id = 0; id < identitiesCount; ++id) {
tempID = identities.GetElementAt(id).QueryInterface(Components.interfaces.nsIMsgIdentity);
if (optionalHint.indexOf(tempID.email.toLowerCase()) >= 0) {
identity = tempID;
break;
}
}
// if we could not find an exact email address match within the hint fields then maybe the message
// was to a mailing list. In this scenario, we won't have a match based on email address.
// Before we just give up, try and search for just a shared domain between the hint and
// the email addresses for our identities. Hey, it is better than nothing and in the case
// of multiple matches here, we'll end up picking the first one anyway which is what we would have done
// if we didn't do this second search. This helps the case for corporate users where mailing lists will have the same domain
// as one of your multiple identities.
if (!identity) {
for (id = 0; id < identitiesCount; ++id) {
tempID = identities.GetElementAt(id).QueryInterface(Components.interfaces.nsIMsgIdentity);
// extract out the partial domain
var start = tempID.email.lastIndexOf("@"); // be sure to include the @ sign in our search to reduce the risk of false positives
if (optionalHint.search(tempID.email.slice(start).toLowerCase()) >= 0) {
identity = tempID;
break;
}
}
}
}
}
catch (ex) {dump (ex + "\n");}
// Still no matches ?
// Give up and pick the first one (if it exists), like we used to.
if (!identity && identitiesCount > 0)
identity = identities.GetElementAt(0).QueryInterface(Components.interfaces.nsIMsgIdentity);
return identity;
}
function getIdentityForServer(server, optionalHint)
{
var identity = null;
if (server) {
// Get the identities associated with this server.
var identities = accountManager.GetIdentitiesForServer(server);
// dump("identities = " + identities + "\n");
// Try and find the best one.
identity = getBestIdentity(identities, optionalHint);
}
return identity;
}
function GetNextNMessages(folder)
{
if (folder) {
var newsFolder = folder.QueryInterface(Components.interfaces.nsIMsgNewsFolder);
if (newsFolder) {
newsFolder.getNextNMessages(msgWindow);
}
}
}
// type is a nsIMsgCompType and format is a nsIMsgCompFormat
function ComposeMessage(type, format, folder, messageArray)
{
var msgComposeType = Components.interfaces.nsIMsgCompType;
var identity = null;
var newsgroup = null;
var server;
// dump("ComposeMessage folder=" + folder + "\n");
try
{
if (folder)
{
// Get the incoming server associated with this uri.
server = folder.server;
// If they hit new or reply and they are reading a newsgroup,
// turn this into a new post or a reply to group.
if (!folder.isServer && server.type == "nntp" && type == msgComposeType.New)
{
type = msgComposeType.NewsPost;
newsgroup = folder.folderURL;
}
identity = getIdentityForServer(server);
// dump("identity = " + identity + "\n");
}
}
catch (ex)
{
dump("failed to get an identity to pre-select: " + ex + "\n");
}
// dump("\nComposeMessage from XUL: " + identity + "\n");
var uri = null;
if (!msgComposeService)
{
dump("### msgComposeService is invalid\n");
return;
}
if (type == msgComposeType.New)
{
// New message.
// dump("OpenComposeWindow with " + identity + "\n");
// If the addressbook sidebar panel is open and has focus, get
// the selected addresses from it.
if (document.commandDispatcher.focusedWindow.document.documentElement.hasAttribute("selectedaddresses"))
NewMessageToSelectedAddresses(type, format, identity);
else
msgComposeService.OpenComposeWindow(null, null, type, format, identity, msgWindow);
return;
}
else if (type == msgComposeType.NewsPost)
{
// dump("OpenComposeWindow with " + identity + " and " + newsgroup + "\n");
msgComposeService.OpenComposeWindow(null, newsgroup, type, format, identity, msgWindow);
return;
}
messenger.SetWindow(window, msgWindow);
var object = null;
if (messageArray && messageArray.length > 0)
{
uri = "";
for (var i = 0; i < messageArray.length; ++i)
{
var messageUri = messageArray[i];
var hdr = messenger.msgHdrFromURI(messageUri);
// If we treat reply from sent specially, do we check for that folder flag here ?
var hintForIdentity = (type == msgComposeType.Template) ? hdr.author : hdr.recipients + hdr.ccList;
var accountKey = hdr.accountKey;
if (accountKey.length > 0)
{
var account = accountManager.getAccount(accountKey);
if (account)
server = account.incomingServer;
}
if (server)
identity = getIdentityForServer(server, hintForIdentity);
if (folder && (!identity || hintForIdentity.search(identity.email) < 0))
{
server = folder.server;
if (server)
{
var tmpIdentity = getIdentityForServer(server, hintForIdentity);
if (tmpIdentity && hintForIdentity.search(tmpIdentity.email) >= 0)
identity = tmpIdentity;
}
}
if (type == msgComposeType.Reply ||
type == msgComposeType.ReplyAll ||
type == msgComposeType.ForwardInline ||
type == msgComposeType.ReplyToGroup ||
type == msgComposeType.ReplyToSender ||
type == msgComposeType.ReplyToSenderAndGroup ||
type == msgComposeType.Template ||
type == msgComposeType.Draft)
{
msgComposeService.OpenComposeWindow(null, messageUri, type, format, identity, msgWindow);
// Limit the number of new compose windows to 8. Why 8 ? I like that number :-)
if (i == 7)
break;
}
else
{
if (i)
uri += ","
uri += messageUri;
}
}
if (type == msgComposeType.ForwardAsAttachment)
msgComposeService.OpenComposeWindow(null, uri, type, format, identity, msgWindow);
}
else
dump("### nodeList is invalid\n");
}
function NewMessageToSelectedAddresses(type, format, identity) {
var abSidebarPanel = document.commandDispatcher.focusedWindow;
var abResultsTree = abSidebarPanel.document.getElementById("abResultsTree");
var abResultsBoxObject = abResultsTree.treeBoxObject;
var abView = abResultsBoxObject.view;
abView = abView.QueryInterface(Components.interfaces.nsIAbView);
var addresses = abView.selectedAddresses;
var params = Components.classes["@mozilla.org/messengercompose/composeparams;1"].createInstance(Components.interfaces.nsIMsgComposeParams);
if (params) {
params.type = type;
params.format = format;
params.identity = identity;
var composeFields = Components.classes["@mozilla.org/messengercompose/composefields;1"].createInstance(Components.interfaces.nsIMsgCompFields);
if (composeFields) {
var addressList = "";
for (var i = 0; i < addresses.Count(); i++) {
addressList = addressList + (i > 0 ? ",":"") + addresses.QueryElementAt(i,Components.interfaces.nsISupportsString).data;
}
composeFields.to = addressList;
params.composeFields = composeFields;
msgComposeService.OpenComposeWindowWithParams(null, params);
}
}
}
function CreateNewSubfolder(chromeWindowURL, preselectedMsgFolder,
dualUseFolders, callBackFunctionName)
{
var preselectedURI;
if (preselectedMsgFolder)
{
var preselectedFolderResource = preselectedMsgFolder.QueryInterface(Components.interfaces.nsIRDFResource);
if (preselectedFolderResource)
preselectedURI = preselectedFolderResource.Value;
dump("preselectedURI = " + preselectedURI + "\n");
}
window.openDialog(chromeWindowURL,
"",
"chrome,titlebar,modal",
{preselectedURI:preselectedURI,
dualUseFolders:dualUseFolders,
okCallback:callBackFunctionName});
}
function NewFolder(name,uri)
{
// dump("uri,name = " + uri + "," + name + "\n");
if (uri && (uri != "") && name && (name != "")) {
var selectedFolderResource = RDF.GetResource(uri);
// dump("selectedFolder = " + uri + "\n");
var compositeDataSource = GetCompositeDataSource("NewFolder");
var folderArray = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
var nameArray = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
folderArray.AppendElement(selectedFolderResource);
var nameLiteral = RDF.GetLiteral(name);
nameArray.AppendElement(nameLiteral);
DoRDFCommand(compositeDataSource, "http://home.netscape.com/NC-rdf#NewFolder", folderArray, nameArray);
}
else {
dump("no name or nothing selected\n");
}
}
function UnSubscribe(folder)
{
// Unsubscribe the current folder from the newsserver, this assumes any confirmation has already
// been made by the user SPL
var server = folder.server;
var subscribableServer = server.QueryInterface(Components.interfaces.nsISubscribableServer);
subscribableServer.unsubscribe(folder.name);
subscribableServer.commitSubscribeChanges();
}
function Subscribe(preselectedMsgFolder)
{
var preselectedURI;
if (preselectedMsgFolder)
{
var preselectedFolderResource = preselectedMsgFolder.QueryInterface(Components.interfaces.nsIRDFResource);
if (preselectedFolderResource)
preselectedURI = preselectedFolderResource.Value;
dump("preselectedURI = " + preselectedURI + "\n");
}
window.openDialog("chrome://messenger/content/subscribe.xul",
"subscribe", "chrome,modal,titlebar,resizable=yes",
{preselectedURI:preselectedURI,
okCallback:SubscribeOKCallback});
}
function SubscribeOKCallback(changeTable)
{
for (var serverURI in changeTable) {
var folder = GetMsgFolderFromUri(serverURI, true);
var server = folder.server;
var subscribableServer =
server.QueryInterface(Components.interfaces.nsISubscribableServer);
for (var name in changeTable[serverURI]) {
if (changeTable[serverURI][name] == true) {
try {
subscribableServer.subscribe(name);
}
catch (ex) {
dump("failed to subscribe to " + name + ": " + ex + "\n");
}
}
else if (changeTable[serverURI][name] == false) {
try {
subscribableServer.unsubscribe(name);
}
catch (ex) {
dump("failed to unsubscribe to " + name + ": " + ex + "\n");
}
}
else {
// no change
}
}
try {
subscribableServer.commitSubscribeChanges();
}
catch (ex) {
dump("failed to commit the changes: " + ex + "\n");
}
}
}
function SaveAsFile(uri)
{
if (uri) {
var filename = null;
try {
var subject = messenger.msgHdrFromURI(uri).mime2DecodedSubject;
filename = GenerateValidFilename(subject, ".eml");
}
catch (ex) {}
messenger.saveAs(uri, true, null, filename);
}
}
function SaveAsTemplate(uri, folder)
{
if (uri) {
var identity = getIdentityForServer(folder.server);
messenger.saveAs(uri, false, identity, null);
}
}
function MarkSelectedMessagesRead(markRead)
{
gDBView.doCommand(markRead ? nsMsgViewCommandType.markMessagesRead : nsMsgViewCommandType.markMessagesUnread);
}
function MarkSelectedMessagesFlagged(markFlagged)
{
gDBView.doCommand(markFlagged ? nsMsgViewCommandType.flagMessages : nsMsgViewCommandType.unflagMessages);
}
function MarkAllMessagesRead(compositeDataSource, folder)
{
var folderResource = folder.QueryInterface(Components.interfaces.nsIRDFResource);
var folderArray = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
folderArray.AppendElement(folderResource);
DoRDFCommand(compositeDataSource, "http://home.netscape.com/NC-rdf#MarkAllMessagesRead", folderArray, null);
}
function DownloadFlaggedMessages(compositeDataSource, folder)
{
dump("fix DownloadFlaggedMessages()\n");
}
function DownloadSelectedMessages(compositeDataSource, messages, markFlagged)
{
dump("fix DownloadSelectedMessages()\n");
}
function ViewPageSource(messages)
{
var numMessages = messages.length;
if (numMessages == 0)
{
dump("MsgViewPageSource(): No messages selected.\n");
return false;
}
try {
// First, get the mail session
const mailSessionContractID = "@mozilla.org/messenger/services/session;1";
const nsIMsgMailSession = Components.interfaces.nsIMsgMailSession;
var mailSession = Components.classes[mailSessionContractID].getService(nsIMsgMailSession);
var mailCharacterSet = "charset=" + msgWindow.mailCharacterSet;
for (var i = 0; i < numMessages; i++)
{
// Now, we need to get a URL from a URI
var url = mailSession.ConvertMsgURIToMsgURL(messages[i], msgWindow);
window.openDialog( "chrome://navigator/content/viewSource.xul",
"_blank", "all,dialog=no", url,
mailCharacterSet);
}
return true;
} catch (e) {
// Couldn't get mail session
return false;
}
}
function doHelpButton()
{
openHelp("mail-offline-items");
}
// XXX The following junkmail code might be going away or changing
const NS_BAYESIANFILTER_CONTRACTID = "@mozilla.org/messenger/filter-plugin;1?name=bayesianfilter";
const nsIJunkMailPlugin = Components.interfaces.nsIJunkMailPlugin;
const nsIMsgDBHdr = Components.interfaces.nsIMsgDBHdr;
var gJunkmailComponent;
function determineActionsForJunkMsgs(aView, aIndices, aActionParams)
{
// we use some arbitrary message to determine the
// message server
var msgURI = aView.getURIForViewIndex(aIndices[0]);
var msgHdr = messenger.msgHdrFromURI(msgURI);
var server = msgHdr.folder.server;
var spamSettings = server.spamSettings;
// note we will do moves/marking as read even if the spam
// feature is disabled, since the user has asked to use it
// despite the disabling
// note also that we will only act on messages which
// _the_current_run_ of the classifier has classified as
// junk, rather than on all junk messages in the folder
aActionParams.markRead = spamSettings.markAsReadOnSpam;
aActionParams.junkTargetFolder = null;
if (!spamSettings.moveOnSpam)
return;
// don't move if we are already in the junk folder
if (msgHdr.folder.flags & MSG_FOLDER_FLAG_JUNK)
return;
var spamFolderURI = spamSettings.spamFolderURI;
if (!spamFolderURI)
{
dump('no spam folder!');
return;
}
aActionParams.junkTargetFolder = GetMsgFolderFromUri(spamFolderURI);
}
function performActionsOnJunkMsgs(aIndices)
{
if (!aIndices.length)
return;
var treeView = gDBView.QueryInterface(Components.interfaces.nsITreeView);
var treeSelection = treeView.selection;
treeSelection.clearSelection();
// select the messages
for (i=0;i<aIndices.length;i++)
treeSelection.rangedSelect(aIndices[i], aIndices[i], true /* augment */);
var actionParams = { markRead: false, junkTargetFolder: null };
determineActionsForJunkMsgs(treeView, aIndices, actionParams);
if (actionParams.markRead)
MarkSelectedMessagesRead(true);
if (actionParams.junkTargetFolder)
{
SetNextMessageAfterDelete();
gDBView.doCommandWithFolder(nsMsgViewCommandType.moveMessages, actionParams.junkTargetFolder);
}
treeSelection.clearSelection();
}
function getJunkmailComponent()
{
if (!gJunkmailComponent) {
gJunkmailComponent = Components.classes[NS_BAYESIANFILTER_CONTRACTID].getService(nsIJunkMailPlugin);
}
}
function analyzeMessageForJunk(aMsgHdr, aMsgIndex, aJunkMsgIndices, aLastMessage, aWhiteListDirectory)
{
var listener = {
onMessageClassified: function(aClassifiedMsgURI, aClassification)
{
// XXX TODO
// update status bar, or a progress dialog
// running junk mail controls manually, on a large folder
// can take a while, and the user doesn't know when we are done.
// XXX TODO
// make the cut off 50, like in nsMsgSearchTerm.cpp
var score =
aClassification == nsIJunkMailPlugin.JUNK ? "100" : "0";
// set these props via the db (instead of the message header
// directly) so that the nsMsgDBView knows to update the UI
//
var db = aMsgHdr.folder.getMsgDatabase(msgWindow);
db.setStringProperty(aMsgHdr.messageKey, "junkscore", score);
db.setStringProperty(aMsgHdr.messageKey, "junkscoreorigin",
"plugin");
if (aClassification == nsIJunkMailPlugin.JUNK)
aJunkMsgIndices.push(aMsgIndex);
if (aLastMessage)
performActionsOnJunkMsgs(aJunkMsgIndices);
}
};
// if we are whitelisting, check if the email address is in the whitelist addressbook.
if (aWhiteListDirectory)
{
var headerParser = Components.classes["@mozilla.org/messenger/headerparser;1"].getService(Components.interfaces.nsIMsgHeaderParser);
var authorEmailAddress = headerParser.extractHeaderAddressMailboxes(null, aMsgHdr.author);
if (aWhiteListDirectory.hasCardForEmailAddress(authorEmailAddress))
// skip over this message, like we do on incoming mail
// the difference is it could be marked as junk from previous analysis
// or from being manually marked by the user.
return;
}
var messageURI = aMsgHdr.folder.generateMessageURI(aMsgHdr.messageKey)
+ "?fetchCompleteMessage=true";
gJunkmailComponent.classifyMessage(messageURI, msgWindow, listener);
}
function filterFolderForJunk()
{
MsgJunkMailInfo(true);
var view = GetDBView();
// need to expand all threads, so we analyze everything
view.doCommand(nsMsgViewCommandType.expandAll);
var treeView = view.QueryInterface(Components.interfaces.nsITreeView);
var count = treeView.rowCount;
if (!count)
return;
var junkMsgsArray = new Array;
var tmpMsgURI = view.getURIForViewIndex(0);
var tmpMsgHdr = messenger.msgHdrFromURI(tmpMsgURI);
var spamSettings = tmpMsgHdr.folder.server.spamSettings;
var whiteListDirectory = null;
if (spamSettings.useWhiteList && spamSettings.whiteListAbURI)
whiteListDirectory = RDF.GetResource(spamSettings.whiteListAbURI).QueryInterface(Components.interfaces.nsIAbMDBDirectory);
getJunkmailComponent();
for (var i = 0; i < count; i++) {
var msgIndex = i;
var msgURI = view.getURIForViewIndex(i);
var msgHdr = messenger.msgHdrFromURI(msgURI);
analyzeMessageForJunk(msgHdr,msgIndex,junkMsgsArray,(i == count-1),whiteListDirectory);
}
}
function JunkSelectedMessages(setAsJunk)
{
MsgJunkMailInfo(true);
// When the user explicitly marks a message as junk, we can mark it as read,
// too. This is independent of the "markAsReadOnSpam" pref, which applies
// only to automatically-classified messages.
// Note that this behaviour should match the one in the back end for marking
// as junk via clicking the 'junk' column.
if (setAsJunk && pref.getBoolPref("mailnews.ui.junk.manualMarkAsJunkMarksRead"))
MarkSelectedMessagesRead(true);
gDBView.doCommand(setAsJunk ? nsMsgViewCommandType.junk
: nsMsgViewCommandType.unjunk);
}
function deleteJunkInFolder()
{
MsgJunkMailInfo(true);
var view = GetDBView();
// need to expand all threads, so we find everything
view.doCommand(nsMsgViewCommandType.expandAll);
var treeView = view.QueryInterface(Components.interfaces.nsITreeView);
var count = treeView.rowCount;
if (!count)
return;
var treeSelection = treeView.selection;
var clearedSelection = false;
// select the junk messages
for (var i = 0; i < count; ++i)
{
var messageUri = view.getURIForViewIndex(i);
var msgHdr = messenger.msgHdrFromURI(messageUri);
var junkScore = msgHdr.getStringProperty("junkscore");
var isJunk = ((junkScore != "") && (junkScore != "0"));
// if the message is junk, select it.
if (isJunk)
{
// only do this once
if (!clearedSelection)
{
// clear the current selection
// since we will be deleting all selected messages
treeSelection.clearSelection();
clearedSelection = true;
treeSelection.selectEventsSuppressed = true;
}
treeSelection.rangedSelect(i, i, true /* augment */);
}
}
// if we didn't clear the selection
// there was no junk, so bail.
if (!clearedSelection)
return;
treeSelection.selectEventsSuppressed = false;
// delete the selected messages
//
// XXX todo
// Should we try to set next message after delete
// to the message selected before we did all this, if it was not junk?
SetNextMessageAfterDelete();
view.doCommand(nsMsgViewCommandType.deleteMsg);
treeSelection.clearSelection();
}