From 2f2f15b7aabe19e45dad9bddb7eb7f4394aa1e21 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Mon, 04 Sep 2006 08:26:30 -0400
Subject: [PATCH] Little improvements for message parsing and encoding

---
 program/js/app.js |  596 +++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 419 insertions(+), 177 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index a5ae90d..1b7312f 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -13,14 +13,13 @@
  
   $Id$
 */
+
 // Constants
 var CONTROL_KEY = 1;
 var SHIFT_KEY = 2;
 var CONTROL_SHIFT_KEY = 3;
-var DRAFT_AUTOSAVE = 10; // Minutes
 
 var rcube_webmail_client;
-var rcube_save_timer;
 
 function rcube_webmail()
   {
@@ -40,10 +39,8 @@
   // webmail client settings
   this.dblclick_time = 600;
   this.message_time = 5000;
-  this.request_timeout = 180000;
-  this._interval = 60000;
+  
   this.mbox_expression = new RegExp('[^0-9a-z\-_]', 'gi');
-  this.env.blank_img = 'skins/default/images/blank.gif';
   
   // mimetypes supported by the browser (default settings)
   this.mimetypes = new Array('text/plain', 'text/html', 'text/xml',
@@ -51,12 +48,16 @@
                              'application/x-javascript', 'application/pdf',
                              'application/x-shockwave-flash');
 
+  // default environment vars
+  this.env.keep_alive = 60;        // seconds
+  this.env.request_timeout = 180;  // seconds
+  this.env.draft_autosave = 300;   // seconds
+
 
   // set environment variable
   this.set_env = function(name, value)
     {
-    //if (!this.busy)
-      this.env[name] = value;    
+    this.env[name] = value;
     };
 
 
@@ -148,8 +149,8 @@
           this.enable_command('add-attachment', 'send-attachment', 'remove-attachment', 'send', true);
           if (this.env.spellcheck)
             this.enable_command('spellcheck', true);
-	  if (this.env.drafts_mailbox)
-	    this.enable_command('savedraft', true);
+          if (this.env.drafts_mailbox)
+            this.enable_command('savedraft', true);
           }
           
         if (this.env.messagecount)
@@ -246,47 +247,64 @@
     // load body click event
     document.onmousedown = function(){ return rcube_webmail_client.reset_click(); };
     document.onkeydown   = function(e){ return rcube_webmail_client.key_pressed(e, msg_list_frame); };
-
     
     // flag object as complete
     this.loaded = true;
-          
+
     // show message
     if (this.pending_message)
       this.display_message(this.pending_message[0], this.pending_message[1]);
-      
-    // start interval for keep-alive/recent_check signal
-    if (this._interval && this.task=='mail' && this.gui_objects.messagelist)
-      this._int = setInterval(this.ref+'.check_for_recent()', this.keep_alive_interval);
-    else if (this.task!='login')
-      this._int = setInterval(this.ref+'.send_keep_alive()', this.keep_alive_interval);
+
+    // start keep-alive interval
+    this.start_keepalive();
     };
 
+
+  // start interval for keep-alive/recent_check signal
+  this.start_keepalive = function()
+    {
+    if (this.env.keep_alive && this.task=='mail' && this.gui_objects.messagelist)
+      this._int = setInterval(this.ref+'.check_for_recent()', this.env.keep_alive * 1000);
+    else if (this.env.keep_alive && this.task!='login')
+      this._int = setInterval(this.ref+'.send_keep_alive()', this.env.keep_alive * 1000);    
+    }
+
+
   // reset last clicked if user clicks on anything other than the message table
-  this.reset_click = function() {
+  this.reset_click = function()
+    {
+    var id;
     this.in_message_list = false;
-	for (var n=0; n<this.selection.length; n++) {
+	for (var n=0; n<this.selection.length; n++)
+	  {
       id = this.selection[n];
-      if (this.list_rows[id].obj) {
+      if (this.list_rows[id] && this.list_rows[id].obj)
+        {
         this.set_classname(this.list_rows[id].obj, 'selected', false);
 		this.set_classname(this.list_rows[id].obj, 'unfocused', true);
-	  }
-    }
-  };
+        }
+      }
+    };
 	
   this.click_on_list = function(e)
     {
     if (!e)
       e = window.event;
 
-    for (var n=0; n<this.selection.length; n++) {
+    for (var n=0; n<this.selection.length; n++)
+      {
       id = this.selection[n];
-      if (this.list_rows[id].obj) {
+      if (this.list_rows[id].obj)
+        {
         this.set_classname(this.list_rows[id].obj, 'selected', true);
 		this.set_classname(this.list_rows[id].obj, 'unfocused', false);
-	  }
-    }
+        }
+      }
 
+    var mbox_li;
+    if (mbox_li = this.get_mailbox_li()) 
+      this.set_classname(mbox_li, 'unfocused', true);
+    
     this.in_message_list = true;
     e.cancelBubble = true;
     };
@@ -441,7 +459,6 @@
  
     // start the auto-save timer
     this.auto_save_start();
-    
     };
 
   this.init_address_input_events = function(obj)
@@ -619,9 +636,10 @@
           if (this.env.search_request<0 || (this.env.search_request && props != this.env.mailbox))
             this.reset_qsearch();
 
-	  // Reset message list header, unless returning from compose/read/etc
-	  if (this.env.mailbox != props && this.message_rows)
-	    this.clear_message_list_header();
+          // Reset message list header, unless returning from compose/read/etc
+          // don't know what this is good for (thomasb, 2006/07/25)
+          //if (this.env.mailbox != props && this.message_rows)
+          //  this.clear_message_list_header();
 
           this.list_mailbox(props);
           }
@@ -645,7 +663,7 @@
           else
             sort_order = this.env.sort_order;
           }
-        
+
         if (this.env.sort_col==sort_col && this.env.sort_order==sort_order)
           break;
 
@@ -689,17 +707,15 @@
           {
           var uid = this.get_single_uid();
           if (uid && (!this.env.uid || uid != this.env.uid))
-	    {
+            {
             if (this.env.mailbox==this.env.drafts_mailbox)
               {
               this.set_busy(true);
-              location.href = this.env.comm_path+'&_action=compose&_draft_uid='+uid+'&_mbox='+escape(this.env.mailbox);
+              location.href = this.env.comm_path+'&_action=compose&_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox);
               }
             else
-              {
               this.show_message(uid);
-	      }
-	    }
+            }
           }
         else if (this.task=='addressbook')
           {
@@ -862,8 +878,9 @@
        
         if (this.task=='mail' && this.env.mailbox==this.env.drafts_mailbox)
           {
-          var uid = this.get_single_uid();
-          url += '&_draft_uid='+uid+'&_mbox='+escape(this.env.mailbox);
+          var uid;
+          if (uid = this.get_single_uid())
+            url += '&_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox);
           } 
         // modify url if we're in addressbook
         else if (this.task=='addressbook')
@@ -918,34 +935,41 @@
         break;
 
       case 'savedraft':
-	// Reset the auto-save timer
-        self.clearTimeout(rcube_save_timer);
+        // Reset the auto-save timer
+        self.clearTimeout(this.save_timer);
 
         if (!this.gui_objects.messageform)
           break;
 
-	// if saving Drafts is disabled in main.inc.php
-	if (!this.env.drafts_mailbox)
-	  break;
+        // if saving Drafts is disabled in main.inc.php
+        if (!this.env.drafts_mailbox)
+          break;
 
         this.set_busy(true, 'savingmessage');
         var form = this.gui_objects.messageform;
-	form.target = "savetarget";
+        form.target = "savetarget";
         form.submit();
         break;
 
       case 'send':
         if (!this.gui_objects.messageform)
           break;
-          
+
         if (!this.check_compose_input())
           break;
+          
+        // Reset the auto-save timer
+        self.clearTimeout(this.save_timer);
 
         // all checks passed, send message
         this.set_busy(true, 'sendingmessage');
         var form = this.gui_objects.messageform;
-	form._draft.value='';
+        form.target = "savetarget";     
+        form._draft.value = '';
         form.submit();
+        
+        // clear timeout (sending could take longer)
+        clearTimeout(this.request_timer);
         break;
 
       case 'add-attachment':
@@ -953,7 +977,7 @@
         
       case 'send-attachment':
         // Reset the auto-save timer
-        self.clearTimeout(rcube_save_timer);
+        self.clearTimeout(this.save_timer);
 
         this.upload_file(props)      
         break;
@@ -968,7 +992,7 @@
         if (uid = this.get_single_uid())
           {
           this.set_busy(true);
-          location.href = this.env.comm_path+'&_action=compose&_reply_uid='+uid+'&_mbox='+escape(this.env.mailbox)+(command=='reply-all' ? '&_all=1' : '');
+          location.href = this.env.comm_path+'&_action=compose&_reply_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(command=='reply-all' ? '&_all=1' : '');
           }
         break;      
 
@@ -977,7 +1001,7 @@
         if (uid = this.get_single_uid())
           {
           this.set_busy(true);
-          location.href = this.env.comm_path+'&_action=compose&_forward_uid='+uid+'&_mbox='+escape(this.env.mailbox);
+          location.href = this.env.comm_path+'&_action=compose&_forward_uid='+uid+'&_mbox='+urlencode(this.env.mailbox);
           }
         break;
         
@@ -985,7 +1009,7 @@
         var uid;
         if (uid = this.get_single_uid())
           {
-          this.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+escape(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : ''));
+          this.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : ''));
           if (this.printwin)
             setTimeout(this.ref+'.printwin.focus()', 20);
           }
@@ -995,7 +1019,7 @@
         var uid;
         if (uid = this.get_single_uid())
           {          
-          this.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+this.env.uid+'&_mbox='+escape(this.env.mailbox));
+          this.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox));
           if (this.sourcewin)
             setTimeout(this.ref+'.sourcewin.focus()', 20);
           }
@@ -1010,7 +1034,7 @@
         if (!props && this.gui_objects.qsearchbox)
           props = this.gui_objects.qsearchbox.value;
         if (props)
-          this.qsearch(escape(props), this.env.mailbox);
+          this.qsearch(urlencode(props), this.env.mailbox);
         break;
 
       // reset quicksearch        
@@ -1118,8 +1142,8 @@
       clearTimeout(this.request_timer);
 
     // set timer for requests
-    if (a && this.request_timeout)
-      this.request_timer = setTimeout(this.ref+'.request_timed_out()', this.request_timeout);
+    if (a && this.env.request_timeout)
+      this.request_timer = setTimeout(this.ref+'.request_timed_out()', this.env.request_timeout * 1000);
     };
 
 
@@ -1174,10 +1198,13 @@
   this.mbox_mouse_up = function(mbox)
     {
     if (this.drag_active)
+      {
+      this.unfocus_mailbox(mbox);
       this.command('moveto', mbox);
+      }
     else
       this.command('list', mbox);
-      
+  
     return false;
     };
 
@@ -1234,7 +1261,7 @@
       if (this.env.mailbox==this.env.drafts_mailbox)
         {
         this.set_busy(true);
-        location.href = this.env.comm_path+'&_action=compose&_draft_uid='+id+'&_mbox='+escape(this.env.mailbox);
+        location.href = this.env.comm_path+'&_action=compose&_draft_uid='+id+'&_mbox='+urlencode(this.env.mailbox);
         }
       else
         {
@@ -1406,7 +1433,9 @@
           }
       }
 	}
-	if (this.last_selected != 0) { this.set_classname(this.list_rows[this.last_selected].obj, 'focused', false);}
+	if (this.last_selected != 0 && this.list_rows[this.last_selected])
+	  this.set_classname(this.list_rows[this.last_selected].obj, 'focused', false);
+
     this.last_selected = id;
     this.set_classname(this.list_rows[id].obj, 'focused', true);        
   };
@@ -1492,7 +1521,7 @@
     if (id)
       {
       this.set_busy(true, 'loading');
-      target.location.href = this.env.comm_path+'&_action=show&_uid='+id+'&_mbox='+escape(this.env.mailbox)+add_url;
+      target.location.href = this.env.comm_path+'&_action=show&_uid='+id+'&_mbox='+urlencode(this.env.mailbox)+add_url;
       }
     };
 
@@ -1545,8 +1574,7 @@
     if (this.env.search_request)
       add_url += '&_search='+this.env.search_request;
       
-    if (this.env.mailbox!=mbox)
-      this.select_mailbox(mbox);
+    this.select_mailbox(mbox);
 
     // load message list remotely
     if (this.gui_objects.messagelist)
@@ -1565,7 +1593,7 @@
     if (mbox)
       {
       this.set_busy(true, 'loading');
-      target.location.href = this.env.comm_path+'&_mbox='+escape(mbox)+(page ? '&_page='+page : '')+add_url;
+      target.location.href = this.env.comm_path+'&_mbox='+urlencode(mbox)+(page ? '&_page='+page : '')+add_url;
       }
     };
 
@@ -1577,7 +1605,7 @@
     this.clear_message_list();
 
     // send request to server
-    var url = '_mbox='+escape(mbox)+(page ? '&_page='+page : '');
+    var url = '_mbox='+urlencode(mbox)+(page ? '&_page='+page : '');
     this.set_busy(true, 'loading');
     this.http_request('list', url+add_url, true);
     };
@@ -1596,18 +1624,24 @@
     
     };
 
+
   this.clear_message_list_header = function()
     {
-    var table = this.gui_objects.messagelist;
+    var table;
+    if (table = this.gui_objects.messagelist)
+      {
+      if (table.colgroup)
+        table.removeChild(table.colgroup);
+      if (table.tHead)
+        table.removeChild(table.tHead);
 
-    var colgroup = document.createElement('COLGROUP');
-    table.removeChild(table.colgroup);
-    table.insertBefore(colgroup, table.thead);
-
-    var thead = document.createElement('THEAD');
-    table.removeChild(table.thead);
-    table.insertBefore(thead, table.tBodies[0]);
+      var colgroup = document.createElement('COLGROUP');
+      var thead = document.createElement('THEAD');
+      table.insertBefore(colgroup, table.tBodies[0]);
+      table.insertBefore(thead, table.tBodies[0]);
+      }
     };
+
 
   this.expunge_mailbox = function(mbox)
     {
@@ -1623,7 +1657,7 @@
        }
 
     // send request to server
-    var url = '_mbox='+escape(mbox);
+    var url = '_mbox='+urlencode(mbox);
     this.http_request('expunge', url+add_url, lock);
     };
 
@@ -1645,12 +1679,25 @@
        }
 
     // send request to server
-    var url = '_mbox='+escape(mbox);
+    var url = '_mbox='+urlencode(mbox);
     this.http_request('purge', url+add_url, lock);
     return true;
     };
     
-
+  this.focus_mailbox = function(mbox)
+    {
+    var mbox_li;
+  	if (this.drag_active && mbox != this.env.mailbox && (mbox_li = this.get_mailbox_li(mbox)))
+      this.set_classname(mbox_li, 'droptarget', true);
+    }
+    
+  this.unfocus_mailbox = function(mbox)
+    {
+    var mbox_li;
+  	if (this.drag_active && (mbox_li = this.get_mailbox_li(mbox)))
+      this.set_classname(mbox_li, 'droptarget', false);
+    }
+  
   // move selected messages to the specified mailbox
   this.move_messages = function(mbox)
     {
@@ -1689,7 +1736,7 @@
       this.set_busy(true, 'movingmessage');
       }
     // send request to server
-    this.http_request('moveto', '_uid='+a_uids.join(',')+'&_mbox='+escape(this.env.mailbox)+'&_target_mbox='+escape(mbox)+'&_from='+(this.env.action ? this.env.action : ''), lock);
+    this.http_request('moveto', '_uid='+a_uids.join(',')+'&_mbox='+urlencode(this.env.mailbox)+'&_target_mbox='+urlencode(mbox)+'&_from='+(this.env.action ? this.env.action : ''), lock);
     };
 
   this.permanently_remove_messages = function() {
@@ -1720,7 +1767,7 @@
       if (new_row) this.select_row(new_row.uid,false,false);
 
     // send request to server
-    this.http_request('delete', '_uid='+a_uids.join(',')+'&_mbox='+escape(this.env.mailbox)+'&_from='+(this.env.action ? this.env.action : ''));
+    this.http_request('delete', '_uid='+a_uids.join(',')+'&_mbox='+urlencode(this.env.mailbox)+'&_from='+(this.env.action ? this.env.action : ''));
   }
     
     
@@ -1913,6 +1960,19 @@
     return true;  
   }
 
+
+  this.get_mailbox_li = function(mbox)
+    {
+    if (this.gui_objects.mailboxlist)
+      {
+      mbox = String((mbox ? mbox : this.env.mailbox)).toLowerCase().replace(this.mbox_expression, '');
+      return document.getElementById('rcmbx'+mbox);
+      }
+    
+    return null;
+    };
+    
+
   /*********************************************************/
   /*********        message compose methods        *********/
   /*********************************************************/
@@ -1963,12 +2023,15 @@
 
     return true;
     };
-    
+
+
   this.auto_save_start = function()
     {
-    rcube_save_timer = self.setTimeout('rcmail.command("savedraft","",this)',DRAFT_AUTOSAVE * 60000);
-    }
- 
+    if (this.env.draft_autosave)
+      this.save_timer = self.setTimeout(this.ref+'.command("savedraft")', this.env.draft_autosave * 1000);
+    };
+
+
   this.compose_field_hash = function()
     {
     // check input fields
@@ -2118,7 +2181,7 @@
 
   // add file name to attachment list
   // called from upload page
-  this.add2attachment_list = function(name,content)
+  this.add2attachment_list = function(name, content)
     {
     if (!this.gui_objects.attachmentlist)
       return false;
@@ -2138,16 +2201,16 @@
     var list = this.gui_objects.attachmentlist.getElementsByTagName("li");
     for (i=0;i<list.length;i++)
       if (list[i].id == name)
-	this.gui_objects.attachmentlist.removeChild(list[i]);
-    }
+        this.gui_objects.attachmentlist.removeChild(list[i]);
+    };
 
   this.remove_attachment = function(name)
     {
     if (name)
-      this.http_request('remove-attachment', '_filename='+escape(name));
+      this.http_request('remove-attachment', '_file='+urlencode(name));
 
     return true;
-    }
+    };
 
   // send remote request to add a new contact
   this.add_contact = function(value)
@@ -2179,7 +2242,14 @@
     this.env.search_request = null;
     return true;
     };
-    
+
+
+  this.sent_successfully = function(msg)
+    {
+    this.list_mailbox();
+    this.display_message(msg, 'confirmation', true);
+    }
+
 
   /*********************************************************/
   /*********     keyboard live-search methods      *********/
@@ -2220,7 +2290,6 @@
           highlight.removeAttribute('id');
           //highlight.removeAttribute('class');
           this.set_classname(highlight, 'selected', false);
-          this.set_classname(highlight, 'unfocused', false);
           }
 
         if (next)
@@ -2640,49 +2709,210 @@
     };
 
 
+  // tell server to create and subscribe a new mailbox
   this.create_folder = function(name)
     {
+	if (this.edit_folder)
+	  this.reset_folder_rename();
+
     var form;
     if ((form = this.gui_objects.editform) && form.elements['_folder_name'])
       name = form.elements['_folder_name'].value;
 
     if (name)
-      this.http_request('create-folder', '_name='+escape(name), true);
+      this.http_request('create-folder', '_name='+urlencode(name), true);
     else if (form.elements['_folder_name'])
       form.elements['_folder_name'].focus();
     };
 
+
+  // entry point for folder renaming
   this.rename_folder = function(props)
     {
-    var form;
-    if ((form = this.gui_objects.editform) && form.elements['_folder_oldname'] && form.elements['_folder_newname'])
-      {	
+    var form, oldname, newname;
+    
+    // rename a specific mailbox
+    if (props)
+      this.edit_foldername(props);
+
+    // use a dropdown and input field (old behavior)
+    else if ((form = this.gui_objects.editform) && form.elements['_folder_oldname'] && form.elements['_folder_newname'])
+      {
       oldname = form.elements['_folder_oldname'].value;
       newname = form.elements['_folder_newname'].value;
       }
 
     if (oldname && newname)
-      this.http_request('rename-folder', '_folder_oldname='+escape(oldname)+'&_folder_newname='+escape(newname));
-
+      this.http_request('rename-folder', '_folder_oldname='+urlencode(oldname)+'&_folder_newname='+urlencode(newname));
     };
 
 
-  this.delete_folder = function(folder)
+  // start editing the mailbox name.
+  // this will replace the name string with an input field
+  this.edit_foldername = function(folder)
     {
-    if (folder)
+    var temp, row, form;
+    var id = this.get_folder_row_id(folder);
+
+    // reset current renaming
+	if (temp = this.edit_folder)
+	  {
+	  this.reset_folder_rename();
+	  if (temp == id)
+	    return;
+	  }
+
+    if (id && (row = document.getElementById(id)))
       {
-      this.http_request('delete-folder', '_mboxes='+escape(folder));
+      this.name_input = document.createElement('INPUT');
+      this.name_input.value = this.env.subscriptionrows[id][1];
+      this.name_input.style.width = '100%';
+      this.name_input.onkeypress = function(e){ rcmail.name_input_keypress(e); };
+      
+      row.cells[0].replaceChild(this.name_input, row.cells[0].firstChild);
+      this.edit_folder = id;
+      this.name_input.select();
+      
+      if (form = this.gui_objects.editform)
+        form.onsubmit = function(){ return false; };
       }
     };
 
 
-  this.remove_folder_row = function(folder)
+  // remove the input field and write the current mailbox name to the table cell
+  this.reset_folder_rename = function()
     {
-    for (var id in this.env.subscriptionrows)
-      if (this.env.subscriptionrows[id]==folder)
+    var cell = this.name_input ? this.name_input.parentNode : null;
+    if (cell && this.edit_folder)
+      cell.innerHTML = this.env.subscriptionrows[this.edit_folder][1];
+      
+    this.edit_folder = null;
+    };
+
+
+  // handler for keyboard events on the input field
+  this.name_input_keypress = function(e)
+    {
+    var key = document.all ? event.keyCode : document.getElementById ? e.keyCode : 0;
+
+    // enter
+    if (key==13)
+      {
+      var newname = this.name_input ? this.name_input.value : null;
+      if (this.edit_folder && newname)
+        this.http_request('rename-folder', '_folder_oldname='+urlencode(this.env.subscriptionrows[this.edit_folder][0])+'&_folder_newname='+urlencode(newname));        
+      }
+    // escape
+    else if (key==27)
+      this.reset_folder_rename();
+    };
+
+
+  // delete a specific mailbox with all its messages
+  this.delete_folder = function(folder)
+    {
+	if (this.edit_folder)
+	  this.reset_folder_rename();
+    
+    if (folder)
+      this.http_request('delete-folder', '_mboxes='+urlencode(folder));
+    };
+
+
+  // add a new folder to the subscription list by cloning a folder row
+  this.add_folder_row = function(name, display_name, replace)
+    {
+    name = name.replace('\\',"");
+    if (!this.gui_objects.subscriptionlist)
+      return false;
+
+    for (var refid in this.env.subscriptionrows)
+      if (this.env.subscriptionrows[refid]!=null)
         break;
 
+    var refrow, form;
+    var tbody = this.gui_objects.subscriptionlist.tBodies[0];
+    var id = replace && replace.id ? replace.id : tbody.childNodes.length+1;
+
+    if (!id || !(refrow = document.getElementById(refid)))
+      {
+      // Refresh page if we don't have a table row to clone
+      location.href = this.env.comm_path+'&_action=folders';
+      }
+    else
+      {
+      // clone a table row if there are existing rows
+      var row = this.clone_table_row(refrow);
+      row.id = 'rcmrow'+id;
+      if (replace)
+        tbody.replaceChild(row, replace);
+      else
+        tbody.appendChild(row);
+      }
+
+    // add to folder/row-ID map
+    this.env.subscriptionrows[row.id] = [name, display_name];
+
+    // set folder name
+    row.cells[0].innerHTML = display_name;
+    if (row.cells[1] && row.cells[1].firstChild.tagName=='INPUT')
+      {
+      row.cells[1].firstChild.value = name;
+      row.cells[1].firstChild.checked = true;
+      }
+       
+    if (row.cells[2] && row.cells[2].firstChild.tagName=='A')
+      row.cells[2].firstChild.onclick = new Function(this.ref+".command('rename-folder','"+name.replace('\'','\\\'')+"')");
+    if (row.cells[3] && row.cells[3].firstChild.tagName=='A')
+      row.cells[3].firstChild.onclick = new Function(this.ref+".command('delete-folder','"+name.replace('\'','\\\'')+"')");
+
+    // add new folder to rename-folder list and clear input field
+    if (!replace && (form = this.gui_objects.editform))
+      {
+      if (form.elements['_folder_oldname'])
+        form.elements['_folder_oldname'].options[form.elements['_folder_oldname'].options.length] = new Option(name,name);
+      if (form.elements['_folder_name'])
+        form.elements['_folder_name'].value = ''; 
+      }
+
+    };
+
+
+  // replace an existing table row with a new folder line
+  this.replace_folder_row = function(oldfolder, newfolder, display_name)
+    {
+    var id = this.get_folder_row_id(oldfolder);
+    var row = document.getElementById(id);
+    
+    // replace an existing table row (if found)
+    this.add_folder_row(newfolder, display_name, row);
+    this.env.subscriptionrows[id] = null;
+    
+    // rename folder in rename-folder dropdown
+    var form, elm;
+    if ((form = this.gui_objects.editform) && (elm = form.elements['_folder_oldname']))
+      {
+      for (var i=0;i<elm.options.length;i++)
+        {
+        if (elm.options[i].value == oldfolder)
+          {
+          elm.options[i].text = display_name;
+          elm.options[i].value = newfolder;
+          break;
+          }
+        }
+
+      form.elements['_folder_newname'].value = '';
+      }
+    };
+    
+
+  // remove the table row of a specific mailbox from the table
+  // (the row will not be removed, just hidden)
+  this.remove_folder_row = function(folder)
+    {
     var row;
+    var id = this.get_folder_row_id(folder);
     if (id && (row = document.getElementById(id)))
       row.style.display = 'none';    
 
@@ -2693,13 +2923,15 @@
       for (var i=0;i<form.elements['_folder_oldname'].options.length;i++)
         {
         if (form.elements['_folder_oldname'].options[i].value == folder) 
-	  {
+          {
           form.elements['_folder_oldname'].options[i] = null;
-	  break;
+          break;
           }
         }
       }
-      form.elements['_folder_newname'].value='';
+    
+    if (form && form.elements['_folder_newname'])
+      form.elements['_folder_newname'].value = '';
     };
 
 
@@ -2709,7 +2941,7 @@
     if ((form = this.gui_objects.editform) && form.elements['_unsubscribed'])
       this.change_subscription('_unsubscribed', '_subscribed', 'subscribe');
     else if (folder)
-      this.http_request('subscribe', '_mboxes='+escape(folder));
+      this.http_request('subscribe', '_mboxes='+urlencode(folder));
     };
 
 
@@ -2719,7 +2951,7 @@
     if ((form = this.gui_objects.editform) && form.elements['_subscribed'])
       this.change_subscription('_subscribed', '_unsubscribed', 'unsubscribe');
     else if (folder)
-      this.http_request('unsubscribe', '_mboxes='+escape(folder));
+      this.http_request('unsubscribe', '_mboxes='+urlencode(folder));
     };
     
 
@@ -2753,58 +2985,21 @@
           list_to[index] = new Option(a_folders[n]);
           }
           
-        this.http_request(action, '_mboxes='+escape(a_folders.join(',')));
+        this.http_request(action, '_mboxes='+urlencode(a_folders.join(',')));
         }
       }
       
     };
 
-
-   // add a new folder to the subscription list by cloning a folder row
-   this.add_folder_row = function(name)
-     {
-     name = name.replace('\\',"");
-     if (!this.gui_objects.subscriptionlist)
-       return false;
-
-     var tbody = this.gui_objects.subscriptionlist.tBodies[0];
-     var id = tbody.childNodes.length+1;
-   
-     if (!tbody.rows[0]) 
-       {
-       // Refresh to create the first table row
-       location.href = this.env.comm_path+'&_action=folders';
-       }
-     else
-       {
-       // clone a table row if there are existing rows
-       var row = this.clone_table_row(tbody.rows[0]);
-       row.id = 'rcmrow'+id;
-       tbody.appendChild(row);
-       }
-
-     // add to folder/row-ID map
-     this.env.subscriptionrows[row.id] = name;
-
-     // set folder name
-     row.cells[0].innerHTML = name;
-     if (row.cells[1].firstChild.tagName=='INPUT')
-       {
-       row.cells[1].firstChild.value = name;
-       row.cells[1].firstChild.checked = true;
-       }
-     if (row.cells[2].firstChild.tagName=='A')
-       row.cells[2].firstChild.onclick = new Function(this.ref+".command('delete-folder','"+name.replace('\'','\\\'')+"')");
-
-     var form;
-     if ((form = this.gui_objects.editform) && form.elements['_folder_name'])
-       form.elements['_folder_name'].value = '';
- 
-     // add new folder to rename-folder list
-     form.elements['_folder_oldname'].options[form.elements['_folder_oldname'].options.length] = new Option(name,name);
-
-     };
-
+  // helper method to find a specific mailbox row ID
+  this.get_folder_row_id = function(folder)
+    {
+    for (var id in this.env.subscriptionrows)
+      if (this.env.subscriptionrows[id] && this.env.subscriptionrows[id][0] == folder)
+        break;
+        
+    return id;
+    };
 
   // duplicate a specific table row
   this.clone_table_row = function(row)
@@ -2978,7 +3173,7 @@
   
     if (!this.gui_objects.message)
       return false;
-     
+
     if (this.message_timer)
       clearTimeout(this.message_timer);
     
@@ -3012,32 +3207,66 @@
   // mark a mailbox as selected and set environment variable
   this.select_mailbox = function(mbox)
     {
-    if (this.gui_objects.mailboxlist)
+    if (this.gui_objects.mailboxlist )
       {
-      var item, reg, text_obj;
-      var s_current = this.env.mailbox.toLowerCase().replace(this.mbox_expression, '');
-      var s_mbox = String(mbox).toLowerCase().replace(this.mbox_expression, '');
-      var s_current = this.env.mailbox.toLowerCase().replace(this.mbox_expression, '');
+      var item, reg, text_obj;      
+      var current_li = this.get_mailbox_li();
+      var mbox_li = this.get_mailbox_li(mbox);
       
-      var current_li = document.getElementById('rcmbx'+s_current);
-      var mbox_li = document.getElementById('rcmbx'+s_mbox);
-      
-      if (current_li) {
+      if (current_li)
+        {
         this.set_classname(current_li, 'selected', false);
         this.set_classname(current_li, 'unfocused', false);
         }
-      if (mbox_li)
+
+      if (mbox_li || this.env.mailbox == mbox)
+        {
+        this.set_classname(mbox_li, 'unfocused', false);
         this.set_classname(mbox_li, 'selected', true);
+        }
+      }
+      
+    // also update mailbox name in window title
+    if (document.title)
+      {
+      var doc_title = String(document.title);
+      var reg = new RegExp(this.env.mailbox.toLowerCase(), 'i');
+      if (this.env.mailbox && doc_title.match(reg))
+        document.title = doc_title.replace(reg, mbox).replace(/^\([0-9]+\)\s+/i, '');
       }
     
     this.env.mailbox = mbox;
     };
 
+
   // for reordering column array, Konqueror workaround
   this.set_message_coltypes = function(coltypes) 
   { 
-  this.coltypes = coltypes; 
-  }
+    this.coltypes = coltypes;
+    
+    // set correct list titles
+    var cell, col;
+    var thead = this.gui_objects.messagelist ? this.gui_objects.messagelist.tHead : null;
+    for (var n=0; thead && n<this.coltypes.length; n++) 
+      {
+      col = this.coltypes[n];
+      if ((cell = thead.rows[0].cells[n+1]) && (col=='from' || col=='to'))
+        {
+        // if we have links for sorting, it's a bit more complicated...
+        if (cell.firstChild && cell.firstChild.tagName=='A')
+          {
+          cell.firstChild.innerHTML = this.get_label(this.coltypes[n]);
+          cell.firstChild.onclick = function(){ return rcmail.command('sort', this.__col, this); };
+          cell.firstChild.__col = col;
+          }
+        else
+          cell.innerHTML = this.get_label(this.coltypes[n]);
+
+        cell.id = 'rcmHead'+col;
+        }
+      }
+
+  };
 
   // create a table row in the message list
   this.add_message_row = function(uid, cols, flags, attachment, attop)
@@ -3120,9 +3349,9 @@
     if (mbox==this.env.mailbox)
       set_title = true;
 
-    var item, reg, text_obj;
+    var reg, text_obj;
+    var item = this.get_mailbox_li(mbox);
     mbox = String(mbox).toLowerCase().replace(this.mbox_expression, '');
-    item = document.getElementById('rcmbx'+mbox);
 
     if (item && item.className && item.className.indexOf('mailbox '+mbox)>=0)
       {
@@ -3291,8 +3520,8 @@
     // send request
     if (request_obj)
       {
-      // prompt('request', this.env.comm_path+'&_action='+escape(action)+'&'+querystring);
-      console('HTTP request: '+this.env.comm_path+'&_action='+escape(action)+'&'+querystring);
+      // prompt('request', this.env.comm_path+'&_action='+urlencode(action)+'&'+querystring);
+      console('HTTP request: '+this.env.comm_path+'&_action='+action+'&'+querystring);
 
       if (lock)
         this.set_busy(true);
@@ -3301,7 +3530,7 @@
       request_obj.__action = action;
       request_obj.onerror = function(o){ rcube_webmail_client.http_error(o); };
       request_obj.oncomplete = function(o){ rcube_webmail_client.http_response(o); };
-      request_obj.GET(this.env.comm_path+'&_action='+escape(action)+'&'+querystring);
+      request_obj.GET(this.env.comm_path+'&_action='+action+'&'+querystring);
       }
     };
 
@@ -3349,7 +3578,7 @@
   // handle HTTP request errors
   this.http_error = function(request_obj)
     {
-    alert('Error sending request: '+request_obj.url);
+    //alert('Error sending request: '+request_obj.url);
 
     if (request_obj.__lock)
       this.set_busy(false);
@@ -3370,6 +3599,12 @@
   // send periodic request to check for recent messages
   this.check_for_recent = function()
     {
+    if (this.busy)
+      {
+      this.send_keep_alive();
+      return;
+      }
+
     this.set_busy(true, 'checkingmail');
     var d = new Date();
     this.http_request('check-recent', '_t='+d.getTime());
@@ -3612,14 +3847,21 @@
 
     else if(this.xmlhttp.readyState == 4)
       {
-      if(this.xmlhttp.status == 0)
-        this.onabort(this);
-      else if(this.xmlhttp.status == 200)
-        this.oncomplete(this);
-      else
+      try {
+        if (this.xmlhttp.status == 0)
+          this.onabort(this);
+        else if(this.xmlhttp.status == 200)
+          this.oncomplete(this);
+        else
+          this.onerror(this);
+
+        this.busy = false;
+        }
+      catch(err)
+        {
         this.onerror(this);
-        
-      this.busy = false;
+        this.busy = false;
+        }
       }
     }
 

--
Gitblit v1.9.1