Page MenuHomePhorge

No OneTemporary

Size
30 KB
Referenced Files
None
Subscribers
None
diff --git a/plugins/kolab_activesync/kolab_activesync.php b/plugins/kolab_activesync/kolab_activesync.php
index 0238f116..19604afa 100644
--- a/plugins/kolab_activesync/kolab_activesync.php
+++ b/plugins/kolab_activesync/kolab_activesync.php
@@ -1,486 +1,517 @@
<?php
/**
* ActiveSync configuration utility for Kolab accounts
*
* @version @package_version@
* @author Aleksander Machniak <machniak@kolabsys.com>
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2011-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_activesync extends rcube_plugin
{
public $task = 'settings';
public $urlbase;
public $backend;
private $rc;
private $ui;
private $folder_meta;
private $root_meta;
const ROOT_MAILBOX = 'INBOX';
const ASYNC_KEY = '/private/vendor/kolab/activesync';
const CTYPE_KEY = '/shared/vendor/kolab/folder-type';
/**
* Plugin initialization.
*/
public function init()
{
$this->rc = rcube::get_instance();
$this->require_plugin('jqueryui');
$this->require_plugin('libkolab');
$this->register_action('plugin.activesync', array($this, 'config_view'));
$this->register_action('plugin.activesync-config', array($this, 'config_frame'));
$this->register_action('plugin.activesync-json', array($this, 'json_command'));
$this->add_texts('localization/', true);
$this->include_script('kolab_activesync.js');
}
/**
* 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 'save':
$devices = $this->list_devices();
$device = $devices[$imei];
$subscriptions = (array) get_input_value('subscribed', RCUBE_INPUT_POST);
$devicealias = get_input_value('devicealias', RCUBE_INPUT_POST, true);
// $syncmode = intval(get_input_value('syncmode', RCUBE_INPUT_POST));
// $laxpic = intval(get_input_value('laxpic', RCUBE_INPUT_POST));
$device['ALIAS'] = $devicealias;
// $device['MODE'] = $syncmode;
// $device['LAXPIC'] = $laxpic;
$err = !$this->device_update($device, $imei);
if (!$err) {
// iterate over folders list and update metadata if necessary
// old subscriptions
foreach ($this->folder_meta() as $folder => $meta) {
$err |= !$this->folder_set($folder, $imei, intval($subscriptions[$folder]));
unset($subsciptions[$folder]);
}
// new subscription
foreach ($subscriptions as $folder => $flag) {
$err |= !$this->folder_set($folder, $imei, intval($flag));
}
$this->rc->output->command('plugin.activesync_save_complete', array(
'success' => !$err, 'id' => $imei, 'alias' => 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':
$success = $this->device_delete($imei);
if ($success) {
$this->rc->output->show_message($this->gettext('successfullydeleted'), 'confirmation');
$this->rc->output->command('plugin.activesync_save_complete', array(
'success' => true, 'id' => $imei, 'delete' => true));
}
else
$this->rc->output->show_message($this->gettext('savingerror'), 'error');
break;
}
$this->rc->output->send();
}
/**
* Render main UI for devices configuration
*/
public function config_view()
{
$storage = $this->rc->get_storage();
// checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
if (!($storage->get_capability('METADATA') || $storage->get_capability('ANNOTATEMORE') || $storage->get_capability('ANNOTATEMORE2'))) {
$this->rc->output->show_message($this->gettext('notsupported'), 'error');
}
require_once $this->home . '/kolab_activesync_ui.php';
$this->ui = new kolab_activesync_ui($this);
$this->register_handler('plugin.devicelist', array($this->ui, 'device_list'));
$this->rc->output->send('kolab_activesync.config');
}
/**
* Render device configuration form
*/
public function config_frame()
{
$storage = $this->rc->get_storage();
// checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
if (!($storage->get_capability('METADATA') || $storage->get_capability('ANNOTATEMORE') || $storage->get_capability('ANNOTATEMORE2'))) {
$this->rc->output->show_message($this->gettext('notsupported'), 'error');
}
require_once $this->home . '/kolab_activesync_ui.php';
$this->ui = new kolab_activesync_ui($this);
if (!empty($_GET['_init'])) {
return $this->rc->output->send('kolab_activesync.configempty');
}
$this->register_handler('plugin.deviceconfigform', array($this->ui, 'device_config_form'));
$this->register_handler('plugin.foldersubscriptions', array($this->ui, 'folder_subscriptions'));
$imei = get_input_value('_id', RCUBE_INPUT_GPC);
$devices = $this->list_devices();
if ($device = $devices[$imei]) {
$this->ui->device = $device;
$this->ui->device['_id'] = $imei;
$this->rc->output->set_env('active_device', $imei);
$this->rc->output->command('parent.enable_command','plugin.delete-device', true);
}
else {
$this->rc->output->show_message($this->gettext('devicenotfound'), 'error');
}
$this->rc->output->send('kolab_activesync.configedit');
}
/**
* Get list of all folders available for sync
*
* @return array List of mailbox folders
*/
public function list_folders()
{
$storage = $this->rc->get_storage();
return $storage->list_folders();
}
/**
* Returns list of folders with assigned type
*
* @return array List of folder types indexed by folder name
*/
public function list_types()
{
if ($this->folder_types === null) {
$storage = $this->rc->get_storage();
$folderdata = $storage->get_metadata('*', self::CTYPE_KEY);
$this->folder_types = array();
foreach ($folderdata as $folder => $data) {
if ($data[self::CTYPE_KEY]) {
$this->folder_types[$folder] = $data[self::CTYPE_KEY];
}
}
}
return $this->folder_types;
}
/**
* List known devices
*
* @return array Device list as hash array
*/
public function list_devices()
{
if ($this->root_meta === null) {
$storage = $this->rc->get_storage();
// @TODO: consider server annotation instead of INBOX
if ($meta = $storage->get_metadata(self::ROOT_MAILBOX, self::ASYNC_KEY)) {
$this->root_meta = $this->unserialize_metadata($meta[self::ROOT_MAILBOX][self::ASYNC_KEY]);
}
else {
$this->root_meta = array();
}
}
if (!empty($this->root_meta['DEVICE']) && is_array($this->root_meta['DEVICE'])) {
return $this->root_meta['DEVICE'];
}
return array();
}
/**
* Getter for folder metadata
*
* @return array Hash array with meta data for each folder
*/
public function folder_meta()
{
if (!isset($this->folder_meta)) {
$this->folder_meta = array();
$storage = $this->rc->get_storage();
// get folders activesync config
$folderdata = $storage->get_metadata("*", self::ASYNC_KEY);
foreach ($folderdata as $folder => $meta) {
if ($asyncdata = $meta[self::ASYNC_KEY]) {
if ($metadata = $this->unserialize_metadata($asyncdata)) {
$this->folder_meta[$folder] = $metadata;
}
}
}
}
return $this->folder_meta;
}
/**
* Sets ActiveSync subscription flag on a folder
*
* @param string $name Folder name (UTF7-IMAP)
* @param string $deviceid Device identifier
* @param int $flag Flag value (0|1|2)
*/
public function folder_set($name, $deviceid, $flag)
{
if (empty($deviceid)) {
return false;
}
// get folders activesync config
$metadata = $this->folder_meta();
$metadata = $metadata[$name];
if ($flag) {
if (empty($metadata)) {
$metadata = array();
}
if (empty($metadata['FOLDER'])) {
$metadata['FOLDER'] = array();
}
if (empty($metadata['FOLDER'][$deviceid])) {
$metadata['FOLDER'][$deviceid] = array();
}
// Z-Push uses:
// 1 - synchronize, no alarms
// 2 - synchronize with alarms
$metadata['FOLDER'][$deviceid]['S'] = $flag;
}
if (!$flag) {
unset($metadata['FOLDER'][$deviceid]['S']);
if (empty($metadata['FOLDER'][$deviceid])) {
unset($metadata['FOLDER'][$deviceid]);
}
if (empty($metadata['FOLDER'])) {
unset($metadata['FOLDER']);
}
if (empty($metadata)) {
$metadata = null;
}
}
// Return if nothing's been changed
if (!self::data_array_diff($this->folder_meta[$name], $metadata)) {
return true;
}
$this->folder_meta[$name] = $metadata;
$storage = $this->rc->get_storage();
return $storage->set_metadata($name, array(
self::ASYNC_KEY => $this->serialize_metadata($metadata)));
}
-
+ /**
+ * Device update
+ *
+ * @param array $device Device data
+ * @param string $id Device ID
+ *
+ * @return bool True on success, False on failure
+ */
public function device_update($device, $id)
{
$devices_list = $this->list_devices();
$old_device = $devices_list[$id];
if (!$old_device) {
return false;
}
// Do nothing if nothing is changed
if (!self::data_array_diff($old_device, $device)) {
return true;
}
$device = array_merge($old_device, $device);
$metadata = $this->root_meta;
$metadata['DEVICE'][$id] = $device;
$metadata = array(self::ASYNC_KEY => $this->serialize_metadata($metadata));
$storage = $this->rc->get_storage();
$result = $storage->set_metadata(self::ROOT_MAILBOX, $metadata);
if ($result) {
// Update local cache
$this->root_meta['DEVICE'][$id] = $device;
}
return $result;
}
-
/**
* Device delete.
*
* @param string $id Device ID
*
* @return bool True on success, False on failure
*/
public function device_delete($id)
{
$devices_list = $this->list_devices();
$old_device = $devices_list[$id];
if (!$old_device) {
return false;
}
unset($this->root_meta['DEVICE'][$id], $this->root_meta['FOLDER'][$id]);
if (empty($this->root_meta['DEVICE'])) {
unset($this->root_meta['DEVICE']);
}
if (empty($this->root_meta['FOLDER'])) {
unset($this->root_meta['FOLDER']);
}
$metadata = $this->serialize_metadata($this->root_meta);
$metadata = array(self::ASYNC_KEY => $metadata);
$storage = $this->rc->get_storage();
// update meta data
$result = $storage->set_metadata(self::ROOT_MAILBOX, $metadata);
if ($result) {
// remove device annotation for every folder
foreach ($this->folder_meta() as $folder => $meta) {
// skip root folder (already handled above)
if ($folder == self::ROOT_MAILBOX)
continue;
if (!empty($meta['FOLDER']) && isset($meta['FOLDER'][$id])) {
unset($meta['FOLDER'][$id]);
if (empty($meta['FOLDER'])) {
unset($this->folder_meta[$folder]['FOLDER']);
unset($meta['FOLDER']);
}
if (empty($meta)) {
unset($this->folder_meta[$folder]);
$meta = null;
}
$metadata = array(self::ASYNC_KEY => $this->serialize_metadata($meta));
$res = $storage->set_metadata($folder, $metadata);
if ($res && $meta) {
$this->folder_meta[$folder] = $meta;
}
}
}
}
return $result;
}
+ /**
+ * Device information (from syncroton database)
+ *
+ * @param string $id Device ID
+ *
+ * @return array Device data
+ */
+ public function device_info($id)
+ {
+ $db = $this->rc->get_dbh();
+ $table = $db->table_name('syncroton_device');
+
+ if (in_array($table, $db->list_tables())) {
+ $fields = array('devicetype', 'acsversion', 'useragent', 'friendlyname', 'os',
+ 'oslanguage', 'phonenumber');
+
+ $result = $db->query("SELECT " . $db->array2list($fields, 'ident')
+ . " FROM $table WHERE owner_id = ? AND id = ?",
+ $this->rc->user->ID, $id);
+
+ if ($result && ($sql_arr = $db->fetch_assoc($result))) {
+ return $sql_arr;
+ }
+ }
+ }
/**
* Helper method to decode saved IMAP metadata
*/
private function unserialize_metadata($str)
{
if (!empty($str)) {
$data = @json_decode($str, true);
return $data;
}
return null;
}
/**
* Helper method to encode IMAP metadata for saving
*/
private function serialize_metadata($data)
{
if (!empty($data) && is_array($data)) {
$data = json_encode($data);
return $data;
}
return null;
}
/**
* Compares two arrays
*
* @param array $array1
* @param array $array2
*
* @return bool True if arrays differs, False otherwise
*/
private static function data_array_diff($array1, $array2)
{
if (!is_array($array1) || !is_array($array2)) {
return $array1 != $array2;
}
if (count($array1) != count($array2)) {
return true;
}
foreach ($array1 as $key => $val) {
if (!array_key_exists($key, $array2)) {
return true;
}
if ($val !== $array2[$key]) {
return true;
}
}
return false;
}
}
diff --git a/plugins/kolab_activesync/kolab_activesync_ui.php b/plugins/kolab_activesync/kolab_activesync_ui.php
index a1912554..6e796cc6 100644
--- a/plugins/kolab_activesync/kolab_activesync_ui.php
+++ b/plugins/kolab_activesync/kolab_activesync_ui.php
@@ -1,197 +1,209 @@
<?php
/**
* ActiveSync configuration user interface builder
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2011-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_activesync_ui
{
private $rc;
private $plugin;
public $device = array();
public function __construct($plugin)
{
$this->plugin = $plugin;
$this->rc = rcube::get_instance();
$skin_path = $this->plugin->local_skin_path() . '/';
$this->skin_path = 'plugins/kolab_activesync/' . $skin_path;
$this->plugin->include_stylesheet($skin_path . 'config.css');
$this->rc->output->include_script('list.js');
}
public function device_list($attrib = array())
{
$attrib += array('id' => 'devices-list');
$devices = $this->plugin->list_devices();
$table = new html_table();
foreach ($devices as $id => $device) {
$name = $device['ALIAS'] ? $device['ALIAS'] : $id;
$table->add_row(array('id' => 'rcmrow' . $id));
$table->add(null, html::span('devicealias', Q($name)) . html::span('devicetype', Q($device['TYPE'])));
}
$this->rc->output->add_gui_object('devicelist', $attrib['id']);
$this->rc->output->set_env('devicecount', count($devices));
return $table->show($attrib);
}
public function device_config_form($attrib = array())
{
$table = new html_table(array('cols' => 2));
$field_id = 'config-device-alias';
$input = new html_inputfield(array('name' => 'devicealias', 'id' => $field_id, 'size' => 40));
$table->add('title', html::label($field_id, $this->plugin->gettext('devicealias')));
$table->add(null, $input->show($this->device['ALIAS'] ? $this->device['ALIAS'] : $this->device['_id']));
/*
$field_id = 'config-device-mode';
$select = new html_select(array('name' => 'syncmode', 'id' => $field_id));
$select->add(array($this->plugin->gettext('modeauto'), $this->plugin->gettext('modeflat'), $this->plugin->gettext('modefolder')), array('-1', '0', '1'));
$table->add('title', html::label($field_id, $this->plugin->gettext('syncmode')));
$table->add(null, $select->show('-1'));
$field_id = 'config-device-laxpic';
$checkbox = new html_checkbox(array('name' => 'laxpic', 'value' => '1', 'id' => $field_id));
$table->add('title', $this->plugin->gettext('imageformat'));
$table->add(null, html::label($field_id, $checkbox->show() . ' ' . $this->plugin->gettext('laxpiclabel')));
*/
+ // read-only device information
+ $info = $this->plugin->device_info($this->device['ID']);
+
+ if (!empty($info)) {
+ foreach ($info as $key => $value) {
+ if ($value) {
+ $table->add('title', Q($this->plugin->gettext($key)));
+ $table->add(null, Q($value));
+ }
+ }
+ }
+
if ($attrib['form']) {
$this->rc->output->add_gui_object('editform', $attrib['form']);
}
return $table->show($attrib);
}
public function folder_subscriptions($attrib = array())
{
if (!$attrib['id'])
$attrib['id'] = 'foldersubscriptions';
// group folders by type (show only known types)
$folder_groups = array('mail' => array(), 'contact' => array(), 'event' => array(), 'task' => array());
$folder_types = $this->plugin->list_types();
$imei = $this->device['_id'];
$subscribed = array();
if ($imei) {
$folder_meta = $this->plugin->folder_meta();
}
foreach ($this->plugin->list_folders() as $folder) {
if ($folder_types[$folder]) {
list($type, ) = explode('.', $folder_types[$folder]);
}
else {
$type = 'mail';
}
if (is_array($folder_groups[$type])) {
$folder_groups[$type][] = $folder;
if (!empty($folder_meta) && ($meta = $folder_meta[$folder])
&& $meta['FOLDER'] && $meta['FOLDER'][$imei]['S']
) {
$subscribed[$folder] = intval($meta['FOLDER'][$imei]['S']);
}
}
}
// build block for every folder type
foreach ($folder_groups as $type => $group) {
if (empty($group)) {
continue;
}
$attrib['type'] = $type;
$html .= html::div('subscriptionblock',
html::tag('h3', $type, $this->plugin->gettext($type)) .
$this->folder_subscriptions_block($group, $attrib, $subscribed));
}
$this->rc->output->add_gui_object('subscriptionslist', $attrib['id']);
return html::div($attrib, $html);
}
public function folder_subscriptions_block($a_folders, $attrib, $subscribed)
{
$alarms = ($attrib['type'] == 'event' || $attrib['type'] == 'task');
$table = new html_table(array('cellspacing' => 0));
$table->add_header('subscription', $attrib['syncicon'] ? html::img(array('src' => $this->skin_path . $attrib['syncicon'], 'title' => $this->plugin->gettext('synchronize'))) : '');
if ($alarms) {
$table->add_header('alarm', $attrib['alarmicon'] ? html::img(array('src' => $this->skin_path . $attrib['alarmicon'], 'title' => $this->plugin->gettext('withalarms'))) : '');
}
$table->add_header('foldername', $this->plugin->gettext('folder'));
$checkbox_sync = new html_checkbox(array('name' => 'subscribed[]', 'class' => 'subscription'));
$checkbox_alarm = new html_checkbox(array('name' => 'alarm[]', 'class' => 'alarm'));
$names = array();
foreach ($a_folders as $folder) {
$foldername = $origname = preg_replace('/^INBOX &raquo;\s+/', '', kolab_storage::object_name($folder));
// find folder prefix to truncate (the same code as in kolab_addressbook plugin)
for ($i = count($names)-1; $i >= 0; $i--) {
if (strpos($foldername, $names[$i].' &raquo; ') === 0) {
$length = strlen($names[$i].' &raquo; ');
$prefix = substr($foldername, 0, $length);
$count = count(explode(' &raquo; ', $prefix));
$foldername = str_repeat('&nbsp;&nbsp;', $count-1) . '&raquo; ' . substr($foldername, $length);
break;
}
}
$names[] = $origname;
$classes = array('mailbox');
if ($folder_class = $this->rc->folder_classname($folder)) {
$foldername = html::quote($this->rc->gettext($folder_class));
$classes[] = $folder_class;
}
$folder_id = 'rcmf' . html_identifier($folder);
$padding = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $level);
$table->add_row();
$table->add('subscription', $checkbox_sync->show(
!empty($subscribed[$folder]) ? $folder : null,
array('value' => $folder, 'id' => $folder_id)));
if ($alarms) {
$table->add('alarm', $checkbox_alarm->show(
intval($subscribed[$folder]) > 1 ? $folder : null,
array('value' => $folder, 'id' => $folder_id.'_alarm')));
}
$table->add(join(' ', $classes), html::label($folder_id, $padding . $foldername));
}
return $table->show();
}
}
diff --git a/plugins/kolab_activesync/localization/en_US.inc b/plugins/kolab_activesync/localization/en_US.inc
index 2399b13e..8f94a518 100644
--- a/plugins/kolab_activesync/localization/en_US.inc
+++ b/plugins/kolab_activesync/localization/en_US.inc
@@ -1,33 +1,40 @@
<?php
$labels = array();
$labels['tabtitle'] = 'Activesync';
$labels['devices'] = 'Devices';
$labels['devicealias'] = 'Device name';
$labels['syncmode'] = 'Sync Mode';
$labels['modeauto'] = 'Determine automatically';
$labels['modeflat'] = 'Force flat mode';
$labels['modefolder'] = 'Force folder mode';
$labels['synchronize'] = 'Synchronize';
$labels['withalarms'] = 'With alarms';
$labels['syncsettings'] = 'Synchronization settings';
$labels['deviceconfig'] = 'Device configration';
$labels['folderstosync'] = 'Folders to synchronize';
$labels['mail'] = 'Email';
$labels['contact'] = 'Address Books';
$labels['event'] = 'Calendars';
$labels['task'] = 'Tasks';
$labels['note'] = 'Notes';
$labels['configuration'] = 'Configuration';
$labels['deletedevice'] = 'Delete device';
$labels['imageformat'] = 'Image format';
$labels['laxpiclabel'] = 'Allow PNG and GIF images';
$labels['nodevices'] = 'There are currently no devices registered.<br/><br/>In order to register a device, please connect it to the server first, using <a href="http://wiki.kolab.org/Z_push#Clients">the instructions in the Wiki</a>. Afterwards the device should become available for configuration here.';
$labels['savingdata'] = 'Saving data...';
$labels['savingerror'] = 'Failed to save configuration';
$labels['notsupported'] = 'Your server does not support metadata/annotations';
$labels['devicedeleteconfirm'] = 'Do you really want to delete the configuration for this device?';
$labels['successfullydeleted'] = 'The device configuration was successfully removed';
$labels['devicenotfound'] = 'Unable to read device configuration';
+$labels['devicetype'] = 'Device type';
+$labels['acsversion'] = 'Protocol version';
+$labels['useragent'] = 'User agent';
+$labels['friendlyname'] = 'Friendly name';
+$labels['os'] = 'Operating system';
+$labels['oslanguage'] = 'OS language';
+$labels['phonenumber'] = 'Phone number';
?>
diff --git a/plugins/kolab_activesync/package.xml b/plugins/kolab_activesync/package.xml
index 09e8d668..dfdd3e30 100644
--- a/plugins/kolab_activesync/package.xml
+++ b/plugins/kolab_activesync/package.xml
@@ -1,82 +1,82 @@
<?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_activesync</name>
<uri>http://git.kolab.org/roundcubemail-plugins-kolab/</uri>
<summary>ActiveSync configuration utility for Kolab accounts</summary>
<description></description>
<lead>
<name>Aleksander Machniak</name>
<user>alec</user>
<email>machniak@kolabsys.com</email>
<active>yes</active>
</lead>
<lead>
<name>Thomas Bruederli</name>
<user>thomasb</user>
<email>bruederli@kolabsys.com</email>
<active>yes</active>
</lead>
- <date>2012-08-29</date>
+ <date>2013-04-09</date>
<version>
- <release>0.9</release>
+ <release>1.0</release>
<api>1.0</api>
</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_activesync.php" role="php"></file>
<file name="kolab_activesync_ui.php" role="php"></file>
<file name="kolab_activesync.js" role="data"></file>
<file name="localization/de_CH.inc" role="data"></file>
<file name="localization/de_DE.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/classic/templates/config.html" role="data"></file>
<file name="skins/classic/templates/configedit.html" role="data"></file>
<file name="skins/classic/templates/configempty.html" role="data"></file>
<file name="skins/classic/config.css" role="data"></file>
<file name="skins/classic/alarm-clock.png" role="data"></file>
<file name="skins/classic/deviceactions.png" role="data"></file>
<file name="skins/classic/foldertypes.png" role="data"></file>
<file name="skins/classic/pointer-left.gif" role="data"></file>
<file name="skins/classic/synchronize.png" role="data"></file>
<file name="skins/larry/templates/config.html" role="data"></file>
<file name="skins/larry/templates/configedit.html" role="data"></file>
<file name="skins/larry/templates/configempty.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>libkolab</name>
<uri>http://kolabsys.com</uri>
</package>
<package>
<name>jqueryui</name>
<channel>pear.roundcube.net</uri>
</package>
</required>
</dependencies>
<phprelease/>
</package>

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 30, 7:11 AM (16 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1179926
Default Alt Text
(30 KB)

Event Timeline