Merge branch 'master' of github.com:roundcube/roundcubemail

Conflicts:
	program/js/list.js
pull/73/head
Aleksander Machniak 12 years ago
commit a522971cf8

@ -1,12 +1,25 @@
CHANGELOG Roundcube Webmail
===========================
- Added attachment_reminder plugin
- Fix IMAP connection issue with default_socket_timeout < 0 and imap_timeout < 0 (#1489090)
- Fix various PHP code bugs found using static analysis (#1489086)
- Fix backslash character handling on vCard import (#1489085)
- Fix csv import from Thunderbird with French localization (#1489059)
- Fix messages list focus issue in Opera and Webkit (#1489058)
- Make PHP code eval() free, use create_function()
- Add option to display email address together with a name in mail preview (#1488732)
- Fix Reply-To header handling in Reply-All action (#1489037)
- Fix so Sender: address is added to Cc: field on reply to all (#1489011)
- Fix so addressbook_search_mode works also for group search (#1489079)
- Fix removal of a contact from a group in LDAP addressbook (#1489081)
- Support CSV import from Atmail (#1489045)
- Inlcude SQL query in the log on SQL error (#1489064)
- Fix handling untagged responses in IMAP FETCH - "could not load message" error (#1489074)
- Fix very small window size in Chrome (#1488931)
- Fix list page reset when viewing a message in Larry skin (#1489076)
- Fix min_refresh_interval handling on preferences save (#1489073)
- Fix PDF support detection for Firefox PDF.js (#1488972)
- Fix messages list focus issue in Internet Explorer (#1489058)
- Add db_prefix configuration option in place of db_table_*/db_sequence_* options
- Make possible to use db_prefix for schema initialization in Installer (#1489067)
- Fix updatedb.sh script so it recognizes also table prefix for external DDL files

@ -0,0 +1,122 @@
#!/usr/bin/env php
<?php
/*
+-----------------------------------------------------------------------+
| bin/updatecss.sh |
| |
| This file is part of the Roundcube Webmail client |
| 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. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Update cache-baster marks for css background images |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' );
require_once INSTALL_PATH . 'program/include/clisetup.php';
// get arguments
$opts = rcube_utils::get_opt(array(
'd' => 'dir',
));
if (empty($opts['dir'])) {
print "Skin directory not specified (--dir). Using skins/ and plugins/skins/.\n";
$dir = INSTALL_PATH . 'skins';
$dir_p = INSTALL_PATH . 'plugins';
$skins = glob("$dir/*", GLOB_ONLYDIR);
$skins_p = glob("$dir_p/*/skins/*", GLOB_ONLYDIR);
$dirs = array_merge($skins, $skins_p);
}
// Check if directory exists
else if (!file_exists($opts['dir'])) {
rcube::raise_error("Specified directory doesn't exist.", false, true);
}
else {
$dirs = array($opts['dir']);
}
foreach ($dirs as $dir) {
$img_dir = $dir . '/images';
if (!file_exists($img_dir)) {
continue;
}
$files = get_files($dir);
$images = get_images($img_dir);
$find = array();
$replace = array();
// build regexps array
foreach ($images as $path => $sum) {
$path_ex = str_replace('.', '\\.', $path);
$find[] = "#url\(['\"]?images/$path_ex(\?v=[a-f0-9-\.]+)?['\"]?\)#";
$replace[] = "url(images/$path?v=$sum)";
}
foreach ($files as $file) {
$file = $dir . '/' . $file;
print "File: $file\n";
$content = file_get_contents($file);
$content = preg_replace($find, $replace, $content, -1, $count);
if ($count) {
file_put_contents($file, $content);
}
}
}
function get_images($dir)
{
$images = array();
$dh = opendir($dir);
while ($file = readdir($dh)) {
if (preg_match('/^(.+)\.(gif|ico|png|jpg|jpeg)$/', $file, $m)) {
$filepath = "$dir/$file";
$images[$file] = substr(md5_file($filepath), 0, 4) . '.' . filesize($filepath);
print "Image: $filepath ({$images[$file]})\n";
}
else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) {
foreach (get_images($dir . '/' . $file) as $img => $sum) {
$images[$file . '/' . $img] = $sum;
}
}
}
closedir($dh);
return $images;
}
function get_files($dir)
{
$files = array();
$dh = opendir($dir);
while ($file = readdir($dh)) {
if (preg_match('/^(.+)\.(css|html)$/', $file, $m)) {
$files[] = $file;
}
else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) {
foreach (get_files($dir . '/' . $file) as $f) {
$files[] = $file . '/' . $f;
}
}
}
closedir($dh);
return $files;
}
?>

@ -890,4 +890,7 @@ $rcmail_config['autocomplete_single'] = false;
// Georgia, Helvetica, Impact, Tahoma, Terminal, Times New Roman, Trebuchet MS, Verdana
$rcmail_config['default_font'] = '';
// Enables display of email address with name instead of a name (and address in title)
$rcmail_config['message_show_email'] = false;
// end of config file

@ -347,7 +347,7 @@ class rcube_install
$this->config = array_merge($this->config, $current);
foreach ((array)$current['ldap_public'] as $key => $values) {
foreach (array_keys((array)$current['ldap_public']) as $key) {
$this->config['ldap_public'][$key] = $current['ldap_public'][$key];
}
}
@ -356,10 +356,11 @@ class rcube_install
* Compare the local database schema with the reference schema
* required for this version of Roundcube
*
* @param boolean True if the schema schould be updated
* @param rcube_db Database object
*
* @return boolean True if the schema is up-to-date, false if not or an error occured
*/
function db_schema_check($DB, $update = false)
function db_schema_check($DB)
{
if (!$this->configured)
return false;
@ -583,7 +584,7 @@ class rcube_install
}
else { // check if all keys are numeric
$isnum = true;
foreach ($var as $key => $value) {
foreach (array_keys($var) as $key) {
if (!is_numeric($key)) {
$isnum = false;
break;

@ -384,7 +384,6 @@ class acl extends rcube_plugin
$table->add_header(array('class' => 'acl'.$key, 'title' => $label), $label);
}
$i = 1;
$js_table = array();
foreach ($acl as $user => $rights) {
if ($this->rc->storage->conn->user == $user) {
@ -433,8 +432,9 @@ class acl extends rcube_plugin
$acl = trim(rcube_utils::get_input_value('_acl', rcube_utils::INPUT_GPC));
$oldid = trim(rcube_utils::get_input_value('_old', rcube_utils::INPUT_GPC));
$acl = array_intersect(str_split($acl), $this->rights_supported());
$users = $oldid ? array($user) : explode(',', $user);
$acl = array_intersect(str_split($acl), $this->rights_supported());
$users = $oldid ? array($user) : explode(',', $user);
$result = 0;
foreach ($users as $user) {
$user = trim($user);

@ -0,0 +1,51 @@
/* Attachment Reminder plugin script */
function rcmail_get_compose_message()
{
var msg;
if (window.tinyMCE && (ed = tinyMCE.get(rcmail.env.composebody))) {
msg = ed.getContent();
msg = msg.replace(/<blockquote[^>]*>(.|[\r\n])*<\/blockquote>/gmi, '');
}
else {
msg = $('#' + rcmail.env.composebody).val();
msg = msg.replace(/^>.*$/gmi, '');
}
return msg;
}
function rcmail_check_message(msg)
{
var i, rx, keywords = rcmail.gettext('keywords', 'attachment_reminder').split(",").concat([".doc", ".pdf"]);
$.each(keywords, function(n) { return RegExp.escape(n); });
rx = new RegExp('(' + keywords.join('|') + ')', 'i');
return msg.search(rx) != -1;
}
function rcmail_have_attachments()
{
return rcmail.env.attachments && $('li', rcmail.gui_objects.attachmentlist).length;
}
if (window.rcmail) {
rcmail.addEventListener('beforesend', function(evt) {
var msg = rcmail_get_compose_message(),
subject = $('#compose-subject').val();
if (!rcmail_have_attachments() && (rcmail_check_message(msg) || rcmail_check_message(subject))) {
if (confirm(rcmail.gettext('forgotattachment', 'attachment_reminder'))) {
if (window.UI && UI.show_uploadform) // Larry skin
UI.show_uploadform();
else if (window.rcmail_ui && rcmail_ui.show_popup) // classic skin
rcmail_ui.show_popup('uploadmenu', true);
return false;
}
}
});
}

@ -0,0 +1,81 @@
<?php
/**
* Attachement Reminder
*
* A plugin that reminds a user to attach the files
*
* @version @package_version@
* @author Thomas Yu - Sian, Liu
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2013 Thomas Yu - Sian, Liu
* Copyright (C) 2013, Kolab Systems AG
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
class attachment_reminder extends rcube_plugin
{
public $task = 'mail|settings';
public $noajax = true;
function init()
{
$rcmail = rcube::get_instance();
if ($rcmail->task == 'mail' && $rcmail->action == 'compose') {
$this->include_script('attachment_reminder.js');
$this->add_texts('localization/', array('keywords', 'forgotattachment'));
}
if ($rcmail->task == 'settings') {
$dont_override = $rcmail->config->get('dont_override', array());
if (!in_array('attachment_reminder', $dont_override)) {
$this->add_hook('preferences_list', array($this, 'prefs_list'));
$this->add_hook('preferences_save', array($this, 'prefs_save'));
}
}
}
function prefs_list($args)
{
if ($args['section'] == 'compose') {
$this->add_texts('localization/');
$reminder = rcube::get_instance()->config->get('attachment_reminder');
$field_id = 'rcmfd_attachment_reminder';
$checkbox = new html_checkbox(array('name' => '_attachment_reminder', 'id' => $field_id, 'value' => 1));
$args['blocks']['main']['options']['attachment_reminder'] = array(
'title' => html::label($field_id, rcube::Q($this->gettext('reminderoption'))),
'content' => $checkbox->show($reminder ? 1 : 0),
);
}
return $args;
}
function prefs_save($args)
{
if ($args['section'] == 'compose') {
$dont_override = rcube::get_instance()->config->get('dont_override', array());
if (!in_array('attachment_reminder', $dont_override)) {
$args['prefs']['attachment_reminder'] = !empty($_POST['_attachment_reminder']);
}
}
return $args;
}
}

@ -0,0 +1,5 @@
<?php
$messages = array();
$messages['forgotattachment'] = "Haben Sie möglicherweise vergessen eine Datei anzuhängen?";
$messages['keywords'] = "anbei,im anhang,angehängt,angefügt,beigefügt,beliegend";

@ -0,0 +1,5 @@
<?php
$messages = array();
$messages['forgotattachment'] = "Haben Sie möglicherweise vergessen eine Datei anzuhängen?";
$messages['keywords'] = "anbei,im anhang,angehängt,angefügt,beigefügt,beliegend";

@ -0,0 +1,6 @@
<?php
$messages = array();
$messages['forgotattachment'] = "Did you forget to attach a file?";
$messages['reminderoption'] = "Remind about forgotten attachments";
$messages['keywords'] = "attachment,file,attach,attached,attaching,enclosed,CV,cover letter";

@ -0,0 +1,5 @@
<?php
$messages = array();
$messages['forgotattachment'] = "¿Olvidó adjuntar un fichero al mensaje?";
$messages['keywords'] = "adjunto";

@ -0,0 +1,5 @@
<?php
$messages = array();
$messages['forgotattachment'] = "Avez vous oublié d'attacher un fichier ?";
$messages['keywords'] = "joins,joint,attaché,CV";

@ -0,0 +1,6 @@
<?php
$messages = array();
$messages['forgotattachment'] = "Sembra che tu abbia dimenticato di allegare un file!\nPremere Annulla per inviare lo stesso.\nOK per tornare al messaggio senza inviare.";
$messages['keywords'] = "allegato,allegati,allegata,allegate,allega,allego,alleghi,attaccato,file,attachment,attach";

@ -0,0 +1,5 @@
<?php
$messages = array();
$messages['forgotattachment'] = "Ben je vergeten het bestand bij te voegen?";
$messages['keywords'] = "attachment,bestand,bijgaand,bijgaande,brief,bijgevoegd,bijgesloten,CV";

@ -0,0 +1,6 @@
<?php
$messages = array();
$messages['forgotattachment'] = "Czy nie zapomniałeś załączyć pliku?";
$messages['reminderoption'] = "Włącz przypominanie o brakującym załączniku";
$messages['keywords'] = "załącznik,plik,załącz,CV";

@ -0,0 +1,5 @@
<?php
$messages = array();
$messages['forgotattachment'] = "您似乎忘記加入附件了,你確定要寄出?";
$messages['keywords'] = "附件,附加,附檔,附上,附加檔案";

@ -0,0 +1,5 @@
<?php
$messages = array();
$messages['forgotattachment'] = "您似乎忘記加入附件了,你確定要寄出?";
$messages['keywords'] = "附件,附加,附檔,附上,附加檔案";

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
http://pear.php.net/dtd/tasks-1.0.xsd
http://pear.php.net/dtd/package-2.0
http://pear.php.net/dtd/package-2.0.xsd">
<name>Attachment Reminder</name>
<summary>Roundcube plugin that prompts you if it looks like you wanted to attach a file but you didn't.</summary>
<description>
This Roundcube plugin reminds the user to attach a file if the composed message text indicates that there should be any.
</description>
<lead>
<name>Aleksander Machniak</name>
<user>alec</user>
<email>alec@alec.pl</email>
<active>yes</active>
</lead>
<lead>
<name>Thomas Yu - Sian , Liu</name>
<active>yes</active>
</lead>
<version>
<release>1.1</release>
<api>1.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://www.gnu.org/licenses/gpl.html">GNU GPLv3+</license>
<notes>-</notes>
<contents>
<dir baseinstalldir="/" name="/">
<file name="attachment_reminder.php" role="php">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="attachment_reminder.js" role="data">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="localization/de_CH.inc" role="data"></file>
<file name="localization/de_DE.inc" role="data"></file>
<file name="localization/en_US.inc" role="data"></file>
<file name="localization/es_ES.inc" role="data"></file>
<file name="localization/fr_FR.inc" role="data"></file>
<file name="localization/it_IT.inc" role="data"></file>
<file name="localization/nl_NL.inc" role="data"></file>
<file name="localization/pl_PL.inc" role="data"></file>
<file name="localization/zh_CN.inc" role="data"></file>
<file name="localization/zh_TW.inc" role="data"></file>
</dir>
<!-- / -->
</contents>
<dependencies>
<required>
<php>
<min>5.2.1</min>
</php>
<pearinstaller>
<min>1.7.0</min>
</pearinstaller>
</required>
</dependencies>
<phprelease/>
</package>

@ -19,8 +19,6 @@ class autologon extends rcube_plugin
function startup($args)
{
$rcmail = rcmail::get_instance();
// change action to login
if (empty($_SESSION['user_id']) && !empty($_GET['_autologin']) && $this->is_localhost())
$args['action'] = 'login';
@ -37,7 +35,7 @@ class autologon extends rcube_plugin
$args['cookiecheck'] = false;
$args['valid'] = true;
}
return $args;
}

@ -194,7 +194,7 @@ class runlog {
public function print_totals(){
$totals = array();
foreach ( $this->run_log as $k => $entry ) {
foreach ($this->run_log as $entry) {
if ( $entry['type'] == 'start' && $entry['ended'] == true) {
$totals[$entry['value']]['duration'] += $entry['duration'];
$totals[$entry['value']]['count'] += 1;

@ -47,6 +47,8 @@ class enigma extends rcube_plugin
$rcmail = rcmail::get_instance();
$this->rc = $rcmail;
$section = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GET);
if ($this->rc->task == 'mail') {
// message parse/display hooks
$this->add_hook('message_part_structure', array($this, 'parse_structure'));
@ -79,7 +81,6 @@ class enigma extends rcube_plugin
$this->register_action('plugin.enigma', array($this, 'preferences_ui'));
// grab keys/certs management iframe requests
$section = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GET);
if ($this->rc->action == 'edit-prefs' && preg_match('/^enigma(certs|keys)/', $section)) {
$this->load_ui();
$this->ui->init($section);
@ -148,7 +149,7 @@ class enigma extends rcube_plugin
*/
function parse_structure($p)
{
$struct = $p['structure'];
// $struct = $p['structure'];
if ($p['mimetype'] == 'text/plain' || $p['mimetype'] == 'application/pgp') {
$this->parse_plain($p);
@ -390,7 +391,7 @@ class enigma extends rcube_plugin
function message_load($p)
{
$this->message = $p['object'];
// handle attachments vcard attachments
foreach ((array)$this->message->attachments as $attachment) {
if ($this->is_keys_part($attachment)) {
@ -398,7 +399,7 @@ class enigma extends rcube_plugin
}
}
// the same with message bodies
foreach ((array)$this->message->parts as $idx => $part) {
foreach ((array)$this->message->parts as $part) {
if ($this->is_keys_part($part)) {
$this->keys_parts[] = $part->mime_id;
$this->keys_bodies[] = $part->mime_id;

@ -374,17 +374,15 @@ class enigma_engine
{
// @TODO: Handle big bodies using (temp) files
// @TODO: caching of verification result
$sig = $this->pgp_driver->verify($msg_body, $sig_body);
$sig = $this->pgp_driver->verify($msg_body, $sig_body);
if (($sig instanceof enigma_error) && $sig->getCode() != enigma_error::E_KEYNOTFOUND)
rcube::raise_error(array(
if (($sig instanceof enigma_error) && $sig->getCode() != enigma_error::E_KEYNOTFOUND)
rcube::raise_error(array(
'code' => 600, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Enigma plugin: " . $error->getMessage()
'message' => "Enigma plugin: " . $sig->getMessage()
), true, false);
//print_r($sig);
return $sig;
}
@ -399,11 +397,9 @@ class enigma_engine
{
// @TODO: Handle big bodies using (temp) files
// @TODO: caching of verification result
$key = ''; $pass = ''; // @TODO
$result = $this->pgp_driver->decrypt($msg_body, $key, $pass);
//print_r($result);
if ($result instanceof enigma_error) {
$err_code = $result->getCode();
if (!in_array($err_code, array(enigma_error::E_KEYNOTFOUND, enigma_error::E_BADPASS)))
@ -430,7 +426,7 @@ class enigma_engine
{
$this->load_pgp_driver();
$result = $this->pgp_driver->list_keys($pattern);
if ($result instanceof enigma_error) {
rcube::raise_error(array(
'code' => 600, 'type' => 'php',
@ -438,7 +434,7 @@ class enigma_engine
'message' => "Enigma plugin: " . $result->getMessage()
), true, false);
}
return $result;
}
@ -501,9 +497,11 @@ class enigma_engine
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST);
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST);
$mime_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_POST);
$storage = $this->rc->get_storage();
if ($uid && $mime_id) {
$part = $this->rc->storage->get_message_part($uid, $mime_id);
$storage->set_folder($mbox);
$part = $storage->get_message_part($uid, $mime_id);
}
if ($part && is_array($result = $this->import_key($part))) {
@ -532,16 +530,4 @@ class enigma_engine
$uid, $part->mime_id, $part);
}
}
/**
* Adds CSS style file to the page header.
*/
private function add_css()
{
$skin = $this->rc->config->get('skin');
if (!file_exists($this->home . "/skins/$skin/enigma.css"))
$skin = 'default';
$this->include_stylesheet("skins/$skin/enigma.css");
}
}

@ -176,8 +176,7 @@ class enigma_ui
$search = rcube_utils::get_input_value('_q', rcube_utils::INPUT_GPC);
// define list of cols to be displayed
$a_show_cols = array('name');
$result = array();
// $a_show_cols = array('name');
// Get the list
$list = $this->enigma->engine->list_keys($search);
@ -200,7 +199,7 @@ class enigma_ui
$size = count($list);
// Add rows
foreach($list as $idx => $key) {
foreach ($list as $key) {
$this->rc->output->command('enigma_add_list_row',
array('name' => rcube::Q($key->name), 'id' => $key->id));
}

@ -21,8 +21,6 @@ class help extends rcube_plugin
function init()
{
$rcmail = rcmail::get_instance();
$this->add_texts('localization/', false);
// register task

@ -206,7 +206,6 @@ class rcube_sieve_script
// rules
foreach ($this->content as $rule) {
$extension = '';
$script = '';
$tests = array();
$i = 0;
@ -1015,11 +1014,10 @@ class rcube_sieve_script
* @param mixed $num Number of tokens to return, 0 for all
* or True for all tokens until separator is found.
* Separator will be returned as last token.
* @param int $in_list Enable to call recursively inside a list
*
* @return mixed Tokens array or string if $num=1
*/
static function tokenize(&$str, $num=0, $in_list=false)
static function tokenize(&$str, $num=0)
{
$result = array();
@ -1054,7 +1052,7 @@ class rcube_sieve_script
// Parenthesized list
case '[':
$str = substr($str, 1);
$result[] = self::tokenize($str, 0, true);
$result[] = self::tokenize($str, 0);
break;
case ']':
$str = substr($str, 1);

@ -1640,7 +1640,7 @@ class managesieve extends rcube_plugin
.'value="' . rcube::Q($action['value']) . '" size="35" '
. $this->error_class($id, 'action', 'value', 'action_varvalue') .' />';
$out .= '<br /><span class="label">' .rcube::Q($this->gettext('setvarmodifiers')) . '</span><br />';
foreach ($set_modifiers as $j => $s_m) {
foreach ($set_modifiers as $s_m) {
$s_m_id = 'action_varmods' . $id . $s_m;
$out .= sprintf('<input type="checkbox" name="_action_varmods[%s][]" value="%s" id="%s"%s />%s<br>',
$id, $s_m, $s_m_id,
@ -1902,7 +1902,7 @@ class managesieve extends rcube_plugin
$user_script = $_SESSION['managesieve_user_script'];
// if the script is not active...
if ($user_script && ($key = array_search($name, $this->active)) === false) {
if ($user_script && array_search($name, $this->active) === false) {
// ...rewrite USER file adding appropriate include command
if ($this->sieve->load($user_script)) {
$script = $this->sieve->script->as_array();
@ -1920,7 +1920,7 @@ class managesieve extends rcube_plugin
// get all active scripts for sorting
foreach ($script as $rid => $rules) {
foreach ($rules['actions'] as $aid => $action) {
foreach ($rules['actions'] as $action) {
if ($action['type'] == 'include' && empty($action['global'])) {
$target = $extension ? preg_replace($regexp, '', $action['target']) : $action['target'];
$list[] = $target;
@ -1988,7 +1988,7 @@ class managesieve extends rcube_plugin
$name = $name.$extension;
foreach ($script as $rid => $rules) {
foreach ($rules['actions'] as $aid => $action) {
foreach ($rules['actions'] as $action) {
if ($action['type'] == 'include' && empty($action['global'])
&& $action['target'] == $name
) {

@ -33,8 +33,6 @@ class new_user_identity extends rcube_plugin
function lookup_user_name($args)
{
$rcmail = rcmail::get_instance();
if ($this->init_ldap($args['host'])) {
$results = $this->ldap->search('*', $args['user'], true);
if (count($results->records) == 1) {

@ -297,7 +297,6 @@ class HTTPSocket {
$status = socket_get_status($socket);
$startTime = time();
$length = 0;
$prevSecond = 0;
while ( !feof($socket) && !$status['timed_out'] )
{
$chunk = fgets($socket,1024);

@ -11,7 +11,8 @@ class rcube_pam_password
{
function save($currpass, $newpass)
{
$user = $_SESSION['username'];
$user = $_SESSION['username'];
$error = '';
if (extension_loaded('pam') || extension_loaded('pam_auth')) {
if (pam_auth($user, $currpass, $error, false)) {

@ -34,8 +34,9 @@ class rcube_sql_password
$db = $rcmail->get_dbh();
}
if ($err = $db->is_error())
if ($db->is_error()) {
return PASSWORD_ERROR;
}
// crypted password
if (strpos($sql, '%c') !== FALSE) {
@ -183,8 +184,8 @@ class rcube_sql_password
$res = $db->query($sql, $sql_vars);
if (!$db->is_error()) {
if (strtolower(substr(trim($query),0,6))=='select') {
if ($result = $db->fetch_array($res))
if (strtolower(substr(trim($sql),0,6)) == 'select') {
if ($db->fetch_array($res))
return PASSWORD_SUCCESS;
} else {
// This is the good case: 1 row updated

@ -67,7 +67,7 @@ class XMail {
function send($msg)
{
socket_write($this->socket,$msg);
if (substr($in = socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") {
if (substr(socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") {
return false;
}
return true;
@ -85,7 +85,7 @@ class XMail {
return false;
}
if (substr($in = socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") {
if (substr(socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") {
socket_close($this->socket);
return false;
}

@ -63,7 +63,7 @@ class squirrelmail_usercopy extends rcube_plugin
if ($this->prefs['___sig'.$i.'___'])
$ident_data['signature'] = $this->prefs['___sig'.$i.'___'];
// insert identity
$identid = $rcmail->user->insert_identity($ident_data);
$rcmail->user->insert_identity($ident_data);
}
}

@ -45,7 +45,7 @@ class vcard_attachments extends rcube_plugin
}
}
// the same with message bodies
foreach ((array)$this->message->parts as $idx => $part) {
foreach ((array)$this->message->parts as $part) {
if ($this->is_vcard($part)) {
$this->vcard_parts[] = $part->mime_id;
$this->vcard_bodies[] = $part->mime_id;
@ -63,7 +63,6 @@ class vcard_attachments extends rcube_plugin
function html_output($p)
{
$attach_script = false;
$icon = 'plugins/vcard_attachments/' .$this->local_skin_path(). '/vcard_add_contact.png';
foreach ($this->vcard_parts as $part) {
$vcards = rcube_vcard::import($this->message->get_part_content($part, null, true));

@ -169,7 +169,7 @@ class zipdownload extends rcube_plugin
for ($i = 0; ($i * $imap->get_pagesize()) <= $count; $i++) {
$a_headers = $imap->list_messages($mbox_name, ($i + 1));
foreach ($a_headers as $n => $header) {
foreach ($a_headers as $header) {
if (empty($header))
continue;
@ -199,7 +199,7 @@ class zipdownload extends rcube_plugin
$zip = new ZipArchive();
$zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
foreach ($uids as $key => $uid){
foreach ($uids as $uid){
$headers = $imap->get_message_headers($uid);
$subject = rcube_mime::decode_mime_string((string)$headers->subject);
$subject = $this->_convert_filename($subject);

@ -62,7 +62,7 @@ function rcmail_url($action, $p=array(), $task=null)
function rcmail_temp_gc()
{
$rcmail = rcmail::get_instance()->temp_gc();
rcmail::get_instance()->temp_gc();
}
function rcube_charset_convert($str, $from, $to=NULL)

@ -596,7 +596,7 @@ class rcmail extends rcube
$post_host = rcube_utils::get_input_value('_host', rcube_utils::INPUT_POST);
$post_user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST);
list($user, $domain) = explode('@', $post_user);
list(, $domain) = explode('@', $post_user);
// direct match in default_host array
if ($default_host[$post_host] || in_array($post_host, array_values($default_host))) {
@ -699,28 +699,6 @@ class rcmail extends rcube
}
/**
* Create unique authorization hash
*
* @param string Session ID
* @param int Timestamp
* @return string The generated auth hash
*/
private function get_auth_hash($sess_id, $ts)
{
$auth_string = sprintf('rcmail*sess%sR%s*Chk:%s;%s',
$sess_id,
$ts,
$this->config->get('ip_check') ? $_SERVER['REMOTE_ADDR'] : '***.***.***.***',
$_SERVER['HTTP_USER_AGENT']);
if (function_exists('sha1'))
return sha1($auth_string);
else
return md5($auth_string);
}
/**
* Build a valid URL to this instance of Roundcube
*
@ -1167,7 +1145,7 @@ class rcmail extends rcube
*/
public function table_output($attrib, $table_data, $a_show_cols, $id_col)
{
$table = new html_table(/*array('cols' => count($a_show_cols))*/);
$table = new html_table($attrib);
// add table header
if (!$attrib['noheader']) {
@ -1532,7 +1510,7 @@ class rcmail extends rcube
$collapsed = $this->config->get('collapsed_folders');
$out = '';
foreach ($arrFolders as $key => $folder) {
foreach ($arrFolders as $folder) {
$title = null;
$folder_class = $this->folder_classname($folder['id']);
$is_collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false;
@ -1618,7 +1596,7 @@ class rcmail extends rcube
{
$out = '';
foreach ($arrFolders as $key => $folder) {
foreach ($arrFolders as $folder) {
// skip exceptions (and its subfolders)
if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) {
continue;

@ -731,14 +731,13 @@ class rcmail_output_html extends rcmail_output
/**
* Determines if a given condition is met
*
* @todo Get rid off eval() once I understand what this does.
* @todo Extend this to allow real conditions, not just "set"
* @param string Condition statement
* @return boolean True if condition is met, False if not
*/
protected function check_condition($condition)
{
return eval("return (".$this->parse_expression($condition).");");
return $this->eval_expression($condition);
}
@ -760,14 +759,15 @@ class rcmail_output_html extends rcmail_output
/**
* Parses expression and replaces variables
* Parse & evaluate a given expression and return its result.
*
* @param string Expression statement
* @return string Expression value
* @param string Expression statement
*
* @return mixed Expression result
*/
protected function parse_expression($expression)
protected function eval_expression ($expression)
{
return preg_replace(
$expression = preg_replace(
array(
'/session:([a-z0-9_]+)/i',
'/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i',
@ -779,14 +779,29 @@ class rcmail_output_html extends rcmail_output
),
array(
"\$_SESSION['\\1']",
"\$this->app->config->get('\\1',rcube_utils::get_boolean('\\3'))",
"\$this->env['\\1']",
"\$app->config->get('\\1',rcube_utils::get_boolean('\\3'))",
"\$env['\\1']",
"rcube_utils::get_input_value('\\1', rcube_utils::INPUT_GPC)",
"\$_COOKIE['\\1']",
"\$this->browser->{'\\1'}",
"\$browser->{'\\1'}",
$this->template_name,
),
$expression);
$expression
);
$fn = create_function('$app,$browser,$env', "return ($expression);");
if (!$fn) {
rcube::raise_error(array(
'code' => 505,
'type' => 'php',
'file' => __FILE__,
'line' => __LINE__,
'message' => "Expression parse error on: ($expression)"), true, false);
return null;
}
return $fn($this->app, $this->browser, $this->env);
}
@ -839,7 +854,7 @@ class rcmail_output_html extends rcmail_output
// show a label
case 'label':
if ($attrib['expression'])
$attrib['name'] = eval("return " . $this->parse_expression($attrib['expression']) .";");
$attrib['name'] = $this->eval_expression($attrib['expression']);
if ($attrib['name'] || $attrib['command']) {
// @FIXME: 'noshow' is useless, remove?
@ -971,8 +986,7 @@ class rcmail_output_html extends rcmail_output
// return code for a specified eval expression
case 'exp':
$value = $this->parse_expression($attrib['expression']);
return eval("return html::quote($value);");
return html::quote($this->eval_expression($attrib['expression']));
// return variable
case 'var':

@ -936,16 +936,13 @@ function rcube_webmail()
url._to = props;
}
else {
// use contact_id passed as command parameter
var n, len, a_cids = [];
var a_cids = [];
// use contact id passed as command parameter
if (props)
a_cids.push(props);
// get selected contacts
else if (this.contact_list) {
var selection = this.contact_list.get_selection();
for (n=0, len=selection.length; n<len; n++)
a_cids.push(selection[n]);
}
else if (this.contact_list)
a_cids = this.contact_list.get_selection();
if (a_cids.length)
this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source }, true);
@ -1582,7 +1579,7 @@ function rcube_webmail()
this.msglist_set_coltypes = function(list)
{
var i, found, name, cols = list.list.tHead.rows[0].cells;
var i, found, name, cols = list.thead.rows[0].cells;
this.env.coltypes = [];
@ -1632,13 +1629,17 @@ function rcube_webmail()
this.open_window = function(url, width, height)
{
var w = Math.min(width, screen.width - 10),
h = Math.min(height, screen.height - 100),
l = (screen.width - w) / 2 + (screen.left || 0),
t = Math.max(0, (screen.height - h) / 2 + (screen.top || 0) - 20),
var dh = (window.outerHeight || 0) - (window.innerHeight || 0),
dw = (window.outerWidth || 0) - (window.innerWidth || 0),
sh = screen.availHeight || screen.height,
sw = screen.availWidth || screen.width,
w = Math.min(width, sw),
h = Math.min(height, sh),
l = Math.max(0, (sw - w) / 2 + (screen.left || 0)),
t = Math.max(0, (sh - h) / 2 + (screen.top || 0)),
wname = 'rcmextwin' + new Date().getTime(),
extwin = window.open(url + (url.match(/\?/) ? '&' : '?') + '_extwin=1', wname,
'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no,location=no');
'width='+(w-dw)+',height='+(h-dh)+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no,location=no');
// write loading... message to empty windows
if (!url && extwin.document) {
@ -1732,10 +1733,7 @@ function rcube_webmail()
+ (flags.flagged ? ' flagged' : '')
+ (flags.unread_children && flags.seen && !this.env.autoexpand_threads ? ' unroot' : '')
+ (message.selected ? ' selected' : ''),
// for performance use DOM instead of jQuery here
row = document.createElement('tr');
row.id = 'rcmrow'+uid;
row = { cols:[], style:{}, id:'rcmrow'+uid };
// message status icons
css_class = 'msgicon';
@ -1799,8 +1797,7 @@ function rcube_webmail()
// add each submitted col
for (n in this.env.coltypes) {
c = this.env.coltypes[n];
col = document.createElement('td');
col.className = String(c).toLowerCase();
col = { className: String(c).toLowerCase() };
if (c == 'flag') {
css_class = (flags.flagged ? 'flagged' : 'unflagged');
@ -1845,8 +1842,7 @@ function rcube_webmail()
html = cols[c];
col.innerHTML = html;
row.appendChild(col);
row.cols.push(col);
}
list.insert_row(row, attop);
@ -2209,7 +2205,7 @@ function rcube_webmail()
if (root)
row = rows[root] ? rows[root].obj : null;
else
row = this.message_list.list.tBodies[0].firstChild;
row = this.message_list.tbody.firstChild;
while (row) {
if (row.nodeType == 1 && (r = rows[row.uid])) {
@ -2385,7 +2381,7 @@ function rcube_webmail()
this.delete_excessive_thread_rows = function()
{
var rows = this.message_list.rows,
tbody = this.message_list.list.tBodies[0],
tbody = this.message_list.tbody,
row = tbody.firstChild,
cnt = this.env.pagesize + 1;
@ -4328,21 +4324,7 @@ function rcube_webmail()
newcid = newcid+'-'+source;
}
if (list.rows[cid] && (row = list.rows[cid].obj)) {
for (c=0; c<cols_arr.length; c++)
if (row.cells[c])
$(row.cells[c]).html(cols_arr[c]);
// cid change
if (newcid) {
newcid = this.html_identifier(newcid);
row.id = 'rcmrow' + newcid;
list.remove_row(cid);
list.init_row(row);
list.selection[0] = newcid;
row.style.display = '';
}
}
list.update_row(cid, cols_arr, newcid, true);
};
// add row to contacts list
@ -4352,7 +4334,7 @@ function rcube_webmail()
return false;
var c, col, list = this.contact_list,
row = document.createElement('tr');
row = { cols:[] };
row.id = 'rcmrow'+this.html_identifier(cid);
row.className = 'contact ' + (classes || '');
@ -4362,10 +4344,10 @@ function rcube_webmail()
// add each submitted col
for (c in cols) {
col = document.createElement('td');
col = {};
col.className = String(c).toLowerCase();
col.innerHTML = cols[c];
row.appendChild(col);
row.cols.push(col);
}
list.insert_row(row);
@ -4471,11 +4453,22 @@ function rcube_webmail()
this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); });
this.name_input_li = $('<li>').addClass(type).append(this.name_input);
var li = type == 'contactsearch' ? $('li:last', this.gui_objects.folderlist) : $('ul.groups li:last', this.get_folder_li(this.env.source,'',true));
var ul, li;
// find list (UL) element
if (type == 'contactsearch')
ul = this.gui_objects.folderlist;
else
ul = $('ul.groups', this.get_folder_li(this.env.source,'',true));
// append to the list
li = $('li:last', ul);
if (li.length)
this.name_input_li.insertAfter(li);
else
this.name_input_li.appendTo(type == 'contactsearch' ? this.gui_objects.folderlist : $('ul.groups', this.get_folder_li(this.env.source,'',true)));
else {
this.name_input_li.appendTo(ul);
ul.show(); // make sure the list is visible
}
}
this.name_input.select().focus();
@ -4532,11 +4525,13 @@ function rcube_webmail()
this.reset_add_input = function()
{
if (this.name_input) {
var li = this.name_input.parent();
if (this.env.group_renaming) {
var li = this.name_input.parent();
li.children().last().show();
this.env.group_renaming = false;
}
else if ($('li', li.parent()).length == 1)
li.parent().hide();
this.name_input.remove();
@ -4964,18 +4959,16 @@ function rcube_webmail()
this.update_identity_row = function(id, name, add)
{
var row, col, list = this.identity_list,
var list = this.identity_list,
rid = this.html_identifier(id);
if (list.rows[rid] && (row = list.rows[rid].obj)) {
$(row.cells[0]).html(name);
}
else if (add) {
row = $('<tr>').attr('id', 'rcmrow'+rid).get(0);
col = $('<td>').addClass('mail').html(name).appendTo(row);
list.insert_row(row);
if (add) {
list.insert_row({ id:'rcmrow'+rid, cols:[ { className:'mail', innerHTML:name } ] });
list.select(rid);
}
else {
list.update_row(rid, [ name ]);
}
};
@ -5750,7 +5743,7 @@ function rcube_webmail()
this.set_message_coltypes = function(coltypes, repl, smart_col)
{
var list = this.message_list,
thead = list ? list.list.tHead : null,
thead = list ? list.thead : null,
cell, col, n, len, th, tr;
this.env.coltypes = coltypes;

@ -30,6 +30,9 @@ function rcube_list_widget(list, p)
this.BACKSPACE_KEY = 8;
this.list = list ? list : null;
this.tagname = this.list ? this.list.nodeName.toLowerCase() : 'table';
this.thead;
this.tbody;
this.frame = null;
this.rows = [];
this.selection = [];
@ -56,7 +59,7 @@ function rcube_list_widget(list, p)
this.focused = false;
this.drag_mouse_start = null;
this.dblclick_time = 600;
this.row_init = function(){};
this.row_init = function(){}; // @deprecated; use list.addEventListener('initrow') instead
// overwrite default paramaters
if (p && typeof p === 'object')
@ -73,11 +76,19 @@ rcube_list_widget.prototype = {
*/
init: function()
{
if (this.list && this.list.tBodies[0]) {
if (this.tagname == 'table' && this.list && this.list.tBodies[0]) {
this.thead = this.list.tHead;
this.tbody = this.list.tBodies[0];
}
else if (this.tagname != 'table' && this.list) {
this.tbody = this.list;
}
if (this.tbody) {
this.rows = [];
this.rowcount = 0;
var r, len, rows = this.list.tBodies[0].rows;
var r, len, rows = this.tbody.childNodes;
for (r=0, len=rows.length; r<len; r++) {
this.init_row(rows[r]);
@ -127,7 +138,8 @@ init_row: function(row)
if (document.all)
row.onselectstart = function() { return false; };
this.row_init(this.rows[uid]);
this.row_init(this.rows[uid]); // legacy support
this.triggerEvent('initrow', this.rows[uid]);
}
},
@ -137,16 +149,16 @@ init_row: function(row)
*/
init_header: function()
{
if (this.list && this.list.tHead) {
if (this.thead) {
this.colcount = 0;
var col, r, p = this;
// add events for list columns moving
if (this.column_movable && this.list.tHead && this.list.tHead.rows) {
for (r=0; r<this.list.tHead.rows[0].cells.length; r++) {
if (this.column_movable && this.thead && this.thead.rows) {
for (r=0; r<this.thead.rows[0].cells.length; r++) {
if (this.column_fixed == r)
continue;
col = this.list.tHead.rows[0].cells[r];
col = this.thead.rows[0].cells[r];
col.onmousedown = function(e){ return p.drag_column(e, this); };
this.colcount++;
}
@ -160,10 +172,16 @@ init_header: function()
*/
clear: function(sel)
{
var tbody = document.createElement('tbody');
if (this.tagname == 'table') {
var tbody = document.createElement('tbody');
this.list.insertBefore(tbody, this.tbody);
this.list.removeChild(this.list.tBodies[1]);
this.tbody = tbody;
}
else {
$(this.row_tagname() + ':not(.thead)', this.tbody).remove();
}
this.list.insertBefore(tbody, this.list.tBodies[0]);
this.list.removeChild(this.list.tBodies[1]);
this.rows = [];
this.rowcount = 0;
@ -181,12 +199,12 @@ clear: function(sel)
*/
remove_row: function(uid, sel_next)
{
var obj = this.rows[uid] ? this.rows[uid].obj : null;
var node = this.rows[uid] ? this.rows[uid].obj : null;
if (!obj)
if (!node)
return;
obj.style.display = 'none';
node.style.display = 'none';
if (sel_next)
this.select_next();
@ -201,9 +219,28 @@ remove_row: function(uid, sel_next)
*/
insert_row: function(row, before)
{
var tbody = this.list.tBodies[0];
var tbody = this.tbody;
// create a real dom node first
if (row.nodeName === undefined) {
// for performance reasons use DOM instead of jQuery here
var domrow = document.createElement(this.row_tagname());
if (row.id) domrow.id = row.id;
if (row.className) domrow.className = row.className;
if (row.style) $.extend(domrow.style, row.style);
for (var domcell, col, i=0; row.cols && i < row.cols.length; i++) {
col = row.cols[i];
domcell = document.createElement(this.col_tagname());
if (col.className) domcell.className = col.className;
if (col.innerHTML) domcell.innerHTML = col.innerHTML;
domrow.appendChild(domcell);
}
row = domrow;
}
if (before && tbody.rows.length)
if (before && tbody.childNodes.length)
tbody.insertBefore(row, (typeof before == 'object' && before.parentNode == tbody) ? before : tbody.firstChild);
else
tbody.appendChild(row);
@ -212,6 +249,28 @@ insert_row: function(row, before)
this.rowcount++;
},
/**
*
*/
update_row: function(id, cols, newid, select)
{
var row = this.rows[id];
if (!row) return false;
var domrow = row.obj;
for (var domcell, col, i=0; cols && i < cols.length; i++) {
this.get_cell(domrow, i).html(cols[i]);
}
if (newid) {
delete this.rows[id];
domrow.id = 'rcmrow' + newid;
this.init_row(domrow);
if (select)
this.selection[0] = newid;
}
},
/**
@ -230,9 +289,9 @@ focus: function(e)
}
// Un-focus already focused elements (#1487123, #1487316, #1488600, #1488620)
// It looks that window.focus() does the job for all browsers, but not Firefox (#1489058)
$(':focus:not(body)').blur();
// un-focus iframe bodies (#1489058), this doesn't work in Opera and Chrome
$('iframe').contents().find('body').blur();
window.focus();
if (e || (e = window.event))
rcube_event.cancel(e);
@ -271,8 +330,8 @@ drag_column: function(e, col)
this.add_dragfix();
// find selected column number
for (var i=0; i<this.list.tHead.rows[0].cells.length; i++) {
if (col == this.list.tHead.rows[0].cells[i]) {
for (var i=0; i<this.thead.rows[0].cells.length; i++) {
if (col == this.thead.rows[0].cells[i]) {
this.selected_column = i;
break;
}
@ -451,7 +510,7 @@ expand: function(row)
this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj });
}
else {
var tbody = this.list.tBodies[0];
var tbody = this.tbody;
new_row = tbody.firstChild;
depth = 0;
last_expanded_parent_depth = 0;
@ -504,7 +563,7 @@ collapse_all: function(row)
return false;
}
else {
new_row = this.list.tBodies[0].firstChild;
new_row = this.tbody.firstChild;
depth = 0;
}
@ -543,7 +602,7 @@ expand_all: function(row)
this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj });
}
else {
new_row = this.list.tBodies[0].firstChild;
new_row = this.tbody.firstChild;
depth = 0;
}
@ -611,7 +670,7 @@ get_prev_row: function()
get_first_row: function()
{
if (this.rowcount) {
var i, len, rows = this.list.tBodies[0].rows;
var i, len, rows = this.tbody.childNodes;
for (i=0, len=rows.length-1; i<len; i++)
if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null)
@ -624,7 +683,7 @@ get_first_row: function()
get_last_row: function()
{
if (this.rowcount) {
var i, rows = this.list.tBodies[0].rows;
var i, rows = this.tbody.childNodes;
for (i=rows.length-1; i>=0; i--)
if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null)
@ -634,6 +693,22 @@ get_last_row: function()
return null;
},
row_tagname: function()
{
var row_tagnames = { table:'tr', ul:'li', '*':'div' };
return row_tagnames[this.tagname] || row_tagnames['*'];
},
col_tagname: function()
{
var col_tagnames = { table:'td', '*':'span' };
return col_tagnames[this.tagname] || col_tagnames['*'];
},
get_cell: function(row, index)
{
return $(this.col_tagname(), row).eq(index);
},
/**
* selects or unselects the proper row depending on the modifier key pressed
@ -781,19 +856,19 @@ shift_select: function(id, control)
this.shift_start = id;
var n, i, j, to_row = this.rows[id],
from_rowIndex = this.rows[this.shift_start].obj.rowIndex,
to_rowIndex = to_row.obj.rowIndex;
from_rowIndex = this._rowIndex(this.rows[this.shift_start].obj),
to_rowIndex = this._rowIndex(to_row.obj);
if (!to_row.expanded && to_row.has_children)
if (to_row = this.rows[(this.row_children(id)).pop()])
to_rowIndex = to_row.obj.rowIndex;
to_rowIndex = this._rowIndex(to_row.obj);
i = ((from_rowIndex < to_rowIndex) ? from_rowIndex : to_rowIndex),
j = ((from_rowIndex > to_rowIndex) ? from_rowIndex : to_rowIndex);
// iterate through the entire message list
for (n in this.rows) {
if (this.rows[n].obj.rowIndex >= i && this.rows[n].obj.rowIndex <= j) {
if (this._rowIndex(this.rows[n].obj) >= i && this._rowIndex(this.rows[n].obj) <= j) {
if (!this.in_selection(n)) {
this.highlight_row(n, true);
}
@ -806,6 +881,13 @@ shift_select: function(id, control)
}
},
/**
* Helper method to emulate the rowIndex property of non-tr elements
*/
_rowIndex: function(obj)
{
return (obj.rowIndex !== undefined) ? obj.rowIndex : $(obj).prevAll().length;
},
/**
* Check if given id is part of the current selection
@ -1150,7 +1232,7 @@ drag_mouse_move: function(e)
this.draglayer.html('');
// get subjects of selected messages
var i, n, obj;
var i, n, obj, me;
for (n=0; n<this.selection.length; n++) {
// only show 12 lines
if (n>12) {
@ -1158,29 +1240,28 @@ drag_mouse_move: function(e)
break;
}
me = this;
if (obj = this.rows[this.selection[n]].obj) {
for (i=0; i<obj.childNodes.length; i++) {
if (obj.childNodes[i].nodeName == 'TD') {
if (n == 0)
this.drag_start_pos = $(obj.childNodes[i]).offset();
$('> '+this.col_tagname(), obj).each(function(i,elem){
if (n == 0)
me.drag_start_pos = $(elem).offset();
if (this.subject_col < 0 || (this.subject_col >= 0 && this.subject_col == i)) {
var subject = $(obj.childNodes[i]).text();
if (!subject)
break;
if (me.subject_col < 0 || (me.subject_col >= 0 && me.subject_col == i)) {
var subject = $(elem).text();
if (subject) {
// remove leading spaces
subject = $.trim(subject);
// truncate line to 50 characters
subject = (subject.length > 50 ? subject.substring(0, 50) + '...' : subject);
var entry = $('<div>').text(subject);
this.draglayer.append(entry);
break;
me.draglayer.append(entry);
}
return false; // break
}
}
});
}
}
@ -1255,7 +1336,7 @@ column_drag_mouse_move: function(e)
if (!this.col_draglayer) {
var lpos = $(this.list).offset(),
cells = this.list.tHead.rows[0].cells;
cells = this.thead.rows[0].cells;
// create dragging layer
this.col_draglayer = $('<div>').attr('id', 'rcmcoldraglayer')
@ -1411,7 +1492,11 @@ del_dragfix: function()
*/
column_replace: function(from, to)
{
var len, cells = this.list.tHead.rows[0].cells,
// only supported for <table> lists
if (!this.thead || !this.thead.rows)
return;
var len, cells = this.thead.rows[0].cells,
elem = cells[from],
before = cells[to],
td = document.createElement('td');
@ -1424,8 +1509,8 @@ column_replace: function(from, to)
cells[0].parentNode.replaceChild(elem, td);
// replace list cells
for (r=0, len=this.list.tBodies[0].rows.length; r<len; r++) {
row = this.list.tBodies[0].rows[r];
for (r=0, len=this.tbody.rows.length; r<len; r++) {
row = this.tbody.rows[r];
elem = row.cells[from];
before = row.cells[to];

@ -678,6 +678,11 @@ class html_table extends html
{
$default_attrib = self::$doctype == 'xhtml' ? array('summary' => '', 'border' => 0) : array();
$this->attrib = array_merge($attrib, $default_attrib);
if (!empty($attrib['tagname']) && $attrib['tagname'] != 'table') {
$this->tagname = $attrib['tagname'];
$this->allowed = self::$common_attrib;
}
}
/**
@ -816,19 +821,20 @@ class html_table extends html
if (!empty($this->header)) {
$rowcontent = '';
foreach ($this->header as $c => $col) {
$rowcontent .= self::tag('td', $col->attrib, $col->content);
$rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content);
}
$thead = self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib));
$thead = $this->tagname == 'table' ? self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib)) :
self::tag($this->_row_tagname(), array('class' => 'thead'), $rowcontent, parent::$common_attrib);
}
foreach ($this->rows as $r => $row) {
$rowcontent = '';
foreach ($row->cells as $c => $col) {
$rowcontent .= self::tag('td', $col->attrib, $col->content);
$rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content);
}
if ($r < $this->rowindex || count($row->cells)) {
$tbody .= self::tag('tr', $row->attrib, $rowcontent, parent::$common_attrib);
$tbody .= self::tag($this->_row_tagname(), $row->attrib, $rowcontent, parent::$common_attrib);
}
}
@ -837,7 +843,7 @@ class html_table extends html
}
// add <tbody>
$this->content = $thead . self::tag('tbody', null, $tbody);
$this->content = $thead . ($this->tagname == 'table' ? self::tag('tbody', null, $tbody) : $tbody);
unset($this->attrib['cols'], $this->attrib['rowsonly']);
return parent::show();
@ -862,4 +868,22 @@ class html_table extends html
$this->rowindex = 0;
}
/**
* Getter for the corresponding tag name for table row elements
*/
private function _row_tagname()
{
static $row_tagnames = array('table' => 'tr', 'ul' => 'li', '*' => 'div');
return $row_tagnames[$this->tagname] ?: $row_tagnames['*'];
}
/**
* Getter for the corresponding tag name for table cell elements
*/
private function _col_tagname()
{
static $col_tagnames = array('table' => 'td', '*' => 'span');
return $col_tagnames[$this->tagname] ?: $col_tagnames['*'];
}
}

@ -309,9 +309,14 @@ abstract class rcube_addressbook
* List all active contact groups of this source
*
* @param string Optional search string to match group name
* @param int Matching mode:
* 0 - partial (*abc*),
* 1 - strict (=),
* 2 - prefix (abc*)
*
* @return array Indexed list of contact groups, each a hash array
*/
function list_groups($search = null)
function list_groups($search = null, $mode = 0)
{
/* empty for address books don't supporting groups */
return array();
@ -370,9 +375,10 @@ abstract class rcube_addressbook
/**
* Add the given contact records the a certain group
*
* @param string Group identifier
* @param array List of contact identifiers to be added
* @return int Number of contacts added
* @param string Group identifier
* @param array|string List of contact identifiers to be added
*
* @return int Number of contacts added
*/
function add_to_group($group_id, $ids)
{
@ -383,9 +389,10 @@ abstract class rcube_addressbook
/**
* Remove the given contact records from a certain group
*
* @param string Group identifier
* @param array List of contact identifiers to be removed
* @return int Number of deleted group members
* @param string Group identifier
* @param array|string List of contact identifiers to be removed
*
* @return int Number of deleted group members
*/
function remove_from_group($group_id, $ids)
{
@ -425,7 +432,7 @@ abstract class rcube_addressbook
$out = array_merge($out, (array)$values);
}
else {
list($f, $type) = explode(':', $c);
list(, $type) = explode(':', $c);
$out[$type] = array_merge((array)$out[$type], (array)$values);
}
}
@ -528,7 +535,7 @@ abstract class rcube_addressbook
*/
public static function compose_contact_key($contact, $sort_col)
{
$key = $contact[$sort_col] . ':' . $row['sourceid'];
$key = $contact[$sort_col] . ':' . $contact['sourceid'];
// add email to a key to not skip contacts with the same name (#1488375)
if (!empty($contact['email'])) {
@ -538,7 +545,6 @@ abstract class rcube_addressbook
return $key;
}
/**
* Compare search value with contact data
*

@ -137,16 +137,34 @@ class rcube_contacts extends rcube_addressbook
* List all active contact groups of this source
*
* @param string Search string to match group name
* @param int Matching mode:
* 0 - partial (*abc*),
* 1 - strict (=),
* 2 - prefix (abc*)
*
* @return array Indexed list of contact groups, each a hash array
*/
function list_groups($search = null)
function list_groups($search = null, $mode = 0)
{
$results = array();
if (!$this->groups)
return $results;
$sql_filter = $search ? " AND " . $this->db->ilike('name', '%'.$search.'%') : '';
if ($search) {
switch (intval($mode)) {
case 1:
$sql_filter = $this->db->ilike('name', $search);
break;
case 2:
$sql_filter = $this->db->ilike('name', $search . '%');
break;
default:
$sql_filter = $this->db->ilike('name', '%' . $search . '%');
}
$sql_filter = " AND $sql_filter";
}
$sql_result = $this->db->query(
"SELECT * FROM ".$this->db->table_name($this->db_groups).
@ -879,9 +897,10 @@ class rcube_contacts extends rcube_addressbook
/**
* Add the given contact records the a certain group
*
* @param string Group identifier
* @param array List of contact identifiers to be added
* @return int Number of contacts added
* @param string Group identifier
* @param array|string List of contact identifiers to be added
*
* @return int Number of contacts added
*/
function add_to_group($group_id, $ids)
{
@ -926,9 +945,10 @@ class rcube_contacts extends rcube_addressbook
/**
* Remove the given contact records from a certain group
*
* @param string Group identifier
* @param array List of contact identifiers to be removed
* @return int Number of deleted group members
* @param string Group identifier
* @param array|string List of contact identifiers to be removed
*
* @return int Number of deleted group members
*/
function remove_from_group($group_id, $ids)
{

@ -130,6 +130,21 @@ class rcube_csv2vcard
'work_state' => 'region:work',
'home_city_short' => 'locality:home',
'home_state_short' => 'region:home',
// Atmail
'date_of_birth' => 'birthday',
'email' => 'email:pref',
'home_mobile' => 'phone:cell',
'home_zip' => 'zipcode:home',
'info' => 'notes',
'user_photo' => 'photo',
'url' => 'website:homepage',
'work_company' => 'organization',
'work_dept' => 'departament',
'work_fax' => 'phone:work,fax',
'work_mobile' => 'phone:work,cell',
'work_title' => 'jobtitle',
'work_zip' => 'zipcode:work',
);
/**
@ -230,8 +245,29 @@ class rcube_csv2vcard
'work_phone' => "Work Phone",
'work_address' => "Work Address",
//'work_address_2' => "Work Address 2",
'work_city' => "Work City",
'work_country' => "Work Country",
'work_state' => "Work State",
'work_zipcode' => "Work ZipCode",
// Atmail
'date_of_birth' => "Date of Birth",
'email' => "Email",
//'email_2' => "Email2",
//'email_3' => "Email3",
//'email_4' => "Email4",
//'email_5' => "Email5",
'home_mobile' => "Home Mobile",
'home_zip' => "Home Zip",
'info' => "Info",
'user_photo' => "User Photo",
'url' => "URL",
'work_company' => "Work Company",
'work_dept' => "Work Dept",
'work_fax' => "Work Fax",
'work_mobile' => "Work Mobile",
'work_title' => "Work Title",
'work_zip' => "Work Zip",
);
protected $local_label_map = array();
@ -268,7 +304,6 @@ class rcube_csv2vcard
{
// convert to UTF-8
$head = substr($csv, 0, 4096);
$fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1?
$charset = rcube_charset::detect($head, RCUBE_CHARSET);
$csv = rcube_charset::convert($csv, $charset);
$head = '';
@ -276,7 +311,7 @@ class rcube_csv2vcard
$this->map = array();
// Parse file
foreach (preg_split("/[\r\n]+/", $csv) as $i => $line) {
foreach (preg_split("/[\r\n]+/", $csv) as $line) {
$elements = $this->parse_line($line);
if (empty($elements)) {
continue;
@ -353,6 +388,12 @@ class rcube_csv2vcard
if (!empty($this->local_label_map)) {
for ($i = 0; $i < $size; $i++) {
$label = $this->local_label_map[$elements[$i]];
// special localization label
if ($label && $label[0] == '_') {
$label = substr($label, 1);
}
if ($label && !empty($this->csv2vcard_map[$label])) {
$map2[$i] = $this->csv2vcard_map[$label];
}
@ -384,9 +425,13 @@ class rcube_csv2vcard
$contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d'];
}
// Empty dates, e.g. "0/0/00", "0000-00-00 00:00:00"
foreach (array('birthday', 'anniversary') as $key) {
if (!empty($contact[$key]) && $contact[$key] == '0/0/00') { // @TODO: localization?
unset($contact[$key]);
if (!empty($contact[$key])) {
$date = preg_replace('/[0[:^word:]]/', '', $contact[$key]);
if (empty($date)) {
unset($contact[$key]);
}
}
}

@ -128,7 +128,7 @@ class rcube_db
$dsn_string = $this->dsn_string($dsn);
$dsn_options = $this->dsn_options($dsn);
if ($db_pconn) {
if ($this->db_pconn) {
$dsn_options[PDO::ATTR_PERSISTENT] = true;
}
@ -405,21 +405,22 @@ class rcube_db
$this->db_error_msg = null;
// send query
$query = $this->dbh->query($query);
$result = $this->dbh->query($query);
if ($query === false) {
if ($result === false) {
$error = $this->dbh->errorInfo();
$this->db_error = true;
$this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]);
rcube::raise_error(array('code' => 500, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__,
'message' => $this->db_error_msg), true, false);
'message' => $this->db_error_msg . " (SQL Query: $query)"
), true, false);
}
$this->last_result = $query;
$this->last_result = $result;
return $query;
return $result;
}
/**

@ -127,7 +127,7 @@ class rcube_db_mysql extends rcube_db
$result[PDO::MYSQL_ATTR_FOUND_ROWS] = true;
// Enable AUTOCOMMIT mode (#1488902)
$dsn_options[PDO::ATTR_AUTOCOMMIT] = true;
$result[PDO::ATTR_AUTOCOMMIT] = true;
return $result;
}
@ -147,7 +147,7 @@ class rcube_db_mysql extends rcube_db
$result = $this->query('SHOW VARIABLES');
while ($sql_arr = $this->fetch_array($result)) {
while ($row = $this->fetch_array($result)) {
$this->variables[$row[0]] = $row[1];
}
}

@ -118,7 +118,7 @@ class rcube_enriched
$quoted = '';
$lines = explode('<br>', $a[2]);
foreach ($lines as $n => $line)
foreach ($lines as $line)
$quoted .= '&gt;'.$line.'<br>';
$body = $a[1].'<span class="quotes">'.$quoted.'</span>'.$a[3];

@ -981,7 +981,7 @@ class rcube_imap extends rcube_storage
// use memory less expensive (and quick) method for big result set
$index = clone $this->index('', $this->sort_field, $this->sort_order);
// get messages uids for one page...
$index->slice($start_msg, min($cnt-$from, $this->page_size));
$index->slice($from, min($cnt-$from, $this->page_size));
if ($slice) {
$index->slice(-$slice, $slice);
@ -1423,8 +1423,6 @@ class rcube_imap extends rcube_storage
*/
protected function search_index($folder, $criteria='ALL', $charset=NULL, $sort_field=NULL)
{
$orig_criteria = $criteria;
if (!$this->check_connection()) {
if ($this->threading) {
return new rcube_result_thread();
@ -2727,7 +2725,7 @@ class rcube_imap extends rcube_storage
// filter folders list according to rights requirements
if ($rights && $this->get_capability('ACL')) {
$a_folders = $this->filter_rights($a_folders, $rights);
$a_mboxes = $this->filter_rights($a_mboxes, $rights);
}
// filter folders and sort them
@ -2783,7 +2781,6 @@ class rcube_imap extends rcube_storage
*/
private function list_folders_update(&$result, $type = null)
{
$delim = $this->get_hierarchy_delimiter();
$namespace = $this->get_namespace();
$search = array();
@ -3846,7 +3843,7 @@ class rcube_imap extends rcube_storage
$delimiter = $this->get_hierarchy_delimiter();
// find default folders and skip folders starting with '.'
foreach ($a_folders as $i => $folder) {
foreach ($a_folders as $folder) {
if ($folder[0] == '.') {
continue;
}

@ -430,7 +430,7 @@ class rcube_imap_cache
." AND uid = ?",
$flags, $msg, $this->userid, $mailbox, (int) $message->uid);
if ($this->db->affected_rows()) {
if ($this->db->affected_rows($res)) {
return;
}
}
@ -983,7 +983,7 @@ class rcube_imap_cache
$uids, true, array('FLAGS'), $index['modseq'], $qresync);
if (!empty($result)) {
foreach ($result as $id => $msg) {
foreach ($result as $msg) {
$uid = $msg->uid;
// Remove deleted message
if ($this->skip_deleted && !empty($msg->flags['DELETED'])) {

@ -746,7 +746,7 @@ class rcube_imap_generic
}
if ($this->prefs['timeout'] <= 0) {
$this->prefs['timeout'] = ini_get('default_socket_timeout');
$this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout')));
}
// Connect
@ -1077,7 +1077,7 @@ class rcube_imap_generic
}
if (!$this->data['READ-WRITE']) {
$this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'EXPUNGE');
$this->setError(self::ERROR_READONLY, "Mailbox is read-only");
return false;
}
@ -1652,7 +1652,6 @@ class rcube_imap_generic
}
if (!empty($criteria)) {
$modseq = stripos($criteria, 'MODSEQ') !== false;
$params .= ($params ? ' ' : '') . $criteria;
}
else {
@ -1791,7 +1790,6 @@ class rcube_imap_generic
if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) {
$flags = explode(' ', strtoupper($matches[1]));
if (in_array('\\DELETED', $flags)) {
$deleted[$id] = $id;
continue;
}
}
@ -1936,7 +1934,7 @@ class rcube_imap_generic
}
if (!$this->data['READ-WRITE']) {
$this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE');
$this->setError(self::ERROR_READONLY, "Mailbox is read-only");
return false;
}
@ -1997,7 +1995,7 @@ class rcube_imap_generic
}
if (!$this->data['READ-WRITE']) {
$this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE');
$this->setError(self::ERROR_READONLY, "Mailbox is read-only");
return false;
}
@ -2172,7 +2170,7 @@ class rcube_imap_generic
// create array with header field:data
if (!empty($headers)) {
$headers = explode("\n", trim($headers));
foreach ($headers as $hid => $resln) {
foreach ($headers as $resln) {
if (ord($resln[0]) <= 32) {
$lines[$ln] .= (empty($lines[$ln]) ? '' : "\n") . trim($resln);
} else {
@ -2180,7 +2178,7 @@ class rcube_imap_generic
}
}
while (list($lines_key, $str) = each($lines)) {
foreach ($lines as $str) {
list($field, $string) = explode(':', $str, 2);
$field = strtolower($field);
@ -2508,7 +2506,7 @@ class rcube_imap_generic
$tokens = $this->tokenizeResponse(preg_replace('/(^\(|\)$)/', '', $line));
for ($i=0; $i<count($tokens); $i+=2) {
if (preg_match('/^(BODY|BINARY)/i', $token)) {
if (preg_match('/^(BODY|BINARY)/i', $tokens[$i])) {
$result = $tokens[$i+1];
$found = true;
break;
@ -3540,7 +3538,7 @@ class rcube_imap_generic
if (is_array($element)) {
reset($element);
while (list($key, $value) = each($element)) {
foreach ($element as $value) {
$string .= ' ' . self::r_implode($value);
}
}

@ -169,7 +169,7 @@ class rcube_ldap extends rcube_addressbook
// Build sub_fields filter
if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) {
$this->sub_filter = '';
foreach ($this->prop['sub_fields'] as $attr => $class) {
foreach ($this->prop['sub_fields'] as $class) {
if (!empty($class)) {
$class = is_array($class) ? array_pop($class) : $class;
$this->sub_filter .= '(objectClass=' . $class . ')';
@ -1035,7 +1035,6 @@ class rcube_ldap extends rcube_addressbook
$mail_field = $this->fieldmap['email'];
// try to extract surname and firstname from displayname
$reverse_map = array_flip($this->fieldmap);
$name_parts = preg_split('/[\s,.]+/', $save_data['name']);
if ($sn_field && $missing[$sn_field]) {
@ -1107,7 +1106,7 @@ class rcube_ldap extends rcube_addressbook
// Remove attributes that need to be added separately (child objects)
$xfields = array();
if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) {
foreach ($this->prop['sub_fields'] as $xf => $xclass) {
foreach (array_keys($this->prop['sub_fields']) as $xf) {
if (!empty($newentry[$xf])) {
$xfields[$xf] = $newentry[$xf];
unset($newentry[$xf]);
@ -1170,7 +1169,7 @@ class rcube_ldap extends rcube_addressbook
}
}
foreach ($this->fieldmap as $col => $fld) {
foreach ($this->fieldmap as $fld) {
if ($fld) {
$val = $ldap_data[$fld];
$old = $old_data[$fld];
@ -1396,6 +1395,10 @@ class rcube_ldap extends rcube_addressbook
*/
protected function add_autovalues(&$attrs)
{
if (empty($this->prop['autovalues'])) {
return;
}
$attrvals = array();
foreach ($attrs as $k => $v) {
$attrvals['{'.$k.'}'] = is_array($v) ? $v[0] : $v;
@ -1403,13 +1406,24 @@ class rcube_ldap extends rcube_addressbook
foreach ((array)$this->prop['autovalues'] as $lf => $templ) {
if (empty($attrs[$lf])) {
// replace {attr} placeholders with concrete attribute values
$templ = preg_replace('/\{\w+\}/', '', strtr($templ, $attrvals));
if (strpos($templ, '(') !== false) {
// replace {attr} placeholders with (escaped!) attribute values to be safely eval'd
$code = preg_replace('/\{\w+\}/', '', strtr($templ, array_map('addslashes', $attrvals)));
$fn = create_function('', "return ($code);");
if (!$fn) {
rcube::raise_error(array(
'code' => 505, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Expression parse error on: ($code)"), true, false);
continue;
}
if (strpos($templ, '(') !== false)
$attrs[$lf] = eval("return ($templ);");
else
$attrs[$lf] = $templ;
$attrs[$lf] = $fn();
}
else {
// replace {attr} placeholders with concrete attribute values
$attrs[$lf] = preg_replace('/\{\w+\}/', '', strtr($templ, $attrvals));
}
}
}
}
@ -1715,9 +1729,14 @@ class rcube_ldap extends rcube_addressbook
* List all active contact groups of this source
*
* @param string Optional search string to match group name
* @param int Matching mode:
* 0 - partial (*abc*),
* 1 - strict (=),
* 2 - prefix (abc*)
*
* @return array Indexed list of contact groups, each a hash array
*/
function list_groups($search = null)
function list_groups($search = null, $mode = 0)
{
if (!$this->groups)
return array();
@ -1729,10 +1748,10 @@ class rcube_ldap extends rcube_addressbook
$groups = array();
if ($search) {
$search = mb_strtolower($search);
foreach ($group_cache as $group) {
if (strpos(mb_strtolower($group['name']), $search) !== false)
if ($this->compare_search_value('name', $group['name'], $search, $mode)) {
$groups[] = $group;
}
}
}
else
@ -1763,7 +1782,7 @@ class rcube_ldap extends rcube_addressbook
$vlv_active = $this->_vlv_set_controls($this->prop['groups'], $vlv_page+1, $page_size);
}
$function = $this->_scope2func($this->prop['groups']['scope'], $ns_function);
$function = $this->_scope2func($this->prop['groups']['scope']);
$res = @$function($this->conn, $base_dn, $filter, array_unique(array('dn', 'objectClass', $name_attr, $email_attr, $sort_attr)));
if ($res === false)
{
@ -1921,9 +1940,10 @@ class rcube_ldap extends rcube_addressbook
/**
* Add the given contact records the a certain group
*
* @param string Group identifier
* @param array List of contact identifiers to be added
* @return int Number of contacts added
* @param string Group identifier
* @param array|string List of contact identifiers to be added
*
* @return int Number of contacts added
*/
function add_to_group($group_id, $contact_ids)
{
@ -1937,8 +1957,8 @@ class rcube_ldap extends rcube_addressbook
$group_name = $group_cache[$group_id]['name'];
$member_attr = $group_cache[$group_id]['member_attr'];
$group_dn = "cn=$group_name,$base_dn";
$new_attrs = array();
$new_attrs = array();
foreach ($contact_ids as $id)
$new_attrs[$member_attr][] = self::dn_decode($id);
@ -1949,28 +1969,32 @@ class rcube_ldap extends rcube_addressbook
$this->cache->remove('groups');
return count($new_attrs['member']);
return count($new_attrs[$member_attr]);
}
/**
* Remove the given contact records from a certain group
*
* @param string Group identifier
* @param array List of contact identifiers to be removed
* @return int Number of deleted group members
* @param string Group identifier
* @param array|string List of contact identifiers to be removed
*
* @return int Number of deleted group members
*/
function remove_from_group($group_id, $contact_ids)
{
if (($group_cache = $this->cache->get('groups')) === null)
$group_cache = $this->_fetch_groups();
if (!is_array($contact_ids))
$contact_ids = explode(',', $contact_ids);
$base_dn = $this->groups_base_dn;
$group_name = $group_cache[$group_id]['name'];
$member_attr = $group_cache[$group_id]['member_attr'];
$group_dn = "cn=$group_name,$base_dn";
$del_attrs = array();
$del_attrs = array();
foreach (explode(",", $contact_ids) as $id)
foreach ($contact_ids as $id)
$del_attrs[$member_attr][] = self::dn_decode($id);
if (!$this->ldap_mod_del($group_dn, $del_attrs)) {
@ -1980,7 +2004,7 @@ class rcube_ldap extends rcube_addressbook
$this->cache->remove('groups');
return count($del_attrs['member']);
return count($del_attrs[$member_attr]);
}
/**

@ -362,7 +362,7 @@ class rcube_message
// parse headers from message/rfc822 part
if (!isset($structure->headers['subject']) && !isset($structure->headers['from'])) {
list($headers, $dump) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 32768));
list($headers, ) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 32768));
$structure->headers = rcube_mime::parse_headers($headers);
}
}

@ -127,10 +127,11 @@ class rcube_mime
* @param int $max List only this number of addresses
* @param boolean $decode Decode address strings
* @param string $fallback Fallback charset if none specified
* @param boolean $addronly Return flat array with e-mail addresses only
*
* @return array Indexed list of addresses
* @return array Indexed list of addresses
*/
static function decode_address_list($input, $max = null, $decode = true, $fallback = null)
static function decode_address_list($input, $max = null, $decode = true, $fallback = null, $addronly = false)
{
$a = self::parse_address_list($input, $decode, $fallback);
$out = array();
@ -145,20 +146,21 @@ class rcube_mime
foreach ($a as $val) {
$j++;
$address = trim($val['address']);
$name = trim($val['name']);
if ($name && $address && $name != $address)
$string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address);
else if ($address)
$string = $address;
else if ($name)
$string = $name;
$out[$j] = array(
'name' => $name,
'mailto' => $address,
'string' => $string
);
if ($addronly) {
$out[$j] = $address;
}
else {
$name = trim($val['name']);
if ($name && $address && $name != $address)
$string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address);
else if ($address)
$string = $address;
else if ($name)
$string = $name;
$out[$j] = array('name' => $name, 'mailto' => $address, 'string' => $string);
}
if ($max && $j==$max)
break;
@ -476,9 +478,10 @@ class rcube_mime
$q_level = 0;
foreach ($text as $idx => $line) {
if ($line[0] == '>') {
// remove quote chars, store level in $q
$line = preg_replace('/^>+/', '', $line, -1, $q);
if (preg_match('/^(>+)/', $line, $m)) {
// remove quote chars
$q = strlen($m[1]);
$line = preg_replace('/^>+/', '', $line);
// remove (optional) space-staffing
$line = preg_replace('/^ /', '', $line);
@ -541,9 +544,10 @@ class rcube_mime
foreach ($text as $idx => $line) {
if ($line != '-- ') {
if ($line[0] == '>') {
// remove quote chars, store level in $level
$line = preg_replace('/^>+/', '', $line, -1, $level);
if (preg_match('/^(>+)/', $line, $m)) {
// remove quote chars
$level = strlen($m[1]);
$line = preg_replace('/^>+/', '', $line);
// remove (optional) space-staffing and spaces before the line end
$line = preg_replace('/(^ | +$)/', '', $line);
$prefix = str_repeat('>', $level) . ' ';
@ -657,8 +661,8 @@ class rcube_mime
$cutLength = $spacePos + 1;
}
else {
$subString = $string;
$cutLength = null;
$subString = $substr_func($string, 0, $breakPos, $charset);
$cutLength = $breakPos + 1;
}
}
else {

@ -162,7 +162,7 @@ abstract class rcube_output
header("Cache-Control: private, must-revalidate");
}
else {
header("Cache-Control: private, no-cache, must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private, no-cache, no-store, must-revalidate, post-check=0, pre-check=0");
header("Pragma: no-cache");
}
}

@ -313,7 +313,6 @@ class rcube_plugin_api
$doc->loadXML($file);
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('rc', "http://pear.php.net/dtd/package-2.0");
$data = array();
// XPaths of plugin metadata elements
$metadata = array(

@ -119,7 +119,7 @@ class rcube_smtp
}
// try to connect to server and exit on failure
$result = $this->conn->connect($smtp_timeout);
$result = $this->conn->connect($CONFIG['smtp_timeout']);
if (PEAR::isError($result)) {
$this->response[] = "Connection failed: ".$result->getMessage();
@ -433,9 +433,9 @@ class rcube_smtp
$recipients = rcube_utils::explode_quoted_string(',', $recipients);
reset($recipients);
while (list($k, $recipient) = each($recipients)) {
foreach ($recipients as $recipient) {
$a = rcube_utils::explode_quoted_string(' ', $recipient);
while (list($k2, $word) = each($a)) {
foreach ($a as $word) {
if (strpos($word, "@") > 0 && $word[strlen($word)-1] != '"') {
$word = preg_replace('/^<|>$/', '', trim($word));
if (in_array($word, $addresses) === false) {

@ -314,11 +314,6 @@ class rcube_spellchecker
if (!$this->plink) {
if (!extension_loaded('pspell')) {
$this->error = "Pspell extension not available";
rcube::raise_error(array(
'code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => $this->error), true, false);
return;
}
@ -372,9 +367,19 @@ class rcube_spellchecker
fclose($fp);
}
// parse HTTP response
if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $store, $m)) {
$http_status = $m[1];
if ($http_status != '200')
$this->error = 'HTTP ' . $m[1] . $m[2];
}
if (!$store) {
$this->error = "Empty result from spelling engine";
}
else if (preg_match('/<spellresult error="([^"]+)"/', $store, $m)) {
$this->error = "Error code $m[1] returned";
}
preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER);
@ -588,7 +593,7 @@ class rcube_spellchecker
if (empty($plugin['abort'])) {
$dict = array();
$this->rc->db->query(
$sql_result = $this->rc->db->query(
"SELECT data FROM ".$this->rc->db->table_name('dictionary')
." WHERE user_id ". ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
." AND " . $this->rc->db->quoteIdentifier('language') . " = ?",

@ -404,7 +404,7 @@ class rcube_utils
$out = array();
$src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST);
foreach ($src as $key => $value) {
foreach (array_keys($src) as $key) {
$fname = $key[0] == '_' ? substr($key, 1) : $key;
if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) {
$out[$fname] = self::get_input_value($key, $mode);

@ -90,7 +90,7 @@ class rcube_vcard
*/
public function __construct($vcard = null, $charset = RCUBE_CHARSET, $detect = false, $fieldmap = array())
{
if (!empty($fielmap)) {
if (!empty($fieldmap)) {
$this->extend_fieldmap($fieldmap);
}
@ -481,7 +481,7 @@ class rcube_vcard
$vcard_block = '';
$in_vcard_block = false;
foreach (preg_split("/[\r\n]+/", $data) as $i => $line) {
foreach (preg_split("/[\r\n]+/", $data) as $line) {
if ($in_vcard_block && !empty($line)) {
$vcard_block .= $line . "\n";
}
@ -784,9 +784,30 @@ class rcube_vcard
}
return $result;
}
$s = strtr($s, $rep2);
}
// some implementations (GMail) use non-standard backslash before colon (#1489085)
// we will handle properly any backslashed character - removing dummy backslahes
// return strtr($s, array("\r" => '', '\\\\' => '\\', '\n' => "\n", '\N' => "\n", '\,' => ',', '\;' => ';'));
$s = str_replace("\r", '', $s);
$pos = 0;
while (($pos = strpos($s, '\\', $pos)) !== false) {
$next = substr($s, $pos + 1, 1);
if ($next == 'n' || $next == 'N') {
$s = substr_replace($s, "\n", $pos, 2);
}
else {
$s = substr_replace($s, '', $pos, 1);
}
$pos += 1;
}
return strtr($s, array("\r" => '', '\\\\' => '\\', '\n' => "\n", '\N' => "\n", '\,' => ',', '\;' => ';'));
return $s;
}
/**

@ -60,8 +60,8 @@ Class utf8 {
function loadCharset($charset) {
$charset = preg_replace(array('/^WINDOWS-*125([0-8])$/', '/^CP-/'), array('CP125\\1', 'CP'), $charset);
if (isset($aliases[$charset]))
$charset = $aliases[$charset];
if (isset($this->aliases[$charset]))
$charset = $this->aliases[$charset];
$this->charset = $charset;

@ -397,6 +397,7 @@ $labels['pagesize'] = 'Rows per page';
$labels['signature'] = 'Signature';
$labels['dstactive'] = 'Summer time';
$labels['showinextwin'] = 'Open message in a new window';
$labels['showemail'] = 'Show email address with display name';
$labels['composeextwin'] = 'Compose in a new window';
$labels['htmleditor'] = 'Compose HTML messages';
$labels['htmlonreply'] = 'on reply to HTML message only';

@ -91,3 +91,20 @@ $map['work_phone'] = "Work Phone";
$map['work_address'] = "Work Address";
$map['work_country'] = "Work Country";
$map['work_zipcode'] = "Work ZipCode";
// Atmail
$map['date_of_birth'] = "Date of Birth";
$map['email'] = "Email";
$map['home_mobile'] = "Home Mobile";
$map['home_zip'] = "Home Zip";
$map['info'] = "Info";
$map['user_photo'] = "User Photo";
$map['url'] = "URL";
$map['work_city'] = "Work City";
$map['work_company'] = "Work Company";
$map['work_dept'] = "Work Dept";
$map['work_fax'] = "Work Fax";
$map['work_mobile'] = "Work Mobile";
$map['work_state'] = "Work State";
$map['work_title'] = "Work Title";
$map['work_zip'] = "Work Zip";

@ -402,6 +402,7 @@ $labels['htmleditor'] = 'Compose HTML messages';
$labels['htmlonreply'] = 'on reply to HTML message';
$labels['htmlonreplyandforward'] = 'on forward or reply to HTML message';
$labels['htmlsignature'] = 'HTML signature';
$labels['showemail'] = 'Show email address with display name';
$labels['previewpane'] = 'Show preview pane';
$labels['skin'] = 'Interface skin';
$labels['logoutclear'] = 'Clear Trash on logout';

@ -0,0 +1,96 @@
<?php
/*
+-----------------------------------------------------------------------+
| localization/<lang>/csv2vcard.inc |
| |
| Localization file of the Roundcube Webmail client |
| Copyright (C) 2005-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
// This is a list of CSV column names specified in CSV file header
// These must be original texts used in Outlook/Thunderbird exported csv files
// Encoding UTF-8
$map = array();
// MS Outlook 2010
$map['anniversary'] = "Anniversaire de mariage ou fête";
$map['assistants_name'] = "Nom de l''assistant(e)";
$map['assistants_phone'] = "Téléphone de l''assistant(e)";
$map['birthday'] = "Anniversaire";
$map['business_city'] = "Ville (bureau)";
$map['business_countryregion'] = "Pays/Région (bureau)";
$map['business_fax'] = "Télécopie (bureau)";
$map['business_phone'] = "Téléphone (bureau)";
$map['business_phone_2'] = "Téléphone 2 (bureau)";
$map['business_postal_code'] = "Code postal (bureau)";
$map['business_state'] = "Dép/Région (bureau)";
$map['business_street'] = "Rue (bureau)";
$map['car_phone'] = "Téléphone (voiture)";
$map['categories'] = "Catégories";
$map['company'] = "Société";
$map['department'] = "Service";
$map['email_address'] = "Adresse de messagerie";
$map['first_name'] = "Prénom";
$map['gender'] = "Sexe";
$map['home_city'] = "Ville (domicile)";
$map['home_countryregion'] = "Pays/Région (domicile)";
$map['home_fax'] = "Télécopie (domicile)";
$map['home_phone'] = "Téléphone (domicile)";
$map['home_phone_2'] = "Téléphone 2 (domicile)";
$map['home_postal_code'] = "Code postal (domicile)";
$map['home_state'] = "Dép/Région (domicile)";
$map['home_street'] = "Rue (domicile)";
$map['job_title'] = "Profession";
$map['last_name'] = "Nom";
$map['managers_name'] = "Manager's Name";
$map['middle_name'] = "Deuxième prénom";
$map['mobile_phone'] = "Tél. mobile";
$map['notes'] = "Notes";
$map['other_city'] = "Ville (autre)";
$map['other_countryregion'] = "Pays/Région (autre)";
$map['other_fax'] = "Télécopie (autre)";
$map['other_phone'] = "Téléphone (autre)";
$map['other_postal_code'] = "Code postal (autre)";
$map['other_state'] = "Dép/Région (autre)";
$map['other_street'] = "Rue (autre)";
$map['pager'] = "Récepteur de radiomessagerie";
$map['primary_phone'] = "Téléphone principal";
$map['spouse'] = "Conjoint(e)";
$map['suffix'] = "Suffixe";
$map['title'] = "Titre";
$map['web_page'] = "Page Web";
// Thunderbird
$map['birth_day'] = "Jour";
$map['birth_month'] = "Mois";
$map['birth_year'] = "Année de naissance";
$map['display_name'] = "Nom à afficher";
$map['fax_number'] = "Fax";
$map['home_address'] = "Adresse privée";
$map['home_country'] = "Région";
$map['home_zipcode'] = "Code postal";
$map['mobile_number'] = "Portable";
$map['nickname'] = "Surnom";
$map['organization'] = "Société";
$map['pager_number'] = "Pager";
$map['primary_email'] = "Adresse électronique principale";
$map['secondary_email'] = "Adresse électronique secondaire";
$map['web_page_1'] = "Site Web 1";
$map['web_page_2'] = "Site Web 2";
$map['work_phone'] = "Tél. professionnel";
$map['work_address'] = "Adresse professionnelle";
$map['work_country'] = "Région";
$map['work_zipcode'] = "Code postal";
// Other
$map['_home_city'] = "Ville";

@ -167,7 +167,7 @@ function rcmail_set_sourcename($abook)
// get address book name (for display)
if ($abook && $_SESSION['addressbooks_count'] > 1) {
$name = $abook->get_name();
if (!$name && $source == 0) {
if (!$name) {
$name = rcube_label('personaladrbook');
}
$OUTPUT->set_env('sourcename', html_entity_decode($name, ENT_COMPAT, 'UTF-8'));
@ -183,7 +183,6 @@ function rcmail_directory_list($attrib)
$attrib['id'] = 'rcmdirectorylist';
$out = '';
$local_id = '0';
$jsdata = array();
$line_templ = html::tag('li', array(
@ -270,7 +269,6 @@ function rcmail_contact_groups($args)
$groups_html = '';
$groups = $RCMAIL->get_address_book($args['source'])->list_groups();
$js_id = $RCMAIL->JQ($args['source']);
if (!empty($groups)) {
$line_templ = html::tag('li', array(
@ -283,7 +281,6 @@ function rcmail_contact_groups($args)
$is_collapsed = strpos($RCMAIL->config->get('collapsed_abooks',''), '&'.rawurlencode($args['source']).'&') !== false;
$args['out'] .= html::div('treetoggle ' . ($is_collapsed ? 'collapsed' : 'expanded'), '&nbsp;');
$jsdata = array();
foreach ($groups as $group) {
$groups_html .= sprintf($line_templ,
rcube_utils::html_identifier('G' . $args['source'] . $group['ID'], true),
@ -297,7 +294,7 @@ function rcmail_contact_groups($args)
}
$args['out'] .= html::tag('ul',
array('class' => 'groups', 'style' => ($is_collapsed ? "display:none;" : null)),
array('class' => 'groups', 'style' => ($is_collapsed || empty($groups) ? "display:none;" : null)),
$groups_html);
return $args;

@ -88,7 +88,7 @@ function rcmail_import_confirm($attrib)
$content = html::p(null, rcube_label(array(
'name' => 'importconfirm',
'nr' => $IMORT_STATS->inserted,
'nr' => $IMPORT_STATS->inserted,
'vars' => $vars,
)) . ($IMPORT_STATS->names ? ':' : '.'));
@ -98,7 +98,7 @@ function rcmail_import_confirm($attrib)
if ($IMPORT_STATS->skipped) {
$content .= html::p(null, rcube_label(array(
'name' => 'importconfirmskipped',
'nr' => $IMORT_STATS->skipped,
'nr' => $IMPORT_STATS->skipped,
'vars' => $vars,
)) . ':');
$content .= html::p('em', join(', ', array_map('Q', $IMPORT_STATS->skipped_names)));

@ -101,8 +101,6 @@ function rcmail_contact_head($attrib)
return false;
}
$microformats = array('name' => 'fn', 'email' => 'email');
$form = array(
'head' => array( // section 'head' is magic!
'content' => array(
@ -177,7 +175,7 @@ function rcmail_contact_details($attrib)
}
function rcmail_render_email_value($email, $col)
function rcmail_render_email_value($email)
{
return html::a(array(
'href' => 'mailto:' . $email,
@ -188,7 +186,7 @@ function rcmail_render_email_value($email, $col)
}
function rcmail_render_url_value($url, $col)
function rcmail_render_url_value($url)
{
$prefix = preg_match('!^(http|ftp)s?://!', $url) ? '' : 'http://';
return html::a(array(
@ -223,7 +221,7 @@ function rcmail_contact_record_groups($contact_id)
}
$hiddenfields = new html_hiddenfield(array('name' => '_source', 'value' => get_input_value('_source', RCUBE_INPUT_GPC)));
$hiddenfields->add(array('name' => '_cid', 'value' => $record['ID']));
$hiddenfields->add(array('name' => '_cid', 'value' => $contact_id));
$form_start = $RCMAIL->output->request_form(array(
'name' => "form", 'method' => "post",

@ -102,7 +102,7 @@ if (!empty($book_types) && strlen($search)) {
// also list matching contact groups
if ($abook->groups && count($contacts) < $MAXNUM) {
foreach ($abook->list_groups($search) as $group) {
foreach ($abook->list_groups($search, $mode) as $group) {
$abook->reset();
$abook->set_group($group['ID']);
$group_prop = $abook->get_group($group['ID']);

@ -327,6 +327,19 @@ foreach ($parts as $header) {
$fvalue .= $v;
if ($v = $MESSAGE->headers->cc)
$fvalue .= (!empty($fvalue) ? $separator : '') . $v;
if ($v = $MESSAGE->headers->get('Sender', false))
$fvalue .= (!empty($fvalue) ? $separator : '') . $v;
// When To: and Reply-To: are the same we add From: address to the list (#1489037)
if ($v = $MESSAGE->headers->from) {
$from = rcube_mime::decode_address_list($v, null, false, $MESSAGE->headers->charset, true);
$to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, false, $MESSAGE->headers->charset, true);
$replyto = rcube_mime::decode_address_list($MESSAGE->headers->replyto, null, false, $MESSAGE->headers->charset, true);
if (count($replyto) && !count(array_diff($to, $replyto)) && count(array_diff($from, $to))) {
$fvalue .= (!empty($fvalue) ? $separator : '') . $v;
}
}
}
}
else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) {
@ -386,7 +399,7 @@ function rcmail_compose_headers($attrib)
{
global $MESSAGE;
list($form_start, $form_end) = get_form_tags($attrib);
list($form_start,) = get_form_tags($attrib);
$out = '';
$part = strtolower($attrib['part']);
@ -450,7 +463,7 @@ function rcmail_compose_headers($attrib)
function rcmail_compose_header_from($attrib)
{
global $MESSAGE, $OUTPUT, $RCMAIL, $compose_mode;
global $MESSAGE, $OUTPUT, $RCMAIL, $COMPOSE, $compose_mode;
// pass the following attributes to the form class
$field_attrib = array('name' => '_from');
@ -553,7 +566,7 @@ function rcmail_message_is_html()
function rcmail_prepare_message_body()
{
global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $LINE_LENGTH, $HTML_MODE;
global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $HTML_MODE;
// use posted message body
if (!empty($_POST['_message'])) {
@ -626,7 +639,7 @@ function rcmail_prepare_message_body()
function rcmail_compose_part_body($part, $isHtml = false)
{
global $RCMAIL, $MESSAGE, $compose_mode;
global $RCMAIL, $MESSAGE, $LINE_LENGTH, $compose_mode;
// Check if we have enough memory to handle the message in it
// #1487424: we need up to 10x more memory than the body
@ -702,7 +715,7 @@ function rcmail_compose_part_body($part, $isHtml = false)
function rcmail_compose_body($attrib)
{
global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $LINE_LENGTH, $HTML_MODE, $MESSAGE_BODY;
global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $HTML_MODE, $MESSAGE_BODY;
list($form_start, $form_end) = get_form_tags($attrib);
unset($attrib['form']);
@ -886,8 +899,7 @@ function rcmail_create_forward_body($body, $bodyIsHtml)
if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts))
$cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml);
$date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long'));
$charset = $RCMAIL->output->get_charset();
$date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long'));
if (!$bodyIsHtml) {
$prefix = "\n\n\n-------- " . rcube_label('originalmessage') . " --------\n";
@ -941,7 +953,7 @@ function rcmail_create_forward_body($body, $bodyIsHtml)
function rcmail_create_draft_body($body, $bodyIsHtml)
{
global $MESSAGE, $OUTPUT, $COMPOSE;
global $MESSAGE, $COMPOSE;
/**
* add attachments
@ -989,7 +1001,7 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml)
global $RCMAIL, $COMPOSE, $compose_mode;
$loaded_attachments = array();
foreach ((array)$COMPOSE['attachments'] as $id => $attachment) {
foreach ((array)$COMPOSE['attachments'] as $attachment) {
$loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment;
}
@ -1076,7 +1088,7 @@ function rcmail_write_forward_attachments()
$names = array();
$loaded_attachments = array();
foreach ((array)$COMPOSE['attachments'] as $id => $attachment) {
foreach ((array)$COMPOSE['attachments'] as $attachment) {
$loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment;
}
@ -1211,10 +1223,11 @@ function rcmail_save_image($path, $mimetype='')
// handle attachments in memory
$data = file_get_contents($path);
$name = rcmail_basename($path);
$attachment = array(
'group' => $COMPOSE['id'],
'name' => rcmail_basename($path),
'name' => $name,
'mimetype' => $mimetype ? $mimetype : rc_mime_content_type($path, $name),
'data' => $data,
'size' => strlen($data),
@ -1484,7 +1497,7 @@ function rcmail_editor_selector($attrib)
$select->add(Q(rcube_label('plaintoggle')), 'plain');
return $select->show($useHtml ? 'html' : 'plain');
/*
foreach ($choices as $value => $text) {
$attrib['id'] = '_' . $value;
$attrib['value'] = $value;
@ -1492,6 +1505,7 @@ function rcmail_editor_selector($attrib)
}
return $selector;
*/
}

@ -224,7 +224,7 @@ function rcmail_message_list($attrib)
if (!in_array('threads', $a_show_cols))
array_unshift($a_show_cols, 'threads');
$skin_path = $_SESSION['skin_path'] = $CONFIG['skin_path'];
$_SESSION['skin_path'] = $CONFIG['skin_path'];
// set client env
$OUTPUT->add_gui_object('messagelist', $attrib['id']);
@ -236,15 +236,13 @@ function rcmail_message_list($attrib)
$OUTPUT->include_script('list.js');
$thead = '';
foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell)
$thead .= html::tag('td', array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']);
$table = new html_table($attrib);
if (!$attrib['noheader']) {
foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell)
$table->add_header(array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']);
}
return html::tag('table',
$attrib,
html::tag('thead', null, html::tag('tr', null, $thead)) .
html::tag('tbody', null, ''),
array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
return $table->show();
}
@ -291,7 +289,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
$thead = $head_replace ? rcmail_message_list_head($_SESSION['list_attrib'], $a_show_cols) : NULL;
// get name of smart From/To column in folder context
if (($f = array_search('fromto', $a_show_cols)) !== false) {
if (array_search('fromto', $a_show_cols) !== false) {
$smart_col = rcmail_message_list_smart_column_name();
}
@ -307,7 +305,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
}
// loop through message headers
foreach ($a_headers as $n => $header) {
foreach ($a_headers as $header) {
if (empty($header))
continue;
@ -381,7 +379,6 @@ function rcmail_message_list_head($attrib, $a_show_cols)
global $RCMAIL;
$skin_path = $_SESSION['skin_path'];
$image_tag = html::img(array('src' => "%s%s", 'alt' => "%s"));
// check to see if we have some settings for sorting
$sort_col = $_SESSION['sort_col'];
@ -417,7 +414,7 @@ function rcmail_message_list_head($attrib, $a_show_cols)
$cells = array();
// get name of smart From/To column in folder context
if (($f = array_search('fromto', $a_show_cols)) !== false) {
if (array_search('fromto', $a_show_cols) !== false) {
$smart_col = rcmail_message_list_smart_column_name();
}
@ -897,7 +894,7 @@ function rcmail_washtml_callback($tagname, $attrib, $content, $washtml)
*/
function rcmail_message_headers($attrib, $headers=null)
{
global $OUTPUT, $MESSAGE, $PRINT_MODE, $RCMAIL;
global $MESSAGE, $PRINT_MODE, $RCMAIL;
static $sa_attrib;
// keep header table attrib
@ -1082,7 +1079,7 @@ function rcmail_message_body($attrib)
$header_attrib[$regs[1]] = $value;
if (!empty($MESSAGE->parts)) {
foreach ($MESSAGE->parts as $i => $part) {
foreach ($MESSAGE->parts as $part) {
if ($part->type == 'headers') {
$out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers));
}
@ -1440,7 +1437,8 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
$c = count($a_parts);
$j = 0;
$out = '';
$allvalues = array();
$allvalues = array();
$show_email = $RCMAIL->config->get('message_show_email');
if ($addicon && !isset($_SESSION['writeable_abook'])) {
$_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false;
@ -1453,7 +1451,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
$string = $part['string'];
// phishing email prevention (#1488981), e.g. "valid@email.addr <phishing@email.addr>"
if ($name && $name != $mailto && strpos($name, '@')) {
if (!$show_email && $name && $name != $mailto && strpos($name, '@')) {
$name = '';
}
@ -1471,13 +1469,21 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
}
else if (check_email($part['mailto'], false)) {
if ($linked) {
$address = html::a(array(
'href' => 'mailto:'.$mailto,
'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)),
'title' => $mailto,
'class' => "rcmContactAddress",
),
Q($name ? $name : $mailto));
$attrs = array(
'href' => 'mailto:' . $mailto,
'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)),
'class' => "rcmContactAddress",
);
if ($show_email && $name && $mailto) {
$content = Q($name ? sprintf('%s <%s>', $name, $mailto) : $mailto);
}
else {
$content = Q($name ? $name : $mailto);
$attrs['title'] = $mailto;
}
$address = html::a($attrs, $content);
}
else {
$address = html::span(array('title' => $mailto, 'class' => "rcmContactAddress"),
@ -1730,8 +1736,7 @@ function rcmail_send_mdn($message, &$smtp_error)
$sent = rcmail_deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file, $options);
if ($sent)
{
if ($sent) {
$RCMAIL->storage->set_flag($message->uid, 'MDNSENT');
return true;
}

@ -228,11 +228,11 @@ function rcmail_remote_objects_msg()
function rcmail_message_buttons()
{
global $MESSAGE, $RCMAIL, $CONFIG;
global $RCMAIL;
$mbox = $RCMAIL->storage->get_folder();
$delim = $RCMAIL->storage->get_hierarchy_delimiter();
$dbox = $CONFIG['drafts_mbox'];
$dbox = $RCMAIL->config->get('drafts_mbox');
// the message is not a draft
if ($mbox != $dbox && strpos($mbox, $dbox.$delim) !== 0) {

@ -40,7 +40,7 @@ function rcmail_user_prefs_form($attrib)
$out = $form_start;
foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $idx => $block) {
foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $block) {
if (!empty($block['options'])) {
$table = new html_table(array('cols' => 2));

@ -283,7 +283,6 @@ function rcube_subscription_form($attrib)
$noselect = false;
$classes = array($i%2 ? 'even' : 'odd');
$folder_js = Q($folder['id']);
$folder_utf8 = rcube_charset_convert($folder['id'], 'UTF7-IMAP');
$display_folder = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $folder['level'])
. Q($protected ? rcmail_localize_foldername($folder['id']) : $folder['name']);
@ -394,7 +393,7 @@ function rcmail_rename_folder($oldname, $newname)
$a_threaded = (array) $RCMAIL->config->get('message_threading', array());
$oldprefix = '/^' . preg_quote($oldname . $delimiter, '/') . '/';
foreach ($a_threaded as $key => $val) {
foreach (array_keys($a_threaded) as $key) {
if ($key == $oldname) {
unset($a_threaded[$key]);
$a_threaded[$newname] = true;

@ -418,6 +418,17 @@ function rcmail_user_prefs($current=null)
);
}
// show checkbox to show email instead of name
if (!isset($no_override['message_show_email'])) {
$field_id = 'rcmfd_message_show_email';
$input_msgshowemail = new html_checkbox(array('name' => '_message_show_email', 'id' => $field_id, 'value' => 1));
$blocks['main']['options']['message_show_email'] = array(
'title' => html::label($field_id, Q(rcube_label('showemail'))),
'content' => $input_msgshowemail->show($config['message_show_email']?1:0),
);
}
// show checkbox for HTML/plaintext messages
if (!isset($no_override['prefer_html'])) {
$field_id = 'rcmfd_htmlmsg';

@ -60,6 +60,7 @@ switch ($CURR_SECTION)
case 'mailview':
$a_user_prefs = array(
'message_extwin' => intval($_POST['_message_extwin']),
'message_show_email' => isset($_POST['_message_show_email']) ? TRUE : FALSE,
'prefer_html' => isset($_POST['_prefer_html']) ? TRUE : FALSE,
'inline_images' => isset($_POST['_inline_images']) ? TRUE : FALSE,
'show_images' => isset($_POST['_show_images']) ? intval($_POST['_show_images']) : 0,

@ -42,6 +42,13 @@ else {
$result = $spellchecker->get_xml();
}
if ($err = $spellchecker->error()) {
rcube::raise_error(array('code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => sprintf("Spell check engine error: " . $err)),
true, false);
}
// set response length
header("Content-Length: " . strlen($result));

@ -46,6 +46,11 @@ else if ($request['method'] == 'learnWord') {
}
if ($error = $spellchecker->error()) {
rcube::raise_error(array('code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => sprintf("Spell check engine error: " . $error)),
true, false);
echo '{"error":{"errstr":"' . addslashes($error) . '","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}';
exit;
}

@ -185,6 +185,10 @@ class Framework_Mime extends PHPUnit_Framework_TestCase
array("----------------------------------------------------------------------------------------\nabc def123456789012345", 76),
"----------------------------------------------------------------------------------------\nabc def123456789012345",
),
array(
array("-------\nabc def", 5),
"-------\nabc\ndef",
),
);
foreach ($samples as $sample) {

@ -65,6 +65,20 @@ class Framework_VCard extends PHPUnit_Framework_TestCase
$this->assertEquals("prefix", $vcard['prefix'], "Decode backslash character");
}
/**
* Backslash parsing test (#1489085)
*/
function test_parse_five()
{
$vcard = "BEGIN:VCARD\nVERSION:3.0\nN:last\\\\\\a;fir\\nst\nURL:http\\://domain.tld\nEND:VCARD";
$vcard = new rcube_vcard($vcard, null);
$vcard = $vcard->get_assoc();
$this->assertEquals("last\\a", $vcard['surname'], "Decode dummy backslash character");
$this->assertEquals("fir\nst", $vcard['firstname'], "Decode backslash character");
$this->assertEquals("http://domain.tld", $vcard['website:other'][0], "Decode dummy backslash character");
}
function test_import()
{
$input = file_get_contents($this->_srcpath('apple.vcf'));

@ -1,2 +1,2 @@
First Name,Last Name,Display Name,Nickname,Primary Email,Secondary Email,Screen Name,Work Phone,Home Phone,Fax Number,Pager Number,Mobile Number,Home Address,Home Address 2,Home City,Home State,Home ZipCode,Home Country,Work Address,Work Address 2,Work City,Work State,Work ZipCode,Work Country,Job Title,Department,Organization,Web Page 1,Web Page 2,Birth Year,Birth Month,Birth Day,Custom 1,Custom 2,Custom 3,Custom 4,Notes,
Firstname,Lastname,Displayname,Nick,test@domain.tld,next@domain.tld,,phone work,phone home,fax,pager,mobile,Priv address,,City,region,xx-xxx,USA,Addr work,,city,region,33-333,Poland,title,department,Organization,http://page.com,http://webpage.tld,1970,11,15,,,,,,
Firstname,Lastname,Displayname,Nick,test@domain.tld,next@domain.tld,,phone work,phone home,fax,pager,mobile,Priv address,,City,region,xx-xxx,USA,Addr work,,Wcity,Wstate,33-333,Poland,title,department,Organization,http://page.com,http://webpage.tld,1970,11,15,,,,,,

1 First Name Last Name Display Name Nickname Primary Email Secondary Email Screen Name Work Phone Home Phone Fax Number Pager Number Mobile Number Home Address Home Address 2 Home City Home State Home ZipCode Home Country Work Address Work Address 2 Work City Work State Work ZipCode Work Country Job Title Department Organization Web Page 1 Web Page 2 Birth Year Birth Month Birth Day Custom 1 Custom 2 Custom 3 Custom 4 Notes
2 Firstname Lastname Displayname Nick test@domain.tld next@domain.tld phone work phone home fax pager mobile Priv address City region xx-xxx USA Addr work city Wcity region Wstate 33-333 Poland title department Organization http://page.com http://webpage.tld 1970 11 15

@ -16,5 +16,5 @@ URL;TYPE=homepage:http://page.com
URL;TYPE=other:http://webpage.tld
BDAY;VALUE=date:1970-11-15
ADR;TYPE=home:;;Priv address;City;region;xx-xxx;USA
ADR;TYPE=work:;;Addr work;;;33-333;Poland
ADR;TYPE=work:;;Addr work;Wcity;Wstate;33-333;Poland
END:VCARD

@ -5,7 +5,7 @@ X
On XX.YY.YYYY Y:YY, Somebody wrote:
> This part is a reply wihtout any flowing lines. rcube_mime::unfold_flowed()
> has to be careful with empty quoted lines because they might end with a
>> has to be careful with empty quoted lines because they might end with a
> space but still shouldn't be considered as flowed!
>
> The above empty line should persist after unfolding.

@ -7,7 +7,7 @@ X
On XX.YY.YYYY Y:YY, Somebody wrote:
> This part is a reply wihtout any flowing lines. rcube_mime::unfold_flowed()
> has to be careful with empty quoted lines because they might end with a
>> has to be careful with empty quoted lines because they might end with a
> space but still shouldn't be considered as flowed!
>
> The above empty line should persist after unfolding.

Loading…
Cancel
Save