From 111acf180dfacf7f049d4d7b6f93b79560f51fc4 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Sun, 28 Oct 2012 08:35:09 -0400
Subject: [PATCH] Fix error in IE<8

---
 program/js/app.js |  541 ++++++++++++++++++++++++++++++++---------------------
 1 files changed, 325 insertions(+), 216 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index a5c7db4..1aa0082 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -48,7 +48,7 @@
   this.env.request_timeout = 180;  // seconds
   this.env.draft_autosave = 0;     // seconds
   this.env.comm_path = './';
-  this.env.blankpage = 'program/blank.gif';
+  this.env.blankpage = 'program/resources/blank.gif';
 
   // set jQuery ajax options
   $.ajaxSetup({
@@ -57,6 +57,8 @@
     error: function(request, status, err){ ref.http_error(request, status, err); },
     beforeSend: function(xmlhttp){ xmlhttp.setRequestHeader('X-Roundcube-Request', ref.env.request_token); }
   });
+
+  $(window).bind('beforeunload', function() { rcmail.unload = true; });
 
   // set environment variable(s)
   this.set_env = function(p, value)
@@ -174,10 +176,10 @@
     }
 
     // enable general commands
-    this.enable_command('logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', 'about', 'switch-task', true);
+    this.enable_command('close', 'logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', 'about', 'switch-task', true);
 
     if (this.env.permaurl)
-      this.enable_command('permaurl', true);
+      this.enable_command('permaurl', 'extwin', true);
 
     switch (this.task) {
 
@@ -206,7 +208,7 @@
           this.gui_objects.messagelist.parentNode.onmousedown = function(e){ return p.click_on_list(e); };
 
           this.message_list.init();
-          this.enable_command('toggle_status', 'toggle_flag', 'menu-open', 'menu-save', true);
+          this.enable_command('toggle_status', 'toggle_flag', 'menu-open', 'menu-save', 'sort', true);
 
           // load messages
           this.command('list');
@@ -247,7 +249,7 @@
           }
         }
         else if (this.env.action == 'compose') {
-          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses'];
+          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses', 'extwin'];
 
           if (this.env.drafts_mailbox)
             this.env.compose_commands.push('savedraft')
@@ -459,7 +461,7 @@
       this.gui_containers.foldertray = $(this.gui_objects.folderlist);
 
     // activate html5 file drop feature (if browser supports it and if configured)
-    if (this.gui_objects.filedrop && this.env.filedrop && ((XMLHttpRequest && XMLHttpRequest.prototype.sendAsBinary) || window.FormData)) {
+    if (this.gui_objects.filedrop && this.env.filedrop && ((window.XMLHttpRequest && XMLHttpRequest.prototype && XMLHttpRequest.prototype.sendAsBinary) || window.FormData)) {
       $(document.body).bind('dragover dragleave drop', function(e){ return ref.document_drag_hover(e, e.type == 'dragover'); });
       $(this.gui_objects.filedrop).addClass('droptarget')
         .bind('dragover dragleave', function(e){ return ref.file_drag_hover(e, e.type == 'dragover'); })
@@ -568,6 +570,19 @@
           parent.location.href = this.env.permaurl;
         break;
 
+      case 'extwin':
+        if (this.env.action == 'compose') {
+          var prevstate = this.env.compose_extwin;
+          $("input[name='_action']", this.gui_objects.messageform).val('compose');
+          this.gui_objects.messageform.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 });
+          this.gui_objects.messageform.target = this.open_window('', 1150, 900);
+          this.gui_objects.messageform.submit();
+        }
+        else {
+          this.open_window(this.env.permaurl, 1000, 1200);
+        }
+        break;
+
       case 'menu-open':
       case 'menu-save':
         this.triggerEvent(command, {props:props});
@@ -580,10 +595,18 @@
         }
         break;
 
+      case 'close':
+        if (this.env.extwin)
+          window.close();
+        break;
+
       case 'list':
         if (props && props != '')
           this.reset_qsearch();
-        if (this.task == 'mail') {
+        if (this.env.action == 'compose' && this.env.extwin) {
+          window.close();
+        }
+        else if (this.task == 'mail') {
           this.list_mailbox(props);
           this.set_button_titles();
         }
@@ -592,12 +615,11 @@
         break;
 
       case 'sort':
-        var sort_order, sort_col = props;
+        var sort_order = this.env.sort_order,
+          sort_col = !this.env.disabled_sort_col ? props : this.env.sort_col;
 
-        if (this.env.sort_col==sort_col)
-          sort_order = this.env.sort_order=='ASC' ? 'DESC' : 'ASC';
-        else
-          sort_order = 'ASC';
+        if (!this.env.disabled_sort_order)
+          sort_order = this.env.sort_col == sort_col && sort_order == 'ASC' ? 'DESC' : 'ASC';
 
         // set table header and update env
         this.set_list_sorting(sort_col, sort_order);
@@ -639,7 +661,7 @@
           uid = this.get_single_uid();
           if (uid && (!this.env.uid || uid != this.env.uid)) {
             if (this.env.mailbox == this.env.drafts_mailbox)
-              this.goto_url('compose', { _draft_uid: uid, _mbox: this.env.mailbox }, true);
+              this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox });
             else
               this.show_message(uid);
           }
@@ -667,8 +689,8 @@
           this.load_identity(props, 'edit-identity');
         else if (this.task == 'mail' && (cid = this.get_single_uid())) {
           url = { _mbox: this.env.mailbox };
-          url[this.env.mailbox == this.env.drafts_mailbox ? '_draft_uid' : '_uid'] = cid;
-          this.goto_url('compose', url, true);
+          url[this.env.mailbox == this.env.drafts_mailbox && props != 'new' ? '_draft_uid' : '_uid'] = cid;
+          this.open_compose_step(url);
         }
         break;
 
@@ -861,47 +883,46 @@
         break;
 
       case 'compose':
-        url = this.url('mail/compose');
+        url = {};
 
         if (this.task == 'mail') {
-          url += '&_mbox='+urlencode(this.env.mailbox);
+          url._mbox = this.env.mailbox;
           if (props)
-             url += '&_to='+urlencode(props);
+             url._to = props;
           // also send search request so we can go back to search result after message is sent
           if (this.env.search_request)
-            url += '&_search='+this.env.search_request;
+            url._search = this.env.search_request;
         }
         // modify url if we're in addressbook
         else if (this.task == 'addressbook') {
           // switch to mail compose step directly
           if (props && props.indexOf('@') > 0) {
-            url = this.get_task_url('mail', url);
-            this.redirect(url + '&_to='+urlencode(props));
+            url._to = props;
+          }
+          else {
+            // use contact_id passed as command parameter
+            var n, len, a_cids = [];
+            if (props)
+              a_cids.push(props);
+            // get selected contacts
+            else if (this.contact_list) {
+              var selection = this.contact_list.get_selection();
+              for (n=0, len=selection.length; n<len; n++)
+                a_cids.push(selection[n]);
+            }
+
+            if (a_cids.length)
+              this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source }, true);
+            else if (this.env.group)
+              this.http_post('mailto', { _gid: this.env.group, _source: this.env.source }, true);
+
             break;
           }
-
-          // use contact_id passed as command parameter
-          var n, len, a_cids = [];
-          if (props)
-            a_cids.push(props);
-          // get selected contacts
-          else if (this.contact_list) {
-            var selection = this.contact_list.get_selection();
-            for (n=0, len=selection.length; n<len; n++)
-              a_cids.push(selection[n]);
-          }
-
-          if (a_cids.length)
-            this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source}, true);
-          else if (this.env.group)
-            this.http_post('mailto', { _gid: this.env.group, _source: this.env.source}, true);
-
-          break;
         }
         else if (props)
-          url += '&_to='+urlencode(props);
+          url._to = props;
 
-        this.redirect(url);
+        this.open_compose_step(url);
         break;
 
       case 'spellcheck':
@@ -920,14 +941,8 @@
         break;
 
       case 'savedraft':
-        var form = this.gui_objects.messageform, msgid;
-
         // Reset the auto-save timer
         clearTimeout(this.save_timer);
-
-        // saving Drafts is disabled
-        if (!form)
-          break;
 
         // compose form did not change
         if (this.cmp_hash == this.compose_field_hash()) {
@@ -938,35 +953,17 @@
         // re-set keep-alive timeout
         this.start_keepalive();
 
-        msgid = this.set_busy(true, 'savingmessage');
-
-        form.target = "savetarget";
-        form._draft.value = '1';
-        form.action = this.add_url(form.action, '_unlock', msgid);
-        form.submit();
+        this.submit_messageform(true);
         break;
 
       case 'send':
-        if (!this.gui_objects.messageform)
-          break;
-
         if (!props.nocheck && !this.check_compose_input(command))
           break;
 
         // Reset the auto-save timer
         clearTimeout(this.save_timer);
 
-        // all checks passed, send message
-        var lang = this.spellcheck_lang(),
-          form = this.gui_objects.messageform,
-          msgid = this.set_busy(true, 'sendingmessage');
-
-        form.target = 'savetarget';
-        form._draft.value = '';
-        form.action = this.add_url(form.action, '_unlock', msgid);
-        form.action = this.add_url(form.action, '_lang', lang);
-        form.submit();
-
+        this.submit_messageform();
         break;
 
       case 'send-attachment':
@@ -998,9 +995,9 @@
             // do reply-list, when list is detected and popup menu wasn't used 
             url._all = (!props && this.commands['reply-list'] ? 'list' : 'all');
           else if (command == 'reply-list')
-            url._all = list;
+            url._all = 'list';
 
-          this.goto_url('compose', url, true);
+          this.open_compose_step(url);
         }
         break;
 
@@ -1010,7 +1007,7 @@
           url = { _forward_uid: uid, _mbox: this.env.mailbox };
           if (command == 'forward-attachment' || (!props && this.env.forward_attachment))
             url._attachment = 1;
-          this.goto_url('compose', url, true);
+          this.open_compose_step(url);
         }
         break;
 
@@ -1469,29 +1466,21 @@
 
   this.doc_mouse_up = function(e)
   {
-    var model, list, li, id;
+    var model, list, id;
 
     // ignore event if jquery UI dialog is open
     if ($(rcube_event.get_target(e)).closest('.ui-dialog, .ui-widget-overlay').length)
       return;
 
-    if (list = this.message_list) {
-      if (!rcube_mouse_is_over(e, list.list.parentNode))
-        list.blur();
-      else
-        list.focus();
+    if (list = this.message_list)
       model = this.env.mailboxes;
-    }
-    else if (list = this.contact_list) {
-      if (!rcube_mouse_is_over(e, list.list.parentNode))
-        list.blur();
-      else
-        list.focus();
+    else if (list = this.contact_list)
       model = this.env.contactfolders;
-    }
-    else if (this.ksearch_value) {
+    else if (this.ksearch_value)
       this.ksearch_blur();
-    }
+
+    if (list && !rcube_mouse_is_over(e, list.list.parentNode))
+      list.blur();
 
     // handle mouse release when dragging
     if (this.drag_active && model && this.env.last_folder_target) {
@@ -1568,14 +1557,17 @@
     if (list.multi_selecting || !this.env.contentframe)
       return;
 
-    if (list.get_single_selection() && window.frames && window.frames[this.env.contentframe]) {
-      if (window.frames[this.env.contentframe].location.href.indexOf(this.env.blankpage)>=0) {
-        if (this.preview_timer)
-          clearTimeout(this.preview_timer);
-        if (this.preview_read_timer)
-          clearTimeout(this.preview_read_timer);
-        this.preview_timer = setTimeout(function(){ ref.msglist_get_preview(); }, 200);
-      }
+    if (list.get_single_selection())
+      return;
+
+    var win = this.get_frame_window(this.env.contentframe);
+
+    if (win && win.location.href.indexOf(this.env.blankpage)>=0) {
+      if (this.preview_timer)
+        clearTimeout(this.preview_timer);
+      if (this.preview_read_timer)
+        clearTimeout(this.preview_read_timer);
+      this.preview_timer = setTimeout(function(){ ref.msglist_get_preview(); }, 200);
     }
   };
 
@@ -1589,7 +1581,7 @@
 
     var uid = list.get_single_selection();
     if (uid && this.env.mailbox == this.env.drafts_mailbox)
-      this.goto_url('compose', { _draft_uid: uid, _mbox: this.env.mailbox }, true);
+      this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox });
     else if (uid)
       this.show_message(uid, false, false);
   };
@@ -1634,7 +1626,7 @@
     for (i=0; i<cols.length; i++)
       if (cols[i].id && cols[i].id.match(/^rcm/)) {
         name = cols[i].id.replace(/^rcm/, '');
-        this.env.coltypes.push(name == 'to' ? 'from' : name);
+        this.env.coltypes.push(name);
       }
 
     if ((found = $.inArray('flag', this.env.coltypes)) >= 0)
@@ -1669,6 +1661,28 @@
     }
 
     return allow ? (copy ? 2 : 1) : 0;
+  };
+
+  this.open_window = function(url, width, height)
+  {
+    var w = Math.min(width, screen.width - 10),
+      h = Math.min(height, screen.height - 100),
+      l = (screen.width - w) / 2 + (screen.left || 0),
+      t = Math.max(0, (screen.height - h) / 2 + (screen.top || 0) - 20);
+
+    var wname = 'rcmextwin' + new Date().getTime(),
+      extwin = window.open(url + '&_extwin=1', wname, 'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no');
+    extwin.moveTo(l,t);
+
+    // write loading... message to empty windows
+    if (!url && extwin.document) {
+      extwin.document.write('<html><body>' + this.get_label('loading') + '</body></html>');
+    }
+
+    // focus window, delayed to bring to front
+    window.setTimeout(function(){ extwin.focus(); }, 10);
+
+    return wname;
   };
 
 
@@ -1827,7 +1841,7 @@
         html = '<span id="flagicn'+uid+'" class="'+css_class+'">&nbsp;</span>';
       }
       else if (c == 'attachment') {
-        if (/application\/|multipart\/m/.test(flags.ctype))
+        if (/application\/|multipart\/(m|signed)/.test(flags.ctype))
           html = '<span class="attachment">&nbsp;</span>';
         else if (/multipart\/report/.test(flags.ctype))
           html = '<span class="report">&nbsp;</span>';
@@ -1913,7 +1927,7 @@
       // make sure new columns are added at the end of the list
       var i, idx, name, newcols = [], oldcols = this.env.coltypes;
       for (i=0; i<oldcols.length; i++) {
-        name = oldcols[i] == 'to' ? 'from' : oldcols[i];
+        name = oldcols[i];
         idx = $.inArray(name, cols);
         if (idx != -1) {
           newcols.push(name);
@@ -1934,18 +1948,18 @@
       this.list_mailbox('', '', sort_col+'_'+sort_order, post_data);
   };
 
-  // when user doble-clicks on a row
+  // when user double-clicks on a row
   this.show_message = function(id, safe, preview)
   {
     if (!id)
       return;
 
-    var target = window,
+    var win, target = window,
       action = preview ? 'preview': 'show',
       url = '&_action='+action+'&_uid='+id+'&_mbox='+urlencode(this.env.mailbox);
 
-    if (preview && this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
-      target = window.frames[this.env.contentframe];
+    if (preview && (win = this.get_frame_window(this.env.contentframe))) {
+      target = win;
       url += '&_framed=1';
     }
 
@@ -1959,10 +1973,17 @@
     // add browser capabilities, so we can properly handle attachments
     url += '&_caps='+urlencode(this.browser_capabilities());
 
-    if (preview && String(target.location.href).indexOf(url) >= 0)
+    if (this.env.extwin)
+      url += '&_extwin=1';
+
+    if (preview && String(target.location.href).indexOf(url) >= 0) {
       this.show_contentframe(true);
+    }
     else {
-      this.location_href(this.env.comm_path+url, target, true);
+      if (!preview && this.env.message_extwin && !this.env.extwin)
+        this.open_window(this.env.comm_path+url, 1000, 1200);
+      else
+        this.location_href(this.env.comm_path+url, target, true);
 
       // mark as read and change mbox unread counter
       if (preview && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read >= 0) {
@@ -1982,18 +2003,35 @@
 
   this.show_contentframe = function(show)
   {
-    var frm, win;
-    if (this.env.contentframe && (frm = $('#'+this.env.contentframe)) && frm.length) {
-      if (!show && (win = window.frames[this.env.contentframe])) {
+    var frame, win, name = this.env.contentframe;
+
+    if (name && (frame = this.get_frame_element(name))) {
+      if (!show && (win = this.get_frame_window(name))) {
         if (win.location && win.location.href.indexOf(this.env.blankpage)<0)
           win.location.href = this.env.blankpage;
       }
       else if (!bw.safari && !bw.konq)
-        frm[show ? 'show' : 'hide']();
-      }
+        $(frame)[show ? 'show' : 'hide']();
+    }
 
     if (!show && this.busy)
       this.set_busy(false, null, this.env.frame_lock);
+  };
+
+  this.get_frame_element = function(id)
+  {
+    var frame;
+
+    if (id && (frame = document.getElementById(id)))
+      return frame;
+  };
+
+  this.get_frame_window = function(id)
+  {
+    var frame = this.get_frame_element(id);
+
+    if (frame && frame.name && window.frames)
+      return window.frames[frame.name];
   };
 
   this.lock_frame = function()
@@ -2039,7 +2077,7 @@
   // list messages of a specific mailbox
   this.list_mailbox = function(mbox, page, sort, url)
   {
-    var target = window;
+    var win, target = window;
 
     if (typeof url != 'object')
       url = {};
@@ -2078,8 +2116,8 @@
       return;
     }
 
-    if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
-      target = window.frames[this.env.contentframe];
+    if (win = this.get_frame_window(this.env.contentframe)) {
+      target = win;
       url._framed = 1;
     }
 
@@ -2457,7 +2495,7 @@
   // set message row status, class and icon
   this.set_message = function(uid, flag, status)
   {
-    var row = this.message_list.rows[uid];
+    var row = this.message_list && this.message_list.rows[uid];
 
     if (!row)
       return false;
@@ -2674,34 +2712,37 @@
   // set a specific flag to one or more messages
   this.mark_message = function(flag, uid)
   {
-    var a_uids = [], r_uids = [], len, n, id,
-      selection = this.message_list ? this.message_list.get_selection() : [];
+    var a_uids = [], r_uids = [], len, n, id, selection,
+      list = this.message_list;
 
     if (uid)
       a_uids[0] = uid;
     else if (this.env.uid)
       a_uids[0] = this.env.uid;
-    else if (this.message_list) {
+    else if (list) {
+      selection = list.get_selection();
       for (n=0, len=selection.length; n<len; n++) {
           a_uids.push(selection[n]);
       }
     }
 
-    if (!this.message_list)
+    if (!list)
       r_uids = a_uids;
-    else
+    else {
+      list.focus();
       for (n=0, len=a_uids.length; n<len; n++) {
         id = a_uids[n];
-        if ((flag=='read' && this.message_list.rows[id].unread) 
-            || (flag=='unread' && !this.message_list.rows[id].unread)
-            || (flag=='delete' && !this.message_list.rows[id].deleted)
-            || (flag=='undelete' && this.message_list.rows[id].deleted)
-            || (flag=='flagged' && !this.message_list.rows[id].flagged)
-            || (flag=='unflagged' && this.message_list.rows[id].flagged))
+        if ((flag=='read' && list.rows[id].unread) 
+            || (flag=='unread' && !list.rows[id].unread)
+            || (flag=='delete' && !list.rows[id].deleted)
+            || (flag=='undelete' && list.rows[id].deleted)
+            || (flag=='flagged' && !list.rows[id].flagged)
+            || (flag=='unflagged' && list.rows[id].flagged))
         {
           r_uids.push(id);
         }
       }
+    }
 
     // nothing to do
     if (!r_uids.length && !this.select_all_mode)
@@ -2970,6 +3011,17 @@
   /*********        message compose methods        *********/
   /*********************************************************/
 
+  this.open_compose_step = function(p)
+  {
+    var url = this.url('mail/compose', p);
+
+    // open new compose window
+    if (this.env.compose_extwin)
+      this.open_window(url, 1150, 900);
+    else
+      this.redirect(url);
+  };
+
   // init message compose form: set focus and eventhandlers
   this.init_messageform = function()
   {
@@ -2983,6 +3035,11 @@
       html_mode = $("input[name='_is_html']").val() == '1',
       ac_fields = ['cc', 'bcc', 'replyto', 'followupto'],
       ac_props;
+
+    // close compose step in opener
+    if (window.opener && opener.rcmail && opener.rcmail.env.action == 'compose') {
+      setTimeout(function(){ opener.history.back(); }, 100);
+    }
 
     // configure parallel autocompletion
     if (this.env.autocomplete_threads > 0) {
@@ -3029,6 +3086,29 @@
 
     obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, props); })
       .attr('autocomplete', 'off');
+  };
+
+  this.submit_messageform = function(draft)
+  {
+    var form = this.gui_objects.messageform;
+
+    if (!form)
+      return;
+
+    // all checks passed, send message
+    var msgid = this.set_busy(true, draft ? 'savingmessage' : 'sendingmessage'),
+      lang = this.spellcheck_lang(),
+      files = [];
+
+    // send files list
+    $('li', this.gui_objects.attachmentlist).each(function() { files.push(this.id.replace(/^rcmfile/, '')); });
+    $('input[name="_attachments"]', form).val(files.join());
+
+    form.target = 'savetarget';
+    form._draft.value = draft ? '1' : '';
+    form.action = this.add_url(form.action, '_unlock', msgid);
+    form.action = this.add_url(form.action, '_lang', lang);
+    form.submit();
   };
 
   this.compose_recipient_select = function(list)
@@ -3297,8 +3377,7 @@
       input_message = $("[name='_message']"),
       message = input_message.val(),
       is_html = ($("input[name='_is_html']").val() == '1'),
-      sig = this.env.identity,
-      sig_separator = this.env.sig_above && (this.env.compose_mode == 'reply' || this.env.compose_mode == 'forward') ? '---' : '-- ';
+      sig = this.env.identity;
 
     // enable manual signature insert
     if (this.env.signatures && this.env.signatures[id]) {
@@ -3311,12 +3390,8 @@
     if (!is_html) {
       // remove the 'old' signature
       if (show_sig && sig && this.env.signatures && this.env.signatures[sig]) {
-
-        sig = this.env.signatures[sig].is_html ? this.env.signatures[sig].plain_text : this.env.signatures[sig].text;
+        sig = this.env.signatures[sig].text;
         sig = sig.replace(/\r\n/g, '\n');
-
-        if (!sig.match(/^--[ -]\n/m))
-          sig = sig_separator + '\n' + sig;
 
         p = this.env.sig_above ? message.indexOf(sig) : message.lastIndexOf(sig);
         if (p >= 0)
@@ -3324,11 +3399,8 @@
       }
       // add the new signature string
       if (show_sig && this.env.signatures && this.env.signatures[id]) {
-        sig = this.env.signatures[id]['is_html'] ? this.env.signatures[id]['plain_text'] : this.env.signatures[id]['text'];
+        sig = this.env.signatures[id].text;
         sig = sig.replace(/\r\n/g, '\n');
-
-        if (!sig.match(/^--[ -]\n/m))
-          sig = sig_separator + '\n' + sig;
 
         if (this.env.sig_above) {
           if (p >= 0) { // in place of removed signature
@@ -3393,21 +3465,8 @@
         }
       }
 
-      if (this.env.signatures[id]) {
-        if (this.env.signatures[id].is_html) {
-          sig = this.env.signatures[id].text;
-          if (!this.env.signatures[id].plain_text.match(/^--[ -]\r?\n/m))
-            sig = sig_separator + '<br />' + sig;
-        }
-        else {
-          sig = this.env.signatures[id].text;
-          if (!sig.match(/^--[ -]\r?\n/m))
-            sig = sig_separator + '\n' + sig;
-          sig = '<pre>' + sig + '</pre>';
-        }
-
-        sigElem.innerHTML = sig;
-      }
+      if (this.env.signatures[id])
+        sigElem.innerHTML = this.env.signatures[id].html;
     }
 
     this.env.identity = id;
@@ -3636,8 +3695,16 @@
   this.sent_successfully = function(type, msg)
   {
     this.display_message(msg, type);
-    // before redirect we need to wait some time for Chrome (#1486177)
-    setTimeout(function(){ ref.list_mailbox(); }, 500);
+
+    if (this.env.extwin && window.opener && opener.rcmail) {
+      this.lock_form(this.gui_objects.messageform);
+      opener.rcmail.display_message(msg, type);
+      setTimeout(function(){ window.close() }, 1000);
+    }
+    else {
+      // before redirect we need to wait some time for Chrome (#1486177)
+      setTimeout(function(){ ref.list_mailbox(); }, 500);
+    }
   };
 
 
@@ -4030,8 +4097,7 @@
 
     // if a group is currently selected, and there is at least one contact selected
     // thend we can enable the group-remove-selected command
-    this.enable_command('group-remove-selected', typeof this.env.group != 'undefined' && list.selection.length > 0);
-
+    this.enable_command('group-remove-selected', this.env.group && list.selection.length > 0);
     this.enable_command('compose', this.env.group || list.selection.length > 0);
     this.enable_command('edit', id && writable);
     this.enable_command('delete', list.selection.length && writable);
@@ -4041,7 +4107,7 @@
 
   this.list_contacts = function(src, group, page)
   {
-    var folder, url = {},
+    var win, folder, url = {},
       target = window;
 
     if (!src)
@@ -4073,8 +4139,8 @@
       return;
     }
 
-    if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
-      target = window.frames[this.env.contentframe];
+    if (win = this.get_frame_window(this.env.contentframe)) {
+      target = win;
       url._framed = 1;
     }
 
@@ -4130,11 +4196,11 @@
   // load contact record
   this.load_contact = function(cid, action, framed)
   {
-    var url = {}, target = window;
+    var win, url = {}, target = window;
 
-    if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
+    if (win = this.get_frame_window(this.env.contentframe)) {
       url._framed = 1;
-      target = window.frames[this.env.contentframe];
+      target = win;
       this.show_contentframe(true);
 
       // load dummy content
@@ -4275,7 +4341,7 @@
     if (!this.gui_objects.contactslist)
       return false;
 
-    var c, list = this.contact_list,
+    var c, col, list = this.contact_list,
       row = document.createElement('tr');
 
     row.id = 'rcmrow'+this.html_identifier(cid);
@@ -4715,11 +4781,11 @@
   {
     if (form && form.elements._photo.value) {
       this.async_upload_form(form, 'upload-photo', function(e) {
-        rcmail.set_busy(false, null, rcmail.photo_upload_id);
+        rcmail.set_busy(false, null, rcmail.file_upload_id);
       });
 
       // display upload indicator
-      this.photo_upload_id = this.set_busy(true, 'uploading');
+      this.file_upload_id = this.set_busy(true, 'uploading');
     }
   };
 
@@ -4734,8 +4800,8 @@
 
   this.photo_upload_end = function()
   {
-    this.set_busy(false, null, this.photo_upload_id);
-    delete this.photo_upload_id;
+    this.set_busy(false, null, this.file_upload_id);
+    delete this.file_upload_id;
   };
 
   this.set_photo_actions = function(id)
@@ -4752,11 +4818,11 @@
   // load advanced search page
   this.advanced_search = function()
   {
-    var url = {_form: 1, _action: 'search'}, target = window;
+    var win, url = {_form: 1, _action: 'search'}, target = window;
 
-    if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
+    if (win = this.get_frame_window(this.env.contentframe)) {
       url._framed = 1;
-      target = window.frames[this.env.contentframe];
+      target = win;
       this.contact_list.clear_selection();
     }
 
@@ -4878,13 +4944,13 @@
   // preferences section select and load options frame
   this.section_select = function(list)
   {
-    var id = list.get_single_selection(), target = window,
+    var win, id = list.get_single_selection(), target = window,
       url = {_action: 'edit-prefs', _section: id};
 
     if (id) {
-      if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
+      if (win = this.get_frame_window(this.env.contentframe)) {
         url._framed = 1;
-        target = window.frames[this.env.contentframe];
+        target = win;
       }
       this.location_href(url, target, true);
     }
@@ -4907,13 +4973,12 @@
     if (action == 'edit-identity' && (!id || id == this.env.iid))
       return false;
 
-    var target = window,
+    var win, target = window,
       url = {_action: action, _iid: id};
 
-    if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
+    if (win = this.get_frame_window(this.env.contentframe)) {
       url._framed = 1;
-      target = window.frames[this.env.contentframe];
-      document.getElementById(this.env.contentframe).style.visibility = 'inherit';
+      target = win;
     }
 
     if (action && (id || action == 'add-identity')) {
@@ -5289,14 +5354,14 @@
   // when user select a folder in manager
   this.show_folder = function(folder, path, force)
   {
-    var target = window,
+    var win, target = window,
       url = '&_action=edit-folder&_mbox='+urlencode(folder);
 
     if (path)
       url += '&_path='+urlencode(path);
 
-    if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
-      target = window.frames[this.env.contentframe];
+    if (win = this.get_frame_window(this.env.contentframe)) {
+      target = win;
       url += '&_framed=1';
     }
 
@@ -5358,13 +5423,6 @@
     }
   };
 
-  // enable/disable buttons for page shifting
-  this.set_page_buttons = function()
-  {
-    this.enable_command('nextpage', 'lastpage', (this.env.pagecount > this.env.current_page));
-    this.enable_command('previouspage', 'firstpage', (this.env.current_page > 1));
-  };
-
   // set event handlers on registered buttons
   this.init_buttons = function()
   {
@@ -5372,7 +5430,7 @@
       if (typeof cmd !== 'string')
         continue;
 
-      for (var i=0; i< this.buttons[cmd].length; i++) {
+      for (var i=0; i<this.buttons[cmd].length; i++) {
         init_button(cmd, this.buttons[cmd][i]);
       }
     }
@@ -5391,28 +5449,31 @@
       button = a_buttons[n];
       obj = document.getElementById(button.id);
 
+      if (!obj)
+        continue;
+
       // get default/passive setting of the button
-      if (obj && button.type == 'image' && !button.status) {
+      if (button.type == 'image' && !button.status) {
         button.pas = obj._original_src ? obj._original_src : obj.src;
         // respect PNG fix on IE browsers
         if (obj.runtimeStyle && obj.runtimeStyle.filter && obj.runtimeStyle.filter.match(/src=['"]([^'"]+)['"]/))
           button.pas = RegExp.$1;
       }
-      else if (obj && !button.status)
+      else if (!button.status)
         button.pas = String(obj.className);
 
       // set image according to button state
-      if (obj && button.type == 'image' && button[state]) {
+      if (button.type == 'image' && button[state]) {
         button.status = state;
         obj.src = button[state];
       }
       // set class name according to button state
-      else if (obj && button[state] !== undefined) {
+      else if (button[state] !== undefined) {
         button.status = state;
         obj.className = button[state];
       }
       // disable/enable input buttons
-      if (obj && button.type=='input') {
+      if (button.type == 'input') {
         button.status = state;
         obj.disabled = !state;
       }
@@ -5635,6 +5696,39 @@
     this.messages = {};
   };
 
+  // open a jquery UI dialog with the given content
+  this.show_popup_dialog = function(html, title)
+  {
+    // forward call to parent window
+    if (this.is_framed()) {
+      parent.rcmail.show_popup_dialog(html, title);
+      return;
+    }
+
+    var popup = $('<div class="popup">')
+      .html(html)
+      .dialog({
+        title: title,
+        modal: true,
+        resizable: true,
+        width: 580,
+        close: function(event, ui) { $(this).remove() }
+      });
+
+      // resize and center popup
+      var win = $(window), w = win.width(), h = win.height(),
+        width = popup.width(), height = popup.height();
+      popup.dialog('option', { height: Math.min(h-40, height+50), width: Math.min(w-20, width+50) })
+        .dialog('option', 'position', ['center', 'center']);  // only works in a separate call (!?)
+  };
+
+  // enable/disable buttons for page shifting
+  this.set_page_buttons = function()
+  {
+    this.enable_command('nextpage', 'lastpage', (this.env.pagecount > this.env.current_page));
+    this.enable_command('previouspage', 'firstpage', (this.env.current_page > 1));
+  };
+
   // mark a mailbox as selected and set environment variable
   this.select_folder = function(name, prefix, encode)
   {
@@ -5681,7 +5775,7 @@
 
   // for reordering column array (Konqueror workaround)
   // and for setting some message list global variables
-  this.set_message_coltypes = function(coltypes, repl)
+  this.set_message_coltypes = function(coltypes, repl, smart_col)
   {
     var list = this.message_list,
       thead = list ? list.list.tHead : null,
@@ -5709,15 +5803,13 @@
 
       for (n=0, len=this.env.coltypes.length; n<len; n++) {
         col = this.env.coltypes[n];
-        if ((cell = thead.rows[0].cells[n]) && (col=='from' || col=='to')) {
+        if ((cell = thead.rows[0].cells[n]) && (col == 'from' || col == 'to' || col == 'fromto')) {
           cell.id = 'rcm'+col;
+          $('span,a', cell).text(this.get_label(col == 'fromto' ? smart_col : col));
           // if we have links for sorting, it's a bit more complicated...
-          if (cell.firstChild && cell.firstChild.tagName.toLowerCase()=='a') {
-            cell = cell.firstChild;
-            cell.onclick = function(){ return rcmail.command('sort', this.__col, this); };
-            cell.__col = col;
-          }
-          cell.innerHTML = this.get_label(col);
+          $('a', cell).click(function(){
+            return rcmail.command('sort', this.id.replace(/^rcm/, ''), this);
+          });
         }
       }
     }
@@ -6118,7 +6210,7 @@
               this.show_contentframe(false);
             // disable commands useless when mailbox is empty
             this.enable_command(this.env.message_commands, 'purge', 'expunge',
-              'select-all', 'select-none', 'sort', 'expand-all', 'expand-unread', 'collapse-all', false);
+              'select-all', 'select-none', 'expand-all', 'expand-unread', 'collapse-all', false);
           }
           if (this.message_list)
             this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:this.message_list.rowcount });
@@ -6131,7 +6223,7 @@
         this.env.qsearch = null;
       case 'list':
         if (this.task == 'mail') {
-          this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0));
+          this.enable_command('show', 'expunge', 'select-all', 'select-none', (this.env.messagecount > 0));
           this.enable_command('purge', this.purge_mailbox_test());
           this.enable_command('expand-all', 'expand-unread', 'collapse-all', this.env.threading && this.env.messagecount);
 
@@ -6167,6 +6259,10 @@
 
     this.set_busy(false, null, lock);
     request.abort();
+
+    // don't display error message on page unload (#1488547)
+    if (this.unload)
+      return;
 
     if (request.status && errmsg)
       this.display_message(this.get_label('servererror') + ' (' + errmsg + ')', 'error');
@@ -6204,7 +6300,7 @@
     // have to do it this way for IE
     // otherwise the form will be posted to a new window
     if (document.all) {
-      var html = '<iframe name="'+frame_name+'" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>';
+      var html = '<iframe name="'+frame_name+'" src="program/resources/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>';
       document.body.insertAdjacentHTML('BeforeEnd', html);
     }
     else { // for standards-compilant browsers
@@ -6254,7 +6350,7 @@
     // prepare multipart form data composition
     var files = e.target.files || e.dataTransfer.files,
       formdata = window.FormData ? new FormData() : null,
-      fieldname = this.env.filedrop.fieldname || '_file',
+      fieldname = (this.env.filedrop.fieldname || '_file') + (this.env.filedrop.single ? '' : '[]'),
       boundary = '------multipartformboundary' + (new Date).getTime(),
       dashdash = '--', crlf = '\r\n',
       multipart = dashdash + boundary + crlf;
@@ -6269,7 +6365,8 @@
         content = '<span>' + (multiple ? ref.get_label('uploadingmany') : files[0].name) + '</span>';
 
       // add to attachments list
-      ref.add2attachment_list(ts, { name:'', html:content, classname:'uploading', complete:false });
+      if (!ref.add2attachment_list(ts, { name:'', html:content, classname:'uploading', complete:false }))
+        ref.file_upload_id = ref.set_busy(true, 'uploading');
 
       // complete multipart content and post request
       multipart += dashdash + boundary + dashdash + crlf;
@@ -6277,10 +6374,11 @@
       $.ajax({
         type: 'POST',
         dataType: 'json',
-        url: ref.url(ref.env.filedrop.action||'upload', { _id:ref.env.compose_id||'', _uploadid:ts, _remote:1 }),
+        url: ref.url(ref.env.filedrop.action||'upload', { _id:ref.env.compose_id||ref.env.cid||'', _uploadid:ts, _remote:1 }),
         contentType: formdata ? false : 'multipart/form-data; boundary=' + boundary,
         processData: false,
         data: formdata || multipart,
+        headers: {'X-Roundcube-Request': ref.env.request_token},
         beforeSend: function(xhr, s) { if (!formdata && xhr.sendAsBinary) xhr.send = xhr.sendAsBinary; },
         success: function(data){ ref.http_response(data); },
         error: function(o, status, err) { ref.http_error(o, status, err, null, 'attachment'); }
@@ -6289,24 +6387,25 @@
 
     // get contents of all dropped files
     var last = this.env.filedrop.single ? 0 : files.length - 1;
-    for (var i=0, f; i <= last && (f = files[i]); i++) {
+    for (var j=0, i=0, f; j <= last && (f = files[i]); i++) {
       if (!f.name) f.name = f.fileName;
       if (!f.size) f.size = f.fileSize;
       if (!f.type) f.type = 'application/octet-stream';
 
-      // binary encode file name
+      // file name contains non-ASCII characters, do UTF8-binary string conversion.
       if (!formdata && /[^\x20-\x7E]/.test(f.name))
         f.name_bin = unescape(encodeURIComponent(f.name));
 
+      // filter by file type if requested
       if (this.env.filedrop.filter && !f.type.match(new RegExp(this.env.filedrop.filter))) {
         // TODO: show message to user
         continue;
       }
 
-      // the easy way with FormData (FF4+, Chrome, Safari)
+      // do it the easy way with FormData (FF 4+, Chrome 5+, Safari 5+)
       if (formdata) {
-        formdata.append(fieldname + '[]', f);
-        if (i == last)
+        formdata.append(fieldname, f);
+        if (j == last)
           return submit_data();
       }
       // use FileReader supporetd by Firefox 3.6
@@ -6314,33 +6413,35 @@
         var reader = new FileReader();
 
         // closure to pass file properties to async callback function
-        reader.onload = (function(file, i) {
+        reader.onload = (function(file, j) {
           return function(e) {
-            multipart += 'Content-Disposition: form-data; name="' + fieldname + '[]"';
+            multipart += 'Content-Disposition: form-data; name="' + fieldname + '"';
             multipart += '; filename="' + (f.name_bin || file.name) + '"' + crlf;
             multipart += 'Content-Length: ' + file.size + crlf;
             multipart += 'Content-Type: ' + file.type + crlf + crlf;
             multipart += e.target.result + crlf;
             multipart += dashdash + boundary + crlf;
 
-            if (i == last)  // we're done, submit the data
+            if (j == last)  // we're done, submit the data
               return submit_data();
           }
-        })(f,i);
+        })(f,j);
         reader.readAsBinaryString(f);
       }
       // Firefox 3
       else if (f.getAsBinary) {
-        multipart += 'Content-Disposition: form-data; name="' + fieldname + '[]"';
+        multipart += 'Content-Disposition: form-data; name="' + fieldname + '"';
         multipart += '; filename="' + (f.name_bin || f.name) + '"' + crlf;
         multipart += 'Content-Length: ' + f.size + crlf;
         multipart += 'Content-Type: ' + f.type + crlf + crlf;
         multipart += f.getAsBinary() + crlf;
         multipart += dashdash + boundary +crlf;
 
-        if (i == last)
+        if (j == last)
           return submit_data();
       }
+
+      j++;
     }
   };
 
@@ -6537,7 +6638,7 @@
 
     img.onload = function() { rcmail.env.browser_capabilities.tif = 1; };
     img.onerror = function() { rcmail.env.browser_capabilities.tif = 0; };
-    img.src = 'program/blank.tif';
+    img.src = 'program/resources/blank.tif';
   };
 
   this.pdf_support_check = function()
@@ -6594,6 +6695,12 @@
     return 0;
   };
 
+  // Cookie setter
+  this.set_cookie = function(name, value, expires)
+  {
+    setCookie(name, value, expires, this.env.cookie_path, this.env.cookie_domain, this.env.cookie_secure);
+  }
+
 }  // end object rcube_webmail
 
 
@@ -6624,6 +6731,8 @@
   }
 };
 
+rcube_webmail.prototype.get_cookie = getCookie;
+
 // copy event engine prototype
 rcube_webmail.prototype.addEventListener = rcube_event_engine.prototype.addEventListener;
 rcube_webmail.prototype.removeEventListener = rcube_event_engine.prototype.removeEventListener;

--
Gitblit v1.9.1