Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
39 KB
Referenced Files
None
Subscribers
None
diff --git a/plugins/kolab_activesync/kolab_activesync_ui.php b/plugins/kolab_activesync/kolab_activesync_ui.php
index b42de972..943783e9 100644
--- a/plugins/kolab_activesync/kolab_activesync_ui.php
+++ b/plugins/kolab_activesync/kolab_activesync_ui.php
@@ -1,310 +1,325 @@
<?php
/**
* ActiveSync configuration user interface builder
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2011-2013, 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
{
public $device = [];
private $rc;
private $plugin;
private $skin_path;
- public const SETUP_URL = 'https://kb.kolabenterprise.com/documentation/setting-up-an-activesync-client';
+ public const SETUP_URL = 'https://kb.kolab.org/documentation/setting-up-an-activesync-client';
+ public const RESET_URL = 'https://kb.kolab.org/documentation/reset-an-activesync-client';
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');
}
public function device_list($attrib = [])
{
$attrib += ['id' => 'devices-list'];
$devices = $this->plugin->engine->list_devices();
$table = new html_table();
foreach ($devices as $id => $device) {
$name = $device['friendlyname'] ? $device['friendlyname'] : $id;
+ if ($device['is_broken']) {
+ // TODO use an icon instead. Perhaps add some css styling.
+ $name = "$name !";
+ }
$table->add_row(['id' => 'rcmrow' . $id]);
$table->add(null, html::span('devicealias', rcube::Q($name))
. ' ' . html::span('devicetype secondary', rcube::Q($device['devicetype'])));
}
$this->rc->output->add_gui_object('devicelist', $attrib['id']);
$this->rc->output->set_env('devicecount', count($devices));
$this->rc->output->include_script('list.js');
return $table->show($attrib);
}
public function device_config_form($attrib = [])
{
$table = new html_table(['cols' => 2]);
$field_id = 'config-device-alias';
$input = new html_inputfield(['name' => 'devicealias', 'id' => $field_id, 'size' => 40]);
$table->add('title', html::label($field_id, $this->plugin->gettext('devicealias')));
$table->add(null, $input->show(!empty($this->device['friendlyname']) ? $this->device['friendlyname'] : $this->device['deviceid']));
foreach (kolab_subscriptions::DEVICE_FIELDS as $key) {
if ($key == 'friendlyname') {
continue;
}
+ if ($key == 'is_broken') {
+ continue;
+ }
$value = $this->device[$key] ?? null;
if ($value) {
$table->add('title', html::label(null, rcube::Q($this->plugin->gettext($key))));
$table->add(null, rcube::Q($value));
}
}
if ($attrib['form']) {
$this->rc->output->add_gui_object('editform', $attrib['form']);
}
return $table->show($attrib);
}
public function folder_subscriptions($attrib = [])
{
if (empty($attrib['id'])) {
$attrib['id'] = 'foldersubscriptions';
}
+ if ($this->device['is_broken']) {
+ $url = $this->rc->config->get('activesync_reset_url', self::RESET_URL);
+ $vars = ['url' => $url];
+ $msg = $this->plugin->gettext(['name' => 'brokendevice', 'vars' => $vars]);
+ return html::div('boxwarning', $msg);
+ }
+
// group folders by type (show only known types)
$use_fieldsets = rcube_utils::get_boolean($attrib['use-fieldsets'] ?? '');
$imei = $this->device['deviceid'];
$html = null;
foreach (['mail', 'contact', 'event', 'task', 'note'] as $type) {
$subscriptions = $this->plugin->engine->list_subscriptions($imei, $type);
$folders = [];
foreach ($this->plugin->engine->list_folders($type) as $folder) {
$f = $folder[0];
$subscribed = 0;
if (!empty($subscriptions[$f])) {
$subscribed = (int) $subscriptions[$f][0];
}
$folders[] = [$f, $folder[1], $subscribed];
}
if (empty($folders)) {
continue;
}
$attrib['type'] = $type;
$table = $this->folder_subscriptions_block($folders, $attrib);
$label = $this->plugin->gettext($type);
if ($use_fieldsets) {
$html .= html::tag('fieldset', 'subscriptionblock', html::tag('legend', $type, $label) . $table);
} else {
$html .= html::div('subscriptionblock', html::tag('h3', $type, $label) . $table);
}
}
$this->rc->output->add_gui_object('subscriptionslist', $attrib['id']);
return html::div($attrib, $html);
}
private function folder_subscriptions_block($a_folders, $attrib)
{
$alarms = ($attrib['type'] == 'event' || $attrib['type'] == 'task');
$table = new html_table(['cellspacing' => 0, 'class' => 'table-striped']);
$table->add_header(
[
'class' => 'subscription checkbox-cell',
'title' => $this->plugin->gettext('synchronize'),
'tabindex' => 0,
],
!empty($attrib['syncicon']) ? html::img(['src' => $this->skin_path . $attrib['syncicon']]) : $this->plugin->gettext('synchronize')
);
if ($alarms) {
$table->add_header(
[
'class' => 'alarm checkbox-cell',
'title' => $this->plugin->gettext('withalarms'),
'tabindex' => 0,
],
!empty($attrib['alarmicon']) ? html::img(['src' => $this->skin_path . $attrib['alarmicon']]) : $this->plugin->gettext('withalarms')
);
}
$table->add_header('foldername', $this->plugin->gettext('folder'));
$checkbox_sync = new html_checkbox(['name' => 'subscribed[]', 'class' => 'subscription']);
$checkbox_alarm = new html_checkbox(['name' => 'alarm[]', 'class' => 'alarm']);
$names = [];
foreach ($a_folders as $folder) {
[$folder, $foldername, $subscribed] = $folder;
// find folder prefix to truncate (the same code as in kolab_addressbook plugin)
$origname = $foldername;
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;
}
}
$folder_id = 'rcmf' . rcube_utils::html_identifier($attrib['type'] . '#' . $folder);
$folder_value = $attrib['type'] . '#' . $folder;
$names[] = $origname;
$classes = ['mailbox'];
$folder_class = $attrib['type'] == 'mail' ? $this->rc->folder_classname($folder) : '';
if ($folder_class) {
if ($this->rc->text_exists($folder_class)) {
$foldername = html::quote($this->rc->gettext($folder_class));
}
$classes[] = $folder_class;
}
$table->add_row();
$disabled = $this->plugin->engine->is_protected($folder, $this->device['devicetype'] ?? 'unknown');
$table->add('subscription checkbox-cell', $checkbox_sync->show(
$subscribed > 0 ? $folder_value : null,
['value' => $folder_value, 'id' => $folder_id, 'disabled' => $disabled]
));
if ($alarms) {
$table->add('alarm checkbox-cell', $checkbox_alarm->show(
$subscribed > 1 ? $folder_value : null,
['value' => $folder_value, 'id' => $folder_id . '_alarm', 'disabled' => $disabled]
));
}
$table->add(implode(' ', $classes), html::label($folder_id, $foldername));
}
return $table->show();
}
/**
* HTML table with a list of Activesync devices and an option to
* subscribe/unsubscribe to a specified folder.
*
* @param string|kolab_storage_dav_folder $folder Folder object or name
* @param array $devices Devices list
* @param string $type Folder type
*
* @return string HTMML table
*/
public function folder_options_table($folder, $devices, $type)
{
$alarms = $type == 'event' || $type == 'task';
$table = new html_table(['cellspacing' => 0, 'id' => 'folder-sync-options', 'class' => 'records-table']);
// table header
$table->add_header(['class' => 'device'], $this->plugin->gettext('devicealias'));
$table->add_header(['class' => 'subscription'], $this->plugin->gettext('synchronize'));
if ($alarms) {
$table->add_header(['class' => 'alarm'], $this->plugin->gettext('withalarms'));
}
$folder_name = is_object($folder) ? $folder->href : $folder;
$subscriptions = $this->plugin->engine->folder_subscriptions($folder_name, $type);
// table records
foreach ($devices as $id => $device) {
$name = $id;
$title = '';
$_name = trim(($device['friendlyname'] ?? '') . ' ' . ($device['os'] ?? ''));
$title = $device['useragent'] ?? '';
if ($_name) {
$name .= " ($_name)";
}
$disabled = $this->plugin->engine->is_protected($folder_name, $device['devicetype'] ?? 'unknown');
$flag = $subscriptions[$id] ?? 0;
$table->add_row();
$table->add(['class' => 'device', 'title' => $title], $name);
$checkbox = new html_checkbox(['name' => "_subscriptions[$id]", 'value' => 1,
'onchange' => 'return activesync_object.update_sync_data(this)']);
$table->add('subscription checkbox-cell', $checkbox->show($flag ? 1 : 0, ['disabled' => $disabled]));
if ($alarms) {
$checkbox_alarm = new html_checkbox(['name' => "_alarms[$id]", 'value' => 1,
'onchange' => 'return activesync_object.update_sync_data(this)']);
$table->add('alarm checkbox-cell', $checkbox_alarm->show($flag > 1 ? 1 : 0, ['disabled' => $disabled]));
}
}
return $table->show();
}
/**
* Displays initial page (when no devices are registered)
*/
public function init_message()
{
$this->rc->output->add_handlers([
'initmessage' => [$this, 'init_message_content'],
]);
$this->rc->output->send('kolab_activesync.configempty');
}
/**
* Handler for initmessage template object
*/
public function init_message_content()
{
$url = $this->rc->config->get('activesync_setup_url', self::SETUP_URL);
$vars = ['url' => $url];
$msg = $this->plugin->gettext(['name' => 'nodevices', 'vars' => $vars]);
return $msg;
}
}
diff --git a/plugins/kolab_activesync/localization/de.inc b/plugins/kolab_activesync/localization/de.inc
index 9045185f..db7ea7f0 100644
--- a/plugins/kolab_activesync/localization/de.inc
+++ b/plugins/kolab_activesync/localization/de.inc
@@ -1,33 +1,34 @@
<?php
$labels['tabtitle'] = 'ActiveSync';
$labels['activesynctitle'] = 'Verwalte ActiveSync-Geräte';
$labels['devices'] = 'Geräte';
$labels['devicealias'] = 'Gerätename';
$labels['synchronize'] = 'Synchronisieren';
$labels['withalarms'] = 'Mit Erinnerungen';
$labels['syncsettings'] = 'Synchronisationseinstellungen';
$labels['deviceconfig'] = 'Gerätekonfiguration';
$labels['folderstosync'] = 'Ordner zum Synchronisieren';
$labels['mail'] = 'E-Mail';
$labels['contact'] = 'Kontakte';
$labels['event'] = 'Kalender';
$labels['task'] = 'Aufgaben';
$labels['note'] = 'Notizen';
$labels['configuration'] = 'Konfiguration';
$labels['deletedevice'] = 'Gerät löschen';
$labels['nodevices'] = 'Es sind aktuell keine Geräte registriert.<br/><br/>Um ein Gerät zu registrieren, bitte zuerst nach der Anleitung von <a href="$url" target="_blank">dieser Seite</a> mit dem Server verbinden. Anschließend sollte das Gerät für die Konfiguration hier zur Verfügung stehen.';
+$labels['brokendevice'] = 'Dieses Gerät ist in einem defekten Zustand. Bitte setzen Sie das Gerät gemäss der Anleitung von <a href="$url" target="_blank">dieser Seite</a> zurück. Anschließend sollte das Gerät für die Konfiguration hier zur Verfügung stehen.';
$labels['savingdata'] = 'Daten werden gespeichert...';
$labels['savingerror'] = 'Fehler beim Speichern der Konfiguration';
$labels['notsupported'] = 'Ihr Server unterstützt keine Activesync-Konfiguration';
$labels['devicedeleteconfirm'] = 'Wollen Sie wirklich alle Einstellungen für dieses Gerät löschen?';
$labels['successfullydeleted'] = 'Die Geräteinstellungen wurden erfolgreich gelöscht';
$labels['devicenotfound'] = 'Es kann nicht auf die Gerätekonfiguration zugegriffen werden.';
$labels['devicetype'] = 'Gerätetyp';
$labels['acsversion'] = 'Protokollversion';
$labels['useragent'] = 'User Agent';
$labels['friendlyname'] = 'Lesbarer Name';
$labels['os'] = 'Betriebssystem';
$labels['oslanguage'] = 'Betriebssystemsprache';
$labels['phonenumber'] = 'Telefonnummer';
$labels['arialabeldeviceframe'] = 'Formular für die Einstellungen zur Gerätesynchronisation';
diff --git a/plugins/kolab_activesync/localization/de_CH.inc b/plugins/kolab_activesync/localization/de_CH.inc
index 5d3b4c4e..12c1b589 100644
--- a/plugins/kolab_activesync/localization/de_CH.inc
+++ b/plugins/kolab_activesync/localization/de_CH.inc
@@ -1,33 +1,34 @@
<?php
$labels['tabtitle'] = 'Activesync';
$labels['activesynctitle'] = 'Verwalte ActiveSync-Geräte';
$labels['devices'] = 'Geräte';
$labels['devicealias'] = 'Gerätename';
$labels['synchronize'] = 'Synchronisieren';
$labels['withalarms'] = 'Mit Erinnerungen';
$labels['syncsettings'] = 'Synchronisationseinstellungen';
$labels['deviceconfig'] = 'Gerätekonfiguration';
$labels['folderstosync'] = 'Order zum Synchronisieren';
$labels['mail'] = 'E-Mail';
$labels['contact'] = 'Kontakte';
$labels['event'] = 'Kalender';
$labels['task'] = 'Aufgaben';
$labels['note'] = 'Notizen';
$labels['configuration'] = 'Konfiguration';
$labels['deletedevice'] = 'Gerät löschen';
$labels['nodevices'] = 'Es sind aktuell keine Geräte registriert.<br/><br/>Um ein Gerät zu registrieren, bitte zuerst nach der Anleitung von <a href="$url" target="_blank">dieser Seite</a> mit dem Server verbinden. Anschließend sollte das Gerät für die Konfiguration hier zur Verfügung stehen.';
+$labels['brokendevice'] = 'Dieses Gerät ist in einem defekten Zustand. Bitte setzen Sie das Gerät gemäss der Anleitung von <a href="$url" target="_blank">dieser Seite</a> zurück. Anschließend sollte das Gerät für die Konfiguration hier zur Verfügung stehen.';
$labels['savingdata'] = 'Daten werden gespeichert...';
$labels['savingerror'] = 'Fehler beim Speichern';
$labels['notsupported'] = 'Ihr Server unterstützt keine Activesync-Konfiguration';
$labels['devicedeleteconfirm'] = 'Wollen Sie wirklich alle Einstellungen für dieses Gerät löschen?';
$labels['successfullydeleted'] = 'Die Geräteinstellungen wurden erfolgreich gelöscht';
$labels['devicenotfound'] = 'Es kann nicht auf die Gerätekonfiguration zugegriffen werden.';
$labels['devicetype'] = 'Gerätetyp';
$labels['acsversion'] = 'Protokollversion';
$labels['useragent'] = 'User Agent';
$labels['friendlyname'] = 'Lesbarer Name';
$labels['os'] = 'Betriebssystem';
$labels['oslanguage'] = 'Betriebssystemsprache';
$labels['phonenumber'] = 'Telefonnummer';
$labels['arialabeldeviceframe'] = 'Formular für die Einstellungen zur Gerätesynchronisation';
diff --git a/plugins/kolab_activesync/localization/de_DE.inc b/plugins/kolab_activesync/localization/de_DE.inc
index 9045185f..db7ea7f0 100644
--- a/plugins/kolab_activesync/localization/de_DE.inc
+++ b/plugins/kolab_activesync/localization/de_DE.inc
@@ -1,33 +1,34 @@
<?php
$labels['tabtitle'] = 'ActiveSync';
$labels['activesynctitle'] = 'Verwalte ActiveSync-Geräte';
$labels['devices'] = 'Geräte';
$labels['devicealias'] = 'Gerätename';
$labels['synchronize'] = 'Synchronisieren';
$labels['withalarms'] = 'Mit Erinnerungen';
$labels['syncsettings'] = 'Synchronisationseinstellungen';
$labels['deviceconfig'] = 'Gerätekonfiguration';
$labels['folderstosync'] = 'Ordner zum Synchronisieren';
$labels['mail'] = 'E-Mail';
$labels['contact'] = 'Kontakte';
$labels['event'] = 'Kalender';
$labels['task'] = 'Aufgaben';
$labels['note'] = 'Notizen';
$labels['configuration'] = 'Konfiguration';
$labels['deletedevice'] = 'Gerät löschen';
$labels['nodevices'] = 'Es sind aktuell keine Geräte registriert.<br/><br/>Um ein Gerät zu registrieren, bitte zuerst nach der Anleitung von <a href="$url" target="_blank">dieser Seite</a> mit dem Server verbinden. Anschließend sollte das Gerät für die Konfiguration hier zur Verfügung stehen.';
+$labels['brokendevice'] = 'Dieses Gerät ist in einem defekten Zustand. Bitte setzen Sie das Gerät gemäss der Anleitung von <a href="$url" target="_blank">dieser Seite</a> zurück. Anschließend sollte das Gerät für die Konfiguration hier zur Verfügung stehen.';
$labels['savingdata'] = 'Daten werden gespeichert...';
$labels['savingerror'] = 'Fehler beim Speichern der Konfiguration';
$labels['notsupported'] = 'Ihr Server unterstützt keine Activesync-Konfiguration';
$labels['devicedeleteconfirm'] = 'Wollen Sie wirklich alle Einstellungen für dieses Gerät löschen?';
$labels['successfullydeleted'] = 'Die Geräteinstellungen wurden erfolgreich gelöscht';
$labels['devicenotfound'] = 'Es kann nicht auf die Gerätekonfiguration zugegriffen werden.';
$labels['devicetype'] = 'Gerätetyp';
$labels['acsversion'] = 'Protokollversion';
$labels['useragent'] = 'User Agent';
$labels['friendlyname'] = 'Lesbarer Name';
$labels['os'] = 'Betriebssystem';
$labels['oslanguage'] = 'Betriebssystemsprache';
$labels['phonenumber'] = 'Telefonnummer';
$labels['arialabeldeviceframe'] = 'Formular für die Einstellungen zur Gerätesynchronisation';
diff --git a/plugins/kolab_activesync/localization/en_US.inc b/plugins/kolab_activesync/localization/en_US.inc
index f0114a23..a19be712 100644
--- a/plugins/kolab_activesync/localization/en_US.inc
+++ b/plugins/kolab_activesync/localization/en_US.inc
@@ -1,33 +1,34 @@
<?php
$labels['tabtitle'] = 'Activesync';
$labels['activesynctitle'] = 'Manage Activesync devices';
$labels['devices'] = 'Devices';
$labels['devicealias'] = 'Device name';
$labels['synchronize'] = 'Synchronize';
$labels['withalarms'] = 'With alarms';
$labels['syncsettings'] = 'Synchronization settings';
$labels['deviceconfig'] = 'Device configuration';
$labels['folderstosync'] = 'Folders to synchronize';
$labels['mail'] = 'Email';
$labels['contact'] = 'Contacts';
$labels['event'] = 'Calendars';
$labels['task'] = 'Tasks';
$labels['note'] = 'Notes';
$labels['configuration'] = 'Configuration';
$labels['deletedevice'] = 'Delete device';
$labels['nodevices'] = 'There are currently no devices registered.<br/><br/>In order to register a device, please connect it to the server first, using instructions from <a href="$url" target="_blank">this page</a>. Afterwards the device should become available for configuration here.';
+$labels['brokendevice'] = 'This device is currently in a broken state. Please reset it using instructions from <a href="$url" target="_blank">this page</a>. Afterwards the device should become available for configuration here again.';
$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';
$labels['arialabeldeviceframe'] = 'Device synchronization settings form';
diff --git a/plugins/libkolab/lib/kolab_subscriptions.php b/plugins/libkolab/lib/kolab_subscriptions.php
index 1e77427f..37a8c38b 100644
--- a/plugins/libkolab/lib/kolab_subscriptions.php
+++ b/plugins/libkolab/lib/kolab_subscriptions.php
@@ -1,576 +1,576 @@
<?php
/**
* A utility class to manage ActiveSync subscriptions (for both IMAP and DAV folders).
*
* @author Aleksander Machniak <machniak@apheleia-it.ch>
*
* Copyright (C) Apheleia IT AG <contact@apheleia-it.ch>
*
* 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_subscriptions
{
- public const DEVICE_FIELDS = ['devicetype', 'acsversion', 'useragent', 'friendlyname', 'os', 'oslanguage', 'phonenumber'];
+ public const DEVICE_FIELDS = ['devicetype', 'acsversion', 'useragent', 'friendlyname', 'os', 'oslanguage', 'phonenumber', 'is_broken'];
/** @var ?kolab_storage_dav DAV storage handler */
private $dav = null;
private $rc;
private $folder_meta;
private $folders_list;
private $folders_type;
private $icache = [];
private $protected_folders = [];
/**
* Object constructor
*
* @param string $dav_url DAV server location. Enables DAV mode.
*/
public function __construct($dav_url = null)
{
$this->rc = rcube::get_instance();
$this->protected_folders = $this->rc->config->get('activesync_force_subscriptions', []);
if ($dav_url) {
$this->dav = new kolab_storage_dav($dav_url);
}
}
/**
* List known devices
*
* @return array<string,array> Device list as hash array
*/
public function list_devices()
{
$db = $this->rc->get_dbh();
$table = $db->table_name('syncroton_device');
$list = [];
$query = $db->query(
"SELECT `id`, `deviceid`, " . $db->array2list(self::DEVICE_FIELDS, 'ident')
. " FROM {$table} WHERE `owner_id` = ?",
$this->rc->user->ID,
);
while ($record = $db->fetch_assoc($query)) {
$list[$record['deviceid']] = $record;
}
return $list;
}
/**
* Get list of all folders available for user
*
* @param string $type Folder type
*
* @return array<array> List of folders (0 - path, 1 - displayname, 2 - optional folder object)
*/
public function list_folders($type)
{
if ($this->folders_list !== null && $this->folders_type == $type) {
return $this->folders_list;
}
if ($this->dav) {
if ($type == 'note') {
$result = [];
} elseif ($type == 'mail') {
$storage = $this->rc->get_storage();
$result = $storage->list_folders();
$result = array_map([$this, 'imap_folder_prop'], $result);
} else {
$result = $this->dav->get_folders($type);
$result = array_map([$this, 'dav_folder_prop'], $result);
}
} else {
$result = kolab_storage::list_folders('', '*', $type, false);
$result = array_map([$this, 'imap_folder_prop'], $result);
}
$this->folders_list = $result;
$this->folders_type = $type;
return $result;
}
/**
* Getter for folders subscription flag on protected folders
*
* @return string|false false if not set, otherwise the flag.
*/
private function get_forced_flag($folder, $devicetype)
{
$forcedFolders = $this->protected_folders[strtolower($devicetype)] ?? [];
foreach ($forcedFolders as $idx => $flag) {
if (preg_match("|^{$idx}\$|", $folder)) {
return $flag;
}
}
return false;
}
/**
* Check if a folder is protected by a forced subscription setting
*
* @param string $folder Folder
* @param string $devicetype Device type
*
* @return bool True if protected
*/
public function is_protected($folder, $devicetype)
{
return $this->get_forced_flag($folder, $devicetype) !== false;
}
/**
* Get folder subscriptions
*
* @param string $deviceid Device IMEI identifier
* @param string $type Folder type
*
* @return array<string,array> Folder subscription flags (0 - flag, 1 - display name, 2 - optional folder object)
*/
public function list_subscriptions($deviceid, $type)
{
if ($this->dav && $type == 'note') {
return [];
}
$result = $this->get_subscriptions($deviceid, $type);
$devicetype = $this->imei_to_type($deviceid);
$folders = $this->list_folders($type);
// Verify if subscribed folders still exist
if (!empty($result)) {
foreach ($result as $idx => $flag) {
reset($folders);
foreach ($folders as $folder) {
if ($folder[0] === (string) $idx) {
// Folder exists, copy the properties
$folder[0] = $flag;
$result[$idx] = $folder;
continue 2;
}
}
$update = true;
unset($result[$idx]);
}
// Update subscriptions if any folder was removed from the list
if (!empty($update)) {
$data = array_map(function ($v) { return $v[0]; }, $result);
$this->update_subscriptions($deviceid, $type, $data);
}
}
// Insert existing folders that match the forced folders set, that aren't already in the result set
// TODO: Because of the regex support in protected_folders we end up doing a lot of comparisons (count(folders) * count(protected_folders)),
// and can't use a map instead.
foreach ($folders as $folder) {
$folderPath = $folder[0];
if (array_key_exists($folderPath, $result)) {
continue;
}
if (($flag = $this->get_forced_flag($folder[0], $devicetype)) !== false) {
$folder[0] = $flag;
$result[$folderPath] = $folder;
}
}
return $result ?? [];
}
/**
* Get list of devices the folder is subscribed to
*
* @param string $folder Folder (IMAP path or DAV path)
* @param string $type Folder type
*
* @return array<string,int> Index is a device IMEI, value is a subscription flag
*/
public function folder_subscriptions($folder, $type = null)
{
$db = $this->rc->get_dbh();
$table = $db->table_name('syncroton_subscriptions');
$device_table = $db->table_name('syncroton_device');
$result = [];
$query = $db->query(
"SELECT s.*, d.`deviceid` FROM {$table} s"
. " JOIN {$device_table} d ON (s.`device_id` = d.`id`)"
. " WHERE `owner_id` = ?"
. ($type ? " AND s.type = " . $db->quote($type) : ''),
$this->rc->user->ID
);
while ($record = $db->fetch_assoc($query)) {
$list = json_decode($record['data'], true);
if (!empty($list[$folder])) {
$result[$record['deviceid']] = $list[$folder];
}
}
return $result;
}
/**
* Set folder subscription flag for specific device
*
* @param string $deviceid Device IMEI identifier
* @param string $folder Folder (an IMAP path or a DAV path)
* @param int $flag Subscription flag (1 or 2)
* @param ?string $type Folder type class
*
* @return bool True on success, False on failure
*/
public function folder_subscribe($deviceid, $folder, $flag, $type = null)
{
// For DAV folders it is required to use $type argument
// otherwise it's hard to get the folder type
if (empty($type)) {
$type = (string) kolab_storage::folder_type($folder);
}
if (!$type) {
$type = 'mail';
}
[$type, ] = explode('.', $type);
if (!in_array($type, ['mail', 'event', 'contact', 'task', 'note'])) {
return false;
}
// Folder hrefs returned by kolab_dav_client aren't normalized, i.e. include path prefix
// We make sure here we use the same path
if ($this->dav && $type != 'mail') {
if ($type == 'note') {
return false;
}
if ($path = parse_url($this->dav->dav->url, PHP_URL_PATH)) {
if (strpos($folder, $path) !== 0) {
$folder = '/' . trim($path, '/') . $folder;
}
}
$folder = rtrim($folder, '/');
}
$subscribed = $this->get_subscriptions($deviceid, $type);
if (isset($subscribed[$folder])) {
if ($subscribed[$folder] == $flag) {
return true;
}
unset($subscribed[$folder]);
}
if ($flag) {
$subscribed[$folder] = (int) $flag;
}
return $this->update_subscriptions($deviceid, $type, $subscribed);
}
/**
* Set folder subscriptions (in SQL database)
*
* @param string $deviceid Device IMEI identifier
* @param string $type Folder type class
* @param array<string,int> $subscriptions Subscriptions
*
* @return bool True on success, False on failure
*/
public function set_subscriptions($deviceid, $type, $subscriptions)
{
$id = $this->imei_to_id($deviceid);
if (empty($id)) {
return false;
}
if ($this->dav && $type == 'note') {
return true;
}
$data = json_encode($subscriptions);
if ($data === false) {
return false;
}
$db = $this->rc->get_dbh();
$table = $db->table_name('syncroton_subscriptions');
$query = $db->query("SELECT 1 FROM $table WHERE `device_id` = ? AND `type` = ?", $id, $type);
if ($record = $db->fetch_array($query)) {
$query = $db->query("UPDATE {$table} SET `data` = ? WHERE `device_id` = ? AND `type` = ?", $data, $id, $type);
} else {
$query = $db->query("INSERT INTO {$table} (`device_id`, `type`, `data`) VALUES (?, ?, ?)", $id, $type, $data);
}
return $db->affected_rows($query) > 0;
}
/**
* Device delete.
*
* @param string $id Device ID
*
* @return bool True on success, False on failure
*/
public function device_delete($id)
{
$db = $this->rc->get_dbh();
$table = $db->table_name('syncroton_device');
$query = $db->query(
"DELETE FROM {$table} WHERE `owner_id` = ? AND `deviceid` = ?",
$this->rc->user->ID,
$id
);
return $db->affected_rows($query) > 0;
}
/**
* Device information
*
* @param string $id Device ID
*
* @return array|null Device data
*/
public function device_info($id)
{
$db = $this->rc->get_dbh();
$table = $db->table_name('syncroton_device');
$query = $db->query(
"SELECT `id`, `deviceid`, " . $db->array2list(self::DEVICE_FIELDS, 'ident')
. " FROM {$table} WHERE `owner_id` = ? AND `deviceid` = ?",
$this->rc->user->ID,
$id
);
if ($device = $db->fetch_assoc($query)) {
return $device;
}
return null;
}
/**
* Device update
*
* @param string $id Device ID
* @param array $device Device data
*
* @return bool True on success, False on failure
*/
public function device_update($id, $device)
{
$db = $this->rc->get_dbh();
$cols = $params = [];
$allow = ['friendlyname'];
foreach ((array) $device as $col => $value) {
$cols[] = $db->quote_identifier($col) . ' = ?';
$params[] = $value;
}
$params[] = $id;
$params[] = $this->rc->user->ID;
$query = $db->query(
'UPDATE ' . $db->table_name('syncroton_device', true) .
' SET ' . implode(', ', $cols) . ' WHERE `deviceid` = ? AND `owner_id` = ?',
$params
);
return $db->affected_rows($query) > 0;
}
/**
* Get subscriptions from database.
*/
private function get_subscriptions($deviceid, $type)
{
$id = $this->imei_to_id($deviceid);
if ($id === null) {
return [];
}
$db = $this->rc->get_dbh();
$table = $db->table_name('syncroton_subscriptions');
// Get the subscriptions from database
$query = $db->query("SELECT `data` FROM {$table} WHERE `device_id` = ? AND `type` = ?", $id, $type);
if ($record = $db->fetch_assoc($query)) {
$result = json_decode($record['data'], true);
}
// No record yet...
if (!isset($result)) {
$result = [];
// Get the old subscriptions from an IMAP annotations, create the record
if (!$this->dav || $type == 'mail') {
foreach ($this->folder_meta() as $folder => $meta) {
if ($meta[0] == $type && !empty($meta[1][$deviceid]['S'])) {
$result[$folder] = (int) $meta[1][$deviceid]['S'];
}
}
}
$data = json_encode($result);
$db->query("INSERT INTO {$table} (`device_id`, `type`, `data`) VALUES (?, ?, ?)", $id, $type, $data);
}
return $result;
}
/**
* Update subscriptions in the database.
*/
private function update_subscriptions($deviceid, $type, $list)
{
$id = $this->imei_to_id($deviceid);
if ($id === null) {
return false;
}
$db = $this->rc->get_dbh();
$table = $db->table_name('syncroton_subscriptions');
$data = json_encode($list);
$query = $db->query("UPDATE {$table} SET `data` = ? WHERE `device_id` = ? AND `type` = ?", $data, $id, $type);
return $db->affected_rows($query) > 0;
}
/**
* Getter for folders metadata (type and activesync subscription)
*
* @return array Hash array with meta data for each folder
*/
private function folder_meta()
{
if ($this->folder_meta === null) {
$this->folder_meta = [];
$storage = $this->rc->get_storage();
$keys = [
kolab_storage::ASYNC_KEY,
kolab_storage::CTYPE_KEY,
kolab_storage::CTYPE_KEY_PRIVATE,
];
// get folders activesync config
$folderdata = $storage->get_metadata('*', $keys);
foreach ((array) $folderdata as $folder => $meta) {
$type = kolab_storage::folder_select_metadata($meta) ?? 'mail';
[$type, ] = explode('.', $type);
$asyncdata = isset($meta[kolab_storage::ASYNC_KEY]) ? json_decode($meta[kolab_storage::ASYNC_KEY], true) : [];
$this->folder_meta[$folder] = [$type ?: 'mail', $asyncdata['FOLDER'] ?? []];
}
}
return $this->folder_meta;
}
/**
* Get syncroton device_id from IMEI identifier
*
* @param string $imei IMEI identifier
*
* @return string|null Syncroton device identifier
*/
private function imei_to_id($imei)
{
$userid = $this->rc->user->ID;
if (isset($this->icache["deviceid:{$userid}:{$imei}"])) {
return $this->icache["deviceid:{$userid}:{$imei}"];
}
$db = $this->rc->get_dbh();
$table = $db->table_name('syncroton_device');
$result = $db->query("SELECT id FROM {$table} WHERE `owner_id` = ? AND `deviceid` = ?", $userid, $imei);
return $this->icache["deviceid:{$userid}:{$imei}"] = $db->fetch_array($result)[0] ?? null;
}
/**
* Get syncroton device type from IMEI identifier
*
* @param string $imei IMEI identifier
*
* @return string|null Syncroton device identifier
*/
private function imei_to_type($imei)
{
$userid = $this->rc->user->ID;
if (isset($this->icache["devicetype:{$userid}:{$imei}"])) {
return $this->icache["devicetype:{$userid}:{$imei}"];
}
$db = $this->rc->get_dbh();
$table = $db->table_name('syncroton_device');
$result = $db->query("SELECT devicetype FROM {$table} WHERE `owner_id` = ? AND `deviceid` = ?", $userid, $imei);
return $this->icache["devicetype:{$userid}:{$imei}"] = $db->fetch_array($result)[0] ?? null;
}
/**
* IMAP folder properties for list_folders/list_subscriptions output
*/
private static function imap_folder_prop($folder)
{
return [
$folder,
kolab_storage::object_prettyname($folder),
];
}
/**
* DAV folder properties for list_folders/list_subscriptions output
*/
private static function dav_folder_prop($folder)
{
return [
$folder->href,
$folder->get_name(),
$folder,
];
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Apr 5, 9:16 PM (4 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18785745
Default Alt Text
(39 KB)

Event Timeline