Page MenuHomePhorge

kolab_tags_engine.php
No OneTemporary

Authored By
Unknown
Size
14 KB
Referenced Files
None
Subscribers
None

kolab_tags_engine.php

<?php
/**
* Kolab Tags engine
*
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
*
* 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 kolab_tags_engine
{
private $backend;
private $plugin;
private $rc;
/**
* Class constructor
*/
public function __construct($plugin)
{
$plugin->require_plugin('libkolab');
require_once $plugin->home . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'kolab_tags_backend.php';
$this->backend = new kolab_tags_backend;
$this->plugin = $plugin;
$this->rc = $plugin->rc;
}
/**
* User interface initialization
*/
public function ui()
{
// set templates of Files UI and widgets
if ($this->rc->task == 'mail') {
$this->plugin->add_texts('localization/');
$this->plugin->include_stylesheet($this->plugin->local_skin_path().'/style.css');
$this->plugin->include_script('kolab_tags.js');
$this->rc->output->add_label('cancel', 'save');
$this->plugin->add_label('tags', 'add', 'edit', 'delete', 'saving',
'nameempty', 'nameexists', 'colorinvalid', 'untag', 'tagname', 'tagcolor');
$this->rc->output->add_handlers(array(
'plugin.taglist' => array($this, 'taglist'),
));
$ui = $this->rc->output->parse('kolab_tags.ui', false, false);
$this->rc->output->add_footer($ui);
// load miniColors
jqueryui::miniColors();
}
}
/**
* Engine actions handler (managing tag objects)
*/
public function actions()
{
$this->plugin->add_texts('localization/');
$action = rcube_utils::get_input_value('_act', rcube_utils::INPUT_POST);
if ($action) {
$this->{'action_' . $action}();
}
// manage tag objects
else {
$delete = (array) rcube_utils::get_input_value('delete', rcube_utils::INPUT_POST);
$update = (array) rcube_utils::get_input_value('update', rcube_utils::INPUT_POST, true);
$add = (array) rcube_utils::get_input_value('add', rcube_utils::INPUT_POST, true);
$response = array();
// tags deletion
foreach ($delete as $uid) {
if ($this->backend->remove($uid)) {
$response['delete'][] = $uid;
}
}
// tags creation
foreach ($add as $tag) {
if ($tag = $this->backend->create($tag)) {
$response['add'][] = $this->parse_tag($tag);
}
}
// tags update
foreach ($update as $tag) {
if ($this->backend->update($tag)) {
$response['update'][] = $this->parse_tag($tag);
}
}
if (!empty($error)) {
$this->rc->output->show_message($this->plugin->gettext('updateerror'), 'error');
}
else {
$this->rc->output->show_message($this->plugin->gettext('updatesuccess'), 'confirmation');
}
$this->rc->output->command('plugin.kolab_tags', $response);
}
$this->rc->output->send();
}
/**
* Remove tag from message(s)
*/
public function action_remove()
{
$tag = rcube_utils::get_input_value('_tag', rcube_utils::INPUT_POST);
$filter = $tag == '*' ? array() : array(array('uid', '=', explode(',', $tag)));
$taglist = $this->backend->list_tags($filter);
$filter = array();
foreach (rcmail::get_uids() as $mbox => $uids) {
if ($uids === '*') {
$filter[$mbox] = $this->build_member_url(array('folder' => $mbox));
}
else {
foreach ((array)$uids as $uid) {
$filter[$mbox][] = $this->build_member_url(array(
'folder' => $mbox,
'uid' => $uid
));
}
}
}
// for every tag...
foreach ($taglist as $tag) {
$updated = false;
// @todo: make sure members list is up-to-date (UIDs are up-to-date)
// ...filter members by folder/uid prefix
foreach ((array) $tag['members'] as $idx => $member) {
foreach ($filter as $folder => $members) {
// list of prefixes
if (is_array($members)) {
foreach ($members as $message) {
if ($member == $message || strpos($member, $message . '?') === 0) {
unset($tag['members'][$idx]);
$updated = true;
}
}
}
// one prefix (all messages in a folder)
else {
if (preg_match('/^' . preg_quote($members, '/') . '\/[0-9]+(\?|$)/', $member)) {
unset($tag['members'][$idx]);
$updated = true;
}
}
}
}
// update tag object
if ($updated) {
if (!$this->backend->update($tag)) {
$error = true;
}
}
}
if ($error) {
if ($_POST['_from'] != 'show') {
$this->rc->output->show_message($this->plugin->gettext('untaggingerror'), 'error');
$this->rc->output->command('list_mailbox');
}
}
else {
$this->rc->output->show_message($this->plugin->gettext('untaggingsuccess'), 'confirmation');
}
}
/**
* Add tag to message(s)
*/
public function action_add()
{
$tag = rcube_utils::get_input_value('_tag', rcube_utils::INPUT_POST);
$filter = array(array('uid', '=', explode(',', $tag)));
$taglist = $this->backend->list_tags($filter);
$storage = $this->rc->get_storage();
$members = array();
// build list of members
foreach (rcmail::get_uids() as $mbox => $uids) {
if ($uids === '*') {
$index = $storage->index($mbox, null, null, true);
$uids = $index->get();
$msgs = $storage->fetch_headers($mbox, $uids, false);
}
else {
$msgs = $storage->fetch_headers($mbox, $uids, false);
}
$members = array_merge($members, $this->build_members($mbox, $msgs));
}
// for every tag...
foreach ($taglist as $tag) {
$tag['members'] = array_unique(array_merge((array) $tag['members'], $members));
// update tag object
if (!$this->backend->update($tag)) {
$error = true;
}
}
if ($error) {
if ($_POST['_from'] != 'show') {
$this->rc->output->show_message($this->plugin->gettext('taggingerror'), 'error');
$this->rc->output->command('list_mailbox');
}
}
else {
$this->rc->output->show_message($this->plugin->gettext('taggingsuccess'), 'confirmation');
}
}
/**
* Template object building tags list/cloud
*/
public function taglist($attrib)
{
$taglist = $this->backend->list_tags();
$taglist = array_map(array($this, 'parse_tag'), $taglist);
$this->rc->output->set_env('tags', $taglist);
$this->rc->output->add_gui_object('taglist', $attrib['id']);
return html::tag('ul', $attrib, '', html::$common_attrib);
}
/**
* Handler for messages list (add tag-boxes in subject line on the list)
*/
public function messages_list_handler($args)
{
if (empty($args['messages'])) {
return;
}
// get tags list
$taglist = $this->backend->list_tags();
// get message UIDs
foreach ($args['messages'] as $msg) {
$message_tags[$msg->uid . '-' . $msg->folder] = null;
}
$uids = array_keys($message_tags);
foreach ($taglist as $tag) {
$tag = $this->parse_tag($tag, true);
foreach ((array) $tag['uids'] as $folder => $_uids) {
array_walk($_uids, function(&$uid, $key, $folder) { $uid .= '-' . $folder; }, $folder);
foreach (array_intersect($uids, $_uids) as $uid) {
$message_tags[$uid][] = $tag['uid'];
}
}
}
$this->rc->output->set_env('message_tags', array_filter($message_tags));
// @TODO: tag counters for the whole folder (search result)
return $args;
}
/**
* Handler for a single message (add tag-boxes in subject line)
*/
public function message_headers_handler($args)
{
$taglist = $this->backend->list_tags();
$uid = $args['uid'];
$folder = $args['folder'];
$tags = array();
foreach ($taglist as $tag) {
$tag = $this->parse_tag($tag, true);
if (in_array($uid, (array)$tag['uids'][$folder])) {
unset($tag['uids']);
$tags[] = $tag;
}
}
if (!empty($tags)) {
$this->rc->output->set_env('message_tags', $tags);
}
return $args;
}
/**
* Handler for messages searching requests
*/
public function imap_search_handler($args)
{
if (empty($args['search_tags'])) {
return $args;
}
// we'll reset to current folder to fix issues when searching in multi-folder mode
$storage = $this->rc->get_storage();
$orig_folder = $storage->get_folder();
// get tags
$tags = $this->backend->list_tags(array(array('uid', '=', $args['search_tags'])));
// sanity check (that should not happen)
if (empty($tags)) {
if ($orig_folder) {
$storage->set_folder($orig_folder);
}
return $args;
}
$search = array();
$folders = (array) $args['folder'];
// collect folders and uids
foreach ($tags as $tag) {
$tag = $this->parse_tag($tag, true);
// tag has no members -> empty search result
if (empty($tag['uids'])) {
goto empty_result;
}
foreach ($tag['uids'] as $folder => $uid_list) {
$search[$folder] = array_merge((array)$search[$folder], $uid_list);
}
}
$search = array_map('array_unique', $search);
$criteria = array();
// modify search folders/criteria
$args['folder'] = array_intersect($folders, array_keys($search));
foreach ($args['folder'] as $folder) {
$criteria[$folder] = ($args['search'] != 'ALL' ? trim($args['search']).' ' : '')
. 'UID ' . rcube_imap_generic::compressMessageSet($search[$folder]);
}
if (!empty($args['folder'])) {
$args['search'] = $criteria;
}
else {
// return empty result
empty_result:
if (count($folders) > 1) {
$args['result'] = new rcube_result_multifolder($args['folder']);
foreach ($args['folder'] as $folder) {
$index = new rcube_result_index($folder, '* SORT');
$args['result']->add($index);
}
}
else {
$class = 'rcube_result_' . ($args['threading'] ? 'thread' : 'index');
$result = $args['threading'] ? '* THREAD' : '* SORT';
$args['result'] = new $class($folder, $result);
}
}
if ($orig_folder) {
$storage->set_folder($orig_folder);
}
return $args;
}
/**
* "Convert" tag object to simple array for use in javascript
*/
private function parse_tag($tag, $list = false)
{
$result = array(
'uid' => $tag['uid'],
'name' => $tag['name'],
'color' => $tag['color'],
);
if ($list) {
$result['uids'] = $this->get_tag_messages($tag);
}
return $result;
}
/**
* Resolve members to folder/UID
*
* @param array $tag Tag object
*
* @return array Folder/UID list
*/
protected function get_tag_messages(&$tag, $force = true)
{
return kolab_storage_config::resolve_members($tag, $force);
}
/**
* Build array of member URIs from set of messages
*/
protected function build_members($folder, $messages)
{
return kolab_storage_config::build_members($folder, $messages);
}
/**
* Parses tag member string
*
* @param string $url Member URI
*
* @return array Message folder, UID, Search headers (Message-Id, Date)
*/
protected function parse_member_url($url)
{
return kolab_storage_config::parse_member_url($url);
}
/**
* Builds member URI
*
* @param array Message folder, UID, Search headers (Message-Id, Date)
*
* @return string $url Member URI
*/
protected function build_member_url($params)
{
return kolab_storage_config::build_member_url($params);
}
}

File Metadata

Mime Type
text/x-php
Expires
Sat, Apr 4, 7:16 AM (1 w, 4 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
20/e3/de941c010f5d87638a7b0a040726
Default Alt Text
kolab_tags_engine.php (14 KB)

Event Timeline