зеркало из https://github.com/mozilla/pjs.git
3585 строки
117 KiB
JavaScript
3585 строки
117 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 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 *****
|
|
|
|
/**
|
|
* interfaces
|
|
*/
|
|
const nsIMsgCompDeliverMode = Components.interfaces.nsIMsgCompDeliverMode;
|
|
const nsIMsgCompSendFormat = Components.interfaces.nsIMsgCompSendFormat;
|
|
const nsIMsgCompConvertible = Components.interfaces.nsIMsgCompConvertible;
|
|
const nsIMsgCompType = Components.interfaces.nsIMsgCompType;
|
|
const nsIMsgCompFormat = Components.interfaces.nsIMsgCompFormat;
|
|
const nsIAbPreferMailFormat = Components.interfaces.nsIAbPreferMailFormat;
|
|
const nsIPlaintextEditorMail = Components.interfaces.nsIPlaintextEditor;
|
|
const nsISupportsString = Components.interfaces.nsISupportsString;
|
|
const mozISpellCheckingEngine = Components.interfaces.mozISpellCheckingEngine;
|
|
|
|
/**
|
|
* In order to distinguish clearly globals that are initialized once when js load (static globals) and those that need to be
|
|
* initialize every time a compose window open (globals), I (ducarroz) have decided to prefix by s... the static one and
|
|
* by g... the other one. Please try to continue and repect this rule in the future. Thanks.
|
|
*/
|
|
/**
|
|
* static globals, need to be initialized only once
|
|
*/
|
|
var sMsgComposeService = Components.classes["@mozilla.org/messengercompose;1"].getService(Components.interfaces.nsIMsgComposeService);
|
|
var sComposeMsgsBundle = document.getElementById("bundle_composeMsgs");
|
|
|
|
var sPrefs = null;
|
|
var sPrefBranchInternal = null;
|
|
var sOther_headers = "";
|
|
|
|
var sAccountManagerDataSource = null;
|
|
var sRDF = null;
|
|
var sNameProperty = null;
|
|
var sDictCount = 0;
|
|
|
|
/* Create message window object. This is use by mail-offline.js and therefore should not be renamed. We need to avoid doing
|
|
this kind of cross file global stuff in the future and instead pass this object as parameter when needed by function
|
|
in the other js file.
|
|
*/
|
|
var msgWindow = Components.classes["@mozilla.org/messenger/msgwindow;1"].createInstance();
|
|
msgWindow = msgWindow.QueryInterface(Components.interfaces.nsIMsgWindow);
|
|
|
|
|
|
/**
|
|
* Global variables, need to be re-initialized every time mostly because we need to release them when the window close
|
|
*/
|
|
var gHideMenus;
|
|
var gMsgCompose;
|
|
var gAccountManager;
|
|
var gIOService;
|
|
var gPromptService;
|
|
var gLDAPPrefsService;
|
|
var gWindowLocked;
|
|
var gContentChanged;
|
|
var gAutoSaving;
|
|
var gCurrentIdentity;
|
|
var defaultSaveOperation;
|
|
var gSendOrSaveOperationInProgress;
|
|
var gCloseWindowAfterSave;
|
|
var gIsOffline;
|
|
var gSessionAdded;
|
|
var gCurrentAutocompleteDirectory;
|
|
var gAutocompleteSession;
|
|
var gSetupLdapAutocomplete;
|
|
var gLDAPSession;
|
|
var gSavedSendNowKey;
|
|
var gSendFormat;
|
|
var gLogComposePerformance;
|
|
|
|
var gMsgIdentityElement;
|
|
var gMsgAddressingWidgetTreeElement;
|
|
var gMsgSubjectElement;
|
|
var gMsgAttachmentElement;
|
|
var gMsgHeadersToolbarElement;
|
|
|
|
// i18n globals
|
|
var gCurrentMailSendCharset;
|
|
var gSendDefaultCharset;
|
|
var gCharsetTitle;
|
|
var gCharsetConvertManager;
|
|
|
|
var gLastWindowToHaveFocus;
|
|
var gReceiptOptionChanged;
|
|
var gAttachVCardOptionChanged;
|
|
|
|
var gMailSession;
|
|
var gAutoSaveInterval;
|
|
var gAutoSaveTimeout;
|
|
|
|
const kComposeAttachDirPrefName = "mail.compose.attach.dir";
|
|
|
|
function InitializeGlobalVariables()
|
|
{
|
|
gAccountManager = Components.classes["@mozilla.org/messenger/account-manager;1"].getService(Components.interfaces.nsIMsgAccountManager);
|
|
gIOService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
|
|
gPromptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
|
|
|
|
//This migrates the LDAPServer Preferences from 4.x to mozilla format.
|
|
gLDAPPrefsService = Components.classes["@mozilla.org/ldapprefs-service;1"];
|
|
if (gLDAPPrefsService) {
|
|
try {
|
|
gLDAPPrefsService = gLDAPPrefsService
|
|
.getService(Components.interfaces.nsILDAPPrefsService);
|
|
} catch (ex) {Components.utils.reportError("ERROR: Cannot get the LDAP prefs service\n" + ex + "\n");}
|
|
if (gLDAPPrefsService) {
|
|
gLDAPPrefsService.migratePrefsIfNeeded();
|
|
}
|
|
}
|
|
|
|
gMsgCompose = null;
|
|
gWindowLocked = false;
|
|
gContentChanged = false;
|
|
gCurrentIdentity = null;
|
|
defaultSaveOperation = "draft";
|
|
gSendOrSaveOperationInProgress = false;
|
|
gAutoSaving = false;
|
|
gCloseWindowAfterSave = false;
|
|
gIsOffline = gIOService.offline;
|
|
gSessionAdded = false;
|
|
gCurrentAutocompleteDirectory = null;
|
|
gAutocompleteSession = null;
|
|
gSetupLdapAutocomplete = false;
|
|
gLDAPSession = null;
|
|
gSavedSendNowKey = null;
|
|
gSendFormat = nsIMsgCompSendFormat.AskUser;
|
|
gCurrentMailSendCharset = null;
|
|
gSendDefaultCharset = null;
|
|
gCharsetTitle = null;
|
|
gCharsetConvertManager = Components.classes['@mozilla.org/charset-converter-manager;1'].getService(Components.interfaces.nsICharsetConverterManager);
|
|
gMailSession = Components.classes["@mozilla.org/messenger/services/session;1"].getService(Components.interfaces.nsIMsgMailSession);
|
|
gHideMenus = false;
|
|
// We are storing the value of the bool logComposePerformance inorder to avoid logging unnecessarily.
|
|
if (sMsgComposeService)
|
|
gLogComposePerformance = sMsgComposeService.logComposePerformance;
|
|
|
|
gLastWindowToHaveFocus = null;
|
|
gReceiptOptionChanged = false;
|
|
gAttachVCardOptionChanged = false;
|
|
}
|
|
InitializeGlobalVariables();
|
|
|
|
function ReleaseGlobalVariables()
|
|
{
|
|
gAccountManager = null;
|
|
gIOService = null;
|
|
gPromptService = null;
|
|
gLDAPPrefsService = null;
|
|
gCurrentIdentity = null;
|
|
gCurrentAutocompleteDirectory = null;
|
|
gAutocompleteSession = null;
|
|
gLDAPSession = null;
|
|
gCharsetConvertManager = null;
|
|
gMsgCompose = null;
|
|
gMailSession = null;
|
|
}
|
|
|
|
function disableEditableFields()
|
|
{
|
|
gMsgCompose.editor.flags |= nsIPlaintextEditorMail.eEditorReadonlyMask;
|
|
var disableElements = document.getElementsByAttribute("disableonsend", "true");
|
|
for (i=0;i<disableElements.length;i++)
|
|
{
|
|
disableElements[i].setAttribute('disabled', 'true');
|
|
}
|
|
}
|
|
|
|
function enableEditableFields()
|
|
{
|
|
gMsgCompose.editor.flags &= ~nsIPlaintextEditorMail.eEditorReadonlyMask;
|
|
var enableElements = document.getElementsByAttribute("disableonsend", "true");
|
|
for (i=0;i<enableElements.length;i++)
|
|
{
|
|
enableElements[i].removeAttribute('disabled');
|
|
}
|
|
}
|
|
|
|
var gComposeRecyclingListener = {
|
|
onClose: function() {
|
|
//Reset recipients and attachments
|
|
ReleaseAutoCompleteState();
|
|
awResetAllRows();
|
|
RemoveAllAttachments();
|
|
|
|
// We need to clear the identity popup menu in case the user will change them.
|
|
// It will be rebuilt later in ComposeStartup
|
|
ClearIdentityListPopup(document.getElementById("msgIdentityPopup"));
|
|
|
|
//Clear the subject
|
|
GetMsgSubjectElement().value = "";
|
|
// be sure to clear the transaction manager for the subject
|
|
GetMsgSubjectElement().editor.transactionManager.clear();
|
|
SetComposeWindowTitle();
|
|
|
|
SetContentAndBodyAsUnmodified();
|
|
disableEditableFields();
|
|
ReleaseGlobalVariables();
|
|
|
|
// Clear the focus
|
|
awGetInputElement(1).removeAttribute('focused');
|
|
|
|
//Reset Boxes size
|
|
document.getElementById("headers-box").removeAttribute("height");
|
|
document.getElementById("appcontent").removeAttribute("height");
|
|
document.getElementById("addresses-box").removeAttribute("width");
|
|
document.getElementById("attachments-box").removeAttribute("width");
|
|
|
|
//Reset menu options
|
|
document.getElementById("format_auto").setAttribute("checked", "true");
|
|
document.getElementById("priority_normal").setAttribute("checked", "true");
|
|
|
|
//Reset toolbars that could be hidden
|
|
if (gHideMenus) {
|
|
document.getElementById("formatMenu").hidden = false;
|
|
document.getElementById("insertMenu").hidden = false;
|
|
var showFormat = document.getElementById("menu_showFormatToolbar")
|
|
showFormat.hidden = false;
|
|
if (showFormat.getAttribute("checked") == "true")
|
|
document.getElementById("FormatToolbar").hidden = false;
|
|
}
|
|
|
|
//Reset editor
|
|
InlineSpellChecker.Init(GetCurrentEditor(), false); // unregister inline spell checking listeners and release the spell checker
|
|
EditorResetFontAndColorAttributes();
|
|
EditorCleanup();
|
|
|
|
//Release the nsIMsgComposeParams object
|
|
if (window.arguments && window.arguments[0])
|
|
window.arguments[0] = null;
|
|
|
|
var event = document.createEvent('Events');
|
|
event.initEvent('compose-window-close', false, true);
|
|
document.getElementById("msgcomposeWindow").dispatchEvent(event);
|
|
if (gAutoSaveTimeout)
|
|
clearTimeout(gAutoSaveTimeout);
|
|
},
|
|
|
|
onReopen: function(params) {
|
|
InitializeGlobalVariables();
|
|
ComposeStartup(true, params);
|
|
|
|
var event = document.createEvent('Events');
|
|
event.initEvent('compose-window-reopen', false, true);
|
|
document.getElementById("msgcomposeWindow").dispatchEvent(event);
|
|
}
|
|
};
|
|
|
|
var stateListener = {
|
|
NotifyComposeFieldsReady: function() {
|
|
ComposeFieldsReady();
|
|
},
|
|
|
|
NotifyComposeBodyReady: function() {},
|
|
|
|
ComposeProcessDone: function(aResult) {
|
|
gWindowLocked = false;
|
|
enableEditableFields();
|
|
updateComposeItems();
|
|
|
|
if (aResult== Components.results.NS_OK)
|
|
{
|
|
if (!gAutoSaving)
|
|
SetContentAndBodyAsUnmodified();
|
|
|
|
if (gCloseWindowAfterSave)
|
|
{
|
|
// Notify the SendListener that Send has been aborted and Stopped
|
|
if (gMsgCompose)
|
|
{
|
|
var externalListener = gMsgCompose.getExternalSendListener();
|
|
if (externalListener)
|
|
{
|
|
externalListener.onSendNotPerformed(null, Components.results.NS_ERROR_ABORT);
|
|
}
|
|
}
|
|
MsgComposeCloseWindow(true);
|
|
}
|
|
}
|
|
// else if we failed to save, and we're autosaving, need to re-mark the editor
|
|
// as changed, so that we won't lose the changes.
|
|
else if (gAutoSaving)
|
|
{
|
|
gMsgCompose.bodyModified = true;
|
|
gContentChanged = true;
|
|
}
|
|
gAutoSaving = false;
|
|
gCloseWindowAfterSave = false;
|
|
},
|
|
|
|
SaveInFolderDone: function(folderURI) {
|
|
DisplaySaveFolderDlg(folderURI);
|
|
}
|
|
};
|
|
|
|
// all progress notifications are done through the nsIWebProgressListener implementation...
|
|
var progressListener = {
|
|
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
|
|
{
|
|
if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_START)
|
|
{
|
|
document.getElementById('compose-progressmeter').setAttribute( "mode", "undetermined" );
|
|
}
|
|
|
|
if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP)
|
|
{
|
|
gSendOrSaveOperationInProgress = false;
|
|
document.getElementById('compose-progressmeter').setAttribute( "mode", "normal" );
|
|
document.getElementById('compose-progressmeter').setAttribute( "value", 0 );
|
|
document.getElementById('statusText').setAttribute('label', '');
|
|
}
|
|
},
|
|
|
|
onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
|
|
{
|
|
// Calculate percentage.
|
|
var percent;
|
|
if ( aMaxTotalProgress > 0 )
|
|
{
|
|
percent = Math.round( (aCurTotalProgress*100)/aMaxTotalProgress );
|
|
if ( percent > 100 )
|
|
percent = 100;
|
|
|
|
document.getElementById('compose-progressmeter').removeAttribute("mode");
|
|
|
|
// Advance progress meter.
|
|
document.getElementById('compose-progressmeter').setAttribute( "value", percent );
|
|
}
|
|
else
|
|
{
|
|
// Progress meter should be barber-pole in this case.
|
|
document.getElementById('compose-progressmeter').setAttribute( "mode", "undetermined" );
|
|
}
|
|
},
|
|
|
|
onLocationChange: function(aWebProgress, aRequest, aLocation)
|
|
{
|
|
// we can ignore this notification
|
|
},
|
|
|
|
onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage)
|
|
{
|
|
// Looks like it's possible that we get call while the document has been already delete!
|
|
// therefore we need to protect ourself by using try/catch
|
|
try {
|
|
statusText = document.getElementById("statusText");
|
|
if (statusText)
|
|
statusText.setAttribute("label", aMessage);
|
|
} catch (ex) {}
|
|
},
|
|
|
|
onSecurityChange: function(aWebProgress, aRequest, state)
|
|
{
|
|
// we can ignore this notification
|
|
},
|
|
|
|
QueryInterface : function(iid)
|
|
{
|
|
if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
|
|
iid.equals(Components.interfaces.nsISupportsWeakReference) ||
|
|
iid.equals(Components.interfaces.nsISupports))
|
|
return this;
|
|
|
|
throw Components.results.NS_NOINTERFACE;
|
|
}
|
|
};
|
|
|
|
var defaultController =
|
|
{
|
|
supportsCommand: function(command)
|
|
{
|
|
switch (command)
|
|
{
|
|
//File Menu
|
|
case "cmd_attachFile":
|
|
case "cmd_attachPage":
|
|
case "cmd_close":
|
|
case "cmd_saveDefault":
|
|
case "cmd_saveAsFile":
|
|
case "cmd_saveAsDraft":
|
|
case "cmd_saveAsTemplate":
|
|
case "cmd_sendButton":
|
|
case "cmd_sendNow":
|
|
case "cmd_sendWithCheck":
|
|
case "cmd_sendLater":
|
|
case "cmd_printSetup":
|
|
case "cmd_print":
|
|
case "cmd_quit":
|
|
|
|
//Edit Menu
|
|
case "cmd_delete":
|
|
case "cmd_selectAll":
|
|
case "cmd_openAttachment":
|
|
case "cmd_account":
|
|
|
|
//View Menu
|
|
case "cmd_showComposeToolbar":
|
|
case "cmd_showFormatToolbar":
|
|
|
|
//Options Menu
|
|
case "cmd_selectAddress":
|
|
case "cmd_outputFormat":
|
|
case "cmd_quoteMessage":
|
|
return true;
|
|
|
|
default:
|
|
// dump("##MsgCompose: command " + command + "no supported!\n");
|
|
return false;
|
|
}
|
|
},
|
|
isCommandEnabled: function(command)
|
|
{
|
|
var composeHTML = gMsgCompose && gMsgCompose.composeHTML;
|
|
|
|
switch (command)
|
|
{
|
|
//File Menu
|
|
case "cmd_attachFile":
|
|
case "cmd_attachPage":
|
|
case "cmd_close":
|
|
case "cmd_saveDefault":
|
|
case "cmd_saveAsFile":
|
|
case "cmd_saveAsDraft":
|
|
case "cmd_saveAsTemplate":
|
|
case "cmd_sendButton":
|
|
case "cmd_sendLater":
|
|
case "cmd_printSetup":
|
|
case "cmd_print":
|
|
case "cmd_sendWithCheck":
|
|
return !gWindowLocked;
|
|
case "cmd_sendNow":
|
|
return !(gWindowLocked || gIsOffline);
|
|
case "cmd_quit":
|
|
return true;
|
|
|
|
//Edit Menu
|
|
case "cmd_delete":
|
|
return MessageGetNumSelectedAttachments();
|
|
case "cmd_selectAll":
|
|
return MessageHasAttachments();
|
|
case "cmd_openAttachment":
|
|
return MessageGetNumSelectedAttachments() == 1;
|
|
case "cmd_account":
|
|
|
|
//View Menu
|
|
case "cmd_showComposeToolbar":
|
|
return true;
|
|
case "cmd_showFormatToolbar":
|
|
return composeHTML;
|
|
|
|
//Options Menu
|
|
case "cmd_selectAddress":
|
|
return !gWindowLocked;
|
|
case "cmd_outputFormat":
|
|
return composeHTML;
|
|
case "cmd_quoteMessage":
|
|
var selectedURIs = GetSelectedMessages();
|
|
if (selectedURIs && selectedURIs.length > 0)
|
|
return true;
|
|
return false;
|
|
|
|
default:
|
|
// dump("##MsgCompose: command " + command + " disabled!\n");
|
|
return false;
|
|
}
|
|
},
|
|
|
|
doCommand: function(command)
|
|
{
|
|
switch (command)
|
|
{
|
|
//File Menu
|
|
case "cmd_attachFile" : if (defaultController.isCommandEnabled(command)) AttachFile(); break;
|
|
case "cmd_attachPage" : AttachPage(); break;
|
|
case "cmd_close" : DoCommandClose(); break;
|
|
case "cmd_saveDefault" : Save(); break;
|
|
case "cmd_saveAsFile" : SaveAsFile(true); break;
|
|
case "cmd_saveAsDraft" : SaveAsDraft(); break;
|
|
case "cmd_saveAsTemplate" : SaveAsTemplate(); break;
|
|
case "cmd_sendButton" :
|
|
if (defaultController.isCommandEnabled(command))
|
|
{
|
|
if (gIOService && gIOService.offline)
|
|
SendMessageLater();
|
|
else
|
|
SendMessage();
|
|
}
|
|
break;
|
|
case "cmd_sendNow" : if (defaultController.isCommandEnabled(command)) SendMessage(); break;
|
|
case "cmd_sendWithCheck" : if (defaultController.isCommandEnabled(command)) SendMessageWithCheck(); break;
|
|
case "cmd_sendLater" : if (defaultController.isCommandEnabled(command)) SendMessageLater(); break;
|
|
case "cmd_printSetup" : NSPrintSetup(); break;
|
|
case "cmd_print" : DoCommandPrint(); break;
|
|
|
|
//Edit Menu
|
|
case "cmd_delete" : if (MessageGetNumSelectedAttachments()) RemoveSelectedAttachment(); break;
|
|
case "cmd_selectAll" : if (MessageHasAttachments()) SelectAllAttachments(); break;
|
|
case "cmd_openAttachment" : if (MessageGetNumSelectedAttachments() == 1) OpenSelectedAttachment(); break;
|
|
case "cmd_account" : MsgAccountManager(null); break;
|
|
|
|
//View Menu
|
|
case "cmd_showComposeToolbar" : goToggleToolbar('composeToolbar2', 'menu_showComposeToolbar'); break;
|
|
case "cmd_showFormatToolbar" : goToggleToolbar('FormatToolbar', 'menu_showFormatToolbar'); break;
|
|
|
|
//Options Menu
|
|
case "cmd_selectAddress" : if (defaultController.isCommandEnabled(command)) SelectAddress(); break;
|
|
case "cmd_quoteMessage" : if (defaultController.isCommandEnabled(command)) QuoteSelectedMessage(); break;
|
|
default:
|
|
// dump("##MsgCompose: don't know what to do with command " + command + "!\n");
|
|
return;
|
|
}
|
|
},
|
|
|
|
onEvent: function(event)
|
|
{
|
|
// dump("DefaultController:onEvent\n");
|
|
}
|
|
}
|
|
|
|
function goOpenNewMessage()
|
|
{
|
|
// if there is a MsgNewMessage function in scope
|
|
// and we should use it, so that we choose the proper
|
|
// identity, based on the selected message or folder
|
|
// if not, bring up the compose window to the default identity
|
|
if ("MsgNewMessage" in window) {
|
|
MsgNewMessage(null);
|
|
return;
|
|
}
|
|
|
|
var msgComposeService = Components.classes["@mozilla.org/messengercompose;1"].getService();
|
|
msgComposeService = msgComposeService.QueryInterface(Components.interfaces.nsIMsgComposeService);
|
|
msgComposeService.OpenComposeWindow(null, null,
|
|
Components.interfaces.nsIMsgCompType.New,
|
|
Components.interfaces.nsIMsgCompFormat.Default,
|
|
null, null);
|
|
}
|
|
|
|
function QuoteSelectedMessage()
|
|
{
|
|
var selectedURIs = GetSelectedMessages();
|
|
if (selectedURIs)
|
|
for (i = 0; i < selectedURIs.length; i++)
|
|
gMsgCompose.quoteMessage(selectedURIs[i]);
|
|
}
|
|
|
|
function GetSelectedMessages()
|
|
{
|
|
if (gMsgCompose) {
|
|
var mailWindow = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService()
|
|
.QueryInterface(Components.interfaces.nsIWindowMediator)
|
|
.getMostRecentWindow("mail:3pane");
|
|
if (mailWindow) {
|
|
return mailWindow.GetSelectedMessages();
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function SetupCommandUpdateHandlers()
|
|
{
|
|
top.controllers.insertControllerAt(0, defaultController);
|
|
}
|
|
|
|
function CommandUpdate_MsgCompose()
|
|
{
|
|
var focusedWindow = top.document.commandDispatcher.focusedWindow;
|
|
|
|
// we're just setting focus to where it was before
|
|
if (focusedWindow == gLastWindowToHaveFocus) {
|
|
//dump("XXX skip\n");
|
|
return;
|
|
}
|
|
|
|
gLastWindowToHaveFocus = focusedWindow;
|
|
|
|
//dump("XXX update, focus on " + focusedWindow + "\n");
|
|
|
|
updateComposeItems();
|
|
}
|
|
|
|
function updateComposeItems()
|
|
{
|
|
try {
|
|
// Edit Menu
|
|
goUpdateCommand("cmd_rewrap");
|
|
|
|
// Insert Menu
|
|
if (gMsgCompose && gMsgCompose.composeHTML)
|
|
{
|
|
goUpdateCommand("cmd_renderedHTMLEnabler");
|
|
goUpdateCommand("cmd_decreaseFont");
|
|
goUpdateCommand("cmd_increaseFont");
|
|
goUpdateCommand("cmd_bold");
|
|
goUpdateCommand("cmd_italic");
|
|
goUpdateCommand("cmd_underline");
|
|
goUpdateCommand("cmd_ul");
|
|
goUpdateCommand("cmd_ol");
|
|
goUpdateCommand("cmd_indent");
|
|
goUpdateCommand("cmd_outdent");
|
|
goUpdateCommand("cmd_align");
|
|
goUpdateCommand("cmd_smiley");
|
|
}
|
|
|
|
// Options Menu
|
|
goUpdateCommand("cmd_spelling");
|
|
goUpdateCommand("cmd_quoteMessage");
|
|
} catch(e) {}
|
|
}
|
|
|
|
function openEditorContextMenu()
|
|
{
|
|
// if we have a mispelled word, do one thing, otherwise show the usual context menu
|
|
var spellCheckNoSuggestionsItem = document.getElementById('spellCheckNoSuggestions');
|
|
var word;
|
|
var misspelledWordStatus = InlineSpellChecker.updateSuggestionsMenu(document.getElementById('msgComposeContext'), spellCheckNoSuggestionsItem,
|
|
word);
|
|
|
|
var hideSpellingItems = (misspelledWordStatus == kSpellNoMispelling);
|
|
spellCheckNoSuggestionsItem.hidden = hideSpellingItems || misspelledWordStatus != kSpellNoSuggestionsFound;
|
|
document.getElementById('spellCheckAddToDictionary').hidden = hideSpellingItems;
|
|
document.getElementById('spellCheckIgnoreWord').hidden = hideSpellingItems;
|
|
document.getElementById('spellCheckAddSep').hidden = hideSpellingItems;
|
|
document.getElementById('spellCheckSuggestionsSeparator').hidden = hideSpellingItems;
|
|
|
|
updateEditItems();
|
|
}
|
|
|
|
function updateEditItems()
|
|
{
|
|
goUpdateCommand("cmd_pasteNoFormatting");
|
|
goUpdateCommand("cmd_pasteQuote");
|
|
goUpdateCommand("cmd_delete");
|
|
goUpdateCommand("cmd_selectAll");
|
|
goUpdateCommand("cmd_openAttachment");
|
|
goUpdateCommand("cmd_find");
|
|
goUpdateCommand("cmd_findNext");
|
|
goUpdateCommand("cmd_findPrev");
|
|
}
|
|
|
|
var messageComposeOfflineObserver = {
|
|
observe: function(subject, topic, state) {
|
|
// sanity checks
|
|
if (topic != "network:offline-status-changed") return;
|
|
if (state == "offline")
|
|
gIsOffline = true;
|
|
else
|
|
gIsOffline = false;
|
|
MessageComposeOfflineStateChanged(gIsOffline);
|
|
|
|
try {
|
|
setupLdapAutocompleteSession();
|
|
} catch (ex) {
|
|
// catch the exception and ignore it, so that if LDAP setup
|
|
// fails, the entire compose window stuff doesn't get aborted
|
|
}
|
|
}
|
|
}
|
|
|
|
function AddMessageComposeOfflineObserver()
|
|
{
|
|
var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
|
|
observerService.addObserver(messageComposeOfflineObserver, "network:offline-status-changed", false);
|
|
|
|
gIsOffline = gIOService.offline;
|
|
// set the initial state of the send button
|
|
MessageComposeOfflineStateChanged(gIsOffline);
|
|
}
|
|
|
|
function RemoveMessageComposeOfflineObserver()
|
|
{
|
|
var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
|
|
observerService.removeObserver(messageComposeOfflineObserver,"network:offline-status-changed");
|
|
}
|
|
|
|
function MessageComposeOfflineStateChanged(goingOffline)
|
|
{
|
|
try {
|
|
var sendButton = document.getElementById("button-send");
|
|
var sendNowMenuItem = document.getElementById("menu-item-send-now");
|
|
|
|
if (!gSavedSendNowKey) {
|
|
gSavedSendNowKey = sendNowMenuItem.getAttribute('key');
|
|
}
|
|
|
|
// don't use goUpdateCommand here ... the defaultController might not be installed yet
|
|
goSetCommandEnabled("cmd_sendNow", defaultController.isCommandEnabled("cmd_sendNow"));
|
|
|
|
if (goingOffline)
|
|
{
|
|
sendButton.label = sendButton.getAttribute('later_label');
|
|
sendButton.setAttribute('tooltiptext', sendButton.getAttribute('later_tooltiptext'));
|
|
sendNowMenuItem.removeAttribute('key');
|
|
}
|
|
else
|
|
{
|
|
sendButton.label = sendButton.getAttribute('now_label');
|
|
sendButton.setAttribute('tooltiptext', sendButton.getAttribute('now_tooltiptext'));
|
|
if (gSavedSendNowKey) {
|
|
sendNowMenuItem.setAttribute('key', gSavedSendNowKey);
|
|
}
|
|
}
|
|
|
|
} catch(e) {}
|
|
}
|
|
|
|
var directoryServerObserver = {
|
|
observe: function(subject, topic, value) {
|
|
try {
|
|
setupLdapAutocompleteSession();
|
|
} catch (ex) {
|
|
// catch the exception and ignore it, so that if LDAP setup
|
|
// fails, the entire compose window doesn't get horked
|
|
}
|
|
}
|
|
}
|
|
|
|
function AddDirectoryServerObserver(flag) {
|
|
if (flag) {
|
|
sPrefBranchInternal.addObserver("ldap_2.autoComplete.useDirectory",
|
|
directoryServerObserver, false);
|
|
sPrefBranchInternal.addObserver("ldap_2.autoComplete.directoryServer",
|
|
directoryServerObserver, false);
|
|
}
|
|
else
|
|
{
|
|
var prefstring = "mail.identity." + gCurrentIdentity.key + ".overrideGlobal_Pref";
|
|
sPrefBranchInternal.addObserver(prefstring, directoryServerObserver, false);
|
|
prefstring = "mail.identity." + gCurrentIdentity.key + ".directoryServer";
|
|
sPrefBranchInternal.addObserver(prefstring, directoryServerObserver, false);
|
|
}
|
|
}
|
|
|
|
function RemoveDirectoryServerObserver(prefstring)
|
|
{
|
|
if (!prefstring) {
|
|
sPrefBranchInternal.removeObserver("ldap_2.autoComplete.useDirectory", directoryServerObserver);
|
|
sPrefBranchInternal.removeObserver("ldap_2.autoComplete.directoryServer", directoryServerObserver);
|
|
}
|
|
else
|
|
{
|
|
var str = prefstring + ".overrideGlobal_Pref";
|
|
sPrefBranchInternal.removeObserver(str, directoryServerObserver);
|
|
str = prefstring + ".directoryServer";
|
|
sPrefBranchInternal.removeObserver(str, directoryServerObserver);
|
|
}
|
|
}
|
|
|
|
function AddDirectorySettingsObserver()
|
|
{
|
|
sPrefBranchInternal.addObserver(gCurrentAutocompleteDirectory, directoryServerObserver, false);
|
|
}
|
|
|
|
function RemoveDirectorySettingsObserver(prefstring)
|
|
{
|
|
sPrefBranchInternal.removeObserver(prefstring, directoryServerObserver);
|
|
}
|
|
|
|
function setupLdapAutocompleteSession()
|
|
{
|
|
var autocompleteLdap = false;
|
|
var autocompleteDirectory = null;
|
|
var prevAutocompleteDirectory = gCurrentAutocompleteDirectory;
|
|
var i;
|
|
|
|
autocompleteLdap = sPrefs.getBoolPref("ldap_2.autoComplete.useDirectory");
|
|
if (autocompleteLdap)
|
|
autocompleteDirectory = sPrefs.getCharPref(
|
|
"ldap_2.autoComplete.directoryServer");
|
|
|
|
if(gCurrentIdentity.overrideGlobalPref) {
|
|
autocompleteDirectory = gCurrentIdentity.directoryServer;
|
|
}
|
|
|
|
// use a temporary to do the setup so that we don't overwrite the
|
|
// global, then have some problem and throw an exception, and leave the
|
|
// global with a partially setup session. we'll assign the temp
|
|
// into the global after we're done setting up the session
|
|
//
|
|
var LDAPSession;
|
|
if (gLDAPSession) {
|
|
LDAPSession = gLDAPSession;
|
|
} else {
|
|
LDAPSession = Components
|
|
.classes["@mozilla.org/autocompleteSession;1?type=ldap"];
|
|
if (LDAPSession) {
|
|
try {
|
|
LDAPSession = LDAPSession.createInstance()
|
|
.QueryInterface(Components.interfaces.nsILDAPAutoCompleteSession);
|
|
} catch (ex) {dump ("ERROR: Cannot get the LDAP autocomplete session\n" + ex + "\n");}
|
|
}
|
|
}
|
|
|
|
if (autocompleteDirectory && !gIsOffline) {
|
|
// Add observer on the directory server we are autocompleting against
|
|
// only if current server is different from previous.
|
|
// Remove observer if current server is different from previous
|
|
gCurrentAutocompleteDirectory = autocompleteDirectory;
|
|
if (prevAutocompleteDirectory) {
|
|
if (prevAutocompleteDirectory != gCurrentAutocompleteDirectory) {
|
|
RemoveDirectorySettingsObserver(prevAutocompleteDirectory);
|
|
AddDirectorySettingsObserver();
|
|
}
|
|
}
|
|
else
|
|
AddDirectorySettingsObserver();
|
|
|
|
// fill in the session params if there is a session
|
|
//
|
|
if (LDAPSession) {
|
|
var serverURL = Components.classes[
|
|
"@mozilla.org/network/ldap-url;1"].
|
|
createInstance().QueryInterface(
|
|
Components.interfaces.nsILDAPURL);
|
|
|
|
try {
|
|
serverURL.spec = sPrefs.getComplexValue(autocompleteDirectory +".uri",
|
|
Components.interfaces.nsISupportsString).data;
|
|
} catch (ex) {
|
|
dump("ERROR: " + ex + "\n");
|
|
}
|
|
LDAPSession.serverURL = serverURL;
|
|
|
|
// get the login to authenticate as, if there is one
|
|
//
|
|
var login = "";
|
|
try {
|
|
login = sPrefs.getComplexValue(
|
|
autocompleteDirectory + ".auth.dn",
|
|
Components.interfaces.nsISupportsString).data;
|
|
} catch (ex) {
|
|
// if we don't have this pref, no big deal
|
|
}
|
|
|
|
// set the LDAP protocol version correctly
|
|
var protocolVersion;
|
|
try {
|
|
protocolVersion = sPrefs.getCharPref(autocompleteDirectory +
|
|
".protocolVersion");
|
|
} catch (ex) {
|
|
// if we don't have this pref, no big deal
|
|
}
|
|
if (protocolVersion == "2") {
|
|
LDAPSession.version =
|
|
Components.interfaces.nsILDAPConnection.VERSION2;
|
|
}
|
|
|
|
// find out if we need to authenticate, and if so, tell the LDAP
|
|
// autocomplete session how to prompt for a password. This window
|
|
// (the compose window) is being used to parent the authprompter.
|
|
//
|
|
LDAPSession.login = login;
|
|
if (login != "") {
|
|
var windowWatcherSvc = Components.classes[
|
|
"@mozilla.org/embedcomp/window-watcher;1"]
|
|
.getService(Components.interfaces.nsIWindowWatcher);
|
|
var domWin =
|
|
window.QueryInterface(Components.interfaces.nsIDOMWindow);
|
|
var authPrompter =
|
|
windowWatcherSvc.getNewAuthPrompter(domWin);
|
|
|
|
LDAPSession.authPrompter = authPrompter;
|
|
}
|
|
|
|
// don't search on non-CJK strings shorter than this
|
|
//
|
|
try {
|
|
LDAPSession.minStringLength = sPrefs.getIntPref(
|
|
autocompleteDirectory + ".autoComplete.minStringLength");
|
|
} catch (ex) {
|
|
// if this pref isn't there, no big deal. just let
|
|
// nsLDAPAutoCompleteSession use its default.
|
|
}
|
|
|
|
// don't search on CJK strings shorter than this
|
|
//
|
|
try {
|
|
LDAPSession.cjkMinStringLength = sPrefs.getIntPref(
|
|
autocompleteDirectory + ".autoComplete.cjkMinStringLength");
|
|
} catch (ex) {
|
|
// if this pref isn't there, no big deal. just let
|
|
// nsLDAPAutoCompleteSession use its default.
|
|
}
|
|
|
|
// we don't try/catch here, because if this fails, we're outta luck
|
|
//
|
|
var ldapFormatter = Components.classes[
|
|
"@mozilla.org/ldap-autocomplete-formatter;1?type=addrbook"]
|
|
.createInstance().QueryInterface(
|
|
Components.interfaces.nsIAbLDAPAutoCompFormatter);
|
|
|
|
// override autocomplete name format?
|
|
//
|
|
try {
|
|
ldapFormatter.nameFormat =
|
|
sPrefs.getComplexValue(autocompleteDirectory +
|
|
".autoComplete.nameFormat",
|
|
Components.interfaces.nsISupportsString).data;
|
|
} catch (ex) {
|
|
// if this pref isn't there, no big deal. just let
|
|
// nsAbLDAPAutoCompFormatter use its default.
|
|
}
|
|
|
|
// override autocomplete mail address format?
|
|
//
|
|
try {
|
|
ldapFormatter.addressFormat =
|
|
sPrefs.getComplexValue(autocompleteDirectory +
|
|
".autoComplete.addressFormat",
|
|
Components.interfaces.nsISupportsString).data;
|
|
} catch (ex) {
|
|
// if this pref isn't there, no big deal. just let
|
|
// nsAbLDAPAutoCompFormatter use its default.
|
|
}
|
|
|
|
try {
|
|
// figure out what goes in the comment column, if anything
|
|
//
|
|
// 0 = none
|
|
// 1 = name of addressbook this card came from
|
|
// 2 = other per-addressbook format
|
|
//
|
|
var showComments = 0;
|
|
showComments = sPrefs.getIntPref(
|
|
"mail.autoComplete.commentColumn");
|
|
|
|
switch (showComments) {
|
|
|
|
case 1:
|
|
// use the name of this directory
|
|
//
|
|
ldapFormatter.commentFormat = sPrefs.getComplexValue(
|
|
autocompleteDirectory + ".description",
|
|
Components.interfaces.nsISupportsString).data;
|
|
break;
|
|
|
|
case 2:
|
|
// override ldap-specific autocomplete entry?
|
|
//
|
|
try {
|
|
ldapFormatter.commentFormat =
|
|
sPrefs.getComplexValue(autocompleteDirectory +
|
|
".autoComplete.commentFormat",
|
|
Components.interfaces.nsISupportsString).data;
|
|
} catch (innerException) {
|
|
// if nothing has been specified, use the ldap
|
|
// organization field
|
|
ldapFormatter.commentFormat = "[o]";
|
|
}
|
|
break;
|
|
|
|
case 0:
|
|
default:
|
|
// do nothing
|
|
}
|
|
} catch (ex) {
|
|
// if something went wrong while setting up comments, try and
|
|
// proceed anyway
|
|
}
|
|
|
|
// set the session's formatter, which also happens to
|
|
// force a call to the formatter's getAttributes() method
|
|
// -- which is why this needs to happen after we've set the
|
|
// various formats
|
|
//
|
|
LDAPSession.formatter = ldapFormatter;
|
|
|
|
// override autocomplete entry formatting?
|
|
//
|
|
try {
|
|
LDAPSession.outputFormat =
|
|
sPrefs.getComplexValue(autocompleteDirectory +
|
|
".autoComplete.outputFormat",
|
|
Components.interfaces.nsISupportsString).data;
|
|
|
|
} catch (ex) {
|
|
// if this pref isn't there, no big deal. just let
|
|
// nsLDAPAutoCompleteSession use its default.
|
|
}
|
|
|
|
// override default search filter template?
|
|
//
|
|
try {
|
|
LDAPSession.filterTemplate = sPrefs.getComplexValue(
|
|
autocompleteDirectory + ".autoComplete.filterTemplate",
|
|
Components.interfaces.nsISupportsString).data;
|
|
|
|
} catch (ex) {
|
|
// if this pref isn't there, no big deal. just let
|
|
// nsLDAPAutoCompleteSession use its default
|
|
}
|
|
|
|
// override default maxHits (currently 100)
|
|
//
|
|
try {
|
|
// XXXdmose should really use .autocomplete.maxHits,
|
|
// but there's no UI for that yet
|
|
//
|
|
LDAPSession.maxHits =
|
|
sPrefs.getIntPref(autocompleteDirectory + ".maxHits");
|
|
} catch (ex) {
|
|
// if this pref isn't there, or is out of range, no big deal.
|
|
// just let nsLDAPAutoCompleteSession use its default.
|
|
}
|
|
|
|
if (!gSessionAdded) {
|
|
// if we make it here, we know that session initialization has
|
|
// succeeded; add the session for all recipients, and
|
|
// remember that we've done so
|
|
var autoCompleteWidget;
|
|
for (i=1; i <= awGetMaxRecipients(); i++)
|
|
{
|
|
autoCompleteWidget = document.getElementById("addressCol2#" + i);
|
|
if (autoCompleteWidget)
|
|
{
|
|
autoCompleteWidget.addSession(LDAPSession);
|
|
// ldap searches don't insert a default entry with the default domain appended to it
|
|
// so reduce the minimum results for a popup to 2 in this case.
|
|
autoCompleteWidget.minResultsForPopup = 2;
|
|
|
|
}
|
|
}
|
|
gSessionAdded = true;
|
|
}
|
|
}
|
|
} else {
|
|
if (gCurrentAutocompleteDirectory) {
|
|
// Remove observer on the directory server since we are not doing Ldap
|
|
// autocompletion.
|
|
RemoveDirectorySettingsObserver(gCurrentAutocompleteDirectory);
|
|
gCurrentAutocompleteDirectory = null;
|
|
}
|
|
if (gLDAPSession && gSessionAdded) {
|
|
for (i=1; i <= awGetMaxRecipients(); i++)
|
|
document.getElementById("addressCol2#" + i).
|
|
removeSession(gLDAPSession);
|
|
gSessionAdded = false;
|
|
}
|
|
}
|
|
|
|
gLDAPSession = LDAPSession;
|
|
gSetupLdapAutocomplete = true;
|
|
}
|
|
|
|
function DoCommandClose()
|
|
{
|
|
var retVal;
|
|
if ((retVal = ComposeCanClose())) {
|
|
|
|
// Notify the SendListener that Send has been aborted and Stopped
|
|
if (gMsgCompose)
|
|
{
|
|
var externalListener = gMsgCompose.getExternalSendListener();
|
|
if (externalListener)
|
|
{
|
|
externalListener.onSendNotPerformed(null, Components.results.NS_ERROR_ABORT);
|
|
}
|
|
}
|
|
|
|
MsgComposeCloseWindow(true);
|
|
|
|
// at this point, we might be caching this window.
|
|
// in which case, we don't want to close it
|
|
if (sMsgComposeService.isCachedWindow(window)) {
|
|
retVal = false;
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
function DoCommandPrint()
|
|
{
|
|
try {
|
|
NSPrint();
|
|
} catch(ex) {dump("#PRINT ERROR: " + ex + "\n");}
|
|
}
|
|
|
|
function ToggleWindowLock()
|
|
{
|
|
gWindowLocked = !gWindowLocked;
|
|
updateComposeItems();
|
|
}
|
|
|
|
/* This function will go away soon as now arguments are passed to the window using a object of type nsMsgComposeParams instead of a string */
|
|
function GetArgs(originalData)
|
|
{
|
|
var args = new Object();
|
|
|
|
if (originalData == "")
|
|
return null;
|
|
|
|
var data = "";
|
|
var separator = String.fromCharCode(1);
|
|
|
|
var quoteChar = "";
|
|
var prevChar = "";
|
|
var nextChar = "";
|
|
for (var i = 0; i < originalData.length; i ++, prevChar = aChar)
|
|
{
|
|
var aChar = originalData.charAt(i)
|
|
var aCharCode = originalData.charCodeAt(i)
|
|
if ( i < originalData.length - 1)
|
|
nextChar = originalData.charAt(i + 1);
|
|
else
|
|
nextChar = "";
|
|
|
|
if (aChar == quoteChar && (nextChar == "," || nextChar == ""))
|
|
{
|
|
quoteChar = "";
|
|
data += aChar;
|
|
}
|
|
else if ((aCharCode == 39 || aCharCode == 34) && prevChar == "=") //quote or double quote
|
|
{
|
|
if (quoteChar == "")
|
|
quoteChar = aChar;
|
|
data += aChar;
|
|
}
|
|
else if (aChar == ",")
|
|
{
|
|
if (quoteChar == "")
|
|
data += separator;
|
|
else
|
|
data += aChar
|
|
}
|
|
else
|
|
data += aChar
|
|
}
|
|
|
|
var pairs = data.split(separator);
|
|
// dump("Compose: argument: {" + data + "}\n");
|
|
|
|
for (i = pairs.length - 1; i >= 0; i--)
|
|
{
|
|
var pos = pairs[i].indexOf('=');
|
|
if (pos == -1)
|
|
continue;
|
|
var argname = pairs[i].substring(0, pos);
|
|
var argvalue = pairs[i].substring(pos + 1);
|
|
if (argvalue.charAt(0) == "'" && argvalue.charAt(argvalue.length - 1) == "'")
|
|
args[argname] = argvalue.substring(1, argvalue.length - 1);
|
|
else
|
|
try {
|
|
args[argname] = decodeURIComponent(argvalue);
|
|
} catch (e) {args[argname] = argvalue;}
|
|
dump("[" + argname + "=" + args[argname] + "]\n");
|
|
}
|
|
return args;
|
|
}
|
|
|
|
function ComposeFieldsReady()
|
|
{
|
|
//If we are in plain text, we need to set the wrap column
|
|
if (! gMsgCompose.composeHTML) {
|
|
try {
|
|
gMsgCompose.editor.QueryInterface(nsIPlaintextEditorMail).wrapWidth
|
|
= gMsgCompose.wrapLength;
|
|
}
|
|
catch (e) {
|
|
dump("### textEditor.wrapWidth exception text: " + e + " - failed\n");
|
|
}
|
|
}
|
|
CompFields2Recipients(gMsgCompose.compFields);
|
|
SetComposeWindowTitle();
|
|
|
|
// need timeout for reply to work
|
|
if (gMsgCompose.composeHTML)
|
|
setTimeout("loadHTMLMsgPrefs();", 0);
|
|
|
|
enableEditableFields();
|
|
AdjustFocus();
|
|
}
|
|
|
|
// checks if the passed in string is a mailto url, if it is, generates nsIMsgComposeParams
|
|
// for the url and returns them.
|
|
function handleMailtoArgs(mailtoUrl)
|
|
{
|
|
// see if the string is a mailto url....do this by checking the first 7 characters of the string
|
|
if (/^mailto:/i.test(mailtoUrl))
|
|
{
|
|
// if it is a mailto url, turn the mailto url into a MsgComposeParams object....
|
|
var uri = gIOService.newURI(mailtoUrl, null, null);
|
|
|
|
if (uri)
|
|
return sMsgComposeService.getParamsForMailto(uri);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function ComposeStartup(recycled, aParams)
|
|
{
|
|
var params = null; // New way to pass parameters to the compose window as a nsIMsgComposeParameters object
|
|
var args = null; // old way, parameters are passed as a string
|
|
|
|
if (aParams)
|
|
params = aParams;
|
|
else if (window.arguments && window.arguments[0]) {
|
|
try {
|
|
if (window.arguments[0] instanceof Components.interfaces.nsIMsgComposeParams)
|
|
params = window.arguments[0];
|
|
else
|
|
params = handleMailtoArgs(window.arguments[0]);
|
|
}
|
|
catch(ex) { dump("ERROR with parameters: " + ex + "\n"); }
|
|
|
|
// if still no dice, try and see if the params is an old fashioned list of string attributes
|
|
// XXX can we get rid of this yet?
|
|
if (!params)
|
|
{
|
|
args = GetArgs(window.arguments[0]);
|
|
}
|
|
}
|
|
|
|
var identityList = document.getElementById("msgIdentity");
|
|
|
|
document.addEventListener("keypress", awDocumentKeyPress, true);
|
|
|
|
if (identityList)
|
|
FillIdentityList(identityList);
|
|
|
|
if (!params) {
|
|
// This code will go away soon as now arguments are passed to the window using a object of type nsMsgComposeParams instead of a string
|
|
|
|
params = Components.classes["@mozilla.org/messengercompose/composeparams;1"].createInstance(Components.interfaces.nsIMsgComposeParams);
|
|
params.composeFields = Components.classes["@mozilla.org/messengercompose/composefields;1"].createInstance(Components.interfaces.nsIMsgCompFields);
|
|
|
|
if (args) { //Convert old fashion arguments into params
|
|
var composeFields = params.composeFields;
|
|
if (args.bodyislink == "true")
|
|
params.bodyIsLink = true;
|
|
if (args.type)
|
|
params.type = args.type;
|
|
if (args.format)
|
|
params.format = args.format;
|
|
if (args.originalMsg)
|
|
params.originalMsgURI = args.originalMsg;
|
|
if (args.preselectid)
|
|
params.identity = getIdentityForKey(args.preselectid);
|
|
if (args.to)
|
|
composeFields.to = args.to;
|
|
if (args.cc)
|
|
composeFields.cc = args.cc;
|
|
if (args.bcc)
|
|
composeFields.bcc = args.bcc;
|
|
if (args.newsgroups)
|
|
composeFields.newsgroups = args.newsgroups;
|
|
if (args.subject)
|
|
composeFields.subject = args.subject;
|
|
if (args.attachment)
|
|
{
|
|
var attachmentList = args.attachment.split(",");
|
|
var attachment;
|
|
for (var i = 0; i < attachmentList.length; i ++)
|
|
{
|
|
attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment);
|
|
attachment.url = attachmentList[i];
|
|
composeFields.addAttachment(attachment);
|
|
}
|
|
}
|
|
if (args.newshost)
|
|
composeFields.newshost = args.newshost;
|
|
if (args.body)
|
|
composeFields.body = args.body;
|
|
}
|
|
}
|
|
|
|
// " <>" is an empty identity, and most likely not valid
|
|
if (!params.identity || params.identity.identityName == " <>") {
|
|
// no pre selected identity, so use the default account
|
|
var identities = gAccountManager.defaultAccount.identities;
|
|
if (identities.Count() == 0)
|
|
identities = gAccountManager.allIdentities;
|
|
params.identity = identities.QueryElementAt(0, Components.interfaces.nsIMsgIdentity);
|
|
}
|
|
|
|
identityList.value = params.identity.key;
|
|
LoadIdentity(true);
|
|
if (sMsgComposeService)
|
|
{
|
|
gMsgCompose = sMsgComposeService.InitCompose(window, params);
|
|
if (gMsgCompose)
|
|
{
|
|
// set the close listener
|
|
gMsgCompose.recyclingListener = gComposeRecyclingListener;
|
|
|
|
//Lets the compose object knows that we are dealing with a recycled window
|
|
gMsgCompose.recycledWindow = recycled;
|
|
|
|
// Get the <editor> element to startup an editor
|
|
var editorElement = GetCurrentEditorElement();
|
|
if (!editorElement)
|
|
{
|
|
dump("Failed to get editor element!\n");
|
|
return;
|
|
}
|
|
|
|
document.getElementById("returnReceiptMenu").setAttribute('checked',
|
|
gMsgCompose.compFields.returnReceipt);
|
|
document.getElementById("cmd_attachVCard").setAttribute('checked',
|
|
gMsgCompose.compFields.attachVCard);
|
|
document.getElementById("menu_inlineSpellCheck").setAttribute('checked', sPrefs.getBoolPref("mail.spellcheck.inline"));
|
|
|
|
// If recycle, editor is already created
|
|
if (!recycled)
|
|
{
|
|
try {
|
|
var editortype = gMsgCompose.composeHTML ? "htmlmail" : "textmail";
|
|
editorElement.makeEditable(editortype, true);
|
|
} catch (e) { dump(" FAILED TO START EDITOR: "+e+"\n"); }
|
|
|
|
// setEditorType MUST be call before setContentWindow
|
|
if (gMsgCompose.composeHTML)
|
|
{
|
|
initLocalFontFaceMenu(document.getElementById("FontFacePopup"));
|
|
}
|
|
else
|
|
{
|
|
//Remove HTML toolbar, format and insert menus as we are editing in plain text mode
|
|
document.getElementById("outputFormatMenu").setAttribute("hidden", true);
|
|
document.getElementById("FormatToolbar").setAttribute("hidden", true);
|
|
document.getElementById("formatMenu").setAttribute("hidden", true);
|
|
document.getElementById("insertMenu").setAttribute("hidden", true);
|
|
document.getElementById("menu_showFormatToolbar").setAttribute("hidden", true);
|
|
}
|
|
|
|
// Do setup common to Message Composer and Web Composer
|
|
EditorSharedStartup();
|
|
}
|
|
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
if (msgCompFields)
|
|
{
|
|
if (params.bodyIsLink)
|
|
{
|
|
var body = msgCompFields.body;
|
|
if (gMsgCompose.composeHTML)
|
|
{
|
|
var cleanBody;
|
|
try {
|
|
cleanBody = decodeURI(body);
|
|
} catch(e) { cleanBody = body;}
|
|
|
|
// XXX : need to do html-escaping here !
|
|
msgCompFields.body = "<BR><A HREF=\"" + body + "\">" + cleanBody + "</A><BR>";
|
|
}
|
|
else
|
|
msgCompFields.body = "\n<" + body + ">\n";
|
|
}
|
|
|
|
var subjectValue = msgCompFields.subject;
|
|
GetMsgSubjectElement().value = subjectValue;
|
|
|
|
var attachments = msgCompFields.attachmentsArray;
|
|
if (attachments)
|
|
for (i = 0; i < attachments.Count(); i ++)
|
|
AddAttachment(attachments.QueryElementAt(i, Components.interfaces.nsIMsgAttachment));
|
|
|
|
if (attachments.Count())
|
|
{
|
|
ChangeAttachmentBucketVisibility(false);
|
|
}
|
|
}
|
|
|
|
var event = document.createEvent('Events');
|
|
event.initEvent('compose-window-init', false, true);
|
|
document.getElementById("msgcomposeWindow").dispatchEvent(event);
|
|
|
|
gMsgCompose.RegisterStateListener(stateListener);
|
|
|
|
if (recycled)
|
|
{
|
|
InitEditor();
|
|
|
|
if (gMsgCompose.composeHTML)
|
|
{
|
|
// Force color picker on toolbar to show document colors
|
|
onFontColorChange();
|
|
onBackgroundColorChange();
|
|
}
|
|
|
|
// reset the priorty field for recycled windows
|
|
updatePriorityToolbarButton('Normal');
|
|
}
|
|
else
|
|
{
|
|
// Add an observer to be called when document is done loading,
|
|
// which creates the editor
|
|
try {
|
|
GetCurrentCommandManager().
|
|
addCommandObserver(gMsgEditorCreationObserver, "obs_documentCreated");
|
|
|
|
// Load empty page to create the editor
|
|
editorElement.webNavigation.loadURI("about:blank", // uri string
|
|
0, // load flags
|
|
null, // referrer
|
|
null, // post-data stream
|
|
null);
|
|
} catch (e) {
|
|
dump(" Failed to startup editor: "+e+"\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// finally, see if we need to auto open the address sidebar.
|
|
var sideBarBox = document.getElementById('sidebar-box');
|
|
if (sideBarBox.getAttribute("sidebarVisible") == "true")
|
|
{
|
|
// if we aren't supposed to have the side bar hidden, make sure it is visible
|
|
if (document.getElementById("sidebar").getAttribute("src") == "")
|
|
setTimeout(toggleAddressPicker, 0); // do this on a delay so we don't hurt perf. on bringing up a new compose window
|
|
}
|
|
gAutoSaveInterval = sPrefs.getBoolPref("mail.compose.autosave")
|
|
? sPrefs.getIntPref("mail.compose.autosaveinterval") * 60000
|
|
: 0;
|
|
|
|
if (gAutoSaveInterval)
|
|
gAutoSaveTimeout = setTimeout(AutoSave, gAutoSaveInterval);
|
|
}
|
|
|
|
// The new, nice, simple way of getting notified when a new editor has been created
|
|
var gMsgEditorCreationObserver =
|
|
{
|
|
observe: function(aSubject, aTopic, aData)
|
|
{
|
|
if (aTopic == "obs_documentCreated")
|
|
{
|
|
var editor = GetCurrentEditor();
|
|
if (editor && GetCurrentCommandManager() == aSubject)
|
|
{
|
|
var editorStyle = editor.QueryInterface(Components.interfaces.nsIEditorStyleSheets);
|
|
editorStyle.addStyleSheet("chrome://messenger/skin/messageQuotes.css");
|
|
InitEditor();
|
|
}
|
|
// Now that we know this document is an editor, update commands now if
|
|
// the document has focus, or next time it receives focus via
|
|
// CommandUpdate_MsgCompose()
|
|
if (gLastWindowToHaveFocus == document.commandDispatcher.focusedWindow)
|
|
updateComposeItems();
|
|
else
|
|
gLastWindowToHaveFocus = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
function WizCallback(state)
|
|
{
|
|
if (state){
|
|
ComposeStartup(false, null);
|
|
}
|
|
else
|
|
{
|
|
if (gMsgCompose)
|
|
gMsgCompose.CloseWindow(false); //Don't try to recyle a bogus window
|
|
else
|
|
window.close();
|
|
// window.tryToClose=ComposeCanClose;
|
|
}
|
|
}
|
|
|
|
function ComposeLoad()
|
|
{
|
|
// First get the preferences service
|
|
try {
|
|
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
|
|
.getService(Components.interfaces.nsIPrefService);
|
|
sPrefs = prefService.getBranch(null);
|
|
sPrefBranchInternal = sPrefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
|
|
}
|
|
catch (ex) {
|
|
dump("failed to preferences services\n");
|
|
}
|
|
|
|
try {
|
|
sOther_headers = sPrefs.getCharPref("mail.compose.other.header");
|
|
}
|
|
catch (ex) {
|
|
dump("failed to get the mail.compose.other.header pref\n");
|
|
}
|
|
|
|
try {
|
|
sAccountManagerDataSource = Components.classes["@mozilla.org/rdf/datasource;1?name=msgaccountmanager"].getService(Components.interfaces.nsIRDFDataSource);
|
|
sRDF = Components.classes['@mozilla.org/rdf/rdf-service;1'].getService(Components.interfaces.nsIRDFService);
|
|
sNameProperty = sRDF.GetResource("http://home.netscape.com/NC-rdf#Name?sort=true");
|
|
}
|
|
catch (ex) {
|
|
dump("failed to get RDF\n");
|
|
}
|
|
|
|
AddMessageComposeOfflineObserver();
|
|
AddDirectoryServerObserver(true);
|
|
|
|
try {
|
|
// XXX: We used to set commentColumn on the initial auto complete column after the document has loaded
|
|
// inside of setupAutocomplete. But this happens too late for the first widget and it was never showing
|
|
// the comment field. Try to set it before the document finishes loading:
|
|
if (sPrefs.getIntPref("mail.autoComplete.commentColumn"))
|
|
document.getElementById('addressCol2#1').showCommentColumn = true;
|
|
}
|
|
catch (ex) {
|
|
// do nothing...
|
|
}
|
|
|
|
if (gLogComposePerformance)
|
|
sMsgComposeService.TimeStamp("Start initializing the compose window (ComposeLoad)", false);
|
|
|
|
try {
|
|
SetupCommandUpdateHandlers();
|
|
var wizardcallback = true;
|
|
var state = verifyAccounts(wizardcallback); // this will do migration, or create a new account if we need to.
|
|
|
|
if (sOther_headers) {
|
|
var selectNode = document.getElementById('addressCol1#1');
|
|
var sOther_headers_Array = sOther_headers.split(",");
|
|
for (var i = 0; i < sOther_headers_Array.length; i++)
|
|
selectNode.appendItem(sOther_headers_Array[i] + ":", "addr_other");
|
|
}
|
|
if (state)
|
|
ComposeStartup(false, null);
|
|
}
|
|
catch (ex) {
|
|
dump("EX: = " + ex + "\n");
|
|
var errorTitle = sComposeMsgsBundle.getString("initErrorDlogTitle");
|
|
var errorMsg = sComposeMsgsBundle.getFormattedString("initErrorDlogMessage",
|
|
[""]);
|
|
if (gPromptService)
|
|
gPromptService.alert(window, errorTitle, errorMsg);
|
|
else
|
|
window.alert(errorMsg);
|
|
|
|
if (gMsgCompose)
|
|
gMsgCompose.CloseWindow(false); //Don't try to recycle a bogus window
|
|
else
|
|
window.close();
|
|
return;
|
|
}
|
|
window.tryToClose=ComposeCanClose;
|
|
if (gLogComposePerformance)
|
|
sMsgComposeService.TimeStamp("Done with the initialization (ComposeLoad). Waiting on editor to load about:blank", false);
|
|
|
|
// initialize the customizeDone method on the customizeable toolbar
|
|
var toolbox = document.getElementById("compose-toolbox");
|
|
toolbox.customizeDone = MailToolboxCustomizeDone;
|
|
|
|
var toolbarset = document.getElementById('customToolbars');
|
|
toolbox.toolbarset = toolbarset;
|
|
}
|
|
|
|
function ComposeUnload()
|
|
{
|
|
dump("\nComposeUnload from XUL\n");
|
|
|
|
EditorCleanup();
|
|
|
|
RemoveMessageComposeOfflineObserver();
|
|
RemoveDirectoryServerObserver(null);
|
|
if (gCurrentIdentity)
|
|
RemoveDirectoryServerObserver("mail.identity." + gCurrentIdentity.key);
|
|
if (gCurrentAutocompleteDirectory)
|
|
RemoveDirectorySettingsObserver(gCurrentAutocompleteDirectory);
|
|
if (gMsgCompose)
|
|
gMsgCompose.UnregisterStateListener(stateListener);
|
|
if (gAutoSaveTimeout)
|
|
clearTimeout(gAutoSaveTimeout);
|
|
}
|
|
|
|
function SetDocumentCharacterSet(aCharset)
|
|
{
|
|
dump("SetDocumentCharacterSet Callback!\n");
|
|
dump(aCharset + "\n");
|
|
|
|
if (gMsgCompose) {
|
|
gMsgCompose.SetDocumentCharset(aCharset);
|
|
gCurrentMailSendCharset = aCharset;
|
|
gCharsetTitle = null;
|
|
SetComposeWindowTitle();
|
|
}
|
|
else
|
|
dump("Compose has not been created!\n");
|
|
}
|
|
|
|
function UpdateMailEditCharset()
|
|
{
|
|
var send_default_charset = gMsgCompose.compFields.defaultCharacterSet;
|
|
// dump("send_default_charset is " + send_default_charset + "\n");
|
|
|
|
var compFieldsCharset = gMsgCompose.compFields.characterSet;
|
|
// dump("gMsgCompose.compFields is " + compFieldsCharset + "\n");
|
|
|
|
if (gCharsetConvertManager) {
|
|
var charsetAlias = gCharsetConvertManager.getCharsetAlias(compFieldsCharset);
|
|
if (charsetAlias == "us-ascii")
|
|
compFieldsCharset = "ISO-8859-1"; // no menu item for "us-ascii"
|
|
}
|
|
|
|
// charset may have been set implicitly in case of reply/forward
|
|
// or use pref default otherwise
|
|
var menuitem = document.getElementById(send_default_charset == compFieldsCharset ?
|
|
send_default_charset : compFieldsCharset);
|
|
if (menuitem)
|
|
menuitem.setAttribute('checked', 'true');
|
|
|
|
// Set a document charset to a default mail send charset.
|
|
if (send_default_charset == compFieldsCharset)
|
|
SetDocumentCharacterSet(send_default_charset);
|
|
}
|
|
|
|
function InitCharsetMenuCheckMark()
|
|
{
|
|
// return if the charset is already set explitily
|
|
if (gCurrentMailSendCharset != null) {
|
|
dump("already set to " + gCurrentMailSendCharset + "\n");
|
|
return;
|
|
}
|
|
|
|
// Check the menu
|
|
UpdateMailEditCharset();
|
|
// use setTimeout workaround to delay checkmark the menu
|
|
// when onmenucomplete is ready then use it instead of oncreate
|
|
// see bug #78290 for the details
|
|
setTimeout("UpdateMailEditCharset()", 0);
|
|
|
|
}
|
|
|
|
function GetCharsetUIString()
|
|
{
|
|
var charset = gMsgCompose.compFields.characterSet;
|
|
if (gSendDefaultCharset == null) {
|
|
gSendDefaultCharset = gMsgCompose.compFields.defaultCharacterSet;
|
|
}
|
|
|
|
charset = charset.toUpperCase();
|
|
if (charset == "US-ASCII")
|
|
charset = "ISO-8859-1";
|
|
|
|
if (charset != gSendDefaultCharset) {
|
|
|
|
if (gCharsetTitle == null) {
|
|
try {
|
|
// check if we have a converter for this charset
|
|
var charsetAlias = gCharsetConvertManager.getCharsetAlias(charset);
|
|
var encoderList = gCharsetConvertManager.getEncoderList();
|
|
var found = false;
|
|
while (encoderList.hasMore()) {
|
|
if (charsetAlias == encoderList.getNext()) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
dump("no charset converter available for " + charset + " default charset is used instead\n");
|
|
// set to default charset, no need to show it in the window title
|
|
gMsgCompose.compFields.characterSet = gSendDefaultCharset;
|
|
return "";
|
|
}
|
|
|
|
// get a localized string
|
|
gCharsetTitle = gCharsetConvertManager.getCharsetTitle(charsetAlias);
|
|
}
|
|
catch (ex) {
|
|
dump("failed to get a charset title of " + charset + "!\n");
|
|
dump("Exception: " + ex + "\n");
|
|
gCharsetTitle = charset; // just show the charset itself
|
|
}
|
|
}
|
|
|
|
return " - " + gCharsetTitle;
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
function GenericSendMessage( msgType )
|
|
{
|
|
dump("GenericSendMessage from XUL\n");
|
|
|
|
dump("Identity = " + getCurrentIdentity() + "\n");
|
|
|
|
if (gMsgCompose != null)
|
|
{
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
if (msgCompFields)
|
|
{
|
|
Recipients2CompFields(msgCompFields);
|
|
var subject = GetMsgSubjectElement().value;
|
|
msgCompFields.subject = subject;
|
|
Attachments2CompFields(msgCompFields);
|
|
|
|
if (msgType == nsIMsgCompDeliverMode.Now || msgType == nsIMsgCompDeliverMode.Later)
|
|
{
|
|
//Do we need to check the spelling?
|
|
if (sPrefs.getBoolPref("mail.SpellCheckBeforeSend"))
|
|
{
|
|
// We disable spellcheck for the following -subject line, attachment pane, identity and addressing widget
|
|
// therefore we need to explicitly focus on the mail body when we have to do a spellcheck.
|
|
SetMsgBodyFrameFocus();
|
|
window.cancelSendMessage = false;
|
|
try {
|
|
window.openDialog("chrome://editor/content/EdSpellCheck.xul", "_blank",
|
|
"chrome,close,titlebar,modal", true, true);
|
|
}
|
|
catch(ex){}
|
|
if(window.cancelSendMessage)
|
|
return;
|
|
}
|
|
|
|
// Check if we have a subject, else ask user for confirmation
|
|
if (subject == "")
|
|
{
|
|
if (gPromptService)
|
|
{
|
|
var result = {value:sComposeMsgsBundle.getString("defaultSubject")};
|
|
if (gPromptService.prompt(
|
|
window,
|
|
sComposeMsgsBundle.getString("sendMsgTitle"),
|
|
sComposeMsgsBundle.getString("subjectDlogMessage"),
|
|
result,
|
|
null,
|
|
{value:0}))
|
|
{
|
|
msgCompFields.subject = result.value;
|
|
var subjectInputElem = GetMsgSubjectElement();
|
|
subjectInputElem.value = result.value;
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
}
|
|
|
|
// check if the user tries to send a message to a newsgroup through a mail account
|
|
var currentAccountKey = getCurrentAccountKey();
|
|
var account = gAccountManager.getAccount(currentAccountKey);
|
|
if (!account)
|
|
{
|
|
throw "UNEXPECTED: currentAccountKey '" + currentAccountKey +
|
|
"' has no matching account!";
|
|
}
|
|
var servertype = account.incomingServer.type;
|
|
|
|
if (servertype != "nntp" && msgCompFields.newsgroups != "")
|
|
{
|
|
// default to ask user if the pref is not set
|
|
var dontAskAgain = sPrefs.getBoolPref("mail.compose.dontWarnMail2Newsgroup");
|
|
|
|
if (!dontAskAgain)
|
|
{
|
|
var checkbox = {value:false};
|
|
var okToProceed = gPromptService.confirmCheck(
|
|
window,
|
|
sComposeMsgsBundle.getString("sendMsgTitle"),
|
|
sComposeMsgsBundle.getString("recipientDlogMessage"),
|
|
sComposeMsgsBundle.getString("CheckMsg"),
|
|
checkbox);
|
|
|
|
if (!okToProceed)
|
|
return;
|
|
|
|
if (checkbox.value)
|
|
sPrefs.setBoolPref(kDontAskAgainPref, true);
|
|
}
|
|
|
|
// remove newsgroups to prevent news_p to be set
|
|
// in nsMsgComposeAndSend::DeliverMessage()
|
|
msgCompFields.newsgroups = "";
|
|
}
|
|
|
|
// Before sending the message, check what to do with HTML message, eventually abort.
|
|
var convert = DetermineConvertibility();
|
|
var action = DetermineHTMLAction(convert);
|
|
// check if e-mail addresses are complete, in case user
|
|
// has turned off autocomplete to local domain.
|
|
if (!CheckValidEmailAddress(msgCompFields.to, msgCompFields.cc, msgCompFields.bcc))
|
|
return;
|
|
|
|
if (action == nsIMsgCompSendFormat.AskUser)
|
|
{
|
|
var recommAction = (convert == nsIMsgCompConvertible.No)
|
|
? nsIMsgCompSendFormat.AskUser
|
|
: nsIMsgCompSendFormat.PlainText;
|
|
var result2 = {action:recommAction,
|
|
convertible:convert,
|
|
abort:false};
|
|
window.openDialog("chrome://messenger/content/messengercompose/askSendFormat.xul",
|
|
"askSendFormatDialog", "chrome,modal,titlebar,centerscreen",
|
|
result2);
|
|
if (result2.abort)
|
|
return;
|
|
action = result2.action;
|
|
}
|
|
|
|
// we will remember the users "send format" decision
|
|
// in the address collector code (see nsAbAddressCollecter::CollectAddress())
|
|
// by using msgCompFields.forcePlainText and msgCompFields.useMultipartAlternative
|
|
// to determine the nsIAbPreferMailFormat (unknown, plaintext, or html)
|
|
// if the user sends both, we remember html.
|
|
switch (action)
|
|
{
|
|
case nsIMsgCompSendFormat.PlainText:
|
|
msgCompFields.forcePlainText = true;
|
|
msgCompFields.useMultipartAlternative = false;
|
|
break;
|
|
case nsIMsgCompSendFormat.HTML:
|
|
msgCompFields.forcePlainText = false;
|
|
msgCompFields.useMultipartAlternative = false;
|
|
break;
|
|
case nsIMsgCompSendFormat.Both:
|
|
msgCompFields.forcePlainText = false;
|
|
msgCompFields.useMultipartAlternative = true;
|
|
break;
|
|
default: dump("\###SendMessage Error: invalid action value\n"); return;
|
|
}
|
|
}
|
|
|
|
// hook for extra compose pre-processing
|
|
var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
|
|
observerService.notifyObservers(window, "mail:composeOnSend", null);
|
|
|
|
// Check if the headers of composing mail can be converted to a mail charset.
|
|
if (msgType == nsIMsgCompDeliverMode.Now ||
|
|
msgType == nsIMsgCompDeliverMode.Later ||
|
|
msgType == nsIMsgCompDeliverMode.Save ||
|
|
msgType == nsIMsgCompDeliverMode.SaveAsDraft ||
|
|
msgType == nsIMsgCompDeliverMode.AutoSaveAsDraft ||
|
|
msgType == nsIMsgCompDeliverMode.SaveAsTemplate)
|
|
{
|
|
var fallbackCharset = new Object;
|
|
if (gPromptService &&
|
|
!gMsgCompose.checkCharsetConversion(getCurrentIdentity(), fallbackCharset))
|
|
{
|
|
var dlgTitle = sComposeMsgsBundle.getString("initErrorDlogTitle");
|
|
var dlgText = sComposeMsgsBundle.getString("12553"); // NS_ERROR_MSG_MULTILINGUAL_SEND
|
|
var result3 = gPromptService.confirmEx(window, dlgTitle, dlgText,
|
|
(gPromptService.BUTTON_TITLE_IS_STRING * gPromptService.BUTTON_POS_0) +
|
|
(gPromptService.BUTTON_TITLE_CANCEL * gPromptService.BUTTON_POS_1) +
|
|
(gPromptService.BUTTON_TITLE_IS_STRING * gPromptService.BUTTON_POS_2),
|
|
sComposeMsgsBundle.getString('sendInUTF8'),
|
|
null,
|
|
sComposeMsgsBundle.getString('sendAnyway'), null, {value:0});
|
|
switch(result3)
|
|
{
|
|
case 0:
|
|
fallbackCharset.value = "UTF-8";
|
|
break;
|
|
case 1: // cancel
|
|
return;
|
|
case 2: // send anyway
|
|
msgCompFields.needToCheckCharset = false;
|
|
break;
|
|
}
|
|
}
|
|
if (fallbackCharset &&
|
|
fallbackCharset.value && fallbackCharset.value != "")
|
|
gMsgCompose.SetDocumentCharset(fallbackCharset.value);
|
|
}
|
|
try {
|
|
|
|
// just before we try to send the message, fire off the compose-send-message event for listeners
|
|
// such as smime so they can do any pre-security work such as fetching certificates before sending
|
|
var event = document.createEvent('Events');
|
|
event.initEvent('compose-send-message', false, true);
|
|
document.getElementById("msgcomposeWindow").dispatchEvent(event);
|
|
gAutoSaving = (msgType == nsIMsgCompDeliverMode.AutoSaveAsDraft);
|
|
// disable the ui if we're not auto-saving
|
|
if (!gAutoSaving)
|
|
{
|
|
gWindowLocked = true;
|
|
disableEditableFields();
|
|
updateComposeItems();
|
|
}
|
|
// if we're auto saving, mark the body as not changed here, and not
|
|
// when the save is done, because the user might change it between now
|
|
// and when the save is done.
|
|
else
|
|
SetContentAndBodyAsUnmodified();
|
|
|
|
var progress = Components.classes["@mozilla.org/messenger/progress;1"].createInstance(Components.interfaces.nsIMsgProgress);
|
|
if (progress)
|
|
{
|
|
progress.registerListener(progressListener);
|
|
gSendOrSaveOperationInProgress = true;
|
|
}
|
|
msgWindow.domWindow = window;
|
|
msgWindow.rootDocShell.allowAuth = true;
|
|
gMsgCompose.SendMsg(msgType, getCurrentIdentity(), currentAccountKey, msgWindow, progress);
|
|
}
|
|
catch (ex) {
|
|
dump("failed to SendMsg: " + ex + "\n");
|
|
gWindowLocked = false;
|
|
enableEditableFields();
|
|
updateComposeItems();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
dump("###SendMessage Error: composeAppCore is null!\n");
|
|
}
|
|
|
|
function CheckValidEmailAddress(to, cc, bcc)
|
|
{
|
|
var invalidStr = null;
|
|
// crude check that the to, cc, and bcc fields contain at least one '@'.
|
|
// We could parse each address, but that might be overkill.
|
|
if (to.length > 0 && (to.indexOf("@") <= 0 || to.indexOf("@") == to.length - 1))
|
|
invalidStr = to;
|
|
else if (cc.length > 0 && (cc.indexOf("@") <= 0 || cc.indexOf("@") == cc.length - 1))
|
|
invalidStr = cc;
|
|
else if (bcc.length > 0 && (bcc.indexOf("@") <= 0 || bcc.indexOf("@") == bcc.length - 1))
|
|
invalidStr = bcc;
|
|
if (invalidStr)
|
|
{
|
|
var errorTitle = sComposeMsgsBundle.getString("sendMsgTitle");
|
|
var errorMsg = sComposeMsgsBundle.getFormattedString("addressInvalid", [invalidStr], 1);
|
|
if (gPromptService)
|
|
gPromptService.alert(window, errorTitle, errorMsg);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function SendMessage()
|
|
{
|
|
dump("SendMessage from XUL\n");
|
|
GenericSendMessage(nsIMsgCompDeliverMode.Now);
|
|
}
|
|
|
|
function SendMessageWithCheck()
|
|
{
|
|
var warn = sPrefs.getBoolPref("mail.warn_on_send_accel_key");
|
|
|
|
if (warn) {
|
|
var checkValue = {value:false};
|
|
var buttonPressed = gPromptService.confirmEx(window,
|
|
sComposeMsgsBundle.getString('sendMessageCheckWindowTitle'),
|
|
sComposeMsgsBundle.getString('sendMessageCheckLabel'),
|
|
(gPromptService.BUTTON_TITLE_IS_STRING * gPromptService.BUTTON_POS_0) +
|
|
(gPromptService.BUTTON_TITLE_CANCEL * gPromptService.BUTTON_POS_1),
|
|
sComposeMsgsBundle.getString('sendMessageCheckSendButtonLabel'),
|
|
null, null,
|
|
sComposeMsgsBundle.getString('CheckMsg'),
|
|
checkValue);
|
|
if (buttonPressed != 0) {
|
|
return;
|
|
}
|
|
if (checkValue.value) {
|
|
sPrefs.setBoolPref("mail.warn_on_send_accel_key", false);
|
|
}
|
|
}
|
|
|
|
GenericSendMessage(gIsOffline ? nsIMsgCompDeliverMode.Later
|
|
: nsIMsgCompDeliverMode.Now);
|
|
}
|
|
|
|
function SendMessageLater()
|
|
{
|
|
dump("SendMessageLater from XUL\n");
|
|
GenericSendMessage(nsIMsgCompDeliverMode.Later);
|
|
}
|
|
|
|
function Save()
|
|
{
|
|
dump("Save from XUL\n");
|
|
switch (defaultSaveOperation)
|
|
{
|
|
case "file" : SaveAsFile(false); break;
|
|
case "template" : SaveAsTemplate(false); break;
|
|
default : SaveAsDraft(false); break;
|
|
}
|
|
}
|
|
|
|
function SaveAsFile(saveAs)
|
|
{
|
|
dump("SaveAsFile from XUL\n");
|
|
var subject = GetMsgSubjectElement().value;
|
|
GetCurrentEditor().setDocumentTitle(subject);
|
|
|
|
if (gMsgCompose.bodyConvertible() == nsIMsgCompConvertible.Plain)
|
|
SaveDocument(saveAs, false, "text/plain");
|
|
else
|
|
SaveDocument(saveAs, false, "text/html");
|
|
defaultSaveOperation = "file";
|
|
}
|
|
|
|
function SaveAsDraft()
|
|
{
|
|
dump("SaveAsDraft from XUL\n");
|
|
|
|
GenericSendMessage(nsIMsgCompDeliverMode.SaveAsDraft);
|
|
defaultSaveOperation = "draft";
|
|
}
|
|
|
|
function SaveAsTemplate()
|
|
{
|
|
dump("SaveAsTemplate from XUL\n");
|
|
|
|
GenericSendMessage(nsIMsgCompDeliverMode.SaveAsTemplate);
|
|
defaultSaveOperation = "template";
|
|
}
|
|
|
|
function MessageFcc(menuItem)
|
|
{
|
|
// Get the id for the folder we're FCC into
|
|
// This is the additional FCC in addition to the
|
|
// default FCC
|
|
destUri = menuItem.getAttribute('id');
|
|
if (gMsgCompose)
|
|
{
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
if (msgCompFields)
|
|
{
|
|
if (msgCompFields.fcc2 == destUri)
|
|
{
|
|
msgCompFields.fcc2 = "nocopy://";
|
|
dump("FCC2: none\n");
|
|
}
|
|
else
|
|
{
|
|
msgCompFields.fcc2 = destUri;
|
|
dump("FCC2: " + destUri + "\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function updatePriorityMenu()
|
|
{
|
|
if (gMsgCompose)
|
|
{
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
if (msgCompFields && msgCompFields.priority)
|
|
{
|
|
var priorityMenu = document.getElementById('priorityMenu' );
|
|
priorityMenu.getElementsByAttribute( "checked", 'true' )[0].removeAttribute('checked');
|
|
priorityMenu.getElementsByAttribute( "value", msgCompFields.priority )[0].setAttribute('checked', 'true');
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
function updatePriorityToolbarButton(newPriorityValue)
|
|
{
|
|
var prioritymenu = document.getElementById('priorityMenu-button');
|
|
if (prioritymenu)
|
|
prioritymenu.value = newPriorityValue;
|
|
}
|
|
|
|
function PriorityMenuSelect(target)
|
|
{
|
|
if (gMsgCompose)
|
|
{
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
if (msgCompFields)
|
|
msgCompFields.priority = target.getAttribute('value');
|
|
|
|
// keep priority toolbar button in synch with possible changes via the menu item
|
|
updatePriorityToolbarButton(target.getAttribute('value'));
|
|
}
|
|
}
|
|
|
|
function OutputFormatMenuSelect(target)
|
|
{
|
|
if (gMsgCompose)
|
|
{
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
var toolbar = document.getElementById("FormatToolbar");
|
|
var format_menubar = document.getElementById("formatMenu");
|
|
var insert_menubar = document.getElementById("insertMenu");
|
|
var show_menuitem = document.getElementById("menu_showFormatToolbar");
|
|
|
|
if (msgCompFields)
|
|
switch (target.getAttribute('id'))
|
|
{
|
|
case "format_auto": gSendFormat = nsIMsgCompSendFormat.AskUser; break;
|
|
case "format_plain": gSendFormat = nsIMsgCompSendFormat.PlainText; break;
|
|
case "format_html": gSendFormat = nsIMsgCompSendFormat.HTML; break;
|
|
case "format_both": gSendFormat = nsIMsgCompSendFormat.Both; break;
|
|
}
|
|
gHideMenus = (gSendFormat == nsIMsgCompSendFormat.PlainText);
|
|
format_menubar.hidden = gHideMenus;
|
|
insert_menubar.hidden = gHideMenus;
|
|
show_menuitem.hidden = gHideMenus;
|
|
toolbar.hidden = gHideMenus ||
|
|
(show_menuitem.getAttribute("checked") == "false");
|
|
}
|
|
}
|
|
|
|
function SelectAddress()
|
|
{
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
|
|
Recipients2CompFields(msgCompFields);
|
|
|
|
var toAddress = msgCompFields.to;
|
|
var ccAddress = msgCompFields.cc;
|
|
var bccAddress = msgCompFields.bcc;
|
|
|
|
window.openDialog("chrome://messenger/content/addressbook/abSelectAddressesDialog.xul",
|
|
"",
|
|
"chrome,resizable,titlebar,modal",
|
|
{composeWindow:top.window,
|
|
msgCompFields:msgCompFields,
|
|
toAddress:toAddress,
|
|
ccAddress:ccAddress,
|
|
bccAddress:bccAddress});
|
|
// We have to set focus to the addressingwidget because we seem to loose focus often
|
|
// after opening the SelectAddresses Dialog- bug # 89950
|
|
AdjustFocus();
|
|
}
|
|
|
|
// walk through the recipients list and add them to the inline spell checker ignore list
|
|
function addRecipientsToIgnoreList(aAddressesToAdd)
|
|
{
|
|
if (InlineSpellChecker.inlineSpellChecker && InlineSpellChecker.inlineSpellChecker.enableRealTimeSpell)
|
|
{
|
|
// break the list of potentially many recipients back into individual names
|
|
var hdrParser = Components.classes["@mozilla.org/messenger/headerparser;1"].getService(Components.interfaces.nsIMsgHeaderParser);
|
|
var emailAddresses = {};
|
|
var names = {};
|
|
var fullNames = {};
|
|
var numAddresses = hdrParser.parseHeadersWithArray(aAddressesToAdd, emailAddresses, names, fullNames);
|
|
var tokenizedNames = new Array();
|
|
|
|
// each name could consist of multiple word delimited by either commas or spaces. i.e. Green Lantern
|
|
// or Lantern,Green. Tokenize on comma first, then tokenize again on spaces.
|
|
for (name in names.value)
|
|
{
|
|
var splitNames = names.value[name].split(',');
|
|
for (var i=0; i < splitNames.length; i++)
|
|
{
|
|
// now tokenize off of white space
|
|
var splitNamesFromWhiteSpaceArray = splitNames[i].split(' ');
|
|
for (var whiteSpaceIndex = 0; whiteSpaceIndex < splitNamesFromWhiteSpaceArray.length; whiteSpaceIndex++)
|
|
if (splitNamesFromWhiteSpaceArray[whiteSpaceIndex])
|
|
tokenizedNames.push(splitNamesFromWhiteSpaceArray[whiteSpaceIndex]);
|
|
}
|
|
}
|
|
|
|
InlineSpellChecker.inlineSpellChecker.ignoreWords(tokenizedNames, tokenizedNames.length);
|
|
}
|
|
}
|
|
|
|
function ToggleInlineSpellChecker(target)
|
|
{
|
|
if (InlineSpellChecker.inlineSpellChecker)
|
|
{
|
|
InlineSpellChecker.editor.setSpellcheckUserOverride(!InlineSpellChecker.inlineSpellChecker.enableRealTimeSpell);
|
|
target.setAttribute('checked', InlineSpellChecker.inlineSpellChecker.enableRealTimeSpell);
|
|
|
|
if (InlineSpellChecker.inlineSpellChecker.enableRealTimeSpell)
|
|
InlineSpellChecker.checkDocument(window.content.document);
|
|
}
|
|
}
|
|
|
|
function InitLanguageMenu()
|
|
{
|
|
var languageMenuList = document.getElementById('languageMenuList');
|
|
if (!languageMenuList)
|
|
return;
|
|
|
|
var spellChecker = Components.classes['@mozilla.org/spellchecker/myspell;1']
|
|
.getService(mozISpellCheckingEngine);
|
|
var o1 = {};
|
|
var o2 = {};
|
|
|
|
// Get the list of dictionaries from
|
|
// the spellchecker.
|
|
|
|
spellChecker.getDictionaryList(o1, o2);
|
|
|
|
var dictList = o1.value;
|
|
var count = o2.value;
|
|
|
|
// If dictionary count hasn't changed then no need to update the menu.
|
|
if (sDictCount == count)
|
|
return;
|
|
|
|
// Store current dictionary count.
|
|
sDictCount = count;
|
|
|
|
// Load the string bundle that will help us map
|
|
// RFC 1766 strings to UI strings.
|
|
var languageBundle = document.getElementById("languageBundle");
|
|
var isoStrArray;
|
|
var langId;
|
|
var langLabel;
|
|
var i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
try
|
|
{
|
|
langId = dictList[i];
|
|
isoStrArray = dictList[i].split("-");
|
|
|
|
if (languageBundle && isoStrArray[0])
|
|
langLabel = languageBundle.getString(isoStrArray[0].toLowerCase());
|
|
|
|
// the user needs to be able to distinguish between the UK English dictionary
|
|
// and say the United States English Dictionary. If we have a isoStr value then
|
|
// wrap it in parentheses and append it to the menu item string. i.e.
|
|
// English (US) and English (UK)
|
|
if (!langLabel)
|
|
langLabel = langId;
|
|
// if we have a language ID like US or UK, append it to the menu item, and any sub-variety
|
|
else if (isoStrArray.length > 1 && isoStrArray[1]) {
|
|
langLabel += ' (' + isoStrArray[1];
|
|
if (isoStrArray.length > 2 && isoStrArray[2])
|
|
langLabel += '-' + isoStrArray[2];
|
|
langLabel += ')';
|
|
}
|
|
}
|
|
catch (ex)
|
|
{
|
|
// getString throws an exception when a key is not found in the
|
|
// bundle. In that case, just use the original dictList string.
|
|
langLabel = langId;
|
|
}
|
|
dictList[i] = [langLabel, langId];
|
|
}
|
|
|
|
// sort by locale-aware collation
|
|
dictList.sort(
|
|
function compareFn(a, b)
|
|
{
|
|
return a[0].localeCompare(b[0]);
|
|
}
|
|
);
|
|
|
|
// Remove any languages from the list.
|
|
while (languageMenuList.hasChildNodes())
|
|
languageMenuList.removeChild(languageMenuList.firstChild);
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
var item = document.createElement("menuitem");
|
|
item.setAttribute("label", dictList[i][0]);
|
|
item.setAttribute("value", dictList[i][1]);
|
|
item.setAttribute('type', 'radio');
|
|
languageMenuList.appendChild(item);
|
|
}
|
|
}
|
|
|
|
function OnShowDictionaryMenu(aTarget)
|
|
{
|
|
InitLanguageMenu();
|
|
var curLang = sPrefs.getComplexValue("spellchecker.dictionary", nsISupportsString).data;
|
|
var languages = aTarget.getElementsByAttribute("value", curLang);
|
|
if (languages.length > 0)
|
|
languages[0].setAttribute("checked", true);
|
|
}
|
|
|
|
function ChangeLanguage(event)
|
|
{
|
|
// We need to change the dictionary language and if we are using inline spell check,
|
|
// recheck the message
|
|
|
|
var spellChecker = Components.classes['@mozilla.org/spellchecker/myspell;1']
|
|
.getService(mozISpellCheckingEngine);
|
|
if (spellChecker.dictionary != event.target.value)
|
|
{
|
|
spellChecker.dictionary = event.target.value;
|
|
var str = Components.classes["@mozilla.org/supports-string;1"]
|
|
.createInstance(nsISupportsString);
|
|
str.data = event.target.value;
|
|
sPrefs.setComplexValue("spellchecker.dictionary", nsISupportsString, str);
|
|
|
|
// now check the document over again with the new dictionary
|
|
if (InlineSpellChecker.inlineSpellChecker)
|
|
if (InlineSpellChecker.inlineSpellChecker.enableRealTimeSpell)
|
|
InlineSpellChecker.checkDocument(window.content.document);
|
|
}
|
|
event.stopPropagation();
|
|
}
|
|
|
|
function ToggleReturnReceipt(target)
|
|
{
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
if (msgCompFields)
|
|
{
|
|
msgCompFields.returnReceipt = ! msgCompFields.returnReceipt;
|
|
target.setAttribute('checked', msgCompFields.returnReceipt);
|
|
gReceiptOptionChanged = true;
|
|
}
|
|
}
|
|
|
|
function ToggleAttachVCard(target)
|
|
{
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
if (msgCompFields)
|
|
{
|
|
msgCompFields.attachVCard = ! msgCompFields.attachVCard;
|
|
target.setAttribute('checked', msgCompFields.attachVCard);
|
|
gAttachVCardOptionChanged = true;
|
|
}
|
|
}
|
|
|
|
function queryISupportsArray(supportsArray, iid) {
|
|
var result = new Array;
|
|
for (var i=0; i<supportsArray.Count(); i++) {
|
|
// dump(i + "," + result[i] + "\n");
|
|
result[i] = supportsArray.QueryElementAt(i, iid);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function ClearIdentityListPopup(popup)
|
|
{
|
|
if (popup)
|
|
while (popup.hasChildNodes())
|
|
popup.removeChild(popup.lastChild);
|
|
}
|
|
|
|
function compareAccountSortOrder(account1, account2)
|
|
{
|
|
var sortValue1, sortValue2;
|
|
|
|
try {
|
|
var res1 = sRDF.GetResource(account1.incomingServer.serverURI);
|
|
sortValue1 = sAccountManagerDataSource.GetTarget(res1, sNameProperty, true).QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
|
}
|
|
catch (ex) {
|
|
dump("XXX ex ");
|
|
if (account1 && account1.incomingServer && account1.incomingServer.serverURI)
|
|
dump(account1.incomingServer.serverURI + ",");
|
|
dump(ex + "\n");
|
|
sortValue1 = "";
|
|
}
|
|
|
|
try {
|
|
var res2 = sRDF.GetResource(account2.incomingServer.serverURI);
|
|
sortValue2 = sAccountManagerDataSource.GetTarget(res2, sNameProperty, true).QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
|
}
|
|
catch (ex) {
|
|
dump("XXX ex ");
|
|
if (account2 && account2.incomingServer && account2.incomingServer.serverURI)
|
|
dump(account2.incomingServer.serverURI + ",");
|
|
dump(ex + "\n");
|
|
sortValue2 = "";
|
|
}
|
|
|
|
if (sortValue1 < sortValue2)
|
|
return -1;
|
|
else if (sortValue1 > sortValue2)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
function FillIdentityList(menulist)
|
|
{
|
|
var accounts = queryISupportsArray(gAccountManager.accounts, Components.interfaces.nsIMsgAccount);
|
|
accounts.sort(compareAccountSortOrder);
|
|
|
|
for (var i in accounts) {
|
|
var server = accounts[i].incomingServer;
|
|
if (!server)
|
|
continue;
|
|
var identites = queryISupportsArray(accounts[i].identities, Components.interfaces.nsIMsgIdentity);
|
|
for (var j in identites) {
|
|
var identity = identites[j];
|
|
var item = menulist.appendItem(identity.identityName, identity.key, server.prettyName);
|
|
item.setAttribute("accountkey", accounts[i].key);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getCurrentIdentity()
|
|
{
|
|
// fill in Identity combobox
|
|
var identityList = document.getElementById("msgIdentity");
|
|
|
|
var identityKey = identityList.value;
|
|
|
|
//dump("Looking for identity " + identityKey + "\n");
|
|
var identity = gAccountManager.getIdentity(identityKey);
|
|
|
|
return identity;
|
|
}
|
|
|
|
function getCurrentAccountKey()
|
|
{
|
|
// get the accounts key
|
|
var identityList = document.getElementById("msgIdentity");
|
|
return identityList.selectedItem.getAttribute("accountkey");
|
|
}
|
|
|
|
function getIdentityForKey(key)
|
|
{
|
|
return gAccountManager.getIdentity(key);
|
|
}
|
|
|
|
function AdjustFocus()
|
|
{
|
|
//dump("XXX adjusting focus\n");
|
|
var element = awGetInputElement(awGetNumberOfRecipients());
|
|
if (element.value == "") {
|
|
//dump("XXX focus on address\n");
|
|
awSetFocus(awGetNumberOfRecipients(), element);
|
|
}
|
|
else
|
|
{
|
|
element = GetMsgSubjectElement();
|
|
if (element.value == "") {
|
|
//dump("XXX focus on subject\n");
|
|
element.focus();
|
|
}
|
|
else {
|
|
//dump("XXX focus on body\n");
|
|
SetMsgBodyFrameFocus();
|
|
}
|
|
}
|
|
}
|
|
|
|
function SetComposeWindowTitle()
|
|
{
|
|
var newTitle = GetMsgSubjectElement().value;
|
|
|
|
/* dump("newTitle = " + newTitle + "\n"); */
|
|
|
|
if (newTitle == "" )
|
|
newTitle = sComposeMsgsBundle.getString("defaultSubject");
|
|
|
|
newTitle += GetCharsetUIString();
|
|
document.title = sComposeMsgsBundle.getString("windowTitlePrefix") + " " + newTitle;
|
|
}
|
|
|
|
// Check for changes to document and allow saving before closing
|
|
// This is hooked up to the OS's window close widget (e.g., "X" for Windows)
|
|
function ComposeCanClose()
|
|
{
|
|
if (gSendOrSaveOperationInProgress)
|
|
{
|
|
var result;
|
|
|
|
if (gPromptService)
|
|
{
|
|
var promptTitle = sComposeMsgsBundle.getString("quitComposeWindowTitle");
|
|
var promptMsg = sComposeMsgsBundle.getString("quitComposeWindowMessage");
|
|
var quitButtonLabel = sComposeMsgsBundle.getString("quitComposeWindowQuitButtonLabel");
|
|
var waitButtonLabel = sComposeMsgsBundle.getString("quitComposeWindowWaitButtonLabel");
|
|
|
|
result = gPromptService.confirmEx(window, promptTitle, promptMsg,
|
|
(gPromptService.BUTTON_TITLE_IS_STRING*gPromptService.BUTTON_POS_0) +
|
|
(gPromptService.BUTTON_TITLE_IS_STRING*gPromptService.BUTTON_POS_1),
|
|
waitButtonLabel, quitButtonLabel, null, null, {value:0});
|
|
|
|
if (result == 1)
|
|
{
|
|
gMsgCompose.abort();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Returns FALSE only if user cancels save action
|
|
if (gContentChanged || gMsgCompose.bodyModified)
|
|
{
|
|
// call window.focus, since we need to pop up a dialog
|
|
// and therefore need to be visible (to prevent user confusion)
|
|
window.focus();
|
|
if (gPromptService)
|
|
{
|
|
result = gPromptService.confirmEx(window,
|
|
sComposeMsgsBundle.getString("saveDlogTitle"),
|
|
sComposeMsgsBundle.getString("saveDlogMessage"),
|
|
(gPromptService.BUTTON_TITLE_SAVE * gPromptService.BUTTON_POS_0) +
|
|
(gPromptService.BUTTON_TITLE_CANCEL * gPromptService.BUTTON_POS_1) +
|
|
(gPromptService.BUTTON_TITLE_DONT_SAVE * gPromptService.BUTTON_POS_2),
|
|
null, null, null,
|
|
null, {value:0});
|
|
switch (result)
|
|
{
|
|
case 0: //Save
|
|
gCloseWindowAfterSave = true;
|
|
SaveAsDraft();
|
|
return false;
|
|
case 1: //Cancel
|
|
return false;
|
|
case 2: //Don't Save
|
|
break;
|
|
}
|
|
}
|
|
|
|
SetContentAndBodyAsUnmodified();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function SetContentAndBodyAsUnmodified()
|
|
{
|
|
gMsgCompose.bodyModified = false;
|
|
gContentChanged = false;
|
|
}
|
|
|
|
function ReleaseAutoCompleteState()
|
|
{
|
|
for (i=1; i <= awGetMaxRecipients(); i++)
|
|
document.getElementById("addressCol2#" + i).removeSession(gLDAPSession);
|
|
|
|
gSessionAdded = false;
|
|
gLDAPSession = null;
|
|
gAutocompleteSession = null;
|
|
}
|
|
|
|
function MsgComposeCloseWindow(recycleIt)
|
|
{
|
|
if (gMsgCompose)
|
|
gMsgCompose.CloseWindow(recycleIt);
|
|
}
|
|
|
|
function GetLastAttachDirectory()
|
|
{
|
|
var lastDirectory;
|
|
|
|
try {
|
|
lastDirectory = sPrefs.getComplexValue(kComposeAttachDirPrefName, Components.interfaces.nsILocalFile);
|
|
}
|
|
catch (ex) {
|
|
// this will fail the first time we attach a file
|
|
// as we won't have a pref value.
|
|
lastDirectory = null;
|
|
}
|
|
|
|
return lastDirectory;
|
|
}
|
|
|
|
// attachedLocalFile must be a nsILocalFile
|
|
function SetLastAttachDirectory(attachedLocalFile)
|
|
{
|
|
try {
|
|
var file = attachedLocalFile.QueryInterface(Components.interfaces.nsIFile);
|
|
var parent = file.parent.QueryInterface(Components.interfaces.nsILocalFile);
|
|
|
|
sPrefs.setComplexValue(kComposeAttachDirPrefName, Components.interfaces.nsILocalFile, parent);
|
|
}
|
|
catch (ex) {
|
|
dump("error: SetLastAttachDirectory failed: " + ex + "\n");
|
|
}
|
|
}
|
|
|
|
function AttachFile()
|
|
{
|
|
var attachments;
|
|
|
|
//Get file using nsIFilePicker and convert to URL
|
|
try {
|
|
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
|
|
fp.init(window, sComposeMsgsBundle.getString("chooseFileToAttach"), nsIFilePicker.modeOpenMultiple);
|
|
|
|
var lastDirectory = GetLastAttachDirectory();
|
|
if (lastDirectory)
|
|
fp.displayDirectory = lastDirectory;
|
|
|
|
fp.appendFilters(nsIFilePicker.filterAll);
|
|
if (fp.show() == nsIFilePicker.returnOK) {
|
|
attachments = fp.files;
|
|
}
|
|
}
|
|
catch (ex) {
|
|
dump("failed to get attachments: " + ex + "\n");
|
|
}
|
|
|
|
if (!attachments || !attachments.hasMoreElements())
|
|
return;
|
|
|
|
var haveSetAttachDirectory = false;
|
|
|
|
while (attachments.hasMoreElements()) {
|
|
var currentFile = attachments.getNext().QueryInterface(Components.interfaces.nsILocalFile);
|
|
|
|
if (!haveSetAttachDirectory) {
|
|
SetLastAttachDirectory(currentFile);
|
|
haveSetAttachDirectory = true;
|
|
}
|
|
|
|
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
|
ioService = ioService.getService(Components.interfaces.nsIIOService);
|
|
var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
|
|
var currentAttachment = fileHandler.getURLSpecFromFile(currentFile);
|
|
|
|
if (!DuplicateFileCheck(currentAttachment)) {
|
|
var attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment);
|
|
attachment.url = currentAttachment;
|
|
AddAttachment(attachment);
|
|
ChangeAttachmentBucketVisibility(false);
|
|
gContentChanged = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
function AddAttachment(attachment)
|
|
{
|
|
if (attachment && attachment.url)
|
|
{
|
|
var bucket = document.getElementById("attachmentBucket");
|
|
|
|
if (!attachment.name)
|
|
attachment.name = gMsgCompose.AttachmentPrettyName(attachment.url, null);
|
|
|
|
// for security reasons, don't allow *-message:// uris to leak out
|
|
// we don't want to reveal the .slt path (for mailbox://), or the username or hostname
|
|
var messagePrefix = /^mailbox-message:|^imap-message:|^news-message:/i;
|
|
if (messagePrefix.test(attachment.name))
|
|
attachment.name = sComposeMsgsBundle.getString("messageAttachmentSafeName");
|
|
else {
|
|
// for security reasons, don't allow mail protocol uris to leak out
|
|
// we don't want to reveal the .slt path (for mailbox://), or the username or hostname
|
|
var mailProtocol = /^mailbox:|^imap:|^s?news:/i;
|
|
if (mailProtocol.test(attachment.name))
|
|
attachment.name = sComposeMsgsBundle.getString("partAttachmentSafeName");
|
|
}
|
|
|
|
var item = bucket.appendItem(attachment.name, "");
|
|
item.attachment = attachment; //full attachment object stored here
|
|
try {
|
|
item.setAttribute("tooltiptext", decodeURI(attachment.url));
|
|
} catch(e) {
|
|
item.setAttribute("tooltiptext", attachment.url);
|
|
}
|
|
item.setAttribute("class", "listitem-iconic");
|
|
|
|
var url = gIOService.newURI(attachment.url, null, null);
|
|
|
|
try
|
|
{
|
|
url = url.QueryInterface( Components.interfaces.nsIURL );
|
|
}
|
|
catch (ex)
|
|
{
|
|
url = null;
|
|
}
|
|
|
|
|
|
// for local file urls, we are better off using the full file url because moz-icon will
|
|
// actually resolve the file url and get the right icon from the file url. All other urls, we should
|
|
// try to extract the file name from them. This fixes issues were an icon wasn't showing up if you dragged
|
|
// a web url that had a query or reference string after the file name and for mailnews urls were the filename
|
|
// is hidden in the url as a &filename= part.
|
|
if (url && url.fileName && !url.schemeIs("file"))
|
|
item.setAttribute("image", "moz-icon://" + url.fileName);
|
|
else
|
|
item.setAttribute("image", "moz-icon:" + attachment.url);
|
|
}
|
|
}
|
|
|
|
function SelectAllAttachments()
|
|
{
|
|
var bucketList = document.getElementById("attachmentBucket");
|
|
if (bucketList)
|
|
bucketList.selectAll();
|
|
}
|
|
|
|
function MessageHasAttachments()
|
|
{
|
|
var bucketList = document.getElementById("attachmentBucket");
|
|
if (bucketList) {
|
|
return (bucketList && bucketList.getRowCount() && (bucketList == top.document.commandDispatcher.focusedElement));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function MessageGetNumSelectedAttachments()
|
|
{
|
|
var bucketList = document.getElementById("attachmentBucket");
|
|
|
|
if (bucketList)
|
|
return bucketList.selectedItems.length;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
function AttachPage()
|
|
{
|
|
if (gPromptService)
|
|
{
|
|
var result = {value:"http://"};
|
|
if (gPromptService.prompt(
|
|
window,
|
|
sComposeMsgsBundle.getString("attachPageDlogTitle"),
|
|
sComposeMsgsBundle.getString("attachPageDlogMessage"),
|
|
result,
|
|
null,
|
|
{value:0}))
|
|
{
|
|
var attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment);
|
|
attachment.url = result.value;
|
|
AddAttachment(attachment);
|
|
ChangeAttachmentBucketVisibility(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
function DuplicateFileCheck(FileUrl)
|
|
{
|
|
var bucket = document.getElementById('attachmentBucket');
|
|
for (var index = 0; index < bucket.getRowCount(); index++)
|
|
{
|
|
var item = bucket.getItemAtIndex(index);
|
|
var attachment = item.attachment;
|
|
if (attachment)
|
|
{
|
|
if (FileUrl == attachment.url)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function Attachments2CompFields(compFields)
|
|
{
|
|
var bucket = document.getElementById('attachmentBucket');
|
|
|
|
//First, we need to clear all attachment in the compose fields
|
|
compFields.removeAttachments();
|
|
|
|
for (var index = 0; index < bucket.getRowCount(); index++)
|
|
{
|
|
var item = bucket.getItemAtIndex(index);
|
|
var attachment = item.attachment;
|
|
if (attachment)
|
|
compFields.addAttachment(attachment);
|
|
}
|
|
}
|
|
|
|
function RemoveAllAttachments()
|
|
{
|
|
var child;
|
|
var bucket = document.getElementById("attachmentBucket");
|
|
while (bucket.getRowCount())
|
|
{
|
|
child = bucket.removeItemAt(bucket.getRowCount() - 1);
|
|
// Let's release the attachment object hold by the node else it won't go away until the window is destroyed
|
|
child.attachment = null;
|
|
}
|
|
|
|
ChangeAttachmentBucketVisibility(true);
|
|
}
|
|
|
|
function ChangeAttachmentBucketVisibility(aHideBucket)
|
|
{
|
|
document.getElementById("attachments-box").collapsed = aHideBucket;
|
|
document.getElementById("attachmentbucket-sizer").collapsed = aHideBucket;
|
|
}
|
|
|
|
function RemoveSelectedAttachment()
|
|
{
|
|
var child;
|
|
var bucket = document.getElementById("attachmentBucket");
|
|
if (bucket.selectedItems.length > 0) {
|
|
for (var index = bucket.selectedCount - 1; index >= 0; index-- )
|
|
{
|
|
child = bucket.removeItemAt(bucket.getIndexOfItem(bucket.getSelectedItem(index)));
|
|
// Let's release the attachment object held by the node else it won't go away until the window is destroyed
|
|
child.attachment = null;
|
|
}
|
|
gContentChanged = true;
|
|
}
|
|
}
|
|
|
|
function FocusOnFirstAttachment()
|
|
{
|
|
var bucketList = document.getElementById("attachmentBucket");
|
|
|
|
if (bucketList && bucketList.getRowCount())
|
|
bucketList.selectedIndex = 0;
|
|
}
|
|
|
|
function AttachmentElementHasItems()
|
|
{
|
|
var element = document.getElementById("attachmentBucket");
|
|
return element ? element.getRowCount() : 0;
|
|
}
|
|
|
|
function OpenSelectedAttachment()
|
|
{
|
|
var child;
|
|
var bucket = document.getElementById("attachmentBucket");
|
|
if (bucket.selectedItems.length == 1)
|
|
{
|
|
var attachmentUrl = bucket.getSelectedItem(0).attachment.url;
|
|
|
|
var messagePrefix = /^mailbox-message:|^imap-message:|^news-message:/i;
|
|
if (messagePrefix.test(attachmentUrl))
|
|
{
|
|
// we must be dealing with a forwarded attachment, treat this special
|
|
var messenger = Components.classes["@mozilla.org/messenger;1"].createInstance();
|
|
messenger = messenger.QueryInterface(Components.interfaces.nsIMessenger);
|
|
var msgHdr = messenger.messageServiceFromURI(attachmentUrl).messageURIToMsgHdr(attachmentUrl);
|
|
if (msgHdr)
|
|
{
|
|
var folderUri = msgHdr.folder.folderURL;
|
|
window.openDialog("chrome://messenger/content/messageWindow.xul", "_blank", "all,chrome,dialog=no,status,toolbar",
|
|
attachmentUrl, folderUri, null );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// turn the url into a nsIURL object then open it
|
|
|
|
var url = gIOService.newURI(attachmentUrl, null, null);
|
|
url = url.QueryInterface( Components.interfaces.nsIURL );
|
|
|
|
if (url)
|
|
{
|
|
var channel = gIOService.newChannelFromURI(url);
|
|
if (channel)
|
|
{
|
|
var uriLoader = Components.classes["@mozilla.org/uriloader;1"].getService(Components.interfaces.nsIURILoader);
|
|
uriLoader.openURI(channel, true, new nsAttachmentOpener());
|
|
} // if channel
|
|
} // if url
|
|
}
|
|
} // if one attachment selected
|
|
}
|
|
|
|
function nsAttachmentOpener()
|
|
{
|
|
}
|
|
|
|
nsAttachmentOpener.prototype =
|
|
{
|
|
QueryInterface: function(iid)
|
|
{
|
|
if (iid.equals(Components.interfaces.nsIURIContentListener) ||
|
|
iid.equals(Components.interfaces.nsIInterfaceRequestor) ||
|
|
iid.equals(Components.interfaces.nsISupports))
|
|
return this;
|
|
throw Components.results.NS_NOINTERFACE;
|
|
},
|
|
|
|
onStartURIOpen: function(uri)
|
|
{
|
|
return;
|
|
},
|
|
|
|
doContent: function(contentType, isContentPreferred, request, contentHandler)
|
|
{
|
|
return;
|
|
},
|
|
|
|
isPreferred: function(contentType, desiredContentType)
|
|
{
|
|
return;
|
|
},
|
|
|
|
canHandleContent: function(contentType, isContentPreferred, desiredContentType)
|
|
{
|
|
return false;
|
|
},
|
|
|
|
getInterface: function(iid)
|
|
{
|
|
if (iid.equals(Components.interfaces.nsIDOMWindowInternal))
|
|
return window;
|
|
else
|
|
return this.QueryInterface(iid);
|
|
},
|
|
|
|
loadCookie: null,
|
|
parentContentListener: null
|
|
}
|
|
|
|
function DetermineHTMLAction(convertible)
|
|
{
|
|
var obj;
|
|
if (! gMsgCompose.composeHTML)
|
|
{
|
|
try {
|
|
obj = new Object;
|
|
gMsgCompose.CheckAndPopulateRecipients(true, false, obj);
|
|
} catch(ex) { dump("gMsgCompose.CheckAndPopulateRecipients failed: " + ex + "\n"); }
|
|
return nsIMsgCompSendFormat.PlainText;
|
|
}
|
|
|
|
if (gSendFormat == nsIMsgCompSendFormat.AskUser)
|
|
{
|
|
//Well, before we ask, see if we can figure out what to do for ourselves
|
|
|
|
var noHtmlRecipients;
|
|
var noHtmlnewsgroups;
|
|
var preferFormat;
|
|
|
|
//Check the address book for the HTML property for each recipient
|
|
try {
|
|
obj = new Object;
|
|
preferFormat = gMsgCompose.CheckAndPopulateRecipients(true, true, obj);
|
|
noHtmlRecipients = obj.value;
|
|
} catch(ex)
|
|
{
|
|
dump("gMsgCompose.CheckAndPopulateRecipients failed: " + ex + "\n");
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
noHtmlRecipients = msgCompFields.to + "," + msgCompFields.cc + "," + msgCompFields.bcc;
|
|
preferFormat = nsIAbPreferMailFormat.unknown;
|
|
}
|
|
dump("DetermineHTMLAction: preferFormat = " + preferFormat + ", noHtmlRecipients are " + noHtmlRecipients + "\n");
|
|
|
|
//Check newsgroups now...
|
|
noHtmlnewsgroups = gMsgCompose.compFields.newsgroups;
|
|
|
|
if (noHtmlRecipients != "" || noHtmlnewsgroups != "")
|
|
{
|
|
if (convertible == nsIMsgCompConvertible.Plain)
|
|
return nsIMsgCompSendFormat.PlainText;
|
|
|
|
if (noHtmlnewsgroups == "")
|
|
{
|
|
switch (preferFormat)
|
|
{
|
|
case nsIAbPreferMailFormat.plaintext :
|
|
return nsIMsgCompSendFormat.PlainText;
|
|
|
|
default :
|
|
//See if a preference has been set to tell us what to do. Note that we do not honor that
|
|
//preference for newsgroups. Only for e-mail addresses.
|
|
var action = sPrefs.getIntPref("mail.default_html_action");
|
|
switch (action)
|
|
{
|
|
case nsIMsgCompSendFormat.PlainText :
|
|
case nsIMsgCompSendFormat.HTML :
|
|
case nsIMsgCompSendFormat.Both :
|
|
return action;
|
|
}
|
|
}
|
|
}
|
|
return nsIMsgCompSendFormat.AskUser;
|
|
}
|
|
else
|
|
return nsIMsgCompSendFormat.HTML;
|
|
}
|
|
else
|
|
{
|
|
try {
|
|
obj = new Object;
|
|
gMsgCompose.CheckAndPopulateRecipients(true, false, obj);
|
|
} catch(ex) { dump("gMsgCompose.CheckAndPopulateRecipients failed: " + ex + "\n"); }
|
|
}
|
|
|
|
return gSendFormat;
|
|
}
|
|
|
|
function DetermineConvertibility()
|
|
{
|
|
if (!gMsgCompose.composeHTML)
|
|
return nsIMsgCompConvertible.Plain;
|
|
|
|
try {
|
|
return gMsgCompose.bodyConvertible();
|
|
} catch(ex) {}
|
|
return nsIMsgCompConvertible.No;
|
|
}
|
|
|
|
function LoadIdentity(startup)
|
|
{
|
|
var identityElement = document.getElementById("msgIdentity");
|
|
var prevIdentity = gCurrentIdentity;
|
|
|
|
if (identityElement) {
|
|
var idKey = identityElement.value;
|
|
gCurrentIdentity = gAccountManager.getIdentity(idKey);
|
|
|
|
// set the account name on the menu list value.
|
|
if (identityElement.selectedItem)
|
|
identityElement.setAttribute('accountname', identityElement.selectedItem.getAttribute('accountname'));
|
|
|
|
if (!startup && prevIdentity && idKey != prevIdentity.key)
|
|
{
|
|
var prefstring = "mail.identity." + prevIdentity.key;
|
|
RemoveDirectoryServerObserver(prefstring);
|
|
var prevReplyTo = prevIdentity.replyTo;
|
|
var prevBcc = "";
|
|
var prevReceipt = prevIdentity.requestReturnReceipt;
|
|
var prevAttachVCard = prevIdentity.attachVCard;
|
|
|
|
if (prevIdentity.doBcc)
|
|
prevBcc += prevIdentity.doBccList;
|
|
|
|
var newReplyTo = gCurrentIdentity.replyTo;
|
|
var newBcc = "";
|
|
var newReceipt = gCurrentIdentity.requestReturnReceipt;
|
|
var newAttachVCard = gCurrentIdentity.attachVCard;
|
|
|
|
if (gCurrentIdentity.doBcc)
|
|
newBcc += gCurrentIdentity.doBccList;
|
|
|
|
var needToCleanUp = false;
|
|
var msgCompFields = gMsgCompose.compFields;
|
|
|
|
if (!gReceiptOptionChanged &&
|
|
prevReceipt == msgCompFields.returnReceipt &&
|
|
prevReceipt != newReceipt)
|
|
{
|
|
msgCompFields.returnReceipt = newReceipt;
|
|
document.getElementById("returnReceiptMenu").setAttribute('checked',msgCompFields.returnReceipt);
|
|
}
|
|
|
|
if (!gAttachVCardOptionChanged &&
|
|
prevAttachVCard == msgCompFields.attachVCard &&
|
|
prevAttachVCard != newAttachVCard)
|
|
{
|
|
msgCompFields.attachVCard = newAttachVCard;
|
|
document.getElementById("cmd_attachVCard").setAttribute('checked',msgCompFields.attachVCard);
|
|
}
|
|
|
|
if (newReplyTo != prevReplyTo)
|
|
{
|
|
needToCleanUp = true;
|
|
if (prevReplyTo != "")
|
|
awRemoveRecipients(msgCompFields, "addr_reply", prevReplyTo);
|
|
if (newReplyTo != "")
|
|
awAddRecipients(msgCompFields, "addr_reply", newReplyTo);
|
|
}
|
|
|
|
if (newBcc != prevBcc)
|
|
{
|
|
needToCleanUp = true;
|
|
if (prevBcc != "")
|
|
awRemoveRecipients(msgCompFields, "addr_bcc", prevBcc);
|
|
if (newBcc != "")
|
|
awAddRecipients(msgCompFields, "addr_bcc", newBcc);
|
|
}
|
|
|
|
if (needToCleanUp)
|
|
awCleanupRows();
|
|
|
|
try {
|
|
gMsgCompose.SetSignature(gCurrentIdentity);
|
|
} catch (ex) { dump("### Cannot set the signature: " + ex + "\n");}
|
|
|
|
var event = document.createEvent('Events');
|
|
event.initEvent('compose-from-changed', false, true);
|
|
document.getElementById("msgcomposeWindow").dispatchEvent(event);
|
|
}
|
|
|
|
AddDirectoryServerObserver(false);
|
|
if (!startup) {
|
|
if (!gAutocompleteSession)
|
|
gAutocompleteSession = Components.classes["@mozilla.org/autocompleteSession;1?type=addrbook"].getService(Components.interfaces.nsIAbAutoCompleteSession);
|
|
if (gAutocompleteSession)
|
|
setDomainName();
|
|
if (sPrefs.getBoolPref("mail.autoComplete.highlightNonMatches"))
|
|
document.getElementById('addressCol2#1').highlightNonMatches = true;
|
|
|
|
try {
|
|
setupLdapAutocompleteSession();
|
|
} catch (ex) {
|
|
// catch the exception and ignore it, so that if LDAP setup
|
|
// fails, the entire compose window doesn't end up horked
|
|
}
|
|
|
|
addRecipientsToIgnoreList(gCurrentIdentity.identityName); // only do this if we aren't starting up....it gets done as part of startup already
|
|
}
|
|
}
|
|
}
|
|
|
|
function setDomainName()
|
|
{
|
|
var defaultDomain = "";
|
|
if (gCurrentIdentity.autocompleteToMyDomain)
|
|
{
|
|
var emailAddr = gCurrentIdentity.email;
|
|
var start = emailAddr.lastIndexOf("@");
|
|
defaultDomain = emailAddr.slice(start + 1);
|
|
}
|
|
|
|
// If autocompleteToMyDomain is false the defaultDomain is emptied
|
|
gAutocompleteSession.defaultDomain = defaultDomain;
|
|
}
|
|
|
|
function setupAutocomplete()
|
|
{
|
|
//Setup autocomplete session if we haven't done so already
|
|
if (!gAutocompleteSession)
|
|
{
|
|
gAutocompleteSession = Components.classes["@mozilla.org/autocompleteSession;1?type=addrbook"].getService(Components.interfaces.nsIAbAutoCompleteSession);
|
|
if (gAutocompleteSession)
|
|
{
|
|
setDomainName();
|
|
|
|
var autoCompleteWidget = document.getElementById("addressCol2#1");
|
|
// When autocompleteToMyDomain is off there is no default entry with the domain
|
|
// appended so reduce the minimum results for a popup to 2 in this case.
|
|
if (!gCurrentIdentity.autocompleteToMyDomain)
|
|
autoCompleteWidget.minResultsForPopup = 2;
|
|
|
|
// if the pref is set to turn on the comment column, honor it here.
|
|
// this element then gets cloned for subsequent rows, so they should
|
|
// honor it as well
|
|
//
|
|
try
|
|
{
|
|
if (sPrefs.getBoolPref("mail.autoComplete.highlightNonMatches"))
|
|
autoCompleteWidget.highlightNonMatches = true;
|
|
|
|
if (sPrefs.getIntPref("mail.autoComplete.commentColumn"))
|
|
autoCompleteWidget.showCommentColumn = true;
|
|
} catch (ex)
|
|
{
|
|
// if we can't get this pref, then don't show the columns (which is
|
|
// what the XUL defaults to)
|
|
}
|
|
|
|
} else
|
|
{
|
|
gAutocompleteSession = 1;
|
|
}
|
|
}
|
|
|
|
if (!gSetupLdapAutocomplete)
|
|
{
|
|
try
|
|
{
|
|
setupLdapAutocompleteSession();
|
|
} catch (ex)
|
|
{
|
|
// catch the exception and ignore it, so that if LDAP setup
|
|
// fails, the entire compose window doesn't end up horked
|
|
}
|
|
}
|
|
}
|
|
|
|
function subjectKeyPress(event)
|
|
{
|
|
switch(event.keyCode) {
|
|
case 9:
|
|
if (!event.shiftKey) {
|
|
SetMsgBodyFrameFocus();
|
|
event.preventDefault();
|
|
}
|
|
break;
|
|
case 13:
|
|
SetMsgBodyFrameFocus();
|
|
break;
|
|
}
|
|
}
|
|
|
|
function AttachmentBucketClicked(event)
|
|
{
|
|
event.currentTarget.focus();
|
|
|
|
if (event.button != 0)
|
|
return;
|
|
|
|
if (event.originalTarget.localName == "listboxbody")
|
|
goDoCommand('cmd_attachFile');
|
|
else if (event.originalTarget.localName == "listitem" && event.detail == 2)
|
|
OpenSelectedAttachment();
|
|
}
|
|
|
|
// we can drag and drop addresses, files, messages and urls into the compose envelope
|
|
var envelopeDragObserver = {
|
|
|
|
canHandleMultipleItems: true,
|
|
|
|
onDrop: function (aEvent, aData, aDragSession)
|
|
{
|
|
var dataList = aData.dataList;
|
|
var dataListLength = dataList.length;
|
|
var errorTitle;
|
|
var attachment;
|
|
var errorMsg;
|
|
|
|
for (var i = 0; i < dataListLength; i++)
|
|
{
|
|
var item = dataList[i].first;
|
|
var prettyName;
|
|
var rawData = item.data;
|
|
|
|
// We could be dropping an attachment OR an address, check and do the right thing..
|
|
|
|
if (item.flavour.contentType == "text/x-moz-url" ||
|
|
item.flavour.contentType == "text/x-moz-message" ||
|
|
item.flavour.contentType == "application/x-moz-file")
|
|
{
|
|
if (item.flavour.contentType == "application/x-moz-file")
|
|
{
|
|
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
|
.getService(Components.interfaces.nsIIOService);
|
|
var fileHandler = ioService.getProtocolHandler("file")
|
|
.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
|
|
rawData = fileHandler.getURLSpecFromFile(rawData);
|
|
}
|
|
else
|
|
{
|
|
var separator = rawData.indexOf("\n");
|
|
if (separator != -1)
|
|
{
|
|
prettyName = rawData.substr(separator+1);
|
|
rawData = rawData.substr(0,separator);
|
|
}
|
|
}
|
|
|
|
if (DuplicateFileCheck(rawData))
|
|
{
|
|
dump("Error, attaching the same item twice\n");
|
|
}
|
|
else
|
|
{
|
|
var isValid = true;
|
|
if (item.flavour.contentType == "text/x-moz-url") {
|
|
// if this is a url (or selected text)
|
|
// see if it's a valid url by checking
|
|
// if we can extract a scheme
|
|
// using the ioservice
|
|
//
|
|
// also skip mailto:, since it doesn't make sense
|
|
// to attach and send mailto urls
|
|
try {
|
|
var scheme = gIOService.extractScheme(rawData);
|
|
// don't attach mailto: urls
|
|
if (scheme == "mailto")
|
|
isValid = false;
|
|
}
|
|
catch (ex) {
|
|
isValid = false;
|
|
}
|
|
}
|
|
|
|
if (isValid) {
|
|
attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"]
|
|
.createInstance(Components.interfaces.nsIMsgAttachment);
|
|
attachment.url = rawData;
|
|
attachment.name = prettyName;
|
|
AddAttachment(attachment);
|
|
ChangeAttachmentBucketVisibility(false);
|
|
}
|
|
}
|
|
}
|
|
else if (item.flavour.contentType == "text/x-moz-address")
|
|
{
|
|
// process the address
|
|
if (rawData)
|
|
DropRecipient(aEvent.target, rawData);
|
|
}
|
|
}
|
|
},
|
|
|
|
onDragOver: function (aEvent, aFlavour, aDragSession)
|
|
{
|
|
if (aFlavour.contentType != "text/x-moz-address")
|
|
{
|
|
// make sure the attachment box is visible during drag over
|
|
var attachmentBox = document.getElementById("attachments-box");
|
|
if (attachmentBox.collapsed)
|
|
ChangeAttachmentBucketVisibility(false);
|
|
}
|
|
else
|
|
{
|
|
DragAddressOverTargetControl(aEvent);
|
|
}
|
|
},
|
|
|
|
onDragExit: function (aEvent, aDragSession)
|
|
{
|
|
},
|
|
|
|
getSupportedFlavours: function ()
|
|
{
|
|
var flavourSet = new FlavourSet();
|
|
flavourSet.appendFlavour("text/x-moz-url");
|
|
flavourSet.appendFlavour("text/x-moz-message");
|
|
flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
|
|
flavourSet.appendFlavour("text/x-moz-address");
|
|
return flavourSet;
|
|
}
|
|
};
|
|
|
|
function DisplaySaveFolderDlg(folderURI)
|
|
{
|
|
try{
|
|
showDialog = gCurrentIdentity.showSaveMsgDlg;
|
|
}//try
|
|
catch (e){
|
|
return;
|
|
}//catch
|
|
|
|
if (showDialog){
|
|
var msgfolder = GetMsgFolderFromUri(folderURI, true);
|
|
if (!msgfolder)
|
|
return;
|
|
var checkbox = {value:0};
|
|
var SaveDlgTitle = sComposeMsgsBundle.getString("SaveDialogTitle");
|
|
var dlgMsg = sComposeMsgsBundle.getFormattedString("SaveDialogMsg",
|
|
[msgfolder.name,
|
|
msgfolder.server.prettyName]);
|
|
|
|
var CheckMsg = sComposeMsgsBundle.getString("CheckMsg");
|
|
if (gPromptService)
|
|
gPromptService.alertCheck(window, SaveDlgTitle, dlgMsg, CheckMsg, checkbox);
|
|
else
|
|
window.alert(dlgMsg);
|
|
try {
|
|
gCurrentIdentity.showSaveMsgDlg = !checkbox.value;
|
|
}//try
|
|
catch (e) {
|
|
return;
|
|
}//catch
|
|
|
|
}//if
|
|
return;
|
|
}
|
|
|
|
function SetMsgAddressingWidgetTreeElementFocus()
|
|
{
|
|
var element = awGetInputElement(awGetNumberOfRecipients());
|
|
awSetFocus(awGetNumberOfRecipients(), element);
|
|
}
|
|
|
|
function SetMsgIdentityElementFocus()
|
|
{
|
|
GetMsgIdentityElement().focus();
|
|
}
|
|
|
|
function SetMsgSubjectElementFocus()
|
|
{
|
|
GetMsgSubjectElement().focus();
|
|
}
|
|
|
|
function SetMsgAttachmentElementFocus()
|
|
{
|
|
GetMsgAttachmentElement().focus();
|
|
FocusOnFirstAttachment();
|
|
}
|
|
|
|
function SetMsgBodyFrameFocus()
|
|
{
|
|
// bug 236219: never just set the focus to window.content, that fails to perform
|
|
// the 'unfocus' operation on the element that currently has focus.
|
|
document.getElementById("appcontent").focus(); // focus to editor's container
|
|
window.content.focus(); // focus to editor
|
|
}
|
|
|
|
function GetMsgAddressingWidgetTreeElement()
|
|
{
|
|
if (!gMsgAddressingWidgetTreeElement)
|
|
gMsgAddressingWidgetTreeElement = document.getElementById("addressingWidgetTree");
|
|
|
|
return gMsgAddressingWidgetTreeElement;
|
|
}
|
|
|
|
function GetMsgIdentityElement()
|
|
{
|
|
if (!gMsgIdentityElement)
|
|
gMsgIdentityElement = document.getElementById("msgIdentity");
|
|
|
|
return gMsgIdentityElement;
|
|
}
|
|
|
|
function GetMsgSubjectElement()
|
|
{
|
|
if (!gMsgSubjectElement)
|
|
gMsgSubjectElement = document.getElementById("msgSubject");
|
|
|
|
return gMsgSubjectElement;
|
|
}
|
|
|
|
function GetMsgAttachmentElement()
|
|
{
|
|
if (!gMsgAttachmentElement)
|
|
gMsgAttachmentElement = document.getElementById("attachmentBucket");
|
|
|
|
return gMsgAttachmentElement;
|
|
}
|
|
|
|
function GetMsgHeadersToolbarElement()
|
|
{
|
|
if (!gMsgHeadersToolbarElement)
|
|
gMsgHeadersToolbarElement = document.getElementById("MsgHeadersToolbar");
|
|
|
|
return gMsgHeadersToolbarElement;
|
|
}
|
|
|
|
function WhichElementHasFocus()
|
|
{
|
|
var msgIdentityElement = GetMsgIdentityElement();
|
|
var msgAddressingWidgetTreeElement = GetMsgAddressingWidgetTreeElement();
|
|
var msgSubjectElement = GetMsgSubjectElement();
|
|
var msgAttachmentElement = GetMsgAttachmentElement();
|
|
|
|
if (top.document.commandDispatcher.focusedWindow == content)
|
|
return content;
|
|
|
|
var currentNode = top.document.commandDispatcher.focusedElement;
|
|
while (currentNode)
|
|
{
|
|
if (currentNode == msgIdentityElement ||
|
|
currentNode == msgAddressingWidgetTreeElement ||
|
|
currentNode == msgSubjectElement ||
|
|
currentNode == msgAttachmentElement)
|
|
return currentNode;
|
|
|
|
currentNode = currentNode.parentNode;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// Function that performs the logic of switching focus from
|
|
// one element to another in the mail compose window.
|
|
// The default element to switch to when going in either
|
|
// direction (shift or no shift key pressed), is the
|
|
// AddressingWidgetTreeElement.
|
|
//
|
|
// The only exception is when the MsgHeadersToolbar is
|
|
// collapsed, then the focus will always be on the body of
|
|
// the message.
|
|
function SwitchElementFocus(event)
|
|
{
|
|
var focusedElement = WhichElementHasFocus();
|
|
|
|
if (event && event.shiftKey)
|
|
{
|
|
if (focusedElement == gMsgAddressingWidgetTreeElement)
|
|
SetMsgIdentityElementFocus();
|
|
else if (focusedElement == gMsgIdentityElement)
|
|
SetMsgBodyFrameFocus();
|
|
else if (focusedElement == content)
|
|
{
|
|
// only set focus to the attachment element if there
|
|
// are any attachments.
|
|
if (AttachmentElementHasItems())
|
|
SetMsgAttachmentElementFocus();
|
|
else
|
|
SetMsgSubjectElementFocus();
|
|
}
|
|
else if (focusedElement == gMsgAttachmentElement)
|
|
SetMsgSubjectElementFocus();
|
|
else
|
|
SetMsgAddressingWidgetTreeElementFocus();
|
|
}
|
|
else
|
|
{
|
|
if (focusedElement == gMsgAddressingWidgetTreeElement)
|
|
SetMsgSubjectElementFocus();
|
|
else if (focusedElement == gMsgSubjectElement)
|
|
{
|
|
// only set focus to the attachment element if there
|
|
// are any attachments.
|
|
if (AttachmentElementHasItems())
|
|
SetMsgAttachmentElementFocus();
|
|
else
|
|
SetMsgBodyFrameFocus();
|
|
}
|
|
else if (focusedElement == gMsgAttachmentElement)
|
|
SetMsgBodyFrameFocus();
|
|
else if (focusedElement == content)
|
|
SetMsgIdentityElementFocus();
|
|
else
|
|
SetMsgAddressingWidgetTreeElementFocus();
|
|
}
|
|
}
|
|
|
|
function toggleAddressPicker()
|
|
{
|
|
var sidebarBox = document.getElementById("sidebar-box");
|
|
var sidebarSplitter = document.getElementById("sidebar-splitter");
|
|
var elt = document.getElementById("viewAddressPicker");
|
|
if (sidebarBox.hidden)
|
|
{
|
|
sidebarBox.hidden = false;
|
|
sidebarSplitter.hidden = false;
|
|
elt.setAttribute("checked","true");
|
|
|
|
var sidebar = document.getElementById("sidebar");
|
|
var sidebarUrl = sidebar.getAttribute("src");
|
|
// if we have yet to initialize the src url on the sidebar than go ahead and do so now...
|
|
// we do this lazily here, so we don't spend time when bringing up the compose window loading the address book
|
|
// data sources. Only when the user opens the address picker do we set the src url for the sidebar...
|
|
if (sidebarUrl == "")
|
|
sidebar.setAttribute("src", "chrome://messenger/content/addressbook/abContactsPanel.xul");
|
|
|
|
sidebarBox.setAttribute("sidebarVisible", "true");
|
|
}
|
|
else
|
|
{
|
|
sidebarBox.hidden = true;
|
|
sidebarSplitter.hidden = true;
|
|
sidebarBox.setAttribute("sidebarVisible", "false");
|
|
elt.removeAttribute("checked");
|
|
}
|
|
}
|
|
|
|
// public method called by the address picker sidebar
|
|
function AddRecipient(recipientType, address)
|
|
{
|
|
awAddRecipient(recipientType, address);
|
|
}
|
|
|
|
function loadHTMLMsgPrefs()
|
|
{
|
|
var pref = GetPrefs();
|
|
var fontFace;
|
|
var fontSize;
|
|
var textColor;
|
|
var bgColor;
|
|
|
|
try {
|
|
fontFace = pref.getCharPref("msgcompose.font_face");
|
|
doStatefulCommand('cmd_fontFace', fontFace);
|
|
} catch (e) {}
|
|
|
|
try {
|
|
fontSize = pref.getCharPref("msgcompose.font_size");
|
|
EditorSetFontSize(fontSize);
|
|
} catch (e) {}
|
|
|
|
var bodyElement = GetBodyElement();
|
|
|
|
try {
|
|
textColor = pref.getCharPref("msgcompose.text_color");
|
|
if (!bodyElement.getAttribute("text"))
|
|
{
|
|
bodyElement.setAttribute("text", textColor);
|
|
gDefaultTextColor = textColor;
|
|
document.getElementById("cmd_fontColor").setAttribute("state", textColor);
|
|
onFontColorChange();
|
|
}
|
|
} catch (e) {}
|
|
|
|
try {
|
|
bgColor = pref.getCharPref("msgcompose.background_color");
|
|
if (!bodyElement.getAttribute("bgcolor"))
|
|
{
|
|
bodyElement.setAttribute("bgcolor", bgColor);
|
|
gDefaultBackgroundColor = bgColor;
|
|
document.getElementById("cmd_backgroundColor").setAttribute("state", bgColor);
|
|
onBackgroundColorChange();
|
|
}
|
|
} catch (e) {}
|
|
}
|
|
|
|
function AutoSave()
|
|
{
|
|
if (gMsgCompose.editor && (gContentChanged || gMsgCompose.bodyModified)
|
|
&& !gSendOrSaveOperationInProgress)
|
|
GenericSendMessage(nsIMsgCompDeliverMode.AutoSaveAsDraft);
|
|
|
|
gAutoSaveTimeout = setTimeout(AutoSave, gAutoSaveInterval);
|
|
}
|
|
|
|
function InitEditor()
|
|
{
|
|
var editor = GetCurrentEditor();
|
|
gMsgCompose.initEditor(editor, window.content);
|
|
InlineSpellChecker.Init(editor, sPrefs.getBoolPref("mail.spellcheck.inline"));
|
|
}
|