Files
server/usr/share/psa-pear/pear/php/Horde/SyncMl/Device.php
2026-01-07 20:52:11 +01:00

285 lines
10 KiB
PHP

<?php
/**
* The Horde_SyncMl_Device:: class provides functionality that is potentially
* (client) device dependant.
*
* If a sync client needs any kind of special conversion of the data sent to it
* or received from it, this is done here. There are two sources of information
* to identify an device: The first (and better) one is the DevInf device info
* sent by the device during a request. If DevInf is not supported or sent by
* the client, the Source/LocURI of the device request might be sufficent to
* identify it.
*
* Copyright 2005-2016 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @author Karsten Fourmont <karsten@horde.org>
* @package SyncMl
*/
class Horde_SyncMl_Device
{
/**
* The original preferred content type of the client, if provided through
* DevInf.
*
* @var string
*/
public $requestedContentType;
/**
* Attempts to return a concrete Horde_SyncMl_Device instance based on $driver.
*
* @param string $driver The type of concrete Horde_SyncMl_Device subclass to
* return.
*
* @return Horde_SyncMl_Device The newly created concrete Horde_SyncMl_Device
* instance, or false on error.
*/
public function factory($driver)
{
$driver = basename($driver);
if (empty($driver) || $driver == 'none' || $driver == 'default') {
$GLOBALS['backend']->logMessage(
'Using default device class', 'DEBUG');
return new Horde_SyncMl_Device();
}
$class = 'Horde_SyncMl_Device_' . $driver;
if (!class_exists($class)) {
return false;
}
$device = new $class();
$GLOBALS['backend']->logMessage('Created device class ' . $class, 'DEBUG');
return $device;
}
/**
* Returns the guessed content type for a database URI.
*
* When a client sends data during a sync but does not provide information
* about the MIME content type with this individual item, this function
* returns the content type the item is supposed to be in.
*
* @param string $database A database URI.
*
* @return string A MIME type that might match the database URI.
*/
public function getPreferredContentType($database)
{
$database = $GLOBALS['backend']->normalize($database);
/* Use some wild guessings. */
if (strpos($database, 'contact') !== false ||
strpos($database, 'card') !== false) {
return 'text/x-vcard';
} elseif (strpos($database, 'note') !== false ||
strpos($database, 'snote') !== false ||
strpos($database, 'memo') !== false) {
return 'text/plain';
} elseif (strpos($database, 'task') !== false ||
strpos($database, 'cal') !== false ||
strpos($database, 'event') !== false) {
return 'text/calendar';
}
}
/**
* Returns the preferrred MIME content type of the client for the given
* sync data type (contacts/tasks/notes/calendar).
*
* The result is passed as an option to the backend export functions.
* This is not the content type ultimately passed to the client but rather
* the content type presented to the backend export functions.
*
* After the data is retrieved from the backend, convertServer2Client()
* can do some post-processing and set the correct content type acceptable
* for the client if necessary.
*
* The default implementation tries to extract the content type from the
* device info. If this does not work, some defaults are used.
*
* If the client does not provice proper DevInf data, this public function may
* have to be overwritten to return the correct values.
*
* @param string $serverSyncURI The URI for the server database: contacts,
* notes, calendar or tasks.
* @param string $sourceSyncURI The URI for the client database. This is
* needed as the DevInf is grouped by
* sourceSyncURIs.
*/
public function getPreferredContentTypeClient($serverSyncURI, $sourceSyncURI)
{
$di = $GLOBALS['backend']->state->deviceInfo;
$ds = $di->getDataStore($sourceSyncURI);
if (!empty($ds)) {
$r = $ds->getPreferredRXContentType();
if (!empty($r)) {
$this->requestedContentType = $r;
return $r;
}
}
$database = $GLOBALS['backend']->normalize($serverSyncURI);
/* No information in DevInf, use some wild guessings. */
if (strpos($database, 'contact') !== false ||
strpos($database, 'card') !== false) {
return 'text/x-vcard';
} elseif (strpos($database, 'note') !== false ||
strpos($database, 'snote') !== false ||
strpos($database, 'memo') !== false) {
// SyncML conformance suite expects this rather than text/x-vnote
return 'text/plain';
} elseif (strpos($database, 'task') !== false ||
strpos($database, 'cal') !== false ||
strpos($database, 'event') !== false) {
return 'text/calendar';
}
}
/**
* Converts the content received from the client for the backend.
*
* Currently strips UID (primary key) information as client and server
* might use different ones.
*
* Charset conversions might be added here too.
*
* @todo remove UID stripping or move it anywhere else.
*
* @param string $content The content to convert.
* @param string $contentType The content type of the content.
*
* @return array Two-element array with the converted content and the
* (possibly changed) new content type.
*/
public function convertClient2Server($content, $contentType)
{
$GLOBALS['backend']->logFile(
Horde_SyncMl_Backend::LOGFILE_DATA,
"\nInput received from client ($contentType):\n$content\n");
// Always remove client UID. UID will be seperately passed in XML.
$content = preg_replace('/(\r\n|\r|\n)UID:.*?(\r\n|\r|\n)/',
'\1', $content, 1);
return array($content, $contentType);
}
/**
* Converts the content from the backend to a format suitable for the
* client device.
*
* Strips the UID (primary key) information as client and server might use
* different ones.
*
* Charset conversions might be added here too.
*
* @param string $content The content to convert
* @param string $contentType The content type of content as returned
* from the backend
* @param string $database The server database URI.
*
* @return array Three-element array with the converted content, the
* (possibly changed) new content type, and encoding type
* (like b64 as used by Funambol).
*/
public function convertServer2Client($content, $contentType, $database)
{
if (is_array($contentType)) {
$contentType = $contentType['ContentType'];
}
$GLOBALS['backend']->logFile(
Horde_SyncMl_Backend::LOGFILE_DATA,
"\nOutput received from backend ($contentType):\n" . $content
. "\n");
/* Always remove server UID. UID will be seperately passed in XML. */
$content = preg_replace('/(\r\n|\r|\n)UID:.*?(\r\n|\r|\n)/',
'\1', $content, 1);
if ($this->useLocalTime()) {
$content = preg_replace_callback(
'/\d{8}T\d{6}Z/',
array($this, '_convertUTC2LocalTime'),
$content);
}
return array($content, $contentType, null);
}
/**
* Returns whether the device handles tasks and events in a single
* "calendar" sync.
*
* This requires special actions on our side as we store this in different
* backend databases.
*
* @return boolean True if tasks and events are processed in a single
* request.
*/
public function handleTasksInCalendar()
{
return false;
}
/**
* Returns whether to send individual status response for each Add, Delete
* and Replace.
*
* @return boolean False if individual status responses should be send.
*/
public function omitIndividualSyncStatus()
{
return false;
}
/**
* Returns whether the payload data should be enclosed in a [CDATA[
* section when sending via XML.
*
* The synchronized data may contain XML special characters like &amp;,
* &lt; or &gt;. Clients might choke when sending these embedded in XML.
* The data should be enclosed in [CDATA[ in these cases. This applies
* only to XML, not to WBXML devices.
*
* @return boolean True if the data should be enclosed in [CDATA[.
*/
public function useCdataTag()
{
return true;
}
/**
* Returns whether the device accepts datetimes only in local time format
* (DTSTART:20061222T130000) instead of the more robust UTC time
* (DTSTART:20061222T110000Z).
*
* @return boolean True if the client doesn't accept UTC datetimes.
*/
public function useLocalTime()
{
return false;
}
/**
* Converts an UTC timestamp like "20061222T110000Z" into a local
* timestamp like "20061222T130000" using the server timezone.
*
* @param array $utc Array with a datetime string in UTC.
*
* @return string The datetime string converted to the local timezone.
*/
protected function _convertUTC2LocalTime($utc)
{
$date = new Horde_Date($utc[0]);
$date->setTimezone(date_default_timezone_get());
return $date->format("Ymd\THis");
}
}