[sync] SyncML working! Step 2/3
Karsten Fourmont
fourmont at gmx.de
Wed Jun 30 10:07:53 PDT 2004
Hi,
here are the patches for the various modules. They are named
<modulename>.patch
Patch framework.patch
---------------------
Contains all patches to framework _except_ to the SyncML Package itself:
DataTreee/sql.php:
1) _load missed a $this->_connect
2) for some strange reasons I sometimes had $this->_connected==true but
$this->_db->connection was int(0) rather than a database resource
handle. I did not take a closer look why this might happen but just
enforced reconnection on !$this->_db->connection
WB_XML/ContentHandler.php:
My P900 was picky about the spacious XML the ContentHandler produces. It
didn't like stuff like:
<tag> password
</tag>
Note the space after <tag>
So I changed it to add newlines and padding _before_ _opening_ tags
only. So you get output like
<foo>
<bar>password</bar></foo>
which seems to be fine with my phone as all tags with actual character
data in it don't have "wrong" whitespace any more.
Patch nag.patch
---------------
lib/api.php: -wrong order of parameters for listBy in api spec
-removed notices for incomplete arguments
Patch mnemo.patch
-----------------
lib/api.php: wrong order of parameters for listBy in api spec and
implementation
Patch kronolith.patch
---------------------
This is a somewhat bigger patch. Basically the issue is as follows:
there seem to be two packages for dealing with iCalendar Data: the
ICalendar package and the Horde_Data package. The later can do proper
charset handling which is needed for SyncML. So I converted the
Kronolith api to use this rather than the ICalendar package. SyncML
works without this patch, but you may run into Charset problems.
1) lib/Driver.php: ignore strange recurrence definitions without "="
2) lib/api.php
import and replace now use Horde::Data rather than the iCalendar
package. This provides charset and other parameter (quoted-printable)
support.
I also added a "listEvents" api function to the Kronolith-Api. It's just
a thin wrapper around Kronoliths listEvents function. This is totally
unrelated to SyncML: I just needed it at some point in time and think it
is just missing from the api to make it reaully useful.
3) lib/Driver/sql.php: fixed small Typo
OK, that's it. I'm really curious if somebody else can get this thing
running.
Having full SyncML support in Horde would be really great: overtaking
Exchange Server and Lotus Notes is fun :-)
Cheers,
Karsten
-------------- next part --------------
Index: lib/api.php
===================================================================
RCS file: /repository/nag/lib/api.php,v
retrieving revision 1.86
diff -u -r1.86 api.php
--- lib/api.php 17 Jun 2004 15:02:26 -0000 1.86
+++ lib/api.php 30 Jun 2004 16:47:41 -0000
@@ -58,7 +58,7 @@
);
$_services['listBy'] = array(
- 'args' => array('timestamp', 'action'),
+ 'args' => array('action', 'timestamp'),
'type' => 'stringArray'
);
@@ -248,7 +248,7 @@
*
* @return string The new GUID, or false on failure.
*/
-function _nag_import($content, $contentType, $tasklist)
+function _nag_import($content, $contentType, $tasklist = null)
{
require_once dirname(__FILE__) . '/base.php';
global $prefs;
@@ -297,7 +297,10 @@
* @TODO Need to check for alarms and set due date, etc.
*/
$hash = $content->toArray();
- $taskId = $storage->add($hash['name'], $hash['desc'], 0, $hash['priority']);
+ $taskId = $storage->add(isset($hash['name']) ? $hash['name'] : "",
+ isset($hash['desc']) ? $hash['desc'] : "",
+ 0,
+ isset($hash['priority']) ? $hash['priority'] : 3);
break;
default:
@@ -430,7 +433,12 @@
* @TODO Need to check for alarms and set due date, etc.
*/
$hash = $content->toArray();
- $result = $storage->modify($task['task_id'], $hash['name'], $hash['desc'], 0, $hash['priority']);
+ $result = $storage->modify($task['task_id'],
+ isset($hash['name']) ? $hash['name'] : "",
+ isset($hash['desc']) ? $hash['desc'] : "",
+ 0,
+ isset($hash['priority']) ? $hash['priority'] : 3);
+
break;
default:
-------------- next part --------------
Index: lib/Driver.php
===================================================================
RCS file: /repository/kronolith/lib/Driver.php,v
retrieving revision 1.75
diff -u -r1.75 Driver.php
--- lib/Driver.php 27 Jun 2004 17:06:25 -0000 1.75
+++ lib/Driver.php 29 Jun 2004 19:03:40 -0000
@@ -611,7 +611,7 @@
// Recurrence.
$rrule = $vEvent->getAttribute('RRULE');
- if (!is_array($rrule) && !is_a($rrule, 'PEAR_Error')) {
+ if (!is_array($rrule) && !is_a($rrule, 'PEAR_Error') && strstr($rrule,'=')) {
// Parse the recurrence rule into keys and values.
$parts = explode(';', $rrule);
foreach ($parts as $part) {
Index: lib/api.php
===================================================================
RCS file: /repository/kronolith/lib/api.php,v
retrieving revision 1.115
diff -u -r1.115 api.php
--- lib/api.php 9 Jun 2004 16:05:22 -0000 1.115
+++ lib/api.php 29 Jun 2004 19:03:44 -0000
@@ -66,6 +66,11 @@
'type' => 'boolean'
);
+$_services['listEvents'] = array(
+ 'args' => array('startstamp' => 'int', 'endstamp' => 'int', 'calendar' => 'string', 'showRecurrence' => 'string'),
+ 'type' => 'array'
+);
+
function _kronolith_listCalendars($owneronly = false, $permission = null)
{
@@ -125,70 +130,100 @@
* text/x-vevent
* @param string $calendar (optional) What calendar should the event be added to?
*
- * @return string The new GUID, or false on failure.
+ * @return string The new GUID, or a PEAR_Error on failure.
*/
function _kronolith_import($content, $contentType, $calendar = null)
{
- require_once dirname(__FILE__) . '/base.php';
- global $kronolith;
+ require_once dirname(__FILE__) . '/base.php';
+ require_once 'Horde/Data.php';
+
+ global $kronolith;
+
+ if (is_a($content, 'PEAR_Error')) {
+ return $content;
+ }
- if (!isset($calendar)) {
- $calendar = Kronolith::getDefaultCalendar(PERMS_EDIT);
+ if (!isset($calendar)) {
+ $calendar = Kronolith::getDefaultCalendar(PERMS_EDIT);
+ }
+ if (!array_key_exists($calendar, Kronolith::listCalendars(false, PERMS_EDIT))) {
+ return PEAR::raiseError(_("Permission Denied"));
+ }
+ $kronolith->open($calendar);
+
+ // legacy code to import a Horde_iCalendar_vevent from the
+ // iCalendar package. We use Horde_Data now instead of the
+ // iCalendar package. If this package gets removed, this
+ // code can go as well.
+
+ if (is_a($content, 'Horde_iCalendar_vevent')) {
+ $event = &$kronolith->getEvent();
+ $event->fromiCalendar($content);
+
+ $guid = $content->getAttribute('UID');
+ if (!is_a($guid, 'PEAR_Error')) {
+ $event->setID($guid);
}
- if (!array_key_exists($calendar, Kronolith::listCalendars(false, PERMS_EDIT))) {
- return PEAR::raiseError(_("Permission Denied"));
+
+ $id = $event->save();
+ return $event->getGUID($id);
+ }
+
+ switch ($contentType) {
+ case 'text/calendar':
+ case 'text/x-icalendar':
+ case 'text/x-vcalendar':
+ case 'text/x-vevent':
+ $data = &Horde_Data::singleton('icalendar');
+ if (is_a($data, 'PEAR_Error')) {
+ return $data;
+ }
+ $r = $data->importData($content);
+ if (is_a($r, 'PEAR_Error')) {
+ return $r;
+ }
+ if ($data->count() == 0) {
+ return PEAR::raiseError(_("No iCalendar data was found."));
+ }
+ if ($data->count() > 1) {
+ return PEAR::raiseError(_("Multiple iCalendar components found; only one vEvent is supported."));
+ }
+ $r = $data->toHash(0);
+ if (is_a($r, 'PEAR_Error')) {
+ return $r;
}
- $kronolith->open($calendar);
- switch ($contentType) {
- case 'text/calendar':
- case 'text/x-icalendar':
- case 'text/x-vcalendar':
- case 'text/x-vevent':
- if (!is_a($content, 'Horde_iCalendar_vevent')) {
- require_once 'Horde/iCalendar.php';
- $iCal = &new Horde_iCalendar();
- if (!$iCal->parsevCalendar($content)) {
- return PEAR::raiseError(_("There was an error importing the iCalendar data."));
- }
-
- $components = $iCal->getComponents();
- switch (count($components)) {
- case 0:
- return PEAR::raiseError(_("No iCalendar data was found."));
-
- case 1:
- $content = $components[0];
- if (!is_a($content, 'Horde_iCalendar_vevent')) {
- return PEAR::raiseError(_("vEvent not found."));
- }
- break;
-
- default:
- return PEAR::raiseError(_("Multiple iCalendar components found; only one vEvent is supported."));
- }
- }
-
- $event = &$kronolith->getEvent();
- $event->fromiCalendar($content);
-
- $guid = $content->getAttribute('UID');
- if (!is_a($guid, 'PEAR_Error')) {
- $event->setID($guid);
- }
+ $event = &$kronolith->getEvent();
- $eventId = $event->save();
- break;
+ if (!$event) {
+ return PEAR::raiseError("Unable to create event object");
+ }
+ if(is_a($event, 'PEAR_Error')) {
+ return $event;
+ }
- default:
- return PEAR::raiseError(_("Unsupported Content-Type."));
+ $event->fromHash($r);
+
+ // if a uid was specified in the content, use it.
+ if(!empty($r['UID'])) {
+ $guid = $r['UID'];
+ if (!is_a($guid, 'PEAR_Error')) {
+ $event->setID($guid);
+ }
}
+
+ $id = $event->save();
- if (is_a($eventId, 'PEAR_Error')) {
- return $eventId;
+ if (is_a($id , 'PEAR_Error')) {
+ return $id;
}
- return $kronolith->getGUID($eventId);
+ return $kronolith->getGUID($id);
+
+ default:
+ return PEAR::raiseError(_("Unsupported Content-Type."));
+ }
+
}
/**
@@ -265,66 +300,93 @@
* text/x-vcalendar
* text/x-vevent
*
- * @return boolean Success or failure.
+ * @return mixed true on Success, PEAR_Error otherwise.
*/
function _kronolith_replace($guid, $content, $contentType)
{
- require_once dirname(__FILE__) . '/base.php';
- global $kronolith;
+ require_once dirname(__FILE__) . '/base.php';
+ require_once 'Horde/Data.php';
- $event = $kronolith->getByGUID($guid);
- if (is_a($event, 'PEAR_Error')) {
- return $event;
+ global $kronolith;
+
+ $event = $kronolith->getByGUID($guid);
+ if (is_a($event, 'PEAR_Error')) {
+ return $event;
+ }
+
+ if (!array_key_exists($event->getCalendar(), Kronolith::listCalendars(false, PERMS_EDIT))) {
+ return PEAR::raiseError(_("Permission Denied"));
+ }
+
+ // legacy code to import a Horde_iCalendar_vevent from the
+ // iCalendar package. We use Horde_Data now instead of the
+ // iCalendar package. If this package gets removed, this
+ // code can go as well.
+ if (is_a($content, 'Horde_iCalendar_vevent')) {
+ $event->fromiCalendar($content);
+
+ $guid = $content->getAttribute('UID');
+ if (!is_a($guid, 'PEAR_Error')) {
+ $event->setID($guid);
}
- if (!array_key_exists($event->getCalendar(), Kronolith::listCalendars(false, PERMS_EDIT))) {
- return PEAR::raiseError(_("Permission Denied"));
+ $id = $event->save();
+ return $is_a($id, 'PEAR_Error') ? $id : true;
+ }
+
+ switch ($contentType) {
+ case 'text/calendar':
+ case 'text/x-icalendar':
+ case 'text/x-vcalendar':
+ case 'text/x-vevent':
+ $data = &Horde_Data::singleton('icalendar');
+ if (is_a($data, 'PEAR_Error')) {
+ return $data;
+ }
+ $r = $data->importData($content);
+ if (is_a($r, 'PEAR_Error')) {
+ return $r;
+ }
+ if ($data->count() == 0) {
+ var_dump($r);die("OK");
+ return PEAR::raiseError(_("No iCalendar data was found."));
+ }
+ if ($data->count() > 1) {
+ return PEAR::raiseError(_("Multiple iCalendar components found; only one vEvent is supported."));
+ }
+ $r = $data->toHash(0);
+ if (is_a($r, 'PEAR_Error')) {
+ return $r;
}
- switch ($contentType) {
- case 'text/calendar':
- case 'text/x-icalendar':
- case 'text/x-vcalendar':
- case 'text/x-vevent':
- if (!is_a($content, 'Horde_iCalendar_vevent')) {
- require_once 'Horde/iCalendar.php';
- $iCal = &new Horde_iCalendar();
- if (!$iCal->parsevCalendar($content)) {
- return PEAR::raiseError(_("There was an error importing the iCalendar data."));
- }
-
- $components = $iCal->getComponents();
- switch (count($components)) {
- case 0:
- return PEAR::raiseError(_("No iCalendar data was found."));
-
- case 1:
- $content = $components[0];
- if (!is_a($content, 'Horde_iCalendar_vevent')) {
- return PEAR::raiseError(_("vEvent not found."));
- }
- break;
-
- default:
- return PEAR::raiseError(_("Multiple iCalendar components found; only one vEvent is supported."));
- }
- }
-
- $event->fromiCalendar($content);
-
- $guid = $content->getAttribute('UID');
- if (!is_a($guid, 'PEAR_Error')) {
- $event->setID($guid);
- }
+ if (!$event) {
+ return PEAR::raiseError("Unable to create event object");
+ }
+ if(is_a($event, 'PEAR_Error')) {
+ return $event;
+ }
- $eventId = $event->save();
- break;
+ $event->fromHash($r);
- default:
- return PEAR::raiseError(_("Unsupported Content-Type."));
+ // if a uid was specified in the content, use it.
+ if(!empty($r['UID'])) {
+ $guid = $r['UID'];
+ if (!is_a($guid, 'PEAR_Error')) {
+ $event->setID($guid);
+ }
}
- return is_a($eventId, 'PEAR_Error') ? $eventId : true;
+ $id = $event->save();
+
+ if (is_a($id , 'PEAR_Error')) {
+ return $id;
+ }
+
+ return true;
+
+ default:
+ return PEAR::raiseError(_("Unsupported Content-Type."));
+ }
}
/**
@@ -420,4 +482,29 @@
}
return true;
+}
+
+/**
+ * List Events for a given time period.
+ *
+ * @param integer $startstamp (optional) The start of the time period to retrieve.
+ * @param integer $endstamp (optional) The end of the time period to retrieve.
+ * @param string $calendar (optional) The calendar to view free/busy
+ * slots for. Defaults to the user's default calendar.
+ * @param boolean $showRecurrence Return every instance of a recurring event?
+ * If false, will only return recurring events
+ * once inside the $startDate - $endDate range.
+ *
+ * @return array of guids
+ */
+function _kronolith_listEvents($startstamp = null, $endstamp = null, $calendar = null,$showRecurrence = true)
+{
+ require_once dirname(__FILE__) . '/base.php';
+
+ if (is_null($calendar)) {
+ $calendar = $GLOBALS['prefs']->getValue('default_share');
+ }
+
+ return Kronolith::listEvents($startstamp, $endstamp, $calendar,$showRecurrence);
+
}
Index: lib/Driver/sql.php
===================================================================
RCS file: /repository/kronolith/lib/Driver/sql.php,v
retrieving revision 1.121
diff -u -r1.121 sql.php
--- lib/Driver/sql.php 22 May 2004 13:02:13 -0000 1.121
+++ lib/Driver/sql.php 29 Jun 2004 19:03:45 -0000
@@ -292,7 +292,7 @@
$res = $this->_db->query($query);
if (is_a($res, 'PEAR_Error')) {
- Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ Horde::logMessage($res, __FILE__, __LINE__, PEAR_LOG_ERR);
return $res;
}
-------------- next part --------------
Index: lib/api.php
===================================================================
RCS file: /repository/mnemo/lib/api.php,v
retrieving revision 1.48
diff -u -r1.48 api.php
--- lib/api.php 9 Jun 2004 16:05:23 -0000 1.48
+++ lib/api.php 29 Jun 2004 19:15:30 -0000
@@ -16,7 +16,7 @@
);
$_services['listBy'] = array(
- 'args' => array('timestamp', 'action'),
+ 'args' => array('action', 'timestamp'),
'type' => 'stringArray'
);
@@ -79,7 +79,7 @@
*
* @return array An array of GUIDs matching the action and time criteria.
*/
-function &_mnemo_listBy($timestamp, $action)
+function &_mnemo_listBy($action, $timestamp)
{
require_once dirname(__FILE__) . '/base.php';
require_once 'Horde/History.php';
-------------- next part --------------
? list.txt
? myinstall.php
? shell.out
? x.php
Index: DataTree/DataTree/sql.php
===================================================================
RCS file: /repository/framework/DataTree/DataTree/sql.php,v
retrieving revision 1.133
diff -u -r1.133 sql.php
--- DataTree/DataTree/sql.php 29 Jun 2004 15:12:45 -0000 1.133
+++ DataTree/DataTree/sql.php 29 Jun 2004 18:44:53 -0000
@@ -102,6 +102,8 @@
}
$root = (string)$root;
+ $this->_connect();
+
$query = sprintf('SELECT datatree_id, datatree_parents FROM %s' .
' WHERE datatree_name = %s AND group_uid = %s ORDER BY datatree_id',
$this->_params['table'],
@@ -1046,7 +1048,7 @@
*/
function _connect()
{
- if (!$this->_connected) {
+ if (!$this->_connected || !$this->_db->connection) {
Horde::assertDriverConfig($this->_params, 'storage',
array('phptype', 'hostspec', 'username', 'database', 'charset'),
'DataTree SQL');
Index: RPC/RPC/syncml.php
===================================================================
RCS file: /repository/framework/RPC/RPC/syncml.php,v
retrieving revision 1.16
diff -u -r1.16 syncml.php
--- RPC/RPC/syncml.php 7 Apr 2004 17:43:42 -0000 1.16
+++ RPC/RPC/syncml.php 29 Jun 2004 18:45:05 -0000
@@ -69,6 +69,12 @@
if (!isset($packetNum)) {
$packetNum = 0;
}
+ $f = @fopen($this->_debugDir . '/syncml.packetnum', 'wb');
+ if ($f) {
+ fwrite($f, $packetNum+1);
+ fclose($f);
+ }
+
$f = @fopen($this->_debugDir . '/syncml_client_' . $packetNum . '.xml', 'wb');
if ($f) {
@@ -99,12 +105,6 @@
fclose($f);
}
- $packetNum++;
- $f = @fopen($this->_debugDir . '/syncml.packetnum', 'wb');
- if ($f) {
- fwrite($f, $packetNum);
- fclose($f);
- }
}
return $xmlinput;
Index: XML_WBXML/WBXML/ContentHandler.php
===================================================================
RCS file: /repository/framework/XML_WBXML/WBXML/ContentHandler.php,v
retrieving revision 1.8
diff -u -r1.8 ContentHandler.php
--- XML_WBXML/WBXML/ContentHandler.php 20 Jan 2004 02:21:54 -0000 1.8
+++ XML_WBXML/WBXML/ContentHandler.php 29 Jun 2004 18:45:12 -0000
@@ -69,6 +69,7 @@
function startElement($uri, $element, $attrs)
{
+ $this->_output .= "\n";
$this->_padspaces();
$this->_output .= '<' . $element;
@@ -84,7 +85,7 @@
$this->_output .= ' ' . $attr['attiribute'] . '="' . $attr['value'] . '"';
}
- $this->_output .= ">\n";
+ $this->_output .= ">";
$this->_indent++;
}
@@ -93,16 +94,14 @@
{
$this->_indent--;
- $this->_padspaces();
- $this->_output .= '</' . $element . ">\n";
+ $this->_output .= '</' . $element . ">";
$this->_currentUri->pop();
}
function characters($str)
{
- $this->_padspaces();
- $this->_output .= $str . "\n";
+ $this->_output .= $str; // . "\n";
}
function opaque($o)
More information about the sync
mailing list