| | |
| | | | Roundcube Webmail Client Script | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2011, The Roundcube Dev Team | |
| | | | Copyright (C) 2005-2012, The Roundcube Dev Team | |
| | | | Copyright (C) 2011, Kolab Systems AG | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | |
| | | this.command_handlers = {}; |
| | | this.onloads = []; |
| | | this.messages = {}; |
| | | this.group2expand = {}; |
| | | |
| | | // create protected reference to myself |
| | | this.ref = 'rcmail'; |
| | |
| | | for (n in this.gui_objects) |
| | | this.gui_objects[n] = rcube_find_object(this.gui_objects[n]); |
| | | |
| | | // clickjacking protection |
| | | if (this.env.x_frame_options) { |
| | | try { |
| | | // bust frame if not allowed |
| | | if (this.env.x_frame_options == 'deny' && top.location.href != self.location.href) |
| | | top.location.href = self.location.href; |
| | | else if (top.location.hostname != self.location.hostname) |
| | | throw 1; |
| | | } catch (e) { |
| | | // possible clickjacking attack: disable all form elements |
| | | $('form').each(function(){ ref.lock_form(this, true); }); |
| | | this.display_message("Blocked: possible clickjacking attack!", 'error'); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // init registered buttons |
| | | this.init_buttons(); |
| | | |
| | |
| | | this.enable_command('reply-list', this.env.list_post); |
| | | |
| | | if (this.env.action == 'show') { |
| | | this.http_request('pagenav', '_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox), |
| | | this.http_request('pagenav', '_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox) |
| | | + (this.env.search_request ? '&_search='+this.env.search_request : ''), |
| | | this.display_message('', 'loading')); |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | else if (this.env.action == 'compose') { |
| | | this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor']; |
| | | this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses']; |
| | | |
| | | if (this.env.drafts_mailbox) |
| | | this.env.compose_commands.push('savedraft') |
| | | |
| | | this.enable_command(this.env.compose_commands, 'identities', true); |
| | | |
| | | // add more commands (not enabled) |
| | | $.merge(this.env.compose_commands, ['add-recipient', 'firstpage', 'previouspage', 'nextpage', 'lastpage']); |
| | | |
| | | if (this.env.spellcheck) { |
| | | this.env.spellcheck.spelling_state_observer = function(s){ ref.set_spellcheck_state(s); }; |
| | |
| | | |
| | | // init message compose form |
| | | this.init_messageform(); |
| | | |
| | | // init address book widget |
| | | if (this.gui_objects.contactslist) { |
| | | this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, |
| | | { multiselect:true, draggable:false, keyboard:false }); |
| | | this.contact_list.addEventListener('select', function(o){ ref.compose_recipeint_select(o); }); |
| | | this.contact_list.addEventListener('dblclick', function(o){ ref.compose_add_recipient('to'); }); |
| | | this.contact_list.init(); |
| | | } |
| | | |
| | | if (this.gui_objects.adressbookslist) { |
| | | this.gui_objects.folderlist = this.gui_objects.adressbookslist; |
| | | this.enable_command('list-adresses', true); |
| | | } |
| | | } |
| | | // show printing dialog |
| | | else if (this.env.action == 'print' && this.env.uid) |
| | |
| | | this.enable_command('preferences', 'identities', 'save', 'folders', true); |
| | | |
| | | if (this.env.action == 'identities') { |
| | | this.enable_command('add', this.env.identities_level < 2); |
| | | this.enable_command('add', 'delete', this.env.identities_level < 2); |
| | | } |
| | | else if (this.env.action == 'edit-identity' || this.env.action == 'add-identity') { |
| | | this.enable_command('add', this.env.identities_level < 2); |
| | | this.enable_command('save', 'delete', 'edit', 'toggle-editor', true); |
| | | this.enable_command('save', 'edit', 'toggle-editor', true); |
| | | if (this.is_framed() && this.env.identities_level < 2) |
| | | this.set_button('delete', 'act'); // activate button but delegate command to parent |
| | | else |
| | | this.enable_command('delete', this.env.identities_level < 2); |
| | | |
| | | if (this.env.action == 'add-identity') |
| | | $("input[type='text']").first().select(); |
| | | } |
| | | else if (this.env.action == 'folders') { |
| | | this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', true); |
| | |
| | | if (!this.gui_objects.messageform) |
| | | break; |
| | | |
| | | if (!this.check_compose_input()) |
| | | if (!props.nocheck && !this.check_compose_input(command)) |
| | | break; |
| | | |
| | | // Reset the auto-save timer |
| | |
| | | case 'send-attachment': |
| | | // Reset the auto-save timer |
| | | self.clearTimeout(this.save_timer); |
| | | |
| | | this.upload_file(props) |
| | | |
| | | this.upload_file(props || this.gui_objects.uploadform); |
| | | break; |
| | | |
| | | case 'insert-sig': |
| | | this.change_identity($("[name='_from']")[0], true); |
| | | break; |
| | | |
| | | case 'list-adresses': |
| | | this.list_contacts(props); |
| | | this.enable_command('add-recipient', false); |
| | | break; |
| | | |
| | | case 'add-recipient': |
| | | this.compose_add_recipient(props); |
| | | break; |
| | | |
| | | case 'reply-all': |
| | |
| | | break; |
| | | |
| | | case 'upload-photo': |
| | | this.upload_contact_photo(props); |
| | | this.upload_contact_photo(props || this.gui_objects.uploadform); |
| | | break; |
| | | |
| | | case 'delete-photo': |
| | |
| | | if (this.folder_auto_timer) |
| | | window.clearTimeout(this.folder_auto_timer); |
| | | |
| | | this.folder_auto_expand = k; |
| | | this.folder_auto_expand = this.env.mailboxes[k].id; |
| | | this.folder_auto_timer = window.setTimeout(function() { |
| | | rcmail.command('collapse-folder', rcmail.folder_auto_expand); |
| | | rcmail.drag_start(null); |
| | |
| | | this.collapse_folder = function(name) |
| | | { |
| | | var li = this.get_folder_li(name, '', true), |
| | | div = $(li.getElementsByTagName('div')[0]); |
| | | |
| | | if (!div || (!div.hasClass('collapsed') && !div.hasClass('expanded'))) |
| | | return; |
| | | |
| | | var ul = $(li.getElementsByTagName('ul')[0]); |
| | | div = $('div:first', li), |
| | | ul = $('ul:first', li); |
| | | |
| | | if (div.hasClass('collapsed')) { |
| | | ul.show(); |
| | |
| | | var reg = new RegExp('&'+urlencode(name)+'&'); |
| | | this.env.collapsed_folders = this.env.collapsed_folders.replace(reg, ''); |
| | | } |
| | | else { |
| | | else if (div.hasClass('expanded')) { |
| | | ul.hide(); |
| | | div.removeClass('expanded').addClass('collapsed'); |
| | | this.env.collapsed_folders = this.env.collapsed_folders+'&'+urlencode(name)+'&'; |
| | |
| | | if (this.env.mailbox.indexOf(name + this.env.delimiter) == 0) |
| | | this.command('list', name); |
| | | } |
| | | else |
| | | return; |
| | | |
| | | // Work around a bug in IE6 and IE7, see #1485309 |
| | | if (bw.ie6 || bw.ie7) { |
| | |
| | | if (page > 0 && page <= this.env.pagecount) { |
| | | this.env.current_page = page; |
| | | |
| | | if (this.task == 'mail') |
| | | this.list_mailbox(this.env.mailbox, page); |
| | | else if (this.task == 'addressbook') |
| | | if (this.task == 'addressbook' || this.contact_list) |
| | | this.list_contacts(this.env.source, this.env.group, page); |
| | | else if (this.task == 'mail') |
| | | this.list_mailbox(this.env.mailbox, page); |
| | | } |
| | | }; |
| | | |
| | |
| | | url += '&_refresh=1'; |
| | | |
| | | this.select_folder(mbox, '', true); |
| | | this.unmark_folder(mbox, 'recent', '', true); |
| | | this.env.mailbox = mbox; |
| | | |
| | | // load message list remotely |
| | |
| | | obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, props); }) |
| | | .attr('autocomplete', 'off'); |
| | | }; |
| | | |
| | | this.compose_recipeint_select = function(list) |
| | | { |
| | | this.enable_command('add-recipient', list.selection.length > 0); |
| | | }; |
| | | |
| | | this.compose_add_recipient = function(field) |
| | | { |
| | | var recipients = [], input = $('#_'+field); |
| | | |
| | | if (this.contact_list && this.contact_list.selection.length) { |
| | | for (var id, n=0; n < this.contact_list.selection.length; n++) { |
| | | id = this.contact_list.selection[n]; |
| | | if (id && this.env.contactdata[id]) { |
| | | recipients.push(this.env.contactdata[id]); |
| | | |
| | | // group is added, expand it |
| | | if (id.charAt(0) == 'E' && this.env.contactdata[id].indexOf('@') < 0 && input.length) { |
| | | var gid = id.substr(1); |
| | | this.group2expand[gid] = { name:this.env.contactdata[id], input:input.get(0) }; |
| | | this.http_request('group-expand', '_source='+urlencode(this.env.source)+'&_gid='+urlencode(gid), false); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (recipients.length && input.length) { |
| | | var oldval = input.val(); |
| | | input.val((oldval ? oldval + this.env.recipients_delimiter : '') + recipients.join(this.env.recipients_delimiter)); |
| | | this.triggerEvent('add-recipient', { field:field, recipients:recipients }); |
| | | } |
| | | }; |
| | | |
| | | // checks the input fields before sending a message |
| | | this.check_compose_input = function() |
| | | this.check_compose_input = function(cmd) |
| | | { |
| | | // check input fields |
| | | var ed, input_to = $("[name='_to']"), |
| | |
| | | |
| | | // display localized warning for missing subject |
| | | if (input_subject.val() == '') { |
| | | var subject = prompt(this.get_label('nosubjectwarning'), this.get_label('nosubject')); |
| | | var myprompt = $('<div class="prompt">').html('<div class="message">' + this.get_label('nosubjectwarning') + '</div>').appendTo(document.body); |
| | | var prompt_value = $('<input>').attr('type', 'text').attr('size', 30).appendTo(myprompt).val(this.get_label('nosubject')); |
| | | |
| | | // user hit cancel, so don't send |
| | | if (!subject && subject !== '') { |
| | | var buttons = {}; |
| | | buttons[this.get_label('cancel')] = function(){ |
| | | input_subject.focus(); |
| | | return false; |
| | | } |
| | | else |
| | | input_subject.val((subject ? subject : this.get_label('nosubject'))); |
| | | $(this).dialog('close'); |
| | | }; |
| | | buttons[this.get_label('sendmessage')] = function(){ |
| | | input_subject.val(prompt_value.val()); |
| | | $(this).dialog('close'); |
| | | ref.command(cmd, { nocheck:true }); // repeat command which triggered this |
| | | }; |
| | | |
| | | myprompt.dialog({ |
| | | modal: true, |
| | | resizable: false, |
| | | buttons: buttons, |
| | | close: function(event, ui) { $(this).remove() } |
| | | }); |
| | | prompt_value.select(); |
| | | return false; |
| | | } |
| | | |
| | | // Apply spellcheck changes if spell checker is active |
| | |
| | | this.display_spellcheck_controls(false); |
| | | this.plain2html($('#'+props.id).val(), props.id); |
| | | tinyMCE.execCommand('mceAddControl', false, props.id); |
| | | |
| | | if (this.env.default_font) |
| | | window.setTimeout(function() { |
| | | $(tinyMCE.get(props.id).getBody()).css('font-family', rcmail.env.default_font); |
| | | }, 500); |
| | | } |
| | | else { |
| | | var thisMCE = tinyMCE.get(props.id), existingHtml; |
| | |
| | | if (!vis) |
| | | this.stop_spellchecking(); |
| | | |
| | | $(this.env.spellcheck.spell_container).css('visibility', vis ? 'visible' : 'hidden'); |
| | | $(this.env.spellcheck.spell_container)[vis ? 'show' : 'hide'](); |
| | | } |
| | | }; |
| | | |
| | |
| | | ts = frame_name.replace(/^rcmupload/, ''); |
| | | |
| | | if (this.env.loadingicon) |
| | | content = '<img src="'+this.env.loadingicon+'" alt="" />'+content; |
| | | content = '<img src="'+this.env.loadingicon+'" alt="" class="uploading" />'+content; |
| | | if (this.env.cancelicon) |
| | | content = '<a title="'+this.get_label('cancel')+'" onclick="return rcmail.cancel_attachment_upload(\''+ts+'\', \''+frame_name+'\');" href="#cancelupload"><img src="'+this.env.cancelicon+'" alt="" /></a>'+content; |
| | | this.add2attachment_list(ts, { name:'', html:content, complete:false }); |
| | | content = '<a title="'+this.get_label('cancel')+'" onclick="return rcmail.cancel_attachment_upload(\''+ts+'\', \''+frame_name+'\');" href="#cancelupload" class="cancelupload"><img src="'+this.env.cancelicon+'" alt="" /></a>'+content; |
| | | this.add2attachment_list(ts, { name:'', html:content, classname:'uploading', complete:false }); |
| | | |
| | | // upload progress support |
| | | if (this.env.upload_progress_time) { |
| | |
| | | if (!this.gui_objects.attachmentlist) |
| | | return false; |
| | | |
| | | var indicator, li = $('<li>').attr('id', name).html(att.html); |
| | | var indicator, li = $('<li>').attr('id', name).addClass(att.classname).html(att.html); |
| | | |
| | | // replace indicator's li |
| | | if (upload_id && (indicator = document.getElementById(upload_id))) { |
| | |
| | | // insert all members of a group |
| | | if (typeof this.env.contacts[id] === 'object' && this.env.contacts[id].id) { |
| | | insert += this.env.contacts[id].name + this.env.recipients_delimiter; |
| | | this.group2expand = $.extend({}, this.env.contacts[id]); |
| | | this.group2expand.input = this.ksearch_input; |
| | | this.group2expand[this.env.contacts[id].id] = $.extend({ input: this.ksearch_input }, this.env.contacts[id]); |
| | | this.http_request('mail/group-expand', '_source='+urlencode(this.env.contacts[id].source)+'&_gid='+urlencode(this.env.contacts[id].id), false); |
| | | } |
| | | else if (typeof this.env.contacts[id] === 'string') { |
| | |
| | | |
| | | this.replace_group_recipients = function(id, recipients) |
| | | { |
| | | if (this.group2expand && this.group2expand.id == id) { |
| | | this.group2expand.input.value = this.group2expand.input.value.replace(this.group2expand.name, recipients); |
| | | this.triggerEvent('autocomplete_insert', { field:this.group2expand.input, insert:recipients }); |
| | | this.group2expand = null; |
| | | if (this.group2expand[id]) { |
| | | this.group2expand[id].input.value = this.group2expand[id].input.value.replace(this.group2expand[id].name, recipients); |
| | | this.triggerEvent('autocomplete_insert', { field:this.group2expand[id].input, insert:recipients }); |
| | | this.group2expand[id] = null; |
| | | } |
| | | }; |
| | | |
| | |
| | | if (this.env.search_request) |
| | | url += '&_search='+this.env.search_request; |
| | | |
| | | this.http_request('list', url, lock); |
| | | this.http_request(this.env.task == 'mail' ? 'list-contacts' : 'list', url, lock); |
| | | }; |
| | | |
| | | this.list_contacts_clear = function() |
| | |
| | | this.delete_contacts = function() |
| | | { |
| | | var selection = this.contact_list.get_selection(), |
| | | undelete = this.env.address_sources[this.env.source].undelete; |
| | | undelete = this.env.source && this.env.address_sources[this.env.source].undelete; |
| | | |
| | | // exit if no mailbox specified or if selection is empty |
| | | if (!(selection.length || this.env.cid) || (!undelete && !confirm(this.get_label('deletecontactconfirm')))) |
| | |
| | | yearRange: '-100:+10', |
| | | showOtherMonths: true, |
| | | selectOtherMonths: true, |
| | | monthNamesShort: this.env.month_names, |
| | | onSelect: function(dateText) { $(this).focus().val(dateText) } |
| | | }); |
| | | $('input.datepicker').datepicker(); |
| | |
| | | if (!id) |
| | | id = this.env.iid ? this.env.iid : selection[0]; |
| | | |
| | | // append token to request |
| | | this.goto_url('delete-identity', '_iid='+id+'&_token='+this.env.request_token, true); |
| | | // submit request with appended token |
| | | if (confirm(this.get_label('deleteidentityconfirm'))) |
| | | this.goto_url('delete-identity', '_iid='+id+'&_token='+this.env.request_token, true); |
| | | |
| | | return true; |
| | | }; |
| | | |
| | | this.update_identity_row = function(id, name, add) |
| | | { |
| | | var row, col, list = this.identity_list, |
| | | rid = this.html_identifier(id); |
| | | |
| | | if (list.rows[rid] && (row = list.rows[rid].obj)) { |
| | | $(row.cells[0]).html(name); |
| | | } |
| | | else if (add) { |
| | | row = $('<tr>').attr('id', 'rcmrow'+rid).get(0); |
| | | col = $('<td>').addClass('mail').html(name).appendTo(row); |
| | | list.insert_row(row); |
| | | list.select(rid); |
| | | } |
| | | }; |
| | | |
| | | |
| | |
| | | obj.click(function() { return ref.hide_message(obj); }); |
| | | } |
| | | |
| | | this.triggerEvent('message', { message:msg, type:type, timeout:timeout, object:obj }); |
| | | |
| | | if (timeout > 0) |
| | | window.setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout); |
| | | return id; |
| | |
| | | // trigger event hook |
| | | this.triggerEvent('selectfolder', { folder:name, prefix:prefix }); |
| | | } |
| | | }; |
| | | |
| | | // adds a class to selected folder |
| | | this.mark_folder = function(name, class_name, prefix, encode) |
| | | { |
| | | $(this.get_folder_li(name, prefix, encode)).addClass(class_name); |
| | | }; |
| | | |
| | | // adds a class to selected folder |
| | | this.unmark_folder = function(name, class_name, prefix, encode) |
| | | { |
| | | $(this.get_folder_li(name, prefix, encode)).removeClass(class_name); |
| | | }; |
| | | |
| | | // helper method to find a folder list item |
| | |
| | | if (typeof content === 'object' && content.type == 'image') |
| | | this.percent_indicator(this.gui_objects.quotadisplay, content); |
| | | else |
| | | $(this.gui_objects.quotadisplay).html(content); |
| | | $(this.gui_objects.quotadisplay).html(content.percent+'%').attr('title', content.title); |
| | | } |
| | | this.triggerEvent('setquota', content); |
| | | }; |
| | | |
| | | // update the mailboxlist |
| | | this.set_unread_count = function(mbox, count, set_title) |
| | | this.set_unread_count = function(mbox, count, set_title, mark) |
| | | { |
| | | if (!this.gui_objects.mailboxlist) |
| | | return false; |
| | | |
| | | this.env.unread_counts[mbox] = count; |
| | | this.set_unread_count_display(mbox, set_title); |
| | | |
| | | if (mark) |
| | | this.mark_folder(mbox, mark, '', true); |
| | | else if (!count) |
| | | this.unmark_folder(mbox, 'recent', '', true); |
| | | }; |
| | | |
| | | // update the mailbox count display |
| | |
| | | } |
| | | |
| | | if (mycount && text_obj.length) |
| | | text_obj.html(' ('+mycount+')'); |
| | | text_obj.html(this.env.unreadwrap.replace(/%[sd]/, mycount)); |
| | | else if (text_obj.length) |
| | | text_obj.remove(); |
| | | |
| | |
| | | |
| | | this.set_pagetitle(new_title); |
| | | } |
| | | }; |
| | | |
| | | this.toggle_prefer_html = function(checkbox) |
| | | { |
| | | $('#rcmfd_show_images').prop('disabled', !checkbox.checked).val(0); |
| | | }; |
| | | |
| | | this.toggle_preview_pane = function(checkbox) |
| | | { |
| | | $('#rcmfd_preview_pane_mark_read').prop('disabled', !checkbox.checked); |
| | | }; |
| | | |
| | | // display fetched raw headers |
| | |
| | | }); |
| | | }; |
| | | |
| | | this.plain2html = function(plainText, id) |
| | | this.plain2html = function(plain, id) |
| | | { |
| | | var lock = this.set_busy(true, 'converting'); |
| | | $('#'+id).val(plainText ? '<pre>'+plainText+'</pre>' : ''); |
| | | |
| | | plain = plain.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); |
| | | $('#'+id).val(plain ? '<pre>'+plain+'</pre>' : ''); |
| | | |
| | | this.set_busy(false, null, lock); |
| | | }; |
| | | |
| | |
| | | this.enable_command('purge', this.purge_mailbox_test()); |
| | | this.enable_command('expand-all', 'expand-unread', 'collapse-all', this.env.threading && this.env.messagecount); |
| | | |
| | | if (response.action == 'list' || response.action == 'search') { |
| | | if ((response.action == 'list' || response.action == 'search') && this.message_list) { |
| | | this.msglist_select(this.message_list); |
| | | this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:this.message_list.rowcount }); |
| | | } |