!import
1 //@line 40 "/home/visbrero/mnt/roisin/rev_control/hg/mozilla/mail/components/compose/content/MsgComposeCommands.js"
2
3 /**
4 * interfaces
5 */
6 const nsIMsgCompDeliverMode = Components.interfaces.nsIMsgCompDeliverMode;
7 const nsIMsgCompSendFormat = Components.interfaces.nsIMsgCompSendFormat;
8 const nsIMsgCompConvertible = Components.interfaces.nsIMsgCompConvertible;
9 const nsIMsgCompType = Components.interfaces.nsIMsgCompType;
10 const nsIMsgCompFormat = Components.interfaces.nsIMsgCompFormat;
11 const nsIAbPreferMailFormat = Components.interfaces.nsIAbPreferMailFormat;
12 const nsIPlaintextEditorMail = Components.interfaces.nsIPlaintextEditor;
13 const nsISupportsString = Components.interfaces.nsISupportsString;
14 const mozISpellCheckingEngine = Components.interfaces.mozISpellCheckingEngine;
15
16 var sDictCount = 0;
17
18 /* Create message window object. This is use by mail-offline.js and therefore should not be renamed. We need to avoid doing
19 this kind of cross file global stuff in the future and instead pass this object as parameter when needed by function
20 in the other js file.
21 */
22 var msgWindow = Components.classes["@mozilla.org/messenger/msgwindow;1"]
23 .createInstance(Components.interfaces.nsIMsgWindow);
24
25 /**
26 * Global variables, need to be re-initialized every time mostly because we need to release them when the window close
27 */
28 var gHideMenus;
29 var gMsgCompose;
30 var gAccountManager;
31 var gIOService;
32 var gPromptService;
33 var gWindowLocked;
34 var gContentChanged;
35 var gAutoSaving;
36 var gCurrentIdentity;
37 var defaultSaveOperation;
38 var gSendOrSaveOperationInProgress;
39 var gCloseWindowAfterSave;
40 var gIsOffline;
41 var gSessionAdded;
42 var gCurrentAutocompleteDirectory;
43 var gAutocompleteSession;
44 var gSetupLdapAutocomplete;
45 var gLDAPSession;
46 var gSavedSendNowKey;
47 var gSendFormat;
48
49 var gMsgIdentityElement;
50 var gMsgAddressingWidgetTreeElement;
51 var gMsgSubjectElement;
52 var gMsgAttachmentElement;
53 var gMsgHeadersToolbarElement;
54
55 // i18n globals
56 var gCurrentMailSendCharset;
57 var gSendDefaultCharset;
58 var gCharsetTitle;
59 var gCharsetConvertManager;
60
61 var gLastWindowToHaveFocus;
62 var gReceiptOptionChanged;
63 var gDSNOptionChanged;
64 var gAttachVCardOptionChanged;
65
66 var gMailSession;
67 var gAutoSaveInterval;
68 var gAutoSaveTimeout;
69 var gAutoSaveKickedIn;
70 var gEditingDraft;
71
72 const kComposeAttachDirPrefName = "mail.compose.attach.dir";
73
InitializeGlobalVariables
Called: ChromeWindow:getService (5 calls, 129 v-uS)
74 function InitializeGlobalVariables()
75 {
76 gAccountManager = Components.classes["@mozilla.org/messenger/account-manager;1"].getService(Components.interfaces.nsIMsgAccountManager);
77 gIOService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
78 gPromptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
79
80 gMsgCompose = null;
81 gWindowLocked = false;
82 gContentChanged = false;
83 gCurrentIdentity = null;
84 defaultSaveOperation = "draft";
85 gSendOrSaveOperationInProgress = false;
86 gAutoSaving = false;
87 gCloseWindowAfterSave = false;
88 gIsOffline = gIOService.offline;
89 gSessionAdded = false;
90 gCurrentAutocompleteDirectory = null;
91 gAutocompleteSession = null;
92 gSetupLdapAutocomplete = false;
93 gLDAPSession = null;
94 gSavedSendNowKey = null;
95 gSendFormat = nsIMsgCompSendFormat.AskUser;
96 gCurrentMailSendCharset = null;
97 gSendDefaultCharset = null;
98 gCharsetTitle = null;
99 gCharsetConvertManager = Components.classes['@mozilla.org/charset-converter-manager;1'].getService(Components.interfaces.nsICharsetConverterManager);
100 gMailSession = Components.classes["@mozilla.org/messenger/services/session;1"].getService(Components.interfaces.nsIMsgMailSession);
101 gHideMenus = false;
102
103 gLastWindowToHaveFocus = null;
104 gReceiptOptionChanged = false;
105 gDSNOptionChanged = false;
106 gAttachVCardOptionChanged = false;
107 }
108 InitializeGlobalVariables();
109
ReleaseGlobalVariables
Called By: ChromeWindow:CloseWindow (1 calls, 16 v-uS)
110 function ReleaseGlobalVariables()
111 {
112 gAccountManager = null;
113 gIOService = null;
114 gPromptService = null;
115 gCurrentIdentity = null;
116 gCurrentAutocompleteDirectory = null;
117 gAutocompleteSession = null;
118 gLDAPSession = null;
119 gCharsetConvertManager = null;
120 gMsgCompose = null;
121 gMailSession = null;
122 }
123
disableEditableFields
Called: ChromeWindow:setAttribute (3 calls, 236 v-uS)
ChromeWindow:getElementsByAttribute (1 calls, 35 v-uS)
Called By: ChromeWindow:CloseWindow (1 calls, 826 v-uS)
124 function disableEditableFields()
125 {
126 gMsgCompose.editor.flags |= nsIPlaintextEditorMail.eEditorReadonlyMask;
127 var disableElements = document.getElementsByAttribute("disableonsend", "true");
128 for (i=0;i<disableElements.length;i++)
129 {
130 disableElements[i].setAttribute('disabled', 'true');
131 }
132 }
133
enableEditableFields
Called: ChromeWindow:removeAttribute (3 calls, 41 v-uS)
ChromeWindow:getElementsByAttribute (1 calls, 31 v-uS)
Called By: MsgComposeCommands.js:ComposeFieldsReady (1 calls, 627 v-uS)
134 function enableEditableFields()
135 {
136 gMsgCompose.editor.flags &= ~nsIPlaintextEditorMail.eEditorReadonlyMask;
137 var enableElements = document.getElementsByAttribute("disableonsend", "true");
138 for (i=0;i<enableElements.length;i++)
139 {
140 enableElements[i].removeAttribute('disabled');
141 }
142 }
143
144 var gComposeRecyclingListener = {
onClose
145 onClose: function() {
146 //Reset recipients and attachments
147 ReleaseAutoCompleteState();
148 awResetAllRows();
149 RemoveAllAttachments();
150
151 // We need to clear the identity popup menu in case the user will change them.
152 // It will be rebuilt later in ComposeStartup
153 ClearIdentityListPopup(document.getElementById("msgIdentityPopup"));
154
155 //Clear the subject
156 GetMsgSubjectElement().value = "";
157 // be sure to clear the transaction manager for the subject
158 GetMsgSubjectElement().editor.transactionManager.clear();
159 SetComposeWindowTitle();
160
161 SetContentAndBodyAsUnmodified();
162 disableEditableFields();
163 ReleaseGlobalVariables();
164
165 // Clear the focus
166 awGetInputElement(1).removeAttribute('focused');
167
168 //Reset Boxes size
169 document.getElementById("headers-box").removeAttribute("height");
170 document.getElementById("appcontent").removeAttribute("height");
171 document.getElementById("addresses-box").removeAttribute("width");
172 document.getElementById("attachments-box").removeAttribute("width");
173
174 //Reset menu options
175 document.getElementById("format_auto").setAttribute("checked", "true");
176 document.getElementById("priority_normal").setAttribute("checked", "true");
177
178 //Reset toolbars that could be hidden
179 if (gHideMenus) {
180 document.getElementById("formatMenu").hidden = false;
181 document.getElementById("insertMenu").hidden = false;
182 var showFormat = document.getElementById("menu_showFormatToolbar")
183 showFormat.hidden = false;
184 if (showFormat.getAttribute("checked") == "true")
185 document.getElementById("FormatToolbar").hidden = false;
186 }
187
188 // Stop InlineSpellCheckerUI so personal dictionary is saved
189 enableInlineSpellCheck(false);
190 // clear any suggestions in the context menu
191 InlineSpellCheckerUI.clearSuggestionsFromMenu();
192
193 //Reset editor
194 EditorResetFontAndColorAttributes();
195 EditorCleanup();
196
197 //Release the nsIMsgComposeParams object
198 if (window.arguments && window.arguments[0])
199 window.arguments[0] = null;
200
201 var event = document.createEvent('Events');
202 event.initEvent('compose-window-close', false, true);
203 document.getElementById("msgcomposeWindow").dispatchEvent(event);
204 if (gAutoSaveTimeout)
205 clearTimeout(gAutoSaveTimeout);
206 },
207
onReopen
208 onReopen: function(params) {
209 InitializeGlobalVariables();
210 ComposeStartup(true, params);
211
212 var event = document.createEvent('Events');
213 event.initEvent('compose-window-reopen', false, true);
214 document.getElementById("msgcomposeWindow").dispatchEvent(event);
215 }
216 };
217
218 var stateListener = {
NotifyComposeFieldsReady
219 NotifyComposeFieldsReady: function() {
220 ComposeFieldsReady();
221 },
222
NotifyComposeBodyReady
223 NotifyComposeBodyReady: function() {},
224
ComposeProcessDone
225 ComposeProcessDone: function(aResult) {
226 gWindowLocked = false;
227 enableEditableFields();
228 updateComposeItems();
229
230 if (aResult== Components.results.NS_OK)
231 {
232 if (!gAutoSaving)
233 SetContentAndBodyAsUnmodified();
234
235 if (gCloseWindowAfterSave)
236 {
237 // Notify the SendListener that Send has been aborted and Stopped
238 if (gMsgCompose)
239 gMsgCompose.onSendNotPerformed(null, Components.results.NS_ERROR_ABORT);
240
241 MsgComposeCloseWindow(true);
242 }
243 }
244 // else if we failed to save, and we're autosaving, need to re-mark the editor
245 // as changed, so that we won't lose the changes.
246 else if (gAutoSaving)
247 {
248 gMsgCompose.bodyModified = true;
249 gContentChanged = true;
250 }
251 gAutoSaving = false;
252 gCloseWindowAfterSave = false;
253 },
254
SaveInFolderDone
255 SaveInFolderDone: function(folderURI) {
256 DisplaySaveFolderDlg(folderURI);
257 }
258 };
259
260 // all progress notifications are done through the nsIWebProgressListener implementation...
261 var progressListener = {
onStateChange
262 onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
263 {
264 if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_START)
265 {
266 document.getElementById('compose-progressmeter').setAttribute( "mode", "undetermined" );
267 }
268
269 if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP)
270 {
271 gSendOrSaveOperationInProgress = false;
272 document.getElementById('compose-progressmeter').setAttribute( "mode", "normal" );
273 document.getElementById('compose-progressmeter').setAttribute( "value", 0 );
274 document.getElementById('statusText').setAttribute('label', '');
275 }
276 },
277
onProgressChange
278 onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
279 {
280 // Calculate percentage.
281 var percent;
282 if ( aMaxTotalProgress > 0 )
283 {
284 percent = Math.round( (aCurTotalProgress*100)/aMaxTotalProgress );
285 if ( percent > 100 )
286 percent = 100;
287
288 document.getElementById('compose-progressmeter').removeAttribute("mode");
289
290 // Advance progress meter.
291 document.getElementById('compose-progressmeter').setAttribute( "value", percent );
292 }
293 else
294 {
295 // Progress meter should be barber-pole in this case.
296 document.getElementById('compose-progressmeter').setAttribute( "mode", "undetermined" );
297 }
298 },
299
onLocationChange
300 onLocationChange: function(aWebProgress, aRequest, aLocation)
301 {
302 // we can ignore this notification
303 },
304
onStatusChange
305 onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage)
306 {
307 // Looks like it's possible that we get call while the document has been already delete!
308 // therefore we need to protect ourself by using try/catch
309 try {
310 statusText = document.getElementById("statusText");
311 if (statusText)
312 statusText.setAttribute("label", aMessage);
313 } catch (ex) {}
314 },
315
onSecurityChange
316 onSecurityChange: function(aWebProgress, aRequest, state)
317 {
318 // we can ignore this notification
319 },
320
QueryInterface
321 QueryInterface : function(iid)
322 {
323 if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
324 iid.equals(Components.interfaces.nsISupportsWeakReference) ||
325 iid.equals(Components.interfaces.nsISupports))
326 return this;
327
328 throw Components.results.NS_NOINTERFACE;
329 }
330 };
331
332 var defaultController =
333 {
supportsCommand
334 supportsCommand: function(command)
335 {
336 switch (command)
337 {
338 //File Menu
339 case "cmd_attachFile":
340 case "cmd_attachPage":
341 case "cmd_close":
342 case "cmd_saveDefault":
343 case "cmd_saveAsFile":
344 case "cmd_saveAsDraft":
345 case "cmd_saveAsTemplate":
346 case "cmd_sendButton":
347 case "cmd_sendNow":
348 case "cmd_sendWithCheck":
349 case "cmd_sendLater":
350 case "cmd_printSetup":
351 case "cmd_print":
352 case "cmd_quit":
353
354 //Edit Menu
355 case "cmd_delete":
356 case "cmd_renameAttachment":
357 case "cmd_selectAll":
358 case "cmd_openAttachment":
359 case "cmd_account":
360
361 //View Menu
362 case "cmd_showComposeToolbar":
363 case "cmd_showFormatToolbar":
364
365 //Options Menu
366 case "cmd_selectAddress":
367 case "cmd_outputFormat":
368 case "cmd_quoteMessage":
369 return true;
370
371 default:
372 // dump("##MsgCompose: command " + command + "no supported!\n");
373 return false;
374 }
375 },
isCommandEnabled
Called By: MsgComposeCommands.js:MessageComposeOfflineStateChanged (1 calls, 10 v-uS)
376 isCommandEnabled: function(command)
377 {
378 var composeHTML = gMsgCompose && gMsgCompose.composeHTML;
379
380 switch (command)
381 {
382 //File Menu
383 case "cmd_attachFile":
384 case "cmd_attachPage":
385 case "cmd_close":
386 case "cmd_saveDefault":
387 case "cmd_saveAsFile":
388 case "cmd_saveAsDraft":
389 case "cmd_saveAsTemplate":
390 case "cmd_sendButton":
391 case "cmd_sendLater":
392 case "cmd_printSetup":
393 case "cmd_print":
394 case "cmd_sendWithCheck":
395 return !gWindowLocked;
396 case "cmd_sendNow":
397 return !(gWindowLocked || gIsOffline);
398 case "cmd_quit":
399 return true;
400
401 //Edit Menu
402 case "cmd_delete":
403 return MessageGetNumSelectedAttachments();
404 case "cmd_selectAll":
405 return MessageHasAttachments();
406 case "cmd_openAttachment":
407 return MessageGetNumSelectedAttachments() == 1;
408 case "cmd_renameAttachment":
409 return MessageGetNumSelectedAttachments() == 1;
410 case "cmd_account":
411
412 //View Menu
413 case "cmd_showComposeToolbar":
414 return true;
415 case "cmd_showFormatToolbar":
416 return composeHTML;
417
418 //Options Menu
419 case "cmd_selectAddress":
420 return !gWindowLocked;
421 case "cmd_outputFormat":
422 return composeHTML;
423 case "cmd_quoteMessage":
424 var selectedURIs = GetSelectedMessages();
425 if (selectedURIs && selectedURIs.length > 0)
426 return true;
427 return false;
428
429 default:
430 // dump("##MsgCompose: command " + command + " disabled!\n");
431 return false;
432 }
433 },
434
doCommand
435 doCommand: function(command)
436 {
437 switch (command)
438 {
439 //File Menu
440 case "cmd_attachFile" : if (defaultController.isCommandEnabled(command)) AttachFile(); break;
441 case "cmd_attachPage" : AttachPage(); break;
442 case "cmd_close" : DoCommandClose(); break;
443 case "cmd_saveDefault" : Save(); break;
444 case "cmd_saveAsFile" : SaveAsFile(true); break;
445 case "cmd_saveAsDraft" : SaveAsDraft(); break;
446 case "cmd_saveAsTemplate" : SaveAsTemplate(); break;
447 case "cmd_sendButton" :
448 if (defaultController.isCommandEnabled(command))
449 {
450 if (gIOService && gIOService.offline)
451 SendMessageLater();
452 else
453 SendMessage();
454 }
455 break;
456 case "cmd_sendNow" : if (defaultController.isCommandEnabled(command)) SendMessage(); break;
457 case "cmd_sendWithCheck" : if (defaultController.isCommandEnabled(command)) SendMessageWithCheck(); break;
458 case "cmd_sendLater" : if (defaultController.isCommandEnabled(command)) SendMessageLater(); break;
459 case "cmd_printSetup" : PrintUtils.showPageSetup(); break;
460 case "cmd_print" : DoCommandPrint(); break;
461
462 //Edit Menu
463 case "cmd_delete" : if (MessageGetNumSelectedAttachments()) RemoveSelectedAttachment(); break;
464 case "cmd_renameAttachment" : if (MessageGetNumSelectedAttachments() == 1) RenameSelectedAttachment(); break;
465 case "cmd_selectAll" : if (MessageHasAttachments()) SelectAllAttachments(); break;
466 case "cmd_openAttachment" : if (MessageGetNumSelectedAttachments() == 1) OpenSelectedAttachment(); break;
467 case "cmd_account" : MsgAccountManager(null); break;
468
469 //View Menu
470 case "cmd_showComposeToolbar" : goToggleToolbar('composeToolbar2', 'menu_showComposeToolbar'); break;
471 case "cmd_showFormatToolbar" : goToggleToolbar('FormatToolbar', 'menu_showFormatToolbar'); break;
472
473 //Options Menu
474 case "cmd_selectAddress" : if (defaultController.isCommandEnabled(command)) SelectAddress(); break;
475 case "cmd_quoteMessage" : if (defaultController.isCommandEnabled(command)) QuoteSelectedMessage(); break;
476 default:
477 // dump("##MsgCompose: don't know what to do with command " + command + "!\n");
478 return;
479 }
480 },
481
onEvent
482 onEvent: function(event)
483 {
484 // dump("DefaultController:onEvent\n");
485 }
486 }
487
goOpenNewMessage
488 function goOpenNewMessage()
489 {
490 // if there is a MsgNewMessage function in scope
491 // and we should use it, so that we choose the proper
492 // identity, based on the selected message or folder
493 // if not, bring up the compose window to the default identity
494 if ("MsgNewMessage" in window) {
495 MsgNewMessage(null);
496 return;
497 }
498
499 var msgComposeService = Components.classes["@mozilla.org/messengercompose;1"].getService();
500 msgComposeService = msgComposeService.QueryInterface(Components.interfaces.nsIMsgComposeService);
501 msgComposeService.OpenComposeWindow(null, null,
502 Components.interfaces.nsIMsgCompType.New,
503 Components.interfaces.nsIMsgCompFormat.Default,
504 null, null);
505 }
506
QuoteSelectedMessage
507 function QuoteSelectedMessage()
508 {
509 var selectedURIs = GetSelectedMessages();
510 if (selectedURIs)
511 for (i = 0; i < selectedURIs.length; i++)
512 gMsgCompose.quoteMessage(selectedURIs[i]);
513 }
514
GetSelectedMessages
Called: ChromeWindow:QueryInterface (4 calls, 72 v-uS)
ChromeWindow:getMostRecentWindow (4 calls, 146 v-uS)
ChromeWindow:getService (4 calls, 82 v-uS)
msgMail3PaneWindow.js:GetSelectedMessages (4 calls, 684 v-uS)
Called By: ChromeWindow:isCommandEnabled (4 calls, 1297 v-uS)
515 function GetSelectedMessages()
516 {
517 if (gMsgCompose) {
518 var mailWindow = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService()
519 .QueryInterface(Components.interfaces.nsIWindowMediator)
520 .getMostRecentWindow("mail:3pane");
521 if (mailWindow) {
522 return mailWindow.GetSelectedMessages();
523 }
524 }
525
526 return null;
527 }
528
SetupCommandUpdateHandlers
Called: ChromeWindow:insertControllerAt (1 calls, 17 v-uS)
Called By: MsgComposeCommands.js:ComposeLoad (1 calls, 73 v-uS)
529 function SetupCommandUpdateHandlers()
530 {
531 top.controllers.insertControllerAt(0, defaultController);
532 }
533
CommandUpdate_MsgCompose
Called: MsgComposeCommands.js:updateComposeItems (4 calls, 23199 v-uS)
Called By: ChromeWindow:XPCNativeWrapper function wrapper (1 calls, 15139 v-uS)
ChromeWindow:focus (1 calls, 4879 v-uS)
XULElement:focus (1 calls, 2742 v-uS)
534 function CommandUpdate_MsgCompose()
535 {
536 var focusedWindow = top.document.commandDispatcher.focusedWindow;
537
538 // we're just setting focus to where it was before
539 if (focusedWindow == gLastWindowToHaveFocus) {
540 //dump("XXX skip\n");
541 return;
542 }
543
544 gLastWindowToHaveFocus = focusedWindow;
545
546 //dump("XXX update, focus on " + focusedWindow + "\n");
547
548 updateComposeItems();
549 }
550
updateComposeItems
Called: globalOverlay.js:goUpdateCommand (63 calls, 27731 v-uS)
Called By: MsgComposeCommands.js:CommandUpdate_MsgCompose (4 calls, 23199 v-uS)
551 function updateComposeItems()
552 {
553 try {
554 // Edit Menu
555 goUpdateCommand("cmd_rewrap");
556
557 // Insert Menu
558 if (gMsgCompose && gMsgCompose.composeHTML)
559 {
560 goUpdateCommand("cmd_renderedHTMLEnabler");
561 goUpdateCommand("cmd_decreaseFont");
562 goUpdateCommand("cmd_increaseFont");
563 goUpdateCommand("cmd_bold");
564 goUpdateCommand("cmd_italic");
565 goUpdateCommand("cmd_underline");
566 goUpdateCommand("cmd_ul");
567 goUpdateCommand("cmd_ol");
568 goUpdateCommand("cmd_indent");
569 goUpdateCommand("cmd_outdent");
570 goUpdateCommand("cmd_align");
571 goUpdateCommand("cmd_smiley");
572 }
573
574 // Options Menu
575 goUpdateCommand("cmd_spelling");
576 goUpdateCommand("cmd_quoteMessage");
577 } catch(e) {}
578 }
579
580 function openEditorContextMenu(popup)
581 {
582 InlineSpellCheckerUI.clearSuggestionsFromMenu();
583 InlineSpellCheckerUI.initFromEvent(document.popupRangeParent, document.popupRangeOffset);
584 var onMisspelling = InlineSpellCheckerUI.overMisspelling;
585 document.getElementById('spellCheckSuggestionsSeparator').hidden = !onMisspelling;
586 document.getElementById('spellCheckAddToDictionary').hidden = !onMisspelling;
587 document.getElementById('spellCheckIgnoreWord').hidden = !onMisspelling;
588 var separator = document.getElementById('spellCheckAddSep');
589 separator.hidden = !onMisspelling;
590 document.getElementById('spellCheckNoSuggestions').hidden = !onMisspelling ||
591 InlineSpellCheckerUI.addSuggestionsToMenu(popup, separator, 5);
592
593 updateEditItems();
594 }
595
updateEditItems
596 function updateEditItems()
597 {
598 goUpdateCommand("cmd_pasteNoFormatting");
599 goUpdateCommand("cmd_pasteQuote");
600 goUpdateCommand("cmd_delete");
601 goUpdateCommand("cmd_renameAttachment");
602 goUpdateCommand("cmd_selectAll");
603 goUpdateCommand("cmd_openAttachment");
604 goUpdateCommand("cmd_find");
605 goUpdateCommand("cmd_findNext");
606 goUpdateCommand("cmd_findPrev");
607 }
608
609 var messageComposeOfflineObserver =
610 {
observe
611 observe: function(subject, topic, state)
612 {
613 // sanity checks
614 if (topic != "network:offline-status-changed")
615 return;
616 gIsOffline = state == "offline";
617 MessageComposeOfflineStateChanged(gIsOffline);
618
619 try {
620 setupLdapAutocompleteSession();
621 } catch (ex) {
622 // catch the exception and ignore it, so that if LDAP setup
623 // fails, the entire compose window stuff doesn't get aborted
624 }
625 }
626 }
627
AddMessageComposeOfflineObserver
Called: ChromeWindow:addObserver (1 calls, 23 v-uS)
ChromeWindow:getService (1 calls, 20 v-uS)
MsgComposeCommands.js:MessageComposeOfflineStateChanged (1 calls, 826 v-uS)
Called By: MsgComposeCommands.js:ComposeLoad (1 calls, 970 v-uS)
628 function AddMessageComposeOfflineObserver()
629 {
630 var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
631 observerService.addObserver(messageComposeOfflineObserver, "network:offline-status-changed", false);
632
633 gIsOffline = gIOService.offline;
634 // set the initial state of the send button
635 MessageComposeOfflineStateChanged(gIsOffline);
636 }
637
RemoveMessageComposeOfflineObserver
Called: ChromeWindow:getService (1 calls, 21 v-uS)
ChromeWindow:removeObserver (1 calls, 22 v-uS)
Called By: MsgComposeCommands.js:ComposeUnload (1 calls, 189 v-uS)
638 function RemoveMessageComposeOfflineObserver()
639 {
640 var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
641 observerService.removeObserver(messageComposeOfflineObserver,"network:offline-status-changed");
642 }
643
MessageComposeOfflineStateChanged
Called: ChromeWindow:getAttribute (3 calls, 51 v-uS)
ChromeWindow:getElementById (2 calls, 508 v-uS)
ChromeWindow:setAttribute (2 calls, 25 v-uS)
MsgComposeCommands.js:isCommandEnabled (1 calls, 10 v-uS)
XULElement:setAttribute (1 calls, 13 v-uS)
globalOverlay.js:goSetCommandEnabled (1 calls, 77 v-uS)
Called By: MsgComposeCommands.js:AddMessageComposeOfflineObserver (1 calls, 826 v-uS)
644 function MessageComposeOfflineStateChanged(goingOffline)
645 {
646 try {
647 var sendButton = document.getElementById("button-send");
648 var sendNowMenuItem = document.getElementById("menu-item-send-now");
649
650 if (!gSavedSendNowKey) {
651 gSavedSendNowKey = sendNowMenuItem.getAttribute('key');
652 }
653
654 // don't use goUpdateCommand here ... the defaultController might not be installed yet
655 goSetCommandEnabled("cmd_sendNow", defaultController.isCommandEnabled("cmd_sendNow"));
656
657 if (goingOffline)
658 {
659 sendButton.label = sendButton.getAttribute('later_label');
660 sendButton.setAttribute('tooltiptext', sendButton.getAttribute('later_tooltiptext'));
661 sendNowMenuItem.removeAttribute('key');
662 }
663 else
664 {
665 sendButton.label = sendButton.getAttribute('now_label');
666 sendButton.setAttribute('tooltiptext', sendButton.getAttribute('now_tooltiptext'));
667 if (gSavedSendNowKey) {
668 sendNowMenuItem.setAttribute('key', gSavedSendNowKey);
669 }
670 }
671
672 } catch(e) {}
673 }
674
675 var directoryServerObserver = {
observe
676 observe: function(subject, topic, value) {
677 try {
678 setupLdapAutocompleteSession();
679 } catch (ex) {
680 // catch the exception and ignore it, so that if LDAP setup
681 // fails, the entire compose window doesn't get horked
682 }
683 }
684 }
685
AddDirectoryServerObserver
Called: ChromeWindow:addObserver (4 calls, 101 v-uS)
ChromeWindow:getService (2 calls, 40 v-uS)
Called By: MsgComposeCommands.js:ComposeLoad (1 calls, 160 v-uS)
MsgComposeCommands.js:LoadIdentity (1 calls, 129 v-uS)
686 function AddDirectoryServerObserver(flag) {
687 var branch = Components.classes["@mozilla.org/preferences-service;1"]
688 .getService(Components.interfaces.nsIPrefBranch2);
689 if (flag) {
690 branch.addObserver("ldap_2.autoComplete.useDirectory",
691 directoryServerObserver, false);
692 branch.addObserver("ldap_2.autoComplete.directoryServer",
693 directoryServerObserver, false);
694 }
695 else
696 {
697 var prefstring = "mail.identity." + gCurrentIdentity.key + ".overrideGlobal_Pref";
698 branch.addObserver(prefstring, directoryServerObserver, false);
699 prefstring = "mail.identity." + gCurrentIdentity.key + ".directoryServer";
700 branch.addObserver(prefstring, directoryServerObserver, false);
701 }
702 }
703
RemoveDirectoryServerObserver
Called: ChromeWindow:removeObserver (2 calls, 70 v-uS)
ChromeWindow:getService (1 calls, 17 v-uS)
Called By: MsgComposeCommands.js:ComposeUnload (1 calls, 177 v-uS)
704 function RemoveDirectoryServerObserver(prefstring)
705 {
706 var branch = Components.classes["@mozilla.org/preferences-service;1"]
707 .getService(Components.interfaces.nsIPrefBranch2);
708 if (!prefstring) {
709 branch.removeObserver("ldap_2.autoComplete.useDirectory",
710 directoryServerObserver);
711 branch.removeObserver("ldap_2.autoComplete.directoryServer",
712 directoryServerObserver);
713 }
714 else
715 {
716 var str = prefstring + ".overrideGlobal_Pref";
717 branch.removeObserver(str, directoryServerObserver);
718 str = prefstring + ".directoryServer";
719 branch.removeObserver(str, directoryServerObserver);
720 }
721 }
722
AddDirectorySettingsObserver
723 function AddDirectorySettingsObserver()
724 {
725 var branch = Components.classes["@mozilla.org/preferences-service;1"]
726 .getService(Components.interfaces.nsIPrefBranch2);
727 branch.addObserver(gCurrentAutocompleteDirectory, directoryServerObserver,
728 false);
729 }
730
RemoveDirectorySettingsObserver
731 function RemoveDirectorySettingsObserver(prefstring)
732 {
733 var branch = Components.classes["@mozilla.org/preferences-service;1"]
734 .getService(Components.interfaces.nsIPrefBranch2);
735 branch.removeObserver(prefstring, directoryServerObserver);
736 }
737
setupLdapAutocompleteSession
738 function setupLdapAutocompleteSession()
739 {
740 var autocompleteLdap = false;
741 var autocompleteDirectory = null;
742 var prevAutocompleteDirectory = gCurrentAutocompleteDirectory;
743 var i;
744
745 autocompleteLdap = getPref("ldap_2.autoComplete.useDirectory");
746 if (autocompleteLdap)
747 autocompleteDirectory = getPref("ldap_2.autoComplete.directoryServer");
748
749 if(gCurrentIdentity.overrideGlobalPref) {
750 autocompleteDirectory = gCurrentIdentity.directoryServer;
751 }
752
753 // use a temporary to do the setup so that we don't overwrite the
754 // global, then have some problem and throw an exception, and leave the
755 // global with a partially setup session. we'll assign the temp
756 // into the global after we're done setting up the session
757 //
758 var LDAPSession;
759 if (gLDAPSession) {
760 LDAPSession = gLDAPSession;
761 } else {
762 LDAPSession = Components
763 .classes["@mozilla.org/autocompleteSession;1?type=ldap"];
764 if (LDAPSession) {
765 try {
766 LDAPSession = LDAPSession.createInstance()
767 .QueryInterface(Components.interfaces.nsILDAPAutoCompleteSession);
768 } catch (ex) {dump ("ERROR: Cannot get the LDAP autocomplete session\n" + ex + "\n");}
769 }
770 }
771
772 if (autocompleteDirectory && !gIsOffline) {
773 // Add observer on the directory server we are autocompleting against
774 // only if current server is different from previous.
775 // Remove observer if current server is different from previous
776 gCurrentAutocompleteDirectory = autocompleteDirectory;
777 if (prevAutocompleteDirectory) {
778 if (prevAutocompleteDirectory != gCurrentAutocompleteDirectory) {
779 RemoveDirectorySettingsObserver(prevAutocompleteDirectory);
780 AddDirectorySettingsObserver();
781 }
782 }
783 else
784 AddDirectorySettingsObserver();
785
786 // fill in the session params if there is a session
787 //
788 if (LDAPSession) {
789 var serverURL = Components.classes[
790 "@mozilla.org/network/ldap-url;1"].
791 createInstance().QueryInterface(
792 Components.interfaces.nsILDAPURL);
793
794 try {
795 serverURL.spec = getPref(autocompleteDirectory + ".uri", true);
796 } catch (ex) {
797 dump("ERROR: " + ex + "\n");
798 }
799 LDAPSession.serverURL = serverURL;
800
801 // get the login to authenticate as, if there is one
802 //
803 var login = "";
804 try {
805 login = getPref(autocompleteDirectory + ".auth.dn", true);
806 } catch (ex) {
807 // if we don't have this pref, no big deal
808 }
809
810 // set the LDAP protocol version correctly
811 var protocolVersion;
812 try {
813 protocolVersion = getPref(autocompleteDirectory +
814 ".protocolVersion");
815 } catch (ex) {
816 // if we don't have this pref, no big deal
817 }
818 if (protocolVersion == "2") {
819 LDAPSession.version =
820 Components.interfaces.nsILDAPConnection.VERSION2;
821 }
822
823 // don't search on non-CJK strings shorter than this
824 //
825 try {
826 LDAPSession.minStringLength = getPref(
827 autocompleteDirectory + ".autoComplete.minStringLength");
828 } catch (ex) {
829 // if this pref isn't there, no big deal. just let
830 // nsLDAPAutoCompleteSession use its default.
831 }
832
833 // don't search on CJK strings shorter than this
834 //
835 try {
836 LDAPSession.cjkMinStringLength = getPref(
837 autocompleteDirectory + ".autoComplete.cjkMinStringLength");
838 } catch (ex) {
839 // if this pref isn't there, no big deal. just let
840 // nsLDAPAutoCompleteSession use its default.
841 }
842
843 // we don't try/catch here, because if this fails, we're outta luck
844 //
845 var ldapFormatter = Components.classes[
846 "@mozilla.org/ldap-autocomplete-formatter;1?type=addrbook"]
847 .createInstance().QueryInterface(
848 Components.interfaces.nsIAbLDAPAutoCompFormatter);
849
850 // override autocomplete name format?
851 //
852 try {
853 ldapFormatter.nameFormat = getPref(autocompleteDirectory +
854 ".autoComplete.nameFormat",
855 true);
856 } catch (ex) {
857 // if this pref isn't there, no big deal. just let
858 // nsAbLDAPAutoCompFormatter use its default.
859 }
860
861 // override autocomplete mail address format?
862 //
863 try {
864 ldapFormatter.addressFormat = getPref(autocompleteDirectory +
865 ".autoComplete.addressFormat",
866 true);
867 } catch (ex) {
868 // if this pref isn't there, no big deal. just let
869 // nsAbLDAPAutoCompFormatter use its default.
870 }
871
872 try {
873 // figure out what goes in the comment column, if anything
874 //
875 // 0 = none
876 // 1 = name of addressbook this card came from
877 // 2 = other per-addressbook format
878 //
879 var showComments = getPref("mail.autoComplete.commentColumn");
880
881 switch (showComments) {
882
883 case 1:
884 // use the name of this directory
885 //
886 ldapFormatter.commentFormat = getPref(
887 autocompleteDirectory + ".description", true);
888 break;
889
890 case 2:
891 // override ldap-specific autocomplete entry?
892 //
893 try {
894 ldapFormatter.commentFormat =
895 getPref(autocompleteDirectory +
896 ".autoComplete.commentFormat", true);
897 } catch (innerException) {
898 // if nothing has been specified, use the ldap
899 // organization field
900 ldapFormatter.commentFormat = "[o]";
901 }
902 break;
903
904 case 0:
905 default:
906 // do nothing
907 }
908 } catch (ex) {
909 // if something went wrong while setting up comments, try and
910 // proceed anyway
911 }
912
913 // set the session's formatter, which also happens to
914 // force a call to the formatter's getAttributes() method
915 // -- which is why this needs to happen after we've set the
916 // various formats
917 //
918 LDAPSession.formatter = ldapFormatter;
919
920 // override autocomplete entry formatting?
921 //
922 try {
923 LDAPSession.outputFormat = getPref(autocompleteDirectory +
924 ".autoComplete.outputFormat",
925 true);
926
927 } catch (ex) {
928 // if this pref isn't there, no big deal. just let
929 // nsLDAPAutoCompleteSession use its default.
930 }
931
932 // override default search filter template?
933 //
934 try {
935 LDAPSession.filterTemplate = getPref(
936 autocompleteDirectory + ".autoComplete.filterTemplate",
937 true);
938
939 } catch (ex) {
940 // if this pref isn't there, no big deal. just let
941 // nsLDAPAutoCompleteSession use its default
942 }
943
944 // override default maxHits (currently 100)
945 //
946 try {
947 // XXXdmose should really use .autocomplete.maxHits,
948 // but there's no UI for that yet
949 //
950 LDAPSession.maxHits = getPref(autocompleteDirectory + ".maxHits");
951 } catch (ex) {
952 // if this pref isn't there, or is out of range, no big deal.
953 // just let nsLDAPAutoCompleteSession use its default.
954 }
955
956 if (!gSessionAdded) {
957 // if we make it here, we know that session initialization has
958 // succeeded; add the session for all recipients, and
959 // remember that we've done so
960 var autoCompleteWidget;
961 for (i=1; i <= awGetMaxRecipients(); i++)
962 {
963 autoCompleteWidget = document.getElementById("addressCol2#" + i);
964 if (autoCompleteWidget)
965 {
966 autoCompleteWidget.addSession(LDAPSession);
967 // ldap searches don't insert a default entry with the default domain appended to it
968 // so reduce the minimum results for a popup to 2 in this case.
969 autoCompleteWidget.minResultsForPopup = 2;
970
971 }
972 }
973 gSessionAdded = true;
974 }
975 }
976 } else {
977 if (gCurrentAutocompleteDirectory) {
978 // Remove observer on the directory server since we are not doing Ldap
979 // autocompletion.
980 RemoveDirectorySettingsObserver(gCurrentAutocompleteDirectory);
981 gCurrentAutocompleteDirectory = null;
982 }
983 if (gLDAPSession && gSessionAdded) {
984 for (i=1; i <= awGetMaxRecipients(); i++)
985 document.getElementById("addressCol2#" + i).
986 removeSession(gLDAPSession);
987 gSessionAdded = false;
988 }
989 }
990
991 gLDAPSession = LDAPSession;
992 gSetupLdapAutocomplete = true;
993 }
994
DoCommandClose
995 function DoCommandClose()
996 {
997 if (ComposeCanClose()) {
998
999 // Notify the SendListener that Send has been aborted and Stopped
1000 if (gMsgCompose)
1001 gMsgCompose.onSendNotPerformed(null, Components.results.NS_ERROR_ABORT);
1002
1003 // note: if we're not caching this window, this destroys it for us
1004 MsgComposeCloseWindow(true);
1005 }
1006
1007 return false;
1008 }
1009
DoCommandPrint
1010 function DoCommandPrint()
1011 {
1012 try {
1013 PrintUtils.print();
1014 } catch(ex) {dump("#PRINT ERROR: " + ex + "\n");}
1015 }
1016
ToggleWindowLock
1017 function ToggleWindowLock()
1018 {
1019 gWindowLocked = !gWindowLocked;
1020 updateComposeItems();
1021 }
1022
1023 /* This function will go away soon as now arguments are passed to the window using a object of type nsMsgComposeParams instead of a string */
GetArgs
1024 function GetArgs(originalData)
1025 {
1026 var args = new Object();
1027
1028 if (originalData == "")
1029 return null;
1030
1031 var data = "";
1032 var separator = String.fromCharCode(1);
1033
1034 var quoteChar = "";
1035 var prevChar = "";
1036 var nextChar = "";
1037 for (var i = 0; i < originalData.length; i ++, prevChar = aChar)
1038 {
1039 var aChar = originalData.charAt(i)
1040 var aCharCode = originalData.charCodeAt(i)
1041 if ( i < originalData.length - 1)
1042 nextChar = originalData.charAt(i + 1);
1043 else
1044 nextChar = "";
1045
1046 if (aChar == quoteChar && (nextChar == "," || nextChar == ""))
1047 {
1048 quoteChar = "";
1049 data += aChar;
1050 }
1051 else if ((aCharCode == 39 || aCharCode == 34) && prevChar == "=") //quote or double quote
1052 {
1053 if (quoteChar == "")
1054 quoteChar = aChar;
1055 data += aChar;
1056 }
1057 else if (aChar == ",")
1058 {
1059 if (quoteChar == "")
1060 data += separator;
1061 else
1062 data += aChar
1063 }
1064 else
1065 data += aChar
1066 }
1067
1068 var pairs = data.split(separator);
1069 // dump("Compose: argument: {" + data + "}\n");
1070
1071 for (i = pairs.length - 1; i >= 0; i--)
1072 {
1073 var pos = pairs[i].indexOf('=');
1074 if (pos == -1)
1075 continue;
1076 var argname = pairs[i].substring(0, pos);
1077 var argvalue = pairs[i].substring(pos + 1);
1078 if (argvalue.charAt(0) == "'" && argvalue.charAt(argvalue.length - 1) == "'")
1079 args[argname] = argvalue.substring(1, argvalue.length - 1);
1080 else
1081 try {
1082 args[argname] = decodeURIComponent(argvalue);
1083 } catch (e) {args[argname] = argvalue;}
1084 dump("[" + argname + "=" + args[argname] + "]\n");
1085 }
1086 return args;
1087 }
1088
ComposeFieldsReady
Called: ChromeWindow:setTimeout (1 calls, 42 v-uS)
MsgComposeCommands.js:AdjustFocus (1 calls, 276 v-uS)
MsgComposeCommands.js:SetComposeWindowTitle (1 calls, 3361 v-uS)
MsgComposeCommands.js:enableEditableFields (1 calls, 627 v-uS)
Called By: ChromeWindow:initEditor (1 calls, 28275 v-uS)
1089 function ComposeFieldsReady()
1090 {
1091 //If we are in plain text, we need to set the wrap column
1092 if (! gMsgCompose.composeHTML) {
1093 try {
1094 gMsgCompose.editor.QueryInterface(nsIPlaintextEditorMail).wrapWidth
1095 = gMsgCompose.wrapLength;
1096 }
1097 catch (e) {
1098 dump("### textEditor.wrapWidth exception text: " + e + " - failed\n");
1099 }
1100 }
1101 CompFields2Recipients(gMsgCompose.compFields);
1102 SetComposeWindowTitle();
1103
1104 // need timeout for reply to work
1105 if (gMsgCompose.composeHTML)
1106 setTimeout("loadHTMLMsgPrefs();", 0);
1107
1108 enableEditableFields();
1109 AdjustFocus();
1110 }
1111
1112 // checks if the passed in string is a mailto url, if it is, generates nsIMsgComposeParams
1113 // for the url and returns them.
handleMailtoArgs
1114 function handleMailtoArgs(mailtoUrl)
1115 {
1116 // see if the string is a mailto url....do this by checking the first 7 characters of the string
1117 if (/^mailto:/i.test(mailtoUrl))
1118 {
1119 // if it is a mailto url, turn the mailto url into a MsgComposeParams object....
1120 var uri = gIOService.newURI(mailtoUrl, null, null);
1121
1122 if (uri) {
1123 var composeSvc = Components.classes["@mozilla.org/messengercompose;1"]
1124 .getService(Components.interfaces.nsIMsgComposeService);
1125 return composeSvc.getParamsForMailto(uri);
1126 }
1127 }
1128
1129 return null;
1130 }
1131
ComposeStartup
Called: ChromeWindow:getElementById (8 calls, 874 v-uS)
XULElement:setAttribute (5 calls, 205 v-uS)
ChromeWindow:setAttribute (4 calls, 129 v-uS)
XULElement:addBroadcastListenerFor (4 calls, 98 v-uS)
XULElement:getAttribute (4 calls, 54 v-uS)
MsgComposeCommands.js:getPref (3 calls, 305 v-uS)
ChromeWindow:Count (2 calls, 20 v-uS)
XULElement:QueryInterface (2 calls, 28 v-uS)
XULElement:createEvent (2 calls, 47 v-uS)
XULElement:dispatchEvent (2 calls, 77 v-uS)
XULElement:initEvent (2 calls, 29 v-uS)
ChromeWindow:InitCompose (1 calls, 498 v-uS)
ChromeWindow:RegisterStateListener (1 calls, 78 v-uS)
ChromeWindow:addCommandObserver (1 calls, 209 v-uS)
ChromeWindow:addEventListener (1 calls, 28 v-uS)
ChromeWindow:createEvent (1 calls, 40 v-uS)
ChromeWindow:dispatchEvent (1 calls, 47 v-uS)
ChromeWindow:getAttribute (1 calls, 18 v-uS)
ChromeWindow:getService (1 calls, 28 v-uS)
ChromeWindow:initEvent (1 calls, 27 v-uS)
ChromeWindow:loadURI (1 calls, 660 v-uS)
ChromeWindow:setTimeout (1 calls, 47 v-uS)
MsgComposeCommands.js:FillIdentityList (1 calls, 1563 v-uS)
MsgComposeCommands.js:GetMsgSubjectElement (1 calls, 59 v-uS)
MsgComposeCommands.js:InitLanguageMenu (1 calls, 3108 v-uS)
MsgComposeCommands.js:LoadIdentity (1 calls, 328 v-uS)
XULElement:getElementsByAttribute (1 calls, 29 v-uS)
XULElement:item (1 calls, 17 v-uS)
editor.js:EditorSharedStartup (1 calls, 10687 v-uS)
editor.js:initLocalFontFaceMenu (1 calls, 56404 v-uS)
editor.xml:makeEditable (1 calls, 3949 v-uS)
editorUtilities.js:GetCurrentCommandManager (1 calls, 1001 v-uS)
editorUtilities.js:GetCurrentEditorElement (1 calls, 224 v-uS)
menulist.xml:contains (1 calls, 28 v-uS)
textbox.xml:_updateVisibleText (1 calls, 129 v-uS)
Called By: MsgComposeCommands.js:ComposeLoad (1 calls, 83097 v-uS)
1132 function ComposeStartup(recycled, aParams)
1133 {
1134 var params = null; // New way to pass parameters to the compose window as a nsIMsgComposeParameters object
1135 var args = null; // old way, parameters are passed as a string
1136
1137 if (aParams)
1138 params = aParams;
1139 else if (window.arguments && window.arguments[0]) {
1140 try {
1141 if (window.arguments[0] instanceof Components.interfaces.nsIMsgComposeParams)
1142 params = window.arguments[0];
1143 else
1144 params = handleMailtoArgs(window.arguments[0]);
1145 }
1146 catch(ex) { dump("ERROR with parameters: " + ex + "\n"); }
1147
1148 // if still no dice, try and see if the params is an old fashioned list of string attributes
1149 // XXX can we get rid of this yet?
1150 if (!params)
1151 {
1152 args = GetArgs(window.arguments[0]);
1153 }
1154 }
1155
1156 var identityList = document.getElementById("msgIdentity");
1157
1158 document.addEventListener("keypress", awDocumentKeyPress, true);
1159
1160 if (identityList)
1161 FillIdentityList(identityList);
1162
1163 if (!params) {
1164 // This code will go away soon as now arguments are passed to the window using a object of type nsMsgComposeParams instead of a string
1165
1166 params = Components.classes["@mozilla.org/messengercompose/composeparams;1"].createInstance(Components.interfaces.nsIMsgComposeParams);
1167 params.composeFields = Components.classes["@mozilla.org/messengercompose/composefields;1"].createInstance(Components.interfaces.nsIMsgCompFields);
1168
1169 if (args) { //Convert old fashion arguments into params
1170 var composeFields = params.composeFields;
1171 if (args.bodyislink == "true")
1172 params.bodyIsLink = true;
1173 if (args.type)
1174 params.type = args.type;
1175 if (args.format)
1176 params.format = args.format;
1177 if (args.originalMsg)
1178 params.originalMsgURI = args.originalMsg;
1179 if (args.preselectid)
1180 params.identity = getIdentityForKey(args.preselectid);
1181 if (args.to)
1182 composeFields.to = args.to;
1183 if (args.cc)
1184 composeFields.cc = args.cc;
1185 if (args.bcc)
1186 composeFields.bcc = args.bcc;
1187 if (args.newsgroups)
1188 composeFields.newsgroups = args.newsgroups;
1189 if (args.subject)
1190 composeFields.subject = args.subject;
1191 if (args.attachment)
1192 {
1193 var attachmentList = args.attachment.split(",");
1194 var attachment;
1195 for (var i = 0; i < attachmentList.length; i ++)
1196 {
1197 attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment);
1198 attachment.url = attachmentList[i];
1199 composeFields.addAttachment(attachment);
1200 }
1201 }
1202 if (args.newshost)
1203 composeFields.newshost = args.newshost;
1204 if (args.body)
1205 composeFields.body = args.body;
1206 }
1207 }
1208
1209 // " <>" is an empty identity, and most likely not valid
1210 if (!params.identity || params.identity.identityName == " <>") {
1211 // no pre selected identity, so use the default account
1212 var identities = gAccountManager.defaultAccount.identities;
1213 if (identities.Count() == 0)
1214 identities = gAccountManager.allIdentities;
1215 params.identity = identities.QueryElementAt(0, Components.interfaces.nsIMsgIdentity);
1216 }
1217
1218 identityList.value = params.identity.key;
1219 LoadIdentity(true);
1220 var composeSvc = Components.classes["@mozilla.org/messengercompose;1"]
1221 .getService(Components.interfaces.nsIMsgComposeService);
1222 gMsgCompose = composeSvc.InitCompose(window, params);
1223 if (gMsgCompose)
1224 {
1225 // set the close listener
1226 gMsgCompose.recyclingListener = gComposeRecyclingListener;
1227
1228 //Lets the compose object knows that we are dealing with a recycled window
1229 gMsgCompose.recycledWindow = recycled;
1230
1231 // Get the <editor> element to startup an editor
1232 var editorElement = GetCurrentEditorElement();
1233
1234 document.getElementById("returnReceiptMenu")
1235 .setAttribute('checked', gMsgCompose.compFields.returnReceipt);
1236 document.getElementById("dsnMenu")
1237 .setAttribute('checked', gMsgCompose.compFields.DSN);
1238 document.getElementById("cmd_attachVCard")
1239 .setAttribute('checked', gMsgCompose.compFields.attachVCard);
1240 document.getElementById("menu_inlineSpellCheck")
1241 .setAttribute('checked', getPref("mail.spellcheck.inline"));
1242
1243 // If recycle, editor is already created
1244 if (!recycled)
1245 {
1246 var editortype = gMsgCompose.composeHTML ? "htmlmail" : "textmail";
1247 editorElement.makeEditable(editortype, true);
1248
1249 // setEditorType MUST be called before setContentWindow
1250 if (gMsgCompose.composeHTML)
1251 {
1252 initLocalFontFaceMenu(document.getElementById("FontFacePopup"));
1253 }
1254 else
1255 {
1256 // Remove HTML toolbar, format and insert menus as we are editing in
1257 // plain text mode
1258 document.getElementById("outputFormatMenu").setAttribute("hidden", true);
1259 document.getElementById("FormatToolbar").setAttribute("hidden", true);
1260 document.getElementById("formatMenu").setAttribute("hidden", true);
1261 document.getElementById("insertMenu").setAttribute("hidden", true);
1262 document.getElementById("menu_showFormatToolbar").setAttribute("hidden", true);
1263 }
1264
1265 // Do setup common to Message Composer and Web Composer
1266 EditorSharedStartup();
1267 InitLanguageMenu();
1268 }
1269
1270 var msgCompFields = gMsgCompose.compFields;
1271 if (msgCompFields)
1272 {
1273 if (params.bodyIsLink)
1274 {
1275 var body = msgCompFields.body;
1276 if (gMsgCompose.composeHTML)
1277 {
1278 var cleanBody;
1279 try {
1280 cleanBody = decodeURI(body);
1281 } catch(e) { cleanBody = body;}
1282
1283 // XXX : need to do html-escaping here !
1284 msgCompFields.body = "<BR><A HREF=\"" + body + "\">" + cleanBody + "</A><BR>";
1285 }
1286 else
1287 msgCompFields.body = "\n<" + body + ">\n";
1288 }
1289
1290 var subjectValue = msgCompFields.subject;
1291 GetMsgSubjectElement().value = subjectValue;
1292
1293 var attachments = msgCompFields.attachmentsArray;
1294 if (attachments)
1295 for (i = 0; i < attachments.Count(); i ++)
1296 AddAttachment(attachments.QueryElementAt(i, Components.interfaces.nsIMsgAttachment));
1297
1298 if (attachments.Count())
1299 {
1300 ChangeAttachmentBucketVisibility(false);
1301 }
1302 }
1303
1304 var event = document.createEvent('Events');
1305 event.initEvent('compose-window-init', false, true);
1306 document.getElementById("msgcomposeWindow").dispatchEvent(event);
1307
1308 gMsgCompose.RegisterStateListener(stateListener);
1309
1310 if (recycled)
1311 {
1312 InitEditor();
1313
1314 if (gMsgCompose.composeHTML)
1315 {
1316 // Force color picker on toolbar to show document colors
1317 onFontColorChange();
1318 onBackgroundColorChange();
1319 }
1320
1321 // reset the priorty field for recycled windows
1322 updatePriorityToolbarButton('Normal');
1323 }
1324 else
1325 {
1326 // Add an observer to be called when document is done loading,
1327 // which creates the editor
1328 try {
1329 GetCurrentCommandManager().
1330 addCommandObserver(gMsgEditorCreationObserver, "obs_documentCreated");
1331
1332 // Load empty page to create the editor
1333 editorElement.webNavigation.loadURI("about:blank", 0, null, null, null);
1334 } catch (e) {
1335 dump(" Failed to startup editor: "+e+"\n");
1336 }
1337 }
1338 }
1339
1340 gEditingDraft = gMsgCompose.compFields.draftId;
1341
1342 // finally, see if we need to auto open the address sidebar.
1343 var sideBarBox = document.getElementById('sidebar-box');
1344 if (sideBarBox.getAttribute("sidebarVisible") == "true")
1345 {
1346 // if we aren't supposed to have the side bar hidden, make sure it is visible
1347 if (document.getElementById("sidebar").getAttribute("src") == "")
1348 setTimeout(toggleAddressPicker, 0); // do this on a delay so we don't hurt perf. on bringing up a new compose window
1349 }
1350 gAutoSaveInterval = getPref("mail.compose.autosave") ?
1351 getPref("mail.compose.autosaveinterval") * 60000 : 0;
1352
1353 if (gAutoSaveInterval)
1354 gAutoSaveTimeout = setTimeout(AutoSave, gAutoSaveInterval);
1355
1356 gAutoSaveKickedIn = false;
1357 }
1358
1359 // The new, nice, simple way of getting notified when a new editor has been created
1360 var gMsgEditorCreationObserver =
1361 {
observe
1362 observe: function(aSubject, aTopic, aData)
1363 {
1364 if (aTopic == "obs_documentCreated")
1365 {
1366 var editor = GetCurrentEditor();
1367 if (editor && GetCurrentCommandManager() == aSubject)
1368 {
1369 var editorStyle = editor.QueryInterface(Components.interfaces.nsIEditorStyleSheets);
1370 editorStyle.addStyleSheet("chrome://messenger/skin/messageQuotes.css");
1371 InitEditor();
1372 }
1373 // Now that we know this document is an editor, update commands now if
1374 // the document has focus, or next time it receives focus via
1375 // CommandUpdate_MsgCompose()
1376 if (gLastWindowToHaveFocus == document.commandDispatcher.focusedWindow)
1377 updateComposeItems();
1378 else
1379 gLastWindowToHaveFocus = null;
1380 }
1381 }
1382 }
1383
WizCallback
1384 function WizCallback(state)
1385 {
1386 if (state){
1387 ComposeStartup(false, null);
1388 }
1389 else
1390 {
1391 MsgComposeCloseWindow(false); // Don't try to recycle a bogus window
1392 // window.tryToClose=ComposeCanClose;
1393 }
1394 }
1395
ComposeLoad
Called: ChromeWindow:getElementById (2 calls, 48 v-uS)
MsgComposeCommands.js:getPref (2 calls, 229 v-uS)
MsgComposeCommands.js:AddDirectoryServerObserver (1 calls, 160 v-uS)
MsgComposeCommands.js:AddMessageComposeOfflineObserver (1 calls, 970 v-uS)
MsgComposeCommands.js:ComposeStartup (1 calls, 83097 v-uS)
MsgComposeCommands.js:SetupCommandUpdateHandlers (1 calls, 73 v-uS)
accountUtils.js:verifyAccounts (1 calls, 742 v-uS)
1396 function ComposeLoad()
1397 {
1398 try {
1399 var other_headers = getPref("mail.compose.other.header");
1400 }
1401 catch (ex) {
1402 dump("failed to get the mail.compose.other.header pref\n");
1403 }
1404
1405 AddMessageComposeOfflineObserver();
1406 AddDirectoryServerObserver(true);
1407
1408 try {
1409 // XXX: We used to set commentColumn on the initial auto complete column after the document has loaded
1410 // inside of setupAutocomplete. But this happens too late for the first widget and it was never showing
1411 // the comment field. Try to set it before the document finishes loading:
1412 if (getPref("mail.autoComplete.commentColumn"))
1413 document.getElementById('addressCol2#1').showCommentColumn = true;
1414 }
1415 catch (ex) {
1416 // do nothing...
1417 }
1418
1419 try {
1420 SetupCommandUpdateHandlers();
1421 var wizardcallback = true;
1422 var state = verifyAccounts(wizardcallback); // this will do migration, or create a new account if we need to.
1423
1424 if (other_headers) {
1425 var selectNode = document.getElementById('addressCol1#1');
1426 var other_headers_Array = other_headers.split(",");
1427 for (var i = 0; i < other_headers_Array.length; i++)
1428 selectNode.appendItem(other_headers_Array[i] + ":", "addr_other");
1429 }
1430 if (state)
1431 ComposeStartup(false, null);
1432 }
1433 catch (ex) {
1434 dump("EX: = " + ex + "\n");
1435 var bundle = document.getElementById("bundle_composeMsgs");
1436 var errorTitle = bundle.getString("initErrorDlogTitle");
1437 var errorMsg = bundle.getFormattedString("initErrorDlogMessage", [""]);
1438
1439 if (gPromptService)
1440 gPromptService.alert(window, errorTitle, errorMsg);
1441 else
1442 window.alert(errorMsg);
1443
1444 MsgComposeCloseWindow(false); // Don't try to recycle a bogus window
1445 return;
1446 }
1447 window.tryToClose=ComposeCanClose;
1448
1449 // initialize the customizeDone method on the customizeable toolbar
1450 var toolbox = document.getElementById("compose-toolbox");
1451 toolbox.customizeDone = MailToolboxCustomizeDone;
1452
1453 var toolbarset = document.getElementById('customToolbars');
1454 toolbox.toolbarset = toolbarset;
1455 }
1456
ComposeUnload
Called: ChromeWindow:clearTimeout (1 calls, 12 v-uS)
ChromeWindow:dump (1 calls, 66 v-uS)
MsgComposeCommands.js:RemoveDirectoryServerObserver (1 calls, 177 v-uS)
MsgComposeCommands.js:RemoveMessageComposeOfflineObserver (1 calls, 189 v-uS)
MsgComposeCommands.js:enableInlineSpellCheck (1 calls, 143 v-uS)
editor.js:EditorCleanup (1 calls, 32 v-uS)
1457 function ComposeUnload()
1458 {
1459 dump("\nComposeUnload from XUL\n");
1460
1461 // Stop InlineSpellCheckerUI so personal dictionary is saved
1462 enableInlineSpellCheck(false);
1463
1464 EditorCleanup();
1465
1466 RemoveMessageComposeOfflineObserver();
1467 RemoveDirectoryServerObserver(null);
1468 if (gCurrentIdentity)
1469 RemoveDirectoryServerObserver("mail.identity." + gCurrentIdentity.key);
1470 if (gCurrentAutocompleteDirectory)
1471 RemoveDirectorySettingsObserver(gCurrentAutocompleteDirectory);
1472 if (gMsgCompose)
1473 gMsgCompose.UnregisterStateListener(stateListener);
1474 if (gAutoSaveTimeout)
1475 clearTimeout(gAutoSaveTimeout);
1476 }
1477
SetDocumentCharacterSet
1478 function SetDocumentCharacterSet(aCharset)
1479 {
1480 dump("SetDocumentCharacterSet Callback!\n");
1481 dump(aCharset + "\n");
1482
1483 if (gMsgCompose) {
1484 gMsgCompose.SetDocumentCharset(aCharset);
1485 gCurrentMailSendCharset = aCharset;
1486 gCharsetTitle = null;
1487 SetComposeWindowTitle();
1488 }
1489 else
1490 dump("Compose has not been created!\n");
1491 }
1492
UpdateMailEditCharset
1493 function UpdateMailEditCharset()
1494 {
1495 var send_default_charset = gMsgCompose.compFields.defaultCharacterSet;
1496 // dump("send_default_charset is " + send_default_charset + "\n");
1497
1498 var compFieldsCharset = gMsgCompose.compFields.characterSet;
1499 // dump("gMsgCompose.compFields is " + compFieldsCharset + "\n");
1500
1501 if (gCharsetConvertManager) {
1502 var charsetAlias = gCharsetConvertManager.getCharsetAlias(compFieldsCharset);
1503 if (charsetAlias == "us-ascii")
1504 compFieldsCharset = "ISO-8859-1"; // no menu item for "us-ascii"
1505 }
1506
1507 // charset may have been set implicitly in case of reply/forward
1508 // or use pref default otherwise
1509 var menuitem = document.getElementById(send_default_charset == compFieldsCharset ?
1510 send_default_charset : compFieldsCharset);
1511 if (menuitem)
1512 menuitem.setAttribute('checked', 'true');
1513
1514 // Set a document charset to a default mail send charset.
1515 if (send_default_charset == compFieldsCharset)
1516 SetDocumentCharacterSet(send_default_charset);
1517 }
1518
1519 function InitCharsetMenuCheckMark()
1520 {
1521 // return if the charset is already set explitily
1522 if (gCurrentMailSendCharset != null) {
1523 dump("already set to " + gCurrentMailSendCharset + "\n");
1524 return;
1525 }
1526
1527 // Check the menu
1528 UpdateMailEditCharset();
1529 // use setTimeout workaround to delay checkmark the menu
1530 // when onmenucomplete is ready then use it instead of oncreate
1531 // see bug #78290 for the details
1532 setTimeout("UpdateMailEditCharset()", 0);
1533
1534 }
1535
GetCharsetUIString
Called: ChromeWindow:toUpperCase (2 calls, 16 v-uS)
Called By: MsgComposeCommands.js:SetComposeWindowTitle (2 calls, 202 v-uS)
1536 function GetCharsetUIString()
1537 {
1538 var charset = gMsgCompose.compFields.characterSet;
1539 if (gSendDefaultCharset == null) {
1540 gSendDefaultCharset = gMsgCompose.compFields.defaultCharacterSet;
1541 }
1542
1543 charset = charset.toUpperCase();
1544 if (charset == "US-ASCII")
1545 charset = "ISO-8859-1";
1546
1547 if (charset != gSendDefaultCharset) {
1548
1549 if (gCharsetTitle == null) {
1550 try {
1551 // check if we have a converter for this charset
1552 var charsetAlias = gCharsetConvertManager.getCharsetAlias(charset);
1553 var encoderList = gCharsetConvertManager.getEncoderList();
1554 var found = false;
1555 while (encoderList.hasMore()) {
1556 if (charsetAlias == encoderList.getNext()) {
1557 found = true;
1558 break;
1559 }
1560 }
1561 if (!found)
1562 {
1563 dump("no charset converter available for " + charset + " default charset is used instead\n");
1564 // set to default charset, no need to show it in the window title
1565 gMsgCompose.compFields.characterSet = gSendDefaultCharset;
1566 return "";
1567 }
1568
1569 // get a localized string
1570 gCharsetTitle = gCharsetConvertManager.getCharsetTitle(charsetAlias);
1571 }
1572 catch (ex) {
1573 dump("failed to get a charset title of " + charset + "!\n");
1574 dump("Exception: " + ex + "\n");
1575 gCharsetTitle = charset; // just show the charset itself
1576 }
1577 }
1578
1579 return " - " + gCharsetTitle;
1580 }
1581
1582 return "";
1583 }
1584
GenericSendMessage
1585 function GenericSendMessage( msgType )
1586 {
1587 dump("GenericSendMessage from XUL\n");
1588
1589 dump("Identity = " + getCurrentIdentity() + "\n");
1590
1591 if (gMsgCompose != null)
1592 {
1593 var msgCompFields = gMsgCompose.compFields;
1594 if (msgCompFields)
1595 {
1596 Recipients2CompFields(msgCompFields);
1597 var subject = GetMsgSubjectElement().value;
1598 msgCompFields.subject = subject;
1599 Attachments2CompFields(msgCompFields);
1600
1601 if (msgType == nsIMsgCompDeliverMode.Now || msgType == nsIMsgCompDeliverMode.Later)
1602 {
1603 //Do we need to check the spelling?
1604 if (getPref("mail.SpellCheckBeforeSend"))
1605 {
1606 // We disable spellcheck for the following -subject line, attachment pane, identity and addressing widget
1607 // therefore we need to explicitly focus on the mail body when we have to do a spellcheck.
1608 SetMsgBodyFrameFocus();
1609 window.cancelSendMessage = false;
1610 try {
1611 window.openDialog("chrome://editor/content/EdSpellCheck.xul", "_blank",
1612 "chrome,close,titlebar,modal", true, true);
1613 }
1614 catch(ex){}
1615 if(window.cancelSendMessage)
1616 return;
1617 }
1618
1619 // Check if we have a subject, else ask user for confirmation
1620 if (subject == "")
1621 {
1622 if (gPromptService)
1623 {
1624 var bundle = document.getElementById("bundle_composeMsgs");
1625 var result = {value: bundle.getString("defaultSubject")};
1626 if (gPromptService.prompt(
1627 window,
1628 bundle.getString("sendMsgTitle"),
1629 bundle.getString("subjectDlogMessage"),
1630 result,
1631 null,
1632 {value:0}))
1633 {
1634 msgCompFields.subject = result.value;
1635 var subjectInputElem = GetMsgSubjectElement();
1636 subjectInputElem.value = result.value;
1637 }
1638 else
1639 return;
1640 }
1641 }
1642
1643 // check if the user tries to send a message to a newsgroup through a mail account
1644 var currentAccountKey = getCurrentAccountKey();
1645 var account = gAccountManager.getAccount(currentAccountKey);
1646 if (!account)
1647 {
1648 throw "UNEXPECTED: currentAccountKey '" + currentAccountKey +
1649 "' has no matching account!";
1650 }
1651 var servertype = account.incomingServer.type;
1652
1653 if (servertype != "nntp" && msgCompFields.newsgroups != "")
1654 {
1655 // default to ask user if the pref is not set
1656 var dontAskAgain = getPref("mail.compose.dontWarnMail2Newsgroup");
1657
1658 if (!dontAskAgain)
1659 {
1660 var checkbox = {value:false};
1661 var bundle = document.getElementById("bundle_composeMsgs");
1662 var okToProceed = gPromptService.confirmCheck(
1663 window,
1664 bundle.getString("sendMsgTitle"),
1665 bundle.getString("recipientDlogMessage"),
1666 bundle.getString("CheckMsg"),
1667 checkbox);
1668
1669 if (!okToProceed)
1670 return;
1671
1672 if (checkbox.value) {
1673 var branch = Components.classes["@mozilla.org/preferences-service;1"]
1674 .getService(Components.interfaces.nsIPrefBranch);
1675
1676 branch.setBoolPref(kDontAskAgainPref, true);
1677 }
1678 }
1679
1680 // remove newsgroups to prevent news_p to be set
1681 // in nsMsgComposeAndSend::DeliverMessage()
1682 msgCompFields.newsgroups = "";
1683 }
1684
1685 // Before sending the message, check what to do with HTML message, eventually abort.
1686 var convert = DetermineConvertibility();
1687 var action = DetermineHTMLAction(convert);
1688 // check if e-mail addresses are complete, in case user
1689 // has turned off autocomplete to local domain.
1690 if (!CheckValidEmailAddress(msgCompFields.to, msgCompFields.cc, msgCompFields.bcc))
1691 return;
1692
1693 if (action == nsIMsgCompSendFormat.AskUser)
1694 {
1695 var recommAction = (convert == nsIMsgCompConvertible.No)
1696 ? nsIMsgCompSendFormat.AskUser
1697 : nsIMsgCompSendFormat.PlainText;
1698 var result2 = {action:recommAction,
1699 convertible:convert,
1700 abort:false};
1701 window.openDialog("chrome://messenger/content/messengercompose/askSendFormat.xul",
1702 "askSendFormatDialog", "chrome,modal,titlebar,centerscreen",
1703 result2);
1704 if (result2.abort)
1705 return;
1706 action = result2.action;
1707 }
1708
1709 // we will remember the users "send format" decision
1710 // in the address collector code (see nsAbAddressCollecter::CollectAddress())
1711 // by using msgCompFields.forcePlainText and msgCompFields.useMultipartAlternative
1712 // to determine the nsIAbPreferMailFormat (unknown, plaintext, or html)
1713 // if the user sends both, we remember html.
1714 switch (action)
1715 {
1716 case nsIMsgCompSendFormat.PlainText:
1717 msgCompFields.forcePlainText = true;
1718 msgCompFields.useMultipartAlternative = false;
1719 break;
1720 case nsIMsgCompSendFormat.HTML:
1721 msgCompFields.forcePlainText = false;
1722 msgCompFields.useMultipartAlternative = false;
1723 break;
1724 case nsIMsgCompSendFormat.Both:
1725 msgCompFields.forcePlainText = false;
1726 msgCompFields.useMultipartAlternative = true;
1727 break;
1728 default: dump("\###SendMessage Error: invalid action value\n"); return;
1729 }
1730 }
1731
1732 // hook for extra compose pre-processing
1733 var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
1734 observerService.notifyObservers(window, "mail:composeOnSend", null);
1735
1736 // Check if the headers of composing mail can be converted to a mail charset.
1737 if (msgType == nsIMsgCompDeliverMode.Now ||
1738 msgType == nsIMsgCompDeliverMode.Later ||
1739 msgType == nsIMsgCompDeliverMode.Save ||
1740 msgType == nsIMsgCompDeliverMode.SaveAsDraft ||
1741 msgType == nsIMsgCompDeliverMode.AutoSaveAsDraft ||
1742 msgType == nsIMsgCompDeliverMode.SaveAsTemplate)
1743 {
1744 var fallbackCharset = new Object;
1745 // Check encoding, switch to UTF-8 if the default encoding doesn't fit.
1746 if (!gMsgCompose.checkCharsetConversion(getCurrentIdentity(), fallbackCharset))
1747 fallbackCharset.value = "UTF-8";
1748
1749 if (fallbackCharset &&
1750 fallbackCharset.value && fallbackCharset.value != "")
1751 gMsgCompose.SetDocumentCharset(fallbackCharset.value);
1752 }
1753 try {
1754
1755 // just before we try to send the message, fire off the compose-send-message event for listeners
1756 // such as smime so they can do any pre-security work such as fetching certificates before sending
1757 var event = document.createEvent('UIEvents');
1758 event.initEvent('compose-send-message', false, true);
1759 var msgcomposeWindow = document.getElementById("msgcomposeWindow");
1760 msgcomposeWindow.setAttribute("msgtype", msgType);
1761 msgcomposeWindow.dispatchEvent(event);
1762 if (event.getPreventDefault())
1763 throw Components.results.NS_ERROR_ABORT;
1764
1765 gAutoSaving = (msgType == nsIMsgCompDeliverMode.AutoSaveAsDraft);
1766 // disable the ui if we're not auto-saving
1767 if (!gAutoSaving)
1768 {
1769 gWindowLocked = true;
1770 disableEditableFields();
1771 updateComposeItems();
1772 }
1773 // if we're auto saving, mark the body as not changed here, and not
1774 // when the save is done, because the user might change it between now
1775 // and when the save is done.
1776 else
1777 SetContentAndBodyAsUnmodified();
1778
1779 var progress = Components.classes["@mozilla.org/messenger/progress;1"].createInstance(Components.interfaces.nsIMsgProgress);
1780 if (progress)
1781 {
1782 progress.registerListener(progressListener);
1783 gSendOrSaveOperationInProgress = true;
1784 }
1785 msgWindow.domWindow = window;
1786 msgWindow.rootDocShell.allowAuth = true;
1787 gMsgCompose.SendMsg(msgType, getCurrentIdentity(), currentAccountKey, msgWindow, progress);
1788 }
1789 catch (ex) {
1790 dump("failed to SendMsg: " + ex + "\n");
1791 gWindowLocked = false;
1792 enableEditableFields();
1793 updateComposeItems();
1794 }
1795 }
1796 }
1797 else
1798 dump("###SendMessage Error: composeAppCore is null!\n");
1799 }
1800
CheckValidEmailAddress
1801 function CheckValidEmailAddress(to, cc, bcc)
1802 {
1803 var invalidStr = null;
1804 // crude check that the to, cc, and bcc fields contain at least one '@'.
1805 // We could parse each address, but that might be overkill.
1806 if (to.length > 0 && (to.indexOf("@") <= 0 || to.indexOf("@") == to.length - 1))
1807 invalidStr = to;
1808 else if (cc.length > 0 && (cc.indexOf("@") <= 0 || cc.indexOf("@") == cc.length - 1))
1809 invalidStr = cc;
1810 else if (bcc.length > 0 && (bcc.indexOf("@") <= 0 || bcc.indexOf("@") == bcc.length - 1))
1811 invalidStr = bcc;
1812 if (invalidStr)
1813 {
1814 var bundle = document.getElementById("bundle_composeMsgs");
1815 var errorTitle = bundle.getString("sendMsgTitle");
1816 var errorMsg = bundle.getFormattedString("addressInvalid", [invalidStr], 1);
1817 if (gPromptService)
1818 gPromptService.alert(window, errorTitle, errorMsg);
1819 return false;
1820 }
1821 return true;
1822 }
1823
SendMessage
1824 function SendMessage()
1825 {
1826 dump("SendMessage from XUL\n");
1827 GenericSendMessage(nsIMsgCompDeliverMode.Now);
1828 }
1829
SendMessageWithCheck
1830 function SendMessageWithCheck()
1831 {
1832 var warn = getPref("mail.warn_on_send_accel_key");
1833
1834 if (warn) {
1835 var checkValue = {value:false};
1836 var bundle = document.getElementById("bundle_composeMsgs");
1837 var buttonPressed = gPromptService.confirmEx(window,
1838 bundle.getString('sendMessageCheckWindowTitle'),
1839 bundle.getString('sendMessageCheckLabel'),
1840 (gPromptService.BUTTON_TITLE_IS_STRING * gPromptService.BUTTON_POS_0) +
1841 (gPromptService.BUTTON_TITLE_CANCEL * gPromptService.BUTTON_POS_1),
1842 bundle.getString('sendMessageCheckSendButtonLabel'),
1843 null, null,
1844 bundle.getString('CheckMsg'),
1845 checkValue);
1846 if (buttonPressed != 0) {
1847 return;
1848 }
1849 if (checkValue.value) {
1850 var branch = Components.classes["@mozilla.org/preferences-service;1"]
1851 .getService(Components.interfaces.nsIPrefBranch);
1852
1853 branch.setBoolPref("mail.warn_on_send_accel_key", false);
1854 }
1855 }
1856
1857 GenericSendMessage(gIsOffline ? nsIMsgCompDeliverMode.Later
1858 : nsIMsgCompDeliverMode.Now);
1859 }
1860
SendMessageLater
1861 function SendMessageLater()
1862 {
1863 dump("SendMessageLater from XUL\n");
1864 GenericSendMessage(nsIMsgCompDeliverMode.Later);
1865 }
1866
Save
1867 function Save()
1868 {
1869 dump("Save from XUL\n");
1870 switch (defaultSaveOperation)
1871 {
1872 case "file" : SaveAsFile(false); break;
1873 case "template" : SaveAsTemplate(false); break;
1874 default : SaveAsDraft(false); break;
1875 }
1876 }
1877
SaveAsFile
1878 function SaveAsFile(saveAs)
1879 {
1880 dump("SaveAsFile from XUL\n");
1881 var subject = GetMsgSubjectElement().value;
1882 GetCurrentEditor().setDocumentTitle(subject);
1883
1884 if (gMsgCompose.bodyConvertible() == nsIMsgCompConvertible.Plain)
1885 SaveDocument(saveAs, false, "text/plain");
1886 else
1887 SaveDocument(saveAs, false, "text/html");
1888 defaultSaveOperation = "file";
1889 }
1890
SaveAsDraft
1891 function SaveAsDraft()
1892 {
1893 dump("SaveAsDraft from XUL\n");
1894
1895 gAutoSaveKickedIn = false;
1896 gEditingDraft = true;
1897
1898 GenericSendMessage(nsIMsgCompDeliverMode.SaveAsDraft);
1899 defaultSaveOperation = "draft";
1900 }
1901
SaveAsTemplate
1902 function SaveAsTemplate()
1903 {
1904 dump("SaveAsTemplate from XUL\n");
1905
1906 gAutoSaveKickedIn = false;
1907 gEditingDraft = false;
1908
1909 GenericSendMessage(nsIMsgCompDeliverMode.SaveAsTemplate);
1910 defaultSaveOperation = "template";
1911 }
1912
1913 // Sets the additional FCC, in addition to the default FCC.
MessageFcc
1914 function MessageFcc(menuItem)
1915 {
1916 if (!gMsgCompose)
1917 return;
1918
1919 var msgCompFields = gMsgCompose.compFields;
1920 if (!msgCompFields)
1921 return;
1922
1923 // Get the uri for the folder to FCC into.
1924 var fccURI = aFolder.URI;
1925 msgCompFields.fcc2 = (msgCompFields.fcc2 == fccUri) ? "nocopy://" : fccUri;
1926 }
1927
1928 function updatePriorityMenu()
1929 {
1930 if (gMsgCompose)
1931 {
1932 var msgCompFields = gMsgCompose.compFields;
1933 if (msgCompFields && msgCompFields.priority)
1934 {
1935 var priorityMenu = document.getElementById('priorityMenu' );
1936 priorityMenu.getElementsByAttribute( "checked", 'true' )[0].removeAttribute('checked');
1937 priorityMenu.getElementsByAttribute( "value", msgCompFields.priority )[0].setAttribute('checked', 'true');
1938 }
1939 }
1940 }
1941
updatePriorityToolbarButton
1942 function updatePriorityToolbarButton(newPriorityValue)
1943 {
1944 var prioritymenu = document.getElementById('priorityMenu-button');
1945 if (prioritymenu)
1946 prioritymenu.value = newPriorityValue;
1947 }
1948
1949 function PriorityMenuSelect(target)
1950 {
1951 if (gMsgCompose)
1952 {
1953 var msgCompFields = gMsgCompose.compFields;
1954 if (msgCompFields)
1955 msgCompFields.priority = target.getAttribute('value');
1956
1957 // keep priority toolbar button in synch with possible changes via the menu item
1958 updatePriorityToolbarButton(target.getAttribute('value'));
1959 }
1960 }
1961
1962 function OutputFormatMenuSelect(target)
1963 {
1964 if (gMsgCompose)
1965 {
1966 var msgCompFields = gMsgCompose.compFields;
1967 var toolbar = document.getElementById("FormatToolbar");
1968 var format_menubar = document.getElementById("formatMenu");
1969 var insert_menubar = document.getElementById("insertMenu");
1970 var show_menuitem = document.getElementById("menu_showFormatToolbar");
1971
1972 if (msgCompFields)
1973 switch (target.getAttribute('id'))
1974 {
1975 case "format_auto": gSendFormat = nsIMsgCompSendFormat.AskUser; break;
1976 case "format_plain": gSendFormat = nsIMsgCompSendFormat.PlainText; break;
1977 case "format_html": gSendFormat = nsIMsgCompSendFormat.HTML; break;
1978 case "format_both": gSendFormat = nsIMsgCompSendFormat.Both; break;
1979 }
1980 gHideMenus = (gSendFormat == nsIMsgCompSendFormat.PlainText);
1981 format_menubar.hidden = gHideMenus;
1982 insert_menubar.hidden = gHideMenus;
1983 show_menuitem.hidden = gHideMenus;
1984 toolbar.hidden = gHideMenus ||
1985 (show_menuitem.getAttribute("checked") == "false");
1986 }
1987 }
1988
SelectAddress
1989 function SelectAddress()
1990 {
1991 var msgCompFields = gMsgCompose.compFields;
1992
1993 Recipients2CompFields(msgCompFields);
1994
1995 var toAddress = msgCompFields.to;
1996 var ccAddress = msgCompFields.cc;
1997 var bccAddress = msgCompFields.bcc;
1998
1999 window.openDialog("chrome://messenger/content/addressbook/abSelectAddressesDialog.xul",
2000 "",
2001 "chrome,resizable,titlebar,modal",
2002 {composeWindow:top.window,
2003 msgCompFields:msgCompFields,
2004 toAddress:toAddress,
2005 ccAddress:ccAddress,
2006 bccAddress:bccAddress});
2007 // We have to set focus to the addressingwidget because we seem to loose focus often
2008 // after opening the SelectAddresses Dialog- bug # 89950
2009 AdjustFocus();
2010 }
2011
2012 // walk through the recipients list and add them to the inline spell checker ignore list
addRecipientsToIgnoreList
Called By: addressingWidgetOverlay.js:CompFields2Recipients (1 calls, 14 v-uS)
2013 function addRecipientsToIgnoreList(aAddressesToAdd)
2014 {
2015 if (InlineSpellCheckerUI.enabled)
2016 {
2017 // break the list of potentially many recipients back into individual names
2018 var hdrParser = Components.classes["@mozilla.org/messenger/headerparser;1"].getService(Components.interfaces.nsIMsgHeaderParser);
2019 var emailAddresses = {};
2020 var names = {};
2021 var fullNames = {};
2022 var numAddresses = hdrParser.parseHeadersWithArray(aAddressesToAdd, emailAddresses, names, fullNames);
2023 var tokenizedNames = new Array();
2024
2025 // each name could consist of multiple word delimited by either commas or spaces. i.e. Green Lantern
2026 // or Lantern,Green. Tokenize on comma first, then tokenize again on spaces.
2027 for (name in names.value)
2028 {
2029 var splitNames = names.value[name].split(',');
2030 for (var i=0; i < splitNames.length; i++)
2031 {
2032 // now tokenize off of white space
2033 var splitNamesFromWhiteSpaceArray = splitNames[i].split(' ');
2034 for (var whiteSpaceIndex = 0; whiteSpaceIndex < splitNamesFromWhiteSpaceArray.length; whiteSpaceIndex++)
2035 if (splitNamesFromWhiteSpaceArray[whiteSpaceIndex])
2036 tokenizedNames.push(splitNamesFromWhiteSpaceArray[whiteSpaceIndex]);
2037 }
2038 }
2039
2040 InlineSpellCheckerUI.mInlineSpellChecker.ignoreWords(tokenizedNames, tokenizedNames.length);
2041 }
2042 }
2043
Called: ChromeWindow:setAttribute (3 calls, 86 v-uS)
ChromeWindow:getElementById (2 calls, 45 v-uS)
ChromeWindow:appendChild (1 calls, 95 v-uS)
ChromeWindow:createElement (1 calls, 65 v-uS)
ChromeWindow:getDictionaryList (1 calls, 26 v-uS)
ChromeWindow:getService (1 calls, 930 v-uS)
ChromeWindow:hasChildNodes (1 calls, 52 v-uS)
ChromeWindow:sort (1 calls, 16 v-uS)
ChromeWindow:split (1 calls, 12 v-uS)
ChromeWindow:toLowerCase (1 calls, 7 v-uS)
stringbundle.xml:getString (1 calls, 1341 v-uS)
Called By: MsgComposeCommands.js:ComposeStartup (1 calls, 3108 v-uS)
2044 function InitLanguageMenu()
2045 {
2046 var languageMenuList = document.getElementById('languageMenuList');
2047 if (!languageMenuList)
2048 return;
2049
2050 var spellChecker = Components.classes['@mozilla.org/spellchecker/engine;1']
2051 .getService(mozISpellCheckingEngine);
2052 var o1 = {};
2053 var o2 = {};
2054
2055 // Get the list of dictionaries from
2056 // the spellchecker.
2057
2058 spellChecker.getDictionaryList(o1, o2);
2059
2060 var dictList = o1.value;
2061 var count = o2.value;
2062
2063 // If dictionary count hasn't changed then no need to update the menu.
2064 if (sDictCount == count)
2065 return;
2066
2067 // Store current dictionary count.
2068 sDictCount = count;
2069
2070 // Load the string bundle that will help us map
2071 // RFC 1766 strings to UI strings.
2072 var languageBundle = document.getElementById("languageBundle");
2073 var isoStrArray;
2074 var langId;
2075 var langLabel;
2076 var i;
2077
2078 for (i = 0; i < count; i++)
2079 {
2080 try
2081 {
2082 langId = dictList[i];
2083 isoStrArray = dictList[i].split("-");
2084
2085 if (languageBundle && isoStrArray[0])
2086 langLabel = languageBundle.getString(isoStrArray[0].toLowerCase());
2087
2088 // the user needs to be able to distinguish between the UK English dictionary
2089 // and say the United States English Dictionary. If we have a isoStr value then
2090 // wrap it in parentheses and append it to the menu item string. i.e.
2091 // English (US) and English (UK)
2092 if (!langLabel)
2093 langLabel = langId;
2094 // if we have a language ID like US or UK, append it to the menu item, and any sub-variety
2095 else if (isoStrArray.length > 1 && isoStrArray[1]) {
2096 langLabel += ' (' + isoStrArray[1];
2097 if (isoStrArray.length > 2 && isoStrArray[2])
2098 langLabel += '-' + isoStrArray[2];
2099 langLabel += ')';
2100 }
2101 }
2102 catch (ex)
2103 {
2104 // getString throws an exception when a key is not found in the
2105 // bundle. In that case, just use the original dictList string.
2106 langLabel = langId;
2107 }
2108 dictList[i] = [langLabel, langId];
2109 }
2110
2111 // sort by locale-aware collation
2112 dictList.sort(
compareFn
2113 function compareFn(a, b)
2114 {
2115 return a[0].localeCompare(b[0]);
2116 }
2117 );
2118
2119 // Remove any languages from the list.
2120 while (languageMenuList.hasChildNodes())
2121 languageMenuList.removeChild(languageMenuList.firstChild);
2122
2123 for (i = 0; i < count; i++)
2124 {
2125 var item = document.createElement("menuitem");
2126 item.setAttribute("label", dictList[i][0]);
2127 item.setAttribute("value", dictList[i][1]);
2128 item.setAttribute('type', 'radio');
2129 languageMenuList.appendChild(item);
2130 }
2131 }
2132
2133 function OnShowDictionaryMenu(aTarget)
2134 {
2135 InitLanguageMenu();
2136 var curLang = getPref("spellchecker.dictionary", true);
2137 var languages = aTarget.getElementsByAttribute("value", curLang);
2138 if (languages.length > 0)
2139 languages[0].setAttribute("checked", true);
2140 }
2141
ChangeLanguage
2142 function ChangeLanguage(event)
2143 {
2144 // We need to change the dictionary language and if we are using inline spell check,
2145 // recheck the message
2146
2147 var spellChecker = Components.classes['@mozilla.org/spellchecker/engine;1']
2148 .getService(mozISpellCheckingEngine);
2149 if (spellChecker.dictionary != event.target.value)
2150 {
2151 spellChecker.dictionary = event.target.value;
2152 var str = Components.classes["@mozilla.org/supports-string;1"]
2153 .createInstance(nsISupportsString);
2154 str.data = event.target.value;
2155 var branch = Components.classes["@mozilla.org/preferences-service;1"]
2156 .getService(Components.interfaces.nsIPrefBranch);
2157
2158 branch.setComplexValue("spellchecker.dictionary", nsISupportsString, str);
2159
2160 // now check the document over again with the new dictionary
2161 if (InlineSpellCheckerUI.enabled)
2162 InlineSpellCheckerUI.mInlineSpellChecker.spellCheckRange(null);
2163 }
2164 event.stopPropagation();
2165 }
2166
ToggleReturnReceipt
2167 function ToggleReturnReceipt(target)
2168 {
2169 var msgCompFields = gMsgCompose.compFields;
2170 if (msgCompFields)
2171 {
2172 msgCompFields.returnReceipt = ! msgCompFields.returnReceipt;
2173 target.setAttribute('checked', msgCompFields.returnReceipt);
2174 gReceiptOptionChanged = true;
2175 }
2176 }
2177
ToggleDSN
2178 function ToggleDSN(target)
2179 {
2180 var msgCompFields = gMsgCompose.compFields;
2181 if (msgCompFields)
2182 {
2183 msgCompFields.DSN = ! msgCompFields.DSN;
2184 target.setAttribute('checked', msgCompFields.DSN);
2185 gDSNOptionChanged = true;
2186 }
2187 }
2188
ToggleAttachVCard
2189 function ToggleAttachVCard(target)
2190 {
2191 var msgCompFields = gMsgCompose.compFields;
2192 if (msgCompFields)
2193 {
2194 msgCompFields.attachVCard = ! msgCompFields.attachVCard;
2195 target.setAttribute('checked', msgCompFields.attachVCard);
2196 gAttachVCardOptionChanged = true;
2197 }
2198 }
2199
queryISupportsArray
Called: ChromeWindow:Count (6 calls, 58 v-uS)
ChromeWindow:QueryElementAt (3 calls, 42 v-uS)
Called By: MsgComposeCommands.js:FillIdentityList (3 calls, 224 v-uS)
2200 function queryISupportsArray(supportsArray, iid) {
2201 var result = new Array;
2202 for (var i=0; i<supportsArray.Count(); i++) {
2203 // dump(i + "," + result[i] + "\n");
2204 result[i] = supportsArray.QueryElementAt(i, iid);
2205 }
2206 return result;
2207 }
2208
Called: ChromeWindow:hasChildNodes (2 calls, 22 v-uS)
ChromeWindow:removeChild (1 calls, 158 v-uS)
Called By: ChromeWindow:CloseWindow (1 calls, 233 v-uS)
2209 function ClearIdentityListPopup(popup)
2210 {
2211 if (popup)
2212 while (popup.hasChildNodes())
2213 popup.removeChild(popup.lastChild);
2214 }
2215
FillIdentityList
Called: MsgComposeCommands.js:queryISupportsArray (3 calls, 224 v-uS)
ChromeWindow:getService (1 calls, 15 v-uS)
ChromeWindow:setAttribute (1 calls, 35 v-uS)
ChromeWindow:sort (1 calls, 69 v-uS)
menulist.xml:appendItem (1 calls, 800 v-uS)
Called By: MsgComposeCommands.js:ComposeStartup (1 calls, 1563 v-uS)
2216 function FillIdentityList(menulist)
2217 {
2218 var mgr = Components.classes["@mozilla.org/messenger/account-manager;1"]
2219 .getService(Components.interfaces.nsIMsgAccountManager);
2220 var accounts = queryISupportsArray(mgr.accounts,
2221 Components.interfaces.nsIMsgAccount);
sortAccounts
2222 function sortAccounts(a, b) {
2223 if (a.key == mgr.defaultAccount.key)
2224 return -1;
2225 if (b.key == mgr.defaultAccount.key)
2226 return 1;
2227 var aIsNews = a.incomingServer.type == "nntp";
2228 var bIsNews = b.incomingServer.type == "nntp";
2229 if (aIsNews && !bIsNews)
2230 return 1;
2231 if (bIsNews && !aIsNews)
2232 return -1;
2233
2234 var aIsLocal = a.incomingServer.type == "none";
2235 var bIsLocal = b.incomingServer.type == "none";
2236 if (aIsLocal && !bIsLocal)
2237 return 1;
2238 if (bIsLocal && !aIsLocal)
2239 return -1;
2240 return 0;
2241 }
2242 accounts.sort(sortAccounts);
2243
2244 for each (var account in accounts) {
2245 var server = account.incomingServer;
2246 if (!server)
2247 continue;
2248 var identites = queryISupportsArray(account.identities,
2249 Components.interfaces.nsIMsgIdentity);
2250 for each (var identity in identites) {
2251 var item = menulist.appendItem(identity.identityName, identity.key, server.prettyName);
2252 item.setAttribute("accountkey", account.key);
2253 }
2254 }
2255 }
2256
getCurrentIdentity
2257 function getCurrentIdentity()
2258 {
2259 // fill in Identity combobox
2260 var identityList = document.getElementById("msgIdentity");
2261
2262 var identityKey = identityList.value;
2263
2264 //dump("Looking for identity " + identityKey + "\n");
2265 var identity = gAccountManager.getIdentity(identityKey);
2266
2267 return identity;
2268 }
2269
getCurrentAccountKey
2270 function getCurrentAccountKey()
2271 {
2272 // get the accounts key
2273 var identityList = document.getElementById("msgIdentity");
2274 return identityList.selectedItem.getAttribute("accountkey");
2275 }
2276
getIdentityForKey
2277 function getIdentityForKey(key)
2278 {
2279 return gAccountManager.getIdentity(key);
2280 }
2281
AdjustFocus
Called: addressingWidgetOverlay.js:awGetNumberOfRecipients (2 calls, 45 v-uS)
addressingWidgetOverlay.js:awGetInputElement (1 calls, 38 v-uS)
addressingWidgetOverlay.js:awSetFocus (1 calls, 117 v-uS)
Called By: MsgComposeCommands.js:ComposeFieldsReady (1 calls, 276 v-uS)
2282 function AdjustFocus()
2283 {
2284 //dump("XXX adjusting focus\n");
2285 var element = awGetInputElement(awGetNumberOfRecipients());
2286 if (element.value == "") {
2287 //dump("XXX focus on address\n");
2288 awSetFocus(awGetNumberOfRecipients(), element);
2289 }
2290 else
2291 {
2292 element = GetMsgSubjectElement();
2293 if (element.value == "") {
2294 //dump("XXX focus on subject\n");
2295 element.focus();
2296 }
2297 else {
2298 //dump("XXX focus on body\n");
2299 SetMsgBodyFrameFocus();
2300 }
2301 }
2302 }
2303
SetComposeWindowTitle
Called: stringbundle.xml:getString (4 calls, 3069 v-uS)
MsgComposeCommands.js:GetCharsetUIString (2 calls, 202 v-uS)
ChromeWindow:getElementById (1 calls, 23 v-uS)
MsgComposeCommands.js:GetMsgSubjectElement (1 calls, 8 v-uS)
XULElement:hasAttribute (1 calls, 17 v-uS)
Called By: ChromeWindow:CloseWindow (1 calls, 439 v-uS)
MsgComposeCommands.js:ComposeFieldsReady (1 calls, 3361 v-uS)
2304 function SetComposeWindowTitle()
2305 {
2306 var newTitle = GetMsgSubjectElement().value;
2307
2308 var bundle = document.getElementById("bundle_composeMsgs");
2309 if (newTitle == "" )
2310 newTitle = bundle.getString("defaultSubject");
2311
2312 newTitle += GetCharsetUIString();
2313 document.title = bundle.getString("windowTitlePrefix") + " " + newTitle;
2314 }
2315
2316 // Check for changes to document and allow saving before closing
2317 // This is hooked up to the OS's window close widget (e.g., "X" for Windows)
ComposeCanClose
2318 function ComposeCanClose()
2319 {
2320 if (gSendOrSaveOperationInProgress)
2321 {
2322 var result;
2323
2324 if (gPromptService)
2325 {
2326 var brandBundle = document.getElementById("brandBundle");
2327 var brandShortName = brandBundle.getString("brandShortName");
2328 var bundle = document.getElementById("bundle_composeMsgs");
2329 var promptTitle = bundle.getString("quitComposeWindowTitle");
2330 var promptMsg = bundle.getFormattedString("quitComposeWindowMessage2",
2331 [brandShortName], 1);
2332 var quitButtonLabel = bundle.getString("quitComposeWindowQuitButtonLabel2");
2333 var waitButtonLabel = bundle.getString("quitComposeWindowWaitButtonLabel2");
2334
2335 result = gPromptService.confirmEx(window, promptTitle, promptMsg,
2336 (gPromptService.BUTTON_TITLE_IS_STRING*gPromptService.BUTTON_POS_0) +
2337 (gPromptService.BUTTON_TITLE_IS_STRING*gPromptService.BUTTON_POS_1),
2338 waitButtonLabel, quitButtonLabel, null, null, {value:0});
2339
2340 if (result == 1)
2341 {
2342 gMsgCompose.abort();
2343 return true;
2344 }
2345 return false;
2346 }
2347 }
2348
2349 // Returns FALSE only if user cancels save action
2350 if (gContentChanged || gMsgCompose.bodyModified || gAutoSaveKickedIn)
2351 {
2352 // call window.focus, since we need to pop up a dialog
2353 // and therefore need to be visible (to prevent user confusion)
2354 window.focus();
2355 if (gPromptService)
2356 {
2357 var bundle = document.getElementById("bundle_composeMsgs");
2358 result = gPromptService.confirmEx(window,
2359 bundle.getString("saveDlogTitle"),
2360 bundle.getString("saveDlogMessage"),
2361 (gPromptService.BUTTON_TITLE_SAVE * gPromptService.BUTTON_POS_0) +
2362 (gPromptService.BUTTON_TITLE_CANCEL * gPromptService.BUTTON_POS_1) +
2363 (gPromptService.BUTTON_TITLE_DONT_SAVE * gPromptService.BUTTON_POS_2),
2364 null, null, null,
2365 null, {value:0});
2366 switch (result)
2367 {
2368 case 0: //Save
2369 gCloseWindowAfterSave = true;
2370 SaveAsDraft();
2371 return false;
2372 case 1: //Cancel
2373 return false;
2374 case 2: //Don't Save
2375 // don't delete the draft if we didn't start off editing a draft
2376 // and the user hasn't explicitly saved it.
2377 if (!gEditingDraft && gAutoSaveKickedIn)
2378 RemoveDraft();
2379 break;
2380 }
2381 }
2382
2383 SetContentAndBodyAsUnmodified();
2384 }
2385
2386 return true;
2387 }
2388
RemoveDraft
2389 function RemoveDraft()
2390 {
2391 try
2392 {
2393 var draftUri = gMsgCompose.compFields.draftId;
2394 var msgKey = draftUri.substr(draftUri.indexOf('#') + 1);
2395 var rdf = Components.classes['@mozilla.org/rdf/rdf-service;1']
2396 .getService(Components.interfaces.nsIRDFService);
2397
2398 var folder = rdf.GetResource(gMsgCompose.savedFolderURI)
2399 .QueryInterface(Components.interfaces.nsIMsgFolder);
2400 try {
2401 const MSG_FOLDER_FLAG_DRAFTS = 0x0400;
2402 if (folder.flags & MSG_FOLDER_FLAG_DRAFTS)
2403 {
2404 var msgs = Components.classes["@mozilla.org/supports-array;1"].
2405 createInstance(Components.interfaces.nsISupportsArray);
2406 msgs.AppendElement(folder.GetMessageHeader(msgKey));
2407 folder.deleteMessages(msgs, null, true, false, null, false);
2408 }
2409 }
2410 catch (ex) // couldn't find header - perhaps an imap folder.
2411 {
2412 var imapFolder = folder.QueryInterface(Components.interfaces.nsIMsgImapMailFolder);
2413 var keyArray = new Array;
2414 keyArray[0] = msgKey;
2415 imapFolder.storeImapFlags(8, true, keyArray, 1, null);
2416 }
2417 } catch (ex) {}
2418 }
2419
SetContentAndBodyAsUnmodified
Called By: ChromeWindow:CloseWindow (1 calls, 26 v-uS)
2420 function SetContentAndBodyAsUnmodified()
2421 {
2422 gMsgCompose.bodyModified = false;
2423 gContentChanged = false;
2424 }
2425
ReleaseAutoCompleteState
Called: addressingWidgetOverlay.js:awGetMaxRecipients (2 calls, 42 v-uS)
ChromeWindow:getElementById (1 calls, 20 v-uS)
autocomplete.xml:removeSession (1 calls, 20 v-uS)
Called By: ChromeWindow:CloseWindow (1 calls, 146 v-uS)
2426 function ReleaseAutoCompleteState()
2427 {
2428 for (i=1; i <= awGetMaxRecipients(); i++)
2429 document.getElementById("addressCol2#" + i).removeSession(gLDAPSession);
2430
2431 gSessionAdded = false;
2432 gLDAPSession = null;
2433 gAutocompleteSession = null;
2434 }
2435
MsgComposeCloseWindow
Called: ChromeWindow:CloseWindow (1 calls, 14349 v-uS)
Called By: bloatTestOverlay.js:handleComposeState (1 calls, 14382 v-uS)
2436 function MsgComposeCloseWindow(recycleIt)
2437 {
2438 if (gMsgCompose)
2439 gMsgCompose.CloseWindow(recycleIt);
2440 else
2441 window.close();
2442 }
2443
GetLastAttachDirectory
2444 function GetLastAttachDirectory()
2445 {
2446 var lastDirectory;
2447
2448 try {
2449 var branch = Components.classes["@mozilla.org/preferences-service;1"]
2450 .getService(Components.interfaces.nsIPrefBranch);
2451 lastDirectory = branch.getComplexValue(kComposeAttachDirPrefName, Components.interfaces.nsILocalFile);
2452 }
2453 catch (ex) {
2454 // this will fail the first time we attach a file
2455 // as we won't have a pref value.
2456 lastDirectory = null;
2457 }
2458
2459 return lastDirectory;
2460 }
2461
2462 // attachedLocalFile must be a nsILocalFile
SetLastAttachDirectory
2463 function SetLastAttachDirectory(attachedLocalFile)
2464 {
2465 try {
2466 var file = attachedLocalFile.QueryInterface(Components.interfaces.nsIFile);
2467 var parent = file.parent.QueryInterface(Components.interfaces.nsILocalFile);
2468
2469 var branch = Components.classes["@mozilla.org/preferences-service;1"]
2470 .getService(Components.interfaces.nsIPrefBranch);
2471 branch.setComplexValue(kComposeAttachDirPrefName, Components.interfaces.nsILocalFile, parent);
2472 }
2473 catch (ex) {
2474 dump("error: SetLastAttachDirectory failed: " + ex + "\n");
2475 }
2476 }
2477
AttachFile
2478 function AttachFile()
2479 {
2480 var attachments;
2481
2482 //Get file using nsIFilePicker and convert to URL
2483 var fp = Components.classes["@mozilla.org/filepicker;1"]
2484 .createInstance(nsIFilePicker);
2485 var bundle = document.getElementById("bundle_composeMsgs");
2486 fp.init(window, bundle.getString("chooseFileToAttach"),
2487 nsIFilePicker.modeOpenMultiple);
2488
2489 var lastDirectory = GetLastAttachDirectory();
2490 if (lastDirectory)
2491 fp.displayDirectory = lastDirectory;
2492
2493 fp.appendFilters(nsIFilePicker.filterAll);
2494 if (fp.show() == nsIFilePicker.returnOK) {
2495 attachments = fp.files;
2496 }
2497
2498 if (!attachments || !attachments.hasMoreElements())
2499 return;
2500
2501 var haveSetAttachDirectory = false;
2502
2503 while (attachments.hasMoreElements()) {
2504 var currentFile = attachments.getNext().QueryInterface(Components.interfaces.nsILocalFile);
2505
2506 if (!haveSetAttachDirectory) {
2507 SetLastAttachDirectory(currentFile);
2508 haveSetAttachDirectory = true;
2509 }
2510
2511 var ioService = Components.classes["@mozilla.org/network/io-service;1"]
2512 ioService = ioService.getService(Components.interfaces.nsIIOService);
2513 var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
2514 var currentAttachment = fileHandler.getURLSpecFromFile(currentFile);
2515
2516 if (!DuplicateFileCheck(currentAttachment)) {
2517 var attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment);
2518 attachment.url = currentAttachment;
2519 AddAttachment(attachment);
2520 ChangeAttachmentBucketVisibility(false);
2521 gContentChanged = true;
2522 }
2523 }
2524 }
2525
AddAttachment
2526 function AddAttachment(attachment)
2527 {
2528 if (attachment && attachment.url)
2529 {
2530 var bucket = document.getElementById("attachmentBucket");
2531
2532 if (!attachment.name)
2533 attachment.name = gMsgCompose.AttachmentPrettyName(attachment.url, null);
2534
2535 var bundle = document.getElementById("bundle_composeMsgs");
2536
2537 // for security reasons, don't allow *-message:// uris to leak out
2538 // we don't want to reveal the .slt path (for mailbox://), or the username or hostname
2539 var messagePrefix = /^mailbox-message:|^imap-message:|^news-message:/i;
2540 if (messagePrefix.test(attachment.name))
2541 attachment.name = bundle.getString("messageAttachmentSafeName");
2542 else {
2543 // for security reasons, don't allow mail protocol uris to leak out
2544 // we don't want to reveal the .slt path (for mailbox://), or the username or hostname
2545 var mailProtocol = /^file:|^mailbox:|^imap:|^s?news:/i;
2546 if (mailProtocol.test(attachment.name))
2547 attachment.name = bundle.getString("partAttachmentSafeName");
2548 }
2549
2550 var item = bucket.appendItem(attachment.name, "");
2551 item.attachment = attachment; //full attachment object stored here
2552 try {
2553 item.setAttribute("tooltiptext", decodeURI(attachment.url));
2554 } catch(e) {
2555 item.setAttribute("tooltiptext", attachment.url);
2556 }
2557 item.setAttribute("class", "listitem-iconic");
2558
2559 var url = gIOService.newURI(attachment.url, null, null);
2560
2561 try
2562 {
2563 url = url.QueryInterface( Components.interfaces.nsIURL );
2564 }
2565 catch (ex)
2566 {
2567 url = null;
2568 }
2569
2570
2571 // for local file urls, we are better off using the full file url because moz-icon will
2572 // actually resolve the file url and get the right icon from the file url. All other urls, we should
2573 // try to extract the file name from them. This fixes issues were an icon wasn't showing up if you dragged
2574 // a web url that had a query or reference string after the file name and for mailnews urls were the filename
2575 // is hidden in the url as a &filename= part.
2576 if (url && url.fileName && !url.schemeIs("file"))
2577 item.setAttribute("image", "moz-icon://" + url.fileName);
2578 else
2579 item.setAttribute("image", "moz-icon:" + attachment.url);
2580 }
2581 }
2582
SelectAllAttachments
2583 function SelectAllAttachments()
2584 {
2585 var bucketList = document.getElementById("attachmentBucket");
2586 if (bucketList)
2587 bucketList.selectAll();
2588 }
2589
MessageHasAttachments
Called: ChromeWindow:getElementById (2 calls, 29 v-uS)
listbox.xml:getRowCount (2 calls, 158 v-uS)
Called By: ChromeWindow:isCommandEnabled (2 calls, 246 v-uS)
2590 function MessageHasAttachments()
2591 {
2592 var bucketList = document.getElementById("attachmentBucket");
2593 if (bucketList) {
2594 return (bucketList && bucketList.getRowCount() && (bucketList == top.document.commandDispatcher.focusedElement));
2595 }
2596 return false;
2597 }
2598
MessageGetNumSelectedAttachments
Called: ChromeWindow:getElementById (2 calls, 29 v-uS)
Called By: ChromeWindow:isCommandEnabled (2 calls, 147 v-uS)
2599 function MessageGetNumSelectedAttachments()
2600 {
2601 var bucketList = document.getElementById("attachmentBucket");
2602 return (bucketList) ? bucketList.selectedItems.length : 0;
2603 }
2604
AttachPage
2605 function AttachPage()
2606 {
2607 if (gPromptService)
2608 {
2609 var result = {value:"http://"};
2610 var bundle = document.getElementById("bundle_composeMsgs");
2611 if (gPromptService.prompt(window,
2612 bundle.getString("attachPageDlogTitle"),
2613 bundle.getString("attachPageDlogMessage"),
2614 result,
2615 null,
2616 {value:0}))
2617 {
2618 var attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment);
2619 attachment.url = result.value;
2620 AddAttachment(attachment);
2621 ChangeAttachmentBucketVisibility(false);
2622 }
2623 }
2624 }
2625
DuplicateFileCheck
2626 function DuplicateFileCheck(FileUrl)
2627 {
2628 var bucket = document.getElementById('attachmentBucket');
2629 for (var index = 0; index < bucket.getRowCount(); index++)
2630 {
2631 var item = bucket.getItemAtIndex(index);
2632 var attachment = item.attachment;
2633 if (attachment)
2634 {
2635 if (FileUrl == attachment.url)
2636 return true;
2637 }
2638 }
2639
2640 return false;
2641 }
2642
Attachments2CompFields
2643 function Attachments2CompFields(compFields)
2644 {
2645 var bucket = document.getElementById('attachmentBucket');
2646
2647 //First, we need to clear all attachment in the compose fields
2648 compFields.removeAttachments();
2649
2650 for (var index = 0; index < bucket.getRowCount(); index++)
2651 {
2652 var item = bucket.getItemAtIndex(index);
2653 var attachment = item.attachment;
2654 if (attachment)
2655 compFields.addAttachment(attachment);
2656 }
2657 }
2658
RemoveAllAttachments
Called: ChromeWindow:getElementById (1 calls, 17 v-uS)
MsgComposeCommands.js:ChangeAttachmentBucketVisibility (1 calls, 91 v-uS)
listbox.xml:getRowCount (1 calls, 122 v-uS)
Called By: ChromeWindow:CloseWindow (1 calls, 272 v-uS)
2659 function RemoveAllAttachments()
2660 {
2661 var child;
2662 var bucket = document.getElementById("attachmentBucket");
2663 while (bucket.getRowCount())
2664 {
2665 child = bucket.removeItemAt(bucket.getRowCount() - 1);
2666 // Let's release the attachment object hold by the node else it won't go away until the window is destroyed
2667 child.attachment = null;
2668 }
2669
2670 ChangeAttachmentBucketVisibility(true);
2671 }
2672
ChangeAttachmentBucketVisibility
Called: ChromeWindow:getElementById (2 calls, 40 v-uS)
Called By: MsgComposeCommands.js:RemoveAllAttachments (1 calls, 91 v-uS)
2673 function ChangeAttachmentBucketVisibility(aHideBucket)
2674 {
2675 document.getElementById("attachments-box").collapsed = aHideBucket;
2676 document.getElementById("attachmentbucket-sizer").collapsed = aHideBucket;
2677 }
2678
RemoveSelectedAttachment
2679 function RemoveSelectedAttachment()
2680 {
2681 var child;
2682 var bucket = document.getElementById("attachmentBucket");
2683 if (bucket.selectedItems.length > 0) {
2684 for (var index = bucket.selectedCount - 1; index >= 0; index-- )
2685 {
2686 child = bucket.removeItemAt(bucket.getIndexOfItem(bucket.getSelectedItem(index)));
2687 // Let's release the attachment object held by the node else it won't go away until the window is destroyed
2688 child.attachment = null;
2689 }
2690 gContentChanged = true;
2691 }
2692 }
2693
RenameSelectedAttachment
2694 function RenameSelectedAttachment()
2695 {
2696 var bucket = document.getElementById("attachmentBucket");
2697 if (bucket.selectedItems.length != 1)
2698 return; // not one attachment selected
2699
2700 var bundle = document.getElementById("bundle_composeMsgs");
2701 var item = bucket.getSelectedItem(0);
2702 var attachmentName = {value: item.attachment.name};
2703 if (gPromptService.prompt(
2704 window,
2705 bundle.getString("renameAttachmentTitle"),
2706 bundle.getString("renameAttachmentMessage"),
2707 attachmentName,
2708 null,
2709 {value: 0}))
2710 {
2711 var modifiedAttachmentName = attachmentName.value;
2712 if (modifiedAttachmentName == "")
2713 return; // name was not filled, bail out
2714
2715 item.label = modifiedAttachmentName;
2716 item.attachment.name = modifiedAttachmentName;
2717 gContentChanged = true;
2718 }
2719 }
2720
FocusOnFirstAttachment
2721 function FocusOnFirstAttachment()
2722 {
2723 var bucketList = document.getElementById("attachmentBucket");
2724
2725 if (bucketList && bucketList.getRowCount())
2726 bucketList.selectedIndex = 0;
2727 }
2728
AttachmentElementHasItems
2729 function AttachmentElementHasItems()
2730 {
2731 var element = document.getElementById("attachmentBucket");
2732 return element ? element.getRowCount() : 0;
2733 }
2734
OpenSelectedAttachment
2735 function OpenSelectedAttachment()
2736 {
2737 var child;
2738 var bucket = document.getElementById("attachmentBucket");
2739 if (bucket.selectedItems.length == 1)
2740 {
2741 var attachmentUrl = bucket.getSelectedItem(0).attachment.url;
2742
2743 var messagePrefix = /^mailbox-message:|^imap-message:|^news-message:/i;
2744 if (messagePrefix.test(attachmentUrl))
2745 {
2746 // we must be dealing with a forwarded attachment, treat this special
2747 var messenger = Components.classes["@mozilla.org/messenger;1"].createInstance();
2748 messenger = messenger.QueryInterface(Components.interfaces.nsIMessenger);
2749 var msgHdr = messenger.messageServiceFromURI(attachmentUrl).messageURIToMsgHdr(attachmentUrl);
2750 if (msgHdr)
2751 {
2752 var folderUri = msgHdr.folder.folderURL;
2753 window.openDialog("chrome://messenger/content/messageWindow.xul", "_blank", "all,chrome,dialog=no,status,toolbar",
2754 attachmentUrl, folderUri, null );
2755 }
2756 }
2757 else
2758 {
2759 // turn the url into a nsIURL object then open it
2760
2761 var url = gIOService.newURI(attachmentUrl, null, null);
2762 url = url.QueryInterface( Components.interfaces.nsIURL );
2763
2764 if (url)
2765 {
2766 var channel = gIOService.newChannelFromURI(url);
2767 if (channel)
2768 {
2769 var uriLoader = Components.classes["@mozilla.org/uriloader;1"].getService(Components.interfaces.nsIURILoader);
2770 uriLoader.openURI(channel, true, new nsAttachmentOpener());
2771 } // if channel
2772 } // if url
2773 }
2774 } // if one attachment selected
2775 }
2776
nsAttachmentOpener
2777 function nsAttachmentOpener()
2778 {
2779 }
2780
2781 nsAttachmentOpener.prototype =
2782 {
QueryInterface
2783 QueryInterface: function(iid)
2784 {
2785 if (iid.equals(Components.interfaces.nsIURIContentListener) ||
2786 iid.equals(Components.interfaces.nsIInterfaceRequestor) ||
2787 iid.equals(Components.interfaces.nsISupports))
2788 return this;
2789 throw Components.results.NS_NOINTERFACE;
2790 },
2791
onStartURIOpen
2792 onStartURIOpen: function(uri)
2793 {
2794 return;
2795 },
2796
doContent
2797 doContent: function(contentType, isContentPreferred, request, contentHandler)
2798 {
2799 return;
2800 },
2801
isPreferred
2802 isPreferred: function(contentType, desiredContentType)
2803 {
2804 return;
2805 },
2806
canHandleContent
2807 canHandleContent: function(contentType, isContentPreferred, desiredContentType)
2808 {
2809 return false;
2810 },
2811
getInterface
2812 getInterface: function(iid)
2813 {
2814 if (iid.equals(Components.interfaces.nsIDOMWindowInternal))
2815 return window;
2816 else
2817 return this.QueryInterface(iid);
2818 },
2819
2820 loadCookie: null,
2821 parentContentListener: null
2822 }
2823
DetermineHTMLAction
2824 function DetermineHTMLAction(convertible)
2825 {
2826 var obj;
2827 if (! gMsgCompose.composeHTML)
2828 {
2829 try {
2830 obj = new Object;
2831 gMsgCompose.checkAndPopulateRecipients(true, false, obj);
2832 } catch(ex) {
2833 dump("gMsgCompose.checkAndPopulateRecipients failed: " + ex + "\n");
2834 }
2835 return nsIMsgCompSendFormat.PlainText;
2836 }
2837
2838 if (gSendFormat == nsIMsgCompSendFormat.AskUser)
2839 {
2840 //Well, before we ask, see if we can figure out what to do for ourselves
2841
2842 var noHtmlRecipients;
2843 var noHtmlnewsgroups;
2844 var preferFormat;
2845
2846 //Check the address book for the HTML property for each recipient
2847 try {
2848 obj = new Object;
2849 preferFormat = gMsgCompose.checkAndPopulateRecipients(true, true, obj);
2850 noHtmlRecipients = obj.value;
2851 } catch(ex) {
2852 dump("gMsgCompose.checkAndPopulateRecipients failed: " + ex + "\n");
2853 var msgCompFields = gMsgCompose.compFields;
2854 noHtmlRecipients = msgCompFields.to + "," + msgCompFields.cc + "," + msgCompFields.bcc;
2855 preferFormat = nsIAbPreferMailFormat.unknown;
2856 }
2857 dump("DetermineHTMLAction: preferFormat = " + preferFormat + ", noHtmlRecipients are " + noHtmlRecipients + "\n");
2858
2859 //Check newsgroups now...
2860 noHtmlnewsgroups = gMsgCompose.compFields.newsgroups;
2861
2862 if (noHtmlRecipients != "" || noHtmlnewsgroups != "")
2863 {
2864 if (convertible == nsIMsgCompConvertible.Plain)
2865 return nsIMsgCompSendFormat.PlainText;
2866
2867 if (noHtmlnewsgroups == "")
2868 {
2869 switch (preferFormat)
2870 {
2871 case nsIAbPreferMailFormat.plaintext :
2872 return nsIMsgCompSendFormat.PlainText;
2873
2874 default :
2875 //See if a preference has been set to tell us what to do. Note that we do not honor that
2876 //preference for newsgroups. Only for e-mail addresses.
2877 var action = getPref("mail.default_html_action");
2878 switch (action)
2879 {
2880 case nsIMsgCompSendFormat.PlainText :
2881 case nsIMsgCompSendFormat.HTML :
2882 case nsIMsgCompSendFormat.Both :
2883 return action;
2884 }
2885 }
2886 }
2887 return nsIMsgCompSendFormat.AskUser;
2888 }
2889 else
2890 return nsIMsgCompSendFormat.HTML;
2891 }
2892 else
2893 {
2894 try {
2895 obj = new Object;
2896 gMsgCompose.checkAndPopulateRecipients(true, false, obj);
2897 } catch(ex) {
2898 dump("gMsgCompose.checkAndPopulateRecipients failed: " + ex + "\n");
2899 }
2900 }
2901
2902 return gSendFormat;
2903 }
2904
DetermineConvertibility
2905 function DetermineConvertibility()
2906 {
2907 if (!gMsgCompose.composeHTML)
2908 return nsIMsgCompConvertible.Plain;
2909
2910 try {
2911 return gMsgCompose.bodyConvertible();
2912 } catch(ex) {}
2913 return nsIMsgCompConvertible.No;
2914 }
2915
LoadIdentity
Called: ChromeWindow:getAttribute (1 calls, 13 v-uS)
ChromeWindow:getElementById (1 calls, 15 v-uS)
ChromeWindow:getIdentity (1 calls, 24 v-uS)
ChromeWindow:setAttribute (1 calls, 29 v-uS)
MsgComposeCommands.js:AddDirectoryServerObserver (1 calls, 129 v-uS)
XULElement:getAttribute (1 calls, 13 v-uS)
Called By: MsgComposeCommands.js:ComposeStartup (1 calls, 328 v-uS)
2916 function LoadIdentity(startup)
2917 {
2918 var identityElement = document.getElementById("msgIdentity");
2919 var prevIdentity = gCurrentIdentity;
2920
2921 if (identityElement) {
2922 var idKey = identityElement.value;
2923 gCurrentIdentity = gAccountManager.getIdentity(idKey);
2924
2925 // set the account name on the menu list value.
2926 if (identityElement.selectedItem)
2927 identityElement.setAttribute('accountname', identityElement.selectedItem.getAttribute('accountname'));
2928
2929 if (!startup && prevIdentity && idKey != prevIdentity.key)
2930 {
2931 var prefstring = "mail.identity." + prevIdentity.key;
2932 RemoveDirectoryServerObserver(prefstring);
2933 var prevReplyTo = prevIdentity.replyTo;
2934 var prevBcc = "";
2935 var prevReceipt = prevIdentity.requestReturnReceipt;
2936 var prevDSN = prevIdentity.DSN;
2937 var prevAttachVCard = prevIdentity.attachVCard;
2938
2939 if (prevIdentity.doBcc)
2940 prevBcc += prevIdentity.doBccList;
2941
2942 var newReplyTo = gCurrentIdentity.replyTo;
2943 var newBcc = "";
2944 var newReceipt = gCurrentIdentity.requestReturnReceipt;
2945 var newDSN = gCurrentIdentity.DSN;
2946 var newAttachVCard = gCurrentIdentity.attachVCard;
2947
2948 if (gCurrentIdentity.doBcc)
2949 newBcc += gCurrentIdentity.doBccList;
2950
2951 var needToCleanUp = false;
2952 var msgCompFields = gMsgCompose.compFields;
2953
2954 if (!gReceiptOptionChanged &&
2955 prevReceipt == msgCompFields.returnReceipt &&
2956 prevReceipt != newReceipt)
2957 {
2958 msgCompFields.returnReceipt = newReceipt;
2959 document.getElementById("returnReceiptMenu").setAttribute('checked',msgCompFields.returnReceipt);
2960 }
2961
2962 if (!gDSNOptionChanged &&
2963 prevDSN == msgCompFields.DSN &&
2964 prevDSN != newDSN)
2965 {
2966 msgCompFields.DSN = newDSN;
2967 document.getElementById("dsnMenu").setAttribute('checked',msgCompFields.DSN);
2968 }
2969
2970 if (!gAttachVCardOptionChanged &&
2971 prevAttachVCard == msgCompFields.attachVCard &&
2972 prevAttachVCard != newAttachVCard)
2973 {
2974 msgCompFields.attachVCard = newAttachVCard;
2975 document.getElementById("cmd_attachVCard").setAttribute('checked',msgCompFields.attachVCard);
2976 }
2977
2978 if (newReplyTo != prevReplyTo)
2979 {
2980 needToCleanUp = true;
2981 if (prevReplyTo != "")
2982 awRemoveRecipients(msgCompFields, "addr_reply", prevReplyTo);
2983 if (newReplyTo != "")
2984 awAddRecipients(msgCompFields, "addr_reply", newReplyTo);
2985 }
2986
2987 if (newBcc != prevBcc)
2988 {
2989 needToCleanUp = true;
2990 if (prevBcc != "")
2991 awRemoveRecipients(msgCompFields, "addr_bcc", prevBcc);
2992 if (newBcc != "")
2993 awAddRecipients(msgCompFields, "addr_bcc", newBcc);
2994 }
2995
2996 if (needToCleanUp)
2997 awCleanupRows();
2998
2999 try {
3000 gMsgCompose.SetSignature(gCurrentIdentity);
3001 } catch (ex) { dump("### Cannot set the signature: " + ex + "\n");}
3002
3003 var event = document.createEvent('Events');
3004 event.initEvent('compose-from-changed', false, true);
3005 document.getElementById("msgcomposeWindow").dispatchEvent(event);
3006 }
3007
3008 AddDirectoryServerObserver(false);
3009 if (!startup) {
3010 if (!gAutocompleteSession)
3011 gAutocompleteSession = Components.classes["@mozilla.org/autocompleteSession;1?type=addrbook"].getService(Components.interfaces.nsIAbAutoCompleteSession);
3012 if (gAutocompleteSession)
3013 setDomainName();
3014 if (getPref("mail.autoComplete.highlightNonMatches"))
3015 document.getElementById('addressCol2#1').highlightNonMatches = true;
3016
3017 try {
3018 setupLdapAutocompleteSession();
3019 } catch (ex) {
3020 // catch the exception and ignore it, so that if LDAP setup
3021 // fails, the entire compose window doesn't end up horked
3022 }
3023
3024 addRecipientsToIgnoreList(gCurrentIdentity.identityName); // only do this if we aren't starting up....it gets done as part of startup already
3025 }
3026 }
3027 }
3028
setDomainName
3029 function setDomainName()
3030 {
3031 var defaultDomain = "";
3032 if (gCurrentIdentity.autocompleteToMyDomain)
3033 {
3034 var emailAddr = gCurrentIdentity.email;
3035 var start = emailAddr.lastIndexOf("@");
3036 defaultDomain = emailAddr.slice(start + 1);
3037 }
3038
3039 // If autocompleteToMyDomain is false the defaultDomain is emptied
3040 gAutocompleteSession.defaultDomain = defaultDomain;
3041 }
3042
setupAutocomplete
3043 function setupAutocomplete()
3044 {
3045 //Setup autocomplete session if we haven't done so already
3046 if (!gAutocompleteSession)
3047 {
3048 gAutocompleteSession = Components.classes["@mozilla.org/autocompleteSession;1?type=addrbook"].getService(Components.interfaces.nsIAbAutoCompleteSession);
3049 if (gAutocompleteSession)
3050 {
3051 setDomainName();
3052
3053 var autoCompleteWidget = document.getElementById("addressCol2#1");
3054 // When autocompleteToMyDomain is off there is no default entry with the domain
3055 // appended so reduce the minimum results for a popup to 2 in this case.
3056 if (!gCurrentIdentity.autocompleteToMyDomain)
3057 autoCompleteWidget.minResultsForPopup = 2;
3058
3059 // if the pref is set to turn on the comment column, honor it here.
3060 // this element then gets cloned for subsequent rows, so they should
3061 // honor it as well
3062 //
3063 try
3064 {
3065 if (getPref("mail.autoComplete.highlightNonMatches"))
3066 autoCompleteWidget.highlightNonMatches = true;
3067
3068 if (getPref("mail.autoComplete.commentColumn"))
3069 autoCompleteWidget.showCommentColumn = true;
3070 } catch (ex)
3071 {
3072 // if we can't get this pref, then don't show the columns (which is
3073 // what the XUL defaults to)
3074 }
3075
3076 } else
3077 {
3078 gAutocompleteSession = 1;
3079 }
3080 }
3081
3082 if (!gSetupLdapAutocomplete)
3083 {
3084 try
3085 {
3086 setupLdapAutocompleteSession();
3087 } catch (ex)
3088 {
3089 // catch the exception and ignore it, so that if LDAP setup
3090 // fails, the entire compose window doesn't end up horked
3091 }
3092 }
3093 }
3094
subjectKeyPress
3095 function subjectKeyPress(event)
3096 {
3097 switch(event.keyCode) {
3098 case 9:
3099 if (!event.shiftKey) {
3100 SetMsgBodyFrameFocus();
3101 event.preventDefault();
3102 }
3103 break;
3104 case 13:
3105 SetMsgBodyFrameFocus();
3106 break;
3107 }
3108 }
3109
AttachmentBucketClicked
3110 function AttachmentBucketClicked(event)
3111 {
3112 event.currentTarget.focus();
3113
3114 if (event.button != 0)
3115 return;
3116
3117 if (event.originalTarget.localName == "listboxbody")
3118 goDoCommand('cmd_attachFile');
3119 else if (event.originalTarget.localName == "listitem" && event.detail == 2)
3120 OpenSelectedAttachment();
3121 }
3122
3123 // we can drag and drop addresses, files, messages and urls into the compose envelope
3124 var envelopeDragObserver = {
3125
3126 canHandleMultipleItems: true,
3127
onDrop
3128 onDrop: function (aEvent, aData, aDragSession)
3129 {
3130 var dataList = aData.dataList;
3131 var dataListLength = dataList.length;
3132 var errorTitle;
3133 var attachment;
3134 var errorMsg;
3135
3136 for (var i = 0; i < dataListLength; i++)
3137 {
3138 var item = dataList[i].first;
3139 var prettyName;
3140 var rawData = item.data;
3141
3142 // We could be dropping an attachment OR an address, check and do the right thing..
3143
3144 if (item.flavour.contentType == "text/x-moz-url" ||
3145 item.flavour.contentType == "text/x-moz-message" ||
3146 item.flavour.contentType == "application/x-moz-file")
3147 {
3148 if (item.flavour.contentType == "application/x-moz-file")
3149 {
3150 var ioService = Components.classes["@mozilla.org/network/io-service;1"]
3151 .getService(Components.interfaces.nsIIOService);
3152 var fileHandler = ioService.getProtocolHandler("file")
3153 .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
3154 rawData = fileHandler.getURLSpecFromFile(rawData);
3155 }
3156 else
3157 {
3158 var separator = rawData.indexOf("\n");
3159 if (separator != -1)
3160 {
3161 prettyName = rawData.substr(separator+1);
3162 rawData = rawData.substr(0,separator);
3163 }
3164 }
3165
3166 if (DuplicateFileCheck(rawData))
3167 {
3168 dump("Error, attaching the same item twice\n");
3169 }
3170 else
3171 {
3172 var isValid = true;
3173 if (item.flavour.contentType == "text/x-moz-url") {
3174 // if this is a url (or selected text)
3175 // see if it's a valid url by checking
3176 // if we can extract a scheme
3177 // using the ioservice
3178 //
3179 // also skip mailto:, since it doesn't make sense
3180 // to attach and send mailto urls
3181 try {
3182 var scheme = gIOService.extractScheme(rawData);
3183 // don't attach mailto: urls
3184 if (scheme == "mailto")
3185 isValid = false;
3186 }
3187 catch (ex) {
3188 isValid = false;
3189 }
3190 }
3191
3192 if (isValid) {
3193 attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"]
3194 .createInstance(Components.interfaces.nsIMsgAttachment);
3195 attachment.url = rawData;
3196 attachment.name = prettyName;
3197 AddAttachment(attachment);
3198 ChangeAttachmentBucketVisibility(false);
3199 }
3200 }
3201 }
3202 else if (item.flavour.contentType == "text/x-moz-address")
3203 {
3204 // process the address
3205 if (rawData)
3206 DropRecipient(aEvent.target, rawData);
3207 }
3208 }
3209 },
3210
onDragOver
3211 onDragOver: function (aEvent, aFlavour, aDragSession)
3212 {
3213 if (aFlavour.contentType != "text/x-moz-address")
3214 {
3215 // make sure the attachment box is visible during drag over
3216 var attachmentBox = document.getElementById("attachments-box");
3217 if (attachmentBox.collapsed)
3218 ChangeAttachmentBucketVisibility(false);
3219 }
3220 else
3221 {
3222 DragAddressOverTargetControl(aEvent);
3223 }
3224 },
3225
onDragExit
3226 onDragExit: function (aEvent, aDragSession)
3227 {
3228 },
3229
getSupportedFlavours
3230 getSupportedFlavours: function ()
3231 {
3232 var flavourSet = new FlavourSet();
3233 flavourSet.appendFlavour("text/x-moz-url");
3234 flavourSet.appendFlavour("text/x-moz-message");
3235 flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
3236 flavourSet.appendFlavour("text/x-moz-address");
3237 return flavourSet;
3238 }
3239 };
3240
DisplaySaveFolderDlg
3241 function DisplaySaveFolderDlg(folderURI)
3242 {
3243 try{
3244 showDialog = gCurrentIdentity.showSaveMsgDlg;
3245 }//try
3246 catch (e){
3247 return;
3248 }//catch
3249
3250 if (showDialog){
3251 var msgfolder = GetMsgFolderFromUri(folderURI, true);
3252 if (!msgfolder)
3253 return;
3254 var checkbox = {value:0};
3255 var bundle = document.getElementById("bundle_composeMsgs");
3256 var SaveDlgTitle = bundle.getString("SaveDialogTitle");
3257 var dlgMsg = bundle.getFormattedString("SaveDialogMsg",
3258 [msgfolder.name,
3259 msgfolder.server.prettyName]);
3260
3261 var CheckMsg = bundle.getString("CheckMsg");
3262 if (gPromptService)
3263 gPromptService.alertCheck(window, SaveDlgTitle, dlgMsg,
3264 bundle.getString("CheckMsg"), checkbox);
3265 else
3266 window.alert(dlgMsg);
3267 try {
3268 gCurrentIdentity.showSaveMsgDlg = !checkbox.value;
3269 }//try
3270 catch (e) {
3271 return;
3272 }//catch
3273
3274 }//if
3275 return;
3276 }
3277
SetMsgAddressingWidgetTreeElementFocus
3278 function SetMsgAddressingWidgetTreeElementFocus()
3279 {
3280 var element = awGetInputElement(awGetNumberOfRecipients());
3281 awSetFocus(awGetNumberOfRecipients(), element);
3282 }
3283
SetMsgIdentityElementFocus
3284 function SetMsgIdentityElementFocus()
3285 {
3286 GetMsgIdentityElement().focus();
3287 }
3288
SetMsgSubjectElementFocus
3289 function SetMsgSubjectElementFocus()
3290 {
3291 GetMsgSubjectElement().focus();
3292 }
3293
SetMsgAttachmentElementFocus
3294 function SetMsgAttachmentElementFocus()
3295 {
3296 GetMsgAttachmentElement().focus();
3297 FocusOnFirstAttachment();
3298 }
3299
SetMsgBodyFrameFocus
3300 function SetMsgBodyFrameFocus()
3301 {
3302 // window.content.focus() fails to blur the currently focused element
3303 document.commandDispatcher
3304 .advanceFocusIntoSubtree(document.getElementById("appcontent"));
3305 }
3306
GetMsgAddressingWidgetTreeElement
3307 function GetMsgAddressingWidgetTreeElement()
3308 {
3309 if (!gMsgAddressingWidgetTreeElement)
3310 gMsgAddressingWidgetTreeElement = document.getElementById("addressingWidgetTree");
3311
3312 return gMsgAddressingWidgetTreeElement;
3313 }
3314
GetMsgIdentityElement
3315 function GetMsgIdentityElement()
3316 {
3317 if (!gMsgIdentityElement)
3318 gMsgIdentityElement = document.getElementById("msgIdentity");
3319
3320 return gMsgIdentityElement;
3321 }
3322
GetMsgSubjectElement
Called: ChromeWindow:getElementById (1 calls, 27 v-uS)
Called By: ChromeWindow:CloseWindow (2 calls, 15 v-uS)
ChromeWindow:getControllerForCommand (1 calls, 8 v-uS)
MsgComposeCommands.js:ComposeStartup (1 calls, 59 v-uS)
MsgComposeCommands.js:SetComposeWindowTitle (1 calls, 8 v-uS)
3323 function GetMsgSubjectElement()
3324 {
3325 if (!gMsgSubjectElement)
3326 gMsgSubjectElement = document.getElementById("msgSubject");
3327
3328 return gMsgSubjectElement;
3329 }
3330
GetMsgAttachmentElement
3331 function GetMsgAttachmentElement()
3332 {
3333 if (!gMsgAttachmentElement)
3334 gMsgAttachmentElement = document.getElementById("attachmentBucket");
3335
3336 return gMsgAttachmentElement;
3337 }
3338
3339 function GetMsgHeadersToolbarElement()
3340 {
3341 if (!gMsgHeadersToolbarElement)
3342 gMsgHeadersToolbarElement = document.getElementById("MsgHeadersToolbar");
3343
3344 return gMsgHeadersToolbarElement;
3345 }
3346
WhichElementHasFocus
3347 function WhichElementHasFocus()
3348 {
3349 var msgIdentityElement = GetMsgIdentityElement();
3350 var msgAddressingWidgetTreeElement = GetMsgAddressingWidgetTreeElement();
3351 var msgSubjectElement = GetMsgSubjectElement();
3352 var msgAttachmentElement = GetMsgAttachmentElement();
3353
3354 if (top.document.commandDispatcher.focusedWindow == content)
3355 return content;
3356
3357 var currentNode = top.document.commandDispatcher.focusedElement;
3358 while (currentNode)
3359 {
3360 if (currentNode == msgIdentityElement ||
3361 currentNode == msgAddressingWidgetTreeElement ||
3362 currentNode == msgSubjectElement ||
3363 currentNode == msgAttachmentElement)
3364 return currentNode;
3365
3366 currentNode = currentNode.parentNode;
3367 }
3368
3369 return null;
3370 }
3371
3372 // Function that performs the logic of switching focus from
3373 // one element to another in the mail compose window.
3374 // The default element to switch to when going in either
3375 // direction (shift or no shift key pressed), is the
3376 // AddressingWidgetTreeElement.
3377 //
3378 // The only exception is when the MsgHeadersToolbar is
3379 // collapsed, then the focus will always be on the body of
3380 // the message.
SwitchElementFocus
3381 function SwitchElementFocus(event)
3382 {
3383 var focusedElement = WhichElementHasFocus();
3384
3385 if (event && event.shiftKey)
3386 {
3387 if (focusedElement == gMsgAddressingWidgetTreeElement)
3388 SetMsgIdentityElementFocus();
3389 else if (focusedElement == gMsgIdentityElement)
3390 SetMsgBodyFrameFocus();
3391 else if (focusedElement == content)
3392 {
3393 // only set focus to the attachment element if there
3394 // are any attachments.
3395 if (AttachmentElementHasItems())
3396 SetMsgAttachmentElementFocus();
3397 else
3398 SetMsgSubjectElementFocus();
3399 }
3400 else if (focusedElement == gMsgAttachmentElement)
3401 SetMsgSubjectElementFocus();
3402 else
3403 SetMsgAddressingWidgetTreeElementFocus();
3404 }
3405 else
3406 {
3407 if (focusedElement == gMsgAddressingWidgetTreeElement)
3408 SetMsgSubjectElementFocus();
3409 else if (focusedElement == gMsgSubjectElement)
3410 {
3411 // only set focus to the attachment element if there
3412 // are any attachments.
3413 if (AttachmentElementHasItems())
3414 SetMsgAttachmentElementFocus();
3415 else
3416 SetMsgBodyFrameFocus();
3417 }
3418 else if (focusedElement == gMsgAttachmentElement)
3419 SetMsgBodyFrameFocus();
3420 else if (focusedElement == content)
3421 SetMsgIdentityElementFocus();
3422 else
3423 SetMsgAddressingWidgetTreeElementFocus();
3424 }
3425 }
3426
toggleAddressPicker
3427 function toggleAddressPicker()
3428 {
3429 var sidebarBox = document.getElementById("sidebar-box");
3430 var sidebarSplitter = document.getElementById("sidebar-splitter");
3431 var elt = document.getElementById("viewAddressPicker");
3432 if (sidebarBox.hidden)
3433 {
3434 sidebarBox.hidden = false;
3435 sidebarSplitter.hidden = false;
3436 elt.setAttribute("checked","true");
3437
3438 var sidebar = document.getElementById("sidebar");
3439 var sidebarUrl = sidebar.getAttribute("src");
3440 // if we have yet to initialize the src url on the sidebar than go ahead and do so now...
3441 // we do this lazily here, so we don't spend time when bringing up the compose window loading the address book
3442 // data sources. Only when the user opens the address picker do we set the src url for the sidebar...
3443 if (sidebarUrl == "")
3444 sidebar.setAttribute("src", "chrome://messenger/content/addressbook/abContactsPanel.xul");
3445
3446 sidebarBox.setAttribute("sidebarVisible", "true");
3447 }
3448 else
3449 {
3450 sidebarBox.hidden = true;
3451 sidebarSplitter.hidden = true;
3452 sidebarBox.setAttribute("sidebarVisible", "false");
3453 elt.removeAttribute("checked");
3454 }
3455 }
3456
3457 // public method called by the address picker sidebar
AddRecipient
3458 function AddRecipient(recipientType, address)
3459 {
3460 awAddRecipient(recipientType, address);
3461 }
3462
loadHTMLMsgPrefs
Called: ChromeWindow:XPCNativeWrapper function wrapper (4 calls, 239 v-uS)
ChromeWindow:getCharPref (4 calls, 114 v-uS)
ChromeWindow:getElementById (2 calls, 32 v-uS)
ChromeWindow:setAttribute (2 calls, 1122 v-uS)
ComposerCommands.js:doStatefulCommand (1 calls, 24274 v-uS)
editor.js:EditorSetFontSize (1 calls, 2898 v-uS)
editor.js:GetBodyElement (1 calls, 444 v-uS)
editor.js:onBackgroundColorChange (1 calls, 123 v-uS)
editor.js:onFontColorChange (1 calls, 137 v-uS)
editorUtilities.js:GetPrefs (1 calls, 9 v-uS)
3463 function loadHTMLMsgPrefs()
3464 {
3465 var pref = GetPrefs();
3466 var fontFace;
3467 var fontSize;
3468 var textColor;
3469 var bgColor;
3470
3471 try {
3472 fontFace = pref.getCharPref("msgcompose.font_face");
3473 doStatefulCommand('cmd_fontFace', fontFace);
3474 } catch (e) {}
3475
3476 try {
3477 fontSize = pref.getCharPref("msgcompose.font_size");
3478 EditorSetFontSize(fontSize);
3479 } catch (e) {}
3480
3481 var bodyElement = GetBodyElement();
3482
3483 try {
3484 textColor = pref.getCharPref("msgcompose.text_color");
3485 if (!bodyElement.getAttribute("text"))
3486 {
3487 bodyElement.setAttribute("text", textColor);
3488 gDefaultTextColor = textColor;
3489 document.getElementById("cmd_fontColor").setAttribute("state", textColor);
3490 onFontColorChange();
3491 }
3492 } catch (e) {}
3493
3494 try {
3495 bgColor = pref.getCharPref("msgcompose.background_color");
3496 if (!bodyElement.getAttribute("bgcolor"))
3497 {
3498 bodyElement.setAttribute("bgcolor", bgColor);
3499 gDefaultBackgroundColor = bgColor;
3500 document.getElementById("cmd_backgroundColor").setAttribute("state", bgColor);
3501 onBackgroundColorChange();
3502 }
3503 } catch (e) {}
3504 }
3505
AutoSave
3506 function AutoSave()
3507 {
3508 if (gMsgCompose.editor && (gContentChanged || gMsgCompose.bodyModified)
3509 && !gSendOrSaveOperationInProgress)
3510 {
3511 GenericSendMessage(nsIMsgCompDeliverMode.AutoSaveAsDraft);
3512 gAutoSaveKickedIn = true;
3513 }
3514
3515 gAutoSaveTimeout = setTimeout(AutoSave, gAutoSaveInterval);
3516 }
3517
InitEditor
Called: ChromeWindow:getElementById (1 calls, 15 v-uS)
ChromeWindow:initEditor (1 calls, 33535 v-uS)
ChromeWindow:setAttribute (1 calls, 89 v-uS)
MsgComposeCommands.js:enableInlineSpellCheck (1 calls, 249 v-uS)
MsgComposeCommands.js:getPref (1 calls, 98 v-uS)
inlineSpellCheckUI.js:init (1 calls, 105 v-uS)
3518 function InitEditor()
3519 {
3520 var editor = GetCurrentEditor();
3521 gMsgCompose.initEditor(editor, window.content);
3522
3523 InlineSpellCheckerUI.init(editor);
3524 enableInlineSpellCheck(getPref("mail.spellcheck.inline"));
3525 document.getElementById('menu_inlineSpellCheck').setAttribute('disabled', !InlineSpellCheckerUI.canSpellCheck);
3526 }
3527
enableInlineSpellCheck
Called: ChromeWindow:getElementById (3 calls, 67 v-uS)
ChromeWindow:setAttribute (3 calls, 87 v-uS)
Object:setSpellcheckUserOverride (3 calls, 227 v-uS)
Called By: ChromeWindow:CloseWindow (1 calls, 155 v-uS)
MsgComposeCommands.js:ComposeUnload (1 calls, 143 v-uS)
MsgComposeCommands.js:InitEditor (1 calls, 249 v-uS)
3528 function enableInlineSpellCheck(aEnableInlineSpellCheck)
3529 {
3530 InlineSpellCheckerUI.enabled = aEnableInlineSpellCheck;
3531 document.getElementById('msgSubject').setAttribute('spellcheck', aEnableInlineSpellCheck);
3532 }
3533
getMailToolbox
3534 function getMailToolbox()
3535 {
3536 return document.getElementById("compose-toolbox");
3537 }
3538
getPref
Called: ChromeWindow:getPrefType (6 calls, 81 v-uS)
ChromeWindow:getService (6 calls, 115 v-uS)
ChromeWindow:getBoolPref (3 calls, 33 v-uS)
ChromeWindow:getCharPref (1 calls, 14 v-uS)
ChromeWindow:getIntPref (1 calls, 11 v-uS)
Called By: MsgComposeCommands.js:ComposeStartup (3 calls, 305 v-uS)
MsgComposeCommands.js:ComposeLoad (2 calls, 229 v-uS)
MsgComposeCommands.js:InitEditor (1 calls, 98 v-uS)
3539 function getPref(aPrefName, aIsComplex) {
3540 const Ci = Components.interfaces;
3541 const prefB = Components.classes["@mozilla.org/preferences-service;1"]
3542 .getService(Ci.nsIPrefBranch);
3543 if (aIsComplex) {
3544 return prefB.getComplexValue(aPrefName, Ci.nsISupportsString).data;
3545 }
3546 switch (prefB.getPrefType(aPrefName)) {
3547 case Ci.nsIPrefBranch.PREF_BOOL:
3548 return prefB.getBoolPref(aPrefName);
3549 case Ci.nsIPrefBranch.PREF_INT:
3550 return prefB.getIntPref(aPrefName);
3551 case Ci.nsIPrefBranch.PREF_STRING:
3552 return prefB.getCharPref(aPrefName);
3553 default: // includes nsIPrefBranch.PREF_INVALID
3554 return null;
3555 }
3556 }