The Sync4J outlook converter uses its native SIF format for data
exchange. Conversion to text/vcalendar etc. is done by SifConverter.php The
connector seems not support DevInf information, so Horde_SyncMl_Device can
only detect it by the decice ID: so in the connector configuration the
device ID must be set to 'sc-pim-' which should be the default anyhow.
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.
public function vtodo2sif($vcard) { $iCal = new Horde_Icalendar(); if (!$iCal->parsevCalendar($vcard)) { return PEAR::raiseError('There was an error importing the data.'); } $components = $iCal->getComponents(); switch (count($components)) { case 0: return PEAR::raiseError('No data was found'); case 1: $content = $components[0]; break; default: return PEAR::raiseError('Multiple components found; only one is supported.'); } $hash['Complete'] = 0; $due = false; $attr = $content->getAllAttributes(); foreach ($attr as $item) { switch ($item['name']) { case 'SUMMARY': $hash['Subject'] = $item['value']; break; case 'DESCRIPTION': $hash['Body'] = $item['value']; break; case 'PRIORITY': if ($item['value'] == 1) { $hash['Importance'] = 2; } elseif ($item['value'] == 5) { $hash['Importance'] = 0; } else { $hash['Importance'] = 1; } break; case 'DTSTART': $hash['StartDate'] = Horde_Icalendar::_exportDateTime($item['value']); break; case 'DUE': $hash['DueDate'] = Horde_Icalendar::_exportDateTime($item['value']); $due = $item['value']; break; case 'AALARM': $hash['ReminderTime'] = $item['value']; $hash['ReminderSet'] = 1; break; case 'STATUS': $hash['Complete'] = $item['value'] == 'COMPLETED' ? 1 : 0; break; case 'CATEGORIES': $hash['Categories'] = $item['value']; break; case 'CLASS': switch (Horde_String::upper($item['value'])) { case 'PUBLIC': $hash['Sensitivity'] = 0; break; case 'PRIVATE': $hash['Sensitivity'] = 2; break; case 'CONFIDENTIAL': $hash['Sensitivity'] = 3; break; } break; } } if ($due && !isset($hash['ReminderSet'])) { // Parse VALARM components. foreach ($content->getComponents() as $component) { if ($component->getType() != 'vAlarm') { continue; } try { $trigger = $component->getAttribute('TRIGGER'); } catch (Horde_Icalendar_Exception $e) { continue; } if (is_array($trigger) || empty($trigger)) { continue; } $hash['ReminderSet'] = 1; $hash['ReminderTime'] = Horde_Icalendar::_exportDateTime($due - $trigger); } } return Horde_SyncMl_Device_sync4j::array2sif($hash, '<?xml version="1.0"?><task>', '</task>'); }
/** * When a test case contains adds/modifies/deletes being sent to the server, * these changes must be extracted from the test data and manually performed * using the api to achieve the desired behaviour by the server * * @throws Horde_Exception */ function testPre($name, $number) { global $debuglevel; $ref0 = getClient($name, $number); // Extract database (in horde: service). if (preg_match('|<Alert>.*?<Target>\\s*<LocURI>([^>]*)</LocURI>.*?</Alert>|si', $ref0, $m)) { $GLOBALS['service'] = $m[1]; } if (!preg_match('|<SyncHdr>.*?<Source>\\s*<LocURI>(.*?)</LocURI>.*?</SyncHdr>|si', $ref0, $m)) { echo $ref0; throw new Horde_Exception('Unable to find device id'); } $device_id = $m[1]; // Start backend session if not already done. if ($GLOBALS['testbackend']->getSyncDeviceID() != $device_id) { $GLOBALS['testbackend']->sessionStart($device_id, null, Horde_SyncMl_Backend::MODE_TEST); } // This makes a login even when a logout has occured when the session got // deleted. $GLOBALS['testbackend']->setUser(SYNCMLTEST_USERNAME); $ref1 = getServer($name, $number + 1); if (!$ref1) { return; } $ref1 = str_replace(array('<![CDATA[', ']]>', '<?xml version="1.0"?><!DOCTYPE SyncML PUBLIC "-//SYNCML//DTD SyncML 1.1//EN" "http://www.syncml.org/docs/syncml_represent_v11_20020213.dtd">'), '', $ref1); // Check for Adds. if (preg_match_all('|<Add>.*?<type[^>]*>(.*?)</type>.*?<LocURI[^>]*>(.*?)</LocURI>.*?<data[^>]*>(.*?)</data>.*?</Add|si', $ref1, $m, PREG_SET_ORDER)) { foreach ($m as $c) { list(, $contentType, $locuri, $data) = $c; // Some Sync4j tweaking. switch (Horde_String::lower($contentType)) { case 'text/x-s4j-sifn': $data = Horde_SyncMl_Device_sync4j::sif2vnote(base64_decode($data)); $contentType = 'text/x-vnote'; $service = 'notes'; break; case 'text/x-s4j-sifc': $data = Horde_SyncMl_Device_sync4j::sif2vcard(base64_decode($data)); $contentType = 'text/x-vcard'; $service = 'contacts'; break; case 'text/x-s4j-sife': $data = Horde_SyncMl_Device_sync4j::sif2vevent(base64_decode($data)); $contentType = 'text/calendar'; $service = 'calendar'; break; case 'text/x-s4j-sift': $data = Horde_SyncMl_Device_sync4j::sif2vtodo(base64_decode($data)); $contentType = 'text/calendar'; $service = 'tasks'; break; case 'text/x-vcalendar': case 'text/calendar': if (preg_match('/(\\r\\n|\\r|\\n)BEGIN:\\s*VTODO/', $data)) { $service = 'tasks'; } else { $service = 'calendar'; } break; default: throw new Horde_Exception("Unable to find service for contentType={$contentType}"); } $result = $GLOBALS['testbackend']->addEntry($service, $data, $contentType); if (is_a($result, 'PEAR_Error')) { echo "error importing data into {$service}:\n{$data}\n"; throw new Horde_Exception_Wrapped($result); } if ($debuglevel >= 2) { echo "simulated {$service} add of {$result} as {$locuri}!\n"; echo ' at ' . date('Y-m-d H:i:s') . "\n"; if ($debuglevel >= 10) { echo "data: {$data}\nsuid={$result}\n"; } } // Store UID used by server. $GLOBALS['mapping_locuri2uid'][$locuri] = $result; } } // Check for Replaces. if (preg_match_all('|<Replace>.*?<type[^>]*>(.*?)</type>.*?<LocURI[^>]*>(.*?)</LocURI>.*?<data[^>]*>(.*?)</data>.*?</Replace|si', $ref1, $m, PREG_SET_ORDER)) { foreach ($m as $c) { list(, $contentType, $locuri, $data) = $c; // Some Sync4j tweaking. switch (Horde_String::lower($contentType)) { case 'sif/note': case 'text/x-s4j-sifn': $data = Horde_SyncMl_Device_sync4j::sif2vnote(base64_decode($data)); $contentType = 'text/x-vnote'; $service = 'notes'; break; case 'sif/contact': case 'text/x-s4j-sifc': $data = Horde_SyncMl_Device_sync4j::sif2vcard(base64_decode($data)); $contentType = 'text/x-vcard'; $service = 'contacts'; break; case 'sif/calendar': case 'text/x-s4j-sife': $data = Horde_SyncMl_Device_sync4j::sif2vevent(base64_decode($data)); $contentType = 'text/calendar'; $service = 'calendar'; break; case 'sif/task': case 'text/x-s4j-sift': $data = Horde_SyncMl_Device_sync4j::sif2vtodo(base64_decode($data)); $contentType = 'text/calendar'; $service = 'tasks'; break; case 'text/x-vcalendar': case 'text/calendar': if (preg_match('/(\\r\\n|\\r|\\n)BEGIN:\\s*VTODO/', $data)) { $service = 'tasks'; } else { $service = 'calendar'; } break; default: throw new Horde_Exception("Unable to find service for contentType={$contentType}"); } /* Get SUID. */ $suid = $GLOBALS['testbackend']->getSuid($service, $locuri); if (empty($suid)) { throw new Horde_Exception("Unable to find SUID for CUID {$locuri} for simulating replace"); } $result = $GLOBALS['testbackend']->replaceEntry($service, $data, $contentType, $suid); if (is_a($result, 'PEAR_Error')) { echo "Error replacing data {$locuri} suid={$suid}!\n"; throw new Horde_Exception_Wrapped($result); } if ($debuglevel >= 2) { echo "simulated {$service} replace of {$locuri} suid={$suid}!\n"; if ($debuglevel >= 10) { echo "data: {$data}\nnew id={$result}\n"; } } } } // Check for Deletes. // <Delete><CmdID>5</CmdID><Item><Target><LocURI>1798147</LocURI></Target></Item></Delete> if (preg_match_all('|<Delete>.*?<Target>\\s*<LocURI>(.*?)</LocURI>|si', $ref1, $m, PREG_SET_ORDER)) { foreach ($m as $d) { list(, $locuri) = $d; /* Get SUID. */ $service = $GLOBALS['service']; $suid = $GLOBALS['testbackend']->getSuid($service, $locuri); if (empty($suid)) { // Maybe we have a handletaskincalendar. if ($service == 'calendar') { if ($debuglevel >= 2) { echo "special tasks delete...\n"; } $service = 'tasks'; $suid = $GLOBALS['testbackend']->getSuid($service, $locuri); } } if (empty($suid)) { throw new Horde_Exception("Unable to find SUID for CUID {$locuri} for simulating {$service} delete"); } $result = $GLOBALS['testbackend']->deleteEntry($service, $suid); // @TODO: simulate a delete by just faking some history data. if (is_a($result, 'PEAR_Error')) { echo "Error deleting data {$locuri}!"; throw new Horde_Exception_Wrapped($result); } if ($debuglevel >= 2) { echo "simulated {$service} delete of {$suid}!\n"; } } } }