From fcc7f861b170596c6970aecb1ddc87a3567b112f Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Sat, 30 Jul 2011 11:32:13 -0400
Subject: [PATCH] Log session validation errors; keep error message when redirecting to login after session error

---
 program/js/app.js |  228 ++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 153 insertions(+), 75 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index 35136bf..a9ed9ad 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -138,14 +138,6 @@
       return;
     }
 
-    // Enable debug console
-    if (!window.console || !window.console.log) {
-      window.console = new rcube_console();
-    }
-    else {
-      $('#console').hide();
-    }
-
     // find all registered gui containers
     for (var n in this.gui_containers)
       this.gui_containers[n] = $('#'+this.gui_containers[n]);
@@ -260,7 +252,10 @@
         }
         // show printing dialog
         else if (this.env.action == 'print' && this.env.uid)
-          window.print();
+          if (bw.safari)
+            window.setTimeout('window.print()', 10);
+          else
+            window.print();
 
         // get unread count for each mailbox
         if (this.gui_objects.mailboxlist) {
@@ -437,6 +432,11 @@
     this.start_keepalive();
   };
 
+  this.log = function(msg)
+  {
+    if (window.console && console.log)
+      console.log(msg);
+  };
 
   /*********************************************************/
   /*********       client command interface        *********/
@@ -1880,9 +1880,7 @@
     if (action == 'preview' && String(target.location.href).indexOf(url) >= 0)
       this.show_contentframe(true);
     else {
-      if (!this.env.frame_lock) {
-        (this.is_framed() ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading');
-      }
+      this.lock_frame();
       this.location_href(this.env.comm_path+url, target);
 
       // mark as read and change mbox unread counter
@@ -1915,6 +1913,12 @@
 
     if (!show && this.busy)
       this.set_busy(false, null, this.env.frame_lock);
+  };
+
+  this.lock_frame = function()
+  {
+    if (!this.env.frame_lock)
+      (this.is_framed() ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading');
   };
 
   // list a specific page
@@ -2871,12 +2875,21 @@
       input_subject = $("input[name='_subject']"),
       input_message = $("[name='_message']").get(0),
       html_mode = $("input[name='_is_html']").val() == '1',
-      ac_fields = ['cc', 'bcc', 'replyto', 'followupto'];
+      ac_fields = ['cc', 'bcc', 'replyto', 'followupto'],
+      ac_props;
+
+    // configure parallel autocompletion
+    if (this.env.autocomplete_threads > 0) {
+      ac_props = {
+        threads: this.env.autocomplete_threads,
+        sources: this.env.autocomplete_sources,
+      };
+    }
 
     // init live search events
-    this.init_address_input_events(input_to);
+    this.init_address_input_events(input_to, ac_props);
     for (var i in ac_fields) {
-      this.init_address_input_events($("[name='_"+ac_fields[i]+"']"));
+      this.init_address_input_events($("[name='_"+ac_fields[i]+"']"), ac_props);
     }
 
     if (!html_mode) {
@@ -2904,9 +2917,9 @@
     this.auto_save_start();
   };
 
-  this.init_address_input_events = function(obj, action)
+  this.init_address_input_events = function(obj, props)
   {
-    obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, action); })
+    obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, props); })
       .attr('autocomplete', 'off');
   };
 
@@ -3441,7 +3454,7 @@
   /*********************************************************/
 
   // handler for keyboard events on address-fields
-  this.ksearch_keydown = function(e, obj, action)
+  this.ksearch_keydown = function(e, obj, props)
   {
     if (this.ksearch_timer)
       clearTimeout(this.ksearch_timer);
@@ -3471,8 +3484,8 @@
         if (mod == SHIFT_KEY)
           break;
 
-     case 13:  // enter
-        if (this.ksearch_selected === null || !this.ksearch_input || !this.ksearch_value)
+      case 13:  // enter
+        if (this.ksearch_selected === null || !this.ksearch_value)
           break;
 
         // insert selected address and hide ksearch pane
@@ -3492,7 +3505,7 @@
     }
 
     // start timer
-    this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results(action); }, 200);
+    this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results(props); }, 200);
     this.ksearch_input = obj;
 
     return true;
@@ -3522,10 +3535,11 @@
       p = inp_value.lastIndexOf(this.ksearch_value, cpos),
       trigger = false,
       insert = '',
-
       // replace search string with full address
       pre = inp_value.substring(0, p),
       end = inp_value.substring(p+this.ksearch_value.length, inp_value.length);
+
+    this.ksearch_destroy();
 
     // insert all members of a group
     if (typeof this.env.contacts[id] === 'object' && this.env.contacts[id].id) {
@@ -3560,7 +3574,7 @@
   };
 
   // address search processor
-  this.ksearch_get_results = function(action)
+  this.ksearch_get_results = function(props)
   {
     var inp_value = this.ksearch_input ? this.ksearch_input.value : null;
 
@@ -3605,59 +3619,102 @@
     if (old_value && old_value.length && this.env.contacts && !this.env.contacts.length && q.indexOf(old_value) == 0)
       return;
 
-    var lock = this.display_message(this.get_label('searching'), 'loading');
-    this.http_post(action ? action : 'mail/autocomplete', '_search='+urlencode(q), lock);
+    this.ksearch_destroy();
+
+    var i, lock, source, xhr, reqid = new Date().getTime(),
+      threads = props && props.threads ? props.threads : 1,
+      sources = props && props.sources ? props.sources : [],
+      action = props && props.action ? props.action : 'mail/autocomplete';
+
+    this.ksearch_data = {id: reqid, sources: sources.slice(), action: action, locks: [], requests: []};
+
+    for (i=0; i<threads; i++) {
+      source = this.ksearch_data.sources.shift();
+      if (threads > 1 && source === null)
+        break;
+
+      lock = this.display_message(this.get_label('searching'), 'loading');
+      xhr = this.http_post(action, '_search='+urlencode(q)+'&_id='+reqid
+        + (source ? '&_source='+urlencode(source) : ''), lock);
+
+      this.ksearch_data.locks.push(lock);
+      this.ksearch_data.requests.push(xhr);
+    }
   };
 
-  this.ksearch_query_results = function(results, search)
+  this.ksearch_query_results = function(results, search, reqid)
   {
     // ignore this outdated search response
-    if (this.ksearch_value && search != this.ksearch_value)
+    if (this.ksearch_input && this.ksearch_value && search != this.ksearch_value)
       return;
 
-    this.env.contacts = results ? results : [];
-    this.ksearch_display_results(this.env.contacts);
-  };
-
-  this.ksearch_display_results = function (a_results)
-  {
     // display search results
-    if (a_results.length && this.ksearch_input && this.ksearch_value) {
-      var p, ul, li, text, s_val = this.ksearch_value;
+    var p, ul, li, text, init, s_val = this.ksearch_value,
+      maxlen = this.env.autocomplete_max ? this.env.autocomplete_max : 15;
 
-      // create results pane if not present
-      if (!this.ksearch_pane) {
-        ul = $('<ul>');
-        this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane').css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body);
-        this.ksearch_pane.__ul = ul[0];
-      }
+    // create results pane if not present
+    if (!this.ksearch_pane) {
+      ul = $('<ul>');
+      this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane')
+        .css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body);
+      this.ksearch_pane.__ul = ul[0];
+    }
 
-      // remove all search results
-      ul = this.ksearch_pane.__ul;
+    ul = this.ksearch_pane.__ul;
+
+    // remove all search results or add to existing list if parallel search
+    if (reqid && this.ksearch_pane.data('reqid') == reqid) {
+      maxlen -= ul.childNodes.length;
+    }
+    else {
+      this.ksearch_pane.data('reqid', reqid);
+      init = 1;
+      // reset content
       ul.innerHTML = '';
+      this.env.contacts = [];
+      // move the results pane right under the input box
+      var pos = $(this.ksearch_input).offset();
+      this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px', display: 'none'});
+    }
 
-      // add each result line to list
-      for (i=0; i < a_results.length; i++) {
-        text = typeof a_results[i] === 'object' ? a_results[i].name : a_results[i];
+    // add each result line to list
+    if (results && results.length) {
+      for (i=0; i < results.length && maxlen > 0; i++) {
+        text = typeof results[i] === 'object' ? results[i].name : results[i];
         li = document.createElement('LI');
         li.innerHTML = text.replace(new RegExp('('+RegExp.escape(s_val)+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>');
         li.onmouseover = function(){ ref.ksearch_select(this); };
         li.onmouseup = function(){ ref.ksearch_click(this) };
         li._rcm_id = i;
         ul.appendChild(li);
+        maxlen -= 1;
       }
-
-      // select the first
-      $(ul.firstChild).attr('id', 'rcmksearchSelected').addClass('selected');
-      this.ksearch_selected = 0;
-
-      // move the results pane right under the input box and make it visible
-      var pos = $(this.ksearch_input).offset();
-      this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px' }).show();
     }
-    // hide results pane
-    else
-      this.ksearch_hide();
+
+    if (ul.childNodes.length) {
+      this.ksearch_pane.show();
+      // select the first
+      if (!this.env.contacts.length) {
+        $('li:first', ul).attr('id', 'rcmksearchSelected').addClass('selected');
+        this.ksearch_selected = 0;
+      }
+    }
+
+    if (results && results.length)
+      this.env.contacts = this.env.contacts.concat(results);
+
+    // run next parallel search
+    if (maxlen > 0 && this.ksearch_data.id == reqid && this.ksearch_data.sources.length) {
+      var lock, xhr, props = this.ksearch_data, source = props.sources.shift();
+      if (source) {
+        lock = this.display_message(this.get_label('searching'), 'loading');
+        xhr = this.http_post(props.action, '_search='+urlencode(s_val)+'&_id='+reqid
+          +'&_source='+urlencode(source), lock);
+
+        this.ksearch_data.locks.push(lock);
+        this.ksearch_data.requests.push(xhr);
+      }
+    }
   };
 
   this.ksearch_click = function(node)
@@ -3674,20 +3731,36 @@
     if (this.ksearch_timer)
       clearTimeout(this.ksearch_timer);
 
-    this.ksearch_value = '';
     this.ksearch_input = null;
     this.ksearch_hide();
   };
 
-
   this.ksearch_hide = function()
   {
     this.ksearch_selected = null;
+    this.ksearch_value = '';
 
     if (this.ksearch_pane)
       this.ksearch_pane.hide();
-   };
 
+    this.ksearch_destroy();
+  };
+
+  // Aborts pending autocomplete requests
+  this.ksearch_destroy = function()
+  {
+    var i, len, ac = this.ksearch_data;
+
+    if (!ac)
+      return;
+
+    for (i=0, len=ac.locks.length; i<len; i++) {
+      this.hide_message(ac.locks[i]); // hide loading message
+      ac.requests[i].abort(); // abort ajax request
+    }
+
+    this.ksearch_data = null;
+  }
 
   /*********************************************************/
   /*********         address book methods          *********/
@@ -3837,8 +3910,10 @@
       if (this.env.group)
         add_url += '&_gid='+urlencode(this.env.group);
 
-      this.set_busy(true);
-      this.location_href(this.env.comm_path+'&_action='+action+'&_source='+urlencode(this.env.source)+'&_cid='+urlencode(cid) + add_url, target);
+      this.lock_frame();
+      this.location_href(this.env.comm_path+'&_action='+action
+        +'&_source='+urlencode(this.env.source)
+        +'&_cid='+urlencode(cid) + add_url, target);
     }
     return true;
   };
@@ -4358,6 +4433,7 @@
       this.contact_list.clear_selection();
     }
 
+    this.lock_frame();
     this.location_href(this.env.comm_path+'&_action=search'+add_url, target);
 
     return true;
@@ -4391,6 +4467,7 @@
         add_url = '&_framed=1';
         target = window.frames[this.env.contentframe];
       }
+      this.lock_frame();
       this.location_href(this.env.comm_path+'&_action=edit-prefs&_section='+id+add_url, target);
     }
 
@@ -4533,7 +4610,7 @@
       reg = new RegExp('[^'+delim+']*['+delim+']', 'g');
       var basename = this.env.mailbox.replace(reg, ''),
         newname = this.env.dstfolder==this.env.delimiter ? basename : this.env.dstfolder+this.env.delimiter+basename;
-        
+
       if (newname != this.env.mailbox) {
         this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.mailbox)+'&_folder_newname='+urlencode(newname), this.set_busy(true, 'foldermoving'));
         this.subscription_list.draglayer.hide();
@@ -4792,9 +4869,7 @@
       this.show_contentframe(true);
     }
     else {
-      if (!this.env.frame_lock) {
-        (parent.rcmail ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading');
-      }
+      this.lock_frame();
       this.location_href(this.env.comm_path+url, target);
     }
   };
@@ -5078,7 +5153,8 @@
       obj.click(function() { return ref.hide_message(obj); });
     }
 
-    window.setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout);
+    if (timeout > 0)
+      window.setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout);
     return id;
   };
 
@@ -5436,11 +5512,11 @@
       url = '?_task=utils&_action=html2text',
       lock = this.set_busy(true, 'converting');
 
-    console.log('HTTP POST: ' + url);
+    this.log('HTTP POST: ' + url);
 
     $.ajax({ type: 'POST', url: url, data: htmlText, contentType: 'application/octet-stream',
       error: function(o, status, err) { rcmail.http_error(o, status, err, lock); },
-      success: function(data) { rcmail.set_busy(false, null, lock); $(document.getElementById(id)).val(data); console.log(data); }
+      success: function(data) { rcmail.set_busy(false, null, lock); $(document.getElementById(id)).val(data); rcmail.log(data); }
     });
   };
 
@@ -5455,7 +5531,7 @@
   /********************************************************/
   /*********        remote request methods        *********/
   /********************************************************/
-  
+
   // compose a valid url with the given parameters
   this.url = function(action, query)
   {
@@ -5533,8 +5609,9 @@
     url += '&_remote=1';
 
     // send request
-    console.log('HTTP GET: ' + url);
-    $.ajax({
+    this.log('HTTP GET: ' + url);
+
+    return $.ajax({
       type: 'GET', url: url, data: { _unlock:(lock?lock:0) }, dataType: 'json',
       success: function(data){ ref.http_response(data); },
       error: function(o, status, err) { rcmail.http_error(o, status, err, lock); }
@@ -5564,8 +5641,9 @@
     }
 
     // send request
-    console.log('HTTP POST: ' + url);
-    $.ajax({
+    this.log('HTTP POST: ' + url);
+
+    return $.ajax({
       type: 'POST', url: url, data: postdata, dataType: 'json',
       success: function(data){ ref.http_response(data); },
       error: function(o, status, err) { rcmail.http_error(o, status, err, lock); }
@@ -5597,7 +5675,7 @@
 
     // if we get javascript code from server -> execute it
     if (response.exec) {
-      console.log(response.exec);
+      this.log(response.exec);
       eval(response.exec);
     }
 

--
Gitblit v1.9.1