Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F9785716
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/plugins/kolab_zpush/kolab_zpush.php b/plugins/kolab_zpush/kolab_zpush.php
index c7469f1d..7624cd00 100644
--- a/plugins/kolab_zpush/kolab_zpush.php
+++ b/plugins/kolab_zpush/kolab_zpush.php
@@ -1,344 +1,344 @@
<?php
/**
* Z-Push configuration utility for Kolab accounts
*
* @version 0.2
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
- * Copyright (C) 2011, Kolab Systems AG <contact@kolabsys.com>
+ * Copyright (C) 2012, 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_zpush extends rcube_plugin
{
public $task = 'settings';
public $urlbase;
private $rc;
private $ui;
private $cache;
private $devices;
private $folders;
private $folders_meta;
private $root_meta;
const ROOT_MAILBOX = 'INBOX';
const CTYPE_KEY = '/shared/vendor/kolab/folder-type';
const ACTIVESYNC_KEY = '/private/vendor/kolab/activesync';
/**
* Plugin initialization.
*/
public function init()
{
$this->rc = rcmail::get_instance();
$this->require_plugin('jqueryui');
$this->add_texts('localization/', true);
$this->include_script('kolab_zpush.js');
$this->register_action('plugin.zpushconfig', array($this, 'config_view'));
$this->register_action('plugin.zpushjson', array($this, 'json_command'));
if ($this->rc->action == 'plugin.zpushconfig')
$this->require_plugin('kolab_core');
}
/**
* Establish IMAP connection
*/
public function init_imap()
{
$this->rc->imap_connect();
$this->cache = $this->rc->get_cache('zpush', 'db', 900);
$this->cache->expunge();
if ($meta = $this->rc->imap->get_metadata(self::ROOT_MAILBOX, self::ACTIVESYNC_KEY)) {
// clear cache if device config changed
if (($oldmeta = $this->cache->read('devicemeta')) && $oldmeta != $meta)
$this->cache->remove();
$this->root_meta = $this->unserialize_metadata($meta[self::ROOT_MAILBOX][self::ACTIVESYNC_KEY]);
$this->cache->remove('devicemeta');
$this->cache->write('devicemeta', $meta);
}
}
/**
* Handle JSON requests
*/
public function json_command()
{
$cmd = get_input_value('cmd', RCUBE_INPUT_GPC);
$imei = get_input_value('id', RCUBE_INPUT_GPC);
switch ($cmd) {
case 'load':
$result = array();
$this->init_imap();
$devices = $this->list_devices();
if ($device = $devices[$imei]) {
$result['id'] = $imei;
$result['devicealias'] = $device['ALIAS'];
$result['syncmode'] = intval($device['MODE']);
$result['laxpic'] = intval($device['LAXPIC']);
$result['subscribed'] = array();
foreach ($this->folders_meta() as $folder => $meta) {
if ($meta[$imei]['S'])
$result['subscribed'][$folder] = intval($meta[$imei]['S']);
}
$this->rc->output->command('plugin.zpush_data_ready', $result);
}
else {
$this->rc->output->show_message($this->gettext('devicenotfound'), 'error');
}
break;
case 'save':
$this->init_imap();
$devices = $this->list_devices();
$syncmode = intval(get_input_value('syncmode', RCUBE_INPUT_POST));
$devicealias = get_input_value('devicealias', RCUBE_INPUT_POST, true);
$laxpic = intval(get_input_value('laxpic', RCUBE_INPUT_POST));
$subsciptions = get_input_value('subscribed', RCUBE_INPUT_POST);
$err = false;
if ($device = $devices[$imei]) {
// update device config if changed
if ($devicealias != $this->root_meta['DEVICE'][$imei]['ALIAS'] ||
$syncmode != $this->root_meta['DEVICE'][$imei]['MODE'] ||
$laxpic != $this->root_meta['DEVICE'][$imei]['LAXPIC'] ||
$subsciptions[self::ROOT_MAILBOX] != $this->root_meta['FOLDER'][$imei]['S']) {
$this->root_meta['DEVICE'][$imei]['MODE'] = $syncmode;
$this->root_meta['DEVICE'][$imei]['ALIAS'] = $devicealias;
$this->root_meta['DEVICE'][$imei]['LAXPIC'] = $laxpic;
$this->root_meta['FOLDER'][$imei]['S'] = intval($subsciptions[self::ROOT_MAILBOX]);
$err = !$this->rc->imap->set_metadata(self::ROOT_MAILBOX,
array(self::ACTIVESYNC_KEY => $this->serialize_metadata($this->root_meta)));
// update cached meta data
if (!$err) {
$this->cache->remove('devicemeta');
$this->cache->write('devicemeta', $this->rc->imap->get_metadata(self::ROOT_MAILBOX, self::ACTIVESYNC_KEY));
}
}
// iterate over folders list and update metadata if necessary
foreach ($this->folders_meta() as $folder => $meta) {
// skip root folder (already handled above)
if ($folder == self::ROOT_MAILBOX)
continue;
if ($subsciptions[$folder] != $meta[$imei]['S']) {
$meta[$imei]['S'] = intval($subsciptions[$folder]);
$this->folders_meta[$folder] = $meta;
unset($meta['TYPE']);
// read metadata first
$folderdata = $this->rc->imap->get_metadata($folder, array(self::ACTIVESYNC_KEY));
if ($asyncdata = $folderdata[$folder][self::ACTIVESYNC_KEY])
$metadata = $this->unserialize_metadata($asyncdata);
$metadata['FOLDER'] = $meta;
$err |= !$this->rc->imap->set_metadata($folder, array(self::ACTIVESYNC_KEY => $this->serialize_metadata($metadata)));
}
}
// update cache
$this->cache->remove('folders');
$this->cache->write('folders', $this->folders_meta);
$this->rc->output->command('plugin.zpush_save_complete', array('success' => !$err, 'id' => $imei, 'devicealias' => Q($devicealias)));
}
if ($err)
$this->rc->output->show_message($this->gettext('savingerror'), 'error');
else
$this->rc->output->show_message($this->gettext('successfullysaved'), 'confirmation');
break;
case 'delete':
$this->init_imap();
$devices = $this->list_devices();
if ($device = $devices[$imei]) {
unset($this->root_meta['DEVICE'][$imei], $this->root_meta['FOLDER'][$imei]);
// update annotation and cached meta data
if ($success = $this->rc->imap->set_metadata(self::ROOT_MAILBOX, array(self::ACTIVESYNC_KEY => $this->serialize_metadata($this->root_meta)))) {
$this->cache->remove('devicemeta');
$this->cache->write('devicemeta', $this->rc->imap->get_metadata(self::ROOT_MAILBOX, self::ACTIVESYNC_KEY));
// remove device annotation in every folder
foreach ($this->folders_meta() as $folder => $meta) {
// skip root folder (already handled above)
if ($folder == self::ROOT_MAILBOX)
continue;
if (isset($meta[$imei])) {
$type = $meta['TYPE']; // remember folder type
unset($meta[$imei], $meta['TYPE']);
// read metadata first and update FOLDER property
$folderdata = $this->rc->imap->get_metadata($folder, array(self::ACTIVESYNC_KEY));
if ($asyncdata = $folderdata[$folder][self::ACTIVESYNC_KEY])
$metadata = $this->unserialize_metadata($asyncdata);
$metadata['FOLDER'] = $meta;
if ($this->rc->imap->set_metadata($folder, array(self::ACTIVESYNC_KEY => $this->serialize_metadata($metadata)))) {
$this->folders_meta[$folder] = $metadata;
$this->folders_meta[$folder]['TYPE'] = $type;
}
}
}
// update cache
$this->cache->remove('folders');
$this->cache->write('folders', $this->folders_meta);
}
}
if ($success) {
$this->rc->output->show_message($this->gettext('successfullydeleted'), 'confirmation');
$this->rc->output->redirect(array('action' => 'plugin.zpushconfig')); // reload UI
}
else
$this->rc->output->show_message($this->gettext('savingerror'), 'error');
break;
}
$this->rc->output->send();
}
/**
* Render main UI for device configuration
*/
public function config_view()
{
require_once($this->home . '/kolab_zpush_ui.php');
$this->init_imap();
// checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
if (!($this->rc->imap->get_capability('METADATA') || $this->rc->imap->get_capability('ANNOTATEMORE') || $this->rc->imap->get_capability('ANNOTATEMORE2'))) {
$this->rc->output->show_message($this->gettext('notsupported'), 'error');
}
$this->ui = new kolab_zpush_ui($this);
$this->register_handler('plugin.devicelist', array($this->ui, 'device_list'));
$this->register_handler('plugin.deviceconfigform', array($this->ui, 'device_config_form'));
$this->register_handler('plugin.foldersubscriptions', array($this->ui, 'folder_subscriptions'));
$this->rc->output->set_env('devicecount', count($this->list_devices()));
$this->rc->output->send('kolab_zpush.config');
}
/**
* List known devices
*
* @return array Device list as hash array
*/
public function list_devices()
{
if (!isset($this->devices)) {
$this->devices = (array)$this->root_meta['DEVICE'];
}
return $this->devices;
}
/**
* Get list of all folders available for sync
*
* @return array List of mailbox folders
*/
public function list_folders()
{
if (!isset($this->folders)) {
// read cached folder meta data
if ($cached_folders = $this->cache->read('folders')) {
$this->folders_meta = $cached_folders;
$this->folders = array_keys($this->folders_meta);
}
// fetch folder data from server
else {
- $this->folders = $this->rc->imap->list_unsubscribed();
+ $this->folders = $this->rc->imap->list_folders();
foreach ($this->folders as $folder) {
$folderdata = $this->rc->imap->get_metadata($folder, array(self::ACTIVESYNC_KEY, self::CTYPE_KEY));
$foldertype = explode('.', $folderdata[$folder][self::CTYPE_KEY]);
if ($asyncdata = $folderdata[$folder][self::ACTIVESYNC_KEY]) {
$metadata = $this->unserialize_metadata($asyncdata);
$this->folders_meta[$folder] = $metadata['FOLDER'];
}
$this->folders_meta[$folder]['TYPE'] = !empty($foldertype[0]) ? $foldertype[0] : 'mail';
}
// cache it!
$this->cache->write('folders', $this->folders_meta);
}
}
return $this->folders;
}
/**
* Getter for folder metadata
*
* @return array Hash array with meta data for each folder
*/
public function folders_meta()
{
if (!isset($this->folders_meta))
$this->list_folders();
return $this->folders_meta;
}
/**
* Helper method to decode saved IMAP metadata
*/
private function unserialize_metadata($str)
{
if (!empty($str))
return @json_decode(base64_decode($str), true);
return null;
}
/**
* Helper method to encode IMAP metadata for saving
*/
private function serialize_metadata($data)
{
if (is_array($data))
return base64_encode(json_encode($data));
return '';
}
}
diff --git a/plugins/kolab_zpush/package.xml b/plugins/kolab_zpush/package.xml
index 6313d1e3..250d1a66 100644
--- a/plugins/kolab_zpush/package.xml
+++ b/plugins/kolab_zpush/package.xml
@@ -1,64 +1,71 @@
<?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>kolab_zpush</name>
- <uri>http://kolabsys.com</uri>
+ <uri>http://git.kolab.org/roundcube-plugins-kolab/</uri>
<summary>Z-Push configuration utility for Kolab accounts</summary>
<description></description>
<lead>
<name>Thomas Bruederli</name>
<user>thomasb</user>
<email>bruederli@kolabsys.com</email>
<active>yes</active>
</lead>
<date>2011-11-14</date>
<time>12:12:00</time>
<version>
- <release>0.2</release>
+ <release>0.3</release>
</version>
<stability>
<release>stable</release>
</stability>
<license uri="http://www.gnu.org/licenses/agpl.html">GNU AGPL</license>
<notes>-</notes>
<contents>
<dir baseinstalldir="/" name="/">
<file name="kolab_zpush.php" role="php"></file>
<file name="kolab_zpush_ui.php" role="php"></file>
<file name="kolab_zpush.js" role="data"></file>
<file name="localization/de_CH.inc" role="data"></file>
<file name="localization/en_US.inc" role="data"></file>
<file name="localization/pl_PL.inc" role="data"></file>
<file name="skins/default/templates/config.html" role="data"></file>
<file name="skins/default/config.css" role="data"></file>
<file name="skins/default/alarm-clock.png" role="data"></file>
<file name="skins/default/deviceactions.png" role="data"></file>
<file name="skins/default/foldertypes.png" role="data"></file>
<file name="skins/default/pointer-left.gif" role="data"></file>
<file name="skins/default/synchronize.png" role="data"></file>
+ <file name="skins/larry/templates/config.html" role="data"></file>
+ <file name="skins/larry/config.css" role="data"></file>
+ <file name="skins/larry/alarm-clock.png" role="data"></file>
+ <file name="skins/larry/deviceactions.png" role="data"></file>
+ <file name="skins/larry/foldertypes.png" role="data"></file>
+ <file name="skins/larry/pointer-left.png" role="data"></file>
+ <file name="skins/larry/synchronize.png" role="data"></file>
<file name="README" role="data"></file>
<file name="LICENSE" role="data"></file>
</dir>
</contents>
<dependencies>
<required>
<php>
<min>5.2.1</min>
</php>
<pearinstaller>
<min>1.7.0</min>
</pearinstaller>
<package>
<name>kolab_core</name>
<uri>http://kolabsys.com</uri>
</package>
<package>
<name>jqueryui</name>
<channel>pear.roundcube.net</uri>
</package>
</required>
</dependencies>
<phprelease/>
</package>
diff --git a/plugins/kolab_zpush/skins/larry/alarm-clock.png b/plugins/kolab_zpush/skins/larry/alarm-clock.png
new file mode 100755
index 00000000..518bdc11
Binary files /dev/null and b/plugins/kolab_zpush/skins/larry/alarm-clock.png differ
diff --git a/plugins/kolab_zpush/skins/larry/config.css b/plugins/kolab_zpush/skins/larry/config.css
new file mode 100644
index 00000000..c7bc1fbb
--- /dev/null
+++ b/plugins/kolab_zpush/skins/larry/config.css
@@ -0,0 +1,140 @@
+/* Stylesheets for the Kolab Z-Push configuration UI */
+
+#configform {
+ padding-top: 15px;
+}
+
+#sectionslist {
+ width: 220px;
+}
+
+#prefs-box {
+ position: absolute;
+ top: 0;
+ left: 232px;
+ right: 0;
+ bottom: 0;
+}
+
+#devices-table {
+ width: 100%;
+ table-layout: fixed;
+}
+
+#devices-table td {
+ cursor: pointer;
+}
+
+#devices-table td span.devicetype {
+ padding-left: 1em;
+ font-style: italic;
+ color: #69939e;
+}
+
+.boxfooter a.button.delete,
+.boxfooter a.buttonPas.delete {
+ background-image: url(deviceactions.png);
+}
+
+div.subscriptionblock {
+ float: left;
+ margin: 0 3em 2em 0;
+ padding: 0;
+}
+
+div.subscriptionblock h3 {
+ font-size: 14px;
+ color: #333;
+ margin: 0 0 0.6em 0;
+ padding: 2px 4px 2px 30px;
+ background: url(foldertypes.png) 4px 2px no-repeat;
+}
+
+div.subscriptionblock h3.contact {
+ background-position: 4px -18px;
+}
+
+div.subscriptionblock h3.event {
+ background-position: 4px -38px;
+}
+
+div.subscriptionblock h3.task {
+ background-position: 4px -58x;
+}
+
+div.subscriptionblock h3.note {
+ background-position: 4px -78px;
+}
+
+#foldersubscriptions thead td {
+ color: #69939e;
+ font-weight: bold;
+ padding: 3px 5px;
+ min-width: 2em;
+ background: #d6eaf3;
+ border-bottom: 2px solid #fff;
+}
+
+#foldersubscriptions tbody td {
+ background: #eee;
+ padding: 2px 5px;
+ border-bottom: 2px solid #fff;
+}
+
+#foldersubscriptions td label {
+ display: block;
+}
+
+#foldersubscriptions td.mailbox {
+ padding-right: 3em;
+ padding-left: 2px;
+ min-width: 12em;
+}
+
+#foldersubscriptions td.virtual {
+ color: #999;
+}
+
+#foldersubscriptions {
+ overflow: auto;
+ max-height: 400px;
+ margin-top: 0.5em;
+}
+
+#introtext {
+ position: absolute;
+ top: 16px;
+ left: 5px;
+ padding-left: 10px;
+ max-width: 40em;
+}
+
+#introtext .pointer-left {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 12px;
+ height: 80%;
+ background: url(pointer-left.png) right center no-repeat;
+}
+
+#introtext .inner {
+ color: #eee;
+ padding: 12px;
+ border: 1px solid #333;
+ border-radius: 4px;
+ text-shadow: 0px 1px 1px #333;
+ background: #5b5b5b;
+ background: -moz-linear-gradient(top, #5b5b5b 0%, #3a3a3a 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#5b5b5b), color-stop(100%,#3a3a3a));
+ background: -o-linear-gradient(top, #5b5b5b 0%, #3a3a3a 100%);
+ background: -ms-linear-gradient(top, #5b5b5b 0%, #3a3a3a 100%);
+ background: linear-gradient(top, #5b5b5b 0%, #3a3a3a 100%);
+ -webkit-box-shadow: inset 0px 0px 0px 1px #7e7e7e, 0 2px 6px 0 #333;
+ -moz-box-shadow: inset 0px 0px 0px 1px #7e7e7e, 0 2px 6px 0 #333;
+ box-shadow: inset 0px 0px 0px 1px #7e7e7e, 0 2px 6px 0 #333;
+}
+
+#introtext a {
+ color: #b0ccd7;
+}
diff --git a/plugins/kolab_zpush/skins/larry/deviceactions.png b/plugins/kolab_zpush/skins/larry/deviceactions.png
new file mode 100644
index 00000000..d2429531
Binary files /dev/null and b/plugins/kolab_zpush/skins/larry/deviceactions.png differ
diff --git a/plugins/kolab_zpush/skins/larry/foldertypes.png b/plugins/kolab_zpush/skins/larry/foldertypes.png
new file mode 100644
index 00000000..4950296a
Binary files /dev/null and b/plugins/kolab_zpush/skins/larry/foldertypes.png differ
diff --git a/plugins/kolab_zpush/skins/larry/pointer-left.png b/plugins/kolab_zpush/skins/larry/pointer-left.png
new file mode 100644
index 00000000..bfa7e86c
Binary files /dev/null and b/plugins/kolab_zpush/skins/larry/pointer-left.png differ
diff --git a/plugins/kolab_zpush/skins/larry/synchronize.png b/plugins/kolab_zpush/skins/larry/synchronize.png
new file mode 100755
index 00000000..ba5ebd1f
Binary files /dev/null and b/plugins/kolab_zpush/skins/larry/synchronize.png differ
diff --git a/plugins/kolab_zpush/skins/larry/templates/config.html b/plugins/kolab_zpush/skins/larry/templates/config.html
new file mode 100644
index 00000000..9671bc6a
--- /dev/null
+++ b/plugins/kolab_zpush/skins/larry/templates/config.html
@@ -0,0 +1,71 @@
+<roundcube:object name="doctype" value="html5" />
+<html>
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<roundcube:include file="/includes/links.html" />
+</head>
+<body>
+
+<roundcube:include file="/includes/header.html" />
+
+<div id="mainscreen" class="offset">
+
+<roundcube:include file="/includes/settingstabs.html" />
+
+<div id="settings-right">
+
+<div id="sectionslist" class="uibox listbox">
+<h2 id="directorylist-title" class="boxtitle"><roundcube:label name="kolab_zpush.devices" /></h2>
+<div class="boxlistcontent">
+ <roundcube:object name="plugin.devicelist" id="devices-table" class="listing" cellspacing="0" />
+</div>
+<div class="boxfooter">
+ <roundcube:button type="link" command="plugin.delete-device" title="kolab_zpush.deletedevice" class="listbutton delete disabled" classAct="listbutton delete" innerClass="inner" content="x" />
+</div>
+</div>
+
+<div id="prefs-box" class="uibox contentbox">
+ <h1 class="boxtitle" style="display:none"><roundcube:label name="kolab_zpush.syncsettings"></h1>
+ <form action="#" method="post" id="configform" class="boxcontent tabbed" style="display:none">
+ <fieldset>
+ <legend><roundcube:label name="kolab_zpush.folderstosync" /></legend>
+ <roundcube:object name="plugin.foldersubscriptions" form="configform" id="foldersubscriptions" syncicon="synchronize.png" alarmicon="alarm-clock.png" />
+ </fieldset>
+ <fieldset>
+ <legend><roundcube:label name="kolab_zpush.deviceconfig" /></legend>
+ <roundcube:object name="plugin.deviceconfigform" form="configform" class="propform" />
+ </fieldset>
+
+ <p class="formbuttons">
+ <roundcube:button type="input" class="button mainaction" command="plugin.save-config" label="save" />
+ <roundcube:button type="input" class="button" command="plugin.delete-device" label="kolab_zpush.deletedevice" />
+ </p>
+ </form>
+
+ <div id="introtext">
+ <div class="inner">
+ <roundcube:if condition="env:devicecount" />
+ <roundcube:label name="kolab_zpush.introtext" />
+ <roundcube:else />
+ <roundcube:label name="kolab_zpush.nodevices" html="true" />
+ <roundcube:endif />
+ </div>
+ <div class="pointer-left"></div>
+ </div>
+
+ <roundcube:object name="message" id="message" class="statusbar" />
+</div>
+
+</div>
+
+<roundcube:include file="/includes/footer.html" />
+
+<script type="text/javascript">
+
+ var viewsplit = new rcube_splitter({ id:'devicelistsplitter', p1:'#sectionslist', p2:'#prefs-box', orientation:'v', relative:true, start:226, min:150, size:12 });
+ rcmail.add_onload('viewsplit.init()');
+
+</script>
+
+</body>
+</html>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Aug 17, 8:27 PM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1257662
Default Alt Text
(23 KB)
Attached To
Mode
R14 roundcubemail-plugins-kolab
Attached
Detach File
Event Timeline
Log In to Comment