]> err.no Git - scalable-opengroupware.org/blob - UI/WebServerResources/MailerUI.js
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1277 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / WebServerResources / MailerUI.js
1 /* JavaScript for SOGoMail */
2 var accounts = {};
3 var mailboxTree;
4 var mailAccounts;
5 if (typeof textMailAccounts != 'undefined') {
6   if (textMailAccounts.length > 0)
7     mailAccounts = textMailAccounts.evalJSON(true);
8   else
9     mailAccounts = new Array();
10 }
11
12 var Mailer = {
13  currentMailbox: null,
14  currentMailboxType: "",
15  currentMessages: {},
16  maxCachedMessages: 20,
17  cachedMessages: new Array()
18 };
19
20 var usersRightsWindowHeight = 320;
21 var usersRightsWindowWidth = 400;
22
23 var pageContent;
24
25 var deleteMessageRequestCount = 0;
26
27 var messageCheckTimer;
28
29 /* mail list */
30
31 function openMessageWindow(msguid, url) {
32   var wId = '';
33   if (msguid) {
34     wId += "SOGo_msg_" + msguid;
35     markMailReadInWindow(window, msguid);
36   }
37   var msgWin = openMailComposeWindow(url, wId);
38   msgWin.focus();
39
40   return false;
41 }
42
43 function onMessageDoubleClick(event) {
44   var action;
45
46   if (Mailer.currentMailboxType == "draft")
47     action = "edit";
48   else
49     action = "popupview";
50
51   return openMessageWindowsForSelection(action, true);
52 }
53
54 function toggleMailSelect(sender) {
55   var row;
56   row = $(sender.name);
57   row.className = sender.checked ? "tableview_selected" : "tableview";
58 }
59
60 function openAddressbook(sender) {
61   var urlstr;
62
63   urlstr = ApplicationBaseURL + "../Contacts/?popup=YES";
64   var w = window.open(urlstr, "Addressbook",
65                       "width=640,height=400,resizable=1,scrollbars=1,toolbar=0,"
66                       + "location=no,directories=0,status=0,menubar=0,copyhistory=0");
67   w.focus();
68
69   return false;
70 }
71
72 function onMenuSharing(event) {
73   var folderID = document.menuTarget.getAttribute("dataname");
74   var type = document.menuTarget.getAttribute("datatype");
75
76   if (type == "additional")
77     window.alert(clabels["The user rights cannot be"
78                          + " edited for this object!"]);
79   else {
80     var urlstr = URLForFolderID(folderID) + "/acls";
81     openAclWindow(urlstr);
82   }
83 }
84
85 /* mail list DOM changes */
86
87 function markMailInWindow(win, msguid, markread) {
88   var row = win.$("row_" + msguid);
89   var subjectCell = win.$("div_" + msguid);
90   if (row && subjectCell) {
91     if (markread) {
92       row.removeClassName("mailer_unreadmail");
93       subjectCell.addClassName("mailer_readmailsubject");
94       var img = win.$("unreaddiv_" + msguid);
95       if (img) {
96         img.removeClassName("mailerUnreadIcon");
97         img.addClassName("mailerReadIcon");
98         img.setAttribute("id", "readdiv_" + msguid);
99         img.setAttribute("src", ResourcesURL + "/icon_read.gif");
100         var title = img.getAttribute("title-markunread");
101         if (title)
102           img.setAttribute("title", title);
103       }
104     }
105     else {
106       row.addClassName("mailer_unreadmail");
107       subjectCell.removeClassName('mailer_readmailsubject');
108       var img = win.$("readdiv_" + msguid);
109       if (img) {
110         img.removeClassName("mailerReadIcon");
111         img.addClassName("mailerUnreadIcon");
112         img.setAttribute("id", "unreaddiv_" + msguid);
113         img.setAttribute("src", ResourcesURL + "/icon_unread.gif");
114         var title = img.getAttribute("title-markread");
115         if (title)
116           img.setAttribute("title", title);
117       }
118     }
119     return true;
120   }
121   else
122     return false;
123 }
124
125 function markMailReadInWindow(win, msguid) {
126   /* this is called by UIxMailView with window.opener */
127   return markMailInWindow(win, msguid, true);
128 }
129
130 /* mail list reply */
131
132 function openMessageWindowsForSelection(action, firstOnly) {
133   if (document.body.hasClassName("popup")) {
134     var url = window.location.href;
135     var parts = url.split("/");
136     parts[parts.length-1] = action;
137     window.location.href = parts.join("/");
138   }
139   else {
140     var messageList = $("messageList");
141     var rows = messageList.getSelectedRowsId();
142     if (rows.length > 0) {
143       for (var i = 0; i < rows.length; i++) {
144         openMessageWindow(rows[i].substr(4),
145                           ApplicationBaseURL + Mailer.currentMailbox
146                           + "/" + rows[i].substr(4)
147                           + "/" + action);
148         if (firstOnly)
149           break;
150       }
151     } else {
152       window.alert(labels["Please select a message."]);
153     }
154   }
155
156   return false;
157 }
158
159 function mailListMarkMessage(event) {
160   var msguid = this.id.split('_')[1];
161   var action;
162   var markread;
163   if ($(this).hasClassName('mailerUnreadIcon')) {
164     action = 'markMessageRead';
165     markread = true;
166   }
167   else {
168     action = 'markMessageUnread';
169     markread = false;
170   }
171   var url = ApplicationBaseURL + Mailer.currentMailbox + "/" + msguid + "/" + action;
172
173   var data = { "window": window, "msguid": msguid, "markread": markread };
174   triggerAjaxRequest(url, mailListMarkMessageCallback, data);
175
176   preventDefault(event);
177   return false;
178 }
179
180 function mailListMarkMessageCallback(http) {
181   if (http.readyState == 4)
182     if (isHttpStatus204(http.status)) {
183       var data = http.callbackData;
184       markMailInWindow(data["window"], data["msguid"], data["markread"]);
185     }
186     else {
187       alert("Message Mark Failed (" + http.status + "): " + http.statusText);
188       window.location.reload();
189     }
190 }
191
192 /* maillist row highlight */
193
194 var oldMaillistHighlight = null; // to remember deleted/selected style
195
196 function ml_highlight(sender) {
197   oldMaillistHighlight = sender.className;
198   if (oldMaillistHighlight == "tableview_highlight")
199     oldMaillistHighlight = null;
200   sender.className = "tableview_highlight";
201 }
202
203 function ml_lowlight(sender) {
204   if (oldMaillistHighlight) {
205     sender.className = oldMaillistHighlight;
206     oldMaillistHighlight = null;
207   }
208   else
209     sender.className = "tableview";
210 }
211
212
213 /* bulk delete of messages */
214
215 function deleteSelectedMessages(sender) {
216   var messageList = $("messageList");
217   var rowIds = messageList.getSelectedRowsId();
218
219   if (rowIds.length > 0) {
220     for (var i = 0; i < rowIds.length; i++) {
221       var url;
222       var rowId = rowIds[i].substr(4);
223       var messageId = Mailer.currentMailbox + "/" + rowId;
224       url = ApplicationBaseURL + messageId + "/trash";
225       deleteMessageRequestCount++;
226       var data = { "id": rowId, "mailbox": Mailer.currentMailbox, "messageId": messageId };
227       triggerAjaxRequest(url, deleteSelectedMessagesCallback, data);
228     }
229   } else {
230     window.alert(labels["Please select a message."]);
231   }
232
233   return false;
234 }
235
236 function deleteSelectedMessagesCallback(http) {
237   if (http.readyState == 4) {
238     if (isHttpStatus204(http.status)) {
239       var data = http.callbackData;
240       deleteCachedMessage(data["messageId"]);
241       deleteMessageRequestCount--;
242       if (Mailer.currentMailbox == data["mailbox"]) {
243         
244         var div = $('messageContent');
245         if (Mailer.currentMessages[Mailer.currentMailbox] == data["id"]) {
246           div.update();
247           Mailer.currentMessages[Mailer.currentMailbox] = null; 
248         }
249
250         var row = $("row_" + data["id"]);
251         var nextRow = row.next("tr");
252         if (!nextRow)
253           nextRow = row.previous("tr");
254         row.parentNode.removeChild(row);
255 //      row.addClassName("deleted"); // when we'll offer "mark as deleted"
256       
257         if (deleteMessageRequestCount == 0) {
258           if (nextRow)
259             Mailer.currentMessages[Mailer.currentMailbox] = nextRow.getAttribute("id").substr(4);
260           openMailbox(data["mailbox"], true);
261         }
262       }
263     }
264   }
265   else
266     log ("deleteSelectedMessagesCallback: problem during ajax request " + http.status);
267 }
268
269 function deleteDraft(url) {
270   /* this is called by UIxMailEditor with window.opener */
271   new Ajax.Request(url, {
272     method: 'post',
273     onFailure: function(transport) {
274         if (!isHttpStatus204)
275           log("draftDeleteCallback: problem during ajax request: " + transport.status);
276       }
277     });
278 }
279
280 function moveMessages(rowIds, folder) {
281   var failCount = 0;
282
283   for (var i = 0; i < rowIds.length; i++) {
284     var url, http;
285
286     /* send AJAX request (synchronously) */
287           
288     var messageId = Mailer.currentMailbox + "/" + rowIds[i];
289     url = (ApplicationBaseURL + messageId
290            + "/move?tofolder=" + folder);
291     http = createHTTPClient();
292     http.open("GET", url, false /* not async */);
293     http.send("");
294     if (http.status == 200) {
295       var row = $("row_" + rowIds[i]);
296       row.parentNode.removeChild(row);
297       deleteCachedMessage(messageId);
298       if (Mailer.currentMessages[Mailer.currentMailbox] == rowIds[i]) {
299         var div = $('messageContent');
300         div.update();
301         Mailer.currentMessages[Mailer.currentMailbox] = null;
302       }
303     }
304     else /* request failed */
305       failCount++;
306
307     /* remove from page */
308
309     /* line-through would be nicer, but hiding is OK too */
310   }
311
312   if (failCount > 0)
313     alert("Could not move " + failCount + " messages!");
314    
315   return failCount;
316 }
317
318 function onMenuDeleteMessage(event) {
319   deleteSelectedMessages();
320   preventDefault(event);
321 }
322
323 function onPrintCurrentMessage(event) {
324   var rowIds = $("messageList").getSelectedRowsId();
325   if (rowIds.length == 0) {
326     window.alert(labels["Please select a message to print."]);
327   }
328   else if (rowIds.length > 1) {
329     window.alert(labels["Please select only one message to print."]);
330   }
331   else
332     window.print();
333
334   preventDefault(event);
335 }
336
337 function onMailboxTreeItemClick(event) {
338   var topNode = $("mailboxTree");
339   var mailbox = this.parentNode.getAttribute("dataname");
340
341   if (topNode.selectedEntry)
342     topNode.selectedEntry.deselect();
343   this.select();
344   topNode.selectedEntry = this;
345
346   search = {};
347   sorting = {};
348   $("searchValue").value = "";
349   initCriteria();
350
351   Mailer.currentMailboxType = this.parentNode.getAttribute("datatype");
352   if (Mailer.currentMailboxType == "account" || Mailer.currentMailboxType == "additional") {
353     Mailer.currentMailbox = mailbox;
354     $("messageContent").update();
355     var table = $("messageList");
356     var head = table.tHead;
357     var body = table.tBodies[0];
358     for (var i = body.rows.length; i > 0; i--)
359       body.deleteRow(i-1);
360     if (head.rows[1])
361       head.rows[1].firstChild.update();
362   }
363   else
364     openMailbox(mailbox);
365    
366   Event.stop(event);
367 }
368
369 function _onMailboxMenuAction(menuEntry, error, actionName) {
370   var targetMailbox = menuEntry.mailbox.fullName();
371   var messages = new Array();
372
373   if (targetMailbox == Mailer.currentMailbox)
374     window.alert(labels[error]);
375   else {
376     if (document.menuTarget.tagName == "DIV")
377       // Menu called from message content view
378       messages.push(Mailer.currentMessages[Mailer.currentMailbox]);
379     else if (Object.isArray(document.menuTarget))
380       // Menu called from multiple selection in messages list view
381       messages = $(document.menuTarget).collect(function(row) {
382           return row.getAttribute("id").substr(4);
383         });
384     else
385       // Menu called from one selection in messages list view
386       messages.push(document.menuTarget.getAttribute("id").substr(4));
387
388     var url_prefix = URLForFolderID(Mailer.currentMailbox) + "/";
389     messages.each(function(msgid, i) {
390         var url = url_prefix + msgid + "/" + actionName
391           + "?folder=" + targetMailbox;
392         triggerAjaxRequest(url, folderRefreshCallback,
393                            ((i == messages.size() - 1)?Mailer.currentMailbox:""));
394       });
395   }
396 }
397
398 function onMailboxMenuMove(event) {
399   _onMailboxMenuAction(this,
400                        "Moving a message into its own folder is impossible!",
401                        "move");
402 }
403
404 function onMailboxMenuCopy(event) {
405   _onMailboxMenuAction(this,
406                        "Copying a message into its own folder is impossible!",
407                        "copy");
408 }
409
410 function refreshMailbox() {
411   var topWindow = getTopWindow();
412   if (topWindow)
413     topWindow.refreshCurrentFolder();
414
415   return false;
416 }
417
418 function onComposeMessage() {
419   var topWindow = getTopWindow();
420   if (topWindow)
421     topWindow.composeNewMessage();
422
423   return false;
424 }
425
426 function composeNewMessage() {
427   var account = Mailer.currentMailbox.split("/")[1];
428   var url = ApplicationBaseURL + "/" + account + "/compose";
429   openMailComposeWindow(url);
430 }
431
432 function openMailbox(mailbox, reload, idx) {
433   if (mailbox != Mailer.currentMailbox || reload) {
434     Mailer.currentMailbox = mailbox;
435     var url = ApplicationBaseURL + encodeURI(mailbox) + "/view?noframe=1";
436     var messageContent = $("messageContent");
437     messageContent.update();
438     lastClickedRow = -1; // from generic.js
439
440     var currentMessage;
441     if (!idx) {
442       currentMessage = Mailer.currentMessages[mailbox];
443       if (currentMessage) {
444         loadMessage(currentMessage);
445         url += '&pageforuid=' + currentMessage;
446       }
447     }
448
449     var searchValue = search["value"];
450     if (searchValue && searchValue.length > 0)
451       url += ("&search=" + search["criteria"]
452               + "&value=" + escape(searchValue));
453     var sortAttribute = sorting["attribute"];
454     if (sortAttribute && sortAttribute.length > 0)
455       url += ("&sort=" + sorting["attribute"]
456               + "&asc=" + sorting["ascending"]);
457     if (idx)
458       url += "&idx=" + idx;
459
460     if (document.messageListAjaxRequest) {
461       document.messageListAjaxRequest.aborted = true;
462       document.messageListAjaxRequest.abort();
463     }
464
465     var mailboxContent = $("mailboxContent");
466     if (mailboxContent.getStyle('visibility') == "hidden") {
467       mailboxContent.setStyle({ visibility: "visible" });
468       var rightDragHandle = $("rightDragHandle");
469       rightDragHandle.setStyle({ visibility: "visible" });
470       messageContent.setStyle({ top: (rightDragHandle.offsetTop
471                                       + rightDragHandle.offsetHeight
472                                       + 'px') });
473     }
474     document.messageListAjaxRequest
475       = triggerAjaxRequest(url, messageListCallback,
476                            currentMessage);
477
478     var quotasUrl = ApplicationBaseURL + mailbox + "/quotas";
479     document.quotasAjaxRequest
480       = triggerAjaxRequest(quotasUrl, quotasCallback);
481   }
482 }
483
484 function openMailboxAtIndex(event) {
485   openMailbox(Mailer.currentMailbox, true, this.getAttribute("idx"));
486
487   Event.stop(event);
488 }
489
490 function messageListCallback(http) {
491   var div = $('mailboxContent');
492   var table = $('messageList');
493   
494   if (http.readyState == 4
495       && http.status == 200) {
496     document.messageListAjaxRequest = null;
497
498     if (table) {
499       // Update table
500       var thead = table.tHead;
501       var addressHeaderCell = thead.rows[0].cells[3];
502       var tbody = table.tBodies[0];
503       var tmp = document.createElement('div');
504       $(tmp).update(http.responseText);
505       thead.rows[1].parentNode.replaceChild(tmp.firstChild.tHead.rows[1], thead.rows[1]);
506       addressHeaderCell.replaceChild(tmp.firstChild.tHead.rows[0].cells[3].lastChild, 
507                                      addressHeaderCell.lastChild);
508       table.replaceChild(tmp.firstChild.tBodies[0], tbody);
509     }
510     else {
511       // Add table
512       div.update(http.responseText);
513       table = $('messageList');
514       configureMessageListEvents(table);
515       TableKit.Resizable.init(table, {'trueResize' : true, 'keepWidth' : true});
516     }
517     configureMessageListBodyEvents(table);
518
519     var selected = http.callbackData;
520     if (selected) {
521       var row = $("row_" + selected);
522       if (row) {
523         row.select();
524         lastClickedRow = row.rowIndex - $(row).up('table').down('thead').getElementsByTagName('tr').length;  
525         div.scrollTop = row.rowIndex * row.getHeight(); // scroll to selected message
526       }
527       else
528         $("messageContent").update();
529     }
530     else
531       div.scrollTop = 0;
532     
533     if (sorting["attribute"] && sorting["attribute"].length > 0) {
534       var sortHeader = $(sorting["attribute"] + "Header");
535       
536       if (sortHeader) {
537         var sortImages = $(table.tHead).getElementsByClassName("sortImage");
538         $(sortImages).each(function(item) {
539             item.remove();
540           });
541
542         var sortImage = createElement("img", "messageSortImage", "sortImage");
543         sortHeader.insertBefore(sortImage, sortHeader.firstChild);
544         if (sorting["ascending"])
545           sortImage.src = ResourcesURL + "/title_sortdown_12x12.png";
546         else
547           sortImage.src = ResourcesURL + "/title_sortup_12x12.png";
548       }
549     }
550   }
551   else {
552     var data = http.responseText;
553     var msg = data.replace(/^(.*\n)*.*<p>((.*\n)*.*)<\/p>(.*\n)*.*$/, "$2");
554     log("messageListCallback: problem during ajax request (readyState = " + http.readyState + ", status = " + http.status + ", response = " + msg + ")");
555   }
556 }
557
558 function quotasCallback(http) {
559   if (http.readyState == 4
560       && http.status == 200) {
561     var hasQuotas = false;
562
563     if (http.responseText.length > 0) {
564       var quotas = http.responseText.evalJSON(true);
565       for (var i in quotas) {
566         hasQuotas = true;
567         break;
568       }
569     }
570     
571     if (hasQuotas) {
572       var treePath = Mailer.currentMailbox.split("/");
573       var quotasMB = new Array();
574       for (var i = 2; i < treePath.length; i++)
575         quotasMB.push(treePath[i].substr(6));
576       var mbQuotas = quotas["/" + quotasMB.join("/")];
577       var used = mbQuotas["usedSpace"];
578       var max = mbQuotas["maxQuota"];
579       var percents = (Math.round(used * 10000 / max) / 100);
580       var format = labels["quotasFormat"];
581       var text = format.formatted(used, max, percents);
582       window.status = text;
583     }
584   }
585 }
586
587 function onMessageContextMenu(event) {
588   var menu = $('messageListMenu');
589   var topNode = $('messageList');
590   var selectedNodes = topNode.getSelectedRows();
591
592   Event.observe(menu, "hideMenu", onMessageContextMenuHide);
593   
594   if (selectedNodes.length > 1)
595     popupMenu(event, "messagesListMenu", selectedNodes);
596   else
597     popupMenu(event, "messageListMenu", this);    
598 }
599
600 function onMessageContextMenuHide(event) {
601   var topNode = $('messageList');
602
603   if (topNode.menuSelectedEntry) {
604     topNode.menuSelectedEntry.deselect();
605     topNode.menuSelectedEntry = null;
606   }
607   if (topNode.menuSelectedRows) {
608     var nodes = topNode.menuSelectedRows;
609     for (var i = 0; i < nodes.length; i++)
610       nodes[i].select();
611     topNode.menuSelectedRows = null;
612   }
613 }
614
615 function onFolderMenuClick(event) {
616   var onhide, menuName;
617    
618   var menutype = this.parentNode.getAttribute("datatype");
619   if (menutype) {
620     if (menutype == "inbox") {
621       menuName = "inboxIconMenu";
622     } else if (menutype == "account") {
623       menuName = "accountIconMenu";
624     } else if (menutype == "trash") {
625       menuName = "trashIconMenu";
626     } else {
627       menuName = "mailboxIconMenu";
628     }
629   } else {
630     menuName = "mailboxIconMenu";
631   }
632
633   var menu = $(menuName);
634   Event.observe(menu, "hideMenu", onFolderMenuHide);
635   popupMenu(event, menuName, this.parentNode);
636
637   var topNode = $("mailboxTree");
638   if (topNode.selectedEntry)
639     topNode.selectedEntry.deselect();
640   if (topNode.menuSelectedEntry)
641     topNode.menuSelectedEntry.deselect();
642   topNode.menuSelectedEntry = this;
643   this.select();
644
645   preventDefault(event);
646 }
647
648 function onFolderMenuHide(event) {
649   var topNode = $("mailboxTree");
650
651   if (topNode.menuSelectedEntry) {
652     topNode.menuSelectedEntry.deselect();
653     topNode.menuSelectedEntry = null;
654   }
655   if (topNode.selectedEntry)
656     topNode.selectedEntry.select();
657 }
658
659 function deleteCachedMessage(messageId) {
660   var done = false;
661   var counter = 0;
662
663   while (counter < Mailer.cachedMessages.length
664          && !done)
665     if (Mailer.cachedMessages[counter]
666         && Mailer.cachedMessages[counter]['idx'] == messageId) {
667       Mailer.cachedMessages.splice(counter, 1);
668       done = true;
669     }
670     else
671       counter++;
672 }
673
674 function getCachedMessage(idx) {
675   var message = null;
676   var counter = 0;
677
678   while (counter < Mailer.cachedMessages.length
679          && message == null)
680     if (Mailer.cachedMessages[counter]
681         && Mailer.cachedMessages[counter]['idx'] == Mailer.currentMailbox + '/' + idx)
682       message = Mailer.cachedMessages[counter];
683     else
684       counter++;
685
686   return message;
687 }
688
689 function storeCachedMessage(cachedMessage) {
690   var oldest = -1;
691   var timeOldest = -1;
692   var counter = 0;
693
694   if (Mailer.cachedMessages.length < Mailer.maxCachedMessages)
695     oldest = Mailer.cachedMessages.length;
696   else {
697     while (Mailer.cachedMessages[counter]) {
698       if (oldest == -1
699           || Mailer.cachedMessages[counter]['time'] < timeOldest) {
700         oldest = counter;
701         timeOldest = Mailer.cachedMessages[counter]['time'];
702       }
703       counter++;
704     }
705
706     if (oldest == -1)
707       oldest = 0;
708   }
709
710   Mailer.cachedMessages[oldest] = cachedMessage;
711 }
712
713 function onMessageSelectionChange() {
714   var rows = this.getSelectedRowsId();
715
716   if (rows.length == 1) {
717     var idx = rows[0].substr(4);
718
719     if (Mailer.currentMessages[Mailer.currentMailbox] != idx) {
720       Mailer.currentMessages[Mailer.currentMailbox] = idx;
721       loadMessage(idx);
722     }
723   }
724 }
725
726 function loadMessage(idx) {
727   if (document.messageAjaxRequest) {
728     document.messageAjaxRequest.aborted = true;
729     document.messageAjaxRequest.abort();
730   }
731
732   var cachedMessage = getCachedMessage(idx);
733
734   markMailInWindow(window, idx, true);
735   if (cachedMessage == null) {
736     var url = (ApplicationBaseURL + Mailer.currentMailbox + "/"
737                + idx + "/view?noframe=1");
738     document.messageAjaxRequest
739       = triggerAjaxRequest(url, messageCallback, idx);
740   } else {
741     var div = $('messageContent');
742     div.update(cachedMessage['text']);
743     cachedMessage['time'] = (new Date()).getTime();
744     document.messageAjaxRequest = null;
745     configureLinksInMessage();
746     resizeMailContent();
747   }
748 }
749
750 function configureLinksInMessage() {
751   var messageDiv = $('messageContent');
752   var mailContentDiv = document.getElementsByClassName('mailer_mailcontent',
753                                                        messageDiv)[0];
754   if (!document.body.hasClassName("popup"))
755     mailContentDiv.observe("contextmenu", onMessageContentMenu);
756
757   var anchors = messageDiv.getElementsByTagName('a');
758   for (var i = 0; i < anchors.length; i++)
759     if (anchors[i].href.substring(0,7) == "mailto:") {
760       $(anchors[i]).observe("click", onEmailTo);
761       $(anchors[i]).observe("contextmenu", onEmailAddressClick);
762     }
763     else
764       $(anchors[i]).observe("click", onMessageAnchorClick);
765
766   var images = messageDiv.getElementsByTagName('img');
767   for (var i = 0; i < images.length; i++)
768     $(images[i]).observe("contextmenu", onImageClick);
769
770   var editDraftButton = $("editDraftButton");
771   if (editDraftButton)
772     Event.observe(editDraftButton, "click",
773                   onMessageEditDraft.bindAsEventListener(editDraftButton));
774
775   configureiCalLinksInMessage();
776 }
777
778 function configureiCalLinksInMessage() {
779   var buttons = { "iCalendarAccept": "accept",
780                   "iCalendarDecline": "decline",
781                   "iCalendarTentative": "tentative",
782                   "iCalendarUpdateUserStatus": "updateUserStatus",
783                   "iCalendarAddToCalendar": "addToCalendar",
784                   "iCalendarDeleteFromCalendar": "deleteFromCalendar" };
785
786   for (var key in buttons) {
787     var button = $(key);
788     if (button) {
789       button.action = buttons[key];
790       Event.observe(button, "click",
791                     onICalendarButtonClick.bindAsEventListener(button));
792     }
793   }
794 }
795
796 function onICalendarButtonClick(event) {
797   var link = $("iCalendarAttachment").value;
798   if (link) {
799     var urlstr = link + "/" + this.action;
800     triggerAjaxRequest(urlstr, ICalendarButtonCallback,
801                        Mailer.currentMailbox + "/"
802                        + Mailer.currentMessages[Mailer.currentMailbox]);
803   }
804   else
805     log("no link");
806 }
807
808 function ICalendarButtonCallback(http) {
809   if (http.readyState == 4)
810     if (isHttpStatus204(http.status)) {
811       var oldMsg = http.callbackData;
812       var msg = Mailer.currentMailbox + "/" + Mailer.currentMessages[Mailer.currentMailbox];
813       if (oldMsg == msg) {
814         deleteCachedMessage(oldMsg);
815         loadMessage(Mailer.currentMessages[Mailer.currentMailbox]);
816       }
817     }
818     else {
819       window.alert("received code: " + http.status);
820     }
821 }
822
823 function resizeMailContent() {
824   var headerTable = document.getElementsByClassName('mailer_fieldtable')[0];
825   var contentDiv = document.getElementsByClassName('mailer_mailcontent')[0];
826   
827   contentDiv.setStyle({ 'top':
828         (Element.getHeight(headerTable) + headerTable.offsetTop) + 'px' });
829 }
830
831 function onMessageContentMenu(event) {
832   var element = getTarget(event);
833   if ((element.tagName == 'A' && element.href.substring(0,7) == "mailto:")
834       || element.tagName == 'IMG')
835     // Don't show the default contextual menu; let the click propagate to 
836     // other observers
837     return true;
838   popupMenu(event, 'messageContentMenu', this);
839 }
840
841 function onMessageEditDraft(event) {
842   return openMessageWindowsForSelection("edit", true);
843 }
844
845 function onEmailAddressClick(event) {
846   popupMenu(event, 'addressMenu', this);
847   preventDefault(event);
848   return false;
849 }
850
851 function onMessageAnchorClick(event) {
852   window.open(this.href);
853   preventDefault(event);
854 }
855
856 function onImageClick(event) {
857   popupMenu(event, 'imageMenu', this);
858   preventDefault(event);
859   return false;
860 }
861
862 function messageCallback(http) {
863   var div = $('messageContent');
864
865   if (http.readyState == 4
866       && http.status == 200) {
867     document.messageAjaxRequest = null;
868     div.update(http.responseText);
869     configureLinksInMessage();
870     resizeMailContent();
871     
872     if (http.callbackData) {
873       var cachedMessage = new Array();
874       cachedMessage['idx'] = Mailer.currentMailbox + '/' + http.callbackData;
875       cachedMessage['time'] = (new Date()).getTime();
876       cachedMessage['text'] = http.responseText;
877       if (cachedMessage['text'].length < 30000)
878         storeCachedMessage(cachedMessage);
879     }
880   }
881   else
882     log("messageCallback: problem during ajax request: " + http.status);
883 }
884
885 function processMailboxMenuAction(mailbox) {
886   var currentNode, upperNode;
887   var mailboxName;
888   var action;
889
890   mailboxName = mailbox.getAttribute('mailboxname');
891   currentNode = mailbox;
892   upperNode = null;
893
894   while (currentNode
895          && !currentNode.hasAttribute('mailboxaction'))
896     currentNode = currentNode.parentNode.parentNode.parentMenuItem;
897
898   if (currentNode)
899     {
900       action = currentNode.getAttribute('mailboxaction');
901       //       var rows  = collectSelectedRows();
902       //       var rString = rows.join(', ');
903       //       alert("performing '" + action + "' on " + rString
904       //             + " to " + mailboxName);
905     }
906 }
907
908 var rowSelectionCount = 0;
909
910 validateControls();
911
912 function showElement(e, shouldShow) {
913   e.style.display = shouldShow ? "" : "none";
914 }
915
916 function enableElement(e, shouldEnable) {
917   if(!e)
918     return;
919   if(shouldEnable) {
920     if(e.hasAttribute("disabled"))
921       e.removeAttribute("disabled");
922   }
923   else {
924     e.setAttribute("disabled", "1");
925   }
926 }
927
928 function validateControls() {
929   var e = $("moveto");
930   this.enableElement(e, rowSelectionCount > 0);
931 }
932
933 function moveTo(uri) {
934   alert("MoveTo: " + uri);
935 }
936
937 /* message menu entries */
938 function onMenuOpenMessage(event) {
939   return openMessageWindowsForSelection('popupview');
940 }
941
942 function onMenuReplyToSender(event) {
943   return openMessageWindowsForSelection('reply');
944 }
945
946 function onMenuReplyToAll(event) {
947   return openMessageWindowsForSelection('replyall');
948 }
949
950 function onMenuForwardMessage(event) {
951   return openMessageWindowsForSelection('forward');
952 }
953
954 function onMenuViewMessageSource(event) {
955   var messageList = $("messageList");
956   var rows = messageList.getSelectedRowsId();
957
958   if (rows.length > 0) {
959     var url = (ApplicationBaseURL + Mailer.currentMailbox + "/"
960                + rows[0].substr(4) + "/viewsource");
961     openMailComposeWindow(url);
962   }
963
964   preventDefault(event);
965 }
966
967 function viewImage(event) {
968   var img = document.menuTarget;
969   window.open(img.getAttribute("src"),'_blank','resizable=1'); 
970 }
971
972 /* contacts */
973 function newContactFromEmail(event) {
974   var mailto = document.menuTarget.innerHTML;
975
976   var email = extractEmailAddress(mailto);
977   var c_name = extractEmailName(mailto);
978   if (email.length > 0)
979     {
980       var url = UserFolderURL + "Contacts/new?contactEmail=" + email;
981       if (c_name)
982         url += "&contactFN=" + c_name;
983       openContactWindow(url);
984     }
985
986   return false; /* stop following the link */
987 }
988
989 function onEmailTo(event) {
990   openMailTo(this.innerHTML.strip());
991   preventDefault(event);
992   return false;
993 }
994
995 function newEmailTo(sender) {
996   return openMailTo(document.menuTarget.innerHTML);
997 }
998
999 function expandUpperTree(node) {
1000   var currentNode = node.parentNode;
1001
1002   while (currentNode.className != "dtree") {
1003     if (currentNode.className == 'clip') {
1004       var id = currentNode.getAttribute("id");
1005       var number = parseInt(id.substr(2));
1006       if (number > 0) {
1007         var cn = mailboxTree.aNodes[number];
1008         mailboxTree.nodeStatus(1, number, cn._ls);
1009       }
1010     }
1011     currentNode = currentNode.parentNode;
1012   }
1013 }
1014
1015 function onHeaderClick(event) {
1016   var headerId = this.getAttribute("id");
1017   var newSortAttribute;
1018   if (headerId == "subjectHeader")
1019     newSortAttribute = "subject";
1020   else if (headerId == "fromHeader")
1021     newSortAttribute = "from";
1022   else if (headerId == "dateHeader")
1023     newSortAttribute = "date";
1024   else
1025     newSortAttribute = "arrival";
1026
1027   if (sorting["attribute"] == newSortAttribute)
1028     sorting["ascending"] = !sorting["ascending"];
1029   else {
1030     sorting["attribute"] = newSortAttribute;
1031     sorting["ascending"] = true;
1032   }
1033   refreshCurrentFolder();
1034   
1035   Event.stop(event);
1036 }
1037
1038 function refreshCurrentFolder() {
1039   openMailbox(Mailer.currentMailbox, true);
1040 }
1041
1042 function refreshFolderByType(type) {
1043   if (Mailer.currentMailboxType == type)
1044     refreshCurrentFolder();
1045 }
1046
1047 var mailboxSpanAcceptType = function(type) {
1048   return (type == "mailRow");
1049 }
1050
1051 var mailboxSpanEnter = function() {
1052   this.addClassName("_dragOver");
1053 }
1054
1055 var mailboxSpanExit = function() {
1056   this.removeClassName("_dragOver");
1057 }
1058
1059 var mailboxSpanDrop = function(data) {
1060   var success = false;
1061
1062   if (data) {
1063     var folder = this.parentNode.parentNode.getAttribute("dataname");
1064     if (folder != Mailer.currentMailbox)
1065       success = (moveMessages(data, folder) == 0);
1066   }
1067   else
1068     success = false;
1069
1070   return success;
1071 }
1072
1073 var plusSignEnter = function() {
1074   var nodeNr = parseInt(this.id.substr(2));
1075   if (!mailboxTree.aNodes[nodeNr]._io)
1076     this.plusSignTimer = setTimeout("openPlusSign('" + nodeNr + "');", 1000);
1077 }
1078
1079 var plusSignExit = function() {
1080   if (this.plusSignTimer) {
1081     clearTimeout(this.plusSignTimer);
1082     this.plusSignTimer = null;
1083   }
1084 }
1085         
1086 function openPlusSign(nodeNr) {
1087   mailboxTree.nodeStatus(1, nodeNr, mailboxTree.aNodes[nodeNr]._ls);
1088   mailboxTree.aNodes[nodeNr]._io = 1;
1089   this.plusSignTimer = null;
1090 }
1091
1092 var messageListGhost = function () {
1093   var newDiv = document.createElement("div");
1094   //   newDiv.style.width = "25px;";
1095   //   newDiv.style.height = "25px;";
1096   newDiv.style.backgroundColor = "#aae;";
1097   newDiv.style.border = "2px solid #a3a;";
1098   newDiv.style.padding = "5px;";
1099   newDiv.ghostOffsetX = 10;
1100   newDiv.ghostOffsetY = 5;
1101
1102   var newImg = document.createElement("img");
1103   newImg.src = ResourcesURL + "/message-mail.png";
1104
1105   var list = $("messageList");
1106   var count = list.getSelectedRows().length;
1107   newDiv.appendChild(newImg);
1108   newDiv.appendChild(document.createElement("br"));
1109   newDiv.appendChild(document.createTextNode(count + " messages..."));
1110
1111   return newDiv;
1112 }
1113
1114 var messageListData = function(type) {
1115   var rows = this.parentNode.parentNode.getSelectedRowsId();
1116   var msgIds = new Array();
1117   for (var i = 0; i < rows.length; i++)
1118     msgIds.push(rows[i].substr(4));
1119
1120   return msgIds;
1121 }
1122
1123 /* a model for a futur refactoring of the sortable table headers mechanism */
1124 function configureMessageListEvents(table) {
1125   if (table) {
1126     table.multiselect = true;
1127     // Each body row can load a message
1128     Event.observe(table, "mousedown",
1129                   onMessageSelectionChange.bindAsEventListener(table));    
1130     // Sortable columns
1131     configureSortableTableHeaders(table);
1132   }
1133 }
1134
1135 function configureMessageListBodyEvents(table) {
1136   if (table) {
1137     // Page navigation
1138     var cell = table.tHead.rows[1].cells[0];
1139     if ($(cell).hasClassName("tbtv_navcell")) {
1140       var anchors = $(cell).childNodesWithTag("a");
1141       for (var i = 0; i < anchors.length; i++)
1142         Event.observe(anchors[i], "click", openMailboxAtIndex.bindAsEventListener(anchors[i]));
1143     }
1144
1145     rows = table.tBodies[0].rows;
1146     for (var i = 0; i < rows.length; i++) {
1147       Event.observe(rows[i], "mousedown", onRowClick);
1148       Event.observe(rows[i], "selectstart", listRowMouseDownHandler);
1149       Event.observe(rows[i], "contextmenu", onMessageContextMenu.bindAsEventListener(rows[i]));
1150       
1151       rows[i].dndTypes = function() { return new Array("mailRow"); };
1152       rows[i].dndGhost = messageListGhost;
1153       rows[i].dndDataForType = messageListData;
1154 //       document.DNDManager.registerSource(rows[i]);
1155
1156       for (var j = 0; j < rows[i].cells.length; j++) {
1157         var cell = rows[i].cells[j];
1158         Event.observe(cell, "mousedown", listRowMouseDownHandler);
1159         if (j == 2 || j == 3 || j == 5)
1160           Event.observe(cell, "dblclick", onMessageDoubleClick.bindAsEventListener(cell));
1161         else if (j == 4) {
1162           var img = cell.childNodesWithTag("img")[0];
1163           Event.observe(img, "click", mailListMarkMessage.bindAsEventListener(img));
1164         }
1165       }
1166     }
1167   }
1168 }
1169
1170 function configureDragHandles() {
1171   var handle = $("verticalDragHandle");
1172   if (handle) {
1173     handle.addInterface(SOGoDragHandlesInterface);
1174     handle.leftMargin = 1;
1175     handle.leftBlock=$("leftPanel");
1176     handle.rightBlock=$("rightPanel");
1177   }
1178
1179   handle = $("rightDragHandle");
1180   if (handle) {
1181     handle.addInterface(SOGoDragHandlesInterface);
1182     handle.upperBlock=$("mailboxContent");
1183     handle.lowerBlock=$("messageContent");
1184   }
1185 }
1186
1187 /* dnd */
1188 function initDnd() {
1189   //   log("MailerUI initDnd");
1190
1191   var tree = $("mailboxTree");
1192   if (tree) {
1193     var images = tree.getElementsByTagName("img");
1194     for (var i = 0; i < images.length; i++) {
1195       if (images[i].id[0] == 'j') {
1196         images[i].dndAcceptType = mailboxSpanAcceptType;
1197         images[i].dndEnter = plusSignEnter;
1198         images[i].dndExit = plusSignExit;
1199         document.DNDManager.registerDestination(images[i]);
1200       }
1201     }
1202     var nodes = document.getElementsByClassName("nodeName", tree);
1203     for (var i = 0; i < nodes.length; i++) {
1204       nodes[i].dndAcceptType = mailboxSpanAcceptType;
1205       nodes[i].dndEnter = mailboxSpanEnter;
1206       nodes[i].dndExit = mailboxSpanExit;
1207       nodes[i].dndDrop = mailboxSpanDrop;
1208       document.DNDManager.registerDestination(nodes[i]);
1209     }
1210   }
1211 }
1212
1213 /* stub */
1214
1215 function refreshContacts() {
1216 }
1217
1218 function openInbox(node) {
1219   var done = false;
1220   openMailbox(node.parentNode.getAttribute("dataname"));
1221   var tree = $("mailboxTree");
1222   tree.selectedEntry = node;
1223   node.select();
1224   mailboxTree.o(1);
1225 }
1226
1227 function initMailer(event) {
1228   if (!$(document.body).hasClassName("popup")) {
1229 //     initDnd();
1230     initMailboxTree();
1231     initMessageCheckTimer();
1232   }
1233
1234   // Default sort options
1235   sorting["attribute"] = "date";
1236   sorting["ascending"] = false;
1237 }
1238
1239 function initMessageCheckTimer() {
1240   var messageCheck = userDefaults["MessageCheck"];
1241   if (messageCheck && messageCheck != "manually") {
1242     var interval;
1243     if (messageCheck == "once_per_hour")
1244       interval = 3600;
1245     else if (messageCheck == "every_minute")
1246       interval = 60;
1247     else {
1248       interval = parseInt(messageCheck.substr(6)) * 60;
1249     }
1250     messageCheckTimer = window.setInterval(onMessageCheckCallback,
1251                                            interval * 1000);
1252   }
1253 }
1254
1255 function onMessageCheckCallback(event) {
1256   refreshMailbox();
1257 }
1258
1259 function initMailboxTree() {
1260   mailboxTree = new dTree("mailboxTree");
1261   mailboxTree.config.folderLinks = true;
1262   mailboxTree.config.hideRoot = true;
1263
1264   mailboxTree.icon.root = ResourcesURL + "/tbtv_account_17x17.gif";
1265   mailboxTree.icon.folder = ResourcesURL + "/tbtv_leaf_corner_17x17.gif";
1266   mailboxTree.icon.folderOpen   = ResourcesURL + "/tbtv_leaf_corner_17x17.gif";
1267   mailboxTree.icon.node = ResourcesURL + "/tbtv_leaf_corner_17x17.gif";
1268   mailboxTree.icon.line = ResourcesURL + "/tbtv_line_17x17.gif";
1269   mailboxTree.icon.join = ResourcesURL + "/tbtv_junction_17x17.gif";
1270   mailboxTree.icon.joinBottom   = ResourcesURL + "/tbtv_corner_17x17.gif";
1271   mailboxTree.icon.plus = ResourcesURL + "/tbtv_plus_17x17.gif";
1272   mailboxTree.icon.plusBottom   = ResourcesURL + "/tbtv_corner_plus_17x17.gif";
1273   mailboxTree.icon.minus = ResourcesURL + "/tbtv_minus_17x17.gif";
1274   mailboxTree.icon.minusBottom = ResourcesURL + "/tbtv_corner_minus_17x17.gif";
1275   mailboxTree.icon.nlPlus = ResourcesURL + "/tbtv_corner_plus_17x17.gif";
1276   mailboxTree.icon.nlMinus = ResourcesURL + "/tbtv_corner_minus_17x17.gif";
1277   mailboxTree.icon.empty = ResourcesURL + "/empty.gif";
1278
1279   mailboxTree.add(0, -1, '');
1280
1281   mailboxTree.pendingRequests = mailAccounts.length;
1282   activeAjaxRequests += mailAccounts.length;
1283   for (var i = 0; i < mailAccounts.length; i++) {
1284     var url = ApplicationBaseURL + mailAccounts[i] + "/mailboxes";
1285     triggerAjaxRequest(url, onLoadMailboxesCallback, mailAccounts[i]);
1286   }
1287 }
1288
1289 function updateMailboxTreeInPage() {
1290   $("folderTreeContent").update(mailboxTree);
1291
1292   var inboxFound = false;
1293   var tree = $("mailboxTree");
1294   var nodes = document.getElementsByClassName("node", tree);
1295   for (i = 0; i < nodes.length; i++) {
1296     Event.observe(nodes[i], "click",
1297                   onMailboxTreeItemClick.bindAsEventListener(nodes[i]));
1298     Event.observe(nodes[i], "contextmenu",
1299                   onFolderMenuClick.bindAsEventListener(nodes[i]));
1300     if (!inboxFound
1301         && nodes[i].parentNode.getAttribute("datatype") == "inbox") {
1302       Mailer.currentMailboxType = "inbox";
1303       openInbox(nodes[i]);
1304       inboxFound = true;
1305     }
1306   }
1307 }
1308
1309 function mailboxMenuNode(type, name) {
1310   var newNode = document.createElement("li");
1311   var icon = MailerUIdTreeExtension.folderIcons[type];
1312   if (!icon)
1313     icon = "tbtv_leaf_corner_17x17.gif";
1314   var image = document.createElement("img");
1315   image.src = ResourcesURL + "/" + icon;
1316   newNode.appendChild(image);
1317   var displayName = MailerUIdTreeExtension.folderNames[type];
1318   if (!displayName)
1319     displayName = name;
1320   newNode.appendChild(document.createTextNode(" " + displayName));
1321
1322   return newNode;
1323 }
1324
1325 function generateMenuForMailbox(mailbox, prefix, callback) {
1326   var menuDIV = document.createElement("div");
1327   $(menuDIV).addClassName("menu");
1328   menuDIV.setAttribute("id", prefix + "Submenu");
1329   var menu = document.createElement("ul");
1330   menuDIV.appendChild(menu);
1331   pageContent.appendChild(menuDIV);
1332
1333   var callbacks = new Array();
1334   if (mailbox.type != "account") {
1335     var newNode = document.createElement("li");
1336     newNode.mailbox = mailbox;
1337     newNode.appendChild(document.createTextNode(labels["This Folder"]));
1338     menu.appendChild(newNode);
1339     menu.appendChild(document.createElement("li"));
1340     callbacks.push(callback);
1341     callbacks.push("-");
1342   }
1343
1344   var submenuCount = 0;
1345   for (var i = 0; i < mailbox.children.length; i++) {
1346     var child = mailbox.children[i];
1347     var newNode = mailboxMenuNode(child.type, child.name);
1348     menu.appendChild(newNode);
1349     if (child.children.length > 0) {
1350       var newPrefix = prefix + submenuCount;
1351       var newSubmenuId = generateMenuForMailbox(child, newPrefix, callback);
1352       callbacks.push(newSubmenuId);
1353       submenuCount++;
1354     }
1355     else {
1356       newNode.mailbox = child;
1357       callbacks.push(callback);
1358     }
1359   }
1360   initMenu(menuDIV, callbacks);
1361
1362   return menuDIV.getAttribute("id");
1363 }
1364
1365 function updateMailboxMenus() {
1366   var mailboxActions = { move: onMailboxMenuMove,
1367                          copy: onMailboxMenuCopy };
1368
1369   for (key in mailboxActions) {
1370     var menuId = key + "MailboxMenu";
1371     var menuDIV = $(menuId);
1372     if (menuDIV)
1373       menuDIV.parentNode.removeChild(menuDIV);
1374
1375     menuDIV = document.createElement("div");
1376     pageContent = $("pageContent");
1377     pageContent.appendChild(menuDIV);
1378
1379     var menu = document.createElement("ul");
1380     menuDIV.appendChild(menu);
1381
1382     $(menuDIV).addClassName("menu");
1383     menuDIV.setAttribute("id", menuId);
1384
1385     var submenuIds = new Array();
1386     for (var i = 0; i < mailAccounts.length; i++) {
1387       var menuEntry = mailboxMenuNode("account", mailAccounts[i]);
1388       menu.appendChild(menuEntry);
1389       var mailbox = accounts[mailAccounts[i]];
1390       var newSubmenuId = generateMenuForMailbox(mailbox,
1391                                                 key, mailboxActions[key]);
1392       submenuIds.push(newSubmenuId);
1393     }
1394     initMenu(menuDIV, submenuIds);
1395   }
1396 }
1397
1398 function onLoadMailboxesCallback(http) {
1399   if (http.readyState == 4
1400       && http.status == 200) {
1401     checkAjaxRequestsState();
1402     if (http.responseText.length > 0) {
1403       var newAccount = buildMailboxes(http.callbackData,
1404                                       http.responseText);
1405       accounts[http.callbackData] = newAccount;
1406       mailboxTree.addMailAccount(newAccount);
1407       mailboxTree.pendingRequests--;
1408       activeAjaxRequests--;
1409       if (!mailboxTree.pendingRequests) {
1410         updateMailboxTreeInPage();
1411         updateMailboxMenus();
1412         checkAjaxRequestsState();
1413       }
1414     }
1415   }
1416
1417   //       var tree = $("mailboxTree");
1418   //       var treeNodes = document.getElementsByClassName("dTreeNode", tree);
1419   //       var i = 0;
1420   //       while (i < treeNodes.length
1421   //         && treeNodes[i].getAttribute("dataname") != Mailer.currentMailbox)
1422   //     i++;
1423   //       if (i < treeNodes.length) {
1424   //     //     log("found mailbox");
1425   //     var links = document.getElementsByClassName("node", treeNodes[i]);
1426   //     if (tree.selectedEntry)
1427   //        tree.selectedEntry.deselect();
1428   //     links[0].select();
1429   //     tree.selectedEntry = links[0];
1430   //     expandUpperTree(links[0]);
1431   //       }
1432 }
1433
1434 function buildMailboxes(accountName, encoded) {
1435   var account = new Mailbox("account", accountName);
1436   var data = encoded.evalJSON(true);
1437   for (var i = 0; i < data.length; i++) {
1438     var currentNode = account;
1439     var names = data[i].path.split("/");
1440     for (var j = 1; j < (names.length - 1); j++) {
1441       var node = currentNode.findMailboxByName(names[j]);
1442       if (!node) {
1443         node = new Mailbox("additional", names[j]);
1444         currentNode.addMailbox(node);
1445       }
1446       currentNode = node;
1447     }
1448     var basename = names[names.length-1];
1449     var leaf = currentNode.findMailboxByName(basename);
1450     if (leaf)
1451       leaf.type = data[i].type;
1452     else {
1453       leaf = new Mailbox(data[i].type, basename);
1454       currentNode.addMailbox(leaf);
1455     }
1456   }
1457
1458   return account;
1459 }
1460
1461 function onMenuCreateFolder(event) {
1462   var name = window.prompt(labels["Name :"], "");
1463   if (name && name.length > 0) {
1464     var folderID = document.menuTarget.getAttribute("dataname");
1465     var urlstr = URLForFolderID(folderID) + "/createFolder?name=" + name;
1466     triggerAjaxRequest(urlstr, folderOperationCallback);
1467   }
1468 }
1469
1470 function onMenuRenameFolder(event) {
1471   var name = window.prompt(labels["Enter the new name of your folder :"]
1472                            ,
1473                            "");
1474   if (name && name.length > 0) {
1475     var folderID = document.menuTarget.getAttribute("dataname");
1476     var urlstr = URLForFolderID(folderID) + "/renameFolder?name=" + name;
1477     triggerAjaxRequest(urlstr, folderOperationCallback);
1478   }
1479 }
1480
1481 function onMenuDeleteFolder(event) {
1482   var answer = window.confirm(labels["Do you really want to move this folder into the trash ?"]);
1483   if (answer) {
1484     var folderID = document.menuTarget.getAttribute("dataname");
1485     var urlstr = URLForFolderID(folderID) + "/deleteFolder";
1486     triggerAjaxRequest(urlstr, folderOperationCallback);
1487   }
1488 }
1489
1490 function onMenuExpungeFolder(event) {
1491   var folderID = document.menuTarget.getAttribute("dataname");
1492   var urlstr = URLForFolderID(folderID) + "/expunge";
1493   triggerAjaxRequest(urlstr, folderRefreshCallback, folderID);
1494 }
1495
1496 function onMenuEmptyTrash(event) {
1497   var folderID = document.menuTarget.getAttribute("dataname");
1498   var urlstr = URLForFolderID(folderID) + "/emptyTrash";
1499   triggerAjaxRequest(urlstr, folderOperationCallback, folderID);
1500
1501   if (folderID == Mailer.currentMailbox) {
1502     var div = $('messageContent');
1503     for (var i = div.childNodes.length - 1; i > -1; i--)
1504       div.removeChild(div.childNodes[i]);
1505     refreshCurrentFolder();
1506   }
1507   var msgID = Mailer.currentMessages[folderID];
1508   if (msgID)
1509     deleteCachedMessage(folderID + "/" + msgID);
1510 }
1511
1512 function _onMenuChangeToXXXFolder(event, folder) {
1513   var type = document.menuTarget.getAttribute("datatype");
1514   if (type == "additional")
1515     window.alert(labels["You need to choose a non-virtual folder!"]);
1516   else {
1517     var folderID = document.menuTarget.getAttribute("dataname");
1518     var urlstr = URLForFolderID(folderID) + "/setAs" + folder + "Folder";
1519     triggerAjaxRequest(urlstr, folderOperationCallback);
1520   }
1521 }
1522
1523 function onMenuChangeToDraftsFolder(event) {
1524   return _onMenuChangeToXXXFolder(event, "Drafts");
1525 }
1526
1527 function onMenuChangeToSentFolder(event) {
1528   return _onMenuChangeToXXXFolder(event, "Sent");
1529 }
1530
1531 function onMenuChangeToTrashFolder(event) {
1532   return _onMenuChangeToXXXFolder(event, "Trash");
1533 }
1534
1535 function onMenuLabelNone() {
1536   var messages = new Array();
1537
1538   if (document.menuTarget.tagName == "DIV")
1539     // Menu called from message content view
1540     messages.push(Mailer.currentMessages[Mailer.currentMailbox]);
1541   else if (Object.isArray(document.menuTarget))
1542     // Menu called from multiple selection in messages list view
1543     $(document.menuTarget).collect(function(row) {
1544         messages.push(row.getAttribute("id").substr(4));
1545       });
1546   else
1547     // Menu called from one selection in messages list view
1548     messages.push(document.menuTarget.getAttribute("id").substr(4));
1549   
1550   var url = ApplicationBaseURL + Mailer.currentMailbox + "/";
1551   messages.each(function(id) {
1552       triggerAjaxRequest(url + id + "/removeAllLabels",
1553                          messageFlagCallback,
1554                          { mailbox: Mailer.currentMailbox, msg: id, label: null } );
1555     });  
1556 }
1557
1558 function _onMenuLabelFlagX(flag) {
1559   var messages = new Hash();
1560
1561   if (document.menuTarget.tagName == "DIV")
1562     // Menu called from message content view
1563     messages.set(Mailer.currentMessages[Mailer.currentMailbox],
1564                  $('tr#row_' + Mailer.currentMessages[Mailer.currentMailbox]).getAttribute("labels"));
1565   else if (Object.isArray(document.menuTarget))
1566     // Menu called from multiple selection in messages list view
1567     $(document.menuTarget).collect(function(row) {
1568         messages.set(row.getAttribute("id").substr(4),
1569                      row.getAttribute("labels"));
1570       });
1571   else
1572     // Menu called from one selection in messages list view
1573     messages.set(document.menuTarget.getAttribute("id").substr(4),
1574                  document.menuTarget.getAttribute("labels"));
1575   
1576   var url = ApplicationBaseURL + Mailer.currentMailbox + "/";
1577   messages.keys().each(function(id) {
1578       var flags = messages.get(id).split(" ");
1579       var operation = "add";
1580       
1581       if (flags.indexOf("label" + flag) > -1)
1582         operation = "remove";
1583
1584       triggerAjaxRequest(url + id + "/" + operation + "Label" + flag,
1585                          messageFlagCallback,
1586                          { mailbox: Mailer.currentMailbox, msg: id,
1587                              label: operation + flag } );
1588     });
1589 }
1590
1591 function onMenuLabelFlag1() {
1592   _onMenuLabelFlagX(1);
1593 }
1594
1595 function onMenuLabelFlag2() {
1596   _onMenuLabelFlagX(2);
1597 }
1598
1599 function onMenuLabelFlag3() {
1600   _onMenuLabelFlagX(3);
1601 }
1602
1603 function onMenuLabelFlag4() {
1604   _onMenuLabelFlagX(4);
1605 }
1606
1607 function onMenuLabelFlag5() {
1608   _onMenuLabelFlagX(5);
1609 }
1610
1611 function folderOperationCallback(http) {
1612   if (http.readyState == 4
1613       && isHttpStatus204(http.status))
1614     initMailboxTree();
1615   else
1616     window.alert(labels["Operation failed"]);
1617 }
1618
1619 function folderRefreshCallback(http) {
1620   if (http.readyState == 4
1621       && isHttpStatus204(http.status)) {
1622     var oldMailbox = http.callbackData;
1623     if (oldMailbox == Mailer.currentMailbox)
1624       refreshCurrentFolder();
1625   }
1626   else
1627     window.alert(labels["Operation failed"]);
1628 }
1629
1630 function messageFlagCallback(http) {
1631   if (http.readyState == 4
1632       && isHttpStatus204(http.status)) {
1633     var data = http.callbackData;
1634     if (data["mailbox"] == Mailer.currentMailbox) {
1635       var row = $("row_" + data["msg"]);
1636       var operation = data["label"];
1637       if (operation) {
1638         var labels = row.getAttribute("labels");
1639         var flags;
1640         if (labels.length > 0)
1641           flags = labels.split(" ");
1642         else
1643           flags = new Array();
1644         if (operation.substr(0, 3) == "add")
1645           flags.push("label" + operation.substr(3));
1646         else {
1647           var flag = "label" + operation.substr(6);
1648           var idx = flags.indexOf(flag);
1649           flags.splice(idx, 1);
1650         }
1651         row.setAttribute("labels", flags.join(" "));
1652       }
1653       else
1654         row.setAttribute("labels", "");
1655     }
1656   }
1657 }
1658
1659 function onLabelMenuPrepareVisibility() {
1660   var messageList = $("messageList");
1661   var flags = {};
1662
1663   if (messageList) {
1664     var rows = messageList.getSelectedRows();
1665     for (var i = 0; i < rows.length; i++) {
1666       $w(rows[i].getAttribute("labels")).each(function(flag) {
1667         flags[flag] = true;
1668         });
1669     }
1670   }
1671
1672   var lis = this.childNodesWithTag("ul")[0].childNodesWithTag("li")
1673   var isFlagged = false;
1674   for (var i = 1; i < 6; i++) {
1675     if (flags["label" + i]) {
1676       isFlagged = true;
1677       lis[1 + i].addClassName("_chosen");
1678     }
1679     else
1680       lis[1 + i].removeClassName("_chosen");
1681   }
1682   if (isFlagged)
1683     lis[0].removeClassName("_chosen");
1684   else
1685     lis[0].addClassName("_chosen");
1686 }
1687
1688 function getMenus() {
1689   var menus = {}
1690   menus["accountIconMenu"] = new Array(null, null, onMenuCreateFolder, null,
1691                                        null, null);
1692   menus["inboxIconMenu"] = new Array(null, null, null, "-", null,
1693                                      onMenuCreateFolder, onMenuExpungeFolder,
1694                                      "-", null,
1695                                      onMenuSharing);
1696   menus["trashIconMenu"] = new Array(null, null, null, "-", null,
1697                                      onMenuCreateFolder, onMenuExpungeFolder,
1698                                      onMenuEmptyTrash, "-", null,
1699                                      onMenuSharing);
1700   menus["mailboxIconMenu"] = new Array(null, null, null, "-", null,
1701                                        onMenuCreateFolder,
1702                                        onMenuRenameFolder,
1703                                        onMenuExpungeFolder,
1704                                        onMenuDeleteFolder,
1705                                        "folderTypeMenu",
1706                                        "-", null,
1707                                        onMenuSharing);
1708   menus["addressMenu"] = new Array(newContactFromEmail, newEmailTo, null);
1709   menus["messageListMenu"] = new Array(onMenuOpenMessage, "-",
1710                                        onMenuReplyToSender,
1711                                        onMenuReplyToAll,
1712                                        onMenuForwardMessage, null,
1713                                        "-", "moveMailboxMenu",
1714                                        "copyMailboxMenu", "label-menu",
1715                                        "mark-menu", "-", null,
1716                                        onMenuViewMessageSource, null,
1717                                        null, onMenuDeleteMessage);
1718   menus["messagesListMenu"] = new Array(onMenuForwardMessage,
1719                                         "-", "moveMailboxMenu",
1720                                        "copyMailboxMenu", "label-menu",
1721                                        "mark-menu", "-",
1722                                         null, null,
1723                                         onMenuDeleteMessage);
1724   menus["imageMenu"] = new Array(viewImage);
1725   menus["messageContentMenu"] = new Array(onMenuReplyToSender,
1726                                           onMenuReplyToAll,
1727                                           onMenuForwardMessage,
1728                                           null, "moveMailboxMenu",
1729                                           "copyMailboxMenu",
1730                                           "-", "label-menu", "mark-menu",
1731                                           "-",
1732                                           null, onMenuViewMessageSource,
1733                                           null, onPrintCurrentMessage,
1734                                           onMenuDeleteMessage);
1735   menus["folderTypeMenu"] = new Array(onMenuChangeToSentFolder,
1736                                       onMenuChangeToDraftsFolder,
1737                                       onMenuChangeToTrashFolder);
1738
1739   menus["label-menu"] = new Array(onMenuLabelNone, "-", onMenuLabelFlag1,
1740                                   onMenuLabelFlag2, onMenuLabelFlag3,
1741                                   onMenuLabelFlag4, onMenuLabelFlag5);
1742   menus["mark-menu"] = new Array(null, null, null, null, "-", null, "-",
1743                                  null, null, null);
1744   menus["searchMenu"] = new Array(setSearchCriteria, setSearchCriteria,
1745                                   setSearchCriteria, setSearchCriteria,
1746                                   setSearchCriteria);
1747   var labelMenu = $("label-menu");
1748   if (labelMenu)
1749     labelMenu.prepareVisibility = onLabelMenuPrepareVisibility;
1750
1751   return menus;
1752 }
1753
1754 FastInit.addOnLoad(initMailer);
1755
1756 function Mailbox(type, name) {
1757   this.type = type;
1758   this.name = name;
1759   this.parentFolder = null;
1760   this.children = new Array();
1761   return this;
1762 }
1763
1764 Mailbox.prototype.dump = function(indent) {
1765   if (!indent)
1766     indent = 0;
1767   log(" ".repeat(indent) + this.name);
1768   for (var i = 0; i < this.children.length; i++) {
1769     this.children[i].dump(indent + 2);
1770   }
1771 }
1772
1773 Mailbox.prototype.fullName = function() {
1774   var fullName = "";
1775
1776   var currentFolder = this;
1777   while (currentFolder.parentFolder) {
1778     fullName = "/folder" + currentFolder.name + fullName;
1779     currentFolder = currentFolder.parentFolder;
1780   }
1781
1782   return "/" + currentFolder.name + fullName;
1783 }
1784
1785 Mailbox.prototype.findMailboxByName = function(name) {
1786   var mailbox = null;
1787
1788   var i = 0;
1789   while (!mailbox && i < this.children.length)
1790     if (this.children[i].name == name)
1791       mailbox = this.children[i];
1792     else
1793       i++;
1794
1795   return mailbox;
1796 }
1797
1798 Mailbox.prototype.addMailbox = function(mailbox) {
1799   mailbox.parentFolder = this;
1800   this.children.push(mailbox);
1801 }