Page MenuHomePhorge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index 2c22d5a47..008d20174 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -1,942 +1,942 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/addressbook/func.inc |
| |
| This file is part of the Roundcube Webmail client |
| 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. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide addressbook functionality and GUI objects |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
$SEARCH_MODS_DEFAULT = array('name'=>1, 'firstname'=>1, 'surname'=>1, 'email'=>1, '*'=>1);
// general definition of contact coltypes
$CONTACT_COLTYPES = array(
'name' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('name'), 'category' => 'main'),
'firstname' => array('type' => 'text', 'size' => 19, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('firstname'), 'category' => 'main'),
'surname' => array('type' => 'text', 'size' => 19, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('surname'), 'category' => 'main'),
'email' => array('type' => 'text', 'size' => 40, 'maxlength' => 254, 'label' => $RCMAIL->gettext('email'), 'subtypes' => array('home','work','other'), 'category' => 'main'),
'middlename' => array('type' => 'text', 'size' => 19, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('middlename'), 'category' => 'main'),
'prefix' => array('type' => 'text', 'size' => 8, 'maxlength' => 20, 'limit' => 1, 'label' => $RCMAIL->gettext('nameprefix'), 'category' => 'main'),
'suffix' => array('type' => 'text', 'size' => 8, 'maxlength' => 20, 'limit' => 1, 'label' => $RCMAIL->gettext('namesuffix'), 'category' => 'main'),
'nickname' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('nickname'), 'category' => 'main'),
'jobtitle' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('jobtitle'), 'category' => 'main'),
'organization' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('organization'), 'category' => 'main'),
'department' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('department'), 'category' => 'main'),
'gender' => array('type' => 'select', 'limit' => 1, 'label' => $RCMAIL->gettext('gender'), 'options' => array('male' => $RCMAIL->gettext('male'), 'female' => $RCMAIL->gettext('female')), 'category' => 'personal'),
'maidenname' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('maidenname'), 'category' => 'personal'),
'phone' => array('type' => 'text', 'size' => 40, 'maxlength' => 20, 'label' => $RCMAIL->gettext('phone'), 'subtypes' => array('home','home2','work','work2','mobile','main','homefax','workfax','car','pager','video','assistant','other'), 'category' => 'main'),
'address' => array('type' => 'composite', 'label' => $RCMAIL->gettext('address'), 'subtypes' => array('home','work','other'), 'childs' => array(
'street' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'label' => $RCMAIL->gettext('street'), 'category' => 'main'),
'locality' => array('type' => 'text', 'size' => 28, 'maxlength' => 50, 'label' => $RCMAIL->gettext('locality'), 'category' => 'main'),
'zipcode' => array('type' => 'text', 'size' => 8, 'maxlength' => 15, 'label' => $RCMAIL->gettext('zipcode'), 'category' => 'main'),
'region' => array('type' => 'text', 'size' => 12, 'maxlength' => 50, 'label' => $RCMAIL->gettext('region'), 'category' => 'main'),
'country' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'label' => $RCMAIL->gettext('country'), 'category' => 'main'),
), 'category' => 'main'),
'birthday' => array('type' => 'date', 'size' => 12, 'maxlength' => 16, 'label' => $RCMAIL->gettext('birthday'), 'limit' => 1, 'render_func' => 'rcmail_format_date_col', 'category' => 'personal'),
'anniversary' => array('type' => 'date', 'size' => 12, 'maxlength' => 16, 'label' => $RCMAIL->gettext('anniversary'), 'limit' => 1, 'render_func' => 'rcmail_format_date_col', 'category' => 'personal'),
'website' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'label' => $RCMAIL->gettext('website'), 'subtypes' => array('homepage','work','blog','profile','other'), 'category' => 'main'),
'im' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'label' => $RCMAIL->gettext('instantmessenger'), 'subtypes' => array('aim','icq','msn','yahoo','jabber','skype','other'), 'category' => 'main'),
'notes' => array('type' => 'textarea', 'size' => 40, 'rows' => 15, 'maxlength' => 500, 'label' => $RCMAIL->gettext('notes'), 'limit' => 1),
'photo' => array('type' => 'image', 'limit' => 1, 'category' => 'main'),
'assistant' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('assistant'), 'category' => 'personal'),
'manager' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('manager'), 'category' => 'personal'),
'spouse' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('spouse'), 'category' => 'personal'),
// TODO: define fields for vcards like GEO, KEY
);
$PAGE_SIZE = $RCMAIL->config->get('addressbook_pagesize', $RCMAIL->config->get('pagesize', 50));
// Addressbook UI
if (!$RCMAIL->action && !$OUTPUT->ajax_call) {
// add list of address sources to client env
$js_list = $RCMAIL->get_address_sources();
// count all/writeable sources
$writeable = 0;
$count = 0;
foreach ($js_list as $sid => $s) {
$count++;
if (!$s['readonly']) {
$writeable++;
}
// unset hidden sources
if ($s['hidden']) {
unset($js_list[$sid]);
}
}
$search_mods = $RCMAIL->config->get('addressbook_search_mods', $SEARCH_MODS_DEFAULT);
$OUTPUT->set_env('search_mods', $search_mods);
$OUTPUT->set_env('address_sources', $js_list);
$OUTPUT->set_env('writable_source', $writeable);
$OUTPUT->set_pagetitle($RCMAIL->gettext('addressbook'));
$_SESSION['addressbooks_count'] = $count;
$_SESSION['addressbooks_count_writeable'] = $writeable;
// select address book
$source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
// use first directory by default
if (!strlen($source) || !isset($js_list[$source])) {
$source = $RCMAIL->config->get('default_addressbook');
if (!strlen($source) || !isset($js_list[$source])) {
$source = strval(key($js_list));
}
}
$CONTACTS = rcmail_contact_source($source, true);
}
// remove undo information...
if ($undo = $_SESSION['contact_undo']) {
// ...after timeout
$undo_time = $RCMAIL->config->get('undo_timeout', 0);
if ($undo['ts'] < time() - $undo_time)
$RCMAIL->session->remove('contact_undo');
}
// register UI objects
$OUTPUT->add_handlers(array(
'directorylist' => 'rcmail_directory_list',
'savedsearchlist' => 'rcmail_savedsearch_list',
'addresslist' => 'rcmail_contacts_list',
'addresslisttitle' => 'rcmail_contacts_list_title',
'addressframe' => 'rcmail_contact_frame',
'recordscountdisplay' => 'rcmail_rowcount_display',
'searchform' => array($OUTPUT, 'search_form')
));
// register action aliases
$RCMAIL->register_action_map(array(
'add' => 'edit.inc',
'group-create' => 'groups.inc',
'group-rename' => 'groups.inc',
'group-delete' => 'groups.inc',
'group-addmembers' => 'groups.inc',
'group-delmembers' => 'groups.inc',
'search-create' => 'search.inc',
'search-delete' => 'search.inc',
));
// instantiate a contacts object according to the given source
function rcmail_contact_source($source=null, $init_env=false, $writable=false)
{
global $RCMAIL, $OUTPUT, $CONTACT_COLTYPES, $PAGE_SIZE;
if (!strlen($source)) {
$source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
}
// Get object
$CONTACTS = $RCMAIL->get_address_book($source, $writable);
$CONTACTS->set_pagesize($PAGE_SIZE);
// set list properties and session vars
if (!empty($_GET['_page']))
$CONTACTS->set_page(($_SESSION['page'] = intval($_GET['_page'])));
else
$CONTACTS->set_page(isset($_SESSION['page']) ? $_SESSION['page'] : 1);
if (!empty($_REQUEST['_gid']))
$CONTACTS->set_group(rcube_utils::get_input_value('_gid', rcube_utils::INPUT_GPC));
if (!$init_env)
return $CONTACTS;
$OUTPUT->set_env('readonly', $CONTACTS->readonly);
$OUTPUT->set_env('source', (string) $source);
// reduce/extend $CONTACT_COLTYPES with specification from the current $CONTACT object
if (is_array($CONTACTS->coltypes)) {
// remove cols not listed by the backend class
$contact_cols = $CONTACTS->coltypes[0] ? array_flip($CONTACTS->coltypes) : $CONTACTS->coltypes;
$CONTACT_COLTYPES = array_intersect_key($CONTACT_COLTYPES, $contact_cols);
// add associative coltypes definition
if (!$CONTACTS->coltypes[0]) {
foreach ($CONTACTS->coltypes as $col => $colprop) {
if (is_array($colprop['childs'])) {
foreach ($colprop['childs'] as $childcol => $childprop)
$colprop['childs'][$childcol] = array_merge((array)$CONTACT_COLTYPES[$col]['childs'][$childcol], $childprop);
}
$CONTACT_COLTYPES[$col] = $CONTACT_COLTYPES[$col] ? array_merge($CONTACT_COLTYPES[$col], $colprop) : $colprop;
}
}
}
$OUTPUT->set_env('photocol', is_array($CONTACT_COLTYPES['photo']));
return $CONTACTS;
}
function rcmail_set_sourcename($abook)
{
global $OUTPUT, $RCMAIL;
// get address book name (for display)
if ($abook && $_SESSION['addressbooks_count'] > 1) {
$name = $abook->get_name();
if (!$name) {
$name = $RCMAIL->gettext('personaladrbook');
}
$OUTPUT->set_env('sourcename', html_entity_decode($name, ENT_COMPAT, 'UTF-8'));
}
}
function rcmail_directory_list($attrib)
{
global $RCMAIL, $OUTPUT;
if (!$attrib['id'])
$attrib['id'] = 'rcmdirectorylist';
$out = '';
$jsdata = array();
$line_templ = html::tag('li', array(
'id' => 'rcmli%s', 'class' => '%s', 'noclose' => true),
html::a(array('href' => '%s',
'rel' => '%s',
'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('list','%s',this)"), '%s'));
$sources = (array) $OUTPUT->get_env('address_sources');
reset($sources);
// currently selected source
$current = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
foreach ($sources as $j => $source) {
$id = strval(strlen($source['id']) ? $source['id'] : $j);
$js_id = rcube::JQ($id);
// set class name(s)
$class_name = 'addressbook';
if ($current === $id)
$class_name .= ' selected';
if ($source['readonly'])
$class_name .= ' readonly';
if ($source['class_name'])
$class_name .= ' ' . $source['class_name'];
$name = !empty($source['name']) ? $source['name'] : $id;
$out .= sprintf($line_templ,
rcube_utils::html_identifier($id, true),
$class_name,
rcube::Q($RCMAIL->url(array('_source' => $id))),
$source['id'],
$js_id, $name);
$groupdata = array('out' => $out, 'jsdata' => $jsdata, 'source' => $id);
if ($source['groups'])
$groupdata = rcmail_contact_groups($groupdata);
$jsdata = $groupdata['jsdata'];
$out = $groupdata['out'];
$out .= '</li>';
}
$OUTPUT->set_env('contactgroups', $jsdata);
$OUTPUT->set_env('collapsed_abooks', (string)$RCMAIL->config->get('collapsed_abooks',''));
$OUTPUT->add_gui_object('folderlist', $attrib['id']);
$OUTPUT->include_script('treelist.js');
// add some labels to client
$OUTPUT->add_label('deletegroupconfirm', 'groupdeleting', 'addingmember', 'removingmember',
'newgroup', 'grouprename', 'searchsave', 'namex', 'save'
);
return html::tag('ul', $attrib, $out, html::$common_attrib);
}
function rcmail_savedsearch_list($attrib)
{
global $RCMAIL, $OUTPUT;
if (!$attrib['id'])
$attrib['id'] = 'rcmsavedsearchlist';
$out = '';
$line_templ = html::tag('li', array(
'id' => 'rcmli%s', 'class' => '%s'),
html::a(array('href' => '#', 'rel' => 'S%s',
'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('listsearch', '%s', this)"), '%s'));
// Saved searches
$sources = $RCMAIL->user->list_searches(rcube_user::SEARCH_ADDRESSBOOK);
- foreach ($sources as $j => $source) {
- $id = $source['id'];
+ foreach ($sources as $source) {
+ $id = $source['id'];
$js_id = rcube::JQ($id);
// set class name(s)
$classes = array('contactsearch');
if (!empty($source['class_name']))
$classes[] = $source['class_name'];
$out .= sprintf($line_templ,
rcube_utils::html_identifier('S'.$id, true),
join(' ', $classes),
$id,
$js_id, (!empty($source['name']) ? rcube::Q($source['name']) : rcube::Q($id))
);
}
$OUTPUT->add_gui_object('savedsearchlist', $attrib['id']);
return html::tag('ul', $attrib, $out, html::$common_attrib);
}
function rcmail_contact_groups($args)
{
global $RCMAIL;
$groups_html = '';
$groups = $RCMAIL->get_address_book($args['source'])->list_groups();
if (!empty($groups)) {
$line_templ = html::tag('li', array(
'id' => 'rcmli%s', 'class' => 'contactgroup'),
html::a(array('href' => '#',
'rel' => '%s:%s',
'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('listgroup',{'source':'%s','id':'%s'},this)"), '%s'));
// append collapse/expand toggle and open a new <ul>
$is_collapsed = strpos($RCMAIL->config->get('collapsed_abooks',''), '&'.rawurlencode($args['source']).'&') !== false;
$args['out'] .= html::div('treetoggle ' . ($is_collapsed ? 'collapsed' : 'expanded'), '&nbsp;');
foreach ($groups as $group) {
$groups_html .= sprintf($line_templ,
rcube_utils::html_identifier('G' . $args['source'] . $group['ID'], true),
$args['source'], $group['ID'],
$args['source'], $group['ID'], rcube::Q($group['name'])
);
$args['jsdata']['G'.$args['source'].$group['ID']] = array(
'source' => $args['source'], 'id' => $group['ID'],
'name' => $group['name'], 'type' => 'group');
}
}
$args['out'] .= html::tag('ul',
array('class' => 'groups', 'style' => ($is_collapsed || empty($groups) ? "display:none;" : null)),
$groups_html);
return $args;
}
// return the contacts list as HTML table
function rcmail_contacts_list($attrib)
{
global $RCMAIL, $CONTACTS, $OUTPUT;
// define list of cols to be displayed
$a_show_cols = array('name','action');
// add id to message list table if not specified
if (!strlen($attrib['id']))
$attrib['id'] = 'rcmAddressList';
// create XHTML table
$out = $RCMAIL->table_output($attrib, array(), $a_show_cols, $CONTACTS->primary_key);
// set client env
$OUTPUT->add_gui_object('contactslist', $attrib['id']);
$OUTPUT->set_env('current_page', (int)$CONTACTS->list_page);
$OUTPUT->include_script('list.js');
// add some labels to client
$OUTPUT->add_label('deletecontactconfirm', 'copyingcontact', 'movingcontact', 'contactdeleting');
return $out;
}
function rcmail_js_contacts_list($result, $prefix='')
{
global $OUTPUT, $RCMAIL;
if (empty($result) || $result->count == 0)
return;
// define list of cols to be displayed
$a_show_cols = array('name','action');
while ($row = $result->next()) {
$row['CID'] = $row['ID'];
$row['email'] = reset(rcube_addressbook::get_col_values('email', $row, true));
$source_id = $OUTPUT->get_env('source');
$a_row_cols = array();
$classes = array($row['_type'] ? $row['_type'] : 'person');
// build contact ID with source ID
if (isset($row['sourceid'])) {
$row['ID'] = $row['ID'].'-'.$row['sourceid'];
$source_id = $row['sourceid'];
}
// format each col
foreach ($a_show_cols as $col) {
$val = '';
switch ($col) {
case 'name':
$val = rcube::Q(rcube_addressbook::compose_list_name($row));
break;
case 'action':
if ($row['_type'] == 'group') {
$val = html::a(array(
'href' => '#list',
'rel' => $row['ID'],
'title' => $RCMAIL->gettext('listgroup'),
'onclick' => sprintf("return %s.command('pushgroup',{'source':'%s','id':'%s'},this,event)", rcmail_output::JS_OBJECT_NAME, $source_id, $row['CID']),
), '&raquo;');
}
else
$val = '';
break;
default:
$val = rcube::Q($row[$col]);
break;
}
$a_row_cols[$col] = $val;
}
if ($row['readonly'])
$classes[] = 'readonly';
$OUTPUT->command($prefix.'add_contact_row', $row['ID'], $a_row_cols, join(' ', $classes), array_intersect_key($row, array('ID'=>1,'readonly'=>1,'_type'=>1,'email'=>1,'name'=>1)));
}
}
function rcmail_contacts_list_title($attrib)
{
global $OUTPUT, $RCMAIL;
$attrib += array('label' => 'contacts', 'id' => 'rcmabooklisttitle', 'tag' => 'span');
unset($attrib['name']);
$OUTPUT->add_gui_object('addresslist_title', $attrib['id']);
$OUTPUT->add_label('contacts','uponelevel');
return html::tag($attrib['tag'], $attrib, $RCMAIL->gettext($attrib['label']), html::$common_attrib);
}
// similar function as /steps/settings/identities.inc::rcmail_identity_frame()
function rcmail_contact_frame($attrib)
{
global $OUTPUT;
if (!$attrib['id'])
$attrib['id'] = 'rcmcontactframe';
return $OUTPUT->frame($attrib, true);
}
function rcmail_rowcount_display($attrib)
{
global $RCMAIL;
if (!$attrib['id'])
$attrib['id'] = 'rcmcountdisplay';
$RCMAIL->output->add_gui_object('countdisplay', $attrib['id']);
if ($attrib['label'])
$_SESSION['contactcountdisplay'] = $attrib['label'];
return html::span($attrib, $RCMAIL->gettext('loading'));
}
function rcmail_get_rowcount_text($result=null)
{
global $RCMAIL, $CONTACTS, $PAGE_SIZE;
// read nr of contacts
if (!$result) {
$result = $CONTACTS->get_result();
}
if ($result->count == 0)
$out = $RCMAIL->gettext('nocontactsfound');
else
$out = $RCMAIL->gettext(array(
'name' => $_SESSION['contactcountdisplay'] ? $_SESSION['contactcountdisplay'] : 'contactsfromto',
'vars' => array(
'from' => $result->first + 1,
'to' => min($result->count, $result->first + $PAGE_SIZE),
'count' => $result->count)
));
return $out;
}
function rcmail_get_type_label($type)
{
global $RCMAIL;
$label = 'type'.$type;
if ($RCMAIL->text_exists($label, '*', $domain))
return $RCMAIL->gettext($label, $domain);
else if (preg_match('/\w+(\d+)$/', $label, $m)
&& ($label = preg_replace('/(\d+)$/', '', $label))
&& $RCMAIL->text_exists($label, '*', $domain))
return $RCMAIL->gettext($label, $domain) . ' ' . $m[1];
return ucfirst($type);
}
function rcmail_contact_form($form, $record, $attrib = null)
{
global $RCMAIL;
// Allow plugins to modify contact form content
$plugin = $RCMAIL->plugins->exec_hook('contact_form', array(
'form' => $form, 'record' => $record));
$form = $plugin['form'];
$record = $plugin['record'];
$edit_mode = $RCMAIL->action != 'show';
$del_button = $attrib['deleteicon'] ? html::img(array('src' => $RCMAIL->output->get_skin_file($attrib['deleteicon']), 'alt' => $RCMAIL->gettext('delete'))) : $RCMAIL->gettext('delete');
unset($attrib['deleteicon']);
$out = '';
// get default coltypes
$coltypes = $GLOBALS['CONTACT_COLTYPES'];
$coltype_labels = array();
foreach ($coltypes as $col => $prop) {
if ($prop['subtypes']) {
$subtype_names = array_map('rcmail_get_type_label', $prop['subtypes']);
$select_subtype = new html_select(array('name' => '_subtype_'.$col.'[]', 'class' => 'contactselectsubtype', 'title' => $prop['label'] . ' ' . $RCMAIL->gettext('type')));
$select_subtype->add($subtype_names, $prop['subtypes']);
$coltypes[$col]['subtypes_select'] = $select_subtype->show();
}
if ($prop['childs']) {
foreach ($prop['childs'] as $childcol => $cp)
$coltype_labels[$childcol] = array('label' => $cp['label']);
}
}
foreach ($form as $section => $fieldset) {
// skip empty sections
if (empty($fieldset['content']))
continue;
$select_add = new html_select(array('class' => 'addfieldmenu', 'rel' => $section));
$select_add->add($RCMAIL->gettext('addfield'), '');
// render head section with name fields (not a regular list of rows)
if ($section == 'head') {
$content = '';
// unset display name if it is composed from name parts
if ($record['name'] == rcube_addressbook::compose_display_name(array('name' => '') + (array)$record))
unset($record['name']);
// group fields
$field_blocks = array(
'names' => array('prefix','firstname','middlename','surname','suffix'),
'displayname' => array('name'),
'nickname' => array('nickname'),
'organization' => array('organization'),
'department' => array('department'),
'jobtitle' => array('jobtitle'),
);
foreach ($field_blocks as $blockname => $colnames) {
$fields = '';
foreach ($colnames as $col) {
// skip cols unknown to the backend
if (!$coltypes[$col])
continue;
// only string values are expected here
if (is_array($record[$col]))
$record[$col] = join(' ', $record[$col]);
if ($RCMAIL->action == 'show') {
if (!empty($record[$col]))
$fields .= html::span('namefield ' . $col, rcube::Q($record[$col])) . " ";
}
else {
$colprop = (array)$fieldset['content'][$col] + (array)$coltypes[$col];
$colprop['id'] = 'ff_'.$col;
if (empty($record[$col]) && !$colprop['visible']) {
$colprop['style'] = 'display:none';
$select_add->add($colprop['label'], $col);
}
$fields .= rcube_output::get_edit_field($col, $record[$col], $colprop, $colprop['type']);
}
}
$content .= html::div($blockname, $fields);
}
if ($edit_mode)
$content .= html::p('addfield', $select_add->show(null));
$out .= html::tag('fieldset', $attrib, (!empty($fieldset['name']) ? html::tag('legend', null, rcube::Q($fieldset['name'])) : '') . $content) ."\n";
continue;
}
$content = '';
if (is_array($fieldset['content'])) {
foreach ($fieldset['content'] as $col => $colprop) {
// remove subtype part of col name
list($field, $subtype) = explode(':', $col);
if (!$subtype) $subtype = 'home';
$fullkey = $col.':'.$subtype;
// skip cols unknown to the backend
if (!$coltypes[$field])
continue;
// merge colprop with global coltype configuration
$colprop += $coltypes[$field];
$label = isset($colprop['label']) ? $colprop['label'] : $RCMAIL->gettext($col);
// prepare subtype selector in edit mode
if ($edit_mode && is_array($colprop['subtypes'])) {
$subtype_names = array_map('rcmail_get_type_label', $colprop['subtypes']);
$select_subtype = new html_select(array('name' => '_subtype_'.$col.'[]', 'class' => 'contactselectsubtype', 'title' => $colprop['label'] . ' ' . $RCMAIL->gettext('type')));
$select_subtype->add($subtype_names, $colprop['subtypes']);
}
else
$select_subtype = null;
if (!empty($colprop['value'])) {
$values = (array)$colprop['value'];
}
else {
// iterate over possible subtypes and collect values with their subtype
if (is_array($colprop['subtypes'])) {
$values = $subtypes = array();
foreach (rcube_addressbook::get_col_values($field, $record) as $st => $vals) {
foreach((array)$vals as $value) {
$i = count($values);
$subtypes[$i] = $st;
$values[$i] = $value;
}
// TODO: add $st to $select_subtype if missing ?
}
}
else {
$values = $record[$fullkey] ? $record[$fullkey] : $record[$field];
$subtypes = null;
}
}
// hack: create empty values array to force this field to be displayed
if (empty($values) && $colprop['visible'])
$values[] = '';
if (!is_array($values)) {
// $values can be an object, don't use (array)$values syntax
$values = !empty($values) ? array($values) : array();
}
$rows = '';
foreach ($values as $i => $val) {
if ($subtypes[$i])
$subtype = $subtypes[$i];
$colprop['id'] = 'ff_' . $col . intval($coltypes[$field]['count']);
// render composite field
if ($colprop['type'] == 'composite') {
$composite = array(); $j = 0;
$template = $RCMAIL->config->get($col . '_template', '{'.join('} {', array_keys($colprop['childs'])).'}');
foreach ($colprop['childs'] as $childcol => $cp) {
if (!empty($val) && is_array($val)) {
$childvalue = $val[$childcol] ? $val[$childcol] : $val[$j];
}
else {
$childvalue = '';
}
if ($edit_mode) {
if ($colprop['subtypes'] || $colprop['limit'] != 1) $cp['array'] = true;
$composite['{'.$childcol.'}'] = rcube_output::get_edit_field($childcol, $childvalue, $cp, $cp['type']) . " ";
}
else {
$childval = $cp['render_func'] ? call_user_func($cp['render_func'], $childvalue, $childcol) : rcube::Q($childvalue);
$composite['{'.$childcol.'}'] = html::span('data ' . $childcol, $childval) . " ";
}
$j++;
}
$coltypes[$field] += (array)$colprop;
$coltypes[$field]['count']++;
$val = preg_replace('/\{\w+\}/', '', strtr($template, $composite));
}
else if ($edit_mode) {
// call callback to render/format value
if ($colprop['render_func'])
$val = call_user_func($colprop['render_func'], $val, $col);
$coltypes[$field] = (array)$colprop + $coltypes[$field];
if ($colprop['subtypes'] || $colprop['limit'] != 1)
$colprop['array'] = true;
// load jquery UI datepicker for date fields
if ($colprop['type'] == 'date') {
$colprop['class'] .= ($colprop['class'] ? ' ' : '') . 'datepicker';
if (!$colprop['render_func'])
$val = rcmail_format_date_col($val);
}
$val = rcube_output::get_edit_field($col, $val, $colprop, $colprop['type']);
$coltypes[$field]['count']++;
}
else if ($colprop['render_func'])
$val = call_user_func($colprop['render_func'], $val, $col);
else if (is_array($colprop['options']) && isset($colprop['options'][$val]))
$val = $colprop['options'][$val];
else
$val = rcube::Q($val);
// use subtype as label
if ($colprop['subtypes'])
$label = rcmail_get_type_label($subtype);
// add delete button/link
if ($edit_mode && !($colprop['visible'] && $colprop['limit'] == 1))
$val .= html::a(array('href' => '#del', 'class' => 'contactfieldbutton deletebutton', 'title' => $RCMAIL->gettext('delete'), 'rel' => $col), $del_button);
// display row with label
if ($label) {
$rows .= html::div('row',
html::div('contactfieldlabel label', $select_subtype ? $select_subtype->show($subtype) : html::label($colprop['id'], rcube::Q($label))) .
html::div('contactfieldcontent '.$colprop['type'], $val));
}
else // row without label
$rows .= html::div('row', html::div('contactfield', $val));
}
// add option to the add-field menu
if (!$colprop['limit'] || $coltypes[$field]['count'] < $colprop['limit']) {
$select_add->add($colprop['label'], $col);
$select_add->_count++;
}
// wrap rows in fieldgroup container
if ($rows) {
$content .= html::tag('fieldset', array('class' => 'contactfieldgroup ' . ($colprop['subtypes'] ? 'contactfieldgroupmulti ' : '') . 'contactcontroller' . $col, 'style' => ($rows ? null : 'display:none')),
($colprop['subtypes'] ? html::tag('legend', null, rcube::Q($colprop['label'])) : ' ') .
$rows);
}
}
if (!$content && (!$edit_mode || !$select_add->_count))
continue;
// also render add-field selector
if ($edit_mode)
$content .= html::p('addfield', $select_add->show(null, array('style' => $select_add->_count ? null : 'display:none')));
$content = html::div(array('id' => 'contactsection' . $section), $content);
}
else {
$content = $fieldset['content'];
}
if ($content)
$out .= html::tag('fieldset', null, html::tag('legend', null, rcube::Q($fieldset['name'])) . $content) ."\n";
}
if ($edit_mode) {
$RCMAIL->output->set_env('coltypes', $coltypes + $coltype_labels);
$RCMAIL->output->set_env('delbutton', $del_button);
$RCMAIL->output->add_label('delete');
}
return $out;
}
function rcmail_contact_photo($attrib)
{
global $SOURCE_ID, $CONTACTS, $CONTACT_COLTYPES, $RCMAIL;
if ($result = $CONTACTS->get_result())
$record = $result->first();
$photo_img = $attrib['placeholder'] ? $RCMAIL->output->get_skin_file($attrib['placeholder']) : 'program/resources/blank.gif';
if ($record['_type'] == 'group' && $attrib['placeholdergroup'])
$photo_img = $RCMAIL->output->get_skin_file($attrib['placeholdergroup']);
$RCMAIL->output->set_env('photo_placeholder', $photo_img);
unset($attrib['placeholder']);
$plugin = $RCMAIL->plugins->exec_hook('contact_photo', array('record' => $record, 'data' => $record['photo']));
// check if we have photo data from contact form
if ($GLOBALS['EDIT_RECORD']) {
$rec = $GLOBALS['EDIT_RECORD'];
if ($rec['photo'] == '-del-') {
$record['photo'] = '';
}
else if ($_SESSION['contacts']['files'][$rec['photo']]) {
$record['photo'] = $file_id = $rec['photo'];
}
}
if ($plugin['url'])
$photo_img = $plugin['url'];
else if (preg_match('!^https?://!i', $record['photo']))
$photo_img = $record['photo'];
else if ($record['photo']) {
$url = array('_action' => 'photo', '_cid' => $record['ID'], '_source' => $SOURCE_ID);
if ($file_id) {
$url['_photo'] = $ff_value = $file_id;
}
$photo_img = $RCMAIL->url($url);
}
else {
$ff_value = '-del-'; // will disable delete-photo action
}
$content = html::div($attrib, html::img(array(
'src' => $photo_img,
'alt' => $RCMAIL->gettext('contactphoto'),
'onerror' => 'this.src = rcmail.env.photo_placeholder',
)));
if ($CONTACT_COLTYPES['photo'] && ($RCMAIL->action == 'edit' || $RCMAIL->action == 'add')) {
$RCMAIL->output->add_gui_object('contactphoto', $attrib['id']);
$hidden = new html_hiddenfield(array('name' => '_photo', 'id' => 'ff_photo', 'value' => $ff_value));
$content .= $hidden->show();
}
return $content;
}
function rcmail_format_date_col($val)
{
global $RCMAIL;
return $RCMAIL->format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d'), false);
}
/**
* Updates saved search after data changed
*/
function rcmail_search_update($return = false)
{
global $RCMAIL;
if (($search_request = $_REQUEST['_search']) && isset($_SESSION['search'][$search_request])) {
$search = (array)$_SESSION['search'][$search_request];
$sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name');
$afields = $return ? $RCMAIL->config->get('contactlist_fields') : array('name', 'email');
$records = array();
foreach ($search as $s => $set) {
$source = $RCMAIL->get_address_book($s);
// reset page
$source->set_page(1);
$source->set_pagesize(9999);
$source->set_search_set($set);
// get records
$result = $source->list_records($afields);
if (!$result->count) {
unset($search[$s]);
continue;
}
if ($return) {
while ($row = $result->next()) {
$row['sourceid'] = $s;
$key = rcube_addressbook::compose_contact_key($row, $sort_col);
$records[$key] = $row;
}
unset($result);
}
$search[$s] = $source->get_search_set();
}
$_SESSION['search'][$search_request] = $search;
return $records;
}
return false;
}
/**
* Returns contact ID(s) and source(s) from GET/POST data
*
* @return array List of contact IDs per-source
*/
function rcmail_get_cids($filter = null)
{
// contact ID (or comma-separated list of IDs) is provided in two
// forms. If _source is an empty string then the ID is a string
// containing contact ID and source name in form: <ID>-<SOURCE>
$cid = rcube_utils::get_input_value('_cid', rcube_utils::INPUT_GPC);
$source = (string) rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
if (is_array($cid)) {
return $cid;
}
if (!preg_match('/^[a-zA-Z0-9\+\/=_-]+(,[a-zA-Z0-9\+\/=_-]+)*$/', $cid)) {
return array();
}
$cid = explode(',', $cid);
$got_source = strlen($source);
$result = array();
// create per-source contact IDs array
foreach ($cid as $id) {
// extract source ID from contact ID (it's there in search mode)
// see #1488959 and #1488862 for reference
if (!$got_source) {
if ($sep = strrpos($id, '-')) {
$contact_id = substr($id, 0, $sep);
$source_id = (string) substr($id, $sep+1);
if (strlen($source_id)) {
$result[$source_id][] = $contact_id;
}
}
}
else {
if (substr($id, -($got_source+1)) === "-$source") {
$id = substr($id, 0, -($got_source+1));
}
$result[$source][] = $id;
}
}
return $filter !== null ? $result[$filter] : $result;
}
diff --git a/program/steps/addressbook/import.inc b/program/steps/addressbook/import.inc
index 5dee5c06a..80bae662c 100644
--- a/program/steps/addressbook/import.inc
+++ b/program/steps/addressbook/import.inc
@@ -1,344 +1,344 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/addressbook/import.inc |
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2008-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: |
| Import contacts from a vCard or CSV file |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+-----------------------------------------------------------------------+
*/
/** The import process **/
$importstep = 'rcmail_import_form';
if (is_array($_FILES['_file'])) {
$replace = (bool)rcube_utils::get_input_value('_replace', rcube_utils::INPUT_GPC);
$target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC);
$with_groups = intval(rcube_utils::get_input_value('_groups', rcube_utils::INPUT_GPC));
$vcards = array();
$upload_error = null;
$CONTACTS = $RCMAIL->get_address_book($target, true);
if (!$CONTACTS->groups) {
$with_groups = false;
}
if ($CONTACTS->readonly) {
$OUTPUT->show_message('addresswriterror', 'error');
}
else {
foreach ((array)$_FILES['_file']['tmp_name'] as $i => $filepath) {
// Process uploaded file if there is no error
$err = $_FILES['_file']['error'][$i];
if ($err) {
$upload_error = $err;
}
else {
$file_content = file_get_contents($filepath);
// let rcube_vcard do the hard work :-)
$vcard_o = new rcube_vcard();
$vcard_o->extend_fieldmap($CONTACTS->vcard_map);
$v_list = $vcard_o->import($file_content);
if (!empty($v_list)) {
$vcards = array_merge($vcards, $v_list);
continue;
}
// no vCards found, try CSV
$csv = new rcube_csv2vcard($_SESSION['language']);
$csv->import($file_content);
$v_list = $csv->export();
if (!empty($v_list)) {
$vcards = array_merge($vcards, $v_list);
}
}
}
}
// no vcards detected
if (!count($vcards)) {
if ($upload_error == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
$size = $RCMAIL->show_bytes(parse_bytes(ini_get('upload_max_filesize')));
$OUTPUT->show_message('filesizeerror', 'error', array('size' => $size));
}
else if ($upload_error) {
$OUTPUT->show_message('fileuploaderror', 'error');
}
else {
$OUTPUT->show_message('importformaterror', 'error');
}
}
else {
$IMPORT_STATS = new stdClass;
$IMPORT_STATS->names = array();
$IMPORT_STATS->skipped_names = array();
$IMPORT_STATS->count = count($vcards);
$IMPORT_STATS->inserted = $IMPORT_STATS->skipped = $IMPORT_STATS->invalid = $IMPORT_STATS->errors = 0;
if ($replace) {
$CONTACTS->delete_all($CONTACTS->groups && $with_groups < 2);
}
if ($with_groups) {
$import_groups = $CONTACTS->list_groups();
}
foreach ($vcards as $vcard) {
$a_record = $vcard->get_assoc();
// Generate contact's display name (must be before validation), the same we do in save.inc
if (empty($a_record['name'])) {
$a_record['name'] = rcube_addressbook::compose_display_name($a_record, true);
// Reset it if equals to email address (from compose_display_name())
if ($a_record['name'] == $a_record['email'][0]) {
$a_record['name'] = '';
}
}
// skip invalid (incomplete) entries
if (!$CONTACTS->validate($a_record, true)) {
$IMPORT_STATS->invalid++;
continue;
}
// We're using UTF8 internally
$email = $vcard->email[0];
$email = rcube_utils::idn_to_utf8($email);
if (!$replace) {
$existing = null;
// compare e-mail address
if ($email) {
$existing = $CONTACTS->search('email', $email, 1, false);
}
// compare display name if email not found
if ((!$existing || !$existing->count) && $vcard->displayname) {
$existing = $CONTACTS->search('name', $vcard->displayname, 1, false);
}
if ($existing && $existing->count) {
$IMPORT_STATS->skipped++;
$IMPORT_STATS->skipped_names[] = $vcard->displayname ? $vcard->displayname : $email;
continue;
}
}
$a_record['vcard'] = $vcard->export();
$plugin = $RCMAIL->plugins->exec_hook('contact_create',
array('record' => $a_record, 'source' => null));
$a_record = $plugin['record'];
// insert record and send response
if (!$plugin['abort'])
$success = $CONTACTS->insert($a_record);
else
$success = $plugin['result'];
if ($success) {
// assign groups for this contact (if enabled)
if ($with_groups && !empty($a_record['groups'])) {
foreach (explode(',', $a_record['groups'][0]) as $group_name) {
if ($group_id = rcmail_import_group_id($group_name, $CONTACTS, $with_groups == 1, $import_groups)) {
$CONTACTS->add_to_group($group_id, $success);
}
}
}
$IMPORT_STATS->inserted++;
$IMPORT_STATS->names[] = $a_record['name'] ? $a_record['name'] : $email;
}
else {
$IMPORT_STATS->errors++;
}
}
$importstep = 'rcmail_import_confirm';
}
}
$OUTPUT->set_pagetitle($RCMAIL->gettext('importcontacts'));
$OUTPUT->add_handlers(array(
'importstep' => $importstep,
'importnav' => 'rcmail_import_buttons',
));
// render page
$OUTPUT->send('importcontacts');
/**
* Handler function to display the import/upload form
*/
function rcmail_import_form($attrib)
{
global $RCMAIL, $OUTPUT;
$target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC);
$attrib += array('id' => "rcmImportForm");
$writable_books = $RCMAIL->get_address_sources(true, true);
$upload = new html_inputfield(array(
'type' => 'file',
'name' => '_file[]',
'id' => 'rcmimportfile',
'size' => 40,
'multiple' => 'multiple',
));
$form = html::p(null, html::label('rcmimportfile', $RCMAIL->gettext('importfromfile')) . $upload->show());
$table = new html_table(array('cols' => 2));
// addressbook selector
if (count($writable_books) > 1) {
$select = new html_select(array('name' => '_target', 'id' => 'rcmimporttarget', 'is_escaped' => true));
foreach ($writable_books as $book) {
$select->add($book['name'], $book['id']);
}
$table->add('title', html::label('rcmimporttarget', $RCMAIL->gettext('importtarget')));
$table->add(null, $select->show($target));
}
else {
$abook = new html_hiddenfield(array('name' => '_target', 'value' => key($writable_books)));
$form .= $abook->show();
}
// selector for group import options
if (count($writable_books) >= 1 || $writable_books[0]->groups) {
$select = new html_select(array('name' => '_groups', 'id' => 'rcmimportgroups', 'is_escaped' => true));
$select->add($RCMAIL->gettext('none'), '0');
$select->add($RCMAIL->gettext('importgroupsall'), '1');
$select->add($RCMAIL->gettext('importgroupsexisting'), '2');
$table->add('title', html::label('rcmimportgroups', $RCMAIL->gettext('importgroups')));
$table->add(null, $select->show(rcube_utils::get_input_value('_groups', rcube_utils::INPUT_GPC)));
}
// checkbox to replace the entire address book
$check_replace = new html_checkbox(array('name' => '_replace', 'value' => 1, 'id' => 'rcmimportreplace'));
$table->add('title', html::label('rcmimportreplace', $RCMAIL->gettext('importreplace')));
$table->add(null, $check_replace->show(rcube_utils::get_input_value('_replace', rcube_utils::INPUT_GPC)));
$form .= $table->show(array('id' => null) + $attrib);
$OUTPUT->set_env('writable_source', !empty($writable_books));
$OUTPUT->add_label('selectimportfile','importwait');
$OUTPUT->add_gui_object('importform', $attrib['id']);
$out = html::p(null, rcube::Q($RCMAIL->gettext('importdesc'), 'show'))
. $OUTPUT->form_tag(array(
'action' => $RCMAIL->url('import'),
'method' => 'post',
'enctype' => 'multipart/form-data') + $attrib,
$form);
return $out;
}
/**
* Render the confirmation page for the import process
*/
function rcmail_import_confirm($attrib)
{
global $IMPORT_STATS, $RCMAIL;
$vars = get_object_vars($IMPORT_STATS);
$vars['names'] = $vars['skipped_names'] = '';
$content = html::p(null, $RCMAIL->gettext(array(
'name' => 'importconfirm',
'nr' => $IMPORT_STATS->inserted,
'vars' => $vars,
)) . ($IMPORT_STATS->names ? ':' : '.'));
if ($IMPORT_STATS->names) {
$content .= html::p('em', join(', ', array_map('Q', $IMPORT_STATS->names)));
}
if ($IMPORT_STATS->skipped) {
$content .= html::p(null, $RCMAIL->gettext(array(
'name' => 'importconfirmskipped',
'nr' => $IMPORT_STATS->skipped,
'vars' => $vars,
)) . ':')
. html::p('em', join(', ', array_map('Q', $IMPORT_STATS->skipped_names)));
}
return html::div($attrib, $content);
}
/**
* Create navigation buttons for the current import step
*/
function rcmail_import_buttons($attrib)
{
global $IMPORT_STATS, $OUTPUT;
$target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC);
$attrib += array('type' => 'input');
unset($attrib['name']);
if (is_object($IMPORT_STATS)) {
$attrib['class'] = trim($attrib['class'] . ' mainaction');
$out = $OUTPUT->button(array('command' => 'list', 'prop' => $target, 'label' => 'done') + $attrib);
}
else {
$cancel = $OUTPUT->button(array('command' => 'list', 'label' => 'cancel') + $attrib);
$attrib['class'] = trim($attrib['class'] . ' mainaction');
$out = $OUTPUT->button(array('command' => 'import', 'label' => 'import') + $attrib);
$out .= '&nbsp;';
$out .= $cancel;
}
return $out;
}
/**
* Returns the matching group id. If group doesn't exist, it'll be created if allowed.
*/
function rcmail_import_group_id($group_name, $CONTACTS, $create, &$import_groups)
{
$group_id = 0;
- foreach ($import_groups as $key => $group) {
+ foreach ($import_groups as $group) {
if (strtolower($group['name']) == strtolower($group_name)) {
$group_id = $group['ID'];
break;
}
}
// create a new group
if (!$group_id && $create) {
$new_group = $CONTACTS->create_group($group_name);
if (!$new_group['ID'])
$new_group['ID'] = $new_group['id'];
$import_groups[] = $new_group;
$group_id = $new_group['ID'];
}
return $group_id;
}
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index 56bc9fb9f..bfb2fac75 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -1,1890 +1,1889 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/mail/compose.inc |
| |
| This file is part of the Roundcube Webmail client |
| 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. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Compose a new mail message with all headers and attachments |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
// define constants for message compose mode
define('RCUBE_COMPOSE_REPLY', 'reply');
define('RCUBE_COMPOSE_FORWARD', 'forward');
define('RCUBE_COMPOSE_DRAFT', 'draft');
define('RCUBE_COMPOSE_EDIT', 'edit');
$MESSAGE_FORM = null;
$COMPOSE_ID = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GET);
$COMPOSE = null;
if ($COMPOSE_ID && $_SESSION['compose_data_'.$COMPOSE_ID])
$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID];
// give replicated session storage some time to synchronize
$retries = 0;
while ($COMPOSE_ID && !is_array($COMPOSE) && $RCMAIL->db->is_replicated() && $retries++ < 5) {
usleep(500000);
$RCMAIL->session->reload();
if ($_SESSION['compose_data_'.$COMPOSE_ID]) {
$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID];
}
}
// Nothing below is called during message composition, only at "new/forward/reply/draft" initialization or
// if a compose-ID is given (i.e. when the compose step is opened in a new window/tab).
if (!is_array($COMPOSE)) {
// Infinite redirect prevention in case of broken session (#1487028)
if ($COMPOSE_ID) {
rcube::raise_error(array('code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Invalid compose ID"), true, true);
}
$COMPOSE_ID = uniqid(mt_rand());
$_SESSION['compose_data_'.$COMPOSE_ID] = array(
'id' => $COMPOSE_ID,
'param' => rcube_utils::request2param(rcube_utils::INPUT_GET, 'task|action', true),
'mailbox' => $RCMAIL->storage->get_folder(),
);
$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID];
rcmail_process_compose_params($COMPOSE);
// check if folder for saving sent messages exists and is subscribed (#1486802)
if ($sent_folder = $COMPOSE['param']['sent_mbox']) {
rcmail_check_sent_folder($sent_folder, true);
}
// redirect to a unique URL with all parameters stored in session
$OUTPUT->redirect(array(
'_action' => 'compose',
'_id' => $COMPOSE['id'],
'_search' => $_REQUEST['_search'],
));
}
// add some labels to client
$OUTPUT->add_label('nosubject', 'nosenderwarning', 'norecipientwarning', 'nosubjectwarning', 'cancel',
'nobodywarning', 'notsentwarning', 'notuploadedwarning', 'savingmessage', 'sendingmessage',
'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'uploadingmany',
'fileuploaderror', 'sendmessage', 'newresponse', 'responsename', 'responsetext', 'save',
'savingresponse', 'restoresavedcomposedata', 'restoremessage', 'delete', 'restore', 'ignore',
'selectimportfile');
$OUTPUT->set_pagetitle($RCMAIL->gettext('compose'));
$OUTPUT->set_env('compose_id', $COMPOSE['id']);
$OUTPUT->set_env('session_id', session_id());
$OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder());
$OUTPUT->set_env('top_posting', intval($RCMAIL->config->get('reply_mode')) > 0);
$OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ',')));
$OUTPUT->set_env('save_localstorage', (bool)$RCMAIL->config->get('compose_save_localstorage'));
$drafts_mbox = $RCMAIL->config->get('drafts_mbox');
$config_show_sig = $RCMAIL->config->get('show_sig', 1);
// add config parameters to client script
if (strlen($drafts_mbox)) {
$OUTPUT->set_env('drafts_mailbox', $drafts_mbox);
$OUTPUT->set_env('draft_autosave', $RCMAIL->config->get('draft_autosave'));
}
// default font for HTML editor
$font = rcmail::font_defs($RCMAIL->config->get('default_font'));
if ($font && !is_array($font)) {
$OUTPUT->set_env('default_font', $font);
}
// default font size for HTML editor
if ($font_size = $RCMAIL->config->get('default_font_size')) {
$OUTPUT->set_env('default_font_size', $font_size);
}
// get reference message and set compose mode
if ($msg_uid = $COMPOSE['param']['draft_uid']) {
$compose_mode = RCUBE_COMPOSE_DRAFT;
$OUTPUT->set_env('draft_id', $msg_uid);
$RCMAIL->storage->set_folder($drafts_mbox);
}
else if ($msg_uid = $COMPOSE['param']['reply_uid']) {
$compose_mode = RCUBE_COMPOSE_REPLY;
}
else if ($msg_uid = $COMPOSE['param']['forward_uid']) {
$compose_mode = RCUBE_COMPOSE_FORWARD;
$COMPOSE['forward_uid'] = $msg_uid;
$COMPOSE['as_attachment'] = !empty($COMPOSE['param']['attachment']);
}
else if ($msg_uid = $COMPOSE['param']['uid']) {
$compose_mode = RCUBE_COMPOSE_EDIT;
}
$COMPOSE['mode'] = $compose_mode;
$OUTPUT->set_env('compose_mode', $compose_mode);
if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) {
// don't add signature in draft/edit mode, we'll also not remove the old-one
// but only on page display, later we should be able to change identity/sig (#1489229)
if ($config_show_sig == 1 || $config_show_sig == 2) {
$OUTPUT->set_env('show_sig_later', true);
}
}
else if ($config_show_sig == 1)
$OUTPUT->set_env('show_sig', true);
else if ($config_show_sig == 2 && empty($compose_mode))
$OUTPUT->set_env('show_sig', true);
else if ($config_show_sig == 3 && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD))
$OUTPUT->set_env('show_sig', true);
// set line length for body wrapping
$LINE_LENGTH = $RCMAIL->config->get('line_length', 72);
if (!empty($msg_uid) && empty($COMPOSE['as_attachment'])) {
$mbox_name = $RCMAIL->storage->get_folder();
// set format before rcube_message construction
// use the same format as for the message view
if (isset($_SESSION['msg_formats'][$mbox_name.':'.$msg_uid])) {
$RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$msg_uid]);
}
else {
$prefer_html = $RCMAIL->config->get('prefer_html') || $RCMAIL->config->get('htmleditor')
|| $compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT;
$RCMAIL->config->set('prefer_html', $prefer_html);
}
$MESSAGE = new rcube_message($msg_uid);
// make sure message is marked as read
if ($MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN'])) {
$RCMAIL->storage->set_flag($msg_uid, 'SEEN');
}
if (!empty($MESSAGE->headers->charset)) {
$RCMAIL->storage->set_charset($MESSAGE->headers->charset);
}
if (!$MESSAGE->headers) {
// error
}
else if ($compose_mode == RCUBE_COMPOSE_FORWARD || $compose_mode == RCUBE_COMPOSE_REPLY) {
if ($compose_mode == RCUBE_COMPOSE_REPLY) {
$COMPOSE['reply_uid'] = $msg_uid;
if (!empty($COMPOSE['param']['all'])) {
$MESSAGE->reply_all = $COMPOSE['param']['all'];
}
}
else {
$COMPOSE['forward_uid'] = $msg_uid;
}
$COMPOSE['reply_msgid'] = $MESSAGE->headers->messageID;
$COMPOSE['references'] = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID);
// Save the sent message in the same folder of the message being replied to
if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $COMPOSE['mailbox'])
&& rcmail_check_sent_folder($sent_folder, false)
) {
$COMPOSE['param']['sent_mbox'] = $sent_folder;
}
}
else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) {
if ($compose_mode == RCUBE_COMPOSE_DRAFT) {
if ($draft_info = $MESSAGE->headers->get('x-draft-info')) {
// get reply_uid/forward_uid to flag the original message when sending
$info = rcmail_draftinfo_decode($draft_info);
if ($info['type'] == 'reply')
$COMPOSE['reply_uid'] = $info['uid'];
else if ($info['type'] == 'forward')
$COMPOSE['forward_uid'] = $info['uid'];
$COMPOSE['mailbox'] = $info['folder'];
// Save the sent message in the same folder of the message being replied to
if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $info['folder'])
&& rcmail_check_sent_folder($sent_folder, false)
) {
$COMPOSE['param']['sent_mbox'] = $sent_folder;
}
}
$COMPOSE['param']['message-id'] = $MESSAGE->headers->get('message-id');
// use message UID as draft_id
$OUTPUT->set_env('draft_id', $msg_uid);
}
if ($in_reply_to = $MESSAGE->headers->get('in-reply-to')) {
$COMPOSE['reply_msgid'] = '<' . $in_reply_to . '>';
}
$COMPOSE['references'] = $MESSAGE->headers->references;
}
}
else {
$MESSAGE = new stdClass();
// apply mailto: URL parameters
if (!empty($COMPOSE['param']['in-reply-to'])) {
$COMPOSE['reply_msgid'] = '<' . $COMPOSE['param']['in-reply-to'] . '>';
}
if (!empty($COMPOSE['param']['references'])) {
$COMPOSE['references'] = $COMPOSE['param']['references'];
}
}
if (!empty($COMPOSE['reply_msgid'])) {
$OUTPUT->set_env('reply_msgid', $COMPOSE['reply_msgid']);
}
$MESSAGE->compose = array();
// get user's identities
$MESSAGE->identities = $RCMAIL->user->list_identities(null, true);
// Set From field value
if (!empty($_POST['_from'])) {
$MESSAGE->compose['from'] = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST);
}
else if (!empty($COMPOSE['param']['from'])) {
$MESSAGE->compose['from'] = $COMPOSE['param']['from'];
}
else if (count($MESSAGE->identities)) {
$ident = rcmail_identity_select($MESSAGE, $MESSAGE->identities, $compose_mode);
$MESSAGE->compose['from_email'] = $ident['email'];
$MESSAGE->compose['from'] = $ident['identity_id'];
}
// Set other headers
$a_recipients = array();
$parts = array('to', 'cc', 'bcc', 'replyto', 'followupto');
$separator = trim($RCMAIL->config->get('recipients_separator', ',')) . ' ';
$from_email = @mb_strtolower($MESSAGE->compose['from_email']);
foreach ($parts as $header) {
$fvalue = '';
$decode_header = true;
$charset = $MESSAGE->headers->charset;
// we have a set of recipients stored is session
if ($header == 'to' && ($mailto_id = $COMPOSE['param']['mailto'])
&& $_SESSION['mailto'][$mailto_id]
) {
$fvalue = urldecode($_SESSION['mailto'][$mailto_id]);
$decode_header = false;
$charset = $RCMAIL->output->charset;
// make session to not grow up too much
unset($_SESSION['mailto'][$mailto_id]);
$COMPOSE['param']['to'] = $fvalue;
}
else if (!empty($_POST['_'.$header])) {
$fvalue = rcube_utils::get_input_value('_'.$header, rcube_utils::INPUT_POST, TRUE);
$charset = $RCMAIL->output->charset;
}
else if (!empty($COMPOSE['param'][$header])) {
$fvalue = $COMPOSE['param'][$header];
$charset = $RCMAIL->output->charset;
}
else if ($compose_mode == RCUBE_COMPOSE_REPLY) {
// get recipent address(es) out of the message headers
if ($header == 'to') {
$mailfollowup = $MESSAGE->headers->others['mail-followup-to'];
$mailreplyto = $MESSAGE->headers->others['mail-reply-to'];
// Reply to mailing list...
if ($MESSAGE->reply_all == 'list' && $mailfollowup)
$fvalue = $mailfollowup;
else if ($MESSAGE->reply_all == 'list'
&& preg_match('/<mailto:([^>]+)>/i', $MESSAGE->headers->others['list-post'], $m))
$fvalue = $m[1];
// Reply to...
else if ($MESSAGE->reply_all && $mailfollowup)
$fvalue = $mailfollowup;
else if ($mailreplyto)
$fvalue = $mailreplyto;
else if (!empty($MESSAGE->headers->replyto))
$fvalue = $MESSAGE->headers->replyto;
else if (!empty($MESSAGE->headers->from))
$fvalue = $MESSAGE->headers->from;
// Reply to message sent by yourself (#1487074, #1489230)
if (!empty($ident) && in_array($ident['ident'], array($fvalue, $MESSAGE->headers->from))) {
$fvalue = $MESSAGE->headers->to;
}
}
// add recipient of original message if reply to all
else if ($header == 'cc' && !empty($MESSAGE->reply_all) && $MESSAGE->reply_all != 'list') {
if ($v = $MESSAGE->headers->to)
$fvalue .= $v;
if ($v = $MESSAGE->headers->cc)
$fvalue .= (!empty($fvalue) ? $separator : '') . $v;
// Use Sender header (#1489011)
if (($v = $MESSAGE->headers->get('Sender', false)) && strpos($v, '-bounces@') === false)
$fvalue .= (!empty($fvalue) ? $separator : '') . $v;
// When To: and Reply-To: are the same we add From: address to the list (#1489037)
if ($v = $MESSAGE->headers->from) {
$from = rcube_mime::decode_address_list($v, null, false, $charset, true);
$to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, false, $charset, true);
$replyto = rcube_mime::decode_address_list($MESSAGE->headers->replyto, null, false, $charset, true);
if (count($replyto) && !count(array_diff($to, $replyto)) && count(array_diff($from, $to))) {
$fvalue .= (!empty($fvalue) ? $separator : '') . $v;
}
}
}
}
else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) {
// get drafted headers
if ($header=='to' && !empty($MESSAGE->headers->to))
$fvalue = $MESSAGE->get_header('to', true);
else if ($header=='cc' && !empty($MESSAGE->headers->cc))
$fvalue = $MESSAGE->get_header('cc', true);
else if ($header=='bcc' && !empty($MESSAGE->headers->bcc))
$fvalue = $MESSAGE->get_header('bcc', true);
else if ($header=='replyto' && !empty($MESSAGE->headers->others['mail-reply-to']))
$fvalue = $MESSAGE->get_header('mail-reply-to');
else if ($header=='replyto' && !empty($MESSAGE->headers->replyto))
$fvalue = $MESSAGE->get_header('reply-to');
else if ($header=='followupto' && !empty($MESSAGE->headers->others['mail-followup-to']))
$fvalue = $MESSAGE->get_header('mail-followup-to');
}
// split recipients and put them back together in a unique way
if (!empty($fvalue) && in_array($header, array('to', 'cc', 'bcc'))) {
$to_addresses = rcube_mime::decode_address_list($fvalue, null, $decode_header, $charset);
$fvalue = array();
foreach ($to_addresses as $addr_part) {
if (empty($addr_part['mailto'])) {
continue;
}
// According to RFC5321 local part of email address is case-sensitive
// however, here it is better to compare addresses in case-insensitive manner
$mailto = format_email(rcube_utils::idn_to_utf8($addr_part['mailto']));
$mailto_lc = mb_strtolower($addr_part['mailto']);
if (($header == 'to' || $compose_mode != RCUBE_COMPOSE_REPLY || $mailto_lc != $from_email)
&& !in_array($mailto_lc, $a_recipients)
) {
if ($addr_part['name'] && $mailto != $addr_part['name']) {
$mailto = format_email_recipient($mailto, $addr_part['name']);
}
$fvalue[] = $mailto;
$a_recipients[] = $mailto_lc;
}
}
$fvalue = implode($separator, $fvalue);
}
$MESSAGE->compose[$header] = $fvalue;
}
unset($a_recipients);
// process $MESSAGE body/attachments, set $MESSAGE_BODY/$HTML_MODE vars and some session data
$MESSAGE_BODY = rcmail_prepare_message_body();
// register UI objects
$OUTPUT->add_handlers(array(
'composeheaders' => 'rcmail_compose_headers',
'composesubject' => 'rcmail_compose_subject',
'composebody' => 'rcmail_compose_body',
'composeattachmentlist' => 'rcmail_compose_attachment_list',
'composeattachmentform' => 'rcmail_compose_attachment_form',
'composeattachment' => 'rcmail_compose_attachment_field',
'filedroparea' => 'compose_file_drop_area',
'priorityselector' => 'rcmail_priority_selector',
'editorselector' => 'rcmail_editor_selector',
'receiptcheckbox' => 'rcmail_receipt_checkbox',
'dsncheckbox' => 'rcmail_dsn_checkbox',
'storetarget' => 'rcmail_store_target_selection',
'addressbooks' => 'rcmail_addressbook_list',
'addresslist' => 'rcmail_contacts_list',
'responseslist' => 'rcmail_compose_responses_list',
));
$OUTPUT->send('compose');
/****** compose mode functions ********/
// process compose request parameters
function rcmail_process_compose_params(&$COMPOSE)
{
if ($COMPOSE['param']['to']) {
$mailto = explode('?', $COMPOSE['param']['to'], 2);
// #1486037: remove "mailto:" prefix
$COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $mailto[0]);
// Supported case-insensitive tokens in mailto URL
$url_tokens = array('to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'body');
if (!empty($mailto[1])) {
parse_str($mailto[1], $query);
foreach ($query as $f => $val) {
if (($key = array_search(strtolower($f), $url_tokens)) !== false) {
$f = $url_tokens[$key];
}
// merge mailto: addresses with addresses from 'to' parameter
if ($f == 'to' && !empty($COMPOSE['param']['to'])) {
$to_addresses = rcube_mime::decode_address_list($COMPOSE['param']['to'], null, true, null, true);
$add_addresses = rcube_mime::decode_address_list($val, null, true);
foreach ($add_addresses as $addr) {
if (!in_array($addr['mailto'], $to_addresses)) {
$to_addresses[] = $addr['mailto'];
$COMPOSE['param']['to'] = (!empty($to_addresses) ? ', ' : '') . $addr['string'];
}
}
}
else {
$COMPOSE['param'][$f] = $val;
}
}
}
}
// resolve _forward_uid=* to an absolute list of messages from a search result
if ($COMPOSE['param']['forward_uid'] == '*' && is_object($_SESSION['search'][1])) {
$COMPOSE['param']['forward_uid'] = $_SESSION['search'][1]->get();
}
// clean HTML message body which can be submitted by URL
if (!empty($COMPOSE['param']['body'])) {
$COMPOSE['param']['body'] = rcmail_wash_html($COMPOSE['param']['body'], array('safe' => false, 'inline_html' => true), array());
}
$RCMAIL = rcmail::get_instance();
// select folder where to save the sent message
$COMPOSE['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox');
// pipe compose parameters thru plugins
$plugin = $RCMAIL->plugins->exec_hook('message_compose', $COMPOSE);
$COMPOSE['param'] = array_merge($COMPOSE['param'], $plugin['param']);
// add attachments listed by message_compose hook
if (is_array($plugin['attachments'])) {
foreach ($plugin['attachments'] as $attach) {
// we have structured data
if (is_array($attach)) {
$attachment = $attach + array('group' => $COMPOSE_ID);
}
// only a file path is given
else {
$filename = basename($attach);
$attachment = array(
'group' => $COMPOSE_ID,
'name' => $filename,
'mimetype' => rcube_mime::file_content_type($attach, $filename),
'path' => $attach,
);
}
// save attachment if valid
if (($attachment['data'] && $attachment['name']) || ($attachment['path'] && file_exists($attachment['path']))) {
$attachment = rcmail::get_instance()->plugins->exec_hook('attachment_save', $attachment);
}
if ($attachment['status'] && !$attachment['abort']) {
unset($attachment['data'], $attachment['status'], $attachment['abort']);
$COMPOSE['attachments'][$attachment['id']] = $attachment;
}
}
}
}
function rcmail_compose_headers($attrib)
{
global $RCMAIL, $MESSAGE;
list($form_start,) = get_form_tags($attrib);
$out = '';
$part = strtolower($attrib['part']);
switch ($part) {
case 'from':
return $form_start . rcmail_compose_header_from($attrib);
case 'to':
case 'cc':
case 'bcc':
$fname = '_' . $part;
$header = $param = $part;
$allow_attrib = array('id', 'class', 'style', 'cols', 'rows', 'tabindex');
$field_type = 'html_textarea';
break;
case 'replyto':
case 'reply-to':
$fname = '_replyto';
$param = 'replyto';
$header = 'reply-to';
case 'followupto':
case 'followup-to':
if (!$fname) {
$fname = '_followupto';
$param = 'followupto';
$header = 'mail-followup-to';
}
$allow_attrib = array('id', 'class', 'style', 'size', 'tabindex');
$field_type = 'html_inputfield';
break;
}
if ($fname && $field_type) {
// pass the following attributes to the form class
$field_attrib = array('name' => $fname, 'spellcheck' => 'false');
foreach ($attrib as $attr => $value) {
if (in_array($attr, $allow_attrib)) {
$field_attrib[$attr] = $value;
}
}
// create teaxtarea object
$input = new $field_type($field_attrib);
$out = $input->show($MESSAGE->compose[$param]);
}
if ($form_start) {
$out = $form_start . $out;
}
// configure autocompletion
$RCMAIL->autocomplete_init();
return $out;
}
function rcmail_compose_header_from($attrib)
{
global $MESSAGE, $OUTPUT, $RCMAIL, $COMPOSE, $compose_mode;
// pass the following attributes to the form class
$field_attrib = array('name' => '_from');
foreach ($attrib as $attr => $value) {
if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex'))) {
$field_attrib[$attr] = $value;
}
}
if (count($MESSAGE->identities)) {
$a_signatures = array();
$identities = array();
$separator = intval($RCMAIL->config->get('reply_mode')) > 0
&& ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- ';
$field_attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.".change_identity(this)";
$select_from = new html_select($field_attrib);
// create SELECT element
foreach ($MESSAGE->identities as $sql_arr) {
$identity_id = $sql_arr['identity_id'];
$select_from->add(format_email_recipient($sql_arr['email'], $sql_arr['name']), $identity_id);
// add signature to array
if (!empty($sql_arr['signature']) && empty($COMPOSE['param']['nosig'])) {
$text = $html = $sql_arr['signature'];
if ($sql_arr['html_signature']) {
$h2t = new rcube_html2text($sql_arr['signature'], false, true);
$text = trim($h2t->get_text());
}
else {
$html = htmlentities($html, ENT_NOQUOTES, RCUBE_CHARSET);
}
if (!preg_match('/^--[ -]\r?\n/m', $text)) {
$text = $separator . "\n" . $text;
$html = $separator . "<br>" . $html;
}
if (!$sql_arr['html_signature']) {
$t2h = new rcube_text2html($sql_arr['signature'], false);
$html = $t2h->get_html();
}
$a_signatures[$identity_id]['text'] = $text;
$a_signatures[$identity_id]['html'] = $html;
}
// add bcc and reply-to
if (!empty($sql_arr['reply-to'])) {
$identities[$identity_id]['replyto'] = $sql_arr['reply-to'];
}
if (!empty($sql_arr['bcc'])) {
$identities[$identity_id]['bcc'] = $sql_arr['bcc'];
}
}
$out = $select_from->show($MESSAGE->compose['from']);
// add signatures to client
$OUTPUT->set_env('signatures', $a_signatures);
$OUTPUT->set_env('identities', $identities);
}
// no identities, display text input field
else {
$field_attrib['class'] = 'from_address';
$input_from = new html_inputfield($field_attrib);
$out = $input_from->show($MESSAGE->compose['from']);
}
return $out;
}
function rcmail_compose_editor_mode()
{
global $RCMAIL, $compose_mode;
static $useHtml;
if ($useHtml !== null) {
return $useHtml;
}
$html_editor = intval($RCMAIL->config->get('htmleditor'));
if (isset($_POST['_is_html'])) {
$useHtml = !empty($_POST['_is_html']);
}
else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) {
$useHtml = rcmail_message_is_html();
}
else if ($compose_mode == RCUBE_COMPOSE_REPLY) {
$useHtml = ($html_editor == 1 || ($html_editor >= 2 && rcmail_message_is_html()));
}
else if ($compose_mode == RCUBE_COMPOSE_FORWARD) {
$useHtml = ($html_editor == 1 || ($html_editor == 3 && rcmail_message_is_html()));
}
else {
$useHtml = ($html_editor == 1);
}
return $useHtml;
}
function rcmail_message_is_html()
{
global $RCMAIL, $MESSAGE;
return $RCMAIL->config->get('prefer_html') && ($MESSAGE instanceof rcube_message) && $MESSAGE->has_html_part(true);
}
function rcmail_prepare_message_body()
{
global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $HTML_MODE;
// use posted message body
if (!empty($_POST['_message'])) {
$body = rcube_utils::get_input_value('_message', rcube_utils::INPUT_POST, true);
$isHtml = (bool) rcube_utils::get_input_value('_is_html', rcube_utils::INPUT_POST);
}
else if ($COMPOSE['param']['body']) {
$body = $COMPOSE['param']['body'];
$isHtml = (bool) $COMPOSE['param']['html'];
}
// forward as attachment
else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $COMPOSE['as_attachment']) {
$isHtml = rcmail_compose_editor_mode();
$body = '';
rcmail_write_forward_attachments();
}
// reply/edit/draft/forward
else if ($compose_mode && ($compose_mode != RCUBE_COMPOSE_REPLY || intval($RCMAIL->config->get('reply_mode')) != -1)) {
$isHtml = rcmail_compose_editor_mode();
$messages = array();
if (!empty($MESSAGE->parts)) {
// collect IDs of message/rfc822 parts
if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) {
foreach ($MESSAGE->attachments as $part) {
if ($part->mimetype == 'message/rfc822') {
$messages[] = $part->mime_id;
}
}
}
foreach ($MESSAGE->parts as $part) {
// skip no-content and attachment parts (#1488557)
if ($part->type != 'content' || !$part->size || $MESSAGE->is_attachment($part)) {
continue;
}
// skip all content parts inside the message/rfc822 part in DRAFT/EDIT mode
foreach ($messages as $mimeid) {
if (strpos($part->mime_id, $mimeid . '.') === 0) {
continue 2;
}
}
if ($part_body = rcmail_compose_part_body($part, $isHtml)) {
$body .= ($body ? ($isHtml ? '<br/>' : "\n") : '') . $part_body;
}
}
}
else {
$body = rcmail_compose_part_body($MESSAGE, $isHtml);
}
// compose reply-body
if ($compose_mode == RCUBE_COMPOSE_REPLY)
$body = rcmail_create_reply_body($body, $isHtml);
// forward message body inline
else if ($compose_mode == RCUBE_COMPOSE_FORWARD)
$body = rcmail_create_forward_body($body, $isHtml);
// load draft message body
else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT)
$body = rcmail_create_draft_body($body, $isHtml);
}
else { // new message
$isHtml = rcmail_compose_editor_mode();
}
$plugin = $RCMAIL->plugins->exec_hook('message_compose_body',
array('body' => $body, 'html' => $isHtml, 'mode' => $compose_mode));
$body = $plugin['body'];
unset($plugin);
// add blocked.gif attachment (#1486516)
if ($isHtml && preg_match('#<img src="\./program/resources/blocked\.gif"#', $body)) {
if ($attachment = rcmail_save_image('program/resources/blocked.gif', 'image/gif')) {
$COMPOSE['attachments'][$attachment['id']] = $attachment;
$url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s',
$RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']);
$body = preg_replace('#\./program/resources/blocked\.gif#', $url, $body);
}
}
$HTML_MODE = $isHtml;
return $body;
}
function rcmail_compose_part_body($part, $isHtml = false)
{
global $RCMAIL, $MESSAGE, $LINE_LENGTH, $compose_mode;
// Check if we have enough memory to handle the message in it
// #1487424: we need up to 10x more memory than the body
if (!rcube_utils::mem_check($part->size * 10)) {
return '';
}
// fetch part if not available
$body = $MESSAGE->get_part_body($part->mime_id, true);
// message is cached but not exists (#1485443), or other error
if ($body === false) {
return '';
}
if ($isHtml) {
if ($part->ctype_secondary == 'html') {
}
else if ($part->ctype_secondary == 'enriched') {
$body = rcube_enriched::to_html($body);
}
else {
// try to remove the signature
if ($compose_mode != RCUBE_COMPOSE_DRAFT && $compose_mode != RCUBE_COMPOSE_EDIT) {
if ($RCMAIL->config->get('strip_existing_sig', true)) {
$body = rcmail_remove_signature($body);
}
}
// add HTML formatting
$body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed');
}
}
else {
if ($part->ctype_secondary == 'enriched') {
$body = rcube_enriched::to_html($body);
$part->ctype_secondary = 'html';
}
if ($part->ctype_secondary == 'html') {
// use html part if it has been used for message (pre)viewing
// decrease line length for quoting
$len = $compose_mode == RCUBE_COMPOSE_REPLY ? $LINE_LENGTH-2 : $LINE_LENGTH;
$txt = new rcube_html2text($body, false, true, $len);
$body = $txt->get_text();
}
else {
if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') {
$body = rcube_mime::unfold_flowed($body);
}
// try to remove the signature
if ($compose_mode != RCUBE_COMPOSE_DRAFT && $compose_mode != RCUBE_COMPOSE_EDIT) {
if ($RCMAIL->config->get('strip_existing_sig', true)) {
$body = rcmail_remove_signature($body);
}
}
}
}
return $body;
}
function rcmail_compose_body($attrib)
{
global $RCMAIL, $OUTPUT, $HTML_MODE, $MESSAGE_BODY;
list($form_start, $form_end) = get_form_tags($attrib);
unset($attrib['form']);
if (empty($attrib['id']))
$attrib['id'] = 'rcmComposeBody';
$attrib['name'] = '_message';
$isHtml = $HTML_MODE;
$out = $form_start ? "$form_start\n" : '';
$saveid = new html_hiddenfield(array('name' => '_draft_saveid', 'value' => $RCMAIL->output->get_env('draft_id')));
$out .= $saveid->show();
$drafttoggle = new html_hiddenfield(array('name' => '_draft', 'value' => 'yes'));
$out .= $drafttoggle->show();
$msgtype = new html_hiddenfield(array('name' => '_is_html', 'value' => ($isHtml ? "1" : "0")));
$out .= $msgtype->show();
$framed = new html_hiddenfield(array('name' => '_framed', 'value' => '1'));
$out .= $framed->show();
// If desired, set this textarea to be editable by TinyMCE
if ($isHtml) {
$MESSAGE_BODY = htmlentities($MESSAGE_BODY, ENT_NOQUOTES, RCUBE_CHARSET);
$attrib['class'] = 'mce_editor';
$attrib['is_escaped'] = true;
$textarea = new html_textarea($attrib);
$out .= $textarea->show($MESSAGE_BODY);
}
else {
$textarea = new html_textarea($attrib);
$out .= $textarea->show('');
// quote plain text, inject into textarea
$table = get_html_translation_table(HTML_SPECIALCHARS);
$MESSAGE_BODY = strtr($MESSAGE_BODY, $table);
$out = substr($out, 0, -11) . $MESSAGE_BODY . '</textarea>';
}
$out .= $form_end ? "\n$form_end" : '';
$OUTPUT->set_env('composebody', $attrib['id']);
// include HTML editor
$RCMAIL->html_editor();
// Set language list
if ($RCMAIL->config->get('enable_spellcheck')) {
$engine = new rcube_spellchecker();
$dictionary = (bool) $RCMAIL->config->get('spellcheck_dictionary');
$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 (!$spellcheck_langs[$lang]) {
$lang = 'en';
}
$OUTPUT->set_env('spell_langs', $spellcheck_langs);
$OUTPUT->set_env('spell_lang', $lang);
$editor_lang_set = array();
foreach ($spellcheck_langs as $key => $name) {
$editor_lang_set[] = ($key == $lang ? '+' : '') . rcube::JQ($name).'='.rcube::JQ($key);
}
// include GoogieSpell
$OUTPUT->include_script('googiespell.js');
$OUTPUT->add_script(sprintf(
"var googie = new GoogieSpell('%s/images/googiespell/','%s&lang=', %s);\n".
"googie.lang_chck_spell = \"%s\";\n".
"googie.lang_rsm_edt = \"%s\";\n".
"googie.lang_close = \"%s\";\n".
"googie.lang_revert = \"%s\";\n".
"googie.lang_no_error_found = \"%s\";\n".
"googie.lang_learn_word = \"%s\";\n".
"googie.setLanguages(%s);\n".
"googie.setCurrentLanguage('%s');\n".
"googie.setDecoration(false);\n".
"googie.decorateTextarea('%s');\n",
$RCMAIL->output->get_skin_path(),
$RCMAIL->url(array('_task' => 'utils', '_action' => 'spell', '_remote' => 1)),
!empty($dictionary) ? 'true' : 'false',
rcube::JQ(rcube::Q($RCMAIL->gettext('checkspelling'))),
rcube::JQ(rcube::Q($RCMAIL->gettext('resumeediting'))),
rcube::JQ(rcube::Q($RCMAIL->gettext('close'))),
rcube::JQ(rcube::Q($RCMAIL->gettext('revertto'))),
rcube::JQ(rcube::Q($RCMAIL->gettext('nospellerrors'))),
rcube::JQ(rcube::Q($RCMAIL->gettext('addtodict'))),
rcube_output::json_serialize($spellcheck_langs),
$lang,
$attrib['id']), 'foot');
$OUTPUT->add_label('checking');
$OUTPUT->set_env('spellcheck_langs', join(',', $editor_lang_set));
}
$out .= "\n".'<iframe name="savetarget" src="program/resources/blank.gif" style="width:0;height:0;border:none;visibility:hidden;" aria-hidden="true"></iframe>';
return $out;
}
function rcmail_create_reply_body($body, $bodyIsHtml)
{
global $RCMAIL, $MESSAGE, $LINE_LENGTH;
// build reply prefix
$from = array_pop(rcube_mime::decode_address_list($MESSAGE->get_header('from'), 1, false, $MESSAGE->headers->charset));
$prefix = $RCMAIL->gettext(array(
'name' => 'mailreplyintro',
'vars' => array(
'date' => $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')),
'sender' => $from['name'] ? $from['name'] : rcube_utils::idn_to_utf8($from['mailto']),
)
));
$reply_mode = intval($RCMAIL->config->get('reply_mode'));
if (!$bodyIsHtml) {
$body = preg_replace('/\r?\n/', "\n", $body);
$body = trim($body, "\n");
// soft-wrap and quote message text
$body = rcmail_wrap_and_quote($body, $LINE_LENGTH);
$prefix .= "\n";
if ($reply_mode > 0) { // top-posting
$prefix = "\n\n\n" . $prefix;
$suffix = '';
}
else {
$suffix = "\n";
}
}
else {
// save inline images to files
$cid_map = rcmail_write_inline_attachments($MESSAGE);
// set is_safe flag (we need this for html body washing)
rcmail_check_safe($MESSAGE);
// clean up html tags
$body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map);
// build reply (quote content)
$prefix = '<p>' . rcube::Q($prefix) . "</p>\n";
$prefix .= '<blockquote>';
if ($reply_mode > 0) { // top-posting
$prefix = '<br>' . $prefix;
$suffix = '</blockquote>';
}
else {
$suffix = '</blockquote><p></p>';
}
}
return $prefix . $body . $suffix;
}
function rcmail_create_forward_body($body, $bodyIsHtml)
{
global $RCMAIL, $MESSAGE, $COMPOSE;
// add attachments
if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts)) {
$cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml);
}
$date = $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long'));
if (!$bodyIsHtml) {
$prefix = "\n\n\n-------- " . $RCMAIL->gettext('originalmessage') . " --------\n";
$prefix .= $RCMAIL->gettext('subject') . ': ' . $MESSAGE->subject . "\n";
$prefix .= $RCMAIL->gettext('date') . ': ' . $date . "\n";
$prefix .= $RCMAIL->gettext('from') . ': ' . $MESSAGE->get_header('from') . "\n";
$prefix .= $RCMAIL->gettext('to') . ': ' . $MESSAGE->get_header('to') . "\n";
if ($cc = $MESSAGE->headers->get('cc')) {
$prefix .= $RCMAIL->gettext('cc') . ': ' . $cc . "\n";
}
if (($replyto = $MESSAGE->headers->get('reply-to')) && $replyto != $MESSAGE->get_header('from')) {
$prefix .= $RCMAIL->gettext('replyto') . ': ' . $replyto . "\n";
}
$prefix .= "\n";
$body = trim($body, "\r\n");
}
else {
// set is_safe flag (we need this for html body washing)
rcmail_check_safe($MESSAGE);
// clean up html tags
$body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map);
$prefix = sprintf(
"<br /><p>-------- " . $RCMAIL->gettext('originalmessage') . " --------</p>" .
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody>" .
"<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" .
"<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" .
"<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" .
"<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>",
$RCMAIL->gettext('subject'), rcube::Q($MESSAGE->subject),
$RCMAIL->gettext('date'), rcube::Q($date),
$RCMAIL->gettext('from'), rcube::Q($MESSAGE->get_header('from'), 'replace'),
$RCMAIL->gettext('to'), rcube::Q($MESSAGE->get_header('to'), 'replace'));
if ($cc = $MESSAGE->headers->get('cc'))
$prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>",
$RCMAIL->gettext('cc'), rcube::Q($cc, 'replace'));
if (($replyto = $MESSAGE->headers->get('reply-to')) && $replyto != $MESSAGE->get_header('from'))
$prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>",
$RCMAIL->gettext('replyto'), rcube::Q($replyto, 'replace'));
$prefix .= "</tbody></table><br>";
}
return $prefix . $body;
}
function rcmail_create_draft_body($body, $bodyIsHtml)
{
global $MESSAGE, $COMPOSE;
// add attachments
// sizeof($MESSAGE->mime_parts can be 1 - e.g. attachment, but no text!
if (empty($COMPOSE['forward_attachments'])
&& is_array($MESSAGE->mime_parts)
&& count($MESSAGE->mime_parts) > 0
) {
$cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml);
}
// clean up HTML tags - XSS prevention (#1489251)
if ($bodyIsHtml) {
$body = rcmail_wash_html($body, array('safe' => 1), $cid_map);
// remove comments (produced by washtml)
$body = preg_replace('/<!--[^>]+-->/', '', $body);
// replace cid with href in inline images links
if (!empty($cid_map)) {
$body = str_replace(array_keys($cid_map), array_values($cid_map), $body);
}
}
return $body;
}
function rcmail_remove_signature($body)
{
global $RCMAIL;
$body = str_replace("\r\n", "\n", $body);
$len = strlen($body);
$sig_max_lines = $RCMAIL->config->get('sig_max_lines', 15);
while (($sp = strrpos($body, "-- \n", $sp ? -$len+$sp-1 : 0)) !== false) {
if ($sp == 0 || $body[$sp-1] == "\n") {
// do not touch blocks with more that X lines
if (substr_count($body, "\n", $sp) < $sig_max_lines) {
$body = substr($body, 0, max(0, $sp-1));
}
break;
}
}
return $body;
}
function rcmail_write_compose_attachments(&$message, $bodyIsHtml)
{
global $RCMAIL, $COMPOSE, $compose_mode;
$loaded_attachments = array();
foreach ((array)$COMPOSE['attachments'] as $attachment) {
$loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment;
}
$cid_map = array();
$messages = array();
foreach ((array)$message->mime_parts as $pid => $part) {
if ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) {
// skip parts that aren't valid attachments
if ($part->ctype_primary == 'multipart' || $part->mimetype == 'application/ms-tnef') {
continue;
}
// skip message attachments in reply mode
if ($part->ctype_primary == 'message' && $compose_mode == RCUBE_COMPOSE_REPLY) {
continue;
}
// skip inline images when forwarding in text mode
if ($part->content_id && $part->disposition == 'inline' && !$bodyIsHtml && $compose_mode == RCUBE_COMPOSE_FORWARD) {
continue;
}
// skip message/rfc822 attachments on forwards (#1489214)
// Thunderbird when forwarding in inline mode displays such attachments
// and skips any attachments from inside of such part, this however
// skipped e.g. images used in HTML body or other attachments. So,
// better to skip .eml attachments but not their content (included files).
if ($part->mimetype == 'message/rfc822') {
if ($compose_mode == RCUBE_COMPOSE_FORWARD) {
continue;
}
$messages[] = $part->mime_id;
}
else if ($compose_mode != RCUBE_COMPOSE_FORWARD) {
// skip attachments included in message/rfc822 attachment (#1486487)
foreach ($messages as $mimeid) {
if (strpos($part->mime_id, $mimeid . '.') === 0) {
continue 2;
}
}
}
if (($attachment = $loaded_attachments[rcmail_attachment_name($part) . $part->mimetype])
|| ($attachment = rcmail_save_attachment($message, $pid))
) {
$COMPOSE['attachments'][$attachment['id']] = $attachment;
if ($bodyIsHtml && ($part->content_id || $part->content_location)) {
$url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s',
$RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']);
if ($part->content_id)
$cid_map['cid:'.$part->content_id] = $url;
else
$cid_map[$part->content_location] = $url;
}
}
}
}
$COMPOSE['forward_attachments'] = true;
return $cid_map;
}
function rcmail_write_inline_attachments(&$message)
{
global $RCMAIL, $COMPOSE;
$cid_map = array();
foreach ((array)$message->mime_parts as $pid => $part) {
if (($part->content_id || $part->content_location) && $part->filename) {
if ($attachment = rcmail_save_attachment($message, $pid)) {
$COMPOSE['attachments'][$attachment['id']] = $attachment;
$url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s',
$RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']);
if ($part->content_id)
$cid_map['cid:'.$part->content_id] = $url;
else
$cid_map[$part->content_location] = $url;
}
}
}
return $cid_map;
}
// Creates attachment(s) from the forwarded message(s)
function rcmail_write_forward_attachments()
{
global $RCMAIL, $COMPOSE, $MESSAGE;
$storage = $RCMAIL->get_storage();
$names = array();
$refs = array();
$loaded_attachments = array();
foreach ((array)$COMPOSE['attachments'] as $attachment) {
$loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment;
}
if ($COMPOSE['forward_uid'] == '*') {
$index = $storage->index(null, rcmail_sort_column(), rcmail_sort_order());
$COMPOSE['forward_uid'] = $index->get();
}
else if (!is_array($COMPOSE['forward_uid']) && strpos($COMPOSE['forward_uid'], ':')) {
$COMPOSE['forward_uid'] = rcube_imap_generic::uncompressMessageSet($COMPOSE['forward_uid']);
}
else if (is_string($COMPOSE['forward_uid'])) {
$COMPOSE['forward_uid'] = explode(',', $COMPOSE['forward_uid']);
}
foreach ((array)$COMPOSE['forward_uid'] as $uid) {
$message = new rcube_message($uid);
if (empty($message->headers)) {
continue;
}
if (!empty($message->headers->charset)) {
$storage->set_charset($message->headers->charset);
}
if (empty($MESSAGE->subject)) {
$MESSAGE->subject = $message->subject;
}
// generate (unique) attachment name
$name = strlen($message->subject) ? mb_substr($message->subject, 0, 64) : 'message_rfc822';
if (!empty($names[$name])) {
$names[$name]++;
$name .= '_' . $names[$name];
}
$names[$name] = 1;
$name .= '.eml';
$data = $path = null;
if (!empty($loaded_attachments[$name . 'message/rfc822'])) {
continue;
}
// don't load too big attachments into memory
if (!rcube_utils::mem_check($message->size)) {
$temp_dir = unslashify($RCMAIL->config->get('temp_dir'));
$path = tempnam($temp_dir, 'rcmAttmnt');
if ($fp = fopen($path, 'w')) {
$storage->get_raw_body($message->uid, $fp);
fclose($fp);
}
else {
return false;
}
}
else {
$data = $storage->get_raw_body($message->uid);
- $curr_mem += $message->size;
}
$attachment = array(
'group' => $COMPOSE['id'],
'name' => $name,
'mimetype' => 'message/rfc822',
'data' => $data,
'path' => $path,
'size' => $path ? filesize($path) : strlen($data),
);
$attachment = $RCMAIL->plugins->exec_hook('attachment_save', $attachment);
if ($attachment['status']) {
unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']);
$COMPOSE['attachments'][$attachment['id']] = $attachment;
}
else if ($path) {
@unlink($path);
}
if ($message->headers->messageID) {
$refs[] = $message->headers->messageID;
}
}
// set In-Reply-To and References headers
if (count($refs) == 1) {
$COMPOSE['reply_msgid'] = $refs[0];
}
if (!empty($refs)) {
$COMPOSE['references'] = implode(' ', $refs);
}
}
function rcmail_save_attachment(&$message, $pid)
{
global $COMPOSE;
$rcmail = rcmail::get_instance();
$part = $message->mime_parts[$pid];
$data = $path = null;
// don't load too big attachments into memory
if (!rcube_utils::mem_check($part->size)) {
$temp_dir = unslashify($rcmail->config->get('temp_dir'));
$path = tempnam($temp_dir, 'rcmAttmnt');
if ($fp = fopen($path, 'w')) {
$message->get_part_body($pid, false, 0, $fp);
fclose($fp);
}
else {
return false;
}
}
else {
$data = $message->get_part_body($pid);
}
$mimetype = $part->ctype_primary . '/' . $part->ctype_secondary;
$filename = rcmail_attachment_name($part);
$attachment = array(
'group' => $COMPOSE['id'],
'name' => $filename,
'mimetype' => $mimetype,
'content_id' => $part->content_id,
'data' => $data,
'path' => $path,
'size' => $path ? filesize($path) : strlen($data),
'charset' => $part->charset,
);
$attachment = $rcmail->plugins->exec_hook('attachment_save', $attachment);
if ($attachment['status']) {
unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']);
return $attachment;
}
else if ($path) {
@unlink($path);
}
return false;
}
function rcmail_save_image($path, $mimetype='')
{
global $COMPOSE;
// handle attachments in memory
$data = file_get_contents($path);
$name = rcmail_basename($path);
$attachment = array(
'group' => $COMPOSE['id'],
'name' => $name,
'mimetype' => $mimetype ? $mimetype : rcube_mime::file_content_type($path, $name),
'data' => $data,
'size' => strlen($data),
);
$attachment = rcmail::get_instance()->plugins->exec_hook('attachment_save', $attachment);
if ($attachment['status']) {
unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']);
return $attachment;
}
return false;
}
function rcmail_basename($filename)
{
// basename() is not unicode safe and locale dependent
if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) {
return preg_replace('/^.*[\\\\\\/]/', '', $filename);
}
else {
return preg_replace('/^.*[\/]/', '', $filename);
}
}
function rcmail_compose_subject($attrib)
{
global $MESSAGE, $COMPOSE, $compose_mode;
list($form_start, $form_end) = get_form_tags($attrib);
unset($attrib['form']);
$attrib['name'] = '_subject';
$attrib['spellcheck'] = 'true';
$textfield = new html_inputfield($attrib);
$subject = '';
// use subject from post
if (isset($_POST['_subject'])) {
$subject = rcube_utils::get_input_value('_subject', rcube_utils::INPUT_POST, TRUE);
}
else if (!empty($COMPOSE['param']['subject'])) {
$subject = $COMPOSE['param']['subject'];
}
// create a reply-subject
else if ($compose_mode == RCUBE_COMPOSE_REPLY) {
if (preg_match('/^re:/i', $MESSAGE->subject))
$subject = $MESSAGE->subject;
else
$subject = 'Re: '.$MESSAGE->subject;
// replace (was: ...) (#1489375)
$subject = preg_replace('/\s*\([wW]as:[^\)]+\)\s*$/', '', $subject);
}
// create a forward-subject
else if ($compose_mode == RCUBE_COMPOSE_FORWARD) {
if (preg_match('/^fwd:/i', $MESSAGE->subject))
$subject = $MESSAGE->subject;
else
$subject = 'Fwd: '.$MESSAGE->subject;
}
// creeate a draft-subject
else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) {
$subject = $MESSAGE->subject;
}
$out = $form_start ? "$form_start\n" : '';
$out .= $textfield->show($subject);
$out .= $form_end ? "\n$form_end" : '';
return $out;
}
function rcmail_compose_attachment_list($attrib)
{
global $RCMAIL, $OUTPUT, $COMPOSE;
// add ID if not given
if (!$attrib['id'])
$attrib['id'] = 'rcmAttachmentList';
$out = "\n";
$jslist = array();
$button = '';
$skin_path = $RCMAIL->config->get('skin_path');
if (is_array($COMPOSE['attachments'])) {
if ($attrib['deleteicon']) {
$button = html::img(array(
'src' => $skin_path . $attrib['deleteicon'],
'alt' => $RCMAIL->gettext('delete')
));
}
else if (rcube_utils::get_boolean($attrib['textbuttons'])) {
$button = rcube::Q($RCMAIL->gettext('delete'));
}
foreach ($COMPOSE['attachments'] as $id => $a_prop) {
if (empty($a_prop)) {
continue;
}
$out .= html::tag('li', array(
'id' => 'rcmfile'.$id,
'class' => rcube_utils::file2class($a_prop['mimetype'], $a_prop['name']),
'onmouseover' => "rcube_webmail.long_subject_title_ex(this, 0)",
),
html::a(array(
'href' => "#delete",
'title' => $RCMAIL->gettext('delete'),
'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", rcmail_output::JS_OBJECT_NAME, $id),
'class' => 'delete',
'tabindex' => $attrib['tabindex'] ?: '0',
'aria-label' => $RCMAIL->gettext('delete') . ' ' . $a_prop['name'],
),
$button
) . rcube::Q($a_prop['name'])
);
$jslist['rcmfile'.$id] = array(
'name' => $a_prop['name'],
'complete' => true,
'mimetype' => $a_prop['mimetype']
);
}
}
if ($attrib['deleteicon'])
$COMPOSE['deleteicon'] = $skin_path . $attrib['deleteicon'];
else if (rcube_utils::get_boolean($attrib['textbuttons']))
$COMPOSE['textbuttons'] = true;
if ($attrib['cancelicon'])
$OUTPUT->set_env('cancelicon', $skin_path . $attrib['cancelicon']);
if ($attrib['loadingicon'])
$OUTPUT->set_env('loadingicon', $skin_path . $attrib['loadingicon']);
$OUTPUT->set_env('attachments', $jslist);
$OUTPUT->add_gui_object('attachmentlist', $attrib['id']);
// put tabindex value into data-tabindex attribute
if (isset($attrib['tabindex'])) {
$attrib['data-tabindex'] = $attrib['tabindex'];
unset($attrib['tabindex']);
}
return html::tag('ul', $attrib, $out, html::$common_attrib);
}
function rcmail_compose_attachment_form($attrib)
{
global $OUTPUT, $RCMAIL;
// set defaults
$attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes');
// Get filesize, enable upload progress bar
$max_filesize = $RCMAIL->upload_init();
$button = new html_inputfield(array('type' => 'button'));
$content = html::div(null, rcmail_compose_attachment_field())
. html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))));
if (rcube_utils::get_boolean($attrib['buttons'])) {
$content .= html::div('buttons',
$button->show($RCMAIL->gettext('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' .
$button->show($RCMAIL->gettext('upload'), array('class' => 'button mainaction', 'onclick' => rcmail_output::JS_OBJECT_NAME . ".command('send-attachment', this.form)"))
);
}
$out = html::div($attrib, $OUTPUT->form_tag(array(
'id' => $attrib['id'] . 'Frm',
'name' => 'uploadform',
'method' => 'post',
'enctype' => 'multipart/form-data'
), $content
));
$OUTPUT->add_gui_object('uploadform', $attrib['id'] . 'Frm');
return $out;
}
function rcmail_compose_attachment_field($attrib = array())
{
$attrib['type'] = 'file';
$attrib['name'] = '_attachments[]';
$attrib['multiple'] = 'multiple';
$field = new html_inputfield($attrib);
return $field->show();
}
function rcmail_priority_selector($attrib)
{
global $RCMAIL, $MESSAGE;
list($form_start, $form_end) = get_form_tags($attrib);
unset($attrib['form']);
$attrib['name'] = '_priority';
$prio_list = array(
$RCMAIL->gettext('lowest') => 5,
$RCMAIL->gettext('low') => 4,
$RCMAIL->gettext('normal') => 0,
$RCMAIL->gettext('high') => 2,
$RCMAIL->gettext('highest') => 1,
);
$selector = new html_select($attrib);
$selector->add(array_keys($prio_list), array_values($prio_list));
if (isset($_POST['_priority']))
$sel = $_POST['_priority'];
else if (isset($MESSAGE->headers->priority) && intval($MESSAGE->headers->priority) != 3)
$sel = $MESSAGE->headers->priority;
else
$sel = 0;
$out = $form_start ? "$form_start\n" : '';
$out .= $selector->show((int) $sel);
$out .= $form_end ? "\n$form_end" : '';
return $out;
}
function rcmail_receipt_checkbox($attrib)
{
global $RCMAIL, $MESSAGE, $compose_mode;
list($form_start, $form_end) = get_form_tags($attrib);
unset($attrib['form']);
if (!isset($attrib['id']))
$attrib['id'] = 'receipt';
$attrib['name'] = '_receipt';
$attrib['value'] = '1';
$checkbox = new html_checkbox($attrib);
if (isset($_POST['_receipt']))
$mdn_default = $_POST['_receipt'];
else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT)))
$mdn_default = (bool) $MESSAGE->headers->mdn_to;
else
$mdn_default = $RCMAIL->config->get('mdn_default');
$out = $form_start ? "$form_start\n" : '';
$out .= $checkbox->show($mdn_default);
$out .= $form_end ? "\n$form_end" : '';
return $out;
}
function rcmail_dsn_checkbox($attrib)
{
global $RCMAIL;
list($form_start, $form_end) = get_form_tags($attrib);
unset($attrib['form']);
if (!isset($attrib['id']))
$attrib['id'] = 'dsn';
$attrib['name'] = '_dsn';
$attrib['value'] = '1';
$checkbox = new html_checkbox($attrib);
if (isset($_POST['_dsn']))
$dsn_value = (int) $_POST['_dsn'];
else
$dsn_value = $RCMAIL->config->get('dsn_default');
$out = $form_start ? "$form_start\n" : '';
$out .= $checkbox->show($dsn_value);
$out .= $form_end ? "\n$form_end" : '';
return $out;
}
function rcmail_editor_selector($attrib)
{
global $RCMAIL;
// determine whether HTML or plain text should be checked
$useHtml = rcmail_compose_editor_mode();
if (empty($attrib['editorid']))
$attrib['editorid'] = 'rcmComposeBody';
if (empty($attrib['name']))
$attrib['name'] = 'editorSelect';
$attrib['onchange'] = "return rcmail.command('toggle-editor', {id: '".$attrib['editorid']."', html: this.value == 'html'}, '', event)";
$select = new html_select($attrib);
$select->add(rcube::Q($RCMAIL->gettext('htmltoggle')), 'html');
$select->add(rcube::Q($RCMAIL->gettext('plaintoggle')), 'plain');
return $select->show($useHtml ? 'html' : 'plain');
}
function rcmail_store_target_selection($attrib)
{
global $COMPOSE, $RCMAIL;
$attrib['name'] = '_store_target';
$select = $RCMAIL->folder_selector(array_merge($attrib, array(
'noselection' => '- ' . $RCMAIL->gettext('dontsave') . ' -',
'folder_filter' => 'mail',
'folder_rights' => 'w',
'realnames' => $RCMAIL->config->get('show_real_foldernames'),
)));
return $select->show(isset($_POST['_store_target']) ? $_POST['_store_target'] : $COMPOSE['param']['sent_mbox'], $attrib);
}
function rcmail_check_sent_folder($folder, $create=false)
{
global $RCMAIL;
// we'll not save the message, so it doesn't matter
if ($RCMAIL->config->get('no_save_sent_messages')) {
return true;
}
if ($RCMAIL->storage->folder_exists($folder, true)) {
return true;
}
// folder may exist but isn't subscribed (#1485241)
if ($create) {
if (!$RCMAIL->storage->folder_exists($folder))
return $RCMAIL->storage->create_folder($folder, true);
else
return $RCMAIL->storage->subscribe($folder);
}
return false;
}
function get_form_tags($attrib)
{
global $RCMAIL, $MESSAGE_FORM, $COMPOSE;
$form_start = '';
if (!$MESSAGE_FORM) {
$hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $RCMAIL->task));
$hiddenfields->add(array('name' => '_action', 'value' => 'send'));
$hiddenfields->add(array('name' => '_id', 'value' => $COMPOSE['id']));
$hiddenfields->add(array('name' => '_attachments'));
$form_start = empty($attrib['form']) ? $RCMAIL->output->form_tag(array('name' => "form", 'method' => "post")) : '';
$form_start .= $hiddenfields->show();
}
$form_end = ($MESSAGE_FORM && !strlen($attrib['form'])) ? '</form>' : '';
$form_name = !empty($attrib['form']) ? $attrib['form'] : 'form';
if (!$MESSAGE_FORM)
$RCMAIL->output->add_gui_object('messageform', $form_name);
$MESSAGE_FORM = $form_name;
return array($form_start, $form_end);
}
function rcmail_addressbook_list($attrib = array())
{
global $RCMAIL, $OUTPUT;
$attrib += array('id' => 'rcmdirectorylist');
$out = '';
$line_templ = html::tag('li', array(
'id' => 'rcmli%s', 'class' => '%s'),
html::a(array('href' => '#list',
'rel' => '%s',
'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('list-adresses','%s',this)"), '%s'));
foreach ($RCMAIL->get_address_sources(false, true) as $j => $source) {
$id = strval(strlen($source['id']) ? $source['id'] : $j);
$js_id = rcube::JQ($id);
// set class name(s)
$class_name = 'addressbook';
if ($source['class_name'])
$class_name .= ' ' . $source['class_name'];
$out .= sprintf($line_templ,
rcube_utils::html_identifier($id,true),
$class_name,
$source['id'],
$js_id, (!empty($source['name']) ? $source['name'] : $id));
}
$OUTPUT->add_gui_object('addressbookslist', $attrib['id']);
return html::tag('ul', $attrib, $out, html::$common_attrib);
}
// return the contacts list as HTML table
function rcmail_contacts_list($attrib = array())
{
global $RCMAIL, $OUTPUT;
$attrib += array('id' => 'rcmAddressList');
// set client env
$OUTPUT->add_gui_object('contactslist', $attrib['id']);
$OUTPUT->set_env('pagecount', 0);
$OUTPUT->set_env('current_page', 0);
$OUTPUT->include_script('list.js');
return $RCMAIL->table_output($attrib, array(), array('name'), 'ID');
}
/**
* Register a certain container as active area to drop files onto
*/
function compose_file_drop_area($attrib)
{
global $OUTPUT;
if ($attrib['id']) {
$OUTPUT->add_gui_object('filedrop', $attrib['id']);
$OUTPUT->set_env('filedrop', array('action' => 'upload', 'fieldname' => '_attachments'));
}
}
/**
*
*/
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',
'tabindex' => '0',
'rel' => $key,
), rcube::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();
}
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 167e30927..e33e965bd 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -1,2166 +1,2166 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/mail/func.inc |
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2005-2014, 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: |
| Provide webmail functionality and GUI objects |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
// always instantiate storage object (but not connect to server yet)
$RCMAIL->storage_init();
// init environment - set current folder, page, list mode
rcmail_init_env();
// set message set for search result
if (!empty($_REQUEST['_search']) && isset($_SESSION['search'])
&& $_SESSION['search_request'] == $_REQUEST['_search']
) {
$RCMAIL->storage->set_search_set($_SESSION['search']);
$OUTPUT->set_env('search_request', $_REQUEST['_search']);
$OUTPUT->set_env('search_text', $_SESSION['last_text_search']);
}
// remove mbox part from _uid
if (($_uid = rcube_utils::get_input_value('_uid', RCUBE_INPUT_GPC)) && !is_array($_uid) && preg_match('/^\d+-.+/', $_uid)) {
list($_uid, $mbox) = explode('-', $_uid, 2);
if (isset($_GET['_uid'])) $_GET['_uid'] = $_uid;
if (isset($_POST['_uid'])) $_POST['_uid'] = $_uid;
$_REQUEST['_uid'] = $_uid;
unset($_uid);
// override mbox
if (!empty($mbox)) {
$_GET['_mbox'] = $mbox;
$_POST['_mbox'] = $mbox;
$RCMAIL->storage->set_folder(($_SESSION['mbox'] = $mbox));
}
}
if (!empty($_SESSION['browser_caps']) && !$OUTPUT->ajax_call) {
$OUTPUT->set_env('browser_capabilities', $_SESSION['browser_caps']);
}
// set main env variables, labels and page title
if (empty($RCMAIL->action) || $RCMAIL->action == 'list') {
// connect to storage server and trigger error on failure
$RCMAIL->storage_connect();
$mbox_name = $RCMAIL->storage->get_folder();
if (empty($RCMAIL->action)) {
// initialize searching result if search_filter is used
if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') {
$RCMAIL->storage->search($mbox_name, $_SESSION['search_filter'], RCUBE_CHARSET, rcmail_sort_column());
$search_request = md5($mbox_name.$_SESSION['search_filter']);
$_SESSION['search'] = $RCMAIL->storage->get_search_set();
$_SESSION['search_request'] = $search_request;
$OUTPUT->set_env('search_request', $search_request);
}
$OUTPUT->set_env('search_mods', rcmail_search_mods());
if (!empty($_SESSION['search_scope']))
$OUTPUT->set_env('search_scope', $_SESSION['search_scope']);
rcmail_list_pagetitle();
}
$threading = (bool) $RCMAIL->storage->get_threading();
$delimiter = $RCMAIL->storage->get_hierarchy_delimiter();
// set current mailbox and some other vars in client environment
$OUTPUT->set_env('mailbox', $mbox_name);
$OUTPUT->set_env('pagesize', $RCMAIL->storage->get_pagesize());
$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);
}
// set special folders
foreach (array('drafts', 'trash', 'junk') as $mbox) {
if ($folder = $RCMAIL->config->get($mbox . '_mbox')) {
$OUTPUT->set_env($mbox . '_mailbox', $folder);
}
}
if (!empty($_GET['_uid'])) {
$OUTPUT->set_env('list_uid', $_GET['_uid']);
}
// set configuration
$RCMAIL->set_env_config(array('delete_junk', 'flag_for_deletion', 'read_when_deleted',
'skip_deleted', 'display_next', 'message_extwin', 'forward_attachment'));
if (!$OUTPUT->ajax_call) {
$OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash',
'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage',
'copy', 'move', 'quota', 'replyall', 'replylist', 'stillsearching',
'flagged', 'unflagged', 'unread', 'deleted', 'replied', 'forwarded',
'priority', 'withattachment', 'fileuploaderror');
}
}
// register UI objects
$OUTPUT->add_handlers(array(
'mailboxlist' => array($RCMAIL, 'folder_list'),
'quotadisplay' => array($RCMAIL, 'quota_display'),
'messages' => 'rcmail_message_list',
'messagecountdisplay' => 'rcmail_messagecount_display',
'mailboxname' => 'rcmail_mailbox_name_display',
'messageheaders' => 'rcmail_message_headers',
'messagefullheaders' => 'rcmail_message_full_headers',
'messagebody' => 'rcmail_message_body',
'messagecontentframe' => 'rcmail_messagecontent_frame',
'messageimportform' => 'rcmail_message_import_form',
'searchfilter' => 'rcmail_search_filter',
'searchform' => array($OUTPUT, 'search_form'),
));
// register action aliases
$RCMAIL->register_action_map(array(
'refresh' => 'check_recent.inc',
'preview' => 'show.inc',
'print' => 'show.inc',
'move' => 'move_del.inc',
'delete' => 'move_del.inc',
'send' => 'sendmail.inc',
'expunge' => 'folders.inc',
'purge' => 'folders.inc',
'remove-attachment' => 'attachments.inc',
'display-attachment' => 'attachments.inc',
'upload' => 'attachments.inc',
'group-expand' => 'autocomplete.inc',
));
/**
* Sets storage properties and session
*/
function rcmail_init_env()
{
global $RCMAIL;
$default_threading = $RCMAIL->config->get('default_list_mode', 'list') == 'threads';
$a_threading = $RCMAIL->config->get('message_threading', array());
$message_sort_col = $RCMAIL->config->get('message_sort_col');
$message_sort_order = $RCMAIL->config->get('message_sort_order');
// set imap properties and session vars
if (!strlen($mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true))) {
$mbox = strlen($_SESSION['mbox']) ? $_SESSION['mbox'] : 'INBOX';
}
if (!($page = intval($_GET['_page']))) {
$page = $_SESSION['page'] ? $_SESSION['page'] : 1;
}
$RCMAIL->storage->set_folder($_SESSION['mbox'] = $mbox);
$RCMAIL->storage->set_page($_SESSION['page'] = $page);
// set default sort col/order to session
if (!isset($_SESSION['sort_col'])) {
$_SESSION['sort_col'] = $message_sort_col ? $message_sort_col : '';
}
if (!isset($_SESSION['sort_order'])) {
$_SESSION['sort_order'] = strtoupper($message_sort_order) == 'ASC' ? 'ASC' : 'DESC';
}
// set threads mode
if (isset($_GET['_threads'])) {
if ($_GET['_threads']) {
// re-set current page number when listing mode changes
if (!$a_threading[$_SESSION['mbox']]) {
$RCMAIL->storage->set_page($_SESSION['page'] = 1);
}
$a_threading[$_SESSION['mbox']] = true;
}
else {
// re-set current page number when listing mode changes
if ($a_threading[$_SESSION['mbox']]) {
$RCMAIL->storage->set_page($_SESSION['page'] = 1);
}
$a_threading[$_SESSION['mbox']] = false;
}
$RCMAIL->user->save_prefs(array('message_threading' => $a_threading));
}
$threading = isset($a_threading[$_SESSION['mbox']]) ? $a_threading[$_SESSION['mbox']] : $default_threading;
$RCMAIL->storage->set_threading($threading);
}
/**
* Sets page title
*/
function rcmail_list_pagetitle()
{
global $RCMAIL;
if ($RCMAIL->output->get_env('search_request')) {
$pagetitle = $RCMAIL->gettext('searchresult');
}
else {
$mbox_name = $RCMAIL->output->get_env('mailbox') ?: $RCMAIL->storage->get_folder();
$delimiter = $RCMAIL->storage->get_hierarchy_delimiter();
$pagetitle = $RCMAIL->localize_foldername($mbox_name, true);
$pagetitle = str_replace($delimiter, " \xC2\xBB ", $pagetitle);
}
$RCMAIL->output->set_pagetitle($pagetitle);
}
/**
* Returns default search mods
*/
function rcmail_search_mods()
{
global $RCMAIL;
$mods = $RCMAIL->config->get('search_mods');
if (empty($mods)) {
$mods = array('*' => array('subject' => 1, 'from' => 1));
foreach (array('sent', 'drafts') as $mbox) {
if ($mbox = $RCMAIL->config->get($mbox . '_mbox')) {
$mods[$mbox] = array('subject' => 1, 'to' => 1);
}
}
}
return $mods;
}
/**
* Returns 'to' if current folder is configured Sent or Drafts
* or their subfolders, otherwise returns 'from'.
*
* @return string Column name
*/
function rcmail_message_list_smart_column_name()
{
global $RCMAIL;
$delim = $RCMAIL->storage->get_hierarchy_delimiter();
$mbox = $RCMAIL->output->get_env('mailbox') ?: $RCMAIL->storage->get_folder();
$sent_mbox = $RCMAIL->config->get('sent_mbox');
$drafts_mbox = $RCMAIL->config->get('drafts_mbox');
if ((strpos($mbox.$delim, $sent_mbox.$delim) === 0 || strpos($mbox.$delim, $drafts_mbox.$delim) === 0)
&& strtoupper($mbox) != 'INBOX'
) {
return 'to';
}
return 'from';
}
/**
* Returns configured messages list sorting column name
* The name is context-sensitive, which means if sorting is set to 'fromto'
* it will return 'from' or 'to' according to current folder type.
*
* @return string Column name
*/
function rcmail_sort_column()
{
global $RCMAIL;
if (isset($_SESSION['sort_col'])) {
$column = $_SESSION['sort_col'];
}
else {
$column = $RCMAIL->config->get('message_sort_col');
}
// get name of smart From/To column in folder context
if ($column == 'fromto') {
$column = rcmail_message_list_smart_column_name();
}
return $column;
}
/**
* Returns configured message list sorting order
*
* @return string Sorting order (ASC|DESC)
*/
function rcmail_sort_order()
{
global $RCMAIL;
if (isset($_SESSION['sort_order'])) {
return $_SESSION['sort_order'];
}
return $RCMAIL->config->get('message_sort_order');
}
/**
* return the message list as HTML table
*/
function rcmail_message_list($attrib)
{
global $RCMAIL, $OUTPUT;
// add some labels to client
$OUTPUT->add_label('from', 'to');
// add id to message list table if not specified
if (!strlen($attrib['id']))
$attrib['id'] = 'rcubemessagelist';
// define list of cols to be displayed based on parameter or config
if (empty($attrib['columns'])) {
$list_cols = $RCMAIL->config->get('list_cols');
$a_show_cols = !empty($list_cols) && is_array($list_cols) ? $list_cols : array('subject');
$OUTPUT->set_env('col_movable', !in_array('list_cols', (array)$RCMAIL->config->get('dont_override')));
}
else {
$a_show_cols = preg_split('/[\s,;]+/', str_replace(array("'", '"'), '', $attrib['columns']));
$attrib['columns'] = $a_show_cols;
}
// save some variables for use in ajax list
$_SESSION['list_attrib'] = $attrib;
// make sure 'threads' and 'subject' columns are present
if (!in_array('subject', $a_show_cols))
array_unshift($a_show_cols, 'subject');
if (!in_array('threads', $a_show_cols))
array_unshift($a_show_cols, 'threads');
$_SESSION['skin_path'] = $RCMAIL->config->get('skin_path');
// set client env
$OUTPUT->add_gui_object('messagelist', $attrib['id']);
$OUTPUT->set_env('autoexpand_threads', intval($RCMAIL->config->get('autoexpand_threads')));
$OUTPUT->set_env('sort_col', $_SESSION['sort_col']);
$OUTPUT->set_env('sort_order', $_SESSION['sort_order']);
$OUTPUT->set_env('messages', array());
$OUTPUT->set_env('listcols', $a_show_cols);
$OUTPUT->include_script('list.js');
$table = new html_table($attrib);
if (!$attrib['noheader']) {
foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell)
$table->add_header(array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']);
}
return $table->show();
}
/**
* return javascript commands to add rows to the message list
*/
function rcmail_js_message_list($a_headers, $insert_top=false, $a_show_cols=null)
{
global $RCMAIL, $OUTPUT;
if (empty($a_show_cols)) {
if (!empty($_SESSION['list_attrib']['columns']))
$a_show_cols = $_SESSION['list_attrib']['columns'];
else {
$list_cols = $RCMAIL->config->get('list_cols');
$a_show_cols = !empty($list_cols) && is_array($list_cols) ? $list_cols : array('subject');
}
}
else {
if (!is_array($a_show_cols)) {
$a_show_cols = preg_split('/[\s,;]+/', str_replace(array("'", '"'), '', $a_show_cols));
}
$head_replace = true;
}
$search_set = $RCMAIL->storage->get_search_set();
$multifolder = $search_set && $search_set[1]->multi;
// add/remove 'folder' column to the list on multi-folder searches
if ($multifolder && !in_array('folder', $a_show_cols)) {
$a_show_cols[] = 'folder';
$head_replace = true;
}
else if (!$multifolder && ($found = array_search('folder', $a_show_cols)) !== false) {
unset($a_show_cols[$found]);
$head_replace = true;
}
$mbox = $RCMAIL->output->get_env('mailbox') ?: $RCMAIL->storage->get_folder();
// make sure 'threads' and 'subject' columns are present
if (!in_array('subject', $a_show_cols))
array_unshift($a_show_cols, 'subject');
if (!in_array('threads', $a_show_cols))
array_unshift($a_show_cols, 'threads');
// Make sure there are no duplicated columns (#1486999)
$a_show_cols = array_unique($a_show_cols);
$_SESSION['list_attrib']['columns'] = $a_show_cols;
// Plugins may set header's list_cols/list_flags and other rcube_message_header variables
// and list columns
$plugin = $RCMAIL->plugins->exec_hook('messages_list',
array('messages' => $a_headers, 'cols' => $a_show_cols));
$a_show_cols = $plugin['cols'];
$a_headers = $plugin['messages'];
$thead = $head_replace ? rcmail_message_list_head($_SESSION['list_attrib'], $a_show_cols) : NULL;
// get name of smart From/To column in folder context
if (array_search('fromto', $a_show_cols) !== false) {
$smart_col = rcmail_message_list_smart_column_name();
}
$OUTPUT->command('set_message_coltypes', $a_show_cols, $thead, $smart_col);
if ($multifolder && $_SESSION['search_scope'] == 'all') {
$OUTPUT->command('select_folder', '');
}
$OUTPUT->set_env('multifolder_listing', $multifolder);
if (empty($a_headers)) {
return;
}
// remove 'threads', 'attachment', 'flag', 'status' columns, we don't need them here
foreach (array('threads', 'attachment', 'flag', 'status', 'priority') as $col) {
if (($key = array_search($col, $a_show_cols)) !== FALSE) {
unset($a_show_cols[$key]);
}
}
// loop through message headers
foreach ($a_headers as $header) {
if (empty($header))
continue;
// make message UIDs unique by appending the folder name
if ($multifolder) {
$header->uid .= '-'.$header->folder;
$header->flags['skip_mbox_check'] = true;
if ($header->parent_uid)
$header->parent_uid .= '-'.$header->folder;
}
$a_msg_cols = array();
$a_msg_flags = array();
// format each col; similar as in rcmail_message_list()
foreach ($a_show_cols as $col) {
$col_name = $col == 'fromto' ? $smart_col : $col;
if (in_array($col_name, array('from', 'to', 'cc', 'replyto')))
$cont = rcmail_address_string($header->$col_name, 3, false, null, $header->charset);
else if ($col == 'subject') {
$cont = trim(rcube_mime::decode_header($header->$col, $header->charset));
if (!$cont) $cont = $RCMAIL->gettext('nosubject');
$cont = rcube::Q($cont);
}
else if ($col == 'size')
$cont = show_bytes($header->$col);
else if ($col == 'date')
$cont = $RCMAIL->format_date($header->date);
else if ($col == 'folder')
$cont = rcube::Q(rcube_charset::convert($header->folder, 'UTF7-IMAP'));
else
$cont = rcube::Q($header->$col);
$a_msg_cols[$col] = $cont;
}
$a_msg_flags = array_change_key_case(array_map('intval', (array) $header->flags));
if ($header->depth)
$a_msg_flags['depth'] = $header->depth;
else if ($header->has_children)
$roots[] = $header->uid;
if ($header->parent_uid)
$a_msg_flags['parent_uid'] = $header->parent_uid;
if ($header->has_children)
$a_msg_flags['has_children'] = $header->has_children;
if ($header->unread_children)
$a_msg_flags['unread_children'] = $header->unread_children;
if ($header->others['list-post'])
$a_msg_flags['ml'] = 1;
if ($header->priority)
$a_msg_flags['prio'] = (int) $header->priority;
$a_msg_flags['ctype'] = rcube::Q($header->ctype);
$a_msg_flags['mbox'] = $header->folder;
// merge with plugin result (Deprecated, use $header->flags)
if (!empty($header->list_flags) && is_array($header->list_flags))
$a_msg_flags = array_merge($a_msg_flags, $header->list_flags);
if (!empty($header->list_cols) && is_array($header->list_cols))
$a_msg_cols = array_merge($a_msg_cols, $header->list_cols);
$OUTPUT->command('add_message_row',
$header->uid,
$a_msg_cols,
$a_msg_flags,
$insert_top);
}
if ($RCMAIL->storage->get_threading()) {
$OUTPUT->command('init_threads', (array) $roots, $mbox);
}
}
/*
* Creates <THEAD> for message list table
*/
function rcmail_message_list_head($attrib, $a_show_cols)
{
global $RCMAIL;
$skin_path = $_SESSION['skin_path'];
// check to see if we have some settings for sorting
$sort_col = $_SESSION['sort_col'];
$sort_order = $_SESSION['sort_order'];
$dont_override = (array) $RCMAIL->config->get('dont_override');
$disabled_sort = in_array('message_sort_col', $dont_override);
$disabled_order = in_array('message_sort_order', $dont_override);
$RCMAIL->output->set_env('disabled_sort_col', $disabled_sort);
$RCMAIL->output->set_env('disabled_sort_order', $disabled_order);
// define sortable columns
if ($disabled_sort)
$a_sort_cols = $sort_col && !$disabled_order ? array($sort_col) : array();
else
$a_sort_cols = array('subject', 'date', 'from', 'to', 'fromto', 'size', 'cc');
if (!empty($attrib['optionsmenuicon'])) {
$onclick = 'return ' . rcmail_output::JS_OBJECT_NAME . ".command('menu-open', 'messagelistmenu', this, event)";
$inner = $RCMAIL->gettext('listoptions');
if (is_string($attrib['optionsmenuicon']) && $attrib['optionsmenuicon'] != 'true') {
$inner = html::img(array('src' => $skin_path . $attrib['optionsmenuicon'], 'alt' => $RCMAIL->gettext('listoptions')));
}
$list_menu = html::a(array(
'href' => '#list-options',
'onclick' => $onclick,
'class' => 'listmenu',
'id' => 'listmenulink',
'title' => $RCMAIL->gettext('listoptions'),
'tabindex' => '0',
), $inner);
}
else {
$list_menu = '';
}
$cells = $coltypes = array();
// get name of smart From/To column in folder context
if (array_search('fromto', $a_show_cols) !== false) {
$smart_col = rcmail_message_list_smart_column_name();
}
foreach ($a_show_cols as $col) {
$label = '';
$sortable = false;
// get column name
switch ($col) {
case 'flag':
$col_name = html::span('flagged', $RCMAIL->gettext('flagged'));
break;
case 'attachment':
case 'priority':
$col_name = html::span($col, $RCMAIL->gettext($col));
break;
case 'status':
$col_name = html::span($col, $RCMAIL->gettext('readstatus'));
break;
case 'threads':
$col_name = $list_menu;
break;
case 'fromto':
$label = $RCMAIL->gettext($smart_col);
$col_name = rcube::Q($label);
break;
default:
$label = $RCMAIL->gettext($col);
$col_name = rcube::Q($label);
}
// make sort links
if (in_array($col, $a_sort_cols)) {
$sortable = true;
$col_name = html::a(array(
'href' => "./#sort",
'class' => 'sortcol',
'rel' => $col,
'title' => $RCMAIL->gettext('sortby')
), $col_name);
}
else if ($col_name[0] != '<') {
$col_name = '<span class="' . $col .'">' . $col_name . '</span>';
}
$sort_class = $col == $sort_col && !$disabled_order ? " sorted$sort_order" : '';
$class_name = $col.$sort_class;
// put it all together
$cells[] = array('className' => $class_name, 'id' => "rcm$col", 'html' => $col_name);
$coltypes[$col] = array('className' => $class_name, 'id' => "rcm$col", 'label' => $label, 'sortable' => $sortable);
}
$RCMAIL->output->set_env('coltypes', $coltypes);
return $cells;
}
/**
* return an HTML iframe for loading mail content
*/
function rcmail_messagecontent_frame($attrib)
{
- global $OUTPUT, $RCMAIL;
+ global $OUTPUT;
if (empty($attrib['id']))
$attrib['id'] = 'rcmailcontentwindow';
return $OUTPUT->frame($attrib, true);
}
function rcmail_messagecount_display($attrib)
{
global $RCMAIL;
if (!$attrib['id'])
$attrib['id'] = 'rcmcountdisplay';
$RCMAIL->output->add_gui_object('countdisplay', $attrib['id']);
$content = $RCMAIL->action != 'show' ? rcmail_get_messagecount_text() : $RCMAIL->gettext('loading');
return html::span($attrib, $content);
}
function rcmail_get_messagecount_text($count = null, $page = null)
{
global $RCMAIL;
if ($page === null) {
$page = $RCMAIL->storage->get_page();
}
$page_size = $RCMAIL->storage->get_pagesize();
$start_msg = ($page-1) * $page_size + 1;
if ($count !== null)
$max = $count;
else if ($RCMAIL->action)
$max = $RCMAIL->storage->count(NULL, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL');
if ($max == 0)
$out = $RCMAIL->storage->get_search_set() ? $RCMAIL->gettext('nomessages') : $RCMAIL->gettext('mailboxempty');
else
$out = $RCMAIL->gettext(array('name' => $RCMAIL->storage->get_threading() ? 'threadsfromto' : 'messagesfromto',
'vars' => array('from' => $start_msg,
'to' => min($max, $start_msg + $page_size - 1),
'count' => $max)));
return rcube::Q($out);
}
function rcmail_mailbox_name_display($attrib)
{
global $RCMAIL;
if (!$attrib['id'])
$attrib['id'] = 'rcmmailboxname';
$RCMAIL->output->add_gui_object('mailboxname', $attrib['id']);
return html::span($attrib, rcmail_get_mailbox_name_text());
}
function rcmail_get_mailbox_name_text()
{
global $RCMAIL;
return $RCMAIL->localize_foldername($RCMAIL->output->get_env('mailbox') ?: $RCMAIL->storage->get_folder());
}
function rcmail_send_unread_count($mbox_name, $force=false, $count=null, $mark='')
{
global $RCMAIL;
$old_unseen = rcmail_get_unseen_count($mbox_name);
if ($count === null)
$unseen = $RCMAIL->storage->count($mbox_name, 'UNSEEN', $force);
else
$unseen = $count;
if ($unseen != $old_unseen || ($mbox_name == 'INBOX'))
$RCMAIL->output->command('set_unread_count', $mbox_name, $unseen,
($mbox_name == 'INBOX'), $unseen && $mark ? $mark : '');
rcmail_set_unseen_count($mbox_name, $unseen);
return $unseen;
}
function rcmail_set_unseen_count($mbox_name, $count)
{
// @TODO: this data is doubled (session and cache tables) if caching is enabled
// Make sure we have an array here (#1487066)
if (!is_array($_SESSION['unseen_count'])) {
$_SESSION['unseen_count'] = array();
}
$_SESSION['unseen_count'][$mbox_name] = $count;
}
function rcmail_get_unseen_count($mbox_name)
{
if (is_array($_SESSION['unseen_count']) && array_key_exists($mbox_name, $_SESSION['unseen_count'])) {
return $_SESSION['unseen_count'][$mbox_name];
}
}
/**
* Sets message is_safe flag according to 'show_images' option value
*
* @param object rcube_message Message
*/
function rcmail_check_safe(&$message)
{
global $RCMAIL;
if (!$message->is_safe
&& ($show_images = $RCMAIL->config->get('show_images'))
&& $message->has_html_part()
) {
switch ($show_images) {
case 1: // known senders only
// get default addressbook, like in addcontact.inc
$CONTACTS = $RCMAIL->get_address_book(-1, true);
if ($CONTACTS) {
$result = $CONTACTS->search('email', $message->sender['mailto'], 1, false);
if ($result->count) {
$message->set_safe(true);
}
}
$RCMAIL->plugins->exec_hook('message_check_safe', array('message' => $message));
break;
case 2: // always
$message->set_safe(true);
break;
}
}
}
/**
* Cleans up the given message HTML Body (for displaying)
*
* @param string HTML
* @param array Display parameters
* @param array CID map replaces (inline images)
* @return string Clean HTML
*/
function rcmail_wash_html($html, $p, $cid_replaces)
{
global $REMOTE_OBJECTS;
$p += array('safe' => false, 'inline_html' => true);
// charset was converted to UTF-8 in rcube_storage::get_message_part(),
// change/add charset specification in HTML accordingly,
// washtml cannot work without that
$meta = '<meta http-equiv="Content-Type" content="text/html; charset='.RCUBE_CHARSET.'" />';
// remove old meta tag and add the new one, making sure
// that it is placed in the head (#1488093)
$html = preg_replace('/<meta[^>]+charset=[a-z0-9-_]+[^>]*>/Ui', '', $html);
$html = preg_replace('/(<head[^>]*>)/Ui', '\\1'.$meta, $html, -1, $rcount);
if (!$rcount) {
$html = '<head>' . $meta . '</head>' . $html;
}
// clean HTML with washhtml by Frederic Motte
$wash_opts = array(
'show_washed' => false,
'allow_remote' => $p['safe'],
'blocked_src' => "./program/resources/blocked.gif",
'charset' => RCUBE_CHARSET,
'cid_map' => $cid_replaces,
'html_elements' => array('body'),
);
if (!$p['inline_html']) {
$wash_opts['html_elements'] = array('html','head','title','body');
}
if ($p['safe']) {
$wash_opts['html_elements'][] = 'link';
$wash_opts['html_attribs'] = array('rel','type');
}
// overwrite washer options with options from plugins
if (isset($p['html_elements']))
$wash_opts['html_elements'] = $p['html_elements'];
if (isset($p['html_attribs']))
$wash_opts['html_attribs'] = $p['html_attribs'];
// initialize HTML washer
$washer = new rcube_washtml($wash_opts);
if (!$p['skip_washer_form_callback']) {
$washer->add_callback('form', 'rcmail_washtml_callback');
}
// allow CSS styles, will be sanitized by rcmail_washtml_callback()
if (!$p['skip_washer_style_callback']) {
$washer->add_callback('style', 'rcmail_washtml_callback');
}
// Remove non-UTF8 characters (#1487813)
$html = rcube_charset::clean($html);
$html = $washer->wash($html);
$REMOTE_OBJECTS = $washer->extlinks;
return $html;
}
/**
* Convert the given message part to proper HTML
* which can be displayed the message view
*
* @param string Message part body
* @param rcube_message_part Message part
* @param array Display parameters array
*
* @return string Formatted HTML string
*/
function rcmail_print_body($body, $part, $p = array())
{
global $RCMAIL;
// trigger plugin hook
$data = $RCMAIL->plugins->exec_hook('message_part_before',
array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id)
+ $p + array('safe' => false, 'plain' => false, 'inline_html' => true));
// convert html to text/plain
if ($data['plain'] && ($data['type'] == 'html' || $data['type'] == 'enriched')) {
if ($data['type'] == 'enriched') {
$data['body'] = rcube_enriched::to_html($data['body']);
}
$txt = new rcube_html2text($data['body'], false, true);
$body = $txt->get_text();
$part->ctype_secondary = 'plain';
}
// text/html
else if ($data['type'] == 'html') {
$body = rcmail_wash_html($data['body'], $data, $part->replaces);
$part->ctype_secondary = $data['type'];
}
// text/enriched
else if ($data['type'] == 'enriched') {
$body = rcube_enriched::to_html($data['body']);
$body = rcmail_wash_html($body, $data, $part->replaces);
$part->ctype_secondary = 'html';
}
else {
// assert plaintext
$body = $data['body'];
$part->ctype_secondary = $data['type'] = 'plain';
}
// free some memory (hopefully)
unset($data['body']);
// plaintext postprocessing
if ($part->ctype_secondary == 'plain') {
$body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed');
}
// allow post-processing of the message body
$data = $RCMAIL->plugins->exec_hook('message_part_after',
array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id) + $data);
return $data['body'];
}
/**
* Handle links and citation marks in plain text message
*
* @param string Plain text string
* @param boolean Set to True if the source text is in format=flowed
*
* @return string Formatted HTML string
*/
function rcmail_plain_body($body, $flowed = false)
{
$options = array('flowed' => $flowed, 'wrap' => !$flowed, 'replacer' => 'rcmail_string_replacer');
$text2html = new rcube_text2html($body, false, $options);
$body = $text2html->get_html();
return $body;
}
/**
* Callback function for washtml cleaning class
*/
function rcmail_washtml_callback($tagname, $attrib, $content, $washtml)
{
switch ($tagname) {
case 'form':
$out = html::div('form', $content);
break;
case 'style':
// decode all escaped entities and reduce to ascii strings
$stripped = preg_replace('/[^a-zA-Z\(:;]/', '', rcube_utils::xss_entity_decode($content));
// now check for evil strings like expression, behavior or url()
if (!preg_match('/expression|behavior|javascript:|import[^a]/i', $stripped)) {
if (!$washtml->get_config('allow_remote') && stripos($stripped, 'url('))
$washtml->extlinks = true;
else
$out = html::tag('style', array('type' => 'text/css'), $content);
break;
}
default:
$out = '';
}
return $out;
}
/**
* return table with message headers
*/
function rcmail_message_headers($attrib, $headers=null)
{
global $MESSAGE, $PRINT_MODE, $RCMAIL;
static $sa_attrib;
// keep header table attrib
if (is_array($attrib) && !$sa_attrib && !$attrib['valueof'])
$sa_attrib = $attrib;
else if (!is_array($attrib) && is_array($sa_attrib))
$attrib = $sa_attrib;
if (!isset($MESSAGE)) {
return false;
}
// get associative array of headers object
if (!$headers) {
$headers_obj = $MESSAGE->headers;
$headers = get_object_vars($MESSAGE->headers);
}
else if (is_object($headers)) {
$headers_obj = $headers;
$headers = get_object_vars($headers_obj);
}
else {
$headers_obj = rcube_message_header::from_array($headers);
}
// show these headers
$standard_headers = array('subject', 'from', 'sender', 'to', 'cc', 'bcc', 'replyto',
'mail-reply-to', 'mail-followup-to', 'date', 'priority');
$exclude_headers = $attrib['exclude'] ? explode(',', $attrib['exclude']) : array();
$output_headers = array();
foreach ($standard_headers as $hkey) {
$ishtml = false;
if ($headers[$hkey])
$value = $headers[$hkey];
else if ($headers['others'][$hkey])
$value = $headers['others'][$hkey];
else if (!$attrib['valueof'])
continue;
if (in_array($hkey, $exclude_headers))
continue;
$header_title = $RCMAIL->gettext(preg_replace('/(^mail-|-)/', '', $hkey));
if ($hkey == 'date') {
if ($PRINT_MODE)
$header_value = $RCMAIL->format_date($value, $RCMAIL->config->get('date_long', 'x'));
else
$header_value = $RCMAIL->format_date($value);
}
else if ($hkey == 'priority') {
if ($value) {
$header_value = html::span('prio' . $value, rcmail_localized_priority($value));
}
else
continue;
}
else if ($hkey == 'replyto') {
if ($headers['replyto'] != $headers['from']) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else
continue;
}
else if ($hkey == 'mail-reply-to') {
if ($headers['mail-replyto'] != $headers['reply-to']
&& $headers['reply-to'] != $headers['from']
) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else
continue;
}
else if ($hkey == 'sender') {
if ($headers['sender'] != $headers['from']) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else
continue;
}
else if ($hkey == 'mail-followup-to') {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else if (in_array($hkey, array('from', 'to', 'cc', 'bcc'))) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else if ($hkey == 'subject' && empty($value))
$header_value = $RCMAIL->gettext('nosubject');
else {
$value = is_array($value) ? implode(' ', $value) : $value;
$header_value = trim(rcube_mime::decode_header($value, $headers['charset']));
}
$output_headers[$hkey] = array(
'title' => $header_title,
'value' => $header_value,
'raw' => $value,
'html' => $ishtml,
);
}
$plugin = $RCMAIL->plugins->exec_hook('message_headers_output', array(
'output' => $output_headers,
'headers' => $headers_obj,
'exclude' => $exclude_headers, // readonly
'folder' => $MESSAGE->folder, // readonly
'uid' => $MESSAGE->uid, // readonly
));
// single header value is requested
if (!empty($attrib['valueof'])) {
return rcube::Q($plugin['output'][$attrib['valueof']]['value'], ($attrib['valueof'] == 'subject' ? 'strict' : 'show'));
}
// compose html table
$table = new html_table(array('cols' => 2));
foreach ($plugin['output'] as $hkey => $row) {
$val = $row['html'] ? $row['value'] : rcube::Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show'));
$table->add(array('class' => 'header-title'), rcube::Q($row['title']));
$table->add(array('class' => 'header '.$hkey), $val);
}
return $table->show($attrib);
}
/**
* Convert Priority header value into a localized string
*/
function rcmail_localized_priority($value)
{
global $RCMAIL;
$labels_map = array(
'1' => 'highest',
'2' => 'high',
'3' => 'normal',
'4' => 'low',
'5' => 'lowest',
);
if ($value && $labels_map[$value]) {
return $RCMAIL->gettext($labels_map[$value]);
}
return '';
}
/**
* return block to show full message headers
*/
-function rcmail_message_full_headers($attrib, $headers=NULL)
+function rcmail_message_full_headers($attrib)
{
global $OUTPUT, $RCMAIL;
$html = html::div(array('id' => "all-headers", 'class' => "all", 'style' => 'display:none'), html::div(array('id' => 'headers-source'), ''));
$html .= html::div(array(
'class' => "more-headers show-headers",
'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('show-headers','',this)",
'title' => $RCMAIL->gettext('togglefullheaders')
), '');
$OUTPUT->add_gui_object('all_headers_row', 'all-headers');
$OUTPUT->add_gui_object('all_headers_box', 'headers-source');
return html::div($attrib, $html);
}
/**
* Handler for the 'messagebody' GUI object
*
* @param array Named parameters
* @return string HTML content showing the message body
*/
function rcmail_message_body($attrib)
{
global $OUTPUT, $MESSAGE, $RCMAIL, $REMOTE_OBJECTS;
if (!is_array($MESSAGE->parts) && empty($MESSAGE->body)) {
return '';
}
if (!$attrib['id'])
$attrib['id'] = 'rcmailMsgBody';
$safe_mode = $MESSAGE->is_safe || intval($_GET['_safe']);
$out = '';
$header_attrib = array();
foreach ($attrib as $attr => $value) {
if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs)) {
$header_attrib[$regs[1]] = $value;
}
}
if (!empty($MESSAGE->parts)) {
foreach ($MESSAGE->parts as $part) {
if ($part->type == 'headers') {
$out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers));
}
else if ($part->type == 'content') {
// unsupported (e.g. encrypted)
if ($part->realtype) {
if ($part->realtype == 'multipart/encrypted' || $part->realtype == 'application/pkcs7-mime') {
$out .= html::span('part-notice', $RCMAIL->gettext('encryptedmessage'));
}
continue;
}
else if (!$part->size) {
continue;
}
// Check if we have enough memory to handle the message in it
// #1487424: we need up to 10x more memory than the body
else if (!rcube_utils::mem_check($part->size * 10)) {
$out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' '
. html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id
.'&_mbox='. urlencode($MESSAGE->folder), $RCMAIL->gettext('download')));
continue;
}
// fetch part body
$body = $MESSAGE->get_part_body($part->mime_id, true);
// extract headers from message/rfc822 parts
if ($part->mimetype == 'message/rfc822') {
$msgpart = rcube_mime::parse_message($body);
if (!empty($msgpart->headers)) {
$part = $msgpart;
$out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers));
}
}
// message is cached but not exists (#1485443), or other error
if ($body === false) {
rcmail_message_error($MESSAGE->uid);
}
$plugin = $RCMAIL->plugins->exec_hook('message_body_prefix',
array('part' => $part, 'prefix' => ''));
$body = rcmail_print_body($body, $part, array('safe' => $safe_mode, 'plain' => !$RCMAIL->config->get('prefer_html')));
if ($part->ctype_secondary == 'html') {
$body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs, $safe_mode);
$div_attr = array('class' => 'message-htmlpart');
$style = array();
if (!empty($attrs)) {
foreach ($attrs as $a_idx => $a_val)
$style[] = $a_idx . ': ' . $a_val;
if (!empty($style))
$div_attr['style'] = implode('; ', $style);
}
$out .= html::div($div_attr, $plugin['prefix'] . $body);
}
else
$out .= html::div('message-part', $plugin['prefix'] . $body);
}
}
}
else {
// Check if we have enough memory to handle the message in it
// #1487424: we need up to 10x more memory than the body
if (!rcube_utils::mem_check(strlen($MESSAGE->body) * 10)) {
$out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' '
. html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part=0'
.'&_mbox='. urlencode($MESSAGE->folder), $RCMAIL->gettext('download')));
}
else {
$plugin = $RCMAIL->plugins->exec_hook('message_body_prefix',
array('part' => $MESSAGE, 'prefix' => ''));
$out .= html::div('message-part',
$plugin['prefix'] . rcmail_plain_body($MESSAGE->body));
}
}
// list images after mail body
if ($RCMAIL->config->get('inline_images', true) && !empty($MESSAGE->attachments)) {
$thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240);
$client_mimetypes = (array)$RCMAIL->config->get('client_mimetypes');
foreach ($MESSAGE->attachments as $attach_prop) {
// skip inline images
if ($attach_prop->content_id && $attach_prop->disposition == 'inline') {
continue;
}
// Content-Type: image/*...
if ($mimetype = rcmail_part_image_type($attach_prop)) {
// display thumbnails
if ($thumbnail_size) {
$show_link = array(
'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false),
'onclick' => sprintf(
'return %s.command(\'load-attachment\',\'%s\',this)',
rcmail_output::JS_OBJECT_NAME,
$attach_prop->mime_id)
);
$out .= html::p('image-attachment',
html::a($show_link + array('class' => 'image-link', 'style' => sprintf('width:%dpx', $thumbnail_size)),
html::img(array(
'class' => 'image-thumbnail',
'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image') . '&_thumb=1',
'title' => $attach_prop->filename,
'alt' => $attach_prop->filename,
'style' => sprintf('max-width:%dpx; max-height:%dpx', $thumbnail_size, $thumbnail_size),
))
) .
html::span('image-filename', rcube::Q($attach_prop->filename)) .
html::span('image-filesize', rcube::Q($RCMAIL->message_part_size($attach_prop))) .
html::span('attachment-links',
(in_array($mimetype, $client_mimetypes) ? html::a($show_link, $RCMAIL->gettext('showattachment')) . '&nbsp;' : '') .
html::a($show_link['href'] . '&_download=1', $RCMAIL->gettext('download'))
) .
html::br(array('style' => 'clear:both'))
);
}
else {
$out .= html::tag('fieldset', 'image-attachment',
html::tag('legend', 'image-filename', rcube::Q($attach_prop->filename)) .
html::p(array('align' => 'center'),
html::img(array(
'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image'),
'title' => $attach_prop->filename,
'alt' => $attach_prop->filename,
)))
);
}
}
}
}
// tell client that there are blocked remote objects
if ($REMOTE_OBJECTS && !$safe_mode) {
$OUTPUT->set_env('blockedobjects', true);
}
return html::div($attrib, $out);
}
function rcmail_part_image_type($part)
{
// Skip TIFF images if browser doesn't support this format...
$tiff_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps']['tif']);
// until we can convert them to JPEG
$tiff_support = $tiff_support || rcube_image::is_convertable('image/tiff');
// Content-type regexp
$mime_regex = $tiff_support ? '/^image\//i' : '/^image\/(?!tif)/i';
// Content-Type: image/*...
if (preg_match($mime_regex, $part->mimetype)) {
return rcmail_fix_mimetype($part->mimetype);
}
// Many clients use application/octet-stream, we'll detect mimetype
// by checking filename extension
// Supported image filename extensions to image type map
$types = array(
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
);
if ($tiff_support) {
$types['tif'] = 'image/tiff';
$types['tiff'] = 'image/tiff';
}
if ($part->filename
&& preg_match('/^application\/octet-stream$/i', $part->mimetype)
&& preg_match('/\.([^.]+)$/i', $part->filename, $m)
&& ($extension = strtolower($m[1]))
&& isset($types[$extension])
) {
return $types[$extension];
}
}
/**
* modify a HTML message that it can be displayed inside a HTML page
*/
function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null, $allow_remote=false)
{
$last_style_pos = 0;
$cont_id = $container_id.($body_id ? ' div.'.$body_id : '');
// find STYLE tags
while (($pos = stripos($body, '<style', $last_style_pos)) && ($pos2 = stripos($body, '</style>', $pos))) {
$pos = strpos($body, '>', $pos) + 1;
$len = $pos2 - $pos;
// replace all css definitions with #container [def]
$styles = substr($body, $pos, $len);
$styles = rcube_utils::mod_css_styles($styles, $cont_id, $allow_remote);
$body = substr_replace($body, $styles, $pos, $len);
$last_style_pos = $pos2 + strlen($styles) - $len;
}
// modify HTML links to open a new window if clicked
$GLOBALS['rcmail_html_container_id'] = $container_id;
$body = preg_replace_callback('/<(a|link|area)\s+([^>]+)>/Ui', 'rcmail_alter_html_link', $body);
unset($GLOBALS['rcmail_html_container_id']);
$body = preg_replace(array(
// add comments arround html and other tags
'/(<!DOCTYPE[^>]*>)/i',
'/(<\?xml[^>]*>)/i',
'/(<\/?html[^>]*>)/i',
'/(<\/?head[^>]*>)/i',
'/(<title[^>]*>.*<\/title>)/Ui',
'/(<\/?meta[^>]*>)/i',
// quote <? of php and xml files that are specified as text/html
'/<\?/',
'/\?>/',
// replace <body> with <div>
'/<body([^>]*)>/i',
'/<\/body>/i',
),
array(
'<!--\\1-->',
'<!--\\1-->',
'<!--\\1-->',
'<!--\\1-->',
'<!--\\1-->',
'<!--\\1-->',
'&lt;?',
'?&gt;',
'<div class="'.$body_id.'"\\1>',
'</div>',
),
$body);
$attributes = array();
// Handle body attributes that doesn't play nicely with div elements
$regexp = '/<div class="' . preg_quote($body_id, '/') . '"([^>]*)/';
if (preg_match($regexp, $body, $m)) {
$attrs = $m[0];
// Get bgcolor, we'll set it as background-color of the message container
if ($m[1] && preg_match('/bgcolor=["\']*([a-z0-9#]+)["\']*/i', $attrs, $mb)) {
$attributes['background-color'] = $mb[1];
$attrs = preg_replace('/bgcolor=["\']*[a-z0-9#]+["\']*/i', '', $attrs);
}
// Get background, we'll set it as background-image of the message container
if ($m[1] && preg_match('/background=["\']*([^"\'>\s]+)["\']*/', $attrs, $mb)) {
$attributes['background-image'] = 'url('.$mb[1].')';
$attrs = preg_replace('/background=["\']*([^"\'>\s]+)["\']*/', '', $attrs);
}
if (!empty($attributes)) {
$body = preg_replace($regexp, rtrim($attrs), $body, 1);
}
// handle body styles related to background image
if ($attributes['background-image']) {
// get body style
if (preg_match('/#'.preg_quote($cont_id, '/').'\s+\{([^}]+)}/i', $body, $m)) {
// get background related style
$regexp = '/(background-position|background-repeat)\s*:\s*([^;]+);/i';
if (preg_match_all($regexp, $m[1], $ma, PREG_SET_ORDER)) {
foreach ($ma as $style) {
$attributes[$style[1]] = $style[2];
}
}
}
}
}
// make sure there's 'rcmBody' div, we need it for proper css modification
// its name is hardcoded in rcmail_message_body() also
else {
$body = '<div class="' . $body_id . '">' . $body . '</div>';
}
return $body;
}
/**
* parse link (a, link, area) attributes and set correct target
*/
function rcmail_alter_html_link($matches)
{
global $RCMAIL;
$tag = strtolower($matches[1]);
$attrib = html::parse_attrib_string($matches[2]);
$end = '>';
// Remove non-printable characters in URL (#1487805)
if ($attrib['href'])
$attrib['href'] = preg_replace('/[\x00-\x1F]/', '', $attrib['href']);
if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href'])) {
$tempurl = 'tmp-' . md5($attrib['href']) . '.css';
$_SESSION['modcssurls'][$tempurl] = $attrib['href'];
$attrib['href'] = $RCMAIL->url(array('task' => 'utils', 'action' => 'modcss', 'u' => $tempurl, 'c' => $GLOBALS['rcmail_html_container_id']));
$end = ' />';
}
else if (preg_match('/^mailto:(.+)/i', $attrib['href'], $mailto)) {
list($mailto, $url) = explode('?', html_entity_decode($mailto[1], ENT_QUOTES, 'UTF-8'), 2);
$url = urldecode($url);
$mailto = urldecode($mailto);
$addresses = rcube_mime::decode_address_list($mailto, null, true);
$mailto = array();
// do sanity checks on recipients
foreach ($addresses as $idx => $addr) {
if (rcube_utils::check_email($addr['mailto'], false)) {
$addresses[$idx] = $addr['mailto'];
$mailto[] = $addr['string'];
}
else {
unset($addresses[$idx]);
}
}
if (!empty($addresses)) {
$attrib['href'] = 'mailto:' . implode(',', $addresses);
$attrib['onclick'] = sprintf(
"return %s.command('compose','%s',this)",
rcmail_output::JS_OBJECT_NAME,
rcube::JQ(implode(',', $mailto) . ($url ? "?$url" : '')));
}
else {
$attrib['href'] = '#NOP';
$attrib['onclick'] = '';
}
}
else if (empty($attrib['href']) && !$attrib['name']) {
$attrib['href'] = './#NOP';
$attrib['onclick'] = 'return false';
}
else if (!empty($attrib['href']) && $attrib['href'][0] != '#') {
$attrib['target'] = '_blank';
}
// Better security by adding rel="noreferrer" (#1484686)
if (($tag == 'a' || $tag == 'area') && $attrib['href'] && $attrib['href'][0] != '#') {
$attrib['rel'] = 'noreferrer';
}
// allowed attributes for a|link|area tags
$allow = array('href','name','target','onclick','id','class','style','title',
'rel','type','media','alt','coords','nohref','hreflang','shape');
return "<$tag" . html::attrib_string($attrib, $allow) . $end;
}
/**
* decode address string and re-format it as HTML links
*/
function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $default_charset=null, $title=null)
{
global $RCMAIL, $PRINT_MODE;
$a_parts = rcube_mime::decode_address_list($input, null, true, $default_charset);
if (!sizeof($a_parts)) {
return $input;
}
$c = count($a_parts);
$j = 0;
$out = '';
$allvalues = array();
$show_email = $RCMAIL->config->get('message_show_email');
if ($addicon && !isset($_SESSION['writeable_abook'])) {
$_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false;
}
foreach ($a_parts as $part) {
$j++;
$name = $part['name'];
$mailto = $part['mailto'];
$string = $part['string'];
$valid = rcube_utils::check_email($mailto, false);
// phishing email prevention (#1488981), e.g. "valid@email.addr <phishing@email.addr>"
if (!$show_email && $valid && $name && $name != $mailto && strpos($name, '@')) {
$name = '';
}
// IDNA ASCII to Unicode
if ($name == $mailto)
$name = rcube_utils::idn_to_utf8($name);
if ($string == $mailto)
$string = rcube_utils::idn_to_utf8($string);
$mailto = rcube_utils::idn_to_utf8($mailto);
if ($PRINT_MODE) {
$address = sprintf('%s &lt;%s&gt;', rcube::Q($name), rcube::Q($mailto));
}
else if ($valid) {
if ($linked) {
$attrs = array(
'href' => 'mailto:' . $mailto,
'class' => 'rcmContactAddress',
'onclick' => sprintf("return %s.command('compose','%s',this)",
rcmail_output::JS_OBJECT_NAME, rcube::JQ(format_email_recipient($mailto, $name))),
);
if ($show_email && $name && $mailto) {
$content = rcube::Q($name ? sprintf('%s <%s>', $name, $mailto) : $mailto);
}
else {
$content = rcube::Q($name ? $name : $mailto);
$attrs['title'] = $mailto;
}
$address = html::a($attrs, $content);
}
else {
$address = html::span(array('title' => $mailto, 'class' => "rcmContactAddress"),
rcube::Q($name ? $name : $mailto));
}
if ($addicon && $_SESSION['writeable_abook']) {
$address .= html::a(array(
'href' => "#add",
'title' => $RCMAIL->gettext('addtoaddressbook'),
'class' => 'rcmaddcontact',
'onclick' => sprintf("return %s.command('add-contact','%s',this)",
rcmail_output::JS_OBJECT_NAME, rcube::JQ($string)),
),
html::img(array(
'src' => $RCMAIL->config->get('skin_path') . $addicon,
'alt' => "Add contact",
)));
}
}
else {
$address = '';
if ($name)
$address .= rcube::Q($name);
if ($mailto)
$address = trim($address . ' ' . rcube::Q($name ? sprintf('<%s>', $mailto) : $mailto));
}
$address = html::span('adr', $address);
$allvalues[] = $address;
if (!$moreadrs)
$out .= ($out ? ', ' : '') . $address;
if ($max && $j == $max && $c > $j) {
if ($linked) {
$moreadrs = $c - $j;
}
else {
$out .= '...';
break;
}
}
}
if ($moreadrs) {
if ($PRINT_MODE) {
$out .= ' ' . html::a(array(
'href' => '#more',
'class' => 'morelink',
'onclick' => '$(this).hide().next().show()',
),
rcube::Q($RCMAIL->gettext(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs)))))
. html::span(array('style' => 'display:none'), join(', ', $allvalues));
}
else {
$out .= ' ' . html::a(array(
'href' => '#more',
'class' => 'morelink',
'onclick' => sprintf("return %s.show_popup_dialog('%s','%s')",
rcmail_output::JS_OBJECT_NAME,
rcube::JQ(join(', ', $allvalues)),
rcube::JQ($title))
),
rcube::Q($RCMAIL->gettext(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs)))));
}
}
return $out;
}
/**
* Wrap text to a given number of characters per line
* but respect the mail quotation of replies messages (>).
* Finally add another quotation level by prepending the lines
* with >
*
* @param string Text to wrap
* @param int The line width
* @return string The wrapped text
*/
function rcmail_wrap_and_quote($text, $length = 72)
{
// Rebuild the message body with a maximum of $max chars, while keeping quoted message.
$max = max(75, $length + 8);
$lines = preg_split('/\r?\n/', trim($text));
$out = '';
foreach ($lines as $line) {
// don't wrap already quoted lines
if ($line[0] == '>') {
$line = '>' . rtrim($line);
}
else if (mb_strlen($line) > $max) {
$newline = '';
foreach (explode("\n", rcube_mime::wordwrap($line, $length - 2)) as $l) {
if (strlen($l))
$newline .= '> ' . $l . "\n";
else
$newline .= ">\n";
}
$line = rtrim($newline);
}
else {
$line = '> ' . $line;
}
// Append the line
$out .= $line . "\n";
}
return rtrim($out, "\n");
}
function rcmail_draftinfo_encode($p)
{
$parts = array();
foreach ($p as $key => $val) {
$encode = $key == 'folder' || strpos($val, ';') !== false;
$parts[] = $key . '=' . ($encode ? 'B::' . base64_encode($val) : $val);
}
return join('; ', $parts);
}
function rcmail_draftinfo_decode($str)
{
$info = array();
foreach (preg_split('/;\s+/', $str) as $part) {
list($key, $val) = explode('=', $part, 2);
if (strpos($val, 'B::') === 0) {
$val = base64_decode(substr($val, 3));
}
else if ($key == 'folder') {
$val = base64_decode($val);
}
$info[$key] = $val;
}
return $info;
}
/**
* clear message composing settings
*/
function rcmail_compose_cleanup($id)
{
if (!isset($_SESSION['compose_data_'.$id])) {
return;
}
$rcmail = rcmail::get_instance();
$rcmail->plugins->exec_hook('attachments_cleanup', array('group' => $id));
$rcmail->session->remove('compose_data_'.$id);
}
/**
* Send the MDN response
*
* @param mixed $message Original message object (rcube_message) or UID
* @param array $smtp_error SMTP error array (reference)
*
* @return boolean Send status
*/
function rcmail_send_mdn($message, &$smtp_error)
{
global $RCMAIL;
if (!is_object($message) || !is_a($message, 'rcube_message')) {
$message = new rcube_message($message);
}
if ($message->headers->mdn_to && empty($message->headers->flags['MDNSENT']) &&
($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*'))
) {
$identity = rcmail_identity_select($message);
$sender = format_email_recipient($identity['email'], $identity['name']);
$recipient = array_shift(rcube_mime::decode_address_list(
$message->headers->mdn_to, 1, true, $message->headers->charset));
$mailto = $recipient['mailto'];
$compose = new Mail_mime("\r\n");
$compose->setParam('text_encoding', 'quoted-printable');
$compose->setParam('html_encoding', 'quoted-printable');
$compose->setParam('head_encoding', 'quoted-printable');
$compose->setParam('head_charset', RCUBE_CHARSET);
$compose->setParam('html_charset', RCUBE_CHARSET);
$compose->setParam('text_charset', RCUBE_CHARSET);
// compose headers array
$headers = array(
'Date' => $RCMAIL->user_date(),
'From' => $sender,
'To' => $message->headers->mdn_to,
'Subject' => $RCMAIL->gettext('receiptread') . ': ' . $message->subject,
'Message-ID' => $RCMAIL->gen_message_id(),
'X-Sender' => $identity['email'],
'References' => trim($message->headers->references . ' ' . $message->headers->messageID),
);
$report = "Final-Recipient: rfc822; {$identity['email']}\r\n"
. "Original-Message-ID: {$message->headers->messageID}\r\n"
. "Disposition: manual-action/MDN-sent-manually; displayed\r\n";
if ($message->headers->to) {
$report .= "Original-Recipient: {$message->headers->to}\r\n";
}
if ($agent = $RCMAIL->config->get('useragent')) {
$headers['User-Agent'] = $agent;
$report .= "Reporting-UA: $agent\r\n";
}
$body = $RCMAIL->gettext("yourmessage") . "\r\n\r\n" .
"\t" . $RCMAIL->gettext("to") . ': ' . rcube_mime::decode_mime_string($message->headers->to, $message->headers->charset) . "\r\n" .
"\t" . $RCMAIL->gettext("subject") . ': ' . $message->subject . "\r\n" .
"\t" . $RCMAIL->gettext("date") . ': ' . $RCMAIL->format_date($message->headers->date, $RCMAIL->config->get('date_long')) . "\r\n" .
"\r\n" . $RCMAIL->gettext("receiptnote");
$compose->headers($headers);
$compose->setContentType('multipart/report', array('report-type'=> 'disposition-notification'));
$compose->setTXTBody(rcube_mime::wordwrap($body, 75, "\r\n"));
$compose->addAttachment($report, 'message/disposition-notification', 'MDNPart2.txt', false, '7bit', 'inline');
if ($RCMAIL->config->get('mdn_use_from')) {
$options['mdn_use_from'] = true;
}
$sent = $RCMAIL->deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file, $options);
if ($sent) {
$RCMAIL->storage->set_flag($message->uid, 'MDNSENT');
return true;
}
}
return false;
}
/**
* Detect recipient identity from specified message
*/
function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'reply')
{
$a_recipients = array();
$a_names = array();
if ($identities === null) {
$identities = rcmail::get_instance()->user->list_identities(null, true);
}
// extract all recipients of the reply-message
if (is_object($MESSAGE->headers) && in_array($compose_mode, array('reply', 'forward'))) {
$a_to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, true, $MESSAGE->headers->charset);
foreach ($a_to as $addr) {
if (!empty($addr['mailto'])) {
$a_recipients[] = strtolower($addr['mailto']);
$a_names[] = $addr['name'];
}
}
if (!empty($MESSAGE->headers->cc)) {
$a_cc = rcube_mime::decode_address_list($MESSAGE->headers->cc, null, true, $MESSAGE->headers->charset);
foreach ($a_cc as $addr) {
if (!empty($addr['mailto'])) {
$a_recipients[] = strtolower($addr['mailto']);
$a_names[] = $addr['name'];
}
}
}
}
// 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 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;
}
}
// use replied/forwarded message recipients
else if (($found = array_search(strtolower($ident['email_ascii']), $a_recipients)) !== false) {
// 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']) {
$from_idx = $idx;
break;
}
}
}
// 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'] !== 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 = strtolower($ident['email_ascii']);
$ident2 = str_replace('@', '=', $ident1);
$ident1 = '<' . $ident1 . '>';
$ident2 = '-' . $ident2 . '@';
foreach ($return_path as $path) {
if ($path == $ident1 || stripos($path, $ident2)) {
$from_idx = $idx;
break 2;
}
}
}
}
// See identity_select plugin for example usage of this hook
$plugin = rcmail::get_instance()->plugins->exec_hook('identity_select',
array('message' => $MESSAGE, 'identities' => $identities, 'selected' => $from_idx));
$selected = $plugin['selected'];
// default identity is always first on the list
return $identities[$selected !== null ? $selected : 0];
}
// Fixes some content-type names
function rcmail_fix_mimetype($name)
{
// Some versions of Outlook create garbage Content-Type:
// application/pdf.A520491B_3BF7_494D_8855_7FAC2C6C0608
if (preg_match('/^application\/pdf.+/', $name)) {
$name = 'application/pdf';
}
// treat image/pjpeg (image/pjpg, image/jpg) as image/jpeg (#1489097)
else if (preg_match('/^image\/p?jpe?g$/', $name)) {
$name = 'image/jpeg';
}
return $name;
}
// return attachment filename, handle empty filename case
function rcmail_attachment_name($attachment, $display = false)
{
global $RCMAIL;
$filename = $attachment->filename;
if ($filename === null || $filename === '') {
if ($attachment->mimetype == 'text/html') {
$filename = $RCMAIL->gettext('htmlmessage');
}
else {
$ext = (array) rcube_mime::get_mime_extensions($attachment->mimetype);
$ext = array_shift($ext);
$filename = $RCMAIL->gettext('messagepart') . ' ' . $attachment->mime_id;
if ($ext) {
$filename .= '.' . $ext;
}
}
}
$filename = preg_replace('[\r\n]', '', $filename);
// Display smart names for some known mimetypes
if ($display) {
if (preg_match('/application\/(pgp|pkcs7)-signature/i', $attachment->mimetype)) {
$filename = $RCMAIL->gettext('digitalsig');
}
}
return $filename;
}
function rcmail_search_filter($attrib)
{
global $RCMAIL;
if (!strlen($attrib['id']))
$attrib['id'] = 'rcmlistfilter';
$attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.'.filter_mailbox(this.value)';
// Content-Type values of messages with attachments
// the same as in app.js:add_message_row()
$ctypes = array('application/', 'multipart/m', 'multipart/signed', 'multipart/report');
// Build search string of "with attachment" filter
$attachment = trim(str_repeat(' OR', count($ctypes)-1));
foreach ($ctypes as $type) {
$attachment .= ' HEADER Content-Type ' . rcube_imap_generic::escape($type);
}
$select_filter = new html_select($attrib);
$select_filter->add($RCMAIL->gettext('all'), 'ALL');
$select_filter->add($RCMAIL->gettext('unread'), 'UNSEEN');
$select_filter->add($RCMAIL->gettext('flagged'), 'FLAGGED');
$select_filter->add($RCMAIL->gettext('unanswered'), 'UNANSWERED');
if (!$RCMAIL->config->get('skip_deleted')) {
$select_filter->add($RCMAIL->gettext('deleted'), 'DELETED');
$select_filter->add($RCMAIL->gettext('undeleted'), 'UNDELETED');
}
$select_filter->add($RCMAIL->gettext('withattachment'), $attachment);
$select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('highest'), 'HEADER X-PRIORITY 1');
$select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('high'), 'HEADER X-PRIORITY 2');
$select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('normal'), 'NOT HEADER X-PRIORITY 1 NOT HEADER X-PRIORITY 2 NOT HEADER X-PRIORITY 4 NOT HEADER X-PRIORITY 5');
$select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('low'), 'HEADER X-PRIORITY 4');
$select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('lowest'), 'HEADER X-PRIORITY 5');
$out = $select_filter->show($_SESSION['search_filter']);
$RCMAIL->output->add_gui_object('search_filter', $attrib['id']);
return $out;
}
-function rcmail_message_error($uid=null)
+function rcmail_message_error()
{
global $RCMAIL;
// Set env variables for messageerror.html template
if ($RCMAIL->action == 'show') {
$mbox_name = $RCMAIL->storage->get_folder();
$RCMAIL->output->set_env('mailbox', $mbox_name);
$RCMAIL->output->set_env('uid', null);
}
// display error message
$RCMAIL->output->show_message('messageopenerror', 'error');
// ... display message error page
$RCMAIL->output->send('messageerror');
}
function rcmail_message_import_form($attrib = array())
{
global $RCMAIL;
// set defaults
$attrib += array('id' => 'rcmImportform', 'buttons' => 'yes');
// Get filesize, enable upload progress bar
$max_filesize = $RCMAIL->upload_init();
$button = new html_inputfield(array('type' => 'button'));
$fileinput = new html_inputfield(array(
'type' => 'file',
'name' => '_file[]',
'multiple' => 'multiple',
'accept' => ".eml, .mbox, message/rfc822, text/*",
));
$content = html::tag('input', array('type' => 'hidden', 'name' => '_unlock', 'value' => ''))
. html::tag('input', array('type' => 'hidden', 'name' => '_framed', 'value' => '1'))
. html::div(null, $fileinput->show())
. html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))));
if (rcube_utils::get_boolean($attrib['buttons'])) {
$content .= html::div('buttons',
$button->show($RCMAIL->gettext('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()"))
. ' ' .
$button->show($RCMAIL->gettext('upload'), array(
'class' => 'button mainaction',
'onclick' => rcmail_output::JS_OBJECT_NAME . ".command('import-messages', this.form)"
)));
}
$out = $RCMAIL->output->form_tag(array(
'id' => $attrib['id'].'Frm',
'method' => 'post',
'enctype' => 'multipart/form-data'
),
$content);
$RCMAIL->output->add_gui_object('importform', $attrib['id'].'Frm');
$RCMAIL->output->add_label('selectimportfile','importwait');
return html::div($attrib, $out);
}
/**
* Add groups from the given address source to the address book widget
*/
function rcmail_compose_contact_groups($abook, $source_id, $search = null, $search_mode = 0)
{
global $RCMAIL, $OUTPUT;
$jsresult = array();
foreach ($abook->list_groups($search, $search_mode) as $group) {
$abook->reset();
$abook->set_group($group['ID']);
// group (distribution list) with email address(es)
if ($group['email']) {
foreach ((array)$group['email'] as $email) {
$row_id = 'G'.$group['ID'];
$jsresult[$row_id] = format_email_recipient($email, $group['name']);
$OUTPUT->command('add_contact_row', $row_id, array(
'contactgroup' => html::span(array('title' => $email), rcube::Q($group['name']))), 'group');
}
}
// make virtual groups clickable to list their members
else if ($group['virtual']) {
$row_id = 'G'.$group['ID'];
$OUTPUT->command('add_contact_row', $row_id, array(
'contactgroup' => html::a(array(
'href' => '#list',
'rel' => $group['ID'],
'title' => $RCMAIL->gettext('listgroup'),
'onclick' => sprintf("return %s.command('pushgroup',{'source':'%s','id':'%s'},this,event)",
rcmail_output::JS_OBJECT_NAME, $source_id, $group['ID']),
), rcube::Q($group['name']) . '&nbsp;' . html::span('action', '&raquo;'))),
'group',
array('ID' => $group['ID'], 'name' => $group['name'], 'virtual' => true));
}
// show group with count
else if (($result = $abook->count()) && $result->count) {
$row_id = 'E'.$group['ID'];
$jsresult[$row_id] = $group['name'];
$OUTPUT->command('add_contact_row', $row_id, array(
'contactgroup' => rcube::Q($group['name'] . ' (' . intval($result->count) . ')')), 'group');
}
}
$abook->reset();
$abook->set_group(0);
return $jsresult;
}
diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc
index 202578676..f34e3c550 100644
--- a/program/steps/settings/edit_folder.inc
+++ b/program/steps/settings/edit_folder.inc
@@ -1,319 +1,321 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/settings/edit_folder.inc |
| |
| This file is part of the Roundcube Webmail client |
| 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. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality to create/edit a folder |
| |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
// register UI objects
$OUTPUT->add_handlers(array(
'folderdetails' => 'rcmail_folder_form',
));
$OUTPUT->add_label('nonamewarning');
$OUTPUT->send('folderedit');
// WARNING: folder names in UI are encoded with RCUBE_CHARSET
function rcmail_folder_form($attrib)
{
global $RCMAIL;
$storage = $RCMAIL->get_storage();
// edited folder name (empty in create-folder mode)
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true);
// predefined path for new folder
$parent = rcube_utils::get_input_value('_path', rcube_utils::INPUT_GPC, true);
$threading_supported = $storage->get_capability('THREAD');
$delimiter = $storage->get_hierarchy_delimiter();
// Get mailbox parameters
if (strlen($mbox)) {
$options = rcmail_folder_options($mbox);
$namespace = $storage->get_namespace();
$path = explode($delimiter, $mbox);
$folder = array_pop($path);
$path = implode($delimiter, $path);
$folder = rcube_charset::convert($folder, 'UTF7-IMAP');
$hidden_fields = array('name' => '_mbox', 'value' => $mbox);
}
else {
$options = array();
$path = $parent;
// allow creating subfolders of INBOX folder
if ($path == 'INBOX') {
$path = $storage->mod_folder($path, 'in');
}
}
// remove personal namespace prefix
if (strlen($path)) {
$path_id = $path;
$path = $storage->mod_folder($path.$delimiter);
if ($path[strlen($path)-1] == $delimiter) {
$path = substr($path, 0, -1);
}
}
$form = array();
// General tab
$form['props'] = array(
'name' => $RCMAIL->gettext('properties'),
);
// Location (name)
if ($options['protected']) {
$foldername = str_replace($delimiter, ' &raquo; ', rcube::Q($RCMAIL->localize_folderpath($mbox)));
}
else if ($options['norename']) {
$foldername = rcube::Q($folder);
}
else {
if (isset($_POST['_name']))
$folder = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true));
$foldername = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30));
$foldername = $foldername->show($folder);
if ($options['special']) {
$foldername .= '&nbsp;(' . rcube::Q($RCMAIL->localize_foldername($mbox)) .')';
}
}
$form['props']['fieldsets']['location'] = array(
'name' => $RCMAIL->gettext('location'),
'content' => array(
'name' => array(
'label' => $RCMAIL->gettext('foldername'),
'value' => $foldername,
),
),
);
if (!empty($options) && ($options['norename'] || $options['protected'])) {
// prevent user from moving folder
$hidden_path = new html_hiddenfield(array('name' => '_parent', 'value' => $path));
$form['props']['fieldsets']['location']['content']['name']['value'] .= $hidden_path->show();
}
else {
$selected = isset($_POST['_parent']) ? $_POST['_parent'] : $path_id;
$exceptions = array($mbox);
// Exclude 'prefix' namespace from parent folders list (#1488349)
// If INBOX. namespace exists, folders created as INBOX subfolders
// will be listed at the same level - selecting INBOX as a parent does nothing
if ($prefix = $storage->get_namespace('prefix')) {
$exceptions[] = substr($prefix, 0, -1);
}
$select = $RCMAIL->folder_selector(array(
'id' => '_parent',
'name' => '_parent',
'noselection' => '---',
'maxlength' => 150,
'unsubscribed' => true,
'skip_noinferiors' => true,
'exceptions' => $exceptions,
'additional' => strlen($selected) ? array($selected) : null,
));
$form['props']['fieldsets']['location']['content']['path'] = array(
'label' => $RCMAIL->gettext('parentfolder'),
'value' => $select->show($selected),
);
}
// Settings
$form['props']['fieldsets']['settings'] = array(
'name' => $RCMAIL->gettext('settings'),
);
// Settings: threading
if ($threading_supported && ($mbox == 'INBOX' || (!$options['noselect'] && !$options['is_root']))) {
$select = new html_select(array('name' => '_viewmode', 'id' => '_viewmode'));
$select->add($RCMAIL->gettext('list'), 0);
$select->add($RCMAIL->gettext('threads'), 1);
if (isset($_POST['_viewmode'])) {
$value = (int) $_POST['_viewmode'];
}
else if (strlen($mbox)) {
$a_threaded = $RCMAIL->config->get('message_threading', array());
$default_mode = $RCMAIL->config->get('default_list_mode', 'list');
$value = (int) (isset($a_threaded[$mbox]) ? $a_threaded[$mbox] : $default_mode == 'threads');
}
$form['props']['fieldsets']['settings']['content']['viewmode'] = array(
'label' => $RCMAIL->gettext('listmode'),
'value' => $select->show($value),
);
}
/*
// Settings: sorting column
$select = new html_select(array('name' => '_sortcol', 'id' => '_sortcol'));
$select->add($RCMAIL->gettext('nonesort'), '');
$select->add($RCMAIL->gettext('arrival'), 'arrival');
$select->add($RCMAIL->gettext('sentdate'), 'date');
$select->add($RCMAIL->gettext('subject'), 'subject');
$select->add($RCMAIL->gettext('fromto'), 'from');
$select->add($RCMAIL->gettext('replyto'), 'replyto');
$select->add($RCMAIL->gettext('cc'), 'cc');
$select->add($RCMAIL->gettext('size'), 'size');
$value = isset($_POST['_sortcol']) ? $_POST['_sortcol'] : '';
$form['props']['fieldsets']['settings']['content']['sortcol'] = array(
'label' => $RCMAIL->gettext('listsorting'),
'value' => $select->show($value),
);
// Settings: sorting order
$select = new html_select(array('name' => '_sortord', 'id' => '_sortord'));
$select->add($RCMAIL->gettext('asc'), 'ASC');
$select->add($RCMAIL->gettext('desc'), 'DESC');
$value = isset($_POST['_sortord']) ? $_POST['_sortord'] : '';
$form['props']['fieldsets']['settings']['content']['sortord'] = array(
'label' => $RCMAIL->gettext('listorder'),
'value' => $select->show(),
);
*/
// Information (count, size) - Edit mode
if (strlen($mbox)) {
// Number of messages
$form['props']['fieldsets']['info'] = array(
'name' => $RCMAIL->gettext('info'),
'content' => array()
);
if ((!$options['noselect'] && !$options['is_root']) || $mbox == 'INBOX') {
$msgcount = $storage->count($mbox, 'ALL', true, false);
// Size
if ($msgcount) {
// create link with folder-size command
$onclick = sprintf("return %s.command('folder-size', '%s', this)",
rcmail_output::JS_OBJECT_NAME, rcube::JQ($mbox));
$size = html::a(array('href' => '#', 'onclick' => $onclick,
'id' => 'folder-size'), $RCMAIL->gettext('getfoldersize'));
}
else {
// no messages -> zero size
$size = 0;
}
$form['props']['fieldsets']['info']['content']['count'] = array(
'label' => $RCMAIL->gettext('messagecount'),
'value' => (int) $msgcount
);
$form['props']['fieldsets']['info']['content']['size'] = array(
'label' => $RCMAIL->gettext('size'),
'value' => $size,
);
}
// show folder type only if we have non-private namespaces
if (!empty($namespace['shared']) || !empty($namespace['others'])) {
$form['props']['fieldsets']['info']['content']['foldertype'] = array(
'label' => $RCMAIL->gettext('foldertype'),
'value' => $RCMAIL->gettext($options['namespace'] . 'folder'));
}
}
// Allow plugins to modify folder form content
$plugin = $RCMAIL->plugins->exec_hook('folder_form',
array('form' => $form, 'options' => $options,
'name' => $mbox, 'parent_name' => $parent));
$form = $plugin['form'];
// Set form tags and hidden fields
list($form_start, $form_end) = get_form_tags($attrib, 'save-folder', null, $hidden_fields);
unset($attrib['form'], $attrib['id']);
// return the complete edit form as table
$out = "$form_start\n";
// Create form output
foreach ($form as $idx => $tab) {
if (!empty($tab['fieldsets']) && is_array($tab['fieldsets'])) {
$content = '';
foreach ($tab['fieldsets'] as $fieldset) {
$subcontent = rcmail_get_form_part($fieldset, $attrib);
if ($subcontent) {
$subcontent = html::tag('legend', null, rcube::Q($fieldset['name'])) . $subcontent;
$content .= html::tag('fieldset', null, $subcontent) ."\n";
}
}
}
else {
$content = rcmail_get_form_part($tab, $attrib);
}
if ($idx != 'props') {
$out .= html::tag('fieldset', null, html::tag('legend', null, rcube::Q($tab['name'])) . $content) ."\n";
}
else {
$out .= $content ."\n";
}
}
$out .= "\n$form_end";
$RCMAIL->output->set_env('messagecount', (int) $msgcount);
$RCMAIL->output->set_env('folder', $mbox);
if ($mbox !== null && empty($_POST)) {
$RCMAIL->output->command('parent.set_quota', $RCMAIL->quota_content(null, $mbox));
}
return $out;
}
function rcmail_get_form_part($form, $attrib = array())
{
+ global $RCMAIL;
+
$content = '';
if (is_array($form['content']) && !empty($form['content'])) {
$table = new html_table(array('cols' => 2));
foreach ($form['content'] as $col => $colprop) {
$colprop['id'] = '_'.$col;
$label = !empty($colprop['label']) ? $colprop['label'] : $RCMAIL->gettext($col);
$table->add('title', html::label($colprop['id'], rcube::Q($label)));
$table->add(null, $colprop['value']);
}
$content = $table->show($attrib);
}
else {
$content = $form['content'];
}
return $content;
}
diff --git a/program/steps/settings/edit_response.inc b/program/steps/settings/edit_response.inc
index 10dec1096..03a6878be 100644
--- a/program/steps/settings/edit_response.inc
+++ b/program/steps/settings/edit_response.inc
@@ -1,108 +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 = rcube_utils::get_input_value('_key', rcube_utils::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(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST));
$text = trim(rcube_utils::get_input_value('_text', rcube_utils::INPUT_POST, true));
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');
}
}
$OUTPUT->set_env('readonly', !empty($RESPONSE_RECORD['static']));
$OUTPUT->add_handler('responseform', 'rcube_response_form');
$OUTPUT->set_pagetitle($RCMAIL->gettext($RCMAIL->action == 'add-response' ? 'addresponse' : 'editresponse'));
$OUTPUT->send('responseedit');
function rcube_response_form($attrib)
{
- global $RCMAIL, $OUTPUT, $RESPONSE_RECORD;
+ global $RCMAIL, $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 = $RCMAIL->gettext('responsename');
$table->add('title', html::label('ffname', rcube::Q($RCMAIL->gettext('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', rcube::Q($RCMAIL->gettext('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;
}
diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc
index 14e41d607..6db0b17e8 100644
--- a/program/steps/settings/folders.inc
+++ b/program/steps/settings/folders.inc
@@ -1,516 +1,515 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/settings/folders.inc |
| |
| This file is part of the Roundcube Webmail client |
| 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. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality of folders management |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
// init IMAP connection
$STORAGE = $RCMAIL->get_storage();
// subscribe mailbox
if ($RCMAIL->action == 'subscribe') {
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
if (strlen($mbox)) {
$result = $STORAGE->subscribe(array($mbox));
// Handle virtual (non-existing) folders
if (!$result && $STORAGE->get_error_code() == -1 &&
$STORAGE->get_response_code() == rcube_storage::TRYCREATE
) {
$result = $STORAGE->create_folder($mbox, true);
if ($result) {
// @TODO: remove 'virtual' class of folder's row
}
}
if ($result) {
// Handle subscription of protected folder (#1487656)
if ($RCMAIL->config->get('protect_default_folders')
&& $STORAGE->is_special_folder($mbox)
) {
$OUTPUT->command('disable_subscription', $mbox);
}
$OUTPUT->show_message('foldersubscribed', 'confirmation');
}
else
$RCMAIL->display_server_error('errorsaving');
}
}
// unsubscribe mailbox
else if ($RCMAIL->action == 'unsubscribe') {
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
if (strlen($mbox)) {
$result = $STORAGE->unsubscribe(array($mbox));
if ($result)
$OUTPUT->show_message('folderunsubscribed', 'confirmation');
else
$RCMAIL->display_server_error('errorsaving');
}
}
// delete an existing mailbox
else if ($RCMAIL->action == 'delete-folder') {
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
if (strlen($mbox)) {
$plugin = $RCMAIL->plugins->exec_hook('folder_delete', array('name' => $mbox));
if (!$plugin['abort']) {
$deleted = $STORAGE->delete_folder($plugin['name']);
}
else {
$deleted = $plugin['result'];
}
// #1488692: update session
if ($deleted && $_SESSION['mbox'] === $mbox) {
$RCMAIL->session->remove('mbox');
}
}
if ($OUTPUT->ajax_call && $deleted) {
// Remove folder and subfolders rows
$OUTPUT->command('remove_folder_row', $mbox);
$OUTPUT->show_message('folderdeleted', 'confirmation');
// Clear content frame
$OUTPUT->command('subscription_select');
$OUTPUT->command('set_quota', $RCMAIL->quota_content());
}
else if (!$deleted) {
$RCMAIL->display_server_error('errorsaving');
}
}
// rename an existing mailbox
else if ($RCMAIL->action == 'rename-folder') {
$name = trim(rcube_utils::get_input_value('_folder_newname', rcube_utils::INPUT_POST, true));
$oldname = rcube_utils::get_input_value('_folder_oldname', rcube_utils::INPUT_POST, true);
if (strlen($name) && strlen($oldname)) {
$rename = rcmail_rename_folder($oldname, $name);
}
if ($rename && $OUTPUT->ajax_call) {
rcmail_update_folder_row($name, $oldname);
}
else if (!$rename) {
$RCMAIL->display_server_error('errorsaving');
}
}
// clear mailbox
else if ($RCMAIL->action == 'purge') {
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
$delimiter = $STORAGE->get_hierarchy_delimiter();
$trash_mbox = $RCMAIL->config->get('trash_mbox');
$trash_regexp = '/^' . preg_quote($trash . $delimiter, '/') . '/';
// we should only be purging trash (or their subfolders)
if (!strlen($trash_mbox) || $mbox === $trash_mbox
|| preg_match($trash_regexp, $mbox)
) {
$success = $STORAGE->delete_message('*', $mbox);
$delete = true;
}
// move to Trash
else {
$success = $STORAGE->move_message('1:*', $trash_mbox, $mbox);
$delete = false;
}
if ($success) {
$OUTPUT->set_env('messagecount', 0);
if ($delete) {
$OUTPUT->show_message('folderpurged', 'confirmation');
$OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $mbox));
}
else {
$OUTPUT->show_message('messagemoved', 'confirmation');
}
$_SESSION['unseen_count'][$mbox] = 0;
$OUTPUT->command('show_folder', $mbox, null, true);
}
else {
$RCMAIL->display_server_error('errorsaving');
}
}
// get mailbox size
else if ($RCMAIL->action == 'folder-size') {
$name = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
$size = $STORAGE->folder_size($name);
// @TODO: check quota and show percentage usage of specified mailbox?
if ($size !== false) {
$OUTPUT->command('folder_size_update', $RCMAIL->show_bytes($size));
}
else {
$RCMAIL->display_server_error();
}
}
if ($OUTPUT->ajax_call) {
$OUTPUT->send();
}
$OUTPUT->set_pagetitle($RCMAIL->gettext('folders'));
$OUTPUT->set_env('prefix_ns', $STORAGE->get_namespace('prefix'));
$OUTPUT->set_env('quota', (bool) $STORAGE->get_capability('QUOTA'));
$OUTPUT->include_script('treelist.js');
// add some labels to client
$OUTPUT->add_label('deletefolderconfirm', 'purgefolderconfirm', 'folderdeleting',
'foldermoving', 'foldersubscribing', 'folderunsubscribing', 'quota');
// register UI objects
$OUTPUT->add_handlers(array(
'foldersubscription' => 'rcmail_subscription_form',
'folderframe' => 'rcmail_folder_frame',
'folderfilter' => 'rcmail_folder_filter',
'quotadisplay' => array($RCMAIL, 'quota_display'),
));
$OUTPUT->send('folders');
// build table with all folders listed by server
function rcmail_subscription_form($attrib)
{
global $RCMAIL, $OUTPUT;
list($form_start, $form_end) = get_form_tags($attrib, 'folders');
unset($attrib['form']);
if (!$attrib['id']) {
$attrib['id'] = 'rcmSubscriptionlist';
}
$STORAGE = $RCMAIL->get_storage();
// get folders from server
$STORAGE->clear_cache('mailboxes', true);
$a_unsubscribed = $STORAGE->list_folders();
$a_subscribed = $STORAGE->list_folders_subscribed('', '*', null, null, true); // unsorted
$delimiter = $STORAGE->get_hierarchy_delimiter();
$namespace = $STORAGE->get_namespace();
$special_folders = array_flip(array_merge(array('inbox' => 'INBOX'), $STORAGE->get_special_folders()));
$protect_default = $RCMAIL->config->get('protect_default_folders');
$seen = array();
$list_folders = array();
// pre-process folders list
foreach ($a_unsubscribed as $i => $folder) {
$folder_id = $folder;
$folder = $STORAGE->mod_folder($folder);
$foldersplit = explode($delimiter, $folder);
$name = rcube_charset::convert(array_pop($foldersplit), 'UTF7-IMAP');
$parent_folder = join($delimiter, $foldersplit);
$level = count($foldersplit);
// add any necessary "virtual" parent folders
if ($parent_folder && !isset($seen[$parent_folder])) {
for ($i=1; $i<=$level; $i++) {
$ancestor_folder = join($delimiter, array_slice($foldersplit, 0, $i));
if ($ancestor_folder && !$seen[$ancestor_folder]++) {
$ancestor_name = rcube_charset::convert($foldersplit[$i-1], 'UTF7-IMAP');
$list_folders[] = array(
'id' => $ancestor_folder,
'name' => $ancestor_name,
'level' => $i-1,
'virtual' => true,
);
}
}
}
// Handle properly INBOX.INBOX situation
if (isset($seen[$folder])) {
continue;
}
$seen[$folder]++;
$list_folders[] = array(
'id' => $folder_id,
'name' => $name,
'level' => $level,
);
}
unset($seen);
$checkbox_subscribe = new html_checkbox(array(
'name' => '_subscribed[]',
'title' => $RCMAIL->gettext('changesubscription'),
'onclick' => rcmail_output::JS_OBJECT_NAME.".command(this.checked?'subscribe':'unsubscribe',this.value)",
));
$js_folders = array();
$folders = array();
$collapsed = $RCMAIL->config->get('collapsed_folders');
// create list of available folders
foreach ($list_folders as $i => $folder) {
- $idx = $i + 1;
$sub_key = array_search($folder['id'], $a_subscribed);
$subscribed = $sub_key !== false;
$protected = $protect_default && isset($special_folders[$folder['id']]);
$noselect = false;
$classes = array();
$folder_utf8 = rcube_charset::convert($folder['id'], 'UTF7-IMAP');
$display_folder = rcube::Q($protected ? $RCMAIL->localize_foldername($folder['id']) : $folder['name']);
if ($folder['virtual']) {
$classes[] = 'virtual';
}
// Check \Noselect flag (of existing folder)
if (!$protected && in_array($folder['id'], $a_unsubscribed)) {
$attrs = $STORAGE->folder_attributes($folder['id']);
$noselect = in_array('\\Noselect', $attrs);
}
$disabled = (($protected && $subscribed) || $noselect);
// Below we will disable subscription option for "virtual" folders
// according to namespaces, but only if they aren't already subscribed.
// User should be able to unsubscribe from the folder
// even if it doesn't exists or is not accessible (OTRS:1000059)
if (!$subscribed && !$disabled && !empty($namespace) && $folder['virtual']) {
// check if the folder is a namespace prefix, then disable subscription option on it
if (!$disabled && $folder['level'] == 0) {
$fname = $folder['id'] . $delimiter;
foreach ($namespace as $ns) {
if (is_array($ns)) {
foreach ($ns as $item) {
if ($item[0] === $fname) {
$disabled = true;
break 2;
}
}
}
}
}
// check if the folder is an other users virtual-root folder, then disable subscription option on it
if (!$disabled && $folder['level'] == 1 && !empty($namespace['other'])) {
$parts = explode($delimiter, $folder['id']);
$fname = $parts[0] . $delimiter;
foreach ($namespace['other'] as $item) {
if ($item[0] === $fname) {
$disabled = true;
break;
}
}
}
// check if the folder is shared, then disable subscription option on it (if not subscribed already)
if (!$disabled) {
$tmp_ns = array_merge((array)$namespace['other'], (array)$namespace['shared']);
foreach ($tmp_ns as $item) {
if (strpos($folder['id'], $item[0]) === 0) {
$disabled = true;
break;
}
}
}
}
$is_collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false;
$folder_id = rcube_utils::html_identifier($folder['id'], true);
if ($folder_class = $RCMAIL->folder_classname($folder['id'])) {
$classes[] = $folder_class;
}
$folders[$folder['id']] = array(
'idx' => $folder_id,
'folder_imap' => $folder['id'],
'folder' => $folder_utf8,
'display' => $display_folder,
'protected' => $protected || $folder['virtual'],
'class' => join(' ', $classes),
'subscribed' => $subscribed,
'level' => $folder['level'],
'collapsed' => $is_collapsed,
'content' => html::a(array('href' => '#'), $display_folder)
. $checkbox_subscribe->show(($subscribed ? $folder['id'] : ''),
array('value' => $folder['id'], 'disabled' => $disabled ? 'disabled' : ''))
);
}
$plugin = $RCMAIL->plugins->exec_hook('folders_list', array('list' => $folders));
// add drop-target representing 'root'
$root = array(
'idx' => rcube_utils::html_identifier('*', true),
'folder_imap' => '*',
'folder' => '',
'display' => '',
'protected' => true,
'class' => 'root',
'content' => '<span>&nbsp;</span>',
);
$folders = array();
$plugin['list'] = array_values($plugin['list']);
array_unshift($plugin['list'], $root);
for ($i = 0, $length = count($plugin['list']); $i<$length; $i++) {
$folders[] = rcmail_folder_tree_element($plugin['list'], $i, $js_folders);
}
$OUTPUT->add_gui_object('subscriptionlist', $attrib['id']);
$OUTPUT->set_env('subscriptionrows', $js_folders);
$OUTPUT->set_env('defaultfolders', array_keys($special_folders));
$OUTPUT->set_env('collapsed_folders', $collapsed);
$OUTPUT->set_env('delimiter', $delimiter);
return $form_start . html::tag('ul', $attrib, implode('', $folders), html::$common_attrib) . $form_end;
}
function rcmail_folder_tree_element($folders, &$key, &$js_folders)
{
$data = $folders[$key];
$idx = 'rcmli' . $data['idx'];
$js_folders[$data['folder_imap']] = array($data['folder'], $data['display'], $data['protected']);
$content = $data['content'];
$attribs = array(
'id' => $idx,
'class' => trim($data['class'] . ' mailbox')
);
$children = array();
while ($folders[$key+1] && $folders[$key+1]['level'] > $data['level']) {
$key++;
$children[] = rcmail_folder_tree_element($folders, $key, $js_folders);
}
if (!empty($children)) {
$content .= html::div('treetoggle ' . ($data['collapsed'] ? 'collapsed' : 'expanded'), '&nbsp;')
. html::tag('ul', array('style' => ($data['collapsed'] ? "display:none" : null)),
implode("\n", $children));
}
return html::tag('li', $attribs, $content);
}
function rcmail_folder_frame($attrib)
{
global $OUTPUT;
if (!$attrib['id']) {
$attrib['id'] = 'rcmfolderframe';
}
return $OUTPUT->frame($attrib, true);
}
function rcmail_folder_filter($attrib)
{
global $RCMAIL;
$storage = $RCMAIL->get_storage();
$namespace = $storage->get_namespace();
if (empty($namespace['personal']) && empty($namespace['shared']) && empty($namespace['other'])) {
return '';
}
if (!$attrib['id']) {
$attrib['id'] = 'rcmfolderfilter';
}
$attrib['onchange'] = rcmail_output::JS_OBJECT_NAME . '.folder_filter(this.value)';
$roots = array();
$select = new html_select($attrib);
$select->add($RCMAIL->gettext('all'), '---');
foreach (array_keys($namespace) as $type) {
foreach ((array)$namespace[$type] as $ns) {
$root = rtrim($ns[0], $ns[1]);
$label = $RCMAIL->gettext('namespace.' . $type);
if (count($namespace[$type]) > 1) {
$label .= ' (' . rcube_charset::convert($root, 'UTF7-IMAP', RCUBE_CHARSET) . ')';
}
$select->add($label, $root);
if (strlen($root)) {
$roots[] = $root;
}
}
}
$RCMAIL->output->add_gui_object('foldersfilter', $attrib['id']);
$RCMAIL->output->set_env('ns_roots', $roots);
return $select->show();
}
function rcmail_rename_folder($oldname, $newname)
{
global $RCMAIL;
$storage = $RCMAIL->get_storage();
$delimiter = $storage->get_hierarchy_delimiter();
$plugin = $RCMAIL->plugins->exec_hook('folder_rename', array(
'oldname' => $oldname, 'newname' => $newname));
if (!$plugin['abort']) {
$renamed = $storage->rename_folder($oldname, $newname);
}
else {
$renamed = $plugin['result'];
}
// update per-folder options for modified folder and its subfolders
if ($renamed) {
$a_threaded = (array) $RCMAIL->config->get('message_threading', array());
$oldprefix = '/^' . preg_quote($oldname . $delimiter, '/') . '/';
foreach ($a_threaded as $key => $val) {
if ($key == $oldname) {
unset($a_threaded[$key]);
$a_threaded[$newname] = $val;
}
else if (preg_match($oldprefix, $key)) {
unset($a_threaded[$key]);
$a_threaded[preg_replace($oldprefix, $newname.$delimiter, $key)] = $val;
}
}
$RCMAIL->user->save_prefs(array('message_threading' => $a_threaded));
// #1488692: update session
if ($_SESSION['mbox'] === $oldname) {
$_SESSION['mbox'] = $newname;
}
return true;
}
return false;
}
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index 0b2039a78..3ec318566 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -1,1394 +1,1394 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/settings/func.inc |
| |
| This file is part of the Roundcube Webmail client |
| 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. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality for user's settings & preferences |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
if (!$OUTPUT->ajax_call) {
$OUTPUT->set_pagetitle($RCMAIL->gettext('preferences'));
}
// register UI objects
$OUTPUT->add_handlers(array(
'settingstabs' => 'rcmail_settings_tabs',
'prefsframe' => 'rcmail_preferences_frame',
'sectionslist' => 'rcmail_sections_list',
'identitieslist' => 'rcmail_identities_list',
));
// register action aliases
$RCMAIL->register_action_map(array(
'folders' => 'folders.inc',
'rename-folder' => 'folders.inc',
'delete-folder' => 'folders.inc',
'subscribe' => 'folders.inc',
'unsubscribe' => 'folders.inc',
'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',
'delete-identity' => 'identities.inc',
'upload-display' => 'upload.inc',
));
// similar function as /steps/settings/identities.inc::rcmail_identity_frame()
function rcmail_preferences_frame($attrib)
{
global $OUTPUT;
if (!$attrib['id']) {
$attrib['id'] = 'rcmprefsframe';
}
return $OUTPUT->frame($attrib, true);
}
function rcmail_sections_list($attrib)
{
global $RCMAIL;
// add id to message list table if not specified
if (!strlen($attrib['id'])) {
$attrib['id'] = 'rcmsectionslist';
}
list($list, $cols) = rcmail_user_prefs();
// create XHTML table
$out = $RCMAIL->table_output($attrib, $list, $cols, 'id');
// set client env
$RCMAIL->output->add_gui_object('sectionslist', $attrib['id']);
$RCMAIL->output->include_script('list.js');
return $out;
}
function rcmail_identities_list($attrib)
{
global $OUTPUT, $RCMAIL;
// add id to message list table if not specified
if (!strlen($attrib['id'])) {
$attrib['id'] = 'rcmIdentitiesList';
}
// get identities list and define 'mail' column
$list = $RCMAIL->user->list_identities();
foreach ($list as $idx => $row) {
$list[$idx]['mail'] = trim($row['name'] . ' <' . rcube_utils::idn_to_utf8($row['email']) .'>');
}
// get all identites from DB and define list of cols to be displayed
$plugin = $RCMAIL->plugins->exec_hook('identities_list', array(
'list' => $list,
'cols' => array('mail')
));
// @TODO: use <UL> instead of <TABLE> for identities list
// create XHTML table
$out = $RCMAIL->table_output($attrib, $plugin['list'], $plugin['cols'], 'identity_id');
// set client env
$OUTPUT->add_gui_object('identitieslist', $attrib['id']);
return $out;
}
// similar function as in /steps/addressbook/edit.inc
function get_form_tags($attrib, $action, $id = null, $hidden = null)
{
global $EDIT_FORM, $RCMAIL;
$form_start = $form_end = '';
if (empty($EDIT_FORM)) {
$request_key = $action . (isset($id) ? '.'.$id : '');
$form_start = $RCMAIL->output->request_form(array(
'name' => 'form',
'method' => 'post',
'task' => $RCMAIL->task,
'action' => $action,
'request' => $request_key,
'noclose' => true
) + $attrib);
if (is_array($hidden)) {
$hiddenfields = new html_hiddenfield($hidden);
$form_start .= $hiddenfields->show();
}
$form_end = !strlen($attrib['form']) ? '</form>' : '';
$EDIT_FORM = !empty($attrib['form']) ? $attrib['form'] : 'form';
$RCMAIL->output->add_gui_object('editform', $EDIT_FORM);
}
return array($form_start, $form_end);
}
function rcmail_user_prefs($current = null)
{
global $RCMAIL;
$sections['general'] = array('id' => 'general', 'section' => $RCMAIL->gettext('uisettings'));
$sections['mailbox'] = array('id' => 'mailbox', 'section' => $RCMAIL->gettext('mailboxview'));
$sections['mailview'] = array('id' => 'mailview','section' => $RCMAIL->gettext('messagesdisplaying'));
$sections['compose'] = array('id' => 'compose', 'section' => $RCMAIL->gettext('messagescomposition'));
$sections['addressbook'] = array('id' => 'addressbook','section' => $RCMAIL->gettext('addressbook'));
$sections['folders'] = array('id' => 'folders', 'section' => $RCMAIL->gettext('specialfolders'));
$sections['server'] = array('id' => 'server', 'section' => $RCMAIL->gettext('serversettings'));
// hook + define list cols
$plugin = $RCMAIL->plugins->exec_hook('preferences_sections_list',
array('list' => $sections, 'cols' => array('section')));
$sections = $plugin['list'];
$config = $RCMAIL->config->all();
$no_override = array_flip((array)$RCMAIL->config->get('dont_override'));
foreach ($sections as $idx => $sect) {
if ($current && $sect['id'] != $current) {
continue;
}
$blocks = array();
switch ($sect['id']) {
// general
case 'general':
$blocks = array(
'main' => array('name' => rcube::Q($RCMAIL->gettext('mainoptions'))),
'skin' => array('name' => rcube::Q($RCMAIL->gettext('skin'))),
'browser' => array('name' => rcube::Q($RCMAIL->gettext('browseroptions'))),
'advanced'=> array('name' => rcube::Q($RCMAIL->gettext('advancedoptions'))),
);
// language selection
if (!isset($no_override['language'])) {
if (!$current) {
continue 2;
}
$a_lang = $RCMAIL->list_languages();
asort($a_lang);
$field_id = 'rcmfd_lang';
$select = new html_select(array('name' => '_language', 'id' => $field_id));
$select->add(array_values($a_lang), array_keys($a_lang));
$blocks['main']['options']['language'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('language'))),
'content' => $select->show($RCMAIL->user->language),
);
}
// timezone selection
if (!isset($no_override['timezone'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_timezone';
$select = new html_select(array('name' => '_timezone', 'id' => $field_id));
$select->add($RCMAIL->gettext('autodetect'), 'auto');
$zones = array();
foreach (DateTimeZone::listIdentifiers() as $i => $tzs) {
try {
$tz = new DateTimeZone($tzs);
$date = new DateTime('2012-12-21', $tz);
$offset = $date->format('Z') + 45000;
$sortkey = sprintf('%06d.%s', $offset, $tzs);
$zones[$sortkey] = array($tzs, $date->format('P'));
}
catch (Exception $e) {}
}
ksort($zones);
foreach ($zones as $zone) {
list($tzs, $offset) = $zone;
$select->add('(GMT ' . $offset . ') ' . strtr($tzs, '_', ' '), $tzs);
}
$blocks['main']['options']['timezone'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('timezone'))),
'content' => $select->show((string)$config['timezone']),
);
}
// date/time formatting
if (!isset($no_override['time_format'])) {
if (!$current) {
continue 2;
}
$reftime = mktime(7,30,0);
$defaults = array('G:i', 'H:i', 'g:i a', 'h:i A');
$formats = (array)$RCMAIL->config->get('time_formats', $defaults);
$field_id = 'rcmfd_time_format';
$select = new html_select(array('name' => '_time_format', 'id' => $field_id));
foreach ($formats as $choice) {
$select->add(date($choice, $reftime), $choice);
}
$blocks['main']['options']['time_format'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('timeformat'))),
'content' => $select->show($RCMAIL->config->get('time_format')),
);
}
if (!isset($no_override['date_format'])) {
if (!$current) {
continue 2;
}
$refdate = mktime(12,30,0,7,24);
$defaults = array('Y-m-d','d-m-Y','Y/m/d','m/d/Y','d/m/Y','d.m.Y','j.n.Y');
$formats = (array)$RCMAIL->config->get('date_formats', $defaults);
$field_id = 'rcmfd_date_format';
$select = new html_select(array('name' => '_date_format', 'id' => $field_id));
foreach ($formats as $choice) {
$select->add(date($choice, $refdate), $choice);
}
$blocks['main']['options']['date_format'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('dateformat'))),
'content' => $select->show($config['date_format']),
);
}
// Show checkbox for toggling 'pretty dates'
if (!isset($no_override['prettydate'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_prettydate';
$input = new html_checkbox(array('name' => '_pretty_date', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['prettydate'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('prettydate'))),
'content' => $input->show($config['prettydate']?1:0),
);
}
if (!isset($no_override['refresh_interval'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_refresh_interval';
$select = new html_select(array('name' => '_refresh_interval', 'id' => $field_id));
$select->add($RCMAIL->gettext('never'), 0);
foreach (array(1, 3, 5, 10, 15, 30, 60) as $min) {
if (!$config['min_refresh_interval'] || $config['min_refresh_interval'] <= $min * 60) {
$label = $RCMAIL->gettext(array('name' => 'everynminutes', 'vars' => array('n' => $min)));
$select->add($label, $min);
}
}
$blocks['main']['options']['refresh_interval'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('refreshinterval'))),
'content' => $select->show($config['refresh_interval']/60),
);
}
// show drop-down for available skins
if (!isset($no_override['skin'])) {
if (!$current) {
continue 2;
}
$skins = rcmail_get_skins();
if (count($skins) > 1) {
$field_id = 'rcmfd_skin';
$input = new html_radiobutton(array('name'=>'_skin'));
foreach ($skins as $skin) {
$thumbnail = "./skins/$skin/thumbnail.png";
if (!is_file($thumbnail))
$thumbnail = './program/resources/blank.gif';
$skinname = ucfirst($skin);
$author_link = $license_link = '';
$meta = @json_decode(@file_get_contents("./skins/$skin/meta.json"), true);
if (is_array($meta) && $meta['name']) {
$skinname = $meta['name'];
$author_link = $meta['url'] ? html::a(array('href' => $meta['url'], 'target' => '_blank'), rcube::Q($meta['author'])) : rcube::Q($meta['author']);
$license_link = $meta['license-url'] ? html::a(array('href' => $meta['license-url'], 'target' => '_blank', 'tabindex' => '-1'), rcube::Q($meta['license'])) : rcube::Q($meta['license']);
}
$skinnames[] = mb_strtolower($skinname);
$blocks['skin']['options'][$skin]['content'] = html::label(array('class' => 'skinselection'),
html::span('skinitem', $input->show($config['skin'], array('value' => $skin, 'id' => $field_id.$skin))) .
html::span('skinitem', html::img(array('src' => $thumbnail, 'class' => 'skinthumbnail', 'alt' => $skin, 'width' => 64, 'height' => 64))) .
html::span('skinitem', html::span('skinname', rcube::Q($skinname)) . html::br() .
html::span('skinauthor', $author_link ? 'by ' . $author_link : '') . html::br() .
html::span('skinlicense', $license_link ? $RCMAIL->gettext('license').':&nbsp;' . $license_link : ''))
);
}
array_multisort($blocks['skin']['options'], SORT_ASC, SORT_STRING, $skinnames);
}
}
// standard_windows option decides if new windows should be
// opened as popups or standard windows (which can be handled by browsers as tabs)
if (!isset($no_override['standard_windows'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_standard_windows';
$checkbox = new html_checkbox(array('name' => '_standard_windows', 'id' => $field_id, 'value' => 1));
$blocks['browser']['options']['standard_windows'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('standardwindows'))),
'content' => $checkbox->show($config['standard_windows']?1:0),
);
}
if ($current) {
$product_name = $RCMAIL->config->get('product_name', 'Roundcube Webmail');
$RCMAIL->output->add_script(sprintf("%s.check_protocol_handler('%s', '#mailtoprotohandler');",
rcmail_output::JS_OBJECT_NAME, rcube::JQ($product_name)), 'docready');
}
$blocks['browser']['options']['mailtoprotohandler'] = array(
'content' => html::a(array(
'href' => '#',
'id' => 'mailtoprotohandler'
),
rcube::Q($RCMAIL->gettext('mailtoprotohandler'))) .
html::span('mailtoprotohandler-status', ''),
);
break;
// Mailbox view (mail screen)
case 'mailbox':
$blocks = array(
'main' => array('name' => rcube::Q($RCMAIL->gettext('mainoptions'))),
'new_message' => array('name' => rcube::Q($RCMAIL->gettext('newmessage'))),
'advanced' => array('name' => rcube::Q($RCMAIL->gettext('advancedoptions'))),
);
// show config parameter for preview pane
if (!isset($no_override['preview_pane'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_preview';
$input = new html_checkbox(array('name' => '_preview_pane', 'id' => $field_id, 'value' => 1,
'onchange' => "$('#rcmfd_preview_pane_mark_read').prop('disabled', !this.checked)"));
$blocks['main']['options']['preview_pane'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('previewpane'))),
'content' => $input->show($config['preview_pane']?1:0),
);
}
// show config parameter for preview pane auto mark as read delay
if (!isset($no_override['preview_pane_mark_read'])) {
if (!$current) {
continue 2;
}
// apply default if config option is not set at all
$config['preview_pane_mark_read'] = $RCMAIL->config->get('preview_pane_mark_read', 0);
$field_id = 'rcmfd_preview_pane_mark_read';
$select = new html_select(array('name' => '_preview_pane_mark_read', 'id' => $field_id,
'disabled' => $config['preview_pane']?0:1));
$select->add($RCMAIL->gettext('never'), '-1');
$select->add($RCMAIL->gettext('immediately'), 0);
foreach (array(5, 10, 20, 30) as $sec) {
$label = $RCMAIL->gettext(array('name' => 'afternseconds', 'vars' => array('n' => $sec)));
$select->add($label, $sec);
}
$blocks['main']['options']['preview_pane_mark_read'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('previewpanemarkread'))),
'content' => $select->show(intval($config['preview_pane_mark_read'])),
);
}
if (!isset($no_override['mdn_requests'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_mdn_requests';
$select = new html_select(array('name' => '_mdn_requests', 'id' => $field_id));
$select->add($RCMAIL->gettext('askuser'), 0);
$select->add($RCMAIL->gettext('autosend'), 1);
$select->add($RCMAIL->gettext('autosendknown'), 3);
$select->add($RCMAIL->gettext('autosendknownignore'), 4);
$select->add($RCMAIL->gettext('ignore'), 2);
$blocks['main']['options']['mdn_requests'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('mdnrequests'))),
'content' => $select->show($config['mdn_requests']),
);
}
if (!isset($no_override['autoexpand_threads'])) {
if (!$current) {
continue 2;
}
$storage = $RCMAIL->get_storage();
$supported = $storage->get_capability('THREAD');
if ($supported) {
$field_id = 'rcmfd_autoexpand_threads';
$select = new html_select(array('name' => '_autoexpand_threads', 'id' => $field_id));
$select->add($RCMAIL->gettext('never'), 0);
$select->add($RCMAIL->gettext('do_expand'), 1);
$select->add($RCMAIL->gettext('expand_only_unread'), 2);
$blocks['main']['options']['autoexpand_threads'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('autoexpand_threads'))),
'content' => $select->show($config['autoexpand_threads']),
);
}
}
// show page size selection
if (!isset($no_override['mail_pagesize'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_mail_pagesize';
$input = new html_inputfield(array('name' => '_mail_pagesize', 'id' => $field_id, 'size' => 5));
$size = intval($config['mail_pagesize'] ? $config['mail_pagesize'] : $config['pagesize']);
$blocks['main']['options']['pagesize'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('pagesize'))),
'content' => $input->show($size ? $size : 50),
);
}
if (!isset($no_override['check_all_folders'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_check_all_folders';
$input = new html_checkbox(array('name' => '_check_all_folders', 'id' => $field_id, 'value' => 1));
$blocks['new_message']['options']['check_all_folders'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('checkallfolders'))),
'content' => $input->show($config['check_all_folders']?1:0),
);
}
break;
// Message viewing
case 'mailview':
$blocks = array(
'main' => array('name' => rcube::Q($RCMAIL->gettext('mainoptions'))),
'advanced' => array('name' => rcube::Q($RCMAIL->gettext('advancedoptions'))),
);
// show checkbox to open message view in new window
if (!isset($no_override['message_extwin'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_message_extwin';
$input = new html_checkbox(array('name' => '_message_extwin', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['message_extwin'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('showinextwin'))),
'content' => $input->show($config['message_extwin']?1:0),
);
}
// show checkbox to show email instead of name
if (!isset($no_override['message_show_email'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_message_show_email';
$input = new html_checkbox(array('name' => '_message_show_email', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['message_show_email'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('showemail'))),
'content' => $input->show($config['message_show_email']?1:0),
);
}
// show checkbox for HTML/plaintext messages
if (!isset($no_override['prefer_html'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_htmlmsg';
$input = new html_checkbox(array('name' => '_prefer_html', 'id' => $field_id, 'value' => 1,
'onchange' => "$('#rcmfd_show_images').prop('disabled', !this.checked).val(0)"));
$blocks['main']['options']['prefer_html'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('preferhtml'))),
'content' => $input->show($config['prefer_html']?1:0),
);
}
if (!isset($no_override['default_charset'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_default_charset';
$blocks['advanced']['options']['default_charset'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('defaultcharset'))),
'content' => $RCMAIL->output->charset_selector(array(
'id' => $field_id, 'name' => '_default_charset', 'selected' => $config['default_charset']
)));
}
if (!isset($no_override['show_images'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_show_images';
$input = new html_select(array('name' => '_show_images', 'id' => $field_id,
'disabled' => !$config['prefer_html']));
$input->add($RCMAIL->gettext('never'), 0);
$input->add($RCMAIL->gettext('fromknownsenders'), 1);
$input->add($RCMAIL->gettext('always'), 2);
$blocks['main']['options']['show_images'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('showremoteimages'))),
'content' => $input->show($config['prefer_html'] ? $config['show_images'] : 0),
);
}
if (!isset($no_override['inline_images'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_inline_images';
$input = new html_checkbox(array('name' => '_inline_images', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['inline_images'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('showinlineimages'))),
'content' => $input->show($config['inline_images']?1:0),
);
}
// "display after delete" checkbox
if (!isset($no_override['display_next'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_displaynext';
$input = new html_checkbox(array('name' => '_display_next', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['display_next'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('displaynext'))),
'content' => $input->show($config['display_next']?1:0),
);
}
break;
// Mail composition
case 'compose':
$blocks = array(
'main' => array('name' => rcube::Q($RCMAIL->gettext('mainoptions'))),
'sig' => array('name' => rcube::Q($RCMAIL->gettext('signatureoptions'))),
'spellcheck' => array('name' => rcube::Q($RCMAIL->gettext('spellcheckoptions'))),
'advanced' => array('name' => rcube::Q($RCMAIL->gettext('advancedoptions'))),
);
// show checkbox to compose messages in a new window
if (!isset($no_override['compose_extwin'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfdcompose_extwin';
$input = new html_checkbox(array('name' => '_compose_extwin', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['compose_extwin'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('composeextwin'))),
'content' => $input->show($config['compose_extwin']?1:0),
);
}
if (!isset($no_override['htmleditor'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_htmleditor';
$select = new html_select(array('name' => '_htmleditor', 'id' => $field_id));
$select->add($RCMAIL->gettext('never'), 0);
$select->add($RCMAIL->gettext('always'), 1);
$select->add($RCMAIL->gettext('htmlonreply'), 2);
$select->add($RCMAIL->gettext('htmlonreplyandforward'), 3);
$blocks['main']['options']['htmleditor'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('htmleditor'))),
'content' => $select->show(intval($config['htmleditor'])),
);
}
if (!isset($no_override['draft_autosave'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_autosave';
$select = new html_select(array('name' => '_draft_autosave', 'id' => $field_id, 'disabled' => empty($config['drafts_mbox'])));
$select->add($RCMAIL->gettext('never'), 0);
foreach (array(1, 3, 5, 10) as $i => $min) {
$label = $RCMAIL->gettext(array('name' => 'everynminutes', 'vars' => array('n' => $min)));
$select->add($label, $min*60);
}
$blocks['main']['options']['draft_autosave'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('autosavedraft'))),
'content' => $select->show($config['draft_autosave']),
);
}
if (!isset($no_override['mime_param_folding'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_param_folding';
$select = new html_select(array('name' => '_mime_param_folding', 'id' => $field_id));
$select->add($RCMAIL->gettext('2231folding'), 0);
$select->add($RCMAIL->gettext('miscfolding'), 1);
$select->add($RCMAIL->gettext('2047folding'), 2);
$blocks['advanced']['options']['mime_param_folding'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('mimeparamfolding'))),
'content' => $select->show($config['mime_param_folding']),
);
}
if (!isset($no_override['force_7bit'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_force_7bit';
$input = new html_checkbox(array('name' => '_force_7bit', 'id' => $field_id, 'value' => 1));
$blocks['advanced']['options']['force_7bit'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('force7bit'))),
'content' => $input->show($config['force_7bit']?1:0),
);
}
if (!isset($no_override['mdn_default'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_mdn_default';
$input = new html_checkbox(array('name' => '_mdn_default', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['mdn_default'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('reqmdn'))),
'content' => $input->show($config['mdn_default']?1:0),
);
}
if (!isset($no_override['dsn_default'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_dsn_default';
$input = new html_checkbox(array('name' => '_dsn_default', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['dsn_default'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('reqdsn'))),
'content' => $input->show($config['dsn_default']?1:0),
);
}
if (!isset($no_override['reply_same_folder'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_reply_same_folder';
$input = new html_checkbox(array('name' => '_reply_same_folder', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['reply_same_folder'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('replysamefolder'))),
'content' => $input->show($config['reply_same_folder']?1:0),
);
}
if (!isset($no_override['reply_mode'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_reply_mode';
$select = new html_select(array('name' => '_reply_mode', 'id' => $field_id));
$select->add($RCMAIL->gettext('replyempty'), -1);
$select->add($RCMAIL->gettext('replybottomposting'), 0);
$select->add($RCMAIL->gettext('replytopposting'), 1);
$blocks['main']['options']['reply_mode'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('whenreplying'))),
'content' => $select->show(intval($config['reply_mode'])),
);
}
if (!isset($no_override['spellcheck_before_send']) && $config['enable_spellcheck']) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_spellcheck_before_send';
$input = new html_checkbox(array('name' => '_spellcheck_before_send', 'id' => $field_id, 'value' => 1));
$blocks['spellcheck']['options']['spellcheck_before_send'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('spellcheckbeforesend'))),
'content' => $input->show($config['spellcheck_before_send']?1:0),
);
}
if ($config['enable_spellcheck']) {
if (!$current) {
continue 2;
}
foreach (array('syms', 'nums', 'caps') as $key) {
$key = 'spellcheck_ignore_'.$key;
if (!isset($no_override[$key])) {
$input = new html_checkbox(array('name' => '_'.$key, 'id' => 'rcmfd_'.$key, 'value' => 1));
$blocks['spellcheck']['options'][$key] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext(str_replace('_', '', $key)))),
'content' => $input->show($config[$key]?1:0),
);
}
}
}
if (!isset($no_override['show_sig'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_show_sig';
$select = new html_select(array('name' => '_show_sig', 'id' => $field_id));
$select->add($RCMAIL->gettext('never'), 0);
$select->add($RCMAIL->gettext('always'), 1);
$select->add($RCMAIL->gettext('newmessageonly'), 2);
$select->add($RCMAIL->gettext('replyandforwardonly'), 3);
$blocks['sig']['options']['show_sig'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('autoaddsignature'))),
'content' => $select->show($RCMAIL->config->get('show_sig', 1)),
);
}
if (!isset($no_override['strip_existing_sig'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_strip_existing_sig';
$input = new html_checkbox(array('name' => '_strip_existing_sig', 'id' => $field_id, 'value' => 1));
$blocks['sig']['options']['strip_existing_sig'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('replyremovesignature'))),
'content' => $input->show($config['strip_existing_sig']?1:0),
);
}
if (!isset($no_override['forward_attachment'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_forward_attachment';
$select = new html_select(array('name' => '_forward_attachment', 'id' => $field_id));
$select->add($RCMAIL->gettext('inline'), 0);
$select->add($RCMAIL->gettext('asattachment'), 1);
$blocks['main']['options']['forward_attachment'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('forwardmode'))),
'content' => $select->show(intval($config['forward_attachment'])),
);
}
if (!isset($no_override['default_font']) || !isset($no_override['default_font_size'])) {
if (!$current) {
continue 2;
}
// Default font size
$field_id = 'rcmfd_default_font_size';
$select_default_font_size = new html_select(array('name' => '_default_font_size', 'id' => $field_id));
$fontsizes = array('', '8pt', '10pt', '12pt', '14pt', '18pt', '24pt', '36pt');
foreach ($fontsizes as $size) {
$select_default_font_size->add($size, $size);
}
// Default font
$field_id = 'rcmfd_default_font';
$select_default_font = new html_select(array('name' => '_default_font', 'id' => $field_id));
$select_default_font->add('', '');
$fonts = rcmail::font_defs();
- foreach ($fonts as $fname => $font) {
+ foreach (array_keys($fonts) as $fname) {
$select_default_font->add($fname, $fname);
}
$blocks['main']['options']['default_font'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('defaultfont'))),
'content' => $select_default_font->show($RCMAIL->config->get('default_font', 1)) .
$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($RCMAIL->gettext('replyalldefault'), 0);
$select->add($RCMAIL->gettext('replyalllist'), 1);
$blocks['main']['options']['reply_all_mode'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('replyallmode'))),
'content' => $select->show(intval($config['reply_all_mode'])),
);
}
if (!isset($no_override['compose_save_localstorage'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_compose_save_localstorage';
$input = new html_checkbox(array('name' => '_compose_save_localstorage', 'id' => $field_id, 'value' => 1));
$blocks['advanced']['options']['compose_save_localstorage'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('savelocalstorage'))),
'content' => $input->show($config['compose_save_localstorage']?1:0),
);
}
break;
// Addressbook config
case 'addressbook':
$blocks = array(
'main' => array('name' => rcube::Q($RCMAIL->gettext('mainoptions'))),
'advanced' => array('name' => rcube::Q($RCMAIL->gettext('advancedoptions'))),
);
if (!isset($no_override['default_addressbook'])
&& (!$current || ($books = $RCMAIL->get_address_sources(true, true)))
) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_default_addressbook';
$select = new html_select(array('name' => '_default_addressbook', 'id' => $field_id));
foreach ($books as $book) {
$select->add(html_entity_decode($book['name'], ENT_COMPAT, 'UTF-8'), $book['id']);
}
$blocks['main']['options']['default_addressbook'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('defaultabook'))),
'content' => $select->show($config['default_addressbook']),
);
}
// show addressbook listing mode selection
if (!isset($no_override['addressbook_name_listing'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_addressbook_name_listing';
$select = new html_select(array('name' => '_addressbook_name_listing', 'id' => $field_id));
$select->add($RCMAIL->gettext('name'), 0);
$select->add($RCMAIL->gettext('firstname') . ' ' . $RCMAIL->gettext('surname'), 1);
$select->add($RCMAIL->gettext('surname') . ' ' . $RCMAIL->gettext('firstname'), 2);
$select->add($RCMAIL->gettext('surname') . ', ' . $RCMAIL->gettext('firstname'), 3);
$blocks['main']['options']['list_name_listing'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('listnamedisplay'))),
'content' => $select->show($config['addressbook_name_listing']),
);
}
// show addressbook sort column
if (!isset($no_override['addressbook_sort_col'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_addressbook_sort_col';
$select = new html_select(array('name' => '_addressbook_sort_col', 'id' => $field_id));
$select->add($RCMAIL->gettext('name'), 'name');
$select->add($RCMAIL->gettext('firstname'), 'firstname');
$select->add($RCMAIL->gettext('surname'), 'surname');
$blocks['main']['options']['sort_col'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('listsorting'))),
'content' => $select->show($config['addressbook_sort_col']),
);
}
// show addressbook page size selection
if (!isset($no_override['addressbook_pagesize'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_addressbook_pagesize';
$input = new html_inputfield(array('name' => '_addressbook_pagesize', 'id' => $field_id, 'size' => 5));
$size = intval($config['addressbook_pagesize'] ? $config['addressbook_pagesize'] : $config['pagesize']);
$blocks['main']['options']['pagesize'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('pagesize'))),
'content' => $input->show($size ? $size : 50),
);
}
if (!isset($no_override['autocomplete_single'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_autocomplete_single';
$checkbox = new html_checkbox(array('name' => '_autocomplete_single', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['autocomplete_single'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('autocompletesingle'))),
'content' => $checkbox->show($config['autocomplete_single']?1:0),
);
}
break;
// Special IMAP folders
case 'folders':
$blocks = array(
'main' => array('name' => rcube::Q($RCMAIL->gettext('mainoptions'))),
'advanced' => array('name' => rcube::Q($RCMAIL->gettext('advancedoptions'))),
);
if (!isset($no_override['show_real_foldernames'])) {
if (!$current) {
continue 2;
}
$field_id = 'show_real_foldernames';
$input = new html_checkbox(array('name' => '_show_real_foldernames', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['show_real_foldernames'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('show_real_foldernames'))),
'content' => $input->show($config['show_real_foldernames']?1:0),
);
}
// Configure special folders
$set = array('drafts_mbox', 'sent_mbox', 'junk_mbox', 'trash_mbox');
if ($current && count(array_intersect($no_override, $set)) < 4) {
$select = $RCMAIL->folder_selector(array(
'noselection' => '---',
'realnames' => true,
'maxlength' => 30,
'folder_filter' => 'mail',
'folder_rights' => 'w',
));
// #1486114, #1488279, #1489219
$onchange = "if ($(this).val() == 'INBOX') $(this).val('')";
}
if (!isset($no_override['drafts_mbox'])) {
if (!$current) {
continue 2;
}
$blocks['main']['options']['drafts_mbox'] = array(
'title' => rcube::Q($RCMAIL->gettext('drafts')),
'content' => $select->show($config['drafts_mbox'], array('name' => "_drafts_mbox", 'onchange' => $onchange)),
);
}
if (!isset($no_override['sent_mbox'])) {
if (!$current) {
continue 2;
}
$blocks['main']['options']['sent_mbox'] = array(
'title' => rcube::Q($RCMAIL->gettext('sent')),
'content' => $select->show($config['sent_mbox'], array('name' => "_sent_mbox", 'onchange' => '')),
);
}
if (!isset($no_override['junk_mbox'])) {
if (!$current) {
continue 2;
}
$blocks['main']['options']['junk_mbox'] = array(
'title' => rcube::Q($RCMAIL->gettext('junk')),
'content' => $select->show($config['junk_mbox'], array('name' => "_junk_mbox", 'onchange' => $onchange)),
);
}
if (!isset($no_override['trash_mbox'])) {
if (!$current) {
continue 2;
}
$blocks['main']['options']['trash_mbox'] = array(
'title' => rcube::Q($RCMAIL->gettext('trash')),
'content' => $select->show($config['trash_mbox'], array('name' => "_trash_mbox", 'onchange' => $onchange)),
);
}
break;
// Server settings
case 'server':
$blocks = array(
'main' => array('name' => rcube::Q($RCMAIL->gettext('mainoptions'))),
'maintenance' => array('name' => rcube::Q($RCMAIL->gettext('maintenance'))),
'advanced' => array('name' => rcube::Q($RCMAIL->gettext('advancedoptions'))),
);
if (!isset($no_override['read_when_deleted'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_read_deleted';
$input = new html_checkbox(array('name' => '_read_when_deleted', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['read_when_deleted'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('readwhendeleted'))),
'content' => $input->show($config['read_when_deleted']?1:0),
);
}
if (!isset($no_override['flag_for_deletion'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_flag_for_deletion';
$input = new html_checkbox(array('name' => '_flag_for_deletion', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['flag_for_deletion'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('flagfordeletion'))),
'content' => $input->show($config['flag_for_deletion']?1:0),
);
}
// don't show deleted messages
if (!isset($no_override['skip_deleted'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_skip_deleted';
$input = new html_checkbox(array('name' => '_skip_deleted', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['skip_deleted'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('skipdeleted'))),
'content' => $input->show($config['skip_deleted']?1:0),
);
}
if (!isset($no_override['delete_always'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_delete_always';
$input = new html_checkbox(array('name' => '_delete_always', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['delete_always'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('deletealways'))),
'content' => $input->show($config['delete_always']?1:0),
);
}
if (!isset($no_override['delete_junk'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_delete_junk';
$input = new html_checkbox(array('name' => '_delete_junk', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['delete_junk'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('deletejunk'))),
'content' => $input->show($config['delete_junk']?1:0),
);
}
// Trash purging on logout
if (!isset($no_override['logout_purge'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_logout_purge';
$input = new html_checkbox(array('name' => '_logout_purge', 'id' => $field_id, 'value' => 1));
$blocks['maintenance']['options']['logout_purge'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('logoutclear'))),
'content' => $input->show($config['logout_purge']?1:0),
);
}
// INBOX compacting on logout
if (!isset($no_override['logout_expunge'])) {
if (!$current) {
continue 2;
}
$field_id = 'rcmfd_logout_expunge';
$input = new html_checkbox(array('name' => '_logout_expunge', 'id' => $field_id, 'value' => 1));
$blocks['maintenance']['options']['logout_expunge'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('logoutcompact'))),
'content' => $input->show($config['logout_expunge']?1:0),
);
}
}
$found = false;
$data = $RCMAIL->plugins->exec_hook('preferences_list',
array('section' => $sect['id'], 'blocks' => $blocks, 'current' => $current));
$advanced_prefs = (array) $RCMAIL->config->get('advanced_prefs');
// create output
foreach ($data['blocks'] as $key => $block) {
if (!empty($block['content']) || !empty($block['options'])) {
$found = true;
}
// move some options to the 'advanced' block as configured by admin
if ($key != 'advanced') {
foreach ($advanced_prefs as $opt) {
if ($block['options'][$opt]) {
$data['blocks']['advanced']['options'][$opt] = $block['options'][$opt];
unset($data['blocks'][$key]['options'][$opt]);
}
}
}
}
// move 'advanced' block to the end of the list
if (!empty($data['blocks']['advanced'])) {
$adv = $data['blocks']['advanced'];
unset($data['blocks']['advanced']);
$data['blocks']['advanced'] = $adv;
}
if (!$found)
unset($sections[$idx]);
else
$sections[$idx]['blocks'] = $data['blocks'];
}
$data = $RCMAIL->plugins->exec_hook('preferences_section_header',
array('section' => $sect['id'], 'header' => '', 'current' => $current));
if(!empty($data['header'])) {
$sections[$idx]['header'] = $data['header'];
}
return array($sections, $plugin['cols']);
}
function rcmail_get_skins()
{
$path = RCUBE_INSTALL_PATH . 'skins';
$skins = array();
$dir = opendir($path);
if (!$dir) {
return false;
}
while (($file = readdir($dir)) !== false) {
$filename = $path.'/'.$file;
if (!preg_match('/^\./', $file) && is_dir($filename) && is_readable($filename)) {
$skins[] = $file;
}
}
closedir($dir);
return $skins;
}
function rcmail_folder_options($mailbox)
{
global $RCMAIL;
$options = $RCMAIL->get_storage()->folder_info($mailbox);
$options['protected'] = $options['is_root'] || ($options['special'] && $RCMAIL->config->get('protect_default_folders'));
return $options;
}
/**
* Updates (or creates) folder row in the subscriptions table
*
* @param string $name Folder name
* @param string $oldname Old folder name (for update)
* @param bool $subscribe Checks subscription checkbox
* @param string $class CSS class name for folder row
*/
function rcmail_update_folder_row($name, $oldname=null, $subscribe=false, $class_name=null)
{
global $RCMAIL, $OUTPUT;
$protect_folders = $RCMAIL->config->get('protect_default_folders');
$storage = $RCMAIL->get_storage();
$delimiter = $storage->get_hierarchy_delimiter();
$name_utf8 = rcube_charset::convert($name, 'UTF7-IMAP');
$protected = $protect_folders && $storage->is_special_folder($name);
$foldersplit = explode($delimiter, $storage->mod_folder($name));
$level = count($foldersplit) - 1;
$display_name = $protected ? $RCMAIL->localize_foldername($name) : rcube_charset::convert($foldersplit[$level], 'UTF7-IMAP');
$class_name = trim($class_name . ' mailbox');
if ($oldname === null) {
$OUTPUT->command('add_folder_row', $name, $name_utf8, $display_name, $protected, $subscribe,
$class_name);
}
else {
$OUTPUT->command('replace_folder_row', $oldname, $name, $name_utf8, $display_name, $protected, $class_name);
}
}
/**
* Render the list of settings sections (AKA tabs)
*/
function rcmail_settings_tabs($attrib)
{
global $RCMAIL, $OUTPUT;
// add default attributes
$attrib += array('tagname' => 'span', 'idprefix' => 'settingstab', 'selclass' => 'selected');
$default_actions = array(
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' => 'manageresponses'),
);
// get all identites from DB and define list of cols to be displayed
$plugin = $RCMAIL->plugins->exec_hook('settings_actions', array(
'actions' => $default_actions,
'attrib' => $attrib,
));
$attrib = $plugin['attrib'];
$tagname = $attrib['tagname'];
$tabs = array();
- foreach ($plugin['actions'] as $k => $action) {
+ foreach ($plugin['actions'] as $action) {
if (!$action['command'] && !$action['href'] && $action['action']) {
$action['href'] = $RCMAIL->url(array('_action' => $action['action']));
}
$button = $OUTPUT->button($action);
$attr = $attrib;
$cmd = $action['action'] ? $action['action'] : $action['command'];
$id = $action['id'] ? $action['id'] : $cmd;
if (!empty($id)) {
$attr['id'] = preg_replace('/[^a-z0-9]/i', '', $attrib['idprefix'] . $id);
}
$classnames = array($attrib['class']);
if (!empty($action['class'])) {
$classnames[] = $action['class'];
}
else if (!empty($cmd)) {
$classnames[] = $cmd;
}
if ($RCMAIL->action == $cmd) {
$classnames[] = $attrib['selclass'];
}
$attr['class'] = join(' ', $classnames);
$tabs[] = html::tag($tagname, $attr, $button, html::$common_attrib);
}
return join('', $tabs);
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Mar 1, 2:01 AM (14 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
165456
Default Alt Text
(291 KB)

Event Timeline