Aleksander Machniak
2013-12-25 c97625e02a95ebd995af8a06c27229581a071ddd
CS fixes
16 files modified
2139 ■■■■ changed files
program/steps/addressbook/edit.inc 73 ●●●●● patch | view | raw | blame | history
program/steps/addressbook/func.inc 64 ●●●● patch | view | raw | blame | history
program/steps/addressbook/groups.inc 209 ●●●● patch | view | raw | blame | history
program/steps/addressbook/import.inc 175 ●●●● patch | view | raw | blame | history
program/steps/addressbook/mailto.inc 4 ●●●● patch | view | raw | blame | history
program/steps/addressbook/save.inc 311 ●●●● patch | view | raw | blame | history
program/steps/mail/addcontact.inc 117 ●●●● patch | view | raw | blame | history
program/steps/mail/attachments.inc 244 ●●●● patch | view | raw | blame | history
program/steps/mail/autocomplete.inc 195 ●●●● patch | view | raw | blame | history
program/steps/mail/copy.inc 7 ●●●●● patch | view | raw | blame | history
program/steps/mail/folders.inc 5 ●●●●● patch | view | raw | blame | history
program/steps/mail/get.inc 647 ●●●● patch | view | raw | blame | history
program/steps/mail/getunread.inc 5 ●●●●● patch | view | raw | blame | history
program/steps/mail/headers.inc 5 ●●●● patch | view | raw | blame | history
program/steps/mail/import.inc 6 ●●●●● patch | view | raw | blame | history
program/steps/utils/error.inc 72 ●●●● patch | view | raw | blame | history
program/steps/addressbook/edit.inc
@@ -5,7 +5,7 @@
 | program/steps/addressbook/edit.inc                                    |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2007, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -169,37 +169,56 @@
function rcmail_upload_photo_form($attrib)
{
  global $RCMAIL, $OUTPUT;
    global $RCMAIL, $OUTPUT;
  // set defaults
  $attrib += array('id' => 'rcmUploadform', 'buttons' => 'yes');
    // set defaults
    $attrib += array('id' => 'rcmUploadform', 'buttons' => 'yes');
  // find max filesize value
  $max_filesize = parse_bytes(ini_get('upload_max_filesize'));
  $max_postsize = parse_bytes(ini_get('post_max_size'));
  if ($max_postsize && $max_postsize < $max_filesize)
    $max_filesize = $max_postsize;
  $max_filesize = $RCMAIL->show_bytes($max_filesize);
    // find max filesize value
    $max_filesize = parse_bytes(ini_get('upload_max_filesize'));
    $max_postsize = parse_bytes(ini_get('post_max_size'));
  $hidden = new html_hiddenfield(array('name' => '_cid', 'value' => $GLOBALS['cid']));
  $input = new html_inputfield(array('type' => 'file', 'name' => '_photo', 'size' => $attrib['size']));
  $button = new html_inputfield(array('type' => 'button'));
    if ($max_postsize && $max_postsize < $max_filesize) {
        $max_filesize = $max_postsize;
    }
    $max_filesize = $RCMAIL->show_bytes($max_filesize);
  $out = html::div($attrib,
    $OUTPUT->form_tag(array('id' => $attrib['id'].'Frm', 'name' => 'uploadform', 'method' => 'post', 'enctype' => 'multipart/form-data'),
      $hidden->show() .
      html::div(null, $input->show()) .
      html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) .
      (rcube_utils::get_boolean($attrib['buttons']) ? 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('upload-photo', this.form)"))
      ) : '')
    )
  );
    $hidden = new html_hiddenfield(array('name' => '_cid', 'value' => $GLOBALS['cid']));
    $input  = new html_inputfield(array('type' => 'file', 'name' => '_photo', 'size' => $attrib['size']));
    $button = new html_inputfield(array('type' => 'button'));
  $OUTPUT->add_label('addphoto','replacephoto');
  $OUTPUT->add_gui_object('uploadform', $attrib['id'].'Frm');
  return $out;
    $content = $hidden->show() . html::div(null, $input->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('upload-photo', 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_label('addphoto','replacephoto');
    $OUTPUT->add_gui_object('uploadform', $attrib['id'].'Frm');
    return $out;
}
// similar function as in /steps/settings/edit_identity.inc
program/steps/addressbook/func.inc
@@ -5,7 +5,7 @@
 | program/steps/addressbook/func.inc                                    |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -23,37 +23,37 @@
// 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
    '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));
program/steps/addressbook/groups.inc
@@ -5,7 +5,7 @@
 | program/steps/addressbook/groups.inc                                  |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2010, The Roundcube Dev Team                            |
 | Copyright (C) 2010-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -19,117 +19,136 @@
 +-----------------------------------------------------------------------+
*/
$source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
$source   = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
$CONTACTS = rcmail_contact_source($source);
if ($CONTACTS->readonly || !$CONTACTS->groups) {
  $OUTPUT->show_message('sourceisreadonly', 'warning');
  $OUTPUT->send();
    $OUTPUT->show_message('sourceisreadonly', 'warning');
    $OUTPUT->send();
}
if ($RCMAIL->action == 'group-addmembers') {
  if (($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_POST)) && ($ids = rcmail_get_cids($source))) {
    $plugin = $RCMAIL->plugins->exec_hook('group_addmembers', array('group_id' => $gid, 'ids' => $ids, 'source' => $source));
    if (($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_POST)) && ($ids = rcmail_get_cids($source))) {
        $plugin = $RCMAIL->plugins->exec_hook('group_addmembers', array(
            'group_id' => $gid,
            'ids'      => $ids,
            'source'   => $source,
        ));
    $CONTACTS->set_group($gid);
    $num2add = count($plugin['ids']);
        $CONTACTS->set_group($gid);
        $num2add = count($plugin['ids']);
    if (!$plugin['abort']) {
      if (($maxnum = $RCMAIL->config->get('max_group_members', 0)) && ($CONTACTS->count()->count + $num2add > $maxnum)) {
        $OUTPUT->show_message('maxgroupmembersreached', 'warning', array('max' => $maxnum));
        $OUTPUT->send();
      }
      $result = $CONTACTS->add_to_group($gid, $plugin['ids']);
        if (!$plugin['abort']) {
            if (($maxnum = $RCMAIL->config->get('max_group_members', 0)) && ($CONTACTS->count()->count + $num2add > $maxnum)) {
                $OUTPUT->show_message('maxgroupmembersreached', 'warning', array('max' => $maxnum));
                $OUTPUT->send();
            }
            $result = $CONTACTS->add_to_group($gid, $plugin['ids']);
        }
        else {
            $result = $plugin['result'];
        }
        if ($result)
            $OUTPUT->show_message('contactaddedtogroup');
        else if ($plugin['abort'] || $CONTACTS->get_error())
            $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
        else
            $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'nogroupassignmentschanged');
    }
    else {
      $result = $plugin['result'];
    }
    if ($result)
      $OUTPUT->show_message('contactaddedtogroup');
    else if ($plugin['abort'] || $CONTACTS->get_error())
      $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
    else
      $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'nogroupassignmentschanged');
  }
}
else if ($RCMAIL->action == 'group-delmembers') {
  if (($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_POST)) && ($ids = rcmail_get_cids($source))) {
    $plugin = $RCMAIL->plugins->exec_hook('group_delmembers', array('group_id' => $gid, 'ids' => $ids, 'source' => $source));
    if (($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_POST)) && ($ids = rcmail_get_cids($source))) {
        $plugin = $RCMAIL->plugins->exec_hook('group_delmembers', array(
            'group_id' => $gid,
            'ids'      => $ids,
            'source'   => $source,
        ));
    if (!$plugin['abort'])
      $result = $CONTACTS->remove_from_group($gid, $plugin['ids']);
    else
      $result = $plugin['result'];
        if (!$plugin['abort'])
            $result = $CONTACTS->remove_from_group($gid, $plugin['ids']);
        else
            $result = $plugin['result'];
    if ($result) {
      $OUTPUT->show_message('contactremovedfromgroup');
      $OUTPUT->command('remove_group_contacts',array('source' => $source, 'gid' => $gid));
        if ($result) {
            $OUTPUT->show_message('contactremovedfromgroup');
            $OUTPUT->command('remove_group_contacts',array('source' => $source, 'gid' => $gid));
        }
        else {
            $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
        }
    }
}
else if ($RCMAIL->action == 'group-create') {
    if ($name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true))) {
        $plugin = $RCMAIL->plugins->exec_hook('group_create', array(
            'name'   => $name,
            'source' => $source,
        ));
        if (!$plugin['abort'])
            $created = $CONTACTS->create_group($plugin['name']);
        else
            $created = $plugin['result'];
    }
    if ($created && $OUTPUT->ajax_call) {
        $created['name'] = rcube::Q($created['name']);
        $OUTPUT->show_message('groupcreated', 'confirmation');
        $OUTPUT->command('insert_contact_group', array('source' => $source) + $created);
    }
    else if (!$created) {
        $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
    }
}
else if ($RCMAIL->action == 'group-rename') {
    if (($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_POST))
        && ($name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true)))
    ) {
        $plugin = $RCMAIL->plugins->exec_hook('group_rename', array(
            'group_id' => $gid,
            'name'     => $name,
            'source'   => $source,
        ));
        if (!$plugin['abort'])
            $newname = $CONTACTS->rename_group($gid, $plugin['name'], $newgid);
        else
            $newname = $plugin['result'];
    }
    if ($newname && $OUTPUT->ajax_call) {
        $OUTPUT->show_message('grouprenamed', 'confirmation');
        $OUTPUT->command('update_contact_group', array(
            'source' => $source, 'id' => $gid, 'name' => rcube::Q($newname), 'newid' => $newgid));
    }
    else if (!$newname) {
        $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
    }
}
else if ($RCMAIL->action == 'group-delete') {
    if ($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_POST)) {
        $plugin = $RCMAIL->plugins->exec_hook('group_delete', array(
            'group_id' => $gid,
            'source'   => $source,
        ));
        if (!$plugin['abort'])
            $deleted = $CONTACTS->delete_group($gid);
        else
            $deleted = $plugin['result'];
    }
    if ($deleted) {
        $OUTPUT->show_message('groupdeleted', 'confirmation');
        $OUTPUT->command('remove_group_item', array('source' => $source, 'id' => $gid));
    }
    else {
      $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
        $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
    }
  }
}
else if ($RCMAIL->action == 'group-create') {
  if ($name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true))) {
    $plugin = $RCMAIL->plugins->exec_hook('group_create', array('name' => $name, 'source' => $source));
    if (!$plugin['abort'])
      $created = $CONTACTS->create_group($plugin['name']);
    else
      $created = $plugin['result'];
  }
  if ($created && $OUTPUT->ajax_call) {
    $created['name'] = rcube::Q($created['name']);
    $OUTPUT->show_message('groupcreated', 'confirmation');
    $OUTPUT->command('insert_contact_group', array('source' => $source) + $created);
  }
  else if (!$created) {
    $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
  }
}
else if ($RCMAIL->action == 'group-rename') {
  if (($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_POST)) && ($name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true)))) {
    $plugin = $RCMAIL->plugins->exec_hook('group_rename', array('group_id' => $gid, 'name' => $name, 'source' => $source));
    if (!$plugin['abort'])
      $newname = $CONTACTS->rename_group($gid, $plugin['name'], $newgid);
    else
      $newname = $plugin['result'];
  }
  if ($newname && $OUTPUT->ajax_call) {
    $OUTPUT->show_message('grouprenamed', 'confirmation');
    $OUTPUT->command('update_contact_group', array(
      'source' => $source, 'id' => $gid, 'name' => rcube::Q($newname), 'newid' => $newgid));
  }
  else if (!$newname)
    $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
}
else if ($RCMAIL->action == 'group-delete') {
  if ($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_POST)) {
    $plugin = $RCMAIL->plugins->exec_hook('group_delete', array('group_id' => $gid, 'source' => $source));
    if (!$plugin['abort'])
      $deleted = $CONTACTS->delete_group($gid);
    else
      $deleted = $plugin['result'];
  }
  if ($deleted) {
    $OUTPUT->show_message('groupdeleted', 'confirmation');
    $OUTPUT->command('remove_group_item', array('source' => $source, 'id' => $gid));
  }
  else
    $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error');
}
// send response
$OUTPUT->send();
program/steps/addressbook/import.inc
@@ -5,7 +5,7 @@
 | program/steps/addressbook/import.inc                                  |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2008-2009, The Roundcube Dev Team                       |
 | 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.                |
@@ -25,69 +25,70 @@
 */
function rcmail_import_form($attrib)
{
  global $RCMAIL, $OUTPUT;
  $target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC);
    global $RCMAIL, $OUTPUT;
  $attrib += array('id' => "rcmImportForm");
    $target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC);
  $writable_books = $RCMAIL->get_address_sources(true, true);
    $attrib += array('id' => "rcmImportForm");
  $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));
    $writable_books = $RCMAIL->get_address_sources(true, true);
  // addressbook selector
  if (count($writable_books) > 1) {
    $select = new html_select(array('name' => '_target', 'id' => 'rcmimporttarget', 'is_escaped' => 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));
    foreach ($writable_books as $book)
        $select->add($book['name'], $book['id']);
    // addressbook selector
    if (count($writable_books) > 1) {
        $select = new html_select(array('name' => '_target', 'id' => 'rcmimporttarget', 'is_escaped' => true));
    $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();
  }
        foreach ($writable_books as $book) {
            $select->add($book['name'], $book['id']);
        }
  // 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('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();
    }
    $table->add('title', html::label('rcmimportgroups', $RCMAIL->gettext('importgroups')));
    $table->add(null, $select->show(rcube_utils::get_input_value('_groups', rcube_utils::INPUT_GPC)));
  }
    // 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');
  // 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)));
        $table->add('title', html::label('rcmimportgroups', $RCMAIL->gettext('importgroups')));
        $table->add(null, $select->show(rcube_utils::get_input_value('_groups', rcube_utils::INPUT_GPC)));
    }
  $form .= $table->show(array('id' => null) + $attrib);
    // 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)));
  $OUTPUT->set_env('writable_source', !empty($writable_books));
  $OUTPUT->add_label('selectimportfile','importwait');
  $OUTPUT->add_gui_object('importform', $attrib['id']);
    $form .= $table->show(array('id' => null) + $attrib);
  $out = html::p(null, rcube::Q($RCMAIL->gettext('importdesc'), 'show'));
    $OUTPUT->set_env('writable_source', !empty($writable_books));
    $OUTPUT->add_label('selectimportfile','importwait');
    $OUTPUT->add_gui_object('importform', $attrib['id']);
  $out .= $OUTPUT->form_tag(array(
      'action' => $RCMAIL->url('import'),
      'method' => 'post',
      'enctype' => 'multipart/form-data') + $attrib,
    $form);
    $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;
    return $out;
}
@@ -96,30 +97,31 @@
 */
function rcmail_import_confirm($attrib)
{
  global $IMPORT_STATS, $RCMAIL;
    global $IMPORT_STATS, $RCMAIL;
  $vars = get_object_vars($IMPORT_STATS);
  $vars['names'] = $vars['skipped_names'] = '';
    $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 ? ':' : '.'));
    $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->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,
        )) . ':');
      $content .= html::p('em', join(', ', array_map('Q', $IMPORT_STATS->skipped_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);
    return html::div($attrib, $content);
}
@@ -128,24 +130,25 @@
 */
function rcmail_import_buttons($attrib)
{
  global $IMPORT_STATS, $OUTPUT;
  $target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC);
    global $IMPORT_STATS, $OUTPUT;
  $attrib += array('type' => 'input');
  unset($attrib['name']);
    $target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC);
  if (is_object($IMPORT_STATS)) {
    $attrib['class'] = trim($attrib['class'] . ' mainaction');
    $out = $OUTPUT->button(array('command' => 'list', 'prop' => $target, 'label' => 'done') + $attrib);
  }
  else {
    $out = $OUTPUT->button(array('command' => 'list', 'label' => 'cancel') + $attrib);
    $out .= '&nbsp;';
    $attrib['class'] = trim($attrib['class'] . ' mainaction');
    $out .= $OUTPUT->button(array('command' => 'import', 'label' => 'import') + $attrib);
  }
    $attrib += array('type' => 'input');
    unset($attrib['name']);
  return $out;
    if (is_object($IMPORT_STATS)) {
        $attrib['class'] = trim($attrib['class'] . ' mainaction');
        $out = $OUTPUT->button(array('command' => 'list', 'prop' => $target, 'label' => 'done') + $attrib);
    }
    else {
        $out = $OUTPUT->button(array('command' => 'list', 'label' => 'cancel') + $attrib);
        $out .= '&nbsp;';
        $attrib['class'] = trim($attrib['class'] . ' mainaction');
        $out .= $OUTPUT->button(array('command' => 'import', 'label' => 'import') + $attrib);
    }
    return $out;
}
@@ -334,8 +337,8 @@
$OUTPUT->set_pagetitle($RCMAIL->gettext('importcontacts'));
$OUTPUT->add_handlers(array(
  'importstep' => $importstep,
  'importnav' => 'rcmail_import_buttons',
    'importstep' => $importstep,
    'importnav'  => 'rcmail_import_buttons',
));
// render page
program/steps/addressbook/mailto.inc
@@ -39,10 +39,10 @@
{
    $source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
    $CONTACTS = $RCMAIL->get_address_book($source);
    $group_id = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_GPC);
    $group_data = $CONTACTS->get_group($group_id);
    // group has an email address assigned: use that
    if ($group_data['email']) {
        $mailto[] = format_email_recipient($group_data['email'][0], $group_data['name']);
program/steps/addressbook/save.inc
@@ -5,7 +5,7 @@
 | program/steps/addressbook/save.inc                                    |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2011, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -19,80 +19,87 @@
 +-----------------------------------------------------------------------+
*/
$CONTACTS = rcmail_contact_source(null, true, true);
$cid      = rcube_utils::get_input_value('_cid', rcube_utils::INPUT_POST);
$CONTACTS      = rcmail_contact_source(null, true, true);
$cid           = rcube_utils::get_input_value('_cid', rcube_utils::INPUT_POST);
$return_action = empty($cid) ? 'add' : 'edit';
// Source changed, display the form again
if (!empty($_GET['_reload'])) {
   $RCMAIL->overwrite_action($return_action);
   return;
    $RCMAIL->overwrite_action($return_action);
    return;
}
// cannot edit record
if ($CONTACTS->readonly) {
  $OUTPUT->show_message('contactreadonly', 'error');
  $RCMAIL->overwrite_action($return_action);
  return;
    $OUTPUT->show_message('contactreadonly', 'error');
    $RCMAIL->overwrite_action($return_action);
    return;
}
// read POST values into hash array
$a_record = array();
foreach ($GLOBALS['CONTACT_COLTYPES'] as $col => $colprop) {
  $fname = '_'.$col;
  if ($colprop['composite'])
    continue;
  // gather form data of composite fields
  if ($colprop['childs']) {
    $values = array();
    foreach ($colprop['childs'] as $childcol => $cp) {
      $vals = rcube_utils::get_input_value('_'.$childcol, rcube_utils::INPUT_POST, true);
      foreach ((array)$vals as $i => $val)
        $values[$i][$childcol] = $val;
    if ($colprop['composite']) {
        continue;
    }
    $subtypes = isset($_REQUEST['_subtype_' . $col]) ? (array)rcube_utils::get_input_value('_subtype_' . $col, rcube_utils::INPUT_POST) : array('');
    foreach ($subtypes as $i => $subtype) {
      $suffix = $subtype ? ':'.$subtype : '';
      if ($values[$i])
        $a_record[$col.$suffix][] = $values[$i];
     }
  }
  // assign values and subtypes
  else if (is_array($_POST[$fname])) {
    $values   = rcube_utils::get_input_value($fname, rcube_utils::INPUT_POST, true);
    $subtypes = rcube_utils::get_input_value('_subtype_' . $col, rcube_utils::INPUT_POST);
    foreach ($values as $i => $val) {
      if ($col == 'email') {
        // extract email from full address specification, e.g. "Name" <addr@domain.tld>
        $addr = rcube_mime::decode_address_list($val, 1, false);
        if (!empty($addr) && ($addr = array_pop($addr)) && $addr['mailto']) {
          $val = $addr['mailto'];
    $fname = '_'.$col;
    // gather form data of composite fields
    if ($colprop['childs']) {
        $values = array();
        foreach ($colprop['childs'] as $childcol => $cp) {
            $vals = rcube_utils::get_input_value('_'.$childcol, rcube_utils::INPUT_POST, true);
            foreach ((array)$vals as $i => $val) {
                $values[$i][$childcol] = $val;
            }
        }
      }
      $subtype = $subtypes[$i] ? ':'.$subtypes[$i] : '';
      $a_record[$col.$subtype][] = $val;
    }
  }
  else if (isset($_POST[$fname])) {
    $a_record[$col] = rcube_utils::get_input_value($fname, rcube_utils::INPUT_POST, true);
    // normalize the submitted date strings
    if ($colprop['type'] == 'date') {
        if ($a_record[$col] && ($dt = rcube_utils::anytodatetime($a_record[$col]))) {
            $a_record[$col] = $dt->format('Y-m-d');
        }
        else {
            unset($a_record[$col]);
        $subtypes = isset($_REQUEST['_subtype_' . $col]) ? (array)rcube_utils::get_input_value('_subtype_' . $col, rcube_utils::INPUT_POST) : array('');
        foreach ($subtypes as $i => $subtype) {
            $suffix = $subtype ? ':'.$subtype : '';
            if ($values[$i]) {
                $a_record[$col.$suffix][] = $values[$i];
            }
        }
    }
  }
    // assign values and subtypes
    else if (is_array($_POST[$fname])) {
        $values   = rcube_utils::get_input_value($fname, rcube_utils::INPUT_POST, true);
        $subtypes = rcube_utils::get_input_value('_subtype_' . $col, rcube_utils::INPUT_POST);
        foreach ($values as $i => $val) {
            if ($col == 'email') {
                // extract email from full address specification, e.g. "Name" <addr@domain.tld>
                $addr = rcube_mime::decode_address_list($val, 1, false);
                if (!empty($addr) && ($addr = array_pop($addr)) && $addr['mailto']) {
                    $val = $addr['mailto'];
                }
            }
            $subtype = $subtypes[$i] ? ':'.$subtypes[$i] : '';
            $a_record[$col.$subtype][] = $val;
        }
    }
    else if (isset($_POST[$fname])) {
        $a_record[$col] = rcube_utils::get_input_value($fname, rcube_utils::INPUT_POST, true);
        // normalize the submitted date strings
        if ($colprop['type'] == 'date') {
            if ($a_record[$col] && ($dt = rcube_utils::anytodatetime($a_record[$col]))) {
                $a_record[$col] = $dt->format('Y-m-d');
            }
            else {
                unset($a_record[$col]);
            }
        }
    }
}
// Generate contact's display name (must be before validation)
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())
    $email = rcube_addressbook::get_col_values('email', $a_record, true);
    if ($a_record['name'] == $email[0]) {
@@ -130,120 +137,122 @@
$source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
// update an existing contact
if (!empty($cid))
{
  $plugin = $RCMAIL->plugins->exec_hook('contact_update',
    array('id' => $cid, 'record' => $a_record, 'source' => $source));
  $a_record = $plugin['record'];
if (!empty($cid)) {
    $plugin = $RCMAIL->plugins->exec_hook('contact_update',
        array('id' => $cid, 'record' => $a_record, 'source' => $source));
    $a_record = $plugin['record'];
  if (!$plugin['abort'])
    $result = $CONTACTS->update($cid, $a_record);
  else
    $result = $plugin['result'];
    if (!$plugin['abort'])
        $result = $CONTACTS->update($cid, $a_record);
    else
        $result = $plugin['result'];
  if ($result) {
    // LDAP DN change
    if (is_string($result) && strlen($result)>1) {
      $newcid = $result;
      // change cid in POST for 'show' action
      $_POST['_cid'] = $newcid;
    if ($result) {
        // LDAP DN change
        if (is_string($result) && strlen($result)>1) {
            $newcid = $result;
            // change cid in POST for 'show' action
            $_POST['_cid'] = $newcid;
        }
        // define list of cols to be displayed
        $a_js_cols = array();
        $record = $CONTACTS->get_record($newcid ? $newcid : $cid, true);
        $record['email'] = reset($CONTACTS->get_col_values('email', $record, true));
        $record['name']  = rcube_addressbook::compose_list_name($record);
        foreach (array('name') as $col) {
            $a_js_cols[] = rcube::Q((string)$record[$col]);
        }
        // update the changed col in list
        $OUTPUT->command('parent.update_contact_row', $cid, $a_js_cols, $newcid, $source, $record);
        // show confirmation
        $OUTPUT->show_message('successfullysaved', 'confirmation', null, false);
        $RCMAIL->overwrite_action('show');
    }
    // define list of cols to be displayed
    $a_js_cols = array();
    $record = $CONTACTS->get_record($newcid ? $newcid : $cid, true);
    $record['email'] = reset($CONTACTS->get_col_values('email', $record, true));
    $record['name']  = rcube_addressbook::compose_list_name($record);
    foreach (array('name') as $col)
      $a_js_cols[] = rcube::Q((string)$record[$col]);
    // update the changed col in list
    $OUTPUT->command('parent.update_contact_row', $cid, $a_js_cols, $newcid, $source, $record);
    // show confirmation
    $OUTPUT->show_message('successfullysaved', 'confirmation', null, false);
    $RCMAIL->overwrite_action('show');
  }
  else {
    // show error message
    $err = $CONTACTS->get_error();
    $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : ($err['message'] ? $err['message'] : 'errorsaving'), 'error', null, false);
    $RCMAIL->overwrite_action('show');
  }
    else {
        // show error message
        $err = $CONTACTS->get_error();
        $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : ($err['message'] ? $err['message'] : 'errorsaving'), 'error', null, false);
        $RCMAIL->overwrite_action('show');
    }
}
// insert a new contact
else {
  // Name of the addressbook already selected on the list
  $orig_source = rcube_utils::get_input_value('_orig_source', rcube_utils::INPUT_GPC);
    // Name of the addressbook already selected on the list
    $orig_source = rcube_utils::get_input_value('_orig_source', rcube_utils::INPUT_GPC);
  if (!strlen($source))
    $source = $orig_source;
  // show notice if existing contacts with same e-mail are found
  foreach ($CONTACTS->get_col_values('email', $a_record, true) as $email) {
      if ($email && ($res = $CONTACTS->search('email', $email, 1, false, true)) && $res->count) {
          $OUTPUT->show_message('contactexists', 'notice', null, false);
          break;
      }
  }
  $plugin = $RCMAIL->plugins->exec_hook('contact_create', array(
    'record' => $a_record, 'source' => $source));
  $a_record = $plugin['record'];
  // insert record and send response
  if (!$plugin['abort'])
    $insert_id = $CONTACTS->insert($a_record);
  else
    $insert_id = $plugin['result'];
  if ($insert_id) {
    $CONTACTS->reset();
    // add new contact to the specified group
    if ($CONTACTS->groups && $CONTACTS->group_id) {
      $plugin = $RCMAIL->plugins->exec_hook('group_addmembers', array(
        'group_id' => $CONTACTS->group_id, 'ids' => $insert_id, 'source' => $source));
      $counts = $CONTACTS->count();
      if (!$plugin['abort']) {
        if (($maxnum = $RCMAIL->config->get('max_group_members', 0)) && ($counts->count + 1 > $maxnum))
          $OUTPUT->show_message('maxgroupmembersreached', 'warning', array('max' => $maxnum));
        $CONTACTS->add_to_group($plugin['group_id'], $plugin['ids']);
      }
    if (!strlen($source)) {
        $source = $orig_source;
    }
    // show notice if existing contacts with same e-mail are found
    foreach ($CONTACTS->get_col_values('email', $a_record, true) as $email) {
        if ($email && ($res = $CONTACTS->search('email', $email, 1, false, true)) && $res->count) {
            $OUTPUT->show_message('contactexists', 'notice', null, false);
            break;
        }
    }
    $plugin = $RCMAIL->plugins->exec_hook('contact_create', array(
        'record' => $a_record, 'source' => $source));
    $a_record = $plugin['record'];
    // insert record and send response
    if (!$plugin['abort'])
        $insert_id = $CONTACTS->insert($a_record);
    else
      $counts = $CONTACTS->count();
        $insert_id = $plugin['result'];
    if ((string)$source === (string)$orig_source) {
      // add contact row or jump to the page where it should appear
      $CONTACTS->reset();
      $result = $CONTACTS->search($CONTACTS->primary_key, $insert_id);
    if ($insert_id) {
        $CONTACTS->reset();
      rcmail_js_contacts_list($result, 'parent.');
      $OUTPUT->command('parent.contact_list.select', rcube_utils::html_identifier($insert_id));
        // add new contact to the specified group
        if ($CONTACTS->groups && $CONTACTS->group_id) {
            $plugin = $RCMAIL->plugins->exec_hook('group_addmembers', array(
                'group_id' => $CONTACTS->group_id, 'ids' => $insert_id, 'source' => $source));
      // update record count display
      $CONTACTS->reset();
      $OUTPUT->command('parent.set_rowcount', rcmail_get_rowcount_text($counts));
            $counts = $CONTACTS->count();
            if (!$plugin['abort']) {
                if (($maxnum = $RCMAIL->config->get('max_group_members', 0)) && ($counts->count + 1 > $maxnum))
                    $OUTPUT->show_message('maxgroupmembersreached', 'warning', array('max' => $maxnum));
                $CONTACTS->add_to_group($plugin['group_id'], $plugin['ids']);
            }
        }
        else {
            $counts = $CONTACTS->count();
        }
        if ((string)$source === (string)$orig_source) {
            // add contact row or jump to the page where it should appear
            $CONTACTS->reset();
            $result = $CONTACTS->search($CONTACTS->primary_key, $insert_id);
            rcmail_js_contacts_list($result, 'parent.');
            $OUTPUT->command('parent.contact_list.select', rcube_utils::html_identifier($insert_id));
            // update record count display
            $CONTACTS->reset();
            $OUTPUT->command('parent.set_rowcount', rcmail_get_rowcount_text($counts));
        }
        else {
            // re-set iframe
            $OUTPUT->command('parent.show_contentframe');
        }
        // show confirmation
        $OUTPUT->show_message('successfullysaved', 'confirmation', null, false);
        $OUTPUT->send('iframe');
    }
    else {
      // re-set iframe
      $OUTPUT->command('parent.show_contentframe');
        // show error message
        $err = $CONTACTS->get_error();
        $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : ($err['message'] ? $err['message'] : 'errorsaving'), 'error', null, false);
        $RCMAIL->overwrite_action('add');
    }
    // show confirmation
    $OUTPUT->show_message('successfullysaved', 'confirmation', null, false);
    $OUTPUT->send('iframe');
  }
  else {
    // show error message
    $err = $CONTACTS->get_error();
    $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : ($err['message'] ? $err['message'] : 'errorsaving'), 'error', null, false);
    $RCMAIL->overwrite_action('add');
  }
}
program/steps/mail/addcontact.inc
@@ -5,7 +5,7 @@
 | program/steps/mail/addcontact.inc                                     |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2009, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -20,69 +20,74 @@
*/
// only process ajax requests
if (!$OUTPUT->ajax_call)
  return;
if (!$OUTPUT->ajax_call) {
    return;
}
// Get default addressbook
$CONTACTS = $RCMAIL->get_address_book(-1, true);
if (!empty($_POST['_address']) && is_object($CONTACTS))
{
  $contact_arr = rcube_mime::decode_address_list(rcube_utils::get_input_value('_address', rcube_utils::INPUT_POST, true), 1, false);
if (!empty($_POST['_address']) && is_object($CONTACTS)) {
    $address = rcube_utils::get_input_value('_address', rcube_utils::INPUT_POST, true);
    $contact_arr = rcube_mime::decode_address_list($address, 1, false);
  if (!empty($contact_arr[1]['mailto'])) {
    $contact = array(
      'email' => $contact_arr[1]['mailto'],
      'name' => $contact_arr[1]['name']
    );
    if (!empty($contact_arr[1]['mailto'])) {
        $contact = array(
            'email' => $contact_arr[1]['mailto'],
            'name'  => $contact_arr[1]['name'],
        );
    // Validity checks
    if (empty($contact['email'])) {
      $OUTPUT->show_message('errorsavingcontact', 'error');
      $OUTPUT->send();
        // Validity checks
        if (empty($contact['email'])) {
            $OUTPUT->show_message('errorsavingcontact', 'error');
            $OUTPUT->send();
        }
        $email = rcube_utils::idn_to_ascii($contact['email']);
        if (!rcube_utils::check_email($email, false)) {
            $OUTPUT->show_message('emailformaterror', 'error', array('email' => $contact['email']));
            $OUTPUT->send();
        }
        $contact['email'] = rcube_utils::idn_to_utf8($contact['email']);
        $contact = $RCMAIL->plugins->exec_hook('contact_displayname', $contact);
        if (empty($contact['firstname']) || empty($contact['surname'])) {
            $contact['name'] = rcube_addressbook::compose_display_name($contact);
        }
        // validate contact record
        if (!$CONTACTS->validate($contact, true)) {
            $error = $CONTACTS->get_error();
            // TODO: show dialog to complete record
            // if ($error['type'] == rcube_addressbook::ERROR_VALIDATE) { }
            $OUTPUT->show_message($error['message'] ? $error['message'] : 'errorsavingcontact', 'error');
            $OUTPUT->send();
        }
        // check for existing contacts
        $existing = $CONTACTS->search('email', $contact['email'], 1, false);
        if ($done = $existing->count) {
            $OUTPUT->show_message('contactexists', 'warning');
        }
        else {
            $plugin = $RCMAIL->plugins->exec_hook('contact_create', array('record' => $contact, 'source' => null));
            $contact = $plugin['record'];
            $done = !$plugin['abort'] ? $CONTACTS->insert($contact) : $plugin['result'];
            if ($done) {
                $OUTPUT->show_message('addedsuccessfully', 'confirmation');
            }
        }
    }
    $email = rcube_utils::idn_to_ascii($contact['email']);
    if (!rcube_utils::check_email($email, false)) {
      $OUTPUT->show_message('emailformaterror', 'error', array('email' => $contact['email']));
      $OUTPUT->send();
    }
    $contact['email'] = rcube_utils::idn_to_utf8($contact['email']);
    $contact = $RCMAIL->plugins->exec_hook('contact_displayname', $contact);
    if (empty($contact['firstname']) || empty($contact['surname']))
      $contact['name'] = rcube_addressbook::compose_display_name($contact);
    // validate contact record
    if (!$CONTACTS->validate($contact, true)) {
      $error = $CONTACTS->get_error();
      // TODO: show dialog to complete record
      // if ($error['type'] == rcube_addressbook::ERROR_VALIDATE) { }
      $OUTPUT->show_message($error['message'] ? $error['message'] : 'errorsavingcontact', 'error');
      $OUTPUT->send();
    }
    // check for existing contacts
    $existing = $CONTACTS->search('email', $contact['email'], 1, false);
    if ($done = $existing->count)
      $OUTPUT->show_message('contactexists', 'warning');
    else {
      $plugin = $RCMAIL->plugins->exec_hook('contact_create', array('record' => $contact, 'source' => null));
      $contact = $plugin['record'];
      $done = !$plugin['abort'] ? $CONTACTS->insert($contact) : $plugin['result'];
      if ($done)
        $OUTPUT->show_message('addedsuccessfully', 'confirmation');
    }
  }
}
if (!$done)
  $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsavingcontact', 'error');
if (!$done) {
    $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsavingcontact', 'error');
}
$OUTPUT->send();
program/steps/mail/attachments.inc
@@ -5,7 +5,7 @@
 | program/steps/mail/attachments.inc                                    |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2009, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -21,62 +21,73 @@
// Upload progress update
if (!empty($_GET['_progress'])) {
  $RCMAIL->upload_progress();
    $RCMAIL->upload_progress();
}
$COMPOSE_ID = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
$COMPOSE    = null;
if ($COMPOSE_ID && $_SESSION['compose_data_' . $COMPOSE_ID]) {
  $SESSION_KEY = 'compose_data_' . $COMPOSE_ID;
  $COMPOSE =& $_SESSION[$SESSION_KEY];
    $SESSION_KEY = 'compose_data_' . $COMPOSE_ID;
    $COMPOSE =& $_SESSION[$SESSION_KEY];
}
if (!$COMPOSE) {
  die("Invalid session var!");
    die("Invalid session var!");
}
// remove an attachment
if ($RCMAIL->action=='remove-attachment')
{
  $id = 'undefined';
  if (preg_match('/^rcmfile(\w+)$/', $_POST['_file'], $regs))
    $id = $regs[1];
  if ($attachment = $COMPOSE['attachments'][$id])
    $attachment = $RCMAIL->plugins->exec_hook('attachment_delete', $attachment);
  if ($attachment['status']) {
    if (is_array($COMPOSE['attachments'][$id])) {
      $RCMAIL->session->remove($SESSION_KEY.'.attachments.'.$id);
      $OUTPUT->command('remove_from_attachment_list', "rcmfile$id");
    }
  }
if ($RCMAIL->action=='remove-attachment') {
    $id = 'undefined';
  $OUTPUT->send();
  exit;
    if (preg_match('/^rcmfile(\w+)$/', $_POST['_file'], $regs)) {
        $id = $regs[1];
    }
    if ($attachment = $COMPOSE['attachments'][$id]) {
        $attachment = $RCMAIL->plugins->exec_hook('attachment_delete', $attachment);
    }
    if ($attachment['status']) {
        if (is_array($COMPOSE['attachments'][$id])) {
            $RCMAIL->session->remove($SESSION_KEY.'.attachments.'.$id);
            $OUTPUT->command('remove_from_attachment_list', "rcmfile$id");
        }
    }
    $OUTPUT->send();
    exit;
}
if ($RCMAIL->action=='display-attachment')
{
  $id = 'undefined';
  if (preg_match('/^rcmfile(\w+)$/', $_GET['_file'], $regs))
    $id = $regs[1];
  if ($attachment = $COMPOSE['attachments'][$id])
    $attachment = $RCMAIL->plugins->exec_hook('attachment_display', $attachment);
if ($RCMAIL->action=='display-attachment') {
    $id = 'undefined';
  if ($attachment['status']) {
    if (empty($attachment['size']))
      $attachment['size'] = $attachment['data'] ? strlen($attachment['data']) : @filesize($attachment['path']);
    if (preg_match('/^rcmfile(\w+)$/', $_GET['_file'], $regs)) {
        $id = $regs[1];
    }
    header('Content-Type: ' . $attachment['mimetype']);
    header('Content-Length: ' . $attachment['size']);
    if ($attachment = $COMPOSE['attachments'][$id]) {
        $attachment = $RCMAIL->plugins->exec_hook('attachment_display', $attachment);
    }
    if ($attachment['data'])
      echo $attachment['data'];
    else if ($attachment['path'])
      readfile($attachment['path']);
  }
  exit;
    if ($attachment['status']) {
        if (empty($attachment['size'])) {
            $attachment['size'] = $attachment['data'] ? strlen($attachment['data']) : @filesize($attachment['path']);
        }
        header('Content-Type: ' . $attachment['mimetype']);
        header('Content-Length: ' . $attachment['size']);
        if ($attachment['data']) {
            echo $attachment['data'];
        }
        else if ($attachment['path']) {
            readfile($attachment['path']);
        }
    }
    exit;
}
/*****  attachment upload action  *****/
@@ -87,91 +98,94 @@
$uploadid = rcube_utils::get_input_value('_uploadid', rcube_utils::INPUT_GET);
if (is_array($_FILES['_attachments']['tmp_name'])) {
  $multiple = count($_FILES['_attachments']['tmp_name']) > 1;
    $multiple = count($_FILES['_attachments']['tmp_name']) > 1;
  foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
    // Process uploaded attachment if there is no error
    $err = $_FILES['_attachments']['error'][$i];
    foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
        // Process uploaded attachment if there is no error
        $err = $_FILES['_attachments']['error'][$i];
    if (!$err) {
      $attachment = array(
        'path' => $filepath,
        'size' => $_FILES['_attachments']['size'][$i],
        'name' => $_FILES['_attachments']['name'][$i],
        'mimetype' => rcube_mime::file_content_type($filepath, $_FILES['_attachments']['name'][$i], $_FILES['_attachments']['type'][$i]),
        'group' => $COMPOSE_ID,
      );
        if (!$err) {
            $attachment = $RCMAIL->plugins->exec_hook('attachment_upload', array(
                'path' => $filepath,
                'size' => $_FILES['_attachments']['size'][$i],
                'name' => $_FILES['_attachments']['name'][$i],
                'mimetype' => rcube_mime::file_content_type($filepath, $_FILES['_attachments']['name'][$i], $_FILES['_attachments']['type'][$i]),
                'group' => $COMPOSE_ID,
            ));
        }
      $attachment = $RCMAIL->plugins->exec_hook('attachment_upload', $attachment);
        if (!$err && $attachment['status'] && !$attachment['abort']) {
            $id = $attachment['id'];
            // store new attachment in session
            unset($attachment['status'], $attachment['abort']);
            $RCMAIL->session->append($SESSION_KEY.'.attachments', $id, $attachment);
            if (($icon = $COMPOSE['deleteicon']) && is_file($icon)) {
                $button = html::img(array(
                    'src' => $icon,
                    'alt' => $RCMAIL->gettext('delete')
                ));
            }
            else if ($COMPOSE['textbuttons']) {
                $button = rcube::Q($RCMAIL->gettext('delete'));
            }
            else {
                $button = '';
            }
            $content = html::a(array(
                'href'    => "#delete",
                'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", rcmail_output::JS_OBJECT_NAME, $id),
                'title'   => $RCMAIL->gettext('delete'),
                'class'   => 'delete',
            ), $button);
            $content .= rcube::Q($attachment['name']);
            $OUTPUT->command('add2attachment_list', "rcmfile$id", array(
                'html'      => $content,
                'name'      => $attachment['name'],
                'mimetype'  => $attachment['mimetype'],
                'classname' => rcube_utils::file2class($attachment['mimetype'], $attachment['name']),
                'complete'  => true), $uploadid);
        }
        else {  // upload failed
            if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
                $size = $RCMAIL->show_bytes(parse_bytes(ini_get('upload_max_filesize')));
                $msg  = $RCMAIL->gettext(array('name' => 'filesizeerror', 'vars' => array('size' => $size)));
            }
            else if ($attachment['error']) {
                $msg = $attachment['error'];
            }
            else {
                $msg = $RCMAIL->gettext('fileuploaderror');
            }
            if ($attachment['error'] || $err != UPLOAD_ERR_NO_FILE) {
                $OUTPUT->command('display_message', $msg, 'error');
                $OUTPUT->command('remove_from_attachment_list', $uploadid);
            }
        }
    }
    if (!$err && $attachment['status'] && !$attachment['abort']) {
      $id = $attachment['id'];
      // store new attachment in session
      unset($attachment['status'], $attachment['abort']);
      $RCMAIL->session->append($SESSION_KEY.'.attachments', $id, $attachment);
      if (($icon = $COMPOSE['deleteicon']) && is_file($icon)) {
        $button = html::img(array(
          'src' => $icon,
          'alt' => $RCMAIL->gettext('delete')
        ));
      }
      else if ($COMPOSE['textbuttons']) {
        $button = rcube::Q($RCMAIL->gettext('delete'));
      }
      else {
        $button = '';
      }
      $content = html::a(array(
        'href' => "#delete",
        'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", rcmail_output::JS_OBJECT_NAME, $id),
        'title' => $RCMAIL->gettext('delete'),
        'class' => 'delete',
      ), $button);
      $content .= rcube::Q($attachment['name']);
      $OUTPUT->command('add2attachment_list', "rcmfile$id", array(
        'html' => $content,
        'name' => $attachment['name'],
        'mimetype' => $attachment['mimetype'],
        'classname' => rcube_utils::file2class($attachment['mimetype'], $attachment['name']),
        'complete' => true), $uploadid);
    }
    else {  // upload failed
      if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
        $size = $RCMAIL->show_bytes(parse_bytes(ini_get('upload_max_filesize')));
        $msg  = $RCMAIL->gettext(array('name' => 'filesizeerror', 'vars' => array('size' => $size)));
      }
      else if ($attachment['error']) {
        $msg = $attachment['error'];
      }
      else {
        $msg = $RCMAIL->gettext('fileuploaderror');
      }
      if ($attachment['error'] || $err != UPLOAD_ERR_NO_FILE) {
        $OUTPUT->command('display_message', $msg, 'error');
        $OUTPUT->command('remove_from_attachment_list', $uploadid);
      }
    }
  }
}
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  // if filesize exceeds post_max_size then $_FILES array is empty,
  // show filesizeerror instead of fileuploaderror
  if ($maxsize = ini_get('post_max_size'))
    $msg = $RCMAIL->gettext(array('name' => 'filesizeerror', 'vars' => array('size' => $RCMAIL->show_bytes(parse_bytes($maxsize)))));
  else
    $msg = $RCMAIL->gettext('fileuploaderror');
  $OUTPUT->command('display_message', $msg, 'error');
  $OUTPUT->command('remove_from_attachment_list', $uploadid);
    // if filesize exceeds post_max_size then $_FILES array is empty,
    // show filesizeerror instead of fileuploaderror
    if ($maxsize = ini_get('post_max_size')) {
        $msg = $RCMAIL->gettext(array(
            'name' => 'filesizeerror',
            'vars' => array('size' => $RCMAIL->show_bytes(parse_bytes($maxsize)))
        ));
    }
    else {
        $msg = $RCMAIL->gettext('fileuploaderror');
    }
    $OUTPUT->command('display_message', $msg, 'error');
    $OUTPUT->command('remove_from_attachment_list', $uploadid);
}
// send html page with JS calls as response
$OUTPUT->command('auto_save_start', false);
$OUTPUT->send('iframe');
program/steps/mail/autocomplete.inc
@@ -5,8 +5,8 @@
 | program/steps/mail/autocomplete.inc                                   |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2008-2011, Roundcube Dev Team                           |
 | Copyright (C) 2011, Kolab Systems AG                                  |
 | Copyright (C) 2008-2013, Roundcube Dev Team                           |
 | Copyright (C) 2011-2013, Kolab Systems AG                             |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -21,24 +21,26 @@
*/
if ($RCMAIL->action == 'group-expand') {
  $abook = $RCMAIL->get_address_book(rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC));
  if ($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_GPC)) {
    $members = array();
    $abook->set_group($gid);
    $abook->set_pagesize(1000);  // TODO: limit number of group members by config
    $result = $abook->list_records($RCMAIL->config->get('contactlist_fields'));
    while ($result && ($sql_arr = $result->iterate())) {
      $emails = (array) $abook->get_col_values('email', $sql_arr, true);
      if (!empty($emails) && ($email = array_shift($emails))) {
        $members[] = format_email_recipient($email, rcube_addressbook::compose_list_name($sql_arr));
      }
    $abook = $RCMAIL->get_address_book(rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC));
    if ($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_GPC)) {
        $abook->set_group($gid);
        $abook->set_pagesize(1000);  // TODO: limit number of group members by config
        $separator = trim($RCMAIL->config->get('recipients_separator', ',')) . ' ';
        $result    = $abook->list_records($RCMAIL->config->get('contactlist_fields'));
        $members   = array();
        while ($result && ($sql_arr = $result->iterate())) {
            $emails = (array) $abook->get_col_values('email', $sql_arr, true);
            if (!empty($emails) && ($email = array_shift($emails))) {
                $members[] = format_email_recipient($email, rcube_addressbook::compose_list_name($sql_arr));
            }
        }
        $OUTPUT->command('replace_group_recipients', $gid, join($separator, array_unique($members)));
    }
    $separator = trim($RCMAIL->config->get('recipients_separator', ',')) . ' ';
    $OUTPUT->command('replace_group_recipients', $gid, join($separator, array_unique($members)));
  }
  $OUTPUT->send();
    $OUTPUT->send();
}
@@ -49,96 +51,107 @@
$source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
$sid    = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
if (strlen($source))
  $book_types = array($source);
else
  $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql');
if (strlen($source)) {
    $book_types = array($source);
}
else {
    $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql');
}
if (!empty($book_types) && strlen($search)) {
  $contacts  = array();
  $sort_keys = array();
  $books_num = count($book_types);
  $search_lc = mb_strtolower($search);
    $contacts  = array();
    $sort_keys = array();
    $books_num = count($book_types);
    $search_lc = mb_strtolower($search);
  foreach ($book_types as $id) {
    $abook = $RCMAIL->get_address_book($id);
    $abook->set_pagesize($MAXNUM);
    foreach ($book_types as $id) {
        $abook = $RCMAIL->get_address_book($id);
        $abook->set_pagesize($MAXNUM);
    if ($result = $abook->search($RCMAIL->config->get('contactlist_fields'), $search, $mode, true, true, 'email')) {
      while ($sql_arr = $result->iterate()) {
        // Contact can have more than one e-mail address
        $email_arr = (array)$abook->get_col_values('email', $sql_arr, true);
        $email_cnt = count($email_arr);
        $idx = 0;
        foreach ($email_arr as $email) {
          if (empty($email)) {
            continue;
          }
        if ($result = $abook->search($RCMAIL->config->get('contactlist_fields'), $search, $mode, true, true, 'email')) {
            while ($sql_arr = $result->iterate()) {
                // Contact can have more than one e-mail address
                $email_arr = (array)$abook->get_col_values('email', $sql_arr, true);
                $email_cnt = count($email_arr);
                $idx       = 0;
          $sql_arr['name'] = rcube_addressbook::compose_list_name($sql_arr);
          $contact = format_email_recipient($email, $sql_arr['name']);
                foreach ($email_arr as $email) {
                    if (empty($email)) {
                        continue;
                    }
          // skip entries that don't match
          if ($email_cnt > 1 && strpos(mb_strtolower($contact), $search_lc) === false) {
            continue;
          }
                    $name    = rcube_addressbook::compose_list_name($sql_arr);
                    $contact = format_email_recipient($email, $name);
          // skip duplicates
          if (!in_array($contact, $contacts)) {
            $contacts[]  = $contact;
            $sort_keys[] = sprintf('%s %03d', $sql_arr['name'] , $idx++);
                    // skip entries that don't match
                    if ($email_cnt > 1 && strpos(mb_strtolower($contact), $search_lc) === false) {
                        continue;
                    }
            if (count($contacts) >= $MAXNUM)
              break 2;
          }
                    // skip duplicates
                    if (!in_array($contact, $contacts)) {
                        $contacts[]  = $contact;
                        $sort_keys[] = sprintf('%s %03d', $sql_arr['name'] , $idx++);
          // skip redundant entries (show only first email address)
          if ($single) {
            break;
          }
        }
      }
    }
                        if (count($contacts) >= $MAXNUM) {
                            break 2;
                        }
                    }
    // also list matching contact groups
    if ($abook->groups && count($contacts) < $MAXNUM) {
      foreach ($abook->list_groups($search, $mode) as $group) {
        $abook->reset();
        $abook->set_group($group['ID']);
        $group_prop = $abook->get_group($group['ID']);
        // group (distribution list) with email address(es)
        if ($group_prop['email']) {
            $idx = 0;
            foreach ((array)$group_prop['email'] as $email) {
                $contacts[]  = format_email_recipient($email, $group['name']);
                $sort_keys[] = sprintf('%s %03d', $group['name'] , $idx++);
                if (count($contacts) >= $MAXNUM)
                  break 2;
                    // skip redundant entries (show only first email address)
                    if ($single) {
                        break;
                    }
                }
            }
        }
        // show group with count
        else if (($result = $abook->count()) && $result->count) {
          $contacts[]  = array('name' => $group['name'] . ' (' . intval($result->count) . ')', 'id' => $group['ID'], 'source' => $id);
          $sort_keys[] = $group['name'];
          if (count($contacts) >= $MAXNUM)
            break;
        // also list matching contact groups
        if ($abook->groups && count($contacts) < $MAXNUM) {
            foreach ($abook->list_groups($search, $mode) as $group) {
                $abook->reset();
                $abook->set_group($group['ID']);
                $group_prop = $abook->get_group($group['ID']);
                // group (distribution list) with email address(es)
                if ($group_prop['email']) {
                    $idx = 0;
                    foreach ((array)$group_prop['email'] as $email) {
                        $contacts[]  = format_email_recipient($email, $group['name']);
                        $sort_keys[] = sprintf('%s %03d', $group['name'] , $idx++);
                        if (count($contacts) >= $MAXNUM) {
                            break 2;
                        }
                    }
                }
                // show group with count
                else if (($result = $abook->count()) && $result->count) {
                    $sort_keys[] = $group['name'];
                    $contacts[]  = array(
                        'name'   => $group['name'] . ' (' . intval($result->count) . ')',
                        'id'     => $group['ID'],
                        'source' => $id
                    );
                    if (count($contacts) >= $MAXNUM) {
                        break;
                    }
                }
            }
        }
      }
    }
  }
  if (count($contacts)) {
    // sort contacts index
    asort($sort_keys, SORT_LOCALE_STRING);
    // re-sort contacts according to index
    foreach ($sort_keys as $idx => $val) {
      $sort_keys[$idx] = $contacts[$idx];
    if (count($contacts)) {
        // sort contacts index
        asort($sort_keys, SORT_LOCALE_STRING);
        // re-sort contacts according to index
        foreach ($sort_keys as $idx => $val) {
            $sort_keys[$idx] = $contacts[$idx];
        }
        $contacts = array_values($sort_keys);
    }
    $contacts = array_values($sort_keys);
  }
}
$OUTPUT->command('ksearch_query_results', $contacts, $search, $sid);
program/steps/mail/copy.inc
@@ -5,7 +5,7 @@
 | program/steps/mail/copy.inc                                           |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2010, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -20,8 +20,9 @@
*/
// only process ajax requests
if (!$OUTPUT->ajax_call)
  return;
if (!$OUTPUT->ajax_call) {
    return;
}
// move messages
if (!empty($_POST['_uid']) && strlen($_POST['_target_mbox'])) {
program/steps/mail/folders.inc
@@ -5,7 +5,7 @@
 | program/steps/mail/folders.inc                                        |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2009, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -20,8 +20,9 @@
*/
// only process ajax requests
if (!$OUTPUT->ajax_call)
if (!$OUTPUT->ajax_call) {
    return;
}
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
program/steps/mail/get.inc
@@ -5,7 +5,7 @@
 | program/steps/mail/get.inc                                            |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2011, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -22,15 +22,15 @@
// show loading page
if (!empty($_GET['_preload'])) {
  $url = preg_replace('/([&?]+)_preload=/', '\\1_mimewarning=1&_embed=', $_SERVER['REQUEST_URI']);
  $message = $RCMAIL->gettext('loadingdata');
    $url = preg_replace('/([&?]+)_preload=/', '\\1_mimewarning=1&_embed=', $_SERVER['REQUEST_URI']);
    $message = $RCMAIL->gettext('loadingdata');
  header('Content-Type: text/html; charset=' . RCUBE_CHARSET);
  print "<html>\n<head>\n"
    header('Content-Type: text/html; charset=' . RCUBE_CHARSET);
    print "<html>\n<head>\n"
        . '<meta http-equiv="refresh" content="0; url='.rcube::Q($url).'">' . "\n"
        . '<meta http-equiv="content-type" content="text/html; charset='.RCUBE_CHARSET.'">' . "\n"
        . "</head>\n<body>\n$message\n</body>\n</html>";
  exit;
    exit;
}
ob_end_clean();
@@ -38,9 +38,9 @@
// similar code as in program/steps/mail/show.inc
if (!empty($_GET['_uid'])) {
  $uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET);
  $RCMAIL->config->set('prefer_html', true);
  $MESSAGE = new rcube_message($uid);
    $uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET);
    $RCMAIL->config->set('prefer_html', true);
    $MESSAGE = new rcube_message($uid);
}
// check connection status
@@ -50,336 +50,349 @@
// show part page
if (!empty($_GET['_frame'])) {
  if ($part_id && ($part = $MESSAGE->mime_parts[$part_id])) {
    $filename = rcmail_attachment_name($part);
    $OUTPUT->set_pagetitle($filename);
  }
    if ($part_id && ($part = $MESSAGE->mime_parts[$part_id])) {
        $filename = rcmail_attachment_name($part);
        $OUTPUT->set_pagetitle($filename);
    }
  // register UI objects
  $OUTPUT->add_handlers(array(
    'messagepartframe'    => 'rcmail_message_part_frame',
    'messagepartcontrols' => 'rcmail_message_part_controls',
  ));
    // register UI objects
    $OUTPUT->add_handlers(array(
        'messagepartframe'    => 'rcmail_message_part_frame',
        'messagepartcontrols' => 'rcmail_message_part_controls',
    ));
  $OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder());
  $OUTPUT->set_env('uid', $uid);
  $OUTPUT->set_env('part', $part_id);
  $OUTPUT->set_env('filename', $filename);
    $OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder());
    $OUTPUT->set_env('uid', $uid);
    $OUTPUT->set_env('part', $part_id);
    $OUTPUT->set_env('filename', $filename);
  $OUTPUT->send('messagepart');
  exit;
    $OUTPUT->send('messagepart');
    exit;
}
// render thumbnail of an image attachment
else if ($_GET['_thumb']) {
  $pid = rcube_utils::get_input_value('_part', rcube_utils::INPUT_GET);
  if ($part = $MESSAGE->mime_parts[$pid]) {
    $thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240);
    $temp_dir       = $RCMAIL->config->get('temp_dir');
    list(,$ext)     = explode('/', $part->mimetype);
    $mimetype       = $part->mimetype;
    $file_ident     = $MESSAGE->headers->messageID . ':' . $part->mime_id . ':' . $part->size . ':' . $part->mimetype;
    $cache_basename = $temp_dir . '/' . md5($file_ident . ':' . $RCMAIL->user->ID . ':' . $thumbnail_size);
    $cache_file     = $cache_basename . '.' . $ext;
    $pid = rcube_utils::get_input_value('_part', rcube_utils::INPUT_GET);
    if ($part = $MESSAGE->mime_parts[$pid]) {
        $thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240);
        $temp_dir       = $RCMAIL->config->get('temp_dir');
        list(,$ext)     = explode('/', $part->mimetype);
        $mimetype       = $part->mimetype;
        $file_ident     = $MESSAGE->headers->messageID . ':' . $part->mime_id . ':' . $part->size . ':' . $part->mimetype;
        $cache_basename = $temp_dir . '/' . md5($file_ident . ':' . $RCMAIL->user->ID . ':' . $thumbnail_size);
        $cache_file     = $cache_basename . '.' . $ext;
    // render thumbnail image if not done yet
    if (!is_file($cache_file)) {
      if ($fp = fopen(($orig_name = $cache_basename . '.orig.' . $ext), 'w')) {
        $MESSAGE->get_part_content($part->mime_id, $fp);
        fclose($fp);
        // render thumbnail image if not done yet
        if (!is_file($cache_file)) {
            if ($fp = fopen(($orig_name = $cache_basename . '.orig.' . $ext), 'w')) {
                $MESSAGE->get_part_content($part->mime_id, $fp);
                fclose($fp);
        $image = new rcube_image($orig_name);
        if ($imgtype = $image->resize($thumbnail_size, $cache_file, true)) {
          $mimetype = 'image/' . $imgtype;
          unlink($orig_name);
        }
        else {
          rename($orig_name, $cache_file);
        }
      }
    }
    if (is_file($cache_file)) {
      header('Content-Type: ' . $mimetype);
      readfile($cache_file);
    }
  }
  exit;
}
else if (strlen($part_id)) {
  if ($part = $MESSAGE->mime_parts[$part_id]) {
    $mimetype = rcmail_fix_mimetype($part->mimetype);
    // allow post-processing of the message body
    $plugin = $RCMAIL->plugins->exec_hook('message_part_get',
      array('uid' => $MESSAGE->uid, 'id' => $part->mime_id, 'mimetype' => $mimetype, 'part' => $part, 'download' => !empty($_GET['_download'])));
    if ($plugin['abort'])
      exit;
    // overwrite modified vars from plugin
    $mimetype   = $plugin['mimetype'];
    $extensions = rcube_mime::get_mime_extensions($mimetype);
    if ($plugin['body'])
      $part->body = $plugin['body'];
    // compare file mimetype with the stated content-type headers and file extension to avoid malicious operations
    if (!empty($_REQUEST['_embed']) && empty($_REQUEST['_nocheck'])) {
      $file_extension = strtolower(pathinfo($part->filename, PATHINFO_EXTENSION));
      // 1. compare filename suffix with expected suffix derived from mimetype
      $valid = $file_extension && in_array($file_extension, (array)$extensions) || !empty($_REQUEST['_mimeclass']);
      // 2. detect the real mimetype of the attachment part and compare it with the stated mimetype and filename extension
      if ($valid || !$file_extension || $mimetype == 'application/octet-stream' || stripos($mimetype, 'text/') === 0) {
        if ($part->body)  // part body is already loaded
          $body = $part->body;
        else if ($part->size && $part->size < 1024*1024)   // load the entire part if it's small enough
          $body = $part->body = $MESSAGE->get_part_content($part->mime_id);
        else  // fetch the first 2K of the message part
          $body = $MESSAGE->get_part_content($part->mime_id, null, true, 2048);
        // detect message part mimetype
        $real_mimetype = rcube_mime::file_content_type($body, $part->filename, $mimetype, true, true);
        list($real_ctype_primary, $real_ctype_secondary) = explode('/', $real_mimetype);
        // accept text/plain with any extension
        if ($real_mimetype == 'text/plain' && $real_mimetype == $mimetype)
          $file_extension = 'txt';
        // ignore differences in text/* mimetypes. Filetype detection isn't very reliable here
        if ($real_ctype_primary == 'text' && strpos($mimetype, $real_ctype_primary) === 0)
          $real_mimetype = $mimetype;
        // get valid file extensions
        $extensions = rcube_mime::get_mime_extensions($real_mimetype);
        $valid_extension = (!$file_extension || in_array($file_extension, (array)$extensions));
        // ignore filename extension if mimeclass matches (#1489029)
        if (!empty($_REQUEST['_mimeclass']) && $real_ctype_primary == $_REQUEST['_mimeclass'])
          $valid_extension = true;
        // fix mimetype for images wrongly declared as octet-stream
        if ($mimetype == 'application/octet-stream' && strpos($real_mimetype, 'image/') === 0 && $valid_extension)
          $mimetype = $real_mimetype;
        $valid = ($real_mimetype == $mimetype && $valid_extension);
      }
      else {
        $real_mimetype = $mimetype;
      }
      // show warning if validity checks failed
      if (!$valid) {
        // send blocked.gif for expected images
        if (empty($_REQUEST['_mimewarning']) && strpos($mimetype, 'image/') === 0) {
          // Do not cache. Failure might be the result of a misconfiguration, thus real content should be returned once fixed.
          $OUTPUT->nocacheing_headers();
          header("Content-Type: image/gif");
          header("Content-Transfer-Encoding: binary");
          readfile(INSTALL_PATH . 'program/resources/blocked.gif');
        }
        else {  // html warning with a button to load the file anyway
          $OUTPUT = new rcmail_html_page();
          $OUTPUT->write(html::tag('html', null, html::tag('body', 'embed',
            html::div(array('class' => 'rcmail-inline-message rcmail-inline-warning'),
              $RCMAIL->gettext(array(
                'name' => 'attachmentvalidationerror',
                'vars' => array(
                  'expected' => $mimetype . ($file_extension ? " (.$file_extension)" : ''),
                  'detected' => $real_mimetype . ($extensions[0] ? " (.$extensions[0])" : ''),
                )
              )) .
              html::p(array('class' => 'rcmail-inline-buttons'),
                html::tag('button',
                  array('onclick' => "location.href='" . $RCMAIL->url(array_merge($_GET, array('_nocheck' => 1))) . "'"),
                  $RCMAIL->gettext('showanyway')))
              )
          )));
        }
        exit;
      }
    }
    // TIFF to JPEG conversion, if needed
    $tiff_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps']['tif']);
    if (!empty($_REQUEST['_embed']) && !$tiff_support
      && $RCMAIL->config->get('im_convert_path')
      && rcmail_part_image_type($part) == 'image/tiff'
    ) {
      $tiff2jpeg = true;
      $mimetype = 'image/jpeg';
    }
    $browser = $RCMAIL->output->browser;
    list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
    if (!$plugin['download'] && $ctype_primary == 'text') {
      header("Content-Type: text/$ctype_secondary; charset=" . ($part->charset ? $part->charset : RCUBE_CHARSET));
    }
    else {
      header("Content-Type: $mimetype");
      header("Content-Transfer-Encoding: binary");
    }
    // deliver part content
    if ($ctype_primary == 'text' && $ctype_secondary == 'html' && empty($plugin['download'])) {
      // 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)) {
        $out = '<body>' . $RCMAIL->gettext('messagetoobig'). ' '
          . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id
            .'&_mbox='. urlencode($RCMAIL->storage->get_folder()), $RCMAIL->gettext('download')) . '</body></html>';
      }
      else {
        // get part body if not available
        if (!$part->body)
          $part->body = $MESSAGE->get_part_content($part->mime_id);
        // show images?
        rcmail_check_safe($MESSAGE);
        // render HTML body
        $out = rcmail_print_body($part, array('safe' => $MESSAGE->is_safe, 'inline_html' => false));
        // insert remote objects warning into HTML body
        if ($REMOTE_OBJECTS) {
          $body_start = 0;
          if ($body_pos = strpos($out, '<body')) {
            $body_start = strpos($out, '>', $body_pos) + 1;
          }
          $out = substr($out, 0, $body_start) .
            html::div(array('class' => 'rcmail-inline-message rcmail-inline-warning'),
              rcube::Q($RCMAIL->gettext('blockedimages')) . '&nbsp;' .
              html::tag('button',
                array('onclick' => "location.href='" . $RCMAIL->url(array_merge($_GET, array('_safe' => 1))) . "'"),
                rcube::Q($RCMAIL->gettext('showimages')))
            ) .
            substr($out, $body_start);
        }
      }
      // check connection status
      if ($part->size && empty($part->body)) {
        check_storage_status();
      }
      $OUTPUT = new rcmail_html_page();
      $OUTPUT->write($out);
    }
    else {
      // don't kill the connection if download takes more than 30 sec.
      @set_time_limit(0);
      $filename = rcmail_attachment_name($part);
      if ($browser->ie && $browser->ver < 7)
        $filename = rawurlencode(abbreviate_string($filename, 55));
      else if ($browser->ie)
        $filename = rawurlencode($filename);
      else
        $filename = addcslashes($filename, '"');
      $disposition = !empty($plugin['download']) ? 'attachment' : 'inline';
      // Workaround for nasty IE bug (#1488844)
      // If Content-Disposition header contains string "attachment" e.g. in filename
      // IE handles data as attachment not inline
      if ($disposition == 'inline' && $browser->ie && $browser->ver < 9) {
        $filename = str_ireplace('attachment', 'attach', $filename);
      }
      // add filename extension if missing
      if (!pathinfo($filename, PATHINFO_EXTENSION) && ($extensions = rcube_mime::get_mime_extensions($mimetype))) {
        $filename .= '.' . $extensions[0];
      }
      header("Content-Disposition: $disposition; filename=\"$filename\"");
      // handle tiff to jpeg conversion
      if (!empty($tiff2jpeg)) {
        $temp_dir  = unslashify($RCMAIL->config->get('temp_dir'));
        $file_path = tempnam($temp_dir, 'rcmAttmnt');
        // write content to temp file
        if ($part->body) {
          $saved = file_put_contents($file_path, $part->body);
        }
        else if ($part->size) {
          $fd = fopen($file_path, 'w');
          $saved = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, false, $fd);
          fclose($fd);
                $image = new rcube_image($orig_name);
                if ($imgtype = $image->resize($thumbnail_size, $cache_file, true)) {
                    $mimetype = 'image/' . $imgtype;
                    unlink($orig_name);
                }
                else {
                    rename($orig_name, $cache_file);
                }
            }
        }
        // convert image to jpeg and send it to the browser
        if ($saved) {
          $image = new rcube_image($file_path);
          if ($image->convert(rcube_image::TYPE_JPG, $file_path)) {
            header("Content-Length: " . filesize($file_path));
            readfile($file_path);
          }
          unlink($file_path);
        if (is_file($cache_file)) {
            header('Content-Type: ' . $mimetype);
            readfile($cache_file);
        }
      }
      // do content filtering to avoid XSS through fake images
      else if (!empty($_REQUEST['_embed']) && $browser->ie && $browser->ver <= 8) {
        if ($part->body) {
          echo preg_match('/<(script|iframe|object)/i', $part->body) ? '' : $part->body;
          $sent = true;
        }
        else if ($part->size) {
          $stdout = fopen('php://output', 'w');
          stream_filter_register('rcube_content', 'rcube_content_filter') or die('Failed to register content filter');
          stream_filter_append($stdout, 'rcube_content');
          $sent = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, false, $stdout);
        }
      }
      // send part as-it-is
      else {
        if ($part->body) {
          header("Content-Length: " . strlen($part->body));
          echo $part->body;
          $sent = true;
        }
        else if ($part->size) {
          if ($size = (int)$part->d_parameters['size']) {
            header("Content-Length: $size");
          }
          // 8th argument disables re-formatting of text/* parts (#1489267)
          $sent = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, true, null, false, 0, false);
        }
      }
      // check connection status
      if ($part->size && !$sent) {
        check_storage_status();
      }
    }
    exit;
  }
}
else if (strlen($part_id)) {
    if ($part = $MESSAGE->mime_parts[$part_id]) {
        $mimetype = rcmail_fix_mimetype($part->mimetype);
        // allow post-processing of the message body
        $plugin = $RCMAIL->plugins->exec_hook('message_part_get', array(
            'uid'      => $MESSAGE->uid,
            'id'       => $part->mime_id,
            'mimetype' => $mimetype,
            'part'     => $part,
            'download' => !empty($_GET['_download'])
        ));
        if ($plugin['abort']) {
            exit;
        }
        // overwrite modified vars from plugin
        $mimetype   = $plugin['mimetype'];
        $extensions = rcube_mime::get_mime_extensions($mimetype);
        if ($plugin['body']) {
            $part->body = $plugin['body'];
        }
        // compare file mimetype with the stated content-type headers and file extension to avoid malicious operations
        if (!empty($_REQUEST['_embed']) && empty($_REQUEST['_nocheck'])) {
            $file_extension = strtolower(pathinfo($part->filename, PATHINFO_EXTENSION));
            // 1. compare filename suffix with expected suffix derived from mimetype
            $valid = $file_extension && in_array($file_extension, (array)$extensions) || !empty($_REQUEST['_mimeclass']);
            // 2. detect the real mimetype of the attachment part and compare it with the stated mimetype and filename extension
            if ($valid || !$file_extension || $mimetype == 'application/octet-stream' || stripos($mimetype, 'text/') === 0) {
                if ($part->body)  // part body is already loaded
                    $body = $part->body;
                else if ($part->size && $part->size < 1024*1024)   // load the entire part if it's small enough
                    $body = $part->body = $MESSAGE->get_part_content($part->mime_id);
                else  // fetch the first 2K of the message part
                    $body = $MESSAGE->get_part_content($part->mime_id, null, true, 2048);
                // detect message part mimetype
                $real_mimetype = rcube_mime::file_content_type($body, $part->filename, $mimetype, true, true);
                list($real_ctype_primary, $real_ctype_secondary) = explode('/', $real_mimetype);
                // accept text/plain with any extension
                if ($real_mimetype == 'text/plain' && $real_mimetype == $mimetype) {
                    $file_extension = 'txt';
                }
                // ignore differences in text/* mimetypes. Filetype detection isn't very reliable here
                if ($real_ctype_primary == 'text' && strpos($mimetype, $real_ctype_primary) === 0) {
                    $real_mimetype = $mimetype;
                }
                // get valid file extensions
                $extensions      = rcube_mime::get_mime_extensions($real_mimetype);
                $valid_extension = (!$file_extension || in_array($file_extension, (array)$extensions));
                // ignore filename extension if mimeclass matches (#1489029)
                if (!empty($_REQUEST['_mimeclass']) && $real_ctype_primary == $_REQUEST['_mimeclass']) {
                    $valid_extension = true;
                }
                // fix mimetype for images wrongly declared as octet-stream
                if ($mimetype == 'application/octet-stream' && strpos($real_mimetype, 'image/') === 0 && $valid_extension) {
                    $mimetype = $real_mimetype;
                }
                $valid = ($real_mimetype == $mimetype && $valid_extension);
            }
            else {
                $real_mimetype = $mimetype;
            }
            // show warning if validity checks failed
            if (!$valid) {
                // send blocked.gif for expected images
                if (empty($_REQUEST['_mimewarning']) && strpos($mimetype, 'image/') === 0) {
                    // Do not cache. Failure might be the result of a misconfiguration, thus real content should be returned once fixed.
                    $OUTPUT->nocacheing_headers();
                    header("Content-Type: image/gif");
                    header("Content-Transfer-Encoding: binary");
                    readfile(INSTALL_PATH . 'program/resources/blocked.gif');
                }
                else {  // html warning with a button to load the file anyway
                    $OUTPUT = new rcmail_html_page();
                    $OUTPUT->write(html::tag('html', null, html::tag('body', 'embed',
                        html::div(array('class' => 'rcmail-inline-message rcmail-inline-warning'),
                            $RCMAIL->gettext(array(
                                'name' => 'attachmentvalidationerror',
                                'vars' => array(
                                    'expected' => $mimetype . ($file_extension ? " (.$file_extension)" : ''),
                                    'detected' => $real_mimetype . ($extensions[0] ? " (.$extensions[0])" : ''),
                                )
                            ))
                            . html::p(array('class' => 'rcmail-inline-buttons'),
                                html::tag('button', array(
                                    'onclick' => "location.href='" . $RCMAIL->url(array_merge($_GET, array('_nocheck' => 1))) . "'"
                                ),
                                $RCMAIL->gettext('showanyway'))
                            )
                        ))));
                }
                exit;
            }
        }
        // TIFF to JPEG conversion, if needed
        $tiff_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps']['tif']);
        if (!empty($_REQUEST['_embed']) && !$tiff_support
            && $RCMAIL->config->get('im_convert_path')
            && rcmail_part_image_type($part) == 'image/tiff'
        ) {
            $tiff2jpeg = true;
            $mimetype  = 'image/jpeg';
        }
        $browser = $RCMAIL->output->browser;
        list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
        if (!$plugin['download'] && $ctype_primary == 'text') {
            header("Content-Type: text/$ctype_secondary; charset=" . ($part->charset ? $part->charset : RCUBE_CHARSET));
        }
        else {
            header("Content-Type: $mimetype");
            header("Content-Transfer-Encoding: binary");
        }
        // deliver part content
        if ($ctype_primary == 'text' && $ctype_secondary == 'html' && empty($plugin['download'])) {
            // 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)) {
                $out = '<body>' . $RCMAIL->gettext('messagetoobig'). ' '
                    . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id
                        .'&_mbox='. urlencode($RCMAIL->storage->get_folder()), $RCMAIL->gettext('download')) . '</body></html>';
            }
            else {
                // get part body if not available
                if (!$part->body) {
                    $part->body = $MESSAGE->get_part_content($part->mime_id);
                }
                // show images?
                rcmail_check_safe($MESSAGE);
                // render HTML body
                $out = rcmail_print_body($part, array('safe' => $MESSAGE->is_safe, 'inline_html' => false));
                // insert remote objects warning into HTML body
                if ($REMOTE_OBJECTS) {
                    $body_start = 0;
                    if ($body_pos = strpos($out, '<body')) {
                        $body_start = strpos($out, '>', $body_pos) + 1;
                    }
                    $out = substr($out, 0, $body_start)
                        . html::div(array('class' => 'rcmail-inline-message rcmail-inline-warning'),
                            rcube::Q($RCMAIL->gettext('blockedimages')) . '&nbsp;' .
                            html::tag('button',
                                array('onclick' => "location.href='" . $RCMAIL->url(array_merge($_GET, array('_safe' => 1))) . "'"),
                                rcube::Q($RCMAIL->gettext('showimages')))
                        )
                        . substr($out, $body_start);
                }
            }
            // check connection status
            if ($part->size && empty($part->body)) {
                check_storage_status();
            }
            $OUTPUT = new rcmail_html_page();
            $OUTPUT->write($out);
        }
        else {
            // don't kill the connection if download takes more than 30 sec.
            @set_time_limit(0);
            $filename = rcmail_attachment_name($part);
            if ($browser->ie && $browser->ver < 7)
                $filename = rawurlencode(abbreviate_string($filename, 55));
            else if ($browser->ie)
                $filename = rawurlencode($filename);
            else
                $filename = addcslashes($filename, '"');
            $disposition = !empty($plugin['download']) ? 'attachment' : 'inline';
            // Workaround for nasty IE bug (#1488844)
            // If Content-Disposition header contains string "attachment" e.g. in filename
            // IE handles data as attachment not inline
            if ($disposition == 'inline' && $browser->ie && $browser->ver < 9) {
                $filename = str_ireplace('attachment', 'attach', $filename);
            }
            // add filename extension if missing
            if (!pathinfo($filename, PATHINFO_EXTENSION) && ($extensions = rcube_mime::get_mime_extensions($mimetype))) {
                $filename .= '.' . $extensions[0];
            }
            header("Content-Disposition: $disposition; filename=\"$filename\"");
            // handle tiff to jpeg conversion
            if (!empty($tiff2jpeg)) {
                $temp_dir  = unslashify($RCMAIL->config->get('temp_dir'));
                $file_path = tempnam($temp_dir, 'rcmAttmnt');
                // write content to temp file
                if ($part->body) {
                    $saved = file_put_contents($file_path, $part->body);
                }
                else if ($part->size) {
                    $fd    = fopen($file_path, 'w');
                    $saved = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, false, $fd);
                    fclose($fd);
                }
                // convert image to jpeg and send it to the browser
                if ($saved) {
                    $image = new rcube_image($file_path);
                    if ($image->convert(rcube_image::TYPE_JPG, $file_path)) {
                        header("Content-Length: " . filesize($file_path));
                        readfile($file_path);
                    }
                    unlink($file_path);
                }
            }
            // do content filtering to avoid XSS through fake images
            else if (!empty($_REQUEST['_embed']) && $browser->ie && $browser->ver <= 8) {
                if ($part->body) {
                    echo preg_match('/<(script|iframe|object)/i', $part->body) ? '' : $part->body;
                    $sent = true;
                }
                else if ($part->size) {
                    $stdout = fopen('php://output', 'w');
                    stream_filter_register('rcube_content', 'rcube_content_filter') or die('Failed to register content filter');
                    stream_filter_append($stdout, 'rcube_content');
                    $sent = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, false, $stdout);
                }
            }
            // send part as-it-is
            else {
                if ($part->body) {
                    header("Content-Length: " . strlen($part->body));
                    echo $part->body;
                    $sent = true;
                }
                else if ($part->size) {
                    if ($size = (int)$part->d_parameters['size']) {
                        header("Content-Length: $size");
                    }
                    // 8th argument disables re-formatting of text/* parts (#1489267)
                    $sent = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, true, null, false, 0, false);
                }
            }
            // check connection status
            if ($part->size && !$sent) {
                check_storage_status();
            }
        }
        exit;
    }
}
// print message
else {
  // send correct headers for content type
  header("Content-Type: text/html");
    // send correct headers for content type
    header("Content-Type: text/html");
  $cont = "<html>\n<head><title></title>\n</head>\n<body>";
  $cont .= rcmail_message_body(array());
  $cont .= "\n</body>\n</html>";
    $cont = "<html>\n<head><title></title>\n</head>\n<body>";
    $cont .= rcmail_message_body(array());
    $cont .= "\n</body>\n</html>";
  $OUTPUT = new rcmail_html_page();
  $OUTPUT->write($cont);
    $OUTPUT = new rcmail_html_page();
    $OUTPUT->write($cont);
  exit;
    exit;
}
program/steps/mail/getunread.inc
@@ -5,7 +5,7 @@
 | program/steps/mail/getunread.inc                                      |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2009, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -21,8 +21,7 @@
$a_folders = $RCMAIL->storage->list_folders_subscribed('', '*', 'mail');
if (!empty($a_folders))
{
if (!empty($a_folders)) {
    $current   = $RCMAIL->storage->get_folder();
    $inbox     = ($current == 'INBOX');
    $trash     = $RCMAIL->config->get('trash_mbox');
program/steps/mail/headers.inc
@@ -19,8 +19,7 @@
 +-----------------------------------------------------------------------+
*/
if ($uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST))
{
if ($uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST)) {
    $source = $RCMAIL->storage->get_raw_headers($uid);
    if ($source !== false) {
@@ -48,5 +47,3 @@
}
exit;
program/steps/mail/import.inc
@@ -32,6 +32,7 @@
        if (!$err) {
            // check file content type first
            list($mtype_primary,) = explode('/', rcube_mime::file_content_type($filepath, $_FILES['_file']['name'][$i], $_FILES['_file']['type'][$i]));
            if (!in_array($mtype_primary, array('text','message'))) {
                $OUTPUT->show_message('importmessageerror', 'error');
                continue;
@@ -39,7 +40,9 @@
            // read the first few lines to detect header-like structure
            $fp = fopen($filepath, 'r');
            do { $line = fgets($fp); }
            do {
                $line = fgets($fp);
            }
            while ($line !== false && trim($line) == '');
            if (!preg_match('/^From\s+-/', $line) && !preg_match('/^[a-z-_]+:\s+.+/i', $line)) {
@@ -103,4 +106,3 @@
// send html page with JS calls as response
$OUTPUT->send('iframe');
program/steps/utils/error.inc
@@ -5,7 +5,7 @@
 | program/steps/utils/error.inc                                         |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
 | Copyright (C) 2005-2013, The Roundcube Dev Team                       |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
@@ -22,10 +22,10 @@
$rcmail = rcmail::get_instance();
// browser is not compatible with this application
if ($ERROR_CODE==409) {
  $user_agent = htmlentities($_SERVER['HTTP_USER_AGENT']);
  $__error_title = 'Your browser does not suit the requirements for this application';
  $__error_text = <<<EOF
if ($ERROR_CODE == 409) {
    $user_agent    = htmlentities($_SERVER['HTTP_USER_AGENT']);
    $__error_title = 'Your browser does not suit the requirements for this application';
    $__error_text  = <<<EOF
<i>Supported browsers:</i><br />
&raquo; &nbsp;Microsoft Internet Explorer 7+<br />
&raquo; &nbsp;Mozilla Firefox 3+<br />
@@ -42,24 +42,24 @@
}
// authorization error
else if ($ERROR_CODE==401) {
  $__error_title = "AUTHORIZATION FAILED";
  $__error_text  = "Could not verify that you are authorized to access this service!<br />\n".
                   "Please contact your server-administrator.";
else if ($ERROR_CODE == 401) {
    $__error_title = "AUTHORIZATION FAILED";
    $__error_text  = "Could not verify that you are authorized to access this service!<br />\n"
        . "Please contact your server-administrator.";
}
// forbidden due to request check
else if ($ERROR_CODE==403) {
  $__error_title = "REQUEST CHECK FAILED";
  $__error_text  = "Access to this service was denied due to failing security checks!<br />\n".
                   "Please contact your server-administrator.";
else if ($ERROR_CODE == 403) {
    $__error_title = "REQUEST CHECK FAILED";
    $__error_text  = "Access to this service was denied due to failing security checks!<br />\n"
        . "Please contact your server-administrator.";
}
// failed request (wrong step in URL)
else if ($ERROR_CODE==404) {
  $__error_title = "REQUEST FAILED/FILE NOT FOUND";
  $request_url = htmlentities($_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
  $__error_text  = <<<EOF
else if ($ERROR_CODE == 404) {
    $request_url   = htmlentities($_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
    $__error_title = "REQUEST FAILED/FILE NOT FOUND";
    $__error_text  = <<<EOF
The requested page was not found!<br />
Please contact your server-administrator.
@@ -69,35 +69,36 @@
}
// database connection error
else if ($ERROR_CODE==601)
{
  $__error_title = "CONFIGURATION ERROR";
  $__error_text  =  nl2br($ERROR_MESSAGE) . "<br />Please read the INSTALL instructions!";
else if ($ERROR_CODE == 601) {
    $__error_title = "CONFIGURATION ERROR";
    $__error_text  =  nl2br($ERROR_MESSAGE) . "<br />Please read the INSTALL instructions!";
}
// database connection error
else if ($ERROR_CODE==603) {
  $__error_title = "DATABASE ERROR: CONNECTION FAILED!";
  $__error_text  =  "Unable to connect to the database!<br />Please contact your server-administrator.";
else if ($ERROR_CODE == 603) {
    $__error_title = "DATABASE ERROR: CONNECTION FAILED!";
    $__error_text  =  "Unable to connect to the database!<br />Please contact your server-administrator.";
}
// system error
else {
  $__error_title = "SERVICE CURRENTLY NOT AVAILABLE!";
  $__error_text  = "Please contact your server-administrator.";
    $__error_title = "SERVICE CURRENTLY NOT AVAILABLE!";
    $__error_text  = "Please contact your server-administrator.";
  if (($rcmail->config->get('debug_level') & 4) && $ERROR_MESSAGE)
    $__error_text = $ERROR_MESSAGE;
  else
    $__error_text = sprintf('Error No. [%s]', $ERROR_CODE);
    if (($rcmail->config->get('debug_level') & 4) && $ERROR_MESSAGE) {
        $__error_text = $ERROR_MESSAGE;
    }
    else {
        $__error_text = sprintf('Error No. [%s]', $ERROR_CODE);
    }
}
$HTTP_ERR_CODE = $ERROR_CODE && $ERROR_CODE < 600 ? $ERROR_CODE : 500;
// Ajax request
if ($rcmail->output && $rcmail->output->type == 'js') {
  header("HTTP/1.0 $HTTP_ERR_CODE $__error_title");
  die;
    header("HTTP/1.0 $HTTP_ERR_CODE $__error_title");
    die;
}
// compose page content
@@ -109,9 +110,9 @@
EOF;
if ($rcmail->output && $rcmail->output->template_exists('error')) {
  $rcmail->output->reset();
  $rcmail->output->set_env('server_error', $ERROR_CODE);
  $rcmail->output->send('error');
    $rcmail->output->reset();
    $rcmail->output->set_env('server_error', $ERROR_CODE);
    $rcmail->output->send('error');
}
$__skin = $rcmail->config->get('skin', 'default');
@@ -137,4 +138,3 @@
EOF;
exit;