alecpl
2008-10-06 163a13c70f0268a5ea61ca8da9ad1d47f155fc2f
program/js/app.js
@@ -64,13 +64,11 @@
      this.env[p] = value;
    };
  // add a localized label to the client environment
  this.add_label = function(key, value)
    {
    this.labels[key] = value;
    };
  // add a button to the button list
  this.register_button = function(command, id, type, act, sel, over)
@@ -122,6 +120,9 @@
    // enable general commands
    this.enable_command('logout', 'mail', 'addressbook', 'settings', true);
    
    if (this.env.permaurl)
      this.enable_command('permaurl', true);
    switch (this.task)
      {
      case 'mail':
@@ -132,11 +133,12 @@
          this.message_list.addEventListener('dblclick', function(o){ p.msglist_dbl_click(o); });
          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_active = true; });
          this.message_list.addEventListener('dragstart', function(o){ p.drag_active = true; if (p.preview_timer) clearTimeout(p.preview_timer); });
          this.message_list.addEventListener('dragmove', function(o, e){ p.drag_move(e); });
          this.message_list.addEventListener('dragend', function(o){ p.drag_active = false; });
          this.message_list.init();
          this.enable_command('toggle_status', true);
          this.enable_command('toggle_status', 'toggle_flag', true);
          
          if (this.gui_objects.mailcontframe)
            {
@@ -151,14 +153,14 @@
          this.set_message_coltypes(this.env.coltypes);
        // enable mail commands
        this.enable_command('list', 'checkmail', 'compose', 'add-contact', 'search', 'reset-search', true);
        this.enable_command('list', 'checkmail', 'compose', 'add-contact', 'search', 'reset-search', 'collapse-folder', true);
        if (this.env.search_text != null && document.getElementById('quicksearchbox') != null)
          document.getElementById('quicksearchbox').value = this.env.search_text;
        
        if (this.env.action=='show' || this.env.action=='preview')
          {
          this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource', 'print', 'load-attachment', true);
          this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource', 'print', 'load-attachment', 'load-headers', true);
          if (this.env.next_uid)
            {
            this.enable_command('nextmessage', true);
@@ -179,14 +181,13 @@
          {
          this.enable_command('compose', 'add-contact', false);
          parent.rcmail.show_contentframe(true);
          parent.rcmail.mark_message('read', this.env.uid);
          }
        if ((this.env.action=='show' || this.env.action=='preview') && this.env.blockedobjects)
          {
          if (this.gui_objects.remoteobjectsmsg)
            this.gui_objects.remoteobjectsmsg.style.display = 'block';
          this.enable_command('load-images', true);
          this.enable_command('load-images', 'always-load', true);
          }
        if (this.env.action=='compose')
@@ -196,24 +197,20 @@
            {
            this.env.spellcheck.spelling_state_observer = function(s){ ref.set_spellcheck_state(s); };
            this.set_spellcheck_state('ready');
            if (rcube_find_object('_is_html').value == '1')
              this.display_spellcheck_controls(false);
            }
          if (this.env.drafts_mailbox)
            this.enable_command('savedraft', true);
          }
        if (this.env.messagecount)
          this.enable_command('select-all', 'select-none', 'sort', 'expunge', true);
          this.enable_command('select-all', 'select-none', 'expunge', true);
        if (this.env.messagecount && (this.env.mailbox==this.env.trash_mailbox || this.env.mailbox==this.env.junk_mailbox))
        if (this.purge_mailbox_test())
          this.enable_command('purge', true);
        this.set_page_buttons();
        // focus main window
        if (this.env.framed && window.parent)
          window.parent.focus();
        else
          window.focus();
        // init message compose form
        if (this.env.action=='compose')
@@ -226,6 +223,7 @@
        // get unread count for each mailbox
        if (this.gui_objects.mailboxlist)
        {
          this.env.unread_counts = {};
          this.gui_objects.folderlist = this.gui_objects.mailboxlist;
          this.http_request('getunread', '');
        }
@@ -250,6 +248,7 @@
          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_active = true; });
          this.contact_list.addEventListener('dragmove', function(o, e){ p.drag_move(e); });
          this.contact_list.addEventListener('dragend', function(o){ p.drag_active = false; });
          this.contact_list.init();
@@ -276,7 +275,10 @@
        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', true);
          this.enable_command('search', 'reset-search', 'moveto', 'import', true);
        if (this.contact_list && this.contact_list.rowcount > 0)
          this.enable_command('export', true);
        this.enable_command('list', true);
        break;
@@ -285,8 +287,10 @@
      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')
          this.enable_command('edit', 'add', 'delete', true);
        if (this.env.action=='identities' || this.env.action=='edit-identity' || this.env.action=='add-identity') {
          this.enable_command('add', 'delete', this.env.multiple_identities);
          this.enable_command('edit', true);
        }
        if (this.env.action=='edit-identity' || this.env.action=='add-identity')
          this.enable_command('save', true);
@@ -313,20 +317,25 @@
      case 'login':
        var input_user = rcube_find_object('rcmloginuser');
        var input_pass = rcube_find_object('rcmloginpwd');
        var input_tz = rcube_find_object('rcmlogintz');
        if (input_user)
          input_user.onkeypress = function(e){ return rcmail.login_user_keypress(e); };
          input_user.onkeyup = function(e){ return rcmail.login_user_keyup(e); };
        if (input_user && input_user.value=='')
          input_user.focus();
        else if (input_pass)
          input_pass.focus();
        // detect client timezone
        if (input_tz)
          input_tz.value = new Date().getTimezoneOffset() / -60;
        this.enable_command('login', true);
        break;
      
      default:
        break;
      }
    // enable basic commands
    this.enable_command('logout', true);
@@ -341,7 +350,6 @@
    // start keep-alive interval
    this.start_keepalive();
    
    // execute all foreign onload scripts
    for (var i=0; i<this.onloads.length; i++)
      {
@@ -352,16 +360,14 @@
      }
    };
  // start interval for keep-alive/recent_check signal
  this.start_keepalive = function()
    {
    if (this.env.keep_alive && !this.env.framed && this.task=='mail' && this.gui_objects.messagelist)
    if (this.env.keep_alive && !this.env.framed && this.task=='mail' && this.gui_objects.mailboxlist)
      this._int = setInterval(function(){ ref.check_for_recent(); }, this.env.keep_alive * 1000);
    else if (this.env.keep_alive && !this.env.framed && this.task!='login')
      this._int = setInterval(function(){ ref.send_keep_alive(); }, this.env.keep_alive * 1000);    
    }
  this.init_message_row = function(row)
  {
@@ -371,6 +377,8 @@
      row.deleted = this.env.messages[uid].deleted ? true : false;
      row.unread = this.env.messages[uid].unread ? true : false;
      row.replied = this.env.messages[uid].replied ? true : false;
      row.flagged = this.env.messages[uid].flagged ? true : false;
      row.forwarded = this.env.messages[uid].forwarded ? true : false;
      }
    // set eventhandler to message icon
@@ -381,8 +389,25 @@
      row.icon._row = row.obj;
      row.icon.onmousedown = function(e) { p.command('toggle_status', this); };
      }
  };
    // global variable 'flagged_col' may be not defined yet
    if (!this.env.flagged_col && this.env.coltypes)
      {
      var found;
      if((found = find_in_array('flag', this.env.coltypes)) >= 0)
          this.set_env('flagged_col', found+1);
      }
    // set eventhandler to flag icon, if icon found
    if (this.env.flagged_col && (row.flagged_icon = row.obj.cells[this.env.flagged_col].childNodes[0])
   && row.flagged_icon.nodeName=='IMG')
      {
      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); };
      }
  };
  // init message compose form: set focus and eventhandlers
  this.init_messageform = function()
@@ -406,7 +431,7 @@
      this.init_address_input_events(input_cc);
    if (input_bcc)
      this.init_address_input_events(input_bcc);
    // add signature according to selected identity
    if (input_from && input_from.type=='select-one')
      this.change_identity(input_from);
@@ -445,11 +470,9 @@
    };
  /*********************************************************/
  /*********       client command interface        *********/
  /*********************************************************/
  // execute a specific command on the web client
  this.command = function(command, props, obj)
@@ -470,14 +493,12 @@
      return false;
      }
      
   // check input before leaving compose step
   if (this.task=='mail' && this.env.action=='compose' && (command=='list' || command=='mail' || command=='addressbook' || command=='settings'))
     {
     if (this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning')))
        return false;
     }
    // process command
    switch (command)
@@ -488,7 +509,7 @@
        break;
      case 'logout':
        this.goto_url('logout', true);
        this.goto_url('logout', '', true);
        break;      
      // commands to switch task
@@ -498,6 +519,12 @@
        this.switch_task(command);
        break;
      case 'permaurl':
        if (obj && obj.href && obj.target)
          return true;
        else if (this.env.permaurl)
          parent.location.href = this.env.permaurl;
          break;
      // misc list commands
      case 'list':
@@ -519,6 +546,11 @@
          this.list_contacts(props);
          this.enable_command('add', (this.env.address_sources && !this.env.address_sources[props].readonly));
          }
        break;
      case 'load-headers':
        this.load_headers(obj);
        break;
@@ -631,7 +663,7 @@
          var input_email = rcube_find_object('_email');
          // user prefs
          if (input_pagesize && isNaN(input_pagesize.value))
          if (input_pagesize && isNaN(parseInt(input_pagesize.value)))
            {
            alert(this.get_label('nopagesizewarning'));
            input_pagesize.focus();
@@ -706,13 +738,37 @@
        this.mark_message(flag, uid);
        break;
        
      case 'toggle_flag':
        if (props && !props._row)
          break;
        var uid;
        var flag = 'flagged';
        if (props._row.uid)
          {
          uid = props._row.uid;
          // toggle flagged/unflagged
          if (this.message_list.rows[uid].flagged)
            flag = 'unflagged';
          }
        this.mark_message(flag, uid);
        break;
      case 'always-load':
        if (this.env.uid && this.env.sender) {
          this.add_contact(urlencode(this.env.sender));
          window.setTimeout(function(){ ref.command('load-images'); }, 300);
          break;
        }
      case 'load-images':
        if (this.env.uid)
          this.show_message(this.env.uid, true, this.env.action=='preview');
        break;
      case 'load-attachment':
        var qstring = '_mbox='+this.env.mailbox+'&_uid='+this.env.uid+'&_part='+props.part;
        var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props.part;
        
        // open attachment in frame if it's of a supported mimetype
        if (this.env.uid && props.mimetype && find_in_array(props.mimetype, this.mimetypes)>=0)
@@ -722,7 +778,7 @@
          this.attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', 'rcubemailattachment');
          if (this.attachment_win)
            {
            setTimeout(function(){ ref.attachment_win.focus(); }, 10);
            window.setTimeout(function(){ ref.attachment_win.focus(); }, 10);
            break;
            }
          }
@@ -765,22 +821,27 @@
      case 'compose':
        var url = this.env.comm_path+'&_action=compose';
       
        if (this.task=='mail' && this.env.mailbox==this.env.drafts_mailbox)
        if (this.task=='mail')
          {
          var uid;
          if (uid = this.get_single_uid())
            url += '&_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox);
          }
         url += '&_mbox='+urlencode(this.env.mailbox);
     if (this.env.mailbox==this.env.drafts_mailbox)
       {
       var uid;
            if (uid = this.get_single_uid())
              url += '&_draft_uid='+uid;
            }
     }
        // modify url if we're in addressbook
        else if (this.task=='addressbook')
          {
          // switch to mail compose step directly
          if (props && props.indexOf('@') > 0)
          {
            {
            url = this.get_task_url('mail', url);
            this.redirect(url + '&_to='+urlencode(props));
            break;
          }
            }
          
          // use contact_id passed as command parameter
          var a_cids = new Array();
@@ -809,11 +870,13 @@
        break;
        
      case 'spellcheck':
        if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready)
          {
        if (window.tinyMCE && tinyMCE.get('compose-body')) {
          tinyMCE.execCommand('mceSpellCheck', true);
        }
        else if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready) {
          this.env.spellcheck.spellCheck(this.env.spellcheck.check_link);
          this.set_spellcheck_state('checking');
          }
        }
        break;
      case 'savedraft':
@@ -890,9 +953,9 @@
          ref.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(function(){ ref.printwin.focus(); }, 20);
            window.setTimeout(function(){ ref.printwin.focus(); }, 20);
            if (this.env.action != 'show')
              this.toggle_read_status('read', [uid]);
              this.mark_message('read', uid);
          }
        }
        break;
@@ -903,7 +966,7 @@
          {
          ref.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox));
          if (this.sourcewin)
            setTimeout(function(){ ref.sourcewin.focus(); }, 20);
            window.setTimeout(function(){ ref.sourcewin.focus(); }, 20);
          }
        break;
@@ -921,7 +984,7 @@
          break;
        }
      // reset quicksearch
      // reset quicksearch
      case 'reset-search':
        var s = this.env.search_request;
        this.reset_qsearch();
@@ -932,6 +995,36 @@
          this.list_contacts(this.env.source);
        break;
      case 'import':
        if (this.env.action == 'import' && this.gui_objects.importform) {
          var file = document.getElementById('rcmimportfile');
          if (file && !file.value) {
            alert(this.get_label('selectimportfile'));
            break;
          }
          this.gui_objects.importform.submit();
          this.set_busy(true, 'importwait');
          this.lock_form(this.gui_objects.importform, true);
        }
        else
          this.goto_url('import');
        break;
      case 'export':
        if (this.contact_list.rowcount > 0) {
          var add_url = (this.env.source ? '_source='+urlencode(this.env.source)+'&' : '');
          if (this.env.search_request)
            add_url += '_search='+this.env.search_request;
          this.goto_url('export', add_url);
        }
        break;
      // collapse/expand folder
      case 'collapse-folder':
        if (props)
          this.collapse_folder(props);
        break;
      // user settings commands
      case 'preferences':
@@ -974,7 +1067,6 @@
    return obj ? false : true;
    };
  // set command enabled or disabled
  this.enable_command = function()
    {
@@ -992,7 +1084,6 @@
      }
      return true;
    };
  // lock/unlock interface
  this.set_busy = function(a, message)
@@ -1020,9 +1111,8 @@
    // set timer for requests
    if (a && this.env.request_timeout)
      this.request_timer = setTimeout(function(){ ref.request_timed_out(); }, this.env.request_timeout * 1000);
      this.request_timer = window.setTimeout(function(){ ref.request_timed_out(); }, this.env.request_timeout * 1000);
    };
  // return a localized string
  this.get_label = function(name)
@@ -1032,7 +1122,6 @@
    else
      return name;
    };
  // switch to another application task
  this.switch_task = function(task)
@@ -1047,7 +1136,6 @@
    this.redirect(url);
    };
  this.get_task_url = function(task, url)
    {
    if (!url)
@@ -1056,7 +1144,6 @@
    return url.replace(/_task=[a-z]+/, '_task='+task);
    };
    
  // called when a request timed out
  this.request_timed_out = function()
    {
@@ -1069,38 +1156,87 @@
  /*********        event handling methods         *********/
  /*********************************************************/
  this.doc_mouse_up = function(e)
    {
    if (this.message_list)
  {
    var model, li;
    if (this.message_list) {
      this.message_list.blur();
    else if (this.contact_list)
      model = this.env.mailboxes;
    }
    else if (this.contact_list) {
      this.contact_list.blur();
    };
  this.focus_folder = function(id)
    {
    var li;
    if (this.drag_active && this.check_droptarget(id) && (li = this.get_folder_li(id)))
      this.set_classname(li, 'droptarget', true);
      model = this.env.address_sources;
    }
  this.unfocus_folder = function(id)
    {
    var li;
    if (this.drag_active && (li = this.get_folder_li(id)))
      this.set_classname(li, 'droptarget', false);
    }
  // onmouseup handler for folder list item
  this.folder_mouse_up = function(id)
    {
    if (this.drag_active)
      {
      this.unfocus_folder(id);
      this.command('moveto', id);
    // handle mouse release when dragging
    if (this.drag_active && model) {
      for (var k in model) {
        if ((li = this.get_folder_li(k)) && rcube_mouse_is_over(e, li.firstChild) && this.check_droptarget(k)) {
          this.set_classname(li, 'droptarget', false);
          this.command('moveto', model[k].id);
          break;
        }
      }
    };
    }
  };
  this.drag_move = function(e)
  {
    var li;
    var model = this.task == 'mail' ? this.env.mailboxes : this.env.address_sources;
    if (this.gui_objects.folderlist && model) {
      for (var k in model) {
        if (li = this.get_folder_li(k))
          this.set_classname(li, 'droptarget', (rcube_mouse_is_over(e, li.firstChild) && this.check_droptarget(k)));
      }
    }
  };
  this.collapse_folder = function(id)
    {
    var div;
    if ((li = this.get_folder_li(id)) &&
        (div = li.getElementsByTagName("div")[0]) &&
        (div.className.match(/collapsed/) || div.className.match(/expanded/)))
      {
      var ul = li.getElementsByTagName("ul")[0];
      if (div.className.match(/collapsed/))
        {
        ul.style.display = '';
        this.set_classname(div, 'collapsed', false);
        this.set_classname(div, 'expanded', true);
        var reg = new RegExp('&'+escape(id)+'&');
        this.set_env('collapsed_folders', this.env.collapsed_folders.replace(reg, ''));
        }
      else
        {
        ul.style.display = 'none';
        this.set_classname(div, 'expanded', false);
        this.set_classname(div, 'collapsed', true);
        this.set_env('collapsed_folders', this.env.collapsed_folders+'&'+escape(id)+'&');
        // select parent folder if one of its childs is currently selected
        if (this.env.mailbox.indexOf(id + this.env.delimiter) == 0)
          this.command('list', id);
        }
      // Work around a bug in IE6 and IE7, see #1485309
      if ((bw.ie6 || bw.ie7) &&
          li.nextSibling &&
          (li.nextSibling.getElementsByTagName("ul").length>0) &&
          li.nextSibling.getElementsByTagName("ul")[0].style &&
          (li.nextSibling.getElementsByTagName("ul")[0].style.display!='none'))
        {
          li.nextSibling.getElementsByTagName("ul")[0].style.display = 'none';
          li.nextSibling.getElementsByTagName("ul")[0].style.display = '';
        }
      this.http_post('save-pref', '_name=collapsed_folders&_value='+escape(this.env.collapsed_folders));
      this.set_unread_count_display(id, false);
      }
    }
  this.click_on_list = function(e)
    {
@@ -1113,9 +1249,8 @@
    if (mbox_li = this.get_folder_li())
      this.set_classname(mbox_li, 'unfocused', true);
    rcube_event.cancel(e);
    return rcube_event.get_button(e) == 2 ? true : rcube_event.cancel(e);
    };
  this.msglist_select = function(list)
    {
@@ -1138,12 +1273,11 @@
      }
    // start timer for message preview (wait for double click)
    if (selected && this.env.contentframe)
      this.preview_timer = setTimeout(function(){ ref.msglist_get_preview(); }, this.dblclick_time + 10);
    if (selected && this.env.contentframe && !list.multi_selecting)
      this.preview_timer = window.setTimeout(function(){ ref.msglist_get_preview(); }, 200);
    else if (this.env.contentframe)
      this.show_contentframe(false);
    };
  this.msglist_dbl_click = function(list)
    {
@@ -1157,17 +1291,17 @@
      this.show_message(uid, false, false);
    };
  this.msglist_keypress = function(list)
    {
    if (list.key_pressed == list.ENTER_KEY)
      this.command('show');
    else if (list.key_pressed == list.DELETE_KEY)
      this.command('delete');
    else if (list.key_pressed == list.BACKSPACE_KEY)
      this.command('delete');
    else
      list.shiftkey = false;
    };
  this.msglist_get_preview = function()
  {
@@ -1178,11 +1312,10 @@
      this.show_contentframe(false);
  };
  
  this.check_droptarget = function(id)
  {
    if (this.task == 'mail')
      return (id != this.env.mailbox);
      return (this.env.mailboxes[id] && this.env.mailboxes[id].id != this.env.mailbox && !this.env.mailboxes[id].virtual);
    else if (this.task == 'addressbook')
      return (id != this.env.source && this.env.address_sources[id] && !this.env.address_sources[id].readonly);
    else if (this.task == 'settings')
@@ -1194,13 +1327,15 @@
  /*********     (message) list functionality      *********/
  /*********************************************************/
  // when user doble-clicks on a row
  this.show_message = function(id, safe, preview)
    {
    if (!id) return;
    var add_url = '';
    var action = preview ? 'preview': 'show';
    var target = window;
    if (preview && this.env.contentframe && window.frames && window.frames[this.env.contentframe])
      {
      target = window.frames[this.env.contentframe];
@@ -1213,36 +1348,43 @@
    // also send search request to get the right messages
    if (this.env.search_request)
      add_url += '&_search='+this.env.search_request;
    if (id)
    var url = '&_action='+action+'&_uid='+id+'&_mbox='+urlencode(this.env.mailbox)+add_url;
    if (action == 'preview' && String(target.location.href).indexOf(url) >= 0)
      this.show_contentframe(true);
    else
      {
      var url = '&_action='+action+'&_uid='+id+'&_mbox='+urlencode(this.env.mailbox)+add_url;
      if (action == 'preview' && String(target.location.href).indexOf(url) >= 0)
        this.show_contentframe(true);
      else
      this.set_busy(true, 'loading');
      target.location.href = this.env.comm_path+url;
      // mark as read and change mbox unread counter
      if (action == 'preview' && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread)
        {
        this.set_busy(true, 'loading');
        target.location.href = this.env.comm_path+url;
        }
        this.set_message(id, 'unread', false);
   if (this.env.unread_counts[this.env.mailbox])
     {
     this.env.unread_counts[this.env.mailbox] -= 1;
     this.set_unread_count(this.env.mailbox, this.env.unread_counts[this.env.mailbox], this.env.mailbox == 'INBOX');
     }
   }
      }
    };
  this.show_contentframe = function(show)
    {
    var frm;
    if (this.env.contentframe && (frm = rcube_find_object(this.env.contentframe)))
      {
      if (!show && window.frames[this.env.contentframe] && frames[this.env.contentframe].location.href.indexOf(this.env.blankpage)<0)
        frames[this.env.contentframe].location.href = this.env.blankpage;
      if (!bw.safari)
      if (!show && window.frames[this.env.contentframe])
        {
        if (window.frames[this.env.contentframe].location.href.indexOf(this.env.blankpage)<0)
          window.frames[this.env.contentframe].location.href = this.env.blankpage;
        }
      else if (!bw.safari)
        frm.style.display = show ? 'block' : 'none';
      }
      
    if (!show && this.busy)
      this.set_busy(false);
    };
  // list a specific page
  this.list_page = function(page)
@@ -1266,7 +1408,6 @@
        this.list_contacts(this.env.source, page);
      }
    };
  // list messages of a specific mailbox
  this.list_mailbox = function(mbox, page, sort)
@@ -1323,7 +1464,6 @@
      }
    };
  // send remote request to load message list
  this.list_mailbox_remote = function(mbox, page, add_url)
    {
@@ -1335,7 +1475,6 @@
    this.set_busy(true, 'loading');
    this.http_request('list', url+add_url, true);
    };
  this.expunge_mailbox = function(mbox)
    {
@@ -1354,7 +1493,6 @@
    var url = '_mbox='+urlencode(mbox);
    this.http_post('expunge', url+add_url, lock);
    };
  this.purge_mailbox = function(mbox)
    {
@@ -1378,7 +1516,118 @@
    return true;
    };
  // test if purge command is allowed
  this.purge_mailbox_test = function()
  {
    return (this.env.messagecount && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox
      || this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter))
      || this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter))));
  };
  // set message icon
  this.set_message_icon = function(uid)
  {
    var icn_src;
    var rows = this.message_list.rows;
    if (!rows[uid])
      return false;
    if (rows[uid].deleted && this.env.deletedicon)
      icn_src = this.env.deletedicon;
    else if (rows[uid].replied && this.env.repliedicon)
      {
      if (rows[uid].forwarded && this.env.forwardedrepliedicon)
        icn_src = this.env.forwardedrepliedicon;
      else
        icn_src = this.env.repliedicon;
      }
    else if (rows[uid].forwarded && this.env.forwardedicon)
      icn_src = this.env.forwardedicon;
    else if (rows[uid].unread && this.env.unreadicon)
      icn_src = this.env.unreadicon;
    else if (this.env.messageicon)
      icn_src = this.env.messageicon;
    if (icn_src && rows[uid].icon)
      rows[uid].icon.src = icn_src;
    icn_src = '';
    if (rows[uid].flagged && this.env.flaggedicon)
      icn_src = this.env.flaggedicon;
    else if (this.env.unflaggedicon)
      icn_src = this.env.unflaggedicon;
    if (rows[uid].flagged_icon && icn_src)
      rows[uid].flagged_icon.src = icn_src;
  }
  // set message status
  this.set_message_status = function(uid, flag, status)
    {
    var rows = this.message_list.rows;
    if (!rows[uid]) return false;
    if (flag == 'unread')
      rows[uid].unread = status;
    else if(flag == 'deleted')
      rows[uid].deleted = status;
    else if (flag == 'replied')
      rows[uid].replied = status;
    else if (flag == 'forwarded')
      rows[uid].forwarded = status;
    else if (flag == 'flagged')
      rows[uid].flagged = status;
    }
  // set message row status, class and icon
  this.set_message = function(uid, flag, status)
    {
    var rows = this.message_list.rows;
    if (!rows[uid]) return false;
    if (flag)
      this.set_message_status(uid, flag, status);
    if (rows[uid].unread && rows[uid].classname.indexOf('unread')<0)
      {
      rows[uid].classname += ' unread';
      this.set_classname(rows[uid].obj, 'unread', true);
      }
    else if (!rows[uid].unread && rows[uid].classname.indexOf('unread')>=0)
      {
      rows[uid].classname = rows[uid].classname.replace(/\s*unread/, '');
      this.set_classname(rows[uid].obj, 'unread', false);
      }
    if (rows[uid].deleted && rows[uid].classname.indexOf('deleted')<0)
      {
      rows[uid].classname += ' deleted';
      this.set_classname(rows[uid].obj, 'deleted', true);
      }
    else if (!rows[uid].deleted && rows[uid].classname.indexOf('deleted')>=0)
      {
      rows[uid].classname = rows[uid].classname.replace(/\s*deleted/, '');
      this.set_classname(rows[uid].obj, 'deleted', false);
      }
    if (rows[uid].flagged && rows[uid].classname.indexOf('flagged')<0)
      {
      rows[uid].classname += ' flagged';
      this.set_classname(rows[uid].obj, 'flagged', true);
      }
    else if (!rows[uid].flagged && rows[uid].classname.indexOf('flagged')>=0)
      {
      rows[uid].classname = rows[uid].classname.replace(/\s*flagged/, '');
      this.set_classname(rows[uid].obj, 'flagged', false);
      }
    this.set_message_icon(uid);
    }
  // move selected messages to the specified mailbox
  this.move_messages = function(mbox)
    {
@@ -1395,20 +1644,20 @@
      lock = true;
      this.set_busy(true, 'movingmessage');
      }
    else
    else if (!this.env.flag_for_deletion)
      this.show_contentframe(false);
    // Hide message command buttons until a message is selected
    this.enable_command('reply', 'reply-all', 'forward', 'delete', 'mark', 'print', false);
    this._with_selected_messages('moveto', lock, add_url);
    this._with_selected_messages('moveto', lock, add_url, (this.env.flag_for_deletion ? false : true));
    };
  // delete selected messages from the current mailbox
  this.delete_messages = function()
    {
    var selection = this.message_list ? this.message_list.get_selection() : new Array();
    // exit if no mailbox specified or if selection is empty
    if (!this.env.uid && !selection.length)
        return;
@@ -1442,7 +1691,6 @@
      this.permanently_remove_messages();
  };
  // delete the selected messages permanently
  this.permanently_remove_messages = function()
    {
@@ -1451,71 +1699,100 @@
      return;
      
    this.show_contentframe(false);
    this._with_selected_messages('delete', false, '&_from='+(this.env.action ? this.env.action : ''));
    this._with_selected_messages('delete', false, '&_from='+(this.env.action ? this.env.action : ''), true);
    };
  // Send a specifc request with UIDs of all selected messages
  // @private
  this._with_selected_messages = function(action, lock, add_url)
    {
  this._with_selected_messages = function(action, lock, add_url, remove)
  {
    var a_uids = new Array();
    if (this.env.uid)
      a_uids[a_uids.length] = this.env.uid;
      a_uids[0] = this.env.uid;
    else
      {
    {
      var selection = this.message_list.get_selection();
      var rows = this.message_list.rows;
      var id;
      for (var n=0; n<selection.length; n++)
        {
        id = selection[n];
        a_uids[a_uids.length] = id;
        this.message_list.remove_row(id, (n == selection.length-1));
        if (remove)
          this.message_list.remove_row(id, (n == selection.length-1));
        else
        {
          rows[id].deleted = true;
          if (this.env.read_when_deleted)
           rows[id].unread = false;
     this.set_message(id);
        }
      }
    }
    // also send search request to get the right messages 
    if (this.env.search_request) 
      add_url += '&_search='+this.env.search_request;
    // send request to server
    this.http_post(action, '_uid='+a_uids.join(',')+'&_mbox='+urlencode(this.env.mailbox)+add_url, lock);
    };
  };
  // set a specific flag to one or more messages
  this.mark_message = function(flag, uid)
    {
    var a_uids = new Array();
    var r_uids = new Array();
    var selection = this.message_list ? this.message_list.get_selection() : new Array();
    if (uid)
      a_uids[0] = uid;
    else if (this.env.uid)
      a_uids[0] = this.env.uid;
    else if (this.message_list)
      {
      for (var id, n=0; n<selection.length; n++)
      for (var n=0; n<selection.length; n++)
        {
        id = selection[n];
        if ((flag=='read' && this.message_list.rows[id].unread) || (flag=='unread' && !this.message_list.rows[id].unread)
            || (flag=='delete' && !this.message_list.rows[id].deleted) || (flag=='undelete' && this.message_list.rows[id].deleted))
          a_uids[a_uids.length] = id;
          a_uids[a_uids.length] = selection[n];
        }
      }
    if (!this.message_list)
      r_uids = a_uids;
    else
      for (var id, n=0; n<a_uids.length; n++)
      {
        id = a_uids[n];
        if ((flag=='read' && this.message_list.rows[id].unread)
            || (flag=='unread' && !this.message_list.rows[id].unread)
            || (flag=='delete' && !this.message_list.rows[id].deleted)
            || (flag=='undelete' && this.message_list.rows[id].deleted)
            || (flag=='flagged' && !this.message_list.rows[id].flagged)
            || (flag=='unflagged' && this.message_list.rows[id].flagged))
        {
          r_uids[r_uids.length] = id;
        }
      }
    // nothing to do
    if (!a_uids.length)
    if (!r_uids.length)
      return;
    switch (flag)
      {
        case 'read':
        case 'unread':
          this.toggle_read_status(flag, a_uids);
          this.toggle_read_status(flag, r_uids);
          break;
        case 'delete':
        case 'undelete':
          this.toggle_delete_status(a_uids);
          this.toggle_delete_status(r_uids);
          break;
        case 'flagged':
        case 'unflagged':
          this.toggle_flagged_status(flag, a_uids);
          break;
      }
    };
@@ -1524,56 +1801,30 @@
  this.toggle_read_status = function(flag, a_uids)
  {
    // mark all message rows as read/unread
    var icn_src;
    var rows = this.message_list.rows;
    for (var i=0; i<a_uids.length; i++)
      {
      uid = a_uids[i];
      if (rows[uid])
        {
        rows[uid].unread = (flag=='unread' ? true : false);
        if (rows[uid].classname.indexOf('unread')<0 && rows[uid].unread)
          {
          rows[uid].classname += ' unread';
          this.set_classname(rows[uid].obj, 'unread', true);
      this.set_message(a_uids[i], 'unread', (flag=='unread' ? true : false));
          if (this.env.unreadicon)
            icn_src = this.env.unreadicon;
          }
        else if (!rows[uid].unread)
          {
          rows[uid].classname = rows[uid].classname.replace(/\s*unread/, '');
          this.set_classname(rows[uid].obj, 'unread', false);
    this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag='+flag);
  };
          if (rows[uid].replied && this.env.repliedicon)
            icn_src = this.env.repliedicon;
          else if (this.env.messageicon)
            icn_src = this.env.messageicon;
          }
  // set image to flagged or unflagged
  this.toggle_flagged_status = function(flag, a_uids)
  {
    // mark all message rows as flagged/unflagged
    for (var i=0; i<a_uids.length; i++)
      this.set_message(a_uids[i], 'flagged', (flag=='flagged' ? true : false));
        if (rows[uid].icon && icn_src)
          rows[uid].icon.src = icn_src;
        }
      }
    this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag='+flag);
  };
  
  // mark all message rows as deleted/undeleted
  this.toggle_delete_status = function(a_uids)
  {
    if (this.env.read_when_deleted)
      this.toggle_read_status('read',a_uids);
    // if deleting message from "view message" don't bother with delete icon
    if (this.env.action == "show")
      return false;
    var rows = this.message_list.rows;
    var rows = this.message_list ? this.message_list.rows : new Array();
    if (a_uids.length==1)
    {
      if (rows[a_uids[0]] && rows[a_uids[0]].classname.indexOf('deleted') < 0)
      if (!rows.length || (rows[a_uids[0]] && !rows[a_uids[0]].deleted))
        this.flag_as_deleted(a_uids);
      else
        this.flag_as_undeleted(a_uids);
@@ -1586,7 +1837,7 @@
    {
      uid = a_uids[i];
      if (rows[uid]) {
        if (rows[uid].classname.indexOf('deleted')<0)
        if (!rows[uid].deleted)
        {
          all_deleted = false;
          break;
@@ -1602,76 +1853,69 @@
    return true;
  };
  this.flag_as_undeleted = function(a_uids)
  {
    // if deleting message from "view message" don't bother with delete icon
    if (this.env.action == "show")
      return false;
    var icn_src;
    var rows = this.message_list.rows;
    for (var i=0; i<a_uids.length; i++)
    {
      uid = a_uids[i];
      if (rows[uid]) {
        rows[uid].deleted = false;
        if (rows[uid].classname.indexOf('deleted') > 0)
        {
          rows[uid].classname = rows[uid].classname.replace(/\s*deleted/, '');
          this.set_classname(rows[uid].obj, 'deleted', false);
        }
        if (rows[uid].unread && this.env.unreadicon)
          icn_src = this.env.unreadicon;
        else if (rows[uid].replied && this.env.repliedicon)
          icn_src = this.env.repliedicon;
        else if (this.env.messageicon)
          icn_src = this.env.messageicon;
        if (rows[uid].icon && icn_src)
          rows[uid].icon.src = icn_src;
      }
    }
      this.set_message(a_uids[i], 'deleted', false);
    this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag=undelete');
    return true;
  };
  this.flag_as_deleted = function(a_uids)
  {
    // if deleting message from "view message" don't bother with delete icon
    if (this.env.action == "show")
      return false;
    var rows = this.message_list.rows;
    var add_url = '';
    var r_uids = new Array();
    var rows = this.message_list ? this.message_list.rows : new Array();
    for (var i=0; i<a_uids.length; i++)
    {
      {
      uid = a_uids[i];
      if (rows[uid]) {
        rows[uid].deleted = true;
        if (rows[uid].classname.indexOf('deleted')<0) {
          rows[uid].classname += ' deleted';
          this.set_classname(rows[uid].obj, 'deleted', true);
      if (rows[uid])
        {
   this.set_message(uid, 'deleted', true);
        if (rows[uid].unread)
          r_uids[r_uids.length] = uid;
        }
        if (rows[uid].icon && this.env.deletedicon)
          rows[uid].icon.src = this.env.deletedicon;
      }
    }
    this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag=delete');
    if (r_uids.length)
      add_url = '&_ruid='+r_uids.join(',');
    this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag=delete'+add_url);
    return true;  
  };
  // flag as read without mark request (called from backend)
  // argument should be a coma-separated list of uids
  this.flag_deleted_as_read = function(uids)
  {
    var icn_src;
    var rows = this.message_list ? this.message_list.rows : new Array();
    var str = String(uids);
    var a_uids = new Array();
    a_uids = str.split(',');
    for (var uid, i=0; i<a_uids.length; i++)
      {
      uid = a_uids[i];
      if (rows[uid])
        {
        rows[uid].unread = false;
        rows[uid].read = true;
   this.set_message(uid);
        }
      }
  };
  /*********************************************************/
  /*********           login form methods          *********/
  /*********************************************************/
  // handler for keyboard events on the _user field
  this.login_user_keypress = function(e)
  this.login_user_keyup = function(e)
  {
    var key = rcube_event.get_keycode(e);
    var elm;
@@ -1689,7 +1933,6 @@
  /*********        message compose methods        *********/
  /*********************************************************/
  
  // checks the input fields before sending a message
  this.check_compose_input = function()
    {
@@ -1697,8 +1940,17 @@
    var input_to = rcube_find_object('_to');
    var input_cc = rcube_find_object('_cc');
    var input_bcc = rcube_find_object('_bcc');
    var input_from = rcube_find_object('_from');
    var input_subject = rcube_find_object('_subject');
    var input_message = rcube_find_object('_message');
    // check sender (if have no identities)
    if (input_from.type == 'text' && !rcube_check_email(input_from.value, true))
      {
      alert(this.get_label('nosenderwarning'));
      input_from.focus();
      return false;
      }
    // check for empty recipient
    var recipients = input_to.value ? input_to.value : (input_cc.value ? input_cc.value : input_bcc.value);
@@ -1727,22 +1979,40 @@
      }
    // check for empty body
    if ((input_message.value == '' && (!window.tinyMCE || tinyMCE.getContent() == '')) && !confirm(this.get_label('nobodywarning')))
    if ((!window.tinyMCE || !tinyMCE.get('compose-body')) && input_message.value == '' && !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')))
      {
      tinyMCE.get('compose-body').focus();
      return false;
      }
    return true;
    };
  this.display_spellcheck_controls = function(vis)
  {
    if (this.env.spellcheck) {
      // stop spellchecking process
      if (!vis && !this.spellcheck_ready)
        {
   exec_event(this.env.spellcheck.check_link, 'click');
   this.set_spellcheck_state('ready');
   }
      this.env.spellcheck.check_link.style.visibility = vis ? 'visible' : 'hidden';
      this.env.spellcheck.switch_lan_pic.style.visibility = vis ? 'visible' : 'hidden';
    }
  };
  this.set_spellcheck_state = function(s)
    {
    this.spellcheck_ready = (s=='check_spelling' || s=='ready');
    this.enable_command('spellcheck', this.spellcheck_ready);
    };
  this.set_draft_id = function(id)
    {
@@ -1760,17 +2030,16 @@
    this.busy = false;
    };
  this.compose_field_hash = function(save)
    {
    // check input fields
    var input_to = rcube_find_object('_to');
    var input_cc = rcube_find_object('_to');
    var input_bcc = rcube_find_object('_to');
    var input_cc = rcube_find_object('_cc');
    var input_bcc = rcube_find_object('_bcc');
    var input_subject = rcube_find_object('_subject');
    var input_message = rcube_find_object('_message');
    var editor, input_message;
    var str = '';
    if (input_to && input_to.value)
      str += input_to.value+':';
    if (input_cc && input_cc.value)
@@ -1779,8 +2048,14 @@
      str += input_bcc.value+':';
    if (input_subject && input_subject.value)
      str += input_subject.value+':';
    if (input_message && input_message.value)
    if (editor = tinyMCE.get('compose-body'))
      str += editor.getContent();
    else
      {
      input_message = rcube_find_object('_message');
      str += input_message.value;
      }
    
    if (save)
      this.cmp_hash = str;
@@ -1788,7 +2063,6 @@
    return str;
    };
    
  this.change_identity = function(obj)
    {
    if (!obj || !obj.options)
@@ -1808,8 +2082,12 @@
      // remove the 'old' signature
      if (this.env.identity && this.env.signatures && this.env.signatures[this.env.identity])
        {
        sig = this.env.signatures[this.env.identity]['text'];
        if (sig.indexOf('-- ')!=0)
        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 (sig.indexOf('-- ')!=0)
          sig = '-- \n'+sig;
        p = message.lastIndexOf(sig);
@@ -1832,34 +2110,32 @@
      }
    else
      {
      var eid = tinyMCE.getEditorId('_message');
      // editor is a TinyMCE_Control object
      var editor = tinyMCE.getInstanceById(eid);
      // if this is null, we should exit
      if (editor == null) {
        return false;
      }
      var msgDoc = editor.getDoc();
      var msgBody = msgDoc.body;
      var editor = tinyMCE.get('compose-body');
      if (this.env.signatures && this.env.signatures[id])
      if (this.env.signatures)
        {
        // Append the signature as a span within the body
        var sigElem = msgDoc.getElementById("_rc_sig");
        // Append the signature as a div within the body
        var sigElem = editor.dom.get("_rc_sig");
   var newsig = '';
   var htmlsig = true;
        if (!sigElem)
          {
          sigElem = msgDoc.createElement("span");
          sigElem = editor.getDoc().createElement("div");
          sigElem.setAttribute("id", "_rc_sig");
          msgBody.appendChild(sigElem);
          editor.getBody().appendChild(sigElem);
          }
        if (this.env.signatures[id]['is_html'])
          {
          sigElem.innerHTML = this.env.signatures[id]['text'];
          }
   if (this.env.signatures[id])
     {
     newsig = this.env.signatures[id]['text'];
     htmlsig = this.env.signatures[id]['is_html'];
     }
        if (htmlsig)
          sigElem.innerHTML = newsig;
        else
          {
          sigElem.innerHTML = '<pre>' + this.env.signatures[id]['text'] + '</pre>';
          }
          sigElem.innerHTML = '<pre>' + newsig + '</pre>';
        }
      }
@@ -1869,7 +2145,6 @@
    this.env.identity = id;
    return true;
    };
  this.show_attachment_form = function(a)
    {
@@ -1902,7 +2177,6 @@
    return true;  
    };
  // upload attachment file
  this.upload_file = function(form)
    {
@@ -1926,7 +2200,7 @@
      // have to do it this way for IE
      // otherwise the form will be posted to a new window
      if(document.all && !window.opera)
      if(document.all)
        {
        var html = '<iframe name="'+frame_name+'" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>';
        document.body.insertAdjacentHTML('BeforeEnd',html);
@@ -1935,8 +2209,9 @@
        {
        var frame = document.createElement('IFRAME');
        frame.name = frame_name;
        frame.width = 10;
        frame.height = 10;
        frame.style.border = 'none';
        frame.style.width = 0;
        frame.style.height = 0;
        frame.style.visibility = 'hidden';
        document.body.appendChild(frame);
        }
@@ -1951,7 +2226,6 @@
    this.gui_objects.attachmentform = form;
    return true;
    };
  // add file name to attachment list
  // called from upload page
@@ -2010,7 +2284,7 @@
      // reset vars
      this.env.current_page = 1;
      this.set_busy(true, 'searching');
      this.http_request('search', '_q='+urlencode(value)+(this.env.mailbox ? '&_mbox='+this.env.mailbox : '')+(this.env.source ? '&_source='+urlencode(this.env.source) : ''), true);
      this.http_request('search', '_q='+urlencode(value)+(this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : '')+(this.env.source ? '&_source='+urlencode(this.env.source) : ''), true);
      }
    return true;
    };
@@ -2025,18 +2299,16 @@
    return true;
    };
  this.sent_successfully = function(msg)
  this.sent_successfully = function(type, msg)
    {
    this.list_mailbox();
    this.display_message(msg, 'confirmation', true);
    this.display_message(msg, type, true);
    }
  /*********************************************************/
  /*********     keyboard live-search methods      *********/
  /*********************************************************/
  // handler for keyboard events on address-fields
  this.ksearch_keypress = function(e, obj)
@@ -2101,12 +2373,11 @@
      }
    // start timer
    this.ksearch_timer = setTimeout(function(){ ref.ksearch_get_results(); }, 200);
    this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results(); }, 200);
    this.ksearch_input = obj;
    
    return true;
    };
  this.insert_recipient = function(id)
  {
@@ -2128,9 +2399,7 @@
    cpos = p+insert.length;
    if (this.ksearch_input.setSelectionRange)
      this.ksearch_input.setSelectionRange(cpos, cpos);
  };
  // address search processor
  this.ksearch_get_results = function()
@@ -2197,8 +2466,6 @@
        {
        li = document.createElement('LI');
        li.innerHTML = a_results[i].replace(/</, '&lt;').replace(/>/, '&gt;');
        li.onmousedown = function(e){ ref.insert_recipient(this._rcm_id); ref.ksearch_pane.show(0); return rcube_event.cancel(e); };
        li.style.cursor = 'pointer';
        li._rcm_id = a_result_ids[i];
        ul.appendChild(li);
        }
@@ -2234,7 +2501,6 @@
      this.ksearch_hide();
    };
  this.ksearch_blur = function(e, obj)
    {
    if (this.ksearch_timer)
@@ -2256,18 +2522,15 @@
    };
  /*********************************************************/
  /*********         address book methods          *********/
  /*********************************************************/
  this.contactlist_keypress = function(list)
    {
      if (list.key_pressed == list.DELETE_KEY)
        this.command('delete');
    };
  this.contactlist_select = function(list)
    {
@@ -2276,17 +2539,16 @@
      var id, frame, ref = this;
      if (id = list.get_single_selection())
        this.preview_timer = setTimeout(function(){ ref.load_contact(id, 'show'); }, this.dblclick_time + 10);
        this.preview_timer = window.setTimeout(function(){ ref.load_contact(id, 'show'); }, 200);
      else if (this.env.contentframe)
        this.show_contentframe(false);
      this.enable_command('edit', id?true:false);
      this.enable_command('compose', list.selection.length > 0);
      this.enable_command('edit', (id && this.env.address_sources && !this.env.address_sources[this.env.source].readonly) ? true : false);
      this.enable_command('delete', list.selection.length && this.env.address_sources && !this.env.address_sources[this.env.source].readonly);
      return false;
    };
  this.list_contacts = function(src, page)
    {
@@ -2330,7 +2592,6 @@
    target.location.href = this.env.comm_path+(src ? '&_source='+urlencode(src) : '')+(page ? '&_page='+page : '')+add_url;
    };
  // send remote request to load contacts list
  this.list_contacts_remote = function(src, page)
    {
@@ -2350,7 +2611,6 @@
    this.set_busy(true, 'loading');
    this.http_request('list', url, true);
    };
  // load contact record
  this.load_contact = function(cid, action, framed)
@@ -2376,13 +2636,13 @@
  // copy a contact to the specified target (group or directory)
  this.copy_contact = function(cid, to)
  {
    {
    if (!cid)
      cid = this.contact_list.get_selection().join(',');
    if (to != this.env.source && cid && this.env.address_sources[to] && !this.env.address_sources[to].readonly)
      this.http_post('copy', '_cid='+urlencode(cid)+'&_source='+urlencode(this.env.source)+'&_to='+urlencode(to));
  };
    };
  this.delete_contacts = function()
@@ -2417,10 +2677,9 @@
      qs += '&_search='+this.env.search_request;
    // send request to server
    this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_from='+(this.env.action ? this.env.action : '')+qs);
    this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source)+'&_from='+(this.env.action ? this.env.action : '')+qs);
    return true;
    };
  // update a contact record in the list
  this.update_contact_row = function(cid, cols_arr)
@@ -2493,7 +2752,6 @@
    return true;
    };
  this.delete_identity = function(id)
    {
    // exit if no mailbox specified or if selection is empty
@@ -2509,18 +2767,18 @@
    return true;
    };
  this.focus_subscription = function(id)
    {
    var row, folder;
    var reg = RegExp('['+RegExp.escape(this.env.delimiter)+']?[^'+RegExp.escape(this.env.delimiter)+']+$');
    if (this.drag_active && (row = document.getElementById(id)))
    if (this.drag_active && this.env.folder && (row = document.getElementById(id)))
      if (this.env.subscriptionrows[id] &&
          (folder = this.env.subscriptionrows[id][0]))
        {
        if (this.check_droptarget(folder) &&
            (folder != this.env.folder.replace(reg, '')) &&
           !this.env.subscriptionrows[this.get_folder_row_id(this.env.folder)][2] &&
       (folder != this.env.folder.replace(reg, '')) &&
            (!folder.match(new RegExp('^'+RegExp.escape(this.env.folder+this.env.delimiter)))))
          {
          this.set_env('dstfolder', folder);
@@ -2534,7 +2792,6 @@
        }
    }
  this.unfocus_subscription = function(id)
    {
      var row;
@@ -2546,14 +2803,12 @@
        this.set_classname(this.subscription_list.frame, 'droptarget', false);
    }
  this.subscription_select = function(list)
    {
    var id, folder;
    if ((id = list.get_single_selection()) &&
        this.env.subscriptionrows['rcmrow'+id] &&
        (folder = this.env.subscriptionrows['rcmrow'+id][0]) &&
        (find_in_array(this.env.defaultfolders, folder)!=0))
        (folder = this.env.subscriptionrows['rcmrow'+id][0]))
      this.set_env('folder', folder);
    else
      this.set_env('folder', null);
@@ -2561,7 +2816,6 @@
    if (this.gui_objects.createfolderhint)
      this.gui_objects.createfolderhint.innerHTML = this.env.folder ? this.get_label('addsubfolderhint') : '';
    };
  this.subscription_move_folder = function(list)
    {
@@ -2578,7 +2832,6 @@
    this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder));
    };
  // tell server to create and subscribe a new mailbox
  this.create_folder = function(name)
    {
@@ -2587,16 +2840,24 @@
    var form;
    if ((form = this.gui_objects.editform) && form.elements['_folder_name'])
      {
      name = form.elements['_folder_name'].value;
    if (this.env.folder && name != '')
      name = this.env.folder+this.env.delimiter+name;
    if (name)
      if (name.indexOf(this.env.delimiter)>=0)
        {
        alert(this.get_label('forbiddencharacter')+' ('+this.env.delimiter+')');
        return false;
        }
      if (this.env.folder && name != '')
        name = this.env.folder+this.env.delimiter+name;
      this.set_busy(true, 'foldercreating');
      this.http_post('create-folder', '_name='+urlencode(name), true);
      }
    else if (form.elements['_folder_name'])
      form.elements['_folder_name'].focus();
    };
  // start renaming the mailbox name.
  // this will replace the name string with an input field
@@ -2605,20 +2866,20 @@
    var temp, row, form;
    // reset current renaming
  if (temp = this.edit_folder)
    {
    this.reset_folder_rename();
    if (temp == id)
      return;
    }
    if (temp = this.edit_folder)
      {
      this.reset_folder_rename();
      if (temp == id)
        return;
      }
    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.value = this.env.subscriptionrows[id][1].replace(reg, '');
      this.name_input.value = this.env.subscriptionrows[id][0].replace(reg, '');
      this.name_input.style.width = '100%';
      reg = new RegExp('['+RegExp.escape(this.env.delimiter)+']?[^'+RegExp.escape(this.env.delimiter)+']+$');
      this.name_input.__parent = this.env.subscriptionrows[id][0].replace(reg, '');
      this.name_input.onkeypress = function(e){ rcmail.name_input_keypress(e); };
@@ -2632,20 +2893,16 @@
      }
    };
  // remove the input field and write the current mailbox name to the table cell
  this.reset_folder_rename = function()
    {
    var cell = this.name_input ? this.name_input.parentNode : null;
    if (cell && this.edit_folder && this.env.subscriptionrows[this.edit_folder])
      {
      var reg = new RegExp('[^'+RegExp.escape(this.env.delimiter)+']*['+RegExp.escape(this.env.delimiter)+']', 'g');
      cell.innerHTML = this.env.subscriptionrows[this.edit_folder][1].replace(reg, '&nbsp;&nbsp;&nbsp;&nbsp;');
      }
      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)
@@ -2658,16 +2915,23 @@
      var newname = this.name_input ? this.name_input.value : null;
      if (this.edit_folder && newname)
        {
        if (newname.indexOf(this.env.delimiter)>=0)
          {
          alert(this.get_label('forbiddencharacter')+' ('+this.env.delimiter+')');
          return false;
          }
        if (this.name_input.__parent)
          newname = this.name_input.__parent + this.env.delimiter + newname;
        this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.subscriptionrows[this.edit_folder][0])+'&_folder_newname='+urlencode(newname));
        this.set_busy(true, 'folderrenaming');
        this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.subscriptionrows[this.edit_folder][0])+'&_folder_newname='+urlencode(newname), true);
        }
      }
    // escape
    else if (key==27)
      this.reset_folder_rename();
    };
  // delete a specific mailbox with all its messages
  this.delete_folder = function(id)
@@ -2679,21 +2943,24 @@
    if (folder && confirm(this.get_label('deletefolderconfirm')))
      {
      this.http_post('delete-folder', '_mboxes='+urlencode(folder));
      this.set_busy(true, 'folderdeleting');
      this.http_post('delete-folder', '_mboxes='+urlencode(folder), true);
      this.set_env('folder', null);
      if (this.gui_objects.createfolderhint)
        this.gui_objects.createfolderhint.innerHTML = '';
      }
    };
  // add a new folder to the subscription list by cloning a folder row
  this.add_folder_row = function(name, display_name, replace)
  this.add_folder_row = function(name, display_name, replace, before)
    {
    name = name.replace('\\',"");
    if (!this.gui_objects.subscriptionlist)
      return false;
    // find not protected folder
    for (var refid in this.env.subscriptionrows)
      if (this.env.subscriptionrows[refid]!=null)
      if (this.env.subscriptionrows[refid]!=null && !this.env.subscriptionrows[refid][2])
        break;
    var refrow, form;
@@ -2717,14 +2984,18 @@
      // clone a table row if there are existing rows
      var row = this.clone_table_row(refrow);
      row.id = id;
      if (replace)
        tbody.replaceChild(row, replace);
      if (before && (before = this.get_folder_row_id(before)))
        tbody.insertBefore(row, document.getElementById(before));
      else
        tbody.appendChild(row);
      if (replace)
        tbody.removeChild(replace);
      }
    // add to folder/row-ID map
    this.env.subscriptionrows[row.id] = [name, display_name];
    this.env.subscriptionrows[row.id] = [name, display_name, 0];
    // set folder name
    row.cells[0].innerHTML = display_name;
@@ -2748,7 +3019,6 @@
        form.elements['_folder_name'].value = ''; 
      }
    this.sort_subscription_list();
    this.init_subscription_list();
    if (selection && document.getElementById('rcmrow'+selection))
      this.subscription_list.select_row(selection);
@@ -2757,15 +3027,14 @@
      document.getElementById(id).scrollIntoView();
    };
  // replace an existing table row with a new folder line
  this.replace_folder_row = function(oldfolder, newfolder, display_name)
  this.replace_folder_row = function(oldfolder, newfolder, display_name, before)
    {
    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.add_folder_row(newfolder, display_name, row, before);
    
    // rename folder in rename-folder dropdown
    var form, elm;
@@ -2784,7 +3053,6 @@
      form.elements['_folder_newname'].value = '';
      }
    };
  // remove the table row of a specific mailbox from the table
  // (the row will not be removed, just hidden)
@@ -2793,7 +3061,7 @@
    var row;
    var id = this.get_folder_row_id(folder);
    if (id && (row = document.getElementById(id)))
      row.style.display = 'none';
      row.style.display = 'none';
    // remove folder from rename-folder list
    var form;
@@ -2813,63 +3081,18 @@
      form.elements['_folder_newname'].value = '';
    };
  this.subscribe_folder = function(folder)
    {
    var form;
    if ((form = this.gui_objects.editform) && form.elements['_unsubscribed'])
      this.change_subscription('_unsubscribed', '_subscribed', 'subscribe');
    else if (folder)
      this.http_post('subscribe', '_mboxes='+urlencode(folder));
    if (folder)
      this.http_post('subscribe', '_mbox='+urlencode(folder));
    };
  this.unsubscribe_folder = function(folder)
    {
    var form;
    if ((form = this.gui_objects.editform) && form.elements['_subscribed'])
      this.change_subscription('_subscribed', '_unsubscribed', 'unsubscribe');
    else if (folder)
      this.http_post('unsubscribe', '_mboxes='+urlencode(folder));
    if (folder)
      this.http_post('unsubscribe', '_mbox='+urlencode(folder));
    };
    
  this.change_subscription = function(from, to, action)
    {
    var form;
    if (form = this.gui_objects.editform)
      {
      var a_folders = new Array();
      var list_from = form.elements[from];
      for (var i=0; list_from && i<list_from.options.length; i++)
        {
        if (list_from.options[i] && list_from.options[i].selected)
          {
          a_folders[a_folders.length] = list_from.options[i].value;
          list_from[i] = null;
          i--;
          }
        }
      // yes, we have some folders selected
      if (a_folders.length)
        {
        var list_to = form.elements[to];
        var index;
        for (var n=0; n<a_folders.length; n++)
          {
          index = list_to.options.length;
          list_to[index] = new Option(a_folders[n]);
          }
        this.http_post(action, '_mboxes='+urlencode(a_folders.join(',')));
        }
      }
    };
  // helper method to find a specific mailbox row ID
  this.get_folder_row_id = function(folder)
    {
@@ -2885,9 +3108,9 @@
    {
    var cell, td;
    var new_row = document.createElement('TR');
    for(var n=0; n<row.childNodes.length; n++)
    for(var n=0; n<row.cells.length; n++)
      {
      cell = row.childNodes[n];
      cell = row.cells[n];
      td = document.createElement('TD');
      if (cell.className)
@@ -2902,37 +3125,10 @@
    return new_row;
    };
  // sort subscription folder list
  this.sort_subscription_list = function()
    {
    var index = new Array();
    var tbody = this.gui_objects.subscriptionlist.tBodies[0];
    var swapped = false;
    for (var i = 0; i<tbody.childNodes.length; i++)
      if (this.env.subscriptionrows[tbody.childNodes[i].id]!=null)
        index.push(i);
    for (i = 0; i<(index.length-1); i++)
      {
      var one = tbody.childNodes[index[i]];
      var two = tbody.childNodes[index[i+1]];
      if (this.env.subscriptionrows[one.id][0].toLowerCase()>
          this.env.subscriptionrows[two.id][0].toLowerCase())
        {
        var swap = one.cloneNode(true);
        tbody.replaceChild(swap, two);
        tbody.replaceChild(two, one);
        swapped = true;
        }
      }
    if (swapped)
      this.sort_subscription_list();
    };
  /*********************************************************/
  /*********           GUI functionality           *********/
  /*********************************************************/
  // eable/disable buttons for page shifting
  this.set_page_buttons = function()
@@ -2943,7 +3139,6 @@
    this.enable_command('firstpage', (this.env.current_page > 1));
    }
  // set button to a specific state
  this.set_button = function(command, state)
    {
@@ -2951,7 +3146,7 @@
    var button, obj;
    if(!a_buttons || !a_buttons.length)
      return;
      return false;
    for(var n=0; n<a_buttons.length; n++)
      {
@@ -3019,7 +3214,7 @@
    var button, img;
    if(!a_buttons || !a_buttons.length)
      return;
      return false;
    for(var n=0; n<a_buttons.length; n++)
      {
@@ -3031,6 +3226,7 @@
          img.src = button.over;
        }
      }
    };
  // mouse down on button
@@ -3075,7 +3271,6 @@
      }
    };
  // set/unset a specific class name
  this.set_classname = function(obj, classname, set)
    {
@@ -3086,14 +3281,12 @@
      obj.className += ' '+classname;
    };
  // write to the document/window title
  this.set_pagetitle = function(title)
  {
    if (title && document.title)
      document.title = title;
  }
  // display a system message
  this.display_message = function(msg, type, hold)
@@ -3126,9 +3319,8 @@
      this.gui_objects.message.onmousedown = function(){ _rcube.hide_message(); return true; };
    
    if (!hold)
      this.message_timer = setTimeout(function(){ ref.hide_message(); }, this.message_time);
      this.message_timer = window.setTimeout(function(){ ref.hide_message(); }, this.message_time);
    };
  // make a message row disapear
  this.hide_message = function()
@@ -3139,7 +3331,6 @@
      this.gui_objects.message.onmousedown = null;
      }
    };
  // mark a mailbox as selected and set environment variable
  this.select_folder = function(name, old)
@@ -3174,7 +3365,6 @@
    return null;
  };
  // for reordering column array, Konqueror workaround
  this.set_message_coltypes = function(coltypes) 
  { 
@@ -3200,9 +3390,12 @@
        cell.id = 'rcmHead'+col;
        }
      if (col == 'subject' && this.message_list)
      else if (col == 'subject' && this.message_list)
        this.message_list.subject_col = n+1;
      else if (col == 'flag' && this.env.unflaggedicon)
        {
     cell.innerHTML = '<img src="'+this.env.unflaggedicon+'" alt="" />';
   }
      }
  };
@@ -3218,22 +3411,39 @@
    
    this.env.messages[uid] = {deleted:flags.deleted?1:0,
                              replied:flags.replied?1:0,
                              unread:flags.unread?1:0};
                              unread:flags.unread?1:0,
               forwarded:flags.forwarded?1:0,
                              flagged:flags.flagged?1:0};
    
    var row = document.createElement('TR');
    row.id = 'rcmrow'+uid;
    row.className = 'message '+(even ? 'even' : 'odd')+(flags.unread ? ' unread' : '')+(flags.deleted ? ' deleted' : '');
    row.className = 'message'
   + (even ? ' even' : ' odd')
        + (flags.unread ? ' unread' : '')
   + (flags.deleted ? ' deleted' : '')
   + (flags.flagged ? ' flagged' : '');
    if (this.message_list.in_selection(uid))
      row.className += ' selected';
    var icon = flags.deleted && this.env.deletedicon ? this.env.deletedicon:
               (flags.unread && this.env.unreadicon ? this.env.unreadicon :
               (flags.replied && this.env.repliedicon ? this.env.repliedicon : this.env.messageicon));
    var icon = this.env.messageicon;
    if (flags.deleted && this.env.deletedicon)
      icon = this.env.deletedicon;
    else if (flags.replied && this.env.repliedicon)
      {
      if (flags.forwarded && this.env.forwardedrepliedicon)
        icon = this.env.forwardedrepliedicon;
      else
        icon = this.env.repliedicon;
      }
    else if (flags.forwarded && this.env.forwardedicon)
      icon = this.env.forwardedicon;
    else if(flags.unread && this.env.unreadicon)
      icon = this.env.unreadicon;
    var col = document.createElement('TD');
    col.className = 'icon';
    col.innerHTML = icon ? '<img src="'+icon+'" alt="" border="0" />' : '';
    col.innerHTML = icon ? '<img src="'+icon+'" alt="" />' : '';
    row.appendChild(col);
    // add each submitted col
@@ -3242,18 +3452,35 @@
      var c = this.coltypes[n];
      col = document.createElement('TD');
      col.className = String(c).toLowerCase();
      col.innerHTML = cols[c];
      if (c=='flag')
        {
        if (flags.flagged && this.env.flaggedicon)
          col.innerHTML = '<img src="'+this.env.flaggedicon+'" alt="" />';
        else if(this.env.unflaggedicon)
          col.innerHTML = '<img src="'+this.env.unflaggedicon+'" alt="" />';
   }
      else
        col.innerHTML = cols[c];
      row.appendChild(col);
      }
    col = document.createElement('TD');
    col.className = 'icon';
    col.innerHTML = attachment && this.env.attachmenticon ? '<img src="'+this.env.attachmenticon+'" alt="" border="0" />' : '';
    col.innerHTML = attachment && this.env.attachmenticon ? '<img src="'+this.env.attachmenticon+'" alt="" />' : '';
    row.appendChild(col);
    this.message_list.insert_row(row, attop);
    };
    // remove 'old' row
    if (attop && this.env.pagesize && this.message_list.rowcount > this.env.pagesize)
      {
   var uid = this.message_list.get_last_row();
        this.message_list.remove_row(uid);
   this.message_list.clear_selection(uid);
      }
    };
  // replace content of row count display
  this.set_rowcount = function(text)
@@ -3265,17 +3492,19 @@
    this.set_page_buttons();
    };
  // replace content of quota display
  this.set_quota = function()
  // replace content of mailboxname display
  this.set_mailboxname = function(content)
    {
    if (this.gui_objects.quotadisplay &&
        this.gui_objects.quotadisplay.attributes.getNamedItem('display') &&
        this.gui_objects.quotadisplay.attributes.getNamedItem('id'))
      this.http_request('quotadisplay', '_display='+
      this.gui_objects.quotadisplay.attributes.getNamedItem('display').nodeValue+
      '&_id='+this.gui_objects.quotadisplay.attributes.getNamedItem('id').nodeValue, false);
     };
    if (this.gui_objects.mailboxname && content)
      this.gui_objects.mailboxname.innerHTML = content;
    };
  // replace content of quota display
  this.set_quota = function(content)
    {
    if (this.gui_objects.quotadisplay && content)
      this.gui_objects.quotadisplay.innerHTML = content;
    };
  // update the mailboxlist
  this.set_unread_count = function(mbox, count, set_title)
@@ -3283,22 +3512,45 @@
    if (!this.gui_objects.mailboxlist)
      return false;
    var reg, text_obj, item;
    this.env.unread_counts[mbox] = count;
    this.set_unread_count_display(mbox, set_title);
    }
  // update the mailbox count display
  this.set_unread_count_display = function(mbox, set_title)
    {
    var reg, text_obj, item, mycount, childcount, div;
    if (item = this.get_folder_li(mbox))
      {
      // set new text
      text_obj = item.firstChild;
      mycount = this.env.unread_counts[mbox] ? this.env.unread_counts[mbox] : 0;
      text_obj = item.getElementsByTagName('a')[0];
      reg = /\s+\([0-9]+\)$/i;
      if (count && text_obj.innerHTML.match(reg))
        text_obj.innerHTML = text_obj.innerHTML.replace(reg, ' ('+count+')');
      else if (count)
        text_obj.innerHTML += ' ('+count+')';
      childcount = 0;
      if ((div = item.getElementsByTagName('div')[0]) &&
          div.className.match(/collapsed/))
        {
        // add children's counters
        for (var k in this.env.unread_counts)
          if (k.indexOf(mbox + this.env.delimiter) == 0) {
            childcount += this.env.unread_counts[k];
     }
        }
      if (mycount && text_obj.innerHTML.match(reg))
        text_obj.innerHTML = text_obj.innerHTML.replace(reg, ' ('+mycount+')');
      else if (mycount)
        text_obj.innerHTML += ' ('+mycount+')';
      else
        text_obj.innerHTML = text_obj.innerHTML.replace(reg, '');
      // set parent's display
      reg = new RegExp(RegExp.escape(this.env.delimiter) + '[^' + RegExp.escape(this.env.delimiter) + ']+$');
      if (mbox.match(reg))
        this.set_unread_count_display(mbox.replace(reg, ''), false);
      // set the right classes
      this.set_classname(item, 'unread', count>0 ? true : false);
      this.set_classname(item, 'unread', (mycount+childcount)>0 ? true : false);
      }
    // set unread count to window title
@@ -3308,17 +3560,16 @@
      var doc_title = String(document.title);
      var new_title = "";
      if (count && doc_title.match(reg))
        new_title = doc_title.replace(reg, '('+count+') ');
      else if (count)
        new_title = '('+count+') '+doc_title;
      if (mycount && doc_title.match(reg))
        new_title = doc_title.replace(reg, '('+mycount+') ');
      else if (mycount)
        new_title = '('+mycount+') '+doc_title;
      else
        new_title = doc_title.replace(reg, '');
        
      this.set_pagetitle(new_title);
      }
    };
  // add row to contacts list
  this.add_contact_row = function(cid, cols, select)
@@ -3347,22 +3598,109 @@
      }
    
    this.contact_list.insert_row(row);
    this.enable_command('export', (this.contact_list.rowcount > 0));
    };
  this.toggle_editor = function(checkbox, textElementName)
  this.toggle_editor = function(checkbox, textAreaId)
    {
    var ischecked = checkbox.checked;
    var composeElement = document.getElementById(textAreaId);
    if (ischecked)
      {
        tinyMCE.execCommand('mceAddControl', true, textElementName);
      var existingPlainText = composeElement.value;
      var htmlText = "<pre>" + existingPlainText + "</pre>";
      composeElement.value = htmlText;
      tinyMCE.execCommand('mceAddControl', true, textAreaId);
      }
    else
      {
        tinyMCE.execCommand('mceRemoveControl', true, textElementName);
      var thisMCE = tinyMCE.get(textAreaId);
      var existingHtml = thisMCE.getContent();
      this.html2plain(existingHtml, textAreaId);
      tinyMCE.execCommand('mceRemoveControl', true, textAreaId);
      }
    };
  this.toggle_prefer_html = function(checkbox)
    {
    var addrbook_show_images;
    if (addrbook_show_images = document.getElementById('rcmfd_addrbook_show_images'))
      addrbook_show_images.disabled = !checkbox.checked;
    }
  // display fetched raw headers
  this.set_headers = function(content)
    {
    if (this.gui_objects.all_headers_row && this.gui_objects.all_headers_box && content)
      {
      var box = this.gui_objects.all_headers_box;
      box.innerHTML = content;
      box.style.display = 'block';
      if (this.env.framed && parent.rcmail)
   parent.rcmail.set_busy(false);
      else
        this.set_busy(false);
      }
    };
  // display all-headers row and fetch raw message headers
  this.load_headers = function(elem)
    {
    if (!this.gui_objects.all_headers_row || !this.gui_objects.all_headers_box || !this.env.uid)
      return;
    this.set_classname(elem, 'show-headers', false);
    this.set_classname(elem, 'hide-headers', true);
    this.gui_objects.all_headers_row.style.display = bw.ie ? 'block' : 'table-row';
    elem.onclick = function() { rcmail.hide_headers(elem); }
    // fetch headers only once
    if (!this.gui_objects.all_headers_box.innerHTML)
      {
      this.display_message(this.get_label('loading'), 'loading', true);
      this.http_post('headers', '_uid='+this.env.uid);
      }
    }
  // hide all-headers row
  this.hide_headers = function(elem)
    {
    if (!this.gui_objects.all_headers_row || !this.gui_objects.all_headers_box)
      return;
    this.set_classname(elem, 'hide-headers', false);
    this.set_classname(elem, 'show-headers', true);
    this.gui_objects.all_headers_row.style.display = 'none';
    elem.onclick = function() { rcmail.load_headers(elem); }
    }
  /********************************************************/
  /*********  html to text conversion functions   *********/
  /********************************************************/
  this.html2plain = function(htmlText, id)
    {
    var http_request = new rcube_http_request();
    var url = this.env.bin_path+'html2text.php';
    var rcmail = this;
    this.set_busy(true, 'converting');
    console.log('HTTP POST: '+url);
    http_request.onerror = function(o) { rcmail.http_error(o); };
    http_request.oncomplete = function(o) { rcmail.set_text_value(o, id); };
    http_request.POST(url, htmlText, 'application/octet-stream');
    }
  this.set_text_value = function(httpRequest, id)
    {
    this.set_busy(false);
    document.getElementById(id).value = httpRequest.get_text();
    console.log(httpRequest.get_text());
    }
  /********************************************************/
@@ -3386,7 +3724,6 @@
    this.redirect(this.env.comm_path+'&_action='+action+querystring, lock);
    };
  this.http_sockets = new Array();
  
  // find a non-busy socket or create a new one
@@ -3405,7 +3742,6 @@
    return this.http_sockets[i];
    };
  
  // send a http request to the server
  this.http_request = function(action, querystring, lock)
    {
@@ -3463,14 +3799,15 @@
  this.http_response = function(request_obj)
    {
    var ctype = request_obj.get_header('Content-Type');
    if (ctype){
    if (ctype)
      {
      ctype = String(ctype).toLowerCase();
      var ctype_array=ctype.split(";");
      ctype = ctype_array[0];
    }
      }
    if (request_obj.__lock)
        this.set_busy(false);
      this.set_busy(false);
    console.log(request_obj.get_text());
@@ -3479,42 +3816,63 @@
      eval(request_obj.get_text());
    // process the response data according to the sent action
    switch (request_obj.__action)
      {
    switch (request_obj.__action) {
      case 'delete':
        if (this.task == 'addressbook') {
          var uid = this.contact_list.get_selection();
          this.enable_command('compose', (uid && this.contact_list.rows[uid]));
          this.enable_command('delete', 'edit', (uid && this.contact_list.rows[uid] && this.env.address_sources && !this.env.address_sources[this.env.source].readonly));
          this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0));
        }
      case 'moveto':
        if (this.env.action=='show')
        if (this.env.action == 'show')
          this.command('list');
        else if (this.message_list)
          this.message_list.init();
        break;
      case 'purge':
      case 'expunge':
        if (!this.env.messagecount && this.task == 'mail') {
          // clear preview pane content
          if (this.env.contentframe)
            this.show_contentframe(false);
          // disable commands useless when mailbox is empty
          this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource',
            'print', 'load-attachment', 'purge', 'expunge', 'select-all', 'select-none', 'sort', false);
        }
        break;
      case 'check-recent':
      case 'getunread':
      case 'list':
        if (this.env.messagecount)
          this.enable_command('purge', (this.env.mailbox==this.env.trash_mailbox || this.env.mailbox==this.env.junk_mailbox));
        this.msglist_select(this.message_list);
        if (this.task == 'mail') {
          if (this.message_list && request_obj.__action == 'list')
            this.msglist_select(this.message_list);
          this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0));
          this.enable_command('purge', this.purge_mailbox_test());
        }
        else if (this.task == 'addressbook')
          this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0));
      case 'expunge':
        this.enable_command('select-all', 'select-none', 'expunge', this.env.messagecount ? true : false);
        break;
      }
    request_obj.reset();
    };
  // handle HTTP request errors
  this.http_error = function(request_obj)
    {
    //alert('Error sending request: '+request_obj.url);
    //alert('Error sending request: '+request_obj.url+' => HTTP '+request_obj.xmlhttp.status);
    if (request_obj.__lock)
      this.set_busy(false);
    request_obj.reset();
    request_obj.__lock = false;
    this.display_message('Unknown Server Error!', 'error');
    };
  // use an image to send a keep-alive siganl to the server
  this.send_keep_alive = function()
@@ -3523,7 +3881,6 @@
    this.http_request('keep-alive', '_t='+d.getTime());
    };
  // send periodic request to check for recent messages
  this.check_for_recent = function()
    {
@@ -3580,7 +3937,6 @@
      return obj.value.length;
    };
  this.set_caret2start = function(obj)
    {
    if (obj.createTextRange)
@@ -3594,7 +3950,6 @@
    obj.focus();
    };
  // set all fields of a form disabled
  this.lock_form = function(form, lock)
@@ -3616,7 +3971,6 @@
  }  // end object rcube_webmail
/**
 * Class for sending HTTP requests
 * @constructor
@@ -3626,7 +3980,6 @@
  this.url = '';
  this.busy = false;
  this.xmlhttp = null;
  // reset object properties
  this.reset = function()
@@ -3643,7 +3996,6 @@
    this.busy = false;
    this.xmlhttp = null;
    }
  // create HTMLHTTP object
  this.build = function()
@@ -3677,11 +4029,10 @@
    this.busy = true;
    this.xmlhttp.onreadystatechange = function(){ _ref.xmlhttp_onreadystatechange(); };
    this.xmlhttp.open('GET', url);
    this.xmlhttp.open('GET', url, true);
    this.xmlhttp.setRequestHeader('X-RoundCube-Referer', bw.get_cookie('roundcube_sessid'));
    this.xmlhttp.send(null);
    };
  this.POST = function(url, body, contentType)
    {
@@ -3715,7 +4066,6 @@
    this.xmlhttp.setRequestHeader('X-RoundCube-Referer', bw.get_cookie('roundcube_sessid'));
    this.xmlhttp.send(req_body);
    };
  // handle onreadystatechange event
  this.xmlhttp_onreadystatechange = function()
@@ -3773,7 +4123,6 @@
// helper function to call the init method with a delay
function call_init(o)
  {
  if (window[o] && window[o].init)
    setTimeout(o+'.init()', 200);
    window.setTimeout('if (window[\''+o+'\'] && window[\''+o+'\'].init) { '+o+'.init(); }',
                      bw.win ? 500 : 200);
  }