thomascube
2011-08-18 b6cd452bd31bfd4b6b94b23fe54b424fdf901e61
program/js/app.js
@@ -138,14 +138,6 @@
      return;
    }
    // Enable debug console
    if (!window.console || !window.console.log) {
      window.console = new rcube_console();
    }
    else {
      $('#console').hide();
    }
    // find all registered gui containers
    for (var n in this.gui_containers)
      this.gui_containers[n] = $('#'+this.gui_containers[n]);
@@ -209,7 +201,7 @@
          $(this.gui_objects.qsearchbox).focusin(function() { rcmail.message_list.blur(); });
        }
        if (this.env.trash_mailbox && this.env.mailbox != this.env.trash_mailbox)
        if (!this.env.flag_for_deletion && this.env.trash_mailbox && this.env.mailbox != this.env.trash_mailbox)
          this.set_alttext('delete', 'movemessagetotrash');
        this.env.message_commands = ['show', 'reply', 'reply-all', 'reply-list', 'forward',
@@ -260,7 +252,10 @@
        }
        // show printing dialog
        else if (this.env.action == 'print' && this.env.uid)
          window.print();
          if (bw.safari)
            window.setTimeout('window.print()', 10);
          else
            window.print();
        // get unread count for each mailbox
        if (this.gui_objects.mailboxlist) {
@@ -314,11 +309,8 @@
          this.enable_command('show', 'edit', true);
          // register handlers for group assignment via checkboxes
          if (this.gui_objects.editform) {
            $('input.groupmember').change(function(){
              var cmd = this.checked ? 'group-addmembers' : 'group-delmembers';
              ref.http_post(cmd, '_cid='+urlencode(ref.env.cid)
                + '&_source='+urlencode(ref.env.source)
                + '&_gid='+urlencode(this.value));
            $('input.groupmember').change(function() {
              ref.group_member_change(this.checked ? 'add' : 'del', ref.env.cid, ref.env.source, this.value);
            });
          }
        }
@@ -338,6 +330,10 @@
        this.enable_command('add', 'import', this.env.writable_source);
        this.enable_command('list', 'listgroup', 'advanced-search', true);
        // load contacts of selected source
        if (!this.env.action)
          this.command('list', this.env.source);
        break;
@@ -433,6 +429,11 @@
    this.start_keepalive();
  };
  this.log = function(msg)
  {
    if (window.console && console.log)
      console.log(msg);
  };
  /*********************************************************/
  /*********       client command interface        *********/
@@ -526,7 +527,7 @@
          this.list_mailbox(props);
          if (this.env.trash_mailbox)
          if (this.env.trash_mailbox && !this.env.flag_for_deletion)
            this.set_alttext('delete', this.env.mailbox != this.env.trash_mailbox ? 'movemessagetotrash' : 'deletemessage');
        }
        else if (this.task == 'addressbook') {
@@ -640,11 +641,6 @@
            // reload form
            if (props == 'reload') {
              form.action += '?_reload=1';
            }
            else if ((input = $("input[name='_name']", form)) &&input.length && input.val() == '') {
              alert(this.get_label('nonamewarning'));
              input.focus();
              break;
            }
            else if (this.task == 'settings' && (this.env.identities_level % 2) == 0  &&
              (input = $("input[name='_email']", form)) && input.length && !rcube_check_email(input.val())
@@ -991,14 +987,14 @@
      // reset quicksearch
      case 'reset-search':
        var s = this.env.search_request;
        var n, s = this.env.search_request || this.env.qsearch;
        this.reset_qsearch();
        if (s && this.env.mailbox)
          this.list_mailbox(this.env.mailbox);
        else if (s && this.task == 'addressbook') {
          if (this.env.source == '') {
            for (var n in this.env.address_sources) break;
            for (n in this.env.address_sources) break;
            this.env.source = n;
            this.env.group = '';
          }
@@ -1377,12 +1373,12 @@
      ul.show();
      div.removeClass('collapsed').addClass('expanded');
      var reg = new RegExp('&'+urlencode(id)+'&');
      this.set_env('collapsed_folders', this.env.collapsed_folders.replace(reg, ''));
      this.env.collapsed_folders = this.env.collapsed_folders.replace(reg, '');
    }
    else {
      ul.hide();
      div.removeClass('expanded').addClass('collapsed');
      this.set_env('collapsed_folders', this.env.collapsed_folders+'&'+urlencode(id)+'&');
      this.env.collapsed_folders = this.env.collapsed_folders+'&'+urlencode(id)+'&';
      // select parent folder if one of its childs is currently selected
      if (this.env.mailbox.indexOf(id + this.env.delimiter) == 0)
@@ -1567,10 +1563,10 @@
      }
    if ((found = $.inArray('flag', this.env.coltypes)) >= 0)
      this.set_env('flagged_col', found);
      this.env.flagged_col = found;
    if ((found = $.inArray('subject', this.env.coltypes)) >= 0)
      this.set_env('subject_col', found);
      this.env.subject_col = found;
    this.command('save-pref', { name: 'list_cols', value: this.env.coltypes, session: 'list_attrib/columns' });
  };
@@ -1876,10 +1872,7 @@
    if (action == 'preview' && String(target.location.href).indexOf(url) >= 0)
      this.show_contentframe(true);
    else {
      if (!this.env.frame_lock) {
        (this.is_framed() ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading');
      }
      this.location_href(this.env.comm_path+url, target);
      this.location_href(this.env.comm_path+url, target, true);
      // 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.env.preview_pane_mark_read >= 0) {
@@ -1911,6 +1904,12 @@
    if (!show && this.busy)
      this.set_busy(false, null, this.env.frame_lock);
  };
  this.lock_frame = function()
  {
    if (!this.env.frame_lock)
      (this.is_framed() ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading');
  };
  // list a specific page
@@ -2867,12 +2866,21 @@
      input_subject = $("input[name='_subject']"),
      input_message = $("[name='_message']").get(0),
      html_mode = $("input[name='_is_html']").val() == '1',
      ac_fields = ['cc', 'bcc', 'replyto', 'followupto'];
      ac_fields = ['cc', 'bcc', 'replyto', 'followupto'],
      ac_props;
    // configure parallel autocompletion
    if (this.env.autocomplete_threads > 0) {
      ac_props = {
        threads: this.env.autocomplete_threads,
        sources: this.env.autocomplete_sources
      };
    }
    // init live search events
    this.init_address_input_events(input_to);
    this.init_address_input_events(input_to, ac_props);
    for (var i in ac_fields) {
      this.init_address_input_events($("[name='_"+ac_fields[i]+"']"));
      this.init_address_input_events($("[name='_"+ac_fields[i]+"']"), ac_props);
    }
    if (!html_mode) {
@@ -2900,9 +2908,9 @@
    this.auto_save_start();
  };
  this.init_address_input_events = function(obj)
  this.init_address_input_events = function(obj, props)
  {
    obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e){ return ref.ksearch_keydown(e, this); })
    obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, props); })
      .attr('autocomplete', 'off');
  };
@@ -3245,11 +3253,21 @@
      return false;
    // get file input field, count files on capable browser
    var field = $('input[type=file]', form).get(0),
    var i, size = 0, field = $('input[type=file]', form).get(0),
      files = field.files ? field.files.length : field.value ? 1 : 0;
    // create hidden iframe and post upload form
    if (files) {
      // check file size
      if (field.files && this.env.max_filesize && this.env.filesizeerror) {
        for (i=0; i<files; i++)
          size += field.files[i].size;
        if (size && size > this.env.max_filesize) {
          this.display_message(this.env.filesizeerror, 'error');
          return;
        }
      }
      var frame_name = this.async_upload_form(form, 'upload', function(e) {
        var d, content = '';
        try {
@@ -3381,7 +3399,7 @@
  this.qsearch = function(value)
  {
    if (value != '') {
      var n, addurl = '', mods_arr = [],
      var n, r, addurl = '', mods_arr = [],
        mods = this.env.search_mods,
        mbox = this.env.mailbox,
        lock = this.set_busy(true, 'searching');
@@ -3405,13 +3423,14 @@
      // reset vars
      this.env.current_page = 1;
      this.http_request('search', '_q='+urlencode(value)
      r = this.http_request('search', '_q='+urlencode(value)
        + (mbox ? '&_mbox='+urlencode(mbox) : '')
        + (this.env.source ? '&_source='+urlencode(this.env.source) : '')
        + (this.env.group ? '&_gid='+urlencode(this.env.group) : '')
        + (addurl ? addurl : ''), lock);
      this.env.qsearch = {lock: lock, request: r};
    }
    return true;
  };
  // reset quick-search form
@@ -3420,8 +3439,11 @@
    if (this.gui_objects.qsearchbox)
      this.gui_objects.qsearchbox.value = '';
    if (this.env.qsearch)
      this.abort_request(this.env.qsearch);
    this.env.qsearch = null;
    this.env.search_request = null;
    return true;
  };
  this.sent_successfully = function(type, msg)
@@ -3437,14 +3459,14 @@
  /*********************************************************/
  // handler for keyboard events on address-fields
  this.ksearch_keydown = function(e, obj)
  this.ksearch_keydown = function(e, obj, props)
  {
    if (this.ksearch_timer)
      clearTimeout(this.ksearch_timer);
    var highlight;
    var key = rcube_event.get_keycode(e);
    var mod = rcube_event.get_modifier(e);
    var highlight,
      key = rcube_event.get_keycode(e),
      mod = rcube_event.get_modifier(e);
    switch (key) {
      case 38:  // key up
@@ -3467,8 +3489,8 @@
        if (mod == SHIFT_KEY)
          break;
     case 13:  // enter
        if (this.ksearch_selected===null || !this.ksearch_input || !this.ksearch_value)
      case 13:  // enter
        if (this.ksearch_selected === null || !this.ksearch_value)
          break;
        // insert selected address and hide ksearch pane
@@ -3488,7 +3510,7 @@
    }
    // start timer
    this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results(); }, 200);
    this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results(props); }, 200);
    this.ksearch_input = obj;
    return true;
@@ -3518,10 +3540,11 @@
      p = inp_value.lastIndexOf(this.ksearch_value, cpos),
      trigger = false,
      insert = '',
      // replace search string with full address
      pre = inp_value.substring(0, p),
      end = inp_value.substring(p+this.ksearch_value.length, inp_value.length);
    this.ksearch_destroy();
    // insert all members of a group
    if (typeof this.env.contacts[id] === 'object' && this.env.contacts[id].id) {
@@ -3556,7 +3579,7 @@
  };
  // address search processor
  this.ksearch_get_results = function()
  this.ksearch_get_results = function(props)
  {
    var inp_value = this.ksearch_input ? this.ksearch_input.value : null;
@@ -3593,6 +3616,8 @@
    var old_value = this.ksearch_value;
    this.ksearch_value = q;
    this.ksearch_destroy();
    // ...string is empty
    if (!q.length)
      return;
@@ -3601,59 +3626,104 @@
    if (old_value && old_value.length && this.env.contacts && !this.env.contacts.length && q.indexOf(old_value) == 0)
      return;
    var lock = this.display_message(this.get_label('searching'), 'loading');
    this.http_post('mail/autocomplete', '_search='+urlencode(q), lock);
    var i, lock, source, xhr, reqid = new Date().getTime(),
      threads = props && props.threads ? props.threads : 1,
      sources = props && props.sources ? props.sources : [],
      action = props && props.action ? props.action : 'mail/autocomplete';
    this.ksearch_data = {id: reqid, sources: sources.slice(), action: action, locks: [], requests: []};
    for (i=0; i<threads; i++) {
      source = this.ksearch_data.sources.shift();
      if (threads > 1 && source === null)
        break;
      lock = this.display_message(this.get_label('searching'), 'loading');
      xhr = this.http_post(action, '_search='+urlencode(q)+'&_id='+reqid
        + (source ? '&_source='+urlencode(source) : ''), lock);
      this.ksearch_data.locks.push(lock);
      this.ksearch_data.requests.push(xhr);
    }
  };
  this.ksearch_query_results = function(results, search)
  this.ksearch_query_results = function(results, search, reqid)
  {
    // ignore this outdated search response
    if (this.ksearch_value && search != this.ksearch_value)
    // search stopped in meantime?
    if (!this.ksearch_value)
      return;
    this.env.contacts = results ? results : [];
    this.ksearch_display_results(this.env.contacts);
  };
    // ignore this outdated search response
    if (this.ksearch_input && search != this.ksearch_value)
      return;
  this.ksearch_display_results = function (a_results)
  {
    // display search results
    if (a_results.length && this.ksearch_input && this.ksearch_value) {
      var p, ul, li, text, s_val = this.ksearch_value;
    var p, ul, li, text, init, s_val = this.ksearch_value,
      maxlen = this.env.autocomplete_max ? this.env.autocomplete_max : 15;
      // create results pane if not present
      if (!this.ksearch_pane) {
        ul = $('<ul>');
        this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane').css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body);
        this.ksearch_pane.__ul = ul[0];
      }
    // create results pane if not present
    if (!this.ksearch_pane) {
      ul = $('<ul>');
      this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane')
        .css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body);
      this.ksearch_pane.__ul = ul[0];
    }
      // remove all search results
      ul = this.ksearch_pane.__ul;
    ul = this.ksearch_pane.__ul;
    // remove all search results or add to existing list if parallel search
    if (reqid && this.ksearch_pane.data('reqid') == reqid) {
      maxlen -= ul.childNodes.length;
    }
    else {
      this.ksearch_pane.data('reqid', reqid);
      init = 1;
      // reset content
      ul.innerHTML = '';
      this.env.contacts = [];
      // move the results pane right under the input box
      var pos = $(this.ksearch_input).offset();
      this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px', display: 'none'});
    }
      // add each result line to list
      for (i=0; i < a_results.length; i++) {
        text = typeof a_results[i] === 'object' ? a_results[i].name : a_results[i];
    // add each result line to list
    if (results && results.length) {
      for (i=0; i < results.length && maxlen > 0; i++) {
        text = typeof results[i] === 'object' ? results[i].name : results[i];
        li = document.createElement('LI');
        li.innerHTML = text.replace(new RegExp('('+RegExp.escape(s_val)+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>');
        li.onmouseover = function(){ ref.ksearch_select(this); };
        li.onmouseup = function(){ ref.ksearch_click(this) };
        li._rcm_id = i;
        li._rcm_id = this.env.contacts.length + i;
        ul.appendChild(li);
        maxlen -= 1;
      }
      // select the first
      $(ul.firstChild).attr('id', 'rcmksearchSelected').addClass('selected');
      this.ksearch_selected = 0;
      // move the results pane right under the input box and make it visible
      var pos = $(this.ksearch_input).offset();
      this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px' }).show();
    }
    // hide results pane
    else
      this.ksearch_hide();
    if (ul.childNodes.length) {
      this.ksearch_pane.show();
      // select the first
      if (!this.env.contacts.length) {
        $('li:first', ul).attr('id', 'rcmksearchSelected').addClass('selected');
        this.ksearch_selected = 0;
      }
    }
    if (results && results.length)
      this.env.contacts = this.env.contacts.concat(results);
    // run next parallel search
    if (maxlen > 0 && this.ksearch_data.id == reqid && this.ksearch_data.sources.length) {
      var lock, xhr, props = this.ksearch_data, source = props.sources.shift();
      if (source) {
        lock = this.display_message(this.get_label('searching'), 'loading');
        xhr = this.http_post(props.action, '_search='+urlencode(s_val)+'&_id='+reqid
          +'&_source='+urlencode(source), lock);
        this.ksearch_data.locks.push(lock);
        this.ksearch_data.requests.push(xhr);
      }
    }
  };
  this.ksearch_click = function(node)
@@ -3670,20 +3740,34 @@
    if (this.ksearch_timer)
      clearTimeout(this.ksearch_timer);
    this.ksearch_value = '';
    this.ksearch_input = null;
    this.ksearch_hide();
  };
  this.ksearch_hide = function()
  {
    this.ksearch_selected = null;
    this.ksearch_value = '';
    if (this.ksearch_pane)
      this.ksearch_pane.hide();
   };
    this.ksearch_destroy();
  };
  // Aborts pending autocomplete requests
  this.ksearch_destroy = function()
  {
    var i, len, ac = this.ksearch_data;
    if (!ac)
      return;
    for (i=0, len=ac.locks.length; i<len; i++)
      this.abort_request({request: ac.requests[i], lock: ac.locks[i]});
    this.ksearch_data = null;
  }
  /*********************************************************/
  /*********         address book methods          *********/
@@ -3833,10 +3917,22 @@
      if (this.env.group)
        add_url += '&_gid='+urlencode(this.env.group);
      this.set_busy(true);
      this.location_href(this.env.comm_path+'&_action='+action+'&_source='+urlencode(this.env.source)+'&_cid='+urlencode(cid) + add_url, target);
      this.location_href(this.env.comm_path+'&_action='+action
        +'&_source='+urlencode(this.env.source)
        +'&_cid='+urlencode(cid) + add_url, target, true);
    }
    return true;
  };
  // add/delete member to/from the group
  this.group_member_change = function(what, cid, source, gid)
  {
    what = what == 'add' ? 'add' : 'del';
    var lock = this.display_message(this.get_label(what == 'add' ? 'addingmember' : 'removingmember'), 'loading');
    this.http_post('group-'+what+'members', '_cid='+urlencode(cid)
      + '&_source='+urlencode(source)
      + '&_gid='+urlencode(gid), lock);
  };
  // copy a contact to the specified target (group or directory)
@@ -3845,23 +3941,22 @@
    if (!cid)
      cid = this.contact_list.get_selection().join(',');
    if (to.type == 'group' && to.source == this.env.source) {
      this.http_post('group-addmembers', '_cid='+urlencode(cid)
        + '&_source='+urlencode(this.env.source)
        + '&_gid='+urlencode(to.id));
    }
    if (to.type == 'group' && to.source == this.env.source)
      this.group_member_change('add', cid, to.source, to.id);
    else if (to.type == 'group' && !this.env.address_sources[to.source].readonly) {
      var lock = this.display_message(this.get_label('copyingcontact'), 'loading');
      this.http_post('copy', '_cid='+urlencode(cid)
        + '&_source='+urlencode(this.env.source)
        + '&_to='+urlencode(to.source)
        + '&_togid='+urlencode(to.id)
        + (this.env.group ? '&_gid='+urlencode(this.env.group) : ''));
        + (this.env.group ? '&_gid='+urlencode(this.env.group) : ''), lock);
    }
    else if (to.id != this.env.source && cid && this.env.address_sources[to.id] && !this.env.address_sources[to.id].readonly) {
      var lock = this.display_message(this.get_label('copyingcontact'), 'loading');
      this.http_post('copy', '_cid='+urlencode(cid)
        + '&_source='+urlencode(this.env.source)
        + '&_to='+urlencode(to.id)
        + (this.env.group ? '&_gid='+urlencode(this.env.group) : ''));
        + (this.env.group ? '&_gid='+urlencode(this.env.group) : ''), lock);
    }
  };
@@ -4016,8 +4111,10 @@
  this.group_delete = function()
  {
    if (this.env.group)
      this.http_post('group-delete', '_source='+urlencode(this.env.source)+'&_gid='+urlencode(this.env.group), true);
    if (this.env.group && confirm(this.get_label('deletegroupconfirm'))) {
      var lock = this.set_busy(true, 'groupdeleting');
      this.http_post('group-delete', '_source='+urlencode(this.env.source)+'&_gid='+urlencode(this.env.group), lock);
    }
  };
  // callback from server upon group-delete command
@@ -4335,7 +4432,7 @@
  this.set_photo_actions = function(id)
  {
    var n, buttons = this.buttons['upload-photo'];
    for (n=0; n < buttons.length; n++)
    for (n=0; buttons && n < buttons.length; n++)
      $('#'+buttons[n].id).html(this.get_label(id == '-del-' ? 'addphoto' : 'replacephoto'));
    $('#ff_photo').val(id);
@@ -4354,7 +4451,7 @@
      this.contact_list.clear_selection();
    }
    this.location_href(this.env.comm_path+'&_action=search'+add_url, target);
    this.location_href(this.env.comm_path+'&_action=search'+add_url, target, true);
    return true;
  };
@@ -4377,17 +4474,14 @@
  // preferences section select and load options frame
  this.section_select = function(list)
  {
    var id = list.get_single_selection();
    var id = list.get_single_selection(), add_url = '', target = window;
    if (id) {
      var add_url = '', 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];
      }
      this.location_href(this.env.comm_path+'&_action=edit-prefs&_section='+id+add_url, target);
      this.location_href(this.env.comm_path+'&_action=edit-prefs&_section='+id+add_url, target, true);
    }
    return true;
@@ -4456,6 +4550,9 @@
      row.obj.onmouseout = function() { p.unfocus_subscription(row.id); };
    };
    this.subscription_list.init();
    $('#mailboxroot')
      .mouseover(function(){ p.focus_subscription(this.id); })
      .mouseout(function(){ p.unfocus_subscription(this.id); })
  };
  this.focus_subscription = function(id)
@@ -4466,18 +4563,16 @@
    if (this.drag_active && this.env.mailbox && (row = document.getElementById(id)))
      if (this.env.subscriptionrows[id] &&
          (folder = this.env.subscriptionrows[id][0])) {
          (folder = this.env.subscriptionrows[id][0]) !== null
      ) {
        if (this.check_droptarget(folder) &&
            !this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2] &&
            (folder != this.env.mailbox.replace(reg, '')) &&
            (!folder.match(new RegExp('^'+RegExp.escape(this.env.mailbox+this.env.delimiter))))) {
          this.set_env('dstfolder', folder);
            (!folder.match(new RegExp('^'+RegExp.escape(this.env.mailbox+this.env.delimiter))))
        ) {
          this.env.dstfolder = folder;
          $(row).addClass('droptarget');
        }
      }
      else if (this.env.mailbox.match(new RegExp(delim))) {
        this.set_env('dstfolder', this.env.delimiter);
        $(this.subscription_list.frame).addClass('droptarget');
      }
  };
@@ -4485,7 +4580,7 @@
  {
    var row = $('#'+id);
    this.set_env('dstfolder', null);
    this.env.dstfolder = null;
    if (this.env.subscriptionrows[id] && row[0])
      row.removeClass('droptarget');
    else
@@ -4499,7 +4594,7 @@
    if (list && (id = list.get_single_selection()) &&
        (folder = this.env.subscriptionrows['rcmrow'+id])
    ) {
      this.set_env('mailbox', folder[0]);
      this.env.mailbox = folder[0];
      this.show_folder(folder[0]);
      this.enable_command('delete-folder', !folder[2]);
    }
@@ -4515,15 +4610,17 @@
    var delim = RegExp.escape(this.env.delimiter),
      reg = RegExp('['+delim+']?[^'+delim+']+$');
    if (this.env.mailbox && this.env.dstfolder && (this.env.dstfolder != this.env.mailbox) &&
    if (this.env.mailbox && this.env.dstfolder !== null && (this.env.dstfolder != this.env.mailbox) &&
        (this.env.dstfolder != this.env.mailbox.replace(reg, ''))
    ) {
      reg = new RegExp('[^'+delim+']*['+delim+']', 'g');
      var lock = this.set_busy(true, 'foldermoving'),
        basename = this.env.mailbox.replace(reg, ''),
        newname = this.env.dstfolder==this.env.delimiter ? basename : this.env.dstfolder+this.env.delimiter+basename;
      var basename = this.env.mailbox.replace(reg, ''),
        newname = this.env.dstfolder === '' ? basename : this.env.dstfolder+this.env.delimiter+basename;
      this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.mailbox)+'&_folder_newname='+urlencode(newname), lock);
      if (newname != this.env.mailbox) {
        this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.mailbox)+'&_folder_newname='+urlencode(newname), this.set_busy(true, 'foldermoving'));
        this.subscription_list.draglayer.hide();
      }
    }
    this.drag_active = false;
    this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder));
@@ -4553,9 +4650,9 @@
    if (!this.gui_objects.subscriptionlist)
      return false;
    var row, n, i, tmp, folders, len, list = [], slist = [],
    var row, n, i, tmp, folders, rowid, list = [], slist = [],
      tbody = this.gui_objects.subscriptionlist.tBodies[0],
      refrow = $('tr', tbody).get(0),
      refrow = $('tr', tbody).get(1),
      id = 'rcmrow'+((new Date).getTime());
    if (!refrow) {
@@ -4582,7 +4679,10 @@
    this.env.subscriptionrows[id] = [name, display_name, 0];
    // sort folders, to find a place where to insert the row
    folders = this.env.subscriptionrows;
    folders = [];
    $.each(this.env.subscriptionrows, function(k,v){ folders.push(v) });
    folders.sort(function(a,b){ return a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0) });
    for (n in folders) {
      // protected folder
      if (folders[n][2]) {
@@ -4598,19 +4698,22 @@
        tmp = null;
      }
    }
    list.sort();
    // make sure protected folders (and their subs) are on top
    list = slist.concat(list);
    // check if subfolder of a protected folder
    for (n=0; n<slist.length; n++) {
      if (name.indexOf(slist[n]+this.env.delimiter) == 0)
        rowid = this.get_folder_row_id(slist[n]);
    }
    // find folder position after sorting
    for (n=0, len=list.length; n<len; n++) {
      if (list[n] == name)
        break;
    for (n=0; !rowid && n<list.length; n++) {
      if (n && list[n] == name)
        rowid = this.get_folder_row_id(list[n-1]);
    }
    // add row to the table
    if (n && n < len)
      $('#'+this.get_folder_row_id(list[n-1])).after(row);
    if (rowid)
      $('#'+rowid).after(row);
    else
      row.appendTo(tbody);
@@ -4772,10 +4875,7 @@
      this.show_contentframe(true);
    }
    else {
      if (!this.env.frame_lock) {
        (parent.rcmail ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading');
      }
      this.location_href(this.env.comm_path+url, target);
      this.location_href(this.env.comm_path+url, target, true);
    }
  };
@@ -5058,7 +5158,8 @@
      obj.click(function() { return ref.hide_message(obj); });
    }
    window.setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout);
    if (timeout > 0)
      window.setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout);
    return id;
  };
@@ -5187,14 +5288,14 @@
    this.env.status_col = null;
    if ((n = $.inArray('subject', this.env.coltypes)) >= 0) {
      this.set_env('subject_col', n);
      this.env.subject_col = n;
      if (list)
        list.subject_col = n;
    }
    if ((n = $.inArray('flag', this.env.coltypes)) >= 0)
      this.set_env('flagged_col', n);
      this.env.flagged_col = n;
    if ((n = $.inArray('status', this.env.coltypes)) >= 0)
      this.set_env('status_col', n);
      this.env.status_col = n;
    if (list)
      list.init_header();
@@ -5416,11 +5517,11 @@
      url = '?_task=utils&_action=html2text',
      lock = this.set_busy(true, 'converting');
    console.log('HTTP POST: ' + url);
    this.log('HTTP POST: ' + url);
    $.ajax({ type: 'POST', url: url, data: htmlText, contentType: 'application/octet-stream',
      error: function(o, status, err) { rcmail.http_error(o, status, err, lock); },
      success: function(data) { rcmail.set_busy(false, null, lock); $(document.getElementById(id)).val(data); console.log(data); }
      success: function(data) { rcmail.set_busy(false, null, lock); $(document.getElementById(id)).val(data); rcmail.log(data); }
    });
  };
@@ -5435,7 +5536,7 @@
  /********************************************************/
  /*********        remote request methods        *********/
  /********************************************************/
  // compose a valid url with the given parameters
  this.url = function(action, query)
  {
@@ -5485,8 +5586,11 @@
    this.redirect(this.url(action, query));
  };
  this.location_href = function(url, target)
  this.location_href = function(url, target, frame)
  {
    if (frame)
      this.lock_frame();
    // simulate real link click to force IE to send referer header
    if (bw.ie && target == window)
      $('<a>').attr('href', url).appendTo(document.body).get(0).click();
@@ -5513,8 +5617,9 @@
    url += '&_remote=1';
    // send request
    console.log('HTTP GET: ' + url);
    $.ajax({
    this.log('HTTP GET: ' + url);
    return $.ajax({
      type: 'GET', url: url, data: { _unlock:(lock?lock:0) }, dataType: 'json',
      success: function(data){ ref.http_response(data); },
      error: function(o, status, err) { rcmail.http_error(o, status, err, lock); }
@@ -5544,12 +5649,22 @@
    }
    // send request
    console.log('HTTP POST: ' + url);
    $.ajax({
    this.log('HTTP POST: ' + url);
    return $.ajax({
      type: 'POST', url: url, data: postdata, dataType: 'json',
      success: function(data){ ref.http_response(data); },
      error: function(o, status, err) { rcmail.http_error(o, status, err, lock); }
    });
  };
  // aborts ajax request
  this.abort_request = function(r)
  {
    if (r.request)
      r.request.abort();
    if (r.lock)
      this.set_busy(false, null, r.lock);
  };
  // handle HTTP response
@@ -5577,7 +5692,7 @@
    // if we get javascript code from server -> execute it
    if (response.exec) {
      console.log(response.exec);
      this.log(response.exec);
      eval(response.exec);
    }
@@ -5638,6 +5753,7 @@
      case 'check-recent':
      case 'getunread':
      case 'search':
        this.env.qsearch = null;
      case 'list':
        if (this.task == 'mail') {
          this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0));
@@ -5843,11 +5959,12 @@
      if (elm.type == 'hidden')
        continue;
      // remember which elem was disabled before lock
      if (lock && elm.disabled)
        this.disabled_form_elements.push(elm);
      else if (lock || $.inArray(elm, this.disabled_form_elements)<0)
      // check this.disabled_form_elements before inArray() as a workaround for FF5 bug
      // http://bugs.jquery.com/ticket/9873
      else if (lock || (this.disabled_form_elements && $.inArray(elm, this.disabled_form_elements)<0))
        elm.disabled = lock;
    }
  };