From a039c626eef6ad0e6c915d1618fbd0e6e40f57a2 Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Thu, 04 Mar 2010 09:39:47 -0500
Subject: [PATCH] - Fix deleting all messages from last list page (#1486293)

---
 program/js/app.js |  909 ++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 616 insertions(+), 293 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index 4f12e80..f6cf04b 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -22,6 +22,7 @@
   this.env = new Object();
   this.labels = new Object();
   this.buttons = new Object();
+  this.buttons_sel = new Object();
   this.gui_objects = new Object();
   this.gui_containers = new Object();
   this.commands = new Object();
@@ -55,7 +56,7 @@
   // set jQuery ajax options
   jQuery.ajaxSetup({ cache:false,
     error:function(request, status, err){ ref.http_error(request, status, err); },
-    beforeSend:function(xmlhttp){ xmlhttp.setRequestHeader('X-RoundCube-Referer', bw.get_cookie('roundcube_sessid')); }
+    beforeSend:function(xmlhttp){ xmlhttp.setRequestHeader('X-RoundCube-Request', ref.env.request_token); }
   });
 
   // set environment variable(s)
@@ -134,7 +135,7 @@
       this.goto_url('error', '_code=0x199');
       return;
       }
-    
+
     // find all registered gui containers
     for (var n in this.gui_containers)
       this.gui_containers[n] = $('#'+this.gui_containers[n]);
@@ -142,6 +143,9 @@
     // find all registered gui objects
     for (var n in this.gui_objects)
       this.gui_objects[n] = rcube_find_object(this.gui_objects[n]);
+      
+    // init registered buttons
+    this.init_buttons();
 
     // tell parent window that this frame is loaded
     if (this.env.framed && parent.rcmail && parent.rcmail.set_busy)
@@ -152,7 +156,7 @@
     
     if (this.env.permaurl)
       this.enable_command('permaurl', true);
-    
+
     switch (this.task)
       {
       case 'mail':
@@ -164,8 +168,8 @@
           this.message_list.addEventListener('keypress', function(o){ p.msglist_keypress(o); });
           this.message_list.addEventListener('select', function(o){ p.msglist_select(o); });
           this.message_list.addEventListener('dragstart', function(o){ p.drag_start(o); });
-          this.message_list.addEventListener('dragmove', function(o, e){ p.drag_move(e); });
-          this.message_list.addEventListener('dragend', function(o, e){ p.drag_end(e); });
+          this.message_list.addEventListener('dragmove', function(e){ p.drag_move(e); });
+          this.message_list.addEventListener('dragend', function(e){ p.drag_end(e); });
           document.onmouseup = function(e){ return p.doc_mouse_up(e); };
 
           this.message_list.init();
@@ -189,7 +193,7 @@
         if (this.env.action=='show' || this.env.action=='preview')
           {
           this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete',
-	    'open', 'mark', 'viewsource', 'download', 'print', 'load-attachment', 'load-headers', true);
+            'open', 'mark', 'edit', 'viewsource', 'download', 'print', 'load-attachment', 'load-headers', true);
 
           if (this.env.next_uid)
             {
@@ -202,7 +206,7 @@
             this.enable_command('firstmessage', true);
             }
         
-	  if (this.env.blockedobjects)
+          if (this.env.blockedobjects)
             {
             if (this.gui_objects.remoteobjectsmsg)
               this.gui_objects.remoteobjectsmsg.style.display = 'block';
@@ -234,6 +238,9 @@
             this.enable_command('savedraft', true);
             
           document.onmouseup = function(e){ return p.doc_mouse_up(e); };
+
+          // init message compose form
+          this.init_messageform();
           }
 
         if (this.env.messagecount)
@@ -243,10 +250,6 @@
           this.enable_command('purge', true);
 
         this.set_page_buttons();
-
-        // init message compose form
-        if (this.env.action=='compose')
-          this.init_messageform();
 
         // show printing dialog
         if (this.env.action=='print')
@@ -277,11 +280,12 @@
         if (this.gui_objects.contactslist)
           {
           this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, {multiselect:true, draggable:true, keyboard:true});
+          this.contact_list.row_init = function(row){ p.triggerEvent('insertrow', { cid:row.uid, row:row }); };
           this.contact_list.addEventListener('keypress', function(o){ p.contactlist_keypress(o); });
           this.contact_list.addEventListener('select', function(o){ p.contactlist_select(o); });
           this.contact_list.addEventListener('dragstart', function(o){ p.drag_start(o); });
-          this.contact_list.addEventListener('dragmove', function(o, e){ p.drag_move(e); });
-          this.contact_list.addEventListener('dragend', function(o, e){ p.drag_end(e); });
+          this.contact_list.addEventListener('dragmove', function(e){ p.drag_move(e); });
+          this.contact_list.addEventListener('dragend', function(e){ p.drag_end(e); });
           this.contact_list.init();
 
           if (this.env.cid)
@@ -301,7 +305,7 @@
         this.set_page_buttons();
         
         if (this.env.address_sources && this.env.address_sources[this.env.source] && !this.env.address_sources[this.env.source].readonly)
-          this.enable_command('add', true);
+          this.enable_command('add', 'import', true);
         
         if (this.env.cid)
           this.enable_command('show', 'edit', true);
@@ -309,7 +313,7 @@
         if ((this.env.action=='add' || this.env.action=='edit') && this.gui_objects.editform)
           this.enable_command('save', true);
         else
-          this.enable_command('search', 'reset-search', 'moveto', 'import', true);
+          this.enable_command('search', 'reset-search', 'moveto', true);
           
         if (this.contact_list && this.contact_list.rowcount > 0)
           this.enable_command('export', true);
@@ -321,15 +325,14 @@
       case 'settings':
         this.enable_command('preferences', 'identities', 'save', 'folders', true);
         
-        if (this.env.action=='identities' || this.env.action=='edit-identity' || this.env.action=='add-identity') {
+        if (this.env.action=='identities') {
           this.enable_command('add', this.env.identities_level < 2);
-          this.enable_command('delete', 'edit', true);
         }
-
-        if (this.env.action=='edit-identity' || this.env.action=='add-identity')
-          this.enable_command('save', true);
-          
-        if (this.env.action=='folders')
+        else if (this.env.action=='edit-identity' || this.env.action=='add-identity') {
+          this.enable_command('add', this.env.identities_level < 2);
+          this.enable_command('save', 'delete', 'edit', true);
+        }
+        else if (this.env.action=='folders')
           this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', 'delete-folder', true);
 
         if (this.gui_objects.identitieslist)
@@ -342,8 +345,15 @@
           if (this.env.iid)
             this.identity_list.highlight_row(this.env.iid);
           }
-
-        if (this.gui_objects.subscriptionlist)
+        else if (this.gui_objects.sectionslist)
+          {
+          this.sections_list = new rcube_list_widget(this.gui_objects.sectionslist, {multiselect:false, draggable:false, keyboard:false});
+          this.sections_list.addEventListener('select', function(o){ p.section_select(o); });
+          this.sections_list.init();
+          this.sections_list.focus();
+          this.sections_list.select_first();  // open first section by default
+        }
+        else if (this.gui_objects.subscriptionlist)
           this.init_subscription_list();
 
         break;
@@ -366,9 +376,6 @@
       default:
         break;
       }
-
-    // enable basic commands
-    this.enable_command('logout', true);
 
     // flag object as complete
     this.loaded = true;
@@ -420,7 +427,7 @@
       }
 
     // set eventhandler to message icon
-    if (row.icon = row.obj.getElementsByTagName('TD')[0].getElementsByTagName('IMG')[0])
+    if (row.icon = row.obj.getElementsByTagName('td')[0].getElementsByTagName('img')[0])
       {
       var p = this;
       row.icon.id = 'msgicn_'+row.uid;
@@ -437,13 +444,15 @@
       }
 
     // set eventhandler to flag icon, if icon found
-    if (this.env.flagged_col && (row.flagged_icon = row.obj.getElementsByTagName('TD')[this.env.flagged_col].getElementsByTagName('IMG')[0]))
+    if (this.env.flagged_col && (row.flagged_icon = row.obj.getElementsByTagName('td')[this.env.flagged_col].getElementsByTagName('img')[0]))
       {
       var p = this;
       row.flagged_icon.id = 'flaggedicn_'+row.uid;
       row.flagged_icon._row = row.obj;
       row.flagged_icon.onmousedown = function(e) { p.command('toggle_flag', this); };
       }
+      
+    this.triggerEvent('insertrow', { uid:uid, row:row });
   };
 
   // init message compose form: set focus and eventhandlers
@@ -457,23 +466,29 @@
     var input_to = $("[name='_to']");
     var input_subject = $("input[name='_subject']");
     var input_message = $("[name='_message']").get(0);
+    var html_mode = $("input[name='_is_html']").val() == '1';
 
     // init live search events
     this.init_address_input_events(input_to);
     this.init_address_input_events($("[name='_cc']"));
     this.init_address_input_events($("[name='_bcc']"));
+    
+    if (!html_mode)
+      this.set_caret_pos(input_message, this.env.top_posting ? 0 : $(input_message).val().length);
 
     // add signature according to selected identity
     if (input_from.attr('type') == 'select-one' && $("input[name='_draft_saveid']").val() == ''
-        && $("input[name='_is_html']").val() != '1') {  // if we have HTML editor, signature is added in callback
+        && !html_mode) {  // if we have HTML editor, signature is added in callback
       this.change_identity(input_from[0]);
     }
+    else if (!html_mode) 
+      this.set_caret_pos(input_message, this.env.top_posting ? 0 : $(input_message).val().length);
 
     if (input_to.val() == '')
       input_to.focus();
     else if (input_subject.val() == '')
       input_subject.focus();
-    else if (input_message)
+    else if (input_message && !html_mode)
       input_message.focus();
 
     // get summary of all field values
@@ -551,14 +566,11 @@
           this.gui_objects.loginform.submit();
         break;
 
-      case 'logout':
-        this.goto_url('logout', '', true);
-        break;
-
       // commands to switch task
       case 'mail':
       case 'addressbook':
       case 'settings':
+      case 'logout':
         this.switch_task(command);
         break;
 
@@ -596,7 +608,7 @@
             this.reset_qsearch();
 
           this.list_contacts(props);
-          this.enable_command('add', (this.env.address_sources && !this.env.address_sources[props].readonly));
+          this.enable_command('add', 'import', (this.env.address_sources && !this.env.address_sources[props].readonly));
           }
         break;
 
@@ -612,8 +624,8 @@
         if (this.env.sort_col==sort_col)
           sort_order = this.env.sort_order=='ASC' ? 'DESC' : 'ASC';
         else
-	  sort_order = 'ASC';
-	
+          sort_order = 'ASC';
+
         // set table header class
         $('#rcm'+this.env.sort_col).removeClass('sorted'+(this.env.sort_order.toUpperCase()));
         $('#rcm'+sort_col).addClass('sorted'+sort_order);
@@ -691,6 +703,10 @@
           this.load_contact(cid, 'edit');
         else if (this.task=='settings' && props)
           this.load_identity(props, 'edit-identity');
+        else if (this.task=='mail' && (cid = this.get_single_uid())) {
+          var url = (this.env.mailbox == this.env.drafts_mailbox) ? '_draft_uid=' : '_uid=';
+          this.goto_url('compose', url+cid+'&_mbox='+urlencode(this.env.mailbox), true);
+        }
         break;
 
       case 'save-identity':
@@ -828,7 +844,7 @@
       case 'select-all':
         if (props == 'invert')
           this.message_list.invert_selection();
-	else
+        else
           this.message_list.select_all(props);
         break;
 
@@ -912,7 +928,7 @@
         break;
         
       case 'spellcheck':
-        if (window.tinyMCE && tinyMCE.get('compose-body')) {
+        if (window.tinyMCE && tinyMCE.get(this.env.composebody)) {
           tinyMCE.execCommand('mceSpellCheck', true);
         }
         else if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready) {
@@ -973,6 +989,10 @@
       
       case 'remove-attachment':
         this.remove_attachment(props);
+        break;
+
+      case 'insert-sig':
+        this.change_identity($("[name='_from']")[0], true);
         break;
 
       case 'reply-all':
@@ -1055,7 +1075,7 @@
           this.lock_form(this.gui_objects.importform, true);
         }
         else
-          this.goto_url('import');
+          this.goto_url('import', (this.env.source ? '_target='+urlencode(this.env.source)+'&' : ''));
         break;
         
       case 'export':
@@ -1205,6 +1225,16 @@
     this.set_busy(false);
     this.display_message('Request timed out!', 'error');
     };
+  
+  this.reload = function(delay)
+  {
+    if (this.env.framed && parent.rcmail)
+      parent.rcmail.reload(delay);
+    else if (delay)
+      window.setTimeout(function(){ rcmail.reload(); }, delay);
+    else if (window.location)
+      location.href = this.env.comm_path;
+  };
 
 
   /*********************************************************/
@@ -1238,6 +1268,14 @@
       this.env.last_folder_target = null;
       list.draglayer.hide();
     }
+    
+    // reset 'pressed' buttons
+    if (this.buttons_sel) {
+      for (var id in this.buttons_sel)
+        if (typeof id != 'function')
+          this.button_out(this.buttons_sel[id], id);
+      this.buttons_sel = {};
+    }
   };
 
   this.drag_start = function(list)
@@ -1262,10 +1300,12 @@
       this.env.folder_coords = new Array();
       for (var k in model) {
         if (li = this.get_folder_li(k)) {
-          pos = $(li.firstChild).offset();
           // only visible folders
-          if (height = li.firstChild.offsetHeight)
-            this.env.folder_coords[k] = { x1:pos.left, y1:pos.top, x2:pos.left + li.firstChild.offsetWidth, y2:pos.top + height };
+          if (height = li.firstChild.offsetHeight) {
+            pos = $(li.firstChild).offset();
+            this.env.folder_coords[k] = { x1:pos.left, y1:pos.top,
+              x2:pos.left + li.firstChild.offsetWidth, y2:pos.top + height, on:0 };
+          }
         }
       }
     }
@@ -1274,14 +1314,19 @@
   this.drag_end = function(e)
   {
     this.drag_active = false;
+    this.env.last_folder_target = null;
+    
+    if (this.folder_auto_timer) {
+      window.clearTimeout(this.folder_auto_timer);
+      this.folder_auto_timer = null;
+      this.folder_auto_expand = null;
+    }
 
     // over the folders
     if (this.gui_objects.folderlist && this.env.folder_coords) {
       for (var k in this.env.folder_coords) {
-        if (k == this.env.last_folder_target) {
+        if (this.env.folder_coords[k].on)
           $(this.get_folder_li(k)).removeClass('droptarget');
-          this.env.last_folder_target = null;
-        }
       }
     }
   };
@@ -1294,38 +1339,58 @@
       var moffset = this.initialListScrollTop-this.gui_objects.folderlist.parentNode.scrollTop;
       var toffset = -moffset-boffset;
 
-      var li, pos, mouse;
+      var li, div, pos, mouse;
       mouse = rcube_event.get_mouse_pos(e);
       pos = this.env.folderlist_coords;
-
       mouse.y += toffset;
 
       // if mouse pointer is outside of folderlist
       if (mouse.x < pos.x1 || mouse.x >= pos.x2 || mouse.y < pos.y1 || mouse.y >= pos.y2) {
         if (this.env.last_folder_target) {
           $(this.get_folder_li(this.env.last_folder_target)).removeClass('droptarget');
+          this.env.folder_coords[this.env.last_folder_target].on = 0;
           this.env.last_folder_target = null;
         }
         return;
       }
-
+    
       // over the folders
       for (var k in this.env.folder_coords) {
         pos = this.env.folder_coords[k];
-        if (this.check_droptarget(k) && ((mouse.x >= pos.x1) && (mouse.x < pos.x2) 
-            && (mouse.y >= pos.y1) && (mouse.y < pos.y2))) {
-          $(this.get_folder_li(k)).addClass('droptarget');
+        if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.y >= pos.y1 && mouse.y < pos.y2
+            && this.check_droptarget(k)) {
+
+          li = this.get_folder_li(k);
+          div = $(li.getElementsByTagName("div")[0]);
+
+          // if the folder is collapsed, expand it after 1sec and restart the drag & drop process.
+          if (div.hasClass('collapsed')) {
+            if (this.folder_auto_timer)
+              window.clearTimeout(this.folder_auto_timer);
+            
+            this.folder_auto_expand = k;
+            this.folder_auto_timer = window.setTimeout(function() {
+                rcmail.command("collapse-folder", rcmail.folder_auto_expand);
+                rcmail.drag_start(null);
+              }, 1000);
+          } else if (this.folder_auto_timer) {
+            window.clearTimeout(this.folder_auto_timer);
+            this.folder_auto_timer = null;
+            this.folder_auto_expand = null;
+          }
+          
+          $(li).addClass('droptarget');
           this.env.last_folder_target = k;
+          this.env.folder_coords[k].on = 1;
         }
-        else {
+        else if (pos.on) {
           $(this.get_folder_li(k)).removeClass('droptarget');
-          if (k == this.env.last_folder_target)
-            this.env.last_folder_target = null;
+          this.env.folder_coords[k].on = 0;
         }
       }
     }
   };
-  
+
   this.collapse_folder = function(id)
     {
     var div;
@@ -1392,12 +1457,12 @@
     if (this.env.mailbox == this.env.drafts_mailbox)
       {
       this.enable_command('reply', 'reply-all', 'forward', false);
-      this.enable_command('show', 'print', 'open', 'download', 'viewsource', selected);
+      this.enable_command('show', 'print', 'open', 'edit', 'download', 'viewsource', selected);
       this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false));
       }
     else
       {
-      this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', 'open', 'download', 'viewsource', selected);
+      this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', 'edit', 'open', 'download', 'viewsource', selected);
       this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false));
       }
 
@@ -1553,15 +1618,14 @@
       this.env.current_page = 1;
       this.set_busy(true, 'searching');
       this.http_request('search', '_filter='+filter
-    	    + (search ? '&_q='+urlencode(search) : '')
-    	    + (this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : ''), true);
+          + (search ? '&_q='+urlencode(search) : '')
+          + (this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : ''), true);
     }
 
 
   // list messages of a specific mailbox
   this.list_mailbox = function(mbox, page, sort)
     {
-    this.last_selected = 0;
     var add_url = '';
     var target = window;
 
@@ -1575,19 +1639,22 @@
     // also send search request to get the right messages
     if (this.env.search_request)
       add_url += '&_search='+this.env.search_request;
-      
+
     // set page=1 if changeing to another mailbox
-    if (!page && mbox != this.env.mailbox)
+    if (!page && this.env.mailbox != mbox)
       {
       page = 1;
       this.env.current_page = page;
-      if (this.message_list)
-        this.message_list.clear_selection();
       this.show_contentframe(false);
       }
-    
+
     if (mbox != this.env.mailbox || (mbox == this.env.mailbox && !page && !sort))
       add_url += '&_refresh=1';
+
+    // unselect selected messages
+    this.last_selected = 0;
+    if (this.message_list)
+      this.message_list.clear_selection();
     
     this.select_folder(mbox, this.env.mailbox);
     this.env.mailbox = mbox;
@@ -1796,13 +1863,13 @@
       lock = true;
       this.set_busy(true, 'movingmessage');
       }
-    else if (!this.env.flag_for_deletion)
+    else
       this.show_contentframe(false);
 
     // Hide message command buttons until a message is selected
-    this.enable_command('reply', 'reply-all', 'forward', 'delete', 'mark', 'print', 'open', 'viewsource', 'download', false);
+    this.enable_command('reply', 'reply-all', 'forward', 'delete', 'mark', 'print', 'open', 'edit', 'viewsource', 'download', false);
 
-    this._with_selected_messages('moveto', lock, add_url, (this.env.flag_for_deletion ? false : true));
+    this._with_selected_messages('moveto', lock, add_url);
     };
 
   // delete selected messages from the current mailbox
@@ -1814,9 +1881,14 @@
     if (!this.env.uid && !selection.length)
       return;
 
-    // if there is a trash mailbox defined and we're not currently in it:
-    if (this.env.trash_mailbox && String(this.env.mailbox).toLowerCase() != String(this.env.trash_mailbox).toLowerCase())
-      {
+    // if config is set to flag for deletion
+    if (this.env.flag_for_deletion)
+      this.mark_message('delete');
+    // if there isn't a defined trash mailbox or we are in it
+    else if (!this.env.trash_mailbox || this.env.mailbox == this.env.trash_mailbox) 
+      this.permanently_remove_messages();
+    // if there is a trash mailbox defined and we're not currently in it
+    else {
       // if shift was pressed delete it immediately
       if (this.message_list && this.message_list.shiftkey)
         {
@@ -1826,21 +1898,6 @@
       else
         this.move_messages(this.env.trash_mailbox);
       }
-    // if there is a trash mailbox defined but we *are* in it:
-    else if (this.env.trash_mailbox && String(this.env.mailbox).toLowerCase() == String(this.env.trash_mailbox).toLowerCase())
-      this.permanently_remove_messages();
-    // if there isn't a defined trash mailbox and the config is set to flag for deletion
-    else if (!this.env.trash_mailbox && this.env.flag_for_deletion)
-      {
-      this.mark_message('delete');
-      if (this.env.action == 'show')
-        this.command('nextmessage', '', this);
-      else if (selection.length == 1)
-        this.message_list.select_next();
-      }
-    // if there isn't a defined trash mailbox and the config is set NOT to flag for deletion
-    else if (!this.env.trash_mailbox) 
-      this.permanently_remove_messages();
   };
 
   // delete the selected messages permanently
@@ -1851,7 +1908,7 @@
       return;
       
     this.show_contentframe(false);
-    this._with_selected_messages('delete', false, '&_from='+(this.env.action ? this.env.action : ''), true);
+    this._with_selected_messages('delete', false, '&_from='+(this.env.action ? this.env.action : ''));
     };
 
   // Send a specifc request with UIDs of all selected messages
@@ -1867,28 +1924,21 @@
       var selection = this.message_list.get_selection();
       var rows = this.message_list.rows;
       var id;
-      for (var n=0; n<selection.length; n++)
-        {
+      for (var n=0; n<selection.length; n++) {
         id = selection[n];
         a_uids[a_uids.length] = id;
-
-        if (remove)
-          this.message_list.remove_row(id, (n == selection.length-1));
-        else
-        {
-          this.set_message_status(id, 'deleted', true);
-          if (this.env.read_when_deleted)
-            this.set_message_status(id, 'unread', false);
-          this.set_message(id);
-        }
+        this.message_list.remove_row(id, (this.env.display_next && n == selection.length-1));
       }
+      // make sure there are no selected rows
+      if (!this.env.display_next)
+        this.message_list.clear_selection();
     }
 
     // also send search request to get the right messages 
     if (this.env.search_request) 
       add_url += '&_search='+this.env.search_request;
 
-    if (this.env.next_uid)
+    if (this.env.display_next && this.env.next_uid)
       add_url += '&_next_uid='+this.env.next_uid;
 
     // send request to server
@@ -2028,15 +2078,33 @@
       uid = a_uids[i];
       if (rows[uid])
         {
-	this.set_message(uid, 'deleted', true);
         if (rows[uid].unread)
           r_uids[r_uids.length] = uid;
+
+	if (this.env.skip_deleted)
+          this.message_list.remove_row(uid, (this.env.display_next && i == this.message_list.selection.length-1));
+	else
+	  this.set_message(uid, 'deleted', true);
         }
       }
 
-    if (r_uids.length)
-      add_url = '&_ruid='+r_uids.join(',');
+    // make sure there are no selected rows
+    if (this.env.skip_deleted && !this.env.display_next && this.message_list)
+      this.message_list.clear_selection();
 
+    add_url = '&_from='+(this.env.action ? this.env.action : '');
+    
+    if (r_uids.length)
+      add_url += '&_ruid='+r_uids.join(',');
+
+    if (this.env.skip_deleted) {
+      // also send search request to get the right messages 
+      if (this.env.search_request) 
+        add_url += '&_search='+this.env.search_request;
+      if (this.env.display_next && this.env.next_uid)
+        add_url += '&_next_uid='+this.env.next_uid;
+    }
+    
     this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag=delete'+add_url);
     return true;  
   };
@@ -2113,6 +2181,14 @@
       return false;
       }
 
+    // check if all files has been uploaded
+    for (var key in this.env.attachments) {
+      if (typeof this.env.attachments[key] == 'object' && !this.env.attachments[key].complete) {
+        alert(this.get_label('notuploadedwarning'));
+        return false;
+      }
+    }
+    
     // display localized warning for missing subject
     if (input_subject.val() == '')
       {
@@ -2131,19 +2207,26 @@
       }
 
     // check for empty body
-    if ((!window.tinyMCE || !tinyMCE.get('compose-body')) && input_message.val() == '' && !confirm(this.get_label('nobodywarning')))
+    if ((!window.tinyMCE || !tinyMCE.get(this.env.composebody))
+	&& input_message.val() == '' && !confirm(this.get_label('nobodywarning')))
       {
       input_message.focus();
       return false;
       }
-    else if (window.tinyMCE && tinyMCE.get('compose-body') && !tinyMCE.get('compose-body').getContent() && !confirm(this.get_label('nobodywarning')))
+    else if (window.tinyMCE && tinyMCE.get(this.env.composebody)
+	&& !tinyMCE.get(this.env.composebody).getContent()
+	&& !confirm(this.get_label('nobodywarning')))
       {
-      tinyMCE.get('compose-body').focus();
+      tinyMCE.get(this.env.composebody).focus();
       return false;
       }
 
     // Apply spellcheck changes if spell checker is active
     this.stop_spellchecking();
+
+    // move body from html editor to textarea (just to be sure, #1485860)
+    if (window.tinyMCE && tinyMCE.get(this.env.composebody))
+      tinyMCE.triggerSave();
 
     return true;
     };
@@ -2205,118 +2288,148 @@
     if (value_subject)
       str += value_subject+':';
     
-    var editor = tinyMCE.get('compose-body');
+    var editor = tinyMCE.get(this.env.composebody);
     if (editor)
       str += editor.getContent();
     else
       str += $("[name='_message']").val();
-    
+
+    if (this.env.attachments)
+      for (var upload_id in this.env.attachments)
+        str += upload_id;
+
     if (save)
       this.cmp_hash = str;
-    
+
     return str;
     };
     
-  this.change_identity = function(obj)
-    {
+  this.change_identity = function(obj, show_sig)
+  {
     if (!obj || !obj.options)
       return false;
+
+    if (!show_sig)
+      show_sig = this.env.show_sig;
 
     var id = obj.options[obj.selectedIndex].value;
     var input_message = $("[name='_message']");
     var message = input_message.val();
     var is_html = ($("input[name='_is_html']").val() == '1');
-    var sig, p, len;
+    var sig_separator = this.env.sig_above && (this.env.compose_mode == 'reply' || this.env.compose_mode == 'forward') ? '---' : '-- ';
+    var sig, cursor_pos, p = -1;
 
     if (!this.env.identity)
       this.env.identity = id
   
-    if (!is_html)
-      {
+    // enable manual signature insert
+    if (this.env.signatures && this.env.signatures[id])
+      this.enable_command('insert-sig', true);
+    else
+      this.enable_command('insert-sig', false);
+
+    if (!is_html) {
       // remove the 'old' signature
-      if (this.env.identity && this.env.signatures && this.env.signatures[this.env.identity])
-        {
-        if (this.env.signatures[this.env.identity]['is_html'])
-          sig = this.env.signatures[this.env.identity]['plain_text'];
-        else
-          sig = this.env.signatures[this.env.identity]['text'];
+      if (show_sig && this.env.identity && this.env.signatures && this.env.signatures[this.env.identity]) {
+        sig = this.env.signatures[this.env.identity].is_html ? this.env.signatures[this.env.identity].plain_text : this.env.signatures[this.env.identity].text;
         
-        if (sig.indexOf('-- ')!=0)
-          sig = '-- \n'+sig;
+        if (sig.indexOf('-- ') != 0)
+          sig = sig_separator + '\n' + sig;
 
-        p = message.lastIndexOf(sig);
-        if (p>=0)
-          message = message.substring(0, p-1) + message.substring(p+sig.length, message.length);
-        }
-
-      message = message.replace(/[\r\n]+$/, '');
-      len = message.length;
+        p = this.env.sig_above ? message.indexOf(sig) : message.lastIndexOf(sig);
+        if (p >= 0)
+          message = message.substring(0, p) + message.substring(p+sig.length, message.length);
+      }
 
       // add the new signature string
-      if (this.env.signatures && this.env.signatures[id])
-        {
-        sig = this.env.signatures[id]['text'];
-        if (this.env.signatures[id]['is_html'])
-          {
-          sig = this.env.signatures[id]['plain_text'];
+      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'];
+        if (sig.indexOf('-- ') != 0)
+          sig = sig_separator + '\n' + sig;
+
+        if (this.env.sig_above) {
+          if (p >= 0) { // in place of removed signature
+            message = message.substring(0, p) + sig + message.substring(p, message.length);
+            cursor_pos = p - 1;
+          } 
+          else if (pos = this.get_caret_pos(input_message.get(0))) { // at cursor position
+            message = message.substring(0, pos) + '\n' + sig + '\n\n' + message.substring(pos, message.length);
+            cursor_pos = pos;
           }
-        if (sig.indexOf('-- ')!=0)
-          sig = '-- \n'+sig;
-        message += '\n\n'+sig;
-	if (len) len += 1;
+          else { // on top
+            cursor_pos = 0;
+            message = '\n\n' + sig + '\n\n' + message.replace(/^[\r\n]+/, '');
+          } 
+        }
+        else {
+          message = message.replace(/[\r\n]+$/, '');
+          cursor_pos = !this.env.top_posting && message.length ? message.length+1 : 0;
+          message += '\n\n' + sig;
         }
       }
-    else
-      {
-      var editor = tinyMCE.get('compose-body');
+      else
+        cursor_pos = this.env.top_posting ? 0 : message.length;
 
-      if (this.env.signatures)
-        {
-        // Append the signature as a div within the body
-        var sigElem = editor.dom.get('_rc_sig');
-        var newsig = '';
-        var htmlsig = true;
+      input_message.val(message);
+      
+      // move cursor before the signature
+      this.set_caret_pos(input_message.get(0), cursor_pos);
+    }
+    else if (is_html && show_sig && this.env.signatures) {  // html
+      var editor = tinyMCE.get(this.env.composebody);
+      var sigElem = editor.dom.get('_rc_sig');
 
-        if (!sigElem)
-          {
-          // add empty line before signature on IE
-          if (bw.ie)
-            editor.getBody().appendChild(editor.getDoc().createElement('br'));
-
-          sigElem = editor.getDoc().createElement('div');
-          sigElem.setAttribute('id', '_rc_sig');
-          editor.getBody().appendChild(sigElem);
+      // Append the signature as a div within the body
+      if (!sigElem) {
+        var body = editor.getBody();
+        var doc = editor.getDoc();
+          
+        sigElem = doc.createElement('div');
+        sigElem.setAttribute('id', '_rc_sig');
+          
+        if (this.env.sig_above) {
+          // if no existing sig and top posting then insert at caret pos
+          editor.getWin().focus(); // correct focus in IE
+            
+          var node = editor.selection.getNode();
+          if (node.nodeName == 'BODY') {
+            // no real focus, insert at start
+            body.insertBefore(sigElem, body.firstChild);
+            body.insertBefore(doc.createElement('br'), body.firstChild);
           }
-
-        if (this.env.signatures[id])
-        {
-          newsig = this.env.signatures[id]['text'];
-          htmlsig = this.env.signatures[id]['is_html'];
-
-          if (newsig) {
-            if (htmlsig && this.env.signatures[id]['plain_text'].indexOf('-- ')!=0)
-              newsig = '<p>-- </p>' + newsig;
-            else if (!htmlsig && newsig.indexOf('-- ')!=0)
-              newsig = '-- \n' + newsig;
+          else {
+            body.insertBefore(sigElem, node.nextSibling);
+            body.insertBefore(doc.createElement('br'), node.nextSibling);
           }
         }
+        else {
+          if (bw.ie)  // add empty line before signature on IE
+            body.appendChild(doc.createElement('br'));
 
-        if (htmlsig)
-          sigElem.innerHTML = newsig;
-        else
-          sigElem.innerHTML = '<pre>' + newsig + '</pre>';
+          body.appendChild(sigElem);
         }
       }
 
-    input_message.val(message);
+      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.indexOf('-- ') != 0)
+            sig = sig_separator + '<br />' + sig;
+        }
+        else {
+          sig = this.env.signatures[id].text;
+          if (sig.indexOf('-- ') != 0)
+            sig = sig_separator + '\n' + sig;
+          sig = '<pre>' + sig + '</pre>';
+        }
 
-    // move cursor before the signature
-    if (!is_html)
-      this.set_caret_pos(input_message.get(0), len);
+        sigElem.innerHTML = sig;
+      }
+    }
 
     this.env.identity = id;
     return true;
-    };
+  };
 
   this.show_attachment_form = function(a)
     {
@@ -2376,7 +2489,7 @@
         }
       else  // for standards-compilant browsers
         {
-        var frame = document.createElement('IFRAME');
+        var frame = document.createElement('iframe');
         frame.name = frame_name;
         frame.style.border = 'none';
         frame.style.width = 0;
@@ -2385,10 +2498,42 @@
         document.body.appendChild(frame);
         }
 
+      // handle upload errors, parsing iframe content in onload
+      var fr = document.getElementsByName(frame_name)[0];
+      $(fr).bind('load', {ts:ts}, function(e) {
+        var content = '';
+        try {
+          if (this.contentDocument) {
+            var d = this.contentDocument;
+          } else if (this.contentWindow) {
+            var d = this.contentWindow.document;
+          }
+          content = d.childNodes[0].innerHTML;
+        } catch (e) {}
+
+        if (!String(content).match(/add2attachment/) && (!bw.opera || (rcmail.env.uploadframe && rcmail.env.uploadframe == e.data.ts))) {
+          rcmail.display_message(rcmail.get_label('fileuploaderror'), 'error');
+          rcmail.remove_from_attachment_list(e.data.ts);
+        }
+        // Opera hack: handle double onload
+        if (bw.opera)
+          rcmail.env.uploadframe = e.data.ts;
+      });
+
       form.target = frame_name;
-      form.action = this.env.comm_path+'&_action=upload';
+      form.action = this.env.comm_path+'&_action=upload&_uploadid='+ts;
       form.setAttribute('enctype', 'multipart/form-data');
       form.submit();
+      
+      // hide upload form
+      this.show_attachment_form(false);
+      // display upload indicator and cancel button
+      var content = this.get_label('uploading');
+      if (this.env.loadingicon)
+        content = '<img src="'+this.env.loadingicon+'" alt="" />'+content;
+      if (this.env.cancelicon)
+        content = '<a title="'+this.get_label('cancel')+'" onclick="return rcmail.cancel_attachment_upload(\''+ts+'\', \''+frame_name+'\');" href="#cancelupload"><img src="'+this.env.cancelicon+'" alt="" /></a>'+content;
+      this.add2attachment_list(ts, { name:'', html:content, complete:false });
       }
     
     // set reference to the form object
@@ -2398,17 +2543,35 @@
 
   // add file name to attachment list
   // called from upload page
-  this.add2attachment_list = function(name, content)
-    {
+  this.add2attachment_list = function(name, att, upload_id)
+  {
     if (!this.gui_objects.attachmentlist)
       return false;
-      
-    $('<li>').attr('id', name).html(content).appendTo(this.gui_objects.attachmentlist);
+    
+    var li = $('<li>').attr('id', name).html(att.html);
+    var indicator;
+    
+    // replace indicator's li
+    if (upload_id && (indicator = document.getElementById(upload_id))) {
+      li.replaceAll(indicator);
+    }
+    else { // add new li
+      li.appendTo(this.gui_objects.attachmentlist);
+    }
+    
+    if (upload_id && this.env.attachments[upload_id])
+      delete this.env.attachments[upload_id];
+    
+    this.env.attachments[name] = att;
+    
     return true;
-    };
+  };
 
   this.remove_from_attachment_list = function(name)
-    {
+  {
+    if (this.env.attachments[name])
+      delete this.env.attachments[name];
+    
     if (!this.gui_objects.attachmentlist)
       return false;
 
@@ -2416,14 +2579,24 @@
     for (i=0;i<list.length;i++)
       if (list[i].id == name)
         this.gui_objects.attachmentlist.removeChild(list[i]);
-    };
+  };
 
   this.remove_attachment = function(name)
     {
-    if (name)
+    if (name && this.env.attachments[name])
       this.http_post('remove-attachment', '_file='+urlencode(name));
 
     return true;
+    };
+
+  this.cancel_attachment_upload = function(name, frame_name)
+    {
+    if (!name || !frame_name)
+      return false;
+
+    this.remove_from_attachment_list(name);
+    $("iframe[name='"+frame_name+"']").remove();
+    return false;
     };
 
   // send remote request to add a new contact
@@ -2443,11 +2616,14 @@
       var addurl = '';
       if (this.message_list) {
         this.message_list.clear();
-	if (this.env.search_mods) {
-          var head_arr = new Array();
-          for (var n in this.env.search_mods)
-	    head_arr.push(n);
-	  addurl += '&_headers='+head_arr.join(',');
+        if (this.env.search_mods) {
+          var mods = this.env.search_mods[this.env.mailbox] ? this.env.search_mods[this.env.mailbox] : this.env.search_mods['*'];
+          if (mods) {
+            var head_arr = new Array();
+            for (var n in mods)
+              head_arr.push(n);
+            addurl += '&_headers='+head_arr.join(',');
+            }
           }
         } else if (this.contact_list) {
         this.contact_list.clear(true);
@@ -2567,7 +2743,7 @@
       return;
     
     // get cursor pos
-    var inp_value = this.ksearch_input.value.toLowerCase();
+    var inp_value = this.ksearch_input.value;
     var cpos = this.get_caret_pos(this.ksearch_input);
     var p = inp_value.lastIndexOf(this.ksearch_value, cpos);
 
@@ -2599,15 +2775,21 @@
     var q = inp_value.substring(p+1, cpos);
 
     // trim query string
-    q = q.replace(/(^\s+|\s+$)/g, '').toLowerCase();
+    q = q.replace(/(^\s+|\s+$)/g, '');
 
-    // Don't (re-)search if string is empty or if the last results are still active
+    // Don't (re-)search if the last results are still active
     if (q == this.ksearch_value)
       return;
     
+    var old_value = this.ksearch_value;
     this.ksearch_value = q;
     
+    // ...string is empty
     if (!q.length)
+      return;
+
+    // ...new search value contains old one and previous search result was empty
+    if (old_value && old_value.length && this.env.contacts && !this.env.contacts.length && q.indexOf(old_value) == 0)
       return;
     
     this.display_message(this.get_label('searching'), 'loading', true);
@@ -2628,8 +2810,8 @@
   this.ksearch_display_results = function (a_results)
   {
     // display search results
-    if (a_results.length && this.ksearch_input) {
-      var p, ul, li;
+    if (a_results.length && this.ksearch_input && this.ksearch_value) {
+      var p, ul, li, s_val = this.ksearch_value;
       
       // create results pane if not present
       if (!this.ksearch_pane) {
@@ -2641,11 +2823,11 @@
       // remove all search results
       ul = this.ksearch_pane.__ul;
       ul.innerHTML = '';
-            
+
       // add each result line to list
       for (i=0; i<a_results.length; i++) {
         li = document.createElement('LI');
-        li.innerHTML = a_results[i].replace(new RegExp('('+this.ksearch_value+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>');
+        li.innerHTML = a_results[i].replace(new RegExp('('+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;
@@ -2855,7 +3037,7 @@
     };
 
   // update a contact record in the list
-  this.update_contact_row = function(cid, cols_arr)
+  this.update_contact_row = function(cid, cols_arr, newcid)
   {
     var row;
     if (this.contact_list.rows[cid] && (row = this.contact_list.rows[cid].obj)) {
@@ -2863,11 +3045,50 @@
         if (row.cells[c])
           $(row.cells[c]).html(cols_arr[c]);
 
+      // cid change
+      if (newcid) {
+	row.id = 'rcmrow' + newcid;
+        this.contact_list.remove_row(cid);
+        this.contact_list.init_row(row);
+	this.contact_list.selection[0] = newcid;
+	row.style.display = '';
+      }
+
       return true;
     }
 
     return false;
   };
+
+  // add row to contacts list
+  this.add_contact_row = function(cid, cols, select)
+    {
+    if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0])
+      return false;
+    
+    var tbody = this.gui_objects.contactslist.tBodies[0];
+    var rowcount = tbody.rows.length;
+    var even = rowcount%2;
+    
+    var row = document.createElement('tr');
+    row.id = 'rcmrow'+cid;
+    row.className = 'contact '+(even ? 'even' : 'odd');
+	    
+    if (this.contact_list.in_selection(cid))
+      row.className += ' selected';
+
+    // add each submitted col
+    for (var c in cols) {
+      col = document.createElement('td');
+      col.className = String(c).toLowerCase();
+      col.innerHTML = cols[c];
+      row.appendChild(col);
+    }
+    
+    this.contact_list.insert_row(row);
+    
+    this.enable_command('export', (this.contact_list.rowcount > 0));
+    };
 
 
   /*********************************************************/
@@ -2883,7 +3104,7 @@
     this.subscription_list.addEventListener('dragend', function(o){ p.subscription_move_folder(o); });
     this.subscription_list.row_init = function (row)
       {
-      var anchors = row.obj.getElementsByTagName('A');
+      var anchors = row.obj.getElementsByTagName('a');
       if (anchors[0])
         anchors[0].onclick = function() { p.rename_folder(row.id); return false; };
       if (anchors[1])
@@ -2894,6 +3115,26 @@
     this.subscription_list.init();
     }
 
+  // preferences section select and load options frame
+  this.section_select = function(list)
+    {
+    var id = list.get_single_selection();
+    
+    if (id) {
+      var add_url = '';
+      var target = window;
+      this.set_busy(true);
+
+      if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
+        add_url = '&_framed=1';
+        target = window.frames[this.env.contentframe];
+        }
+      target.location.href = this.env.comm_path+'&_action=edit-prefs&_section='+id+add_url;
+      }
+
+    return true;
+    };
+
   this.identity_select = function(list)
     {
     var id;
@@ -2901,7 +3142,7 @@
       this.load_identity(id, 'edit-identity');
     };
 
-  // load contact record
+  // load identity record
   this.load_identity = function(id, action)
     {
     if (action=='edit-identity' && (!id || id==this.env.iid))
@@ -2934,8 +3175,9 @@
     if (!id)
       id = this.env.iid ? this.env.iid : selection[0];
 
-    // if (this.env.framed && id)
-    this.goto_url('delete-identity', '_iid='+id, true);
+    // append token to request
+    this.goto_url('delete-identity', '_iid='+id+'&_token='+this.env.request_token, true);
+    
     return true;
     };
 
@@ -3049,7 +3291,8 @@
     if (id && this.env.subscriptionrows[id] && (row = document.getElementById(id)))
       {
       var reg = new RegExp('.*['+RegExp.escape(this.env.delimiter)+']');
-      this.name_input = document.createElement('INPUT');
+      this.name_input = document.createElement('input');
+      this.name_input.type = 'text';
       this.name_input.value = this.env.subscriptionrows[id][0].replace(reg, '');
 
       reg = new RegExp('['+RegExp.escape(this.env.delimiter)+']?[^'+RegExp.escape(this.env.delimiter)+']+$');
@@ -3129,10 +3372,13 @@
     if (!this.gui_objects.subscriptionlist)
       return false;
 
-    // find not protected folder    
-    for (var refid in this.env.subscriptionrows)
-      if (this.env.subscriptionrows[refid]!=null && !this.env.subscriptionrows[refid][2])
+    // find not protected folder
+    var refid;
+    for (var rid in this.env.subscriptionrows)
+      if (this.env.subscriptionrows[rid]!=null && !this.env.subscriptionrows[rid][2]) {
+        refid = rid;
         break;
+      }
 
     var refrow, form;
     var tbody = this.gui_objects.subscriptionlist.tBodies[0];
@@ -3145,10 +3391,11 @@
       refid = replace.id;
     }
 
-    if (!id || !(refrow = document.getElementById(refid)))
+    if (!id || !refid || !(refrow = document.getElementById(refid)))
       {
       // Refresh page if we don't have a table row to clone
       this.goto_url('folders');
+      return false;
       }
     else
       {
@@ -3174,8 +3421,8 @@
     // set messages count to zero
     if (!replace)
       row.cells[1].innerHTML = '*';
-    
-    if (!replace && row.cells[2] && row.cells[2].firstChild.tagName=='INPUT')
+
+    if (!replace && row.cells[2] && row.cells[2].firstChild.tagName.toLowerCase()=='input')
       {
       row.cells[2].firstChild.value = name;
       row.cells[2].firstChild.checked = true;
@@ -3278,11 +3525,11 @@
   this.clone_table_row = function(row)
     {
     var cell, td;
-    var new_row = document.createElement('TR');
+    var new_row = document.createElement('tr');
     for(var n=0; n<row.cells.length; n++)
       {
       cell = row.cells[n];
-      td = document.createElement('TD');
+      td = document.createElement('td');
 
       if (cell.className)
         td.className = cell.className;
@@ -3303,12 +3550,49 @@
 
   // eable/disable buttons for page shifting
   this.set_page_buttons = function()
-    {
+  {
     this.enable_command('nextpage', (this.env.pagecount > this.env.current_page));
     this.enable_command('lastpage', (this.env.pagecount > this.env.current_page));
     this.enable_command('previouspage', (this.env.current_page > 1));
     this.enable_command('firstpage', (this.env.current_page > 1));
+  };
+  
+  // set event handlers on registered buttons
+  this.init_buttons = function()
+  {
+    for (var cmd in this.buttons) {
+      if (typeof cmd != 'string')
+        continue;
+      
+      for (var i=0; i< this.buttons[cmd].length; i++) {
+        var prop = this.buttons[cmd][i];
+        var elm = document.getElementById(prop.id);
+        if (!elm)
+          continue;
+
+        var preload = false;
+        if (prop.type == 'image') {
+          elm = elm.parentNode;
+          preload = true;
+        }
+        
+        elm._command = cmd;
+        elm._id = prop.id;
+        if (prop.sel) {
+          elm.onmousedown = function(e){ return rcmail.button_sel(this._command, this._id); };
+          elm.onmouseup = function(e){ return rcmail.button_out(this._command, this._id); };
+          if (preload)
+            new Image().src = prop.sel;
+        }
+        if (prop.over) {
+          elm.onmouseover = function(e){ return rcmail.button_over(this._command, this._id); };
+          elm.onmouseout = function(e){ return rcmail.button_out(this._command, this._id); };
+          if (preload)
+            new Image().src = prop.over;
+        }
+      }
     }
+  };
 
   // set button to a specific state
   this.set_button = function(command, state)
@@ -3370,7 +3654,7 @@
         if (button.type=='image' && obj)
         {
           obj.setAttribute('alt', this.get_label(label));
-          if ((link = obj.parentNode) && link.tagName == 'A')
+          if ((link = obj.parentNode) && link.tagName.toLowerCase() == 'a')
             link.setAttribute('title', this.get_label(label));
         }
         else if (obj)
@@ -3380,67 +3664,79 @@
 
   // mouse over button
   this.button_over = function(command, id)
-    {
+  {
     var a_buttons = this.buttons[command];
-    var button, img;
+    var button, elm;
 
     if(!a_buttons || !a_buttons.length)
       return false;
 
     for(var n=0; n<a_buttons.length; n++)
-      {
+    {
       button = a_buttons[n];
       if(button.id==id && button.status=='act')
-        {
-        img = document.getElementById(button.id);
-        if (img && button.over)
-          img.src = button.over;
+      {
+        elm = document.getElementById(button.id);
+        if (elm && button.over) {
+          if (button.type == 'image')
+            elm.src = button.over;
+          else
+            elm.className = button.over;
         }
       }
-      
-    };
+    }
+  };
 
   // mouse down on button
   this.button_sel = function(command, id)
-    {
+  {
     var a_buttons = this.buttons[command];
-    var button, img;
+    var button, elm;
 
     if(!a_buttons || !a_buttons.length)
       return;
 
     for(var n=0; n<a_buttons.length; n++)
-      {
+    {
       button = a_buttons[n];
       if(button.id==id && button.status=='act')
-        {
-        img = document.getElementById(button.id);
-        if (img && button.sel)
-          img.src = button.sel;
+      {
+        elm = document.getElementById(button.id);
+        if (elm && button.sel) {
+          if (button.type == 'image')
+            elm.src = button.sel;
+          else
+            elm.className = button.sel;
         }
+        this.buttons_sel[id] = command;
       }
-    };
+    }
+  };
 
   // mouse out of button
   this.button_out = function(command, id)
-    {
+  {
     var a_buttons = this.buttons[command];
-    var button, img;
+    var button, elm;
 
     if(!a_buttons || !a_buttons.length)
       return;
 
     for(var n=0; n<a_buttons.length; n++)
-      {
+    {
       button = a_buttons[n];
       if(button.id==id && button.status=='act')
-        {
-        img = document.getElementById(button.id);
-        if (img && button.act)
-          img.src = button.act;
+      {
+        elm = document.getElementById(button.id);
+        if (elm && button.act) {
+          if (button.type == 'image')
+            elm.src = button.act;
+          else
+            elm.className = button.act;
         }
       }
-    };
+    }
+  };
 
   // write to the document/window title
   this.set_pagetitle = function(title)
@@ -3498,7 +3794,6 @@
       if ((current_li = this.get_folder_li(old))) {
         $(current_li).removeClass('selected').removeClass('unfocused');
       }
-
       if ((target_li = this.get_folder_li(name))) {
         $(target_li).removeClass('unfocused').addClass('selected');
       }
@@ -3513,7 +3808,7 @@
   {
     if (this.gui_objects.folderlist)
     {
-      name = String(name).replace(this.identifier_expr, '');
+      name = String(name).replace(this.identifier_expr, '_');
       return document.getElementById('rcmli'+name);
     }
 
@@ -3534,7 +3829,7 @@
       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')
+        if (cell.firstChild && cell.firstChild.tagName.toLowerCase()=='a')
           {
           cell.firstChild.innerHTML = this.get_label(this.coltypes[n]);
           cell.firstChild.onclick = function(){ return rcmail.command('sort', this.__col, this); };
@@ -3580,7 +3875,7 @@
         + (this.message_list.in_selection(uid) ? ' selected' : '');
 
     // for performance use DOM instead of jQuery here
-    var row = document.createElement('TR');
+    var row = document.createElement('tr');
     row.id = 'rcmrow'+uid;
     row.className = css_class;
     
@@ -3600,7 +3895,7 @@
       icon = this.env.unreadicon;
     
     // add icon col
-    var col = document.createElement('TD');
+    var col = document.createElement('td');
     col.className = 'icon';
     col.innerHTML = icon ? '<img src="'+icon+'" alt="" />' : '';
     row.appendChild(col);
@@ -3608,7 +3903,7 @@
     // add each submitted col
     for (var n = 0; n < this.coltypes.length; n++) {
       var c = this.coltypes[n];
-      col = document.createElement('TD');
+      col = document.createElement('td');
       col.className = String(c).toLowerCase();
             
       if (c=='flag') {
@@ -3626,7 +3921,6 @@
       }
 
     this.message_list.insert_row(row, attop);
-    this.triggerEvent('insertrow', { uid:uid, row:row });
 
     // remove 'old' row
     if (attop && this.env.pagesize && this.message_list.rowcount > this.env.pagesize) {
@@ -3662,8 +3956,12 @@
   // replace content of quota display
   this.set_quota = function(content)
     {
-    if (content && this.gui_objects.quotadisplay)
-      $(this.gui_objects.quotadisplay).html(content);
+    if (content && this.gui_objects.quotadisplay) {
+      if (typeof(content) == 'object')
+        this.percent_indicator(this.gui_objects.quotadisplay, content);
+      else
+        $(this.gui_objects.quotadisplay).html(content);
+      }
     };
 
   // update the mailboxlist
@@ -3743,37 +4041,6 @@
       window.focus();
     }
 
-  // add row to contacts list
-  this.add_contact_row = function(cid, cols, select)
-    {
-    if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0])
-      return false;
-    
-    var tbody = this.gui_objects.contactslist.tBodies[0];
-    var rowcount = tbody.rows.length;
-    var even = rowcount%2;
-    
-    var row = document.createElement('TR');
-    row.id = 'rcmrow'+cid;
-    row.className = 'contact '+(even ? 'even' : 'odd');
-	    
-    if (this.contact_list.in_selection(cid))
-      row.className += ' selected';
-
-    // add each submitted col
-    for (var c in cols) {
-      col = document.createElement('TD');
-      col.className = String(c).toLowerCase();
-      col.innerHTML = cols[c];
-      row.appendChild(col);
-    }
-    
-    this.contact_list.insert_row(row);
-    this.triggerEvent('insertrow', { cid:cid, row:row });
-    
-    this.enable_command('export', (this.contact_list.rowcount > 0));
-    };
-
   this.toggle_prefer_html = function(checkbox)
     {
     var addrbook_show_images;
@@ -3823,6 +4090,61 @@
     elem.onclick = function() { rcmail.load_headers(elem); }
     }
 
+  // percent (quota) indicator
+  this.percent_indicator = function(obj, data)
+    {
+    if (!data || !obj)
+      return false;
+
+    var limit_high = 80;
+    var limit_mid  = 55;
+    var width = data.width ? data.width : this.env.indicator_width ? this.env.indicator_width : 100;
+    var height = data.height ? data.height : this.env.indicator_height ? this.env.indicator_height : 14;
+    var quota = data.percent ? Math.abs(parseInt(data.percent)) : 0;
+    var quota_width = parseInt(quota / 100 * width);
+    var pos = $(obj).position();
+
+    this.env.indicator_width = width;
+    this.env.indicator_height = height;
+    
+    // overlimit
+    if (quota_width > width) {
+      quota_width = width;
+      quota = 100; 
+      }
+  
+    // main div
+    var main = $('<div>');
+    main.css({position: 'absolute', top: pos.top, left: pos.left,
+	width: width + 'px', height: height + 'px', zIndex: 100, lineHeight: height + 'px'})
+	.attr('title', data.title).addClass('quota_text').html(quota + '%');
+    // used bar
+    var bar1 = $('<div>');
+    bar1.css({position: 'absolute', top: pos.top + 1, left: pos.left + 1,
+	width: quota_width + 'px', height: height + 'px', zIndex: 99});
+    // background
+    var bar2 = $('<div>');
+    bar2.css({position: 'absolute', top: pos.top + 1, left: pos.left + 1,
+	width: width + 'px', height: height + 'px', zIndex: 98})
+	.addClass('quota_bg');
+
+    if (quota >= limit_high) {
+      main.addClass(' quota_text_high');
+      bar1.addClass('quota_high');
+      }
+    else if(quota >= limit_mid) {
+      main.addClass(' quota_text_mid');
+      bar1.addClass('quota_mid');
+      }
+    else {
+      main.addClass(' quota_text_normal');
+      bar1.addClass('quota_low');
+      }
+
+    // replace quota image
+    obj.innerHTML = '';
+    $(obj).append(bar1).append(bar2).append(main);
+    }
 
   /********************************************************/
   /*********  html to text conversion functions   *********/
@@ -3861,7 +4183,7 @@
 
     if (this.env.framed && window.parent)
       parent.location.href = url;
-    else  
+    else
       location.href = url;
     };
 
@@ -3878,7 +4200,7 @@
     var url = this.env.comm_path + '&_action=' + action + '&' + querystring
     
     // send request
-    console.log('HTTP POST: ' + url);
+    console.log('HTTP GET: ' + url);
     jQuery.get(url, { _unlock:(lock?1:0) }, function(data){ ref.http_response(data); }, 'json');
   };
 
@@ -3942,8 +4264,8 @@
       
       case 'moveto':
         if (this.env.action == 'show') {
-	  // re-enable commands on move/delete error
-	  this.enable_command('reply', 'reply-all', 'forward', 'delete', 'mark', 'print', 'open', 'viewsource', 'download', true);
+          // re-enable commands on move/delete error
+          this.enable_command('reply', 'reply-all', 'forward', 'delete', 'mark', 'print', 'open', 'edit', 'viewsource', 'download', true);
         } else if (this.message_list)
           this.message_list.init();
         break;
@@ -3956,8 +4278,8 @@
             this.show_contentframe(false);
           // disable commands useless when mailbox is empty
           this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 
-	    'mark', 'viewsource', 'open', 'download', 'print', 'load-attachment', 
-	    'purge', 'expunge', 'select-all', 'select-none', 'sort', false);
+            'mark', 'viewsource', 'open', 'edit', 'download', 'print', 'load-attachment', 
+            'purge', 'expunge', 'select-all', 'select-none', 'sort', false);
         }
         break;
 
@@ -4003,15 +4325,17 @@
     };
 
   // send periodic request to check for recent messages
-  this.check_for_recent = function(setbusy)
+  this.check_for_recent = function(refresh)
     {
     if (this.busy)
       return;
 
-    if (setbusy)
-      this.set_busy(true, 'checkingmail');
-
     var addurl = '_t=' + (new Date().getTime());
+
+    if (refresh) {
+      this.set_busy(true, 'checkingmail');
+      addurl += '&_refresh=1';
+    }
 
     if (this.gui_objects.messagelist)
       addurl += '&_list=1';
@@ -4105,4 +4429,3 @@
 rcube_webmail.prototype.addEventListener = rcube_event_engine.prototype.addEventListener;
 rcube_webmail.prototype.removeEventListener = rcube_event_engine.prototype.removeEventListener;
 rcube_webmail.prototype.triggerEvent = rcube_event_engine.prototype.triggerEvent;
-

--
Gitblit v1.9.1