Aleksander Machniak
2013-05-30 ecbc8770c6aa9c2d68bf932f9dfa5dc8956bc8d1
program/js/app.js
@@ -3,8 +3,8 @@
 | Roundcube Webmail Client Script                                       |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
 | Copyright (C) 2011, Kolab Systems AG                                  |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 | Copyright (C) 2011-2012, Kolab Systems AG                             |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -219,7 +219,7 @@
        if (this.gui_objects.qsearchbox) {
          if (this.env.search_text != null)
            this.gui_objects.qsearchbox.value = this.env.search_text;
          $(this.gui_objects.qsearchbox).focusin(function() { rcmail.message_list.blur(); });
          $(this.gui_objects.qsearchbox).focusin(function() { rcmail.message_list && rcmail.message_list.blur(); });
        }
        this.set_button_titles();
@@ -251,7 +251,7 @@
          }
        }
        else if (this.env.action == 'compose') {
          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses', 'extwin'];
          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses', 'search', 'reset-search', 'extwin'];
          if (this.env.drafts_mailbox)
            this.env.compose_commands.push('savedraft')
@@ -312,7 +312,7 @@
        }
        // detect browser capabilities
        if (!this.is_framed())
        if (!this.is_framed() && !this.env.extwin)
          this.browser_capabilities_check();
        break;
@@ -361,7 +361,7 @@
        if (this.gui_objects.editform) {
          this.enable_command('save', true);
          if (this.env.action == 'add' || this.env.action == 'edit')
          if (this.env.action == 'add' || this.env.action == 'edit' || this.env.action == 'search')
              this.init_contact_form();
        }
@@ -509,7 +509,7 @@
      return false;
    // let the browser handle this click (shift/ctrl usually opens the link in a new window/tab)
    if ((obj && obj.href && String(obj.href).indexOf(location.href) < 0) && rcube_event.get_modifier(event)) {
    if ((obj && obj.href && String(obj.href).indexOf('#') < 0) && rcube_event.get_modifier(event)) {
      return true;
    }
@@ -583,11 +583,11 @@
          var prevstate = this.env.compose_extwin;
          $("input[name='_action']", this.gui_objects.messageform).val('compose');
          this.gui_objects.messageform.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 });
          this.gui_objects.messageform.target = this.open_window('', 1150, 900);
          this.gui_objects.messageform.target = this.open_window('', 1100, 900);
          this.gui_objects.messageform.submit();
        }
        else {
          this.open_window(this.env.permaurl, 1000, 1200);
          this.open_window(this.env.permaurl, 900, 900);
        }
        break;
@@ -820,12 +820,10 @@
        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 && this.env.mimetypes && $.inArray(props.mimetype, $.map(this.env.mimetypes, function(v,k){ return v })) >= 0) {
          if (props.mimetype == 'text/html')
            qstring += '&_safe=1';
          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);
        if (this.env.uid && props.mimetype && this.env.mimetypes && $.inArray(props.mimetype, this.env.mimetypes) >= 0) {
          var attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', this.html_identifier('rcubemailattachment'+this.env.uid+props.part));
          if (attachment_win) {
            setTimeout(function(){ attachment_win.focus(); }, 10);
            break;
          }
        }
@@ -946,8 +944,8 @@
        // Reset the auto-save timer
        clearTimeout(this.save_timer);
        // compose form did not change
        if (this.cmp_hash == this.compose_field_hash()) {
        // compose form did not change (and draft wasn't saved already)
        if (this.env.draft_id && this.cmp_hash == this.compose_field_hash()) {
          this.auto_save_start();
          break;
        }
@@ -1052,8 +1050,13 @@
        this.reset_qsearch();
        this.select_all_mode = false;
        if (s && this.env.mailbox)
        if (s && this.env.action == 'compose') {
          if (this.contact_list)
            this.list_contacts_clear();
        }
        else if (s && this.env.mailbox) {
          this.list_mailbox(this.env.mailbox, 1);
        }
        else if (s && this.task == 'addressbook') {
          if (this.env.source == '') {
            for (n in this.env.address_sources) break;
@@ -1549,7 +1552,7 @@
    // start timer for message preview (wait for double click)
    if (selected && this.env.contentframe && !list.multi_selecting && !this.dummy_select)
      this.preview_timer = setTimeout(function(){ ref.msglist_get_preview(); }, 200);
      this.preview_timer = setTimeout(function() { ref.msglist_get_preview(); }, this.dblclick_time);
    else if (this.env.contentframe)
      this.show_contentframe(false);
  };
@@ -1565,12 +1568,13 @@
    var win = this.get_frame_window(this.env.contentframe);
    if (win && win.location.href.indexOf(this.env.blankpage)>=0) {
    if (win && win.location.href.indexOf(this.env.blankpage) >= 0) {
      if (this.preview_timer)
        clearTimeout(this.preview_timer);
      if (this.preview_read_timer)
        clearTimeout(this.preview_read_timer);
      this.preview_timer = setTimeout(function(){ ref.msglist_get_preview(); }, 200);
      this.preview_timer = setTimeout(function() { ref.msglist_get_preview(); }, this.dblclick_time);
    }
  };
@@ -1578,11 +1582,11 @@
  {
    if (this.preview_timer)
      clearTimeout(this.preview_timer);
    if (this.preview_read_timer)
      clearTimeout(this.preview_read_timer);
    var uid = list.get_single_selection();
    if (uid && this.env.mailbox == this.env.drafts_mailbox)
      this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox });
    else if (uid)
@@ -1675,11 +1679,10 @@
    var w = Math.min(width, screen.width - 10),
      h = Math.min(height, screen.height - 100),
      l = (screen.width - w) / 2 + (screen.left || 0),
      t = Math.max(0, (screen.height - h) / 2 + (screen.top || 0) - 20);
    var wname = 'rcmextwin' + new Date().getTime(),
      extwin = window.open(url + '&_extwin=1', wname, 'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no');
    extwin.moveTo(l,t);
      t = Math.max(0, (screen.height - h) / 2 + (screen.top || 0) - 20),
      wname = 'rcmextwin' + new Date().getTime(),
      extwin = window.open(url + (url.match(/\?/) ? '&' : '?') + '_extwin=1', wname,
        'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no,location=no');
    // write loading... message to empty windows
    if (!url && extwin.document) {
@@ -1687,7 +1690,7 @@
    }
    // focus window, delayed to bring to front
    window.setTimeout(function(){ extwin.focus(); }, 10);
    window.setTimeout(function() { extwin.focus(); }, 10);
    return wname;
  };
@@ -3018,7 +3021,8 @@
    }
    else {
      this.redirect(url);
      window.resizeTo(Math.max(1150, $(window).width()), Math.max(900, $(window).height()));
      if (this.env.extwin)
        window.resizeTo(Math.max(1150, $(window).width()), Math.max(900, $(window).height()));
    }
  };
@@ -3034,10 +3038,10 @@
      input_message = $("[name='_message']").get(0),
      html_mode = $("input[name='_is_html']").val() == '1',
      ac_fields = ['cc', 'bcc', 'replyto', 'followupto'],
      ac_props;
      ac_props, opener_rc = this.opener();
    // close compose step in opener
    if (window.opener && opener.rcmail && opener.rcmail.env.action == 'compose') {
    if (opener_rc && opener_rc.env.action == 'compose') {
      setTimeout(function(){ opener.history.back(); }, 100);
      this.env.opened_extwin = true;
    }
@@ -3109,6 +3113,13 @@
    form._draft.value = draft ? '1' : '';
    form.action = this.add_url(form.action, '_unlock', msgid);
    form.action = this.add_url(form.action, '_lang', lang);
    // register timer to notify about connection timeout
    this.submit_timer = setTimeout(function(){
      ref.set_busy(false, null, msgid);
      ref.display_message(ref.get_label('requesttimedout'), 'error');
    }, this.env.request_timeout * 1000);
    form.submit();
  };
@@ -3119,7 +3130,7 @@
  this.compose_add_recipient = function(field)
  {
    var recipients = [], input = $('#_'+field);
    var recipients = [], input = $('#_'+field), delim = this.env.recipients_delimiter;
    if (this.contact_list && this.contact_list.selection.length) {
      for (var id, n=0; n < this.contact_list.selection.length; n++) {
@@ -3138,8 +3149,10 @@
    }
    if (recipients.length && input.length) {
      var oldval = input.val();
      input.val((oldval ? oldval + this.env.recipients_delimiter : '') + recipients.join(this.env.recipients_delimiter));
      var oldval = input.val(), rx = new RegExp(RegExp.escape(delim) + '\\s*$');
      if (oldval && !rx.test(oldval))
        oldval += delim + ' ';
      input.val(oldval + recipients.join(delim + ' ') + delim + ' ');
      this.triggerEvent('add-recipient', { field:field, recipients:recipients });
    }
  };
@@ -3329,6 +3342,15 @@
  this.set_draft_id = function(id)
  {
    var rc;
    if (!this.env.draft_id && id && (rc = this.opener())) {
      // refresh the drafts folder in opener window
      if (rc.env.task == 'mail' && rc.env.action == '' && rc.env.mailbox == this.env.drafts_mailbox)
        rc.command('checkmail');
    }
    this.env.draft_id = id;
    $("input[name='_draft_saveid']").val(id);
  };
@@ -3394,7 +3416,7 @@
        sig = this.env.signatures[sig].text;
        sig = sig.replace(/\r\n/g, '\n');
        p = this.env.sig_above ? message.indexOf(sig) : message.lastIndexOf(sig);
        p = this.env.top_posting ? message.indexOf(sig) : message.lastIndexOf(sig);
        if (p >= 0)
          message = message.substring(0, p) + message.substring(p+sig.length, message.length);
      }
@@ -3403,7 +3425,7 @@
        sig = this.env.signatures[id].text;
        sig = sig.replace(/\r\n/g, '\n');
        if (this.env.sig_above) {
        if (this.env.top_posting) {
          if (p >= 0) { // in place of removed signature
            message = message.substring(0, p) + sig + message.substring(p, message.length);
            cursor_pos = p - 1;
@@ -3447,7 +3469,7 @@
        sigElem = doc.createElement('div');
        sigElem.setAttribute('id', '_rc_sig');
        if (this.env.sig_above) {
        if (this.env.top_posting) {
          // if no existing sig and top posting then insert at caret pos
          editor.getWin().focus(); // correct focus in IE & Chrome
@@ -3648,7 +3670,8 @@
      // reset vars
      this.env.current_page = 1;
      r = this.http_request('search', url, lock);
      var action = this.env.action == 'compose' && this.contact_list ? 'search-contacts' : 'search';
      r = this.http_request(action, url, lock);
      this.env.qsearch = {lock: lock, request: r};
    }
@@ -3703,13 +3726,19 @@
    this.env.search_id = null;
  };
  this.sent_successfully = function(type, msg)
  this.sent_successfully = function(type, msg, target)
  {
    this.display_message(msg, type);
    if (this.env.extwin && window.opener && opener.rcmail) {
    if (this.env.extwin) {
      var rc = this.opener();
      this.lock_form(this.gui_objects.messageform);
      opener.rcmail.display_message(msg, type);
      if (rc) {
        rc.display_message(msg, type);
        // refresh the folder where sent message was saved
        if (target && rc.env.task == 'mail' && rc.env.action == '' && rc.env.mailbox == target)
          rc.command('checkmail');
      }
      setTimeout(function(){ window.close() }, 1000);
    }
    else {
@@ -4084,6 +4113,7 @@
    var n, id, sid, ref = this, writable = false,
      source = this.env.source ? this.env.address_sources[this.env.source] : null;
    // we don't have dblclick handler here, so use 200 instead of this.dblclick_time
    if (id = list.get_single_selection())
      this.preview_timer = setTimeout(function(){ ref.load_contact(id, 'show'); }, 200);
    else if (this.env.contentframe)
@@ -4141,7 +4171,7 @@
    if (this.env.search_id)
      folder = 'S'+this.env.search_id;
    else
    else if (!this.env.search_request)
      folder = group ? 'G'+src+group : src;
    this.select_folder(folder);
@@ -4194,7 +4224,7 @@
    this.env.source = src;
    this.env.group = group;
    // also send search request to get the right messages
    // also send search request to get the right records
    if (this.env.search_request)
      url._search = this.env.search_request;
@@ -4277,7 +4307,7 @@
        this.group_member_change('add', cid, dest, to.id);
      else {
        var lock = this.display_message(this.get_label('copyingcontact'), 'loading'),
          post_data = {_cid: cid, _source: source, _to: dest, _togid: to.id, _gid: group};
          post_data = {_cid: cid, _source: this.env.source, _to: dest, _togid: to.id, _gid: group};
        this.http_post('copy', post_data, lock);
      }
@@ -4285,7 +4315,7 @@
    // target is an addressbook
    else if (to.id != source) {
      var lock = this.display_message(this.get_label('copyingcontact'), 'loading'),
        post_data = {_cid: cid, _source: source, _to: to.id, _gid: group};
        post_data = {_cid: cid, _source: this.env.source, _to: to.id, _gid: group};
      this.http_post('copy', post_data, lock);
    }
@@ -4396,10 +4426,11 @@
  {
    var ref = this, col;
    this.set_photo_actions($('#ff_photo').val());
    for (col in this.env.coltypes)
      this.init_edit_field(col, null);
    if (this.env.coltypes) {
      this.set_photo_actions($('#ff_photo').val());
      for (col in this.env.coltypes)
        this.init_edit_field(col, null);
    }
    $('.contactfieldgroup .row a.deletebutton').click(function() {
      ref.delete_edit_field(this);
@@ -4426,6 +4457,11 @@
    }
    $("input[type='text']:visible").first().focus();
    // Submit search form on Enter
    if (this.env.action == 'search')
      $(this.gui_objects.editform).append($('<input type="submit">').hide())
        .submit(function() { $('input.mainaction').click(); return false; });
  };
  this.group_create = function()
@@ -6327,12 +6363,29 @@
    // redirect to url specified in location header if not empty
    var location_url = request.getResponseHeader("Location");
    if (location_url)
    if (location_url && this.env.action != 'compose')  // don't redirect on compose screen, contents might get lost (#1488926)
      this.redirect(location_url);
    // 403 Forbidden response (CSRF prevention) - reload the page.
    // In case there's a new valid session it will be used, otherwise
    // login form will be presented (#1488960).
    if (request.status == 403) {
      (this.is_framed() ? parent : window).location.reload();
      return;
    }
    // re-send keep-alive requests after 30 seconds
    if (action == 'keep-alive')
      setTimeout(function(){ ref.keep_alive(); ref.start_keepalive(); }, 30000);
  };
  // callback when an iframe finished loading
  this.iframe_loaded = function(unlock)
  {
    this.set_busy(false, null, unlock);
    if (this.submit_timer)
      clearTimeout(this.submit_timer);
  };
  // post the given form to a hidden iframe
@@ -6573,6 +6626,17 @@
  /*********            helper methods            *********/
  /********************************************************/
  // get window.opener.rcmail if available
  this.opener = function()
  {
    // catch Error: Permission denied to access property rcmail
    try {
      if (window.opener && !opener.closed && opener.rcmail)
        return opener.rcmail;
    }
    catch (e) {}
  };
  // check if we're in show mode or if we have a unique selection
  // and return the message uid
  this.get_single_uid = function()