Page MenuHomePhorge

No OneTemporary

Size
23 KB
Referenced Files
None
Subscribers
None
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

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)

Event Timeline