2012-03-06 09:58:01 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Kolab core library
|
|
|
|
*
|
|
|
|
* Plugin to setup a basic environment for the interaction with a Kolab server.
|
|
|
|
* Other Kolab-related plugins will depend on it and can use the library classes
|
|
|
|
*
|
|
|
|
* @version @package_version@
|
|
|
|
* @author Thomas Bruederli <bruederli@kolabsys.com>
|
|
|
|
*
|
2015-03-31 14:55:02 +02:00
|
|
|
* Copyright (C) 2012-2015, Kolab Systems AG <contact@kolabsys.com>
|
2012-03-06 09:58:01 +01:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class libkolab extends rcube_plugin
|
|
|
|
{
|
2013-09-26 14:53:52 +02:00
|
|
|
static $http_requests = array();
|
2015-04-20 16:25:48 +02:00
|
|
|
static $bonnie_api = false;
|
2013-09-26 14:53:52 +02:00
|
|
|
|
2012-03-06 09:58:01 +01:00
|
|
|
/**
|
|
|
|
* Required startup method of a Roundcube plugin
|
|
|
|
*/
|
|
|
|
public function init()
|
|
|
|
{
|
|
|
|
// load local config
|
|
|
|
$this->load_config();
|
|
|
|
|
|
|
|
// extend include path to load bundled lib classes
|
|
|
|
$include_path = $this->home . '/lib' . PATH_SEPARATOR . ini_get('include_path');
|
|
|
|
set_include_path($include_path);
|
|
|
|
|
2014-04-23 20:00:24 +02:00
|
|
|
$this->add_hook('storage_init', array($this, 'storage_init'));
|
|
|
|
$this->add_hook('user_delete', array('kolab_storage', 'delete_user_folders'));
|
|
|
|
|
2012-06-20 18:41:06 +02:00
|
|
|
$rcmail = rcube::get_instance();
|
2012-05-16 16:32:49 +02:00
|
|
|
try {
|
|
|
|
kolab_format::$timezone = new DateTimeZone($rcmail->config->get('timezone', 'GMT'));
|
|
|
|
}
|
|
|
|
catch (Exception $e) {
|
2012-11-06 11:46:15 +01:00
|
|
|
rcube::raise_error($e, true);
|
2012-05-16 16:32:49 +02:00
|
|
|
kolab_format::$timezone = new DateTimeZone('GMT');
|
|
|
|
}
|
2015-04-20 16:25:48 +02:00
|
|
|
|
|
|
|
$this->add_texts('localization/', $rcmail->output->type == 'html' && $rcmail->task == 'mail');
|
|
|
|
|
|
|
|
// embed scripts and templates for email message audit trail
|
|
|
|
if ($rcmail->task == 'mail' && self::get_bonnie_api()) {
|
|
|
|
if ($rcmail->output->type == 'html') {
|
|
|
|
$this->add_hook('render_page', array($this, 'bonnie_render_page'));
|
|
|
|
|
|
|
|
$this->include_script('js/audittrail.js');
|
|
|
|
$this->include_stylesheet($this->local_skin_path() . '/libkolab.css');
|
|
|
|
|
|
|
|
// add 'Show history' item to message menu
|
|
|
|
$this->api->add_content(html::tag('li', null,
|
|
|
|
$this->api->output->button(array(
|
|
|
|
'command' => 'kolab-mail-history',
|
|
|
|
'label' => 'libkolab.showhistory',
|
|
|
|
'type' => 'link',
|
|
|
|
'classact' => 'icon history active',
|
|
|
|
'class' => 'icon history',
|
|
|
|
'innerclass' => 'icon history',
|
|
|
|
))),
|
|
|
|
'messagemenu');
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->register_action('plugin.message-changelog', array($this, 'message_changelog'));
|
|
|
|
}
|
2012-03-06 09:58:01 +01:00
|
|
|
}
|
|
|
|
|
2012-04-21 18:43:33 +02:00
|
|
|
/**
|
|
|
|
* Hook into IMAP FETCH HEADER.FIELDS command and request Kolab-specific headers
|
|
|
|
*/
|
|
|
|
function storage_init($p)
|
|
|
|
{
|
2012-06-12 13:39:15 +02:00
|
|
|
$p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE X-KOLAB-MIME-VERSION');
|
2012-04-21 18:43:33 +02:00
|
|
|
return $p;
|
|
|
|
}
|
2013-09-26 14:53:52 +02:00
|
|
|
|
2015-04-20 16:25:48 +02:00
|
|
|
/**
|
|
|
|
* Getter for a singleton instance of the Bonnie API
|
|
|
|
*
|
|
|
|
* @return mixed kolab_bonnie_api instance if configured, false otherwise
|
|
|
|
*/
|
|
|
|
public static function get_bonnie_api()
|
|
|
|
{
|
|
|
|
// get configuration for the Bonnie API
|
|
|
|
if (!self::$bonnie_api && ($bonnie_config = rcube::get_instance()->config->get('kolab_bonnie_api', false))) {
|
|
|
|
self::$bonnie_api = new kolab_bonnie_api($bonnie_config);
|
|
|
|
}
|
|
|
|
|
|
|
|
return self::$bonnie_api;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hook to append the message history dialog template to the mail view
|
|
|
|
*/
|
|
|
|
function bonnie_render_page($p)
|
|
|
|
{
|
|
|
|
if (($p['template'] === 'mail' || $p['template'] === 'message') && !$p['kolab-audittrail']) {
|
|
|
|
// append a template for the audit trail dialog
|
|
|
|
$this->api->output->add_footer(
|
|
|
|
html::div(array('id' => 'mailmessagehistory', 'class' => 'uidialog', 'aria-hidden' => 'true', 'style' => 'display:none'),
|
|
|
|
self::object_changelog_table(array('class' => 'records-table changelog-table'))
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$this->api->output->set_env('kolab_audit_trail', true);
|
|
|
|
$p['kolab-audittrail'] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handler for message audit trail changelog requests
|
|
|
|
*/
|
|
|
|
public function message_changelog()
|
|
|
|
{
|
|
|
|
if (!self::$bonnie_api) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$rcmail = rcube::get_instance();
|
|
|
|
$msguid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST, true);
|
|
|
|
$mailbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST);
|
|
|
|
|
|
|
|
$result = $msguid && $mailbox ? self::$bonnie_api->changelog('mail', null, $mailbox, $msguid) : null;
|
|
|
|
if (is_array($result)) {
|
|
|
|
if (is_array($result['changes'])) {
|
|
|
|
$dtformat = $rcmail->config->get('date_format') . ' ' . $rcmail->config->get('time_format');
|
|
|
|
array_walk($result['changes'], function(&$change) use ($dtformat, $rcmail) {
|
|
|
|
if ($change['date']) {
|
|
|
|
$dt = rcube_utils::anytodatetime($change['date']);
|
|
|
|
if ($dt instanceof DateTime) {
|
|
|
|
$change['date'] = $rcmail->format_date($dt, $dtformat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
$this->api->output->command('plugin.message_render_changelog', $result['changes']);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$this->api->output->command('plugin.message_render_changelog', false);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->api->output->send();
|
|
|
|
}
|
|
|
|
|
2013-09-26 14:53:52 +02:00
|
|
|
/**
|
|
|
|
* Wrapper function to load and initalize the HTTP_Request2 Object
|
|
|
|
*
|
|
|
|
* @param string|Net_Url2 Request URL
|
|
|
|
* @param string Request method ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT')
|
|
|
|
* @param array Configuration for this Request instance, that will be merged
|
|
|
|
* with default configuration
|
|
|
|
*
|
|
|
|
* @return HTTP_Request2 Request object
|
|
|
|
*/
|
|
|
|
public static function http_request($url = '', $method = 'GET', $config = array())
|
|
|
|
{
|
|
|
|
$rcube = rcube::get_instance();
|
|
|
|
$http_config = (array) $rcube->config->get('kolab_http_request');
|
|
|
|
|
|
|
|
// deprecated configuration options
|
2013-09-30 15:43:39 +02:00
|
|
|
if (empty($http_config)) {
|
2013-09-26 14:53:52 +02:00
|
|
|
foreach (array('ssl_verify_peer', 'ssl_verify_host') as $option) {
|
|
|
|
$value = $rcube->config->get('kolab_' . $option, true);
|
|
|
|
if (is_bool($value)) {
|
|
|
|
$http_config[$option] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!empty($config)) {
|
|
|
|
$http_config = array_merge($http_config, $config);
|
|
|
|
}
|
|
|
|
|
2015-02-19 05:02:54 -05:00
|
|
|
// force CURL adapter, this allows to handle correctly
|
|
|
|
// compressed responses with SplObserver registered (kolab_files) (#4507)
|
|
|
|
$http_config['adapter'] = 'HTTP_Request2_Adapter_Curl';
|
|
|
|
|
2013-09-26 14:53:52 +02:00
|
|
|
$key = md5(serialize($http_config));
|
|
|
|
|
|
|
|
if (!($request = self::$http_requests[$key])) {
|
|
|
|
// load HTTP_Request2
|
|
|
|
require_once 'HTTP/Request2.php';
|
|
|
|
|
|
|
|
try {
|
|
|
|
$request = new HTTP_Request2();
|
|
|
|
$request->setConfig($http_config);
|
|
|
|
}
|
|
|
|
catch (Exception $e) {
|
|
|
|
rcube::raise_error($e, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// proxy User-Agent string
|
|
|
|
$request->setHeader('user-agent', $_SERVER['HTTP_USER_AGENT']);
|
|
|
|
|
|
|
|
self::$http_requests[$key] = $request;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cleanup
|
|
|
|
try {
|
|
|
|
$request->setBody('');
|
|
|
|
$request->setUrl($url);
|
|
|
|
$request->setMethod($method);
|
|
|
|
}
|
|
|
|
catch (Exception $e) {
|
|
|
|
rcube::raise_error($e, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $request;
|
|
|
|
}
|
2014-07-29 14:34:03 +02:00
|
|
|
|
2015-03-25 11:55:21 +01:00
|
|
|
/**
|
|
|
|
* Table oultine for object changelog display
|
|
|
|
*/
|
|
|
|
public static function object_changelog_table($attrib = array())
|
|
|
|
{
|
|
|
|
$rcube = rcube::get_instance();
|
2015-04-20 16:25:48 +02:00
|
|
|
$attrib += array('domain' => 'libkolab');
|
2015-03-25 11:55:21 +01:00
|
|
|
|
|
|
|
$table = new html_table(array('cols' => 5, 'border' => 0, 'cellspacing' => 0));
|
|
|
|
$table->add_header('diff', '');
|
|
|
|
$table->add_header('revision', $rcube->gettext('revision', $attrib['domain']));
|
|
|
|
$table->add_header('date', $rcube->gettext('date', $attrib['domain']));
|
|
|
|
$table->add_header('user', $rcube->gettext('user', $attrib['domain']));
|
|
|
|
$table->add_header('operation', $rcube->gettext('operation', $attrib['domain']));
|
|
|
|
$table->add_header('actions', ' ');
|
|
|
|
|
|
|
|
return $table->show($attrib);
|
|
|
|
}
|
|
|
|
|
2014-07-29 14:34:03 +02:00
|
|
|
/**
|
|
|
|
* Wrapper function for generating a html diff using the FineDiff class by Raymond Hill
|
|
|
|
*/
|
2015-03-31 14:55:02 +02:00
|
|
|
public static function html_diff($from, $to, $is_html = null)
|
2014-07-29 14:34:03 +02:00
|
|
|
{
|
2015-03-31 14:55:02 +02:00
|
|
|
// auto-detect text/html format
|
|
|
|
if ($is_html === null) {
|
|
|
|
$from_html = (preg_match('/<(html|body)(\s+[a-z]|>)/', $from, $m) && strpos($from, '</'.$m[1].'>') > 0);
|
|
|
|
$to_html = (preg_match('/<(html|body)(\s+[a-z]|>)/', $to, $m) && strpos($to, '</'.$m[1].'>') > 0);
|
|
|
|
$is_html = $from_html || $to_html;
|
|
|
|
|
|
|
|
// ensure both parts are of the same format
|
|
|
|
if ($is_html && !$from_html) {
|
|
|
|
$converter = new rcube_text2html($from, false, array('wrap' => true));
|
|
|
|
$from = $converter->get_html();
|
|
|
|
}
|
|
|
|
if ($is_html && !$to_html) {
|
|
|
|
$converter = new rcube_text2html($to, false, array('wrap' => true));
|
|
|
|
$to = $converter->get_html();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// compute diff from HTML
|
|
|
|
if ($is_html) {
|
|
|
|
include_once __dir__ . '/vendor/Caxy/HtmlDiff/Match.php';
|
|
|
|
include_once __dir__ . '/vendor/Caxy/HtmlDiff/Operation.php';
|
|
|
|
include_once __dir__ . '/vendor/Caxy/HtmlDiff/HtmlDiff.php';
|
|
|
|
|
|
|
|
// replace data: urls with a transparent image to avoid memory problems
|
|
|
|
$from = preg_replace('/src="data:image[^"]+/', 'src="data:image/gif;base64,R0lGODlhAQABAPAAAOjq6gAAACH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAAAsAAAAAAEAAQAAAgJEAQA7', $from);
|
|
|
|
$to = preg_replace('/src="data:image[^"]+/', 'src="data:image/gif;base64,R0lGODlhAQABAPAAAOjq6gAAACH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAAAsAAAAAAEAAQAAAgJEAQA7', $to);
|
2014-07-29 14:34:03 +02:00
|
|
|
|
2015-03-31 14:55:02 +02:00
|
|
|
$diff = new Caxy\HtmlDiff\HtmlDiff($from, $to);
|
|
|
|
$diffhtml = $diff->build();
|
|
|
|
|
|
|
|
// remove empty inserts (from tables)
|
|
|
|
return preg_replace('!<ins class="diff\w+">\s*</ins>!Uims', '', $diffhtml);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
include_once __dir__ . '/vendor/finediff.php';
|
|
|
|
|
|
|
|
$diff = new FineDiff($from, $to, FineDiff::$wordGranularity);
|
|
|
|
return $diff->renderDiffToHTML();
|
|
|
|
}
|
2014-07-29 14:34:03 +02:00
|
|
|
}
|
2015-03-10 14:30:50 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a date() format string to render identifiers for recurrence instances
|
|
|
|
*
|
|
|
|
* @param array Hash array with event properties
|
|
|
|
* @return string Format string
|
|
|
|
*/
|
|
|
|
public static function recurrence_id_format($event)
|
|
|
|
{
|
|
|
|
return $event['allday'] ? 'Ymd' : 'Ymd\THis';
|
|
|
|
}
|
2012-03-06 09:58:01 +01:00
|
|
|
}
|