summaryrefslogtreecommitdiff
path: root/program
diff options
context:
space:
mode:
Diffstat (limited to 'program')
-rw-r--r--program/include/rcmail.php38
-rw-r--r--program/include/rcmail_output_html.php13
-rw-r--r--program/js/app.js444
-rw-r--r--program/js/common.js8
-rw-r--r--program/js/editor.js4
-rw-r--r--program/js/list.js114
-rw-r--r--program/lib/Roundcube/html.php8
-rw-r--r--program/lib/Roundcube/rcube_addressbook.php27
-rw-r--r--program/lib/Roundcube/rcube_contacts.php4
-rw-r--r--program/lib/Roundcube/rcube_html2text.php4
-rw-r--r--program/lib/Roundcube/rcube_ldap.php73
-rw-r--r--program/lib/Roundcube/rcube_mime.php2
-rw-r--r--program/lib/Roundcube/rcube_plugin_api.php5
-rw-r--r--program/lib/Roundcube/rcube_spellcheck_atd.php12
-rw-r--r--program/lib/Roundcube/rcube_spellcheck_enchant.php18
-rw-r--r--program/lib/Roundcube/rcube_spellcheck_engine.php7
-rw-r--r--program/lib/Roundcube/rcube_spellcheck_googie.php36
-rw-r--r--program/lib/Roundcube/rcube_spellcheck_pspell.php29
-rw-r--r--program/lib/Roundcube/rcube_spellchecker.php50
-rw-r--r--program/lib/Roundcube/rcube_user.php12
-rw-r--r--program/lib/Roundcube/rcube_utils.php82
-rw-r--r--program/lib/Roundcube/rcube_vcard.php31
-rw-r--r--program/localization/be_BE/labels.inc44
-rw-r--r--program/localization/be_BE/messages.inc18
-rw-r--r--program/localization/bg_BG/labels.inc8
-rw-r--r--program/localization/bg_BG/messages.inc5
-rw-r--r--program/localization/bs_BA/messages.inc3
-rw-r--r--program/localization/ca_ES/labels.inc12
-rw-r--r--program/localization/ca_ES/messages.inc3
-rw-r--r--program/localization/cs_CZ/labels.inc8
-rw-r--r--program/localization/cs_CZ/messages.inc2
-rw-r--r--program/localization/cy_GB/messages.inc3
-rw-r--r--program/localization/da_DK/labels.inc12
-rw-r--r--program/localization/da_DK/messages.inc5
-rw-r--r--program/localization/de_CH/labels.inc8
-rw-r--r--program/localization/de_CH/messages.inc5
-rw-r--r--program/localization/en_US/labels.inc12
-rw-r--r--program/localization/en_US/messages.inc2
-rw-r--r--program/localization/es_ES/messages.inc3
-rw-r--r--program/localization/fa_IR/labels.inc16
-rw-r--r--program/localization/fa_IR/messages.inc3
-rw-r--r--program/localization/fi_FI/labels.inc8
-rw-r--r--program/localization/fi_FI/messages.inc2
-rw-r--r--program/localization/fr_FR/labels.inc8
-rw-r--r--program/localization/hu_HU/labels.inc8
-rw-r--r--program/localization/hu_HU/messages.inc5
-rw-r--r--program/localization/it_IT/messages.inc3
-rw-r--r--program/localization/ja_JP/labels.inc8
-rw-r--r--program/localization/ja_JP/messages.inc2
-rw-r--r--program/localization/lb_LU/labels.inc12
-rw-r--r--program/localization/lb_LU/messages.inc5
-rw-r--r--program/localization/lv_LV/labels.inc9
-rw-r--r--program/localization/lv_LV/messages.inc5
-rw-r--r--program/localization/nl_NL/labels.inc8
-rw-r--r--program/localization/nl_NL/messages.inc2
-rw-r--r--program/localization/pt_BR/labels.inc8
-rw-r--r--program/localization/pt_BR/messages.inc5
-rw-r--r--program/localization/pt_PT/labels.inc8
-rw-r--r--program/localization/pt_PT/messages.inc2
-rw-r--r--program/localization/ru_RU/messages.inc2
-rw-r--r--program/localization/sk_SK/labels.inc8
-rw-r--r--program/localization/sk_SK/messages.inc5
-rw-r--r--program/localization/sl_SI/labels.inc12
-rw-r--r--program/localization/sl_SI/messages.inc5
-rw-r--r--program/localization/sv_SE/labels.inc8
-rw-r--r--program/localization/sv_SE/messages.inc5
-rw-r--r--program/localization/tr_TR/messages.inc5
-rw-r--r--program/localization/uk_UA/messages.inc2
-rw-r--r--program/steps/addressbook/save.inc4
-rw-r--r--program/steps/mail/compose.inc63
-rw-r--r--program/steps/mail/func.inc53
-rw-r--r--program/steps/mail/sendmail.inc33
-rw-r--r--program/steps/settings/edit_response.inc107
-rw-r--r--program/steps/settings/func.inc22
-rw-r--r--program/steps/settings/responses.inc128
-rw-r--r--program/steps/settings/save_prefs.inc1
-rw-r--r--program/steps/utils/save_pref.inc22
-rw-r--r--program/steps/utils/spell.inc3
78 files changed, 1473 insertions, 316 deletions
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index 0483f0e18..4b3f13760 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -346,6 +346,44 @@ class rcmail extends rcube
return $list;
}
+ /**
+ * Getter for compose responses.
+ * These are stored in local config and user preferences.
+ *
+ * @param boolean True to sort the list alphabetically
+ * @param boolean True if only this user's responses shall be listed
+ * @return array List of the current user's stored responses
+ */
+ public function get_compose_responses($sorted = false, $user_only = false)
+ {
+ $responses = array();
+
+ if (!$user_only) {
+ foreach ($this->config->get('compose_responses_static', array()) as $response) {
+ if (empty($response['key']))
+ $response['key'] = substr(md5($response['name']), 0, 16);
+ $response['static'] = true;
+ $response['class'] = 'readonly';
+ $k = $sorted ? '0000-' . strtolower($response['name']) : $response['key'];
+ $responses[$k] = $response;
+ }
+ }
+
+ foreach ($this->config->get('compose_responses', array()) as $response) {
+ if (empty($response['key']))
+ $response['key'] = substr(md5($response['name']), 0, 16);
+ $k = $sorted ? strtolower($response['name']) : $response['key'];
+ $responses[$k] = $response;
+ }
+
+ // sort list by name
+ if ($sorted) {
+ ksort($responses, SORT_LOCALE_STRING);
+ }
+
+ return array_values($responses);
+ }
+
/**
* Init output object for GUI and add common scripts.
diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php
index 7cab3725e..8a960673d 100644
--- a/program/include/rcmail_output_html.php
+++ b/program/include/rcmail_output_html.php
@@ -1165,7 +1165,7 @@ class rcmail_output_html extends rcmail_output
}
else if ($attrib['type'] == 'link') {
$btn_content = isset($attrib['content']) ? $attrib['content'] : ($attrib['label'] ? $attrib['label'] : $attrib['command']);
- $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style', 'tabindex', 'target');
+ $link_attrib = array_merge(html::$common_attrib, array('href', 'onclick', 'tabindex', 'target'));
if ($attrib['innerclass'])
$btn_content = html::span($attrib['innerclass'], $btn_content);
}
@@ -1280,7 +1280,12 @@ class rcmail_output_html extends rcmail_output
*/
public function _write($templ = '', $base_path = '')
{
- $output = empty($templ) ? $this->default_template : trim($templ);
+ $output = trim($templ);
+
+ if (empty($output)) {
+ $output = $this->default_template;
+ $is_empty = true;
+ }
// set default page title
if (empty($this->pagetitle)) {
@@ -1371,8 +1376,8 @@ class rcmail_output_html extends rcmail_output
}
// add css files in head, before scripts, for speed up with parallel downloads
- if (!empty($this->css_files) &&
- (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>')))
+ if (!empty($this->css_files) && !$is_empty
+ && (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>')))
) {
$css = '';
foreach ($this->css_files as $file) {
diff --git a/program/js/app.js b/program/js/app.js
index 7fbab8003..1f75e219c 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -256,12 +256,14 @@ function rcube_webmail()
}
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'];
+ this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel',
+ 'toggle-editor', 'list-adresses', 'pushgroup', 'search', 'reset-search', 'extwin',
+ 'insert-response', 'save-response'];
if (this.env.drafts_mailbox)
this.env.compose_commands.push('savedraft')
- this.enable_command(this.env.compose_commands, 'identities', true);
+ this.enable_command(this.env.compose_commands, 'identities', 'responses', true);
// add more commands (not enabled)
$.merge(this.env.compose_commands, ['add-recipient', 'firstpage', 'previouspage', 'nextpage', 'lastpage']);
@@ -272,6 +274,23 @@ function rcube_webmail()
this.enable_command('spellcheck', true);
}
+ // init canned response functions
+ if (this.gui_objects.responseslist) {
+ $('a.insertresponse', this.gui_objects.responseslist)
+ .attr('unselectable', 'on')
+ .mousedown(function(e){ return rcube_event.cancel(e); })
+ .mouseup(function(e){
+ ref.command('insert-response', $(this).attr('rel'));
+ $(document.body).trigger('mouseup'); // hides the menu
+ return rcube_event.cancel(e);
+ });
+
+ // avoid textarea loosing focus when hitting the save-response button/link
+ for (var i=0; this.buttons['save-response'] && i < this.buttons['save-response'].length; i++) {
+ $('#'+this.buttons['save-response'][i].id).mousedown(function(e){ return rcube_event.cancel(e); })
+ }
+ }
+
document.onmouseup = function(e){ return p.doc_mouse_up(e); };
// init message compose form
@@ -381,7 +400,7 @@ function rcube_webmail()
break;
case 'settings':
- this.enable_command('preferences', 'identities', 'save', 'folders', true);
+ this.enable_command('preferences', 'identities', 'responses', 'save', 'folders', true);
if (this.env.action == 'identities') {
this.enable_command('add', this.env.identities_level < 2);
@@ -402,6 +421,9 @@ function rcube_webmail()
parent.rcmail.enable_command('purge', this.env.messagecount);
$("input[type='text']").first().select();
}
+ else if (this.env.action == 'responses') {
+ this.enable_command('add', true);
+ }
if (this.gui_objects.identitieslist) {
this.identity_list = new rcube_list_widget(this.gui_objects.identitieslist, {multiselect:false, draggable:false, keyboard:false});
@@ -418,8 +440,22 @@ function rcube_webmail()
this.sections_list.init();
this.sections_list.focus();
}
- else if (this.gui_objects.subscriptionlist)
+ else if (this.gui_objects.subscriptionlist) {
this.init_subscription_list();
+ }
+ else if (this.gui_objects.responseslist) {
+ this.responses_list = new rcube_list_widget(this.gui_objects.responseslist, {multiselect:false, draggable:false, keyboard:false});
+ this.responses_list.addEventListener('select', function(list){
+ var win, id = list.get_single_selection();
+ p.enable_command('delete', !!id && $.inArray(id, p.env.readonly_responses) < 0);
+ if (id && (win = p.get_frame_window(p.env.contentframe))) {
+ p.set_busy(true);
+ p.location_href({ _action:'edit-response', _key:id, _framed:1 }, win);
+ }
+ });
+ this.responses_list.init();
+ this.responses_list.focus();
+ }
break;
@@ -463,6 +499,7 @@ function rcube_webmail()
// flag object as complete
this.loaded = true;
+ this.env.lastrefresh = new Date();
// show message
if (this.pending_message)
@@ -725,6 +762,13 @@ function rcube_webmail()
case 'add':
if (this.task == 'addressbook')
this.load_contact(0, 'add');
+ else if (this.task == 'settings' && this.env.action == 'responses') {
+ var frame;
+ if ((frame = this.get_frame_window(this.env.contentframe))) {
+ this.set_busy(true);
+ this.location_href({ _action:'add-response', _framed:1 }, frame);
+ }
+ }
else if (this.task == 'settings') {
this.identity_list.clear_selection();
this.load_identity(0, 'add-identity');
@@ -788,7 +832,10 @@ function rcube_webmail()
// addressbook task
else if (this.task == 'addressbook')
this.delete_contacts();
- // user settings task
+ // settings: canned response
+ else if (this.task == 'settings' && this.env.action == 'responses')
+ this.delete_response();
+ // settings: user identities
else if (this.task == 'settings')
this.delete_identity();
break;
@@ -815,37 +862,24 @@ function rcube_webmail()
break;
case 'toggle_status':
- if (props && !props._row)
- break;
-
- flag = 'read';
-
- if (props._row.uid) {
- uid = props._row.uid;
+ case 'toggle_flag':
+ flag = command == 'toggle_flag' ? 'flagged' : 'read';
+ if (uid = props) {
+ // toggle flagged/unflagged
+ if (flag == 'flagged') {
+ if (this.message_list.rows[uid].flagged)
+ flag = 'unflagged';
+ }
// toggle read/unread
- if (this.message_list.rows[uid].deleted)
+ else if (this.message_list.rows[uid].deleted)
flag = 'undelete';
else if (!this.message_list.rows[uid].unread)
flag = 'unread';
- }
- this.mark_message(flag, uid);
- break;
-
- case 'toggle_flag':
- if (props && !props._row)
- break;
-
- 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);
}
- this.mark_message(flag, uid);
+
break;
case 'always-load':
@@ -1031,7 +1065,7 @@ function rcube_webmail()
url = {_reply_uid: uid, _mbox: this.env.mailbox};
if (command == 'reply-all')
// do reply-list, when list is detected and popup menu wasn't used
- url._all = (!props && this.commands['reply-list'] ? 'list' : 'all');
+ url._all = (!props && this.env.reply_all_mode == 1 && this.commands['reply-list'] ? 'list' : 'all');
else if (command == 'reply-list')
url._all = 'list';
@@ -1173,6 +1207,7 @@ function rcube_webmail()
// user settings commands
case 'preferences':
case 'identities':
+ case 'responses':
case 'folders':
this.goto_url('settings/' + command);
break;
@@ -1439,7 +1474,7 @@ function rcube_webmail()
// select the folder if one of its childs is currently selected
// don't select if it's virtual (#1488346)
- if (this.env.mailbox && this.env.mailbox.indexOf(name + this.env.delimiter) == 0 && !node.virtual)
+ if (this.env.mailbox && this.env.mailbox.startsWith(name + this.env.delimiter) && !node.virtual)
this.command('list', name);
}
else {
@@ -1620,8 +1655,8 @@ function rcube_webmail()
this.env.coltypes = [];
for (i=0; i<cols.length; i++)
- if (cols[i].id && cols[i].id.match(/^rcm/)) {
- name = cols[i].id.replace(/^rcm/, '');
+ if (cols[i].id && cols[i].id.startsWith('rcm')) {
+ name = cols[i].id.slice(3);
this.env.coltypes.push(name);
}
@@ -1704,7 +1739,7 @@ function rcube_webmail()
this.init_message_row = function(row)
{
- var expando, self = this, uid = row.uid,
+ var i, fn = {}, self = this, uid = row.uid,
status_icon = (this.env.status_col != null ? 'status' : 'msg') + 'icn' + row.uid;
if (uid && this.env.messages[uid])
@@ -1712,8 +1747,7 @@ function rcube_webmail()
// set eventhandler to status icon
if (row.icon = document.getElementById(status_icon)) {
- row.icon._row = row.obj;
- row.icon.onclick = function(e) { self.command('toggle_status', this); return rcube_event.cancel(e); };
+ fn.icon = function(e) { self.command('toggle_status', uid); };
}
// save message icon position too
@@ -1722,24 +1756,28 @@ function rcube_webmail()
else
row.msgicon = row.icon;
- // set eventhandler to flag icon, if icon found
+ // set eventhandler to flag icon
if (this.env.flagged_col != null && (row.flagicon = document.getElementById('flagicn'+row.uid))) {
- row.flagicon._row = row.obj;
- row.flagicon.onclick = function(e) { self.command('toggle_flag', this); return rcube_event.cancel(e); };
+ fn.flagicon = function(e) { self.command('toggle_flag', uid); };
}
- if (!row.depth && row.has_children && (expando = document.getElementById('rcmexpando'+row.uid))) {
- row.expando = expando;
- expando.onclick = function(e) { return self.expand_message_row(e, uid); };
+ // set event handler to thread expand/collapse icon
+ if (!row.depth && row.has_children && (row.expando = document.getElementById('rcmexpando'+row.uid))) {
+ fn.expando = function(e) { self.expand_message_row(e, uid); };
+ }
+
+ // attach events
+ $.each(fn, function(i, f) {
+ row[i].onclick = function(e) { f(e); return rcube_event.cancel(e); };
if (bw.touch) {
- expando.addEventListener('touchend', function(e) {
+ row[i].addEventListener('touchend', function(e) {
if (e.changedTouches.length == 1) {
- self.expand_message_row(e, uid);
+ f(e);
return rcube_event.cancel(e);
}
}, false);
}
- }
+ });
this.triggerEvent('insertrow', { uid:uid, row:row });
};
@@ -2024,12 +2062,14 @@ function rcube_webmail()
if (name && (frame = this.get_frame_element(name))) {
if (!show && (win = this.get_frame_window(name))) {
- if (win.stop)
- win.stop();
- else // IE
- win.document.execCommand('Stop');
+ if (win.location.href.indexOf(this.env.blankpage) < 0) {
+ if (win.stop)
+ win.stop();
+ else // IE
+ win.document.execCommand('Stop');
- win.location.href = this.env.blankpage;
+ win.location.href = this.env.blankpage;
+ }
}
else if (!bw.safari && !bw.konq)
$(frame)[show ? 'show' : 'hide']();
@@ -2704,9 +2744,6 @@ function rcube_webmail()
}
}
- if (this.env.display_next && this.env.next_uid)
- post_data._next_uid = this.env.next_uid;
-
if (count < 0)
post_data._count = (count*-1);
// remove threads from the end of the list
@@ -2742,6 +2779,9 @@ function rcube_webmail()
if (this.env.search_request)
data._search = this.env.search_request;
+ if (this.env.display_next && this.env.next_uid)
+ data._next_uid = this.env.next_uid;
+
return data;
};
@@ -2992,9 +3032,12 @@ function rcube_webmail()
// test if purge command is allowed
this.purge_mailbox_test = function()
{
- return (this.env.exists && (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))));
+ return (this.env.exists && (
+ this.env.mailbox == this.env.trash_mailbox
+ || this.env.mailbox == this.env.junk_mailbox
+ || this.env.mailbox.startsWith(this.env.trash_mailbox + this.env.delimiter)
+ || this.env.mailbox.startsWith(this.env.junk_mailbox + this.env.delimiter)
+ ));
};
@@ -3285,6 +3328,154 @@ function rcube_webmail()
return true;
};
+ this.insert_response = function(key)
+ {
+ var insert = this.env.textresponses[key] ? this.env.textresponses[key].text : null;
+ if (!insert)
+ return false;
+
+ // insert into tinyMCE editor
+ if ($("input[name='_is_html']").val() == '1') {
+ var editor = tinyMCE.get(this.env.composebody);
+ editor.getWin().focus(); // correct focus in IE & Chrome
+ editor.selection.setContent(insert, { format:'text' });
+ }
+ // replace selection in compose textarea
+ else {
+ var textarea = rcube_find_object(this.env.composebody),
+ selection = $(textarea).is(':focus') ? this.get_input_selection(textarea) : { start:0, end:0 },
+ inp_value = textarea.value;
+ pre = inp_value.substring(0, selection.start),
+ end = inp_value.substring(selection.end, inp_value.length);
+
+ // insert response text
+ textarea.value = pre + insert + end;
+
+ // set caret after inserted text
+ this.set_caret_pos(textarea, selection.start + insert.length);
+ textarea.focus();
+ }
+ };
+
+ /**
+ * Open the dialog to save a new canned response
+ */
+ this.save_response = function()
+ {
+ var sigstart, text = '', strip = false;
+
+ // get selected text from tinyMCE editor
+ if ($("input[name='_is_html']").val() == '1') {
+ var editor = tinyMCE.get(this.env.composebody);
+ editor.getWin().focus(); // correct focus in IE & Chrome
+ text = editor.selection.getContent({ format:'text' });
+
+ if (!text) {
+ text = editor.getContent({ format:'text' });
+ strip = true;
+ }
+ }
+ // get selected text from compose textarea
+ else {
+ var textarea = rcube_find_object(this.env.composebody), sigstart;
+ if (textarea && $(textarea).is(':focus')) {
+ text = this.get_input_selection(textarea).text;
+ }
+
+ if (!text && textarea) {
+ text = textarea.value;
+ strip = true;
+ }
+ }
+
+ // strip off signature
+ if (strip) {
+ sigstart = text.indexOf('-- \n');
+ if (sigstart > 0) {
+ text = text.substring(0, sigstart);
+ }
+ }
+
+ // show dialog to enter a name and to modify the text to be saved
+ var buttons = {},
+ html = '<form class="propform">' +
+ '<div class="prop block"><label>' + this.get_label('responsename') + '</label>' +
+ '<input type="text" name="name" id="ffresponsename" size="40" /></div>' +
+ '<div class="prop block"><label>' + this.get_label('responsetext') + '</label>' +
+ '<textarea name="text" id="ffresponsetext" cols="40" rows="8"></textarea></div>' +
+ '</form>';
+
+ buttons[this.gettext('save')] = function(e) {
+ var name = $('#ffresponsename').val(),
+ text = $('#ffresponsetext').val();
+
+ if (!text) {
+ $('#ffresponsetext').select();
+ return false;
+ }
+ if (!name)
+ name = text.substring(0,40);
+
+ var lock = ref.display_message(ref.get_label('savingresponse'), 'loading');
+ ref.http_post('settings/responses', { _insert:1, _name:name, _text:text }, lock);
+ $(this).dialog('close');
+ };
+
+ buttons[this.gettext('cancel')] = function() {
+ $(this).dialog('close');
+ };
+
+ this.show_popup_dialog(html, this.gettext('savenewresponse'), buttons);
+
+ $('#ffresponsetext').val(text);
+ $('#ffresponsename').select();
+ };
+
+ this.add_response_item = function(response)
+ {
+ var key = response.key;
+ this.env.textresponses[key] = response;
+
+ // append to responses list
+ if (this.gui_objects.responseslist) {
+ var li = $('<li>').appendTo(this.gui_objects.responseslist);
+ $('<a>').addClass('insertresponse active')
+ .attr('href', '#')
+ .attr('rel', key)
+ .html(this.quote_html(response.name))
+ .appendTo(li)
+ .mousedown(function(e){
+ return rcube_event.cancel(e);
+ })
+ .mouseup(function(e){
+ ref.command('insert-response', key);
+ $(document.body).trigger('mouseup'); // hides the menu
+ return rcube_event.cancel(e);
+ });
+ }
+ };
+
+ this.edit_responses = function()
+ {
+ // TODO: implement inline editing of responses
+ };
+
+ this.delete_response = function(key)
+ {
+ if (!key && this.responses_list) {
+ var selection = this.responses_list.get_selection();
+ key = selection[0];
+ }
+
+ // submit delete request
+ if (key && confirm(this.get_label('deleteresponseconfirm'))) {
+ this.http_post('settings/delete-response', { _key: key }, false);
+ return true;
+ }
+
+ return false;
+ };
+
this.stop_spellchecking = function()
{
var ed;
@@ -3559,6 +3750,7 @@ function rcube_webmail()
}
this.env.identity = id;
+ this.triggerEvent('change_identity');
return true;
};
@@ -3990,7 +4182,7 @@ function rcube_webmail()
return;
// ...new search value contains old one and previous search was not finished or its result was empty
- if (old_value && old_value.length && q.indexOf(old_value) == 0 && (!ac || ac.num <= 0) && this.env.contacts && !this.env.contacts.length)
+ if (old_value && old_value.length && q.startsWith(old_value) && (!ac || ac.num <= 0) && this.env.contacts && !this.env.contacts.length)
return;
var i, lock, source, xhr, reqid = new Date().getTime(),
@@ -5210,6 +5402,35 @@ function rcube_webmail()
}
};
+ this.update_response_row = function(response, oldkey)
+ {
+ var list = this.responses_list;
+
+ if (list && oldkey) {
+ list.update_row(oldkey, [ response.name ], response.key, true);
+ }
+ else if (list) {
+ list.insert_row({ id:'rcmrow'+response.key, cols:[ { className:'name', innerHTML:response.name } ] });
+ list.select(response.key);
+ }
+ };
+
+ this.remove_response = function(key)
+ {
+ var frame;
+
+ if (this.env.textresponses) {
+ delete this.env.textresponses[key];
+ }
+
+ if (this.responses_list) {
+ this.responses_list.remove_row(key);
+ if (this.env.contentframe && (frame = this.get_frame_window(this.env.contentframe))) {
+ frame.location.href = this.env.blankpage;
+ }
+ }
+ };
+
/*********************************************************/
/********* folder manager methods *********/
@@ -5246,7 +5467,7 @@ function rcube_webmail()
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))))
+ (!folder.startsWith(this.env.mailbox + this.env.delimiter))
) {
this.env.dstfolder = folder;
$(row).addClass('droptarget');
@@ -5372,7 +5593,7 @@ function rcube_webmail()
tmp = tmp_name;
}
// protected folder's child
- else if (tmp && folders[n][0].indexOf(tmp) == 0)
+ else if (tmp && folders[n][0].startsWith(tmp))
slist.push(folders[n][0]);
// other
else {
@@ -5383,7 +5604,7 @@ function rcube_webmail()
// check if subfolder of a protected folder
for (n=0; n<slist.length; n++) {
- if (name.indexOf(slist[n]+this.env.delimiter) == 0)
+ if (name.startsWith(slist[n] + this.env.delimiter))
rowid = this.get_folder_row_id(slist[n]);
}
@@ -5495,13 +5716,13 @@ function rcube_webmail()
this.get_subfolders = function(folder)
{
var name, list = [],
- regex = new RegExp('^'+RegExp.escape(folder)+RegExp.escape(this.env.delimiter)),
+ prefix = folder + this.env.delimiter,
row = $('#'+this.get_folder_row_id(folder)).get(0);
while (row = row.nextSibling) {
if (row.id) {
name = this.env.subscriptionrows[row.id][0];
- if (regex.test(name)) {
+ if (name && name.startsWith(prefix)) {
list.push(row.id);
}
else
@@ -5898,24 +6119,23 @@ function rcube_webmail()
};
// open a jquery UI dialog with the given content
- this.show_popup_dialog = function(html, title, buttons)
+ this.show_popup_dialog = function(html, title, buttons, options)
{
// forward call to parent window
if (this.is_framed()) {
- parent.rcmail.show_popup_dialog(html, title, buttons);
- return;
+ return parent.rcmail.show_popup_dialog(html, title, buttons);
}
var popup = $('<div class="popup">')
.html(html)
- .dialog({
+ .dialog($.extend({
title: title,
buttons: buttons,
modal: true,
resizable: true,
width: 500,
close: function(event, ui) { $(this).remove() }
- });
+ }, options || {}));
// resize and center popup
var win = $(window), w = win.width(), h = win.height(),
@@ -5925,6 +6145,8 @@ function rcube_webmail()
height: Math.min(h - 40, height + 75 + (buttons ? 50 : 0)),
width: Math.min(w - 20, width + 20)
});
+
+ return popup;
};
// enable/disable buttons for page shifting
@@ -6103,7 +6325,7 @@ function rcube_webmail()
div.className.match(/collapsed/)) {
// add children's counters
for (var k in this.env.unread_counts)
- if (k.indexOf(mbox + this.env.delimiter) == 0)
+ if (k.startsWith(mbox + this.env.delimiter))
childcount += this.env.unread_counts[k];
}
@@ -6297,7 +6519,7 @@ function rcube_webmail()
if (result === false)
return false;
else
- query = result;
+ url = this.url(action, result);
}
url += '&_remote=1';
@@ -6534,7 +6756,7 @@ function rcube_webmail()
// post the given form to a hidden iframe
this.async_upload_form = function(form, action, onload)
{
- var ts = new Date().getTime(),
+ var frame, ts = new Date().getTime(),
frame_name = 'rcmupload'+ts;
// upload progress support
@@ -6553,21 +6775,19 @@ function rcube_webmail()
// have to do it this way for IE
// otherwise the form will be posted to a new window
if (document.all) {
- var html = '<iframe name="'+frame_name+'" src="program/resources/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>';
- document.body.insertAdjacentHTML('BeforeEnd', html);
+ document.body.insertAdjacentHTML('BeforeEnd', '<iframe name="'+frame_name+'"'
+ + ' src="program/resources/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>');
+ frame = $('iframe[name="'+frame_name+'"]');
}
- else { // for standards-compilant browsers
- var frame = document.createElement('iframe');
- frame.name = frame_name;
- frame.style.border = 'none';
- frame.style.width = 0;
- frame.style.height = 0;
- frame.style.visibility = 'hidden';
- document.body.appendChild(frame);
+ // for standards-compliant browsers
+ else {
+ frame = $('<iframe>').attr('name', frame_name)
+ .css({border: 'none', width: 0, height: 0, visibility: 'hidden'})
+ .appendTo(document.body);
}
// handle upload errors, parsing iframe content in onload
- $(frame_name).bind('load', {ts:ts}, onload);
+ frame.bind('load', {ts:ts}, onload);
$(form).attr({
target: frame_name,
@@ -6744,6 +6964,9 @@ function rcube_webmail()
if (this.task == 'mail' && this.gui_objects.mailboxlist)
params = this.check_recent_params();
+ params._last = Math.floor(this.env.lastrefresh.getTime() / 1000);
+ this.env.lastrefresh = new Date();
+
// plugins should bind to 'requestrefresh' event to add own params
this.http_request('refresh', params, lock);
};
@@ -6770,6 +6993,14 @@ function rcube_webmail()
/********* helper methods *********/
/********************************************************/
+ /**
+ * Quote html entities
+ */
+ this.quote_html = function(str)
+ {
+ return String(str).replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+ };
+
// get window.opener.rcmail if available
this.opener = function()
{
@@ -6834,6 +7065,57 @@ function rcube_webmail()
}
};
+ // get selected text from an input field
+ // http://stackoverflow.com/questions/7186586/how-to-get-the-selected-text-in-textarea-using-jquery-in-internet-explorer-7
+ this.get_input_selection = function(obj)
+ {
+ var start = 0, end = 0,
+ normalizedValue, range,
+ textInputRange, len, endRange;
+
+ if (typeof obj.selectionStart == "number" && typeof obj.selectionEnd == "number") {
+ normalizedValue = obj.value;
+ start = obj.selectionStart;
+ end = obj.selectionEnd;
+ }
+ else {
+ range = document.selection.createRange();
+
+ if (range && range.parentElement() == obj) {
+ len = obj.value.length;
+ normalizedValue = obj.value; //.replace(/\r\n/g, "\n");
+
+ // create a working TextRange that lives only in the input
+ textInputRange = obj.createTextRange();
+ textInputRange.moveToBookmark(range.getBookmark());
+
+ // Check if the start and end of the selection are at the very end
+ // of the input, since moveStart/moveEnd doesn't return what we want
+ // in those cases
+ endRange = obj.createTextRange();
+ endRange.collapse(false);
+
+ if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
+ start = end = len;
+ }
+ else {
+ start = -textInputRange.moveStart("character", -len);
+ start += normalizedValue.slice(0, start).split("\n").length - 1;
+
+ if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
+ end = len;
+ }
+ else {
+ end = -textInputRange.moveEnd("character", -len);
+ end += normalizedValue.slice(0, end).split("\n").length - 1;
+ }
+ }
+ }
+ }
+
+ return { start:start, end:end, text:normalizedValue.substr(start, end-start) };
+ };
+
// disable/enable all fields of a form
this.lock_form = function(form, lock)
{
diff --git a/program/js/common.js b/program/js/common.js
index afaf91639..02934f734 100644
--- a/program/js/common.js
+++ b/program/js/common.js
@@ -592,6 +592,14 @@ Date.prototype.getStdTimezoneOffset = function()
return tzo;
}
+// define String's startsWith() method for old browsers
+if (!String.prototype.startsWith) {
+ String.prototype.startsWith = function(search, position) {
+ position = position || 0;
+ return this.slice(position, search.length) === search;
+ };
+}
+
// Make getElementById() case-sensitive on IE
if (bw.ie) {
document._getElementById = document.getElementById;
diff --git a/program/js/editor.js b/program/js/editor.js
index 6d7b9538a..020971d6e 100644
--- a/program/js/editor.js
+++ b/program/js/editor.js
@@ -161,8 +161,8 @@ function rcmail_editor_images()
for (i in files) {
att = files[i];
- if (att.complete && att.mimetype.indexOf('image/') == 0) {
- list.push([att.name, rcmail.env.comm_path+'&_action=display-attachment&_file='+i+'&_id='+rcmail.env.compose_id]);
+ if (att.complete && att.mimetype.startsWith('image/')) {
+ list.push([att.name, rcmail.env.comm_path+'&_id='+rcmail.env.compose_id+'&_action=display-attachment&_file='+i]);
}
}
diff --git a/program/js/list.js b/program/js/list.js
index cb69bc462..e1d57745c 100644
--- a/program/js/list.js
+++ b/program/js/list.js
@@ -31,6 +31,7 @@ function rcube_list_widget(list, p)
this.list = list ? list : null;
this.tagname = this.list ? this.list.nodeName.toLowerCase() : 'table';
+ this.id_regexp = /^rcmrow([a-z0-9\-_=\+\/]+)/i;
this.thead;
this.tbody;
this.fixed_header;
@@ -55,7 +56,6 @@ function rcube_list_widget(list, p)
this.column_fixed = null;
this.last_selected = 0;
this.shift_start = 0;
- this.in_selection_before = false;
this.focused = false;
this.drag_mouse_start = null;
this.dblclick_time = 500; // default value on MS Windows is 500
@@ -111,7 +111,7 @@ init: function()
init_row: function(row)
{
// make references in internal array and set event handlers
- if (row && String(row.id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)) {
+ if (row && String(row.id).match(this.id_regexp)) {
var self = this,
uid = RegExp.$1;
row.uid = uid;
@@ -405,10 +405,7 @@ drag_column: function(e, col)
drag_row: function(e, id)
{
// don't do anything (another action processed before)
- var evtarget = rcube_event.get_target(e),
- tagname = evtarget.tagName.toLowerCase();
-
- if (evtarget && (tagname == 'input' || tagname == 'img' || (tagname != 'a' && evtarget.onclick)))
+ if (!this.is_event_target(e))
return true;
// accept right-clicks
@@ -420,12 +417,13 @@ drag_row: function(e, id)
// selects currently unselected row
if (!this.in_selection_before) {
var mod_key = rcube_event.get_modifier(e);
- this.select_row(id, mod_key, false);
+ this.select_row(id, mod_key, true);
}
if (this.draggable && this.selection.length && this.in_selection(id)) {
this.drag_start = true;
this.drag_mouse_start = rcube_event.get_mouse_pos(e);
+
rcube_event.add_listener({event:'mousemove', object:this, method:'drag_mouse_move'});
rcube_event.add_listener({event:'mouseup', object:this, method:'drag_mouse_up'});
if (bw.touch) {
@@ -446,19 +444,16 @@ drag_row: function(e, id)
*/
click_row: function(e, id)
{
- var now = new Date().getTime(),
- mod_key = rcube_event.get_modifier(e),
- evtarget = rcube_event.get_target(e),
- tagname = evtarget.tagName.toLowerCase();
-
- if ((evtarget && (tagname == 'input' || tagname == 'img')))
+ // don't do anything (another action processed before)
+ if (!this.is_event_target(e))
return true;
- var dblclicked = now - this.rows[id].clicked < this.dblclick_time;
+ var now = new Date().getTime(),
+ dblclicked = now - this.rows[id].clicked < this.dblclick_time;
// unselects currently selected row
- if (!this.drag_active && this.in_selection_before == id && !dblclicked)
- this.select_row(id, mod_key, false);
+ if (!this.drag_active && !dblclicked && this.in_selection_before == id)
+ this.select_row(id, rcube_event.get_modifier(e), true);
this.drag_start = false;
this.in_selection_before = false;
@@ -482,6 +477,18 @@ click_row: function(e, id)
},
+/**
+ * Check target of the current event
+ */
+is_event_target: function(e)
+{
+ var target = rcube_event.get_target(e),
+ tagname = target.tagName.toLowerCase();
+
+ return !(target && (tagname == 'input' || tagname == 'img' || (tagname != 'a' && target.onclick)));
+},
+
+
/*
* Returns thread root ID for specified row ID
*/
@@ -726,7 +733,7 @@ get_first_row: function()
var i, len, rows = this.tbody.childNodes;
for (i=0, len=rows.length-1; i<len; i++)
- if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null)
+ if (rows[i].id && String(rows[i].id).match(this.id_regexp) && this.rows[RegExp.$1] != null)
return RegExp.$1;
}
@@ -739,7 +746,7 @@ get_last_row: function()
var i, rows = this.tbody.childNodes;
for (i=rows.length-1; i>=0; i--)
- if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null)
+ if (rows[i].id && String(rows[i].id).match(this.id_regexp) && this.rows[RegExp.$1] != null)
return RegExp.$1;
}
@@ -769,6 +776,7 @@ get_cell: function(row, index)
select_row: function(id, mod_key, with_mouse)
{
var select_before = this.selection.join(',');
+
if (!this.multiselect)
mod_key = 0;
@@ -787,7 +795,7 @@ select_row: function(id, mod_key, with_mouse)
break;
case CONTROL_KEY:
- if (!with_mouse)
+ if (with_mouse)
this.highlight_row(id, true);
break;
@@ -799,6 +807,7 @@ select_row: function(id, mod_key, with_mouse)
this.highlight_row(id, false);
break;
}
+
this.multi_selecting = true;
}
@@ -856,14 +865,8 @@ select_first: function(mod_key)
{
var row = this.get_first_row();
if (row) {
- if (mod_key) {
- this.shift_select(row, mod_key);
- this.triggerEvent('select');
- this.scrollto(row);
- }
- else {
- this.select(row);
- }
+ this.select_row(row, mod_key, false);
+ this.scrollto(row);
}
},
@@ -875,14 +878,8 @@ select_last: function(mod_key)
{
var row = this.get_last_row();
if (row) {
- if (mod_key) {
- this.shift_select(row, mod_key);
- this.triggerEvent('select');
- this.scrollto(row);
- }
- else {
- this.select(row);
- }
+ this.select_row(row, mod_key, false);
+ this.scrollto(row);
}
},
@@ -912,7 +909,8 @@ shift_select: function(id, control)
from_rowIndex = this._rowIndex(this.rows[this.shift_start].obj),
to_rowIndex = this._rowIndex(to_row.obj);
- if (!to_row.expanded && to_row.has_children)
+ // if we're going down the list, and we hit a thread, and it's closed, select the whole thread
+ if (from_rowIndex < to_rowIndex && !to_row.expanded && to_row.has_children)
if (to_row = this.rows[(this.row_children(id)).pop()])
to_rowIndex = this._rowIndex(to_row.obj);
@@ -934,6 +932,7 @@ shift_select: function(id, control)
}
},
+
/**
* Helper method to emulate the rowIndex property of non-tr elements
*/
@@ -1134,10 +1133,13 @@ key_press: function(e)
// Stop propagation so that the browser doesn't scroll
rcube_event.cancel(e);
return this.use_arrow_key(keyCode, mod_key);
- case 61:
- case 107: // Plus sign on a numeric keypad (fc11 + firefox 3.5.2)
- case 109:
case 32:
+ rcube_event.cancel(e);
+ return this.select_row(this.last_selected, mod_key, true);
+ case 37: // Left arrow key
+ case 39: // Right arrow key
+ case 107: // Plus sign on a numeric keypad
+ case 109: // Minus sign on a numeric keypad
// Stop propagation
rcube_event.cancel(e);
var ret = this.use_plusminus_key(keyCode, mod_key);
@@ -1202,21 +1204,30 @@ use_arrow_key: function(keyCode, mod_key)
use_plusminus_key: function(keyCode, mod_key)
{
var selected_row = this.rows[this.last_selected];
- if (!selected_row)
+
+ if (!selected_row || !selected_row.has_children)
return;
- if (keyCode == 32)
- keyCode = selected_row.expanded ? 109 : 61;
- if (keyCode == 61 || keyCode == 107)
+ // expand
+ if (keyCode == 39 || keyCode == 107) {
+ if (selected_row.expanded)
+ return;
+
if (mod_key == CONTROL_KEY || this.multiexpand)
this.expand_all(selected_row);
else
- this.expand(selected_row);
- else
+ this.expand(selected_row);
+ }
+ // collapse
+ else {
+ if (!selected_row.expanded)
+ return;
+
if (mod_key == CONTROL_KEY || this.multiexpand)
this.collapse_all(selected_row);
else
this.collapse(selected_row);
+ }
this.update_expando(selected_row.uid, selected_row.expanded);
@@ -1231,7 +1242,8 @@ scrollto: function(id)
{
var row = this.rows[id].obj;
if (row && this.frame) {
- var scroll_to = Number(row.offsetTop);
+ var scroll_to = Number(row.offsetTop),
+ head_offset = 0;
// expand thread if target row is hidden (collapsed)
if (!scroll_to && this.rows[id].parent_uid) {
@@ -1240,8 +1252,14 @@ scrollto: function(id)
scroll_to = Number(row.offsetTop);
}
- if (scroll_to < Number(this.frame.scrollTop))
- this.frame.scrollTop = scroll_to;
+ if (this.fixed_header)
+ head_offset = Number(this.thead.offsetHeight);
+
+ // if row is above the frame (or behind header)
+ if (scroll_to < Number(this.frame.scrollTop) + head_offset) {
+ // scroll window so that row isn't behind header
+ this.frame.scrollTop = scroll_to - head_offset;
+ }
else if (scroll_to + Number(row.offsetHeight) > Number(this.frame.scrollTop) + Number(this.frame.offsetHeight))
this.frame.scrollTop = (scroll_to + Number(row.offsetHeight)) - Number(this.frame.offsetHeight);
}
diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php
index 5911c04d7..f6f744cb2 100644
--- a/program/lib/Roundcube/html.php
+++ b/program/lib/Roundcube/html.php
@@ -3,7 +3,7 @@
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2011, The Roundcube Dev Team |
+ | Copyright (C) 2005-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -32,8 +32,8 @@ class html
public static $doctype = 'xhtml';
public static $lc_tags = true;
- public static $common_attrib = array('id','class','style','title','align');
- public static $containers = array('iframe','div','span','p','h1','h2','h3','form','textarea','table','thead','tbody','tr','th','td','style','script');
+ public static $common_attrib = array('id','class','style','title','align','unselectable');
+ public static $containers = array('iframe','div','span','p','h1','h2','h3','ul','form','textarea','table','thead','tbody','tr','th','td','style','script');
/**
@@ -645,7 +645,7 @@ class html_select extends html
$option_content = self::quote($option_content);
}
- $this->content .= self::tag('option', $attr + $option, $option_content, array('class','style','title','disabled'));
+ $this->content .= self::tag('option', $attr + $option, $option_content, array('value','label','class','style','title','disabled','selected'));
}
return parent::show();
diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php
index 6e2b439d8..886f65cb9 100644
--- a/program/lib/Roundcube/rcube_addressbook.php
+++ b/program/lib/Roundcube/rcube_addressbook.php
@@ -209,6 +209,7 @@ abstract class rcube_addressbook
public function validate(&$save_data, $autofix = false)
{
$rcube = rcube::get_instance();
+ $valid = true;
// check validity of email addresses
foreach ($this->get_col_values('email', $save_data, true) as $email) {
@@ -216,12 +217,28 @@ abstract class rcube_addressbook
if (!rcube_utils::check_email(rcube_utils::idn_to_ascii($email))) {
$error = $rcube->gettext(array('name' => 'emailformaterror', 'vars' => array('email' => $email)));
$this->set_error(self::ERROR_VALIDATE, $error);
- return false;
+ $valid = false;
+ break;
}
}
}
- return true;
+ // allow plugins to do contact validation and auto-fixing
+ $plugin = $rcube->plugins->exec_hook('contact_validate', array(
+ 'record' => $save_data,
+ 'autofix' => $autofix,
+ 'valid' => $valid,
+ ));
+
+ if ($valid && !$plugin['valid']) {
+ $this->set_error(self::ERROR_VALIDATE, $plugin['error']);
+ }
+
+ if (is_array($plugin['record'])) {
+ $save_data = $plugin['record'];
+ }
+
+ return $plugin['valid'];
}
/**
@@ -515,8 +532,12 @@ abstract class rcube_addressbook
$fn = join(' ', array($contact['surname'], $contact['firstname'], $contact['middlename']));
else if ($compose_mode == 1)
$fn = join(' ', array($contact['firstname'], $contact['middlename'], $contact['surname']));
- else
+ else if ($compose_mode == 0)
$fn = !empty($contact['name']) ? $contact['name'] : join(' ', array($contact['prefix'], $contact['firstname'], $contact['middlename'], $contact['surname'], $contact['suffix']));
+ else {
+ $plugin = rcube::get_instance()->plugins->exec_hook('contact_listname', array('contact' => $contact));
+ $fn = $plugin['fn'];
+ }
$fn = trim($fn, ', ');
diff --git a/program/lib/Roundcube/rcube_contacts.php b/program/lib/Roundcube/rcube_contacts.php
index 6d01368a1..5c9e5ab39 100644
--- a/program/lib/Roundcube/rcube_contacts.php
+++ b/program/lib/Roundcube/rcube_contacts.php
@@ -592,8 +592,8 @@ class rcube_contacts extends rcube_addressbook
// validate e-mail addresses
$valid = parent::validate($save_data, $autofix);
- // require at least one e-mail address (syntax check is already done)
- if ($valid && !array_filter($this->get_col_values('email', $save_data, true))) {
+ // require at least one email address or a name
+ if ($valid && !strlen($save_data['firstname'].$save_data['surname'].$save_data['name']) && !array_filter($this->get_col_values('email', $save_data, true))) {
$this->set_error(self::ERROR_VALIDATE, 'noemailwarning');
$valid = false;
}
diff --git a/program/lib/Roundcube/rcube_html2text.php b/program/lib/Roundcube/rcube_html2text.php
index 6f79e2f8e..01362e6fb 100644
--- a/program/lib/Roundcube/rcube_html2text.php
+++ b/program/lib/Roundcube/rcube_html2text.php
@@ -608,7 +608,7 @@ class rcube_html2text
$this->width = $p_width;
// Add citation markers and create <pre> block
- $body = preg_replace_callback('/((?:^|\n)>*)([^\n]*)/', array($this, 'blockquote_citation_ballback'), trim($body));
+ $body = preg_replace_callback('/((?:^|\n)>*)([^\n]*)/', array($this, 'blockquote_citation_callback'), trim($body));
$body = '<pre>' . htmlspecialchars($body) . '</pre>';
$text = substr_replace($text, $body . "\n", $start, $end + 13 - $start);
@@ -624,7 +624,7 @@ class rcube_html2text
/**
* Callback function to correctly add citation markers for blockquote contents
*/
- public function blockquote_citation_ballback($m)
+ public function blockquote_citation_callback($m)
{
$line = ltrim($m[2]);
$space = $line[0] == '>' ? '' : ' ';
diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php
index 64288f973..b733e2465 100644
--- a/program/lib/Roundcube/rcube_ldap.php
+++ b/program/lib/Roundcube/rcube_ldap.php
@@ -52,7 +52,7 @@ class rcube_ldap extends rcube_addressbook
*
* @var array
*/
- private static $group_types = array(
+ private $group_types = array(
'group' => 'member',
'groupofnames' => 'member',
'kolabgroupofnames' => 'member',
@@ -94,6 +94,9 @@ class rcube_ldap extends rcube_addressbook
$this->prop['groups']['name_attr'] = 'cn';
if (empty($this->prop['groups']['scope']))
$this->prop['groups']['scope'] = 'sub';
+ // extend group objectclass => member attribute mapping
+ if (!empty($this->prop['groups']['class_member_attr']))
+ $this->group_types = array_merge($this->group_types, $this->prop['groups']['class_member_attr']);
// add group name attrib to the list of attributes to be fetched
$fetch_attributes[] = $this->prop['groups']['name_attr'];
@@ -292,6 +295,14 @@ class rcube_ldap extends rcube_addressbook
if ($this->prop['search_base_dn'] && $this->prop['search_filter']
&& (strstr($bind_dn, '%dn') || strstr($this->base_dn, '%dn') || strstr($this->groups_base_dn, '%dn'))
) {
+ $search_attribs = array('uid');
+ if ($search_bind_attrib = (array)$this->prop['search_bind_attrib']) {
+ foreach ($search_bind_attrib as $r => $attr) {
+ $search_attribs[] = $attr;
+ $replaces[$r] = '';
+ }
+ }
+
$search_bind_dn = strtr($this->prop['search_bind_dn'], $replaces);
$search_base_dn = strtr($this->prop['search_base_dn'], $replaces);
$search_filter = strtr($this->prop['search_filter'], $replaces);
@@ -321,10 +332,18 @@ class rcube_ldap extends rcube_addressbook
}
}
- $res = $ldap->search($search_base_dn, $search_filter, 'sub', array('uid'));
+ $res = $ldap->search($search_base_dn, $search_filter, 'sub', $search_attribs);
if ($res) {
$res->rewind();
$replaces['%dn'] = $res->get_dn();
+
+ // add more replacements from 'search_bind_attrib' config
+ if ($search_bind_attrib) {
+ $res = $res->current();
+ foreach ($search_bind_attrib as $r => $attr) {
+ $replaces[$r] = $res[$attr][0];
+ }
+ }
}
if ($ldap != $this->ldap) {
@@ -355,6 +374,23 @@ class rcube_ldap extends rcube_addressbook
$this->base_dn = strtr($this->base_dn, $replaces);
$this->groups_base_dn = strtr($this->groups_base_dn, $replaces);
+ // replace placeholders in filter settings
+ if (!empty($this->prop['filter']))
+ $this->prop['filter'] = strtr($this->prop['filter'], $replaces);
+ if (!empty($this->prop['groups']['filter']))
+ $this->prop['groups']['filter'] = strtr($this->prop['groups']['filter'], $replaces);
+ if (!empty($this->prop['groups']['member_filter']))
+ $this->prop['groups']['member_filter'] = strtr($this->prop['groups']['member_filter'], $replaces);
+
+ if (!empty($this->prop['group_filters'])) {
+ foreach ($this->prop['group_filters'] as $i => $gf) {
+ if (!empty($gf['base_dn']))
+ $this->prop['group_filters'][$i]['base_dn'] = strtr($gf['base_dn'], $replaces);
+ if (!empty($gf['filter']))
+ $this->prop['group_filters'][$i]['filter'] = strtr($gf['filter'], $replaces);
+ }
+ }
+
if (empty($bind_user)) {
$bind_user = $u;
}
@@ -559,9 +595,10 @@ class rcube_ldap extends rcube_addressbook
/**
* Get all members of the given group
*
- * @param string Group DN
- * @param array Group entries (if called recursively)
- * @return array Accumulated group members
+ * @param string Group DN
+ * @param boolean Count only
+ * @param array Group entries (if called recursively)
+ * @return array Accumulated group members
*/
function list_group_members($dn, $count = false, $entries = null)
{
@@ -569,7 +606,7 @@ class rcube_ldap extends rcube_addressbook
// fetch group object
if (empty($entries)) {
- $attribs = array('dn','objectClass','member','uniqueMember','memberURL');
+ $attribs = array_merge(array('dn','objectClass','memberURL'), array_values($this->group_types));
$entries = $this->ldap->read_entries($dn, '(objectClass=*)', $attribs);
if ($entries === false) {
return $group_members;
@@ -581,17 +618,17 @@ class rcube_ldap extends rcube_addressbook
$attrs = array();
foreach ((array)$entry['objectclass'] as $objectclass) {
- if (strtolower($objectclass) == 'groupofurls') {
- $members = $this->_list_group_memberurl($dn, $entry, $count);
- $group_members = array_merge($group_members, $members);
- }
- else if (($member_attr = $this->get_group_member_attr(array($objectclass), ''))
+ if (($member_attr = $this->get_group_member_attr(array($objectclass), ''))
&& ($member_attr = strtolower($member_attr)) && !in_array($member_attr, $attrs)
) {
$members = $this->_list_group_members($dn, $entry, $member_attr, $count);
$group_members = array_merge($group_members, $members);
$attrs[] = $member_attr;
}
+ else if (!empty($entry['memberurl'])) {
+ $members = $this->_list_group_memberurl($dn, $entry, $count);
+ $group_members = array_merge($group_members, $members);
+ }
if ($this->prop['sizelimit'] && count($group_members) > $this->prop['sizelimit']) {
break 2;
@@ -608,6 +645,7 @@ class rcube_ldap extends rcube_addressbook
* @param string Group DN
* @param array Group entry
* @param string Member attribute to use
+ * @param boolean Count only
* @return array Accumulated group members
*/
private function _list_group_members($dn, $entry, $attr, $count)
@@ -621,8 +659,7 @@ class rcube_ldap extends rcube_addressbook
// read these attributes for all members
$attrib = $count ? array('dn','objectClass') : $this->prop['list_attributes'];
- $attrib[] = 'member';
- $attrib[] = 'uniqueMember';
+ $attrib = array_merge($attrib, array_values($this->group_types));
$attrib[] = 'memberURL';
$filter = $this->prop['groups']['member_filter'] ? $this->prop['groups']['member_filter'] : '(objectclass=*)';
@@ -669,7 +706,7 @@ class rcube_ldap extends rcube_addressbook
if ($result = $this->ldap->search($m[1], $filter, $m[2], $attrs, $this->group_data)) {
$entries = $result->entries();
for ($j = 0; $j < $entries['count']; $j++) {
- if (self::is_group_entry($entries[$j]) && ($nested_group_members = $this->list_group_members($entries[$j]['dn'], $count)))
+ if ($this->is_group_entry($entries[$j]) && ($nested_group_members = $this->list_group_members($entries[$j]['dn'], $count)))
$group_members = array_merge($group_members, $nested_group_members);
else
$group_members[] = $entries[$j];
@@ -1354,7 +1391,7 @@ class rcube_ldap extends rcube_addressbook
$out[$this->primary_key] = self::dn_encode($rec['dn']);
// determine record type
- if (self::is_group_entry($rec)) {
+ if ($this->is_group_entry($rec)) {
$out['_type'] = 'group';
$out['readonly'] = true;
$fieldmap['name'] = $this->group_data['name_attr'] ? $this->group_data['name_attr'] : $this->prop['groups']['name_attr'];
@@ -1479,11 +1516,11 @@ class rcube_ldap extends rcube_addressbook
/**
* Determines whether the given LDAP entry is a group record
*/
- private static function is_group_entry($entry)
+ private function is_group_entry($entry)
{
$classes = array_map('strtolower', (array)$entry['objectclass']);
- return count(array_intersect(array_keys(self::$group_types), $classes)) > 0;
+ return count(array_intersect(array_keys($this->group_types), $classes)) > 0;
}
/**
@@ -1914,7 +1951,7 @@ class rcube_ldap extends rcube_addressbook
if (!empty($object_classes)) {
foreach ((array)$object_classes as $oc) {
- if ($attr = self::$group_types[strtolower($oc)]) {
+ if ($attr = $this->group_types[strtolower($oc)]) {
return $attr;
}
}
diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php
index 9c2220328..a931c27c1 100644
--- a/program/lib/Roundcube/rcube_mime.php
+++ b/program/lib/Roundcube/rcube_mime.php
@@ -810,7 +810,7 @@ class rcube_mime
}
$mime_types = $mime_extensions = array();
- $regex = "/([\w\+\-\.\/]+)\t+([\w\s]+)/i";
+ $regex = "/([\w\+\-\.\/]+)\s+([\w\s]+)/i";
foreach((array)$lines as $line) {
// skip comments or mime types w/o any extensions
if ($line[0] == '#' || !preg_match($regex, $line, $matches))
diff --git a/program/lib/Roundcube/rcube_plugin_api.php b/program/lib/Roundcube/rcube_plugin_api.php
index 5a25ada02..2258f1486 100644
--- a/program/lib/Roundcube/rcube_plugin_api.php
+++ b/program/lib/Roundcube/rcube_plugin_api.php
@@ -35,8 +35,9 @@ class rcube_plugin_api
public $url = 'plugins/';
public $task = '';
public $output;
- public $handlers = array();
- public $allowed_prefs = array();
+ public $handlers = array();
+ public $allowed_prefs = array();
+ public $allowed_session_prefs = array();
protected $plugins = array();
protected $tasks = array();
diff --git a/program/lib/Roundcube/rcube_spellcheck_atd.php b/program/lib/Roundcube/rcube_spellcheck_atd.php
index 68e8b7cb8..9f073f56f 100644
--- a/program/lib/Roundcube/rcube_spellcheck_atd.php
+++ b/program/lib/Roundcube/rcube_spellcheck_atd.php
@@ -39,6 +39,18 @@ class rcube_spellcheck_atd extends rcube_spellcheck_engine
);
/**
+ * Return a list of languages supported by this backend
+ *
+ * @see rcube_spellcheck_engine::languages()
+ */
+ function languages()
+ {
+ $langs = array_values($this->langhosts);
+ $langs[] = 'en';
+ return $langs;
+ }
+
+ /**
* Set content and check spelling
*
* @see rcube_spellcheck_engine::check()
diff --git a/program/lib/Roundcube/rcube_spellcheck_enchant.php b/program/lib/Roundcube/rcube_spellcheck_enchant.php
index a22251e00..14d6fff46 100644
--- a/program/lib/Roundcube/rcube_spellcheck_enchant.php
+++ b/program/lib/Roundcube/rcube_spellcheck_enchant.php
@@ -31,6 +31,24 @@ class rcube_spellcheck_enchant extends rcube_spellcheck_engine
private $matches = array();
/**
+ * Return a list of languages supported by this backend
+ *
+ * @see rcube_spellcheck_engine::languages()
+ */
+ function languages()
+ {
+ $this->init();
+
+ $langs = array();
+ $dicts = enchant_broker_list_dicts($this->enchant_broker);
+ foreach ($dicts as $dict) {
+ $langs[] = preg_replace('/-.*$/', '', $dict['lang_tag']);
+ }
+
+ return array_unique($langs);
+ }
+
+ /**
* Initializes Enchant dictionary
*/
private function init()
diff --git a/program/lib/Roundcube/rcube_spellcheck_engine.php b/program/lib/Roundcube/rcube_spellcheck_engine.php
index 88e10ac05..3cb4ca3de 100644
--- a/program/lib/Roundcube/rcube_spellcheck_engine.php
+++ b/program/lib/Roundcube/rcube_spellcheck_engine.php
@@ -43,6 +43,13 @@ abstract class rcube_spellcheck_engine
}
/**
+ * Return a list of languages supported by this backend
+ *
+ * @return array Indexed list of language codes
+ */
+ abstract function languages();
+
+ /**
* Set content and check spelling
*
* @param string $text Text content for spellchecking
diff --git a/program/lib/Roundcube/rcube_spellcheck_googie.php b/program/lib/Roundcube/rcube_spellcheck_googie.php
index 70507dc23..3777942a6 100644
--- a/program/lib/Roundcube/rcube_spellcheck_googie.php
+++ b/program/lib/Roundcube/rcube_spellcheck_googie.php
@@ -26,13 +26,28 @@
*/
class rcube_spellcheck_googie extends rcube_spellcheck_engine
{
- const GOOGLE_HOST = 'ssl://www.google.com';
- const GOOGLE_PORT = 443;
+ const GOOGIE_HOST = 'ssl://spell.roundcube.net';
+ const GOOGIE_PORT = 443;
private $matches = array();
private $content;
/**
+ * Return a list of languages supported by this backend
+ *
+ * @see rcube_spellcheck_engine::languages()
+ */
+ function languages()
+ {
+ return array('am','ar','ar','bg','br','ca','cs','cy','da',
+ 'de_CH','de_DE','el','en_GB','en_US',
+ 'eo','es','et','eu','fa','fi','fr_FR','ga','gl','gl',
+ 'he','hr','hu','hy','is','it','ku','lt','lv','nl',
+ 'pl','pt_BR','pt_PT','ro','ru',
+ 'sk','sl','sv','uk');
+ }
+
+ /**
* Set content and check spelling
*
* @see rcube_spellcheck_engine::check()
@@ -52,25 +67,25 @@ class rcube_spellcheck_googie extends rcube_spellcheck_engine
$path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '') . $this->lang;
}
else {
- $host = self::GOOGLE_HOST;
- $port = self::GOOGLE_PORT;
+ $host = self::GOOGIE_HOST;
+ $port = self::GOOGIE_PORT;
$path = '/tbproxy/spell?lang=' . $this->lang;
}
- // Google has some problem with spaces, use \n instead
- $gtext = str_replace(' ', "\n", $text);
+ $path .= sprintf('&key=%06d', $_SESSION['user_id']);
$gtext = '<?xml version="1.0" encoding="utf-8" ?>'
.'<spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1">'
- .'<text>' . $gtext . '</text>'
+ .'<text>' . htmlspecialchars($text, ENT_QUOTES, RCUBE_CHARSET) . '</text>'
.'</spellrequest>';
$store = '';
if ($fp = fsockopen($host, $port, $errno, $errstr, 30)) {
$out = "POST $path HTTP/1.0\r\n";
$out .= "Host: " . str_replace('ssl://', '', $host) . "\r\n";
+ $out .= "User-Agent: Roundcube Webmail/" . RCMAIL_VERSION . " (Googiespell Wrapper)\r\n";
$out .= "Content-Length: " . strlen($gtext) . "\r\n";
- $out .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $out .= "Content-Type: text/xml\r\n";
$out .= "Connection: Close\r\n\r\n";
$out .= $gtext;
fwrite($fp, $out);
@@ -83,8 +98,10 @@ class rcube_spellcheck_googie extends rcube_spellcheck_engine
// parse HTTP response
if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $store, $m)) {
$http_status = $m[1];
- if ($http_status != '200')
+ if ($http_status != '200') {
$this->error = 'HTTP ' . $m[1] . $m[2];
+ $this->error .= "\n" . $store;
+ }
}
if (!$store) {
@@ -92,6 +109,7 @@ class rcube_spellcheck_googie extends rcube_spellcheck_engine
}
else if (preg_match('/<spellresult error="([^"]+)"/', $store, $m) && $m[1]) {
$this->error = "Error code $m[1] returned";
+ $this->error .= preg_match('/<errortext>([^<]+)/', $store, $m) ? ": " . html_entity_decode($m[1]) : '';
}
preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER);
diff --git a/program/lib/Roundcube/rcube_spellcheck_pspell.php b/program/lib/Roundcube/rcube_spellcheck_pspell.php
index ce089ed8f..b12684e43 100644
--- a/program/lib/Roundcube/rcube_spellcheck_pspell.php
+++ b/program/lib/Roundcube/rcube_spellcheck_pspell.php
@@ -30,6 +30,35 @@ class rcube_spellcheck_pspell extends rcube_spellcheck_engine
private $matches = array();
/**
+ * Return a list of languages supported by this backend
+ *
+ * @see rcube_spellcheck_engine::languages()
+ */
+ function languages()
+ {
+ $defaults = array('en');
+ $langs = array();
+
+ // get aspell dictionaries
+ exec('aspell dump dicts', $dicts);
+ if (!empty($dicts)) {
+ $seen = array();
+ foreach ($dicts as $lang) {
+ $lang = preg_replace('/-.*$/', '', $lang);
+ $langc = strlen($lang) == 2 ? $lang.'_'.strtoupper($lang) : $lang;
+ if (!$seen[$langc]++)
+ $langs[] = $lang;
+ }
+ $langs = array_unique($langs);
+ }
+ else {
+ $langs = $defaults;
+ }
+
+ return $langs;
+ }
+
+ /**
* Initializes PSpell dictionary
*/
private function init()
diff --git a/program/lib/Roundcube/rcube_spellchecker.php b/program/lib/Roundcube/rcube_spellchecker.php
index 31835dbb5..3182ff378 100644
--- a/program/lib/Roundcube/rcube_spellchecker.php
+++ b/program/lib/Roundcube/rcube_spellchecker.php
@@ -65,6 +65,52 @@ class rcube_spellchecker
}
}
+ /**
+ * Return a list of supported languages
+ */
+ function languages()
+ {
+ // trust configuration
+ $configured = $this->rc->config->get('spellcheck_languages');
+ if (!empty($configured) && is_array($configured) && !$configured[0]) {
+ return $configured;
+ }
+ else if (!empty($configured)) {
+ $langs = (array)$configured;
+ }
+ else if ($this->backend) {
+ $langs = $this->backend->languages();
+ }
+
+ // load index
+ @include(RCUBE_LOCALIZATION_DIR . 'index.inc');
+
+ // add correct labels
+ $languages = array();
+ foreach ($langs as $lang) {
+ $langc = strtolower(substr($lang, 0, 2));
+ $alias = $rcube_language_aliases[$langc];
+ if (!$alias) {
+ $alias = $langc.'_'.strtoupper($langc);
+ }
+ if ($rcube_languages[$lang]) {
+ $languages[$lang] = $rcube_languages[$lang];
+ }
+ else if ($rcube_languages[$alias]) {
+ $languages[$lang] = $rcube_languages[$alias];
+ }
+ else {
+ $languages[$lang] = ucfirst($lang);
+ }
+ }
+
+ // remove possible duplicates (#1489395)
+ $languages = array_unique($languages);
+
+ asort($languages);
+
+ return $languages;
+ }
/**
* Set content and check spelling
@@ -152,7 +198,7 @@ class rcube_spellchecker
// send output
$out = '<?xml version="1.0" encoding="'.RCUBE_CHARSET.'"?><spellresult charschecked="'.mb_strlen($this->content).'">';
- foreach ($this->matches as $item) {
+ foreach ((array)$this->matches as $item) {
$out .= '<c o="'.$item[1].'" l="'.$item[2].'">';
$out .= is_array($item[4]) ? implode("\t", $item[4]) : $item[4];
$out .= '</c>';
@@ -173,7 +219,7 @@ class rcube_spellchecker
{
$result = array();
- foreach ($this->matches as $item) {
+ foreach ((array)$this->matches as $item) {
if ($this->engine == 'pspell') {
$word = $item[0];
}
diff --git a/program/lib/Roundcube/rcube_user.php b/program/lib/Roundcube/rcube_user.php
index 5e9c9af80..57f63361d 100644
--- a/program/lib/Roundcube/rcube_user.php
+++ b/program/lib/Roundcube/rcube_user.php
@@ -163,8 +163,16 @@ class rcube_user
if (!$this->ID)
return false;
- $config = $this->rc->config;
- $old_prefs = (array)$this->get_prefs();
+ $plugin = $this->rc->plugins->exec_hook('preferences_update', array(
+ 'userid' => $this->ID, 'prefs' => $a_user_prefs, 'old' => (array)$this->get_prefs()));
+
+ if (!empty($plugin['abort'])) {
+ return;
+ }
+
+ $a_user_prefs = $plugin['prefs'];
+ $old_prefs = $plugin['old'];
+ $config = $this->rc->config;
// merge (partial) prefs array with existing settings
$save_prefs = $a_user_prefs + $old_prefs;
diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php
index b73bc0812..27a618d83 100644
--- a/program/lib/Roundcube/rcube_utils.php
+++ b/program/lib/Roundcube/rcube_utils.php
@@ -454,6 +454,9 @@ class rcube_utils
// cut out all contents between { and }
while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) {
+ $nested = strpos($source, '{', $pos+1);
+ if ($nested && $nested < $pos2) // when dealing with nested blocks (e.g. @media), take the inner one
+ $pos = $nested;
$length = $pos2 - $pos - 1;
$styles = substr($source, $pos+1, $length);
@@ -744,40 +747,13 @@ class rcube_utils
*/
public static function strtotime($date)
{
- $date = trim($date);
-
- // check for MS Outlook vCard date format YYYYMMDD
- if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) {
- return mktime(0,0,0, intval($m[2]), intval($m[3]), intval($m[1]));
- }
-
- // common little-endian formats, e.g. dd/mm/yyyy (not all are supported by strtotime)
- if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m)
- && $m[1] > 0 && $m[1] <= 31 && $m[2] > 0 && $m[2] <= 12 && $m[3] >= 1970
- ) {
- return mktime(0,0,0, intval($m[2]), intval($m[1]), intval($m[3]));
- }
+ $date = self::clean_datestr($date);
// unix timestamp
if (is_numeric($date)) {
return (int) $date;
}
- // Clean malformed data
- $date = preg_replace(
- array(
- '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal
- '/[^a-z0-9\x20\x09:+-]/i', // remove any invalid characters
- '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names
- ),
- array(
- '\\1',
- '',
- '',
- ), $date);
-
- $date = trim($date);
-
// if date parsing fails, we have a date in non-rfc format.
// remove token from the end and try again
while ((($ts = @strtotime($date)) === false) || ($ts < 0)) {
@@ -805,8 +781,8 @@ class rcube_utils
return $date;
}
- $dt = false;
- $date = trim($date);
+ $dt = false;
+ $date = self::clean_datestr($date);
// try to parse string with DateTime first
if (!empty($date)) {
@@ -831,6 +807,52 @@ class rcube_utils
return $dt;
}
+ /**
+ * Clean up date string for strtotime() input
+ *
+ * @param string $date Date string
+ *
+ * @return string Date string
+ */
+ public static function clean_datestr($date)
+ {
+ $date = trim($date);
+
+ // check for MS Outlook vCard date format YYYYMMDD
+ if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) {
+ return sprintf('%04d-%02d-%02d 00:00:00', intval($m[1]), intval($m[2]), intval($m[3]));
+ }
+
+ // Clean malformed data
+ $date = preg_replace(
+ array(
+ '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal
+ '/[^a-z0-9\x20\x09:+-\/]/i', // remove any invalid characters
+ '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names
+ ),
+ array(
+ '\\1',
+ '',
+ '',
+ ), $date);
+
+ $date = trim($date);
+
+ // try to fix dd/mm vs. mm/dd discrepancy, we can't do more here
+ if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m)) {
+ $mdy = $m[2] > 12 && $m[1] <= 12;
+ $day = $mdy ? $m[2] : $m[1];
+ $month = $mdy ? $m[1] : $m[2];
+ $date = sprintf('%04d-%02d-%02d 00:00:00', intval($m[3]), $month, $day);
+ }
+ // I've found that YYYY.MM.DD is recognized wrong, so here's a fix
+ else if (preg_match('/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/', $date)) {
+ $date = str_replace('.', '-', $date) . ' 00:00:00';
+ }
+
+ return $date;
+ }
+
/*
* Idn_to_ascii wrapper.
* Intl/Idn modules version of this function doesn't work with e-mail address
diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php
index d54dc56ad..5f74ccbd4 100644
--- a/program/lib/Roundcube/rcube_vcard.php
+++ b/program/lib/Roundcube/rcube_vcard.php
@@ -518,20 +518,28 @@ class rcube_vcard
*/
public static function cleanup($vcard)
{
- // Convert special types (like Skype) to normal type='skype' classes with this simple regex ;)
- $vcard = preg_replace(
- '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
- '\2;type=\5\3:\4',
- $vcard);
-
// convert Apple X-ABRELATEDNAMES into X-* fields for better compatibility
$vcard = preg_replace_callback(
'/item(\d+)\.(X-ABRELATEDNAMES)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
array('self', 'x_abrelatednames_callback'),
$vcard);
- // Remove cruft like item1.X-AB*, item1.ADR instead of ADR, and empty lines
- $vcard = preg_replace(array('/^item\d*\.X-AB.*$/m', '/^item\d*\./m', "/\n+/"), array('', '', "\n"), $vcard);
+ // Cleanup
+ $vcard = preg_replace(array(
+ // convert special types (like Skype) to normal type='skype' classes with this simple regex ;)
+ '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
+ '/^item\d*\.X-AB.*$/m', // remove cruft like item1.X-AB*
+ '/^item\d*\./m', // remove item1.ADR instead of ADR
+ '/\n+/', // remove empty lines
+ '/^(N:[^;\R]*)$/m', // if N doesn't have any semicolons, add some
+ ),
+ array(
+ '\2;type=\5\3:\4',
+ '',
+ '',
+ "\n",
+ '\1;;;;',
+ ), $vcard);
// convert X-WAB-GENDER to X-GENDER
if (preg_match('/X-WAB-GENDER:(\d)/', $vcard, $matches)) {
@@ -539,9 +547,6 @@ class rcube_vcard
$vcard = preg_replace('/X-WAB-GENDER:\d/', 'X-GENDER:' . $value, $vcard);
}
- // if N doesn't have any semicolons, add some
- $vcard = preg_replace('/^(N:[^;\R]*)$/m', '\1;;;;', $vcard);
-
return $vcard;
}
@@ -612,8 +617,8 @@ class rcube_vcard
$enc = null;
foreach($regs2[1] as $attrid => $attr) {
+ $attr = preg_replace('/[\s\t\n\r\0\x0B]/', '', $attr);
if ((list($key, $value) = explode('=', $attr)) && $value) {
- $value = trim($value);
if ($key == 'ENCODING') {
$value = strtoupper($value);
// add next line(s) to value string if QP line end detected
@@ -792,7 +797,7 @@ class rcube_vcard
return $result;
}
- $s = strtr($s, $rep2);
+ $s = trim(strtr($s, $rep2));
}
// some implementations (GMail) use non-standard backslash before colon (#1489085)
diff --git a/program/localization/be_BE/labels.inc b/program/localization/be_BE/labels.inc
index b5a3ed6d8..549c315a6 100644
--- a/program/localization/be_BE/labels.inc
+++ b/program/localization/be_BE/labels.inc
@@ -29,7 +29,7 @@ $labels['drafts'] = 'Чарнавікі';
$labels['sent'] = 'Дасланыя';
$labels['trash'] = 'Сметніца';
$labels['junk'] = 'Спам';
-$labels['show_real_foldernames'] = 'Паказваць сапраўдныя імёны для адмысловых папак';
+$labels['show_real_foldernames'] = 'Паказваць сапраўдныя назвы для адмысловых папак';
$labels['subject'] = 'Тэма';
$labels['from'] = 'Ад каго';
$labels['sender'] = 'Адпраўнік';
@@ -44,7 +44,7 @@ $labels['priority'] = 'Прыярытэт';
$labels['organization'] = 'Установа';
$labels['readstatus'] = 'Не прачытанае';
$labels['listoptions'] = 'Параметры спісу...';
-$labels['mailboxlist'] = 'Тэчкі';
+$labels['mailboxlist'] = 'Папкі';
$labels['messagesfromto'] = 'Паведамленні $from—$to з $count';
$labels['threadsfromto'] = 'Абмеркаванні $from—$to з $count';
$labels['messagenrof'] = 'Паведамленне $nr з $count';
@@ -52,11 +52,11 @@ $labels['fromtoshort'] = '$from—$to з $count';
$labels['copy'] = 'Капіраваць';
$labels['move'] = 'Перамясціць';
$labels['moveto'] = 'Перамясціць у...';
-$labels['download'] = 'Спампаваць';
-$labels['open'] = 'Адчыніць';
+$labels['download'] = 'Сцягнуць';
+$labels['open'] = 'Адкрыць';
$labels['showattachment'] = 'Паказаць';
$labels['showanyway'] = 'Усё адно паказваць';
-$labels['filename'] = 'Імя файла';
+$labels['filename'] = 'Назва файла';
$labels['filesize'] = 'Памер файла';
$labels['addtoaddressbook'] = 'Дадаць у адрасную кнігу';
$labels['sun'] = 'нд';
@@ -177,8 +177,8 @@ $labels['msgtext'] = 'Усё паведамленне';
$labels['body'] = 'Цела';
$labels['type'] = 'Тып';
$labels['namex'] = 'Імя';
-$labels['openinextwin'] = 'Адчыніць у новым акне';
-$labels['emlsave'] = 'Спампаваць (.eml)';
+$labels['openinextwin'] = 'Адкрыць у новым акне';
+$labels['emlsave'] = 'Сцягнуць (.eml)';
$labels['changeformattext'] = 'Паказаць як просты тэкст';
$labels['changeformathtml'] = 'Паказаць як HTML';
$labels['editasnew'] = 'Адрэдагаваць як новае';
@@ -197,11 +197,19 @@ $labels['spellcheck'] = 'Правапіс';
$labels['checkspelling'] = 'Праверыць правапіс';
$labels['resumeediting'] = 'Працягнуць рэдагаванне';
$labels['revertto'] = 'Адкаціцца на';
+$labels['responses'] = 'Адказы';
+$labels['insertresponse'] = 'Уставіць адказ';
+$labels['manageresponses'] = 'Кіраваць адказамі';
+$labels['savenewresponse'] = 'Захаваць новы адказ';
+$labels['editresponses'] = 'Рэдагаваць адказы';
+$labels['editresponse'] = 'Рэдагаваць адказ';
+$labels['responsename'] = 'Назва';
+$labels['responsetext'] = 'Тэкст адказу';
$labels['attach'] = 'Далучыць';
$labels['attachments'] = 'Далучэнні';
-$labels['upload'] = 'Запампаваць';
+$labels['upload'] = 'Апублікаваць';
$labels['uploadprogress'] = '$percent ($current з $total)';
-$labels['close'] = 'Зачыніць';
+$labels['close'] = 'Закрыць';
$labels['messageoptions'] = 'Параметры паведамлення...';
$labels['low'] = 'Нізкі';
$labels['lowest'] = 'Найнізшы';
@@ -228,7 +236,7 @@ $labels['mdnrequest'] = 'Адпраўнік пажадаў даведацца а
$labels['receiptread'] = 'Пацверджанне атрымання (прачытання)';
$labels['yourmessage'] = 'Гэта пацверджанне аб атрыманні вашага паведамлення';
$labels['receiptnote'] = 'Заўвага: Гэтае пацверджанне значыць адно, што паведамленне было адлюстравана на экране кампутара адрасата. Няма гарантыі, што атрымальнік прачытаў альбо зразумеў змест паведамлення.';
-$labels['name'] = 'Экраннае імя';
+$labels['name'] = 'Экранная назва';
$labels['firstname'] = 'Імя';
$labels['surname'] = 'Прозвішча';
$labels['middlename'] = 'Другое імя';
@@ -286,10 +294,10 @@ $labels['edit'] = 'Рэдагаваць';
$labels['cancel'] = 'Скасаваць';
$labels['save'] = 'Захаваць';
$labels['delete'] = 'Выдаліць';
-$labels['rename'] = 'Перайменаваць';
+$labels['rename'] = 'Пераназваць';
$labels['addphoto'] = 'Дадаць';
$labels['replacephoto'] = 'Замяніць';
-$labels['uploadphoto'] = 'Запампаваць фота';
+$labels['uploadphoto'] = 'Апублікаваць фота';
$labels['newcontact'] = 'Стварыць новую картку кантакта';
$labels['deletecontact'] = 'Выдаліць абраных кантактаў';
$labels['composeto'] = 'Скласці ліст да';
@@ -300,7 +308,7 @@ $labels['exportall'] = 'Экспартаваць усё';
$labels['exportsel'] = 'Экспартаваць абранае';
$labels['exportvcards'] = 'Экспартаваць кантакты ў фармаце vCard';
$labels['newcontactgroup'] = 'Стварыць новую групу кантактаў';
-$labels['grouprename'] = 'Перайменаваць групу';
+$labels['grouprename'] = 'Пераназваць групу';
$labels['groupdelete'] = 'Выдаліць групу';
$labels['groupremoveselected'] = 'Выдаліць абраных кантакаў з групы';
$labels['previouspage'] = 'Папярэдняя старонка';
@@ -321,7 +329,7 @@ $labels['importreplace'] = 'Замяніць адрасную кнігу цал
$labels['importgroups'] = 'Імпартаваць прызначэнні групы';
$labels['importgroupsall'] = 'Усе (стварыць групы пры неабходнасці)';
$labels['importgroupsexisting'] = 'Толькі для існуючых груп';
-$labels['importdesc'] = 'Кантакты можна запампаваць з існуючай адраснай кнігі.<br/>На дадзены момант падтрымліваюцца адрасы ў фарматах <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> і CSV (значэнні цераз коску).';
+$labels['importdesc'] = 'Кантакты можна загрузіць з існуючай адраснай кнігі.<br/>На дадзены момант падтрымліваюцца адрасы ў фарматах <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> і CSV (значэнні праз коску).';
$labels['done'] = 'Гатова';
$labels['settingsfor'] = 'Настаўленні для';
$labels['about'] = 'Апісанне';
@@ -348,13 +356,13 @@ $labels['timezone'] = 'Часавая зона';
$labels['pagesize'] = 'Радкоў на старонку';
$labels['signature'] = 'Подпіс';
$labels['dstactive'] = 'Летні/зімовы час';
-$labels['showinextwin'] = 'Адчыняць паведамленне ў новым акне';
+$labels['showinextwin'] = 'Адкрываць паведамленні ў новым акне';
$labels['composeextwin'] = 'Складаць у новым акне';
$labels['htmleditor'] = 'Складаць паведамленні ў HTML';
$labels['htmlonreply'] = 'у адказ на паведамленні ў HTML';
$labels['htmlonreplyandforward'] = 'пры перасылцы альбо ў адказ на паведамленні ў HTML';
$labels['htmlsignature'] = 'Подпіс у HTML';
-$labels['showemail'] = 'Паказваць адрас электроннай пошты разам з экранным імем';
+$labels['showemail'] = 'Паказваць адрас электроннай пошты разам з экраннай назвай';
$labels['previewpane'] = 'Панэль прагляду';
$labels['skin'] = 'Тэма інтэрфейсу';
$labels['logoutclear'] = 'Ачышчаць Сметніцу па выхадзе';
@@ -384,7 +392,7 @@ $labels['never'] = 'ніколі';
$labels['immediately'] = 'імгненна';
$labels['messagesdisplaying'] = 'Адлюстраванне паведамленняў';
$labels['messagescomposition'] = 'Складанне паведамленняў';
-$labels['mimeparamfolding'] = 'Імёны далучэнняў';
+$labels['mimeparamfolding'] = 'Назвы далучэнняў';
$labels['2231folding'] = 'Поўны RFC 2231 (Thunderbird)';
$labels['miscfolding'] = 'RFC 2047/2231 (MS Outlook)';
$labels['2047folding'] = 'Поўны RFC 2047 (інш.)';
@@ -429,7 +437,7 @@ $labels['forwardmode'] = 'Перасылка паведамленняў';
$labels['inline'] = 'у тэксце';
$labels['asattachment'] = 'як далучэнне';
$labels['folder'] = 'Папка';
-$labels['folders'] = 'Тэчкі';
+$labels['folders'] = 'Папкі';
$labels['foldername'] = 'Назва папкі';
$labels['subscribed'] = 'Падпісаная';
$labels['messagecount'] = 'Паведамленні';
diff --git a/program/localization/be_BE/messages.inc b/program/localization/be_BE/messages.inc
index 4b2f07a2f..5833fd8a4 100644
--- a/program/localization/be_BE/messages.inc
+++ b/program/localization/be_BE/messages.inc
@@ -35,8 +35,8 @@ $messages['loggedout'] = 'Сесія скасавана. Да пабачэння
$messages['mailboxempty'] = 'У скрынцы пуста.';
$messages['refreshing'] = 'Абнаўляецца...';
$messages['loading'] = 'Загружаецца...';
-$messages['uploading'] = 'Файл запампоўваюцца...';
-$messages['uploadingmany'] = 'Файлы запампоўваюцца...';
+$messages['uploading'] = 'Файл зацягваецца...';
+$messages['uploadingmany'] = 'Файлы зацягваюцца...';
$messages['loadingdata'] = 'Загружаюцца даныя...';
$messages['checkingmail'] = 'Праверка новых паведамленняў...';
$messages['sendingmessage'] = 'Паведамленне адпраўляецца...';
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Паведамленні адпраўлены.';
$messages['savingmessage'] = 'Паведамленне захоўваецца...';
$messages['messagesaved'] = 'Паведамленне захавана ў Чарнавікі.';
$messages['successfullysaved'] = 'Захавана.';
+$messages['savingresponse'] = 'Тэкст адказу захоўваецца...';
+$messages['deleteresponseconfirm'] = 'Напраўду выдаліць тэкст адказу?';
$messages['addedsuccessfully'] = 'Кантакт дададзены ў адрасную кнігу.';
$messages['contactexists'] = 'Кантакт з такім самым адрасам эл. пошты ўжо існуе.';
$messages['contactnameexists'] = 'Кантакт з такім самым імем ужо існуе.';
@@ -82,7 +84,7 @@ $messages['nobodywarning'] = 'Адправіць гэта паведамленн
$messages['notsentwarning'] = 'Паведамленне не адпраўлена. Жадаеце скасаваць сваё паведамленне?';
$messages['noldapserver'] = 'Задайце ldap-сервер для пошуку.';
$messages['nosearchname'] = 'Задайце імя кантакта альбо адрас электроннай пошты.';
-$messages['notuploadedwarning'] = 'Не ўсе далучэнні пакуль яшчэ запампаваныя. Пачакайце альбо скасуйце аперацыю.';
+$messages['notuploadedwarning'] = 'Не ўсе далучэнні пакуль яшчэ зацягнутыя. Пачакайце альбо скасуйце аперацыю.';
$messages['searchsuccessful'] = 'Знойдзена $nr паведамленняў.';
$messages['contactsearchsuccessful'] = 'Знойдзена $nr кантактаў.';
$messages['searchnomatch'] = 'Пошук не даў выніку.';
@@ -97,8 +99,8 @@ $messages['folderexpunged'] = 'Папка сціснута. ';
$messages['deletedsuccessfully'] = 'Выдалена.';
$messages['converting'] = 'Фарматаванне выдаляецца...';
$messages['messageopenerror'] = 'Не ўдалося загрузіць паведамленне з сервера.';
-$messages['fileuploaderror'] = 'Не ўдалося запампаваць файл.';
-$messages['filesizeerror'] = 'Запампаваны файл перавышае максімальна дазволены памер $size.';
+$messages['fileuploaderror'] = 'Не ўдалося зацягнуць файл.';
+$messages['filesizeerror'] = 'Зацягнуты файл перавышае максімальна дазволены памер $size.';
$messages['copysuccess'] = '$nr кантактаў скапіявана.';
$messages['movesuccess'] = '$nr кантактаў перамешчана.';
$messages['copyerror'] = 'Не ўдалося скапіяваць ніводнага кантакта.';
@@ -118,17 +120,17 @@ $messages['errorsendingreceipt'] = 'Не ўдалося адправіць па
$messages['deleteidentityconfirm'] = 'Напраўду выдаліць гэтую тоеснасць?';
$messages['nodeletelastidentity'] = 'Гэтую тоеснасць выдаліць няможна, бо апошняя.';
$messages['forbiddencharacter'] = 'Назва папкі змяшчае забаронены знак.';
-$messages['selectimportfile'] = 'Абярыце файл на запампоўку.';
+$messages['selectimportfile'] = 'Абярыце файл да зацягвання.';
$messages['addresswriterror'] = 'Абраная адрасная кніга ёсць толькі-для-чытання.';
$messages['contactaddedtogroup'] = 'Кантакты дададзены ў групу.';
$messages['contactremovedfromgroup'] = 'Кантакты выдаленыя з групы.';
$messages['nogroupassignmentschanged'] = 'Усе прызначэнні групы засталіся без зменаў.';
$messages['importwait'] = 'Ідзе імпартаванне. Чакайце...';
-$messages['importformaterror'] = 'Імпартаванне не ўдалося! Запампаваны файл не ўтрымоўвае слушных даных на імпарт.';
+$messages['importformaterror'] = 'Імпартаванне не ўдалося! Загружаны файл не ўтрымоўвае слушных даных на імпарт.';
$messages['importconfirm'] = '<b>$inserted кантактаў імпартаваныя</b>';
$messages['importconfirmskipped'] = '<b>Прапушчана $skipped існуючых запісаў</b>';
$messages['importmessagesuccess'] = '$nr паведамленняў імпартавана';
-$messages['importmessageerror'] = 'Не ўдалося імпартаваць! Запампаваны файл не ёсць слушным паведамленнем альбо файлам паштовай скрынкі';
+$messages['importmessageerror'] = 'Не ўдалося імпартаваць! Загружаны файл не ёсць слушным паведамленнем альбо файлам паштовай скрынкі';
$messages['opnotpermitted'] = 'Аперацыя не дазволеная!';
$messages['nofromaddress'] = 'У абранай тоеснасці не стае адрасу эл. пошты.';
$messages['editorwarning'] = 'Змена рэдактара прывядзе да страты фарматавання. Працягнуць?';
diff --git a/program/localization/bg_BG/labels.inc b/program/localization/bg_BG/labels.inc
index 29c99e8f4..0394f19b9 100644
--- a/program/localization/bg_BG/labels.inc
+++ b/program/localization/bg_BG/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Правопис';
$labels['checkspelling'] = 'Проверка на правописа';
$labels['resumeediting'] = 'Продължи черновата';
$labels['revertto'] = 'Върни се към';
+$labels['responses'] = 'Отговори';
+$labels['insertresponse'] = 'Вмъкване на отговори';
+$labels['manageresponses'] = 'Настройка на отговори';
+$labels['savenewresponse'] = 'Запис на нов отговор';
+$labels['editresponses'] = 'Редакция на отговори';
+$labels['editresponse'] = 'Редакция на отговор';
+$labels['responsename'] = 'Име';
+$labels['responsetext'] = 'Текст на отговор';
$labels['attach'] = 'Прикачи';
$labels['attachments'] = 'Прикачени файлове';
$labels['upload'] = 'Качи';
diff --git a/program/localization/bg_BG/messages.inc b/program/localization/bg_BG/messages.inc
index 210eda1b1..48e1fbcc0 100644
--- a/program/localization/bg_BG/messages.inc
+++ b/program/localization/bg_BG/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Писмото е изпратено успешно.
$messages['savingmessage'] = 'Записване на писмо...';
$messages['messagesaved'] = 'Писмото е записано в Чернови.';
$messages['successfullysaved'] = 'Успешен запис.';
+$messages['savingresponse'] = 'Записване текст на отговор...';
+$messages['deleteresponseconfirm'] = 'Желаете ли да изтриете текст за отговор?';
$messages['addedsuccessfully'] = 'Контактът е добавен в адресната книга.';
$messages['contactexists'] = 'Вече съществува контакт с този e-mail адрес.';
$messages['contactnameexists'] = 'Вече съществува контакт с това име.';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'Търсеният контакт не е нам
$messages['contactsearchonly'] = 'Използвайте полето за да търсите контакти';
$messages['sendingfailed'] = 'Неуспешно изпращане на писмо.';
$messages['senttooquickly'] = 'Моля изчакайте $sec секунди преди да изпратите писмото.';
+$messages['errorsavingsent'] = 'Възникна грешка при записване на изпратеното писмо.';
+$messages['errorsaving'] = 'Възникна грешка при записването.';
$messages['errormoving'] = 'Писмото не може да бъде преместено.';
$messages['errorcopying'] = 'Писмото не може да бъде копирано.';
$messages['errordeleting'] = 'Писмото не може да бъде изтрито.';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'SMTP грешка: $msg';
$messages['emailformaterror'] = 'Невалиден e-mail адрес: $email';
$messages['toomanyrecipients'] = 'Прекалено много адреси за изпращане (максимум: $max).';
$messages['maxgroupmembersreached'] = 'Броят на членовете на групата е повече от максималния: $max.';
+$messages['internalerror'] = 'Възникна вътрешна грешка. Моля опитайте отново.';
$messages['contactdelerror'] = 'Невъзможно изтриване на контакти.';
$messages['contactdeleted'] = 'Контактът беше изтрит успешно.';
$messages['contactrestoreerror'] = 'Неуспешно възстановяване на изтрите контакти.';
diff --git a/program/localization/bs_BA/messages.inc b/program/localization/bs_BA/messages.inc
index 3424013c5..9e0f083ff 100644
--- a/program/localization/bs_BA/messages.inc
+++ b/program/localization/bs_BA/messages.inc
@@ -54,6 +54,8 @@ $messages['contactnotfound'] = 'Traženi kontakt nije pronađen.';
$messages['contactsearchonly'] = 'Unesite neki pojam za pretragu';
$messages['sendingfailed'] = 'Greška pri slanju poruke.';
$messages['senttooquickly'] = 'Molimo sačekajte $sec sekundi prije slanja ove poruke.';
+$messages['errorsavingsent'] = 'Desila se greška pri snimanju poslane poruke.';
+$messages['errorsaving'] = 'Desila se greška pri snimanju.';
$messages['errormoving'] = 'Nije moguće premjestiti poruke.';
$messages['errorcopying'] = 'Nije moguće kopirati poruke.';
$messages['errordeleting'] = 'Nije moguće obrisati poruke.';
@@ -140,6 +142,7 @@ $messages['smtperror'] = 'SMTP greška: $msg';
$messages['emailformaterror'] = 'Netačna email adresa: $email';
$messages['toomanyrecipients'] = 'Previše primaoca. Smanjite broj primaoca na $max.';
$messages['maxgroupmembersreached'] = 'Broj članova grupe prelazi maksimum od $max.';
+$messages['internalerror'] = 'Dogodila se interna greška. Molimo vas da pokušate ponovo.';
$messages['contactdelerror'] = 'Kontakti ne mogu biti obrisani.';
$messages['contactdeleted'] = 'Kontakti su uspješno obrisani.';
$messages['contactrestoreerror'] = 'Nije moguće vratiti obrisane kontakte.';
diff --git a/program/localization/ca_ES/labels.inc b/program/localization/ca_ES/labels.inc
index 065431fbc..a93b18434 100644
--- a/program/localization/ca_ES/labels.inc
+++ b/program/localization/ca_ES/labels.inc
@@ -175,14 +175,14 @@ $labels['resetsearch'] = 'Neteja cerca';
$labels['searchmod'] = 'Cerca modificadors';
$labels['msgtext'] = 'Missatge sencer';
$labels['body'] = 'Cos';
-$labels['type'] = 'tipus:';
+$labels['type'] = 'Tipus';
$labels['namex'] = 'Nom';
$labels['openinextwin'] = 'Obre a una nova finestra';
$labels['emlsave'] = 'Descarrega (.eml)';
$labels['changeformattext'] = 'Mostra en format de text net';
$labels['changeformathtml'] = 'Mostra en format HTML';
$labels['editasnew'] = 'Edita com a nou';
-$labels['send'] = 'Enviar';
+$labels['send'] = 'Envia';
$labels['sendmessage'] = 'Envia el missatge';
$labels['savemessage'] = 'Desa aquest esborrany';
$labels['addattachment'] = 'Adjunta un fitxer';
@@ -316,7 +316,11 @@ $labels['searchdelete'] = 'Suprimeix la cerca';
$labels['import'] = 'Importa';
$labels['importcontacts'] = 'Importa contactes';
$labels['importfromfile'] = 'Importa des d\'un fitxer:';
+$labels['importtarget'] = 'Afegeix contactes a';
$labels['importreplace'] = 'Reemplaça la llibreta d\'adreçes sencera';
+$labels['importgroups'] = 'Importa assignacions de grup';
+$labels['importgroupsall'] = 'Tot (crea grups si és necessari)';
+$labels['importgroupsexisting'] = 'Només per a grups existents';
$labels['importdesc'] = 'Podeu carregar contactes des d\'una llibreta de direccions.<br/>Actualment donem suport a la importació d\'adreces des de fitxers de tipus <a href="http://ca.wikipedia.org/wiki/VCard">vCard</a> o CSV (valors separats per comes).';
$labels['done'] = 'Fet';
$labels['settingsfor'] = 'Configuració per a';
@@ -344,8 +348,8 @@ $labels['timezone'] = 'Fus horari';
$labels['pagesize'] = 'Files per pàgina';
$labels['signature'] = 'Signatura';
$labels['dstactive'] = 'Horari d\'estiu';
-$labels['showinextwin'] = 'Obrir el missatge en una nova finestra';
-$labels['composeextwin'] = 'Redactar en una nova finestra';
+$labels['showinextwin'] = 'Obre el missatge en una nova finestra';
+$labels['composeextwin'] = 'Redacta en una nova finestra';
$labels['htmleditor'] = 'Escriu missatges en HTML';
$labels['htmlonreply'] = 'només en resposta a missatges en HTML';
$labels['htmlonreplyandforward'] = 'en reenviament o resposta a missatge HTML';
diff --git a/program/localization/ca_ES/messages.inc b/program/localization/ca_ES/messages.inc
index 06a72cb50..5f5854de8 100644
--- a/program/localization/ca_ES/messages.inc
+++ b/program/localization/ca_ES/messages.inc
@@ -54,6 +54,8 @@ $messages['contactnotfound'] = 'No s\'ha trobat el contacte sol·licitat.';
$messages['contactsearchonly'] = 'Introduïu termes de cerca per trobar contactes';
$messages['sendingfailed'] = 'Error enviant el missatge.';
$messages['senttooquickly'] = 'Si us plau, espereu $sec segon(s) abans d\'enviar aquest missatge.';
+$messages['errorsavingsent'] = 'S\'ha produït un error mentre es desava el missatge enviat.';
+$messages['errorsaving'] = 'S\'ha produït un error mentre es desava.';
$messages['errormoving'] = 'No s\'ha pogut moure el(s) missatge(s).';
$messages['errorcopying'] = 'No s\'ha pogut copiar el(s) missatge(s).';
$messages['errordeleting'] = 'No s\'ha pogut suprimir el(s) missatge(s).';
@@ -140,6 +142,7 @@ $messages['smtperror'] = 'Error SMTP: $msg';
$messages['emailformaterror'] = 'Adreça de correu no vàlida: $email';
$messages['toomanyrecipients'] = 'Massa destinataris. Reduïu el nombre de destinataris a $max.';
$messages['maxgroupmembersreached'] = 'El nombre de membres del grup excedeix el màxim de $max.';
+$messages['internalerror'] = 'S\'ha produït un error intern. Si us plau torneu-ho a provar.';
$messages['contactdelerror'] = 'No s\'han pogut suprimir el(s) contacte(s).';
$messages['contactdeleted'] = 'Contacte(s) suprimit(s) correctament.';
$messages['contactrestoreerror'] = 'No s\'ha pogut restaurar el(s) contacte(s) suprimit(s).';
diff --git a/program/localization/cs_CZ/labels.inc b/program/localization/cs_CZ/labels.inc
index d887d8d0a..aac514ec5 100644
--- a/program/localization/cs_CZ/labels.inc
+++ b/program/localization/cs_CZ/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Pravopis';
$labels['checkspelling'] = 'Zkontrolovat pravopis';
$labels['resumeediting'] = 'Pokračovat v úpravách';
$labels['revertto'] = 'Přejít na';
+$labels['responses'] = 'Odpovědi';
+$labels['insertresponse'] = 'Vložit odpověd';
+$labels['manageresponses'] = 'Spravovat odpovědí';
+$labels['savenewresponse'] = 'Uložit novou odpověď';
+$labels['editresponses'] = 'Upravit odpovědi';
+$labels['editresponse'] = 'Upravit odpověď';
+$labels['responsename'] = 'Název';
+$labels['responsetext'] = 'Text odpovědi';
$labels['attach'] = 'Přiložit';
$labels['attachments'] = 'Přílohy';
$labels['upload'] = 'Nahrát';
diff --git a/program/localization/cs_CZ/messages.inc b/program/localization/cs_CZ/messages.inc
index 0bd6b0e82..2e3a75c52 100644
--- a/program/localization/cs_CZ/messages.inc
+++ b/program/localization/cs_CZ/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Zpráva byla odeslána';
$messages['savingmessage'] = 'Ukládám zprávu...';
$messages['messagesaved'] = 'Zpráva uložena do Rozepsané';
$messages['successfullysaved'] = 'Uloženo';
+$messages['savingresponse'] = 'Ukládám text odpovědi...';
+$messages['deleteresponseconfirm'] = 'Opravdu chcete odstranit tento text odpovědi?';
$messages['addedsuccessfully'] = 'Kontakt byl úspěšně přidán do adresáře';
$messages['contactexists'] = 'Kontakt se zadanou e-mailovou adresou již existuje';
$messages['contactnameexists'] = 'Kontakt se stejným jménem již existuje';
diff --git a/program/localization/cy_GB/messages.inc b/program/localization/cy_GB/messages.inc
index 5dd8230c7..be6c4dac6 100644
--- a/program/localization/cy_GB/messages.inc
+++ b/program/localization/cy_GB/messages.inc
@@ -54,6 +54,8 @@ $messages['contactnotfound'] = 'Ni gafwyd hyd i\'r cysylltiad gofynnwyd amdano';
$messages['contactsearchonly'] = 'Rhowch dermau chwilio i ganfod cysylltiadau';
$messages['sendingfailed'] = 'Methwyd danfon y neges';
$messages['senttooquickly'] = 'Arhoswch $sec eiliad cyn danfon y neges';
+$messages['errorsavingsent'] = 'Fe gafwyd gwall wrth gadw\'r neges ddanfonwyd.';
+$messages['errorsaving'] = 'Fe gafwyd gwall wrth gadw';
$messages['errormoving'] = 'Methwyd symud y neges';
$messages['errorcopying'] = 'Methwyd copïo\'r neges(euon)';
$messages['errordeleting'] = 'Methwyd dileu y neges';
@@ -140,6 +142,7 @@ $messages['smtperror'] = 'Gwall SMTP: $msg';
$messages['emailformaterror'] = 'Cyfeiriad e-bost anghywir: $email';
$messages['toomanyrecipients'] = 'Gormod o dderbynnwyr. Lleihewch y nifer i $max';
$messages['maxgroupmembersreached'] = 'Mae nifer o aelodau\'r grŵp yn fwy na\'r uchafswm o $max';
+$messages['internalerror'] = 'Fe gafwyd gwall mewnol. Rhowch gynnig arni eto.';
$messages['contactdelerror'] = 'Methwyd dileu cyswllt';
$messages['contactdeleted'] = 'Cyswllt wedi ei ddileu yn llwyddiannus';
$messages['contactrestoreerror'] = 'Methwyd adfer y cyswllt/cysylltiadau a ddilëwyd';
diff --git a/program/localization/da_DK/labels.inc b/program/localization/da_DK/labels.inc
index 52de86d92..53d32090c 100644
--- a/program/localization/da_DK/labels.inc
+++ b/program/localization/da_DK/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Stav';
$labels['checkspelling'] = 'Stavekontrol';
$labels['resumeediting'] = 'Genoptag redigering';
$labels['revertto'] = 'Vend tilbage til';
+$labels['responses'] = 'Svar';
+$labels['insertresponse'] = 'Indsæt et svar';
+$labels['manageresponses'] = 'Administrer svar';
+$labels['savenewresponse'] = 'Gem et nyt svar';
+$labels['editresponses'] = 'Rediger svar';
+$labels['editresponse'] = 'Rediger svar';
+$labels['responsename'] = 'Navn';
+$labels['responsetext'] = 'Svartekst';
$labels['attach'] = 'Vedhæft';
$labels['attachments'] = 'Vedhæftninger';
$labels['upload'] = 'Overfør';
@@ -316,7 +324,11 @@ $labels['searchdelete'] = 'Slet søgning';
$labels['import'] = 'Importér';
$labels['importcontacts'] = 'Importér kontakter';
$labels['importfromfile'] = 'Importér fra fil:';
+$labels['importtarget'] = 'Tilføj kontakter til';
$labels['importreplace'] = 'Overskriv hele adressebogen';
+$labels['importgroups'] = 'Importer gruppetildelinger';
+$labels['importgroupsall'] = 'Alle (opret grupper hvis nødvendigt)';
+$labels['importgroupsexisting'] = 'Kun for eksisterende grupper';
$labels['importdesc'] = 'Du kan uploade kontakter fra en eksisterende adressebog. <br/>I øjeblikket supportere vi import af adresser fra <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> og CSV (komma-separeret) data format.';
$labels['done'] = 'Færdig';
$labels['settingsfor'] = 'Indstillinger for';
diff --git a/program/localization/da_DK/messages.inc b/program/localization/da_DK/messages.inc
index c12236eef..1e4635b8d 100644
--- a/program/localization/da_DK/messages.inc
+++ b/program/localization/da_DK/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Beskeden blev afsendt succesfuldt.';
$messages['savingmessage'] = 'Gemmer besked...';
$messages['messagesaved'] = 'Beskeden er gemt i kladdemappen.';
$messages['successfullysaved'] = 'Gemt succesfuldt';
+$messages['savingresponse'] = 'Gemmer svartekst...';
+$messages['deleteresponseconfirm'] = 'Er du sikker på, at du ønsker at slette svarteksten?';
$messages['addedsuccessfully'] = 'Kontakten blev tilføjet adressebogen.';
$messages['contactexists'] = 'Der er allerede en kontakt med denne e-mailadresse.';
$messages['contactnameexists'] = 'En kontakt med samme navn eksisterer allerede.';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'Den søgte kontakt blev ikke fundet.';
$messages['contactsearchonly'] = 'Indtast søgeord for at finde kontakter.';
$messages['sendingfailed'] = 'Beskeden kunne ikke sendes.';
$messages['senttooquickly'] = 'Vent venligst $sec sekunder før du sender denne besked.';
+$messages['errorsavingsent'] = 'Der opstod en fejl ved at gemme den sendte besked.';
+$messages['errorsaving'] = 'Der opstod en fejl ved at gemme.';
$messages['errormoving'] = 'Beskeden kunne ikke flyttes.';
$messages['errorcopying'] = 'Beskeden kunne ikke kopieres.';
$messages['errordeleting'] = 'Beskeden kunne ikke slettes.';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'SMTP fejl: $msg';
$messages['emailformaterror'] = 'Ugyldig e-mailadresse: $email';
$messages['toomanyrecipients'] = 'For mange modtagere. Reducer antallet af modtagere til $max.';
$messages['maxgroupmembersreached'] = 'Antallet af gruppemedlemmer overstiger maksimum på $max.';
+$messages['internalerror'] = 'En intern fejl opstod. Prøv venligst igen.';
$messages['contactdelerror'] = 'Kunne ikke slette kontakt(er).';
$messages['contactdeleted'] = 'Kontakt(er) slettet.';
$messages['contactrestoreerror'] = 'Kunne ikke gendanne slettede kontakt(er).';
diff --git a/program/localization/de_CH/labels.inc b/program/localization/de_CH/labels.inc
index e5fe1ec66..b416d0b98 100644
--- a/program/localization/de_CH/labels.inc
+++ b/program/localization/de_CH/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Rechtschreibung';
$labels['checkspelling'] = 'Rechtschreibung prüfen';
$labels['resumeediting'] = 'Bearbeitung fortsetzen';
$labels['revertto'] = 'Zurück zu';
+$labels['responses'] = 'Antworten';
+$labels['insertresponse'] = 'Antwort einfügen';
+$labels['manageresponses'] = 'Antworten verwalten';
+$labels['savenewresponse'] = 'Neue Antwort speichern';
+$labels['editresponses'] = 'Antworten bearbeiten';
+$labels['editresponse'] = 'Antwort bearbeiten';
+$labels['responsename'] = 'Name';
+$labels['responsetext'] = 'Antworttext';
$labels['attach'] = 'Anhängen';
$labels['attachments'] = 'Anhänge';
$labels['upload'] = 'Hochladen';
diff --git a/program/localization/de_CH/messages.inc b/program/localization/de_CH/messages.inc
index 4e5ccaa46..2f3257703 100644
--- a/program/localization/de_CH/messages.inc
+++ b/program/localization/de_CH/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Nachricht erfolgreich gesendet';
$messages['savingmessage'] = 'Nachricht wird gespeichert...';
$messages['messagesaved'] = 'Nachricht als Entwurf gespeichert';
$messages['successfullysaved'] = 'Erfolgreich gespeichert';
+$messages['savingresponse'] = 'Antwort wird gespeichert...';
+$messages['deleteresponseconfirm'] = 'Wollen Sie diese Antwort wirklich löschen?';
$messages['addedsuccessfully'] = 'Kontakt zum Adressbuch hinzugefügt';
$messages['contactexists'] = 'Es existiert bereits ein Kontakt mit dieser E-Mail-Adresse.';
$messages['contactnameexists'] = 'Es existiert bereits ein Kontakt mit diesem Namen';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'Die gewählte Adresse wurde nicht gefunden';
$messages['contactsearchonly'] = 'Geben Sie einen Suchbegriff ein, um Kontakte zu finden';
$messages['sendingfailed'] = 'Versand der Nachricht fehlgeschlagen';
$messages['senttooquickly'] = 'Bitte warten Sie $sec Sekunde(n) vor dem Senden dieser Nachricht';
+$messages['errorsavingsent'] = 'Beim Speichern der gesendeten Nachricht ist ein Fehler aufgetreten.';
+$messages['errorsaving'] = 'Beim Speichern ist ein Fehler aufgetreten.';
$messages['errormoving'] = 'Nachricht(en) konnte(n) nicht verschoben werden.';
$messages['errorcopying'] = 'Nachticht(en) konnte(n) nicht kopiert werden.';
$messages['errordeleting'] = 'Nachricht(en) konnte(n) nicht gelöscht werden.';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'SMTP Fehler: $msg';
$messages['emailformaterror'] = 'Ungültige E-Mail-Adresse: $email';
$messages['toomanyrecipients'] = 'Zuviele Empfänger angegeben. Reduzieren Sie die Empfängeradressen auf $max.';
$messages['maxgroupmembersreached'] = 'Die Anzahl Adressen in dieser Gruppe überschreitet das Maximum von $max.';
+$messages['internalerror'] = 'Ein interner Fehler ist aufgetreten. Bitte versuchen Sie den Vorgang erneut.';
$messages['contactdelerror'] = 'Fehler beim Löschen.';
$messages['contactdeleted'] = 'Kontakt(e) erfolgreich gelöscht.';
$messages['contactrestoreerror'] = 'Die gelöschten Kontakte konnten nicht wiederhergestellt werden.';
diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc
index 840c9358c..8f221a3a9 100644
--- a/program/localization/en_US/labels.inc
+++ b/program/localization/en_US/labels.inc
@@ -232,6 +232,15 @@ $labels['checkspelling'] = 'Check spelling';
$labels['resumeediting'] = 'Resume editing';
$labels['revertto'] = 'Revert to';
+$labels['responses'] = 'Responses';
+$labels['insertresponse'] = 'Insert a response';
+$labels['manageresponses'] = 'Manage responses';
+$labels['savenewresponse'] = 'Save new response';
+$labels['editresponses'] = 'Edit responses';
+$labels['editresponse'] = 'Edit response';
+$labels['responsename'] = 'Name';
+$labels['responsetext'] = 'Response Text';
+
$labels['attach'] = 'Attach';
$labels['attachments'] = 'Attachments';
$labels['upload'] = 'Upload';
@@ -484,6 +493,9 @@ $labels['standardwindows'] = 'Handle popups as standard windows';
$labels['forwardmode'] = 'Messages forwarding';
$labels['inline'] = 'inline';
$labels['asattachment'] = 'as attachment';
+$labels['replyallmode'] = 'Default action of [Reply all] button';
+$labels['replyalldefault'] = 'reply to all';
+$labels['replyalllist'] = 'reply to mailing list only (if found)';
$labels['folder'] = 'Folder';
$labels['folders'] = 'Folders';
diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc
index 9733109ad..033c820d1 100644
--- a/program/localization/en_US/messages.inc
+++ b/program/localization/en_US/messages.inc
@@ -46,6 +46,8 @@ $messages['messagesent'] = 'Message sent successfully.';
$messages['savingmessage'] = 'Saving message...';
$messages['messagesaved'] = 'Message saved to Drafts.';
$messages['successfullysaved'] = 'Successfully saved.';
+$messages['savingresponse'] = 'Saving response text...';
+$messages['deleteresponseconfirm'] = 'Do you really want to delete this response text?';
$messages['addedsuccessfully'] = 'Contact added successfully to address book.';
$messages['contactexists'] = 'A contact with the same e-mail address already exists.';
$messages['contactnameexists'] = 'A contact with the same name already exists.';
diff --git a/program/localization/es_ES/messages.inc b/program/localization/es_ES/messages.inc
index 3a8b5ab31..694544cca 100644
--- a/program/localization/es_ES/messages.inc
+++ b/program/localization/es_ES/messages.inc
@@ -54,6 +54,8 @@ $messages['contactnotfound'] = 'El contacto solicitado no existe.';
$messages['contactsearchonly'] = 'Ingrese algún criterio para buscar contactos';
$messages['sendingfailed'] = 'Error al enviar mensaje.';
$messages['senttooquickly'] = 'Por favor, espere $sec segundo(s) antes de mandar este mensaje.';
+$messages['errorsavingsent'] = 'Ha ocurrido un error al guardar el mensaje enviado.';
+$messages['errorsaving'] = 'Ha ocurrido un error al guardar.';
$messages['errormoving'] = 'No se ha podido mover el/los mensaje(s).';
$messages['errorcopying'] = 'No se ha podido copiar el/los mensaje(s).';
$messages['errordeleting'] = 'No se ha podido eliminar el/los mensaje(s).';
@@ -140,6 +142,7 @@ $messages['smtperror'] = 'Error SMTP: $msg';
$messages['emailformaterror'] = 'Dirección e-mail incorrecta: $email';
$messages['toomanyrecipients'] = 'Hay demasiados destinatarios. Reduzca el número de destinatarios a $max.';
$messages['maxgroupmembersreached'] = 'El número de miembros del grupo excede el máximo de $max.';
+$messages['internalerror'] = 'Ha ocurrido un error interno. Por favor, inténtelo de nuevo.';
$messages['contactdelerror'] = 'No se ha podido eliminar el/los contacto(s).';
$messages['contactdeleted'] = 'Contacto(s) eliminado(s) correctamente.';
$messages['contactrestoreerror'] = 'No se han podido restaurar los contactos borrados.';
diff --git a/program/localization/fa_IR/labels.inc b/program/localization/fa_IR/labels.inc
index de23577a0..14f6f8621 100644
--- a/program/localization/fa_IR/labels.inc
+++ b/program/localization/fa_IR/labels.inc
@@ -18,16 +18,16 @@
$labels['welcome'] = 'به $product خوش آمدید';
$labels['username'] = 'نام کاربری';
$labels['password'] = 'گذرواژه';
-$labels['server'] = 'سرویس‌دهنده';
+$labels['server'] = 'سرور';
$labels['login'] = 'ورود';
-$labels['logout'] = 'برون‌رفت';
-$labels['mail'] = 'پست';
+$labels['logout'] = 'خروج';
+$labels['mail'] = 'نامه';
$labels['settings'] = 'تنظیمات';
$labels['addressbook'] = 'دفتر نشانی';
$labels['inbox'] = 'صندوق ورودی';
$labels['drafts'] = 'پیش‌نویس‌ها';
$labels['sent'] = 'فرستاده شده';
-$labels['trash'] = 'حذف شده‌ها';
+$labels['trash'] = 'زباله‌دان';
$labels['junk'] = 'بنجل';
$labels['show_real_foldernames'] = 'نمایش نام واقعی برای پوشه‌های ویژه';
$labels['subject'] = 'موضوع';
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'املاء';
$labels['checkspelling'] = 'بررسی املایی';
$labels['resumeediting'] = 'ادامه‌ی ویرایش';
$labels['revertto'] = 'برگرداندن به';
+$labels['responses'] = 'پاسخ‌ها';
+$labels['insertresponse'] = 'درج پاسخ';
+$labels['manageresponses'] = 'مدیریت پاسخ‌ها';
+$labels['savenewresponse'] = 'ذخیره پاسخ جدید';
+$labels['editresponses'] = 'ویرایش پاسخ‌ها';
+$labels['editresponse'] = 'ویرایش پاسخ';
+$labels['responsename'] = 'نام';
+$labels['responsetext'] = 'متن پاسخ';
$labels['attach'] = 'پیوست کردن';
$labels['attachments'] = 'پیوست‌ها';
$labels['upload'] = 'بارگذاری';
diff --git a/program/localization/fa_IR/messages.inc b/program/localization/fa_IR/messages.inc
index 43f5a6c2a..502b0445a 100644
--- a/program/localization/fa_IR/messages.inc
+++ b/program/localization/fa_IR/messages.inc
@@ -54,6 +54,8 @@ $messages['contactnotfound'] = 'مخاطب درخواست شده پیدا نشد
$messages['contactsearchonly'] = 'برای یافتن مخاطب عبارتی را جستجو کنید';
$messages['sendingfailed'] = 'ارسال پیغام ناموفق بود.';
$messages['senttooquickly'] = 'لطفا قبل از ارسال این پیغام $sec ثانیه صبر کنید.';
+$messages['errorsavingsent'] = 'خطایی رخ داده است پیام ارسالی ذخیره می گردد.';
+$messages['errorsaving'] = 'خطایی در ذخیره کردن رخ داده است.';
$messages['errormoving'] = 'پیغام(ها) منتقل نشدند.';
$messages['errorcopying'] = 'پیغام(ها) کپی نشدند.';
$messages['errordeleting'] = 'پیغام(ها) حذف نشدند.';
@@ -140,6 +142,7 @@ $messages['smtperror'] = 'خطای SMTP: $msg';
$messages['emailformaterror'] = 'پست الکترونیکی نامعتبر: $email';
$messages['toomanyrecipients'] = 'گیرنده‌های بیش از اندازه: تعداد گیرنده ها را به $max کاهش دهید.';
$messages['maxgroupmembersreached'] = 'تعداد اعضای گروه بیشتر از $max است.';
+$messages['internalerror'] = 'یک خطای داخلی رخ داده است. لطفا دوباره سعی کنید.';
$messages['contactdelerror'] = 'حذف مخاطب(ها) انجام شد.';
$messages['contactdeleted'] = 'مخاطب(ها) با موفقیت حذف شدند.';
$messages['contactrestoreerror'] = 'مخاطب(های) حذف شده بازگردانی نخواهند شد.';
diff --git a/program/localization/fi_FI/labels.inc b/program/localization/fi_FI/labels.inc
index 8a9064028..1e5e26193 100644
--- a/program/localization/fi_FI/labels.inc
+++ b/program/localization/fi_FI/labels.inc
@@ -196,6 +196,13 @@ $labels['spellcheck'] = 'Oikeinkirjoitus';
$labels['checkspelling'] = 'Tarkista oikeinkirjoitus';
$labels['resumeediting'] = 'Jatka muokkausta';
$labels['revertto'] = 'Muuta takaisin';
+$labels['responses'] = 'Vastaukset';
+$labels['manageresponses'] = 'Hallitse vastauksia';
+$labels['savenewresponse'] = 'Tallenna uusi vastaus';
+$labels['editresponses'] = 'Muokkaa vastauksia';
+$labels['editresponse'] = 'Muokkaa vastausta';
+$labels['responsename'] = 'Nimi';
+$labels['responsetext'] = 'Vastausteksti';
$labels['attach'] = 'Liitä';
$labels['attachments'] = 'Liitetiedostot';
$labels['upload'] = 'Lisää';
@@ -315,6 +322,7 @@ $labels['import'] = 'Tuo';
$labels['importcontacts'] = 'Tuo yhteystiedot';
$labels['importfromfile'] = 'Tuo tiedostosta:';
$labels['importreplace'] = 'Korvaa koko osoitekirja';
+$labels['importgroupsall'] = 'Kaikki (luo ryhmät tarvittaessa)';
$labels['importdesc'] = 'Voit tuoda yhteystietoja olemassa olevasta osoitekirjasta.<br/>Tuettuja muotoja ovat <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> ja CSV (pilkuin erotetut arvot).';
$labels['done'] = 'Valmis';
$labels['settingsfor'] = 'Asetukset';
diff --git a/program/localization/fi_FI/messages.inc b/program/localization/fi_FI/messages.inc
index 1b3c3ea49..a94339af1 100644
--- a/program/localization/fi_FI/messages.inc
+++ b/program/localization/fi_FI/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Viesti lähetetty';
$messages['savingmessage'] = 'Tallennetaan viestiä...';
$messages['messagesaved'] = 'Viesti tallennettu "Luonnokset"-kansioon';
$messages['successfullysaved'] = 'Tallennus onnistui';
+$messages['savingresponse'] = 'Tallennetaan vastaustekstiä...';
+$messages['deleteresponseconfirm'] = 'Haluatko varmasti poistaa tämän vastaustekstin?';
$messages['addedsuccessfully'] = 'Yhteystieto lisätty osoitekirjaan';
$messages['contactexists'] = 'Samalla sähköpostiosoitteella on jo olemassa yhteystieto';
$messages['contactnameexists'] = 'Yhteystieto samalla nimellä on jo olemassa';
diff --git a/program/localization/fr_FR/labels.inc b/program/localization/fr_FR/labels.inc
index dd0acf4f1..14d1066f9 100644
--- a/program/localization/fr_FR/labels.inc
+++ b/program/localization/fr_FR/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Orthographe';
$labels['checkspelling'] = 'Vérifier l\'orthographe';
$labels['resumeediting'] = 'Retourner à l\'édition';
$labels['revertto'] = 'Revenir à';
+$labels['responses'] = 'Réponses';
+$labels['insertresponse'] = 'Insérer une réponse';
+$labels['manageresponses'] = 'Gérer les réponses';
+$labels['savenewresponse'] = 'Sauvegarder une nouvelle réponse';
+$labels['editresponses'] = 'Editer les réponses';
+$labels['editresponse'] = 'Editer la réponse';
+$labels['responsename'] = 'Nom';
+$labels['responsetext'] = 'Texte de la réponse';
$labels['attach'] = 'Joindre';
$labels['attachments'] = 'Fichiers joints';
$labels['upload'] = 'Transférer';
diff --git a/program/localization/hu_HU/labels.inc b/program/localization/hu_HU/labels.inc
index 648ac759f..f8d6a1c23 100644
--- a/program/localization/hu_HU/labels.inc
+++ b/program/localization/hu_HU/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Helyesírás ellenőrzés';
$labels['checkspelling'] = 'Helyesírás-ellenőrzés';
$labels['resumeediting'] = 'Helyesírás-ellenőrzés vége';
$labels['revertto'] = 'Visszaállítás erre';
+$labels['responses'] = 'Válaszok';
+$labels['insertresponse'] = 'Egy válasz beillesztése';
+$labels['manageresponses'] = 'Válaszok kezelése';
+$labels['savenewresponse'] = 'Új válasz mentése';
+$labels['editresponses'] = 'Válaszok szerkesztése';
+$labels['editresponse'] = 'Válasz szerkesztése';
+$labels['responsename'] = 'Név';
+$labels['responsetext'] = 'Válasz Szöveg';
$labels['attach'] = 'Csatolás';
$labels['attachments'] = 'Csatolmányok';
$labels['upload'] = 'Feltöltés';
diff --git a/program/localization/hu_HU/messages.inc b/program/localization/hu_HU/messages.inc
index 3ca87a52f..79de6ed2b 100644
--- a/program/localization/hu_HU/messages.inc
+++ b/program/localization/hu_HU/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Az üzenet elküldve';
$messages['savingmessage'] = 'Az üzenet mentése...';
$messages['messagesaved'] = 'Az üzenet elmentve a Piszkozatokhoz';
$messages['successfullysaved'] = 'A mentés sikerült';
+$messages['savingresponse'] = 'A válasz szövegének mentése...';
+$messages['deleteresponseconfirm'] = 'Biztosan törli ezt a válasz szöveget?';
$messages['addedsuccessfully'] = 'A kapcsolat hozzáadása a címjegyzékhez megtörtént';
$messages['contactexists'] = 'Ezzel az e-mail címmel már létezik kapcsolat';
$messages['contactnameexists'] = 'Ezzel a névvel már létezik kapcsolat';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'A kiválasztott kapcsolat nem található';
$messages['contactsearchonly'] = 'Adjon meg keresőkifejezéseket a kapcsolatok közti kereséshez';
$messages['sendingfailed'] = 'Az üzenet elküldése nem sikerült';
$messages['senttooquickly'] = 'Kérem várjon még $sec másodpercet az üzenet elküldése előtt';
+$messages['errorsavingsent'] = 'Hiba történt az elküldött üzenet mentése közben';
+$messages['errorsaving'] = 'A mentés során hiba lépett fel';
$messages['errormoving'] = 'Az üzenet(ek)et nem sikerült áthelyezni';
$messages['errorcopying'] = 'Az üzenet(ek)et nem sikerült másolni';
$messages['errordeleting'] = 'Az üzenet(ek)et nem sikerült törölni';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'SMTP hiba ($code): $msg';
$messages['emailformaterror'] = 'Helytelen formátumú e-mail cím: $email';
$messages['toomanyrecipients'] = 'Túl sok a címzett. Csökkentse a címzettek számát maximum $max címre!';
$messages['maxgroupmembersreached'] = 'A csoport létszáma meghaladja a maximum $max főt';
+$messages['internalerror'] = 'Belső hiba történt. Kérjük próbálja újra!';
$messages['contactdelerror'] = 'Hiba a kapcsolat(ok) törlésekor';
$messages['contactdeleted'] = 'Kapcsolat(ok) sikeresen törölve';
$messages['contactrestoreerror'] = 'Nem sikerült a törölt kapcsolat(ok) helyreállítása';
diff --git a/program/localization/it_IT/messages.inc b/program/localization/it_IT/messages.inc
index c5a81044e..0fd084f1b 100644
--- a/program/localization/it_IT/messages.inc
+++ b/program/localization/it_IT/messages.inc
@@ -54,6 +54,8 @@ $messages['contactnotfound'] = 'Il contatto richiesto non è stato trovato';
$messages['contactsearchonly'] = 'Inserisci dei termini per cercare i contatti';
$messages['sendingfailed'] = 'Impossibile inviare il messaggio';
$messages['senttooquickly'] = 'Per favore, attendi $sec secondi prima di inviare questo messaggio';
+$messages['errorsavingsent'] = 'Si è verificato un errore nel savare il messaggio inviato.';
+$messages['errorsaving'] = 'Si è verificato un errore nel salvataggio.';
$messages['errormoving'] = 'Impossibile spostare il messaggio';
$messages['errorcopying'] = 'Impossibile copiare il messaggio';
$messages['errordeleting'] = 'Impossibile eliminare il messaggio';
@@ -140,6 +142,7 @@ $messages['smtperror'] = 'Errore SMTP: $msg';
$messages['emailformaterror'] = 'Indirizzo e-mail non corretto: $email';
$messages['toomanyrecipients'] = 'Numero eccessivo di destinatari, ridurlo a $max';
$messages['maxgroupmembersreached'] = 'Il numero dei membri del gruppo eccede il massimo di $max';
+$messages['internalerror'] = 'Si è verificato un errore interno. Riprovare più tardi.';
$messages['contactdelerror'] = 'Impossibile eliminare il/i contatto/i';
$messages['contactdeleted'] = 'Contatto/i correttamente eliminato/i';
$messages['contactrestoreerror'] = 'Impossibile ripristinare il/i contatto/i cancellato/i';
diff --git a/program/localization/ja_JP/labels.inc b/program/localization/ja_JP/labels.inc
index aadc8fce0..ef52695bb 100644
--- a/program/localization/ja_JP/labels.inc
+++ b/program/localization/ja_JP/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'スペル';
$labels['checkspelling'] = 'スペルチェック';
$labels['resumeediting'] = '編集を再開';
$labels['revertto'] = '元に戻す';
+$labels['responses'] = '回答';
+$labels['insertresponse'] = '回答を挿入';
+$labels['manageresponses'] = '回答を管理';
+$labels['savenewresponse'] = '新しい回答を保存';
+$labels['editresponses'] = '回答を編集';
+$labels['editresponse'] = '回答を編集';
+$labels['responsename'] = '名前';
+$labels['responsetext'] = '回答の文章';
$labels['attach'] = '添付';
$labels['attachments'] = '添付ファイル';
$labels['upload'] = 'アップロード';
diff --git a/program/localization/ja_JP/messages.inc b/program/localization/ja_JP/messages.inc
index fb03bc0f8..abe5a6e7a 100644
--- a/program/localization/ja_JP/messages.inc
+++ b/program/localization/ja_JP/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'メッセージを送信しました。';
$messages['savingmessage'] = 'メッセージを保存中...';
$messages['messagesaved'] = 'メッセージを下書きに保存しました。';
$messages['successfullysaved'] = '保存しました。';
+$messages['savingresponse'] = '回答の文章を保存中...';
+$messages['deleteresponseconfirm'] = 'この回答の文章を本当に削除しますか?';
$messages['addedsuccessfully'] = '連絡先をアドレス帳に追加しました。';
$messages['contactexists'] = '同じメールアドレスの連絡先が既に存在します。';
$messages['contactnameexists'] = '同じ名前の連絡先が既に存在します。';
diff --git a/program/localization/lb_LU/labels.inc b/program/localization/lb_LU/labels.inc
index d32a263a1..cbd5a12a8 100644
--- a/program/localization/lb_LU/labels.inc
+++ b/program/localization/lb_LU/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Orthographie';
$labels['checkspelling'] = 'Orthographie kontrolléieren';
$labels['resumeediting'] = 'Weider editéieren';
$labels['revertto'] = 'Zréck bei';
+$labels['responses'] = 'Äntwerten';
+$labels['insertresponse'] = 'Äntwert afügen';
+$labels['manageresponses'] = 'Äntwerte geréieren';
+$labels['savenewresponse'] = 'Nei Äntwert späicheren';
+$labels['editresponses'] = 'Äntwerten Editéieren';
+$labels['editresponse'] = 'Äntwert editéieren';
+$labels['responsename'] = 'Numm';
+$labels['responsetext'] = 'Äntwert-Text';
$labels['attach'] = 'Drunhänken';
$labels['attachments'] = 'Unhäng';
$labels['upload'] = 'Eroplueden';
@@ -316,7 +324,11 @@ $labels['searchdelete'] = 'Sich läschen';
$labels['import'] = 'Importéieren';
$labels['importcontacts'] = 'Kontakter importéieren';
$labels['importfromfile'] = 'Aus Fichier importéieren:';
+$labels['importtarget'] = 'Kontakter dobäisetze bei';
$labels['importreplace'] = 'Dat ganzt Adressbuch ersetzen';
+$labels['importgroups'] = 'Gruppen-Zouweisung importéieren';
+$labels['importgroupsall'] = 'All (nei Gruppen uleeën falls néideg)';
+$labels['importgroupsexisting'] = 'Just fir Gruppen déi schon existéieren';
$labels['importdesc'] = 'Du kanns Kontakter aus engem existéierenden Adressbuch eroplueden.<br/>Mir ënnerstëtze momentan en Adress-Import vum <a href="http://en.wikipedia.org/wiki/VCard">vCard</a>- oder CSV (mat Komma getrennt)-Date-Format.';
$labels['done'] = 'Erleedegt';
$labels['settingsfor'] = 'Astellunge fir';
diff --git a/program/localization/lb_LU/messages.inc b/program/localization/lb_LU/messages.inc
index 8ef0b2f6c..fc053b59e 100644
--- a/program/localization/lb_LU/messages.inc
+++ b/program/localization/lb_LU/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Message erfollegräich verschéckt.';
$messages['savingmessage'] = 'Message gëtt gespäichert...';
$messages['messagesaved'] = 'Message als Brouillon gespäichert.';
$messages['successfullysaved'] = 'Erfollegräich gespäichert.';
+$messages['savingresponse'] = 'Äntwert-Text gëtt gespäichert...';
+$messages['deleteresponseconfirm'] = 'Wëlls du dësen Äntwert-Text wierklech läschen?';
$messages['addedsuccessfully'] = 'Kontakt erfollegräich an d\'Adressbuch gesat.';
$messages['contactexists'] = 'Et existéiert schon e Kontakt mat der selweschter E-Mail-Adress.';
$messages['contactnameexists'] = 'Et existéiert schon e Kontakt mam selweschten Numm.';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'Den ugefrotene Kontakt gouf net fonnt.';
$messages['contactsearchonly'] = 'Gëff e puer Sichbegrëffer a fir Kontakter ze fannen';
$messages['sendingfailed'] = 'De Message konnt net verschéckt ginn.';
$messages['senttooquickly'] = 'Waart wann ech gelift $sec Sekonn(en) bevir s du de Message verschécks. ';
+$messages['errorsavingsent'] = 'Beim Späichere vum geschéckte Message ass e Feeler opgetruden.';
+$messages['errorsaving'] = 'Beim Späicheren ass e Feeler opgetrueden.';
$messages['errormoving'] = 'D\'Messagë konnten net verréckelt ginn.';
$messages['errorcopying'] = 'D\'Messagë konnten net kopéiert ginn.';
$messages['errordeleting'] = 'D\'Messagë konnten net geläscht ginn.';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'SMTP-Feeler: $msg';
$messages['emailformaterror'] = 'Ongëlteg E-Mail-Adress: $email';
$messages['toomanyrecipients'] = 'Zevill Empfänger. Reduzéier d\'Zuel vun den Empfänger op $max.';
$messages['maxgroupmembersreached'] = 'D\'Unzuel vu Gruppememberen iwwersteigt de Maximum vun $max.';
+$messages['internalerror'] = 'En interne Feeler ass opgetrueden. Probéier w.e.gl nach eng Kéier.';
$messages['contactdelerror'] = 'Kontakter konnten net geläscht ginn.';
$messages['contactdeleted'] = 'Kontakter erfollegräich geläscht.';
$messages['contactrestoreerror'] = 'Déi geläschte Kontakter konnten net recuperéiert ginn.';
diff --git a/program/localization/lv_LV/labels.inc b/program/localization/lv_LV/labels.inc
index 95afc4c49..0f80350bb 100644
--- a/program/localization/lv_LV/labels.inc
+++ b/program/localization/lv_LV/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Izrunāt';
$labels['checkspelling'] = 'Pārbaudīt pareizrakstību';
$labels['resumeediting'] = 'Turpināt rediģēšanu';
$labels['revertto'] = 'Atgriezt uz';
+$labels['responses'] = 'Atbildes';
+$labels['insertresponse'] = 'Ievietot atbildi';
+$labels['manageresponses'] = 'Pārvaldīt atbildes';
+$labels['savenewresponse'] = 'Saglabāt jauno atbildi';
+$labels['editresponses'] = 'Rediģēt atbildes';
+$labels['editresponse'] = 'Rediģēt atbildi';
+$labels['responsename'] = 'Vārds';
+$labels['responsetext'] = 'Atbildes teksts';
$labels['attach'] = 'Pievienot';
$labels['attachments'] = 'Pielikumi';
$labels['upload'] = 'Augšupielādēt';
@@ -318,6 +326,7 @@ $labels['importcontacts'] = 'Importēt kontaktus';
$labels['importfromfile'] = 'Importēt no faila:';
$labels['importtarget'] = 'Kontaktus pievienot';
$labels['importreplace'] = 'Aizvietot visu adrešu grāmatu';
+$labels['importgroups'] = 'Importēt grupu piesaistes';
$labels['importgroupsall'] = 'Visus (ja nepieciešams, izveidojiet grupas)';
$labels['importgroupsexisting'] = 'Tikai esošām grupām';
$labels['importdesc'] = 'Jūs varat ieimportēt kontaktus no jau esošas adrešu grāmatas.<br/>Uz doto brīdi tiek atbalstīti <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> vai CSV (ar komatu atdalītie) datu formāti.';
diff --git a/program/localization/lv_LV/messages.inc b/program/localization/lv_LV/messages.inc
index f27b01b84..55cff4134 100644
--- a/program/localization/lv_LV/messages.inc
+++ b/program/localization/lv_LV/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Vēstule nosūtīta veiksmīgi';
$messages['savingmessage'] = 'Vēstule tiek saglabāta ...';
$messages['messagesaved'] = 'Vēstule saglabāta Uzmetumos';
$messages['successfullysaved'] = 'Veiksmīgi saglabāts.';
+$messages['savingresponse'] = 'Tiek saglabāts atbildes teksts ...';
+$messages['deleteresponseconfirm'] = 'Vai Jūs tiešām gribat dzēst šo atbildes tekstu?';
$messages['addedsuccessfully'] = 'Kontakts veiksmīgi pievienots adrešu grāmatai';
$messages['contactexists'] = 'Kontakts ar šādu e-pasta adresi jau eksistē';
$messages['contactnameexists'] = 'Kontakts ar šādu vārdu jau eksistē.';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'Pieprasītais kontakts nav atrasts';
$messages['contactsearchonly'] = 'Lai atrastu kontaktus, ievadiet meklēšanas kritērijus';
$messages['sendingfailed'] = 'Vēstule netika nosūtīta';
$messages['senttooquickly'] = 'Lūdzu uzgaidiet $sec sekundi(-es) pirms sūtiet šo vēstuli';
+$messages['errorsavingsent'] = 'Saglabājot nosūtīto vēstuli notika kļūda - vēstule netika saglabāta';
+$messages['errorsaving'] = 'Saglabājot vēstuli notika kļūda - vēstule netika saglabāta';
$messages['errormoving'] = 'Vēstule(s) netika pārvietota(s)';
$messages['errorcopying'] = 'Vēstules pārkopēt neizdevās';
$messages['errordeleting'] = 'Vēstules izdzēst neizdevās';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'SMTP kļūda: $msg';
$messages['emailformaterror'] = 'Nepareiza e-pasta adrese: $email';
$messages['toomanyrecipients'] = 'Pārāk daudz saņēmēju. Samaziniet skaitu līdz $max.';
$messages['maxgroupmembersreached'] = 'Grupas dalībnieku skaits pārsniedz limitu $max.';
+$messages['internalerror'] = 'Atgadījās servera iekšējā kļūda. Lūdzu mēģiniet vēlreiz.';
$messages['contactdelerror'] = 'Kontaktus izdzēst neizdevās.';
$messages['contactdeleted'] = 'Kontakti izdzēsti veiksmīgi.';
$messages['contactrestoreerror'] = 'Izdzēstos kontaktus atjaunot neizdevās.';
diff --git a/program/localization/nl_NL/labels.inc b/program/localization/nl_NL/labels.inc
index f0e4a74b4..b5f273659 100644
--- a/program/localization/nl_NL/labels.inc
+++ b/program/localization/nl_NL/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Spelling';
$labels['checkspelling'] = 'Controleer spelling';
$labels['resumeediting'] = 'Doorgaan met opstellen';
$labels['revertto'] = 'Terugwijzigen in';
+$labels['responses'] = 'Reacties';
+$labels['insertresponse'] = 'Reactie invoegen';
+$labels['manageresponses'] = 'Reacties beheren';
+$labels['savenewresponse'] = 'Nieuwe reactie opslaan';
+$labels['editresponses'] = 'Bewerk reactie';
+$labels['editresponse'] = 'Bewerk reactie';
+$labels['responsename'] = 'Naam';
+$labels['responsetext'] = 'Reactie';
$labels['attach'] = 'Bijvoegen';
$labels['attachments'] = 'Bijlagen';
$labels['upload'] = 'Toevoegen';
diff --git a/program/localization/nl_NL/messages.inc b/program/localization/nl_NL/messages.inc
index 22f9e0f6b..f6081bd8e 100644
--- a/program/localization/nl_NL/messages.inc
+++ b/program/localization/nl_NL/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Bericht succesvol verstuurd.';
$messages['savingmessage'] = 'Bericht wordt opgeslagen...';
$messages['messagesaved'] = 'Bericht opgeslagen in Concepten.';
$messages['successfullysaved'] = 'Succesvol opgeslagen.';
+$messages['savingresponse'] = 'Reactie wordt opgeslagen...';
+$messages['deleteresponseconfirm'] = 'Weet u zeker dat u deze reactie wilt verwijderen?';
$messages['addedsuccessfully'] = 'Contactpersoon succesvol toegevoegd aan het adresboek.';
$messages['contactexists'] = 'Er bestaat al een contactpersoon met dit e-mailadres.';
$messages['contactnameexists'] = 'Er bestaat al een contactpersoon met deze naam.';
diff --git a/program/localization/pt_BR/labels.inc b/program/localization/pt_BR/labels.inc
index 13db63e99..e42b1ce95 100644
--- a/program/localization/pt_BR/labels.inc
+++ b/program/localization/pt_BR/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Revisar';
$labels['checkspelling'] = 'Verificar ortografia';
$labels['resumeediting'] = 'Continuar a edição';
$labels['revertto'] = 'Reverter para';
+$labels['responses'] = 'Respostas';
+$labels['insertresponse'] = 'Inserir uma resposta';
+$labels['manageresponses'] = 'Gerenciar respostas';
+$labels['savenewresponse'] = 'Salvar nova resposta';
+$labels['editresponses'] = 'Editar respostas';
+$labels['editresponse'] = 'Editar resposta';
+$labels['responsename'] = 'Nome';
+$labels['responsetext'] = 'Texto da resposta';
$labels['attach'] = 'Anexar';
$labels['attachments'] = 'Anexos';
$labels['upload'] = 'Enviar arquivo';
diff --git a/program/localization/pt_BR/messages.inc b/program/localization/pt_BR/messages.inc
index 2f5782373..823dad22e 100644
--- a/program/localization/pt_BR/messages.inc
+++ b/program/localization/pt_BR/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Mensagem enviada com sucesso';
$messages['savingmessage'] = 'Salvando Mensagem...';
$messages['messagesaved'] = 'Mensagem salva em Rascunhos';
$messages['successfullysaved'] = 'Salvo com sucesso';
+$messages['savingresponse'] = 'Salvando texto de resposta...';
+$messages['deleteresponseconfirm'] = 'Você realmente deseja apagar este texto de resposta?';
$messages['addedsuccessfully'] = 'Contato incluído com sucesso no catálogo de endereços.';
$messages['contactexists'] = 'Já existe um contato com esse mesmo e-mail.';
$messages['contactnameexists'] = 'Já existe um contato com o mesmo nome.';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'O contato solicitado não foi encontrado.';
$messages['contactsearchonly'] = 'Informe os termos de pesquisa para localizar os contatos';
$messages['sendingfailed'] = 'Falha no envio da mensagem.';
$messages['senttooquickly'] = 'Aguarde $sec s para enviar a mensagem.';
+$messages['errorsavingsent'] = 'Ocorreu um erro ao salvar a mensagem enviada.';
+$messages['errorsaving'] = 'Ocorreu um erro ao salvar.';
$messages['errormoving'] = 'Não foi possível mover a(s) mensagem(ns).';
$messages['errorcopying'] = 'Não foi possível copiar a(s) mensagem(ns).';
$messages['errordeleting'] = 'Não foi possível apagar a(s) mensagem(ns).';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'Erro SMTP: $msg';
$messages['emailformaterror'] = 'Endereço de e-mail inválido: $email';
$messages['toomanyrecipients'] = 'Há muitos destinatários. Reduza o número de destinatários para $max.';
$messages['maxgroupmembersreached'] = 'O número de membros do grupo excede o máximo de $max';
+$messages['internalerror'] = 'Ocorreu um erro interno. Por favor tente novamente.';
$messages['contactdelerror'] = 'Não foi possível excluir o(s) contato(s).';
$messages['contactdeleted'] = 'Contato(s) excluído(s) com sucesso.';
$messages['contactrestoreerror'] = 'Não foi possivel recuperar o(s) contato(s) excluído(s).';
diff --git a/program/localization/pt_PT/labels.inc b/program/localization/pt_PT/labels.inc
index b12830031..b6db8a41e 100644
--- a/program/localization/pt_PT/labels.inc
+++ b/program/localization/pt_PT/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Corrector Ortográfico';
$labels['checkspelling'] = 'Verificar ortografia';
$labels['resumeediting'] = 'Continuar a edição';
$labels['revertto'] = 'Reverter para';
+$labels['responses'] = 'Respostas';
+$labels['insertresponse'] = 'Insira uma resposta';
+$labels['manageresponses'] = 'Gerir respostas';
+$labels['savenewresponse'] = 'Gravar nova resposta';
+$labels['editresponses'] = 'Editar respostas';
+$labels['editresponse'] = 'Editar resposta';
+$labels['responsename'] = 'Nome';
+$labels['responsetext'] = 'Texto da resposta';
$labels['attach'] = 'Anexar';
$labels['attachments'] = 'Anexos';
$labels['upload'] = 'Carregar';
diff --git a/program/localization/pt_PT/messages.inc b/program/localization/pt_PT/messages.inc
index 06e78198d..fed7fa09e 100644
--- a/program/localization/pt_PT/messages.inc
+++ b/program/localization/pt_PT/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Mensagem enviada com sucesso';
$messages['savingmessage'] = 'A guardar mensagem...';
$messages['messagesaved'] = 'Mensagem guardada como rascunho';
$messages['successfullysaved'] = 'Guardado com sucesso';
+$messages['savingresponse'] = 'A guardar texto de resposta...';
+$messages['deleteresponseconfirm'] = 'Deseja realmente apagar este texto de resposta?';
$messages['addedsuccessfully'] = 'Contacto adicionado com sucesso';
$messages['contactexists'] = 'Já existe um contacto com este e-mail';
$messages['contactnameexists'] = 'Já existe um contacto com este nome.';
diff --git a/program/localization/ru_RU/messages.inc b/program/localization/ru_RU/messages.inc
index d8da5ee5c..2509ba49b 100644
--- a/program/localization/ru_RU/messages.inc
+++ b/program/localization/ru_RU/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Сообщение отправлено.';
$messages['savingmessage'] = 'Сохранение сообщения...';
$messages['messagesaved'] = 'Сохранено в Черновиках.';
$messages['successfullysaved'] = 'Сохранено.';
+$messages['savingresponse'] = 'Сохранение текста ответа...';
+$messages['deleteresponseconfirm'] = 'Вы действительно хотите удалить этот текст ответа?';
$messages['addedsuccessfully'] = 'Контакт добавлен в адресную книгу.';
$messages['contactexists'] = 'Контакт с этим адресом e-mail уже существует.';
$messages['contactnameexists'] = 'Контакт с таким именем уже существует.';
diff --git a/program/localization/sk_SK/labels.inc b/program/localization/sk_SK/labels.inc
index 36d9850a0..93bca166f 100644
--- a/program/localization/sk_SK/labels.inc
+++ b/program/localization/sk_SK/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Pravopis';
$labels['checkspelling'] = 'Skontrolovať pravopis';
$labels['resumeediting'] = 'Pokračovať v úpravách';
$labels['revertto'] = 'Vrátiť sa na';
+$labels['responses'] = 'Odpovede';
+$labels['insertresponse'] = 'Vložiť odpoveď';
+$labels['manageresponses'] = 'Spravovať odpovede';
+$labels['savenewresponse'] = 'Uložiť novú odpoveď';
+$labels['editresponses'] = 'Upraviť odpovede';
+$labels['editresponse'] = 'Upraviť odpoveď';
+$labels['responsename'] = 'Meno';
+$labels['responsetext'] = 'Text odpovede';
$labels['attach'] = 'Priložiť';
$labels['attachments'] = 'Prílohy';
$labels['upload'] = 'Nahrať';
diff --git a/program/localization/sk_SK/messages.inc b/program/localization/sk_SK/messages.inc
index db830c2a7..71d5d52c1 100644
--- a/program/localization/sk_SK/messages.inc
+++ b/program/localization/sk_SK/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Správa bola úspešne odoslaná';
$messages['savingmessage'] = 'Správa sa ukladá...';
$messages['messagesaved'] = 'Správa bola uložená medzi Rozpísané správy';
$messages['successfullysaved'] = 'Úspešne uložená';
+$messages['savingresponse'] = 'Ukladanie textu odpovede...';
+$messages['deleteresponseconfirm'] = 'Naozaj chcete vymazať text odpovede?';
$messages['addedsuccessfully'] = 'Kontakt bol pridaný do adresára';
$messages['contactexists'] = 'Kontakt s touto e-mailovou adresou už existuje';
$messages['contactnameexists'] = 'Kontakt s rovnakým menom už existuje.';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'Požadovaný kontakt nebol nájdený';
$messages['contactsearchonly'] = 'Zadaj nejaký vyhľadávací výraz pre hľadanie kontaktov.';
$messages['sendingfailed'] = 'Odosielanie správy zlyhalo';
$messages['senttooquickly'] = 'Počkajte $sec sekúnd pred odoslaním tejto správy';
+$messages['errorsavingsent'] = 'Počas ukladania odoslanej správy nastala chyba.';
+$messages['errorsaving'] = 'Počas ukladania nastala chyba.';
$messages['errormoving'] = 'Správa sa nedá presunúť';
$messages['errorcopying'] = 'Správa sa nedá skopírovať';
$messages['errordeleting'] = 'Správa sa nedá zmazať';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'Chyba SMTP: $msg';
$messages['emailformaterror'] = 'Neplatná e-mailová adresa: $email';
$messages['toomanyrecipients'] = 'Príliš veľa príjemcov. Zmenšite počet príjemcov na $max.';
$messages['maxgroupmembersreached'] = 'Počet členov skupiny dosiahol maxima z $max';
+$messages['internalerror'] = 'Došlo k internej chybe systému. Prosím skúste to ešte raz.';
$messages['contactdelerror'] = 'Nemôžem vymazať kontakt(y)';
$messages['contactdeleted'] = 'Kontakt(y) bol vymazaný';
$messages['contactrestoreerror'] = 'Nemôžem obnoviť zmazané kontakty';
diff --git a/program/localization/sl_SI/labels.inc b/program/localization/sl_SI/labels.inc
index f93684d69..f1e9010d4 100644
--- a/program/localization/sl_SI/labels.inc
+++ b/program/localization/sl_SI/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Črkovanje';
$labels['checkspelling'] = 'Preglej pravopis';
$labels['resumeediting'] = 'Nadaljuj z urejanjem';
$labels['revertto'] = 'Razveljavi';
+$labels['responses'] = 'Odgovori';
+$labels['insertresponse'] = 'Vnesi odgovor';
+$labels['manageresponses'] = 'Uredi odgovore';
+$labels['savenewresponse'] = 'Shrani nove odgovore';
+$labels['editresponses'] = 'Uredi odgovore';
+$labels['editresponse'] = 'Uredi odgovor';
+$labels['responsename'] = 'Ime';
+$labels['responsetext'] = 'Tekst za odgovor';
$labels['attach'] = 'Pripni';
$labels['attachments'] = 'Priponke';
$labels['upload'] = 'Naloži';
@@ -316,7 +324,11 @@ $labels['searchdelete'] = 'Izbriši iskanje';
$labels['import'] = 'Uvozi';
$labels['importcontacts'] = 'Uvozi stike';
$labels['importfromfile'] = 'Uvozi iz datoteke:';
+$labels['importtarget'] = 'Dodaj stike v';
$labels['importreplace'] = 'Zamenjaj celoten imenik';
+$labels['importgroups'] = 'Vnesi skupinske zadolžitve';
+$labels['importgroupsall'] = 'Vse (ustvari skupine, če je potrebno)';
+$labels['importgroupsexisting'] = 'Samo za obstoječe skupine';
$labels['importdesc'] = 'Stike lahko naložite iz obstoječega imenika. <br/>Trenutno je podprt uvoz stikov v zapisu <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> ali v CSV (z vejico ločene vrednosti) zapisu.';
$labels['done'] = 'Dokončano';
$labels['settingsfor'] = 'Nastavitve za';
diff --git a/program/localization/sl_SI/messages.inc b/program/localization/sl_SI/messages.inc
index f1beffc0f..3d1ea677c 100644
--- a/program/localization/sl_SI/messages.inc
+++ b/program/localization/sl_SI/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Sporočilo je bilo uspešno poslano.';
$messages['savingmessage'] = 'Shranjevanje sporočila...';
$messages['messagesaved'] = 'Sporočilo je bilo shranjeno v Osnutke';
$messages['successfullysaved'] = 'Uspešno shranjeno.';
+$messages['savingresponse'] = 'Shranjevanje odgovora...';
+$messages['deleteresponseconfirm'] = 'Ste prepričani, da želite izbrisati ta odgovor?';
$messages['addedsuccessfully'] = 'Stik je bil uspešno dodan v imenik.';
$messages['contactexists'] = 'Stik s tem elektronskim naslovom že obstaja.';
$messages['contactnameexists'] = 'Stik s tem imenom že obstaja';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'Iskanega stika ni bilo mogoče najti.';
$messages['contactsearchonly'] = 'Vpišite iskalni parameter za iskanje stika';
$messages['sendingfailed'] = 'Sporočila ni bilo mogoče poslati.';
$messages['senttooquickly'] = 'Počakajte $sec sekund in nato znova poskusite s pošiljanjem sporočila.';
+$messages['errorsavingsent'] = 'Pri shranjevanju poslanega sporočila je prišlo do napake.';
+$messages['errorsaving'] = 'Pri shranjevanju je prišlo do napake.';
$messages['errormoving'] = 'Sporočila ni bilo mogoče premakniti.';
$messages['errorcopying'] = 'Sporočila ni bilo mogoče kopirati.';
$messages['errordeleting'] = 'Sporočila ni bilo mogoče izbrisati.';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'Napaka pri pošiljanju:$msg';
$messages['emailformaterror'] = 'Nepravilen elektronski naslov: $email';
$messages['toomanyrecipients'] = 'Navedli ste preveč prejemnikov. Zmanjšajte število prejemnikov na $max';
$messages['maxgroupmembersreached'] = 'Število članov skupine presega največje dovoljeno število $max.';
+$messages['internalerror'] = 'Prišlo je do napake. Poskusite znova.';
$messages['contactdelerror'] = 'Stika/ov ni bilo mogoče izbrisati';
$messages['contactdeleted'] = 'Stik/i so bili uspešno izbrisani';
$messages['contactrestoreerror'] = 'Ni bilo mogoče obnoviti izbrisanih stikov.';
diff --git a/program/localization/sv_SE/labels.inc b/program/localization/sv_SE/labels.inc
index 48f71ab57..8116afeff 100644
--- a/program/localization/sv_SE/labels.inc
+++ b/program/localization/sv_SE/labels.inc
@@ -197,6 +197,14 @@ $labels['spellcheck'] = 'Rättstava';
$labels['checkspelling'] = 'Kontrollera stavning';
$labels['resumeediting'] = 'Återuppta redigering';
$labels['revertto'] = 'Återgå till';
+$labels['responses'] = 'Responser';
+$labels['insertresponse'] = 'Infoga respons';
+$labels['manageresponses'] = 'Hantera responser';
+$labels['savenewresponse'] = 'Spara ny respons';
+$labels['editresponses'] = 'Ändra responser';
+$labels['editresponse'] = 'Ändra respons';
+$labels['responsename'] = 'Namn';
+$labels['responsetext'] = 'Responstext';
$labels['attach'] = 'Bifoga';
$labels['attachments'] = 'Bilagor';
$labels['upload'] = 'Bifoga';
diff --git a/program/localization/sv_SE/messages.inc b/program/localization/sv_SE/messages.inc
index 2773ae4c7..16bbd5a23 100644
--- a/program/localization/sv_SE/messages.inc
+++ b/program/localization/sv_SE/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Meddelandet har skickats.';
$messages['savingmessage'] = 'Sparar meddelande...';
$messages['messagesaved'] = 'Meddelandet har sparats i Utkast';
$messages['successfullysaved'] = 'Informationen har sparats.';
+$messages['savingresponse'] = 'Sparar responstext...';
+$messages['deleteresponseconfirm'] = 'Vill du verkligen ta bort denna responstext?';
$messages['addedsuccessfully'] = 'Kontakten har lagts till i adressboken.';
$messages['contactexists'] = 'En kontakt med den här adressen finns redan';
$messages['contactnameexists'] = 'En kontakt med det här namnet finns redan';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'Efterfrågad kontakt hittades inte';
$messages['contactsearchonly'] = 'Ange sökord för att hitta kontakter';
$messages['sendingfailed'] = 'Meddelandet kunde inte skickas';
$messages['senttooquickly'] = 'Vänta ytterligare $sec sekunder med att skicka meddelandet';
+$messages['errorsavingsent'] = 'Ett fel inträffade när det skickade meddelandet skulle sparas';
+$messages['errorsaving'] = 'Meddelandet kunde inte sparas';
$messages['errormoving'] = 'Meddelandet kunde inte flyttas';
$messages['errorcopying'] = 'Meddelandet kunde inte kopieras';
$messages['errordeleting'] = 'Meddelandet kunde inte tas bort';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'SMTP-fel: $msg';
$messages['emailformaterror'] = 'Felaktig adress: $email';
$messages['toomanyrecipients'] = 'Förmånga mottagare. Minska antalet till högst $max';
$messages['maxgroupmembersreached'] = 'Antalet gruppmedlemmar får inte överstiga $max';
+$messages['internalerror'] = 'Ett internt fel uppstod. Försök igen.';
$messages['contactdelerror'] = 'Kontakt kunde inte tas bort';
$messages['contactdeleted'] = 'Kontakt borttagen.';
$messages['contactrestoreerror'] = 'Borttagna kontakter kunde inte återskapas';
diff --git a/program/localization/tr_TR/messages.inc b/program/localization/tr_TR/messages.inc
index 0b2ac1e46..182fc966b 100644
--- a/program/localization/tr_TR/messages.inc
+++ b/program/localization/tr_TR/messages.inc
@@ -44,6 +44,8 @@ $messages['messagesent'] = 'Posta gönderildi';
$messages['savingmessage'] = 'Posta kaydediliyor...';
$messages['messagesaved'] = 'Posta taslaklara kaydedildi';
$messages['successfullysaved'] = 'Kaydedildi';
+$messages['savingresponse'] = 'Yanıt metni kaydediliyor...';
+$messages['deleteresponseconfirm'] = 'Yanıt metnini gerçekten silmek istiyor musunuz?';
$messages['addedsuccessfully'] = 'Kişi adres defterine eklendi';
$messages['contactexists'] = 'Rehberde bu e-posta adresine sahip biri zaten var';
$messages['contactnameexists'] = 'Rehberde bu ada sahip biri zaten var.';
@@ -54,6 +56,8 @@ $messages['contactnotfound'] = 'İstenen kişi bulunamadı';
$messages['contactsearchonly'] = 'Kişi aramak için arama terimleri giriniz';
$messages['sendingfailed'] = 'Posta gönderilemedi';
$messages['senttooquickly'] = 'Lütfen bu postayı göndermeden önce $sec saniye bekleyin';
+$messages['errorsavingsent'] = 'Gönderilen postayı kaydederken hata oluştu.';
+$messages['errorsaving'] = 'Kaydederken bir hata oluştu.';
$messages['errormoving'] = 'Posta taşınamadı';
$messages['errorcopying'] = 'Posta kopyalanamadı';
$messages['errordeleting'] = 'Posta silinemedi';
@@ -140,6 +144,7 @@ $messages['smtperror'] = 'SMTP Hatası: $msg';
$messages['emailformaterror'] = 'Hatalı e-posta adresi: $email';
$messages['toomanyrecipients'] = 'Çok fazla alıcı. En fazla $max alıcı girebilirsiniz.';
$messages['maxgroupmembersreached'] = 'Grup üyelerinin sayısı $max sınırını aşıyor.';
+$messages['internalerror'] = 'Dahili bir hata oluştu. Lütfen tekrar deneyin.';
$messages['contactdelerror'] = 'Kişi(ler) silinemedi';
$messages['contactdeleted'] = 'Kişi(ler) silindi';
$messages['contactrestoreerror'] = 'Silinen kişi(ler) geri getirilemiyor.';
diff --git a/program/localization/uk_UA/messages.inc b/program/localization/uk_UA/messages.inc
index 669190c2e..620e1520b 100644
--- a/program/localization/uk_UA/messages.inc
+++ b/program/localization/uk_UA/messages.inc
@@ -53,6 +53,7 @@ $messages['contactnotfound'] = 'Запитаний контакт не знай
$messages['contactsearchonly'] = 'Введіть деякі критерії пошуку, щоб знайти контакти';
$messages['sendingfailed'] = 'Не вдалося відправити листа';
$messages['senttooquickly'] = 'Будь ласка, зачекайте $sec секунд для відправки листа';
+$messages['errorsavingsent'] = 'Помилка при збереженні відправленого повідомлення.';
$messages['errormoving'] = 'Не вдалося перемістити листи';
$messages['errorcopying'] = 'Не вдалося зкопіювати листи';
$messages['errordeleting'] = 'Не вдалося видалити листи';
@@ -96,6 +97,7 @@ $messages['converting'] = 'Видалення форматування...';
$messages['messageopenerror'] = 'Не вдалося завантажити повідомлення з сервера';
$messages['fileuploaderror'] = 'Не вдалося вкласти файл';
$messages['filesizeerror'] = 'Розмір вибраного файлу перевищує максимально дозволений ($size)';
+$messages['copyerror'] = 'Не вдалося скопіювати жодного контакту.';
$messages['sourceisreadonly'] = 'Дане джерело адрес доступне лише для читання';
$messages['errorsavingcontact'] = 'Неможливо зберегти адресу контакту';
$messages['movingmessage'] = 'Переміщення листа...';
diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc
index 2adc53bcf..7911802b9 100644
--- a/program/steps/addressbook/save.inc
+++ b/program/steps/addressbook/save.inc
@@ -80,8 +80,8 @@ foreach ($GLOBALS['CONTACT_COLTYPES'] as $col => $colprop) {
// normalize the submitted date strings
if ($colprop['type'] == 'date') {
- if ($timestamp = rcube_utils::strtotime($a_record[$col])) {
- $a_record[$col] = date('Y-m-d', $timestamp);
+ if ($a_record[$col] && ($dt = rcube_utils::anytodatetime($a_record[$col]))) {
+ $a_record[$col] = $dt->format('Y-m-d');
}
else {
unset($a_record[$col]);
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index dc2452506..646d2bcd1 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -109,7 +109,8 @@ if (!is_array($COMPOSE))
$OUTPUT->add_label('nosubject', 'nosenderwarning', 'norecipientwarning', 'nosubjectwarning', 'cancel',
'nobodywarning', 'notsentwarning', 'notuploadedwarning', 'savingmessage', 'sendingmessage',
'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'uploadingmany',
- 'fileuploaderror', 'sendmessage');
+ 'fileuploaderror', 'sendmessage', 'savenewresponse', 'responsename', 'responsetext', 'save',
+ 'savingresponse');
$OUTPUT->set_env('compose_id', $COMPOSE['id']);
$OUTPUT->set_pagetitle(rcube_label('compose'));
@@ -852,29 +853,14 @@ function rcmail_compose_body($attrib)
// Set language list
if (!empty($CONFIG['enable_spellcheck'])) {
- $engine = $RCMAIL->config->get('spellcheck_engine','googie');
+ $engine = new rcube_spellchecker();
$dictionary = (bool) $RCMAIL->config->get('spellcheck_dictionary');
- $spellcheck_langs = (array) $RCMAIL->config->get('spellcheck_languages',
- array('da'=>'Dansk', 'de'=>'Deutsch', 'en' => 'English', 'es'=>'Español',
- 'fr'=>'Français', 'it'=>'Italiano', 'nl'=>'Nederlands', 'pl'=>'Polski',
- 'pt'=>'Português', 'ru'=>'Русский', 'fi'=>'Suomi', 'sv'=>'Svenska'));
-
- // googie works only with two-letter codes
- if ($engine == 'googie') {
- $lang = strtolower(substr($_SESSION['language'], 0, 2));
-
- $spellcheck_langs_googie = array();
- foreach ($spellcheck_langs as $key => $name)
- $spellcheck_langs_googie[strtolower(substr($key,0,2))] = $name;
- $spellcheck_langs = $spellcheck_langs_googie;
- }
- else {
- $lang = $_SESSION['language'];
+ $spellcheck_langs = $engine->languages();
+ $lang = $_SESSION['language'];
- // if not found in the list, try with two-letter code
- if (!$spellcheck_langs[$lang])
- $lang = strtolower(substr($lang, 0, 2));
- }
+ // if not found in the list, try with two-letter code
+ if (!$spellcheck_langs[$lang])
+ $lang = strtolower(substr($lang, 0, 2));
if (!$spellcheck_langs[$lang])
$lang = 'en';
@@ -1757,6 +1743,38 @@ function compose_file_drop_area($attrib)
}
+/**
+ *
+ */
+function rcmail_compose_responses_list($attrib)
+{
+ global $RCMAIL, $OUTPUT;
+
+ $attrib += array('id' => 'rcmresponseslist', 'tagname' => 'ul', 'cols' => 1);
+
+ $jsenv = array();
+ $list = new html_table($attrib);
+ foreach ($RCMAIL->get_compose_responses(true) as $response) {
+ $key = $response['key'];
+ $item = html::a(array(
+ 'href '=> '#'.urlencode($response['name']),
+ 'class' => rtrim('insertresponse ' . $attrib['itemclass']),
+ 'unselectable' => 'on',
+ 'rel' => $key,
+ ), Q($response['name']));
+
+ $jsenv[$key] = $response;
+ $list->add(array(), $item);
+ }
+
+ // set client env
+ $OUTPUT->set_env('textresponses', $jsenv);
+ $OUTPUT->add_gui_object('responseslist', $attrib['id']);
+
+ return $list->show();
+}
+
+
// register UI objects
$OUTPUT->add_handlers(array(
'composeheaders' => 'rcmail_compose_headers',
@@ -1773,6 +1791,7 @@ $OUTPUT->add_handlers(array(
'storetarget' => 'rcmail_store_target_selection',
'addressbooks' => 'rcmail_addressbook_list',
'addresslist' => 'rcmail_contacts_list',
+ 'responseslist' => 'rcmail_compose_responses_list',
));
$OUTPUT->send('compose');
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 48afecb60..78a977b82 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -97,6 +97,7 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list') {
$OUTPUT->set_env('delimiter', $delimiter);
$OUTPUT->set_env('threading', $threading);
$OUTPUT->set_env('threads', $threading || $RCMAIL->storage->get_capability('THREAD'));
+ $OUTPUT->set_env('reply_all_mode', (int) $RCMAIL->config->get('reply_all_mode'));
$OUTPUT->set_env('preview_pane_mark_read', $RCMAIL->config->get('preview_pane_mark_read', 0));
if ($RCMAIL->storage->get_capability('QUOTA')) {
$OUTPUT->set_env('quota', true);
@@ -1775,28 +1776,34 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r
}
}
- $from_idx = null;
- $found_idx = null;
- $default_identity = 0; // default identity is always first on the list
+ // decode From: address
+ $from = rcube_mime::decode_address_list($MESSAGE->headers->from, null, true, $MESSAGE->headers->charset);
+ $from = array_shift($from);
+ $from['mailto'] = strtolower($from['mailto']);
+
+ $from_idx = null;
+ $found_idx = array('to' => null, 'from' => null);
+ $check_from = in_array($compose_mode, array('draft', 'edit', 'reply'));
// Select identity
foreach ($identities as $idx => $ident) {
- // use From header
- if (in_array($compose_mode, array('draft', 'edit'))) {
- if ($MESSAGE->headers->from == $ident['ident']) {
+ // use From: header when in edit/draft or reply-to-self
+ if ($check_from && $from['mailto'] == strtolower($ident['email_ascii'])) {
+ // remember first matching identity address
+ if ($found_idx['from'] === null) {
+ $found_idx['from'] = $idx;
+ }
+ // match identity name
+ if ($from['name'] && $ident['name'] && $from['name'] == $ident['name']) {
$from_idx = $idx;
break;
}
}
- // reply to yourself
- else if ($compose_mode == 'reply' && $MESSAGE->headers->from == $ident['ident']) {
- $from_idx = $idx;
- break;
- }
- // use replied message recipients
+ // use replied/forwarded message recipients
else if (($found = array_search(strtolower($ident['email_ascii']), $a_recipients)) !== false) {
- if ($found_idx === null) {
- $found_idx = $idx;
+ // remember first matching identity address
+ if ($found_idx['to'] === null) {
+ $found_idx['to'] = $idx;
}
// match identity name
if ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name']) {
@@ -1806,22 +1813,27 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r
}
}
- // If matching by name+address doesn't found any matches, get first found address (identity)
+ // If matching by name+address didn't find any matches,
+ // get first found identity (address) if any
if ($from_idx === null) {
- $from_idx = $found_idx;
+ $from_idx = $found_idx['from'] !== null ? $found_idx['from'] : $found_idx['to'];
}
// Try Return-Path
if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) {
+ $return_path = array_map('strtolower', (array) $return_path);
+
foreach ($identities as $idx => $ident) {
// Return-Path header contains an email address, but on some mailing list
// it can be e.g. <pear-dev-return-55250-local=domain.tld@lists.php.net>
// where local@domain.tld is the address we're looking for (#1489241)
- $ident1 = $ident['email_ascii'];
+ $ident1 = strtolower($ident['email_ascii']);
$ident2 = str_replace('@', '=', $ident1);
+ $ident1 = '<' . $ident1 . '>';
+ $ident2 = '-' . $ident2 . '@';
- foreach ((array)$return_path as $path) {
- if (stripos($path, $ident1) !== false || stripos($path, $ident2)) {
+ foreach ($return_path as $path) {
+ if ($path == $ident1 || stripos($path, $ident2)) {
$from_idx = $idx;
break 2;
}
@@ -1835,7 +1847,8 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r
$selected = $plugin['selected'];
- return $identities[$selected !== null ? $selected : $default_identity];
+ // default identity is always first on the list
+ return $identities[$selected !== null ? $selected : 0];
}
// Fixes some content-type names
diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc
index ccb8978be..52b02ecff 100644
--- a/program/steps/mail/sendmail.inc
+++ b/program/steps/mail/sendmail.inc
@@ -615,22 +615,39 @@ else {
}
// add stored attachments, if any
-if (is_array($COMPOSE['attachments']))
-{
+if (is_array($COMPOSE['attachments'])) {
foreach ($COMPOSE['attachments'] as $id => $attachment) {
// This hook retrieves the attachment contents from the file storage backend
$attachment = $RCMAIL->plugins->exec_hook('attachment_get', $attachment);
- $dispurl = '/\ssrc\s*=\s*[\'"]*\S+display-attachment\S+file=rcmfile' . preg_quote($attachment['id']) . '[\s\'"]*/';
- $message_body = $MAIL_MIME->getHTMLBody();
- if ($isHtml && (preg_match($dispurl, $message_body) > 0)) {
- $message_body = preg_replace($dispurl, ' src="'.$attachment['name'].'" ', $message_body);
+ if ($isHtml) {
+ $dispurl = '/\ssrc\s*=\s*[\'"]*\S+display-attachment\S+file=rcmfile' . preg_quote($attachment['id']) . '[\s\'"]*/';
+ $message_body = $MAIL_MIME->getHTMLBody();
+ $is_inline = preg_match($dispurl, $message_body);
+ }
+ else {
+ $is_inline = false;
+ }
+
+ // inline image
+ if ($is_inline) {
+ // Mail_Mime does not support many inline attachments with the same name (#1489406)
+ // we'll generate cid: urls here to workaround this
+ $cid = preg_replace('/[^0-9a-zA-Z]/', '', uniqid(time(), true));
+ if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $from, $matches)) {
+ $cid .= $matches[1];
+ } else {
+ $cid .= '@localhost';
+ }
+
+ $message_body = preg_replace($dispurl, ' src="cid:' . $cid . '" ', $message_body);
+
$MAIL_MIME->setHTMLBody($message_body);
if ($attachment['data'])
- $MAIL_MIME->addHTMLImage($attachment['data'], $attachment['mimetype'], $attachment['name'], false);
+ $MAIL_MIME->addHTMLImage($attachment['data'], $attachment['mimetype'], $attachment['name'], false, $cid);
else
- $MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name'], true);
+ $MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name'], true, $cid);
}
else {
$ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914
diff --git a/program/steps/settings/edit_response.inc b/program/steps/settings/edit_response.inc
new file mode 100644
index 000000000..49856775a
--- /dev/null
+++ b/program/steps/settings/edit_response.inc
@@ -0,0 +1,107 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/steps/settings/edit_response.inc |
+ | |
+ | This file is part of the Roundcube Webmail client |
+ | Copyright (C) 2013, The Roundcube Dev Team |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | PURPOSE: |
+ | Show edit form for a canned response record or to add a new one |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+*/
+
+$responses = $RCMAIL->get_compose_responses();
+
+// edit-response
+if (($key = get_input_value('_key', RCUBE_INPUT_GPC))) {
+ foreach ($responses as $i => $response) {
+ if ($response['key'] == $key) {
+ $RESPONSE_RECORD = $response;
+ $RESPONSE_RECORD['index'] = $i;
+ break;
+ }
+ }
+}
+
+// save response
+if ($RCMAIL->action == 'save-response' && isset($_POST['_name']) && !$RESPONSE_RECORD['static']) {
+ $name = trim(get_input_value('_name', RCUBE_INPUT_POST));
+ $text = trim(get_input_value('_text', RCUBE_INPUT_POST));
+
+ if (!empty($name) && !empty($text)) {
+ $dupes = 0;
+ foreach ($responses as $i => $resp) {
+ if ($RESPONSE_RECORD && $RESPONSE_RECORD['index'] === $i)
+ continue;
+ if (strcasecmp($name, preg_replace('/\s\(\d+\)$/', '', $resp['name'])) == 0)
+ $dupes++;
+ }
+ if ($dupes) { // require a unique name
+ $name .= ' (' . ++$dupes . ')';
+ }
+
+ $response = array('name' => $name, 'text' => $text, 'format' => 'text', 'key' => substr(md5($name), 0, 16));
+ if ($RESPONSE_RECORD && $responses[$RESPONSE_RECORD['index']]) {
+ $responses[$RESPONSE_RECORD['index']] = $response;
+ }
+ else {
+ $responses[] = $response;
+ }
+
+ $responses = array_filter($responses, function($item){ return empty($item['static']); });
+ if ($RCMAIL->user->save_prefs(array('compose_responses' => array_values($responses)))) {
+ $RCMAIL->output->show_message('successfullysaved', 'confirmation');
+ $RCMAIL->output->command('parent.update_response_row', $response, $key);
+ $RCMAIL->overwrite_action('edit-response');
+ $RESPONSE_RECORD = $response;
+ }
+ }
+ else {
+ $RCMAIL->output->show_message('formincomplete', 'error');
+ }
+}
+
+
+function rcube_response_form($attrib)
+{
+ global $RCMAIL, $OUTPUT, $RESPONSE_RECORD;
+
+ // Set form tags and hidden fields
+ $disabled = !empty($RESPONSE_RECORD['static']);
+ $key = $RESPONSE_RECORD['key'];
+ list($form_start, $form_end) = get_form_tags($attrib, 'save-response', $key, array('name' => '_key', 'value' => $key));
+ unset($attrib['form'], $attrib['id']);
+
+ // return the complete edit form as table
+ $out = "$form_start\n";
+
+ $table = new html_table(array('cols' => 2));
+ $label = rcube_label('responsename');
+
+ $table->add('title', html::label('ffname', Q(rcube_label('responsename'))));
+ $table->add(null, rcube_output::get_edit_field('name', $RESPONSE_RECORD['name'], array('id' => 'ffname', 'size' => $attrib['size'], 'disabled' => $disabled), 'text'));
+
+ $table->add('title', html::label('fftext', Q(rcube_label('responsetext'))));
+ $table->add(null, rcube_output::get_edit_field('text', $RESPONSE_RECORD['text'], array('id' => 'fftext', 'size' => $attrib['textareacols'], 'rows' => $attrib['textarearows'], 'disabled' => $disabled), 'textarea'));
+
+ $out .= $table->show($attrib);
+ $out .= $form_end;
+
+ return $out;
+}
+
+$OUTPUT->set_env('readonly', !empty($RESPONSE_RECORD['static']));
+$OUTPUT->add_handler('responseform', 'rcube_response_form');
+$OUTPUT->set_pagetitle(rcube_label(($RCMAIL->action=='add-response' ? 'savenewresponse' : 'editresponse')));
+
+$OUTPUT->send('responseedit');
+
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index af278e5fa..c922aca08 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -869,6 +869,24 @@ function rcmail_user_prefs($current = null)
$select_default_font_size->show($RCMAIL->config->get('default_font_size', 1))
);
}
+
+ if (!isset($no_override['reply_all_mode'])) {
+ if (!$current) {
+ continue 2;
+ }
+
+ $field_id = 'rcmfd_reply_all_mode';
+ $select = new html_select(array('name' => '_reply_all_mode', 'id' => $field_id));
+
+ $select->add(rcube_label('replyalldefault'), 0);
+ $select->add(rcube_label('replyalllist'), 1);
+
+ $blocks['main']['options']['reply_all_mode'] = array(
+ 'title' => html::label($field_id, Q(rcube_label('replyallmode'))),
+ 'content' => $select->show(intval($config['reply_all_mode'])),
+ );
+ }
+
break;
// Addressbook config
@@ -1260,6 +1278,7 @@ function rcmail_settings_tabs($attrib)
array('command' => 'preferences', 'type' => 'link', 'label' => 'preferences', 'title' => 'editpreferences'),
array('command' => 'folders', 'type' => 'link', 'label' => 'folders', 'title' => 'managefolders'),
array('command' => 'identities', 'type' => 'link', 'label' => 'identities', 'title' => 'manageidentities'),
+ array('command' => 'responses', 'type' => 'link', 'label' => 'responses', 'title' => 'editresponses'),
);
// get all identites from DB and define list of cols to be displayed
@@ -1321,4 +1340,7 @@ $RCMAIL->register_action_map(array(
'purge' => 'folders.inc',
'folder-size' => 'folders.inc',
'add-identity' => 'edit_identity.inc',
+ 'add-response' => 'edit_response.inc',
+ 'save-response' => 'edit_response.inc',
+ 'delete-response' => 'responses.inc',
));
diff --git a/program/steps/settings/responses.inc b/program/steps/settings/responses.inc
new file mode 100644
index 000000000..cfc4148c3
--- /dev/null
+++ b/program/steps/settings/responses.inc
@@ -0,0 +1,128 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/steps/settings/responses.inc |
+ | |
+ | This file is part of the Roundcube Webmail client |
+ | Copyright (C) 2013, The Roundcube Dev Team |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | PURPOSE: |
+ | Manage and save canned response texts |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+*/
+
+
+if (!empty($_POST['_insert'])) {
+ $name = trim(get_input_value('_name', RCUBE_INPUT_POST));
+ $text = trim(get_input_value('_text', RCUBE_INPUT_POST));
+
+ if (!empty($name) && !empty($text)) {
+ $dupes = 0;
+ $responses = $RCMAIL->get_compose_responses(false, true);
+ foreach ($responses as $resp) {
+ if (strcasecmp($name, preg_replace('/\s\(\d+\)$/', '', $resp['name'])) == 0)
+ $dupes++;
+ }
+ if ($dupes) { // require a unique name
+ $name .= ' (' . ++$dupes . ')';
+ }
+
+ $response = array('name' => $name, 'text' => $text, 'format' => 'text', 'key' => substr(md5($name), 0, 16));
+ $responses[] = $response;
+
+ if ($RCMAIL->user->save_prefs(array('compose_responses' => $responses))) {
+ $RCMAIL->output->command('add_response_item', $response);
+ $RCMAIL->output->command('display_message', rcube_label('successfullysaved'), 'confirmation');
+ }
+ else {
+ $RCMAIL->output->command('display_message', rcube_label('errorsaving'), 'error');
+ }
+ }
+
+ // send response
+ $RCMAIL->output->send();
+}
+
+
+if ($RCMAIL->action == 'delete-response') {
+ if ($key = get_input_value('_key', RCUBE_INPUT_GPC)) {
+ $responses = $RCMAIL->get_compose_responses(false, true);
+ foreach ($responses as $i => $response) {
+ if (empty($response['key']))
+ $response['key'] = substr(md5($response['name']), 0, 16);
+ if ($response['key'] == $key) {
+ unset($responses[$i]);
+ $deleted = $RCMAIL->user->save_prefs(array('compose_responses' => $responses));
+ break;
+ }
+ }
+ }
+
+ if ($deleted) {
+ $RCMAIL->output->command('display_message', rcube_label('deletedsuccessfully'), 'confirmation');
+ $RCMAIL->output->command('remove_response', $key);
+ }
+
+ if ($RCMAIL->output->ajax_call) {
+ $RCMAIL->output->send();
+ }
+}
+
+
+$OUTPUT->set_pagetitle(rcube_label('responses'));
+$OUTPUT->include_script('list.js');
+
+
+/**
+ *
+ */
+function rcmail_responses_list($attrib)
+{
+ global $RCMAIL, $OUTPUT;
+
+ $attrib += array('id' => 'rcmresponseslist', 'tagname' => 'table', 'cols' => 1);
+
+ $plugin = $RCMAIL->plugins->exec_hook('responses_list', array(
+ 'list' => $RCMAIL->get_compose_responses(true),
+ 'cols' => array('name')
+ ));
+
+ $out = rcube_table_output($attrib, $plugin['list'], $plugin['cols'], 'key');
+
+ // set client env
+ $OUTPUT->add_gui_object('responseslist', $attrib['id']);
+ $OUTPUT->set_env('readonly_responses', array_values(array_map(function($rec){ return $rec['key']; },
+ array_filter($plugin['list'], function($item){ return !empty($item['static']); }))));
+
+ return $out;
+}
+
+
+// similar function as /steps/addressbook/func.inc::rcmail_contact_frame()
+function rcmail_response_frame($attrib)
+{
+ global $OUTPUT;
+
+ if (!$attrib['id']) {
+ $attrib['id'] = 'rcmResponseFrame';
+ }
+
+ $OUTPUT->set_env('contentframe', $attrib['id']);
+ return $OUTPUT->frame($attrib, true);
+}
+
+$OUTPUT->add_handlers(array(
+ 'responseframe' => 'rcmail_response_frame',
+ 'responseslist' => 'rcmail_responses_list',
+));
+$OUTPUT->add_label('deleteresponseconfirm');
+
+$OUTPUT->send('responses');
diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc
index 717c7ad8c..bcd05bb85 100644
--- a/program/steps/settings/save_prefs.inc
+++ b/program/steps/settings/save_prefs.inc
@@ -90,6 +90,7 @@ switch ($CURR_SECTION)
'strip_existing_sig' => isset($_POST['_strip_existing_sig']),
'default_font' => get_input_value('_default_font', RCUBE_INPUT_POST),
'default_font_size' => get_input_value('_default_font_size', RCUBE_INPUT_POST),
+ 'reply_all_mode' => intval($_POST['_reply_all_mode']),
'forward_attachment' => !empty($_POST['_forward_attachment']),
);
diff --git a/program/steps/utils/save_pref.inc b/program/steps/utils/save_pref.inc
index 7def8733d..7c30be71b 100644
--- a/program/steps/utils/save_pref.inc
+++ b/program/steps/utils/save_pref.inc
@@ -5,7 +5,7 @@
| program/steps/utils/save_pref.inc |
| |
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2010, The Roundcube Dev Team |
+ | Copyright (C) 2005-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -19,16 +19,26 @@
+-----------------------------------------------------------------------+
*/
-$name = get_input_value('_name', RCUBE_INPUT_POST);
-$value = get_input_value('_value', RCUBE_INPUT_POST);
+$name = get_input_value('_name', RCUBE_INPUT_POST);
+$value = get_input_value('_value', RCUBE_INPUT_POST);
+$sessname = get_input_value('_session', RCUBE_INPUT_POST);
+
+// Whitelisted preferences and session variables, others
+// can be added by plugins
$whitelist = array(
'preview_pane',
'list_cols',
'collapsed_folders',
'collapsed_abooks',
);
+$whitelist_sess = array(
+ 'list_attrib/columns',
+);
+
+$whitelist = array_merge($whitelist, $RCMAIL->plugins->allowed_prefs);
+$whitelist_sess = array_merge($whitelist_sess, $RCMAIL->plugins->allowed_session_prefs);
-if (!in_array($name, array_merge($whitelist, $RCMAIL->plugins->allowed_prefs))) {
+if (!in_array($name, $whitelist) || ($sessname && !in_array($sessname, $whitelist_sess))) {
raise_error(array('code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => sprintf("Hack attempt detected (user: %s)", $RCMAIL->get_user_name())),
@@ -42,7 +52,7 @@ if (!in_array($name, array_merge($whitelist, $RCMAIL->plugins->allowed_prefs)))
$RCMAIL->user->save_prefs(array($name => $value));
// update also session if requested
-if ($sessname = get_input_value('_session', RCUBE_INPUT_POST)) {
+if ($sessname) {
// Support multidimensional arrays...
$vars = explode('/', $sessname);
@@ -57,5 +67,3 @@ if ($sessname = get_input_value('_session', RCUBE_INPUT_POST)) {
$OUTPUT->reset();
$OUTPUT->send();
-
-
diff --git a/program/steps/utils/spell.inc b/program/steps/utils/spell.inc
index 1c68e8328..595cfd6f2 100644
--- a/program/steps/utils/spell.inc
+++ b/program/steps/utils/spell.inc
@@ -47,6 +47,9 @@ if ($err = $spellchecker->error()) {
'file' => __FILE__, 'line' => __LINE__,
'message' => "Spell check engine error: " . trim($err)),
true, false);
+
+ header("HTTP/1.0 500 Internal Server Error");
+ exit;
}
// set response length