From 77de23fa939338546a3e049459ffd29edd9058c2 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Sun, 11 Nov 2012 04:32:05 -0500
Subject: [PATCH] Added cross-task 'refresh' request for system state updates

---
 program/js/app.js |  533 +++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 338 insertions(+), 195 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index de61b21..25fddf1 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -176,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) {
 
@@ -208,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');
@@ -249,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')
@@ -424,12 +424,14 @@
           $('#rcmloginpwd').focus();
 
         // detect client timezone
-        var dt = new Date(),
-          tz = dt.getTimezoneOffset() / -60,
-          stdtz = dt.getStdTimezoneOffset() / -60;
-
-        $('#rcmlogintz').val(stdtz);
-        $('#rcmlogindst').val(tz > stdtz ? 1 : 0);
+        if (window.jstz && !bw.ie6) {
+          var timezone = jstz.determine();
+          if (timezone.name())
+            $('#rcmlogintz').val(timezone.name());
+        }
+        else {
+          $('#rcmlogintz').val(new Date().getStdTimezoneOffset() / -60);
+        }
 
         // display 'loading' message on form submit, lock submit button
         $('form').submit(function () {
@@ -480,7 +482,8 @@
         this.onloads[i]();
       }
 
-    // start keep-alive interval
+    // start keep-alive and refresh intervals
+    this.start_refresh();
     this.start_keepalive();
   };
 
@@ -570,6 +573,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});
@@ -582,10 +598,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();
         }
@@ -594,12 +618,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);
@@ -641,7 +664,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);
           }
@@ -669,8 +692,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;
 
@@ -858,52 +881,47 @@
           this.show_message(this.env.first_uid);
         break;
 
-      case 'checkmail':
-        this.check_for_recent(true);
-        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':
@@ -930,9 +948,6 @@
           this.auto_save_start();
           break;
         }
-
-        // re-set keep-alive timeout
-        this.start_keepalive();
 
         this.submit_messageform(true);
         break;
@@ -976,9 +991,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;
 
@@ -988,7 +1003,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;
 
@@ -1447,29 +1462,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) {
@@ -1546,14 +1553,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);
     }
   };
 
@@ -1567,7 +1577,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);
   };
@@ -1647,6 +1657,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;
   };
 
 
@@ -1912,18 +1944,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';
     }
 
@@ -1937,10 +1969,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) {
@@ -1960,18 +1999,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()
@@ -2002,6 +2058,15 @@
     }
   };
 
+  // sends request to check for recent messages
+  this.checkmail = function()
+  {
+    var lock = this.set_busy(true, 'checkingmail'),
+      params = this.check_recent_params();
+
+    this.http_request('check-recent', params, lock);
+  };
+
   // list messages of a specific mailbox using filter
   this.filter_mailbox = function(filter)
   {
@@ -2017,7 +2082,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 = {};
@@ -2056,8 +2121,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;
     }
 
@@ -2435,7 +2500,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;
@@ -2652,34 +2717,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)
@@ -2948,6 +3016,20 @@
   /*********        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.env.extwin) {
+      this.open_window(url, 1150, 900);
+    }
+    else {
+      this.redirect(url);
+      window.resizeTo(Math.max(1150, $(window).width()), Math.max(900, $(window).height()));
+    }
+  };
+
   // init message compose form: set focus and eventhandlers
   this.init_messageform = function()
   {
@@ -2961,6 +3043,12 @@
       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);
+      this.env.opened_extwin = true;
+    }
 
     // configure parallel autocompletion
     if (this.env.autocomplete_threads > 0) {
@@ -2980,7 +3068,7 @@
       this.set_caret_pos(input_message, this.env.top_posting ? 0 : $(input_message).val().length);
       // add signature according to selected identity
       // if we have HTML editor, signature is added in callback
-      if (input_from.prop('type') == 'select-one') {
+      if (input_from.prop('type') == 'select-one' && !this.env.opened_extwin) {
         this.change_identity(input_from[0]);
       }
     }
@@ -3298,8 +3386,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]) {
@@ -3312,12 +3399,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)
@@ -3325,11 +3408,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
@@ -3394,21 +3474,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;
@@ -3637,8 +3704,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);
+    }
   };
 
 
@@ -4041,7 +4116,7 @@
 
   this.list_contacts = function(src, group, page)
   {
-    var folder, url = {},
+    var win, folder, url = {},
       target = window;
 
     if (!src)
@@ -4073,8 +4148,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 +4205,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
@@ -4752,11 +4827,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 +4953,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 +4982,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 +5363,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';
     }
 
@@ -5631,6 +5705,32 @@
     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()
   {
@@ -5714,13 +5814,11 @@
         col = this.env.coltypes[n];
         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 == 'fromto' ? smart_col : col);
+          $('a', cell).click(function(){
+            return rcmail.command('sort', this.id.replace(/^rcm/, ''), this);
+          });
         }
       }
     }
@@ -5950,10 +6048,18 @@
     if (lock || lock === null)
       this.set_busy(true);
 
-    if (this.is_framed())
+    if (this.is_framed()) {
       parent.rcmail.redirect(url, lock);
-    else
+    }
+    else {
+      if (this.env.extwin) {
+        if (typeof url == 'string')
+          url += (url.indexOf('?') < 0 ? '?' : '&') + '_extwin=1';
+        else
+          url._extwin = 1;
+      }
       this.location_href(url, window);
+    }
   };
 
   this.goto_url = function(action, query, lock)
@@ -5974,6 +6080,9 @@
       $('<a>').attr('href', url).appendTo(document.body).get(0).click();
     else
       target.location.href = url;
+
+    // reset keep-alive interval
+    this.start_keepalive();
   };
 
   // send a http request to the server
@@ -6002,6 +6111,9 @@
       success: function(data){ ref.http_response(data); },
       error: function(o, status, err) { ref.http_error(o, status, err, lock, action); }
     });
+
+    // reset keep-alive interval
+    this.start_keepalive();
   };
 
   // send a http POST request to the server
@@ -6019,7 +6131,7 @@
     // trigger plugin hook
     var result = this.triggerEvent('request'+action, postdata);
     if (result !== undefined) {
-      // abort if one the handlers returned false
+      // abort if one of the handlers returned false
       if (result === false)
         return false;
       else
@@ -6034,6 +6146,9 @@
       success: function(data){ ref.http_response(data); },
       error: function(o, status, err) { ref.http_error(o, status, err, lock, action); }
     });
+
+    // reset keep-alive interval
+    this.start_keepalive();
   };
 
   // aborts ajax request
@@ -6121,20 +6236,21 @@
               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 });
         }
         break;
 
+      case 'refresh':
       case 'check-recent':
       case 'getunread':
       case 'search':
         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);
 
@@ -6161,6 +6277,9 @@
 
     this.triggerEvent('responseafter', {response: response});
     this.triggerEvent('responseafter'+response.action, {response: response});
+
+    // reset keep-alive interval
+    this.start_keepalive();
   };
 
   // handle HTTP request errors
@@ -6184,9 +6303,7 @@
 
     // re-send keep-alive requests after 30 seconds
     if (action == 'keep-alive')
-      setTimeout(function(){ ref.keep_alive(); }, 30000);
-    else if (action == 'check-recent')
-      setTimeout(function(){ ref.check_for_recent(false); }, 30000);
+      setTimeout(function(){ ref.keep_alive(); ref.start_keepalive(); }, 30000);
   };
 
   // post the given form to a hidden iframe
@@ -6356,20 +6473,28 @@
     }
   };
 
-
-  // starts interval for keep-alive/check-recent signal
+  // starts interval for keep-alive signal
   this.start_keepalive = function()
   {
-    if (!this.env.keep_alive || this.env.framed)
+    if (!this.env.session_lifetime || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print')
       return;
 
-    if (this._int)
-      clearInterval(this._int);
+    if (this._keepalive)
+      clearInterval(this._keepalive);
 
-    if (this.task == 'mail' && this.gui_objects.mailboxlist)
-      this._int = setInterval(function(){ ref.check_for_recent(false); }, this.env.keep_alive * 1000);
-    else if (this.task != 'login' && this.env.action != 'print')
-      this._int = setInterval(function(){ ref.keep_alive(); }, this.env.keep_alive * 1000);
+    this._keepalive = setInterval(function(){ ref.keep_alive(); }, this.env.session_lifetime * 0.5 * 1000);
+  };
+
+  // starts interval for refresh signal
+  this.start_refresh = function()
+  {
+    if (!this.env.keep_alive || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print')
+      return;
+
+    if (this._refresh)
+      clearInterval(this._refresh);
+
+    this._refresh = setInterval(function(){ ref.refresh(); }, this.env.keep_alive * 1000);
   };
 
   // sends keep-alive signal
@@ -6379,29 +6504,39 @@
       this.http_request('keep-alive');
   };
 
-  // sends request to check for recent messages
-  this.check_for_recent = function(refresh)
+  // sends refresh signal
+  this.refresh = function()
   {
-    if (this.busy)
+    if (this.busy) {
+      // try again after 10 seconds
+      setTimeout(function(){ ref.refresh(); ref.start_refresh(); }, 10000);
       return;
-
-    var lock, url = {_mbox: this.env.mailbox};
-
-    if (refresh) {
-      lock = this.set_busy(true, 'checkingmail');
-      url._refresh = 1;
-      // reset check-recent interval
-      this.start_keepalive();
     }
 
-    if (this.gui_objects.messagelist)
-      url._list = 1;
-    if (this.gui_objects.quotadisplay)
-      url._quota = 1;
-    if (this.env.search_request)
-      url._search = this.env.search_request;
+    var params = {}, lock = this.set_busy(true, 'refreshing');
 
-    this.http_request('check-recent', url, lock);
+    if (this.task == 'mail' && this.gui_objects.mailboxlist)
+      params = this.check_recent_params();
+
+    // plugins should bind to 'requestrefresh' event to add own params
+    this.http_request('refresh', params, lock);
+  };
+
+  // returns check-recent request parameters
+  this.check_recent_params = function()
+  {
+    var params = {_mbox: this.env.mailbox};
+
+    if (this.gui_objects.mailboxlist)
+      params._folderlist = 1;
+    if (this.gui_objects.messagelist)
+      params._list = 1;
+    if (this.gui_objects.quotadisplay)
+      params._quota = 1;
+    if (this.env.search_request)
+      params._search = this.env.search_request;
+
+    return params;
   };
 
 
@@ -6606,6 +6741,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
 
 
@@ -6636,6 +6777,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