| | |
| | | else if (this.env.action == 'compose') { |
| | | this.env.address_group_stack = []; |
| | | this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', |
| | | 'toggle-editor', 'list-adresses', 'pushgroup', 'search', 'reset-search', 'extwin', |
| | | 'toggle-editor', 'list-addresses', 'pushgroup', 'search', 'reset-search', 'extwin', |
| | | 'insert-response', 'save-response', 'menu-open', 'menu-close']; |
| | | |
| | | if (this.env.drafts_mailbox) |
| | |
| | | // init message compose form |
| | | this.init_messageform(); |
| | | } |
| | | else if (this.env.action == 'get') |
| | | else if (this.env.action == 'get') { |
| | | this.enable_command('download', 'print', true); |
| | | if (this.env.is_message) { |
| | | this.enable_command('reply', 'reply-all', 'edit', 'viewsource', |
| | | 'forward', 'forward-inline', 'forward-attachment', true); |
| | | if (this.env.list_post) |
| | | this.enable_command('reply-list', true); |
| | | } |
| | | } |
| | | // show printing dialog |
| | | else if (this.env.action == 'print' && this.env.uid |
| | | && !this.env.is_pgp_content && !this.env.pgp_mime_part |
| | |
| | | if (this.gui_objects.mailboxlist) { |
| | | this.env.unread_counts = {}; |
| | | this.gui_objects.folderlist = this.gui_objects.mailboxlist; |
| | | this.http_request('getunread'); |
| | | this.http_request('getunread', {_page: this.env.current_page}); |
| | | } |
| | | |
| | | // init address book widget |
| | |
| | | |
| | | if (this.gui_objects.addressbookslist) { |
| | | this.gui_objects.folderlist = this.gui_objects.addressbookslist; |
| | | this.enable_command('list-adresses', true); |
| | | this.enable_command('list-addresses', true); |
| | | } |
| | | |
| | | // ask user to send MDN |
| | |
| | | this.display_message.apply(this, this.pending_message); |
| | | |
| | | // init treelist widget |
| | | if (this.gui_objects.folderlist && window.rcube_treelist_widget) { |
| | | if (this.gui_objects.folderlist && window.rcube_treelist_widget |
| | | // some plugins may load rcube_treelist_widget and there's one case |
| | | // when this will cause problems - addressbook widget in compose, |
| | | // which already has been initialized using rcube_list_widget |
| | | && this.gui_objects.folderlist != this.gui_objects.addressbookslist |
| | | ) { |
| | | this.treelist = new rcube_treelist_widget(this.gui_objects.folderlist, { |
| | | selectable: true, |
| | | id_prefix: 'rcmli', |
| | |
| | | break; |
| | | } |
| | | |
| | | this.goto_url('get', qstring+'&_download=1', false); |
| | | this.goto_url('get', qstring+'&_download=1', false, true); |
| | | break; |
| | | |
| | | case 'select-all': |
| | |
| | | this.change_identity($("[name='_from']")[0], true); |
| | | break; |
| | | |
| | | case 'list-adresses': |
| | | case 'list-addresses': |
| | | this.list_contacts(props); |
| | | this.enable_command('add-recipient', false); |
| | | break; |
| | |
| | | this.open_window(this.env.comm_path + url, true, true); |
| | | } |
| | | } |
| | | else if (this.env.action == 'get') { |
| | | else if (this.env.action == 'get' && !this.env.is_message) { |
| | | this.gui_objects.messagepartframe.contentWindow.print(); |
| | | } |
| | | else if (uid = this.get_single_uid()) { |
| | | url = this.url('print', this.params_from_uid(uid, {_safe: this.env.safemode ? 1 : 0})); |
| | | if (this.open_window(url, true, true)) { |
| | | if (this.env.action != 'show') |
| | | if (this.env.action != 'show' && this.env.action != 'get') |
| | | this.mark_message('read', uid); |
| | | } |
| | | } |
| | |
| | | |
| | | case 'download': |
| | | if (this.env.action == 'get') { |
| | | location.href = location.href.replace(/_frame=/, '_download='); |
| | | location.href = this.secure_url(location.href.replace(/_frame=/, '_download=')); |
| | | } |
| | | else if (uid = this.get_single_uid()) { |
| | | this.goto_url('viewsource', this.params_from_uid(uid, {_save: 1})); |
| | | this.goto_url('viewsource', this.params_from_uid(uid, {_save: 1}), false, true); |
| | | } |
| | | break; |
| | | |
| | |
| | | |
| | | case 'export': |
| | | if (this.contact_list.rowcount > 0) { |
| | | this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _search: this.env.search_request }); |
| | | this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _search: this.env.search_request }, false, true); |
| | | } |
| | | break; |
| | | |
| | | case 'export-selected': |
| | | if (this.contact_list.rowcount > 0) { |
| | | this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _cid: this.contact_list.get_selection().join(',') }); |
| | | this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _cid: this.contact_list.get_selection().join(',') }, false, true); |
| | | } |
| | | break; |
| | | |
| | |
| | | |
| | | if (!aborted && this.triggerEvent('after'+command, props) === false) |
| | | ret = false; |
| | | this.triggerEvent('actionafter', { props:props, action:command, aborted:aborted }); |
| | | this.triggerEvent('actionafter', { props:props, action:command, aborted:aborted, ret:ret }); |
| | | |
| | | return ret === false ? false : obj ? false : true; |
| | | }; |
| | |
| | | if (task == 'mail') |
| | | url += '&_mbox=INBOX'; |
| | | else if (task == 'logout' && !this.env.server_error) { |
| | | url += '&_token=' + this.env.request_token; |
| | | url = this.secure_url(url); |
| | | this.clear_compose_data(); |
| | | } |
| | | |
| | |
| | | |
| | | return url + '?' + name + '=' + value; |
| | | }; |
| | | |
| | | // append CSRF protection token to the given url |
| | | this.secure_url = function(url) |
| | | { |
| | | return this.add_url(url, '_token', this.env.request_token); |
| | | }, |
| | | |
| | | this.is_framed = function() |
| | | { |
| | |
| | | flagged: flags.flagged?1:0, |
| | | has_children: flags.has_children?1:0, |
| | | depth: flags.depth?flags.depth:0, |
| | | unread_children: flags.unread_children?flags.unread_children:0, |
| | | parent_uid: flags.parent_uid?flags.parent_uid:0, |
| | | unread_children: flags.unread_children || 0, |
| | | flagged_children: flags.flagged_children || 0, |
| | | parent_uid: flags.parent_uid || 0, |
| | | selected: this.select_all_mode || this.message_list.in_selection(uid), |
| | | ml: flags.ml?1:0, |
| | | ctype: flags.ctype, |
| | |
| | | |
| | | if (flags.unread_children && flags.seen && !message.expanded) |
| | | row_class += ' unroot'; |
| | | |
| | | if (flags.flagged_children && !message.expanded) |
| | | row_class += ' flaggedroot'; |
| | | } |
| | | |
| | | tree += '<span id="msgicn'+row.id+'" class="'+css_class+status_class+'" title="'+status_label+'"></span>'; |
| | |
| | | html = '<span class="attachment" title="'+label+'"></span>'; |
| | | else if (/multipart\/report/.test(flags.ctype)) |
| | | html = '<span class="report"></span>'; |
| | | else |
| | | else |
| | | html = ' '; |
| | | } |
| | | else if (c == 'status') { |
| | |
| | | { |
| | | var row = this.message_list.rows[uid]; |
| | | |
| | | // handle unread_children mark |
| | | // handle unread_children/flagged_children mark |
| | | row.expanded = !row.expanded; |
| | | this.set_unread_children(uid); |
| | | this.set_flagged_children(uid); |
| | | row.expanded = !row.expanded; |
| | | |
| | | this.message_list.expand_row(e, uid); |
| | |
| | | } |
| | | else if (flag == 'unread' && p.has_children) { |
| | | // unread_children may be undefined |
| | | p.unread_children = p.unread_children ? p.unread_children + 1 : 1; |
| | | p.unread_children = (p.unread_children || 0) + 1; |
| | | } |
| | | else if (flag == 'unflagged' && p.flagged_children) { |
| | | p.flagged_children--; |
| | | } |
| | | else if (flag == 'flagged' && p.has_children) { |
| | | p.flagged_children = (p.flagged_children || 0) + 1; |
| | | } |
| | | else { |
| | | return; |
| | |
| | | |
| | | this.set_message_icon(root); |
| | | this.set_unread_children(root); |
| | | this.set_flagged_children(root); |
| | | }; |
| | | |
| | | // update thread indicators for all messages in a thread below the specified message |
| | |
| | | |
| | | if (!row.depth) // root message: decrease roots count |
| | | count--; |
| | | else if (row.unread) { |
| | | // update unread_children for thread root |
| | | |
| | | // update unread_children for thread root |
| | | if (row.depth && row.unread) { |
| | | parent = this.message_list.find_root(uid); |
| | | rows[parent].unread_children--; |
| | | this.set_unread_children(parent); |
| | | } |
| | | |
| | | // update unread_children for thread root |
| | | if (row.depth && row.flagged) { |
| | | parent = this.message_list.find_root(uid); |
| | | rows[parent].flagged_children--; |
| | | this.set_flagged_children(parent); |
| | | } |
| | | |
| | | parent = row.parent_uid; |
| | |
| | | row = row.nextSibling; |
| | | } |
| | | |
| | | // update unread_children for roots |
| | | for (r=0; r<roots.length; r++) |
| | | // update unread_children/flagged_children for roots |
| | | for (r=0; r<roots.length; r++) { |
| | | this.set_unread_children(roots[r].uid); |
| | | this.set_flagged_children(roots[r].uid); |
| | | } |
| | | |
| | | return count; |
| | | }; |
| | |
| | | if (row.unread != status) |
| | | this.update_thread_root(uid, status ? 'unread' : 'read'); |
| | | } |
| | | else if (flag == 'flagged') { |
| | | this.update_thread_root(uid, status ? 'flagged' : 'unflagged'); |
| | | } |
| | | |
| | | if ($.inArray(flag, ['unread', 'deleted', 'replied', 'forwarded', 'flagged']) > -1) |
| | | row[flag] = status; |
| | |
| | | if (row.parent_uid) |
| | | return; |
| | | |
| | | if (!row.unread && row.unread_children && !row.expanded) |
| | | $(row.obj).addClass('unroot'); |
| | | else |
| | | $(row.obj).removeClass('unroot'); |
| | | var enable = !row.unread && row.unread_children && !row.expanded; |
| | | $(row.obj)[enable ? 'addClass' : 'removeClass']('unroot'); |
| | | }; |
| | | |
| | | // sets flaggedroot (flagged_children) class of parent row |
| | | this.set_flagged_children = function(uid) |
| | | { |
| | | var row = this.message_list.rows[uid]; |
| | | |
| | | if (row.parent_uid) |
| | | return; |
| | | |
| | | var enable = row.flagged_children && !row.expanded; |
| | | $(row.obj)[enable ? 'addClass' : 'removeClass']('flaggedroot'); |
| | | }; |
| | | |
| | | // copy selected messages to the specified mailbox |
| | |
| | | mailvelope.getKeyring(keyring).then(function(kr) { |
| | | ref.mailvelope_keyring = kr; |
| | | ref.mailvelope_init(action, kr); |
| | | }).catch(function(err) { |
| | | }, function(err) { |
| | | // attempt to create a new keyring for this app/user |
| | | mailvelope.createKeyring(keyring).then(function(kr) { |
| | | ref.mailvelope_keyring = kr; |
| | | ref.mailvelope_init(action, kr); |
| | | }).catch(function(err) { |
| | | }, function(err) { |
| | | console.error(err); |
| | | }); |
| | | }); |
| | |
| | | // enable encrypted compose toggle |
| | | this.enable_command('compose-encrypted', !is_html); |
| | | } |
| | | |
| | | // make sure to disable encryption button after toggling editor into HTML mode |
| | | this.addEventListener('actionafter', function(args) { |
| | | if (args.ret && args.action == 'toggle-editor') |
| | | ref.enable_command('compose-encrypted', !args.props.html); |
| | | }); |
| | | } |
| | | }; |
| | | |
| | |
| | | ref.remove_from_attachment_list(name); |
| | | }); |
| | | } |
| | | }).catch(function(err) { |
| | | }, function(err) { |
| | | console.error(err); |
| | | console.log(options); |
| | | }); |
| | |
| | | |
| | | // list recipients with missing keys |
| | | if (!isvalid && missing_keys.length) { |
| | | // load publickey.js |
| | | if (!$('script#publickeyjs').length) { |
| | | $('<script>') |
| | | .attr('id', 'publickeyjs') |
| | | .attr('src', ref.assets_path('program/js/publickey.js')) |
| | | .appendTo(document.body); |
| | | } |
| | | |
| | | // display dialog with missing keys |
| | | ref.show_popup_dialog( |
| | | ref.get_label('nopubkeyfor').replace('$email', missing_keys.join(', ')) + |
| | |
| | | |
| | | form.submit(); |
| | | |
| | | }).catch(function(err) { |
| | | }, function(err) { |
| | | console.log(err); |
| | | }); // mailvelope_editor.encrypt() |
| | | |
| | | }).catch(function(err) { |
| | | }, function(err) { |
| | | console.error(err); |
| | | }); // mailvelope_keyring.validKeyForAddress(senders) |
| | | |
| | | }).catch(function(err) { |
| | | }, function(err) { |
| | | console.error(err); |
| | | }); // mailvelope_keyring.validKeyForAddress(recipients) |
| | | |
| | |
| | | $(selector).addClass('mailvelope').children().not('iframe').hide(); |
| | | ref.hide_message(msgid); |
| | | setTimeout(function() { $(window).resize(); }, 10); |
| | | }).catch(function(err) { |
| | | }, function(err) { |
| | | console.error(err); |
| | | ref.hide_message(msgid); |
| | | ref.display_message('Message decryption failed: ' + err.message, 'error') |
| | |
| | | if (missing_keys.length) { |
| | | ref.display_message(ref.get_label('nopubkeyfor').replace('$email', missing_keys.join(', ')), 'warning'); |
| | | } |
| | | }, function() { |
| | | }).fail(function() { |
| | | console.error('Pubkey lookup failed with', arguments); |
| | | ref.hide_message(lock); |
| | | ref.display_message('pubkeysearcherror', 'error'); |
| | |
| | | btn.closest('.key').fadeOut(); |
| | | ref.display_message(ref.get_label('keyimportsuccess').replace('$key', $key), 'confirmation'); |
| | | } |
| | | }).catch(function(err) { |
| | | }, function(err) { |
| | | console.log(err); |
| | | }); |
| | | }); |
| | |
| | | } |
| | | |
| | | if (!html_mode) { |
| | | pos = this.env.top_posting ? 0 : input_message.value.length; |
| | | pos = this.env.top_posting && this.env.compose_mode ? 0 : input_message.value.length; |
| | | |
| | | // add signature according to selected identity |
| | | // if we have HTML editor, signature is added in a callback |
| | |
| | | if (result) { |
| | | // update internal format flag |
| | | $("input[name='_is_html']").val(props.html ? 1 : 0); |
| | | // enable encrypted compose toggle |
| | | this.enable_command('compose-encrypted', !props.html); |
| | | } |
| | | |
| | | return result; |
| | |
| | | '<textarea name="text" id="ffresponsetext" cols="40" rows="8"></textarea></div>' + |
| | | '</form>'; |
| | | |
| | | buttons[this.gettext('save')] = function(e) { |
| | | buttons[this.get_label('save')] = function(e) { |
| | | var name = $('#ffresponsename').val(), |
| | | text = $('#ffresponsetext').val(); |
| | | |
| | |
| | | $(this).dialog('close'); |
| | | }; |
| | | |
| | | buttons[this.gettext('cancel')] = function() { |
| | | buttons[this.get_label('cancel')] = function() { |
| | | $(this).dialog('close'); |
| | | }; |
| | | |
| | | this.show_popup_dialog(html, this.gettext('newresponse'), buttons, {button_classes: ['mainaction']}); |
| | | this.show_popup_dialog(html, this.get_label('newresponse'), buttons, {button_classes: ['mainaction']}); |
| | | |
| | | $('#ffresponsetext').val(text); |
| | | $('#ffresponsename').select(); |
| | |
| | | // add link to pop back to parent group |
| | | if (this.env.address_group_stack.length > 1) { |
| | | $('<a href="#list">...</a>') |
| | | .attr('title', this.gettext('uponelevel')) |
| | | .attr('title', this.get_label('uponelevel')) |
| | | .addClass('poplink') |
| | | .appendTo(boxtitle) |
| | | .click(function(e){ return ref.command('popgroup','',this); }); |
| | |
| | | var url = '?_task=utils&_action=' + (format == 'html' ? 'html2text' : 'text2html'), |
| | | lock = this.set_busy(true, 'converting'); |
| | | |
| | | this.log('HTTP POST: ' + url); |
| | | |
| | | $.ajax({ type: 'POST', url: url, data: text, contentType: 'application/octet-stream', |
| | | error: function(o, status, err) { ref.http_error(o, status, err, lock); }, |
| | | success: function(data) { |
| | |
| | | } |
| | | }; |
| | | |
| | | this.goto_url = function(action, query, lock) |
| | | this.goto_url = function(action, query, lock, secure) |
| | | { |
| | | this.redirect(this.url(action, query), lock); |
| | | var url = this.url(action, query) |
| | | if (secure) url = this.secure_url(url); |
| | | this.redirect(url, lock); |
| | | }; |
| | | |
| | | this.location_href = function(url, target, frame) |
| | |
| | | if (response.env) |
| | | this.set_env(response.env); |
| | | |
| | | var i; |
| | | |
| | | // we have labels to add |
| | | if (typeof response.texts === 'object') { |
| | | for (var name in response.texts) |
| | | if (typeof response.texts[name] === 'string') |
| | | this.add_label(name, response.texts[name]); |
| | | for (i in response.texts) |
| | | if (typeof response.texts[i] === 'string') |
| | | this.add_label(i, response.texts[i]); |
| | | } |
| | | |
| | | // if we get javascript code from server -> execute it |
| | | if (response.exec) { |
| | | this.log(response.exec); |
| | | eval(response.exec); |
| | | } |
| | | |
| | | // execute callback functions of plugins |
| | | if (response.callbacks && response.callbacks.length) { |
| | | for (var i=0; i < response.callbacks.length; i++) |
| | | for (i=0; i < response.callbacks.length; i++) |
| | | this.triggerEvent(response.callbacks[i][0], response.callbacks[i][1]); |
| | | } |
| | | |
| | |
| | | this.enable_command('set-listmode', this.env.threads && !is_multifolder); |
| | | if (list.rowcount > 0 && !$(document.activeElement).is('input,textarea')) |
| | | list.focus(); |
| | | this.msglist_select(list); |
| | | |
| | | // trigger 'select' so all dependent actions update its state |
| | | // e.g. plugins use this event to activate buttons (#1490647) |
| | | list.triggerEvent('select'); |
| | | } |
| | | |
| | | if (response.action != 'getunread') |
| | |
| | | // html5 file-drop API |
| | | this.document_drag_hover = function(e, over) |
| | | { |
| | | e.preventDefault(); |
| | | // don't e.preventDefault() here to not block text dragging on the page (#1490619) |
| | | $(this.gui_objects.filedrop)[(over?'addClass':'removeClass')]('active'); |
| | | }; |
| | | |
| | |
| | | if (uri = e.dataTransfer.getData('roundcube-uri')) { |
| | | var ts = new Date().getTime(), |
| | | // jQuery way to escape filename (#1490530) |
| | | content = $('<span>').text(e.dataTransfer.getData('roundcube-name') || this.gettext('attaching')).html(); |
| | | content = $('<span>').text(e.dataTransfer.getData('roundcube-name') || this.get_label('attaching')).html(); |
| | | |
| | | args._uri = uri; |
| | | args._uploadid = ts; |
| | |
| | | if (!this.env.browser_capabilities) |
| | | this.env.browser_capabilities = {}; |
| | | |
| | | if (this.env.browser_capabilities.pdf === undefined) |
| | | this.env.browser_capabilities.pdf = this.pdf_support_check(); |
| | | |
| | | if (this.env.browser_capabilities.flash === undefined) |
| | | this.env.browser_capabilities.flash = this.flash_support_check(); |
| | | |
| | | if (this.env.browser_capabilities.tif === undefined) |
| | | this.tif_support_check(); |
| | | $.each(['pdf', 'flash', 'tif'], function() { |
| | | if (ref.env.browser_capabilities[this] === undefined) |
| | | ref.env.browser_capabilities[this] = ref[this + '_support_check'](); |
| | | }); |
| | | }; |
| | | |
| | | // Returns browser capabilities string |
| | |
| | | |
| | | this.tif_support_check = function() |
| | | { |
| | | var img = new Image(); |
| | | window.setTimeout(function() { |
| | | var img = new Image(); |
| | | img.onload = function() { ref.env.browser_capabilities.tif = 1; }; |
| | | img.onerror = function() { ref.env.browser_capabilities.tif = 0; }; |
| | | img.src = ref.assets_path('program/resources/blank.tif'); |
| | | }, 10); |
| | | |
| | | img.onload = function() { ref.env.browser_capabilities.tif = 1; }; |
| | | img.onerror = function() { ref.env.browser_capabilities.tif = 0; }; |
| | | img.src = this.assets_path('program/resources/blank.tif'); |
| | | return 0; |
| | | }; |
| | | |
| | | this.pdf_support_check = function() |
| | |
| | | return 1; |
| | | } |
| | | |
| | | window.setTimeout(function() { |
| | | $('<object>').css({position: 'absolute', left: '-10000px'}) |
| | | .attr({data: ref.assets_path('program/resources/dummy.pdf'), width: 1, height: 1, type: 'application/pdf'}) |
| | | .load(function() { ref.env.browser_capabilities.pdf = 1; }) |
| | | .error(function() { ref.env.browser_capabilities.pdf = 0; }) |
| | | .appendTo($('body')); |
| | | }, 10); |
| | | |
| | | return 0; |
| | | }; |
| | | |