Overview

Packages

  • None
  • SyncMl

Classes

  • Horde_SyncMl
  • Horde_SyncMl_Backend
  • Horde_SyncMl_Backend_Horde
  • Horde_SyncMl_Command
  • Horde_SyncMl_Command_Alert
  • Horde_SyncMl_Command_Final
  • Horde_SyncMl_Command_Get
  • Horde_SyncMl_Command_Map
  • Horde_SyncMl_Command_Put
  • Horde_SyncMl_Command_Replace
  • Horde_SyncMl_Command_Results
  • Horde_SyncMl_Command_Status
  • Horde_SyncMl_Command_Sync
  • Horde_SyncMl_Command_SyncHdr
  • Horde_SyncMl_ContentHandler
  • Horde_SyncMl_DataStore
  • Horde_SyncMl_Device
  • Horde_SyncMl_Device_Nokia
  • Horde_SyncMl_Device_P800
  • Horde_SyncMl_Device_sync4j
  • Horde_SyncMl_Device_Sync4JMozilla
  • Horde_SyncMl_Device_Synthesis
  • Horde_SyncMl_DeviceInfo
  • Horde_SyncMl_Property
  • Horde_SyncMl_PropertyParameter
  • Horde_SyncMl_State
  • Horde_SyncMl_Sync
  • Horde_SyncMl_SyncElement
  • Horde_SyncMl_Translation
  • Horde_SyncMl_XmlOutput
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The Horde_SyncMl_Device:: class provides functionality that is potentially
  4:  * (client) device dependant.
  5:  *
  6:  * If a sync client needs any kind of special conversion of the data sent to it
  7:  * or received from it, this is done here. There are two sources of information
  8:  * to identify an device: The first (and better) one is the DevInf device info
  9:  * sent by the device during a request. If DevInf is not supported or sent by
 10:  * the client, the Source/LocURI of the device request might be sufficent to
 11:  * identify it.
 12:  *
 13:  * Copyright 2005-2012 Horde LLC (http://www.horde.org/)
 14:  *
 15:  * See the enclosed file COPYING for license information (LGPL). If you
 16:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 17:  *
 18:  * @author  Karsten Fourmont <karsten@horde.org>
 19:  * @package SyncMl
 20:  */
 21: class Horde_SyncMl_Device
 22: {
 23:     /**
 24:      * The original preferred content type of the client, if provided through
 25:      * DevInf.
 26:      *
 27:      * @var string
 28:      */
 29:     public $requestedContentType;
 30: 
 31:     /**
 32:      * Attempts to return a concrete Horde_SyncMl_Device instance based on $driver.
 33:      *
 34:      * @param string $driver  The type of concrete Horde_SyncMl_Device subclass to
 35:      *                        return.
 36:      *
 37:      * @return Horde_SyncMl_Device  The newly created concrete Horde_SyncMl_Device
 38:      *                        instance, or false on error.
 39:      */
 40:     public function factory($driver)
 41:     {
 42:         $driver = basename($driver);
 43: 
 44:         if (empty($driver) || $driver == 'none' || $driver == 'default') {
 45:             $GLOBALS['backend']->logMessage(
 46:                 'Using default device class', 'DEBUG');
 47:             return new Horde_SyncMl_Device();
 48:         }
 49: 
 50:         $class = 'Horde_SyncMl_Device_' . $driver;
 51:         if (!class_exists($class)) {
 52:             return false;
 53:         }
 54: 
 55:         $device = new $class();
 56:         $GLOBALS['backend']->logMessage('Created device class ' . $class, 'DEBUG');
 57:         return $device;
 58:     }
 59: 
 60:     /**
 61:      * Returns the guessed content type for a database URI.
 62:      *
 63:      * When a client sends data during a sync but does not provide information
 64:      * about the MIME content type with this individual item, this function
 65:      * returns the content type the item is supposed to be in.
 66:      *
 67:      * @param string $database  A database URI.
 68:      *
 69:      * @return string  A MIME type that might match the database URI.
 70:      */
 71:     public function getPreferredContentType($database)
 72:     {
 73:         $database = $GLOBALS['backend']->normalize($database);
 74: 
 75:         /* Use some wild guessings. */
 76:         if (strpos($database, 'contact') !== false ||
 77:             strpos($database, 'card') !== false) {
 78:             return 'text/x-vcard';
 79:         } elseif (strpos($database, 'note') !== false ||
 80:                   strpos($database, 'memo') !== false) {
 81:             return 'text/plain';
 82:         } elseif (strpos($database, 'task') !== false ||
 83:                   strpos($database, 'cal') !== false ||
 84:                   strpos($database, 'event') !== false) {
 85:             return 'text/calendar';
 86:         }
 87:     }
 88: 
 89:     /**
 90:      * Returns the preferrred MIME content type of the client for the given
 91:      * sync data type (contacts/tasks/notes/calendar).
 92:      *
 93:      * The result is passed as an option to the backend export functions.
 94:      * This is not the content type ultimately passed to the client but rather
 95:      * the content type presented to the backend export functions.
 96:      *
 97:      * After the data is retrieved from the backend, convertServer2Client()
 98:      * can do some post-processing and set the correct content type acceptable
 99:      * for the client if necessary.
100:      *
101:      * The default implementation tries to extract the content type from the
102:      * device info. If this does not work, some defaults are used.
103:      *
104:      * If the client does not provice proper DevInf data, this public function may
105:      * have to be overwritten to return the correct values.
106:      *
107:      * @param string $serverSyncURI  The URI for the server database: contacts,
108:      *                               notes, calendar or tasks.
109:      * @param string $sourceSyncURI  The URI for the client database. This is
110:      *                               needed as the DevInf is grouped by
111:      *                               sourceSyncURIs.
112:      */
113:     public function getPreferredContentTypeClient($serverSyncURI, $sourceSyncURI)
114:     {
115:         $di = $GLOBALS['backend']->state->deviceInfo;
116:         $ds = $di->getDataStore($sourceSyncURI);
117:         if (!empty($ds)) {
118:             $r = $ds->getPreferredRXContentType();
119:             if (!empty($r)) {
120:                 $this->requestedContentType = $r;
121:                 return $r;
122:             }
123:         }
124: 
125:         $database = $GLOBALS['backend']->normalize($serverSyncURI);
126: 
127:         /* No information in DevInf, use some wild guessings. */
128:         if (strpos($database, 'contact') !== false ||
129:             strpos($database, 'card') !== false) {
130:             return 'text/x-vcard';
131:         } elseif (strpos($database, 'note') !== false ||
132:                   strpos($database, 'memo') !== false) {
133:             // SyncML conformance suite expects this rather than text/x-vnote
134:             return 'text/plain';
135:         } elseif (strpos($database, 'task') !== false ||
136:                   strpos($database, 'cal') !== false ||
137:                   strpos($database, 'event') !== false) {
138:             return 'text/calendar';
139:         }
140:     }
141: 
142:     /**
143:      * Converts the content received from the client for the backend.
144:      *
145:      * Currently strips UID (primary key) information as client and server
146:      * might use different ones.
147:      *
148:      * Charset conversions might be added here too.
149:      *
150:      * @todo remove UID stripping or move it anywhere else.
151:      *
152:      * @param string $content      The content to convert.
153:      * @param string $contentType  The content type of the content.
154:      *
155:      * @return array  Two-element array with the converted content and the
156:      *                (possibly changed) new content type.
157:      */
158:     public function convertClient2Server($content, $contentType)
159:     {
160:         $GLOBALS['backend']->logFile(
161:             Horde_SyncMl_Backend::LOGFILE_DATA,
162:             "\nInput received from client ($contentType):\n$content\n");
163: 
164:         // Always remove client UID. UID will be seperately passed in XML.
165:         $content = preg_replace('/(\r\n|\r|\n)UID:.*?(\r\n|\r|\n)/',
166:                                 '\1', $content, 1);
167: 
168:         return array($content, $contentType);
169:     }
170: 
171:     /**
172:      * Converts the content from the backend to a format suitable for the
173:      * client device.
174:      *
175:      * Strips the UID (primary key) information as client and server might use
176:      * different ones.
177:      *
178:      * Charset conversions might be added here too.
179:      *
180:      * @param string $content      The content to convert
181:      * @param string $contentType  The content type of content as returned
182:      *                             from the backend
183:      * @param string $database     The server database URI.
184:      *
185:      * @return array  Three-element array with the converted content, the
186:      *                (possibly changed) new content type, and encoding type
187:      *                (like b64 as used by Funambol).
188:      */
189:     public function convertServer2Client($content, $contentType, $database)
190:     {
191:         if (is_array($contentType)) {
192:             $contentType = $contentType['ContentType'];
193:         }
194: 
195:         $GLOBALS['backend']->logFile(
196:             Horde_SyncMl_Backend::LOGFILE_DATA,
197:             "\nOutput received from backend ($contentType):\n" . $content
198:             . "\n");
199: 
200:         /* Always remove server UID. UID will be seperately passed in XML. */
201:         $content = preg_replace('/(\r\n|\r|\n)UID:.*?(\r\n|\r|\n)/',
202:                                 '\1', $content, 1);
203: 
204:         if ($this->useLocalTime()) {
205:             $content = preg_replace_callback(
206:                 '/\d{8}T\d{6}Z/',
207:                 array($this, '_convertUTC2LocalTime'),
208:                 $content);
209:         }
210: 
211:         return array($content, $contentType, null);
212:     }
213: 
214:     /**
215:      * Returns whether the device handles tasks and events in a single
216:      * "calendar" sync.
217:      *
218:      * This requires special actions on our side as we store this in different
219:      * backend databases.
220:      *
221:      * @return boolean  True if tasks and events are processed in a single
222:      *                  request.
223:      */
224:     public function handleTasksInCalendar()
225:     {
226:         return false;
227:     }
228: 
229:     /**
230:      * Returns whether to send individual status response for each Add, Delete
231:      * and Replace.
232:      *
233:      * @return boolean  False if individual status responses should be send.
234:      */
235:     public function omitIndividualSyncStatus()
236:     {
237:         return false;
238:     }
239: 
240:     /**
241:      * Returns whether the payload data should be enclosed in a [CDATA[
242:      * section when sending via XML.
243:      *
244:      * The synchronized data may contain XML special characters like &amp;,
245:      * &lt; or &gt;. Clients might choke when sending these embedded in XML.
246:      * The data should be enclosed in [CDATA[ in these cases.  This applies
247:      * only to XML, not to WBXML devices.
248:      *
249:      * @return boolean  True if the data should be enclosed in [CDATA[.
250:      */
251:     public function useCdataTag()
252:     {
253:         return true;
254:     }
255: 
256:     /**
257:      * Returns whether the device accepts datetimes only in local time format
258:      * (DTSTART:20061222T130000) instead of the more robust UTC time
259:      * (DTSTART:20061222T110000Z).
260:      *
261:      * @return boolean  True if the client doesn't accept UTC datetimes.
262:      */
263:     public function useLocalTime()
264:     {
265:         return false;
266:     }
267: 
268:     /**
269:      * Converts an UTC timestamp like "20061222T110000Z" into a local
270:      * timestamp like "20061222T130000" using the server timezone.
271:      *
272:      * @param array $utc  Array with a datetime string in UTC.
273:      *
274:      * @return string  The datetime string converted to the local timezone.
275:      */
276:     protected function _convertUTC2LocalTime($utc)
277:     {
278:         $date = new Horde_Date($utc[0]);
279:         $date->setTimezone(date_default_timezone_get());
280:         return $date->format("Ymd\THis");
281:     }
282: }
283: 
API documentation generated by ApiGen