diff --git a/plugins/libkolab/js/audittrail.js b/plugins/libkolab/js/audittrail.js
index 641fa23e..b680114e 100644
--- a/plugins/libkolab/js/audittrail.js
+++ b/plugins/libkolab/js/audittrail.js
@@ -46,7 +46,7 @@ libkolab_audittrail.object_history_dialog = function(p)
// hide and reset changelog table
$dialog.find('div.notfound-message').remove();
$dialog.find('.changelog-table').show().children('tbody')
- .html('
' + rcmail.gettext('loading') + ' |
');
+ .html('' + rcmail.gettext('loading') + ' |
');
// open jquery UI dialog
$dialog.dialog({
@@ -163,7 +163,7 @@ libkolab_audittrail.render_changelog = function(data, object, folder)
var i, change, accessible, op_append,
first = data.length - 1, last = 0,
is_writeable = !!folder.editable,
- op_labels = { APPEND: 'actionappend', MOVE: 'actionmove', DELETE: 'actiondelete' },
+ op_labels = { RECEIVE: 'actionreceive', APPEND: 'actionappend', MOVE: 'actionmove', DELETE: 'actiondelete', READ: 'actionread', FLAGSET: 'actionflagset', FLAGCLEAR: 'actionflagclear' },
actions = ' ' +
(is_writeable ? '' : ''),
tbody = $dialog.find('.changelog-table tbody').html('');
@@ -175,6 +175,9 @@ libkolab_audittrail.render_changelog = function(data, object, folder)
if (change.op == 'MOVE' && change.mailbox) {
op_append = ' ⇢ ' + change.mailbox;
}
+ else if ((change.op == 'FLAGSET' || change.op == 'FLAGCLEAR') && change.flags) {
+ op_append = ': ' + change.flags;
+ }
else {
op_append = '';
}
@@ -187,7 +190,7 @@ libkolab_audittrail.render_changelog = function(data, object, folder)
.append('' + Q(i+1) + ' | ')
.append('' + Q(change.date || '') + ' | ')
.append('' + Q(change.user || 'undisclosed') + ' | ')
- .append('' + Q(rcmail.gettext(op_labels[change.op] || '', data.module) + (op_append ? ' ...' : '')) + ' | ')
+ .append('' + Q(rcmail.gettext(op_labels[change.op] || '', data.module) + op_append) + ' | ')
.append('' + (accessible && change.op != 'DELETE' ? actions.replace(/\{rev\}/g, change.rev) : '') + ' | ')
.appendTo(tbody);
}
@@ -210,3 +213,49 @@ libkolab_audittrail.dialog_resize = function(id, height, width)
$(id).dialog('option', { height: Math.min(h-20, height+130), width: Math.min(w-20, width+50) })
.dialog('option', 'position', ['center', 'center']); // only works in a separate call (!?)
};
+
+
+// register handlers for mail message history
+window.rcmail && rcmail.addEventListener('init', function(e) {
+ var loading_lock;
+
+ if (rcmail.env.task == 'mail') {
+ rcmail.register_command('kolab-mail-history', function() {
+ var dialog, uid = rcmail.get_single_uid(), rec = { uid: uid, mbox: rcmail.get_message_mailbox(uid) };
+ if (!uid || !window.libkolab_audittrail) {
+ return false;
+ }
+
+ // render dialog
+ $dialog = libkolab_audittrail.object_history_dialog({
+ module: 'libkolab',
+ container: '#mailmessagehistory',
+ title: rcmail.gettext('objectchangelog','libkolab')
+ });
+
+ $dialog.data('rec', rec);
+
+ // fetch changelog data
+ loading_lock = rcmail.set_busy(true, 'loading', loading_lock);
+ rcmail.http_post('plugin.message-changelog', { _uid: rec.uid, _mbox: rec.mbox }, loading_lock);
+
+ }, rcmail.env.action == 'show');
+
+ rcmail.addEventListener('plugin.message_render_changelog', function(data) {
+ var $dialog = $('#mailmessagehistory'),
+ rec = $dialog.data('rec');
+
+ if (data === false || !data.length || !event) {
+ // display 'unavailable' message
+ $('' + rcmail.gettext('objectchangelognotavailable','libkolab') + '
')
+ .insertBefore($dialog.find('.changelog-table').hide());
+ return;
+ }
+
+ data.module = 'libkolab';
+ libkolab_audittrail.render_changelog(data, rec, {});
+ });
+
+ rcmail.env.message_commands.push('kolab-mail-history');
+ }
+});
diff --git a/plugins/libkolab/libkolab.php b/plugins/libkolab/libkolab.php
index 4abb288f..1dede0d3 100644
--- a/plugins/libkolab/libkolab.php
+++ b/plugins/libkolab/libkolab.php
@@ -28,6 +28,7 @@
class libkolab extends rcube_plugin
{
static $http_requests = array();
+ static $bonnie_api = false;
/**
* Required startup method of a Roundcube plugin
@@ -52,6 +53,32 @@ class libkolab extends rcube_plugin
rcube::raise_error($e, true);
kolab_format::$timezone = new DateTimeZone('GMT');
}
+
+ $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'));
+ }
}
/**
@@ -63,6 +90,75 @@ class libkolab extends rcube_plugin
return $p;
}
+ /**
+ * 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();
+ }
+
/**
* Wrapper function to load and initalize the HTTP_Request2 Object
*
@@ -135,6 +231,7 @@ class libkolab extends rcube_plugin
public static function object_changelog_table($attrib = array())
{
$rcube = rcube::get_instance();
+ $attrib += array('domain' => 'libkolab');
$table = new html_table(array('cols' => 5, 'border' => 0, 'cellspacing' => 0));
$table->add_header('diff', '');
diff --git a/plugins/libkolab/localization/en_US.inc b/plugins/libkolab/localization/en_US.inc
new file mode 100644
index 00000000..c74d0040
--- /dev/null
+++ b/plugins/libkolab/localization/en_US.inc
@@ -0,0 +1,32 @@
+