mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-26 16:49:10 +01:00
- merged SyncML-1.2 branch with trunk:
svn merge ^/trunk/phpgwapi@27377 ^/branches/SyncML-1.2/phpgwapi .
This commit is contained in:
parent
ab20b324e0
commit
e667e168b4
@ -39,7 +39,7 @@ class contenthistory
|
||||
*
|
||||
* @param string $_appName the appname example: infolog_notes
|
||||
* @param int $_id the internal egwapp content id
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
function expireMapping($_appName, $_id)
|
||||
{
|
||||
@ -163,7 +163,7 @@ class contenthistory
|
||||
// now update the time stamp
|
||||
$newData = array (
|
||||
'sync_changedby' => $GLOBALS['egw_info']['user']['account_id'],
|
||||
$_action == 'modify' ? 'sync_modified' : 'sync_deleted' => $_ts ,
|
||||
$_action == 'delete' ? 'sync_deleted' : 'sync_modified' => $this->db->to_timestamp($_ts),
|
||||
);
|
||||
$this->db->update(self::TABLE, $newData, $where,__LINE__,__FILE__);
|
||||
break;
|
||||
|
769
phpgwapi/inc/horde/Horde/Date.php
Normal file
769
phpgwapi/inc/horde/Horde/Date.php
Normal file
@ -0,0 +1,769 @@
|
||||
<?php
|
||||
|
||||
define('HORDE_DATE_SUNDAY', 0);
|
||||
define('HORDE_DATE_MONDAY', 1);
|
||||
define('HORDE_DATE_TUESDAY', 2);
|
||||
define('HORDE_DATE_WEDNESDAY', 3);
|
||||
define('HORDE_DATE_THURSDAY', 4);
|
||||
define('HORDE_DATE_FRIDAY', 5);
|
||||
define('HORDE_DATE_SATURDAY', 6);
|
||||
|
||||
define('HORDE_DATE_MASK_SUNDAY', 1);
|
||||
define('HORDE_DATE_MASK_MONDAY', 2);
|
||||
define('HORDE_DATE_MASK_TUESDAY', 4);
|
||||
define('HORDE_DATE_MASK_WEDNESDAY', 8);
|
||||
define('HORDE_DATE_MASK_THURSDAY', 16);
|
||||
define('HORDE_DATE_MASK_FRIDAY', 32);
|
||||
define('HORDE_DATE_MASK_SATURDAY', 64);
|
||||
define('HORDE_DATE_MASK_WEEKDAYS', 62);
|
||||
define('HORDE_DATE_MASK_WEEKEND', 65);
|
||||
define('HORDE_DATE_MASK_ALLDAYS', 127);
|
||||
|
||||
define('HORDE_DATE_MASK_SECOND', 1);
|
||||
define('HORDE_DATE_MASK_MINUTE', 2);
|
||||
define('HORDE_DATE_MASK_HOUR', 4);
|
||||
define('HORDE_DATE_MASK_DAY', 8);
|
||||
define('HORDE_DATE_MASK_MONTH', 16);
|
||||
define('HORDE_DATE_MASK_YEAR', 32);
|
||||
define('HORDE_DATE_MASK_ALLPARTS', 63);
|
||||
|
||||
/**
|
||||
* Horde Date wrapper/logic class, including some calculation
|
||||
* functions.
|
||||
*
|
||||
* $Horde: framework/Date/Date.php,v 1.8.10.18 2008/09/17 08:46:04 jan Exp $
|
||||
*
|
||||
* @package Horde_Date
|
||||
*/
|
||||
class Horde_Date {
|
||||
|
||||
/**
|
||||
* Year
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $year;
|
||||
|
||||
/**
|
||||
* Month
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $month;
|
||||
|
||||
/**
|
||||
* Day
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $mday;
|
||||
|
||||
/**
|
||||
* Hour
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $hour = 0;
|
||||
|
||||
/**
|
||||
* Minute
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $min = 0;
|
||||
|
||||
/**
|
||||
* Second
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $sec = 0;
|
||||
|
||||
/**
|
||||
* Internally supported strftime() specifiers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_supportedSpecs = '%CdDeHImMnRStTyY';
|
||||
|
||||
/**
|
||||
* Build a new date object. If $date contains date parts, use them to
|
||||
* initialize the object.
|
||||
*
|
||||
* Recognized formats:
|
||||
* - arrays with keys 'year', 'month', 'mday', 'day' (since Horde 3.2),
|
||||
* 'hour', 'min', 'minute' (since Horde 3.2), 'sec'
|
||||
* - objects with properties 'year', 'month', 'mday', 'hour', 'min', 'sec'
|
||||
* - yyyy-mm-dd hh:mm:ss (since Horde 3.1)
|
||||
* - yyyymmddhhmmss (since Horde 3.1)
|
||||
* - yyyymmddThhmmssZ (since Horde 3.1.4)
|
||||
* - unix timestamps
|
||||
*/
|
||||
function Horde_Date($date = null)
|
||||
{
|
||||
if (function_exists('nl_langinfo')) {
|
||||
$this->_supportedSpecs .= 'bBpxX';
|
||||
}
|
||||
|
||||
if (is_array($date) || is_object($date)) {
|
||||
foreach ($date as $key => $val) {
|
||||
if (in_array($key, array('year', 'month', 'mday', 'hour', 'min', 'sec'))) {
|
||||
$this->$key = (int)$val;
|
||||
}
|
||||
}
|
||||
|
||||
// If $date['day'] is present and numeric we may have been passed
|
||||
// a Horde_Form_datetime array.
|
||||
if (is_array($date) && isset($date['day']) &&
|
||||
is_numeric($date['day'])) {
|
||||
$this->mday = (int)$date['day'];
|
||||
}
|
||||
// 'minute' key also from Horde_Form_datetime
|
||||
if (is_array($date) && isset($date['minute'])) {
|
||||
$this->min = $date['minute'];
|
||||
}
|
||||
} elseif (!is_null($date)) {
|
||||
// Match YYYY-MM-DD HH:MM:SS, YYYYMMDDHHMMSS and YYYYMMDD'T'HHMMSS'Z'.
|
||||
if (preg_match('/(\d{4})-?(\d{2})-?(\d{2})T? ?(\d{2}):?(\d{2}):?(\d{2})Z?/', $date, $parts)) {
|
||||
$this->year = (int)$parts[1];
|
||||
$this->month = (int)$parts[2];
|
||||
$this->mday = (int)$parts[3];
|
||||
$this->hour = (int)$parts[4];
|
||||
$this->min = (int)$parts[5];
|
||||
$this->sec = (int)$parts[6];
|
||||
} else {
|
||||
// Try as a timestamp.
|
||||
$parts = @getdate($date);
|
||||
if ($parts) {
|
||||
$this->year = $parts['year'];
|
||||
$this->month = $parts['mon'];
|
||||
$this->mday = $parts['mday'];
|
||||
$this->hour = $parts['hours'];
|
||||
$this->min = $parts['minutes'];
|
||||
$this->sec = $parts['seconds'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
*/
|
||||
function isLeapYear($year)
|
||||
{
|
||||
if (strlen($year) != 4 || preg_match('/\D/', $year)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the day of the year (1-366) that corresponds to the
|
||||
* first day of the given week.
|
||||
*
|
||||
* TODO: with PHP 5.1+, see http://derickrethans.nl/calculating_start_and_end_dates_of_a_week.php
|
||||
*
|
||||
* @param integer $week The week of the year to find the first day of.
|
||||
* @param integer $year The year to calculate for.
|
||||
*
|
||||
* @return integer The day of the year of the first day of the given week.
|
||||
*/
|
||||
function firstDayOfWeek($week, $year)
|
||||
{
|
||||
$jan1 = new Horde_Date(array('year' => $year, 'month' => 1, 'mday' => 1));
|
||||
$start = $jan1->dayOfWeek();
|
||||
if ($start > HORDE_DATE_THURSDAY) {
|
||||
$start -= 7;
|
||||
}
|
||||
return (($week * 7) - (7 + $start)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
*/
|
||||
function daysInMonth($month, $year)
|
||||
{
|
||||
if ($month == 2) {
|
||||
if (Horde_Date::isLeapYear($year)) {
|
||||
return 29;
|
||||
} else {
|
||||
return 28;
|
||||
}
|
||||
} elseif ($month == 4 || $month == 6 || $month == 9 || $month == 11) {
|
||||
return 30;
|
||||
} else {
|
||||
return 31;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the day of the week (0 = Sunday, 6 = Saturday) of this
|
||||
* object's date.
|
||||
*
|
||||
* @return integer The day of the week.
|
||||
*/
|
||||
function dayOfWeek()
|
||||
{
|
||||
if ($this->month > 2) {
|
||||
$month = $this->month - 2;
|
||||
$year = $this->year;
|
||||
} else {
|
||||
$month = $this->month + 10;
|
||||
$year = $this->year - 1;
|
||||
}
|
||||
|
||||
$day = (floor((13 * $month - 1) / 5) +
|
||||
$this->mday + ($year % 100) +
|
||||
floor(($year % 100) / 4) +
|
||||
floor(($year / 100) / 4) - 2 *
|
||||
floor($year / 100) + 77);
|
||||
|
||||
return (int)($day - 7 * floor($day / 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the day number of the year (1 to 365/366).
|
||||
*
|
||||
* @return integer The day of the year.
|
||||
*/
|
||||
function dayOfYear()
|
||||
{
|
||||
$monthTotals = array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
|
||||
$dayOfYear = $this->mday + $monthTotals[$this->month - 1];
|
||||
if (Horde_Date::isLeapYear($this->year) && $this->month > 2) {
|
||||
++$dayOfYear;
|
||||
}
|
||||
|
||||
return $dayOfYear;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the week of the month.
|
||||
*
|
||||
* @since Horde 3.2
|
||||
*
|
||||
* @return integer The week number.
|
||||
*/
|
||||
function weekOfMonth()
|
||||
{
|
||||
return ceil($this->mday / 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the week of the year, first Monday is first day of first week.
|
||||
*
|
||||
* @return integer The week number.
|
||||
*/
|
||||
function weekOfYear()
|
||||
{
|
||||
return $this->format('W');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of weeks in the given year (52 or 53).
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param integer $year The year to count the number of weeks in.
|
||||
*
|
||||
* @return integer $numWeeks The number of weeks in $year.
|
||||
*/
|
||||
function weeksInYear($year)
|
||||
{
|
||||
// Find the last Thursday of the year.
|
||||
$day = 31;
|
||||
$date = new Horde_Date(array('year' => $year, 'month' => 12, 'mday' => $day, 'hour' => 0, 'min' => 0, 'sec' => 0));
|
||||
while ($date->dayOfWeek() != HORDE_DATE_THURSDAY) {
|
||||
--$date->mday;
|
||||
}
|
||||
return $date->weekOfYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date of this object to the $nth weekday of $weekday.
|
||||
*
|
||||
* @param integer $weekday The day of the week (0 = Sunday, etc).
|
||||
* @param integer $nth The $nth $weekday to set to (defaults to 1).
|
||||
*/
|
||||
function setNthWeekday($weekday, $nth = 1)
|
||||
{
|
||||
if ($weekday < HORDE_DATE_SUNDAY || $weekday > HORDE_DATE_SATURDAY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->mday = 1;
|
||||
$first = $this->dayOfWeek();
|
||||
if ($weekday < $first) {
|
||||
$this->mday = 8 + $weekday - $first;
|
||||
} else {
|
||||
$this->mday = $weekday - $first + 1;
|
||||
}
|
||||
$this->mday += 7 * $nth - 7;
|
||||
|
||||
$this->correct();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function dump($prefix = '')
|
||||
{
|
||||
echo ($prefix ? $prefix . ': ' : '') . $this->year . '-' . $this->month . '-' . $this->mday . "<br />\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the date currently represented by this object a valid date?
|
||||
*
|
||||
* @return boolean Validity, counting leap years, etc.
|
||||
*/
|
||||
function isValid()
|
||||
{
|
||||
if ($this->year < 0 || $this->year > 9999) {
|
||||
return false;
|
||||
}
|
||||
return checkdate($this->month, $this->mday, $this->year);
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct any over- or underflows in any of the date's members.
|
||||
*
|
||||
* @param integer $mask We may not want to correct some overflows.
|
||||
*/
|
||||
function correct($mask = HORDE_DATE_MASK_ALLPARTS)
|
||||
{
|
||||
if ($mask & HORDE_DATE_MASK_SECOND) {
|
||||
while ($this->sec < 0) {
|
||||
--$this->min;
|
||||
$this->sec += 60;
|
||||
}
|
||||
while ($this->sec > 59) {
|
||||
++$this->min;
|
||||
$this->sec -= 60;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mask & HORDE_DATE_MASK_MINUTE) {
|
||||
while ($this->min < 0) {
|
||||
--$this->hour;
|
||||
$this->min += 60;
|
||||
}
|
||||
while ($this->min > 59) {
|
||||
++$this->hour;
|
||||
$this->min -= 60;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mask & HORDE_DATE_MASK_HOUR) {
|
||||
while ($this->hour < 0) {
|
||||
--$this->mday;
|
||||
$this->hour += 24;
|
||||
}
|
||||
while ($this->hour > 23) {
|
||||
++$this->mday;
|
||||
$this->hour -= 24;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mask & HORDE_DATE_MASK_MONTH) {
|
||||
while ($this->month > 12) {
|
||||
++$this->year;
|
||||
$this->month -= 12;
|
||||
}
|
||||
while ($this->month < 1) {
|
||||
--$this->year;
|
||||
$this->month += 12;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mask & HORDE_DATE_MASK_DAY) {
|
||||
while ($this->mday > Horde_Date::daysInMonth($this->month, $this->year)) {
|
||||
$this->mday -= Horde_Date::daysInMonth($this->month, $this->year);
|
||||
++$this->month;
|
||||
$this->correct(HORDE_DATE_MASK_MONTH);
|
||||
}
|
||||
while ($this->mday < 1) {
|
||||
--$this->month;
|
||||
$this->correct(HORDE_DATE_MASK_MONTH);
|
||||
$this->mday += Horde_Date::daysInMonth($this->month, $this->year);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this date to another date object to see which one is
|
||||
* greater (later). Assumes that the dates are in the same
|
||||
* timezone.
|
||||
*
|
||||
* @param mixed $date The date to compare to.
|
||||
*
|
||||
* @return integer == 0 if the dates are equal
|
||||
* >= 1 if this date is greater (later)
|
||||
* <= -1 if the other date is greater (later)
|
||||
*/
|
||||
function compareDate($date)
|
||||
{
|
||||
if (!is_a($date, 'Horde_Date')) {
|
||||
$date = new Horde_Date($date);
|
||||
}
|
||||
|
||||
if ($this->year != $date->year) {
|
||||
return $this->year - $date->year;
|
||||
}
|
||||
if ($this->month != $date->month) {
|
||||
return $this->month - $date->month;
|
||||
}
|
||||
|
||||
return $this->mday - $date->mday;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this to another date object by time, to see which one
|
||||
* is greater (later). Assumes that the dates are in the same
|
||||
* timezone.
|
||||
*
|
||||
* @param mixed $date The date to compare to.
|
||||
*
|
||||
* @return integer == 0 if the dates are equal
|
||||
* >= 1 if this date is greater (later)
|
||||
* <= -1 if the other date is greater (later)
|
||||
*/
|
||||
function compareTime($date)
|
||||
{
|
||||
if (!is_a($date, 'Horde_Date')) {
|
||||
$date = new Horde_Date($date);
|
||||
}
|
||||
|
||||
if ($this->hour != $date->hour) {
|
||||
return $this->hour - $date->hour;
|
||||
}
|
||||
if ($this->min != $date->min) {
|
||||
return $this->min - $date->min;
|
||||
}
|
||||
|
||||
return $this->sec - $date->sec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this to another date object, including times, to see
|
||||
* which one is greater (later). Assumes that the dates are in the
|
||||
* same timezone.
|
||||
*
|
||||
* @param mixed $date The date to compare to.
|
||||
*
|
||||
* @return integer == 0 if the dates are equal
|
||||
* >= 1 if this date is greater (later)
|
||||
* <= -1 if the other date is greater (later)
|
||||
*/
|
||||
function compareDateTime($date)
|
||||
{
|
||||
if (!is_a($date, 'Horde_Date')) {
|
||||
$date = new Horde_Date($date);
|
||||
}
|
||||
|
||||
if ($diff = $this->compareDate($date)) {
|
||||
return $diff;
|
||||
}
|
||||
|
||||
return $this->compareTime($date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time offset for local time zone.
|
||||
*
|
||||
* @param boolean $colon Place a colon between hours and minutes?
|
||||
*
|
||||
* @return string Timezone offset as a string in the format +HH:MM.
|
||||
*/
|
||||
function tzOffset($colon = true)
|
||||
{
|
||||
$secs = $this->format('Z');
|
||||
|
||||
if ($secs < 0) {
|
||||
$sign = '-';
|
||||
$secs = -$secs;
|
||||
} else {
|
||||
$sign = '+';
|
||||
}
|
||||
$colon = $colon ? ':' : '';
|
||||
$mins = intval(($secs + 30) / 60);
|
||||
return sprintf('%s%02d%s%02d',
|
||||
$sign, $mins / 60, $colon, $mins % 60);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unix timestamp representation of this date.
|
||||
*
|
||||
* @return integer A unix timestamp.
|
||||
*/
|
||||
function timestamp()
|
||||
{
|
||||
if (class_exists('DateTime')) {
|
||||
return $this->format('U');
|
||||
} else {
|
||||
return Horde_Date::_mktime($this->hour, $this->min, $this->sec, $this->month, $this->mday, $this->year);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unix timestamp representation of this date, 12:00am.
|
||||
*
|
||||
* @return integer A unix timestamp.
|
||||
*/
|
||||
function datestamp()
|
||||
{
|
||||
if (class_exists('DateTime')) {
|
||||
$dt = new DateTime();
|
||||
$dt->setDate($this->year, $this->month, $this->mday);
|
||||
$dt->setTime(0, 0, 0);
|
||||
return $dt->format('U');
|
||||
} else {
|
||||
return Horde_Date::_mktime(0, 0, 0, $this->month, $this->mday, $this->year);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time using the specifiers available in date() or in the DateTime
|
||||
* class' format() method.
|
||||
*
|
||||
* @since Horde 3.3
|
||||
*
|
||||
* @param string $format
|
||||
*
|
||||
* @return string Formatted time.
|
||||
*/
|
||||
function format($format)
|
||||
{
|
||||
if (class_exists('DateTime')) {
|
||||
$dt = new DateTime();
|
||||
$dt->setDate($this->year, $this->month, $this->mday);
|
||||
$dt->setTime($this->hour, $this->min, $this->sec);
|
||||
return $dt->format($format);
|
||||
} else {
|
||||
return date($format, $this->timestamp());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time in ISO-8601 format. Works correctly since Horde 3.2.
|
||||
*
|
||||
* @return string Date and time in ISO-8601 format.
|
||||
*/
|
||||
function iso8601DateTime()
|
||||
{
|
||||
return $this->rfc3339DateTime() . $this->tzOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time in RFC 2822 format.
|
||||
*
|
||||
* @return string Date and time in RFC 2822 format.
|
||||
*/
|
||||
function rfc2822DateTime()
|
||||
{
|
||||
return $this->format('D, j M Y H:i:s') . ' ' . $this->tzOffset(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time in RFC 3339 format.
|
||||
*
|
||||
* @since Horde 3.1
|
||||
*
|
||||
* @return string Date and time in RFC 3339 format. The seconds part has
|
||||
* been added with Horde 3.2.
|
||||
*/
|
||||
function rfc3339DateTime()
|
||||
{
|
||||
return $this->format('Y-m-d\TH:i:s');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time to standard 'ctime' format.
|
||||
*
|
||||
* @return string Date and time.
|
||||
*/
|
||||
function cTime()
|
||||
{
|
||||
return $this->format('D M j H:i:s Y');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date and time using strftime() format.
|
||||
*
|
||||
* @since Horde 3.1
|
||||
*
|
||||
* @return string strftime() formatted date and time.
|
||||
*/
|
||||
function strftime($format)
|
||||
{
|
||||
if (preg_match('/%[^' . $this->_supportedSpecs . ']/', $format)) {
|
||||
return strftime($format, $this->timestamp());
|
||||
} else {
|
||||
return $this->_strftime($format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date and time using a limited set of the strftime() format.
|
||||
*
|
||||
* @return string strftime() formatted date and time.
|
||||
*/
|
||||
function _strftime($format)
|
||||
{
|
||||
if (preg_match('/%[bBpxX]/', $format)) {
|
||||
require_once 'Horde/NLS.php';
|
||||
}
|
||||
|
||||
return preg_replace(
|
||||
array('/%b/e',
|
||||
'/%B/e',
|
||||
'/%C/e',
|
||||
'/%d/e',
|
||||
'/%D/e',
|
||||
'/%e/e',
|
||||
'/%H/e',
|
||||
'/%I/e',
|
||||
'/%m/e',
|
||||
'/%M/e',
|
||||
'/%n/',
|
||||
'/%p/e',
|
||||
'/%R/e',
|
||||
'/%S/e',
|
||||
'/%t/',
|
||||
'/%T/e',
|
||||
'/%x/e',
|
||||
'/%X/e',
|
||||
'/%y/e',
|
||||
'/%Y/',
|
||||
'/%%/'),
|
||||
array('$this->_strftime(NLS::getLangInfo(constant(\'ABMON_\' . (int)$this->month)))',
|
||||
'$this->_strftime(NLS::getLangInfo(constant(\'MON_\' . (int)$this->month)))',
|
||||
'(int)($this->year / 100)',
|
||||
'sprintf(\'%02d\', $this->mday)',
|
||||
'$this->_strftime(\'%m/%d/%y\')',
|
||||
'sprintf(\'%2d\', $this->mday)',
|
||||
'sprintf(\'%02d\', $this->hour)',
|
||||
'sprintf(\'%02d\', $this->hour == 0 ? 12 : ($this->hour > 12 ? $this->hour - 12 : $this->hour))',
|
||||
'sprintf(\'%02d\', $this->month)',
|
||||
'sprintf(\'%02d\', $this->min)',
|
||||
"\n",
|
||||
'$this->_strftime(NLS::getLangInfo($this->hour < 12 ? AM_STR : PM_STR))',
|
||||
'$this->_strftime(\'%H:%M\')',
|
||||
'sprintf(\'%02d\', $this->sec)',
|
||||
"\t",
|
||||
'$this->_strftime(\'%H:%M:%S\')',
|
||||
'$this->_strftime(NLS::getLangInfo(D_FMT))',
|
||||
'$this->_strftime(NLS::getLangInfo(T_FMT))',
|
||||
'substr(sprintf(\'%04d\', $this->year), -2)',
|
||||
(int)$this->year,
|
||||
'%'),
|
||||
$format);
|
||||
}
|
||||
|
||||
/**
|
||||
* mktime() implementation that supports dates outside of 1970-2038,
|
||||
* from http://phplens.com/phpeverywhere/adodb_date_library.
|
||||
*
|
||||
* @TODO remove in Horde 4
|
||||
*
|
||||
* This does NOT work with pre-1970 daylight saving times.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
function _mktime($hr, $min, $sec, $mon = false, $day = false,
|
||||
$year = false, $is_dst = false, $is_gmt = false)
|
||||
{
|
||||
if ($mon === false) {
|
||||
return $is_gmt
|
||||
? @gmmktime($hr, $min, $sec)
|
||||
: @mktime($hr, $min, $sec);
|
||||
}
|
||||
|
||||
if ($year > 1901 && $year < 2038 &&
|
||||
($year >= 1970 || version_compare(PHP_VERSION, '5.0.0', '>='))) {
|
||||
return $is_gmt
|
||||
? @gmmktime($hr, $min, $sec, $mon, $day, $year)
|
||||
: @mktime($hr, $min, $sec, $mon, $day, $year);
|
||||
}
|
||||
|
||||
$gmt_different = $is_gmt
|
||||
? 0
|
||||
: (mktime(0, 0, 0, 1, 2, 1970, 0) - gmmktime(0, 0, 0, 1, 2, 1970, 0));
|
||||
|
||||
$mon = intval($mon);
|
||||
$day = intval($day);
|
||||
$year = intval($year);
|
||||
|
||||
if ($mon > 12) {
|
||||
$y = floor($mon / 12);
|
||||
$year += $y;
|
||||
$mon -= $y * 12;
|
||||
} elseif ($mon < 1) {
|
||||
$y = ceil((1 - $mon) / 12);
|
||||
$year -= $y;
|
||||
$mon += $y * 12;
|
||||
}
|
||||
|
||||
$_day_power = 86400;
|
||||
$_hour_power = 3600;
|
||||
$_min_power = 60;
|
||||
|
||||
$_month_table_normal = array('', 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
|
||||
$_month_table_leaf = array('', 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
|
||||
|
||||
$_total_date = 0;
|
||||
if ($year >= 1970) {
|
||||
for ($a = 1970; $a <= $year; $a++) {
|
||||
$leaf = Horde_Date::isLeapYear($a);
|
||||
if ($leaf == true) {
|
||||
$loop_table = $_month_table_leaf;
|
||||
$_add_date = 366;
|
||||
} else {
|
||||
$loop_table = $_month_table_normal;
|
||||
$_add_date = 365;
|
||||
}
|
||||
if ($a < $year) {
|
||||
$_total_date += $_add_date;
|
||||
} else {
|
||||
for ($b = 1; $b < $mon; $b++) {
|
||||
$_total_date += $loop_table[$b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ($_total_date + $day - 1) * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;
|
||||
}
|
||||
|
||||
for ($a = 1969 ; $a >= $year; $a--) {
|
||||
$leaf = Horde_Date::isLeapYear($a);
|
||||
if ($leaf == true) {
|
||||
$loop_table = $_month_table_leaf;
|
||||
$_add_date = 366;
|
||||
} else {
|
||||
$loop_table = $_month_table_normal;
|
||||
$_add_date = 365;
|
||||
}
|
||||
if ($a > $year) {
|
||||
$_total_date += $_add_date;
|
||||
} else {
|
||||
for ($b = 12; $b > $mon; $b--) {
|
||||
$_total_date += $loop_table[$b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$_total_date += $loop_table[$mon] - $day;
|
||||
$_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
|
||||
$_day_time = $_day_power - $_day_time;
|
||||
$ret = -($_total_date * $_day_power + $_day_time - $gmt_different);
|
||||
if ($ret < -12220185600) {
|
||||
// If earlier than 5 Oct 1582 - gregorian correction.
|
||||
return $ret + 10 * 86400;
|
||||
} elseif ($ret < -12219321600) {
|
||||
// If in limbo, reset to 15 Oct 1582.
|
||||
return -12219321600;
|
||||
} else {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -113,8 +113,8 @@ class Horde_RPC_syncml extends Horde_RPC {
|
||||
* that came up for later debugging. */
|
||||
$errorLogging = ob_get_clean();
|
||||
if (!empty($errorLogging)) {
|
||||
#Horde::logMessage('SyncML: caught output=' .
|
||||
# $errorLogging, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML: caught output=' .
|
||||
$errorLogging, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
return $response;
|
||||
|
@ -1,16 +1,14 @@
|
||||
<?php
|
||||
|
||||
require_once 'Horde/Util.php';
|
||||
|
||||
$GLOBALS['_HORDE_STRING_CHARSET'] = 'iso-8859-1';
|
||||
|
||||
/**
|
||||
* The String:: class provides static methods for charset and locale safe
|
||||
* string manipulation.
|
||||
*
|
||||
* $Horde: framework/Util/String.php,v 1.50 2005/02/10 17:09:44 jan Exp $
|
||||
* $Horde: framework/Util/String.php,v 1.43.6.31 2008/10/23 21:28:38 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2005 Jan Schneider <jan@horde.org>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
@ -21,18 +19,40 @@ $GLOBALS['_HORDE_STRING_CHARSET'] = 'iso-8859-1';
|
||||
*/
|
||||
class String {
|
||||
|
||||
/**
|
||||
* Caches the result of extension_loaded() calls.
|
||||
*
|
||||
* @param string $ext The extension name.
|
||||
*
|
||||
* @return boolean Is the extension loaded?
|
||||
*
|
||||
* @see Util::extensionExists()
|
||||
*/
|
||||
function extensionExists($ext)
|
||||
{
|
||||
static $cache = array();
|
||||
|
||||
if (!isset($cache[$ext])) {
|
||||
$cache[$ext] = extension_loaded($ext);
|
||||
}
|
||||
|
||||
return $cache[$ext];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default charset that the String:: methods will use if none is
|
||||
* explicitely specified.
|
||||
* explicitly specified.
|
||||
*
|
||||
* @param string $charset The charset to use as the default one.
|
||||
*/
|
||||
function setDefaultCharset($charset)
|
||||
{
|
||||
$GLOBALS['_HORDE_STRING_CHARSET'] = $charset;
|
||||
if (Util::extensionExists('mbstring') &&
|
||||
if (String::extensionExists('mbstring') &&
|
||||
function_exists('mb_regex_encoding')) {
|
||||
@mb_regex_encoding($charset);
|
||||
$old_error = error_reporting(0);
|
||||
mb_regex_encoding(String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,44 +64,53 @@ class String {
|
||||
* The original string is returned if conversion failed or none
|
||||
* of the extensions were available.
|
||||
*
|
||||
* @param mixed $input The data to be converted. If $input is an an
|
||||
* array, the array's values get converted
|
||||
* recursively.
|
||||
* @param string $from The string's current charset.
|
||||
* @param string $to The charset to convert the string to. If not
|
||||
* specified, the global variable
|
||||
* $_HORDE_STRING_CHARSET will be used.
|
||||
* @param bool $recursion Internally used.
|
||||
* @param mixed $input The data to be converted. If $input is an an array,
|
||||
* the array's values get converted recursively.
|
||||
* @param string $from The string's current charset.
|
||||
* @param string $to The charset to convert the string to. If not
|
||||
* specified, the global variable
|
||||
* $_HORDE_STRING_CHARSET will be used.
|
||||
*
|
||||
* @return string The converted string.
|
||||
* @return mixed The converted input data.
|
||||
*/
|
||||
function convertCharset($input, $from, $to = null, $recursion = false)
|
||||
function convertCharset($input, $from, $to = null)
|
||||
{
|
||||
/* Don't bother converting numbers. */
|
||||
if (is_numeric($input)) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
/* Get the user's default character set if none passed in. */
|
||||
if (is_null($to)) {
|
||||
$to = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
|
||||
/* If the from and to character sets are identical, return now. */
|
||||
if (!$recursion) {
|
||||
$from = String::lower($from);
|
||||
$to = String::lower($to);
|
||||
}
|
||||
$from = String::lower($from);
|
||||
$to = String::lower($to);
|
||||
if ($from == $to) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
if (is_array($input)) {
|
||||
$tmp = array();
|
||||
foreach ($input as $key => $val) {
|
||||
$tmp[String::convertCharset($key, $from, $to, true)] = String::convertCharset($val, $from, $to, true);
|
||||
while (list($key, $val) = each($input)) {
|
||||
$tmp[String::_convertCharset($key, $from, $to)] = String::convertCharset($val, $from, $to);
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
if (is_object($input)) {
|
||||
// PEAR_Error objects are almost guaranteed to contain recursion,
|
||||
// which will cause a segfault in PHP. We should never reach
|
||||
// this line, but add a check and a log message to help the devs
|
||||
// track down and fix this issue.
|
||||
if (is_a($input, 'PEAR_Error')) {
|
||||
Horde::logMessage('Called convertCharset() on a PEAR_Error object. ' . print_r($input, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return '';
|
||||
}
|
||||
$vars = get_object_vars($input);
|
||||
foreach ($vars as $key => $val) {
|
||||
$input->$key = String::convertCharset($val, $from, $to, true);
|
||||
while (list($key, $val) = each($vars)) {
|
||||
$input->$key = String::convertCharset($val, $from, $to);
|
||||
}
|
||||
return $input;
|
||||
}
|
||||
@ -90,43 +119,62 @@ class String {
|
||||
return $input;
|
||||
}
|
||||
|
||||
$output = false;
|
||||
return String::_convertCharset($input, $from, $to);
|
||||
}
|
||||
|
||||
/* Use utf8_[en|de]code() if possible. */
|
||||
/**
|
||||
* Internal function used to do charset conversion.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param string $input See String::convertCharset().
|
||||
* @param string $from See String::convertCharset().
|
||||
* @param string $to See String::convertCharset().
|
||||
*
|
||||
* @return string The converted string.
|
||||
*/
|
||||
function _convertCharset($input, $from, $to)
|
||||
{
|
||||
$output = '';
|
||||
$from_check = (($from == 'iso-8859-1') || ($from == 'us-ascii'));
|
||||
if ($from_check && ($to == 'utf-8')) {
|
||||
return utf8_encode($input);
|
||||
}
|
||||
|
||||
$to_check = (($to == 'iso-8859-1') || ($to == 'us-ascii'));
|
||||
if (($from == 'utf-8') && $to_check) {
|
||||
return utf8_decode($input);
|
||||
|
||||
/* Use utf8_[en|de]code() if possible and if the string isn't too
|
||||
* large (less than 16 MB = 16 * 1024 * 1024 = 16777216 bytes) - these
|
||||
* functions use more memory. */
|
||||
if (strlen($input) < 16777216 || !(String::extensionExists('iconv') || String::extensionExists('mbstring'))) {
|
||||
if ($from_check && ($to == 'utf-8')) {
|
||||
return utf8_encode($input);
|
||||
}
|
||||
|
||||
if (($from == 'utf-8') && $to_check) {
|
||||
return utf8_decode($input);
|
||||
}
|
||||
}
|
||||
|
||||
/* First try iconv with transliteration. */
|
||||
if ($from != 'utf7-imap' &&
|
||||
$to != 'utf7-imap' &&
|
||||
Util::extensionExists('iconv')) {
|
||||
ini_set('track_errors', 1);
|
||||
/* We need to tack an extra character temporarily because
|
||||
* of a bug in iconv() if the last character is not a 7
|
||||
* bit ASCII character. */
|
||||
if (($from != 'utf7-imap') &&
|
||||
($to != 'utf7-imap') &&
|
||||
String::extensionExists('iconv')) {
|
||||
/* We need to tack an extra character temporarily because of a bug
|
||||
* in iconv() if the last character is not a 7 bit ASCII
|
||||
* character. */
|
||||
$oldTrackErrors = ini_set('track_errors', 1);
|
||||
unset($php_errormsg);
|
||||
$output = @iconv($from, $to . '//TRANSLIT', $input . 'x');
|
||||
if (isset($php_errormsg)) {
|
||||
$output = false;
|
||||
} else {
|
||||
$output = String::substr($output, 0, -1, $to);
|
||||
}
|
||||
ini_restore('track_errors');
|
||||
$output = (isset($php_errormsg)) ? false : String::substr($output, 0, -1, $to);
|
||||
ini_set('track_errors', $oldTrackErrors);
|
||||
}
|
||||
|
||||
/* Next try mbstring. */
|
||||
if (!$output && Util::extensionExists('mbstring')) {
|
||||
$output = @mb_convert_encoding($input, $to, $from);
|
||||
if (!$output && String::extensionExists('mbstring')) {
|
||||
$old_error = error_reporting(0);
|
||||
$output = mb_convert_encoding($input, $to, String::_mbstringCharset($from));
|
||||
error_reporting($old_error);
|
||||
}
|
||||
|
||||
/* At last try imap_utf7_[en|de]code if appropriate. */
|
||||
if (!$output && Util::extensionExists('imap')) {
|
||||
if (!$output && String::extensionExists('imap')) {
|
||||
if ($from_check && ($to == 'utf7-imap')) {
|
||||
return @imap_utf7_encode($input);
|
||||
}
|
||||
@ -135,7 +183,7 @@ class String {
|
||||
}
|
||||
}
|
||||
|
||||
return !$output ? $input : $output;
|
||||
return (!$output) ? $input : $output;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,12 +203,14 @@ class String {
|
||||
|
||||
if ($locale) {
|
||||
/* The existence of mb_strtolower() depends on the platform. */
|
||||
if (Util::extensionExists('mbstring') &&
|
||||
if (String::extensionExists('mbstring') &&
|
||||
function_exists('mb_strtolower')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$ret = @mb_strtolower($string, $charset);
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strtolower($string, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
@ -173,7 +223,7 @@ class String {
|
||||
}
|
||||
if (!isset($lowers[$string])) {
|
||||
$language = setlocale(LC_CTYPE, 0);
|
||||
setlocale(LC_CTYPE, 'en_US');
|
||||
setlocale(LC_CTYPE, 'C');
|
||||
$lowers[$string] = strtolower($string);
|
||||
setlocale(LC_CTYPE, $language);
|
||||
}
|
||||
@ -203,7 +253,9 @@ class String {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$ret = @mb_strtoupper($string, $charset);
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strtoupper($string, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
@ -216,7 +268,7 @@ class String {
|
||||
}
|
||||
if (!isset($uppers[$string])) {
|
||||
$language = setlocale(LC_CTYPE, 0);
|
||||
setlocale(LC_CTYPE, 'en_US');
|
||||
setlocale(LC_CTYPE, 'C');
|
||||
$uppers[$string] = strtoupper($string);
|
||||
setlocale(LC_CTYPE, $language);
|
||||
}
|
||||
@ -251,31 +303,34 @@ class String {
|
||||
/**
|
||||
* Returns part of a string.
|
||||
*
|
||||
* @param string $string The string to be converted.
|
||||
* @param int $start The part's start position, zero based.
|
||||
* @param int $length The part's length.
|
||||
* @param string $charset The charset to use when calculating the part's
|
||||
* position and length, defaults to current charset.
|
||||
* @param string $string The string to be converted.
|
||||
* @param integer $start The part's start position, zero based.
|
||||
* @param integer $length The part's length.
|
||||
* @param string $charset The charset to use when calculating the part's
|
||||
* position and length, defaults to current
|
||||
* charset.
|
||||
*
|
||||
* @return string The string's part.
|
||||
*/
|
||||
function substr($string, $start, $length = null, $charset = null)
|
||||
{
|
||||
if (Util::extensionExists('mbstring')) {
|
||||
if (is_null($length)) {
|
||||
$length = String::length($string, $charset) - $start;
|
||||
}
|
||||
if ($length == 0) {
|
||||
return '';
|
||||
}
|
||||
if (String::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
if (is_null($length)) {
|
||||
$length = String::length($string, $charset);
|
||||
}
|
||||
$ret = @mb_substr($string, $start, $length, $charset);
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_substr($string, $start, $length, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
if (is_null($length)) {
|
||||
$length = String::length($string);
|
||||
}
|
||||
return substr($string, $start, $length);
|
||||
}
|
||||
|
||||
@ -290,11 +345,17 @@ class String {
|
||||
*/
|
||||
function length($string, $charset = null)
|
||||
{
|
||||
if (Util::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$ret = @mb_strlen($string, $charset);
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$charset = String::lower($charset);
|
||||
if ($charset == 'utf-8' || $charset == 'utf8') {
|
||||
return strlen(utf8_decode($string));
|
||||
}
|
||||
if (String::extensionExists('mbstring')) {
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strlen($string, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
@ -308,22 +369,24 @@ class String {
|
||||
*
|
||||
* @param string $haystack The string to search through.
|
||||
* @param string $needle The string to search for.
|
||||
* @param int $offset Allows to specify which character in haystack
|
||||
* @param integer $offset Allows to specify which character in haystack
|
||||
* to start searching.
|
||||
* @param string $charset The charset to use when searching for the
|
||||
* $needle string.
|
||||
*
|
||||
* @return int The position of first occurrence.
|
||||
* @return integer The position of first occurrence.
|
||||
*/
|
||||
function pos($haystack, $needle, $offset = 0, $charset = null)
|
||||
{
|
||||
if (Util::extensionExists('mbstring')) {
|
||||
if (String::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
ini_set('track_errors', 1);
|
||||
$ret = @mb_strpos($haystack, $needle, $offset, $charset);
|
||||
ini_restore('track_errors');
|
||||
$track_errors = ini_set('track_errors', 1);
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strpos($haystack, $needle, $offset, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
ini_set('track_errors', $track_errors);
|
||||
if (!isset($php_errormsg)) {
|
||||
return $ret;
|
||||
}
|
||||
@ -337,7 +400,7 @@ class String {
|
||||
* This method behaves exactly like str_pad but is multibyte safe.
|
||||
*
|
||||
* @param string $input The string to be padded.
|
||||
* @param int $length The length of the resulting string.
|
||||
* @param integer $length The length of the resulting string.
|
||||
* @param string $pad The string to pad the input string with. Must
|
||||
* be in the same charset like the input string.
|
||||
* @param const $type The padding type. One of STR_PAD_LEFT,
|
||||
@ -388,22 +451,89 @@ class String {
|
||||
/**
|
||||
* Wraps the text of a message.
|
||||
*
|
||||
* @todo Make multibyte-save.
|
||||
* @since Horde 3.2
|
||||
*
|
||||
* @access public
|
||||
* @param string $string String containing the text to wrap.
|
||||
* @param integer $width Wrap the string at this number of
|
||||
* characters.
|
||||
* @param string $break Character(s) to use when breaking lines.
|
||||
* @param boolean $cut Whether to cut inside words if a line
|
||||
* can't be wrapped.
|
||||
* @param string $charset Character set to use when breaking lines.
|
||||
* @param boolean $line_folding Whether to apply line folding rules per
|
||||
* RFC 822 or similar. The correct break
|
||||
* characters including leading whitespace
|
||||
* have to be specified too.
|
||||
*
|
||||
* @param string $text String containing the text to wrap.
|
||||
* @param optional integer $length Wrap $text at this number of
|
||||
* characters.
|
||||
* @param optional string $break_char Character(s) to use when breaking
|
||||
* lines.
|
||||
* @param optional string $charset Character set to use when breaking
|
||||
* lines.
|
||||
* @param optional boolean $quote Ignore lines that are wrapped with
|
||||
* the '>' character (RFC 2646)? If
|
||||
* true, we don't remove any padding
|
||||
* whitespace at the end of the
|
||||
* string.
|
||||
* @return string String containing the wrapped text.
|
||||
*/
|
||||
function wordwrap($string, $width = 75, $break = "\n", $cut = false,
|
||||
$charset = null, $line_folding = false)
|
||||
{
|
||||
/* Get the user's default character set if none passed in. */
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$charset = String::_mbstringCharset($charset);
|
||||
$string = String::convertCharset($string, $charset, 'utf-8');
|
||||
$wrapped = '';
|
||||
|
||||
while (String::length($string, 'utf-8') > $width) {
|
||||
$line = String::substr($string, 0, $width, 'utf-8');
|
||||
$string = String::substr($string, String::length($line, 'utf-8'), null, 'utf-8');
|
||||
// Make sure didn't cut a word, unless we want hard breaks anyway.
|
||||
if (!$cut && preg_match('/^(.+?)(\s|\r?\n)/u', $string, $match)) {
|
||||
$line .= $match[1];
|
||||
$string = String::substr($string, String::length($match[1], 'utf-8'), null, 'utf-8');
|
||||
}
|
||||
// Wrap at existing line breaks.
|
||||
if (preg_match('/^(.*?)(\r?\n)(.*)$/u', $line, $match)) {
|
||||
$wrapped .= $match[1] . $match[2];
|
||||
$string = $match[3] . $string;
|
||||
continue;
|
||||
}
|
||||
// Wrap at the last colon or semicolon followed by a whitespace if
|
||||
// doing line folding.
|
||||
if ($line_folding &&
|
||||
preg_match('/^(.*?)(;|:)(\s+.*)$/u', $line, $match)) {
|
||||
$wrapped .= $match[1] . $match[2] . $break;
|
||||
$string = $match[3] . $string;
|
||||
continue;
|
||||
}
|
||||
// Wrap at the last whitespace of $line.
|
||||
if ($line_folding) {
|
||||
$sub = '(.+[^\s])';
|
||||
} else {
|
||||
$sub = '(.*)';
|
||||
}
|
||||
if (preg_match('/^' . $sub . '(\s+)(.*)$/u', $line, $match)) {
|
||||
$wrapped .= $match[1] . $break;
|
||||
$string = ($line_folding ? $match[2] : '') . $match[3] . $string;
|
||||
continue;
|
||||
}
|
||||
// Hard wrap if necessary.
|
||||
if ($cut) {
|
||||
$wrapped .= String::substr($line, 0, $width, 'utf-8') . $break;
|
||||
$string = String::substr($line, $width, null, 'utf-8') . $string;
|
||||
continue;
|
||||
}
|
||||
$wrapped .= $line;
|
||||
}
|
||||
|
||||
return String::convertCharset($wrapped . $string, 'utf-8', $charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the text of a message.
|
||||
*
|
||||
* @param string $text String containing the text to wrap.
|
||||
* @param integer $length Wrap $text at this number of characters.
|
||||
* @param string $break_char Character(s) to use when breaking lines.
|
||||
* @param string $charset Character set to use when breaking lines.
|
||||
* @param boolean $quote Ignore lines that are wrapped with the '>'
|
||||
* character (RFC 2646)? If true, we don't
|
||||
* remove any padding whitespace at the end of
|
||||
* the string.
|
||||
*
|
||||
* @return string String containing the wrapped text.
|
||||
*/
|
||||
@ -422,7 +552,7 @@ class String {
|
||||
if ($input != '-- ') {
|
||||
$input = rtrim($input);
|
||||
}
|
||||
$line = wordwrap($input, $length, $break_char);
|
||||
$line = String::wordwrap($input, $length, $break_char, false, $charset);
|
||||
}
|
||||
|
||||
$paragraphs[] = $line;
|
||||
@ -432,9 +562,8 @@ class String {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the every character in the parameter is an
|
||||
* alphabetic character. This method doesn't work with any charset
|
||||
* other than the current charset yet.
|
||||
* Returns true if the every character in the parameter is an alphabetic
|
||||
* character.
|
||||
*
|
||||
* @param $string The string to test.
|
||||
* @param $charset The charset to use when testing the string.
|
||||
@ -443,26 +572,30 @@ class String {
|
||||
*/
|
||||
function isAlpha($string, $charset = null)
|
||||
{
|
||||
if (Util::extensionExists('mbstring')) {
|
||||
$old_charset = mb_regex_encoding();
|
||||
if ($charset != $old_charset) {
|
||||
@mb_regex_encoding($charset);
|
||||
}
|
||||
$alpha = !mb_ereg_match('[^[:alpha:]]', $string);
|
||||
if ($charset != $old_charset) {
|
||||
@mb_regex_encoding($old_charset);
|
||||
}
|
||||
return $alpha;
|
||||
if (!String::extensionExists('mbstring')) {
|
||||
return ctype_alpha($string);
|
||||
}
|
||||
|
||||
return ctype_alpha($string);
|
||||
$charset = String::_mbstringCharset($charset);
|
||||
$old_charset = mb_regex_encoding();
|
||||
$old_error = error_reporting(0);
|
||||
|
||||
if ($charset != $old_charset) {
|
||||
mb_regex_encoding($charset);
|
||||
}
|
||||
$alpha = !mb_ereg_match('[^[:alpha:]]', $string);
|
||||
if ($charset != $old_charset) {
|
||||
mb_regex_encoding($old_charset);
|
||||
}
|
||||
|
||||
error_reporting($old_error);
|
||||
|
||||
return $alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if every character in the parameter is a lowercase
|
||||
* letter in the current locale.
|
||||
*
|
||||
* @access public
|
||||
* Returns true if ever character in the parameter is a lowercase letter in
|
||||
* the current locale.
|
||||
*
|
||||
* @param $string The string to test.
|
||||
* @param $charset The charset to use when testing the string.
|
||||
@ -476,10 +609,8 @@ class String {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if every character in the parameter is an
|
||||
* uppercase letter in the current locale.
|
||||
*
|
||||
* @access public
|
||||
* Returns true if every character in the parameter is an uppercase letter
|
||||
* in the current locale.
|
||||
*
|
||||
* @param string $string The string to test.
|
||||
* @param string $charset The charset to use when testing the string.
|
||||
@ -493,63 +624,59 @@ class String {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a regex match search on the text provided. Will correctly
|
||||
* handle text with multibyte characters if the mbstring extensions and
|
||||
* the mbregex functions are available. Will use the preg_match()
|
||||
* function if possible or if the mbregex ereg function is not available.
|
||||
* Performs a multibyte safe regex match search on the text provided.
|
||||
*
|
||||
* @access public
|
||||
* @since Horde 3.1
|
||||
*
|
||||
* @param string $text The text to search.
|
||||
* @param array $regex The regular expressions to use. These
|
||||
* expressions should conform to ereg() rules -
|
||||
* extended perl rules are NOT supported.
|
||||
* Additionally, do NOT add perl regex delimiters
|
||||
* (e.g. '/' or '|') to the beginning/end.
|
||||
* @param array $regex The regular expressions to use, without perl
|
||||
* regex delimiters (e.g. '/' or '|').
|
||||
* @param string $charset The character set of the text.
|
||||
*
|
||||
* @return array The matches array from the first regex that matches.
|
||||
*/
|
||||
function regexMatch($text, $regex, $charset = null)
|
||||
{
|
||||
static $mbregex;
|
||||
if (!isset($mbregex)) {
|
||||
$mbregex = function_exists('mb_ereg');
|
||||
}
|
||||
|
||||
$use_mb = false;
|
||||
|
||||
if ($mbregex && !is_null($charset) &&
|
||||
(String::lower($charset) != 'utf-8')) {
|
||||
$old_charset = mb_regex_encoding();
|
||||
if ($charset != $old_charset) {
|
||||
@mb_regex_encoding($charset);
|
||||
} else {
|
||||
unset($old_charset);
|
||||
}
|
||||
$use_mb = true;
|
||||
if (!empty($charset)) {
|
||||
$regex = String::convertCharset($regex, $charset, 'utf-8');
|
||||
$text = String::convertCharset($text, $charset, 'utf-8');
|
||||
}
|
||||
|
||||
$matches = array();
|
||||
|
||||
foreach ($regex as $val) {
|
||||
if ($use_mb) {
|
||||
if (mb_ereg($val, $text, $matches)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (preg_match('/' . $val . '/u', $text, $matches)) {
|
||||
break;
|
||||
}
|
||||
if (preg_match('/' . $val . '/u', $text, $matches)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($old_charset)) {
|
||||
@mb_regex_encoding($old_charset);
|
||||
|
||||
if (!empty($charset)) {
|
||||
$matches = String::convertCharset($matches, 'utf-8', $charset);
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround charsets that don't work with mbstring functions.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param string $charset The original charset.
|
||||
*
|
||||
* @return string The charset to use with mbstring functions.
|
||||
*/
|
||||
function _mbstringCharset($charset)
|
||||
{
|
||||
/* mbstring functions do not handle the 'ks_c_5601-1987' &
|
||||
* 'ks_c_5601-1989' charsets. However, these charsets are used, for
|
||||
* example, by various versions of Outlook to send Korean characters.
|
||||
* Use UHC (CP949) encoding instead. See, e.g.,
|
||||
* http://lists.w3.org/Archives/Public/ietf-charsets/2001AprJun/0030.html */
|
||||
if (in_array(String::lower($charset), array('ks_c_5601-1987', 'ks_c_5601-1989'))) {
|
||||
$charset = 'UHC';
|
||||
}
|
||||
|
||||
return $charset;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,32 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3.0
|
||||
*
|
||||
* The Horde_SyncML_SyncHdr and Horde_SyncML_SyncBody classes provides
|
||||
* a SyncHdr and SyncBody in SyncML Representation Protocol, version
|
||||
* 1.1 5.2.2 and 5.2.3. Most of the work is passed on to
|
||||
* Horde_SyncML_Command_Alert and Horde_SyncML_Command_Sync.
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
include_once 'Horde/SyncML/Command/Status.php';
|
||||
include_once 'Horde/SyncML/Command/Alert.php';
|
||||
include_once 'Horde/SyncML/Command/Final.php';
|
||||
include_once 'Horde/SyncML/Command/Sync.php';
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElementItem.php';
|
||||
|
||||
/**
|
||||
* The Horde_SyncML_SyncHdr and Horde_SyncML_SyncBody classes provides
|
||||
* a SyncHdr and SyncBody in SyncML Representation Protocol, version
|
||||
* 1.1 5.2.2 and 5.2.3. Most of the work is passed on to
|
||||
* Horde_SyncML_Command_Alert and Horde_SyncML_Command_Sync.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML.php,v 1.21 2004/07/21 19:26:36 karsten Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
*
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_ContentHandler {
|
||||
|
||||
/**
|
||||
@ -144,41 +144,52 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
|
||||
var $_credType;
|
||||
|
||||
var $_maxMsgSize;
|
||||
|
||||
function getStateFromSession($sourceURI, $locName, $sessionID)
|
||||
{
|
||||
// Remove any existing session since we'll be contructing a
|
||||
// custom session id.
|
||||
session_regenerate_id();
|
||||
session_destroy();
|
||||
|
||||
// we need to (re-)load the eGW session-handler, as session_destroy unloads custom session-handlers
|
||||
if (function_exists('init_session_handler'))
|
||||
{
|
||||
init_session_handler();
|
||||
if (function_exists('init_session_handler')) {
|
||||
init_session_handler();
|
||||
}
|
||||
// Reload the Horde SessionHandler if necessary.
|
||||
|
||||
// Reload the Horde SessionHandler if necessary.
|
||||
Horde::setupSessionHandler();
|
||||
|
||||
// It would seem multisync does not send the user name once it
|
||||
// has been authorized. Make sure we have a valid session id.
|
||||
if(!empty($_GET['syncml_sessionid'])) {
|
||||
session_id($_GET['syncml_sessionid']);
|
||||
Horde::logMessage('SyncML['. session_id() .']: reusing existing session', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() .']: reusing existing session',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
#session_id('syncml' . preg_replace('/[^a-zA-Z0-9]/', '', $sourceURI . $sessionID));
|
||||
session_id('syncml-' . md5(uniqid(rand(), true)));
|
||||
Horde::logMessage('SyncML['. session_id() .']: starting new session for '.$this->_locName, __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
Horde::logMessage('SyncML['. session_id() .']: starting new session for '
|
||||
. $this->_locName, __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
}
|
||||
|
||||
@session_start();
|
||||
|
||||
if (!isset($_SESSION['SyncML.state'])) {
|
||||
// Create a new state if one does not already exist.
|
||||
Horde::logMessage('SyncML['. session_id() .']: create new session state variable', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() .']: create new session state variable for '
|
||||
. $sourceURI, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
# LK $_SESSION['SyncML.state'] = new Horde_SyncML_State($sourceURI, $locName, $sessionID);
|
||||
$_SESSION['SyncML.state'] = new EGW_SyncML_State($sourceURI, $locName, $sessionID);
|
||||
}
|
||||
#if($_SESSION['SyncML.state']->_isAuthorized)
|
||||
# Horde::logMessage('SyncML['. session_id() .']: is session authorized', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
|
||||
if($_SESSION['SyncML.state']->isAuthorized()) {
|
||||
Horde::logMessage('SyncML['. session_id() .']: session is authorized',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
#Horde::logMessage('SyncML['. session_id() . "]:\n" . print_r($_SESSION['SyncML.state'], true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
return $_SESSION['SyncML.state'];
|
||||
}
|
||||
@ -216,18 +227,26 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
#Horde::logMessage('SymcML: SyncHdr done. Try to load state from session.', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state = $this->getStateFromSession($this->_sourceURI, $this->_locName, $this->_sessionID);
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: package '.$this->_msgID.' +++++++++++++++++++++ started', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() .']: package '
|
||||
. $this->_msgID.' +++++++++++++++++++++ started',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->setVersion($this->_version);
|
||||
$state->setMsgID($this->_msgID);
|
||||
$state->setTargetURI($this->_targetURI);
|
||||
$state->setWBXML(is_a($this->_output, 'XML_WBXML_Encoder'));
|
||||
if(isset($this->_credData) && isset($this->_locName) && !$state->isAuthorized())
|
||||
{
|
||||
|
||||
if(isset($this->_credData)
|
||||
&& isset($this->_locName)
|
||||
&& !$state->isAuthorized()) {
|
||||
$state->setPassword($this->_credData);
|
||||
$state->setLocName($this->_locName);
|
||||
}
|
||||
|
||||
if (isset($this->_maxMsgSize)) {
|
||||
$state->setMaxMsgSize($this->_maxMsgSize);
|
||||
}
|
||||
|
||||
#$str = 'authorized=' . $state->isAuthorized();
|
||||
#$str .= ' version=' . $state->getVersion();
|
||||
#$str .= ' msgid=' . $state->getMsgID();
|
||||
@ -246,11 +265,17 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
case 3:
|
||||
if ($element == 'VerProto') {
|
||||
// </VerProto></SyncHdr></SyncML>
|
||||
if (trim($this->_chars) == 'SyncML/1.1') {
|
||||
$this->_version = 1;
|
||||
} else {
|
||||
$this->_version = 0;
|
||||
}
|
||||
switch (strtolower(trim($this->_chars))) {
|
||||
case 'syncml/1.2':
|
||||
$this->_version = 2;
|
||||
break;
|
||||
case 'syncml/1.1':
|
||||
$this->_version = 1;
|
||||
break;
|
||||
default:
|
||||
$this->_version = 0;
|
||||
break;
|
||||
}
|
||||
} elseif ($element == 'SessionID') {
|
||||
// </SessionID></SyncHdr></SyncML>
|
||||
$this->_sessionID = trim($this->_chars);
|
||||
@ -271,8 +296,7 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
|
||||
$tmp = explode(':', $this->_credData, 2);
|
||||
// set only if not set by LocName already
|
||||
if(!isset($this->_locName))
|
||||
{
|
||||
if(!isset($this->_locName)) {
|
||||
$this->_locName = $tmp[0];
|
||||
}
|
||||
$this->_credData = $tmp[1];
|
||||
@ -282,26 +306,34 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_isSource) {
|
||||
// </LocURI></Source></SyncHdr></SyncML>
|
||||
$this->_sourceURI = trim($this->_chars);
|
||||
} else {
|
||||
// </LocURI></Target></SyncHdr></SyncML>
|
||||
$this->_targetURI = trim($this->_chars);
|
||||
}
|
||||
} elseif ($element == 'LocName') {
|
||||
if ($this->_isSource) {
|
||||
// </LocName></Source></SyncHdr></SyncML>
|
||||
$this->_locName = trim($this->_chars);
|
||||
}
|
||||
} elseif ($element == 'Data') {
|
||||
// </Data></Cred></SyncHdr></SyncML>
|
||||
if ($this->_isCred) {
|
||||
$this->_credData = trim($this->_chars);
|
||||
}
|
||||
}
|
||||
break;
|
||||
switch ($element) {
|
||||
case 'LocURI':
|
||||
if ($this->_isSource) {
|
||||
// </LocURI></Source></SyncHdr></SyncML>
|
||||
$this->_sourceURI = trim($this->_chars);
|
||||
} else {
|
||||
// </LocURI></Target></SyncHdr></SyncML>
|
||||
$this->_targetURI = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'LocName':
|
||||
if ($this->_isSource) {
|
||||
// </LocName></Source></SyncHdr></SyncML>
|
||||
$this->_locName = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'Data':
|
||||
// </Data></Cred></SyncHdr></SyncML>
|
||||
if ($this->_isCred) {
|
||||
$this->_credData = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'MaxMsgSize':
|
||||
//</MaxMsgSize></Meta></SyncHdr></SyncML>
|
||||
$this->_maxMsgSize = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if ($this->_isCred) {
|
||||
@ -323,19 +355,31 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
{
|
||||
$attrs = array();
|
||||
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$uri = $state->getURI();
|
||||
$uriMeta = $state->getURIMeta();
|
||||
$output->startElement($uri, 'SyncHdr', $attrs);
|
||||
|
||||
$output->startElement($uri, 'VerDTD', $attrs);
|
||||
$chars = ($this->_version == 1) ? '1.1' : '1.0';
|
||||
if ($this->_version == 2) {
|
||||
$chars = '1.2';
|
||||
} elseif ($this->_version == 1) {
|
||||
$chars = '1.1';
|
||||
} else {
|
||||
$chars = '1.0';
|
||||
}
|
||||
$output->characters($chars);
|
||||
$output->endElement($uri, 'VerDTD');
|
||||
|
||||
$output->startElement($uri, 'VerProto', $attrs);
|
||||
$chars = ($this->_version == 1) ? 'SyncML/1.1' : 'SyncML/1.0';
|
||||
if ($this->_version == 2) {
|
||||
$chars = 'SyncML/1.2';
|
||||
} elseif ($this->_version == 1) {
|
||||
$chars = 'SyncML/1.1';
|
||||
} else {
|
||||
$chars = 'SyncML/1.0';
|
||||
}
|
||||
$output->characters($chars);
|
||||
$output->endElement($uri, 'VerProto');
|
||||
|
||||
@ -359,37 +403,40 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
$output->endElement($uri, 'LocURI');
|
||||
$output->endElement($uri, 'Source');
|
||||
|
||||
if(session_id() != '' && !strpos($this->_targetURI,'syncml_sessionid')) {
|
||||
$output->startElement($uri, 'RespURI', $attrs);
|
||||
if (session_id() != '' && !strpos($this->_targetURI,'syncml_sessionid')) {
|
||||
$output->startElement($uri, 'RespURI', $attrs);
|
||||
|
||||
// some clients don't send the whole URL as targetURI
|
||||
if (strpos($this->_targetURI,$_SERVER['PHP_SELF']) === false) {
|
||||
$output->characters($this->_targetURI . $_SERVER['PHP_SELF'] . '?syncml_sessionid=' . session_id());
|
||||
} else {
|
||||
$output->characters($this->_targetURI . '?syncml_sessionid=' . session_id());
|
||||
// some clients don't send the whole URL as targetURI
|
||||
if (strpos($this->_targetURI,$_SERVER['PHP_SELF']) === false) {
|
||||
$output->characters($this->_targetURI . $_SERVER['PHP_SELF'] . '?syncml_sessionid=' . session_id());
|
||||
} else {
|
||||
$output->characters($this->_targetURI . '?syncml_sessionid=' . session_id());
|
||||
}
|
||||
$output->endElement($uri, 'RespURI');
|
||||
}
|
||||
$output->endElement($uri, 'RespURI');
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
$output->startElement($uri, 'Meta', $attrs);
|
||||
|
||||
// Dummy Max MsqSize, this is just put in to make the packet
|
||||
// work, it is not a real value.
|
||||
if (!($maxMsgSize = $state->getMaxMsgSizeClient())) {
|
||||
// Dummy MaxMsqSize, this is just put in to make the packet
|
||||
// work, it is not our real value.
|
||||
$maxMsgSize = 50000;
|
||||
}
|
||||
$output->startElement($uriMeta, 'MaxMsgSize', $attrs);
|
||||
$chars = '50000';
|
||||
$output->characters($chars);
|
||||
$output->characters($maxMsgSize);
|
||||
$output->endElement($uriMeta, 'MaxMsgSize');
|
||||
|
||||
// Dummy MaxObjSize, this is just put in to make the packet
|
||||
// work, it is not a real value.
|
||||
$output->startElement($uriMeta, 'MaxObjSize', $attrs);
|
||||
$chars = '4000000';
|
||||
$output->characters($chars);
|
||||
$output->endElement($uriMeta, 'MaxObjSize');
|
||||
#// Dummy MaxObjSize, this is just put in to make the packet
|
||||
#// work, it is not our real value.
|
||||
#if ($this->_version > 0) {
|
||||
# // Don't send this to old devices
|
||||
# $output->startElement($uriMeta, 'MaxObjSize', $attrs);
|
||||
# $output->characters('4000000');
|
||||
# $output->endElement($uriMeta, 'MaxObjSize');
|
||||
#}
|
||||
|
||||
$output->endElement($uri, 'Meta');
|
||||
*/
|
||||
|
||||
$output->endElement($uri, 'SyncHdr');
|
||||
}
|
||||
@ -448,26 +495,27 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
|
||||
$this->_actionCommands = false; // so far, we have not seen commands that require action from our side
|
||||
$state->_sendFinal = false;
|
||||
|
||||
// <SyncML><SyncBody>
|
||||
$this->_output->startElement($uri, $element, $attrs);
|
||||
|
||||
if($state->getLocName())
|
||||
{
|
||||
// Right our status about the header.
|
||||
$status = new Horde_SyncML_Command_Status(($state->isAuthorized()) ?
|
||||
RESPONSE_AUTHENTICATION_ACCEPTED : RESPONSE_INVALID_CREDENTIALS, 'SyncHdr');
|
||||
}
|
||||
else
|
||||
{
|
||||
if($state->getLocName()) {
|
||||
if($state->isAuthConfirmed()) {
|
||||
// Right our status about the header
|
||||
$status = new Horde_SyncML_Command_Status(($state->isAuthorized()) ?
|
||||
RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS, 'SyncHdr');
|
||||
} else {
|
||||
// Right our status about the header.
|
||||
$status = new Horde_SyncML_Command_Status(($state->isAuthorized()) ?
|
||||
RESPONSE_AUTHENTICATION_ACCEPTED : RESPONSE_INVALID_CREDENTIALS, 'SyncHdr');
|
||||
}
|
||||
} else {
|
||||
// Request credentials if not sent so far
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_MISSING_CREDENTIALS, 'SyncHdr');
|
||||
}
|
||||
@ -475,6 +523,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
$status->setSourceRef($state->getSourceURI());
|
||||
$status->setTargetRef($state->getTargetURI());
|
||||
$status->setCmdRef(0);
|
||||
$state->clearNumberOfElements();
|
||||
|
||||
/*$str = 'authorized=' . $state->isAuthorized();
|
||||
$str .= ' version=' . $state->getVersion();
|
||||
@ -483,11 +532,12 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
$str .= ' target=' . $state->getTargetURI();
|
||||
*/
|
||||
$this->_currentCmdID = $status->output($this->_currentCmdID, $this->_output);
|
||||
if ($state->isAuthorized()) {
|
||||
$state->AuthConfirmed();
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
// <SyncML><SyncBody><[Command]>
|
||||
#Horde::logMessage('SyncML['. session_id() ."]: found command $element ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$this->_currentCommand = Horde_SyncML_Command::factory($element);
|
||||
@ -497,7 +547,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
// We've got to do something! This can't be the last
|
||||
// packet.
|
||||
$this->_actionCommands = true;
|
||||
Horde::logMessage('SyncML['. session_id() ."]: found action commands <$element> " . $this->_actionCommands, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() ."]: found action commands <$element> ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
switch($element)
|
||||
@ -516,23 +566,29 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element) {
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
// </SyncBody></SyncML>
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: package ----------------------- done', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if($state->getSyncStatus() == CLIENT_SYNC_FINNISHED && $state->getAlert222Received() == true) {
|
||||
$state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED);
|
||||
if ($state->getAlert222Received() == true) {
|
||||
// the Funambol specialty
|
||||
if ($state->getSyncStatus() == CLIENT_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED);
|
||||
}
|
||||
$state->setAlert222Received(false);
|
||||
}
|
||||
|
||||
|
||||
// send the sync reply
|
||||
// we do still have some data to send OR
|
||||
// we should reply to the Sync command
|
||||
if($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED) {
|
||||
if($state->getSyncStatus() > CLIENT_SYNC_FINNISHED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED) {
|
||||
$sync = new Horde_SyncML_Command_Sync();
|
||||
$this->_currentCmdID = $sync->syncToClient($this->_currentCmdID, $this->_output);
|
||||
}
|
||||
@ -546,13 +602,13 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
|
||||
$this->_output->endElement($uri, $element);
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus ' . $state->getSyncStatus() .'actionCommands: '.$this->_actionCommands, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus = '. $state->getSyncStatus() .', actionCommands = '.
|
||||
($this->_actionCommands ? 'True' : 'False'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if (!$this->_actionCommands && $state->getSyncStatus() == SERVER_SYNC_FINNISHED) {
|
||||
// this packet did not contain any real actions, just status and map.
|
||||
// This means, we're through! The session can be closed and
|
||||
// the Anchors saved for the next Sync
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$state->writeSyncSummary();
|
||||
$log = $state->getLog();
|
||||
@ -560,6 +616,9 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
foreach($log as $k => $v) {
|
||||
$s .= " $k=$v";
|
||||
}
|
||||
if (strlen(trim($s)) == 0) {
|
||||
$s = ' Both parties were already in sync';
|
||||
}
|
||||
Horde::logMessage('SyncML['. session_id() .']: summary:' . $s, __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
# Horde::logMessage('SyncML['. session_id() .']: destroying sync session '.session_id(), __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
# // session can be closed here!
|
||||
@ -571,7 +630,6 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
// this packet did not contain any real actions, just status and map.
|
||||
// This means, we're through! The session can be closed and
|
||||
// the Anchors saved for the next Sync
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$state->writeSyncSummary();
|
||||
$log = $state->getLog();
|
||||
@ -579,6 +637,9 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
foreach($log as $k => $v) {
|
||||
$s .= " $k=$v";
|
||||
}
|
||||
if (strlen(trim($s)) == 0) {
|
||||
$s = ' Both parties were already in sync';
|
||||
}
|
||||
Horde::logMessage('SyncML['. session_id() .']: summary:' . $s, __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: destroying sync session '.session_id(), __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
@ -586,75 +647,53 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
session_unset();
|
||||
session_destroy();
|
||||
}
|
||||
if($state->getSyncStatus() == CLIENT_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED);
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus(client sync acknowledged) '.$state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// </[Command]></SyncBody></SyncML>
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
// this should be moved to case 2:
|
||||
if($element == 'Final')
|
||||
{
|
||||
// make sure that we request devinfo, if we not have them already
|
||||
|
||||
/* if(!$state->getClientDeviceInfo())
|
||||
{
|
||||
$attrs = array();
|
||||
$this->_output->startElement($state->getURI(), 'Get', $attrs);
|
||||
$this->_output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$this->_output->characters($this->_currentCmdID);
|
||||
$this->_currentCmdID++;
|
||||
$this->_output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$this->_output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$this->_output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
if(is_a($this->_output, 'XML_WBXML_Encoder'))
|
||||
$this->_output->characters('application/vnd.syncml-devinf+wbxml');
|
||||
else
|
||||
$this->_output->characters('application/vnd.syncml-devinf+xml');
|
||||
$this->_output->endElement($state->getURIMeta(), 'Type');
|
||||
$this->_output->endElement($state->getURI(), 'Meta');
|
||||
|
||||
$this->_output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$this->_output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$this->_output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$this->_output->characters(($state->getVersion() == 0) ? './devinf10' : './devinf11');
|
||||
$this->_output->endElement($state->getURI(), 'LocURI');
|
||||
$this->_output->endElement($state->getURI(), 'Target');
|
||||
$this->_output->endElement($state->getURI(), 'Item');
|
||||
|
||||
$this->_output->endElement($state->getURI(), 'Get');
|
||||
} */
|
||||
}
|
||||
|
||||
$this->_currentCommand->endElement($uri, $element);
|
||||
|
||||
switch($element) {
|
||||
case 'Final':
|
||||
if($state->getSyncStatus() == CLIENT_SYNC_STARTED) {
|
||||
$state->setSyncStatus(CLIENT_SYNC_FINNISHED);
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus(client sync finnished) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
case 'Final':
|
||||
$this->_actionCommands = false;
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
if($state->getSyncStatus() == SERVER_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(SERVER_SYNC_ACKNOWLEDGED);
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus(server sync acknowledged) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
if ($state->getSyncStatus() == CLIENT_SYNC_STARTED) {
|
||||
if (strtolower($deviceInfo['manufacturer']) == 'funambol'
|
||||
&& isset($deviceInfo['softwareVersion'])) {
|
||||
$swversion = $deviceInfo['softwareVersion'];
|
||||
if ($swversion < 1.0) {
|
||||
// e.g. Mozilla plugin uses this range
|
||||
$swversion = $swversion * 10;
|
||||
}
|
||||
if($swversion < 7.0) {
|
||||
// We wait for a ALERT_NEXT_MESSAGE from Funambol clients
|
||||
Horde::logMessage('SyncML['. session_id()
|
||||
. "]: Special treatment for Funambol version $swversion activated",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setSyncStatus(CLIENT_SYNC_FINNISHED);
|
||||
} else {
|
||||
$state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED);
|
||||
}
|
||||
} else {
|
||||
$state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_clientSentFinal = true;
|
||||
#Horde::logMessage('SyncML['. session_id() .']: Sync _syncTag = '. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
if ($state->getSyncStatus() == SERVER_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(SERVER_SYNC_ACKNOWLEDGED);
|
||||
}
|
||||
|
||||
break;
|
||||
$this->_clientSentFinal = true;
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus(server sync acknowledged) '
|
||||
. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->_currentCmdID = $this->_currentCommand->output($this->_currentCmdID, $this->_output);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
$this->_currentCmdID = $this->_currentCommand->output($this->_currentCmdID, $this->_output);
|
||||
break;
|
||||
}
|
||||
|
||||
unset($this->_currentCommand);
|
||||
break;
|
||||
|
@ -1,80 +1,166 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
|
||||
/**
|
||||
* The Horde_SyncML_Command class provides a super class fo SyncBody commands.
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command.php,v 1.4 2004/07/03 15:26:46 chuck Exp $
|
||||
* The SyncML_Command class provides a base class for handling all <SyncBody>
|
||||
* commands.
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* A SyncML command is a protocol primitive. Each SyncML command specifies to
|
||||
* a recipient an individual operation that is to be performed.
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* The SyncML_Command objects are hooked into the XML parser of the
|
||||
* SyncML_ContentHandler class and are reponsible for parsing a single command
|
||||
* inside the SyncBody section of a SyncML message. All actions that must be
|
||||
* executed for a single SyncML command are handled by these objects, by means
|
||||
* of the handleCommand() method.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Jan Schneider <jan@horde.org>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State_egw.php';
|
||||
|
||||
class Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command, like 'Put'.
|
||||
*
|
||||
* Must be overwritten by a sub class.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName;
|
||||
|
||||
/**
|
||||
* The command ID (<CmdID>).
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_cmdID;
|
||||
|
||||
var $_xmlStack;
|
||||
/**
|
||||
* Stack for holding the XML elements during creation of the object from
|
||||
* the XML event flow.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_stack = array();
|
||||
|
||||
var $_chars;
|
||||
/**
|
||||
* Buffer for the parsed character data.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_chars = '';
|
||||
|
||||
function &factory($command, $params = null)
|
||||
/**
|
||||
* Start element handler for the XML parser, delegated from
|
||||
* SyncML_ContentHandler::startElement().
|
||||
*
|
||||
* @param string $uri The namespace URI of the element.
|
||||
* @param string $element The element tag name.
|
||||
* @param array $attrs A hash with the element's attributes.
|
||||
*/
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
include_once 'Horde/SyncML/Command/' . $command . '.php';
|
||||
$class = 'Horde_SyncML_Command_' . $command;
|
||||
if (class_exists($class)) {
|
||||
return $cmd = new $class($params);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Class definition of ' . $class . ' not found.', __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::raiseError('Class definition of ' . $class . ' not found.');
|
||||
}
|
||||
}
|
||||
|
||||
function output($currentCmdID, $output)
|
||||
{
|
||||
}
|
||||
|
||||
function startElement($uri, $localName, $attrs)
|
||||
{
|
||||
$this->_xmlStack++;
|
||||
$this->_stack[] = $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* End element handler for the XML parser, delegated from
|
||||
* SyncML_ContentHandler::endElement().
|
||||
*
|
||||
* @param string $uri The namespace URI of the element.
|
||||
* @param string $element The element tag name.
|
||||
*/
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
if ($element == 'CmdID') {
|
||||
$this->_cmdID = intval(trim($this->_chars));
|
||||
}
|
||||
break;
|
||||
if (count($this->_stack) == 2 &&
|
||||
$element == 'CmdID') {
|
||||
$this->_cmdID = intval(trim($this->_chars));
|
||||
}
|
||||
|
||||
if (isset($this->_chars)) {
|
||||
unset($this->_chars);
|
||||
if (strlen($this->_chars)) {
|
||||
$this->_chars = '';
|
||||
}
|
||||
|
||||
$this->_xmlStack--;
|
||||
array_pop($this->_stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Character data handler for the XML parser, delegated from
|
||||
* SyncML_ContentHandler::characters().
|
||||
*
|
||||
* @param string $str The data string.
|
||||
*/
|
||||
function characters($str)
|
||||
{
|
||||
$tempValue = trim($str);
|
||||
|
||||
if(empty($tempValue)) return;
|
||||
|
||||
if (isset($this->_chars)) {
|
||||
$this->_chars = $this->_chars . $str;
|
||||
$this->_chars .= $str;
|
||||
} else {
|
||||
$this->_chars = $str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command name this instance is reponsible for.
|
||||
*
|
||||
* @return string The command name this object is handling.
|
||||
*/
|
||||
function getCommandName()
|
||||
{
|
||||
return $this->_cmdName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is supposed to implement the actual business logic of the
|
||||
* command once the XML parsing is complete.
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to return a concrete Horde_SyncML_Command instance based on
|
||||
* $command.
|
||||
*
|
||||
* @param string $command The type of the concrete
|
||||
* SyncML_Comment subclass to
|
||||
* return.
|
||||
* @param $params Optional Parameter.
|
||||
*
|
||||
* @return SyncML_Command The newly created concrete SyncML_Command
|
||||
* instance, or false on error.
|
||||
*/
|
||||
function &factory($command, $params = null)
|
||||
{
|
||||
$command = basename($command);
|
||||
$class = 'Horde_SyncML_Command_' . $command;
|
||||
|
||||
if (!class_exists($class)) {
|
||||
include_once 'Horde/SyncML/Command/' . $command . '.php';
|
||||
}
|
||||
if (class_exists($class)) {
|
||||
$cmd = new $class($params);
|
||||
} else {
|
||||
$msg = 'SyncML: Class definition of ' . $class . ' not found.';
|
||||
Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
require_once 'PEAR.php';
|
||||
$cmd = PEAR::raiseError($msg);
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,56 +1,87 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* The Horde_SyncML_Alert class provides a SyncML implementation of
|
||||
* the Alert command as defined in SyncML Representation Protocol,
|
||||
* version 1.1 5.5.2.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command/Alert.php,v 1.18 2004/07/03 15:21:14 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State_egw.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* @var integer $_alert
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Alert';
|
||||
|
||||
/**
|
||||
* The alert type. Should be one of the ALERT_* constants.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_alert;
|
||||
|
||||
/**
|
||||
* @var string $_sourceURI
|
||||
* Source database of the Alert command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceLocURI;
|
||||
|
||||
/**
|
||||
* @var string $_targetURI
|
||||
* Target database of the Alert command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
|
||||
/**
|
||||
* @var string $_metaAnchorNext
|
||||
* Optional parameter for the Target database.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetLocURIParameters;
|
||||
|
||||
/**
|
||||
* The current time this synchronization happens, from the <Meta><Next>
|
||||
* element.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_metaAnchorNext;
|
||||
|
||||
/**
|
||||
* @var integer $_metaAnchorLast
|
||||
* The last time when synchronization happened, from the <Meta><Last>
|
||||
* element.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_metaAnchorLast;
|
||||
|
||||
/**
|
||||
* Use in xml tag.
|
||||
* The filter expression the client provided
|
||||
* (e.g. the time range for calendar synchronization)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_isInSource;
|
||||
var $_filterExpression = '';
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of Alert.
|
||||
@ -64,6 +95,8 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
global $registry;
|
||||
|
||||
$attrs = array();
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
@ -76,323 +109,389 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
|
||||
$clientAnchorNext = $this->_metaAnchorNext;
|
||||
|
||||
if($this->_alert < ALERT_RESULT_ALERT) {
|
||||
if ($this->_alert == ALERT_TWO_WAY ||
|
||||
$this->_alert == ALERT_ONE_WAY_FROM_CLIENT ||
|
||||
$this->_alert == ALERT_ONE_WAY_FROM_SERVER) {
|
||||
// Check if we have information about previous sync.
|
||||
$info = $state->getSyncSummary($this->_targetLocURI);
|
||||
if (is_a($info, 'DataTreeObject')) {
|
||||
$x = $info->get('ClientAnchor');
|
||||
$clientlast = $x[$type];
|
||||
$x = $info->get('ServerAnchor');
|
||||
$serverAnchorLast = $x[$type];
|
||||
} elseif (is_array($info)) {
|
||||
$clientlast = $info['ClientAnchor'];
|
||||
$serverAnchorLast = $info['ServerAnchor'];
|
||||
} else {
|
||||
$clientlast = false;
|
||||
$serverAnchorLast = 0;
|
||||
}
|
||||
$state->setServerAnchorLast($type, $serverAnchorLast);
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
if ($clientlast !== false){
|
||||
// Info about previous successful sync sessions found.
|
||||
Horde::logMessage('SyncML: Previous sync found for target ' . $type
|
||||
. '; client timestamp: ' . $clientlast,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Store client's Next Anchor in State. After successful sync
|
||||
// this is then written to persistence for negotiation of
|
||||
// further syncs.
|
||||
$state->setClientAnchorNext($type, $this->_metaAnchorNext);
|
||||
// Check if anchor sent from client matches our own stored
|
||||
// data.
|
||||
if ($clientlast == $this->_metaAnchorLast) {
|
||||
// Last sync anchors matche, TwoWaySync will do.
|
||||
$anchormatch = true;
|
||||
Horde::logMessage('SyncML: Anchor timestamps match, TwoWaySync possible. Syncing data since '
|
||||
. date('Y-m-d H:i:s', $serverAnchorLast),
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
// Server and client have different anchors, enforce
|
||||
// SlowSync/RefreshSync
|
||||
Horde::logMessage('SyncML: Client requested sync with anchor timestamp '
|
||||
. $this->_metaAnchorLast
|
||||
. ' but server has recorded timestamp '
|
||||
. $clientlast . '. Enforcing SlowSync',
|
||||
__FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$anchormatch = false;
|
||||
$clientlast = 0;
|
||||
}
|
||||
} else {
|
||||
// No info about previous sync, use SlowSync or RefreshSync.
|
||||
Horde::logMessage('SyncML: No info about previous syncs found for device ' .
|
||||
$state->getSourceURI() . ' and target ' . $type,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$clientlast = 0;
|
||||
$serverAnchorLast = 0;
|
||||
$anchormatch = false;
|
||||
}
|
||||
} else {
|
||||
// SlowSync requested, no anchor check required.
|
||||
$anchormatch = true;
|
||||
}
|
||||
|
||||
$info = $state->getSyncSummary($this->_targetLocURI);
|
||||
#Horde::logMessage("SyncML: Anchor match, TwoWaySync sinceee " . $clientlast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (is_a($info, 'DataTreeObject')) {
|
||||
$x = $info->get('ClientAnchor');
|
||||
$clientlast = $x[$type];
|
||||
$x = $info->get('ServerAnchor');
|
||||
$state->setServerAnchorLast($type, $x[$type]);
|
||||
} elseif (is_array($info)) {
|
||||
$clientlast = $info['ClientAnchor'];
|
||||
$state->setServerAnchorLast($type, $info['ServerAnchor']);
|
||||
} else {
|
||||
$clientlast = false;
|
||||
$state->setServerAnchorLast($type, 0);
|
||||
}
|
||||
|
||||
Horde::logMessage('SyncML: checking anchor targetLocURI: clientlast: ' . $clientlast .' / '. $this->_metaAnchorLast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Set Server Anchor for this sync to current time.
|
||||
$state->setServerAnchorNext($type,time());
|
||||
if ($clientlast !== false && $clientlast == $this->_metaAnchorLast) {
|
||||
// Last Sync Anchor matches, TwoWaySync will do.
|
||||
$code = RESPONSE_OK;
|
||||
Horde::logMessage("SyncML: Anchor match, TwoWaySync since " . $clientlast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
Horde::logMessage("SyncML: Anchor mismatch, enforcing SlowSync clientlast $clientlast serverlast ".$this->_metaAnchorLast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Mismatch, enforce slow sync. 508=RESPONSE_REFRESH_REQUIRED 201=ALERT_SLOW_SYNC
|
||||
$this->_alert = 201;
|
||||
$code = 508;
|
||||
// create new synctype
|
||||
$sync = &Horde_SyncML_Sync::factory($this->_alert);
|
||||
$sync->_targetLocURI = $this->_targetLocURI;
|
||||
$sync->_sourceLocURI = $this->_sourceLocURI;
|
||||
if(isset($this->_targetLocURIParameters))
|
||||
$sync->_targetLocURIParameters = $this->_targetLocURIParameters;
|
||||
$state->setSync($this->_targetLocURI, $sync);
|
||||
// PH : no longer delete entire content_map entries for client before SlowSync,
|
||||
// use content_map to verify if content is mapped correctly
|
||||
//$state->removeAllUID($this->_targetLocURI);
|
||||
}
|
||||
// Determine sync type and status response code.
|
||||
Horde::logMessage("SyncML: Alert " . $this->_alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
switch ($this->_alert) {
|
||||
case ALERT_NEXT_MESSAGE:
|
||||
$state->setAlert222Received(true);
|
||||
case ALERT_RESULT_ALERT:
|
||||
case ALERT_NO_END_OF_DATA:
|
||||
// Nothing to do on our side
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
if ($this->_alert == ALERT_NEXT_MESSAGE) {
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setItemSourceLocURI($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
}
|
||||
}
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
return $currentCmdID;
|
||||
case ALERT_TWO_WAY:
|
||||
if ($anchormatch) {
|
||||
$synctype = ALERT_TWO_WAY;
|
||||
$response = RESPONSE_OK;
|
||||
} else {
|
||||
$synctype = ALERT_SLOW_SYNC;
|
||||
$response = RESPONSE_REFRESH_REQUIRED;
|
||||
}
|
||||
break;
|
||||
|
||||
$status = new Horde_SyncML_Command_Status($code, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
case ALERT_SLOW_SYNC:
|
||||
$synctype = ALERT_SLOW_SYNC;
|
||||
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
|
||||
break;
|
||||
|
||||
// Mirror Next Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorNext)) {
|
||||
$status->setItemDataAnchorNext($this->_metaAnchorNext);
|
||||
}
|
||||
case ALERT_ONE_WAY_FROM_CLIENT:
|
||||
if ($anchormatch) {
|
||||
$synctype = ALERT_ONE_WAY_FROM_CLIENT;
|
||||
$response = RESPONSE_OK;
|
||||
} else {
|
||||
$synctype = ALERT_REFRESH_FROM_CLIENT;
|
||||
$response = RESPONSE_REFRESH_REQUIRED;
|
||||
}
|
||||
break;
|
||||
|
||||
// Mirror Last Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorLast)) {
|
||||
$status->setItemDataAnchorLast($this->_metaAnchorLast);
|
||||
}
|
||||
case ALERT_REFRESH_FROM_CLIENT:
|
||||
$synctype = ALERT_REFRESH_FROM_CLIENT;
|
||||
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
// We will erase the current server content,
|
||||
// then we can add the client's contents.
|
||||
|
||||
if ($state->isAuthorized()) {
|
||||
$output->startElement($state->getURI(), 'Alert', $attrs);
|
||||
$hordeType = $state->getHordeType($this->_targetLocURI);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
$state->setTargetURI($this->_targetLocURI);
|
||||
$deletes = $state->getClientItems();
|
||||
if (is_array($deletes)) {
|
||||
foreach ($deletes as $delete) {
|
||||
$registry->call($hordeType . '/delete', array($delete));
|
||||
}
|
||||
Horde::logMessage("SyncML: RefreshFromClient " . count($deletes) . " entries deleted for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
$anchormatch = false;
|
||||
break;
|
||||
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
$chars = $this->_alert;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
case ALERT_ONE_WAY_FROM_SERVER:
|
||||
if ($anchormatch) {
|
||||
$synctype = ALERT_ONE_WAY_FROM_SERVER;
|
||||
$response = RESPONSE_OK;
|
||||
} else {
|
||||
$synctype = ALERT_REFRESH_FROM_SERVER;
|
||||
$response = RESPONSE_REFRESH_REQUIRED;
|
||||
}
|
||||
break;
|
||||
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
case ALERT_REFRESH_FROM_SERVER:
|
||||
$synctype = ALERT_REFRESH_FROM_SERVER;
|
||||
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
|
||||
break;
|
||||
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $this->_sourceLocURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
|
||||
if ($this->_targetLocURI != null) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = (isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
case ALERT_RESUME:
|
||||
// @TODO: Suspend and Resume is not supported yet
|
||||
$synctype = ALERT_SLOW_SYNC;
|
||||
$response = RESPONSE_REFRESH_REQUIRED;
|
||||
break;
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
default:
|
||||
// We can't handle this one
|
||||
Horde::logMessage('SyncML: Unknown sync type ' . $this->_alert,
|
||||
__FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_BAD_REQUEST, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Anchor', $attrs);
|
||||
// Store client's Next Anchor in State and
|
||||
// set server's Next Anchor. After successful sync
|
||||
// this is then written to persistence for negotiation of
|
||||
// further syncs.
|
||||
$state->setClientAnchorNext($type, $this->_metaAnchorNext);
|
||||
$serverAnchorNext = time();
|
||||
$state->setServerAnchorNext($type, $serverAnchorNext);
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Last', $attrs);
|
||||
$chars = $state->getServerAnchorLast($type);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURIMeta(), 'Last');
|
||||
// Now set interval to retrieve server changes from, defined by
|
||||
// ServerAnchor [Last,Next]
|
||||
if ($synctype != ALERT_TWO_WAY &&
|
||||
$synctype != ALERT_ONE_WAY_FROM_CLIENT &&
|
||||
$synctype != ALERT_ONE_WAY_FROM_SERVER) {
|
||||
$serverAnchorLast = 0;
|
||||
#if (!$anchormatch) {
|
||||
// Erase existing map:
|
||||
$state->removeAllUID($this->_targetLocURI);
|
||||
#}
|
||||
}
|
||||
// Now create the actual SyncML_Sync object, if it doesn't exist yet.
|
||||
$sync = &$state->getSync($this->_targetLocURI);
|
||||
if (!$sync) {
|
||||
Horde::logMessage('SyncML: Creating SyncML_Sync object for target '
|
||||
. $this->_targetLocURI . '; sync type ' . $synctype,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$sync = &Horde_SyncML_Sync::factory($synctype);
|
||||
$state->clearConflictItems($this->_targetLocURI);
|
||||
}
|
||||
$sync->setTargetLocURI($this->_targetLocURI);
|
||||
$sync->setSourceLocURI($this->_sourceLocURI);
|
||||
$sync->setLocName($state->getLocName()); // We need it for conflict handling
|
||||
$sync->setsyncType($synctype);
|
||||
$sync->setFilterExpression($this->_filterExpression);
|
||||
$state->setSync($this->_targetLocURI, $sync);
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Next', $attrs);
|
||||
$chars = $state->getServerAnchorNext($type);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURIMeta(), 'Next');
|
||||
$status = new Horde_SyncML_Command_Status($response, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
|
||||
$output->endElement($state->getURIMeta(), 'Anchor');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
$output->endElement($state->getURI(), 'Alert');
|
||||
// Mirror Next Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorNext)) {
|
||||
$status->setItemDataAnchorNext($this->_metaAnchorNext);
|
||||
}
|
||||
|
||||
// still needed? lars
|
||||
$state->_sendFinal = true;
|
||||
|
||||
$currentCmdID++;
|
||||
// Mirror Last Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorLast)) {
|
||||
$status->setItemDataAnchorLast($this->_metaAnchorLast);
|
||||
}
|
||||
|
||||
if($state->_devinfoRequested == false &&
|
||||
$this->_sourceLocURI != null &&
|
||||
is_a($state->getPreferedContentTypeClient($this->_sourceLocURI), 'PEAR_Error')) {
|
||||
|
||||
$output->startElement($state->getURI(), 'Get', $attrs);
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$output->characters($currentCmdID);
|
||||
$currentCmdID++;
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
if(is_a($output, 'XML_WBXML_Encoder')) {
|
||||
$output->characters('application/vnd.syncml-devinf+wbxml');
|
||||
} else {
|
||||
$output->characters('application/vnd.syncml-devinf+xml');
|
||||
}
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters(($state->getVersion() == 0) ? './devinf10' : './devinf11');
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
|
||||
$output->endElement($state->getURI(), 'Get');
|
||||
|
||||
$state->_devinfoRequested = true;
|
||||
}
|
||||
}
|
||||
$output->startElement($state->getURI(), 'Alert', $attrs);
|
||||
|
||||
} elseif ($this->_alert == ALERT_NEXT_MESSAGE) {
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
$status->setItemSourceLocURI($this->_sourceLocURI);
|
||||
$status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$state->setAlert222Received(true);
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
$chars = $synctype;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
|
||||
} else {
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
}
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $this->_sourceLocURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
|
||||
if ($this->_targetLocURI != null) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = (isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Anchor', $attrs);
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Last', $attrs);
|
||||
$chars = $state->getServerAnchorLast($type);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURIMeta(), 'Last');
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Next', $attrs);
|
||||
$chars = $state->getServerAnchorNext($type);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURIMeta(), 'Next');
|
||||
|
||||
$output->endElement($state->getURIMeta(), 'Anchor');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
$output->endElement($state->getURI(), 'Alert');
|
||||
|
||||
// Final packet of this message
|
||||
$state->_sendFinal = true;
|
||||
|
||||
$currentCmdID++;
|
||||
|
||||
if ($state->_devinfoRequested == false &&
|
||||
$this->_sourceLocURI != null &&
|
||||
is_a($state->getPreferedContentTypeClient($this->_sourceLocURI), 'PEAR_Error')) {
|
||||
|
||||
Horde::logMessage("SyncML: PreferedContentTypeClient missing, sending <Get>", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$output->startElement($state->getURI(), 'Get', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$output->characters($currentCmdID);
|
||||
$currentCmdID++;
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
if (is_a($output, 'XML_WBXML_Encoder')) {
|
||||
$output->characters('application/vnd.syncml-devinf+wbxml');
|
||||
} else {
|
||||
$output->characters('application/vnd.syncml-devinf+xml');
|
||||
}
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
if ($state->getVersion() == 2) {
|
||||
$output->characters('./devinf12');
|
||||
} elseif ($state->getVersion() == 1) {
|
||||
$output->characters('./devinf11');
|
||||
} else {
|
||||
$output->characters('./devinf10');
|
||||
}
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
|
||||
$output->endElement($state->getURI(), 'Get');
|
||||
|
||||
$state->_devinfoRequested = true;
|
||||
}
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property sourceURI.
|
||||
* End element handler for the XML parser, delegated from
|
||||
* SyncML_ContentHandler::endElement().
|
||||
*
|
||||
* @param string $sourceURI New value of property sourceURI.
|
||||
* @param string $uri The namespace URI of the element.
|
||||
* @param string $element The element tag name.
|
||||
*/
|
||||
function setSourceLocURI($sourceURI)
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
$this->_sourceLocURI = $sourceURI;
|
||||
}
|
||||
|
||||
function getTargetLocURI()
|
||||
{
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property targetURI.
|
||||
*
|
||||
* @param string $targetURI New value of property targetURI.
|
||||
*/
|
||||
// is this function still used???
|
||||
function setTargetURI($targetURI)
|
||||
{
|
||||
$this->_targetLocURI = $targetURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property targetURI.
|
||||
*
|
||||
* @param string $targetURI New value of property targetURI.
|
||||
*/
|
||||
function setTargetLocURI($targetURI)
|
||||
{
|
||||
$this->_targetLocURI = $targetURI;
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 3:
|
||||
if ($element == 'Target') {
|
||||
$this->_isInSource = false;
|
||||
} else {
|
||||
$this->_isInSource = true;
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'Data') {
|
||||
$this->_alert = intval(trim($this->_chars));
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI') {
|
||||
switch ($this->_stack[2]) {
|
||||
case 'Source':
|
||||
$this->_sourceLocURI = trim($this->_chars);
|
||||
break;
|
||||
case 'Target':
|
||||
$targetLocURIData = explode('?/',trim($this->_chars));
|
||||
|
||||
$this->_targetLocURI = $targetLocURIData[0];
|
||||
|
||||
if (isset($targetLocURIData[1])) {
|
||||
$this->_targetLocURIParameters = $targetLocURIData[1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
switch ($element) {
|
||||
case 'Next':
|
||||
$this->_metaAnchorNext = trim($this->_chars);
|
||||
break;
|
||||
case 'Last':
|
||||
$this->_metaAnchorLast = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
if ($element == 'Data'
|
||||
&& $this->_stack[2] == 'Target'
|
||||
&& $this->_stack[3] == 'Filter'
|
||||
&& $this->_stack[4] == 'Record'
|
||||
&& $this->_stack[5] == 'Item') {
|
||||
$this->_filterExpression = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 1:
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
$sync = $state->getSync($this->_targetLocURI);
|
||||
|
||||
if (!$sync && $this->_alert < ALERT_RESULT_ALERT) {
|
||||
Horde::logMessage('SyncML: create new sync for ' . $this->_targetLocURI . ' ' . $this->_alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$sync = &Horde_SyncML_Sync::factory($this->_alert);
|
||||
|
||||
$sync->_targetLocURI = $this->_targetLocURI;
|
||||
$sync->_sourceLocURI = $this->_sourceLocURI;
|
||||
if(isset($this->_targetLocURIParameters)) {
|
||||
$sync->_targetLocURIParameters = $this->_targetLocURIParameters;
|
||||
}
|
||||
|
||||
$state->setSync($this->_targetLocURI, $sync);
|
||||
|
||||
if($this->_alert == ALERT_SLOW_SYNC || $this->_alert == ALERT_REFRESH_FROM_SERVER) {
|
||||
$state->removeAllUID($this->_targetLocURI);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ($element == 'Data') {
|
||||
$this->_alert = intval(trim($this->_chars));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_isInSource) {
|
||||
$this->_sourceLocURI = trim($this->_chars);
|
||||
} else {
|
||||
$targetLocURIData = explode('?/',trim($this->_chars));
|
||||
|
||||
$this->_targetLocURI = $targetLocURIData[0];
|
||||
|
||||
if(isset($targetLocURIData[1])) {
|
||||
$this->_targetLocURIParameters = $targetLocURIData[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if ($element == 'Next') {
|
||||
$this->_metaAnchorNext = trim($this->_chars);
|
||||
} else if ($element == 'Last') {
|
||||
$this->_metaAnchorLast = trim($this->_chars);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
function getAlert()
|
||||
{
|
||||
return $this->_alert;
|
||||
}
|
||||
|
||||
function setAlert($alert)
|
||||
{
|
||||
$this->_alert = $alert;
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,24 +1,31 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* The Horde_SyncML_Command_Final class.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command/Final.php,v 1.10 2004/05/26 17:41:30 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
class Horde_SyncML_Command_Final extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Final';
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
@ -1,32 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
include_once 'Horde/SyncML/Command/Results.php';
|
||||
|
||||
/**
|
||||
* The Horde_SyncML_Command_Get class.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command/Get.php,v 1.14 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
$ref = ($state->getVersion() == 0) ? './devinf10' : './devinf11';
|
||||
if ($state->getVersion() == 2) {
|
||||
$ref = './devinf12';
|
||||
} elseif ($state->getVersion() == 1) {
|
||||
$ref = './devinf11';
|
||||
} else {
|
||||
$ref = './devinf10';
|
||||
}
|
||||
|
||||
$status = new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), 'Get');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
@ -74,7 +79,13 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'DevInf', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'VerDTD', $attrs);
|
||||
$output->characters(($state->getVersion() == 0) ? '1.0' : '1.1');
|
||||
if ($state->getVersion() == 2) {
|
||||
$output->characters('1.2');
|
||||
} elseif($state->getVersion() == 1) {
|
||||
$output->characters('1.1');
|
||||
} else {
|
||||
$output->characters('1.0');
|
||||
}
|
||||
$output->endElement($state->getURIDevInf() , 'VerDTD', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'Man', $attrs);
|
||||
$output->characters('www.egroupware.org');
|
||||
@ -85,12 +96,22 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
$output->startElement($state->getURIDevInf() , 'DevTyp', $attrs);
|
||||
$output->characters('server');
|
||||
$output->endElement($state->getURIDevInf() , 'DevTyp', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'UTC', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'UTC', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SupportNumberOfChanges', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'SupportNumberOfChanges', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SupportLargeObjs', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'SupportLargeObjs', $attrs);
|
||||
$this->_writeDataStore('./notes', 'text/x-vnote', '1.1', $output,
|
||||
array('text/plain' => '1.0'));
|
||||
$this->_writeDataStore('./contacts', 'text/x-vcard', '2.1', $output);
|
||||
$this->_writeDataStore('./tasks', 'text/x-vcalendar', '1.0', $output);
|
||||
$this->_writeDataStore('./calendar', 'text/x-vcalendar', '1.0', $output);
|
||||
$this->_writeDataStore('./caltasks', 'text/x-vcalendar', '1.0', $output);
|
||||
$this->_writeDataStore('./contacts', 'text/vcard', '3.0', $output,
|
||||
array('text/x-vcard' => '2.1'));
|
||||
$this->_writeDataStore('./tasks', 'text/calendar', '2.0', $output,
|
||||
array('text/x-vcalendar' => '1.0'));
|
||||
$this->_writeDataStore('./calendar', 'text/calendar', '2.0', $output,
|
||||
array('text/x-vcalendar' => '1.0'));
|
||||
$this->_writeDataStore('./caltasks', 'text/calendar', '2.0', $output,
|
||||
array('text/x-vcalendar' => '1.0'));
|
||||
$output->endElement($state->getURIDevInf() , 'DevInf', $attrs);
|
||||
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
@ -111,7 +132,7 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
* @param string $version: data for <(R|T)x-Pref><VerCT>
|
||||
* @param string &$output contenthandler that will received the output.
|
||||
* @param array $additionaltypes: array of additional types for Tx and Rx;
|
||||
* format array('text/vcard' => '2.0')
|
||||
* format array('text/vcard' => '3.0')
|
||||
*/
|
||||
function _writeDataStore($sourceref, $mimetype, $version, &$output,
|
||||
$additionaltypes = false)
|
||||
@ -124,6 +145,9 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
$output->startElement($state->getURIDevInf() , 'SourceRef', $attrs);
|
||||
$output->characters($sourceref);
|
||||
$output->endElement($state->getURIDevInf() , 'SourceRef', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'MaxGUIDSize', $attrs);
|
||||
$output->characters(255);
|
||||
$output->endElement($state->getURIDevInf() , 'MaxGUIDSize', $attrs);
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'Rx-Pref', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'CTType', $attrs);
|
||||
@ -170,12 +194,13 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
}
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'SyncCap', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SyncType', $attrs);
|
||||
$output->characters('1');
|
||||
$output->endElement($state->getURIDevInf() , 'SyncType', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SyncType', $attrs);
|
||||
$output->characters('2');
|
||||
$output->endElement($state->getURIDevInf() , 'SyncType', $attrs);
|
||||
// We support all sync Types from 1-6: two way, slow, refresh|update
|
||||
// from client|server
|
||||
for ($i = 1; $i <= 6; ++$i) {
|
||||
$output->startElement($state->getURIDevInf(), 'SyncType', $attrs);
|
||||
$output->characters($i);
|
||||
$output->endElement($state->getURIDevInf(), 'SyncType', $attrs);
|
||||
}
|
||||
$output->endElement($state->getURIDevInf() , 'SyncCap', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'DataStore', $attrs);
|
||||
}
|
||||
|
@ -1,43 +1,60 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* The Horde_SyncML_Map class provides a SyncML implementation of
|
||||
* the Map command as defined in SyncML Representation Protocol,
|
||||
* version 1.0.1 5.5.8.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command/Map.php,v 1.1 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2004 Karsten Fourmont <fourmont@gmx.de>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
class Horde_SyncML_Command_Map extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* @var string $_sourceURI
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Map';
|
||||
|
||||
/**
|
||||
* Source database of the Map command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceLocURI;
|
||||
|
||||
/**
|
||||
* @var string $_targetURI
|
||||
* Target database of the Map command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
|
||||
/**
|
||||
* Use in xml tag.
|
||||
* Recipient map item specifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_isInSource;
|
||||
|
||||
var $_mapTarget;
|
||||
|
||||
/**
|
||||
* Originator map item specifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_mapSource;
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
@ -60,76 +77,25 @@ class Horde_SyncML_Command_Map extends Horde_SyncML_Command {
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property sourceURI.
|
||||
*
|
||||
* @param string $sourceURI New value of property sourceURI.
|
||||
*/
|
||||
function setSourceLocURI($sourceURI)
|
||||
{
|
||||
$this->_sourceURI = $sourceURI;
|
||||
}
|
||||
|
||||
function getTargetLocURI()
|
||||
{
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property targetURI.
|
||||
*
|
||||
* @param string $targetURI New value of property targetURI.
|
||||
*/
|
||||
function setTargetURI($targetURI)
|
||||
{
|
||||
$this->_targetURI = $targetURI;
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
if ($element == 'Target') {
|
||||
$this->_isInSource = false;
|
||||
}
|
||||
if ($element == 'Source') {
|
||||
$this->_isInSource = true;
|
||||
}
|
||||
if ($element == 'MapItem') {
|
||||
unset($this->_mapTarget);
|
||||
unset($this->_mapSource);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if ($element == 'Target') {
|
||||
$this->_isInSource = false;
|
||||
}
|
||||
if ($element == 'Source') {
|
||||
$this->_isInSource = true;
|
||||
}
|
||||
break;
|
||||
if (count($this->_stack) == 2 &&
|
||||
$element == 'MapItem') {
|
||||
unset($this->_mapTarget);
|
||||
unset($this->_mapSource);
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 1:
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
$sync = $state->getSync($this->_targetLocURI);
|
||||
|
||||
if (!$sync) {
|
||||
}
|
||||
|
||||
$_SESSION['SyncML.state'] = $state;
|
||||
break;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'MapItem') {
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
$sync = $state->getSync($this->_targetLocURI);
|
||||
if (!$state->isAuthorized()) {
|
||||
Horde::logMessage('SyncML: Not Authorized in the middle of MapItem!', __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
@ -149,26 +115,20 @@ class Horde_SyncML_Command_Map extends Horde_SyncML_Command {
|
||||
|
||||
case 3:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_isInSource) {
|
||||
if ($this->_stack[1] == 'Source') {
|
||||
$this->_sourceLocURI = trim($this->_chars);
|
||||
} else {
|
||||
} elseif ($this->_stack[1] == 'Target') {
|
||||
$targetLocURIData = explode('?/',trim($this->_chars));
|
||||
|
||||
$this->_targetLocURI = $targetLocURIData[0];
|
||||
|
||||
if(isset($targetLocURIData[1]))
|
||||
{
|
||||
$this->_targetLocURIParameters = $targetLocURIData[1];
|
||||
}
|
||||
$this->_targetLocURI = $targetLocURIData[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_isInSource) {
|
||||
if ($this->_stack[2] == 'Source') {
|
||||
$this->_mapSource = trim($this->_chars);
|
||||
} else {
|
||||
} elseif ($this->_stack[2] == 'Target') {
|
||||
$this->_mapTarget = trim($this->_chars);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Put.php,v 1.12 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Put';
|
||||
|
||||
/**
|
||||
* @var string $_manufacturer
|
||||
*/
|
||||
@ -36,6 +44,12 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
|
||||
var $_oem;
|
||||
|
||||
/**
|
||||
* @var array $_deviceInfo
|
||||
*/
|
||||
|
||||
var $_deviceInfo;
|
||||
|
||||
/**
|
||||
* @var string $_softwareVersion
|
||||
*/
|
||||
@ -43,62 +57,63 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
var $_softwareVersion;
|
||||
|
||||
function endElement($uri, $element) {
|
||||
switch ($this->_xmlStack) {
|
||||
switch (count($this->_stack)) {
|
||||
case 5:
|
||||
switch($element) {
|
||||
switch ($element) {
|
||||
case 'DataStore':
|
||||
$this->_deviceInfo['dataStore'][$this->_sourceReference] = array(
|
||||
$this->_deviceInfo['dataStore'][$this->_sourceReference] = array (
|
||||
'maxGUIDSize' => $this->_maxGUIDSize,
|
||||
'rxPreference' => $this->_rxPreference,
|
||||
'txPreference' => $this->_txPreference,
|
||||
'syncCapabilities' => $this->_syncCapabilities,
|
||||
'properties' => $this->_properties,
|
||||
);
|
||||
break;
|
||||
|
||||
|
||||
case 'DevID':
|
||||
$this->_deviceInfo['deviceID'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'DevTyp':
|
||||
$this->_deviceInfo['deviceType'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'FwV':
|
||||
$this->_deviceInfo['firmwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'HwV':
|
||||
$this->_deviceInfo['hardwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'Man':
|
||||
$this->_deviceInfo['manufacturer'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'Mod':
|
||||
$this->_deviceInfo['model'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'OEM':
|
||||
$this->_deviceInfo['oem'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'SwV':
|
||||
$this->_deviceInfo['softwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'SupportLargeObjs':
|
||||
$this->_deviceInfo['supportLargeObjs'] = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'SupportNumberOfChanges':
|
||||
$this->_deviceInfo['supportNumberOfChanges'] = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'UTC':
|
||||
$this->_deviceInfo['UTC'] = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'VerDTD':
|
||||
$this->_deviceInfo['DTDVersion'] = trim($this->_chars);
|
||||
break;
|
||||
@ -109,18 +124,18 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
case 'MaxGUIDSize':
|
||||
$this->_maxGUIDSize = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'Rx-Pref':
|
||||
$this->_rxPreference = array(
|
||||
'contentType' => $this->_contentType,
|
||||
'contentVersion' => $this->_contentVersion,
|
||||
);
|
||||
break;
|
||||
|
||||
|
||||
case 'SourceRef':
|
||||
$this->_sourceReference = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'Tx-Pref':
|
||||
$this->_txPreference = array(
|
||||
'contentType' => $this->_contentType,
|
||||
@ -129,7 +144,7 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 7:
|
||||
switch($element) {
|
||||
case 'CTType':
|
||||
@ -178,87 +193,165 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'SyncType':
|
||||
$this->_syncCapabilities[] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'VerCT':
|
||||
$this->_contentVersion = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Property':
|
||||
if (isset($this->_PropName)) {
|
||||
$this->_properties[$this->_contentType][$this->_contentVersion][$this->_PropName] = array(
|
||||
'Size' => $this->_PropSize,
|
||||
'NoTruncate' => $this->_PropNoTruncate,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
switch($element) {
|
||||
case 'PropName':
|
||||
$this->_PropName = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Size':
|
||||
$this->_PropSize = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'NoTruncate':
|
||||
$this->_PropNoTruncate = true;
|
||||
break;
|
||||
}
|
||||
beak;
|
||||
}
|
||||
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
|
||||
function finalizeDeviceInfo()
|
||||
{
|
||||
// get some more information about the device from out of band data
|
||||
|
||||
$ua = $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
if (preg_match("/^\s*Funambol (.*) (\d+\.\d+\.\d+)\s*$/i", $ua, $matches))
|
||||
{
|
||||
if (!isset($this->_deviceInfo['manufacturer']))
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
if (!isset($this->_deviceInfo['model']))
|
||||
$this->_deviceInfo['model'] = 'Funambol ' . trim($matches[1]);
|
||||
if (!isset($this->_deviceInfo['softwareVersion']))
|
||||
$this->_deviceInfo['softwareVersion'] = $matches[2];
|
||||
if (preg_match("/^\s*Funambol (.*) [^\d]*(\d+\.?\d*)[\.|\d]*\s*$/i", $ua, $matches)) {
|
||||
// Funambol uses the hardware Manufacturer we don't care about
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
$this->_deviceInfo['model'] = trim($matches[1]);
|
||||
$this->_deviceInfo['softwareVersion'] = floatval($matches[2]);
|
||||
|
||||
if (!isset($this->_deviceInfo['deviceType']))
|
||||
{
|
||||
switch (strtolower(trim($matches[1])))
|
||||
{
|
||||
case 'outlook plug-in':
|
||||
default:
|
||||
$this->_deviceInfo['deviceType'] = 'workstation';
|
||||
break;
|
||||
if (!isset($this->_deviceInfo['deviceType'])) {
|
||||
switch (strtolower(trim($matches[1]))) {
|
||||
case 'pocket pc plug-in':
|
||||
$this->_deviceInfo['deviceType'] = 'windowsmobile';
|
||||
break;
|
||||
case 'outlook plug-in':
|
||||
default:
|
||||
$this->_deviceInfo['deviceType'] = 'workstation';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$devid = $this->_deviceInfo['deviceID'];
|
||||
switch (strtolower($devid))
|
||||
{
|
||||
switch (strtolower($this->_deviceInfo['deviceID'])) {
|
||||
case 'fmz-thunderbird-plugin':
|
||||
if (empty($this->_devinceInfo['manufacturer']))
|
||||
if (empty($this->_devinceInfo['manufacturer'])) {
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
if (empty($this->_devinceInfo['model']))
|
||||
}
|
||||
if (empty($this->_devinceInfo['model'])) {
|
||||
$this->_deviceInfo['model'] = 'ThunderBird';
|
||||
if (empty($this->_devinceInfo['softwareVersion']))
|
||||
$this->_deviceInfo['softwareVersion'] = '0.3';
|
||||
}
|
||||
if (empty($this->_devinceInfo['softwareVersion'])) {
|
||||
$this->_deviceInfo['softwareVersion'] = '3.0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (preg_match('/Funambol.*/i', $this->_deviceInfo['manufacturer'])) {
|
||||
$this->_deviceInfo['supportLargeObjs'] = true;
|
||||
}
|
||||
|
||||
switch (strtolower($this->_deviceInfo['manufacturer'])) {
|
||||
case 'sonyericsson':
|
||||
case 'sony ericsson':
|
||||
if (strtolower($this->_deviceInfo['model']) == 'w890i') {
|
||||
$this->_deviceInfo['supportLargeObjs'] = false;
|
||||
}
|
||||
break;
|
||||
case 'synthesis ag':
|
||||
foreach ($this->_deviceInfo['dataStore'] as &$ctype) {
|
||||
$ctype['maxGUIDSize'] = 255;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function output($currentCmdID, &$output ) {
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$status = new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), 'Put');
|
||||
|
||||
$status = new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), $this->_cmdName);
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
$ref = ($state->getVersion() == 0) ? './devinf10' : './devinf11';
|
||||
|
||||
|
||||
if ($state->getVersion() == 2) {
|
||||
$ref = './devinf12';
|
||||
} elseif ($state->getVersion() == 1) {
|
||||
$ref = './devinf11';
|
||||
} else {
|
||||
$ref = './devinf10';
|
||||
}
|
||||
|
||||
$status->setSourceRef($ref);
|
||||
|
||||
|
||||
if($state->isAuthorized()) {
|
||||
$this->finalizeDeviceInfo();
|
||||
|
||||
if(count((array)$this->_deviceInfo) > 0) {
|
||||
$state->setClientDeviceInfo($this->_deviceInfo);
|
||||
$devInfo = $state->getClientDeviceInfo();
|
||||
if (is_array($devInfo['dataStore'])
|
||||
&& $devInfo['softwareVersion'] == $this->_deviceInfo['softwareVersion']) {
|
||||
// merge with existing information
|
||||
$devInfo['dataStore'] =
|
||||
array_merge($devInfo['dataStore'],
|
||||
$this->_deviceInfo['dataStore']);
|
||||
} else {
|
||||
// new device
|
||||
$devInfo = $this->_deviceInfo;
|
||||
}
|
||||
#Horde::logMessage("SyncML: Put DeviceInfo:\n" . print_r($this->_deviceInfo, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setClientDeviceInfo($devInfo);
|
||||
$state->writeClientDeviceInfo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs) {
|
||||
#Horde::logMessage("SyncML: startElement[" . count($this->_stack) . "] $uri $element", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
switch (count($this->_stack)) {
|
||||
case 4:
|
||||
switch ($element) {
|
||||
case 'DataStore':
|
||||
$this->_properties = array();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
switch ($element) {
|
||||
case 'Property':
|
||||
unset($this->_PropName);
|
||||
$this->_PropSize = -1;
|
||||
$this->_PropNoTruncate = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Replace.php,v 1.7 2004/05/26 17:41:30 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Final extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Replace';
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
return $currentCmdID;
|
||||
|
@ -1,291 +1,36 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Results.php,v 1.11 2004/07/02 19:24:44 chuck Exp $
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* The SyncML_Command_Results class provides a SyncML implementation of the
|
||||
* Results command as defined in SyncML Representation Protocol, version 1.1,
|
||||
* section 5.5.12.
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* The Results command is used to return the results of a Search or Get
|
||||
* command. Currently SyncML_Command_Results behaves the same as
|
||||
* SyncML_Command_Put. The only results we get is the same DevInf as for the
|
||||
* Put command.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
class Horde_SyncML_Command_Results extends Horde_SyncML_Command {
|
||||
include_once 'Horde/SyncML/Command/Put.php';
|
||||
|
||||
var $_cmdRef;
|
||||
var $_type;
|
||||
var $_data;
|
||||
var $_locSourceURI;
|
||||
var $_deviceInfo;
|
||||
|
||||
function endElement($uri, $element) {
|
||||
#Horde::logMessage('SyncML: put endelement ' . $element . ' chars ' . $this->_chars, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 5:
|
||||
switch($element) {
|
||||
case 'DataStore':
|
||||
$this->_deviceInfo['dataStore'][$this->_sourceReference] = array (
|
||||
'maxGUIDSize' => $this->_maxGUIDSize,
|
||||
'rxPreference' => $this->_rxPreference,
|
||||
'txPreference' => $this->_txPreference,
|
||||
'syncCapabilities' => $this->_syncCapabilities,
|
||||
);
|
||||
break;
|
||||
|
||||
case 'DevID':
|
||||
$this->_deviceInfo['deviceID'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'DevTyp':
|
||||
$this->_deviceInfo['deviceType'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'FwV':
|
||||
$this->_deviceInfo['firmwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'HwV':
|
||||
$this->_deviceInfo['hardwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Man':
|
||||
$this->_deviceInfo['manufacturer'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Mod':
|
||||
$this->_deviceInfo['model'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'OEM':
|
||||
$this->_deviceInfo['oem'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'SwV':
|
||||
$this->_deviceInfo['softwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'SupportLargeObjs':
|
||||
$this->_deviceInfo['supportLargeObjs'] = true;
|
||||
break;
|
||||
|
||||
case 'SupportNumberOfChanges':
|
||||
$this->_deviceInfo['supportNumberOfChanges'] = true;
|
||||
break;
|
||||
|
||||
case 'UTC':
|
||||
$this->_deviceInfo['UTC'] = true;
|
||||
break;
|
||||
|
||||
case 'VerDTD':
|
||||
$this->_deviceInfo['DTDVersion'] = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
class Horde_SyncML_Command_Results extends Horde_SyncML_Command_Put {
|
||||
|
||||
case 6:
|
||||
switch($element) {
|
||||
case 'MaxGUIDSize':
|
||||
$this->_maxGUIDSize = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Rx-Pref':
|
||||
$this->_rxPreference = array (
|
||||
'contentType' => $this->_contentType,
|
||||
'contentVersion' => $this->_contentVersion,
|
||||
);
|
||||
break;
|
||||
|
||||
case 'SourceRef':
|
||||
$this->_sourceReference = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Tx-Pref':
|
||||
$this->_txPreference = array(
|
||||
'contentType' => $this->_contentType,
|
||||
'contentVersion' => $this->_contentVersion,
|
||||
);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
switch($element) {
|
||||
case 'CTType':
|
||||
$this->_contentType = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'SyncType':
|
||||
$this->_syncCapabilities[] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'VerCT':
|
||||
$this->_contentVersion = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Results';
|
||||
|
||||
function finalizeDeviceInfo()
|
||||
{
|
||||
// get some more information about the device from out of band data
|
||||
|
||||
$ua = $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
if (preg_match("/^\s*Funambol (.*) (\d+\.\d+\.\d+)\s*$/i", $ua, $matches))
|
||||
{
|
||||
if (!isset($this->_deviceInfo['manufacturer']))
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
if (!isset($this->_deviceInfo['model']))
|
||||
$this->_deviceInfo['model'] = 'Funambol ' . trim($matches[1]);
|
||||
if (!isset($this->_deviceInfo['softwareVersion']))
|
||||
$this->_deviceInfo['softwareVersion'] = $matches[2];
|
||||
|
||||
if (!isset($this->_deviceInfo['deviceType']))
|
||||
{
|
||||
switch (strtolower(trim($matches[1])))
|
||||
{
|
||||
case 'outlook plug-in':
|
||||
default:
|
||||
$this->_deviceInfo['deviceType'] = 'workstation';
|
||||
break;
|
||||
case 'pocket pc plug-in':
|
||||
$this->_deviceInfo['deviceType'] = 'windowsmobile';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$devid = $this->_deviceInfo['deviceID'];
|
||||
switch (strtolower($devid))
|
||||
{
|
||||
case 'fmz-thunderbird-plugin':
|
||||
if (empty($this->_devinceInfo['manufacturer']))
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
if (empty($this->_devinceInfo['model']))
|
||||
$this->_deviceInfo['model'] = 'ThunderBird';
|
||||
if (empty($this->_devinceInfo['softwareVersion']))
|
||||
$this->_deviceInfo['softwareVersion'] = '0.3';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function output($currentCmdID, &$output) {
|
||||
if(!isset($this->_locSourceURI)) {
|
||||
#Horde::logMessage('SyncML: BIG TODO!!!!!!!!!!!!!!!!!! parse reply', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$status = new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), 'Results');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
$ref = ($state->getVersion() == 0) ? './devinf10' : './devinf11';
|
||||
|
||||
$status->setSourceRef($ref);
|
||||
|
||||
if($state->isAuthorized()) {
|
||||
$this->finalizeDeviceInfo();
|
||||
if(count((array)$this->_deviceInfo) > 0) {
|
||||
$state->setClientDeviceInfo($this->_deviceInfo);
|
||||
$state->writeClientDeviceInfo();
|
||||
}
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
} else {
|
||||
#Horde::logMessage('SyncML: BIG TODO!!!!!!!!!!!!!!!!!! generate reponse', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
$attrs = array();
|
||||
$output->startElement($state->getURI(), 'Results', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'MsgRef', $attrs);
|
||||
$chars = $state->getMsgID();
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'MsgRef');
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdRef', $attrs);
|
||||
$chars = $this->_cmdRef;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdRef');
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
$output->characters($this->_type);
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $this->_locSourceURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
|
||||
// Need to send this information as opaque data so the WBXML
|
||||
// will understand it.
|
||||
$output->opaque($this->_data);
|
||||
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
|
||||
$output->endElement($state->getURI(), 'Results');
|
||||
|
||||
$currentCmdID++;
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property cmdRef.
|
||||
*
|
||||
* @param string $cmdRef New value of property cmdRef.
|
||||
*/
|
||||
function setCmdRef($cmdRef) {
|
||||
$this->_cmdRef = $cmdRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property Type.
|
||||
*
|
||||
* @param string $type New value of property type.
|
||||
*/
|
||||
function setType($type) {
|
||||
$this->_type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property data.
|
||||
*
|
||||
* @param string $data New value of property data.
|
||||
*/
|
||||
function setData($data) {
|
||||
$this->_data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property locSourceURI.
|
||||
*
|
||||
* @param string $locSourceURI New value of property locSourceURI.
|
||||
*/
|
||||
function setlocSourceURI($locSourceURI) {
|
||||
$this->_locSourceURI = $locSourceURI;
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Status.php,v 1.15 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Status';
|
||||
|
||||
/**
|
||||
* The Response code of the command sent to the client, that this
|
||||
* Status response refers to.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_response;
|
||||
|
||||
/**
|
||||
* The command ID (CmdID) of the command sent to the client, that this
|
||||
* Status response refers to.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_cmdRef;
|
||||
|
||||
/**
|
||||
* Must be present.
|
||||
* The command (Add, Replace, etc) sent to the client, that this Status
|
||||
* response refers to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmd;
|
||||
|
||||
/**
|
||||
* Must if not null (what does this mean?).
|
||||
* The server ID of the sent object, that this Status response refers to.
|
||||
*
|
||||
* This element is optional. If specified, Status response refers to a
|
||||
* single Item in the command sent to the client. It refers to all Items in
|
||||
* the sent command otherwise.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceRef;
|
||||
|
||||
|
||||
/**
|
||||
* The client ID of the sent object, that this Status response refers to.
|
||||
*
|
||||
* This element is optional. If specified, Status response refers to a
|
||||
* single Item in the command sent to the client. It refers to all Items in
|
||||
* the sent command otherwise.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetRef;
|
||||
|
||||
var $_chalMetaFormat;
|
||||
@ -48,6 +87,15 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
|
||||
var $_itemSourceLocURI;
|
||||
|
||||
var $_syncItems;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param integer $response The response code.
|
||||
* @param string $cmd The command sent to the client,
|
||||
* that this Status response refers to.
|
||||
*/
|
||||
function Horde_SyncML_Command_Status($response = null, $cmd = null)
|
||||
{
|
||||
if ($response != null) {
|
||||
@ -61,12 +109,11 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$attrs = array();
|
||||
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
if ($this->_cmd != null) {
|
||||
$attrs = array();
|
||||
$output->startElement($state->getURI(), 'Status', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
@ -174,61 +221,41 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
|
||||
if (isset($this->_itemTargetLocURI) && isset($this->_itemSourceLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
if (isset($this->_syncItems)) {
|
||||
// Support multible items per command
|
||||
foreach ($this->_syncItems as $locURI => &$syncItem) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($locURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
} elseif (isset($this->_itemTargetLocURI) || isset($this->_itemSourceLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemTargetLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemSourceLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
if (isset($this->_itemTargetLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemTargetLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
if (isset($this->_itemSourceLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemSourceLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
|
||||
$output->endElement($state->getURI(), 'Status');
|
||||
|
||||
$currentCmdID++;
|
||||
|
||||
// moredata pending request them
|
||||
/* if($this->_response == RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED) {
|
||||
$output->startElement($state->getURI(), 'Alert', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
$output->characters(ALERT_NEXT_MESSAGE);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
|
||||
if (isset($this->_itemTargetLocURI) && isset($this->_itemSourceLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemTargetLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemSourceLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
|
||||
$output->endElement($state->getURI(), 'Alert');
|
||||
|
||||
$currentCmdID++;
|
||||
} */
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
@ -323,4 +350,14 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
{
|
||||
$this->_itemTargetLocURI = $itemTargetLocURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the the list of handled SyncItems
|
||||
*
|
||||
* @param array $syncItems The Items of the command
|
||||
*/
|
||||
function setSyncItems(&$syncItems)
|
||||
{
|
||||
$this->_syncItems = $syncItems;
|
||||
}
|
||||
}
|
||||
|
@ -1,220 +1,258 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
include_once 'Horde/SyncML/Sync/SlowSync.php';
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromServerSync.php';
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromClientSync.php';
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromServerSync.php';
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromClientSync.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync.php,v 1.17 2004/07/03 15:21:14 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync extends Horde_Syncml_Command {
|
||||
class Horde_SyncML_Command_Sync extends Horde_SyncML_Command {
|
||||
|
||||
var $_isInSource;
|
||||
var $_currentSyncElement;
|
||||
var $_syncElements = array();
|
||||
|
||||
function output($currentCmdID, &$output) {
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$attrs = array();
|
||||
|
||||
Horde::logMessage('SyncML: $this->_targetURI = ' . $this->_targetURI, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_OK, 'Sync');
|
||||
|
||||
// $status->setState($state);
|
||||
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if ($this->_targetURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetURIParameters) ? $this->_targetURI.'?/'.$this->_targetURIParameters : $this->_targetURI));
|
||||
}
|
||||
|
||||
if ($this->_sourceURI != null) {
|
||||
$status->setSourceRef($this->_sourceURI);
|
||||
}
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
|
||||
if($sync = $state->getSync($this->_targetURI)) {
|
||||
$currentCmdID = $sync->startSync($currentCmdID, $output);
|
||||
|
||||
foreach ($this->_syncElements as $element) {
|
||||
$currentCmdID = $sync->nextSyncCommand($currentCmdID, $element, $output);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Sync';
|
||||
|
||||
/**
|
||||
* Source database of the <Sync> command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceURI;
|
||||
|
||||
/**
|
||||
* Target database of the <Sync> command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetURI;
|
||||
|
||||
/**
|
||||
* Optional parameter for the Target.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetURIParameters;
|
||||
|
||||
/**
|
||||
* SyncML_SyncElement object for the currently parsed sync command.
|
||||
*
|
||||
* @var SyncML_SyncElement
|
||||
*/
|
||||
var $_curItem;
|
||||
|
||||
/**
|
||||
* List of all SyncML_SyncElement objects that have parsed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_syncElements = array();
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
Horde::logMessage('SyncML: $this->_targetURI = ' . $this->_targetURI, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_OK, 'Sync');
|
||||
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if ($this->_targetURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetURIParameters) ? $this->_targetURI.'?/'.$this->_targetURIParameters : $this->_targetURI));
|
||||
}
|
||||
|
||||
if ($this->_sourceURI != null) {
|
||||
$status->setSourceRef($this->_sourceURI);
|
||||
}
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
|
||||
if ($sync = &$state->getSync($this->_targetURI)) {
|
||||
$currentCmdID = $sync->startSync($currentCmdID, $output);
|
||||
|
||||
foreach ($this->_syncElements as $element) {
|
||||
$currentCmdID = $sync->nextSyncCommand($currentCmdID, $element, $output);
|
||||
}
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function getTargetURI() {
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'Replace' || $element == 'Add' || $element == 'Delete') {
|
||||
$this->_currentSyncElement = &Horde_SyncML_Command_Sync_SyncElement::factory($element);
|
||||
// $this->_currentSyncElement->setVersion($this->_version);
|
||||
// $this->_currentSyncElement->setCmdRef($this->_cmdID);
|
||||
// $this->_currentSyncElement->setMsgID($this->_msgID);
|
||||
} elseif ($element == 'Target') {
|
||||
$this->_isInSource = false;
|
||||
} else {
|
||||
$this->_isInSource = true;
|
||||
if ($element == 'Replace' ||
|
||||
$element == 'Add' ||
|
||||
$element == 'Delete') {
|
||||
Horde::logMessage("SyncML: sync element $element found", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$this->_curItem = &Horde_SyncML_Command_Sync_SyncElement::factory($element);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($this->_currentSyncElement)) {
|
||||
$this->_currentSyncElement->startElement($uri, $element, $attrs);
|
||||
if (isset($this->_curItem)) {
|
||||
$this->_curItem->startElement($uri, $element, $attrs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// We create a seperate Sync Element for the Sync Data sent
|
||||
// from the Server to the client as we want to process the
|
||||
// client sync information before.
|
||||
|
||||
function syncToClient($currentCmdID, &$output)
|
||||
{
|
||||
Horde::logMessage('SyncML: starting sync to client', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML: starting sync to client', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
if($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED)
|
||||
{
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
$targets = $state->getTargets();
|
||||
Horde::logMessage('SyncML: starting sync to client '.$targets[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$attrs = array();
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
if($state->getSyncStatus() >= CLIENT_SYNC_FINNISHED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED)
|
||||
{
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
$targets = $state->getTargets();
|
||||
foreach($targets as $target)
|
||||
{
|
||||
$sync = $state->getSync($target);
|
||||
|
||||
// make sure that the state reflects what is currently being done
|
||||
$state->_currentSourceURI = $sync->_sourceLocURI;
|
||||
$state->_currentTargetURI = $sync->_targetLocURI;
|
||||
|
||||
$output->startElement($state->getURI(), 'Sync', $attrs);
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$output->characters($currentCmdID);
|
||||
$currentCmdID++;
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $sync->_sourceLocURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
#$chars = $sync->_targetLocURI;
|
||||
$chars = (isset($sync->_targetLocURIParameters) ? $sync->_targetLocURI.'?/'.$sync->_targetLocURIParameters : $sync->_targetLocURI);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
|
||||
if(!$sync->_syncDataLoaded)
|
||||
{
|
||||
$numberOfItems = $sync->loadData();
|
||||
if($deviceInfo['supportNumberOfChanges'])
|
||||
$sync = &$state->getSync($target);
|
||||
Horde::logMessage('SyncML['. session_id() .']: sync alerttype '. $sync->_syncType .' found for target ' . $target, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync->_syncType == ALERT_ONE_WAY_FROM_CLIENT ||
|
||||
$sync->_syncType == ALERT_REFRESH_FROM_CLIENT) {
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: From client Sync, no sync of '. $target .' to client', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->clearSync($target);
|
||||
|
||||
} else if ($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED) {
|
||||
|
||||
Horde::logMessage("SyncML: starting sync to client $target", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$attrs = array();
|
||||
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
|
||||
$output->startElement($state->getURI(), 'Sync', $attrs);
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$output->characters($currentCmdID);
|
||||
$currentCmdID++;
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $sync->_sourceLocURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = (isset($sync->_targetLocURIParameters) ? $sync->_targetLocURI.'?/'.$sync->_targetLocURIParameters : $sync->_targetLocURI);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
|
||||
if(!$sync->_syncDataLoaded)
|
||||
{
|
||||
$output->startElement($state->getURI(), 'NumberOfChanged', $attrs);
|
||||
$output->characters($numberOfItems);
|
||||
$output->endElement($state->getURI(), 'NumberOfChanged');
|
||||
$numberOfItems = $sync->loadData();
|
||||
if($deviceInfo['supportNumberOfChanges'])
|
||||
{
|
||||
$output->startElement($state->getURI(), 'NumberOfChanges', $attrs);
|
||||
$output->characters($numberOfItems);
|
||||
$output->endElement($state->getURI(), 'NumberOfChanges');
|
||||
}
|
||||
}
|
||||
|
||||
$currentCmdID = $sync->endSync($currentCmdID, $output);
|
||||
|
||||
$output->endElement($state->getURI(), 'Sync');
|
||||
|
||||
if (isset($state->curSyncItem) ||
|
||||
$state->getNumberOfElements() === false) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Horde::logMessage("SyncML: Waiting for client ACKNOWLEDGE for $target", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
$currentCmdID = $sync->endSync($currentCmdID, $output);
|
||||
|
||||
$output->endElement($state->getURI(), 'Sync');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// no syncs left
|
||||
if($state->getTargets() === FALSE)
|
||||
if($state->getTargets() === FALSE &&
|
||||
!isset($state->curSyncItem)) {
|
||||
$state->setSyncStatus(SERVER_SYNC_FINNISHED);
|
||||
|
||||
Horde::logMessage('SyncML: syncStatus(server_sync_finnished) '. $state->getSyncStatus, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage('SyncML: syncStatus(syncToClient) = '. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
if (isset($this->_currentSyncElement)) {
|
||||
$this->_currentSyncElement->endElement($uri, $element);
|
||||
if (isset($this->_curItem)) {
|
||||
$this->_curItem->endElement($uri, $element);
|
||||
}
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'Replace' || $element == 'Add' || $element == 'Delete') {
|
||||
$this->_syncElements[] = $this->_currentSyncElement;
|
||||
unset($this->_currentSyncElement);
|
||||
if ($element == 'Replace' ||
|
||||
$element == 'Add' ||
|
||||
$element == 'Delete') {
|
||||
$this->_syncElements[] = &$this->_curItem;
|
||||
unset($this->_curItem);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
if ($element == 'LocURI' && !isset($this->_currentSyncElement)) {
|
||||
if ($this->_isInSource) {
|
||||
if ($element == 'LocURI' && !isset($this->_curItem)) {
|
||||
if ($this->_stack[1] == 'Source') {
|
||||
$this->_sourceURI = trim($this->_chars);
|
||||
$state->_currentSourceURI = $this->_sourceURI;
|
||||
} else {
|
||||
$this->_targetURI = trim($this->_chars);
|
||||
|
||||
} elseif ($this->_stack[1] == 'Target') {
|
||||
$targetURIData = explode('?/',trim($this->_chars));
|
||||
|
||||
$this->_targetURI = $targetURIData[0];
|
||||
$state->_currentTargetURI = $this->_targetURI;
|
||||
|
||||
if(isset($targetURIData[1]))
|
||||
{
|
||||
$this->_targetURIParameters = $targetURIData[1];
|
||||
$state->_currentTargetURIParameters = $this->_targetURIParameters;
|
||||
}
|
||||
|
||||
$this->_targetURI = $targetURIData[0];
|
||||
|
||||
if (isset($targetURIData[1])) {
|
||||
$this->_targetURIParameters = $targetURIData[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function characters($str)
|
||||
{
|
||||
if (isset($this->_currentSyncElement)) {
|
||||
$this->_currentSyncElement->characters($str);
|
||||
if (isset($this->_curItem)) {
|
||||
$this->_curItem->characters($str);
|
||||
} else {
|
||||
if (isset($this->_chars)) {
|
||||
$this->_chars = $this->_chars . $str;
|
||||
$this->_chars .= $str;
|
||||
} else {
|
||||
$this->_chars = $str;
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/Add.php,v 1.10 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_Add extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
|
||||
var $_status = RESPONSE_ITEM_ADDED;
|
||||
@ -24,9 +24,10 @@ class Horde_SyncML_Command_Sync_Add extends Horde_SyncML_Command_Sync_SyncElemen
|
||||
$status = new Horde_SyncML_Command_Status($this->_status, 'Add');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if (isset($this->_luid)) {
|
||||
$status->setSourceRef($this->_luid);
|
||||
if (!empty($this->_items)) {
|
||||
$status->setSyncItems($this->_items);
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
|
@ -1,106 +1,44 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/ContentSyncElement.php,v 1.12 2004/07/02 19:24:44 chuck Exp $
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElementItem.php';
|
||||
|
||||
/**
|
||||
* The content: vcard data, etc.
|
||||
*/
|
||||
var $_content;
|
||||
|
||||
/**
|
||||
* Local to server: our Horde guid.
|
||||
*/
|
||||
var $_locURI;
|
||||
|
||||
var $_targetURI;
|
||||
var $_contentType;
|
||||
|
||||
function setSourceURI($uri)
|
||||
{
|
||||
$this->_locURI = $uri;
|
||||
}
|
||||
|
||||
function getSourceURI()
|
||||
{
|
||||
return $this->_locURI;
|
||||
}
|
||||
|
||||
function setTargetURI($uri)
|
||||
{
|
||||
$this->_targetURI = $uri;
|
||||
}
|
||||
|
||||
function getTargetURI()
|
||||
{
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
function setContentType($c)
|
||||
{
|
||||
$this->_contentType = $c;
|
||||
}
|
||||
|
||||
function setContentFormat($_format)
|
||||
{
|
||||
$this->_contentFormat = $_format;
|
||||
}
|
||||
|
||||
function getContentType()
|
||||
{
|
||||
return $this->_contentType;
|
||||
}
|
||||
|
||||
function getContent()
|
||||
{
|
||||
return $this->_content;
|
||||
}
|
||||
|
||||
function setContent($content)
|
||||
{
|
||||
$this->_content = $content;
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
if ($element == 'Data') {
|
||||
$this->_content = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
class Horde_SyncML_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_Sync_SyncElementItem {
|
||||
|
||||
function outputCommand($currentCmdID, &$output, $command)
|
||||
{
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
$maxMsgSize = $state->getMaxMsgSizeClient();
|
||||
$maxGUIDSize = $state->getMaxGUIDSizeClient();
|
||||
|
||||
if ($this->_moreData) {
|
||||
$command = $this->_command;
|
||||
} else {
|
||||
$this->_command = $command;
|
||||
}
|
||||
|
||||
$attrs = array();
|
||||
$output->startElement($state->getURI(), $command, $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->characters($currentCmdID);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
/*
|
||||
if (isset($this->_contentType)) {
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
@ -108,43 +46,100 @@ class Horde_SyncML_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
}
|
||||
*/
|
||||
if (isset($this->_content) && !$this->_moreData) {
|
||||
$this->_content = trim($this->_content);
|
||||
$this->_contentSize = strlen($this->_content);
|
||||
if (strtolower($this->_contentFormat) == 'b64') {
|
||||
$this->_content = base64_encode($this->_content);
|
||||
}
|
||||
} else {
|
||||
$this->_contentSize = 0;
|
||||
}
|
||||
|
||||
if (isset($this->_content)
|
||||
|| isset($this->_locURI) || isset($this->targetURI)) {
|
||||
// <command><Meta>
|
||||
if ($this->_contentSize || isset($this->_contentType) || isset($this->_contentFormat)) {
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
if (isset($this->_contentType)) {
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
$output->characters($this->_contentType);
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
}
|
||||
if (isset($this->_contentFormat)) {
|
||||
$output->startElement($state->getURIMeta(), 'Format', $attrs);
|
||||
$output->characters($this->_contentFormat);
|
||||
$output->endElement($state->getURIMeta(), 'Format');
|
||||
}
|
||||
if ($this->_contentSize) {
|
||||
$output->startElement($state->getURIMeta(), 'Size', $attrs);
|
||||
$output->characters(($this->_contentSize));
|
||||
$output->endElement($state->getURIMeta(), 'Size');
|
||||
}
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
}
|
||||
|
||||
if (isset($this->_content) || isset($this->_luid) || isset($this->_guid)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
// send only when sending adds
|
||||
if ($this->_locURI != null && (strtolower($command) == 'add')) {
|
||||
|
||||
// <command><Item><Source><LocURI>
|
||||
if (isset($this->_guid)) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = substr($this->_locURI,0,39);
|
||||
$state->setUIDMapping($this->_locURI, $chars);
|
||||
$chars = substr($this->_guid, 0, $maxGUIDSize);
|
||||
$state->setUIDMapping($this->_guid, $chars);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
|
||||
if(isset($this->_contentFormat)) {
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Format', $attrs);
|
||||
$output->characters($this->_contentFormat);
|
||||
$output->endElement($state->getURIMeta(), 'Format');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
}
|
||||
|
||||
if ($this->_targetURI != null) {
|
||||
// <command><Item><Target><LocURI>
|
||||
if (isset($this->_luid)) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $this->_targetURI;
|
||||
$output->characters($chars);
|
||||
$output->characters($this->_luid);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
|
||||
|
||||
// <command><Item><Data>
|
||||
if (isset($this->_content)) {
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
#$chars = '<![CDATA['.$this->_content.']]>';
|
||||
$chars = $this->_content;
|
||||
$output->characters($chars);
|
||||
$currentSize = $output->getOutputSize();
|
||||
Horde::logMessage("SyncML: $command: current = $currentSize, max = $maxMsgSize", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (!$maxMsgSize ||
|
||||
(($currentSize + MIN_MSG_LEFT + $this->_contentSize) <= $maxMsgSize)) {
|
||||
$chars = $this->_content;
|
||||
unset($this->_content);
|
||||
$this->_moreData = false;
|
||||
} else {
|
||||
$sizeLeft = $maxMsgSize - $currentSize - MIN_MSG_LEFT;
|
||||
if ($sizeLeft < 0) {
|
||||
Horde::logMessage("SyncML: $command: split with $currentSize for $maxMsgSize, increase MIN_MSG_LEFT!", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$sizeLeft = 0;
|
||||
}
|
||||
// don't let us loose characters by trimming
|
||||
while (($this->_contentSize > $sizeLeft) &&
|
||||
(strlen(trim(substr($this->_content, $sizeLeft - 1, 2))) < 2)) {
|
||||
Horde::logMessage("SyncML: $command: split at $sizeLeft hit WS!", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$sizeLeft++;
|
||||
}
|
||||
$chars = substr($this->_content, 0, $sizeLeft);
|
||||
$this->_content = substr($this->_content, $sizeLeft, $this->_contentSize - $sizeLeft);
|
||||
Horde::logMessage("SyncML: $command: "
|
||||
. $this->_contentSize . " split at $sizeLeft:\n"
|
||||
. $chars, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$this->_moreData = true;
|
||||
}
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
|
||||
// <command><Item><MoreData/>
|
||||
if ($this->_moreData) {
|
||||
$output->startElement($state->getURI(), 'MoreData', $attrs);
|
||||
$output->endElement($state->getURI(), 'MoreData');
|
||||
}
|
||||
}
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/Delete.php,v 1.9 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_Delete extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
@ -22,8 +22,8 @@ class Horde_SyncML_Command_Sync_Delete extends Horde_SyncML_Command_Sync_SyncEle
|
||||
$status = new Horde_SyncML_Command_Status($this->_status, 'Delete');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if (isset($this->_luid)) {
|
||||
$status->setSourceRef($this->_luid);
|
||||
if (!empty($this->_items)) {
|
||||
$status->setSyncItems($this->_items);
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
|
@ -1,32 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/Replace.php,v 1.9 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_Replace extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
|
||||
function output($currentCmdID, &$output) {
|
||||
$status = new Horde_SyncML_Command_Status($this->_status, 'Replace');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if (isset($this->_luid)) {
|
||||
$status->setSourceRef($this->_luid);
|
||||
}
|
||||
|
||||
#$status->setItemSourceLocURI($this->_sourceLocURI);
|
||||
#$status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
|
||||
|
||||
if (!empty($this->_items)) {
|
||||
$status->setSyncItems($this->_items);
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
|
@ -1,37 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/SyncElement.php,v 1.11 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Copyright 2005-2006 Lars Kneschke <l.kneschke@metaways.de>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_SyncElement extends Horde_SyncML_Command {
|
||||
|
||||
var $_luid;
|
||||
var $_guid;
|
||||
var $_isSource;
|
||||
var $_content;
|
||||
var $_contentSize;
|
||||
var $_contentType;
|
||||
var $_contentFormat;
|
||||
var $_status = RESPONSE_OK;
|
||||
var $_items;
|
||||
|
||||
var $_curItem;
|
||||
var $_items = array();
|
||||
var $_moreData = false;
|
||||
var $_command = false;
|
||||
|
||||
function &factory($command, $params = null) {
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElementItem.php';
|
||||
@include_once 'Horde/SyncML/Command/Sync/' . $command . '.php';
|
||||
|
||||
|
||||
$class = 'Horde_SyncML_Command_Sync_' . $command;
|
||||
|
||||
|
||||
if (class_exists($class)) {
|
||||
#Horde::logMessage('SyncML: Class definition of ' . $class . ' found in SyncElement::factory.', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $element = new $class($params);
|
||||
@ -44,78 +47,122 @@ class Horde_SyncML_Command_Sync_SyncElement extends Horde_SyncML_Command {
|
||||
|
||||
function startElement($uri, $element, $attrs) {
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 3:
|
||||
if ($element == 'Source') {
|
||||
$this->_isSource = true;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
switch (count($this->_stack)) {
|
||||
case 1:
|
||||
$this->_command = $element;
|
||||
break;
|
||||
case 2:
|
||||
if ($element == 'Item') {
|
||||
if (isset($state->curSyncItem)) {
|
||||
// Copy from state in case of <MoreData>.
|
||||
$this->_curItem = &$state->curSyncItem;
|
||||
if (isset($this->_luid) &&
|
||||
($this->_luid != $this->_curItem->_luid)) {
|
||||
Horde::logMessage('SyncML: moreData mismatch for LocURI ' .
|
||||
$this->_curItem->_luid . ' (' . $this->_luid . ')', __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: moreData item found for LocURI ' . $this->_curItem->_luid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
unset($state->curSyncItem);
|
||||
} else {
|
||||
$this->_curItem = new Horde_SyncML_Command_Sync_SyncElementItem();
|
||||
}
|
||||
$this->_moreData = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function endElement($uri, $element) {
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$search = array('/ *\n/','/ *$/m');
|
||||
$replace = array('','');
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
|
||||
switch (count($this->_stack)) {
|
||||
case 1:
|
||||
$this->_command = false;
|
||||
// Need to add sync elements to the Sync method?
|
||||
#error_log('total # of items: '.count($this->_items));
|
||||
#error_log(print_r($this->_items[10], true));
|
||||
break;
|
||||
case 2;
|
||||
if($element == 'Item') {
|
||||
$item = new Horde_SyncML_Command_Sync_SyncElementItem();
|
||||
|
||||
if($this->_luid) {
|
||||
$item->setLocURI($this->_luid);
|
||||
$item->setContent($this->_content);
|
||||
$item->setContentType($this->_contentType);
|
||||
|
||||
$this->_curItem->setLocURI($this->_luid);
|
||||
$this->_curItem->setContentType($this->_contentType);
|
||||
$this->_curItem->setContentFormat($this->_contentFormat);
|
||||
$this->_curItem->setCommand($this->_command);
|
||||
|
||||
if($this->_contentSize)
|
||||
$item->setContentType($this->_contentSize);
|
||||
if($this->_moreData)
|
||||
$item->setMoreData($this->_moreData);
|
||||
|
||||
$this->_items[$this->_luid] = $item;
|
||||
$this->_curItem->setContentSize($this->_contentSize);
|
||||
if($this->_moreData) {
|
||||
$state->curSyncItem = &$this->_curItem;
|
||||
Horde::logMessage('SyncML: moreData item saved for LocURI ' . $this->_curItem->_luid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
if (strtolower($this->_curItem->getContentFormat()) == 'b64') {
|
||||
$content = $this->_curItem->getContent();
|
||||
$content = ($content ? base64_decode($content) : '');
|
||||
$this->_curItem->setContent($content);
|
||||
#Horde::logMessage('SyncML: BASE64 encoded item for LocURI '
|
||||
# . $this->_curItem->_luid . ":\n $content", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
$this->_items[$this->_luid] = $this->_curItem;
|
||||
}
|
||||
}
|
||||
|
||||
unset($this->_content);
|
||||
unset($this->_contentSize);
|
||||
unset($this->_luid);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if ($element == 'Source') {
|
||||
$this->_isSource = false;
|
||||
} elseif ($element == 'Data') {
|
||||
$this->_content = $this->_chars;
|
||||
} elseif ($element == 'MoreData') {
|
||||
$this->_moreData = TRUE;
|
||||
} elseif ($element == 'Type') {
|
||||
if(empty($this->_contentType))
|
||||
$this->_contentType = trim($this->_chars);
|
||||
switch ($element) {
|
||||
case 'Data':
|
||||
$this->_curItem->_content .= $this->_chars;
|
||||
break;
|
||||
case 'MoreData':
|
||||
$this->_moreData = true;
|
||||
break;
|
||||
case 'Type':
|
||||
if(empty($this->_contentType)) {
|
||||
$this->_contentType = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'Format':
|
||||
$this->_contentFormat = strtolower(trim($this->_chars));
|
||||
break;
|
||||
case 'Size':
|
||||
$this->_contentSize = $this->_chars;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI' && $this->_isSource) {
|
||||
$this->_luid = trim($this->_chars);
|
||||
} elseif ($element == 'Type') {
|
||||
$this->_contentType = trim($this->_chars);
|
||||
} elseif ($element == 'Size') {
|
||||
$this->_contentSize = trim($this->_chars);
|
||||
switch ($element) {
|
||||
case 'LocURI':
|
||||
if ($this->_stack[2] == 'Source') {
|
||||
$this->_luid = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'Type':
|
||||
$this->_contentType = trim($this->_chars);
|
||||
break;
|
||||
case 'Format':
|
||||
$this->_contentFormat = strtolower(trim($this->_chars));
|
||||
break;
|
||||
case 'Size':
|
||||
$this->_contentSize = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
function getSyncElementItems() {
|
||||
return (array)$this->_items;
|
||||
}
|
||||
|
||||
function getSyncElementItems() {
|
||||
return (array)$this->_items;
|
||||
}
|
||||
|
||||
function getLocURI()
|
||||
{
|
||||
@ -149,14 +196,17 @@ class Horde_SyncML_Command_Sync_SyncElement extends Horde_SyncML_Command {
|
||||
|
||||
function getContent()
|
||||
{
|
||||
return $this->_content;
|
||||
if ($this->_curItem) {
|
||||
return $this->_curItem->getcontent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function setContent($content)
|
||||
function hasMoreData()
|
||||
{
|
||||
$this->_content = $content;
|
||||
return $this->_moreData;
|
||||
}
|
||||
|
||||
|
||||
function setStatus($_status)
|
||||
{
|
||||
$this->_status = $_status;
|
||||
|
@ -1,67 +1,95 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/SyncElement.php,v 1.11 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Copyright 2005-2006 Lars Kneschke <l.kneschke@metaways.de>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_SyncElementItem {
|
||||
|
||||
var $_luid;
|
||||
var $_guid;
|
||||
var $_content;
|
||||
var $_content = '';
|
||||
var $_contentSize;
|
||||
var $_contentType;
|
||||
var $_contentFormat;
|
||||
var $_command;
|
||||
var $_moreData = false;
|
||||
|
||||
|
||||
function getLocURI() {
|
||||
return $this->_luid;
|
||||
}
|
||||
|
||||
|
||||
function getGUID() {
|
||||
return $this->_guid;
|
||||
}
|
||||
|
||||
|
||||
function getContentType() {
|
||||
return $this->_contentType;
|
||||
}
|
||||
|
||||
|
||||
function getContentFormat() {
|
||||
return $this->_contentFormat;
|
||||
}
|
||||
|
||||
function getContent() {
|
||||
return $this->_content;
|
||||
}
|
||||
|
||||
|
||||
function getContentSize() {
|
||||
if (isset($this->_contentSize)) {
|
||||
return $this->_contentSize;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getCommand() {
|
||||
return $this->_command;
|
||||
}
|
||||
|
||||
function setLocURI($luid) {
|
||||
$this->_luid = $luid;
|
||||
}
|
||||
|
||||
|
||||
function setGUID($guid) {
|
||||
$this->_guid = $guid;
|
||||
}
|
||||
|
||||
function setContent($content) {
|
||||
$this->_content = $content;
|
||||
|
||||
function setContent($_content) {
|
||||
$this->_content = $_content;
|
||||
}
|
||||
|
||||
function setContentSize($_size) {
|
||||
$this->_contentSize = $_size;
|
||||
}
|
||||
|
||||
function setContentType($_contentType) {
|
||||
$this->_contentType = $_contentType;
|
||||
function setContentType($_type) {
|
||||
$this->_contentType = $_type;
|
||||
}
|
||||
|
||||
function setContentFormat($_format) {
|
||||
$this->_contentFormat = $_format;
|
||||
}
|
||||
|
||||
function setMoreData($_status) {
|
||||
$this->_moreData = $_status;
|
||||
}
|
||||
|
||||
function hasMoreData() {
|
||||
return $this->_moreData;
|
||||
}
|
||||
|
||||
function setCommand($_command) {
|
||||
$this->_command = $_command;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
define('ALERT_DISPLAY', 100);
|
||||
|
||||
@ -21,6 +35,10 @@ define('ALERT_RESULT_ALERT', 221);
|
||||
define('ALERT_NEXT_MESSAGE', 222);
|
||||
define('ALERT_NO_END_OF_DATA', 223);
|
||||
|
||||
// Not (really) implemented.
|
||||
define('ALERT_SUSPEND', 224); // New in SyncML 1.2
|
||||
define('ALERT_RESUME', 225); // New in SyncML 1.2
|
||||
|
||||
define('MIME_SYNCML_XML', 'application/vnd.syncml+xml');
|
||||
define('MIME_SYNCML_WBXML', 'application/vnd.syncml+wbxml');
|
||||
|
||||
@ -107,7 +125,7 @@ define('RESPONSE_COMMAND_FAILED', 500);
|
||||
// define('RESPONSE_COMMAND_FAILED', 505);
|
||||
// define('RESPONSE_COMMAND_FAILED', 506);
|
||||
// define('RESPONSE_COMMAND_FAILED', 507);
|
||||
// define('RESPONSE_COMMAND_FAILED', 508);
|
||||
define('RESPONSE_REFRESH_REQUIRED', 508);
|
||||
// define('RESPONSE_COMMAND_FAILED', 509);
|
||||
// define('RESPONSE_COMMAND_FAILED', 510);
|
||||
// define('RESPONSE_COMMAND_FAILED', 511);
|
||||
@ -117,12 +135,15 @@ define('RESPONSE_COMMAND_FAILED', 500);
|
||||
// define('RESPONSE_COMMAND_FAILED', 515);
|
||||
define('RESPONSE_ATOMIC_ROLL_BACK_FAILED', 516);
|
||||
|
||||
define('NAME_SPACE_URI_SYNCML', 'syncml:syncml1.0');
|
||||
define('NAME_SPACE_URI_SYNCML_1_0', 'syncml:syncml1.0');
|
||||
define('NAME_SPACE_URI_SYNCML_1_1', 'syncml:syncml1.1');
|
||||
define('NAME_SPACE_URI_METINF', 'syncml:metinf');
|
||||
define('NAME_SPACE_URI_SYNCML_1_2', 'syncml:syncml1.2');
|
||||
define('NAME_SPACE_URI_METINF_1_0', 'syncml:metinf1.0');
|
||||
define('NAME_SPACE_URI_METINF_1_1', 'syncml:metinf1.1');
|
||||
define('NAME_SPACE_URI_DEVINF', 'syncml:devinf');
|
||||
define('NAME_SPACE_URI_METINF_1_2', 'syncml:metinf1.2');
|
||||
define('NAME_SPACE_URI_DEVINF_1_0', 'syncml:devinf1.0');
|
||||
define('NAME_SPACE_URI_DEVINF_1_1', 'syncml:devinf1.1');
|
||||
define('NAME_SPACE_URI_DEVINF_1_2', 'syncml:devinf1.2');
|
||||
|
||||
define('CLIENT_SYNC_STARTED', 1);
|
||||
define('CLIENT_SYNC_FINNISHED', 2);
|
||||
@ -131,8 +152,18 @@ define('SERVER_SYNC_DATA_PENDING', 4);
|
||||
define('SERVER_SYNC_FINNISHED', 5);
|
||||
define('SERVER_SYNC_ACKNOWLEDGED', 6);
|
||||
|
||||
// conflict management
|
||||
define('CONFLICT_CLIENT_WINNING', 0);
|
||||
define('CONFLICT_SERVER_WINNING', 1);
|
||||
define('CONFLICT_MERGE_DATA', 2);
|
||||
define('CONFLICT_RESOLVED_WITH_DUPLICATE', 3);
|
||||
define('CONFLICT_CLIENT_CHANGES_IGNORED', 4);
|
||||
define('CONFLICT_CLIENT_REFRESH_ENFORCED', 5);
|
||||
|
||||
define('MAX_DATA', 19);
|
||||
define('MAX_ENTRIES', 10);
|
||||
define('MAX_ENTRIES', 10); // default
|
||||
define('MAX_GUID_SIZE', 64);
|
||||
define('MIN_MSG_LEFT', 200); // Overhead
|
||||
|
||||
/**
|
||||
* The Horde_SyncML_State class provides a SyncML state object.
|
||||
@ -148,6 +179,7 @@ define('MAX_ENTRIES', 10);
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @modified Joerg Lehrke <jlehrke@noc.de> 2009/01/20, support all syn types
|
||||
*/
|
||||
class Horde_SyncML_State {
|
||||
|
||||
@ -157,6 +189,10 @@ class Horde_SyncML_State {
|
||||
|
||||
var $_msgID;
|
||||
|
||||
var $_maxMsgSize;
|
||||
|
||||
var $_maxGUIDSize;
|
||||
|
||||
var $_targetURI;
|
||||
|
||||
var $_sourceURI;
|
||||
@ -169,6 +205,8 @@ class Horde_SyncML_State {
|
||||
|
||||
var $_isAuthorized;
|
||||
|
||||
var $_AuthConfirmed;
|
||||
|
||||
var $_uri;
|
||||
|
||||
var $_uriMeta;
|
||||
@ -181,7 +219,7 @@ class Horde_SyncML_State {
|
||||
|
||||
var $_serverAnchorNext = array(); // written to db after successful sync
|
||||
|
||||
var $_clientDeviceInfo = array();
|
||||
var $_clientDeviceInfo;
|
||||
|
||||
// array list of changed items, which need to be synced to the client
|
||||
var $_changedItems;
|
||||
@ -192,8 +230,11 @@ class Horde_SyncML_State {
|
||||
// array list of added items, which need to be synced to the client
|
||||
var $_addedItems;
|
||||
|
||||
// bool flag that we need to more data
|
||||
var $_syncStatus;
|
||||
// array list of items, which need to be refreshed at the client
|
||||
var $_conflictItems;
|
||||
|
||||
// current session status
|
||||
var $_syncStatus = 0;
|
||||
|
||||
var $_log = array();
|
||||
|
||||
@ -208,6 +249,22 @@ class Horde_SyncML_State {
|
||||
*/
|
||||
var $_uidMappings = array();
|
||||
|
||||
/**
|
||||
* Current sync element sent from client.
|
||||
*
|
||||
* Stored in state if one element is split into multiple message packets.
|
||||
*
|
||||
* @var SyncML_SyncElement
|
||||
*/
|
||||
var $curSyncItem;
|
||||
|
||||
/**
|
||||
* Number of sync elements sent to client within current message.
|
||||
*
|
||||
* @var _numberOfElements
|
||||
*/
|
||||
var $_numberOfElements;
|
||||
|
||||
/**
|
||||
* Creates a new instance of Horde_SyncML_State.
|
||||
*/
|
||||
@ -220,7 +277,8 @@ class Horde_SyncML_State {
|
||||
$this->setPassword($password);
|
||||
}
|
||||
|
||||
$this->isAuthorized = false;
|
||||
$this->_isAuthorized = false;
|
||||
$this->_isAuthConfirmed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,7 +292,7 @@ class Horde_SyncML_State {
|
||||
* retrieve the real egw uid for a given send uid
|
||||
*/
|
||||
function getUIDMapping($_sentEgwUid) {
|
||||
if(isset($this->_uidMappings[$_sentEgwUid])) {
|
||||
if(strlen("$_sentEgwUid") && isset($this->_uidMappings[$_sentEgwUid])) {
|
||||
return $this->_uidMappings[$_sentEgwUid];
|
||||
}
|
||||
|
||||
@ -311,6 +369,16 @@ class Horde_SyncML_State {
|
||||
return false;
|
||||
}
|
||||
|
||||
function &getConflictItems($_type)
|
||||
{
|
||||
if(isset($this->_conflictItems[$_type]))
|
||||
{
|
||||
return $this->_conflictItems[$_type];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getMoreDataPending()
|
||||
{
|
||||
return $this->_moreDataPending;
|
||||
@ -321,6 +389,14 @@ class Horde_SyncML_State {
|
||||
return $this->_msgID;
|
||||
}
|
||||
|
||||
function getMaxMsgSizeClient()
|
||||
{
|
||||
if (isset($this->_maxMsgSize)) {
|
||||
return $this->_maxMsgSize;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function setWBXML($wbxml)
|
||||
{
|
||||
$this->_wbxml = $wbxml;
|
||||
@ -341,6 +417,11 @@ class Horde_SyncML_State {
|
||||
$this->_addedItems[$_type] = $_addedItems;
|
||||
}
|
||||
|
||||
function pushAddedItem($_type, $_addedItems)
|
||||
{
|
||||
$this->_addedItems[$_type] = $_addedItems;
|
||||
}
|
||||
|
||||
function setChangedItems($_type, $_changedItems)
|
||||
{
|
||||
$this->_changedItems[$_type] = $_changedItems;
|
||||
@ -356,9 +437,14 @@ class Horde_SyncML_State {
|
||||
$this->_deletedItems[$_type] = $_deletedItems;
|
||||
}
|
||||
|
||||
function setMoreDataPending($_state)
|
||||
function addConflictItem($_type, $_conflict)
|
||||
{
|
||||
$this->_moreDataPending = $_state;
|
||||
$this->_conflictItems[$_type][] = $_conflict;
|
||||
}
|
||||
|
||||
function clearConflictItems($_type)
|
||||
{
|
||||
$this->_conflictItems[$_type] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -370,6 +456,15 @@ class Horde_SyncML_State {
|
||||
$this->_msgID = $msgID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property maxMsgSize.
|
||||
* @param size New value of property maxMsgSize.
|
||||
*/
|
||||
function setMaxMsgSize($size)
|
||||
{
|
||||
$this->_maxMsgSize = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property locName.
|
||||
* @param locName New value of property locName.
|
||||
@ -408,15 +503,20 @@ class Horde_SyncML_State {
|
||||
{
|
||||
$this->_version = $version;
|
||||
|
||||
if ($version == 0) {
|
||||
$this->_uri = NAME_SPACE_URI_SYNCML;
|
||||
$this->_uriMeta = NAME_SPACE_URI_METINF;
|
||||
$this->_uriDevInf = NAME_SPACE_URI_DEVINF;
|
||||
} else {
|
||||
if ($version == 2) {
|
||||
$this->_uri = NAME_SPACE_URI_SYNCML_1_2;
|
||||
$this->_uriMeta = NAME_SPACE_URI_METINF_1_2;
|
||||
$this->_uriDevInf = NAME_SPACE_URI_DEVINF_1_2;
|
||||
} elseif ($version == 1) {
|
||||
$this->_uri = NAME_SPACE_URI_SYNCML_1_1;
|
||||
$this->_uriMeta = NAME_SPACE_URI_METINF_1_1;
|
||||
$this->_uriDevInf = NAME_SPACE_URI_DEVINF_1_1;
|
||||
}
|
||||
} else {
|
||||
$this->_uri = NAME_SPACE_URI_SYNCML_1_0;
|
||||
$this->_uriMeta = NAME_SPACE_URI_METINF_1_0;
|
||||
$this->_uriDevInf = NAME_SPACE_URI_DEVINF_1_0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function setSessionID($sessionID)
|
||||
@ -457,6 +557,16 @@ class Horde_SyncML_State {
|
||||
return $this->_isAuthorized;
|
||||
}
|
||||
|
||||
function isAuthConfirmed()
|
||||
{
|
||||
return $this->_AuthConfirmed;
|
||||
}
|
||||
|
||||
function AuthConfirmed()
|
||||
{
|
||||
$this->_AuthConfirmed = true;
|
||||
}
|
||||
|
||||
function clearSync($target)
|
||||
{
|
||||
unset($this->_syncs[$target]);
|
||||
@ -486,6 +596,9 @@ class Horde_SyncML_State {
|
||||
$targets[] = $target;
|
||||
}
|
||||
|
||||
// Make sure we keep the order
|
||||
sort($targets);
|
||||
|
||||
return $targets;
|
||||
}
|
||||
|
||||
@ -502,6 +615,7 @@ class Horde_SyncML_State {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function getURIMeta()
|
||||
{
|
||||
return $this->_uriMeta;
|
||||
@ -548,8 +662,9 @@ class Horde_SyncML_State {
|
||||
* this->_locName . $this->_sourceURI . $type . $locid so you can
|
||||
* have different syncs with different devices. If an entry
|
||||
* already exists, it is overwritten.
|
||||
* Expired entries can be deleted at the next session start.
|
||||
*/
|
||||
function setUID($type, $locid, $guid, $ts=0)
|
||||
function setUID($type, $locid, $guid, $ts=0, $expired=0)
|
||||
{
|
||||
$dt = &$this->getDataTree();
|
||||
|
||||
@ -558,6 +673,7 @@ class Horde_SyncML_State {
|
||||
$gid->set('type', $type);
|
||||
$gid->set('locid', $locid);
|
||||
$gid->set('ts', $ts);
|
||||
$gid->set('expired', $expired);
|
||||
|
||||
$r = $dt->add($gid);
|
||||
if (is_a($r, 'PEAR_Error')) {
|
||||
@ -657,54 +773,41 @@ class Horde_SyncML_State {
|
||||
*/
|
||||
function adjustContentType($type, $target = null)
|
||||
{
|
||||
$ctype;
|
||||
if (is_array($type))
|
||||
{
|
||||
if (is_array($type)) {
|
||||
$ctype = $type['ContentType'];
|
||||
$res = $type;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$ctype = $type;
|
||||
$res = array();
|
||||
$res['ContentType'] = $ctype;
|
||||
}
|
||||
|
||||
$deviceInfo = $this->getClientDeviceInfo();
|
||||
$deviceInfo = $this->getClientDeviceInfo();
|
||||
$manufacturer = isset($deviceInfo['manufacturer']) ? strtolower($deviceInfo['manufacturer']) : 'unknown';
|
||||
switch ($manufacturer) {
|
||||
case 'funambol':
|
||||
switch (strtolower($deviceInfo['model'])) {
|
||||
case 'thunderbird':
|
||||
case 'mozilla plugin':
|
||||
$res['mayFragment'] = 1;
|
||||
break;
|
||||
default:
|
||||
if (isset($deviceInfo['softwareVersion'])
|
||||
&& $deviceInfo['softwareVersion'] < 4.0) {
|
||||
$res['mayFragment'] = 0;
|
||||
} else {
|
||||
$res['mayFragment'] = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$res['mayFragment'] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($deviceInfo['manufacturer']))
|
||||
{
|
||||
switch (strtolower($deviceInfo['manufacturer']))
|
||||
{
|
||||
case 'funambol':
|
||||
if (strtolower($deviceInfo['model']) == 'thunderbird')
|
||||
{
|
||||
$res['mayFragment'] = 1;
|
||||
}
|
||||
|
||||
if (isset($deviceInfo['softwareVersion'])
|
||||
&& $deviceInfo['softwareVersion']{0} == '3')
|
||||
{
|
||||
// anything beyond 6.0 supports fragmentation
|
||||
$res['mayFragment'] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$res['mayFragment'] = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($res['mayFragment']))
|
||||
{
|
||||
$res['mayFragment'] = 1;
|
||||
}
|
||||
|
||||
|
||||
// the funambol specific types need to be encoded in base 64
|
||||
switch(strtolower($ctype))
|
||||
{
|
||||
// the funambol specific types need to be encoded in base64
|
||||
switch (strtolower($ctype)) {
|
||||
case 'text/x-s4j-sifc':
|
||||
case 'text/x-s4j-sife':
|
||||
case 'text/x-s4j-sift':
|
||||
@ -712,17 +815,15 @@ class Horde_SyncML_State {
|
||||
$res['ContentFormat'] = 'b64';
|
||||
break;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function getPreferedContentType($type)
|
||||
{
|
||||
$_type = str_replace('./','',$type);
|
||||
switch(strtolower($_type))
|
||||
{
|
||||
switch (strtolower($_type)) {
|
||||
case 'contacts':
|
||||
return 'text/x-vcard';
|
||||
return 'text/vcard';
|
||||
break;
|
||||
|
||||
case 'notes':
|
||||
@ -730,9 +831,10 @@ class Horde_SyncML_State {
|
||||
break;
|
||||
|
||||
case 'calendar':
|
||||
case 'events':
|
||||
case 'tasks':
|
||||
case 'caltasks':
|
||||
return 'text/x-vcalendar';
|
||||
return 'text/calendar';
|
||||
break;
|
||||
|
||||
case 'sifcalendar':
|
||||
@ -778,6 +880,7 @@ class Horde_SyncML_State {
|
||||
return 'tasks';
|
||||
break;
|
||||
|
||||
case 'events':
|
||||
case 'calendar':
|
||||
return 'calendar';
|
||||
break;
|
||||
@ -815,7 +918,6 @@ class Horde_SyncML_State {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the preferred contenttype of the client for the given
|
||||
* sync data type (database).
|
||||
@ -826,12 +928,33 @@ class Horde_SyncML_State {
|
||||
function getPreferedContentTypeClient($_sourceLocURI, $_targetLocURI = null) {
|
||||
$deviceInfo = $this->getClientDeviceInfo();
|
||||
|
||||
if(isset($deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType']))
|
||||
{
|
||||
return $this->adjustContentType($deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType'], $_targetLocURI);
|
||||
if(isset($deviceInfo['dataStore'][$_sourceLocURI]['maxGUIDSize']['contentType'])) {
|
||||
$this->_maxGUIDSize = $deviceInfo['dataStore'][$this->_sourceURI]['maxGUIDSize']['contentType'];
|
||||
}
|
||||
|
||||
Horde::logMessage('SyncML: sourceLocURI ' . $_sourceLocURI .' not found', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if(isset($deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType']))
|
||||
{
|
||||
$ctype = $deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType'];
|
||||
$cvers = $deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentVersion'];
|
||||
$cfrmt = $deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentFormat'];
|
||||
$cprops = $deviceInfo['dataStore'][$_sourceLocURI]['properties'][$ctype][$cvers];
|
||||
if (isset($deviceInfo['dataStore'][$_sourceLocURI]['maxGUIDSize'])) {
|
||||
// get UID properties from maxGUIDSize
|
||||
$cprops['UID']['Size'] = $deviceInfo['dataStore'][$_sourceLocURI]['maxGUIDSize'];
|
||||
$cprops['UID']['NoTruncate'] = true;
|
||||
}
|
||||
$clientPrefs = array(
|
||||
'ContentType' => $ctype,
|
||||
'ContentFormat' => $cfrmt,
|
||||
'mayFragment' => 1,
|
||||
'Properties' => $cprops,
|
||||
);
|
||||
#Horde::logMessage('SyncML: sourceLocURI ' . $_sourceLocURI . " clientPrefs:\n"
|
||||
# . print_r($clientPrefs, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $this->adjustContentType($clientPrefs, $_targetLocURI);
|
||||
}
|
||||
|
||||
Horde::logMessage('SyncML: sourceLocURI ' . $_sourceLocURI . " not found:\n" . print_r($deviceInfo, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if ($_targetLocURI != null)
|
||||
{
|
||||
@ -841,6 +964,19 @@ class Horde_SyncML_State {
|
||||
return PEAR::raiseError(_('sourceLocURI not found'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MaxGUIDSize of the client
|
||||
*/
|
||||
|
||||
function getMaxGUIDSizeClient() {
|
||||
$maxGUIDSize = MAX_GUID_SIZE;
|
||||
|
||||
if (isset($this->_maxGUIDSize)) {
|
||||
$maxGUIDSize = $this->_maxGUIDSize;
|
||||
}
|
||||
return $maxGUIDSize;
|
||||
}
|
||||
|
||||
function setClientAnchorNext($type, $a)
|
||||
{
|
||||
$this->_clientAnchorNext[$type] = $a;
|
||||
@ -900,6 +1036,11 @@ class Horde_SyncML_State {
|
||||
*/
|
||||
function getClientDeviceInfo()
|
||||
{
|
||||
if (isset($this->_clientDeviceInfo) && is_array($this->_clientDeviceInfo)) {
|
||||
// use cached information
|
||||
return $this->_clientDeviceInfo;
|
||||
}
|
||||
|
||||
$dt = &$this->getDataTree();
|
||||
|
||||
$id = $dt->getId($this->_locName . $this->_sourceURI . 'deviceInfo');
|
||||
@ -907,7 +1048,7 @@ class Horde_SyncML_State {
|
||||
return false;
|
||||
}
|
||||
|
||||
$info = $dt->getObjectById($id);
|
||||
$info = $dt->getObjectById($id);
|
||||
|
||||
return $info->get('ClientDeviceInfo');
|
||||
}
|
||||
@ -1070,4 +1211,23 @@ class Horde_SyncML_State {
|
||||
$this->_receivedAlert222 = (bool)$_status;
|
||||
}
|
||||
|
||||
function incNumberOfElements() {
|
||||
$this->_numberOfElements++;
|
||||
}
|
||||
|
||||
function clearNumberOfElements() {
|
||||
$this->_numberOfElements = 0;
|
||||
}
|
||||
|
||||
function getNumberOfElements() {
|
||||
if (isset($this->_numberOfElements)) {
|
||||
return $this->_numberOfElements;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function maxNumberOfElements() {
|
||||
unset($this->_numberOfElements);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare SyncML
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke
|
||||
* @package syncml
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Lars Kneschke <lkneschke@egroupware.org>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
include_once dirname(__FILE__).'/State.php';
|
||||
|
||||
/**
|
||||
@ -17,45 +21,42 @@ include_once dirname(__FILE__).'/State.php';
|
||||
class EGW_SyncML_State extends Horde_SyncML_State
|
||||
{
|
||||
var $table_devinfo = 'egw_syncmldevinfo';
|
||||
|
||||
|
||||
/*
|
||||
* store the mappings of egw uids to client uids
|
||||
*/
|
||||
var $uidMappings = array();
|
||||
|
||||
|
||||
/**
|
||||
* get the local content id from a syncid
|
||||
*
|
||||
* @param sting $_syncid id used in syncml
|
||||
* @return int local egw content id
|
||||
*/
|
||||
function get_egwID($_syncid)
|
||||
{
|
||||
/**
|
||||
* get the local content id from a syncid
|
||||
*
|
||||
* @param sting $_syncid id used in syncml
|
||||
* @return int local egw content id
|
||||
*/
|
||||
function get_egwID($_syncid) {
|
||||
$syncIDParts = explode('-',$_syncid);
|
||||
array_shift($syncIDParts);
|
||||
$_id = implode ('', $syncIDParts);
|
||||
return $_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* when got a entry last added/modified/deleted
|
||||
*
|
||||
* @param $_syncid containing appName-contentid
|
||||
* @param $_action string can be add, delete or modify
|
||||
* @return string the last timestamp
|
||||
*/
|
||||
function getSyncTSforAction($_syncid, $_action)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* when got a entry last added/modified/deleted
|
||||
*
|
||||
* @param $_syncid containing appName-contentid
|
||||
* @param $_action string can be add, delete or modify
|
||||
* @return string the last timestamp
|
||||
*/
|
||||
function getSyncTSforAction($_syncid, $_action) {
|
||||
$syncIDParts = explode('-',$_syncid);
|
||||
$_appName = array_shift($syncIDParts);
|
||||
$_id = implode ('', $syncIDParts);
|
||||
|
||||
|
||||
$ts = $GLOBALS['egw']->contenthistory->getTSforAction($_appName, $_id, $_action);
|
||||
|
||||
|
||||
return $ts;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* get the timestamp for action
|
||||
*
|
||||
@ -63,57 +64,94 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
*
|
||||
* @param string$_appName the appname example: infolog_notes
|
||||
* @param string $_action can be modify, add or delete
|
||||
* @param string $_ts timestamp where to start searching from
|
||||
* @param string $_ts timestamp where to start searching from
|
||||
* @return array containing syncIDs with changes
|
||||
*/
|
||||
function getHistory($_appName, $_action, $_ts)
|
||||
{
|
||||
function getHistory($_appName, $_action, $_ts) {
|
||||
$guidList = array ();
|
||||
$syncIdList = array ();
|
||||
$idList = $GLOBALS['egw']->contenthistory->getHistory($_appName, $_action, $_ts);
|
||||
foreach ($idList as $idItem)
|
||||
{
|
||||
$syncIdList[] = $_appName . '-' . $idItem;
|
||||
if ($idItem) // ignore inconsistent entries
|
||||
{
|
||||
$syncIdList[] = $_appName . '-' . $idItem;
|
||||
}
|
||||
}
|
||||
return $syncIdList;
|
||||
return $syncIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp (if set) of the last change to the
|
||||
* obj:guid, that was caused by the client. This is stored to
|
||||
* avoid mirroring these changes back to the client.
|
||||
*/
|
||||
function getChangeTS($type, $guid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
#Horde::logMessage('SyncML: getChangeTS for ' . $mapID .' / '. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if ($ts = $GLOBALS['egw']->db->select('egw_contentmap', 'map_timestamp', array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn())
|
||||
{
|
||||
#Horde::logMessage('SyncML: getChangeTS changets is ' . $GLOBALS['egw']->db->from_timestamp($ts), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $GLOBALS['egw']->db->from_timestamp($ts);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about the clients device info if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* a array containing all available infos about the device
|
||||
*/
|
||||
function getClientDeviceInfo()
|
||||
{
|
||||
if(($deviceID = $GLOBALS['egw']->db->select('egw_syncmldeviceowner', 'owner_devid',array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn()))
|
||||
* Returns the timestamp (if set) of the last change to the
|
||||
* obj:guid, that was caused by the client. This is stored to
|
||||
* avoid mirroring these changes back to the client.
|
||||
*/
|
||||
function getChangeTS($type, $guid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
#Horde::logMessage('SyncML: getChangeTS for ' . $mapID
|
||||
# . ' / '. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if ($ts = $GLOBALS['egw']->db->select('egw_contentmap', 'map_timestamp',
|
||||
array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn()) {
|
||||
#Horde::logMessage('SyncML: getChangeTS changets is '
|
||||
# . $GLOBALS['egw']->db->from_timestamp($ts),
|
||||
# __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $GLOBALS['egw']->db->from_timestamp($ts);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exceptions for a GUID which the client knows of
|
||||
*/
|
||||
function getGUIDExceptions($type, $guid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
#Horde::logMessage('SyncML: getChangeTS for ' . $mapID
|
||||
# . ' / '. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$guid_exceptions = array();
|
||||
$where = array ('map_id' => $mapID,);
|
||||
$where[] = "map_guid LIKE '$guid" . ":%'";
|
||||
|
||||
// Fetch all exceptions which the client knows of
|
||||
foreach ($GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', $where,
|
||||
__LINE__,__FILE__, false, '', 'syncml') as $row)
|
||||
{
|
||||
$parts = preg_split('/:/', $row['map_guid']);
|
||||
$Id = $parts[0];
|
||||
$extension = $parts[1];
|
||||
$guid_exceptions[$extension] = $row['map_guid'];
|
||||
}
|
||||
return $guid_exceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about the clients device info if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* a array containing all available infos about the device
|
||||
*/
|
||||
function getClientDeviceInfo() {
|
||||
#Horde::logMessage("SyncML: getClientDeviceInfo " . $this->_locName
|
||||
# . ", " . $this->_sourceURI, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (isset($this->_clientDeviceInfo)
|
||||
&& is_array($this->_clientDeviceInfo)) {
|
||||
// use cached information
|
||||
return $this->_clientDeviceInfo;
|
||||
}
|
||||
|
||||
if (($deviceID = $GLOBALS['egw']->db->select('egw_syncmldeviceowner',
|
||||
'owner_devid',
|
||||
array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
$cols = array(
|
||||
'dev_dtdversion',
|
||||
'dev_numberofchanges',
|
||||
@ -129,156 +167,156 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
'dev_utc',
|
||||
);
|
||||
|
||||
#Horde::logMessage("SyncML: getClientDeviceInfo $deviceID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$where = array(
|
||||
'dev_id' => $deviceID,
|
||||
'dev_id' => $deviceID,
|
||||
);
|
||||
|
||||
if (($row = $GLOBALS['egw']->db->select('egw_syncmldevinfo', $cols, $where, __LINE__, __FILE__, false, '', 'syncml')->fetch()))
|
||||
{
|
||||
return array (
|
||||
'DTDVersion' => $row['dev_dtdversion'],
|
||||
'supportNumberOfChanges'=> $row['dev_numberofchanges'],
|
||||
'supportLargeObjs' => $row['dev_largeobjs'],
|
||||
'UTC' => $row['dev_utc'],
|
||||
'softwareVersion' => $row['dev_swversion'],
|
||||
'hardwareVersion' => $row['dev_hwversion'],
|
||||
'firmwareVersion' => $row['dev_fwversion'],
|
||||
'oem' => $row['dev_oem'],
|
||||
'model' => $row['dev_model'],
|
||||
'manufacturer' => $row['dev_manufacturer'],
|
||||
'deviceType' => $row['dev_devicetype'],
|
||||
'dataStore' => unserialize($row['dev_datastore']),
|
||||
if (($row = $GLOBALS['egw']->db->select('egw_syncmldevinfo',
|
||||
$cols, $where, __LINE__, __FILE__, false, '', 'syncml')->fetch())) {
|
||||
$deviceMaxEntries = 'maxEntries-' . $this->_sourceURI;
|
||||
$deviceUIDExtension = 'uidExtension-' . $this->_sourceURI;
|
||||
$deviceNonBlockingAllday = 'nonBlockingAllday-' . $this->_sourceURI;
|
||||
$syncml_prefs = $GLOBALS['egw_info']['user']['preferences']['syncml'];
|
||||
$this->_clientDeviceInfo = array (
|
||||
'DTDVersion' => $row['dev_dtdversion'],
|
||||
'supportNumberOfChanges' => $row['dev_numberofchanges'],
|
||||
'supportLargeObjs' => $row['dev_largeobjs'],
|
||||
'UTC' => $row['dev_utc'],
|
||||
'softwareVersion' => $row['dev_swversion'],
|
||||
'hardwareVersion' => $row['dev_hwversion'],
|
||||
'firmwareVersion' => $row['dev_fwversion'],
|
||||
'oem' => $row['dev_oem'],
|
||||
'model' => $row['dev_model'],
|
||||
'manufacturer' => $row['dev_manufacturer'],
|
||||
'deviceType' => $row['dev_devicetype'],
|
||||
'maxMsgSize' => $this->_maxMsgSize,
|
||||
'maxEntries' => $syncml_prefs[$deviceMaxEntries],
|
||||
'uidExtension' => $syncml_prefs[$deviceUIDExtension],
|
||||
'nonBlockingAllday' => $syncml_prefs[$deviceNonBlockingAllday],
|
||||
'dataStore' => unserialize($row['dev_datastore']),
|
||||
);
|
||||
return $this->_clientDeviceInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns GUIDs of all client items
|
||||
*/
|
||||
function _getClientItems($type)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
* returns GUIDs of all client items
|
||||
*/
|
||||
function getClientItems() {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $this->_targetURI;
|
||||
|
||||
$guids = array();
|
||||
foreach($GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_expired' => 0,
|
||||
), __LINE__, __FILE__, false, '', 'syncml') as $row)
|
||||
{
|
||||
$guids[] = $row['map_guid'];
|
||||
}
|
||||
return $guids ? $guids : false;
|
||||
$guids = array();
|
||||
foreach($GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_expired' => false,
|
||||
), __LINE__, __FILE__, false, '', 'syncml') as $row) {
|
||||
$guids[] = $row['map_guid'];
|
||||
}
|
||||
return $guids ? $guids : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Horde server guid (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) for a given client
|
||||
* locid. Returns false if no such id is stored yet.
|
||||
*
|
||||
* Opposite of getLocId which returns the locid for a given guid.
|
||||
*/
|
||||
function getGlobalUID($type, $locid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
/**
|
||||
* Retrieves the Horde server guid (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) for a given client
|
||||
* locid. Returns false if no such id is stored yet.
|
||||
*
|
||||
* Opposite of getLocId which returns the locid for a given guid.
|
||||
*/
|
||||
function getGlobalUID($type, $locid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
#Horde::logMessage('SyncML: search GlobalUID for ' . $mapID .' / '.$locid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
#Horde::logMessage('SyncML: search GlobalUID for ' . $mapID .' / '.$locid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
return $GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
'map_expired' => 0,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn();
|
||||
}
|
||||
return $GLOBALS['egw']->db->select('egw_contentmap', 'map_guid',
|
||||
array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
'map_expired' => false,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a EGW GUID (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) to a client ID as
|
||||
* used by the sync client (like 12) returns false if no such id
|
||||
* is stored yet.
|
||||
*/
|
||||
function getLocID($type, $guid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
/**
|
||||
* Converts a EGW GUID (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) to a client ID as
|
||||
* used by the sync client (like 12) returns false if no such id
|
||||
* is stored yet.
|
||||
*/
|
||||
function getLocID($type, $guid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
Horde::logMessage('SyncML: search LocID for ' . $mapID .' / '.$guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML: search LocID for ' . $mapID . ' / ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if (($locuid = $GLOBALS['egw']->db->select('egw_contentmap', 'map_locuid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn()))
|
||||
{
|
||||
Horde::logMessage('SyncML: found LocID: '.$locuid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
return $locuid;
|
||||
}
|
||||
if (($locuid = $GLOBALS['egw']->db->select('egw_contentmap', 'map_locuid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
Horde::logMessage('SyncML: found LocID: '.$locuid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
return $locuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about the previous sync if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* ClientAnchor: the clients Next Anchor of the previous sync.
|
||||
* ServerAnchor: the Server Next Anchor of the previous sync.
|
||||
*/
|
||||
function getSyncSummary($type)
|
||||
{
|
||||
/**
|
||||
* Retrieves information about the previous sync if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* ClientAnchor: the clients Next Anchor of the previous sync.
|
||||
* ServerAnchor: the Server Next Anchor of the previous sync.
|
||||
*/
|
||||
function getSyncSummary($type) {
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
|
||||
#Horde::logMessage("SyncML: get SYNCSummary for $deviceID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: getSyncSummary for $deviceID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if (($row = $GLOBALS['egw']->db->select('egw_syncmlsummary', array('sync_serverts','sync_clientts'), array(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetch()))
|
||||
{
|
||||
#Horde::logMessage("SyncML: get SYNCSummary for $deviceID serverts: ".$row['sync_serverts']." clients: ".$row['sync_clientts'], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return array(
|
||||
'ClientAnchor' => $row['sync_clientts'],
|
||||
'ServerAnchor' => $row['sync_serverts'],
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (($row = $GLOBALS['egw']->db->select('egw_syncmlsummary', array('sync_serverts','sync_clientts'), array(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetch())) {
|
||||
Horde::logMessage("SyncML: getSyncSummary for $deviceID serverts: ".$row['sync_serverts']." clients: ".$row['sync_clientts'], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return array(
|
||||
'ClientAnchor' => $row['sync_clientts'],
|
||||
'ServerAnchor' => $row['sync_serverts'],
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isAuthorized()
|
||||
{
|
||||
if (!$this->_isAuthorized)
|
||||
{
|
||||
if(!isset($this->_locName) && !isset($this->_password))
|
||||
{
|
||||
function isAuthorized() {
|
||||
if (!$this->_isAuthorized) {
|
||||
if(!isset($this->_locName) && !isset($this->_password)) {
|
||||
Horde::logMessage('SyncML: Authentication not yet possible currently. Username and password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!isset($this->_password))
|
||||
{
|
||||
if(!isset($this->_password)) {
|
||||
Horde::logMessage('SyncML: Authentication not yet possible currently. Password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(strpos($this->_locName,'@') === False)
|
||||
{
|
||||
if(strpos($this->_locName,'@') === False) {
|
||||
$this->_locName .= '@'.$GLOBALS['egw_info']['server']['default_domain'];
|
||||
}
|
||||
|
||||
#Horde::logMessage('SyncML: authenticate with username: ' . $this->_locName . ' and password: ' . $this->_password, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if($GLOBALS['sessionid'] = $GLOBALS['egw']->session->create($this->_locName,$this->_password,'text'))
|
||||
{
|
||||
$this->_isAuthorized = true;
|
||||
Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
else
|
||||
{
|
||||
if($GLOBALS['sessionid'] = $GLOBALS['egw']->session->create($this->_locName,$this->_password,'text')) {
|
||||
|
||||
if ($GLOBALS['egw_info']['user']['apps']['syncml']) {
|
||||
$this->_isAuthorized = true;
|
||||
Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
$this->_isAuthorized = false;
|
||||
Horde::logMessage('SyncML is not enabled for this user', __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
}
|
||||
} else {
|
||||
$this->_isAuthorized = false;
|
||||
Horde::logMessage('SyncML: Authentication of ' . $this->_locName . ' failed' , __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// store sessionID in a variable, because ->verify maybe resets that value
|
||||
$sessionID = session_id();
|
||||
if(!$GLOBALS['egw']->session->verify($sessionID, 'staticsyncmlkp3')) {
|
||||
@ -290,11 +328,10 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all locid<->guid mappings for the given type.
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeAllUID($type)
|
||||
{
|
||||
* Removes all locid<->guid mappings for the given type.
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeAllUID($type) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
Horde::logMessage("SyncML: state->removeAllUID(type=$type)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
@ -302,17 +339,16 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', array('map_id' => $mapID), __LINE__, __FILE__, 'syncml');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in SlowSync
|
||||
* Removes all locid<->guid mappings for the given type,
|
||||
* that are older than $ts.
|
||||
*
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeOldUID($type, $ts)
|
||||
{
|
||||
* Used in SlowSync
|
||||
* Removes all locid<->guid mappings for the given type,
|
||||
* that are older than $ts.
|
||||
*
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeOldUID($type, $ts) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
$where[] = "map_id = '".$mapID."' AND map_timestamp < '".$GLOBALS['egw']->db->to_timestamp($ts)."'";
|
||||
|
||||
@ -324,102 +360,151 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the locid<->guid mapping for the given locid. Returns
|
||||
* the guid that was removed or false if no mapping entry was
|
||||
* found.
|
||||
*/
|
||||
function removeUID($type, $locid)
|
||||
{
|
||||
* Used at session end to cleanup expired entries
|
||||
* Removes all locid<->guid mappings for the given type,
|
||||
* that are marked as expired and older than $ts.
|
||||
*
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeExpiredUID($type, $ts) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$where['map_id'] = $mapID;
|
||||
$where['map_expired'] = true;
|
||||
$where[] = "map_timestamp <= '".$GLOBALS['egw']->db->to_timestamp($ts)."'";
|
||||
|
||||
Horde::logMessage("SyncML: state->removeExpiredUID(type=$type)",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an entry is already expired
|
||||
*
|
||||
* Returns true for expired mappings.
|
||||
*/
|
||||
function isExpiredUID($type, $locid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
$expired = false;
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
);
|
||||
if (($expired = $GLOBALS['egw']->db->select('egw_contentmap', 'map_expired',
|
||||
$where, __LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
Horde::logMessage('SyncML: found LocID: '. $locid,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
return $expired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the locid<->guid mapping for the given locid. Returns
|
||||
* the guid that was removed or false if no mapping entry was
|
||||
* found.
|
||||
*/
|
||||
function removeUID($type, $locid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$where = array (
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid
|
||||
);
|
||||
|
||||
if (!($guid = $GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', $where, __LINE__, __FILE__, false, '', 'syncml')->fetchColumn()))
|
||||
{
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid) : nothing to remove", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
if (!($guid = $GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', $where,
|
||||
__LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid)"
|
||||
. " nothing to remove", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
return false;
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid) : removing guid:$guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid): "
|
||||
. "removing guid $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where, __LINE__, __FILE__, 'syncml');
|
||||
|
||||
return $guid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a given client $locid and Horde server $guid pair into the
|
||||
* map table to allow mapping between the client's and server's
|
||||
* IDs. Actually there are two maps: from the localid to the guid
|
||||
* and vice versa. The localid is converted to a key as follows:
|
||||
* this->_locName . $this->_sourceURI . $type . $locid so you can
|
||||
* have different syncs with different devices. If an entry
|
||||
* already exists, it is overwritten.
|
||||
*/
|
||||
function setUID($type, $locid, $_guid, $ts=0)
|
||||
{
|
||||
#Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
#Horde::logMessage("SyncML: setUID ". $this->getUIDMapping($guid), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// problem: entries created from client, come here with the (long) server guid,
|
||||
// but getUIDMapping does not know them and can not map server-guid <--> client guid
|
||||
$guid = $this->getUIDMapping($_guid);
|
||||
if($guid === false)
|
||||
{
|
||||
// this message is not really usefull here because setUIDMapping is only called when adding content to the client,
|
||||
// however setUID is called also when adding content from the client. So in all other conditions this
|
||||
// message will be logged.
|
||||
Horde::logMessage("SyncML: setUID $type, $locid, $guid something went wrong!!! Mapping not found.", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$guid = $_guid;
|
||||
//return false;
|
||||
}
|
||||
Horde::logMessage("SyncML: setUID $_guid => $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
/**
|
||||
* Puts a given client $locid and Horde server $guid pair into the
|
||||
* map table to allow mapping between the client's and server's
|
||||
* IDs. Actually there are two maps: from the localid to the guid
|
||||
* and vice versa. The localid is converted to a key as follows:
|
||||
* this->_locName . $this->_sourceURI . $type . $locid so you can
|
||||
* have different syncs with different devices. If an entry
|
||||
* already exists, it is overwritten.
|
||||
* Expired entries can be deleted at the next session start.
|
||||
*/
|
||||
function setUID($type, $locid, $_guid, $ts=0, $expired=false) {
|
||||
#Horde::logMessage("SyncML: setUID $type, $locid, $_guid, $ts ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if(!$ts) $ts = time();
|
||||
if (!strlen("$_guid")) {
|
||||
// We can't handle this case otherwise
|
||||
return;
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// problem: entries created from client, come here with the (long) server guid,
|
||||
// but getUIDMapping does not know them and can not map server-guid <--> client guid
|
||||
$guid = $this->getUIDMapping($_guid);
|
||||
if($guid === false) {
|
||||
// this message is not really usefull here because setUIDMapping is only called when adding content to the client,
|
||||
// however setUID is called also when adding content from the client. So in all other conditions this
|
||||
// message will be logged.
|
||||
//Horde::logMessage("SyncML: setUID $type, $locid, $guid something went wrong!!! Mapping not found.", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$guid = $_guid;
|
||||
//return false;
|
||||
}
|
||||
#Horde::logMessage("SyncML: setUID $_guid => $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
if(!$ts) $ts = time();
|
||||
|
||||
// delete all client id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where, __LINE__, __FILE__, 'syncml');
|
||||
Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// delete all egw id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where, __LINE__, __FILE__, 'syncml');
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$data = $where + array(
|
||||
'map_locuid' => $locid,
|
||||
'map_timestamp' => $ts,
|
||||
'map_expired' => 0,
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_contentmap', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
// expire all client id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
);
|
||||
$data = array (
|
||||
'map_expired' => true,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
|
||||
#Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts $mapID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
// delete all egw id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
|
||||
$data = $where + array(
|
||||
'map_locuid' => $locid,
|
||||
'map_timestamp' => $ts,
|
||||
'map_expired' => ($expired ? true : false),
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_contentmap', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
|
||||
/**
|
||||
* writes clients deviceinfo into database
|
||||
*/
|
||||
function writeClientDeviceInfo()
|
||||
{
|
||||
if (!isset($this->_clientDeviceInfo) || !is_array($this->_clientDeviceInfo))
|
||||
{
|
||||
* writes clients deviceinfo into database
|
||||
*/
|
||||
function writeClientDeviceInfo() {
|
||||
if (!isset($this->_clientDeviceInfo)
|
||||
|| !is_array($this->_clientDeviceInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isset($this->size_dev_hwversion))
|
||||
{
|
||||
if(!isset($this->size_dev_hwversion)) {
|
||||
$tableDefDevInfo = $GLOBALS['egw']->db->get_table_definitions('syncml',$this->table_devinfo);
|
||||
$this->size_dev_hwversion = $tableDefDevInfo['fd']['dev_hwversion']['precision'];
|
||||
unset($tableDefDevInfo);
|
||||
@ -437,77 +522,89 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
'dev_fwversion' => $firmwareVersion,
|
||||
);
|
||||
|
||||
if (($deviceID = $GLOBALS['egw']->db->select('egw_syncmldevinfo', 'dev_id', $where, __LINE__, __FILE__, false, '', 'syncml')->fetchColumn()))
|
||||
{
|
||||
if (($deviceID = $GLOBALS['egw']->db->select('egw_syncmldevinfo', 'dev_id', $where,
|
||||
__LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
$data = array (
|
||||
'dev_datastore' => serialize($this->_clientDeviceInfo['dataStore']),
|
||||
);
|
||||
$GLOBALS['egw']->db->update('egw_syncmldevinfo', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
else
|
||||
{
|
||||
$GLOBALS['egw']->db->update('egw_syncmldevinfo', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
} else {
|
||||
$data = array (
|
||||
'dev_dtdversion' => $this->_clientDeviceInfo['DTDVersion'],
|
||||
'dev_numberofchanges' => $this->_clientDeviceInfo['supportNumberOfChanges'] ? true : false,
|
||||
'dev_largeobjs' => $this->_clientDeviceInfo['supportLargeObjs'] ? true : false,
|
||||
'dev_utc' => $this->_clientDeviceInfo['UTC'] ? true : false,
|
||||
'dev_swversion' => $softwareVersion,
|
||||
'dev_hwversion' => $hardwareVersion,
|
||||
'dev_fwversion' => $firmwareVersion,
|
||||
'dev_oem' => $this->_clientDeviceInfo['oem'],
|
||||
'dev_model' => $this->_clientDeviceInfo['model'],
|
||||
'dev_manufacturer' => $this->_clientDeviceInfo['manufacturer'],
|
||||
'dev_devicetype' => $this->_clientDeviceInfo['deviceType'],
|
||||
'dev_datastore' => serialize($this->_clientDeviceInfo['dataStore']),
|
||||
'dev_dtdversion' => $this->_clientDeviceInfo['DTDVersion'],
|
||||
'dev_numberofchanges' => ($this->_clientDeviceInfo['supportNumberOfChanges'] ? true : false),
|
||||
'dev_largeobjs' => ($this->_clientDeviceInfo['supportLargeObjs'] ? true : false),
|
||||
'dev_utc' => ($this->_clientDeviceInfo['UTC'] ? true : false),
|
||||
'dev_swversion' => $softwareVersion,
|
||||
'dev_hwversion' => $hardwareVersion,
|
||||
'dev_fwversion' => $firmwareVersion,
|
||||
'dev_oem' => $this->_clientDeviceInfo['oem'],
|
||||
'dev_model' => $this->_clientDeviceInfo['model'],
|
||||
'dev_manufacturer' => $this->_clientDeviceInfo['manufacturer'],
|
||||
'dev_devicetype' => $this->_clientDeviceInfo['deviceType'],
|
||||
'dev_datastore' => serialize($this->_clientDeviceInfo['dataStore']),
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_syncmldevinfo', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
|
||||
$deviceID = $GLOBALS['egw']->db->get_last_insert_id('egw_syncmldevinfo', 'dev_id');
|
||||
}
|
||||
|
||||
$data = array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
'owner_devid' => $deviceID,
|
||||
);
|
||||
$where = array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_syncmldeviceowner', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
|
||||
if ($GLOBALS['egw']->db->select('egw_syncmldeviceowner', 'owner_devid', $where,
|
||||
__LINE__, __FILE__, false, '', 'syncml')->fetchColumn()) {
|
||||
$data = array (
|
||||
'owner_devid' => $deviceID,
|
||||
);
|
||||
$GLOBALS['egw']->db->update('egw_syncmldeviceowner', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
} else {
|
||||
$data = array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
'owner_devid' => $deviceID,
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_syncmldeviceowner', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After a successful sync, the client and server's Next Anchors
|
||||
* are written to the database so they can be used to negotiate
|
||||
* upcoming syncs.
|
||||
*/
|
||||
function writeSyncSummary()
|
||||
{
|
||||
#parent::writeSyncSummary();
|
||||
/**
|
||||
* After a successful sync, the client and server's Next Anchors
|
||||
* are written to the database so they can be used to negotiate
|
||||
* upcoming syncs.
|
||||
*/
|
||||
function writeSyncSummary() {
|
||||
#parent::writeSyncSummary();
|
||||
|
||||
if (!isset($this->_serverAnchorNext) || !is_array($this->_serverAnchorNext))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!isset($this->_serverAnchorNext)
|
||||
|| !is_array($this->_serverAnchorNext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
|
||||
foreach((array)$this->_serverAnchorNext as $type => $a)
|
||||
{
|
||||
Horde::logMessage("SyncML: write SYNCSummary for $deviceID $type serverts: $a clients: ".$this->_clientAnchorNext[$type], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
foreach((array)$this->_serverAnchorNext as $type => $a) {
|
||||
Horde::logMessage("SyncML: write SYNCSummary for $deviceID "
|
||||
. "$type serverts: $a clients: "
|
||||
. $this->_clientAnchorNext[$type],
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$where = array(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type,
|
||||
);
|
||||
$where = array(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type,
|
||||
);
|
||||
|
||||
$data = array(
|
||||
'sync_serverts' => $a,
|
||||
'sync_clientts' => $this->_clientAnchorNext[$type]
|
||||
);
|
||||
$data = array(
|
||||
'sync_serverts' => $a,
|
||||
'sync_clientts' => $this->_clientAnchorNext[$type]
|
||||
);
|
||||
|
||||
$GLOBALS['egw']->db->insert('egw_syncmlsummary', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
}
|
||||
$GLOBALS['egw']->db->insert('egw_syncmlsummary', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,230 +1,466 @@
|
||||
<?php
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Sync.php,v 1.7 2004/09/14 04:27:05 chuck Exp $
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
class Horde_SyncML_Sync {
|
||||
|
||||
/**
|
||||
* Target, either contacts, notes, events,
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
/**
|
||||
* Target, either contacts, notes, events,
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
|
||||
var $_sourceLocURI;
|
||||
var $_sourceLocURI;
|
||||
|
||||
/**
|
||||
* Return if all commands success.
|
||||
*/
|
||||
var $globalSuccess;
|
||||
|
||||
/**
|
||||
* This is the content type to use to export data.
|
||||
*/
|
||||
var $preferedContentType;
|
||||
|
||||
/**
|
||||
* Do have the sync data loaded from the database already?
|
||||
*/
|
||||
var $syncDataLoaded;
|
||||
|
||||
function &factory($alert)
|
||||
{
|
||||
Horde::logMessage('SyncML: new sync for alerttype ' . $alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
switch ($alert) {
|
||||
case ALERT_TWO_WAY:
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
return $sync = new Horde_SyncML_Sync_TwoWaySync();
|
||||
|
||||
case ALERT_SLOW_SYNC:
|
||||
include_once 'Horde/SyncML/Sync/SlowSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_SlowSync();
|
||||
|
||||
case ALERT_ONE_WAY_FROM_CLIENT:
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromClientSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_OneWayFromClientSync();
|
||||
|
||||
case ALERT_REFRESH_FROM_CLIENT:
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromClientSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_RefreshFromClientSync();
|
||||
|
||||
case ALERT_ONE_WAY_FROM_SERVER:
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromServerSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_OneWayFromServerSync();
|
||||
|
||||
case ALERT_REFRESH_FROM_SERVER:
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromServerSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_RefreshFromServerSync();
|
||||
}
|
||||
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::raiseError('Alert ' . $alert . ' not found.');
|
||||
}
|
||||
|
||||
function nextSyncCommand($currentCmdID, &$syncCommand, &$output)
|
||||
{
|
||||
$result = $this->runSyncCommand($syncCommand);
|
||||
return $syncCommand->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
function startSync($currentCmdID, &$output)
|
||||
{
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function endSync($currentCmdID, &$output)
|
||||
{
|
||||
return $currentCmdID;
|
||||
}
|
||||
var $_locName;
|
||||
|
||||
/**
|
||||
* Here's where the actual processing of a client-sent Sync
|
||||
* Command takes place. Entries are added, deleted or replaced
|
||||
* from the server database by using Horde API (Registry) calls.
|
||||
*/
|
||||
* The synchronization method, one of the ALERT_* constants.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_syncType;
|
||||
|
||||
/**
|
||||
* Return if all commands success.
|
||||
*/
|
||||
var $globalSuccess;
|
||||
|
||||
/**
|
||||
* This is the content type to use to export data.
|
||||
*/
|
||||
var $preferedContentType;
|
||||
|
||||
/**
|
||||
* Optional filter expression for this content.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_filterExpression = '';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Do have the sync data loaded from the database already?
|
||||
*/
|
||||
var $syncDataLoaded;
|
||||
|
||||
function &factory($alert) {
|
||||
Horde::logMessage('SyncML: new sync for alerttype ' . $alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
switch ($alert) {
|
||||
case ALERT_TWO_WAY:
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
return $sync = new Horde_SyncML_Sync_TwoWaySync();
|
||||
|
||||
case ALERT_SLOW_SYNC:
|
||||
include_once 'Horde/SyncML/Sync/SlowSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_SlowSync();
|
||||
|
||||
case ALERT_ONE_WAY_FROM_CLIENT:
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromClientSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_OneWayFromClientSync();
|
||||
|
||||
case ALERT_REFRESH_FROM_CLIENT:
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromClientSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_RefreshFromClientSync();
|
||||
|
||||
case ALERT_ONE_WAY_FROM_SERVER:
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromServerSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_OneWayFromServerSync();
|
||||
|
||||
case ALERT_REFRESH_FROM_SERVER:
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromServerSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_RefreshFromServerSync();
|
||||
}
|
||||
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::raiseError('Alert ' . $alert . ' not found.');
|
||||
}
|
||||
|
||||
function nextSyncCommand($currentCmdID, &$syncCommand, &$output) {
|
||||
$result = $this->runSyncCommand($syncCommand);
|
||||
return $syncCommand->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
function startSync($currentCmdID, &$output) {
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function endSync($currentCmdID, &$output) {
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property sourceURI.
|
||||
*
|
||||
* @param string $sourceURI New value of property sourceLocURI.
|
||||
*/
|
||||
function setSourceLocURI($sourceURI) {
|
||||
$this->_sourceLocURI = $sourceURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property targetURI.
|
||||
*
|
||||
* @param string $targetURI New value of property targetLocURI.
|
||||
*/
|
||||
function setTargetLocURI($targetURI) {
|
||||
$this->_targetLocURI = $targetURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property syncType.
|
||||
*
|
||||
* @param integer $syncType New value of property syncType.
|
||||
*/
|
||||
function setSyncType($syncType) {
|
||||
$this->_syncType = $syncType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property locName.
|
||||
*
|
||||
* @param string $locName New value of property locName.
|
||||
*/
|
||||
function setLocName($locName) {
|
||||
$this->_locName = $locName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property filterExpression.
|
||||
*
|
||||
* @param string $expression New value of property filterExpression.
|
||||
*/
|
||||
function setFilterExpression($expression) {
|
||||
$this->_filterExpression = $expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Here's where the actual processing of a client-sent Sync
|
||||
* Command takes place. Entries are added, deleted or replaced
|
||||
* from the server database by using Horde API (Registry) calls.
|
||||
*/
|
||||
function runSyncCommand(&$command) {
|
||||
#Horde::logMessage('SyncML: content type is ' . $command->getContentType() .' moreData '. $command->_moreData, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
global $registry;
|
||||
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
if(isset($state->_moreData['luid'])) {
|
||||
if(($command->_luid == $state->_moreData['luid'])) {
|
||||
Horde::logMessage('SyncML: got next moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$lastChunks = implode('',$state->_moreData['chunks']);
|
||||
$command->_content = $lastChunks.$command->_content;
|
||||
$stringlen1 = strlen($lastChunks);
|
||||
$stringlen2 = strlen($command->_content);
|
||||
|
||||
if(!$command->_moreData && strlen($command->_content) != $state->_moreData['contentSize']) {
|
||||
$command->_status = RESPONSE_SIZE_MISMATCH;
|
||||
$state->_moreData = array();
|
||||
|
||||
return;
|
||||
} elseif(!$command->_moreData && strlen($command->_content) == $state->_moreData['contentSize']) {
|
||||
$state->_moreData = array();
|
||||
Horde::logMessage('SyncML: chunk ended successful type is ' . $command->getContentType() .' content is '. $command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
} else {
|
||||
// alert 223 needed too
|
||||
#$command->_status = ALERT_NO_END_OF_DATA;
|
||||
|
||||
$state->_moreData = array();
|
||||
|
||||
return;
|
||||
|
||||
if ($command->hasMoreData()) {
|
||||
Horde::logMessage('SyncML: moreData: TRUE', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$command->setStatus(RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED);
|
||||
return true;
|
||||
}
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
|
||||
$syncml_prefs = $GLOBALS['egw_info']['user']['preferences']['syncml'];
|
||||
if (isset($syncml_prefs[$type])) {
|
||||
$sync_conflicts = $syncml_prefs[$type];
|
||||
} else {
|
||||
$sync_conflicts = CONFLICT_SERVER_WINNING;
|
||||
}
|
||||
|
||||
$state->setLocName($this->_locName);
|
||||
$locName = $state->getLocName();
|
||||
$sourceURI = $state->getSourceURI();
|
||||
$hordeType = $state->getHordeType($type);
|
||||
$refts = $state->getServerAnchorLast($type);
|
||||
$state->setTargetURI($type);
|
||||
$changes = array();
|
||||
// First we get all changes done after the previous sync start
|
||||
foreach ($registry->call($hordeType. '/listBy',
|
||||
array('action' => 'modify',
|
||||
'timestamp' => $refts,
|
||||
'type' => $type,
|
||||
'filter' => $this->_filterExpression)) as $change) {
|
||||
// now we have to remove the ones
|
||||
// that came from the last sync with this client
|
||||
$guid_ts = $state->getSyncTSforAction($change, 'modify');
|
||||
$sync_ts = $state->getChangeTS($type, $change);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
Horde::logMessage("SyncML: change: $change ignored, " .
|
||||
"came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
$changes[] = $change;
|
||||
}
|
||||
|
||||
// don't add/replace the data currently, they are not yet complete
|
||||
if($command->_moreData == TRUE) {
|
||||
$state->_moreData['chunks'][] = $command->_content;
|
||||
$state->_moreData['luid'] = $command->_luid;
|
||||
|
||||
// gets only set with the first chunk of data
|
||||
if(isset($command->_contentSize))
|
||||
$state->_moreData['contentSize'] = $command->_contentSize;
|
||||
|
||||
$command->_status = RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED;
|
||||
Horde::logMessage('SyncML: added moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$hordeType = $type = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($hordeType);
|
||||
|
||||
Horde::logMessage('SyncML: runSyncCommand found ' . count($changes) .
|
||||
" possible conflicts for $type", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if(!$contentType = $command->getContentType()) {
|
||||
$contentType = $state->getPreferedContentType($type);
|
||||
}
|
||||
|
||||
|
||||
if (($contentType == 'text/x-vcalendar' || $contentType == 'text/calendar')
|
||||
&& strpos($command->getContent(), 'BEGIN:VTODO') !== false)
|
||||
{
|
||||
&& strpos($command->getContent(), 'BEGIN:VTODO') !== false) {
|
||||
$hordeType = 'tasks';
|
||||
}
|
||||
|
||||
$syncElementItems = $command->getSyncElementItems();
|
||||
|
||||
|
||||
foreach($syncElementItems as $syncItem) {
|
||||
|
||||
|
||||
$guid = false;
|
||||
|
||||
|
||||
$contentSize = strlen($syncItem->_content);
|
||||
if ((($size = $syncItem->getContentSize()) !== false) &&
|
||||
($contentSize != $size) &&
|
||||
($contentSize + 1 != $size)) {
|
||||
Horde::logMessage('SyncML: content size missmatch for LocURI '
|
||||
. $syncItem->getLocURI() . ": $contentSize ($size)",
|
||||
__FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$command->setStatus(RESPONSE_SIZE_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_a($command, 'Horde_SyncML_Command_Sync_Add')) {
|
||||
if ($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
// We enforce the client not to change anything
|
||||
if ($sync_conflicts > CONFLICT_CLIENT_CHANGES_IGNORED) {
|
||||
// delete this item from client
|
||||
Horde::logMessage('SyncML: Server RO! REMOVE '
|
||||
. $syncItem->getLocURI() . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, '!D' . $syncItem->getLocURI());
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Server RO! '
|
||||
. 'REJECT all client changes',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->log('Client-AddReplaceIgnored');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
|
||||
if (!is_a($guid, 'PEAR_Error') && $guid != false) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-Add");
|
||||
Horde::logMessage('SyncML: added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->log('Client-Add');
|
||||
Horde::logMessage('SyncML: added client entry as '
|
||||
. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
$state->log("Client-AddFailure");
|
||||
Horde::logMessage('SyncML: Error in adding client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log('Client-AddFailure');
|
||||
Horde::logMessage('SyncML: Error in adding client entry: '
|
||||
. $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
}
|
||||
} elseif (is_a($command, 'Horde_SyncML_Command_Sync_Delete')) {
|
||||
// We can't remove the mapping entry as we need to keep
|
||||
// the timestamp information.
|
||||
$guid = $state->removeUID($type, $syncItem->getLocURI());
|
||||
#$guid = $state->getGlobalUID($type, $syncItem->getLocURI());
|
||||
Horde::logMessage('SyncML: about to delete entry ' . $type .' / '. $guid . ' due to client request '.$syncItem->getLocURI(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if (!$guid) {
|
||||
// the entry is no longer on the server
|
||||
$state->log('Client-DeleteFailure');
|
||||
Horde::logMessage('SyncML: Failure deleting client entry, '
|
||||
. 'gone already on server!',
|
||||
__FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
continue;
|
||||
}
|
||||
if ($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
// We enforce the client not to change anything
|
||||
if ($sync_conflicts > CONFLICT_CLIENT_CHANGES_IGNORED) {
|
||||
Horde::logMessage('SyncML: Server RO! ADD '
|
||||
. $guid . ' to client again',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
// $state->addConflictItem($type, $guid);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: '.
|
||||
'Server RO! REJECT all client changes',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
}
|
||||
$state->log('Client-DeleteIgnored');
|
||||
continue;
|
||||
}
|
||||
elseif ($sync_conflicts == CONFLICT_RESOLVED_WITH_DUPLICATE &&
|
||||
in_array($guid, $changes))
|
||||
{
|
||||
Horde::logMessage('SyncML: '.
|
||||
'Server has updated version to keep',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->log('Client-DeleteIgnored');
|
||||
continue;
|
||||
}
|
||||
elseif ($sync_conflicts == CONFLICT_MERGE_DATA)
|
||||
{
|
||||
Horde::logMessage('SyncML: Server Merge Only: ADD '
|
||||
. $guid . ' to client again',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
// $state->addConflictItem($type, $guid);
|
||||
$state->log('Client-DeleteIgnored');
|
||||
continue;
|
||||
}
|
||||
|
||||
Horde::logMessage('SyncML: about to delete entry '
|
||||
. $type .' / '. $guid . ' due to client request '
|
||||
. $syncItem->getLocURI(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if (!is_a($guid, 'PEAR_Error') && $guid != false) {
|
||||
$registry->call($hordeType . '/delete', array($guid));
|
||||
#$ts = $state->getSyncTSforAction($guid, 'delete');
|
||||
#$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-Delete");
|
||||
Horde::logMessage('SyncML: deleted entry ' . $guid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$ts = $state->getSyncTSforAction($guid, 'delete');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts, 1);
|
||||
$state->log('Client-Delete');
|
||||
Horde::logMessage('SyncML: deleted entry '
|
||||
. $guid . ' due to client request',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
$state->log("Client-DeleteFailure");
|
||||
Horde::logMessage('SyncML: Failure deleting client entry, maybe gone already on server. msg:'. $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log('Client-DeleteFailure');
|
||||
Horde::logMessage('SyncML: Failure deleting client entry, '
|
||||
. 'maybe gone already on server. msg: '
|
||||
. $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
}
|
||||
} elseif (is_a($command, 'Horde_SyncML_Command_Sync_Replace')) {
|
||||
$guid = $state->getGlobalUID($type, $syncItem->getLocURI());
|
||||
$replace = true;
|
||||
$ok = false;
|
||||
if ($guid) {
|
||||
Horde::logMessage('SyncML: locuri'. $syncItem->getLocURI() . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
// Entry exists: replace current one.
|
||||
$ok = $registry->call($hordeType . '/replace',
|
||||
array($guid, $state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
if (!is_a($ok, 'PEAR_Error')) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
Horde::logMessage('SyncML: replaced entry due to client request guid: ' .$guid. ' ts: ' .$ts, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->log("Client-Replace");
|
||||
$ok = true;
|
||||
} else {
|
||||
// Entry may have been deleted; try adding it.
|
||||
$ok = false;
|
||||
$merge = false;
|
||||
if ($guid)
|
||||
{
|
||||
Horde::logMessage('SyncML: locuri'. $syncItem->getLocURI() . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) || in_array($guid, $changes))
|
||||
{
|
||||
Horde::logMessage('SyncML: CONFLICT for locuri'. $syncItem->getLocURI() . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
switch ($sync_conflicts)
|
||||
{
|
||||
case CONFLICT_CLIENT_WINNING:
|
||||
$command->setStatus(RESPONSE_CONFLICT_RESOLVED_WITH_CLIENT_WINNING);
|
||||
break;
|
||||
case CONFLICT_SERVER_WINNING:
|
||||
Horde::logMessage('SyncML: REJECT client change for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$ok = true;
|
||||
$replace = false;
|
||||
$state->log('Client-AddReplaceIgnored');
|
||||
break;
|
||||
case CONFLICT_MERGE_DATA:
|
||||
Horde::logMessage('SyncML: Merge server and client data for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$merge = true;
|
||||
break;
|
||||
case CONFLICT_RESOLVED_WITH_DUPLICATE:
|
||||
$replace = false;
|
||||
break;
|
||||
case CONFLICT_CLIENT_CHANGES_IGNORED:
|
||||
Horde::logMessage('SyncML: Server RO! REJECT client change for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$ok = true;
|
||||
$replace = false;
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log('Client-AddReplaceIgnored');
|
||||
break;
|
||||
default: // We enforce our data on client
|
||||
Horde::logMessage('SyncML: Server RO! UNDO client change for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, $guid);
|
||||
$ok = true;
|
||||
$replace = false;
|
||||
}
|
||||
}
|
||||
elseif ($sync_conflicts == CONFLICT_MERGE_DATA)
|
||||
{
|
||||
Horde::logMessage('SyncML: Merge server and client data for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$merge = true;
|
||||
}
|
||||
|
||||
if ($replace)
|
||||
{
|
||||
// Entry exists: replace/merge with current one.
|
||||
$ok = $registry->call($hordeType . '/replace',
|
||||
array($guid, $state->convertClient2Server($syncItem->getContent(),
|
||||
$contentType), $contentType, $merge));
|
||||
if (!is_a($ok, 'PEAR_Error') && $ok != false)
|
||||
{
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
if ($merge)
|
||||
{
|
||||
Horde::logMessage('SyncML: Merged entry due to client request guid: ' .
|
||||
$guid . ' ts: ' . $ts, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
else
|
||||
{
|
||||
Horde::logMessage('SyncML: replaced entry due to client request guid: ' .
|
||||
$guid . ' ts: ' . $ts, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
$state->log('Client-Replace');
|
||||
$ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Entry may have been deleted; try adding it.
|
||||
$ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!$ok) {
|
||||
// Entry does not exist in map or database: add a new one.
|
||||
Horde::logMessage('SyncML: try to add contentype ' . $contentType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Entry does either not exist in map or database, or should be added due to a conflict
|
||||
|
||||
if ($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
// We enforce the client not to change anything
|
||||
if ($sync_conflicts > CONFLICT_CLIENT_CHANGES_IGNORED) {
|
||||
// delete this item from client
|
||||
Horde::logMessage('SyncML: Server RO! REMOVE ' . $syncItem->getLocURI() . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, '!D' . $syncItem->getLocURI());
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Server RO! REJECT all client changes',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Horde::logMessage('SyncML: try to add contentype '
|
||||
. $contentType . ' for locuri ' . $syncItem->getLocURI(),
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
//continue;
|
||||
$oguid = $guid;
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType, $guid));
|
||||
if (!is_a($guid, 'PEAR_Error')) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
if ($oguid != $guid) {
|
||||
// We add a new entry
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
Horde::logMessage('SyncML: added entry '
|
||||
. $guid . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->log('Client-Add');
|
||||
} else {
|
||||
// We replaced an entry
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
Horde::logMessage('SyncML: replaced entry '
|
||||
. $guid . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->log('Client-Replace');
|
||||
}
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-AddReplace");
|
||||
Horde::logMessage('SyncML: r/ added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Error in replacing/add client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log("Client-AddFailure");
|
||||
Horde::logMessage('SyncML: Error in replacing/'
|
||||
. 'add client entry:' . $guid->message,
|
||||
__FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log('Client-AddFailure');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $guid;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
include_once 'Horde/SyncML/Sync/SlowSync.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Sync/RefreshFromClientSync.php,v 1.8 2004/09/14 04:27:06 chuck Exp $
|
||||
@ -15,20 +15,9 @@ include_once 'Horde/SyncML/Sync.php';
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Sync_RefreshFromClientSync extends Horde_SyncML_Sync {
|
||||
|
||||
class Horde_SyncML_Sync_RefreshFromClientSync extends Horde_SyncML_Sync_SlowSync {
|
||||
/**
|
||||
* We need to erase the current server contents, then we can add
|
||||
* We needed to erase the current server contents, then we can add
|
||||
* the client's contents.
|
||||
*/
|
||||
function startSync($currentCmdID, &$output)
|
||||
{
|
||||
$deletes = $registry->call($this->targetLocURI, '/list', array());
|
||||
foreach ($delete as $deletes) {
|
||||
$registry->call($this->targetLocURI . '/delete', array($delete));
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,87 +1,167 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Sync/RefreshFromServerSync.php,v 1.9 2004/07/03 15:21:15 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Sync_RefreshFromServerSync extends Horde_SyncML_Sync_TwoWaySync {
|
||||
function handleSync($currentCmdID, $hordeType, $syncType, &$output, $refts) {
|
||||
global $registry;
|
||||
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
|
||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$maxMsgSize = $state->getMaxMsgSizeClient();
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
if (isset($deviceInfo['maxEntries'])) {
|
||||
$maxEntries = $deviceInfo['maxEntries'];
|
||||
if (!$maxMsgSize && !$maxEntries) {
|
||||
// fallback to default
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
} else {
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
|
||||
$serverAnchorNext = $state->getServerAnchorNext($syncType);
|
||||
$counter = 0;
|
||||
|
||||
|
||||
if (isset($state->curSyncItem)) {
|
||||
// Finish the pending sync item
|
||||
$cmd = &$state->curSyncItem;
|
||||
unset($state->curSyncItem);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Sync');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = &$cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
|
||||
$adds = &$state->getAddedItems($syncType);
|
||||
Horde::logMessage("SyncML: ".count($adds).
|
||||
' added items found for '.$syncType ,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if(is_array($adds)) {
|
||||
while($guid = array_shift($adds)) {
|
||||
$currentSize = $output->getOutputSize();
|
||||
// return if we have to much data
|
||||
if (($maxEntries && ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
|| ($maxMsgSize
|
||||
&& (($currentSize + MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
if ($locID = $state->getLocID($syncType, $guid)) {
|
||||
Horde::logMessage("SyncML: RefreshFromServerSync add to client: $guid ignored, already at client($locID)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'add');
|
||||
if ($guid_ts > $serverAnchorNext) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde::logMessage("SyncML: RefreshFromServerSync add $guid is in our future", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType));
|
||||
Horde::logMessage("SyncML: slowsync add $guid to client ". print_r($c, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat']))
|
||||
{
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
|
||||
$cmd->setSourceURI($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
Horde::logMessage("SyncML: refresh failed to export guid $guid:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->log("Server-ExportFailed");
|
||||
continue;
|
||||
}
|
||||
|
||||
$size = strlen($c);
|
||||
// return if we have to much data
|
||||
if ($maxMsgSize && !$deviceInfo['supportLargeObjs']) {
|
||||
if (($size + MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
Horde::logMessage("SyncML: refresh failed to export guid $guid due to size $size", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$state->log("Server-ExportFailed");
|
||||
continue;
|
||||
}
|
||||
if (($currentSize + $size + MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: refresh add $guid to client\n$c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
|
||||
$cmd->setContent($c);
|
||||
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat'])) {
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
|
||||
$cmd->setGUID($guid);
|
||||
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// moreData split; put the guid back in the list and return
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = &$cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
|
||||
#Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
|
||||
Horde::logMessage("SyncML: All items handled for sync $syncType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->removeExpiredUID($syncType, $serverAnchorNext);
|
||||
$state->clearSync($syncType);
|
||||
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
|
||||
function loadData() {
|
||||
global $registry;
|
||||
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
|
||||
$state->setTargetURI($syncType);
|
||||
$future = $state->getServerAnchorNext($syncType);
|
||||
$delta_add = 0;
|
||||
|
||||
Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setAddedItems($hordeType, $registry->call($hordeType. '/list', array()));
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
$state->setAddedItems($syncType, $registry->call($hordeType. '/listBy',
|
||||
array('action' => 'add',
|
||||
'timestamp' => $future,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression)));
|
||||
$delta_add = count($state->getAddedItems($hordeType));
|
||||
$state->setAddedItems($syncType, $registry->call($hordeType. '/list', array('filter' => $this->_filterExpression)));
|
||||
$this->_syncDataLoaded = TRUE;
|
||||
|
||||
return count($state->getAddedItems($hordeType));
|
||||
|
||||
return count($state->getAddedItems($syncType)) - $delta_add;
|
||||
}
|
||||
}
|
||||
|
@ -1,194 +1,282 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* Slow sync may just work; I think most of the work is going to be
|
||||
* done by the API.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Sync/SlowSync.php,v 1.7 2004/05/26 17:32:50 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
|
||||
class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
|
||||
|
||||
function handleSync($currentCmdID, $hordeType, $syncType, &$output, $refts) {
|
||||
global $registry;
|
||||
|
||||
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$maxMsgSize = $state->getMaxMsgSizeClient();
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
if (isset($deviceInfo['maxEntries'])) {
|
||||
$maxEntries = $deviceInfo['maxEntries'];
|
||||
if (!$maxMsgSize && !$maxEntries) {
|
||||
// fallback to default
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
} else {
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
|
||||
$serverAnchorNext = $state->getServerAnchorNext($syncType);
|
||||
|
||||
|
||||
// now we remove all UID from contentmap that have not been verified in this slowsync
|
||||
$state->removeOldUID($syncType, $serverAnchorNext);
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$counter = 0;
|
||||
|
||||
|
||||
if (isset($state->curSyncItem)) {
|
||||
// Finish the pending sync item
|
||||
$cmd = &$state->curSyncItem;
|
||||
unset($state->curSyncItem);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Sync');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = &$cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
|
||||
$adds = &$state->getAddedItems($syncType);
|
||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$syncType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if(is_array($adds)) {
|
||||
while($guid = array_shift($adds)) {
|
||||
|
||||
$currentSize = $output->getOutputSize();
|
||||
|
||||
// return if we have to much data
|
||||
if (($maxEntries && ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment']) ||
|
||||
($maxMsgSize && (($currentSize + MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
if ($locID = $state->getLocID($syncType, $guid)) {
|
||||
Horde::logMessage("SyncML: slowsync add to client: $guid ignored, already at client($locID)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'add');
|
||||
if ($guid_ts > $serverAnchorNext) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde::logMessage("SyncML: slowsync add $guid is in our future", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType));
|
||||
#Horde::logMessage("SyncML: slowsync add guid $guid to client ". print_r($c, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat']))
|
||||
{
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
Horde::logMessage("SyncML: slowsync failed to export guid $guid:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
$size = strlen($c);
|
||||
// return if we have to much data
|
||||
if ($maxMsgSize && !$deviceInfo['supportLargeObjs']) {
|
||||
if (($size + MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
Horde::logMessage("SyncML: slowsync failed to export guid $guid due to size $size", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
$cmd->setSourceURI($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
if (($currentSize + $size + MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: slowsync add guid $guid to client\n$c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat'])) {
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
$cmd->setGUID($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = &$cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
|
||||
#Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
|
||||
Horde::logMessage("SyncML: All items handled for sync $syncType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->removeExpiredUID($syncType, $serverAnchorNext);
|
||||
$state->clearSync($syncType);
|
||||
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Here's where the actual processing of a client-sent Sync
|
||||
* Command takes place. Entries are added or replaced
|
||||
* from the server database by using Horde API (Registry) calls.
|
||||
*/
|
||||
function runSyncCommand(&$command) {
|
||||
#Horde::logMessage('SyncML: content type is ' . $command->getContentType() .' moreData '. $command->_moreData, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
global $registry;
|
||||
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
if(isset($state->_moreData['luid'])) {
|
||||
if(($command->_luid == $state->_moreData['luid'])) {
|
||||
Horde::logMessage('SyncML: got next moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$lastChunks = implode('',$state->_moreData['chunks']);
|
||||
$command->_content = $lastChunks.$command->_content;
|
||||
$stringlen1 = strlen($lastChunks);
|
||||
$stringlen2 = strlen($command->_content);
|
||||
|
||||
if(!$command->_moreData && strlen($command->_content) != $state->_moreData['contentSize']) {
|
||||
$command->_status = RESPONSE_SIZE_MISMATCH;
|
||||
$state->_moreData = array();
|
||||
|
||||
return;
|
||||
} elseif(!$command->_moreData && strlen($command->_content) == $state->_moreData['contentSize']) {
|
||||
$state->_moreData = array();
|
||||
Horde::logMessage('SyncML: chunk ended successful type is ' . $command->getContentType() .' content is '. $command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
} else {
|
||||
// alert 223 needed too
|
||||
#$command->_status = ALERT_NO_END_OF_DATA;
|
||||
|
||||
$state->_moreData = array();
|
||||
|
||||
|
||||
if ($command->hasMoreData()) {
|
||||
Horde::logMessage('SyncML: moreData: TRUE', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$command->setStatus(RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED);
|
||||
return true;
|
||||
}
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
|
||||
$syncml_prefs = $GLOBALS['egw_info']['user']['preferences']['syncml'];
|
||||
if (isset($syncml_prefs[$type])) {
|
||||
$sync_conflicts = $syncml_prefs[$type];
|
||||
} else {
|
||||
$sync_conflicts = CONFLICT_SERVER_WINNING;
|
||||
}
|
||||
|
||||
$hordeType = $state->getHordeType($type);
|
||||
|
||||
$syncElementItems = $command->getSyncElementItems();
|
||||
|
||||
foreach($syncElementItems as $syncItem) {
|
||||
|
||||
$contentSize = strlen($syncItem->_content);
|
||||
if ((($size = $syncItem->getContentSize()) !== false) &&
|
||||
($contentSize != $size) &&
|
||||
($contentSize + 1 != $size)) {
|
||||
Horde::logMessage('SyncML: content size missmatch for LocURI ' . $syncItem->_luid .
|
||||
": $contentSize ($size)", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$command->setStatus(RESPONSE_SIZE_MISMATCH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// don't add/replace the data currently, they are not yet complete
|
||||
if($command->_moreData == TRUE) {
|
||||
$state->_moreData['chunks'][] = $command->_content;
|
||||
$state->_moreData['luid'] = $command->_luid;
|
||||
|
||||
// gets only set with the first chunk of data
|
||||
if(isset($command->_contentSize))
|
||||
$state->_moreData['contentSize'] = $command->_contentSize;
|
||||
|
||||
$command->_status = RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED;
|
||||
Horde::logMessage('SyncML: added moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($type);
|
||||
|
||||
$syncElementItems = $command->getSyncElementItems();
|
||||
|
||||
foreach($syncElementItems as $syncItem) {
|
||||
|
||||
if(!$contentType = $syncItem->getContentType()) {
|
||||
$contentType = $state->getPreferedContentType($type);
|
||||
}
|
||||
|
||||
|
||||
if (($contentType == 'text/x-vcalendar' || $contentType == 'text/calendar')
|
||||
&& strpos($syncItem->getContent(), 'BEGIN:VTODO') !== false)
|
||||
{
|
||||
&& strpos($syncItem->getContent(), 'BEGIN:VTODO') !== false) {
|
||||
$hordeType = 'tasks';
|
||||
}
|
||||
|
||||
|
||||
$guid = false;
|
||||
|
||||
|
||||
$guid = $registry->call($hordeType . '/search',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType, $state->getGlobalUID($type, $syncItem->getLocURI()) ));
|
||||
|
||||
|
||||
if ($guid) {
|
||||
# entry exists in database already. Just update the mapping
|
||||
Horde::logMessage('SyncML: adding mapping for locuri:'. $syncItem->getLocURI() . ' and guid:' . $guid , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, mktime());
|
||||
$state->log("Client-Replace");
|
||||
} else {
|
||||
# Entry does not exist in database: add a new one.
|
||||
$state->removeUID($type, $syncItem->getLocURI());
|
||||
Horde::logMessage('SyncML: try to add contentype ' . $contentType .' to '. $hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
if (!is_a($guid, 'PEAR_Error') && $guid != false) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-AddReplace");
|
||||
Horde::logMessage('SyncML: r/ added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Check if the found entry came from the client
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'add');
|
||||
$sync_ts = $state->getChangeTS($type, $guid);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Entry came from the client, so we get a duplicate here
|
||||
Horde::logMessage('SyncML: CONFLICT for locuri ' . $syncItem->getLocURI()
|
||||
. ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
if ($sync_conflicts != CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
$state->log("Client-AddReplaceIgnored");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Error in replacing/add client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log("Client-AddFailure");
|
||||
# Entry exists in database already. Just update the mapping
|
||||
Horde::logMessage('SyncML: adding mapping for locuri:'
|
||||
. $syncItem->getLocURI() . ' and guid:' . $guid,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, mktime());
|
||||
$state->log("Client-Map");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
// We enforce the client not to change anything
|
||||
if ($sync_conflicts > CONFLICT_CLIENT_CHANGES_IGNORED) {
|
||||
// delete this item from client
|
||||
Horde::logMessage('SyncML: Server RO! REMOVE ' . $syncItem->getLocURI()
|
||||
. ' from client', __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, '!D' . $syncItem->getLocURI());
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Server RO! REJECT all client changes',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->log("Client-AddReplaceIgnored");
|
||||
}
|
||||
$command->setStatus(RESPONSE_NO_EXECUTED);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add entry to the database.
|
||||
$state->removeUID($type, $syncItem->getLocURI());
|
||||
Horde::logMessage('SyncML: try to add contentype ' . $contentType .' to '. $hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
if (!is_a($guid, 'PEAR_Error') && $guid != false) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
if (!$ts) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
}
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-AddReplace");
|
||||
Horde::logMessage('SyncML: r/ added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Error in replacing/add client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log("Client-AddFailure");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function loadData() {
|
||||
global $registry;
|
||||
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
|
||||
$state->setTargetURI($syncType);
|
||||
$future = $state->getServerAnchorNext($syncType);
|
||||
$delta_add = 0;
|
||||
|
||||
Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setAddedItems($hordeType, $registry->call($hordeType. '/list', array()));
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
$delta_add = count($registry->call($hordeType. '/listBy',
|
||||
array('action' => 'add',
|
||||
'timestamp' => $future,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression)));
|
||||
$state->setAddedItems($syncType, $registry->call($hordeType. '/list', array('filter' => $this->_filterExpression)));
|
||||
$this->_syncDataLoaded = TRUE;
|
||||
|
||||
return count($state->getAddedItems($hordeType));
|
||||
|
||||
return count($state->getAddedItems($syncType)) - $delta_add;
|
||||
}
|
||||
}
|
||||
|
@ -1,175 +1,329 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/ContentSyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Sync/TwoWaySync.php,v 1.12 2004/07/26 09:24:38 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
*
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
|
||||
|
||||
function endSync($currentCmdID, &$output) {
|
||||
function endSync($currentCmdID, & $output) {
|
||||
global $registry;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
$syncType = $this->_targetLocURI;
|
||||
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
|
||||
$refts = $state->getServerAnchorLast($syncType);
|
||||
$currentCmdID = $this->handleSync($currentCmdID,
|
||||
$hordeType,
|
||||
$syncType,
|
||||
$output,
|
||||
$refts);
|
||||
$currentCmdID = $this->handleSync($currentCmdID, $hordeType, $syncType, $output, $refts);
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function handleSync($currentCmdID, $hordeType, $syncType,&$output, $refts) {
|
||||
function handleSync($currentCmdID, $hordeType, $syncType, & $output, $refts) {
|
||||
global $registry;
|
||||
|
||||
// array of Items which got modified, but got never send to the client before
|
||||
$missedAdds = array();
|
||||
$missedAdds = array ();
|
||||
// array of Items which the client wanted to add, but must be deleted due to
|
||||
// user's sync policy
|
||||
$remoteDeletes = array ();
|
||||
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$counter = 0;
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
$maxMsgSize = $state->getMaxMsgSizeClient();
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
$changes = &$state->getChangedItems($hordeType);
|
||||
$deletes = &$state->getDeletedItems($hordeType);
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
if (isset($deviceInfo['maxEntries'])) {
|
||||
$maxEntries = $deviceInfo['maxEntries'];
|
||||
if (!$maxMsgSize && !$maxEntries) {
|
||||
// fallback to default
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
} else {
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: ".count($changes).' changed items found for '.$hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: ".count($deletes).' deleted items found for '.$hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$serverAnchorNext = $state->getServerAnchorNext($syncType);
|
||||
|
||||
|
||||
if (isset ($state->curSyncItem)) {
|
||||
// Finish the pending sync item
|
||||
$cmd = & $state->curSyncItem;
|
||||
unset ($state->curSyncItem);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Sync');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = & $cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
|
||||
$changes = & $state->getChangedItems($syncType);
|
||||
$deletes = & $state->getDeletedItems($syncType);
|
||||
$adds = & $state->getAddedItems($syncType);
|
||||
$conflicts = & $state->getConflictItems($syncType);
|
||||
|
||||
// manage the conflict items
|
||||
foreach ( $conflicts as $refresh) {
|
||||
if (preg_match('/^!D(.*)/', $refresh, $matches)) {
|
||||
// delete locuri
|
||||
$remoteDeletes[] = $matches[1];
|
||||
} else {
|
||||
$adds[] = $refresh;
|
||||
}
|
||||
}
|
||||
|
||||
Horde :: logMessage('SyncML: ' . count($changes) . ' changed items found for ' . $syncType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage('SyncML: ' . count($deletes) . ' deleted items found for ' . $syncType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage('SyncML: ' . count($remoteDeletes) . ' items to delete on client found for ' . $syncType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage('SyncML: ' . count($adds) . ' added items (' . count($refresh) . ' refreshs) found for ' . $syncType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// handle changes
|
||||
if(is_array($changes)) {
|
||||
while($guid = array_shift($changes)) {
|
||||
if (is_array($changes)) {
|
||||
while ($guid = array_shift($changes)) {
|
||||
$currentSize = $output->getOutputSize();
|
||||
// return if we have to much data
|
||||
if (($maxEntries
|
||||
&& ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset ($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
|| ($maxMsgSize
|
||||
&& (($currentSize +MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$changes[] = $guid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$sync_ts = $state->getChangeTS($syncType, $guid);
|
||||
Horde::logMessage("SyncML: timestamp modify guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: timestamp modify $guid guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
// Don't mirror that back to the client.
|
||||
Horde::logMessage("SyncML: change: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: change: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
if ($guid_ts > $serverAnchorNext) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde :: logMessage("SyncML: change $guid is in our future: $serverAnchorNext", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
Horde::logMessage("SyncML: change $guid hs_ts:$guid_ts dt_ts:" . $state->getChangeTS($syncType, $guid), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$locid = $state->getLocID($syncType, $guid);
|
||||
if (!$locid) {
|
||||
// somehow we missed to add, lets store the uid, so we add this entry later
|
||||
$missedAdds[] = $guid;
|
||||
Horde::logMessage("SyncML: unable to create change for $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
Horde :: logMessage("SyncML: unable to create change for $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a replace request for client.
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
$c = $registry->call($hordeType. '/export',
|
||||
array('guid' => $guid, 'contentType' => $contentType));
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
$c = $registry->call($hordeType . '/export', array (
|
||||
'guid' => $guid,
|
||||
'contentType' => $contentType
|
||||
));
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
// Item in history but not in database. Strange, but can happen.
|
||||
Horde::logMessage("SyncML: change: $guid export content: $c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
# LK $cmd->setContent($state->convertServer2Client($c, $contentType));
|
||||
$cmd->setContent($c);
|
||||
$cmd->setSourceURI($guid);
|
||||
$cmd->setTargetURI($locid);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat']))
|
||||
{
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
Horde :: logMessage("SyncML: change: export of guid $guid failed:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
$size = strlen($c);
|
||||
// return if we have to much data
|
||||
if ($maxMsgSize && !$deviceInfo['supportLargeObjs']) {
|
||||
if (($size +MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
Horde :: logMessage("SyncML: change: export of guid $guid failed due to size $size", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$state->log('Server-ExportFailed');
|
||||
continue;
|
||||
}
|
||||
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Replace');
|
||||
$state->log('Server-Replace');
|
||||
|
||||
// return if we have to much data
|
||||
if (++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
if (($currentSize + $size +MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
// put the item back in the queue
|
||||
$changes[] = $guid;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
Horde :: logMessage("SyncML: change: export guid $guid, content:\n$c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
# LK $cmd->setContent($state->convertServer2Client($c, $contentType));
|
||||
$cmd->setContent($c);
|
||||
$cmd->setLocURI($locid);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset ($contentType['ContentFormat'])) {
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Replace');
|
||||
$state->log('Server-Replace');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = & $cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
Horde::logMessage("SyncML: handling sync (changes done) ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: handling sync (changes done) " . $currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// handle deletes
|
||||
if(is_array($deletes)) {
|
||||
while($guid = array_shift($deletes)) {
|
||||
if (is_array($deletes)) {
|
||||
while ($guid = array_shift($deletes)) {
|
||||
$currentSize = $output->getOutputSize();
|
||||
// return if we have to much data
|
||||
if (($maxEntries && ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset ($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
|| ($maxMsgSize
|
||||
&& (($currentSize +MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$deletes[] = $guid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'delete');
|
||||
$sync_ts = $state->getChangeTS($syncType, $guid);
|
||||
Horde::logMessage("SyncML: timestamp delete guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: timestamp delete guid_ts: $guid_ts sync_ts: $sync_ts",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
// Don't mirror that back to the client.
|
||||
Horde::logMessage("SyncML: delete $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: delete $guid ignored, came from client",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts < $serverAnchorNext
|
||||
&& ($locid = $state->getLocID($syncType, $guid))) {
|
||||
// Now we can remove the past
|
||||
$state->removeUID($syncType, $locid);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($guid_ts > $serverAnchorNext) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde :: logMessage("SyncML: delete $guid is in our future: $serverAnchorNext", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
$locid = $state->getLocID($syncType, $guid);
|
||||
if (!$locid) {
|
||||
Horde::logMessage("SyncML: unable to create delete for $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
Horde :: logMessage("SyncML: unable to delete $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$state->log("Server-DeleteFailure");
|
||||
continue;
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: delete: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: delete: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Create a Delete request for client.
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$cmd->setTargetURI($locid);
|
||||
$cmd->setSourceURI($guid);
|
||||
$cmd->setLocURI($locid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Delete');
|
||||
$state->log('Server-Delete');
|
||||
$state->removeUID($syncType, $locid);
|
||||
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = & $cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
|
||||
// handle remote deletes due to conflicts
|
||||
if (count($remoteDeletes) > 0) {
|
||||
while ($locid = array_shift($remoteDeletes)) {
|
||||
$currentSize = $output->getOutputSize();
|
||||
// return if we have to much data
|
||||
if (($maxEntries && ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset ($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
|| ($maxMsgSize
|
||||
&& (($currentSize +MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$remoteDeletes[] = $locid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
Horde :: logMessage("SyncML: delete client locid: $locid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Create a Delete request for client.
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$cmd->setLocURI($locid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Delete');
|
||||
$state->log('Server-DeletedConflicts');
|
||||
$state->removeUID($syncType, $locid);
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = & $cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
#Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// handle missing adds.
|
||||
if(count($missedAdds) > 0) {
|
||||
Horde::logMessage("SyncML: add missed changes as adds ".count($adds).' / '.$missedAdds[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setAddedItems($hordeType, array_merge($adds, $missedAdds));
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
Horde::logMessage("SyncML: merged adds counter ".count($adds).' / '.$adds[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (count($missedAdds) > 0) {
|
||||
Horde :: logMessage("SyncML: add missed changes as adds " . count($adds) . ' / ' . $missedAdds[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$adds = array_merge($adds, $missedAdds);
|
||||
Horde :: logMessage("SyncML: merged adds counter " . count($adds) . ' / ' . $adds[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
if(is_array($adds)) {
|
||||
while($guid = array_shift($adds)) {
|
||||
if (is_array($adds)) {
|
||||
while ($guid = array_shift($adds)) {
|
||||
$currentSize = $output->getOutputSize();
|
||||
// return if we have to much data
|
||||
if (($maxEntries && ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset ($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
|| ($maxMsgSize
|
||||
&& (($currentSize +MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'add');
|
||||
$sync_ts = $state->getChangeTS($syncType, $guid);
|
||||
Horde::logMessage("SyncML: timestamp add $guid guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: timestamp add $guid guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
// Don't mirror that back to the client.
|
||||
Horde::logMessage("SyncML: add: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: add: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
if ($guid_ts > $serverAnchorNext && !in_array($guid, $conflicts)) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde :: logMessage("SyncML: add $guid is in our future: $serverAnchorNext", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -179,47 +333,65 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
|
||||
// For slow sync (ts=0): do not add data for which we
|
||||
// have a locid again. This is a heuristic to avoid
|
||||
// duplication of entries.
|
||||
Horde::logMessage("SyncML: skipping add of guid $guid as there already is a locid $locid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: skipping add of guid $guid as there already is a locid $locid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
Horde::logMessage("SyncML: add: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: add: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Create an Add request for client.
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$c = $registry->call($hordeType . '/export',
|
||||
array(
|
||||
'guid' => $guid ,
|
||||
'contentType' => $contentType ,
|
||||
)
|
||||
);
|
||||
$c = $registry->call($hordeType . '/export', array (
|
||||
'guid' => $guid,
|
||||
'contentType' => $contentType,
|
||||
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
));
|
||||
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
// Item in history but not in database. Strange, but can happen.
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat']))
|
||||
{
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
$cmd->setSourceURI($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
Horde :: logMessage("SyncML: add: export of guid $guid failed:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
$size = strlen($c);
|
||||
// return if we have to much data
|
||||
if ($maxMsgSize && !$deviceInfo['supportLargeObjs']) {
|
||||
if (($size +MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
Horde :: logMessage("SyncML: add: export of guid $guid failed due to size $size", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$state->log("Server-ExportFailed");
|
||||
continue;
|
||||
}
|
||||
if (($currentSize + $size +MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
Horde :: logMessage("SyncML: add guid $guid to client\n$c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset ($contentType['ContentFormat'])) {
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
$cmd->setGUID($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// moreData split; put the guid back in the list and return
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = & $cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
#Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: All items handled for sync $syncType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->removeExpiredUID($syncType, time());
|
||||
$state->clearSync($syncType);
|
||||
|
||||
return $currentCmdID;
|
||||
@ -228,24 +400,53 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
|
||||
function loadData() {
|
||||
global $registry;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
$state->setTargetURI($syncType);
|
||||
$refts = $state->getServerAnchorLast($syncType);
|
||||
$future = $state->getServerAnchorNext($syncType);
|
||||
$delta_mod = 0;
|
||||
$delta_add = 0;
|
||||
|
||||
Horde::logMessage("SyncML: reading changed items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setChangedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'modify', 'timestamp' => $refts)));
|
||||
Horde :: logMessage("SyncML: reading changed items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$delta_mod = count($registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'modify',
|
||||
'timestamp' => $future,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
$state->setChangedItems($syncType, $registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'modify',
|
||||
'timestamp' => $refts,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
|
||||
Horde::logMessage("SyncML: reading deleted items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setDeletedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'delete', 'timestamp' => $refts)));
|
||||
Horde :: logMessage("SyncML: reading deleted items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setDeletedItems($syncType, $registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'delete',
|
||||
'timestamp' => $refts,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
|
||||
Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setAddedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'add', 'timestamp' => $refts)));
|
||||
Horde :: logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$delta_add = count($registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'add',
|
||||
'timestamp' => $future,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
$state->setAddedItems($syncType, $registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'add',
|
||||
'timestamp' => $refts,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
|
||||
$this->_syncDataLoaded = TRUE;
|
||||
|
||||
return count($state->getChangedItems($hordeType)) +
|
||||
count($state->getDeletedItems($hordeType)) +
|
||||
count($state->getAddedItems($hordeType));
|
||||
return count($state->getChangedItems($syncType)) - $delta_mod +count($state->getDeletedItems($syncType)) + count($state->getAddedItems($syncType)) - $delta_add +count($state->getConflictItems($syncType));
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vAlarms.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/valarm.php,v 1.8 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/valarm.php,v 1.8.10.8 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,11 +20,6 @@ class Horde_iCalendar_valarm extends Horde_iCalendar {
|
||||
return 'vAlarm';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VALARM');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VALARM');
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
require_once EGW_API_INC.'/horde/Horde/iCalendar.php';
|
||||
|
||||
|
||||
// The following were shamelessly yoinked from Contact_Vcard_Build
|
||||
// Part numbers for N components.
|
||||
define('VCARD_N_FAMILY', 0);
|
||||
@ -27,49 +26,47 @@ define('VCARD_GEO_LON', 1);
|
||||
/**
|
||||
* Class representing vCard entries.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vcard.php,v 1.2 2004/08/18 03:16:24 chuck Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vcard.php,v 1.3.10.16 2008/09/22 04:16:30 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Karsten Fourmont (karsten@horde.org)
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Karsten Fourmont <karsten@horde.org>
|
||||
* @version $Revision$
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_vcard extends Horde_iCalendar {
|
||||
|
||||
function Horde_iCalendar_vcard($version = '2.1')
|
||||
{
|
||||
return parent::Horde_iCalendar($version);
|
||||
}
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'vcard';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
return parent::parsevCalendar($data, 'vcard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike vevent and vtodo, a vcard is normally not enclosed in an
|
||||
* iCalendar container. (BEGIN..END)
|
||||
*/
|
||||
function exportvCalendar()
|
||||
{
|
||||
#$requiredAttributes['BODY'] = '';
|
||||
$requiredAttributes['VERSION'] = '2.1';
|
||||
$requiredAttributes['VERSION'] = $this->_version;
|
||||
$requiredAttributes['N'] = ';;;;;;';
|
||||
if ($this->_version == '3.0') {
|
||||
$requiredAttributes['FN'] = '';
|
||||
}
|
||||
|
||||
foreach ($requiredAttributes as $name => $default_value) {
|
||||
if (is_a($this->getattribute($name), 'PEAR_Error')) {
|
||||
if (is_a($this->getAttribute($name), 'PEAR_Error')) {
|
||||
$this->setAttribute($name, $default_value);
|
||||
}
|
||||
}
|
||||
//error_log(__METHOD__.":requiredAttributes->".print_r($requiredAttributes,true));
|
||||
//njv:$buffcontent = ob_get_clean();
|
||||
#error_log(__METHOD__.":".print_r($buffcontent,true));
|
||||
#ob_end_clean();
|
||||
|
||||
return $this->_exportvData('VCARD') . $this->_newline;
|
||||
return $this->_exportvData('VCARD');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,8 +77,7 @@ class Horde_iCalendar_vcard extends Horde_iCalendar {
|
||||
* to
|
||||
* "Professor Dagobert T Duck Sen"
|
||||
*
|
||||
* @return string Full name of vcard "N" tag
|
||||
* or null if no N tag.
|
||||
* @return string Full name of vcard "N" tag or null if no N tag.
|
||||
*/
|
||||
function printableName()
|
||||
{
|
||||
@ -90,6 +86,8 @@ class Horde_iCalendar_vcard extends Horde_iCalendar {
|
||||
return null;
|
||||
}
|
||||
|
||||
$name_arr = array();
|
||||
|
||||
if (!empty($name_parts[VCARD_N_PREFIX])) {
|
||||
$name_arr[] = $name_parts[VCARD_N_PREFIX];
|
||||
}
|
||||
@ -118,6 +116,11 @@ class Horde_iCalendar_vcard extends Horde_iCalendar {
|
||||
*/
|
||||
function getBareEmail($address)
|
||||
{
|
||||
// Empty values are still empty.
|
||||
if (!$address) {
|
||||
return $address;
|
||||
}
|
||||
|
||||
require_once 'Mail/RFC822.php';
|
||||
require_once 'Horde/MIME.php';
|
||||
|
||||
@ -126,8 +129,9 @@ class Horde_iCalendar_vcard extends Horde_iCalendar {
|
||||
$rfc822 = new Mail_RFC822();
|
||||
}
|
||||
|
||||
$rfc822->validateMailbox($address);
|
||||
|
||||
if (!$rfc822->validateMailbox($address)) {
|
||||
return $address;
|
||||
}
|
||||
return MIME::rfc822WriteAddress($address->mailbox, $address->host);
|
||||
}
|
||||
|
||||
|
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vEvents.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vevent.php,v 1.31 2004/08/18 03:16:24 chuck Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vevent.php,v 1.31.10.15 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,32 +20,28 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
return 'vEvent';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VEVENT');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
// Default values.
|
||||
$requiredAttributes = array();
|
||||
$requiredAttributes['DTSTAMP'] = time();
|
||||
#$requiredAttributes['ORGANIZER'] = 'Unknown Organizer';
|
||||
$requiredAttributes['UID'] = $this->_exportDateTime(time()) . '@' . $_SERVER['SERVER_NAME'];
|
||||
$requiredAttributes['UID'] = $this->_exportDateTime(time())
|
||||
. substr(str_pad(base_convert(microtime(), 10, 36), 16, uniqid(mt_rand()), STR_PAD_LEFT), -16)
|
||||
. '@' . (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost');
|
||||
|
||||
$method = !empty($this->_container) ?
|
||||
$this->_container->getAttribute('METHOD') : 'PUBLISH';
|
||||
|
||||
switch ($method) {
|
||||
case 'PUBLISH':
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
break;
|
||||
|
||||
case 'REQUEST':
|
||||
$requiredAttributes['ATTENDEE'] = '';
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
break;
|
||||
|
||||
case 'REPLY':
|
||||
@ -54,9 +49,9 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
break;
|
||||
|
||||
case 'ADD':
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SEQUENCE'] = 1;
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
break;
|
||||
|
||||
case 'CANCEL':
|
||||
@ -88,7 +83,8 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
function updateAttendee($email, $status, $fullname = '')
|
||||
{
|
||||
foreach ($this->_attributes as $key => $attribute) {
|
||||
if ($attribute['name'] == 'ATTENDEE' && $attribute['value'] == 'MAILTO:' . $email) {
|
||||
if ($attribute['name'] == 'ATTENDEE' &&
|
||||
$attribute['value'] == 'mailto:' . $email) {
|
||||
$this->_attributes[$key]['params']['PARTSTAT'] = $status;
|
||||
if (!empty($fullname)) {
|
||||
$this->_attributes[$key]['params']['CN'] = $fullname;
|
||||
@ -101,7 +97,7 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
if (!empty($fullname)) {
|
||||
$params['CN'] = $fullname;
|
||||
}
|
||||
$this->setAttribute('ATTENDEE', 'MAILTO:' . $email, $params);
|
||||
$this->setAttribute('ATTENDEE', 'mailto:' . $email, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,7 +109,7 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
{
|
||||
$organizer = $this->getAttribute('ORGANIZER', true);
|
||||
if (is_a($organizer, 'PEAR_Error')) {
|
||||
return null;
|
||||
return _("An unknown person");
|
||||
}
|
||||
|
||||
if (isset($organizer[0]['CN'])) {
|
||||
@ -128,7 +124,7 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
/**
|
||||
* Update this event with details from another event.
|
||||
*
|
||||
* @param object Horde_iCalendar_vEvent $vevent The vEvent with latest details.
|
||||
* @param Horde_iCalendar_vEvent $vevent The vEvent with latest details.
|
||||
*/
|
||||
function updateFromvEvent($vevent)
|
||||
{
|
||||
@ -137,7 +133,9 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
$currentValue = $this->getAttribute($newAttribute['name']);
|
||||
if (is_a($currentValue, 'PEAR_error')) {
|
||||
// Already exists so just add it.
|
||||
$this->setAttribute($newAttribute['name'], $newAttribute['value'], $newAttribute['params']);
|
||||
$this->setAttribute($newAttribute['name'],
|
||||
$newAttribute['value'],
|
||||
$newAttribute['params']);
|
||||
} else {
|
||||
// Already exists so locate and modify.
|
||||
$found = false;
|
||||
@ -178,19 +176,21 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
* Update just the attendess of event with details from another
|
||||
* event.
|
||||
*
|
||||
* @param object Horde_iCalendar_vEvent $vevent The vEvent with latest details
|
||||
* @param Horde_iCalendar_vEvent $vevent The vEvent with latest details
|
||||
*/
|
||||
function updateAttendeesFromvEvent($vevent)
|
||||
{
|
||||
$newAttributes = $vevent->getAllAttributes();
|
||||
foreach ($newAttributes as $newAttribute) {
|
||||
if (!$newAttribute['name'] == 'ATTENDEE') {
|
||||
if ($newAttribute['name'] != 'ATTENDEE') {
|
||||
continue;
|
||||
}
|
||||
$currentValue = $this->getAttribute($newAttribute['name']);
|
||||
if (is_a($currentValue, 'PEAR_error')) {
|
||||
// Already exists so just add it.
|
||||
$this->setAttribute($newAttribute['name'], $newAttribute['value'], $newAttribute['params']);
|
||||
$this->setAttribute($newAttribute['name'],
|
||||
$newAttribute['value'],
|
||||
$newAttribute['params']);
|
||||
} else {
|
||||
// Already exists so locate and modify.
|
||||
$found = false;
|
||||
|
@ -1,52 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* Class representing vFreebusys.
|
||||
* Class representing vFreebusy components.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vfreebusy.php,v 1.16 2004/08/18 03:16:24 chuck Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vfreebusy.php,v 1.16.10.17 2008/09/17 08:46:57 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @todo Don't use timestamps
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
|
||||
var $_busyPeriods = array();
|
||||
var $_extraParams = array();
|
||||
|
||||
/**
|
||||
* Returns the type of this calendar component.
|
||||
*
|
||||
* @return string The type of this component.
|
||||
*/
|
||||
function getType()
|
||||
{
|
||||
return 'vFreebusy';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
/**
|
||||
* Parses a string containing vFreebusy data.
|
||||
*
|
||||
* @param string $data The data to parse.
|
||||
*/
|
||||
function parsevCalendar($data, $type = null, $charset = null)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VFREEBUSY');
|
||||
parent::parsevCalendar($data, 'VFREEBUSY', $charset);
|
||||
|
||||
// Do something with all the busy periods.
|
||||
foreach ($this->_attributes as $key => $attribute) {
|
||||
if ($attribute['name'] == 'FREEBUSY') {
|
||||
foreach ($attribute['value'] as $value) {
|
||||
if (array_key_exists('duration', $attribute['value'])) {
|
||||
$this->addBusyPeriod('BUSY', $value['start'], null, $value['duration']);
|
||||
} else {
|
||||
$this->addBusyPeriod('BUSY', $value['start'], $value['end']);
|
||||
}
|
||||
}
|
||||
unset($this->_attributes[$key]);
|
||||
if ($attribute['name'] != 'FREEBUSY') {
|
||||
continue;
|
||||
}
|
||||
foreach ($attribute['values'] as $value) {
|
||||
$params = isset($attribute['params'])
|
||||
? $attribute['params']
|
||||
: array();
|
||||
if (isset($value['duration'])) {
|
||||
$this->addBusyPeriod('BUSY', $value['start'], null,
|
||||
$value['duration'], $params);
|
||||
} else {
|
||||
$this->addBusyPeriod('BUSY', $value['start'],
|
||||
$value['end'], null, $params);
|
||||
}
|
||||
}
|
||||
unset($this->_attributes[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component exported as string.
|
||||
*
|
||||
* @return string The exported vFreeBusy information according to the
|
||||
* iCalender format specification.
|
||||
*/
|
||||
function exportvCalendar()
|
||||
{
|
||||
foreach ($this->_busyPeriods as $start => $end) {
|
||||
$periods = array(array('start' => $start, 'end' => $end));
|
||||
$this->setAttribute('FREEBUSY', $periods);
|
||||
$this->setAttribute('FREEBUSY', $periods,
|
||||
isset($this->_extraParams[$start])
|
||||
? $this->_extraParams[$start] : array());
|
||||
}
|
||||
|
||||
$res = parent::_exportvData('VFREEBUSY');
|
||||
@ -61,7 +87,9 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a display name for this object.
|
||||
* Returns a display name for this object.
|
||||
*
|
||||
* @return string A clear text name for displaying this object.
|
||||
*/
|
||||
function getName()
|
||||
{
|
||||
@ -71,12 +99,12 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
|
||||
if (is_a($method, 'PEAR_Error') || $method == 'PUBLISH') {
|
||||
$attr = 'ORGANIZER';
|
||||
} else if ($method == 'REPLY') {
|
||||
} elseif ($method == 'REPLY') {
|
||||
$attr = 'ATTENDEE';
|
||||
}
|
||||
|
||||
$name = $this->getAttribute($attr, true);
|
||||
if (array_key_exists('CN', $name[0])) {
|
||||
if (!is_a($name, 'PEAR_Error') && isset($name[0]['CN'])) {
|
||||
return $name[0]['CN'];
|
||||
}
|
||||
|
||||
@ -90,7 +118,9 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email address for this object.
|
||||
* Returns the email address for this object.
|
||||
*
|
||||
* @return string The email address of this object's owner.
|
||||
*/
|
||||
function getEmail()
|
||||
{
|
||||
@ -100,7 +130,7 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
|
||||
if (is_a($method, 'PEAR_Error') || $method == 'PUBLISH') {
|
||||
$attr = 'ORGANIZER';
|
||||
} else if ($method == 'REPLY') {
|
||||
} elseif ($method == 'REPLY') {
|
||||
$attr = 'ATTENDEE';
|
||||
}
|
||||
|
||||
@ -113,13 +143,34 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the busy periods.
|
||||
*
|
||||
* @return array All busy periods.
|
||||
*/
|
||||
function getBusyPeriods()
|
||||
{
|
||||
return $this->_busyPeriods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the free periods of time in a given period.
|
||||
* Returns any additional freebusy parameters.
|
||||
*
|
||||
* @return array Additional parameters of the freebusy periods.
|
||||
*/
|
||||
function getExtraParams()
|
||||
{
|
||||
return $this->_extraParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the free periods of time in a given period.
|
||||
*
|
||||
* @param integer $startStamp The start timestamp.
|
||||
* @param integer $endStamp The end timestamp.
|
||||
*
|
||||
* @return array A hash with free time periods, the start times as the
|
||||
* keys and the end times as the values.
|
||||
*/
|
||||
function getFreePeriods($startStamp, $endStamp)
|
||||
{
|
||||
@ -131,21 +182,21 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
return $periods;
|
||||
}
|
||||
|
||||
// Locate the first time in the requested period we have data
|
||||
// for.
|
||||
// Locate the first time in the requested period we have data for.
|
||||
$nextstart = max($startStamp, $this->getStart());
|
||||
|
||||
// Check each busy period and add free periods in between.
|
||||
foreach ($this->_busyPeriods as $start => $end) {
|
||||
if ($start <= $endStamp && $end >= $nextstart) {
|
||||
$periods[$nextstart] = min($start, $endStamp);
|
||||
if ($nextstart <= $start) {
|
||||
$periods[$nextstart] = min($start, $endStamp);
|
||||
}
|
||||
$nextstart = min($end, $endStamp);
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't read the end of the requested period but still
|
||||
// have data then mark as free to the end of the period or
|
||||
// available data.
|
||||
// If we didn't read the end of the requested period but still have
|
||||
// data then mark as free to the end of the period or available data.
|
||||
if ($nextstart < $endStamp && $nextstart < $this->getEnd()) {
|
||||
$periods[$nextstart] = min($this->getEnd(), $endStamp);
|
||||
}
|
||||
@ -154,16 +205,29 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a busy period to the info.
|
||||
* Adds a busy period to the info.
|
||||
*
|
||||
* This function may throw away data in case you add a period with a start
|
||||
* date that already exists. The longer of the two periods will be chosen
|
||||
* (and all information associated with the shorter one will be removed).
|
||||
*
|
||||
* @param string $type The type of the period. Either 'FREE' or
|
||||
* 'BUSY'; only 'BUSY' supported at the moment.
|
||||
* @param integer $start The start timestamp of the period.
|
||||
* @param integer $end The end timestamp of the period.
|
||||
* @param integer $duration The duration of the period. If specified, the
|
||||
* $end parameter will be ignored.
|
||||
* @param array $extra Additional parameters for this busy period.
|
||||
*/
|
||||
function addBusyPeriod($type, $start, $end = null, $duration = null)
|
||||
function addBusyPeriod($type, $start, $end = null, $duration = null,
|
||||
$extra = array())
|
||||
{
|
||||
if ($type == "FREE") {
|
||||
if ($type == 'FREE') {
|
||||
// Make sure this period is not marked as busy.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the end time is duration was specified.
|
||||
// Calculate the end time if duration was specified.
|
||||
$tempEnd = is_null($duration) ? $end : $start + $duration;
|
||||
|
||||
// Make sure the period length is always positive.
|
||||
@ -171,26 +235,35 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
$start = min($start, $tempEnd);
|
||||
|
||||
if (isset($this->_busyPeriods[$start])) {
|
||||
// Already a period starting at this time. Extend to the
|
||||
// length of the longest of the two.
|
||||
$this->_busyPeriods[$start] = max($end, $this->_busyPeriods[$start]);
|
||||
// Already a period starting at this time. Change the current
|
||||
// period only if the new one is longer. This might be a problem
|
||||
// if the callee assumes that there is no simplification going
|
||||
// on. But since the periods are stored using the start time of
|
||||
// the busy periods we have to throw away data here.
|
||||
if ($end > $this->_busyPeriods[$start]) {
|
||||
$this->_busyPeriods[$start] = $end;
|
||||
$this->_extraParams[$start] = $extra;
|
||||
}
|
||||
} else {
|
||||
// Add a new busy period.
|
||||
$this->_busyPeriods[$start] = $end;
|
||||
$this->_extraParams[$start] = $extra;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp of the start of the time period this free
|
||||
* busy information covers.
|
||||
* Returns the timestamp of the start of the time period this free busy
|
||||
* information covers.
|
||||
*
|
||||
* @return integer A timestamp.
|
||||
*/
|
||||
function getStart()
|
||||
{
|
||||
if (!is_a($this->getAttribute('DTSTART'), 'PEAR_Error')) {
|
||||
return $this->getAttribute('DTSTART');
|
||||
} else if (count($this->_busyPeriods)) {
|
||||
} elseif (count($this->_busyPeriods)) {
|
||||
return min(array_keys($this->_busyPeriods));
|
||||
} else {
|
||||
return false;
|
||||
@ -198,14 +271,16 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp of the end of the time period this free busy
|
||||
* Returns the timestamp of the end of the time period this free busy
|
||||
* information covers.
|
||||
*
|
||||
* @return integer A timestamp.
|
||||
*/
|
||||
function getEnd()
|
||||
{
|
||||
if (!is_a($this->getAttribute('DTEND'), 'PEAR_Error')) {
|
||||
return $this->getAttribute('DTEND');
|
||||
} else if (count($this->_busyPeriods)) {
|
||||
} elseif (count($this->_busyPeriods)) {
|
||||
return max(array_values($this->_busyPeriods));
|
||||
} else {
|
||||
return false;
|
||||
@ -213,7 +288,16 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the busy periods of another VFreebusy into this one.
|
||||
* Merges the busy periods of another Horde_iCalendar_vfreebusy object
|
||||
* into this one.
|
||||
*
|
||||
* This might lead to simplification no matter what you specify for the
|
||||
* "simplify" flag since periods with the same start date will lead to the
|
||||
* shorter period being removed (see addBusyPeriod).
|
||||
*
|
||||
* @param Horde_iCalendar_vfreebusy $freebusy A freebusy object.
|
||||
* @param boolean $simplify If true, simplify() will
|
||||
* called after the merge.
|
||||
*/
|
||||
function merge($freebusy, $simplify = true)
|
||||
{
|
||||
@ -221,70 +305,155 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
return false;
|
||||
}
|
||||
|
||||
$extra = $freebusy->getExtraParams();
|
||||
foreach ($freebusy->getBusyPeriods() as $start => $end) {
|
||||
$this->addBusyPeriod('BUSY', $start, $end);
|
||||
// This might simplify the busy periods without taking the
|
||||
// "simplify" flag into account.
|
||||
$this->addBusyPeriod('BUSY', $start, $end, null,
|
||||
isset($extra[$start])
|
||||
? $extra[$start] : array());
|
||||
}
|
||||
|
||||
$thisattr = $this->getAttribute('DTSTART');
|
||||
$thatattr = $freebusy->getAttribute('DTSTART');
|
||||
if (is_a($thisattr, 'PEAR_Error') && !is_a($thatattr, 'PEAR_Error')) {
|
||||
$this->setAttribute('DTSTART', $thatattr);
|
||||
$this->setAttribute('DTSTART', $thatattr, array(), false);
|
||||
} elseif (!is_a($thatattr, 'PEAR_Error')) {
|
||||
if ($thatattr > $thisattr) {
|
||||
$this->setAttribute('DTSTART', $thatattr);
|
||||
if ($thatattr < $thisattr) {
|
||||
$this->setAttribute('DTSTART', $thatattr, array(), false);
|
||||
}
|
||||
}
|
||||
|
||||
$thisattr = $this->getAttribute('DTEND');
|
||||
$thatattr = $freebusy->getAttribute('DTEND');
|
||||
if (is_a($thisattr, 'PEAR_Error') && !is_a($thatattr, 'PEAR_Error')) {
|
||||
$this->setAttribute('DTEND', $thatattr);
|
||||
$this->setAttribute('DTEND', $thatattr, array(), false);
|
||||
} elseif (!is_a($thatattr, 'PEAR_Error')) {
|
||||
if ($thatattr < $thisattr) {
|
||||
$this->setAttribute('DTEND', $thatattr);
|
||||
if ($thatattr > $thisattr) {
|
||||
$this->setAttribute('DTEND', $thatattr, array(), false);
|
||||
}
|
||||
}
|
||||
|
||||
if ($simplify) {
|
||||
$this->simplify();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all overlaps and simplify the busy periods array as much
|
||||
* as possible.
|
||||
* Removes all overlaps and simplifies the busy periods array as much as
|
||||
* possible.
|
||||
*/
|
||||
function simplify()
|
||||
{
|
||||
$clean = false;
|
||||
$busy = array($this->_busyPeriods, $this->_extraParams);
|
||||
while (!$clean) {
|
||||
$result = $this->_simplify($busy[0], $busy[1]);
|
||||
$clean = $result === $busy;
|
||||
$busy = $result;
|
||||
}
|
||||
|
||||
ksort($result[1], SORT_NUMERIC);
|
||||
$this->_extraParams = $result[1];
|
||||
|
||||
ksort($result[0], SORT_NUMERIC);
|
||||
$this->_busyPeriods = $result[0];
|
||||
}
|
||||
|
||||
function _simplify($busyPeriods, $extraParams = array())
|
||||
{
|
||||
$checked = array();
|
||||
$checkedExtra = array();
|
||||
$checkedEmpty = true;
|
||||
foreach ($this->_busyPeriods as $start => $end) {
|
||||
|
||||
foreach ($busyPeriods as $start => $end) {
|
||||
if ($checkedEmpty) {
|
||||
$checked[$start] = $end;
|
||||
$checkedExtra[$start] = isset($extraParams[$start])
|
||||
? $extraParams[$start] : array();
|
||||
$checkedEmpty = false;
|
||||
} else {
|
||||
$added = false;
|
||||
foreach ($checked as $testStart => $testEnd) {
|
||||
if ($start == $testStart) {
|
||||
$checked[$testStart] = max($testEnd, $end);
|
||||
$added = true;
|
||||
} else if ($end <= $testEnd && $end >= $testStart) {
|
||||
// Replace old period if the new period lies around the
|
||||
// old period.
|
||||
if ($start <= $testStart && $end >= $testEnd) {
|
||||
// Remove old period entry.
|
||||
unset($checked[$testStart]);
|
||||
$checked[min($testStart, $start)] = max($testEnd, $end);
|
||||
unset($checkedExtra[$testStart]);
|
||||
// Add replacing entry.
|
||||
$checked[$start] = $end;
|
||||
$checkedExtra[$start] = isset($extraParams[$start])
|
||||
? $extraParams[$start] : array();
|
||||
$added = true;
|
||||
} elseif ($start >= $testStart && $end <= $testEnd) {
|
||||
// The new period lies fully within the old
|
||||
// period. Just forget about it.
|
||||
$added = true;
|
||||
} elseif (($end <= $testEnd && $end >= $testStart) ||
|
||||
($start >= $testStart && $start <= $testEnd)) {
|
||||
// Now we are in trouble: Overlapping time periods. If
|
||||
// we allow for additional parameters we cannot simply
|
||||
// choose one of the two parameter sets. It's better
|
||||
// to leave two separated time periods.
|
||||
$extra = isset($extraParams[$start])
|
||||
? $extraParams[$start] : array();
|
||||
$testExtra = isset($checkedExtra[$testStart])
|
||||
? $checkedExtra[$testStart] : array();
|
||||
// Remove old period entry.
|
||||
unset($checked[$testStart]);
|
||||
unset($checkedExtra[$testStart]);
|
||||
// We have two periods overlapping. Are their
|
||||
// additional parameters the same or different?
|
||||
$newStart = min($start, $testStart);
|
||||
$newEnd = max($end, $testEnd);
|
||||
if ($extra === $testExtra) {
|
||||
// Both periods have the same information. So we
|
||||
// can just merge.
|
||||
$checked[$newStart] = $newEnd;
|
||||
$checkedExtra[$newStart] = $extra;
|
||||
} else {
|
||||
// Extra parameters are different. Create one
|
||||
// period at the beginning with the params of the
|
||||
// first period and create a trailing period with
|
||||
// the params of the second period. The break
|
||||
// point will be the end of the first period.
|
||||
$break = min($end, $testEnd);
|
||||
$checked[$newStart] = $break;
|
||||
$checkedExtra[$newStart] =
|
||||
isset($extraParams[$newStart])
|
||||
? $extraParams[$newStart] : array();
|
||||
$checked[$break] = $newEnd;
|
||||
$highStart = max($start, $testStart);
|
||||
$checkedExtra[$break] =
|
||||
isset($extraParams[$highStart])
|
||||
? $extraParams[$highStart] : array();
|
||||
|
||||
// Ensure we also have the extra data in the
|
||||
// extraParams.
|
||||
$extraParams[$break] =
|
||||
isset($extraParams[$highStart])
|
||||
? $extraParams[$highStart] : array();
|
||||
}
|
||||
$added = true;
|
||||
}
|
||||
|
||||
if ($added) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$added) {
|
||||
$checked[$start] = $end;
|
||||
$checkedExtra[$start] = isset($extraParams[$start])
|
||||
? $extraParams[$start] : array();
|
||||
}
|
||||
}
|
||||
}
|
||||
ksort($checked, SORT_NUMERIC);
|
||||
$this->_busyPeriods = $checked;
|
||||
|
||||
return array($checked, $checkedExtra);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vJournals.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vjournal.php,v 1.8 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vjournal.php,v 1.8.10.8 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,11 +20,6 @@ class Horde_iCalendar_vjournal extends Horde_iCalendar {
|
||||
return 'vJournal';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VJOURNAL');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VJOURNAL');
|
||||
|
@ -5,29 +5,29 @@ require_once EGW_API_INC.'/horde/Horde/iCalendar.php';
|
||||
/**
|
||||
* Class representing vNotes.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vnote.php,v 1.2 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vnote.php,v 1.3.10.9 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @version $Revision$
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_vnote extends Horde_iCalendar {
|
||||
|
||||
function Horde_iCalendar_vnote($version = '1.1')
|
||||
{
|
||||
return parent::Horde_iCalendar($version);
|
||||
}
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'vNote';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
return parent::parsevCalendar($data, 'VNOTE');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike vevent and vtodo, a vnote is normally not enclosed in an
|
||||
* iCalendar container. (BEGIN..END)
|
||||
@ -43,7 +43,7 @@ class Horde_iCalendar_vnote extends Horde_iCalendar {
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_exportvData('VNOTE') . $this->_newline;
|
||||
return $this->_exportvData('VNOTE');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vTimezones.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vtimezone.php,v 1.8 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vtimezone.php,v 1.8.10.9 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,16 +20,145 @@ class Horde_iCalendar_vtimezone extends Horde_iCalendar {
|
||||
return 'vTimeZone';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VTIMEZONE');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VTIMEZONE');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse child components of the vTimezone component. Returns an
|
||||
* array with the exact time of the time change as well as the
|
||||
* 'from' and 'to' offsets around the change. Time is arbitrarily
|
||||
* based on UTC for comparison.
|
||||
*/
|
||||
function parseChild(&$child, $year)
|
||||
{
|
||||
// Make sure 'time' key is first for sort().
|
||||
$result['time'] = 0;
|
||||
|
||||
$t = $child->getAttribute('TZOFFSETFROM');
|
||||
if (is_a($t, 'PEAR_Error')) {
|
||||
return false;
|
||||
}
|
||||
$result['from'] = ($t['hour'] * 60 * 60 + $t['minute'] * 60) * ($t['ahead'] ? 1 : -1);
|
||||
|
||||
$t = $child->getAttribute('TZOFFSETTO');
|
||||
if (is_a($t, 'PEAR_Error')) {
|
||||
return false;
|
||||
}
|
||||
$result['to'] = ($t['hour'] * 60 * 60 + $t['minute'] * 60) * ($t['ahead'] ? 1 : -1);
|
||||
|
||||
$switch_time = $child->getAttribute('DTSTART');
|
||||
if (is_a($switch_time, 'PEAR_Error')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rrules = $child->getAttribute('RRULE');
|
||||
if (is_a($rrules, 'PEAR_Error')) {
|
||||
if (!is_int($switch_time)) {
|
||||
return false;
|
||||
}
|
||||
// Convert this timestamp from local time to UTC for
|
||||
// comparison (All dates are compared as if they are UTC).
|
||||
$t = getdate($switch_time);
|
||||
$result['time'] = @gmmktime($t['hours'], $t['minutes'], $t['seconds'],
|
||||
$t['mon'], $t['mday'], $t['year']);
|
||||
return $result;
|
||||
}
|
||||
|
||||
$rrules = explode(';', $rrules);
|
||||
foreach ($rrules as $rrule) {
|
||||
$t = explode('=', $rrule);
|
||||
switch ($t[0]) {
|
||||
case 'FREQ':
|
||||
if ($t[1] != 'YEARLY') {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'INTERVAL':
|
||||
if ($t[1] != '1') {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'BYMONTH':
|
||||
$month = intval($t[1]);
|
||||
break;
|
||||
|
||||
case 'BYDAY':
|
||||
$len = strspn($t[1], '1234567890-+');
|
||||
if ($len == 0) {
|
||||
return false;
|
||||
}
|
||||
$weekday = substr($t[1], $len);
|
||||
$weekdays = array(
|
||||
'SU' => 0,
|
||||
'MO' => 1,
|
||||
'TU' => 2,
|
||||
'WE' => 3,
|
||||
'TH' => 4,
|
||||
'FR' => 5,
|
||||
'SA' => 6
|
||||
);
|
||||
$weekday = $weekdays[$weekday];
|
||||
$which = intval(substr($t[1], 0, $len));
|
||||
break;
|
||||
|
||||
case 'UNTIL':
|
||||
if (intval($year) > intval(substr($t[1], 0, 4))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($month) || !isset($weekday)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_int($switch_time)) {
|
||||
// Was stored as localtime.
|
||||
$switch_time = strftime('%H:%M:%S', $switch_time);
|
||||
$switch_time = explode(':', $switch_time);
|
||||
} else {
|
||||
$switch_time = explode('T', $switch_time);
|
||||
if (count($switch_time) != 2) {
|
||||
return false;
|
||||
}
|
||||
$switch_time[0] = substr($switch_time[1], 0, 2);
|
||||
$switch_time[2] = substr($switch_time[1], 4, 2);
|
||||
$switch_time[1] = substr($switch_time[1], 2, 2);
|
||||
}
|
||||
|
||||
// Get the timestamp for the first day of $month.
|
||||
$when = gmmktime($switch_time[0], $switch_time[1], $switch_time[2],
|
||||
$month, 1, $year);
|
||||
// Get the day of the week for the first day of $month.
|
||||
$first_of_month_weekday = intval(gmstrftime('%w', $when));
|
||||
|
||||
// Go to the first $weekday before first day of $month.
|
||||
if ($weekday >= $first_of_month_weekday) {
|
||||
$weekday -= 7;
|
||||
}
|
||||
$when -= ($first_of_month_weekday - $weekday) * 60 * 60 * 24;
|
||||
|
||||
// If going backwards go to the first $weekday after last day
|
||||
// of $month.
|
||||
if ($which < 0) {
|
||||
do {
|
||||
$when += 60*60*24*7;
|
||||
} while (intval(gmstrftime('%m', $when)) == $month);
|
||||
}
|
||||
|
||||
// Calculate $weekday number $which.
|
||||
$when += $which * 60 * 60 * 24 * 7;
|
||||
|
||||
$result['time'] = $when;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vTodos.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vtodo.php,v 1.13 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vtodo.php,v 1.13.10.8 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,11 +20,6 @@ class Horde_iCalendar_vtodo extends Horde_iCalendar {
|
||||
return 'vTodo';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VTODO');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VTODO');
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Constants are from Binary XML Content Format Specification Version
|
||||
* 1.3, 25 July 2001 found at http://www.wapforum.org
|
||||
* Constants are from Binary XML Content Format Specification Version 1.3, 25
|
||||
* July 2001 found at http://www.wapforum.org
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -49,8 +49,16 @@ define('DPI_DTD_WML_1_3', '-//WAPFORUM//DTD WML 1.3//EN');
|
||||
define('DPI_DTD_PROV_1_0', '-//WAPFORUM//DTD PROV 1.0//EN');
|
||||
define('DPI_DTD_WTA_WML_1_2', '-//WAPFORUM//DTD WTA-WML 1.2//EN');
|
||||
define('DPI_DTD_CHANNEL_1_2', '-//WAPFORUM//DTD CHANNEL 1.2//EN');
|
||||
|
||||
define('DPI_DTD_SYNCML_1_0', '-//SYNCML//DTD SyncML 1.0//EN');
|
||||
define('DPI_DTD_DEVINF_1_0', '-//SYNCML//DTD DevInf 1.0//EN');
|
||||
define('DPI_DTD_METINF_1_0', '-//SYNCML//DTD MetInf 1.0//EN');
|
||||
define('DPI_DTD_SYNCML_1_1', '-//SYNCML//DTD SyncML 1.1//EN');
|
||||
define('DPI_DTD_DEVINF_1_1', '-//SYNCML//DTD DevInf 1.1//EN');
|
||||
define('DPI_DTD_METINF_1_1', '-//SYNCML//DTD MetInf 1.1//EN');
|
||||
define('DPI_DTD_SYNCML_1_2', '-//SYNCML//DTD SyncML 1.2//EN');
|
||||
define('DPI_DTD_DEVINF_1_2', '-//SYNCML//DTD DevInf 1.2//EN');
|
||||
define('DPI_DTD_METINF_1_2', '-//SYNCML//DTD MetInf 1.2//EN');
|
||||
|
||||
/**
|
||||
* Only default character encodings from J2SE are currently supported.
|
||||
@ -63,13 +71,14 @@ define('CHARSET_UTF_16LE', 'UTF-16LE');
|
||||
define('CHARSET_UTF_16', 'UTF-16');
|
||||
|
||||
/**
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML.php,v 1.13.12.11 2008/01/02 11:31:02 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* $Horde: framework/XML_WBXML/WBXML.php,v 1.18 2006/01/01 21:10:25 jan Exp $
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML {
|
||||
@ -173,8 +182,17 @@ class XML_WBXML {
|
||||
// Not all SyncML clients know this, so we
|
||||
// should use the string table.
|
||||
// 0xFD1 => DPI_DTD_SYNCML_1_1,
|
||||
4051 => DPI_DTD_SYNCML_1_1,
|
||||
4052 => DPI_DTD_DEVINF_1_1,
|
||||
// These codes are taken from libwbxml wbxml_tables.h:
|
||||
4049 => DPI_DTD_SYNCML_1_0, // 0x0fd1
|
||||
4050 => DPI_DTD_DEVINF_1_0, // 0x0fd2
|
||||
4051 => DPI_DTD_SYNCML_1_1, // 0x0fd3
|
||||
4052 => DPI_DTD_DEVINF_1_1, // 0x0fd4
|
||||
4609 => DPI_DTD_SYNCML_1_2, // 0x1201
|
||||
//@todo: verify this:
|
||||
4611 => DPI_DTD_DEVINF_1_2 // 0x1203
|
||||
// taken from libxml but might be wrong:
|
||||
// 4610 => DPI_DTD_DEVINF_1_2, // 0x1202
|
||||
// 4611 => DPI_DTD_METINF_1_2 // 0x1203
|
||||
);
|
||||
return isset($DPIString[$i]) ? $DPIString[$i] : null;
|
||||
}
|
||||
@ -197,8 +215,18 @@ class XML_WBXML {
|
||||
DPI_DTD_WTA_WML_1_2 => 12,
|
||||
DPI_DTD_CHANNEL_1_2 => 13,
|
||||
|
||||
// Not all SyncML clients know this, so we
|
||||
// Not all SyncML clients know this, so maybe we
|
||||
// should use the string table.
|
||||
// These codes are taken from libwbxml wbxml_tables.h:
|
||||
DPI_DTD_SYNCML_1_0 => 4049,
|
||||
DPI_DTD_DEVINF_1_0 => 4050,
|
||||
DPI_DTD_SYNCML_1_1 => 4051,
|
||||
DPI_DTD_DEVINF_1_1 => 4052,
|
||||
DPI_DTD_SYNCML_1_2 => 4609, // 0x1201
|
||||
// DPI_DTD_DEVINF_1_2 => 4610, // 0x1202
|
||||
// DPI_DTD_METINF_1_2 => 4611 // 0x1203
|
||||
//@todo: verify this
|
||||
DPI_DTD_DEVINF_1_2 => 4611 // 0x1203
|
||||
// DPI_DTD_SYNCML_1_1 => 0xFD1,
|
||||
// DPI_DTD_DEVINF_1_1 => 0xFD2,
|
||||
);
|
||||
|
@ -1,15 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/ContentHandler.php,v 1.15 2006/01/01 21:10:25 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* $Horde: framework/XML_WBXML/WBXML/ContentHandler.php,v 1.9.10.11 2008/08/26 15:41:13 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_ContentHandler {
|
||||
@ -35,9 +36,13 @@ class XML_WBXML_ContentHandler {
|
||||
$this->_currentUri = new XML_WBXML_LifoQueue();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function raiseError($error)
|
||||
{
|
||||
include_once 'PEAR.php';
|
||||
if (!class_exists('PEAR')) {
|
||||
require 'PEAR.php';
|
||||
}
|
||||
return PEAR::raiseError($error);
|
||||
}
|
||||
|
||||
@ -71,7 +76,7 @@ class XML_WBXML_ContentHandler {
|
||||
return strlen($this->_output);
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
function startElement($uri, $element, $attrs = array())
|
||||
{
|
||||
$this->_output .= '<' . $element;
|
||||
|
||||
@ -104,12 +109,7 @@ class XML_WBXML_ContentHandler {
|
||||
|
||||
function opaque($o)
|
||||
{
|
||||
// I can check the first chanracter and see if it is WBXML.
|
||||
if (ord($o[0]) < 10) {
|
||||
// Should decode this, I really need a call back function.
|
||||
} else {
|
||||
$this->_output .= $o;
|
||||
}
|
||||
$this->_output .= $o;
|
||||
}
|
||||
|
||||
function setOpaqueHandler($opaqueHandler)
|
||||
@ -122,6 +122,15 @@ class XML_WBXML_ContentHandler {
|
||||
unset($this->_opaqueHandler);
|
||||
}
|
||||
|
||||
function createSubHandler()
|
||||
{
|
||||
$name = get_class($this); // clone current class
|
||||
$sh = new $name();
|
||||
$sh->setCharset($this->getCharsetStr());
|
||||
$sh->setVersion($this->getVersion());
|
||||
return $sh;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class XML_WBXML_LifoQueue {
|
||||
|
@ -1,15 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD.php,v 1.8 2006/01/01 21:10:25 jan Exp $
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD.php,v 1.6.12.8 2008/01/02 11:31:02 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTD {
|
||||
@ -88,6 +89,11 @@ class XML_WBXML_DTD {
|
||||
function toCodePageURI($uri)
|
||||
{
|
||||
$uri = strtolower($uri);
|
||||
if (!isset($this->strCodePagesURI[$uri])) {
|
||||
//Horde::logMessage("WBXML unable to find codepage for $uri!", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
//die("unable to find codepage for $uri!\n");
|
||||
}
|
||||
|
||||
$ret = isset($this->strCodePagesURI[$uri]) ? $this->strCodePagesURI[$uri] : false;
|
||||
|
||||
return $ret;
|
||||
|
@ -3,16 +3,17 @@
|
||||
include_once 'XML/WBXML/DTD.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncML.php,v 1.11 2006/01/01 21:10:26 jan Exp $
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncML.php,v 1.6.12.8 2008/01/02 11:31:03 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTD_SyncML extends XML_WBXML_DTD {
|
||||
@ -72,17 +73,29 @@ class XML_WBXML_DTD_SyncML extends XML_WBXML_DTD {
|
||||
$this->setTag(0x30, "Reserved for future use"); // 0x00
|
||||
$this->setTag(0x31, "VerDTD"); // 0x00
|
||||
$this->setTag(0x32, "VerProto"); // 0x00
|
||||
$this->setTag(0x33, "NumberOfChanged"); // 0x00
|
||||
$this->setTag(0x33, "NumberOfChanges"); // 0x00
|
||||
$this->setTag(0x34, "MoreData"); // 0x00
|
||||
$this->setTag(0x35, "Field"); // 0x00
|
||||
$this->setTag(0x36, "Filter"); // 0x00
|
||||
$this->setTag(0x37, "Record"); // 0x00
|
||||
$this->setTag(0x38, "FilterType"); // 0x00
|
||||
$this->setTag(0x39, "SourceParent"); // 0x00
|
||||
$this->setTag(0x3a, "TargetParent"); // 0x00
|
||||
$this->setTag(0x3b, "Move"); // 0x00
|
||||
$this->setTag(0x3c, "Correlator"); // 0x00
|
||||
|
||||
if ($this->version == 0) {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml1.0');
|
||||
$this->setCodePage(1, '-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf');
|
||||
$this->setURI('syncml:syncml1.0');
|
||||
} else {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1');
|
||||
$this->setCodePage(1, '-//SYNCML//DTD MetInf 1.1//EN', 'syncml:metinf1.1');
|
||||
if ($this->version == 1) {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_1, 'syncml:syncml1.1');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_1, 'syncml:metinf1.1');
|
||||
$this->setURI('syncml:syncml1.1');
|
||||
} elseif ($this->version == 2) {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_2, 'syncml:syncml1.2');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_2, 'syncml:metinf1.2');
|
||||
$this->setURI('syncml:syncml1.2');
|
||||
} else {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_0, 'syncml:syncml1.0');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_0, 'syncml:metinf1.0');
|
||||
$this->setURI('syncml:syncml1.0');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,17 @@
|
||||
include_once 'XML/WBXML/DTD.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLDevInf.php,v 1.11 2006/01/01 21:10:26 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLDevInf.php,v 1.4.12.8 2008/01/02 11:31:03 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTD_SyncMLDevInf extends XML_WBXML_DTD {
|
||||
@ -26,6 +27,8 @@ class XML_WBXML_DTD_SyncMLDevInf extends XML_WBXML_DTD {
|
||||
* | sed -e 's#^.*\"\([^\"]*\)\", *\(0x..\), \(0x..\) },.*$# \$this->setTag\(\3, \"\1\"\); // \2#g'
|
||||
*/
|
||||
|
||||
#Horde::logMessage("XML_WBXML_DTD_SyncMLDevInf version=" . $this->version, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$this->setTag(0x05, "CTCap"); // 0x00
|
||||
$this->setTag(0x06, "CTType"); // 0x00
|
||||
$this->setTag(0x07, "DataStore"); // 0x00
|
||||
@ -64,13 +67,25 @@ class XML_WBXML_DTD_SyncMLDevInf extends XML_WBXML_DTD {
|
||||
$this->setTag(0x28, "UTC"); // 0x00
|
||||
$this->setTag(0x29, "SupportNumberOfChanges"); // 0x00
|
||||
$this->setTag(0x2a, "SupportLargeObjs"); // 0x00
|
||||
$this->setTag(0x2b, "Property"); // 0x00
|
||||
$this->setTag(0x2c, "PropParam"); // 0x00
|
||||
$this->setTag(0x2d, "MaxOccur"); // 0x00
|
||||
$this->setTag(0x2e, "NoTruncate"); // 0x00
|
||||
$this->setTag(0x30, "Filter-Rx"); // 0x00
|
||||
$this->setTag(0x31, "FilterCap"); // 0x00
|
||||
$this->setTag(0x32, "FilterKeyword"); // 0x00
|
||||
$this->setTag(0x33, "FieldLevel"); // 0x00
|
||||
$this->setTag(0x34, "SupportHierarchicalSync"); // 0x00
|
||||
|
||||
if ($this->version == 0) {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD DevInf 1.0//EN', 'syncml:devinf');
|
||||
$this->setURI('syncml:devinf');
|
||||
} else {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD DevInf 1.1//EN', 'syncml:devinf1.1');
|
||||
if ($this->version == 1) {
|
||||
$this->setCodePage(0, DPI_DTD_DEVINF_1_1, 'syncml:devinf1.1');
|
||||
$this->setURI('syncml:devinf1.1');
|
||||
} elseif ($this->version == 2) {
|
||||
$this->setCodePage(0, DPI_DTD_DEVINF_1_2, 'syncml:devinf1.2');
|
||||
$this->setURI('syncml:devinf1.2');
|
||||
} else {
|
||||
$this->setCodePage(0, DPI_DTD_DEVINF_1_0, 'syncml:devinf1.0');
|
||||
$this->setURI('syncml:devinf1.0');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,17 @@
|
||||
include_once 'XML/WBXML/DTD.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLMetInf.php,v 1.9 2006/01/01 21:10:26 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLMetInf.php,v 1.4.12.8 2008/01/02 11:31:03 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTD_SyncMLMetInf extends XML_WBXML_DTD {
|
||||
@ -43,17 +44,22 @@ class XML_WBXML_DTD_SyncMLMetInf extends XML_WBXML_DTD {
|
||||
$this->setTag(0x12, "Size"); // 0x01
|
||||
$this->setTag(0x13, "Type"); // 0x01
|
||||
$this->setTag(0x14, "Version"); // 0x01
|
||||
$this->setTag(0x15, "MaxObjSize"); // 0x01
|
||||
$this->setTag(0x16, "FieldLevel"); // 0x01
|
||||
|
||||
if ($this->version == 0) {
|
||||
#$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:SYNCML1.0');
|
||||
$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml1.0');
|
||||
$this->setCodePage(1, '-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf');
|
||||
$this->setURI('syncml:metinf');
|
||||
} else {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1');
|
||||
$this->setCodePage(1, '-//SYNCML//DTD MetInf 1.1//EN', 'syncml:metinf1.1');
|
||||
if ($this->version == 1) {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_1, 'syncml:syncml1.1');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_1, 'syncml:metinf1.1');
|
||||
$this->setURI('syncml:metinf1.1');
|
||||
//$this->setURI('syncml:metinf'); // for some funny reason, libwbxml produces no :metinf1.1 here
|
||||
} elseif ($this->version == 2) {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_2, 'syncml:syncml1.2');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_2, 'syncml:metinf1.2');
|
||||
$this->setURI('syncml:metinf1.2');
|
||||
} else {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_0, 'syncml:syncml1.0');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_0, 'syncml:metinf1.0');
|
||||
$this->setURI('syncml:metinf1.0');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,50 +5,94 @@ include_once 'XML/WBXML/DTD/SyncMLMetInf.php';
|
||||
include_once 'XML/WBXML/DTD/SyncMLDevInf.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTDManager.php,v 1.7 2006/01/01 21:10:25 jan Exp $
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTDManager.php,v 1.3.12.14 2008/01/02 11:31:02 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July
|
||||
* 2001 found at http://www.wapforum.org
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTDManager {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
var $_strDTD = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
var $_strDTDURI = array();
|
||||
|
||||
/**
|
||||
*/
|
||||
function XML_WBXML_DTDManager()
|
||||
{
|
||||
$this->registerDTD('-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml1.0', new XML_WBXML_DTD_SyncML(0));
|
||||
$this->registerDTD('-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1', new XML_WBXML_DTD_SyncML(1));
|
||||
$this->registerDTD(DPI_DTD_SYNCML_1_0, 'syncml:syncml1.0', new XML_WBXML_DTD_SyncML(0));
|
||||
$this->registerDTD(DPI_DTD_SYNCML_1_1, 'syncml:syncml1.1', new XML_WBXML_DTD_SyncML(1));
|
||||
$this->registerDTD(DPI_DTD_SYNCML_1_2, 'syncml:syncml1.2', new XML_WBXML_DTD_SyncML(2));
|
||||
|
||||
$this->registerDTD('-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf', new XML_WBXML_DTD_SyncMLMetInf(0));
|
||||
$this->registerDTD('-//SYNCML//DTD MetInf 1.1//EN', 'syncml:metinf1.1', new XML_WBXML_DTD_SyncMLMetInf(1));
|
||||
$this->registerDTD(DPI_DTD_METINF_1_0, 'syncml:metinf1.0', new XML_WBXML_DTD_SyncMLMetInf(0));
|
||||
$this->registerDTD(DPI_DTD_METINF_1_1, 'syncml:metinf1.1', new XML_WBXML_DTD_SyncMLMetInf(1));
|
||||
$this->registerDTD(DPI_DTD_METINF_1_2, 'syncml:metinf1.2', new XML_WBXML_DTD_SyncMLMetInf(2));
|
||||
|
||||
$this->registerDTD('-//SYNCML//DTD DevInf 1.0//EN', 'syncml:devinf', new XML_WBXML_DTD_SyncMLDevInf(0));
|
||||
$this->registerDTD('-//SYNCML//DTD DevInf 1.1//EN', 'syncml:devinf1.1', new XML_WBXML_DTD_SyncMLDevInf(1));
|
||||
$this->registerDTD(DPI_DTD_DEVINF_1_0, 'syncml:devinf1.0', new XML_WBXML_DTD_SyncMLDevInf(0));
|
||||
$this->registerDTD(DPI_DTD_DEVINF_1_1, 'syncml:devinf1.1', new XML_WBXML_DTD_SyncMLDevInf(1));
|
||||
$this->registerDTD(DPI_DTD_DEVINF_1_2, 'syncml:devinf1.2', new XML_WBXML_DTD_SyncMLDevInf(2));
|
||||
}
|
||||
|
||||
function getInstance($publicIdentifier)
|
||||
/**
|
||||
*/
|
||||
function &getInstance($publicIdentifier)
|
||||
{
|
||||
return isset($this->_strDTD[$publicIdentifier]) ? $this->_strDTD[$publicIdentifier] : null;
|
||||
$publicIdentifier = strtolower($publicIdentifier);
|
||||
if (isset($this->_strDTD[$publicIdentifier])) {
|
||||
$dtd = &$this->_strDTD[$publicIdentifier];
|
||||
} else {
|
||||
$dtd = null;
|
||||
}
|
||||
return $dtd;
|
||||
}
|
||||
|
||||
function getInstanceURI($uri)
|
||||
/**
|
||||
*/
|
||||
function &getInstanceURI($uri)
|
||||
{
|
||||
$uri = strtolower($uri);
|
||||
return isset($this->_strDTDURI[$uri]) ? $this->_strDTDURI[$uri] : null;
|
||||
|
||||
// some manual hacks:
|
||||
if ($uri == 'syncml:syncml') {
|
||||
$uri = 'syncml:syncml1.0';
|
||||
}
|
||||
if ($uri == 'syncml:metinf') {
|
||||
$uri = 'syncml:metinf1.0';
|
||||
}
|
||||
if ($uri == 'syncml:devinf') {
|
||||
$uri = 'syncml:devinf1.0';
|
||||
}
|
||||
|
||||
if (isset($this->_strDTDURI[$uri])) {
|
||||
$dtd = &$this->_strDTDURI[$uri];
|
||||
} else {
|
||||
$dtd = null;
|
||||
}
|
||||
return $dtd;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function registerDTD($publicIdentifier, $uri, &$dtd)
|
||||
{
|
||||
$dtd->setDPI($publicIdentifier);
|
||||
|
||||
$publicIdentifier = strtolower($publicIdentifier);
|
||||
|
||||
$this->_strDTD[$publicIdentifier] = $dtd;
|
||||
$this->_strDTDURI[strtolower($uri)] = $dtd;
|
||||
}
|
||||
|
@ -5,16 +5,17 @@ include_once 'XML/WBXML/DTDManager.php';
|
||||
include_once 'XML/WBXML/ContentHandler.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/Decoder.php,v 1.36 2006/01/01 21:10:25 jan Exp $
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/Decoder.php,v 1.22.10.11 2008/01/02 11:31:02 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July
|
||||
* 2001 found at http://www.wapforum.org
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
@ -84,7 +85,8 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
*
|
||||
* @param XML_WBXML_ContentHandler $ch The contentHandler
|
||||
*/
|
||||
function setContentHandler(&$ch) {
|
||||
function setContentHandler(&$ch)
|
||||
{
|
||||
$this->_ch = &$ch;
|
||||
}
|
||||
/**
|
||||
@ -96,7 +98,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
{
|
||||
$value = $input{$this->_strpos++};
|
||||
$value = ord($value);
|
||||
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
@ -133,12 +135,8 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
*/
|
||||
function decode($wbxml)
|
||||
{
|
||||
// fix for Nokia Series 60 which seem to send empty data block sometimes
|
||||
if(strlen($wbxml) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->_error = false; // reset state
|
||||
|
||||
$this->_strpos = 0;
|
||||
|
||||
if (empty($this->_ch)) {
|
||||
@ -149,6 +147,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
// version = u_int8
|
||||
// currently 1, 2 or 3
|
||||
$this->_wbxmlVersion = $this->getVersionNumber($wbxml);
|
||||
#Horde::logMessage("WBXML[" . $this->_strpos . "] version " . $this->_wbxmlVersion, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Get Document Public Idetifier from Section 5.5
|
||||
// publicid = mb_u_int32 | (zero index)
|
||||
@ -156,9 +155,11 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
// Containing the value zero (0)
|
||||
// The actual DPI is determined after the String Table is read.
|
||||
$dpiStruct = $this->getDocumentPublicIdentifier($wbxml);
|
||||
|
||||
// Get Charset from 5.6
|
||||
// charset = mb_u_int32
|
||||
$this->_charset = $this->getCharset($wbxml);
|
||||
#Horde::logMessage("WBXML[" . $this->_strpos . "] charset " . $this->_charset, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Get String Table from 5.7
|
||||
// strb1 = length *byte
|
||||
@ -166,8 +167,8 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
// Get Document Public Idetifier from Section 5.5.
|
||||
$this->_dpi = $this->getDocumentPublicIdentifierImpl($dpiStruct['dpiType'],
|
||||
$dpiStruct['dpiNumber'],
|
||||
$this->_stringTable);
|
||||
$dpiStruct['dpiNumber']);
|
||||
#$this->_stringTable);
|
||||
|
||||
// Now the real fun begins.
|
||||
// From Sections 5.2 and 5.8
|
||||
@ -180,8 +181,8 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
$this->_tagDTD = $this->_dtdManager->getInstance($this->_dpi);
|
||||
|
||||
if (!$this->_tagDTD) {
|
||||
return $this->raiseError('No DTD found for '
|
||||
. $this->_dpi . '/'
|
||||
return $this->raiseError('No DTD found for '
|
||||
. $this->_dpi . '/'
|
||||
. $dpiStruct['dpiNumber']);
|
||||
}
|
||||
|
||||
@ -204,6 +205,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
function getDocumentPublicIdentifier($input)
|
||||
{
|
||||
$i = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
|
||||
if ($i == 0) {
|
||||
return array('dpiType' => 2,
|
||||
'dpiNumber' => $this->getByte($input));
|
||||
@ -218,6 +220,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
if ($dpiType == 1) {
|
||||
return XML_WBXML::getDPIString($dpiNumber);
|
||||
} else {
|
||||
#Horde::logMessage("WBXML string table $dpiNumber:\n" . print_r($this->_stringTable, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $this->getStringTableEntry($dpiNumber);
|
||||
}
|
||||
}
|
||||
@ -235,7 +238,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the string table.
|
||||
* Retrieves the string table.
|
||||
* The string table consists of an mb_u_int32 length
|
||||
* and then length bytes forming the table.
|
||||
* References to the string table refer to the
|
||||
@ -254,10 +257,10 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
{
|
||||
if ($index >= strlen($this->_stringTable)) {
|
||||
$this->_error =
|
||||
$this->_ch->raiseError('Invalid offset ' . $index
|
||||
. ' value encountered around position '
|
||||
. $this->_strpos
|
||||
. '. Broken wbxml?');
|
||||
$this->raiseError('Invalid offset ' . $index
|
||||
. ' value encountered around position '
|
||||
. $this->_strpos
|
||||
. '. Broken wbxml?');
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -270,17 +273,17 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
if (ord($ch) == 0) {
|
||||
return ''; // don't return '#'
|
||||
}
|
||||
|
||||
|
||||
while (ord($ch) != 0) {
|
||||
$str[$i++] = $ch;
|
||||
if ($index >= strlen($this->_stringTable)) {
|
||||
break;
|
||||
break;
|
||||
}
|
||||
$ch = $this->_stringTable[$index++];
|
||||
}
|
||||
// print "string table entry: $str\n";
|
||||
return $str;
|
||||
|
||||
|
||||
}
|
||||
|
||||
function _decode($input)
|
||||
@ -288,7 +291,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
$token = $this->getByte($input);
|
||||
$str = '';
|
||||
|
||||
#print "position: " . $this->_strpos . " token: " . $token . " str10: " . substr($input, $this->_strpos, 10) . "\n"; // @todo: remove debug output
|
||||
// print "position: " . $this->_strpos . " token: " . $token . " str10: " . substr($input, $this->_strpos, 10) . "\n"; // @todo: remove debug output
|
||||
|
||||
switch ($token) {
|
||||
case XML_WBXML_GLOBAL_TOKEN_STR_I:
|
||||
@ -370,34 +373,36 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
case XML_WBXML_GLOBAL_TOKEN_OPAQUE:
|
||||
// Section 5.8.4.6
|
||||
$size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
// print "opaque of size $size\n"; // @todo remove debug
|
||||
$b = $this->_substr($input, $this->_strpos, $size);
|
||||
#$b = mb_substr($input, $this->_strpos, $size, 'ISO-8859-1');
|
||||
$this->_strpos += $size;
|
||||
if ($size > 0) {
|
||||
#Horde::logMessage("WBXML opaque document size=$size, next=" . ord($input{$this->_strpos}), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$b = $this->_substr($input, $this->_strpos, $size);
|
||||
// print "opaque of size $size: ($b)\n"; // @todo remove debug
|
||||
$this->_strpos += $size;
|
||||
// opaque data inside a <data> element may or may not be
|
||||
// a nested wbxml document (for example devinf data).
|
||||
// We find out by checking the first byte of the data: if it's
|
||||
// 1, 2 or 3 we expect it to be the version number of a wbxml
|
||||
// document and thus start a new wbxml decoder instance on it.
|
||||
|
||||
// opaque data inside a <data> element may or may not be
|
||||
// a nested wbxml document (for example devinf data).
|
||||
// We find out by checking the first byte of the data: if it's
|
||||
// 1, 2 or 3 we expect it to be the version number of a wbxml
|
||||
// document and thus start a new wbxml decoder instance on it.
|
||||
|
||||
if ($this->_isData && ord($b) <= 10) {
|
||||
$decoder = new XML_WBXML_Decoder(true);
|
||||
$decoder->setContentHandler($this->_ch);
|
||||
$s = $decoder->decode($b);
|
||||
// /* // @todo: FIXME currently we can't decode Nokia
|
||||
// DevInf data. So ignore error for the time beeing.
|
||||
if (is_a($s, 'PEAR_Error')) {
|
||||
$this->_error = $s;
|
||||
return;
|
||||
if ($this->_isData && ord($b) < 10) {
|
||||
#Horde::logMessage("WBXML opaque document size=$size, \$b[0]=" . ord($b), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$decoder = new XML_WBXML_Decoder(true);
|
||||
$decoder->setContentHandler($this->_ch);
|
||||
$s = $decoder->decode($b);
|
||||
// /* // @todo: FIXME currently we can't decode Nokia
|
||||
// DevInf data. So ignore error for the time beeing.
|
||||
if (is_a($s, 'PEAR_Error')) {
|
||||
$this->_error = $s;
|
||||
return;
|
||||
}
|
||||
// */
|
||||
// $this->_ch->characters($s);
|
||||
} else {
|
||||
/* normal opaque behaviour: just copy the raw data: */
|
||||
// print "opaque handled as string=$b\n"; // @todo remove debug
|
||||
$this->_ch->characters($b);
|
||||
}
|
||||
// */
|
||||
// $this->_ch->characters($s);
|
||||
} else {
|
||||
/* normal opaque behaviour: just copy the raw data: */
|
||||
$this->_ch->characters( $b);
|
||||
}
|
||||
|
||||
// old approach to deal with opaque data inside ContentHandler:
|
||||
// FIXME Opaque is used by SYNCML. Opaque data that depends on the context
|
||||
// if (contentHandler instanceof OpaqueContentHandler) {
|
||||
@ -650,7 +655,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
*/
|
||||
function termstr($input)
|
||||
{
|
||||
$str = '#'; // must start with nonempty string to allow array access
|
||||
$str = '#'; // must start with nonempty string to allow array access
|
||||
$i = 0;
|
||||
$ch = $input[$this->_strpos++];
|
||||
if (ord($ch) == 0) {
|
||||
@ -679,6 +684,5 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -6,16 +6,17 @@ include_once 'XML/WBXML/DTDManager.php';
|
||||
include_once 'Horde/String.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/Encoder.php,v 1.39 2006/01/01 21:10:25 jan Exp $
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/Encoder.php,v 1.25.10.17 2008/08/26 15:41:21 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July
|
||||
* 2001 found at http://www.wapforum.org
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
@ -38,7 +39,7 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
var $_subParser = null;
|
||||
var $_subParserStack = 0;
|
||||
|
||||
|
||||
/**
|
||||
* The XML parser.
|
||||
*
|
||||
@ -97,7 +98,10 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
function writeHeader($uri)
|
||||
{
|
||||
$this->_dtd = &$this->_dtdManager->getInstanceURI($uri);
|
||||
|
||||
if (!$this->_dtd) {
|
||||
// TODO: proper error handling
|
||||
die('Unable to find dtd for ' . $uri);
|
||||
}
|
||||
$dpiString = $this->_dtd->getDPI();
|
||||
|
||||
// Set Version Number from Section 5.4
|
||||
@ -132,7 +136,11 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
function writeDocumentPublicIdentifier($dpiString, &$strings)
|
||||
{
|
||||
$i = XML_WBXML::getDPIInt($dpiString);
|
||||
$i = 0;
|
||||
|
||||
// The OMA test suite doesn't like DPI as integer code.
|
||||
// So don't try lookup and always send full DPI string.
|
||||
// $i = XML_WBXML::getDPIInt($dpiString);
|
||||
|
||||
if ($i == 0) {
|
||||
$strings[0] = $dpiString;
|
||||
@ -191,7 +199,7 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
function _getBytes($string, $cs)
|
||||
{
|
||||
$string = String::convertCharset($string, $cs, 'utf-8');
|
||||
$string = String::convertCharset($string, $cs, 'utf-8');
|
||||
$nbytes = strlen($string);
|
||||
|
||||
$bytes = array();
|
||||
@ -210,8 +218,10 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
return array($uri, $name);
|
||||
}
|
||||
|
||||
function startElement($uri, $name, $attributes)
|
||||
function startElement($uri, $name, $attributes = array())
|
||||
{
|
||||
#Horde::logMessage("WBXML Encoder $uri, " . ($this->_hasWrittenHeader ? 'true' : 'false'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if ($this->_subParser == null) {
|
||||
if (!$this->_hasWrittenHeader) {
|
||||
$this->writeHeader($uri);
|
||||
@ -222,11 +232,11 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
if ($this->_subParser == null) {
|
||||
$this->writeTag($name, $attributes, true, $this->_charset);
|
||||
} else {
|
||||
$this->_subParser->startElement($uri,$name, $attributes);
|
||||
$this->_subParser->startElement($uri, $name, $attributes);
|
||||
}
|
||||
} else {
|
||||
$this->_subParserStack++;
|
||||
$this->_subParser->startElement($uri,$name,$attributes);
|
||||
$this->_subParser->startElement($uri, $name, $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,12 +247,12 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
$this->startElement($uri, $name, $attributes);
|
||||
}
|
||||
|
||||
function opaque($bytes)
|
||||
function opaque($o)
|
||||
{
|
||||
if ($this->_subParser == null) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_OPAQUE);
|
||||
XML_WBXML::intToMBUInt32($this->_output, count($bytes));
|
||||
$this->_output .= $bytes;
|
||||
XML_WBXML::intToMBUInt32($this->_output, strlen($o));
|
||||
$this->_output .= $o;
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,7 +284,6 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
function writeTag($name, $attrs, $hasContent, $cs)
|
||||
{
|
||||
|
||||
if ($attrs != null && !count($attrs)) {
|
||||
$attrs = null;
|
||||
}
|
||||
@ -309,7 +318,7 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if ($attrs != null && is_array($attrs) && count($attrs) > 0 ) {
|
||||
if ($attrs != null && is_array($attrs) && count($attrs) > 0) {
|
||||
$this->writeAttributes($attrs, $cs);
|
||||
}
|
||||
}
|
||||
@ -376,11 +385,16 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
function changecodepage($uri)
|
||||
{
|
||||
// @todo: this is a hack!
|
||||
// what's the reason for this hack???? Lars
|
||||
if ($uri != 'syncml:devinf' && $uri != 'syncml:metinf' && $uri != 'syncml:syncml1.0' && !preg_match('/1\.1$/', $uri)) {
|
||||
if ($this->_dtd->getVersion() == 2 && !preg_match('/1\.2$/', $uri)) {
|
||||
$uri .= '1.2';
|
||||
}
|
||||
if ($this->_dtd->getVersion() == 1 && !preg_match('/1\.1$/', $uri)) {
|
||||
$uri .= '1.1';
|
||||
}
|
||||
if ($this->_dtd->getVersion() == 0 && !preg_match('/1\.0$/', $uri)) {
|
||||
$uri .= '1.0';
|
||||
}
|
||||
|
||||
$cp = $this->_dtd->toCodePageURI($uri);
|
||||
if (strlen($cp)) {
|
||||
$this->_dtd = &$this->_dtdManager->getInstanceURI($uri);
|
||||
|
@ -21,7 +21,7 @@ $conf['auth']['driver'] = 'auto';
|
||||
$conf['log']['priority'] = PEAR_LOG_DEBUG;
|
||||
$conf['log']['ident'] = 'EGWSYNC';
|
||||
$conf['log']['params'] = array();
|
||||
$conf['log']['name'] = '/tmp/egroupware_syncml.log';
|
||||
$conf['log']['name'] = '/tmp/egroupware_syncml-1.6.log';
|
||||
$conf['log']['params']['append'] = true;
|
||||
$conf['log']['type'] = 'error_log';
|
||||
$conf['log']['enabled'] = true;
|
||||
|
@ -21,8 +21,16 @@ ini_set('magic_quotes_runtime', 0);
|
||||
* include_path, you must add an ini_set() call here to add their location to
|
||||
* the include_path. */
|
||||
// ini_set('include_path', dirname(__FILE__) . PATH_SEPARATOR . ini_get('include_path'));
|
||||
set_include_path(dirname(__FILE__). '/../../horde/' . PATH_SEPARATOR . dirname(__FILE__). '/../../../../egw-pear/' . PATH_SEPARATOR . get_include_path());
|
||||
//set_include_path(dirname(__FILE__). '/../../horde/' . PATH_SEPARATOR . dirname(__FILE__). '/../../../../egw-pear/' . PATH_SEPARATOR . get_include_path());
|
||||
|
||||
@define('EGW_BASE', dirname(dirname(__FILE__) . '/../../../../rpc.php'));
|
||||
// Check for a prior definition of HORDE_BASE (perhaps by an
|
||||
// auto_prepend_file definition for site customization).
|
||||
if (!defined('HORDE_BASE')) {
|
||||
@define('HORDE_BASE', EGW_BASE . '/phpgwapi/inc/horde/');
|
||||
}
|
||||
|
||||
set_include_path(HORDE_BASE . PATH_SEPARATOR . EGW_BASE . '/egw-pear/' . PATH_SEPARATOR . get_include_path());
|
||||
/* PEAR base class. */
|
||||
include_once 'PEAR.php';
|
||||
|
||||
@ -30,14 +38,17 @@ include_once 'PEAR.php';
|
||||
include_once 'Horde.php';
|
||||
include_once 'Horde/Registry.php';
|
||||
#include_once 'Horde/DataTree.php';
|
||||
#include_once 'Horde/String.php';
|
||||
include_once 'Horde/String.php';
|
||||
include_once 'Horde/Date.php';
|
||||
include_once 'Horde/NLS.php';
|
||||
#include_once 'Horde/Notification.php';
|
||||
#include_once 'Horde/Auth.php';
|
||||
#include_once 'Horde/Browser.php';
|
||||
#include_once 'Horde/Perms.php';
|
||||
include_once 'Horde/iCalendar.php';
|
||||
//include_once 'Horde/Notification.php';
|
||||
//include_once 'Horde/Auth.php';
|
||||
//include_once 'Horde/Browser.php';
|
||||
//include_once 'Horde/Perms.php';
|
||||
|
||||
#/* Browser detection object. */
|
||||
#if (class_exists('Browser')) {
|
||||
# $browser = &Browser::singleton();
|
||||
#}
|
||||
/* Browser detection object. *
|
||||
if (class_exists('Browser')) {
|
||||
$browser = &Browser::singleton();
|
||||
}
|
||||
*/
|
Loading…
Reference in New Issue
Block a user