4 commits - plugins/kolab_notes plugins/libkolab

Thomas Brüderli bruederli at kolabsys.com
Tue Apr 15 09:46:06 CEST 2014


 plugins/kolab_notes/kolab_notes.php                  |  170 +++++++++++++++++--
 plugins/kolab_notes/localization/en_US.inc           |    3 
 plugins/kolab_notes/notes.js                         |   85 +++++----
 plugins/kolab_notes/skins/larry/notes.css            |   56 +++++-
 plugins/kolab_notes/skins/larry/sprites.png          |binary
 plugins/kolab_notes/skins/larry/templates/notes.html |   10 +
 plugins/libkolab/lib/kolab_format.php                |   37 ++--
 plugins/libkolab/lib/kolab_format_note.php           |   11 +
 plugins/libkolab/lib/kolab_storage.php               |   27 +++
 9 files changed, 335 insertions(+), 64 deletions(-)

New commits:
commit ee269df7ae566bfefbb4b6934abf74a7aaee2f6e
Merge: f0ecee1 1a6f7e8
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Mon Apr 14 18:25:53 2014 +0200

    Merge branch 'master' of ssh://git.kolab.org/git/roundcubemail-plugins-kolab



commit f0ecee1e5851ecd027b3ffb959cc6b9de3a056f0
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Mon Apr 14 18:25:23 2014 +0200

    Implement full notes display and editing from mail view

diff --git a/plugins/kolab_notes/kolab_notes.php b/plugins/kolab_notes/kolab_notes.php
index 3be3ab9..2c47855 100644
--- a/plugins/kolab_notes/kolab_notes.php
+++ b/plugins/kolab_notes/kolab_notes.php
@@ -34,6 +34,7 @@ class kolab_notes extends rcube_plugin
     private $lists;
     private $folders;
     private $cache = array();
+    private $message_notes = array();
 
     /**
      * Required startup method of a Roundcube plugin
@@ -68,6 +69,8 @@ class kolab_notes extends rcube_plugin
         $this->rc->load_language($_SESSION['language'], array('notes.notes' => $this->gettext('navtitle')));  // add label for task title
 
         if ($args['task'] == 'notes') {
+            $this->add_hook('storage_init', array($this, 'storage_init'));
+
             // register task actions
             $this->register_action('index', array($this, 'notes_view'));
             $this->register_action('fetch', array($this, 'notes_fetch'));
@@ -77,6 +80,8 @@ class kolab_notes extends rcube_plugin
             $this->register_action('dialog-ui', array($this, 'dialog_view'));
         }
         else if ($args['task'] == 'mail') {
+            $this->add_hook('storage_init', array($this, 'storage_init'));
+            $this->add_hook('message_load', array($this, 'mail_message_load'));
             $this->add_hook('message_compose', array($this, 'mail_message_compose'));
             $this->add_hook('template_object_messagebody', array($this, 'mail_messagebody_html'));
 
@@ -93,19 +98,36 @@ class kolab_notes extends rcube_plugin
                     ))),
                     'messagemenu');
 
-                $this->api->output->add_label('kolab_notes.appendnote', 'save', 'cancel');
+                $this->api->output->add_label('kolab_notes.appendnote', 'kolab_notes.editnote', 'kolab_notes.deletenotesconfirm', 'kolab_notes.entertitle', 'save', 'delete', 'cancel', 'close');
                 $this->include_script('notes_mail.js');
             }
         }
 
         if (!$this->rc->output->ajax_call && (!$this->rc->output->env['framed'] || in_array($args['action'], array('folder-acl','dialog-ui')))) {
-            require_once($this->home . '/kolab_notes_ui.php');
-            $this->ui = new kolab_notes_ui($this);
-            $this->ui->init();
+            $this->load_ui();
         }
     }
 
     /**
+     * Hook into IMAP FETCH HEADER.FIELDS command and request MESSAGE-ID
+     */
+    public function storage_init($p)
+    {
+        $p['fetch_headers'] = trim($p['fetch_headers'] . ' MESSAGE-ID');
+        return $p;
+    }
+
+    /**
+     * Load and initialize UI class
+     */
+    private function load_ui()
+    {
+        require_once($this->home . '/kolab_notes_ui.php');
+        $this->ui = new kolab_notes_ui($this);
+        $this->ui->init();
+    }
+
+    /**
      * Read available calendars for the current user and store them internally
      */
     private function _read_lists($force = false)
@@ -205,8 +227,8 @@ class kolab_notes extends rcube_plugin
 
         // attempt to create a default folder for this user
         if (empty($this->lists)) {
-            #if ($this->create_list(array('name' => 'Tasks', 'color' => '0000CC', 'default' => true)))
-            #    $this->_read_lists(true);
+            $folder = kolab_storage::folder_update(array('name' => 'Notes', 'type' => 'note', 'default' => true, 'subscribed' => true));
+            $this->_read_lists(true);
         }
 
         return $this->lists;
@@ -234,10 +256,10 @@ class kolab_notes extends rcube_plugin
         // resolve message reference
         if ($msgref = rcube_utils::get_input_value('_msg', RCUBE_INPUT_GPC, true)) {
             $storage = $this->rc->get_storage();
-            $storage->set_options(array('all_headers' => true));
             list($uid, $folder) = explode('-', $msgref, 2);
             if ($message = $storage->get_message_headers($msgref)) {
                 $this->rc->output->set_env('kolab_notes_template', array(
+                    '_from_mail' => true,
                     'title' => $message->get('subject'),
                     'links' => array(array(
                         'uri' => $this->get_message_uri($message, $folder),
@@ -346,7 +368,7 @@ class kolab_notes extends rcube_plugin
 
         // encode for client use
         if (is_array($data)) {
-            $this->_client_encode($data);
+            $this->_client_encode($data, true);
         }
 
         $this->rc->output->command('plugin.render_note', $data);
@@ -393,7 +415,7 @@ class kolab_notes extends rcube_plugin
     /**
      * Helper method to encode the given note record for use in the client
      */
-    private function _client_encode(&$note)
+    private function _client_encode(&$note, $resolve = false)
     {
         foreach ($note as $key => $prop) {
             if ($key[0] == '_' || $key == 'x-custom') {
@@ -413,6 +435,14 @@ class kolab_notes extends rcube_plugin
             $note['html'] = $this->_wash_html($note['description']);
         }
 
+        // resolve message links
+        if (is_array($note['links'])) {
+            $me = $this;
+            $note['links'] = array_map(function($link) use ($me, $resolve){
+                return $me->get_message_reference($link, $resolve) ?: array('uri' => $link);
+            }, $note['links']);
+        }
+
         return $note;
     }
 
@@ -680,11 +710,47 @@ class kolab_notes extends rcube_plugin
     }
 
     /**
-     * Handler for 'messagebody_html' hooks
+     * Lookup backend storage and find notes tagged with the given message-ID
+     */
+    public function mail_message_load($p)
+    {
+        $this->message = $p['object'];
+        $this->message_notes = array();
+
+        // TODO: only query for notes if message was flagged with $KolabNotes ?
+
+        $message_id = trim($p['object']->headers->messageID, '<> ');
+        if ($message_id && $p['object']->uid) {
+            $query = array(array('tags','=','ref:' . $message_id));
+            foreach (kolab_storage::select($query, 'note') as $record) {
+                $record['list'] = kolab_storage::folder_id($record['_mailbox']);
+                $this->message_notes[] = $record;
+            }
+        }
+    }
+
+    /**
+     * Handler for 'messagebody_html' hook
      */
     public function mail_messagebody_html($args)
     {
-      
+        $html = '';
+        foreach ($this->message_notes as $note) {
+            $html .= html::a(array(
+                'href' => $this->rc->url(array('task' => 'notes', '_list' => $note['list'], '_id' => $note['uid'])),
+                'class' => 'kolabnotesref',
+                'rel' => $note['uid'] . '@' . $note['list'],
+                'target' => '_blank',
+            ), Q($note['title']));
+        }
+
+        // prepend note links to message body
+        if ($html) {
+            $this->load_ui();
+            $args['content'] = html::div('kolabmessagenotes', $html) . $args['content'];
+        }
+
+        return $args;
     }
 
     /**
@@ -714,7 +780,7 @@ class kolab_notes extends rcube_plugin
             'Subject' => $note['title'],
             'Date' => $note['changed']->format('r'),
         ));
-        console($note);
+
         if ($this->is_html($note)) {
             $message->setHTMLBody($note['description']);
 
@@ -735,9 +801,79 @@ class kolab_notes extends rcube_plugin
         return $message->getMessage();
     }
 
+    /**
+     * Build a URI representing the given message reference
+     */
     private function get_message_uri($headers, $folder)
     {
-      return sprintf('imap://%s/%s#%s', $headers->folder ?: $folder, $headers->uid, urlencode($headers->messageID));
+        return sprintf('imap://%s/%s?message-id=%s&subject=%s',
+            $headers->folder ?: $folder,
+            $headers->uid,
+            urlencode($headers->messageID),
+            urlencode($headers->get('subject'))
+        );
+    }
+
+    /**
+     * Extract message reference components from the given URI
+     */
+    private function parse_message_uri($uri)
+    {
+        $url = parse_url($uri);
+        if ($url['scheme'] == 'imap') {
+            parse_str($url['query'], $param);
+            $linkref = array(
+                'uri' => $uri,
+                'message_id' => $param['message-id'] ?: urldecode($url['fragment']),
+                'subject' => $param['subject'],
+            );
+
+            $path = explode('/', $url['host'] . $url['path']);
+            $linkref['msguid'] = array_pop($path);
+            $linkref['folder'] = join('/', $path);
+
+            return $linkref;
+        }
+
+        return false;
+    }
+
+    /**
+     * Resolve the email message reference from the given URI
+     */
+    public function get_message_reference($uri, $resolve = false)
+    {
+        if ($linkref = $this->parse_message_uri($uri)) {
+            // fetch message subject
+            if ($resolve || empty($linkref['subject'])) {
+                $imap = $this->rc->get_storage();
+                if (!($message = $imap->get_message_headers($linrkef['msguid'], $linkref['folder']))) {
+                    // try to find message using the message_id fragment
+                    $index = $imap->search_once($imap->list_folders_subscribed('', '*', 'mail', null, true), 'HEADER MESSAGE-ID ' . $linkref['message_id']);
+                    if ($index->count()) {
+                        $uid = reset($index->get());
+                        $folder = $index->get_parameters('MAILBOX');
+                        if ($message = $imap->get_message_headers($uid, $folder)) {
+                            // replace metadata
+                            $linkref['subject'] = $message->get('subject');
+                            $linkref['msguid'] = $message->uid;
+                            $linkref['folder'] = $message->folder;
+                            $linkref['uri'] = $this->get_message_uri($message, $folder);
+                        }
+                    }
+                }
+            }
+
+            $linkref['mailurl'] = $this->rc->url(array(
+                'task' => 'mail',
+                'action' => 'show',
+                'mbox' => $linkref['folder'],
+                'uid' => $linkref['msguid'],
+                'rel' => 'note',
+            ));
+        }
+
+        return $linkref;
     }
 
     /**
@@ -749,6 +885,14 @@ class kolab_notes extends rcube_plugin
 
         // TODO: handle attachments
 
+        // convert link references into simple URIs
+        if (array_key_exists('links', $note)) {
+            $object['links'] = array_map(function($link){ return is_array($link) ? $link['uri'] : strval($link); }, $note['links']);
+        }
+        else {
+            $object['links'] = $old['links'];
+        }
+
         // clean up HTML content
         $object['description'] = $this->_wash_html($note['description']);
         $is_html = true;
diff --git a/plugins/kolab_notes/localization/en_US.inc b/plugins/kolab_notes/localization/en_US.inc
index ccb737d..5e3d1bb 100644
--- a/plugins/kolab_notes/localization/en_US.inc
+++ b/plugins/kolab_notes/localization/en_US.inc
@@ -24,7 +24,8 @@ $labels['tabsharing'] = 'Sharing';
 $labels['discard'] = 'Discard';
 $labels['abort'] = 'Abort';
 $labels['unsavedchanges'] = 'Unsaved Changes!';
-$labels['appendnote'] = 'Add a note';
+$labels['appendnote'] = 'Add a Note';
+$labels['editnote'] = 'Edit Note';
 $labels['savein'] = 'Save in';
 
 $labels['savingdata'] = 'Saving data...';
diff --git a/plugins/kolab_notes/notes.js b/plugins/kolab_notes/notes.js
index c05be5a..41dcac1 100644
--- a/plugins/kolab_notes/notes.js
+++ b/plugins/kolab_notes/notes.js
@@ -236,6 +236,7 @@ function rcube_kolab_notes_ui(settings)
     function init_dialog()
     {
         rcmail.register_command('save', save_note, true);
+        rcmail.addEventListener('plugin.render_note', render_note);
         rcmail.addEventListener('plugin.update_note', function(data){
             data.id = rcmail.html_identifier_encode(data.uid);
             notesdata[data.id] = data;
@@ -259,19 +260,24 @@ function rcube_kolab_notes_ui(settings)
         }
 
         init_editor();
-        setTimeout(function(){
-            me.selected_note = $.extend({
-                list: me.selected_list,
-                uid: null,
-                title: rcmail.gettext('newnote','kolab_notes'),
-                description: '',
-                categories: [],
-                created: rcmail.gettext('now', 'kolab_notes'),
-                changed: rcmail.gettext('now', 'kolab_notes')
-            }, rcmail.env.kolab_notes_template || {});
-            render_note(me.selected_note);
-
-        }, 100);
+        if (settings.selected_uid) {
+            me.selected_list = settings.selected_list;
+            edit_note(settings.selected_uid);
+        }
+        else {
+            setTimeout(function(){
+                me.selected_note = $.extend({
+                    list: me.selected_list,
+                    uid: null,
+                    title: rcmail.gettext('newnote','kolab_notes'),
+                    description: '',
+                    categories: [],
+                    created: rcmail.gettext('now', 'kolab_notes'),
+                    changed: rcmail.gettext('now', 'kolab_notes')
+                }, rcmail.env.kolab_notes_template || {});
+                render_note(me.selected_note);
+            }, 100);
+        }
     }
     this.init_dialog = init_dialog;
 
@@ -319,16 +325,7 @@ function rcube_kolab_notes_ui(settings)
 
         // register click handler for message links
         $(rcmail.gui_objects.notesattachmentslist).on('click', 'li a.messagelink', function(){
-            var uri = $(this).attr('rel');
-            if (uri && uri.match(/imap:\/\/.+/)) {
-                var path = uri.split('#')[0].substr(7).split('/'),
-                    uid = path.pop(),
-                    folder = path.join('/');
-                if (folder && uid) {
-                    rcmail.open_window(rcmail.url('mail/show', { _mbox: folder, _uid: uid, _rel: 'note' }));
-                }
-            }
-
+            rcmail.open_window(this.href);
             return false;
         });
     }
@@ -715,13 +712,14 @@ function rcube_kolab_notes_ui(settings)
             return;
         }
 
-        var list = me.notebooks[data.list] || me.notebooks[me.selected_list];
+        var list = me.notebooks[data.list] || me.notebooks[me.selected_list] || {};
             content = $('#notecontent').val(data.description),
             readonly = data.readonly || !list.editable,
             attachmentslist = $(rcmail.gui_objects.notesattachmentslist).html('');
         $('.notetitle', rcmail.gui_objects.noteviewtitle).val(data.title).prop('disabled', readonly);
         $('.dates .notecreated', rcmail.gui_objects.noteviewtitle).html(Q(data.created || ''));
         $('.dates .notechanged', rcmail.gui_objects.noteviewtitle).html(Q(data.changed || ''));
+        $(rcmail.gui_objects.notebooks).filter('select').val(list.id);
         if (data.created || data.changed) {
             $('.dates', rcmail.gui_objects.noteviewtitle).show();
         }
@@ -753,15 +751,24 @@ function rcube_kolab_notes_ui(settings)
 
         if (data.links) {
             $.each(data.links, function(i, link){
-                $('<li>').addClass('link')
+                var li = $('<li>').addClass('link')
                     .addClass('message eml')
                     .append($('<a>')
-                        .attr('href', '#show')
-                        .attr('rel', link.uri)
+                        .attr('href', link.mailurl)
                         .addClass('messagelink')
                         .html(Q(link.subject || link.message_id || link.uri))
                     )
                     .appendTo(attachmentslist);
+/*
+                if (!readonly && !data._from_mail) {
+                    $('<a>')
+                        .attr('href', '#delete')
+                        .attr('title', rcmail.gettext('delete'))
+                        .addClass('delete')
+                        .html(rcmail.gettext('delete'))
+                        .appendTo(li);
+                }
+*/
             });
         }
 
@@ -770,6 +777,9 @@ function rcube_kolab_notes_ui(settings)
                 .on('click', function(){ $('.tagline .placeholder').hide(); });
         }
 
+        if (!data.list)
+            data.list = list.id;
+
         me.selected_note = data;
         me.selected_note.id = rcmail.html_identifier_encode(data.uid);
         rcmail.enable_command('save', list.editable && !data.readonly);
@@ -781,7 +791,7 @@ function rcube_kolab_notes_ui(settings)
             html = text2html(html);
         }
 
-        var node, editor = tinyMCE.get('notecontent');
+        var node, editor = tinyMCE.get('notecontent'), is_html = false;
         if (!readonly && editor) {
             $(rcmail.gui_objects.notesdetailview).hide();
             $(rcmail.gui_objects.noteseditform).show();
@@ -795,13 +805,17 @@ function rcube_kolab_notes_ui(settings)
                 $('.notetitle', rcmail.gui_objects.noteviewtitle).focus().select();
 
             // read possibly re-formatted content back from editor for later comparison
-            me.selected_note.description = editor.getContent({ format:'html' })
+            me.selected_note.description = editor.getContent({ format:'html' });
+            is_html = true;
         }
         else {
             $(rcmail.gui_objects.noteseditform).hide();
             $(rcmail.gui_objects.notesdetailview).html(html).show();
         }
 
+        // notify subscribers
+        rcmail.triggerEvent('kolab_notes_render', { data:data, readonly:readonly, html:is_html });
+
         // Trigger resize (needed for proper editor resizing)
         $(window).resize();
     }
@@ -1010,6 +1024,11 @@ function rcube_kolab_notes_ui(settings)
         if (me.selected_note.links)
             savedata.links = me.selected_note.links;
 
+        // add reference to old list if changed
+        if (me.selected_note.list && savedata.list != me.selected_note.list) {
+            savedata._fromlist = me.selected_note.list;
+        }
+
         // do some input validation
         if (savedata.title == '') {
             alert(rcmail.gettext('entertitle', 'kolab_notes'));
@@ -1032,11 +1051,12 @@ function rcube_kolab_notes_ui(settings)
      */
     function get_save_data()
     {
-        var editor = tinyMCE.get('notecontent');
+        var editor = tinyMCE.get('notecontent'),
+            listselect = $('option:selected', rcmail.gui_objects.notebooks);
         var savedata = {
             title: trim($('.notetitle', rcmail.gui_objects.noteviewtitle).val()),
             description: editor ? editor.getContent({ format:'html' }) : $('#notecontent').val(),
-            list: me.selected_note.list || me.selected_list,
+            list: listselect.length ? listselect.val() : me.selected_note.list || me.selected_list,
             uid: me.selected_note.uid,
             categories: []
         };
@@ -1068,7 +1088,8 @@ function rcube_kolab_notes_ui(settings)
 
         return savedata.title != me.selected_note.title
             || savedata.description != me.selected_note.description
-            || savedata.categories.join(',') != (me.selected_note.categories || []).join(',');
+            || savedata.categories.join(',') != (me.selected_note.categories || []).join(',')
+            || savedata.list != me.selected_note.list;
     }
 
     /**
diff --git a/plugins/kolab_notes/skins/larry/notes.css b/plugins/kolab_notes/skins/larry/notes.css
index 96d283b..96e962f 100644
--- a/plugins/kolab_notes/skins/larry/notes.css
+++ b/plugins/kolab_notes/skins/larry/notes.css
@@ -103,7 +103,7 @@
 }
 
 .notesview .toolbarmenu.iconized .selected span.icon {
-	background: url(sprites.png) -5px -109px no-repeat;
+	background: url(sprites.png) -4px -110px no-repeat;
 }
 
 .notesview #notedetailsbox {
@@ -137,16 +137,18 @@
 	width: 100%;
 }
 
-.notesdialog #noteform {
-	bottom: 30px;
-}
-
 .notesview #notedetails {
 	padding: 8px;
 	-webkit-box-sizing: border-box;
 	   -moz-box-sizing: border-box;
 	    -ms-box-sizing: border-box;
 	        box-sizing: border-box;
+	border-bottom: 1px solid #dfdfdf;
+}
+
+.notesdialog #noteform,
+.notesdialog #notedetails {
+	bottom: 30px;
 }
 
 .notesview #notedetails pre {
@@ -266,12 +268,16 @@
 	position: absolute;
 	left: 0;
 	right: 0;
-	bottom: 0;
+	bottom: 41px;
 	height: 27px;
 	background: #fff;
 	padding-left: 10px;
 }
 
+.notesdialog #notereferences {
+	bottom: 0;
+}
+
 .notesview #notebooks li {
 	margin: 0;
 	height: 20px;
@@ -369,4 +375,42 @@
 	   -moz-box-sizing: border-box;
 	    -ms-box-sizing: border-box;
 	        box-sizing: border-box;
+}
+
+.notesview .attachmentslist li.message.eml {
+	display: inline-block;
+	background-image: url(sprites.png);
+	background-position: -6px -128px;
+	margin-right: 1em;
+}
+
+.notesview .attachmentslist li.message a.messagelink {
+	padding-left: 24px;
+}
+
+ul.toolbarmenu li .appendnote span.icon {
+	background-image: url(sprites.png);
+	background-position: -4px -170px;
+}
+
+div.kolabmessagenotes {
+	margin: 8px 8px;
+	padding: 4px 8px;
+	border: 1px solid #dfdfdf;
+	background: #fafafa;
+	border-radius: 4px;
+}
+
+div.kolabmessagenotes a.kolabnotesref {
+	display: inline-block;
+	color: #333;
+	font-weight: bold;
+	padding: 3px 15px 2px 22px;
+	text-shadow: 0px 1px 1px #fff;
+	text-decoration: none;
+	white-space: nowrap;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	max-width: 12em;
+	background: url(sprites.png) -6px -151px no-repeat;
 }
\ No newline at end of file
diff --git a/plugins/kolab_notes/skins/larry/sprites.png b/plugins/kolab_notes/skins/larry/sprites.png
index 184cef4..62aff65 100644
Binary files a/plugins/kolab_notes/skins/larry/sprites.png and b/plugins/kolab_notes/skins/larry/sprites.png differ
diff --git a/plugins/kolab_notes/skins/larry/templates/notes.html b/plugins/kolab_notes/skins/larry/templates/notes.html
index 75fa188..8f35b61 100644
--- a/plugins/kolab_notes/skins/larry/templates/notes.html
+++ b/plugins/kolab_notes/skins/larry/templates/notes.html
@@ -60,6 +60,9 @@
             <roundcube:object name="plugin.notetitle" id="notedetailstitle" class="boxtitle" />
             <roundcube:object name="plugin.editform" id="noteform" />
             <roundcube:object name="plugin.detailview" id="notedetails" class="scroller" />
+            <div id="notereferences">
+                <roundcube:object name="plugin.attachments_list" id="attachment-list" class="attachmentslist" />
+            </div>
             <div class="footerleft formbuttons">
                 <roundcube:button command="save" type="input" class="button mainaction" label="save" />
             </div>
@@ -115,9 +118,16 @@ $(document).ready(function(e){
         var form = $('#noteform, #notedetails'),
             content = $('#notecontent'),
             header = $('#notedetailstitle'),
+            footer = $('#notereferences'),
             w, h;
 
+        if ($('#attachment-list li').length)
+            footer.show();
+        else
+            footer.hide();
+
         form.css('top', header.outerHeight()+'px');
+        form.css('bottom', ((footer.is(':visible') ? footer.outerHeight()+4 : 0) + 41) + 'px');
 
         w = form.outerWidth();
         h = form.outerHeight();


commit e0bc40f16047ae908ca256b661f2532a7f83b831
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Mon Apr 14 18:25:04 2014 +0200

    Allow to store email message references for note objects (link format tentative) + store message-id in cache for querying

diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php
index 563fbc6..7c34310 100644
--- a/plugins/libkolab/lib/kolab_format.php
+++ b/plugins/libkolab/lib/kolab_format.php
@@ -502,6 +502,11 @@ abstract class kolab_format
         return array();
     }
 
+    /**
+     * Utility function to extract object attachment data
+     *
+     * @param array Hash array reference to append attachment data into
+     */
     protected function get_attachments(&$object)
     {
         // handle attachments
@@ -520,13 +525,19 @@ abstract class kolab_format
                     'content'  => $content,
                 );
             }
-            else if (substr($attach->uri(), 0, 4) == 'http') {
+            else if (in_array(substr($attach->uri(), 0, 4), array('http','imap'))) {
                 $object['links'][] = $attach->uri();
             }
         }
     }
 
-    protected function set_attachments($object)
+    /**
+     * Utility function to set attachment properties to the kolabformat object
+     *
+     * @param array  Object data as hash array
+     * @param boolean True to always overwrite attachment information
+     */
+    protected function set_attachments($object, $write = true)
     {
         // save attachments
         $vattach = new vectorattachment;
@@ -537,16 +548,17 @@ abstract class kolab_format
             $attach->setLabel((string)$attr['name']);
             $attach->setUri('cid:' . $cid, $attr['mimetype'] ?: 'application/octet-stream');
             if ($attach->isValid()) {
-              $vattach->push($attach);
+                $vattach->push($attach);
+                $write = true;
             }
             else {
-              rcube::raise_error(array(
-                  'code' => 660,
-                  'type' => 'php',
-                  'file' => __FILE__,
-                  'line' => __LINE__,
-                  'message' => "Invalid attributes for attachment $cid: " . var_export($attr, true),
-              ), true);
+                rcube::raise_error(array(
+                    'code' => 660,
+                    'type' => 'php',
+                    'file' => __FILE__,
+                    'line' => __LINE__,
+                    'message' => "Invalid attributes for attachment $cid: " . var_export($attr, true),
+                ), true);
             }
         }
 
@@ -554,8 +566,11 @@ abstract class kolab_format
             $attach = new Attachment;
             $attach->setUri($link, 'unknown');
             $vattach->push($attach);
+            $write = true;
         }
 
-        $this->obj->setAttachments($vattach);
+        if ($write) {
+            $this->obj->setAttachments($vattach);
+        }
     }
 }
diff --git a/plugins/libkolab/lib/kolab_format_note.php b/plugins/libkolab/lib/kolab_format_note.php
index 08b7735..bca5156 100644
--- a/plugins/libkolab/lib/kolab_format_note.php
+++ b/plugins/libkolab/lib/kolab_format_note.php
@@ -109,10 +109,19 @@ class kolab_format_note extends kolab_format
     {
         $tags = array();
 
-        foreach ((array) $this->data['categories'] as $cat) {
+        foreach ((array)$this->data['categories'] as $cat) {
             $tags[] = rcube_utils::normalize_string($cat);
         }
 
+        // add tag for message references
+        foreach ((array)$this->data['links'] as $link) {
+            $url = parse_url($link);
+            if ($url['scheme'] == 'imap') {
+                parse_str($url['query'], $param);
+                $tags[] = 'ref:' . trim($param['message-id'] ?: urldecode($url['fragment']), '<> ');
+            }
+        }
+
         return $tags;
     }
 


commit e25fd88b73c512169ca60d885be0babebf7f3a07
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Mon Apr 14 18:21:19 2014 +0200

    Provide static fuction to query for objects address kolab groupware folders

diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index b5e529c..b7c981b 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -177,6 +177,33 @@ class kolab_storage
         return false;
     }
 
+    /**
+     * Execute cross-folder searches with the given query.
+     *
+     * @param array  Pseudo-SQL query as list of filter parameter triplets
+     * @param string Object type (contact,event,task,journal,file,note,configuration)
+     * @return array List of Kolab data objects (each represented as hash array)
+     * @see kolab_storage_format::select()
+     */
+    public static function select($query, $type)
+    {
+        self::setup();
+        $folder = null;
+        $result = array();
+
+        foreach ((array)self::list_folders('', '*', $type) as $foldername) {
+            if (!$folder)
+                $folder = new kolab_storage_folder($foldername);
+            else
+                $folder->set_folder($foldername);
+
+            foreach ($folder->select($query, '*') as $object) {
+                $result[] = $object;
+            }
+        }
+
+        return $result;
+    }
 
     /**
      *




More information about the commits mailing list