mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-22 07:53:39 +01:00
using new Horde code in vendor for CalDAV/CardDAV, moved all old Horde and SyncML code to syncml app, not sure it is still functional
This commit is contained in:
parent
99b7fc66a0
commit
3b4708f9ea
@ -1,315 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Addressbook - SIF parser
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke <lkneschke@egroupware.org>
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @package addressbook
|
||||
* @subpackage export
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
class addressbook_sif extends addressbook_bo
|
||||
{
|
||||
var $sifMapping = array(
|
||||
'Anniversary' => '',
|
||||
'AssistantName' => 'assistent',
|
||||
'AssistantTelephoneNumber' => 'tel_assistent',
|
||||
'BillingInformation' => '',
|
||||
'Birthday' => 'bday',
|
||||
'Body' => 'note',
|
||||
'Business2TelephoneNumber' => '',
|
||||
'BusinessAddressCity' => 'adr_one_locality',
|
||||
'BusinessAddressCountry' => 'adr_one_countryname',
|
||||
'BusinessAddressPostalCode' => 'adr_one_postalcode',
|
||||
'BusinessAddressPostOfficeBox' => 'adr_one_street2',
|
||||
'BusinessAddressState' => 'adr_one_region',
|
||||
'BusinessAddressStreet' => 'adr_one_street',
|
||||
'BusinessFaxNumber' => 'tel_fax',
|
||||
'BusinessTelephoneNumber' => 'tel_work',
|
||||
'CallbackTelephoneNumber' => '',
|
||||
'CarTelephoneNumber' => 'tel_car',
|
||||
'Categories' => 'cat_id',
|
||||
'Children' => '',
|
||||
'Companies' => '',
|
||||
'CompanyMainTelephoneNumber' => '',
|
||||
'CompanyName' => 'org_name',
|
||||
'ComputerNetworkName' => '',
|
||||
'Department' => 'org_unit',
|
||||
'Email1Address' => 'email',
|
||||
'Email1AddressType' => '',
|
||||
'Email2Address' => 'email_home',
|
||||
'Email2AddressType' => '',
|
||||
'Email3Address' => '',
|
||||
'Email3AddressType' => '',
|
||||
'FileAs' => 'n_fileas',
|
||||
'FirstName' => 'n_given',
|
||||
'Hobby' => '',
|
||||
'Home2TelephoneNumber' => '',
|
||||
'HomeAddressCity' => 'adr_two_locality',
|
||||
'HomeAddressCountry' => 'adr_two_countryname',
|
||||
'HomeAddressPostalCode' => 'adr_two_postalcode',
|
||||
'HomeAddressPostOfficeBox' => 'adr_two_street2',
|
||||
'HomeAddressState' => 'adr_two_region',
|
||||
'HomeAddressStreet' => 'adr_two_street',
|
||||
'HomeFaxNumber' => 'tel_fax_home',
|
||||
'HomeTelephoneNumber' => 'tel_home',
|
||||
'Importance' => '',
|
||||
'Initials' => '',
|
||||
'JobTitle' => 'title',
|
||||
'Language' => '',
|
||||
'LastName' => 'n_family',
|
||||
'ManagerName' => '',
|
||||
'MiddleName' => 'n_middle',
|
||||
'Mileage' => '',
|
||||
'MobileTelephoneNumber' => 'tel_cell',
|
||||
'NickName' => '',
|
||||
'OfficeLocation' => 'room',
|
||||
'OrganizationalIDNumber' => '',
|
||||
'OtherAddressCity' => '',
|
||||
'OtherAddressCountry' => '',
|
||||
'OtherAddressPostalCode' => '',
|
||||
'OtherAddressPostOfficeBox' => '',
|
||||
'OtherAddressState' => '',
|
||||
'OtherAddressStreet' => '',
|
||||
'OtherFaxNumber' => '',
|
||||
'OtherTelephoneNumber' => 'tel_other',
|
||||
'PagerNumber' => 'tel_pager',
|
||||
'PrimaryTelephoneNumber' => 'tel_prefer',
|
||||
'Profession' => 'role',
|
||||
'RadioTelephoneNumber' => '',
|
||||
'Sensitivity' => 'private',
|
||||
'Spouse' => '',
|
||||
'Subject' => '',
|
||||
'Suffix' => 'n_suffix',
|
||||
'TelexNumber' => '',
|
||||
'Title' => 'n_prefix',
|
||||
'WebPage' => 'url',
|
||||
'YomiCompanyName' => '',
|
||||
'YomiFirstName' => '',
|
||||
'YomiLastName' => '',
|
||||
'HomeWebPage' => 'url_home',
|
||||
'Folder' => '',
|
||||
);
|
||||
|
||||
// standard headers
|
||||
const xml_decl = '<?xml version="1.0" encoding="UTF-8"?>';
|
||||
const SIF_decl = '<SIFVersion>1.1</SIFVersion>';
|
||||
|
||||
function startElement($_parser, $_tag, $_attributes)
|
||||
{
|
||||
}
|
||||
|
||||
function endElement($_parser, $_tag)
|
||||
{
|
||||
if (!empty($this->sifMapping[$_tag]))
|
||||
{
|
||||
$this->contact[$this->sifMapping[$_tag]] = trim($this->sifData);
|
||||
}
|
||||
unset($this->sifData);
|
||||
}
|
||||
|
||||
function characterData($_parser, $_data)
|
||||
{
|
||||
$this->sifData .= $_data;
|
||||
}
|
||||
|
||||
function siftoegw($sifData)
|
||||
{
|
||||
|
||||
#$tmpfname = tempnam('/tmp/sync/contents','sifc_');
|
||||
|
||||
#$handle = fopen($tmpfname, "w");
|
||||
#fwrite($handle, $sifData);
|
||||
#fclose($handle);
|
||||
|
||||
// Horde::logMessage("SyncML siftoegw:\n$sifData", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$this->xml_parser = xml_parser_create('UTF-8');
|
||||
xml_set_object($this->xml_parser, $this);
|
||||
xml_parser_set_option($this->xml_parser, XML_OPTION_CASE_FOLDING, false);
|
||||
xml_set_element_handler($this->xml_parser, "startElement", "endElement");
|
||||
xml_set_character_data_handler($this->xml_parser, "characterData");
|
||||
$this->strXmlData = xml_parse($this->xml_parser, $sifData);
|
||||
if (!$this->strXmlData)
|
||||
{
|
||||
error_log(sprintf("XML error: %s at line %d",
|
||||
xml_error_string(xml_get_error_code($this->xml_parser)),
|
||||
xml_get_current_line_number($this->xml_parser)));
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->contact as $key => $value)
|
||||
{
|
||||
$value = preg_replace('/<\!\[CDATA\[(.+)\]\]>/Usim', '$1', $value);
|
||||
$value = $GLOBALS['egw']->translation->convert($value, 'utf-8');
|
||||
switch ($key) {
|
||||
case 'cat_id':
|
||||
if (!empty($value))
|
||||
{
|
||||
$categories1 = explode(',', $value);
|
||||
$categories2 = explode(';', $value);
|
||||
$finalContact[$key] = count($categories1) > count($categories2) ? $categories1 : $categories2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'private':
|
||||
$finalContact[$key] = (int) ($value > 0); // eGW private is 0 (public) or 1 (private), SIF seems to use 0 and 2
|
||||
break;
|
||||
|
||||
default:
|
||||
$finalContact[$key] = str_replace("\r\n", "\n", $value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->fixup_contact($finalContact);
|
||||
// Horde::logMessage("SyncML siftoegw: " . print_r($finalContact, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $finalContact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search an exactly matching entry (used for slow sync)
|
||||
*
|
||||
* @param string $_sifdata
|
||||
* @return array of matching contact-ids
|
||||
*/
|
||||
function search($_sifdata, $contentID=null, $relax=false)
|
||||
{
|
||||
$result = array();
|
||||
|
||||
if (($contact = $this->siftoegw($_sifdata)))
|
||||
{
|
||||
if ($contentID)
|
||||
{
|
||||
$contact['contact_id'] = $contentID;
|
||||
}
|
||||
$result = $this->find_contact($contact, $relax);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* import a vard into addressbook
|
||||
*
|
||||
* @return int contact id
|
||||
* @param string $_vcard the vcard
|
||||
* @param int/string $_abID=null the internal addressbook id or !$_abID for a new enty
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
*/
|
||||
function addSIF($_sifdata, $_abID=null, $merge=false)
|
||||
{
|
||||
if (!$contact = $this->siftoegw($_sifdata))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($_abID)
|
||||
{
|
||||
if (($old_contact = $this->read($_abID)))
|
||||
{
|
||||
if ($merge)
|
||||
{
|
||||
foreach ($contact as $key => $value)
|
||||
{
|
||||
if (!empty($old_contact[$key]))
|
||||
{
|
||||
$contact[$key] = $old_contact[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($old_contact['account_id']))
|
||||
{
|
||||
$contact['account_id'] = $old_contact['account_id'];
|
||||
}
|
||||
if (is_array($contact['cat_id']))
|
||||
{
|
||||
$contact['cat_id'] = implode(',',$this->find_or_add_categories($contact['cat_id'], $_abID));
|
||||
}
|
||||
else
|
||||
{
|
||||
// restore from orignal
|
||||
$contact['cat_id'] = $old_contact['cat_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
// update entry
|
||||
$contact['id'] = $_abID;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_array($contact['cat_id']))
|
||||
{
|
||||
$contact['cat_id'] = implode(',',$this->find_or_add_categories($contact['cat_id'], -1));
|
||||
}
|
||||
}
|
||||
return $this->save($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* return a sifc
|
||||
*
|
||||
* @param int $_id the id of the contact
|
||||
* @return string containing the vcard
|
||||
*/
|
||||
function getSIF($_id)
|
||||
{
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
|
||||
$fields = array_unique(array_values($this->sifMapping));
|
||||
sort($fields);
|
||||
|
||||
if (!($entry = $this->read($_id))) return false;
|
||||
|
||||
$sifContact = self::xml_decl . "\n<contact>" . self::SIF_decl;
|
||||
|
||||
#error_log(print_r($entry,true));
|
||||
|
||||
// fillup some defaults such as n_fn and n_fileas is needed
|
||||
$this->fixup_contact($entry);
|
||||
|
||||
foreach ($this->sifMapping as $sifField => $egwField)
|
||||
{
|
||||
if (empty($egwField)) continue;
|
||||
|
||||
#error_log("$sifField => $egwField");
|
||||
#error_log('VALUE1: '.$entry[0][$egwField]);
|
||||
$value = $GLOBALS['egw']->translation->convert($entry[$egwField], $sysCharSet, 'utf-8');
|
||||
#error_log('VALUE2: '.$value);
|
||||
|
||||
switch ($sifField)
|
||||
{
|
||||
case 'Sensitivity':
|
||||
$value = 2 * $value; // eGW private is 0 (public) or 1 (private)
|
||||
$sifContact .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Folder':
|
||||
# skip currently. This is the folder where Outlook stores the contact.
|
||||
#$sifContact .= "<$sifField>/</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value)) {
|
||||
$value = implode(", ", $this->get_categories($value));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars(trim($value), ENT_NOQUOTES, 'utf-8');
|
||||
$sifContact .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sifContact .= "</contact>";
|
||||
|
||||
return $sifContact;
|
||||
}
|
||||
}
|
@ -12,9 +12,6 @@
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/SyncML/State.php');
|
||||
|
||||
/**
|
||||
* Addressbook - vCard parser
|
||||
*
|
||||
@ -75,7 +72,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
'REV' => array('modified'),
|
||||
//set for Apple: 'X-ABSHOWAS' => array('fileas_type'), // Horde vCard class uses uppercase prop-names!
|
||||
);
|
||||
|
||||
|
||||
var $supportedFields;
|
||||
|
||||
/**
|
||||
@ -130,8 +127,8 @@ class addressbook_vcal extends addressbook_bo
|
||||
* import a vard into addressbook
|
||||
*
|
||||
* @param string $_vcard the vcard
|
||||
* @param int/string $_abID=null the internal addressbook id or !$_abID for a new enty
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
* @param int/string $_abID =null the internal addressbook id or !$_abID for a new enty
|
||||
* @param boolean $merge =false merge data with existing entry
|
||||
* @param string $charset The encoding charset for $text. Defaults to
|
||||
* utf-8 for new format, iso-8859-1 for old format.
|
||||
* @return int contact id
|
||||
@ -146,7 +143,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
{
|
||||
if ($merge)
|
||||
{
|
||||
foreach ($contact as $key => $value)
|
||||
foreach (array_keys($contact) as $key)
|
||||
{
|
||||
if (!empty($old_contact[$key]))
|
||||
{
|
||||
@ -197,17 +194,13 @@ class addressbook_vcal extends addressbook_bo
|
||||
* return a vcard
|
||||
*
|
||||
* @param int/string $_id the id of the contact
|
||||
* @param string $_charset='UTF-8' encoding of the vcard, default UTF-8
|
||||
* @param boolean $extra_charset_attribute=true GroupDAV/CalDAV dont need the charset attribute and some clients have problems with it
|
||||
* @param string $_charset ='UTF-8' encoding of the vcard, default UTF-8
|
||||
* @param boolean $extra_charset_attribute =true GroupDAV/CalDAV dont need the charset attribute and some clients have problems with it
|
||||
* @return string containing the vcard
|
||||
*/
|
||||
function getVCard($_id,$_charset='UTF-8',$extra_charset_attribute=true)
|
||||
{
|
||||
require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar/vcard.php');
|
||||
|
||||
#Horde::logMessage("vCalAddressbook clientProperties:\n" . print_r($this->clientProperties, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$vCard = new Horde_iCalendar_vcard($this->version);
|
||||
$vCard = new Horde_Icalendar_Vcard($this->version);
|
||||
$vCard->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Addressbook '.$GLOBALS['egw_info']['apps']['phpgwapi']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
|
||||
@ -525,7 +518,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
|
||||
if (is_array($_supportedFields)) $this->supportedFields = $_supportedFields;
|
||||
}
|
||||
|
||||
|
||||
function setDatabaseFields($_databaseFields)
|
||||
{
|
||||
if (is_array($_databaseFields)) $this->databaseFields = $_databaseFields;
|
||||
@ -551,7 +544,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
array2string($_vcard)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar.php');
|
||||
// require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar.php');
|
||||
|
||||
if(!($_vcard instanceof Horde_iCalendar))
|
||||
{
|
||||
@ -1053,14 +1046,12 @@ class addressbook_vcal extends addressbook_bo
|
||||
* return a groupVCard
|
||||
*
|
||||
* @param array $list values for 'list_uid', 'list_name', 'list_modified', 'members'
|
||||
* @param string $version='3.0' vcard version
|
||||
* @param string $version ='3.0' vcard version
|
||||
* @return string containing the vcard
|
||||
*/
|
||||
function getGroupVCard(array $list,$version='3.0')
|
||||
{
|
||||
require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar/vcard.php');
|
||||
|
||||
$vCard = new Horde_iCalendar_vcard($version);
|
||||
$vCard = new Horde_Icalendar_Vcard($version);
|
||||
$vCard->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Addressbook '.$GLOBALS['egw_info']['apps']['phpgwapi']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
|
||||
|
@ -12,8 +12,6 @@
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
|
||||
/**
|
||||
* iCal import and export via Horde iCalendar classes
|
||||
*
|
||||
@ -178,7 +176,7 @@ class calendar_ical extends calendar_boupdate
|
||||
parent::__construct();
|
||||
if ($this->log) $this->logfile = $GLOBALS['egw_info']['server']['temp_dir']."/log-vcal";
|
||||
$this->clientProperties = $_clientProperties;
|
||||
$this->vCalendar = new Horde_iCalendar;
|
||||
$this->vCalendar = new Horde_Icalendar;
|
||||
$this->addressbook = new addressbook_bo;
|
||||
}
|
||||
|
||||
@ -187,12 +185,12 @@ class calendar_ical extends calendar_boupdate
|
||||
* Exports one calendar event to an iCalendar item
|
||||
*
|
||||
* @param int|array $events (array of) cal_id or array of the events with timestamps in server time
|
||||
* @param string $version='1.0' could be '2.0' too
|
||||
* @param string $method='PUBLISH'
|
||||
* @param int $recur_date=0 if set export the next recurrence at or after the timestamp,
|
||||
* @param string $version ='1.0' could be '2.0' too
|
||||
* @param string $method ='PUBLISH'
|
||||
* @param int $recur_date =0 if set export the next recurrence at or after the timestamp,
|
||||
* default 0 => export whole series (or events, if not recurring)
|
||||
* @param string $principalURL='' Used for CalDAV exports
|
||||
* @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8
|
||||
* @param string $principalURL ='' Used for CalDAV exports
|
||||
* @param string $charset ='UTF-8' encoding of the vcalendar, default UTF-8
|
||||
* @return string|boolean string with iCal or false on error (e.g. no permission to read the event)
|
||||
*/
|
||||
function &exportVCal($events, $version='1.0', $method='PUBLISH', $recur_date=0, $principalURL='', $charset='UTF-8')
|
||||
@ -231,7 +229,7 @@ class calendar_ical extends calendar_boupdate
|
||||
$version = '2.0';
|
||||
}
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal = new Horde_Icalendar;
|
||||
$vcal->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Calendar '.$GLOBALS['egw_info']['apps']['calendar']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
$vcal->setAttribute('VERSION', $version);
|
||||
@ -330,7 +328,7 @@ class calendar_ical extends calendar_boupdate
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
"($_id, $recurrence) Gratuitous pseudo exception, skipped ...\n",
|
||||
"(, $recurrence) Gratuitous pseudo exception, skipped ...\n",
|
||||
3,$this->logfile);
|
||||
}
|
||||
continue; // unsupported status only exception
|
||||
@ -377,7 +375,7 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
}
|
||||
|
||||
$vevent = Horde_iCalendar::newComponent('VEVENT', $vcal);
|
||||
$vevent = Horde_Icalendar::newComponent('VEVENT', $vcal);
|
||||
$parameters = $attributes = $values = array();
|
||||
|
||||
if ($this->productManufacturer == 'sonyericsson')
|
||||
@ -429,6 +427,7 @@ class calendar_ical extends calendar_boupdate
|
||||
case 'ATTENDEE':
|
||||
foreach ((array)$event['participants'] as $uid => $status)
|
||||
{
|
||||
$quantity = $role = null;
|
||||
calendar_so::split_status($status, $quantity, $role);
|
||||
// do not include event owner/ORGANIZER as participant in his own calendar, if he is only participant
|
||||
if (count($event['participants']) == 1 && $event['owner'] == $uid) continue;
|
||||
@ -442,10 +441,9 @@ class calendar_ical extends calendar_boupdate
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ .
|
||||
'()attendee:' . array2string($info) ."\n",3,$this->logfile);
|
||||
}
|
||||
$participantCN = trim(empty($info['cn']) ? $info['name'] : $info['cn']);
|
||||
$participantCN = str_replace(array('\\', ',', ';', ':'),
|
||||
array('\\\\', '\\,', '\\;', '\\:'),
|
||||
$participantCN);
|
||||
trim(empty($info['cn']) ? $info['name'] : $info['cn']));
|
||||
if ($version == '1.0')
|
||||
{
|
||||
$participantURL = trim('"' . $participantCN . '"' . (empty($info['email']) ? '' : ' <' . $info['email'] .'>'));
|
||||
@ -861,7 +859,7 @@ class calendar_ical extends calendar_boupdate
|
||||
$attributes['LAST-MODIFIED'] = $event['modified'];
|
||||
}
|
||||
$attributes['DTSTAMP'] = time();
|
||||
foreach ((array)$event['alarm'] as $alarmID => $alarmData)
|
||||
foreach ((array)$event['alarm'] as $alarmData)
|
||||
{
|
||||
// skip over alarms that don't have the minimum required info
|
||||
if (!$alarmData['offset'] && !$alarmData['time']) continue;
|
||||
@ -928,7 +926,7 @@ class calendar_ical extends calendar_boupdate
|
||||
$alarmData['offset'] = false;
|
||||
}
|
||||
|
||||
$valarm = Horde_iCalendar::newComponent('VALARM',$vevent);
|
||||
$valarm = Horde_Icalendar::newComponent('VALARM',$vevent);
|
||||
if ($alarmData['offset'] !== false)
|
||||
{
|
||||
$valarm->setAttribute('TRIGGER', -$alarmData['offset'],
|
||||
@ -1122,6 +1120,7 @@ class calendar_ical extends calendar_boupdate
|
||||
|
||||
date_default_timezone_set($tzid);
|
||||
|
||||
$msg = null;
|
||||
foreach ($events as $event)
|
||||
{
|
||||
if (!is_array($event)) continue; // the iterator may return false
|
||||
@ -1390,8 +1389,7 @@ class calendar_ical extends calendar_boupdate
|
||||
// They can now only remove themselfs, if that is desired, after storing the event first.
|
||||
|| !isset($event['participants'][$event['owner']]))
|
||||
{
|
||||
$status = $event['owner'] == $this->user ? 'A' : 'U';
|
||||
$status = calendar_so::combine_status($status, 1, 'CHAIR');
|
||||
$status = calendar_so::combine_status($event['owner'] == $this->user ? 'A' : 'U', 1, 'CHAIR');
|
||||
if (!is_array($event['participants'])) $event['participants'] = array();
|
||||
$event['participants'][$event['owner']] = $status;
|
||||
}
|
||||
@ -1769,9 +1767,9 @@ class calendar_ical extends calendar_boupdate
|
||||
/**
|
||||
* get the value of an attribute by its name
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param array $components
|
||||
* @param string $name eg. 'DTSTART'
|
||||
* @param string $what='value'
|
||||
* @param string $what ='value'
|
||||
* @return mixed
|
||||
*/
|
||||
static function _get_attribute($components,$name,$what='value')
|
||||
@ -2150,7 +2148,7 @@ class calendar_ical extends calendar_boupdate
|
||||
* Convert vCalendar data in EGw events
|
||||
*
|
||||
* @param string|resource $_vcalData
|
||||
* @param string $principalURL='' Used for CalDAV imports
|
||||
* @param string $principalURL ='' Used for CalDAV imports
|
||||
* @param string $charset The encoding charset for $text. Defaults to
|
||||
* utf-8 for new format, iso-8859-1 for old format.
|
||||
* @return Iterator|array|boolean Iterator if resource given or array of events on success, false on failure
|
||||
@ -2183,7 +2181,7 @@ class calendar_ical extends calendar_boupdate
|
||||
date_default_timezone_set($tzid);
|
||||
|
||||
$events = array();
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal = new Horde_Icalendar;
|
||||
if (!$vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset))
|
||||
{
|
||||
if ($this->log)
|
||||
@ -2194,9 +2192,7 @@ class calendar_ical extends calendar_boupdate
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
return false;
|
||||
}
|
||||
$version = $vcal->getAttribute('VERSION');
|
||||
|
||||
foreach ($vcal->getComponents() as $n => $component)
|
||||
foreach ($vcal->getComponents() as $component)
|
||||
{
|
||||
if (($event = $this->_ical2egw_callback($component,$this->tzid,$principalURL)))
|
||||
{
|
||||
@ -2209,14 +2205,14 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for egw_ical_iterator to convert Horde_iCalendar_vevent to EGw event array
|
||||
* Callback for egw_ical_iterator to convert Horde_iCalendar_Vevent to EGw event array
|
||||
*
|
||||
* @param Horde_iCalendar $component
|
||||
* @param string $tzid timezone
|
||||
* @param string $principalURL='' Used for CalDAV imports
|
||||
* @return array|boolean event array or false if $component is no Horde_iCalendar_vevent
|
||||
* @param string $principalURL ='' Used for CalDAV imports
|
||||
* @return array|boolean event array or false if $component is no Horde_Icalendar_Vevent
|
||||
*/
|
||||
function _ical2egw_callback(Horde_iCalendar $component, $tzid, $principalURL='')
|
||||
function _ical2egw_callback(Horde_Icalendar $component, $tzid, $principalURL='')
|
||||
{
|
||||
//unset($component->_container); _debug_array($component);
|
||||
|
||||
@ -2225,7 +2221,7 @@ class calendar_ical extends calendar_boupdate
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.'() '.get_class($component)." found\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
if (!is_a($component, 'Horde_iCalendar_vevent') ||
|
||||
if (!is_a($component, 'Horde_Icalendar_Vevent') ||
|
||||
!($event = $this->vevent2egw($component, $component->_container->getAttribute('VERSION'), $this->supportedFields, $principalURL)))
|
||||
{
|
||||
return false;
|
||||
@ -2246,7 +2242,7 @@ class calendar_ical extends calendar_boupdate
|
||||
$alarms = $event['alarm'];
|
||||
foreach ($component->getComponents() as $valarm)
|
||||
{
|
||||
if (is_a($valarm, 'Horde_iCalendar_valarm'))
|
||||
if (is_a($valarm, 'Horde_Icalendar_Valarm'))
|
||||
{
|
||||
$this->valarm2egw($alarms, $valarm);
|
||||
}
|
||||
@ -2265,13 +2261,15 @@ class calendar_ical extends calendar_boupdate
|
||||
* @param array $component VEVENT
|
||||
* @param string $version vCal version (1.0/2.0)
|
||||
* @param array $supportedFields supported fields of the device
|
||||
* @param string $principalURL='' Used for CalDAV imports, no longer used in favor of groupdav_principals::url2uid()
|
||||
* @param string $check_component='Horde_iCalendar_vevent'
|
||||
* @param string $principalURL ='' Used for CalDAV imports, no longer used in favor of groupdav_principals::url2uid()
|
||||
* @param string $check_component ='Horde_Icalendar_Vevent'
|
||||
*
|
||||
* @return array|boolean event on success, false on failure
|
||||
*/
|
||||
function vevent2egw(&$component, $version, $supportedFields, $principalURL='', $check_component='Horde_iCalendar_vevent')
|
||||
function vevent2egw(&$component, $version, $supportedFields, $principalURL='', $check_component='Horde_Icalendar_Vevent')
|
||||
{
|
||||
unset($principalURL); // not longer used, but required in function signature
|
||||
|
||||
if ($check_component && !is_a($component, $check_component))
|
||||
{
|
||||
if ($this->log)
|
||||
@ -2421,9 +2419,10 @@ class calendar_ical extends calendar_boupdate
|
||||
break;
|
||||
case 'DESCRIPTION':
|
||||
$vcardData['description'] = str_replace("\r\n", "\n", $attributes['value']);
|
||||
$matches = null;
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $attributes['value'], $matches))
|
||||
{
|
||||
if (!isset($vCardData['uid'])
|
||||
if (!isset($vcardData['uid'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$vcardData['uid'] = $matches[1];
|
||||
@ -2463,6 +2462,7 @@ class calendar_ical extends calendar_boupdate
|
||||
switch($type)
|
||||
{
|
||||
case 'D': // 1.0
|
||||
$recurenceMatches = null;
|
||||
if (preg_match('/D(\d+) #(\d+)/', $recurence, $recurenceMatches))
|
||||
{
|
||||
$vcardData['recur_interval'] = $recurenceMatches[1];
|
||||
@ -2495,6 +2495,7 @@ class calendar_ical extends calendar_boupdate
|
||||
$days = explode(' ',trim($recurenceMatches[2]));
|
||||
}
|
||||
|
||||
$repeatMatches = null;
|
||||
if (preg_match('/#(\d+)/',$recurenceMatches[4],$repeatMatches))
|
||||
{
|
||||
if ($repeatMatches[1]) $vcardData['recur_count'] = $repeatMatches[1];
|
||||
@ -2847,6 +2848,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
// keep role 'CHAIR' from an external organizer, even if he is a regular participant with a different role
|
||||
// as this is currently the only way to store an external organizer and send him iMip responses
|
||||
$q = $r = null;
|
||||
if (isset($vcardData['participants'][$uid]) && ($s=$vcardData['participants'][$uid]) &&
|
||||
calendar_so::split_status($s, $q, $r) && $r == 'CHAIR')
|
||||
{
|
||||
@ -3065,12 +3067,12 @@ class calendar_ical extends calendar_boupdate
|
||||
* Create a freebusy vCal for the given user(s)
|
||||
*
|
||||
* @param int $user account_id
|
||||
* @param mixed $end=null end-date, default now+1 month
|
||||
* @param boolean $utc=true if false, use severtime for dates
|
||||
* @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8
|
||||
* @param mixed $start=null default now
|
||||
* @param string $method='PUBLISH' or eg. 'REPLY'
|
||||
* @param array $extra=null extra attributes to add
|
||||
* @param mixed $end =null end-date, default now+1 month
|
||||
* @param boolean $utc =true if false, use severtime for dates
|
||||
* @param string $charset ='UTF-8' encoding of the vcalendar, default UTF-8
|
||||
* @param mixed $start =null default now
|
||||
* @param string $method ='PUBLISH' or eg. 'REPLY'
|
||||
* @param array $extra =null extra attributes to add
|
||||
* X-CALENDARSERVER-MASK-UID can be used to not include an event specified by this uid as busy
|
||||
*/
|
||||
function freebusy($user,$end=null,$utc=true, $charset='UTF-8', $start=null, $method='PUBLISH', array $extra=null)
|
||||
@ -3078,14 +3080,13 @@ class calendar_ical extends calendar_boupdate
|
||||
if (!$start) $start = time(); // default now
|
||||
if (!$end) $end = time() + 100*DAY_s; // default next 100 days
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal = new Horde_Icalendar;
|
||||
$vcal->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Calendar '.$GLOBALS['egw_info']['apps']['calendar']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
$vcal->setAttribute('VERSION','2.0');
|
||||
$vcal->setAttribute('METHOD',$method);
|
||||
|
||||
$vfreebusy = Horde_iCalendar::newComponent('VFREEBUSY',$vcal);
|
||||
if ($uid) $vfreebusy->setAttribute('UID', $uid);
|
||||
$vfreebusy = Horde_Icalendar::newComponent('VFREEBUSY',$vcal);
|
||||
|
||||
$attributes = array(
|
||||
'DTSTAMP' => time(),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,12 +7,10 @@
|
||||
* @package infolog
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-13 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-15 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
|
||||
/**
|
||||
* EGroupware: GroupDAV access: infolog handler
|
||||
*
|
||||
@ -66,7 +64,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
parent::__construct($app, $groupdav);
|
||||
|
||||
$this->bo = new infolog_bo();
|
||||
$this->vCalendar = new Horde_iCalendar;
|
||||
$this->vCalendar = new Horde_Icalendar;
|
||||
|
||||
// since 1.9.002 we allow clients to specify the URL when creating a new event, as specified by CalDAV
|
||||
if (version_compare($GLOBALS['egw_info']['apps']['calendar']['version'], '1.9.002', '>='))
|
||||
|
@ -7,13 +7,10 @@
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @author Ralf Becker <RalfBecker@outdoor-training.de>
|
||||
* @package infolog
|
||||
* @subpackage syncml
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
|
||||
/**
|
||||
* InfoLog: Create and parse iCal's
|
||||
*/
|
||||
@ -112,14 +109,14 @@ class infolog_ical extends infolog_bo
|
||||
* Exports multiple InfoLogs
|
||||
*
|
||||
* @param array $tasks array of info_ids or task arrays
|
||||
* @param string $_version='2.0'
|
||||
* @param string $_method=null only set for iTip messages
|
||||
* @param string $charset='UTF-8'
|
||||
* @param string $_version ='2.0'
|
||||
* @param string $_method =null only set for iTip messages
|
||||
* @param string $charset ='UTF-8'
|
||||
* @return string|boolean string with vCal or false on error (eg. no permission to read the event)
|
||||
*/
|
||||
function exportVCalendar(array $tasks, $_version='2.0', $_method=null, $charset='UTF-8')
|
||||
{
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal = new Horde_Icalendar;
|
||||
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
@ -135,14 +132,14 @@ class infolog_ical extends infolog_bo
|
||||
* Exports one InfoLog tast to an iCalendar VTODO
|
||||
*
|
||||
* @param int|array $task infolog_id or infolog-tasks data
|
||||
* @param string $_version='2.0' could be '1.0' too
|
||||
* @param string $_method='PUBLISH'
|
||||
* @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8
|
||||
* @param Horde_iCalendar $vcal=null optional iCalendar object to add vtodo to
|
||||
* @param string $_version ='2.0' could be '1.0' too
|
||||
* @param string $_method ='PUBLISH'
|
||||
* @param string $charset ='UTF-8' encoding of the vcalendar, default UTF-8
|
||||
* @param Horde_Icalendar $vcal =null optional iCalendar object to add vtodo to
|
||||
*
|
||||
* @return string|boolean string with vCal or false on error (eg. no permission to read the event)
|
||||
*/
|
||||
function exportVTODO($task, $_version='2.0',$_method='PUBLISH', $charset='UTF-8',Horde_iCalendar $vcal=null)
|
||||
function exportVTODO($task, $_version='2.0',$_method='PUBLISH', $charset='UTF-8',Horde_Icalendar $vcal=null)
|
||||
{
|
||||
if (is_array($task))
|
||||
{
|
||||
@ -190,7 +187,7 @@ class infolog_ical extends infolog_bo
|
||||
array2string($taskData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
if (!isset($vcal)) $vcal = new Horde_iCalendar;
|
||||
if (!isset($vcal)) $vcal = new Horde_Icalendar;
|
||||
$vcal->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware InfoLog '.$GLOBALS['egw_info']['apps']['infolog']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']),array(),false);
|
||||
$vcal->setAttribute('VERSION',$_version,array(),false);
|
||||
@ -203,7 +200,7 @@ class infolog_ical extends infolog_bo
|
||||
if (!calendar_timezones::add_vtimezone($vcal, $tzid))
|
||||
{
|
||||
error_log(__METHOD__."() unknown TZID='$tzid', defaulting to user timezone '".egw_time::$user_timezone->getName()."'!");
|
||||
calendar_timezones::add_vtimezone($vcal, $tzid=egw_time::$user_timezone->getName());
|
||||
calendar_timezones::add_vtimezone($vcal, egw_time::$user_timezone->getName());
|
||||
$tzid = null;
|
||||
}
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
@ -212,7 +209,7 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
}
|
||||
|
||||
$vevent = Horde_iCalendar::newComponent('VTODO',$vcal);
|
||||
$vevent = Horde_Icalendar::newComponent('VTODO',$vcal);
|
||||
|
||||
if (!isset($this->clientProperties['SUMMARY']['Size']))
|
||||
{
|
||||
@ -407,7 +404,7 @@ class infolog_ical extends infolog_bo
|
||||
if ($value[1] == ':' && ($v = unserialize($value)) !== false) $value = $v;
|
||||
foreach((array)$value as $compvData)
|
||||
{
|
||||
$comp = Horde_iCalendar::newComponent(substr($name,3), $vevent);
|
||||
$comp = Horde_Icalendar::newComponent(substr($name,3), $vevent);
|
||||
$comp->parsevCalendar($compvData,substr($name,3),'utf-8');
|
||||
$vevent->addComponent($comp);
|
||||
}
|
||||
@ -440,7 +437,7 @@ class infolog_ical extends infolog_bo
|
||||
* set date-time attribute to DATE or DATE-TIME depending on value
|
||||
* 00:00 uses DATE else DATE-TIME
|
||||
*
|
||||
* @param Horde_iCalendar_* $vevent
|
||||
* @param Horde_Icalendar_* $vevent
|
||||
* @param string $attr attribute name
|
||||
* @param int $time timestamp in server-time
|
||||
* @param string $tzid timezone to use for client, null for user-time, false for server-time
|
||||
@ -448,7 +445,7 @@ class infolog_ical extends infolog_bo
|
||||
static function setDateOrTime(&$vevent, $attr, $time, $tzid)
|
||||
{
|
||||
$params = array();
|
||||
$time_in = $time;
|
||||
//$time_in = $time;
|
||||
|
||||
if ($tzid)
|
||||
{
|
||||
@ -507,19 +504,20 @@ class infolog_ical extends infolog_bo
|
||||
* Import a VTODO component of an iCal
|
||||
*
|
||||
* @param string $_vcalData
|
||||
* @param int $_taskID=-1 info_id, default -1 = new entry
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
* @param int $user=null delegate new task to this account_id, default null
|
||||
* @param string $charset=null The encoding charset for $text. Defaults to
|
||||
* @param int $_taskID =-1 info_id, default -1 = new entry
|
||||
* @param boolean $merge =false merge data with existing entry (no longer used)
|
||||
* @param int $user =null delegate new task to this account_id, default null
|
||||
* @param string $charset =null The encoding charset for $text. Defaults to
|
||||
* utf-8 for new format, iso-8859-1 for old format.
|
||||
* @param string $caldav_name=null CalDAV URL name-part for new entries
|
||||
* @param array $callback_data=null array with callback and further parameters, first param is task to save
|
||||
* @param string $caldav_name =null CalDAV URL name-part for new entries
|
||||
* @param array $callback_data =null array with callback and further parameters, first param is task to save
|
||||
* signature array callback($task, $param1, ...)
|
||||
* @return int|boolean integer info_id or false on error
|
||||
*/
|
||||
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false, $user=null, $charset=null, $caldav_name=null,
|
||||
array $callback_data=null)
|
||||
{
|
||||
unset($merge); // no longer used, but required by function signature
|
||||
|
||||
if ($this->tzid)
|
||||
{
|
||||
@ -575,7 +573,7 @@ class infolog_ical extends infolog_bo
|
||||
'info_access','info_status','info_percent','info_datecompleted',
|
||||
)));
|
||||
// remove all iCal fields not supported by EGroupware (stored like custom fields)
|
||||
foreach($old as $name => $value)
|
||||
foreach(array_keys($old) as $name)
|
||||
{
|
||||
if (substr($name,0,2) == '##') unset($old[$name]);
|
||||
}
|
||||
@ -595,8 +593,8 @@ class infolog_ical extends infolog_bo
|
||||
* Search a matching infolog entry for the VTODO data
|
||||
*
|
||||
* @param string $_vcalData VTODO
|
||||
* @param int $contentID=null infolog_id (or null, if unkown)
|
||||
* @param boolean $relax=false if true, a weaker match algorithm is used
|
||||
* @param int $contentID =null infolog_id (or null, if unkown)
|
||||
* @param boolean $relax =false if true, a weaker match algorithm is used
|
||||
* @param string $charset The encoding charset for $text. Defaults to
|
||||
* utf-8 for new format, iso-8859-1 for old format.
|
||||
*
|
||||
@ -630,7 +628,7 @@ class infolog_ical extends infolog_bo
|
||||
* Convert VTODO into a eGW infolog entry
|
||||
*
|
||||
* @param string $_vcalData VTODO data
|
||||
* @param int $_taskID=-1 infolog_id of the entry
|
||||
* @param int $_taskID =-1 infolog_id of the entry
|
||||
* @param string $charset The encoding charset for $text. Defaults to
|
||||
* utf-8 for new format, iso-8859-1 for old format.
|
||||
*
|
||||
@ -644,7 +642,7 @@ class infolog_ical extends infolog_bo
|
||||
array2string($_vcalData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal = new Horde_Icalendar;
|
||||
if (!($vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset)))
|
||||
{
|
||||
if ($this->log)
|
||||
@ -655,8 +653,6 @@ class infolog_ical extends infolog_bo
|
||||
return false;
|
||||
}
|
||||
|
||||
$version = $vcal->getAttribute('VERSION');
|
||||
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
|
||||
@ -670,7 +666,7 @@ class infolog_ical extends infolog_bo
|
||||
|
||||
foreach ($vcal->getComponents() as $component)
|
||||
{
|
||||
if (!is_a($component, 'Horde_iCalendar_vtodo'))
|
||||
if (!is_a($component, 'Horde_Icalendar_Vtodo'))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
@ -731,6 +727,7 @@ class infolog_ical extends infolog_bo
|
||||
|
||||
case 'DESCRIPTION':
|
||||
$value = str_replace("\r\n", "\n", $attribute['value']);
|
||||
$matches = null;
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (!isset($taskData['info_uid'])
|
||||
@ -899,7 +896,7 @@ class infolog_ical extends infolog_bo
|
||||
*
|
||||
* @param int $_noteID the infolog_id of the entry
|
||||
* @param string $_type content type (e.g. text/plain)
|
||||
* @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8
|
||||
* @param string $charset ='UTF-8' encoding of the vcalendar, default UTF-8
|
||||
*
|
||||
* @return string|boolean VNOTE representation of the infolog entry or false on error
|
||||
*/
|
||||
@ -923,7 +920,7 @@ class infolog_ical extends infolog_bo
|
||||
$note['info_cat'] = translation::convert($cats[0],
|
||||
translation::charset(), $charset);
|
||||
}
|
||||
$vnote = new Horde_iCalendar_vnote();
|
||||
$vnote = new Horde_Icalendar_Vnote();
|
||||
$vnote->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware InfoLog '.$GLOBALS['egw_info']['apps']['infolog']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
$vnote->setAttribute('VERSION', '1.1');
|
||||
@ -961,15 +958,15 @@ class infolog_ical extends infolog_bo
|
||||
$options['ENCODING'] = 'FUNAMBOL-QP';
|
||||
}
|
||||
}
|
||||
$vevent->setAttribute($field, $value, $options);
|
||||
$vnote->setAttribute($field, $value, $options);
|
||||
}
|
||||
if ($note['info_startdate'])
|
||||
{
|
||||
$vnote->setAttribute('DCREATED',$note['info_startdate']);
|
||||
$vnote->setAttribute('CREATED',$note['info_startdate']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$vnote->setAttribute('DCREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'add'));
|
||||
$vnote->setAttribute('CREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'add'));
|
||||
}
|
||||
$vnote->setAttribute('LAST-MODIFIED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'modify'));
|
||||
|
||||
@ -991,8 +988,8 @@ class infolog_ical extends infolog_bo
|
||||
*
|
||||
* @param string $_vcalData
|
||||
* @param string $_type content type (eg.g text/plain)
|
||||
* @param int $_noteID=-1 info_id, default -1 = new entry
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
* @param int $_noteID =-1 info_id, default -1 = new entry
|
||||
* @param boolean $merge =false merge data with existing entry (no longer used)
|
||||
* @param string $charset The encoding charset for $text. Defaults to
|
||||
* utf-8 for new format, iso-8859-1 for old format.
|
||||
*
|
||||
@ -1000,6 +997,7 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
function importVNOTE(&$_vcalData, $_type, $_noteID=-1, $merge=false, $charset=null)
|
||||
{
|
||||
unset($merge); // no longer used, but required by function signature
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
@ -1048,7 +1046,7 @@ class infolog_ical extends infolog_bo
|
||||
*
|
||||
* @param string $_data VNOTE data
|
||||
* @param string $_type content type (eg.g text/plain)
|
||||
* @param int $_noteID=-1 infolog_id of the entry
|
||||
* @param int $_noteID =-1 infolog_id of the entry
|
||||
* @param string $charset The encoding charset for $text. Defaults to
|
||||
* utf-8 for new format, iso-8859-1 for old format.
|
||||
*
|
||||
@ -1068,9 +1066,9 @@ class infolog_ical extends infolog_bo
|
||||
case 'text/plain':
|
||||
$note = array();
|
||||
$note['info_type'] = 'note';
|
||||
$txt = translation::convert($_data, $charset);
|
||||
$txt = str_replace("\r\n", "\n", $txt);
|
||||
$txt = str_replace("\r\n", "\n", translation::convert($_data, $charset));
|
||||
|
||||
$match = null;
|
||||
if (preg_match('/([^\n]+)\n\n(.*)/ms', $txt, $match))
|
||||
{
|
||||
$note['info_subject'] = $match[1];
|
||||
@ -1083,14 +1081,13 @@ class infolog_ical extends infolog_bo
|
||||
break;
|
||||
|
||||
case 'text/x-vnote':
|
||||
$vnote = new Horde_iCalendar;
|
||||
if (!$vcal->parsevCalendar($_data, 'VCALENDAR', $charset)) return false;
|
||||
$version = $vcal->getAttribute('VERSION');
|
||||
$vnote = new Horde_Icalendar;
|
||||
if (!$vnote->parsevCalendar($_data, 'VCALENDAR', $charset)) return false;
|
||||
|
||||
$components = $vnote->getComponent();
|
||||
foreach ($components as $component)
|
||||
{
|
||||
if (is_a($component, 'Horde_iCalendar_vnote'))
|
||||
if (is_a($component, 'Horde_Icalendar_Vnote'))
|
||||
{
|
||||
$note = array();
|
||||
$note['info_type'] = 'note';
|
||||
|
@ -1,668 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* InfoLog - SIF Parser
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke <lkneschke@egroupware.org>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @package infolog
|
||||
* @subpackage syncml
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
|
||||
/**
|
||||
* InfoLog: Create and parse SIF
|
||||
*
|
||||
*/
|
||||
class infolog_sif extends infolog_bo
|
||||
{
|
||||
// array containing the result of the xml parser
|
||||
var $_extractedSIFData;
|
||||
|
||||
// array containing the current mappings(task or note)
|
||||
var $_currentSIFMapping;
|
||||
|
||||
var $_sifNoteMapping = array(
|
||||
'Body' => 'info_des',
|
||||
'Categories' => 'info_cat',
|
||||
'Color' => '',
|
||||
'Date' => 'info_startdate',
|
||||
'Height' => '',
|
||||
'Left' => '',
|
||||
'Subject' => 'info_subject',
|
||||
'Top' => '',
|
||||
'Width' => '',
|
||||
);
|
||||
|
||||
// mappings for SIFTask to InfologTask
|
||||
var $_sifTaskMapping = array(
|
||||
'ActualWork' => '',
|
||||
'BillingInformation' => '',
|
||||
'Body' => 'info_des',
|
||||
'Categories' => 'info_cat',
|
||||
'Companies' => '',
|
||||
'Complete' => 'complete',
|
||||
'DateCompleted' => 'info_datecompleted',
|
||||
'DueDate' => 'info_enddate',
|
||||
'Importance' => 'info_priority',
|
||||
'IsRecurring' => '',
|
||||
'Mileage' => '',
|
||||
'PercentComplete' => 'info_percent',
|
||||
'ReminderSet' => '',
|
||||
'ReminderTime' => '',
|
||||
'Sensitivity' => 'info_access',
|
||||
'StartDate' => 'info_startdate',
|
||||
'Status' => 'info_status',
|
||||
'Subject' => 'info_subject',
|
||||
'TeamTask' => '',
|
||||
'TotalWork' => '',
|
||||
'RecurrenceType' => '',
|
||||
'Interval' => '',
|
||||
'MonthOfYear' => '',
|
||||
'DayOfMonth' => '',
|
||||
'DayOfWeekMask' => '',
|
||||
'Instance' => '',
|
||||
'PatternStartDate' => '',
|
||||
'NoEndDate' => '',
|
||||
'PatternEndDate' => '',
|
||||
'Occurrences' => '',
|
||||
);
|
||||
|
||||
// standard headers
|
||||
const xml_decl = '<?xml version="1.0" encoding="UTF-8"?>';
|
||||
const SIF_decl = '<SIFVersion>1.1</SIFVersion>';
|
||||
|
||||
/**
|
||||
* name and version of the sync-client
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $productName = 'mozilla plugin';
|
||||
var $productSoftwareVersion = '0.3';
|
||||
|
||||
/**
|
||||
* Shall we use the UID extensions of the description field?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $uidExtension = false;
|
||||
|
||||
/**
|
||||
* user preference: Use this timezone for import from and export to device
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $tzid = null;
|
||||
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $log = false;
|
||||
var $logfile="/tmp/log-infolog-sif";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
if ($this->log) $this->logfile = $GLOBALS['egw_info']['server']['temp_dir']."/log-infolog-sif";
|
||||
$this->vCalendar = new Horde_iCalendar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DateTime value for a given time and timezone
|
||||
*
|
||||
* @param int|string|DateTime $time in server-time as returned by calendar_bo for $data_format='server'
|
||||
* @param string $tzid TZID of event or 'UTC' or NULL for palmos timestamps in usertime
|
||||
*
|
||||
*/
|
||||
function getDateTime($time, $tzid)
|
||||
{
|
||||
if (empty($tzid) || $tzid == 'UTC')
|
||||
{
|
||||
return $this->vCalendar->_exportDateTime(egw_time::to($time,'ts'));
|
||||
}
|
||||
if (!is_a($time,'DateTime'))
|
||||
{
|
||||
$time = new egw_time($time,egw_time::$server_timezone);
|
||||
}
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
{
|
||||
self::$tz_cache[$tzid] = calendar_timezones::DateTimeZone($tzid);
|
||||
}
|
||||
// check for date --> export it as such
|
||||
if ($time->format('Hi') == '0000')
|
||||
{
|
||||
$arr = egw_time::to($time, 'array');
|
||||
$time = new egw_time($arr, self::$tz_cache[$tzid]);
|
||||
$value = $time->format('Y-m-d');
|
||||
}
|
||||
else
|
||||
{
|
||||
$time->setTimezone(self::$tz_cache[$tzid]);
|
||||
$value = $time->format('Ymd\THis');
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
function startElement($_parser, $_tag, $_attributes)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
function endElement($_parser, $_tag)
|
||||
{
|
||||
#error_log("infolog: tag=$_tag data=".trim($this->sifData));
|
||||
if (!empty($this->_currentSIFMapping[$_tag]))
|
||||
{
|
||||
$this->_extractedSIFData[$this->_currentSIFMapping[$_tag]] = trim($this->sifData);
|
||||
}
|
||||
unset($this->sifData);
|
||||
}
|
||||
|
||||
function characterData($_parser, $_data)
|
||||
{
|
||||
$this->sifData .= $_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert SIF data into a eGW infolog entry
|
||||
*
|
||||
* @param string $sifData the SIF data
|
||||
* @param string $_sifType type (note/task)
|
||||
* @param int $_id=-1 the infolog id
|
||||
* @return array infolog entry or false on error
|
||||
*/
|
||||
function siftoegw($sifData, $_sifType, $_id=-1)
|
||||
{
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_sifType, $_id)\n" .
|
||||
array2string($sifData) . "\n", 3, $this->logfile);
|
||||
}
|
||||
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
|
||||
switch ($_sifType)
|
||||
{
|
||||
case 'note':
|
||||
$this->_currentSIFMapping = $this->_sifNoteMapping;
|
||||
break;
|
||||
|
||||
case 'task':
|
||||
$this->_currentSIFMapping = $this->_sifTaskMapping;
|
||||
break;
|
||||
|
||||
default:
|
||||
// we don't know how to handle this
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->xml_parser = xml_parser_create('UTF-8');
|
||||
xml_set_object($this->xml_parser, $this);
|
||||
xml_parser_set_option($this->xml_parser, XML_OPTION_CASE_FOLDING, false);
|
||||
xml_set_element_handler($this->xml_parser, "startElement", "endElement");
|
||||
xml_set_character_data_handler($this->xml_parser, "characterData");
|
||||
$this->strXmlData = xml_parse($this->xml_parser, $sifData);
|
||||
|
||||
if (!$this->strXmlData)
|
||||
{
|
||||
error_log(sprintf("XML error: %s at line %d",
|
||||
xml_error_string(xml_get_error_code($this->xml_parser)),
|
||||
xml_get_current_line_number($this->xml_parser)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!array($this->_extractedSIFData))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()[PARSER FAILD]\n",
|
||||
3, $this->logfile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$infoData = array();
|
||||
|
||||
switch ($_sifType)
|
||||
{
|
||||
case 'task':
|
||||
$infoData['info_type'] = 'task';
|
||||
$infoData['info_status'] = 'not-started';
|
||||
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$minimum_uid_length = 8;
|
||||
}
|
||||
|
||||
foreach ($this->_extractedSIFData as $key => $value)
|
||||
{
|
||||
$value = preg_replace('/<\!\[CDATA\[(.+)\]\]>/Usim', '$1', $value);
|
||||
$value = $GLOBALS['egw']->translation->convert($value, 'utf-8', $sysCharSet);
|
||||
#error_log("infolog key=$key => value=$value");
|
||||
if (empty($value)) continue;
|
||||
|
||||
switch($key)
|
||||
{
|
||||
case 'info_access':
|
||||
$infoData[$key] = ((int)$value > 0) ? 'private' : 'public';
|
||||
break;
|
||||
|
||||
case 'info_datecompleted':
|
||||
case 'info_enddate':
|
||||
case 'info_startdate':
|
||||
if (!empty($value))
|
||||
{
|
||||
$infoData[$key] = $this->vCalendar->_parseDateTime($value);
|
||||
// somehow the client always deliver a timestamp about 3538 seconds, when no startdate set.
|
||||
if ($infoData[$key] < 10000) unset($infoData[$key]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'info_cat':
|
||||
if (!empty($value))
|
||||
{
|
||||
$categories = $this->find_or_add_categories(explode(';', $value), $_id);
|
||||
$infoData['info_cat'] = $categories[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'info_priority':
|
||||
$infoData[$key] = (int)$value;
|
||||
break;
|
||||
|
||||
case 'info_status':
|
||||
switch ($value)
|
||||
{
|
||||
case '0':
|
||||
$infoData[$key] = 'not-started';
|
||||
break;
|
||||
case '1':
|
||||
$infoData[$key] = 'ongoing';
|
||||
break;
|
||||
case '2':
|
||||
$infoData[$key] = 'done';
|
||||
$infoData['info_percent'] = 100;
|
||||
break;
|
||||
case '3':
|
||||
$infoData[$key] = 'waiting';
|
||||
break;
|
||||
case '4':
|
||||
if ($this->productName == 'blackberry plug-in')
|
||||
{
|
||||
$infoData[$key] = 'deferred';
|
||||
}
|
||||
else
|
||||
{
|
||||
$infoData[$key] = 'cancelled';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$infoData[$key] = 'ongoing';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'complete':
|
||||
$infoData['info_status'] = 'done';
|
||||
$infoData['info_percent'] = 100;
|
||||
break;
|
||||
|
||||
case 'info_des':
|
||||
// extract our UID and PARENT_UID information
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$infoData['info_uid'] = $matches[1];
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
if (preg_match('/\s*\[PARENT_UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$infoData['info_id_parent'] = $this->getParentID($matches[1]);
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
|
||||
default:
|
||||
$infoData[$key] = str_replace("\r\n", "\n", $value);
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
"key=$key => value=" . $infoData[$key] . "\n", 3, $this->logfile);
|
||||
}
|
||||
}
|
||||
if (empty($infoData['info_datecompleted']))
|
||||
{
|
||||
$infoData['info_datecompleted'] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'note':
|
||||
$infoData['info_type'] = 'note';
|
||||
|
||||
foreach ($this->_extractedSIFData as $key => $value)
|
||||
{
|
||||
$value = preg_replace('/<\!\[CDATA\[(.+)\]\]>/Usim', '$1', $value);
|
||||
$value = $GLOBALS['egw']->translation->convert($value, 'utf-8', $sysCharSet);
|
||||
|
||||
#error_log("infolog client key=$key => value=" . $value);
|
||||
switch ($key)
|
||||
{
|
||||
case 'info_startdate':
|
||||
if (!empty($value))
|
||||
{
|
||||
$infoData[$key] = $this->vCalendar->_parseDateTime($value);
|
||||
// somehow the client always deliver a timestamp about 3538 seconds, when no startdate set.
|
||||
if ($infoData[$key] < 10000) $infoData[$key] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$infoData[$key] = '';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'info_cat':
|
||||
if (!empty($value))
|
||||
{
|
||||
$categories = $this->find_or_add_categories(explode(';', $value), $_id);
|
||||
$infoData['info_cat'] = $categories[0];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$infoData[$key] = str_replace("\r\n", "\n", $value);
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
"key=$key => value=" . $infoData[$key] . "\n", 3, $this->logfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($infoData) . "\n", 3, $this->logfile);
|
||||
}
|
||||
return $infoData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for SIF data a matching infolog entry
|
||||
*
|
||||
* @param string $sifData the SIF data
|
||||
* @param string $_sifType type (note/task)
|
||||
* @param int $contentID=null infolog_id (or null, if unkown)
|
||||
* @param boolean $relax=false if true, a weaker match algorithm is used
|
||||
* @return infolog_id of a matching entry or false, if nothing was found
|
||||
*/
|
||||
function searchSIF($_sifData, $_sifType, $contentID=null, $relax=false)
|
||||
{
|
||||
if (!($egwData = $this->siftoegw($_sifData, $_sifType, $contentID))) return array();
|
||||
|
||||
if ($contentID) $egwData['info_id'] = $contentID;
|
||||
|
||||
if ($_sifType == 'note') unset($egwData['info_startdate']);
|
||||
|
||||
return $this->findInfo($egwData, $relax, $this->tzid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add SIF data entry
|
||||
*
|
||||
* @param string $sifData the SIF data
|
||||
* @param string $_sifType type (note/task)
|
||||
* @param boolean $merge=false reserved for future use
|
||||
* @return infolog_id of the new entry or false, for errors
|
||||
*/
|
||||
function addSIF($_sifData, $_id, $_sifType, $merge=false)
|
||||
{
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($this->tzid);
|
||||
}
|
||||
$egwData = $this->siftoegw($_sifData, $_sifType, $_id);
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
if (!$egwData) return false;
|
||||
|
||||
if ($_id > 0) $egwData['info_id'] = $_id;
|
||||
|
||||
return $this->write($egwData, true, true, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export an infolog entry as SIF data
|
||||
*
|
||||
* @param int $_id the infolog_id of the entry
|
||||
* @param string $_sifType type (note/task)
|
||||
* @return string SIF representation of the infolog entry
|
||||
*/
|
||||
function getSIF($_id, $_sifType)
|
||||
{
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
|
||||
if (!($infoData = $this->read($_id, true, 'server'))) return false;
|
||||
|
||||
switch($_sifType)
|
||||
{
|
||||
case 'task':
|
||||
if ($infoData['info_id_parent'])
|
||||
{
|
||||
$parent = $this->read($infoData['info_id_parent']);
|
||||
$infoData['info_id_parent'] = $parent['info_uid'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$infoData['info_id_parent'] = '';
|
||||
}
|
||||
|
||||
if (!preg_match('/\[UID:.+\]/m', $infoData['info_des']))
|
||||
{
|
||||
$infoData['info_des'] .= "\r\n[UID:" . $infoData['info_uid'] . "]";
|
||||
if ($infoData['info_id_parent'] != '')
|
||||
{
|
||||
$infoData['info_des'] .= "\r\n[PARENT_UID:" . $infoData['info_id_parent'] . "]";
|
||||
}
|
||||
}
|
||||
|
||||
$sifTask = self::xml_decl . "\n<task>" . self::SIF_decl;
|
||||
|
||||
foreach ($this->_sifTaskMapping as $sifField => $egwField)
|
||||
{
|
||||
if (empty($egwField)) continue;
|
||||
|
||||
$value = $GLOBALS['egw']->translation->convert($infoData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
switch ($sifField)
|
||||
{
|
||||
|
||||
case 'Complete':
|
||||
// is handled with DateCompleted
|
||||
break;
|
||||
|
||||
case 'DateCompleted':
|
||||
if ($infoData[info_status] != 'done')
|
||||
{
|
||||
$sifTask .= "<DateCompleted></DateCompleted><Complete>0</Complete>";
|
||||
continue;
|
||||
}
|
||||
$sifTask .= "<Complete>1</Complete>";
|
||||
|
||||
case 'DueDate':
|
||||
case 'StartDate':
|
||||
$sifTask .= "<$sifField>";
|
||||
if (!empty($value))
|
||||
{
|
||||
$sifTask .= $this->getDateTime($value, $this->tzid);
|
||||
}
|
||||
$sifTask .= "</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Importance':
|
||||
if ($value > 3) $value = 3;
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Sensitivity':
|
||||
$value = ($value == 'private' ? '2' : '0');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Status':
|
||||
switch ($value)
|
||||
{
|
||||
case 'cancelled':
|
||||
case 'deferred':
|
||||
$value = '4';
|
||||
break;
|
||||
case 'waiting':
|
||||
case 'nonactive':
|
||||
$value = '3';
|
||||
break;
|
||||
case 'done':
|
||||
case 'archive':
|
||||
case 'billed':
|
||||
$value = '2';
|
||||
break;
|
||||
case 'not-started':
|
||||
case 'template':
|
||||
$value = '0';
|
||||
break;
|
||||
default: //ongoing
|
||||
$value = 1;
|
||||
break;
|
||||
}
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value) && $value)
|
||||
{
|
||||
$value = implode('; ', $this->get_categories(array($value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_NOQUOTES, 'utf-8');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sifTask .= '<ActualWork>0</ActualWork><IsRecurring>0</IsRecurring></task>';
|
||||
return $sifTask;
|
||||
|
||||
case 'note':
|
||||
$sifNote = self::xml_decl . "\n<note>" . self::SIF_decl;
|
||||
|
||||
foreach ($this->_sifNoteMapping as $sifField => $egwField)
|
||||
{
|
||||
if(empty($egwField)) continue;
|
||||
|
||||
$value = $GLOBALS['egw']->translation->convert($infoData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
switch ($sifField)
|
||||
{
|
||||
case 'Date':
|
||||
$sifNote .= "<$sifField>";
|
||||
if (!empty($value))
|
||||
{
|
||||
$sifNote .= $this->getDateTime($value, $this->tzid);
|
||||
}
|
||||
$sifNote .= "</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = implode('; ', $this->get_categories(array($value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_QUOTES, 'utf-8');
|
||||
$sifNote .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sifNote .= '</note>';
|
||||
return $sifNote;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the supported fields
|
||||
*
|
||||
* Currently we only store name and version, manucfacturer is always Funambol
|
||||
*
|
||||
* @param string $_productName
|
||||
* @param string $_productSoftwareVersion
|
||||
*/
|
||||
function setSupportedFields($_productName='', $_productSoftwareVersion='')
|
||||
{
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
if (isset($deviceInfo) && is_array($deviceInfo))
|
||||
{
|
||||
if (isset($deviceInfo['uidExtension']) &&
|
||||
$deviceInfo['uidExtension'])
|
||||
{
|
||||
$this->uidExtension = true;
|
||||
}
|
||||
if (isset($deviceInfo['tzid']) &&
|
||||
$deviceInfo['tzid'])
|
||||
{
|
||||
switch ($deviceInfo['tzid'])
|
||||
{
|
||||
case -1:
|
||||
$this->tzid = false;
|
||||
break;
|
||||
case -2:
|
||||
$this->tzid = null;
|
||||
break;
|
||||
default:
|
||||
$this->tzid = $deviceInfo['tzid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
// store product name and version, to be able to use it elsewhere
|
||||
if ($_productName)
|
||||
{
|
||||
$this->productName = strtolower($_productName);
|
||||
if (preg_match('/^[^\d]*(\d+\.?\d*)[\.|\d]*$/', $_productSoftwareVersion, $matches))
|
||||
{
|
||||
$this->productSoftwareVersion = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,411 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The Browser_imode:: class extends the Browser API by providing
|
||||
* specific information about Imode handsets.
|
||||
*
|
||||
* $Horde: framework/Browser/Browser/imode.php,v 1.9 2005/01/12 15:45:17 chuck Exp $
|
||||
*
|
||||
* Copyright 2000-2005 Mika Tuupola
|
||||
* Copyright 2002-2005 Chuck Hagenbuch <chuck@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 Chuck Hagenbuch <chuck@horde.org>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_Browser
|
||||
*/
|
||||
class Browser_imode {
|
||||
|
||||
/**
|
||||
* Device data. From http://www.nttdocomo.co.jp/i/tag/s5.html#5_1
|
||||
*
|
||||
* @var array $_data
|
||||
*/
|
||||
var $_data = array(
|
||||
'D209i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 90,
|
||||
'textwidth' => 8, 'textheight' => 7,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'F209i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 91,
|
||||
'textwidth' => 8, 'textheight' => 7,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'N209i' => array(
|
||||
'imagewidth' => 108, 'imageheight' => 82,
|
||||
'textwidth' => 9, 'textheight' => 6,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'P209i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 87,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'P209is' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 87,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'R209i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 72,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'ER209i' => array(
|
||||
'imagewidth' => 120, 'imageheight' => 72,
|
||||
'textwidth' => 10, 'textheight' => 6,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'KO209i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 96,
|
||||
'textwidth' => 8, 'textheight' => 8,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'D210i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 91,
|
||||
'textwidth' => 8, 'textheight' => 7,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'F210i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 113,
|
||||
'textwidth' => 8, 'textheight' => 8,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'N210i' => array(
|
||||
'imagewidth' => 118, 'imageheight' => 113,
|
||||
'textwidth' => 10, 'textheight' => 8,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'P210i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 91,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'KO210i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 96,
|
||||
'textwidth' => 8, 'textheight' => 8,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'SO210i' => array(
|
||||
'imagewidth' => 120, 'imageheight' => 113,
|
||||
'textwidth' => 8, 'textheight' => 7,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'D501i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 72,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 'black',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'F501i' => array(
|
||||
'imagewidth' => 112, 'imageheight' => 84,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 'black',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'N501i' => array(
|
||||
'imagewidth' => 118, 'imageheight' => 128,
|
||||
'textwidth' => 10, 'textheight' =>10,
|
||||
'color' => 'black',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'P501i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 120,
|
||||
'textwidth' => 8, 'textheight' => 8,
|
||||
'color' => 'black',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'D502i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 90,
|
||||
'textwidth' => 8, 'textheight' => 7,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'F502i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 91,
|
||||
'textwidth' => 8, 'textheight' => 7,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'F502it' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 91,
|
||||
'textwidth' => 8, 'textheight' => 7,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'N502i' => array(
|
||||
'imagewidth' => 118, 'imageheight' => 128,
|
||||
'textwidth' => 10, 'textheight' => 10,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'N502it' => array(
|
||||
'imagewidth' => 118, 'imageheight' => 128,
|
||||
'textwidth' => 10, 'textheight' => 10,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'P502i' => array(
|
||||
'imagewidth' => 96, 'imageheighth' => 117,
|
||||
'textwidth' => 8, 'textheight' => 8,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'NM502i' => array(
|
||||
'imagewidth' => 111, 'imageheight' => 77,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 'black',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'SO502i' => array(
|
||||
'imagewidth' => 120, 'imageheight' => 120,
|
||||
'textwidth' => 8, 'textheight' => 8,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'SO502iwm' => array(
|
||||
'imagewidth' => 120, 'imageheight' => 113,
|
||||
'textwidth' => 8, 'textheight' => 7,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'F503i' => array(
|
||||
'imagewidth' => 120, 'imageheight' => 130,
|
||||
'textwidth' => 10, 'textheight' => 10,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'F503iS' => array(
|
||||
'imagewidth' => 120, 'imageheight' => 130,
|
||||
'textwidth' => 12, 'textheight' => 12,
|
||||
'color' => 4096,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'P503i' => array(
|
||||
'imagewidth' => 120, 'imageheight' => 130,
|
||||
'textwidth' => 12, 'textheight' => 10,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'P503iS' => array(
|
||||
'imagewidth' => 120, 'imageheight' => 130,
|
||||
'textwidth' => 12, 'textheight' => 10,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'SO503i' => array(
|
||||
'imagewidth' => 120, 'imageheight' => 113,
|
||||
'textwidth' => 8.5, 'textheight' => 7,
|
||||
'color' => 65536,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'D503i' => array(
|
||||
'imagewidth' => 132, 'imageheight' => 126,
|
||||
'textwidth' => 8, 'textheight' => 7,
|
||||
'color' => 4096,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'N503i' => array(
|
||||
'imagewidth' => 118, 'imageheight' => 128,
|
||||
'textwidth' => 10, 'textheight' => 10,
|
||||
'color' => 4096,
|
||||
'imageformats' => array('gif', 'jpg')
|
||||
),
|
||||
'N503iS' => array(
|
||||
'imagewidth' => 118, 'imageheight' => 128,
|
||||
'textwidth' => 10, 'textheight' => 10,
|
||||
'color' => 4096,
|
||||
'imageformats' => array('gif', 'jpg')
|
||||
),
|
||||
'N691i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 72,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'SH821i' => array(
|
||||
'imagewidth' => 96, 'imageheight' => 78,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 256,
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'N821i' => array(
|
||||
'imagewidth' => 118, 'imageheight' => 128,
|
||||
'textwidth' => 10, 'textheight' => 10,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'P821i' => array(
|
||||
'imagewidth' => 118, 'imageheight' => 128,
|
||||
'textwidth' => 10, 'textheight' => 10,
|
||||
'color' => 'grey',
|
||||
'imageformats' => array('gif')
|
||||
),
|
||||
'safe' => array(
|
||||
'imagewidth' => 94, 'imageheight' => 72,
|
||||
'textwidth' => 8, 'textheight' => 6,
|
||||
'color' => 'black',
|
||||
'imageformats' => array('gif')
|
||||
)
|
||||
);
|
||||
|
||||
var $_manufacturerlist = array(
|
||||
'D' => 'Mitsubishi',
|
||||
'P' => 'Panasonic (Matsushita)',
|
||||
'NM' => 'Nokia',
|
||||
'SO' => 'Sony',
|
||||
'F' => 'Fujitsu',
|
||||
'N' => 'Nec',
|
||||
'SH' => 'Sharp',
|
||||
'ER' => 'Ericsson',
|
||||
'R' => 'Japan Radio',
|
||||
'KO' => 'Kokusai (Hitachi)'
|
||||
);
|
||||
|
||||
var $_extra = array(
|
||||
't' => 'Transport layer',
|
||||
'e' => 'English language',
|
||||
's' => 'Second version'
|
||||
);
|
||||
|
||||
var $_user_agent;
|
||||
var $_model;
|
||||
var $_manufacturer;
|
||||
var $_httpversion;
|
||||
var $_cache = 5;
|
||||
|
||||
/**
|
||||
* Does not handle bogus user_agents or most of the other error
|
||||
* situation properly yet.
|
||||
*
|
||||
* Example usage:
|
||||
* $ua = new Browser_imode($_SERVEr['HTTP_USER_AGENT']);
|
||||
*
|
||||
* @param string $input The user agent to match.
|
||||
*/
|
||||
function Browser_imode($input)
|
||||
{
|
||||
$_error = 0;
|
||||
$temp = explode('/', $input);
|
||||
|
||||
$this->_user_agent = $input;
|
||||
$this->_httpversion = $temp[1];
|
||||
$this->_model = $temp[2];
|
||||
if ($temp[3]) {
|
||||
$this->_cache = substr($temp[3], 1);
|
||||
}
|
||||
|
||||
preg_match('/(^[a-zA-Z]+)([0-9]+i)(.*)\/?(.*)/', $this->_model, $matches);
|
||||
|
||||
// @TODO: Fix situation of unknown manufacturer. Implement
|
||||
// extrainfo properly.
|
||||
$this->_manufacturer = $this->_manufacturerlist[$matches[1]];
|
||||
$this->_extra = $matches[3];
|
||||
|
||||
if (!($this->_data[$this->_model])) {
|
||||
$_error = PEAR::raiseError('Unknown User Agent');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example usage:
|
||||
* $imagedim = $ua->getImageDimensions();
|
||||
* $imagewidth = $imagedim[0];
|
||||
* $imageheight = $imagedim[1];
|
||||
*
|
||||
* @return array The maximum imagewidth and imageheight that
|
||||
* fit on the handset screen without scrolling.
|
||||
*/
|
||||
function getImageDimensions()
|
||||
{
|
||||
$data = $this->_data[$this->_model];
|
||||
return array($data['imagewidth'], $data['imageheight']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example usage:
|
||||
* $textdim = $ua->getTextDimensions();
|
||||
* $textwidth = $textdim[0];
|
||||
* $textheight = $textdim[1];
|
||||
*
|
||||
* @return array The Maximum textwidth and textheight that
|
||||
* fit on the handset screen without scrolling.
|
||||
*/
|
||||
function getTextDimensions()
|
||||
{
|
||||
return array($this->_data[$this->_model]['textwidth'],
|
||||
$this->_data[$this->_model]['textheight']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer The amount of handset cache in kilobytes.
|
||||
*/
|
||||
function getCache()
|
||||
{
|
||||
return (int)$this->_cache;
|
||||
}
|
||||
|
||||
function getManufacturer()
|
||||
{
|
||||
return $this->_manufacturer;
|
||||
}
|
||||
|
||||
function getExtra()
|
||||
{
|
||||
return $this->_extra;
|
||||
}
|
||||
|
||||
function getImageFormats()
|
||||
{
|
||||
return $this->_data[$this->_model]['imageformats'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer Which color model the handset supports.
|
||||
* Values have the following meaning:
|
||||
* 0 -> black and white
|
||||
* 1 -> 4 tone greyscale
|
||||
* 2 -> 256 color
|
||||
*/
|
||||
function getColor()
|
||||
{
|
||||
return $this->_data[$this->_model]['color'];
|
||||
}
|
||||
|
||||
function getHTTPVersion()
|
||||
{
|
||||
return $this->_httpversion;
|
||||
}
|
||||
|
||||
function isColor()
|
||||
{
|
||||
return $this->_data[$this->_model]['color'] == 256;
|
||||
}
|
||||
|
||||
function isGreyScale()
|
||||
{
|
||||
return $this->_data[$this->_model]['color'] == 'grey';
|
||||
}
|
||||
|
||||
function isBlackAndWhite()
|
||||
{
|
||||
return $this->_data[$this->_model]['color'] == 'black';
|
||||
}
|
||||
|
||||
}
|
@ -1,769 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,523 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The NLS:: class provides Native Language Support. This includes common
|
||||
* methods for handling language detection and selection, timezones, and
|
||||
* hostname->country lookups.
|
||||
*
|
||||
* $Horde: framework/NLS/NLS.php,v 1.86 2005/02/28 15:45:56 jan Exp $
|
||||
*
|
||||
* Copyright 1999-2005 Jon Parise <jon@horde.org>
|
||||
* Copyright 1999-2005 Chuck Hagenbuch <chuck@horde.org>
|
||||
* Copyright 2002-2005 Jan Schneider <jan@horde.org>
|
||||
* Copyright 2003-2005 Michael Slusarz <slusarz@bigworm.colorado.edu>
|
||||
*
|
||||
* 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 Jon Parise <jon@horde.org>
|
||||
* @author Chuck Hagenbuch <chuck@horde.org>
|
||||
* @author Jan Schneider <jan@horde.org>
|
||||
* @author Michael Slusarz <slusarz@bigworm.colorado.edu>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_NLS
|
||||
*/
|
||||
class NLS {
|
||||
|
||||
/**
|
||||
* Selects the most preferred language for the current client session.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return string The selected language abbreviation.
|
||||
*/
|
||||
function select()
|
||||
{
|
||||
global $nls, $prefs;
|
||||
|
||||
$lang = Util::getFormData('new_lang');
|
||||
|
||||
/* First, check if language pref is locked and, if so, set it to its
|
||||
value */
|
||||
if (isset($prefs) && $prefs->isLocked('language')) {
|
||||
$language = $prefs->getValue('language');
|
||||
/* Check if the user selected a language from the login screen */
|
||||
} elseif (!empty($lang)) {
|
||||
$language = $lang;
|
||||
/* Check if we have a language set in a cookie */
|
||||
} elseif (isset($_SESSION['horde_language'])) {
|
||||
$language = $_SESSION['horde_language'];
|
||||
/* Use site-wide default, if one is defined */
|
||||
} elseif (!empty($nls['defaults']['language'])) {
|
||||
$language = $nls['defaults']['language'];
|
||||
/* Try browser-accepted languages. */
|
||||
} elseif (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
/* The browser supplies a list, so return the first valid one. */
|
||||
$browser_langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
foreach ($browser_langs as $lang) {
|
||||
/* Strip quality value for language */
|
||||
if (($pos = strpos($lang, ';')) !== false) {
|
||||
$lang = substr($lang, 0, $pos);
|
||||
}
|
||||
$lang = NLS::_map(trim($lang));
|
||||
if (NLS::isValid($lang)) {
|
||||
$language = $lang;
|
||||
break;
|
||||
}
|
||||
/* In case no full match, save best guess based on prefix */
|
||||
if (!isset($partial_lang) &&
|
||||
NLS::isValid(NLS::_map(substr($lang, 0, 2)))) {
|
||||
$partial_lang = NLS::_map(substr($lang, 0, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($language)) {
|
||||
if (isset($partial_lang)) {
|
||||
$language = $partial_lang;
|
||||
} else {
|
||||
/* No dice auto-detecting, default to US English. */
|
||||
$language = 'en_US';
|
||||
}
|
||||
}
|
||||
|
||||
return basename($language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the language.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param optional string $lang The language abbriviation.
|
||||
*/
|
||||
function setLang($lang = null)
|
||||
{
|
||||
include_once HORDE_BASE . '/config/nls.php';
|
||||
|
||||
if (empty($lang) || !NLS::isValid($lang)) {
|
||||
$lang = NLS::select();
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['language']) && $GLOBALS['language'] == $lang) {
|
||||
return;
|
||||
}
|
||||
|
||||
$GLOBALS['language'] = $lang;
|
||||
|
||||
/* First try language with the current charset. */
|
||||
$lang_charset = $lang . '.' . NLS::getCharset();
|
||||
if ($lang_charset != setlocale(LC_ALL, $lang_charset)) {
|
||||
/* Next try language with its default charset. */
|
||||
global $nls;
|
||||
$charset = !empty($nls['charsets'][$lang]) ? $nls['charsets'][$lang] : $nls['defaults']['charset'];
|
||||
$lang_charset = $lang . '.' . $charset;
|
||||
NLS::_cachedCharset(0, $charset);
|
||||
if ($lang_charset != setlocale(LC_ALL, $lang_charset)) {
|
||||
/* At last try language solely. */
|
||||
$lang_charset = $lang;
|
||||
setlocale(LC_ALL, $lang_charset);
|
||||
}
|
||||
}
|
||||
@putenv('LANG=' . $lang_charset);
|
||||
@putenv('LANGUAGE=' . $lang_charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the gettext domain.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $app The application name.
|
||||
* @param string $directory The directory where the application's
|
||||
* LC_MESSAGES directory resides.
|
||||
* @param string $charset The charset.
|
||||
*/
|
||||
function setTextdomain($app, $directory, $charset)
|
||||
{
|
||||
bindtextdomain($app, $directory);
|
||||
textdomain($app);
|
||||
|
||||
/* The existence of this function depends on the platform. */
|
||||
if (function_exists('bind_textdomain_codeset')) {
|
||||
NLS::_cachedCharset(0, bind_textdomain_codeset($app, $charset));
|
||||
}
|
||||
|
||||
if (!headers_sent()) {
|
||||
header('Content-Type: text/html; charset=' . $charset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the supplied language is valid.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $language The abbreviated name of the language.
|
||||
*
|
||||
* @return boolean True if the language is valid, false if it's not
|
||||
* valid or unknown.
|
||||
*/
|
||||
function isValid($language)
|
||||
{
|
||||
return !empty($GLOBALS['nls']['languages'][$language]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps languages with common two-letter codes (such as nl) to the
|
||||
* full gettext code (in this case, nl_NL). Returns the language
|
||||
* unmodified if it isn't an alias.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param string $language The language code to map.
|
||||
*
|
||||
* @return string The mapped language code.
|
||||
*/
|
||||
|
||||
function _map($language)
|
||||
{
|
||||
require_once 'Horde/String.php';
|
||||
|
||||
$aliases = &$GLOBALS['nls']['aliases'];
|
||||
|
||||
// Translate the $language to get broader matches.
|
||||
// (eg. de-DE should match de_DE)
|
||||
$trans_lang = str_replace('-', '_', $language);
|
||||
$lang_parts = explode('_', $trans_lang);
|
||||
$trans_lang = String::lower($lang_parts[0]);
|
||||
if (isset($lang_parts[1])) {
|
||||
$trans_lang .= '_' . String::upper($lang_parts[1]);
|
||||
}
|
||||
|
||||
// See if we get a match for this
|
||||
if (!empty($aliases[$trans_lang])) {
|
||||
return $aliases[$trans_lang];
|
||||
}
|
||||
|
||||
// If we get that far down, the language cannot be found.
|
||||
// Return $trans_lang.
|
||||
return $trans_lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset for the current language.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param boolean $original If true returns the original charset of the
|
||||
* translation, the actually used one otherwise.
|
||||
*
|
||||
* @return string The character set that should be used with the current
|
||||
* locale settings.
|
||||
*/
|
||||
function getCharset($original = false)
|
||||
{
|
||||
global $language, $nls;
|
||||
|
||||
/* Get cached results. */
|
||||
$cacheKey = intval($original);
|
||||
$charset = NLS::_cachedCharset($cacheKey);
|
||||
if (!is_null($charset)) {
|
||||
return $charset;
|
||||
}
|
||||
|
||||
if ($original) {
|
||||
$charset = empty($nls['charsets'][$language]) ? $nls['defaults']['charset'] : $nls['charsets'][$language];
|
||||
} else {
|
||||
require_once 'Horde/Browser.php';
|
||||
$browser = &Browser::singleton();
|
||||
|
||||
if ($browser->hasFeature('utf') &&
|
||||
(Util::extensionExists('iconv') ||
|
||||
Util::extensionExists('mbstring'))) {
|
||||
$charset = 'UTF-8';
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($charset)) {
|
||||
$charset = NLS::getExternalCharset();
|
||||
}
|
||||
|
||||
NLS::_cachedCharset($cacheKey, $charset);
|
||||
return $charset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current charset of the environment
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return string The character set that should be used with the current
|
||||
* locale settings.
|
||||
*/
|
||||
function getExternalCharset()
|
||||
{
|
||||
global $language, $nls;
|
||||
|
||||
/* Get cached results. */
|
||||
$charset = NLS::_cachedCharset(2);
|
||||
if (!is_null($charset)) {
|
||||
return $charset;
|
||||
}
|
||||
|
||||
$lang_charset = setlocale(LC_ALL, 0);
|
||||
if (strpos($lang_charset, ';') === false &&
|
||||
strpos($lang_charset, '/') === false) {
|
||||
$lang_charset = explode('.', $lang_charset);
|
||||
if ((count($lang_charset) == 2) && !empty($lang_charset[1])) {
|
||||
NLS::_cachedCharset(2, $lang_charset[1]);
|
||||
return $lang_charset[1];
|
||||
}
|
||||
}
|
||||
|
||||
return (!empty($nls['charsets'][$language])) ? $nls['charsets'][$language] : $nls['defaults']['charset'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or returns the charset used under certain conditions.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param integer $index The ID of a cache slot. 0 for the UI charset, 1
|
||||
* for the translation charset and 2 for the
|
||||
* external charset.
|
||||
* @param string $charset If specified, this charset will be stored in the
|
||||
* given cache slot. Otherwise the content of the
|
||||
* specified cache slot will be returned.
|
||||
*/
|
||||
function _cachedCharset($index, $charset = null)
|
||||
{
|
||||
static $cache;
|
||||
|
||||
if (!isset($cache)) {
|
||||
$cache = array();
|
||||
}
|
||||
|
||||
if ($charset == null) {
|
||||
return isset($cache[$index]) ? $cache[$index] : null;
|
||||
} else {
|
||||
$cache[$index] = $charset;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset to use for outgoing emails.
|
||||
*
|
||||
* @return string The preferred charset for outgoing mails based on
|
||||
* the user's preferences and the current language.
|
||||
*/
|
||||
function getEmailCharset()
|
||||
{
|
||||
global $prefs, $language, $nls;
|
||||
|
||||
$charset = $prefs->getValue('sending_charset');
|
||||
if (!empty($charset)) {
|
||||
return $charset;
|
||||
}
|
||||
return isset($nls['emails'][$language]) ? $nls['emails'][$language] :
|
||||
(isset($nls['charsets'][$language]) ? $nls['charsets'][$language] : $nls['defaults']['charset']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if character set is valid for htmlspecialchars() calls.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $charset The character set to check.
|
||||
*
|
||||
* @return boolean Is charset valid for the current system?
|
||||
*/
|
||||
function checkCharset($charset)
|
||||
{
|
||||
static $check;
|
||||
|
||||
if (is_null($charset) || empty($charset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($check[$charset])) {
|
||||
return $check[$charset];
|
||||
} elseif (!isset($check)) {
|
||||
$check = array();
|
||||
}
|
||||
|
||||
$valid = true;
|
||||
|
||||
ini_set('track_errors', 1);
|
||||
@htmlspecialchars('', ENT_COMPAT, $charset);
|
||||
if (isset($php_errormsg)) {
|
||||
$valid = false;
|
||||
}
|
||||
ini_restore('track_errors');
|
||||
|
||||
$check[$charset] = $valid;
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current timezone, if available.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function setTimeZone()
|
||||
{
|
||||
global $prefs;
|
||||
|
||||
$tz = $prefs->getValue('timezone');
|
||||
if (!empty($tz)) {
|
||||
@putenv('TZ=' . $tz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the locale info returned by localeconv(), but cache it, to
|
||||
* avoid repeated calls.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return array The results of localeconv().
|
||||
*/
|
||||
function getLocaleInfo()
|
||||
{
|
||||
static $lc_info;
|
||||
|
||||
if (!isset($lc_info)) {
|
||||
$lc_info = localeconv();
|
||||
}
|
||||
|
||||
return $lc_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the language info returned by nl_langinfo(), but cache it, to
|
||||
* avoid repeated calls.
|
||||
*
|
||||
* @access public
|
||||
* @since Horde 3.1
|
||||
*
|
||||
* @param const $item The langinfo item to return.
|
||||
*
|
||||
* @return array The results of nl_langinfo().
|
||||
*/
|
||||
function getLangInfo($item)
|
||||
{
|
||||
static $nl_info = array();
|
||||
|
||||
if (!isset($nl_info[$item])) {
|
||||
$nl_info[$item] = nl_langinfo($item);
|
||||
}
|
||||
|
||||
return $nl_info[$item];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get country information from a hostname or IP address.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $host The hostname or IP address.
|
||||
*
|
||||
* @return mixed On success, return an array with the following entries:
|
||||
* 'code' => Country Code
|
||||
* 'name' => Country Name
|
||||
* On failure, return false.
|
||||
*/
|
||||
function getCountryByHost($host)
|
||||
{
|
||||
global $conf;
|
||||
|
||||
/* List of generic domains that we know is not in the country TLD
|
||||
list. See: http://www.iana.org/gtld/gtld.htm */
|
||||
$generic = array(
|
||||
'aero', 'biz', 'com', 'coop', 'edu', 'gov', 'info', 'int', 'mil',
|
||||
'museum', 'name', 'net', 'org', 'pro'
|
||||
);
|
||||
|
||||
$checkHost = $host;
|
||||
if (preg_match('/^\d+\.\d+\.\d+\.\d+$/', $host)) {
|
||||
$checkHost = @gethostbyaddr($host);
|
||||
}
|
||||
|
||||
/* Get the TLD of the hostname. */
|
||||
$pos = strrpos($checkHost, '.');
|
||||
if ($pos === false) {
|
||||
return false;
|
||||
}
|
||||
$domain = String::lower(substr($checkHost, $pos + 1));
|
||||
|
||||
/* Try lookup via TLD first. */
|
||||
if (!in_array($domain, $generic)) {
|
||||
require 'Horde/NLS/tld.php';
|
||||
if (isset($tld[$domain])) {
|
||||
return array('code' => $domain, 'name' => $tld[$domain]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try GeoIP lookup next. */
|
||||
if (!empty($conf['geoip']['datafile'])) {
|
||||
require_once 'Horde/NLS/GeoIP.php';
|
||||
$geoip = &NLS_GeoIP::singleton($conf['geoip']['datafile']);
|
||||
$id = $geoip->countryIdByName($checkHost);
|
||||
if (!empty($id)) {
|
||||
return array('code' => String::lower($GLOBALS['GEOIP_COUNTRY_CODES'][$id]), 'name' => $GLOBALS['GEOIP_COUNTRY_NAMES'][$id]);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Horde image link to the country flag.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $host The hostname or IP address.
|
||||
*
|
||||
* @return string The image URL, or the empty string on error.
|
||||
*/
|
||||
function generateFlagImageByHost($host)
|
||||
{
|
||||
global $registry;
|
||||
|
||||
$data = NLS::getCountryByHost($host);
|
||||
if ($data !== false) {
|
||||
$img = $data['code'] . '.png';
|
||||
if (file_exists($registry->get('themesfs', 'horde') . '/graphics/flags/' . $img)) {
|
||||
return Horde::img($img, $data['name'], '', $registry->getImageDir('horde') . '/flags');
|
||||
} else {
|
||||
return '[' . $data['name'] . ']';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either a specific or all ISO-3166 country names.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param optional string $code The ISO 3166 country code.
|
||||
*
|
||||
* @return mixed If a country code has been requested will return the
|
||||
* corresponding country name. If empty will return an
|
||||
* array of all the country codes and their names.
|
||||
*/
|
||||
function &getCountryISO($code = '')
|
||||
{
|
||||
static $countries = array();
|
||||
if (empty($countries)) {
|
||||
require_once 'Horde/NLS/countries.php';
|
||||
}
|
||||
if (empty($code)) {
|
||||
return $countries;
|
||||
} elseif (isset($countries[$code])) {
|
||||
return $countries[$code];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,252 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The Horde_RPC:: class provides a set of server and client methods for
|
||||
* RPC communication.
|
||||
*
|
||||
* TODO:
|
||||
* - Introspection documentation and method signatures.
|
||||
*
|
||||
* EXAMPLE:
|
||||
* <code>
|
||||
* $response = Horde_RPC::request('xmlrpc',
|
||||
* 'http://localhost:80/horde/rpc.php'
|
||||
* 'contacts.search',
|
||||
* array(array('jan'), array('localsql'),
|
||||
* array('name', 'email')),
|
||||
* array('user' => Auth::getAuth(),
|
||||
* 'pass' => Auth::getCredential('password')));
|
||||
* </code>
|
||||
*
|
||||
* $Horde: framework/RPC/RPC.php,v 1.14 2006/01/01 21:10:10 jan Exp $
|
||||
*
|
||||
* Copyright 2002-2006 Jan Schneider <jan@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 Jan Schneider <jan@horde.org>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_RPC
|
||||
*/
|
||||
class Horde_RPC {
|
||||
|
||||
/**
|
||||
* Whether we need an authorized user or not.
|
||||
*
|
||||
* @access protected
|
||||
* @var boolean
|
||||
*/
|
||||
var $_authorize = true;
|
||||
|
||||
/**
|
||||
* RPC server constructor
|
||||
*
|
||||
* @access private
|
||||
* @return object An RPC server instance.
|
||||
*/
|
||||
function Horde_RPC()
|
||||
{
|
||||
register_shutdown_function(array($this, 'shutdown'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the RPC server.
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
function shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Check authentication. Different backends may handle
|
||||
* authentication in different ways. The base class implementation
|
||||
* checks for HTTP Authentication against the Horde auth setup.
|
||||
*
|
||||
* @return boolean Returns true if authentication is successful.
|
||||
* Should send appropriate "not authorized" headers
|
||||
* or other response codes/body if auth fails,
|
||||
* and take care of exiting.
|
||||
*/
|
||||
function authorize()
|
||||
{
|
||||
if (!$this->_authorize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$auth = &Auth::singleton($GLOBALS['conf']['auth']['driver']);
|
||||
|
||||
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
$user = $_SERVER['PHP_AUTH_USER'];
|
||||
$pass = $_SERVER['PHP_AUTH_PW'];
|
||||
}
|
||||
|
||||
if (!isset($user)
|
||||
|| !$auth->authenticate($user, array('password' => $pass))) {
|
||||
header('WWW-Authenticate: Basic realm="Horde RPC"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo '401 Unauthorized';
|
||||
exit;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request body input. Different RPC backends can override
|
||||
* this to return an open stream to php://stdin, for instance -
|
||||
* whatever is easiest to handle in the getResponse() method.
|
||||
*
|
||||
* The base class implementation looks for $HTTP_RAW_POST_DATA and
|
||||
* returns that if it's available; otherwise, it returns the
|
||||
* contents of php://stdin.
|
||||
*
|
||||
* @return mixed The input - a string (default), a filehandle, etc.
|
||||
*/
|
||||
function getInput()
|
||||
{
|
||||
if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
|
||||
return $GLOBALS['HTTP_RAW_POST_DATA'];
|
||||
} else {
|
||||
return implode("\r\n", file('php://input'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an RPC request to the server and returns the result.
|
||||
*
|
||||
* @param string The raw request string.
|
||||
*
|
||||
* @return string The XML encoded response from the server.
|
||||
*/
|
||||
function getResponse($request)
|
||||
{
|
||||
return _("not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Content-Type of the response.
|
||||
*
|
||||
* @return string The MIME Content-Type of the RPC response.
|
||||
*/
|
||||
function getResponseContentType()
|
||||
{
|
||||
return 'text/xml';
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an RPC request and sends it to the RPC server.
|
||||
*
|
||||
* This statically called method is actually the RPC client.
|
||||
*
|
||||
* @param string $driver The protocol driver to use. Currently 'soap'
|
||||
* and 'xmlrpc' are available.
|
||||
* @param string $url The path to the RPC server on the called host.
|
||||
* @param string $method The method to call.
|
||||
* @param array $params A hash containing any necessary parameters for
|
||||
* the method call.
|
||||
* @param $options Associative array of parameters depending on
|
||||
* the selected protocol driver.
|
||||
*
|
||||
* @return mixed The returned result from the method or a PEAR
|
||||
* error object on failure.
|
||||
*/
|
||||
function request($driver, $url, $method, $params = null, $options = array())
|
||||
{
|
||||
if (is_array($driver)) {
|
||||
list($app, $driver) = $driver;
|
||||
}
|
||||
|
||||
$driver = basename($driver);
|
||||
|
||||
if (!empty($app)) {
|
||||
require_once $app . '/lib/RPC/' . $driver . '.php';
|
||||
} elseif (@file_exists(dirname(__FILE__) . '/RPC/' . $driver . '.php')) {
|
||||
require_once dirname(__FILE__) . '/RPC/' . $driver . '.php';
|
||||
} else {
|
||||
@include_once 'Horde/RPC/' . $driver . '.php';
|
||||
}
|
||||
$class = 'Horde_RPC_' . $driver;
|
||||
if (class_exists($class)) {
|
||||
return call_user_func(array($class, 'request'), $url, $method, $params, $options);
|
||||
} else {
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::raiseError('Class definition of ' . $class . ' not found.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to return a concrete RPC server instance based on
|
||||
* $driver.
|
||||
*
|
||||
* @param mixed $driver The type of concrete RPC subclass to return. If
|
||||
* $driver is an array, then we will look in
|
||||
* $driver[0]/lib/RPC/ for the subclass
|
||||
* implementation named $driver[1].php.
|
||||
* @param array $params A hash containing any additional configuration or
|
||||
* connection parameters a subclass might need.
|
||||
*
|
||||
* @return Horde_RPC The newly created concrete Horde_RPC server instance,
|
||||
* or a PEAR_Error on an error.
|
||||
*/
|
||||
function &factory($driver, $params = null)
|
||||
{
|
||||
if (is_array($driver)) {
|
||||
list($app, $driver) = $driver;
|
||||
}
|
||||
|
||||
$driver = basename($driver);
|
||||
|
||||
if (!empty($app)) {
|
||||
require_once $app . '/lib/RPC/' . $driver . '.php';
|
||||
} elseif (@file_exists(dirname(__FILE__) . '/RPC/' . $driver . '.php')) {
|
||||
require_once dirname(__FILE__) . '/RPC/' . $driver . '.php';
|
||||
} else {
|
||||
@include_once 'Horde/RPC/' . $driver . '.php';
|
||||
}
|
||||
$class = 'Horde_RPC_' . $driver;
|
||||
if (class_exists($class)) {
|
||||
$rpc = new $class($params);
|
||||
} else {
|
||||
require_once 'PEAR.php';
|
||||
$rpc = PEAR::raiseError('Class definition of ' . $class . ' not found.');
|
||||
}
|
||||
|
||||
return $rpc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to return a reference to a concrete RPC server
|
||||
* instance based on $driver. It will only create a new instance
|
||||
* if no RPC server instance with the same parameters currently
|
||||
* exists.
|
||||
*
|
||||
* This should be used if multiple RPC servers (and thus, multiple RPC
|
||||
* server instances) are required.
|
||||
*
|
||||
* This method must be invoked as: $var = &Horde_RPC::singleton()
|
||||
*
|
||||
* @param string $driver The type of concrete RPC subclass to return.
|
||||
* @param array $params A hash containing any additional configuration or
|
||||
* connection parameters a subclass might need.
|
||||
*
|
||||
* @return Horde_RPC The concrete Horde_RPC server reference, or a
|
||||
* PEAR_Error on an error.
|
||||
*/
|
||||
function &singleton($driver, $params = null)
|
||||
{
|
||||
static $instances;
|
||||
|
||||
if (!isset($instances)) {
|
||||
$instances = array();
|
||||
}
|
||||
|
||||
$signature = serialize(array($driver, $params));
|
||||
if (!array_key_exists($signature, $instances)) {
|
||||
$instances[$signature] = &Horde_RPC::factory($driver, $params);
|
||||
}
|
||||
|
||||
return $instances[$signature];
|
||||
}
|
||||
|
||||
}
|
@ -1,273 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once 'Horde/SyncML.php';
|
||||
#require_once 'Horde/SyncML/State.php';
|
||||
require_once 'Horde/SyncML/State_egw.php';
|
||||
require_once 'Horde/SyncML/Command/Status.php';
|
||||
|
||||
/**
|
||||
* The Horde_RPC_syncml class provides a SyncML implementation of the Horde
|
||||
* RPC system.
|
||||
*
|
||||
* $Horde: framework/RPC/RPC/syncml.php,v 1.27 2006/01/01 21:10:11 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2006 Chuck Hagenbuch <chuck@horde.org>
|
||||
* 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.
|
||||
*
|
||||
* @author Chuck Hagenbuch <chuck@horde.org>
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_RPC
|
||||
*/
|
||||
class Horde_RPC_syncml extends Horde_RPC {
|
||||
|
||||
/**
|
||||
* Output ContentHandler used to output XML events.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
var $_output;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
var $_xmlStack = 0;
|
||||
|
||||
/**
|
||||
* Debug directory, if set will store copies of all packets.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_debugDir = '/tmp/sync';
|
||||
|
||||
/**
|
||||
* Default character set. Only supports UTF-8(ASCII?).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* SyncML handles authentication internally, so bypass the RPC framework
|
||||
* auth check by just returning true here.
|
||||
*/
|
||||
function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an RPC request to the server and returns the result.
|
||||
*
|
||||
* @param string $request The raw request string.
|
||||
*
|
||||
* @return string The XML encoded response from the server.
|
||||
*/
|
||||
function getResponse($request)
|
||||
{
|
||||
/* Catch any errors/warnings/notices that may get thrown while
|
||||
* processing. Don't want to let anything go to the client that's not
|
||||
* part of the valid response. */
|
||||
ob_start();
|
||||
|
||||
/* Very useful for debugging. Logs WBXML packets to
|
||||
* $this->_debugDir. */
|
||||
if (!empty($this->_debugDir) && is_dir($this->_debugDir)) {
|
||||
$packetNum = @intval(file_get_contents($this->_debugDir . '/syncml.packetnum'));
|
||||
if (!isset($packetNum)) {
|
||||
$packetNum = 0;
|
||||
}
|
||||
|
||||
$f = @fopen($this->_debugDir . '/syncml_client_' . $packetNum . '.xml', 'wb');
|
||||
if ($f) {
|
||||
fwrite($f, $request);
|
||||
fclose($f);
|
||||
}
|
||||
}
|
||||
|
||||
require_once 'XML/WBXML/ContentHandler.php';
|
||||
$this->_output = new XML_WBXML_ContentHandler();
|
||||
|
||||
$this->_parse($request);
|
||||
$response = '<?xml version="1.0" encoding="' . $this->_charset . '"?>';
|
||||
$response .= $this->_output->getOutput();
|
||||
|
||||
/* Very useful for debugging. */
|
||||
if (!empty($this->_debugDir) && is_dir($this->_debugDir)) {
|
||||
$f = @fopen($this->_debugDir . '/syncml_server_' . $packetNum . '.xml', 'wb');
|
||||
if ($f) {
|
||||
fwrite($f, $response);
|
||||
fclose($f);
|
||||
}
|
||||
|
||||
$fp = @fopen($this->_debugDir . '/syncml.packetnum', 'w');
|
||||
if ($fp) {
|
||||
fwrite($fp, ++$packetNum);
|
||||
fclose($fp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the output buffer that we started above, and log anything
|
||||
* that came up for later debugging. */
|
||||
$errorLogging = ob_get_clean();
|
||||
if (!empty($errorLogging)) {
|
||||
Horde::logMessage('SyncML: caught output=' .
|
||||
$errorLogging, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function _parse($xml)
|
||||
{
|
||||
/* try to extract charset from XML text */
|
||||
if(preg_match('/^\s*<\?xml[^>]*encoding\s*=\s*"([^"]*)"/i',
|
||||
$xml, $m)) {
|
||||
$this->_charset = $m[1];
|
||||
}
|
||||
#NLS::setCharset($this->_charset);
|
||||
#String::setDefaultCharset($this->_charset);
|
||||
|
||||
/* Create the XML parser and set method references. */
|
||||
$this->_parser = xml_parser_create_ns($this->_charset);
|
||||
xml_set_object($this->_parser, $this);
|
||||
xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
|
||||
xml_set_element_handler($this->_parser, '_startElement', '_endElement');
|
||||
xml_set_character_data_handler($this->_parser, '_characters');
|
||||
xml_set_processing_instruction_handler($this->_parser, '');
|
||||
xml_set_external_entity_ref_handler($this->_parser, '');
|
||||
|
||||
if (!xml_parse($this->_parser, $xml)) {
|
||||
return $this->raiseError(sprintf('XML error: %s at line %d',
|
||||
xml_error_string(xml_get_error_code($this->_parser)),
|
||||
xml_get_current_line_number($this->_parser)));
|
||||
}
|
||||
|
||||
xml_parser_free($this->_parser);
|
||||
}
|
||||
|
||||
function _startElement($parser, $tag, $attributes)
|
||||
{
|
||||
list($uri, $name) = $this->_splitURI($tag);
|
||||
|
||||
$this->startElement($uri, $name, $attributes);
|
||||
}
|
||||
|
||||
function _characters($parser, $chars)
|
||||
{
|
||||
$this->characters($chars);
|
||||
}
|
||||
|
||||
function _endElement($parser, $tag)
|
||||
{
|
||||
list($uri, $name) = $this->_splitURI($tag);
|
||||
|
||||
$this->endElement($uri, $name);
|
||||
}
|
||||
|
||||
function _splitURI($tag)
|
||||
{
|
||||
$parts = explode(':', $tag);
|
||||
$name = array_pop($parts);
|
||||
$uri = implode(':', $parts);
|
||||
return array($uri, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Content-Type of the response.
|
||||
*
|
||||
* @return string The MIME Content-Type of the RPC response.
|
||||
*/
|
||||
function getResponseContentType()
|
||||
{
|
||||
return 'application/vnd.syncml+xml';
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
$this->_xmlStack++;
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 1:
|
||||
// <SyncML>
|
||||
// Defined in SyncML Representation Protocol, version 1.1 5.2.1
|
||||
$this->_output->startElement($uri, $element, $attrs);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Either <SyncML><SyncHdr> or <SyncML><SyncBody>
|
||||
if (!isset($this->_contentHandler)) {
|
||||
// If not defined then create SyncHdr.
|
||||
$this->_contentHandler = new Horde_SyncML_SyncmlHdr();
|
||||
$this->_contentHandler->setOutput($this->_output);
|
||||
}
|
||||
|
||||
$this->_contentHandler->startElement($uri, $element, $attrs);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isset($this->_contentHandler)) {
|
||||
$this->_contentHandler->startElement($uri, $element, $attrs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 1:
|
||||
// </SyncML>
|
||||
// Defined in SyncML Representation Protocol, version 1.1 5.2.1
|
||||
$this->_output->endElement($uri, $element);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Either </SyncHdr></SyncML> or </SyncBody></SyncML>
|
||||
if ($element == 'SyncHdr') {
|
||||
// Then we get the state from SyncMLHdr, and create a new
|
||||
// SyncMLBody.
|
||||
$this->_contentHandler->endElement($uri, $element);
|
||||
|
||||
unset($this->_contentHandler);
|
||||
|
||||
$this->_contentHandler = new Horde_SyncML_SyncmlBody();
|
||||
$this->_contentHandler->setOutput($this->_output);
|
||||
} else {
|
||||
// No longer used.
|
||||
$this->_contentHandler->endElement($uri, $element);
|
||||
unset($this->_contentHandler);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// </*></SyncHdr></SyncML> or </*></SyncBody></SyncML>
|
||||
if (isset($this->_contentHandler)) {
|
||||
$this->_contentHandler->endElement($uri, $element);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($this->_chars)) {
|
||||
unset($this->_chars);
|
||||
}
|
||||
|
||||
$this->_xmlStack--;
|
||||
}
|
||||
|
||||
function characters($str)
|
||||
{
|
||||
if (isset($this->_contentHandler)) {
|
||||
$this->_contentHandler->characters($str);
|
||||
}
|
||||
}
|
||||
|
||||
function raiseError($str)
|
||||
{
|
||||
return Horde::logMessage($str, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
}
|
||||
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__FILE__) . '/syncml.php';
|
||||
require_once 'XML/WBXML/Decoder.php';
|
||||
require_once 'XML/WBXML/Encoder.php';
|
||||
|
||||
/**
|
||||
* The Horde_RPC_syncml_wbxml class provides a SyncML implementation of the
|
||||
* Horde RPC system using WBXML encoding.
|
||||
*
|
||||
* $Horde: framework/RPC/RPC/syncml_wbxml.php,v 1.18 2006/01/01 21:10:11 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2006 Chuck Hagenbuch <chuck@horde.org>
|
||||
* 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.
|
||||
*
|
||||
* @author Chuck Hagenbuch <chuck@horde.org>
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_RPC
|
||||
*/
|
||||
class Horde_RPC_syncml_wbxml extends Horde_RPC_syncml {
|
||||
|
||||
/**
|
||||
* Sends an RPC request to the server and returns the result.
|
||||
*
|
||||
* @param string $request The raw request string.
|
||||
*
|
||||
* @return string The WBXML encoded response from the server (binary).
|
||||
*/
|
||||
function getResponse($request)
|
||||
{
|
||||
/* Catch any errors/warnings/notices that may get thrown while
|
||||
* processing. Don't want to let anything go to the client that's not
|
||||
* part of the valid response. */
|
||||
ob_start();
|
||||
|
||||
/* Very useful for debugging. Logs WBXML packets to
|
||||
* $this->_debugDir. */
|
||||
if (!empty($this->_debugDir) && is_dir($this->_debugDir)) {
|
||||
$packetNum = @intval(file_get_contents($this->_debugDir . '/syncml.packetnum'));
|
||||
if (!isset($packetNum)) {
|
||||
$packetNum = 0;
|
||||
}
|
||||
|
||||
$fp = fopen($this->_debugDir . '/syncml_client_' . $packetNum . '.wbxml', 'wb');
|
||||
fwrite($fp, $request);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
|
||||
$decoder = new XML_WBXML_Decoder();
|
||||
$this->_output = new XML_WBXML_Encoder();
|
||||
|
||||
$decoder->setContentHandler($this);
|
||||
|
||||
$r = $decoder->decode($request);
|
||||
if (is_a($r, 'PEAR_Error')) {
|
||||
Horde::logMessage('SyncML: ' .
|
||||
$r->getMessage(), __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
}
|
||||
|
||||
$this->_output->setVersion($decoder->getVersion());
|
||||
$this->_output->setCharset($decoder->getCharsetStr());
|
||||
$response = $this->_output->getOutput();
|
||||
|
||||
if (is_a($response, 'PEAR_Error')) {
|
||||
Horde::logMessage($response, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$response = $response->getMessage();
|
||||
}
|
||||
|
||||
if (!empty($this->_debugDir) && is_dir($this->_debugDir)) {
|
||||
$fp = fopen($this->_debugDir . '/syncml_server_' . $packetNum . '.wbxml', 'wb');
|
||||
fwrite($fp, $response);
|
||||
fclose($fp);
|
||||
|
||||
$fp = @fopen($this->_debugDir . '/syncml.packetnum', 'w');
|
||||
if ($fp) {
|
||||
fwrite($fp, ++$packetNum);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Clear the output buffer that we started above, and log anything
|
||||
* that came up for later debugging. */
|
||||
$errorLogging = ob_get_clean();
|
||||
if (!empty($errorLogging)) {
|
||||
Horde::logMessage('SyncML: caught output=' . $errorLogging,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Content-Type of the response.
|
||||
*
|
||||
* @return string The MIME Content-Type of the RPC response.
|
||||
*/
|
||||
function getResponseContentType()
|
||||
{
|
||||
return 'application/vnd.syncml+wbxml';
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,705 +0,0 @@
|
||||
<?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.43.6.38 2009-09-15 16:36:14 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2009 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 Jan Schneider <jan@horde.org>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_Util
|
||||
*/
|
||||
class String {
|
||||
|
||||
/**
|
||||
* Caches the result of extension_loaded() calls.
|
||||
*
|
||||
* @param string $ext The extension name.
|
||||
*
|
||||
* @return boolean Is the extension loaded?
|
||||
*
|
||||
* @see Util::extensionExists()
|
||||
*/
|
||||
public static 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
|
||||
* explicitly specified.
|
||||
*
|
||||
* @param string $charset The charset to use as the default one.
|
||||
*/
|
||||
public static function setDefaultCharset($charset)
|
||||
{
|
||||
$GLOBALS['_HORDE_STRING_CHARSET'] = $charset;
|
||||
if (String::extensionExists('mbstring') &&
|
||||
function_exists('mb_regex_encoding')) {
|
||||
$old_error = error_reporting(0);
|
||||
mb_regex_encoding(String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string from one charset to another.
|
||||
*
|
||||
* Works only if either the iconv or the mbstring extension
|
||||
* are present and best if both are available.
|
||||
* 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.
|
||||
*
|
||||
* @return mixed The converted input data.
|
||||
*/
|
||||
public static 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 ($from == $to) {
|
||||
return $input;
|
||||
}
|
||||
$from = String::lower($from);
|
||||
$to = String::lower($to);
|
||||
if ($from == $to) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
if (is_array($input)) {
|
||||
$tmp = array();
|
||||
reset($input);
|
||||
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);
|
||||
while (list($key, $val) = each($vars)) {
|
||||
$input->$key = String::convertCharset($val, $from, $to);
|
||||
}
|
||||
return $input;
|
||||
}
|
||||
|
||||
if (!is_string($input)) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
return String::_convertCharset($input, $from, $to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal public static 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.
|
||||
*/
|
||||
public static function _convertCharset($input, $from, $to)
|
||||
{
|
||||
$output = '';
|
||||
$from_check = (($from == 'iso-8859-1') || ($from == 'us-ascii'));
|
||||
$to_check = (($to == 'iso-8859-1') || ($to == 'us-ascii'));
|
||||
|
||||
/* 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
|
||||
* public static 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') &&
|
||||
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');
|
||||
$output = (isset($php_errormsg)) ? false : String::substr($output, 0, -1, $to);
|
||||
ini_set('track_errors', $oldTrackErrors);
|
||||
}
|
||||
|
||||
/* Next try mbstring. */
|
||||
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 && String::extensionExists('imap')) {
|
||||
if ($from_check && ($to == 'utf7-imap')) {
|
||||
return @imap_utf7_encode($input);
|
||||
}
|
||||
if (($from == 'utf7-imap') && $to_check) {
|
||||
return @imap_utf7_decode($input);
|
||||
}
|
||||
}
|
||||
|
||||
return (!$output) ? $input : $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a string lowercase.
|
||||
*
|
||||
* @param string $string The string to be converted.
|
||||
* @param boolean $locale If true the string will be converted based on a
|
||||
* given charset, locale independent else.
|
||||
* @param string $charset If $locale is true, the charset to use when
|
||||
* converting. If not provided the current charset.
|
||||
*
|
||||
* @return string The string with lowercase characters
|
||||
*/
|
||||
public static function lower($string, $locale = false, $charset = null)
|
||||
{
|
||||
static $lowers;
|
||||
|
||||
if ($locale) {
|
||||
/* The existence of mb_strtolower() depends on the platform. */
|
||||
if (String::extensionExists('mbstring') &&
|
||||
function_exists('mb_strtolower')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strtolower($string, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
return strtolower($string);
|
||||
}
|
||||
|
||||
if (!isset($lowers)) {
|
||||
$lowers = array();
|
||||
}
|
||||
if (!isset($lowers[$string])) {
|
||||
$language = setlocale(LC_CTYPE, 0);
|
||||
setlocale(LC_CTYPE, 'C');
|
||||
$lowers[$string] = strtolower($string);
|
||||
setlocale(LC_CTYPE, $language);
|
||||
}
|
||||
|
||||
return $lowers[$string];
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a string uppercase.
|
||||
*
|
||||
* @param string $string The string to be converted.
|
||||
* @param boolean $locale If true the string will be converted based on a
|
||||
* given charset, locale independent else.
|
||||
* @param string $charset If $locale is true, the charset to use when
|
||||
* converting. If not provided the current charset.
|
||||
*
|
||||
* @return string The string with uppercase characters
|
||||
*/
|
||||
public static function upper($string, $locale = false, $charset = null)
|
||||
{
|
||||
static $uppers;
|
||||
|
||||
if ($locale) {
|
||||
/* The existence of mb_strtoupper() depends on the
|
||||
* platform. */
|
||||
if (function_exists('mb_strtoupper')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strtoupper($string, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
return strtoupper($string);
|
||||
}
|
||||
|
||||
if (!isset($uppers)) {
|
||||
$uppers = array();
|
||||
}
|
||||
if (!isset($uppers[$string])) {
|
||||
$language = setlocale(LC_CTYPE, 0);
|
||||
setlocale(LC_CTYPE, 'C');
|
||||
$uppers[$string] = strtoupper($string);
|
||||
setlocale(LC_CTYPE, $language);
|
||||
}
|
||||
|
||||
return $uppers[$string];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with the first letter capitalized if it is
|
||||
* alphabetic.
|
||||
*
|
||||
* @param string $string The string to be capitalized.
|
||||
* @param boolean $locale If true the string will be converted based on a
|
||||
* given charset, locale independent else.
|
||||
* @param string $charset The charset to use, defaults to current charset.
|
||||
*
|
||||
* @return string The capitalized string.
|
||||
*/
|
||||
public static function ucfirst($string, $locale = false, $charset = null)
|
||||
{
|
||||
if ($locale) {
|
||||
$first = String::substr($string, 0, 1, $charset);
|
||||
if (String::isAlpha($first, $charset)) {
|
||||
$string = String::upper($first, true, $charset) . String::substr($string, 1, null, $charset);
|
||||
}
|
||||
} else {
|
||||
$string = String::upper(substr($string, 0, 1), false) . substr($string, 1);
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns part of a string.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public static function substr($string, $start, $length = null, $charset = null)
|
||||
{
|
||||
if (is_null($length)) {
|
||||
$length = String::length($string, $charset) - $start;
|
||||
}
|
||||
|
||||
if ($length == 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/* Try mbstring. */
|
||||
if (String::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_substr($string, $start, $length, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
/* mb_substr() returns empty string on failure. */
|
||||
if (strlen($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try iconv. */
|
||||
if (function_exists('iconv_substr')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
|
||||
$old_error = error_reporting(0);
|
||||
$ret = iconv_substr($string, $start, $length, $charset);
|
||||
error_reporting($old_error);
|
||||
/* iconv_substr() returns false on failure. */
|
||||
if ($ret !== false) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
return substr($string, $start, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character (not byte) length of a string.
|
||||
*
|
||||
* @param string $string The string to return the length of.
|
||||
* @param string $charset The charset to use when calculating the string's
|
||||
* length.
|
||||
*
|
||||
* @return string The string's part.
|
||||
*/
|
||||
public static function length($string, $charset = null)
|
||||
{
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$charset = String::lower($charset);
|
||||
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;
|
||||
}
|
||||
}
|
||||
if ($charset == 'utf-8' || $charset == 'utf8') {
|
||||
return strlen(utf8_decode($string));
|
||||
}
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numeric position of the first occurrence of $needle
|
||||
* in the $haystack string.
|
||||
*
|
||||
* @param string $haystack The string to search through.
|
||||
* @param string $needle The string to search for.
|
||||
* @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 integer The position of first occurrence.
|
||||
*/
|
||||
public static function pos($haystack, $needle, $offset = 0, $charset = null)
|
||||
{
|
||||
if (String::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$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;
|
||||
}
|
||||
}
|
||||
return strpos($haystack, $needle, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string padded to a certain length with another string.
|
||||
*
|
||||
* This method behaves exactly like str_pad but is multibyte safe.
|
||||
*
|
||||
* @param string $input The string to be padded.
|
||||
* @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,
|
||||
* STR_PAD_RIGHT, or STR_PAD_BOTH.
|
||||
* @param string $charset The charset of the input and the padding
|
||||
* strings.
|
||||
*
|
||||
* @return string The padded string.
|
||||
*/
|
||||
public static function pad($input, $length, $pad = ' ', $type = STR_PAD_RIGHT,
|
||||
$charset = null)
|
||||
{
|
||||
$mb_length = String::length($input, $charset);
|
||||
$sb_length = strlen($input);
|
||||
$pad_length = String::length($pad, $charset);
|
||||
|
||||
/* Return if we already have the length. */
|
||||
if ($mb_length >= $length) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
/* Shortcut for single byte strings. */
|
||||
if ($mb_length == $sb_length && $pad_length == strlen($pad)) {
|
||||
return str_pad($input, $length, $pad, $type);
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case STR_PAD_LEFT:
|
||||
$left = $length - $mb_length;
|
||||
$output = String::substr(str_repeat($pad, ceil($left / $pad_length)), 0, $left, $charset) . $input;
|
||||
break;
|
||||
case STR_PAD_BOTH:
|
||||
$left = floor(($length - $mb_length) / 2);
|
||||
$right = ceil(($length - $mb_length) / 2);
|
||||
$output = String::substr(str_repeat($pad, ceil($left / $pad_length)), 0, $left, $charset) .
|
||||
$input .
|
||||
String::substr(str_repeat($pad, ceil($right / $pad_length)), 0, $right, $charset);
|
||||
break;
|
||||
case STR_PAD_RIGHT:
|
||||
$right = $length - $mb_length;
|
||||
$output = $input . String::substr(str_repeat($pad, ceil($right / $pad_length)), 0, $right, $charset);
|
||||
break;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the text of a message.
|
||||
*
|
||||
* @since Horde 3.2
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @return string String containing the wrapped text.
|
||||
*/
|
||||
public static 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).*)/us', $string, $match)) {
|
||||
$line .= $match[1];
|
||||
$string = $match[2];
|
||||
}
|
||||
// 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 .= $line . $break;
|
||||
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.
|
||||
*/
|
||||
public static function wrap($text, $length = 80, $break_char = "\n", $charset = null,
|
||||
$quote = false)
|
||||
{
|
||||
$paragraphs = array();
|
||||
|
||||
foreach (preg_split('/\r?\n/', $text) as $input) {
|
||||
if ($quote && (strpos($input, '>') === 0)) {
|
||||
$line = $input;
|
||||
} else {
|
||||
/* We need to handle the Usenet-style signature line
|
||||
* separately; since the space after the two dashes is
|
||||
* REQUIRED, we don't want to trim the line. */
|
||||
if ($input != '-- ') {
|
||||
$input = rtrim($input);
|
||||
}
|
||||
$line = String::wordwrap($input, $length, $break_char, false, $charset);
|
||||
}
|
||||
|
||||
$paragraphs[] = $line;
|
||||
}
|
||||
|
||||
return implode($break_char, $paragraphs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return boolean True if the parameter was alphabetic only.
|
||||
*/
|
||||
public static function isAlpha($string, $charset = null)
|
||||
{
|
||||
if (!String::extensionExists('mbstring')) {
|
||||
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 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.
|
||||
*
|
||||
* @return boolean True if the parameter was lowercase.
|
||||
*/
|
||||
public static function isLower($string, $charset = null)
|
||||
{
|
||||
return ((String::lower($string, true, $charset) === $string) &&
|
||||
String::isAlpha($string, $charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return boolean True if the parameter was uppercase.
|
||||
*/
|
||||
public static function isUpper($string, $charset = null)
|
||||
{
|
||||
return ((String::upper($string, true, $charset) === $string) &&
|
||||
String::isAlpha($string, $charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a multibyte safe regex match search on the text provided.
|
||||
*
|
||||
* @since Horde 3.1
|
||||
*
|
||||
* @param string $text The text to search.
|
||||
* @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.
|
||||
*/
|
||||
public static function regexMatch($text, $regex, $charset = null)
|
||||
{
|
||||
if (!empty($charset)) {
|
||||
$regex = String::convertCharset($regex, $charset, 'utf-8');
|
||||
$text = String::convertCharset($text, $charset, 'utf-8');
|
||||
}
|
||||
|
||||
$matches = array();
|
||||
foreach ($regex as $val) {
|
||||
if (preg_match('/' . $val . '/u', $text, $matches)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($charset)) {
|
||||
$matches = String::convertCharset($matches, 'utf-8', $charset);
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround charsets that don't work with mbstring public static functions.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param string $charset The original charset.
|
||||
*
|
||||
* @return string The charset to use with mbstring public static functions.
|
||||
*/
|
||||
public static function _mbstringCharset($charset)
|
||||
{
|
||||
/* mbstring public static 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,752 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_ContentHandler {
|
||||
|
||||
/**
|
||||
* Output ContentHandler used to output XML events.
|
||||
* @var object $_output
|
||||
*/
|
||||
var $_output;
|
||||
|
||||
/**
|
||||
* @var integer $_xmlStack
|
||||
*/
|
||||
var $_xmlStack = 1;
|
||||
|
||||
/**
|
||||
* @var string $_chars
|
||||
*/
|
||||
var $_chars;
|
||||
|
||||
function setOutput(&$output)
|
||||
{
|
||||
$this->_output = &$output;
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
$this->_xmlStack++;
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
if (isset($this->_chars)) {
|
||||
unset($this->_chars);
|
||||
}
|
||||
|
||||
$this->_xmlStack--;
|
||||
}
|
||||
|
||||
function characters($str)
|
||||
{
|
||||
if (isset($this->_chars)) {
|
||||
$this->_chars = $this->_chars . $str;
|
||||
} else {
|
||||
$this->_chars = $str;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined in SyncML Representation Protocol, version 1.1 5.2.2
|
||||
*
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
|
||||
/**
|
||||
* Used to specify if in Source tag. Defined in SyncML
|
||||
* Representation Protocol, version 1.1 5.1.20.
|
||||
*
|
||||
* @var boolean $_isSource
|
||||
*/
|
||||
var $_isSource = false;
|
||||
|
||||
/**
|
||||
* Defined in SyncML Representation Protocol, version 1.1
|
||||
* 5.1.9. User name.
|
||||
*
|
||||
* @var string $_locName
|
||||
*/
|
||||
var $_locName;
|
||||
|
||||
/**
|
||||
* Defined in SyncML Representation Protocol, version 1.1 5.1.18
|
||||
*
|
||||
* @var string $_sessionID
|
||||
*/
|
||||
|
||||
var $_sessionID;
|
||||
|
||||
/**
|
||||
* Defined in SyncML Representation Protocol, version 1.1. Must
|
||||
* be 1.0 (0), 1.1 (1) or 1.2(2).
|
||||
*
|
||||
* @var string $_version
|
||||
*/
|
||||
var $_version;
|
||||
|
||||
/**
|
||||
* Defined in SyncML Representation Protocol, version 1.1 5.1.12
|
||||
*
|
||||
* @var string $_msgID
|
||||
*/
|
||||
var $_msgID;
|
||||
|
||||
/**
|
||||
* Defined in SyncML Representation Protocol, version 1.1 5.1.10
|
||||
*
|
||||
* @var string $_targetURI
|
||||
*/
|
||||
var $_targetURI;
|
||||
|
||||
/**
|
||||
* Defined in SyncML Representation Protocol, version 1.1 5.1.10,
|
||||
* 5.1.20
|
||||
*
|
||||
* @var string $_sourceURI
|
||||
*/
|
||||
var $_sourceURI;
|
||||
|
||||
var $_isCred;
|
||||
|
||||
var $_credData;
|
||||
|
||||
var $_credFormat;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// 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);
|
||||
} 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);
|
||||
}
|
||||
|
||||
@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 for '
|
||||
. $sourceURI, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$_SESSION['SyncML.state'] = new EGW_SyncML_State($sourceURI, $locName, $sessionID);
|
||||
}
|
||||
|
||||
|
||||
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'];
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 3:
|
||||
if ($element == 'Source') {
|
||||
// <SyncML><SyncHdr><Source>
|
||||
$this->_isSource = true;
|
||||
} elseif ($element == 'Cred') {
|
||||
$this->_isCred = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
// </SyncHdr></SyncML>
|
||||
Horde::logMessage('SyncML['. session_id() .']: package '
|
||||
. $this->_msgID.' +++++++++++++++++++++ started',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Find the state.
|
||||
//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);
|
||||
|
||||
$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()) {
|
||||
$state->setPassword($this->_credData);
|
||||
$state->setLocName($this->_locName);
|
||||
}
|
||||
|
||||
if (isset($this->_maxMsgSize)) {
|
||||
$state->setMaxMsgSize($this->_maxMsgSize);
|
||||
}
|
||||
|
||||
// $_SESSION['SyncML.state'] = $state;
|
||||
|
||||
#Horde::logMessage('SymcML: session id 2 =' . session_id(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Got the state; now write our SyncHdr header.
|
||||
$this->outputSyncHdr($this->_output);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if ($element == 'VerProto') {
|
||||
// </VerProto></SyncHdr></SyncML>
|
||||
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);
|
||||
} elseif ($element == 'MsgID') {
|
||||
// </MsgID></SyncHdr></SyncML>
|
||||
$this->_msgID = intval(trim($this->_chars));
|
||||
} elseif ($element == 'Source') {
|
||||
// </Source></SyncHdr></SyncML>
|
||||
$this->_isSource = false;
|
||||
} elseif ($element == 'Cred') {
|
||||
// </Cred></SyncHdr></SyncML>
|
||||
$this->_isCred = false;
|
||||
|
||||
// We only support b64 for now
|
||||
//if ($this->_credFormat == 'b64') {
|
||||
$this->_credData = base64_decode($this->_credData);
|
||||
//}
|
||||
|
||||
$tmp = explode(':', $this->_credData, 2);
|
||||
// set only if not set by LocName already
|
||||
if (!isset($this->_locName)) {
|
||||
$this->_locName = $tmp[0];
|
||||
}
|
||||
$this->_credData = $tmp[1];
|
||||
|
||||
#Horde::logMessage('SyncML['. session_id() .']: $this->_locName: ' . $this->_locName, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
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) {
|
||||
if ($element == 'Format') {
|
||||
// </Format></Meta></Cred></SyncHdr></SyncML>
|
||||
$this->_credFormat = trim($this->_chars);
|
||||
} elseif ($element == 'Type') {
|
||||
// </Type></Meta></Cred></SyncHdr></SyncML>
|
||||
$this->_credType = trim($this->_chars);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
function outputSyncHdr(&$output)
|
||||
{
|
||||
$attrs = array();
|
||||
|
||||
$state =& $_SESSION['SyncML.state'];
|
||||
|
||||
$uri = $state->getURI();
|
||||
$uriMeta = $state->getURIMeta();
|
||||
$output->startElement($uri, 'SyncHdr', $attrs);
|
||||
|
||||
$output->startElement($uri, 'VerDTD', $attrs);
|
||||
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);
|
||||
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');
|
||||
|
||||
$output->startElement($uri, 'SessionID', $attrs);
|
||||
$output->characters($this->_sessionID);
|
||||
$output->endElement($uri, 'SessionID');
|
||||
|
||||
$output->startElement($uri, 'MsgID', $attrs);
|
||||
$output->characters($this->_msgID);
|
||||
$output->endElement($uri, 'MsgID');
|
||||
|
||||
$output->startElement($uri, 'Target', $attrs);
|
||||
$output->startElement($uri, 'LocURI', $attrs);
|
||||
$output->characters($this->_sourceURI);
|
||||
$output->endElement($uri, 'LocURI');
|
||||
$output->endElement($uri, 'Target');
|
||||
|
||||
$output->startElement($uri, 'Source', $attrs);
|
||||
$output->startElement($uri, 'LocURI', $attrs);
|
||||
$output->characters($this->_targetURI);
|
||||
$output->endElement($uri, 'LocURI');
|
||||
$output->endElement($uri, 'Source');
|
||||
|
||||
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());
|
||||
}
|
||||
$output->endElement($uri, 'RespURI');
|
||||
}
|
||||
|
||||
|
||||
$output->startElement($uri, 'Meta', $attrs);
|
||||
|
||||
if (!($maxMsgSize = $state->getMaxMsgSizeClient()) || $maxMsgSize > 10000) {
|
||||
// Use a realistic message size to cope with
|
||||
$maxMsgSize = 10000;
|
||||
}
|
||||
$output->startElement($uriMeta, 'MaxMsgSize', $attrs);
|
||||
$output->characters($maxMsgSize);
|
||||
$output->endElement($uriMeta, 'MaxMsgSize');
|
||||
|
||||
#// 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');
|
||||
}
|
||||
|
||||
function getSourceURI()
|
||||
{
|
||||
return $this->_sourceURI;
|
||||
}
|
||||
|
||||
function getLocName()
|
||||
{
|
||||
return $this->_locName;
|
||||
}
|
||||
|
||||
function getSessionID()
|
||||
{
|
||||
return $this->_sessionID;
|
||||
}
|
||||
|
||||
function getVersion()
|
||||
{
|
||||
return $this->_version;
|
||||
}
|
||||
|
||||
function getMsgID()
|
||||
{
|
||||
return $this->_msgID;
|
||||
}
|
||||
|
||||
function getTargetURI()
|
||||
{
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
function opaque($o)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined in SyncML Representation Protocol, version 1.1 5.2.3
|
||||
*
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
|
||||
var $_currentCmdID = 1;
|
||||
|
||||
var $_currentCommand;
|
||||
|
||||
var $_actionCommands = false;
|
||||
|
||||
var $_clientSentFinal = false;
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
$state =& $_SESSION['SyncML.state'];
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
$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()) {
|
||||
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');
|
||||
}
|
||||
|
||||
$status->setSourceRef($state->getSourceURI());
|
||||
$status->setTargetRef($state->getTargetURI());
|
||||
$status->setCmdRef(0);
|
||||
$state->clearNumberOfElements();
|
||||
|
||||
/*$str = 'authorized=' . $state->isAuthorized();
|
||||
$str .= ' version=' . $state->getVersion();
|
||||
$str .= ' msgid=' . $state->getMsgID();
|
||||
$str .= ' source=' . $state->getSourceURI();
|
||||
$str .= ' target=' . $state->getTargetURI();
|
||||
*/
|
||||
$this->_currentCmdID = $status->output($this->_currentCmdID, $this->_output);
|
||||
if ($state->isAuthorized()) {
|
||||
$state->AuthConfirmed();
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// <SyncML><SyncBody><[Command]>
|
||||
#Horde::logMessage('SyncML['. session_id() ."]: found command $element ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$this->_currentCommand = Horde_SyncML_Command::factory($element);
|
||||
$this->_currentCommand->startElement($uri, $element, $attrs);
|
||||
|
||||
if ($element != 'Status' && $element != 'Map' && $element != 'Final') {
|
||||
// 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> ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
switch ($element)
|
||||
{
|
||||
case 'Sync':
|
||||
$state->setSyncStatus(CLIENT_SYNC_STARTED);
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus(client sync started) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// <SyncML><SyncBody><Command><...>
|
||||
$this->_currentCommand->startElement($uri, $element, $attrs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
$state =& $_SESSION['SyncML.state'];
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
// </SyncBody></SyncML>
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: package ----------------------- done', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if ($state->getAlert222Received() == true) {
|
||||
// the Funambol specialty
|
||||
if ($state->getSyncStatus() == CLIENT_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED);
|
||||
}
|
||||
$state->setAlert222Received(false);
|
||||
}
|
||||
|
||||
if ($state->needDeviceInfo()) $this->outputGetRequest();
|
||||
|
||||
// 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_FINNISHED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED) {
|
||||
$sync = new Horde_SyncML_Command_Sync();
|
||||
$this->_currentCmdID = $sync->syncToClient($this->_currentCmdID, $this->_output);
|
||||
}
|
||||
|
||||
// send the Final tag if possible
|
||||
#if ($state->getSyncStatus() != SERVER_SYNC_DATA_PENDING && $state->getSyncStatus() != CLIENT_SYNC_STARTED) {
|
||||
if ($state->getSyncStatus() >= SERVER_SYNC_FINNISHED || $state->_sendFinal) {
|
||||
$final = new Horde_SyncML_Command_Final();
|
||||
$this->_currentCmdID = $final->output($this->_currentCmdID, $this->_output);
|
||||
}
|
||||
|
||||
$this->_output->endElement($uri, $element);
|
||||
|
||||
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
|
||||
Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!',
|
||||
__FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$state->writeSyncSummary();
|
||||
$log = $state->getLog();
|
||||
$s="";
|
||||
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!
|
||||
# session_unset();
|
||||
# session_destroy();
|
||||
}
|
||||
|
||||
if (!$this->_actionCommands && $state->getSyncStatus() == SERVER_SYNC_ACKNOWLEDGED) {
|
||||
// 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
|
||||
Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!',
|
||||
__FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$state->writeSyncSummary();
|
||||
$log = $state->getLog();
|
||||
$s="";
|
||||
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!
|
||||
session_unset();
|
||||
session_destroy();
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// </[Command]></SyncBody></SyncML>
|
||||
|
||||
$this->_currentCommand->endElement($uri, $element);
|
||||
|
||||
switch ($element) {
|
||||
case 'Final':
|
||||
$this->_actionCommands = false;
|
||||
|
||||
if ($state->getSyncStatus() == CLIENT_SYNC_STARTED) {
|
||||
if ($state->isAuthorized() &&
|
||||
($deviceInfo = $state->getClientDeviceInfo()) &&
|
||||
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 (3.0 < $swversion && $swversion < 7.0) {
|
||||
// We wait for a ALERT_NEXT_MESSAGE from Funambol old 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);
|
||||
}
|
||||
|
||||
} elseif ($state->getSyncStatus() == SERVER_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(SERVER_SYNC_ACKNOWLEDGED);
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
unset($this->_currentCommand);
|
||||
break;
|
||||
|
||||
default:
|
||||
// </...></[Command]></SyncBody></SyncML>
|
||||
$this->_currentCommand->endElement($uri, $element);
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
function characters($str) {
|
||||
if (isset($this->_currentCommand)) {
|
||||
$this->_currentCommand->characters($str);
|
||||
}
|
||||
}
|
||||
|
||||
function outputGetRequest()
|
||||
{
|
||||
$attrs = array();
|
||||
|
||||
$state =& $_SESSION['SyncML.state'];
|
||||
|
||||
$uri = $state->getURI();
|
||||
$uriMeta = $state->getURIMeta();
|
||||
|
||||
Horde::logMessage('SyncML: PreferedContentTypeClient missing, sending <Get>',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$this->_output->startElement($uri, 'Get', $attrs);
|
||||
|
||||
$this->_output->startElement($uri, 'CmdID', $attrs);
|
||||
$this->_output->characters($this->_currentCmdID);
|
||||
$this->_currentCmdID++;
|
||||
$this->_output->endElement($uri, 'CmdID');
|
||||
|
||||
$this->_output->startElement($uri, 'Meta', $attrs);
|
||||
$this->_output->startElement($uriMeta, '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($uriMeta, 'Type');
|
||||
$this->_output->endElement($uri, 'Meta');
|
||||
|
||||
$this->_output->startElement($uri, 'Item', $attrs);
|
||||
$this->_output->startElement($uri, 'Target', $attrs);
|
||||
$this->_output->startElement($uri, 'LocURI', $attrs);
|
||||
if ($state->getVersion() == 2) {
|
||||
$this->_output->characters('./devinf12');
|
||||
} elseif ($state->getVersion() == 1) {
|
||||
$this->_output->characters('./devinf11');
|
||||
} else {
|
||||
$this->_output->characters('./devinf10');
|
||||
}
|
||||
$this->_output->endElement($uri, 'LocURI');
|
||||
$this->_output->endElement($uri, 'Target');
|
||||
$this->_output->endElement($uri, 'Item');
|
||||
|
||||
$this->_output->endElement($uri, 'Get');
|
||||
|
||||
$state->deviceInfoRequested();
|
||||
}
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* The SyncML_Command class provides a base class for handling all <SyncBody>
|
||||
* commands.
|
||||
*
|
||||
* A SyncML command is a protocol primitive. Each SyncML command specifies to
|
||||
* a recipient an individual operation that is to be performed.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Stack for holding the XML elements during creation of the object from
|
||||
* the XML event flow.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_stack = array();
|
||||
|
||||
/**
|
||||
* Buffer for the parsed character data.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_chars = '';
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$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)
|
||||
{
|
||||
if (count($this->_stack) == 2 &&
|
||||
$element == 'CmdID') {
|
||||
$this->_cmdID = intval(trim($this->_chars));
|
||||
}
|
||||
|
||||
if (strlen($this->_chars)) {
|
||||
$this->_chars = '';
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (isset($this->_chars)) {
|
||||
$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);
|
||||
if (empty($cmd->_cmdName)) $cmd->_cmdName = $command;
|
||||
} 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,466 +0,0 @@
|
||||
<?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.
|
||||
*
|
||||
*
|
||||
* 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_egw.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Alert';
|
||||
|
||||
/**
|
||||
* The alert type. Should be one of the ALERT_* constants.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_alert;
|
||||
|
||||
/**
|
||||
* Source database of the Alert command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceLocURI;
|
||||
|
||||
/**
|
||||
* Target database of the Alert command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The last time when synchronization happened, from the <Meta><Last>
|
||||
* element.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_metaAnchorLast;
|
||||
|
||||
/**
|
||||
* The filter expression the client provided
|
||||
* (e.g. the time range for calendar synchronization)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_filterExpression = '';
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of Alert.
|
||||
*/
|
||||
function Horde_SyncML_Command_Alert($alert = null)
|
||||
{
|
||||
if ($alert != null) {
|
||||
$this->_alert = $alert;
|
||||
}
|
||||
}
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
global $registry;
|
||||
|
||||
$attrs = array();
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
// Handle unauthorized first.
|
||||
if (!$state->isAuthorized()) {
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_INVALID_CREDENTIALS, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
|
||||
$clientAnchorNext = $this->_metaAnchorNext;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
// Check if anchor sent from client matches our own stored
|
||||
// data.
|
||||
if ($clientlast == $this->_metaAnchorLast) {
|
||||
// Last sync anchors match, 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
case ALERT_SLOW_SYNC:
|
||||
$synctype = ALERT_SLOW_SYNC;
|
||||
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
case ALERT_REFRESH_FROM_CLIENT:
|
||||
$synctype = ALERT_REFRESH_FROM_CLIENT;
|
||||
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
|
||||
|
||||
// We will erase the current server content,
|
||||
// then we can add the client's contents.
|
||||
|
||||
$hordeType = $state->getHordeType($this->_targetLocURI);
|
||||
|
||||
$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;
|
||||
|
||||
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;
|
||||
|
||||
case ALERT_REFRESH_FROM_SERVER:
|
||||
$synctype = ALERT_REFRESH_FROM_SERVER;
|
||||
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
|
||||
$anchormatch = false;
|
||||
break;
|
||||
|
||||
case ALERT_RESUME:
|
||||
// @TODO: Suspend and Resume is not supported yet
|
||||
$synctype = ALERT_SLOW_SYNC;
|
||||
$response = RESPONSE_REFRESH_REQUIRED;
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['slowsync_ignore_map']) &&
|
||||
$GLOBALS['egw_info']['user']['preferences']['syncml']['slowsync_ignore_map']
|
||||
|| !$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);
|
||||
$hordeType = $state->getHordeType($this->_targetLocURI);
|
||||
$changes =& $registry->call($hordeType. '/listBy',
|
||||
array('action' => 'modify',
|
||||
'timestamp' => $serverAnchorLast,
|
||||
'type' => $this->_targetLocURI,
|
||||
'filter' => $this->_filterExpression));
|
||||
$state->setChangedItems($this->_targetLocURI, $changes);
|
||||
|
||||
// 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);
|
||||
|
||||
$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));
|
||||
}
|
||||
|
||||
// Mirror Next Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorNext)) {
|
||||
$status->setItemDataAnchorNext($this->_metaAnchorNext);
|
||||
}
|
||||
|
||||
// Mirror Last Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorLast)) {
|
||||
$status->setItemDataAnchorLast($this->_metaAnchorLast);
|
||||
}
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
|
||||
$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);
|
||||
$chars = $synctype;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
|
||||
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 ? $chars : '0'); // Some devices don't like empty anchors
|
||||
$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++;
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (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;
|
||||
}
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* The Horde_SyncML_Command_Final class.
|
||||
*
|
||||
*
|
||||
* 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';
|
||||
|
||||
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'];
|
||||
|
||||
$attrs = array();
|
||||
$output->startElement($state->getURI(), 'Final', $attrs);
|
||||
|
||||
$output->endElement($state->getURI(), 'Final');
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
}
|
@ -1,247 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Get';
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
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), $this->_cmdName);
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
$status->setTargetRef($ref);
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
|
||||
if ($state->isAuthorized()) {
|
||||
$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->_cmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdRef');
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
if (is_a($output, 'XML_WBXML_Encoder')) {
|
||||
$output->characters(MIME_SYNCML_DEVICE_INFO_WBXML);
|
||||
} else {
|
||||
$output->characters(MIME_SYNCML_DEVICE_INFO_XML);
|
||||
}
|
||||
|
||||
$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);
|
||||
$output->characters($ref);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'DevInf', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'VerDTD', $attrs);
|
||||
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');
|
||||
$output->endElement($state->getURIDevInf() , 'Man', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'Mod', $attrs);
|
||||
$output->characters('DS Server');
|
||||
$output->endElement($state->getURIDevInf() , 'Mod', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'OEM', $attrs);
|
||||
$output->characters('-');
|
||||
$output->endElement($state->getURIDevInf() , 'OEM', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'FwV', $attrs);
|
||||
$output->characters('-');
|
||||
$output->endElement($state->getURIDevInf() , 'FwV', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SwV', $attrs);
|
||||
$output->characters('1.7.x');
|
||||
$output->endElement($state->getURIDevInf() , 'SwV', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'HwV', $attrs);
|
||||
$output->characters('-');
|
||||
$output->endElement($state->getURIDevInf() , 'HwV', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'DevID', $attrs);
|
||||
$output->characters($_SERVER['HTTP_HOST']);
|
||||
$output->endElement($state->getURIDevInf() , 'DevID', $attrs);
|
||||
$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/vcard', '3.0', $output,
|
||||
array('text/x-vcard' => '2.1'));
|
||||
$this->_writeDataStore('card', '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('jobs', '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('events', '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'));
|
||||
// Funambol special Datastore
|
||||
$this->_writeDataStore('configuration', 'text/plain', '1.0', $output);
|
||||
$output->endElement($state->getURIDevInf() , 'DevInf', $attrs);
|
||||
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
$output->endElement($state->getURI(), 'Results');
|
||||
/*
|
||||
$output->startElement($state->getURIDevInf() , 'Ext', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'XNam', $attrs);
|
||||
$output->characters('X-funambol-smartslow');
|
||||
$output->endElement($state->getURIDevInf() , 'XNam', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'Ext', $attrs);
|
||||
*/
|
||||
$currentCmdID++;
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes DevInf data for one DataStore.
|
||||
*
|
||||
* @param string $sourceref: data for SourceRef element.
|
||||
* @param string $mimetype: data for <(R|T)x-Pref><CTType>
|
||||
* @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' => '3.0')
|
||||
*/
|
||||
function _writeDataStore($sourceref, $mimetype, $version, &$output,
|
||||
$additionaltypes = false)
|
||||
{
|
||||
$attrs = array();
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'DataStore', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SourceRef', $attrs);
|
||||
$output->characters($sourceref);
|
||||
$output->endElement($state->getURIDevInf() , 'SourceRef', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'DisplayName', $attrs);
|
||||
$output->characters($sourceref);
|
||||
$output->endElement($state->getURIDevInf() , 'DisplayName', $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);
|
||||
$output->characters($mimetype);
|
||||
$output->endElement($state->getURIDevInf() , 'CTType', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'VerCT', $attrs);
|
||||
$output->characters($version);
|
||||
$output->endElement($state->getURIDevInf() , 'VerCT', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'Rx-Pref', $attrs);
|
||||
|
||||
if (is_array($additionaltypes)) {
|
||||
foreach ($additionaltypes as $ct => $ctver){
|
||||
$output->startElement($state->getURIDevInf() , 'Rx', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'CTType', $attrs);
|
||||
$output->characters($ct);
|
||||
$output->endElement($state->getURIDevInf() , 'CTType', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'VerCT', $attrs);
|
||||
$output->characters($ctver);
|
||||
$output->endElement($state->getURIDevInf() , 'VerCT', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'Rx', $attrs);
|
||||
}
|
||||
}
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'Tx-Pref', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'CTType', $attrs);
|
||||
$output->characters($mimetype);
|
||||
$output->endElement($state->getURIDevInf() , 'CTType', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'VerCT', $attrs);
|
||||
$output->characters($version);
|
||||
$output->endElement($state->getURIDevInf() , 'VerCT', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'Tx-Pref', $attrs);
|
||||
|
||||
if (is_array($additionaltypes)) {
|
||||
foreach ($additionaltypes as $ct => $ctver){
|
||||
$output->startElement($state->getURIDevInf() , 'Tx', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'CTType', $attrs);
|
||||
$output->characters($ct);
|
||||
$output->endElement($state->getURIDevInf() , 'CTType', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'VerCT', $attrs);
|
||||
$output->characters($ctver);
|
||||
$output->endElement($state->getURIDevInf() , 'VerCT', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'Tx', $attrs);
|
||||
}
|
||||
}
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'SyncCap', $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,141 +0,0 @@
|
||||
<?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.
|
||||
*
|
||||
*
|
||||
* 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>
|
||||
* @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 {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Map';
|
||||
|
||||
/**
|
||||
* Source database of the Map command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceLocURI;
|
||||
|
||||
/**
|
||||
* Target database of the Map command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
|
||||
/**
|
||||
* Recipient map item specifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_mapTarget;
|
||||
|
||||
/**
|
||||
* Originator map item specifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_mapSource;
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$attrs = array();
|
||||
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
$status = new Horde_SyncML_Command_Status($state->isAuthorized() ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS, 'Map');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef($this->_targetLocURI);
|
||||
}
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
if (count($this->_stack) == 2 &&
|
||||
$element == 'MapItem') {
|
||||
unset($this->_mapTarget);
|
||||
unset($this->_mapSource);
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'MapItem') {
|
||||
$sync = $state->getSync($this->_targetLocURI);
|
||||
if (!$state->isAuthorized()) {
|
||||
Horde::logMessage('SyncML: Not Authorized in the middle of MapItem!', __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
} else {
|
||||
Horde::logMessage("SyncML: creating Map for source=" .
|
||||
$this->_mapSource . " and target=" . $this->_mapTarget, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Overwrite existing data by removing it first:
|
||||
$ts = $state->getServerAnchorNext($this->_targetLocURI);
|
||||
$r = $state->setUID($this->_targetLocURI, $this->_mapSource, $this->_mapTarget, $ts);
|
||||
if (is_a($r, 'PEAR_Error')) {
|
||||
Horde::logMessage('SyncML: PEAR Error: ' . $r->getMessage(), __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_stack[1] == 'Source') {
|
||||
$this->_sourceLocURI = trim($this->_chars);
|
||||
} elseif ($this->_stack[1] == 'Target') {
|
||||
$targetLocURIData = explode('?/',trim($this->_chars));
|
||||
$this->_targetLocURI = $targetLocURIData[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_stack[2] == 'Source') {
|
||||
$this->_mapSource = trim($this->_chars);
|
||||
} elseif ($this->_stack[2] == 'Target') {
|
||||
$this->_mapTarget = trim($this->_chars);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
}
|
@ -1,364 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Put';
|
||||
|
||||
/**
|
||||
* @var string $_manufacturer
|
||||
*/
|
||||
|
||||
var $_manufacturer;
|
||||
|
||||
/**
|
||||
* @var string $_model
|
||||
*/
|
||||
|
||||
var $_model;
|
||||
|
||||
/**
|
||||
* @var string $_oem
|
||||
*/
|
||||
|
||||
var $_oem;
|
||||
|
||||
/**
|
||||
* @var array $_deviceInfo
|
||||
*/
|
||||
|
||||
var $_deviceInfo;
|
||||
|
||||
/**
|
||||
* @var string $_softwareVersion
|
||||
*/
|
||||
|
||||
var $_softwareVersion;
|
||||
|
||||
function endElement($uri, $element) {
|
||||
switch (count($this->_stack)) {
|
||||
case 5:
|
||||
switch ($element) {
|
||||
case 'DataStore':
|
||||
$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;
|
||||
}
|
||||
break;
|
||||
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 = strtolower(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);
|
||||
if (substr($this->_contentType, 0, 14) == "text/x-s4j-sif")
|
||||
{
|
||||
// workaround a little bug in sync4j for mobile v3.1.3 (and possibly others)
|
||||
// where the content-type is set to just one value regardless of
|
||||
// the source... this further leads to a failure to send updates
|
||||
// by the server since it does not know how to convert say tasks to text/x-s4j-sifc
|
||||
// (it should be text/x-s4j-sift).
|
||||
switch ($this->_sourceReference)
|
||||
{
|
||||
case 'contact':
|
||||
case 'card':
|
||||
if ($this->_contentType != "text/x-s4j-sifc")
|
||||
{
|
||||
error_log("forcing 'contact' content type to 'text/x-s4j-sifc' instead of '".$this->_contentType."'");
|
||||
$this->_contentType = "text/x-s4j-sifc";
|
||||
}
|
||||
break;
|
||||
case 'calendar':
|
||||
case 'appointment':
|
||||
if ($this->_contentType != "text/x-s4j-sife")
|
||||
{
|
||||
error_log("forcing 'calendar' content type to 'text/x-s4j-sife' instead of '".$this->_contentType."'");
|
||||
$this->_contentType = "text/x-s4j-sife";
|
||||
}
|
||||
break;
|
||||
case 'task':
|
||||
if ($this->_contentType != "text/x-s4j-sift")
|
||||
{
|
||||
error_log("forcing 'task' content type to 'text/x-s4j-sift' instead of '".$this->_contentType."'");
|
||||
$this->_contentType = "text/x-s4j-sift";
|
||||
}
|
||||
break;
|
||||
case 'note':
|
||||
if ($this->_contentType != "text/x-s4j-sifn")
|
||||
{
|
||||
error_log("forcing 'note' content type to 'text/x-s4j-sifn' instead of '".$this->_contentType."'");
|
||||
$this->_contentType = "text/x-s4j-sifn";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
#error_log("Leaving ContentType='".$this->_contentType."' as is for source '".$this->_sourceReference."'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 (($pos = strpos($ua, 'Funambol'))!== false) {
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
$this->_deviceInfo['model'] = 'generic';
|
||||
$this->_deviceInfo['softwareVersion'] = 3.1; // force special treatment
|
||||
$type = substr($ua, $pos + 9);
|
||||
if (preg_match("/^(.*) [^\d]*(\d+\.?\d*)[\.|\d]*\s*$/i", $type, $matches)) {
|
||||
// Funambol uses the hardware Manufacturer we don't care about
|
||||
$this->_deviceInfo['model'] = trim($matches[1]);
|
||||
$this->_deviceInfo['softwareVersion'] = floatval($matches[2]);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch (strtolower($this->_deviceInfo['deviceID'])) {
|
||||
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'] = '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), $this->_cmdName);
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
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) {
|
||||
$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,32 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Command_Replace extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Replace';
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* 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/Put.php';
|
||||
|
||||
class Horde_SyncML_Command_Results extends Horde_SyncML_Command_Put {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Results';
|
||||
|
||||
}
|
@ -1,363 +0,0 @@
|
||||
<?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';
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* The command (Add, Replace, etc) sent to the client, that this Status
|
||||
* response refers to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmd;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
var $_chalMetaType;
|
||||
|
||||
var $_chalMetaNextNonce;
|
||||
|
||||
var $_itemDataAnchorNext;
|
||||
|
||||
var $_itemDataAnchorLast;
|
||||
|
||||
var $_itemTargetLocURI;
|
||||
|
||||
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) {
|
||||
$this->_response = $response;
|
||||
}
|
||||
|
||||
if ($cmd != null) {
|
||||
$this->_cmd = $cmd;
|
||||
}
|
||||
}
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$attrs = array();
|
||||
|
||||
if ($this->_cmd != null) {
|
||||
$output->startElement($state->getURI(), 'Status', $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(), 'Cmd', $attrs);
|
||||
$chars = $this->_cmd;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Cmd');
|
||||
|
||||
if (isset($this->_targetRef)) {
|
||||
$output->startElement($state->getURI(), 'TargetRef', $attrs);
|
||||
$chars = $this->_targetRef;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'TargetRef');
|
||||
}
|
||||
|
||||
if (isset($this->_sourceRef)) {
|
||||
$output->startElement($state->getURI(), 'SourceRef', $attrs);
|
||||
$chars = $this->_sourceRef;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'SourceRef');
|
||||
}
|
||||
|
||||
// If we are responding to the SyncHdr and we are not
|
||||
// authorized then request basic authorization.
|
||||
//
|
||||
// FIXME: Right now we always send this, ignoring the
|
||||
// isAuthorized() test. Is that correct?
|
||||
if ($this->_cmd == 'SyncHdr' && !$state->isAuthorized()) {
|
||||
$this->_chalMetaFormat = 'b64';
|
||||
$this->_chalMetaType = 'syncml:auth-basic';
|
||||
}
|
||||
|
||||
if (isset($this->_chalMetaFormat) && isset($this->_chalMetaType)) {
|
||||
$output->startElement($state->getURI(), 'Chal', $attrs);
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
|
||||
$metainfuri = $state->getURIMeta();
|
||||
|
||||
$output->startElement($metainfuri, 'Format', $attrs);
|
||||
$chars = $this->_chalMetaFormat;
|
||||
$output->characters($chars);
|
||||
$output->endElement($metainfuri, 'Format');
|
||||
|
||||
$output->startElement($metainfuri, 'Type', $attrs);
|
||||
$chars = $this->_chalMetaType;
|
||||
$output->characters($chars);
|
||||
$output->endElement($metainfuri, 'Type');
|
||||
|
||||
// $output->startElement($metainfuri, 'NextNonce', $attrs);
|
||||
// $chars = $this->_chalMetaNextNonce;
|
||||
// $output->characters($chars);
|
||||
// $output->endElement($metainfuri, 'NextNonce');
|
||||
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
$output->endElement($state->getURI(), 'Chal');
|
||||
}
|
||||
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
$chars = $this->_response;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
|
||||
if (isset($this->_itemDataAnchorNext) || isset($this->_itemDataAnchorLast)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
|
||||
$metainfuri = $state->getURIMeta();
|
||||
// $metainfuri = $state->getURI(); // debug by FOU
|
||||
|
||||
$output->startElement($metainfuri, 'Anchor', $attrs);
|
||||
|
||||
if (isset($this->_itemDataAnchorNext)) {
|
||||
|
||||
$output->startElement($metainfuri, 'Next', $attrs);
|
||||
$chars = $this->_itemDataAnchorNext;
|
||||
$output->characters($chars);
|
||||
$output->endElement($metainfuri, 'Next');
|
||||
}
|
||||
|
||||
if (isset($this->_itemDataAnchorLast)) {
|
||||
|
||||
$output->startElement($metainfuri, 'Last', $attrs);
|
||||
$chars = $this->_itemDataAnchorLast;
|
||||
$output->characters($chars);
|
||||
$output->endElement($metainfuri, 'Last');
|
||||
}
|
||||
|
||||
$output->endElement($metainfuri, 'Anchor');
|
||||
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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++;
|
||||
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property response.
|
||||
*
|
||||
* @param string $response New value of property response.
|
||||
*/
|
||||
function setResponse($response)
|
||||
{
|
||||
$this->_response = $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property cmd.
|
||||
*
|
||||
* @param string $cmd New value of property cmd.
|
||||
*/
|
||||
function setCmd($cmd)
|
||||
{
|
||||
$this->_cmd = $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property cmdRef.
|
||||
*
|
||||
* @param string $cmdRef New value of property cmdRef.
|
||||
*/
|
||||
function setCmdRef($cmdRef)
|
||||
{
|
||||
$this->_cmdRef = $cmdRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property sourceRef.
|
||||
*
|
||||
* @param string $sourceRef New value of property sourceRef.
|
||||
*/
|
||||
function setSourceRef($sourceRef)
|
||||
{
|
||||
$this->_sourceRef = $sourceRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property targetRef.
|
||||
*
|
||||
* @param string $targetRef New value of property targetRef.
|
||||
*/
|
||||
function setTargetRef($targetRef)
|
||||
{
|
||||
$this->_targetRef = $targetRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property itemDataAnchorNext.
|
||||
*
|
||||
* @param string $itemDataAnchorNext New value of property itemDataAnchorNext.
|
||||
*/
|
||||
function setItemDataAnchorNext($itemDataAnchorNext)
|
||||
{
|
||||
$this->_itemDataAnchorNext = $itemDataAnchorNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property itemDataAnchorLast.
|
||||
*
|
||||
* @param string $itemDataAnchorLast New value of property itemDataAnchorLast.
|
||||
*/
|
||||
function setItemDataAnchorLast($itemDataAnchorLast)
|
||||
{
|
||||
$this->_itemDataAnchorLast = $itemDataAnchorLast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property itemSourceLocURI.
|
||||
*
|
||||
* @param string $itemSourceLocURI New value of property itemSourceLocURI.
|
||||
*/
|
||||
function setItemSourceLocURI($itemSourceLocURI)
|
||||
{
|
||||
$this->_itemSourceLocURI = $itemSourceLocURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property itemTargetLocURI.
|
||||
*
|
||||
* @param string $itemTargetLocURI New value of property itemTargetLocURI.
|
||||
*/
|
||||
function setItemTargetLocURI($itemTargetLocURI)
|
||||
{
|
||||
$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,267 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Command_Sync extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
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->_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);
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
if ($state->getSyncStatus() >= CLIENT_SYNC_FINNISHED
|
||||
&& $state->getSyncStatus() < SERVER_SYNC_FINNISHED)
|
||||
{
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
if (($targets = $state->getTargets())) {
|
||||
foreach ($targets as $target)
|
||||
{
|
||||
$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);
|
||||
|
||||
} elseif ($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)
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no syncs left
|
||||
if ($state->getTargets() === false &&
|
||||
!isset($state->curSyncItem)) {
|
||||
$state->setSyncStatus(SERVER_SYNC_FINNISHED);
|
||||
}
|
||||
Horde::logMessage('SyncML: syncStatus(syncToClient) = ' .
|
||||
$state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
if (isset($this->_curItem)) {
|
||||
$this->_curItem->endElement($uri, $element);
|
||||
}
|
||||
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'Replace' ||
|
||||
$element == 'Add' ||
|
||||
$element == 'Delete') {
|
||||
$this->_syncElements[] = &$this->_curItem;
|
||||
unset($this->_curItem);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if ($element == 'LocURI' && !isset($this->_curItem)) {
|
||||
if ($this->_stack[1] == 'Source') {
|
||||
$this->_sourceURI = trim($this->_chars);
|
||||
} elseif ($this->_stack[1] == 'Target') {
|
||||
$targetURIData = explode('?/',trim($this->_chars));
|
||||
|
||||
$this->_targetURI = $targetURIData[0];
|
||||
|
||||
if (isset($targetURIData[1])) {
|
||||
$this->_targetURIParameters = $targetURIData[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
|
||||
}
|
||||
|
||||
function characters($str)
|
||||
{
|
||||
if (isset($this->_curItem)) {
|
||||
$this->_curItem->characters($str);
|
||||
} else {
|
||||
if (isset($this->_chars)) {
|
||||
$this->_chars .= $str;
|
||||
} else {
|
||||
$this->_chars = $str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Command_Sync_Add extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
|
||||
var $_status = RESPONSE_ITEM_ADDED;
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$status = new Horde_SyncML_Command_Status($this->_status, 'Add');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if (!empty($this->_items)) {
|
||||
$status->setSyncItems($this->_items);
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
<?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/Sync/SyncElementItem.php';
|
||||
|
||||
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();
|
||||
$contentFormat = isset($this->_contentFormat) ? strtolower($this->_contentFormat) : '';
|
||||
$output->startElement($state->getURI(), $command, $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$output->characters($currentCmdID);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
if (isset($this->_content) && !$this->_moreData) {
|
||||
$this->_contentSize = strlen($this->_content);
|
||||
} else {
|
||||
$this->_contentSize = 0;
|
||||
}
|
||||
switch ($contentFormat) {
|
||||
case 'strictxml':
|
||||
break;
|
||||
case 'htmlenc':
|
||||
if (!$state->isWBXML() && $this->_contentSize) {
|
||||
$this->_content = htmlspecialchars($this->_content, ENT_COMPAT, 'UTF-8');
|
||||
}
|
||||
break;
|
||||
case 'b64':
|
||||
if ($this->_contentSize) {
|
||||
$this->_content = base64_encode($this->_content);
|
||||
}
|
||||
default:
|
||||
$contentFormat = '';
|
||||
}
|
||||
|
||||
// <command><Meta>
|
||||
if ($this->_contentSize || isset($this->_contentType) ||
|
||||
(!$contentFormat && 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 (!$contentFormat && 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);
|
||||
|
||||
// <command><Item><Source><LocURI>
|
||||
if (isset($this->_guid)) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = substr($this->_guid, 0, $maxGUIDSize);
|
||||
$state->setUIDMapping($this->_guid, $chars);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
|
||||
// <command><Item><Target><LocURI>
|
||||
if (isset($this->_luid)) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_luid);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
|
||||
|
||||
// <command><Item><Data>
|
||||
if (isset($this->_content)) {
|
||||
$this->_contentSize = strlen($this->_content);
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
$currentSize = $output->getOutputSize();
|
||||
Horde::logMessage("SyncML: $command: current = $currentSize, max = $maxMsgSize", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (!$maxMsgSize ||
|
||||
(($currentSize + MIN_MSG_LEFT + $this->_contentSize + 12) <= $maxMsgSize)) {
|
||||
$chars = $this->_content;
|
||||
unset($this->_content);
|
||||
$this->_moreData = false;
|
||||
} else {
|
||||
$sizeLeft = $maxMsgSize - $currentSize - MIN_MSG_LEFT - 12;
|
||||
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;
|
||||
}
|
||||
switch ($contentFormat) {
|
||||
case 'strictxml':
|
||||
if (!$state->isWBXML()) {
|
||||
$chars = '<![CDATA['. $chars. ']]>';
|
||||
}
|
||||
break;
|
||||
}
|
||||
$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');
|
||||
}
|
||||
|
||||
$output->endElement($state->getURI(), $command);
|
||||
|
||||
$currentCmdID++;
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Command_Sync_Delete extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$status = new Horde_SyncML_Command_Status($this->_status, 'Delete');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if (!empty($this->_items)) {
|
||||
$status->setSyncItems($this->_items);
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
<?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';
|
||||
|
||||
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 (!empty($this->_items)) {
|
||||
$status->setSyncItems($this->_items);
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Command_Sync_SyncElement extends Horde_SyncML_Command {
|
||||
|
||||
var $_luid;
|
||||
var $_guid;
|
||||
var $_contentSize = 0;
|
||||
var $_contentType;
|
||||
var $_contentFormat;
|
||||
var $_status = RESPONSE_OK;
|
||||
var $_curItem;
|
||||
var $_items = array();
|
||||
var $_failed = 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);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Class definition of ' . $class . ' not found in SyncElement::factory.', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::raiseError('Class definition of ' . $class . ' not found.');
|
||||
}
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs) {
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
$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 (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') {
|
||||
if ($this->_luid) {
|
||||
$this->_curItem->setLocURI($this->_luid);
|
||||
$this->_curItem->setContentType($this->_contentType);
|
||||
$this->_curItem->setContentFormat($this->_contentFormat);
|
||||
$this->_curItem->setCommand($this->_command);
|
||||
|
||||
if ($this->_contentSize)
|
||||
$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 {
|
||||
$content = $this->_curItem->getContent();
|
||||
$contentSize = strlen($content);
|
||||
if ((($size = $this->_curItem->getContentSize()) !== false) &&
|
||||
abs($contentSize - $size) > 3) {
|
||||
Horde::logMessage('SyncML: content size mismatch for LocURI ' . $this->_luid .
|
||||
": $contentSize ($size) : " . $content,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$this->_failed[$this->_luid] = $this->_curItem;
|
||||
} else {
|
||||
if (strtolower($this->_curItem->getContentFormat()) == 'b64') {
|
||||
$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);
|
||||
}
|
||||
#Horde::logMessage('SyncML: Data for ' . $this->_luid . ': ' . $this->_curItem->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$this->_items[$this->_luid] = $this->_curItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($this->_contentSize);
|
||||
unset($this->_luid);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch ($element) {
|
||||
case 'Data':
|
||||
$content = $this->_chars;
|
||||
if ($this->_contentFormat == 'b64') $content = trim($content);
|
||||
#Horde::logMessage('SyncML: Data for ' . $this->_luid . ': ' . $content, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$this->_curItem->_content .= $content;
|
||||
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 = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
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 getSyncElementFailures() {
|
||||
return (array)$this->_failed;
|
||||
}
|
||||
|
||||
function getLocURI()
|
||||
{
|
||||
return $this->_luid;
|
||||
}
|
||||
|
||||
function getGUID()
|
||||
{
|
||||
return $this->_guid;
|
||||
}
|
||||
|
||||
function setLocURI($luid)
|
||||
{
|
||||
$this->_luid = $luid;
|
||||
}
|
||||
|
||||
function setGUID($guid)
|
||||
{
|
||||
$this->_guid = $guid;
|
||||
}
|
||||
|
||||
function setContentType($c)
|
||||
{
|
||||
$this->_contentType = $c;
|
||||
}
|
||||
|
||||
function getContentType()
|
||||
{
|
||||
return $this->_contentType;
|
||||
}
|
||||
|
||||
function getContent()
|
||||
{
|
||||
if ($this->_curItem) {
|
||||
return $this->_curItem->getcontent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function hasMoreData()
|
||||
{
|
||||
return $this->_moreData;
|
||||
}
|
||||
|
||||
function setStatus($_status)
|
||||
{
|
||||
$this->_status = $_status;
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Command_Sync_SyncElementItem {
|
||||
|
||||
var $_luid;
|
||||
var $_guid;
|
||||
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 setContentSize($_size) {
|
||||
$this->_contentSize = $_size;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,738 +0,0 @@
|
||||
<?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 Lars Kneschke <lkneschke@egroupware.org>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
include_once dirname(__FILE__).'/State.php';
|
||||
|
||||
/**
|
||||
* The EGW_SyncML_State class provides a SyncML state object.
|
||||
*/
|
||||
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();
|
||||
|
||||
/*
|
||||
* the domain of the current user
|
||||
*/
|
||||
var $_account_domain = 'default';
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$syncIDParts = explode('-',$_syncid);
|
||||
$_appName = array_shift($syncIDParts);
|
||||
$_id = implode ('', $syncIDParts);
|
||||
|
||||
$ts = $GLOBALS['egw']->contenthistory->getTSforAction($_appName, $_id, $_action);
|
||||
|
||||
if (strstr($_id, ':')) {
|
||||
// pseudo entries are related to parent entry
|
||||
$parentId = array_shift(explode(':', $_id));
|
||||
$pts = $GLOBALS['egw']->contenthistory->getTSforAction($_appName, $parentId, $_action);
|
||||
if ($pts > $ts) $ts = $pts; // We have changed the parent
|
||||
}
|
||||
return $ts;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the timestamp for action
|
||||
*
|
||||
* find which content changed since $_ts for application $_appName
|
||||
*
|
||||
* @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 array $readableItems (optional) readable items of current user
|
||||
* @return array containing syncIDs with changes
|
||||
*/
|
||||
function getHistory($_appName, $_action, $_ts, $readableItems = false) {
|
||||
$guidList = array();
|
||||
$syncIdList = array();
|
||||
$userItems = false;
|
||||
if (is_array($readableItems))
|
||||
{
|
||||
$userItems = array();
|
||||
foreach($readableItems as $guid)
|
||||
{
|
||||
if (preg_match('/.*-(\d+)(:(\d+))?/', $guid, $matches))
|
||||
{
|
||||
// We use only the real items' ids
|
||||
$userItems[] = $matches[1];
|
||||
}
|
||||
}
|
||||
$userItems = array_unique($userItems);
|
||||
}
|
||||
$idList = $GLOBALS['egw']->contenthistory->getHistory($_appName, $_action, $_ts, $userItems);
|
||||
foreach ($idList as $idItem)
|
||||
{
|
||||
if ($idItem) // ignore inconsistent entries
|
||||
{
|
||||
$syncIdList[] = $_appName . '-' . $idItem;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
$syncml_prefs = $GLOBALS['egw_info']['user']['preferences']['syncml'];
|
||||
$deviceMaxEntries = 'maxEntries-' . $this->_clientDeviceInfo['devId'];
|
||||
$deviceUIDExtension = 'uidExtension-' . $this->_clientDeviceInfo['devId'];
|
||||
$deviceNonBlockingAllday = 'nonBlockingAllday-' . $this->_clientDeviceInfo['devId'];
|
||||
$deviceTimezone = 'tzid-' . $this->_clientDeviceInfo['devId'];
|
||||
$deviceCharSet = 'charset-' . $this->_clientDeviceInfo['devId'];
|
||||
if (isset($this->_clientDeviceInfo)
|
||||
&& is_array($this->_clientDeviceInfo)) {
|
||||
// update user preferences
|
||||
$this->_clientDeviceInfo['maxEntries'] = $syncml_prefs[$deviceMaxEntries];
|
||||
$this->_clientDeviceInfo['uidExtension'] = $syncml_prefs[$deviceUIDExtension];
|
||||
$this->_clientDeviceInfo['nonBlockingAllday'] = $syncml_prefs[$deviceNonBlockingAllday];
|
||||
$this->_clientDeviceInfo['tzid'] = $syncml_prefs[$deviceTimezone];
|
||||
$this->_clientDeviceInfo['charset'] = $syncml_prefs[$deviceCharSet];
|
||||
// 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())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cols = array(
|
||||
'dev_dtdversion',
|
||||
'dev_numberofchanges',
|
||||
'dev_largeobjs',
|
||||
'dev_swversion',
|
||||
'dev_fwversion',
|
||||
'dev_hwversion',
|
||||
'dev_oem',
|
||||
'dev_model',
|
||||
'dev_manufacturer',
|
||||
'dev_devicetype',
|
||||
'dev_datastore',
|
||||
'dev_utc',
|
||||
);
|
||||
|
||||
#Horde::logMessage("SyncML: getClientDeviceInfo $deviceID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$where = array(
|
||||
'dev_id' => $deviceID,
|
||||
);
|
||||
|
||||
|
||||
|
||||
if (($row = $GLOBALS['egw']->db->select('egw_syncmldevinfo',
|
||||
$cols, $where, __LINE__, __FILE__, false, '', 'syncml')->fetch())) {
|
||||
$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],
|
||||
'tzid' => $syncml_prefs[$deviceTimezone],
|
||||
'charset' => $syncml_prefs[$deviceCharSet],
|
||||
'devId' => $deviceID,
|
||||
'persistent' => $deviceID,
|
||||
'dataStore' => unserialize($row['dev_datastore']),
|
||||
);
|
||||
return $this->_clientDeviceInfo;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns GUIDs of all client items
|
||||
*/
|
||||
function getClientItems($type=false) {
|
||||
if (!$type) $type = $this->_targetURI;
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: 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: 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(!isset($this->_locName))
|
||||
{
|
||||
Horde::logMessage('SyncML: Authentication not yet possible. Username not available',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
// store sessionID in a variable, because create() and verify() reset this value
|
||||
$sessionID = session_id();
|
||||
|
||||
if (strpos($this->_locName,'@') === False)
|
||||
{
|
||||
$this->_account_domain = $GLOBALS['egw_info']['server']['default_domain'];
|
||||
$this->_locName .= '@'. ($this->_account_domain ? $this->_account_domain : 'default');
|
||||
}
|
||||
else
|
||||
{
|
||||
$parts = explode('@',$this->_locName);
|
||||
$this->_account_domain = array_pop($parts);
|
||||
}
|
||||
|
||||
if (!is_object($GLOBALS['egw']))
|
||||
{
|
||||
// Let the EGw core create the infrastructure classes
|
||||
$_POST['login'] = $this->_locName;
|
||||
$_REQUEST['domain'] = $this->_account_domain;
|
||||
$GLOBALS['egw_info']['server']['default_domain'] = $this->_account_domain;
|
||||
$GLOBALS['egw_info']['user']['domain'] = $this->_account_domain;
|
||||
$GLOBALS['egw_info']['flags']['currentapp'] = 'login';
|
||||
$GLOBALS['egw_info']['flags']['noapi'] = false;
|
||||
require_once(EGW_API_INC . '/functions.inc.php');
|
||||
}
|
||||
|
||||
$GLOBALS['egw_info']['flags']['currentapp'] = 'syncml';
|
||||
|
||||
if (!$this->_isAuthorized)
|
||||
{
|
||||
|
||||
if (!isset($this->_password))
|
||||
{
|
||||
Horde::logMessage('SyncML: Authentication not yet possible. Credetials missing',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($GLOBALS['egw']->session->create($this->_locName,$this->_password,'text'))
|
||||
{
|
||||
if ($GLOBALS['egw_info']['user']['apps']['syncml'])
|
||||
{
|
||||
$this->_isAuthorized = 1;
|
||||
// restore the original sessionID
|
||||
session_regenerate_id();
|
||||
session_id($sessionID);
|
||||
$GLOBALS['sessionid'] = $sessionID;
|
||||
@session_start();
|
||||
Horde::logMessage('SyncML_EGW[' . $GLOBALS['sessionid']
|
||||
.']: Authentication of ' . $this->_locName . ' succeded',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$syncml_prefs = $GLOBALS['egw_info']['user']['preferences']['syncml'];
|
||||
if (($deviceID = $GLOBALS['egw']->db->select('egw_syncmldeviceowner',
|
||||
'owner_devid',
|
||||
array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
$allowed_name = 'allowed-' . $deviceID;
|
||||
if (isset($syncml_prefs[$allowed_name]))
|
||||
{
|
||||
$deviceAllowed = $syncml_prefs[$allowed_name];
|
||||
}
|
||||
else
|
||||
{
|
||||
$deviceAllowed = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$deviceAllowed = -1; // Unkown device
|
||||
}
|
||||
if (!$GLOBALS['egw_info']['user']['apps']['admin'] &&
|
||||
isset($syncml_prefs['deny_unknown_devices']) &&
|
||||
$syncml_prefs['deny_unknown_devices'] != 0)
|
||||
{
|
||||
if ($syncml_prefs['deny_unknown_devices'] == -1 &&
|
||||
$deviceAllowed != 1 ||
|
||||
$syncml_prefs['deny_unknown_devices'] == 1 &&
|
||||
$deviceAllowed == 0)
|
||||
{
|
||||
$this->_isAuthorized = -1;
|
||||
Horde::logMessage('SyncML: Device is not allowed for user ' . $this->_locName,
|
||||
__FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_isAuthorized = -1; // Authorization failed!
|
||||
Horde::logMessage('SyncML is not enabled for user '
|
||||
. $this->_locName, __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_isAuthorized = -1;
|
||||
Horde::logMessage('SyncML: Authentication of ' . $this->_locName
|
||||
. ' failed', __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
elseif ($this->_isAuthorized > 0)
|
||||
{
|
||||
if (!$GLOBALS['egw']->session->verify($sessionID, 'staticsyncmlkp3'))
|
||||
{
|
||||
Horde::logMessage('SyncML_EGW: egw session(' . $sessionID
|
||||
. ') could not be not verified' ,
|
||||
__FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
}
|
||||
if (empty($GLOBALS['egw_info']['user']['passwd']))
|
||||
{
|
||||
$GLOBALS['egw_info']['user']['passwd'] = $this->_password;
|
||||
}
|
||||
}
|
||||
return ($this->_isAuthorized > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
$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) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
$where[] = "map_id = '".$mapID."' AND map_timestamp < '".$GLOBALS['egw']->db->to_timestamp($ts)."'";
|
||||
|
||||
Horde::logMessage("SyncML: state->removeOldUID(type=$type)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where, __LINE__, __FILE__, 'syncml');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
return false;
|
||||
}
|
||||
|
||||
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.
|
||||
* 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 (!strlen("$_guid")) {
|
||||
// We can't handle this case otherwise
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
if(!$ts) $ts = time();
|
||||
|
||||
Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
// expire all client id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
|
||||
// expire old EGw id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
/*
|
||||
$data = array ('map_expired' => true);
|
||||
$GLOBALS['egw']->db->update('egw_contentmap', $data, $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)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->_clientDeviceInfo['persistent'])) {
|
||||
// the device information was updated
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
$softwareVersion = !empty($this->_clientDeviceInfo['softwareVersion']) ? $this->_clientDeviceInfo['softwareVersion'] : '';
|
||||
$hardwareVersion = !empty($this->_clientDeviceInfo['hardwareVersion']) ? substr($this->_clientDeviceInfo['hardwareVersion'], 0, $this->size_dev_hwversion) : '';
|
||||
$firmwareVersion = !empty($this->_clientDeviceInfo['firmwareVersion']) ? $this->_clientDeviceInfo['firmwareVersion'] : '';
|
||||
|
||||
$where = array(
|
||||
'dev_model' => $this->_clientDeviceInfo['model'],
|
||||
'dev_manufacturer' => $this->_clientDeviceInfo['manufacturer'],
|
||||
'dev_swversion' => $softwareVersion,
|
||||
'dev_hwversion' => $hardwareVersion,
|
||||
'dev_fwversion' => $firmwareVersion,
|
||||
);
|
||||
|
||||
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 {
|
||||
$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']),
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_syncmldevinfo', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
|
||||
$deviceID = $GLOBALS['egw']->db->get_last_insert_id('egw_syncmldevinfo', 'dev_id');
|
||||
}
|
||||
|
||||
$this->_clientDeviceInfo['persistent'] = $deviceID;
|
||||
}
|
||||
|
||||
$data = $where = array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
);
|
||||
|
||||
$GLOBALS['egw']->db->delete('egw_syncmldeviceowner', $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
|
||||
$data['owner_devid'] = $this->_clientDeviceInfo['persistent'];
|
||||
|
||||
$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();
|
||||
|
||||
if (!isset($this->_serverAnchorNext)
|
||||
|| !is_array($this->_serverAnchorNext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$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);
|
||||
|
||||
$where = array(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type,
|
||||
);
|
||||
|
||||
$data = array(
|
||||
'sync_serverts' => $a,
|
||||
'sync_clientts' => $this->_clientAnchorNext[$type]
|
||||
);
|
||||
|
||||
$GLOBALS['egw']->db->insert('egw_syncmlsummary', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
}
|
||||
}
|
@ -1,467 +0,0 @@
|
||||
<?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$
|
||||
*/
|
||||
|
||||
class Horde_SyncML_Sync {
|
||||
|
||||
/**
|
||||
* Target, either contacts, notes, events,
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
|
||||
var $_sourceLocURI;
|
||||
|
||||
var $_locName;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$this->runSyncCommand($syncCommand);
|
||||
if ($syncCommand->hasMoreData()) {
|
||||
Horde::logMessage('SyncML: moreData: TRUE', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$syncCommand->setStatus(RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sourceURI.
|
||||
*
|
||||
* @return string $sourceURI or false on error.
|
||||
*/
|
||||
function getSourceLocURI() {
|
||||
if (empty($this->_sourceLocURI)) {
|
||||
return false;
|
||||
}
|
||||
return $this->_sourceLocURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
global $registry;
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
|
||||
$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);
|
||||
$serverAnchorLast = $state->getServerAnchorLast($type);
|
||||
$changes = array();
|
||||
foreach($state->getChangedItems($type) 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
$hordeType = 'tasks';
|
||||
}
|
||||
|
||||
$syncElementItems = $command->getSyncElementItems();
|
||||
|
||||
foreach($syncElementItems as $syncItem) {
|
||||
|
||||
$guid = false;
|
||||
$locURI = $syncItem->getLocURI();
|
||||
|
||||
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 $locURI from client",
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, $locURI);
|
||||
} 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, $locURI, $guid, $ts);
|
||||
$state->log('Client-Add');
|
||||
Horde::logMessage("SyncML: added client entry $locURI as $guid",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
$state->log('Client-AddFailure');
|
||||
Horde::logMessage('SyncML: Error in adding client entry ' . $locURI . ': '
|
||||
. $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
}
|
||||
} elseif (is_a($command, 'Horde_SyncML_Command_Sync_Delete')) {
|
||||
$guid = $state->removeUID($type, $locURI);
|
||||
if (!$guid) {
|
||||
// the entry is no longer on the server
|
||||
$state->log('Client-DeleteFailure');
|
||||
Horde::logMessage('SyncML: Failure deleting client entry ' . $locURI
|
||||
. ', gone on server already!',
|
||||
__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->pushAddedItem($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->pushAddedItem($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, $locURI, $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 ' . $locURI
|
||||
. ', maybe gone on server already: '
|
||||
. $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
}
|
||||
} elseif (is_a($command, 'Horde_SyncML_Command_Sync_Replace')) {
|
||||
$guid = $state->getGlobalUID($type, $locURI);
|
||||
$replace = true;
|
||||
$ok = false;
|
||||
$merge = false;
|
||||
if ($hordeType == 'configuration')
|
||||
{
|
||||
$command->setStatus(RESPONSE_ALREADY_EXISITS);
|
||||
}
|
||||
if ($guid)
|
||||
{
|
||||
Horde::logMessage('SyncML: locuri '. $locURI . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) || in_array($guid, $changes))
|
||||
{
|
||||
Horde::logMessage('SyncML: CONFLICT for locuri ' . $locURI . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
switch ($sync_conflicts)
|
||||
{
|
||||
case CONFLICT_CLIENT_WINNING:
|
||||
$command->setStatus(RESPONSE_CONFLICT_RESOLVED_WITH_CLIENT_WINS);
|
||||
break;
|
||||
case CONFLICT_SERVER_WINNING:
|
||||
Horde::logMessage('SyncML: REJECT client change for locuri ' .
|
||||
$locURI . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$command->setStatus(RESPONSE_CONFLICT_RESOLVED_WITH_SERVER_WINS);
|
||||
$ok = true;
|
||||
$replace = false;
|
||||
$state->log('Client-AddReplaceIgnored');
|
||||
break;
|
||||
case CONFLICT_MERGE_DATA:
|
||||
Horde::logMessage('SyncML: Merge server and client data for locuri ' .
|
||||
$locURI . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$command->setStatus(RESPONSE_CONFLICT_RESOLVED_WITH_MERGE);
|
||||
$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 ' .
|
||||
$locURI . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$command->setStatus(RESPONSE_PERMISSION_DENIED);
|
||||
$ok = true;
|
||||
$replace = false;
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$state->setUID($type, $locURI, $guid, $ts);
|
||||
$state->log('Client-AddReplaceIgnored');
|
||||
break;
|
||||
default: // We enforce our data on client
|
||||
Horde::logMessage('SyncML: Server RO! UNDO client change for locuri ' .
|
||||
$locURI . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$command->setStatus(RESPONSE_PERMISSION_DENIED);
|
||||
$state->pushChangedItem($type, $guid);
|
||||
$ok = true;
|
||||
$replace = false;
|
||||
}
|
||||
}
|
||||
elseif ($sync_conflicts == CONFLICT_MERGE_DATA)
|
||||
{
|
||||
Horde::logMessage('SyncML: Merge server and client data for locuri ' .
|
||||
$locURI . ' 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, $type, $merge));
|
||||
if (!is_a($ok, 'PEAR_Error') && $ok != false)
|
||||
{
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$state->setUID($type, $locURI, $guid, $ts);
|
||||
if ($merge)
|
||||
{
|
||||
Horde::logMessage('SyncML: Merged entry ' . $locURI . ' due to client request guid: ' .
|
||||
$guid . ' ts: ' . $ts, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
else
|
||||
{
|
||||
Horde::logMessage('SyncML: replaced entry ' . $locURI . ' 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 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 ' . $locURI . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, $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 ' . $locURI,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
//continue;
|
||||
$oguid = $guid;
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType, $guid));
|
||||
if (!is_a($guid, 'PEAR_Error')) {
|
||||
if ($oguid != $guid) {
|
||||
// We add a new entry
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
Horde::logMessage('SyncML: added entry ' . $locURI . ' guid '
|
||||
. $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 ' . $locURI . ' guid '
|
||||
. $guid . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->log('Client-Replace');
|
||||
}
|
||||
$state->setUID($type, $locURI, $guid, $ts);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Error in replacing/'
|
||||
. 'add client entry ' . $locURI . ' : ' . $guid->message,
|
||||
__FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log('Client-AddFailure');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
|
||||
/**
|
||||
* No need to run anything at begining or end of sync, Sync will
|
||||
* handle this.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Sync/OneWayFromClientSync.php,v 1.6 2004/05/26 17:32:50 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_OneWayFromClientSync extends Horde_SyncML_Sync {
|
||||
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
|
||||
/**
|
||||
* Will run normal $end from TwoWaySync, the client should not send
|
||||
* any changes.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Sync/OneWayFromServerSync.php,v 1.6 2004/05/26 17:32:50 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_OneWayFromServerSync extends Horde_SyncML_Sync_TwoWaySync {
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<?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 $
|
||||
*
|
||||
* 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_RefreshFromClientSync extends Horde_SyncML_Sync_SlowSync {
|
||||
/**
|
||||
* We needed to erase the current server contents, then we can add
|
||||
* the client's contents.
|
||||
*/
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Sync_RefreshFromServerSync extends Horde_SyncML_Sync_TwoWaySync {
|
||||
function handleSync($currentCmdID, $hordeType, $syncType, &$output, $refts) {
|
||||
global $registry;
|
||||
|
||||
$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);
|
||||
|
||||
if (isset($state->curSyncItem)) {
|
||||
// Finish the pending sync item
|
||||
$cmd = &$state->curSyncItem;
|
||||
if (!is_a($cmd, 'Horde_SyncML_Command_Sync_ContentSyncElement')) {
|
||||
// Conflict with other datastore
|
||||
Horde :: logMessage("SyncML: handleSync($currentCmdID, $hordeType, $syncType) moreData conflict found",
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
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);
|
||||
$c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType));
|
||||
|
||||
if ($c === false) continue; // no content to export
|
||||
|
||||
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: 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);
|
||||
/* The items, which now match the filter criteria are show here, too
|
||||
$state->setAddedItems($syncType, $registry->call($hordeType. '/listBy',
|
||||
array('action' => 'add',
|
||||
'timestamp' => $future,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression)));
|
||||
$delta_add = count($state->getAddedItems($hordeType));
|
||||
*/
|
||||
$state->mergeAddedItems($syncType, $registry->call($hordeType. '/list',array('filter' => $this->_filterExpression)));
|
||||
|
||||
$this->_syncDataLoaded = TRUE;
|
||||
|
||||
return count($state->getAddedItems($syncType)) - $delta_add;
|
||||
}
|
||||
}
|
@ -1,314 +0,0 @@
|
||||
<?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.
|
||||
*
|
||||
*
|
||||
* 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/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);
|
||||
|
||||
if (isset($state->curSyncItem)) {
|
||||
// Finish the pending sync item
|
||||
$cmd = &$state->curSyncItem;
|
||||
if (!is_a($cmd, 'Horde_SyncML_Command_Sync_ContentSyncElement')) {
|
||||
// Conflict with other datastore
|
||||
Horde :: logMessage("SyncML: handleSync($currentCmdID, $hordeType, $syncType) moreData conflict found",
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
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);
|
||||
$conflicts =& $state->getConflictItems($syncType);
|
||||
Horde::logMessage('SyncML: ' .count($adds). ' added items found for ' .$syncType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML: ' . count($conflicts) . ' items to delete on client 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);
|
||||
$c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType));
|
||||
|
||||
if ($c === false) continue; // no content to export
|
||||
|
||||
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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
// handle remote deletes due to conflicts
|
||||
if (count($conflicts) > 0) {
|
||||
while ($locid = array_shift($conflicts)) {
|
||||
$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
|
||||
$conflicts[] = $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: 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) {
|
||||
global $registry;
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$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) {
|
||||
|
||||
if(!$contentType = $syncItem->getContentType()) {
|
||||
$contentType = $state->getPreferedContentType($type);
|
||||
}
|
||||
|
||||
if (($contentType == 'text/x-vcalendar' || $contentType == 'text/calendar')
|
||||
&& strpos($syncItem->getContent(), 'BEGIN:VTODO') !== false) {
|
||||
$hordeType = 'tasks';
|
||||
}
|
||||
|
||||
$guid = false;
|
||||
$locURI = $syncItem->getLocURI();
|
||||
|
||||
$oguid = $state->getGlobalUID($type, $locURI);
|
||||
|
||||
$guid = $registry->call($hordeType . '/search',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType, $oguid, $type));
|
||||
|
||||
if (!is_a($guid, 'PEAR_Error') && $guid) {
|
||||
// Check if the found entry came from the client
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'add');
|
||||
$sync_ts = $state->getChangeTS($type, $guid);
|
||||
if ($oguid != $guid && $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");
|
||||
$command->setStatus(RESPONSE_CONFILCT_RESOLVED_WITH_DUPLICATE);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
# Entry exists in database already. Just update the mapping
|
||||
Horde::logMessage("SyncML: adding mapping for locuri: $locURI and guid: $guid",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setUID($type, $locURI, $guid);
|
||||
$state->log("Client-Map");
|
||||
$command->setStatus(RESPONSE_ALREADY_EXISITS);
|
||||
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 $locURI from client",
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, $locURI);
|
||||
} 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, $locURI);
|
||||
Horde::logMessage("SyncML: try to add $locURI with 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) {
|
||||
// first we try the modification timestamp then the creation ts
|
||||
if (!($ts = $state->getSyncTSforAction($guid, 'modify'))) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
}
|
||||
$state->setUID($type, $locURI, $guid, $ts);
|
||||
$state->log("Client-AddReplace");
|
||||
Horde::logMessage("SyncML: replaced/added client entry $locURI as $guid",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Error in replacing/add client entry ' . $locURI . ': '. $guid->message,
|
||||
__FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log("Client-AddFailure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadData() {
|
||||
global $registry;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
$state->setTargetURI($syncType);
|
||||
$future = $state->getServerAnchorNext($syncType);
|
||||
|
||||
$state->mergeAddedItems($syncType, $registry->call($hordeType. '/list', array('filter' => $this->_filterExpression)));
|
||||
|
||||
$this->_syncDataLoaded = TRUE;
|
||||
|
||||
return count($state->getAddedItems($syncType)) + count($state->getConflictItems($syncType));
|
||||
}
|
||||
}
|
@ -1,460 +0,0 @@
|
||||
<?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';
|
||||
|
||||
class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
|
||||
|
||||
function endSync($currentCmdID, & $output) {
|
||||
global $registry;
|
||||
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
$syncType = $this->_targetLocURI;
|
||||
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
|
||||
$refts = $state->getServerAnchorLast($syncType);
|
||||
$currentCmdID = $this->handleSync($currentCmdID, $hordeType, $syncType, $output, $refts);
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
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 ();
|
||||
|
||||
$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);
|
||||
|
||||
|
||||
if (isset ($state->curSyncItem)) {
|
||||
// Finish the pending sync item
|
||||
$cmd = & $state->curSyncItem;
|
||||
if (!is_a($cmd, 'Horde_SyncML_Command_Sync_ContentSyncElement')) {
|
||||
// Conflict with other datastore
|
||||
Horde :: logMessage("SyncML: handleSync($currentCmdID, $hordeType, $syncType) moreData conflict found",
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
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);
|
||||
|
||||
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($conflicts) . ' items to delete on client found for ' . $syncType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML: ' . count($adds) . ' added items found for ' . $syncType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// handle 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 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);
|
||||
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;
|
||||
}
|
||||
$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);
|
||||
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 ($c === false) continue; // no content to export
|
||||
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
// Item in history but not in database. Strange, but can happen.
|
||||
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;
|
||||
}
|
||||
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);
|
||||
|
||||
// handle 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);
|
||||
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);
|
||||
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 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);
|
||||
// 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-Delete');
|
||||
$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();
|
||||
}
|
||||
}
|
||||
|
||||
// handle remote deletes due to conflicts
|
||||
if (count($conflicts) > 0) {
|
||||
while ($locid = array_shift($conflicts)) {
|
||||
$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
|
||||
$conflicts[] = $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);
|
||||
$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)) {
|
||||
$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;
|
||||
}
|
||||
|
||||
// first we try the modification timestamp then the creation ts
|
||||
if (!($guid_ts = $state->getSyncTSforAction($guid, 'modify'))) {
|
||||
$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);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
$locid = $state->getLocID($syncType, $guid);
|
||||
|
||||
if ($locid && $refts == 0) {
|
||||
// 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);
|
||||
continue;
|
||||
}
|
||||
Horde :: logMessage("SyncML: add: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Create an Add request for client.
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
$c = $registry->call($hordeType . '/export', array (
|
||||
'guid' => $guid,
|
||||
'contentType' => $contentType,
|
||||
|
||||
));
|
||||
|
||||
if ($c === false) continue; // no content to export
|
||||
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
// Item in history but not in database. Strange, but can happen.
|
||||
Horde :: logMessage("SyncML: add: 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: 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: All items handled for sync $syncType",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->removeExpiredUID($syncType, time());
|
||||
$state->clearSync($syncType);
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function loadData() {
|
||||
global $registry;
|
||||
|
||||
$state =& $_SESSION['SyncML.state'];
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
$refts = $state->getServerAnchorLast($syncType);
|
||||
$future = $state->getServerAnchorNext($syncType);
|
||||
|
||||
$addedItems =& $registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'add',
|
||||
'timestamp' => $refts,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
));
|
||||
|
||||
$state->setAddedItems($syncType, $addedItems);
|
||||
|
||||
$changedItems =& $state->getChangedItems($syncType);
|
||||
|
||||
$deletedItems =& $registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'delete',
|
||||
'timestamp' => $refts,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
));
|
||||
foreach ($deletedItems as $guid)
|
||||
{
|
||||
if (strstr($guid, ':'))
|
||||
{
|
||||
$parentGUID = array_shift(explode(':', $guid));
|
||||
if (!in_array($parentGUID, $changedItems))
|
||||
{
|
||||
$changedItems[] = $parentGUID;
|
||||
}
|
||||
}
|
||||
}
|
||||
$state->setDeletedItems($syncType, $deletedItems);
|
||||
|
||||
$this->_syncDataLoaded = true;
|
||||
|
||||
return count($changedItems) + count($deletedItems) + count($addedItems) + count($state->getConflictItems($syncType));
|
||||
}
|
||||
}
|
@ -1,836 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Error code for a missing driver configuration.
|
||||
*/
|
||||
define('HORDE_ERROR_DRIVER_CONFIG_MISSING', 1);
|
||||
|
||||
/**
|
||||
* Error code for an incomplete driver configuration.
|
||||
*/
|
||||
define('HORDE_ERROR_DRIVER_CONFIG', 2);
|
||||
|
||||
/**
|
||||
* The Util:: class provides generally useful methods of different kinds.
|
||||
*
|
||||
* $Horde: framework/Util/Util.php,v 1.388 2005/01/12 15:51:12 chuck Exp $
|
||||
*
|
||||
* Copyright 1999-2005 Chuck Hagenbuch <chuck@horde.org>
|
||||
* Copyright 1999-2005 Jon Parise <jon@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 Chuck Hagenbuch <chuck@horde.org>
|
||||
* @author Jon Parise <jon@horde.org>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_Util
|
||||
*/
|
||||
class Util {
|
||||
|
||||
/**
|
||||
* Returns an object's clone.
|
||||
*
|
||||
* @param object &$obj The object to clone.
|
||||
*
|
||||
* @return object The cloned object.
|
||||
*/
|
||||
function &cloneObject(&$obj)
|
||||
{
|
||||
if (version_compare(zend_version(), '2', '>')) {
|
||||
return clone($obj);
|
||||
} else {
|
||||
$newObj = $obj;
|
||||
return $newObj;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffers the output from a function call, like readfile() or
|
||||
* highlight_string(), that prints the output directly, so that instead it
|
||||
* can be returned as a string and used.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $function The function to run.
|
||||
* @param mixed $arg1 First argument to $function().
|
||||
* @param mixed $arg2 Second argument to $function().
|
||||
* @param mixed $arg... ...
|
||||
* @param mixed $argN Nth argument to $function().
|
||||
*
|
||||
* @return string The output of the function.
|
||||
*/
|
||||
function bufferOutput()
|
||||
{
|
||||
if (func_num_args() == 0) {
|
||||
return false;
|
||||
}
|
||||
$eval = false;
|
||||
$args = func_get_args();
|
||||
$function = array_shift($args);
|
||||
if (is_array($function)) {
|
||||
if (!is_callable($function)) {
|
||||
return false;
|
||||
}
|
||||
} elseif (($function == 'include') ||
|
||||
($function == 'include_once') ||
|
||||
($function == 'require') ||
|
||||
($function == 'require_once')) {
|
||||
$eval = true;
|
||||
} elseif (!function_exists($function) &&
|
||||
($function != 'eval')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
if ($eval) {
|
||||
eval($function . " '" . implode(',', $args) . "';");
|
||||
} elseif ($function == 'eval') {
|
||||
eval($args[0]);
|
||||
} else {
|
||||
call_user_func_array($function, $args);
|
||||
}
|
||||
$output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a value has been set by the script and not by GET,
|
||||
* POST, or cookie input. The value being checked MUST be in the global
|
||||
* scope.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $varname The variable name to check.
|
||||
*
|
||||
* @return mixed Null if the var is in user input, the variable value
|
||||
* otherwise.
|
||||
*/
|
||||
function nonInputVar($varname)
|
||||
{
|
||||
if (isset($_GET[$varname]) ||
|
||||
isset($_POST[$varname]) ||
|
||||
isset($_COOKIE[$varname])) {
|
||||
return null;
|
||||
} else {
|
||||
return isset($GLOBALS[$varname]) ? $GLOBALS[$varname] : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a name=value pair to the end of an URL, taking care of whether
|
||||
* there are existing parameters and whether to use ?, & or & as the
|
||||
* glue. All data will be urlencoded.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $url The URL to modify
|
||||
* @param mixed $parameter Either the name=value pair to add
|
||||
* (DEPRECATED) -or-
|
||||
* the name value -or-
|
||||
* an array of name/value pairs.
|
||||
* @param string $value If specified, the value part ($parameter is
|
||||
* then assumed to just be the parameter name).
|
||||
* @param boolean $encode If true, and we don't have argument separators
|
||||
* yet, the argument separator gets encoded.
|
||||
*
|
||||
* @return string The modified URL.
|
||||
*
|
||||
* @since Horde 2.1
|
||||
*/
|
||||
function addParameter($url, $parameter, $value = null, $encode = true)
|
||||
{
|
||||
if (empty($parameter)) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
if (!is_array($parameter)) {
|
||||
/* This is deprecated should be removed in the future. */
|
||||
if (is_null($value)) {
|
||||
@list($parameter, $value) = explode('=', $parameter, 2);
|
||||
}
|
||||
$add = array($parameter => $value);
|
||||
} else {
|
||||
$add = $parameter;
|
||||
}
|
||||
|
||||
$arg = $encode ? '&' : '&';
|
||||
if (($pos = strpos($url, '?')) === false) {
|
||||
$glue = '?';
|
||||
} else {
|
||||
/* Check if the argument separator has been already
|
||||
* htmlentities-ized in the URL. */
|
||||
$query = substr($url, $pos + 1);
|
||||
if (preg_match('/=.*?&.*?=/', $query)) {
|
||||
$arg = '&';
|
||||
$query = strtr($query, array_flip(get_html_translation_table(HTML_ENTITIES)));
|
||||
} elseif (preg_match('/=.*?&.*?=/', $query)) {
|
||||
$arg = '&';
|
||||
}
|
||||
$pairs = explode($arg, $query);
|
||||
$params = array();
|
||||
foreach ($pairs as $pair) {
|
||||
$pair = explode('=', $pair, 2);
|
||||
$params[$pair[0]] = count($pair) == 2 ? $pair[1] : '';
|
||||
}
|
||||
$glue = $arg;
|
||||
}
|
||||
|
||||
$url_params = array();
|
||||
foreach ($add as $parameter => $value) {
|
||||
if (!isset($params[$parameter])) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $val) {
|
||||
$url_params[] = urlencode($parameter) . '[]=' . urlencode($val);
|
||||
}
|
||||
} else {
|
||||
$url_params[] = urlencode($parameter) . '=' . urlencode($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($url_params)) {
|
||||
return $url . $glue . implode($arg, $url_params);
|
||||
} else {
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes name=value pairs from a URL.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $url The URL to modify.
|
||||
* @param mixed $remove Either a single parameter to remove or an array
|
||||
* of parameters to remove.
|
||||
*
|
||||
* @return string The modified URL.
|
||||
*
|
||||
* @since Horde 2.2
|
||||
*/
|
||||
function removeParameter($url, $remove)
|
||||
{
|
||||
if (!is_array($remove)) {
|
||||
$remove = array($remove);
|
||||
}
|
||||
|
||||
/* Return immediately if there are no parameters to remove. */
|
||||
if (($pos = strpos($url, '?')) === false) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$entities = false;
|
||||
list($url, $query) = explode('?', $url, 2);
|
||||
|
||||
/* Check if the argument separator has been already
|
||||
* htmlentities-ized in the URL. */
|
||||
if (preg_match('/=.*?&.*?=/', $query)) {
|
||||
$entities = true;
|
||||
$query = strtr($query, array_flip(get_html_translation_table(HTML_ENTITIES)));
|
||||
}
|
||||
|
||||
/* Get the list of parameters. */
|
||||
$pairs = explode('&', $query);
|
||||
$params = array();
|
||||
foreach ($pairs as $pair) {
|
||||
$pair = explode('=', $pair, 2);
|
||||
$params[$pair[0]] = count($pair) == 2 ? $pair[1] : '';
|
||||
}
|
||||
|
||||
/* Remove the parameters. */
|
||||
foreach ($remove as $param) {
|
||||
unset($params[$param]);
|
||||
}
|
||||
|
||||
if (!count($params)) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
/* Flatten arrays.
|
||||
* FIXME: should handle more than one array level somehow. */
|
||||
$add = array();
|
||||
foreach ($params as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
foreach ($val as $v) {
|
||||
$add[] = $key . '[]=' . $v;
|
||||
}
|
||||
} else {
|
||||
$add[] = $key . '=' . $val;
|
||||
}
|
||||
}
|
||||
|
||||
$query = implode('&', $add);
|
||||
if ($entities) {
|
||||
$query = htmlentities($query);
|
||||
}
|
||||
|
||||
return $url . '?' . $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a url with the 'nocache' parameter added, if the browser is
|
||||
* buggy and caches old URLs.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $url The URL to modify.
|
||||
*
|
||||
* @return string The requested URI.
|
||||
*/
|
||||
function nocacheUrl($url)
|
||||
{
|
||||
static $rand_num;
|
||||
|
||||
require_once 'Horde/Browser.php';
|
||||
$browser = &Browser::singleton();
|
||||
|
||||
/* We may need to set a dummy parameter 'nocache' since some
|
||||
* browsers do not always honor the 'no-cache' header. */
|
||||
if ($browser->hasQuirk('cache_same_url')) {
|
||||
if (!isset($rand_num)) {
|
||||
$rand_num = base_convert(microtime(), 10, 36);
|
||||
}
|
||||
return Util::addParameter($url, 'nocache', $rand_num);
|
||||
} else {
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hidden form input containing the session name and id.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param boolean $append_session 0 = only if needed, 1 = always.
|
||||
*
|
||||
* @return string The hidden form input, if needed/requested.
|
||||
*/
|
||||
function formInput($append_session = 0)
|
||||
{
|
||||
if ($append_session == 1 ||
|
||||
!isset($_COOKIE[session_name()])) {
|
||||
return '<input type="hidden" name="' . htmlspecialchars(session_name()) . '" value="' . htmlspecialchars(session_id()) . "\" />\n";
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a hidden form input containing the session name and id.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param boolean $append_session 0 = only if needed, 1 = always.
|
||||
*/
|
||||
function pformInput($append_session = 0)
|
||||
{
|
||||
echo Util::formInput($append_session);
|
||||
}
|
||||
|
||||
/**
|
||||
* If magic_quotes_gpc is in use, run stripslashes() on $var.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string &$var The string to un-quote, if necessary.
|
||||
*
|
||||
* @return string $var, minus any magic quotes.
|
||||
*/
|
||||
function dispelMagicQuotes(&$var)
|
||||
{
|
||||
static $magic_quotes;
|
||||
|
||||
if (!isset($magic_quotes)) {
|
||||
$magic_quotes = get_magic_quotes_gpc();
|
||||
}
|
||||
|
||||
if ($magic_quotes) {
|
||||
if (!is_array($var)) {
|
||||
$var = stripslashes($var);
|
||||
} else {
|
||||
array_walk($var, array('Util', 'dispelMagicQuotes'));
|
||||
}
|
||||
}
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a form variable from GET or POST data, stripped of magic quotes if
|
||||
* necessary. If the variable is somehow set in both the GET data and the
|
||||
* POST data, the value from the POST data will be returned and the GET
|
||||
* value will be ignored.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $var The name of the form variable to look for.
|
||||
* @param string $default The value to return if the variable is not
|
||||
* there.
|
||||
*
|
||||
* @return string The cleaned form variable, or $default.
|
||||
*/
|
||||
function getFormData($var, $default = null)
|
||||
{
|
||||
return (($val = Util::getPost($var)) !== null)
|
||||
? $val : Util::getGet($var, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a form variable from GET data, stripped of magic quotes if
|
||||
* necessary. This function will NOT return a POST variable.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $var The name of the form variable to look for.
|
||||
* @param string $default The value to return if the variable is not
|
||||
* there.
|
||||
*
|
||||
* @return string The cleaned form variable, or $default.
|
||||
*
|
||||
* @since Horde 2.2
|
||||
*/
|
||||
function getGet($var, $default = null)
|
||||
{
|
||||
return (isset($_GET[$var]))
|
||||
? Util::dispelMagicQuotes($_GET[$var])
|
||||
: $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a form variable from POST data, stripped of magic quotes if
|
||||
* necessary. This function will NOT return a GET variable.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $var The name of the form variable to look for.
|
||||
* @param string $default The value to return if the variable is not
|
||||
* there.
|
||||
*
|
||||
* @return string The cleaned form variable, or $default.
|
||||
*
|
||||
* @since Horde 2.2
|
||||
*/
|
||||
function getPost($var, $default = null)
|
||||
{
|
||||
return (isset($_POST[$var]))
|
||||
? Util::dispelMagicQuotes($_POST[$var])
|
||||
: $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the location of the system temporary directory.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return string A directory name which can be used for temp files.
|
||||
* Returns false if one could not be found.
|
||||
*/
|
||||
function getTempDir()
|
||||
{
|
||||
/* First, try PHP's upload_tmp_dir directive. */
|
||||
$tmp = ini_get('upload_tmp_dir');
|
||||
|
||||
/* Otherwise, try to determine the TMPDIR environment
|
||||
* variable. */
|
||||
if (empty($tmp)) {
|
||||
$tmp = getenv('TMPDIR');
|
||||
}
|
||||
|
||||
/* If we still cannot determine a value, then cycle through a
|
||||
* list of preset possibilities. */
|
||||
$tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
|
||||
'c:\windows\temp', 'c:\winnt\temp');
|
||||
while (empty($tmp) && count($tmp_locations)) {
|
||||
$tmp_check = array_shift($tmp_locations);
|
||||
if (@is_dir($tmp_check)) {
|
||||
$tmp = $tmp_check;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it is still empty, we have failed, so return false;
|
||||
* otherwise return the directory determined. */
|
||||
return empty($tmp) ? false : $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary filename for the lifetime of the script, and
|
||||
* (optionally) register it to be deleted at request shutdown.
|
||||
*
|
||||
* @param string $prefix Prefix to make the temporary name more
|
||||
* recognizable.
|
||||
* @param boolean $delete Delete the file at the end of the request?
|
||||
* @param string $dir Directory to create the temporary file in.
|
||||
* @param boolean $secure If deleting file, should we securely delete the
|
||||
* file?
|
||||
*
|
||||
* @return string Returns the full path-name to the temporary file.
|
||||
* Returns false if a temp file could not be created.
|
||||
*/
|
||||
function getTempFile($prefix = '', $delete = true, $dir = '', $secure = false)
|
||||
{
|
||||
if (empty($dir) || !is_dir($dir)) {
|
||||
$tmp_dir = Util::getTempDir();
|
||||
} else {
|
||||
$tmp_dir = $dir;
|
||||
}
|
||||
|
||||
if (empty($tmp_dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tmp_file = tempnam($tmp_dir, $prefix);
|
||||
|
||||
/* If the file was created, then register it for deletion and return */
|
||||
if (empty($tmp_file)) {
|
||||
return false;
|
||||
} else {
|
||||
if ($delete) {
|
||||
Util::deleteAtShutdown($tmp_file, true, $secure);
|
||||
}
|
||||
return $tmp_file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary directory in the system's temporary directory.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param boolean $delete Delete the temporary directory at the end of
|
||||
* the request?
|
||||
* @param string $temp_dir Use this temporary directory as the directory
|
||||
* where the temporary directory will be created.
|
||||
*
|
||||
* @return string The pathname to the new temporary directory.
|
||||
* Returns false if directory not created.
|
||||
*/
|
||||
function createTempDir($delete = true, $temp_dir = null)
|
||||
{
|
||||
if (is_null($temp_dir)) {
|
||||
$temp_dir = Util::getTempDir();
|
||||
}
|
||||
|
||||
if (empty($temp_dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the first 8 characters of a random string to use as a temporary
|
||||
directory name. */
|
||||
do {
|
||||
$temp_dir .= '/' . substr(base_convert(mt_rand() . microtime(), 10, 36), 0, 8);
|
||||
} while (file_exists($temp_dir));
|
||||
|
||||
$old_umask = umask(0000);
|
||||
if (!mkdir($temp_dir, 0700)) {
|
||||
$temp_dir = false;
|
||||
} elseif ($delete) {
|
||||
Util::deleteAtShutdown($temp_dir);
|
||||
}
|
||||
umask($old_umask);
|
||||
|
||||
return $temp_dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given elements at request shutdown.
|
||||
*
|
||||
* If called with a filename will delete that file at request shutdown; if
|
||||
* called with a directory will remove that directory and all files in that
|
||||
* directory at request shutdown.
|
||||
*
|
||||
* If called with no arguments, return all elements to be deleted (this
|
||||
* should only be done by Util::_deleteAtShutdown).
|
||||
*
|
||||
* The first time it is called, it initializes the array and registers
|
||||
* Util::_deleteAtShutdown() as a shutdown function - no need to do so
|
||||
* manually.
|
||||
*
|
||||
* The second parameter allows the unregistering of previously registered
|
||||
* elements.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $filename The filename to be deleted at the end of the
|
||||
* request.
|
||||
* @param boolean $register If true, then register the element for
|
||||
* deletion, otherwise, unregister it.
|
||||
* @param boolean $secure If deleting file, should we securely delete
|
||||
* the file?
|
||||
*/
|
||||
function deleteAtShutdown($filename = false, $register = true,
|
||||
$secure = false)
|
||||
{
|
||||
static $dirs, $files, $securedel;
|
||||
|
||||
/* Initialization of variables and shutdown functions. */
|
||||
if (is_null($dirs)){
|
||||
$dirs = array();
|
||||
$files = array();
|
||||
$securedel = array();
|
||||
register_shutdown_function(array('Util', '_deleteAtShutdown'));
|
||||
}
|
||||
|
||||
if ($filename) {
|
||||
if ($register) {
|
||||
if (@is_dir($filename)) {
|
||||
$dirs[$filename] = true;
|
||||
} else {
|
||||
$files[$filename] = true;
|
||||
}
|
||||
if ($secure) {
|
||||
$securedel[$filename] = true;
|
||||
}
|
||||
} else {
|
||||
unset($dirs[$filename]);
|
||||
unset($files[$filename]);
|
||||
unset($securedel[$filename]);
|
||||
}
|
||||
} else {
|
||||
return array($dirs, $files, $securedel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes registered files at request shutdown.
|
||||
*
|
||||
* This function should never be called manually; it is registered as a
|
||||
* shutdown function by Util::deleteAtShutdown() and called automatically
|
||||
* at the end of the request. It will retrieve the list of folders and
|
||||
* files to delete from Util::deleteAtShutdown()'s static array, and then
|
||||
* iterate through, deleting folders recursively.
|
||||
*
|
||||
* Contains code from gpg_functions.php.
|
||||
* Copyright (c) 2002-2003 Braverock Ventures
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _deleteAtShutdown()
|
||||
{
|
||||
$registered = Util::deleteAtShutdown();
|
||||
$dirs = $registered[0];
|
||||
$files = $registered[1];
|
||||
$secure = $registered[2];
|
||||
|
||||
foreach ($files as $file => $val) {
|
||||
/* Delete files */
|
||||
if ($val && @file_exists($file)) {
|
||||
/* Should we securely delete the file by overwriting the
|
||||
data with a random string? */
|
||||
if (isset($secure[$file])) {
|
||||
$random_str = '';
|
||||
for ($i = 0; $i < filesize($file); $i++) {
|
||||
$random_str .= chr(mt_rand(0, 255));
|
||||
}
|
||||
$fp = fopen($file, 'r+');
|
||||
fwrite($fp, $random_str);
|
||||
fclose($fp);
|
||||
}
|
||||
@unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($dirs as $dir => $val) {
|
||||
/* Delete directories */
|
||||
if ($val && @file_exists($dir)) {
|
||||
/* Make sure directory is empty. */
|
||||
$dir_class = dir($dir);
|
||||
while (false !== ($entry = $dir_class->read())) {
|
||||
if ($entry != '.' && $entry != '..') {
|
||||
@unlink($dir . '/' . $entry);
|
||||
}
|
||||
}
|
||||
$dir_class->close();
|
||||
@rmdir($dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs javascript code to close the current window.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $code Any addtional javascript code to run before
|
||||
* closing the window.
|
||||
*/
|
||||
function closeWindowJS($code = '')
|
||||
{
|
||||
echo '<script language="JavaScript" type="text/javascript">' . $code .
|
||||
'window.close();</script>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the result of extension_loaded() calls.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param string $ext The extension name.
|
||||
*
|
||||
* @return boolean Is the extension loaded?
|
||||
*/
|
||||
function extensionExists($ext)
|
||||
{
|
||||
static $cache = array();
|
||||
|
||||
if (!isset($cache[$ext])) {
|
||||
$cache[$ext] = extension_loaded($ext);
|
||||
}
|
||||
|
||||
return $cache[$ext];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to load a PHP extension, behaving correctly for all operating
|
||||
* systems.
|
||||
*
|
||||
* @param string $ext The extension to load.
|
||||
*
|
||||
* @return boolean True if the extension is now loaded, false if not.
|
||||
* True can mean that the extension was already loaded,
|
||||
* OR was loaded dynamically.
|
||||
*/
|
||||
function loadExtension($ext)
|
||||
{
|
||||
/* If $ext is already loaded, our work is done. */
|
||||
if (Util::extensionExists($ext)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* See if we can call dl() at all, by the current ini settings. */
|
||||
if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (substr(PHP_OS, 0, 3) == 'WIN') {
|
||||
$suffix = 'dll';
|
||||
} else {
|
||||
switch (PHP_OS) {
|
||||
case 'HP-UX':
|
||||
$suffix = 'sl';
|
||||
break;
|
||||
|
||||
case 'AIX':
|
||||
$suffix = 'a';
|
||||
break;
|
||||
|
||||
case 'OSX':
|
||||
$suffix = 'bundle';
|
||||
break;
|
||||
|
||||
default:
|
||||
$suffix = 'so';
|
||||
}
|
||||
}
|
||||
|
||||
return @dl($ext . '.' . $suffix) || @dl('php_' . $ext . '.' . $suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all necessary parameters for a driver's configuration are set
|
||||
* and returns a PEAR_Error if something is missing.
|
||||
*
|
||||
* @param array $params The configuration array with all parameters.
|
||||
* @param array $fields An array with mandatory parameter names for this
|
||||
* driver.
|
||||
* @param string $name The clear text name of the driver. If not
|
||||
* specified, the application name will be used.
|
||||
* @param array $info A hash containing detailed information about the
|
||||
* driver. Will be passed as the userInfo to the
|
||||
* PEAR_Error.
|
||||
*/
|
||||
function assertDriverConfig($params, $fields, $name, $info = array())
|
||||
{
|
||||
$info = array_merge($info,
|
||||
array('params' => $params,
|
||||
'fields' => $fields,
|
||||
'name' => $name));
|
||||
|
||||
if (!is_array($params) || !count($params)) {
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::throwError(sprintf(_("No configuration information specified for %s."), $name),
|
||||
HORDE_ERROR_DRIVER_CONFIG_MISSING,
|
||||
$info);
|
||||
}
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if (!isset($params[$field])) {
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::throwError(sprintf(_("Required '%s' not specified in configuration."), $field, $name),
|
||||
HORDE_ERROR_DRIVER_CONFIG,
|
||||
$info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a format string to be used by strftime().
|
||||
*
|
||||
* @param string $format A format string as used by date().
|
||||
*
|
||||
* @return string A format string as similar as possible to $format.
|
||||
*/
|
||||
function date2strftime($format)
|
||||
{
|
||||
$dateSymbols = array('a', 'A', 'd', 'D', 'F', 'g', 'G', 'h', 'H', 'i', 'j', 'l', 'm', 'M', 'n', 'r', 's', 'T', 'w', 'W', 'y', 'Y', 'z', 'm/d/Y', 'M', "\n", 'g:i a', 'G:i', "\t", 'H:i:s', '%');
|
||||
$strftimeSymbols = array('%p', '%p', '%d', '%a', '%B', '%I', '%H', '%I', '%H', '%M', '%e', '%A', '%m', '%b', '%m', '%a, %e %b %Y %T %Z', '%S', '%Z', '%w', '%V', '%y', '%Y', '%j', '%D', '%h', '%n', '%r', '%R', '%t', '%T', '%%');
|
||||
|
||||
$result = '';
|
||||
for ($pos = 0; $pos < strlen($format);) {
|
||||
for ($symbol = 0; $symbol < count($dateSymbols); $symbol++) {
|
||||
if (strpos($format, $dateSymbols[$symbol], $pos) === $pos) {
|
||||
$result .= $strftimeSymbols[$symbol];
|
||||
$pos += strlen($dateSymbols[$symbol]);
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$result .= substr($format, $pos, 1);
|
||||
$pos++;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a format string to be used by date().
|
||||
*
|
||||
* @param string $format A format string as used by strftime().
|
||||
*
|
||||
* @return string A format string as similar as possible to $format.
|
||||
*/
|
||||
function strftime2date($format)
|
||||
{
|
||||
$dateSymbols = array('a', 'A', 'd', 'D', 'F', 'g', 'G', 'h', 'H', 'i', 'j', 'l', 'm', 'M', 'n', 'r', 's', 'T', 'w', 'W', 'y', 'Y', 'z', 'm/d/Y', 'M', "\n", 'g:i a', 'G:i', "\t", 'H:i:s', '%');
|
||||
$strftimeSymbols = array('%p', '%p', '%d', '%a', '%B', '%I', '%H', '%I', '%H', '%M', '%e', '%A', '%m', '%b', '%m', '%a, %e %b %Y %T %Z', '%S', '%Z', '%w', '%V', '%y', '%Y', '%j', '%D', '%h', '%n', '%r', '%R', '%t', '%T', '%%');
|
||||
|
||||
return str_replace($strftimeSymbols, $dateSymbols, $format);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!function_exists('_')) {
|
||||
function _($string)
|
||||
{
|
||||
return $string;
|
||||
}
|
||||
|
||||
function bindtextdomain()
|
||||
{
|
||||
}
|
||||
|
||||
function textdomain()
|
||||
{
|
||||
}
|
||||
|
||||
function dgettext($domain, $message)
|
||||
{
|
||||
return $message;
|
||||
}
|
||||
|
||||
function ngettext($singular, $plural, $number)
|
||||
{
|
||||
return $number > 1 ? $plural : $singular;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class representing vAlarms.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/valarm.php,v 1.8.10.8 2008/07/03 08:42:58 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 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_valarm extends Horde_iCalendar {
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'vAlarm';
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VALARM');
|
||||
}
|
||||
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
<?php
|
||||
|
||||
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);
|
||||
define('VCARD_N_GIVEN', 1);
|
||||
define('VCARD_N_ADDL', 2);
|
||||
define('VCARD_N_PREFIX', 3);
|
||||
define('VCARD_N_SUFFIX', 4);
|
||||
|
||||
// Part numbers for ADR components.
|
||||
define('VCARD_ADR_POB', 0);
|
||||
define('VCARD_ADR_EXTEND', 1);
|
||||
define('VCARD_ADR_STREET', 2);
|
||||
define('VCARD_ADR_LOCALITY', 3);
|
||||
define('VCARD_ADR_REGION', 4);
|
||||
define('VCARD_ADR_POSTCODE', 5);
|
||||
define('VCARD_ADR_COUNTRY', 6);
|
||||
|
||||
// Part numbers for GEO components.
|
||||
define('VCARD_GEO_LAT', 0);
|
||||
define('VCARD_GEO_LON', 1);
|
||||
|
||||
/**
|
||||
* Class representing vCard entries.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vcard.php,v 1.3.10.16 2008/09/22 04:16:30 chuck 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 Karsten Fourmont <karsten@horde.org>
|
||||
* @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';
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike vevent and vtodo, a vcard is normally not enclosed in an
|
||||
* iCalendar container. (BEGIN..END)
|
||||
*/
|
||||
function exportvCalendar()
|
||||
{
|
||||
$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')) {
|
||||
$this->setAttribute($name, $default_value);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_exportvData('VCARD');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contents of the "N" tag as a printable Name:
|
||||
* i.e. converts:
|
||||
*
|
||||
* N:Duck;Dagobert;T;Professor;Sen.
|
||||
* to
|
||||
* "Professor Dagobert T Duck Sen"
|
||||
*
|
||||
* @return string Full name of vcard "N" tag or null if no N tag.
|
||||
*/
|
||||
function printableName()
|
||||
{
|
||||
$name_parts = $this->getAttributeValues('N');
|
||||
if (is_a($name_parts, 'PEAR_Error')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$name_arr = array();
|
||||
|
||||
if (!empty($name_parts[VCARD_N_PREFIX])) {
|
||||
$name_arr[] = $name_parts[VCARD_N_PREFIX];
|
||||
}
|
||||
if (!empty($name_parts[VCARD_N_GIVEN])) {
|
||||
$name_arr[] = $name_parts[VCARD_N_GIVEN];
|
||||
}
|
||||
if (!empty($name_parts[VCARD_N_ADDL])) {
|
||||
$name_arr[] = $name_parts[VCARD_N_ADDL];
|
||||
}
|
||||
if (!empty($name_parts[VCARD_N_FAMILY])) {
|
||||
$name_arr[] = $name_parts[VCARD_N_FAMILY];
|
||||
}
|
||||
if (!empty($name_parts[VCARD_N_SUFFIX])) {
|
||||
$name_arr[] = $name_parts[VCARD_N_SUFFIX];
|
||||
}
|
||||
|
||||
return implode(' ', $name_arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to make a given email address rfc822 compliant.
|
||||
*
|
||||
* @param string $address An email address.
|
||||
*
|
||||
* @return string The RFC822-formatted email address.
|
||||
*/
|
||||
function getBareEmail($address)
|
||||
{
|
||||
// Empty values are still empty.
|
||||
if (!$address) {
|
||||
return $address;
|
||||
}
|
||||
|
||||
require_once 'Mail/RFC822.php';
|
||||
require_once 'Horde/MIME.php';
|
||||
|
||||
static $rfc822;
|
||||
if (is_null($rfc822)) {
|
||||
$rfc822 = new Mail_RFC822();
|
||||
}
|
||||
|
||||
if (!$rfc822->validateMailbox($address)) {
|
||||
return $address;
|
||||
}
|
||||
return MIME::rfc822WriteAddress($address->mailbox, $address->host);
|
||||
}
|
||||
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class representing vEvents.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vevent.php,v 1.31.10.15 2008/07/03 08:42:58 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 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'vEvent';
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
// Default values.
|
||||
$requiredAttributes = array();
|
||||
$requiredAttributes['DTSTAMP'] = time();
|
||||
/* This is handled by the upper layers.
|
||||
$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'] = '';
|
||||
break;
|
||||
|
||||
case 'REQUEST':
|
||||
$requiredAttributes['ATTENDEE'] = '';
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
break;
|
||||
|
||||
case 'REPLY':
|
||||
$requiredAttributes['ATTENDEE'] = '';
|
||||
break;
|
||||
|
||||
case 'ADD':
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SEQUENCE'] = 1;
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
break;
|
||||
|
||||
case 'CANCEL':
|
||||
$requiredAttributes['ATTENDEE'] = '';
|
||||
$requiredAttributes['SEQUENCE'] = 1;
|
||||
break;
|
||||
|
||||
case 'REFRESH':
|
||||
$requiredAttributes['ATTENDEE'] = '';
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($requiredAttributes as $name => $default_value) {
|
||||
if (is_a($this->getAttribute($name), 'PEAR_Error')) {
|
||||
$this->setAttribute($name, $default_value);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::_exportvData('VEVENT');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the status of an attendee of an event.
|
||||
*
|
||||
* @param $email The email address of the attendee.
|
||||
* @param $status The participant status to set.
|
||||
* @param $fullname The full name of the participant to set.
|
||||
*/
|
||||
function updateAttendee($email, $status, $fullname = '')
|
||||
{
|
||||
foreach ($this->_attributes as $key => $attribute) {
|
||||
if ($attribute['name'] == 'ATTENDEE' &&
|
||||
$attribute['value'] == 'mailto:' . $email) {
|
||||
$this->_attributes[$key]['params']['PARTSTAT'] = $status;
|
||||
if (!empty($fullname)) {
|
||||
$this->_attributes[$key]['params']['CN'] = $fullname;
|
||||
}
|
||||
unset($this->_attributes[$key]['params']['RSVP']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
$params = array('PARTSTAT' => $status);
|
||||
if (!empty($fullname)) {
|
||||
$params['CN'] = $fullname;
|
||||
}
|
||||
$this->setAttribute('ATTENDEE', 'mailto:' . $email, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the organizer display name or email.
|
||||
*
|
||||
* @return string The organizer name to display for this event.
|
||||
*/
|
||||
function organizerName()
|
||||
{
|
||||
$organizer = $this->getAttribute('ORGANIZER', true);
|
||||
if (is_a($organizer, 'PEAR_Error')) {
|
||||
return _("An unknown person");
|
||||
}
|
||||
|
||||
if (isset($organizer[0]['CN'])) {
|
||||
return $organizer[0]['CN'];
|
||||
}
|
||||
|
||||
$organizer = parse_url($this->getAttribute('ORGANIZER'));
|
||||
|
||||
return $organizer['path'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this event with details from another event.
|
||||
*
|
||||
* @param Horde_iCalendar_vEvent $vevent The vEvent with latest details.
|
||||
*/
|
||||
function updateFromvEvent($vevent)
|
||||
{
|
||||
$newAttributes = $vevent->getAllAttributes();
|
||||
foreach ($newAttributes as $newAttribute) {
|
||||
$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']);
|
||||
} else {
|
||||
// Already exists so locate and modify.
|
||||
$found = false;
|
||||
|
||||
// Try matching the attribte name and value incase
|
||||
// only the params changed (eg attendee updating
|
||||
// status).
|
||||
foreach ($this->_attributes as $id => $attr) {
|
||||
if ($attr['name'] == $newAttribute['name'] &&
|
||||
$attr['value'] == $newAttribute['value']) {
|
||||
// merge the params
|
||||
foreach ($newAttribute['params'] as $param_id => $param_name) {
|
||||
$this->_attributes[$id]['params'][$param_id] = $param_name;
|
||||
}
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
// Else match the first attribute with the same
|
||||
// name (eg changing start time).
|
||||
foreach ($this->_attributes as $id => $attr) {
|
||||
if ($attr['name'] == $newAttribute['name']) {
|
||||
$this->_attributes[$id]['value'] = $newAttribute['value'];
|
||||
// Merge the params.
|
||||
foreach ($newAttribute['params'] as $param_id => $param_name) {
|
||||
$this->_attributes[$id]['params'][$param_id] = $param_name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update just the attendess of event with details from another
|
||||
* event.
|
||||
*
|
||||
* @param Horde_iCalendar_vEvent $vevent The vEvent with latest details
|
||||
*/
|
||||
function updateAttendeesFromvEvent($vevent)
|
||||
{
|
||||
$newAttributes = $vevent->getAllAttributes();
|
||||
foreach ($newAttributes as $newAttribute) {
|
||||
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']);
|
||||
} else {
|
||||
// Already exists so locate and modify.
|
||||
$found = false;
|
||||
// Try matching the attribte name and value incase
|
||||
// only the params changed (eg attendee updating
|
||||
// status).
|
||||
foreach ($this->_attributes as $id => $attr) {
|
||||
if ($attr['name'] == $newAttribute['name'] &&
|
||||
$attr['value'] == $newAttribute['value']) {
|
||||
// Merge the params.
|
||||
foreach ($newAttribute['params'] as $param_id => $param_name) {
|
||||
$this->_attributes[$id]['params'][$param_id] = $param_name;
|
||||
}
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
// Else match the first attribute with the same
|
||||
// name (eg changing start time).
|
||||
foreach ($this->_attributes as $id => $attr) {
|
||||
if ($attr['name'] == $newAttribute['name']) {
|
||||
$this->_attributes[$id]['value'] = $newAttribute['value'];
|
||||
// Merge the params.
|
||||
foreach ($newAttribute['params'] as $param_id => $param_name) {
|
||||
$this->_attributes[$id]['params'][$param_id] = $param_name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,459 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class representing vFreebusy components.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vfreebusy.php,v 1.16.10.17 2008/09/17 08:46:57 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.
|
||||
*
|
||||
* @todo Don't use timestamps
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @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';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string containing vFreebusy data.
|
||||
*
|
||||
* @param string $data The data to parse.
|
||||
*/
|
||||
function parsevCalendar($data, $type = null, $charset = null)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VFREEBUSY', $charset);
|
||||
|
||||
// Do something with all the busy periods.
|
||||
foreach ($this->_attributes as $key => $attribute) {
|
||||
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,
|
||||
isset($this->_extraParams[$start])
|
||||
? $this->_extraParams[$start] : array());
|
||||
}
|
||||
|
||||
$res = parent::_exportvData('VFREEBUSY');
|
||||
|
||||
foreach ($this->_attributes as $key => $attribute) {
|
||||
if ($attribute['name'] == 'FREEBUSY') {
|
||||
unset($this->_attributes[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a display name for this object.
|
||||
*
|
||||
* @return string A clear text name for displaying this object.
|
||||
*/
|
||||
function getName()
|
||||
{
|
||||
$name = '';
|
||||
$method = !empty($this->_container) ?
|
||||
$this->_container->getAttribute('METHOD') : 'PUBLISH';
|
||||
|
||||
if (is_a($method, 'PEAR_Error') || $method == 'PUBLISH') {
|
||||
$attr = 'ORGANIZER';
|
||||
} elseif ($method == 'REPLY') {
|
||||
$attr = 'ATTENDEE';
|
||||
}
|
||||
|
||||
$name = $this->getAttribute($attr, true);
|
||||
if (!is_a($name, 'PEAR_Error') && isset($name[0]['CN'])) {
|
||||
return $name[0]['CN'];
|
||||
}
|
||||
|
||||
$name = $this->getAttribute($attr);
|
||||
if (is_a($name, 'PEAR_Error')) {
|
||||
return '';
|
||||
} else {
|
||||
$name = parse_url($name);
|
||||
return $name['path'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the email address for this object.
|
||||
*
|
||||
* @return string The email address of this object's owner.
|
||||
*/
|
||||
function getEmail()
|
||||
{
|
||||
$name = '';
|
||||
$method = !empty($this->_container)
|
||||
? $this->_container->getAttribute('METHOD') : 'PUBLISH';
|
||||
|
||||
if (is_a($method, 'PEAR_Error') || $method == 'PUBLISH') {
|
||||
$attr = 'ORGANIZER';
|
||||
} elseif ($method == 'REPLY') {
|
||||
$attr = 'ATTENDEE';
|
||||
}
|
||||
|
||||
$name = $this->getAttribute($attr);
|
||||
if (is_a($name, 'PEAR_Error')) {
|
||||
return '';
|
||||
} else {
|
||||
$name = parse_url($name);
|
||||
return $name['path'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the busy periods.
|
||||
*
|
||||
* @return array All busy periods.
|
||||
*/
|
||||
function getBusyPeriods()
|
||||
{
|
||||
return $this->_busyPeriods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$this->simplify();
|
||||
$periods = array();
|
||||
|
||||
// Check that we have data for some part of this period.
|
||||
if ($this->getEnd() < $startStamp || $this->getStart() > $endStamp) {
|
||||
return $periods;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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 ($nextstart < $endStamp && $nextstart < $this->getEnd()) {
|
||||
$periods[$nextstart] = min($this->getEnd(), $endStamp);
|
||||
}
|
||||
|
||||
return $periods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
$extra = array())
|
||||
{
|
||||
if ($type == 'FREE') {
|
||||
// Make sure this period is not marked as busy.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the end time if duration was specified.
|
||||
$tempEnd = is_null($duration) ? $end : $start + $duration;
|
||||
|
||||
// Make sure the period length is always positive.
|
||||
$end = max($start, $tempEnd);
|
||||
$start = min($start, $tempEnd);
|
||||
|
||||
if (isset($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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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');
|
||||
} elseif (count($this->_busyPeriods)) {
|
||||
return min(array_keys($this->_busyPeriods));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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');
|
||||
} elseif (count($this->_busyPeriods)) {
|
||||
return max(array_values($this->_busyPeriods));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (!is_a($freebusy, 'Horde_iCalendar_vfreebusy')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$extra = $freebusy->getExtraParams();
|
||||
foreach ($freebusy->getBusyPeriods() as $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, array(), false);
|
||||
} elseif (!is_a($thatattr, 'PEAR_Error')) {
|
||||
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, array(), false);
|
||||
} elseif (!is_a($thatattr, 'PEAR_Error')) {
|
||||
if ($thatattr > $thisattr) {
|
||||
$this->setAttribute('DTEND', $thatattr, array(), false);
|
||||
}
|
||||
}
|
||||
|
||||
if ($simplify) {
|
||||
$this->simplify();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ($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) {
|
||||
// Replace old period if the new period lies around the
|
||||
// old period.
|
||||
if ($start <= $testStart && $end >= $testEnd) {
|
||||
// Remove old period entry.
|
||||
unset($checked[$testStart]);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($checked, $checkedExtra);
|
||||
}
|
||||
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class representing vJournals.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vjournal.php,v 1.8.10.8 2008/07/03 08:42:58 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 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_vjournal extends Horde_iCalendar {
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'vJournal';
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VJOURNAL');
|
||||
}
|
||||
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once EGW_API_INC.'/horde/Horde/iCalendar.php';
|
||||
|
||||
/**
|
||||
* Class representing vNotes.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vnote.php,v 1.3.10.9 2008/07/03 08:42:58 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 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @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';
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike vevent and vtodo, a vnote is normally not enclosed in an
|
||||
* iCalendar container. (BEGIN..END)
|
||||
*/
|
||||
function exportvCalendar()
|
||||
{
|
||||
$requiredAttributes['BODY'] = '';
|
||||
$requiredAttributes['VERSION'] = '1.1';
|
||||
|
||||
foreach ($requiredAttributes as $name => $default_value) {
|
||||
if (is_a($this->getattribute($name), 'PEAR_Error')) {
|
||||
$this->setAttribute($name, $default_value);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_exportvData('VNOTE');
|
||||
}
|
||||
|
||||
}
|
@ -1,254 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class representing vTimezones.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vtimezone.php,v 1.8.10.9 2008/07/03 08:42:58 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 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
* @changes 2010/02/26 Joerg Lehrke <jlehrke@noc.de>: Add RDATE support (for KDE 4.x)
|
||||
*/
|
||||
class Horde_iCalendar_vtimezone extends Horde_iCalendar {
|
||||
|
||||
function getType()
|
||||
{
|
||||
return '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;
|
||||
$rrule_interval = 0; // 0 undefined, 1 yearly, 12 monthly
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
$rdates = $child->getAttribute('RDATE');
|
||||
if (!is_a($rdates, 'PEAR_Error')) {
|
||||
foreach ($rdates as $rdate) {
|
||||
$switch_time = $switch_time['value'];
|
||||
$switch_year = date("Y", $switch_time);
|
||||
if ($switch_year == $year) {
|
||||
$t = getdate($switch_time);
|
||||
$result['time'] = @gmmktime($t['hours'], $t['minutes'], $t['seconds'],
|
||||
$t['mon'], $t['mday'], $t['year']);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
$switch_year = date("Y", $switch_time);
|
||||
if ($switch_year > $year) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rrules = explode(';', $rrules);
|
||||
foreach ($rrules as $rrule) {
|
||||
$t = explode('=', $rrule);
|
||||
switch ($t[0]) {
|
||||
case 'FREQ':
|
||||
switch($t[1]) {
|
||||
case 'YEARLY':
|
||||
if ($rrule_interval == 12) {
|
||||
return false;
|
||||
}
|
||||
$rrule_interval = 1;
|
||||
break;
|
||||
case 'MONTHLY':
|
||||
if ($rrule_interval == 1) {
|
||||
return false;
|
||||
}
|
||||
$rrule_interval = 12;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'INTERVAL':
|
||||
if ($rrule_interval && $t[1] != $rrule_interval) {
|
||||
return false;
|
||||
}
|
||||
$rrule_interval = intval($t[1]);
|
||||
if ($rrule_interval != 1 && $rrule_interval != 12) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'COUNT':
|
||||
if ($switch_year + intval($t[1]) < intval($year)) {
|
||||
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 ($rrule_interval == 12) {
|
||||
$month = date("n", $switch_time);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_standard extends Horde_iCalendar {
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'standard';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'STANDARD');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('STANDARD');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_daylight extends Horde_iCalendar {
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'daylight';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'DAYLIGHT');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('DAYLIGHT');
|
||||
}
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class representing vTodos.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vtodo.php,v 1.13.10.8 2008/07/03 08:42:58 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 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_vtodo extends Horde_iCalendar {
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'vTodo';
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VTODO');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this todo to an array of attributes.
|
||||
*
|
||||
* @return array Array containing the details of the todo in a hash
|
||||
* as used by Horde applications.
|
||||
*/
|
||||
function toArray()
|
||||
{
|
||||
$todo = array();
|
||||
|
||||
$name = $this->getAttribute('SUMMARY');
|
||||
if (!is_array($name) && !is_a($name, 'PEAR_Error')) {
|
||||
$todo['name'] = $name;
|
||||
}
|
||||
$desc = $this->getAttribute('DESCRIPTION');
|
||||
if (!is_array($desc) && !is_a($desc, 'PEAR_Error')) {
|
||||
$todo['desc'] = $desc;
|
||||
}
|
||||
|
||||
$priority = $this->getAttribute('PRIORITY');
|
||||
if (!is_array($priority) && !is_a($priority, 'PEAR_Error')) {
|
||||
$todo['priority'] = $priority;
|
||||
}
|
||||
|
||||
$due = $this->getAttribute('DTSTAMP');
|
||||
if (!is_array($due) && !is_a($due, 'PEAR_Error')) {
|
||||
$todo['due'] = $due;
|
||||
}
|
||||
|
||||
return $todo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attributes for this todo item from an array.
|
||||
*
|
||||
* @param array $todo Array containing the details of the todo in
|
||||
* the same format that toArray() exports.
|
||||
*/
|
||||
function fromArray($todo)
|
||||
{
|
||||
if (isset($todo['name'])) {
|
||||
$this->setAttribute('SUMMARY', $todo['name']);
|
||||
}
|
||||
if (isset($todo['desc'])) {
|
||||
$this->setAttribute('DESCRIPTION', $todo['desc']);
|
||||
}
|
||||
|
||||
if (isset($todo['priority'])) {
|
||||
$this->setAttribute('PRIORITY', $todo['priority']);
|
||||
}
|
||||
|
||||
if (isset($todo['due'])) {
|
||||
$this->setAttribute('DTSTAMP', $todo['due']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,300 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Constants are from Binary XML Content Format Specification Version 1.3, 25
|
||||
* July 2001 found at http://www.wapforum.org
|
||||
*/
|
||||
|
||||
/**
|
||||
* From 7.1 Global Tokens.
|
||||
*/
|
||||
|
||||
define('XML_WBXML_GLOBAL_TOKEN_SWITCH_PAGE', 0); // 0x00
|
||||
define('XML_WBXML_GLOBAL_TOKEN_END', 1); // 0x01
|
||||
define('XML_WBXML_GLOBAL_TOKEN_ENTITY', 2); // 0x02
|
||||
define('XML_WBXML_GLOBAL_TOKEN_STR_I', 3); // 0x03
|
||||
define('XML_WBXML_GLOBAL_TOKEN_LITERAL', 4); // 0x04
|
||||
|
||||
define('XML_WBXML_GLOBAL_TOKEN_EXT_I_0', 64); // 0x40
|
||||
define('XML_WBXML_GLOBAL_TOKEN_EXT_I_1', 65); // 0x41
|
||||
define('XML_WBXML_GLOBAL_TOKEN_EXT_I_2', 66); // 0x42
|
||||
define('XML_WBXML_GLOBAL_TOKEN_PI', 67); // 0x43
|
||||
define('XML_WBXML_GLOBAL_TOKEN_LITERAL_C', 68); // 0x44
|
||||
|
||||
define('XML_WBXML_GLOBAL_TOKEN_EXT_T_0', 128); // 0x80
|
||||
define('XML_WBXML_GLOBAL_TOKEN_EXT_T_1', 129); // 0x81
|
||||
define('XML_WBXML_GLOBAL_TOKEN_EXT_T_2', 130); // 0x82
|
||||
define('XML_WBXML_GLOBAL_TOKEN_STR_T', 131); // 0x83
|
||||
define('XML_WBXML_GLOBAL_TOKEN_LITERAL_A', 132); // 0x84
|
||||
|
||||
define('XML_WBXML_GLOBAL_TOKEN_EXT_0', 192); // 0xC0
|
||||
define('XML_WBXML_GLOBAL_TOKEN_EXT_1', 193); // 0xC1
|
||||
define('XML_WBXML_GLOBAL_TOKEN_EXT_2', 194); // 0xC2
|
||||
define('XML_WBXML_GLOBAL_TOKEN_OPAQUE', 195); // 0xC3
|
||||
define('XML_WBXML_GLOBAL_TOKEN_LITERAL_AC', 196); // 0xC4
|
||||
|
||||
/**
|
||||
* Not sure where defined.
|
||||
* ADD CHAPTER
|
||||
*/
|
||||
define('DPI_DTD_WML_1_0', '-//WAPFORUM//DTD WML 1.0//EN');
|
||||
define('DPI_DTD_WTA_1_0', '-//WAPFORUM//DTD WTA 1.0//EN');
|
||||
define('DPI_DTD_WML_1_1', '-//WAPFORUM//DTD WML 1.1//EN');
|
||||
define('DPI_DTD_SI_1_1', '-//WAPFORUM//DTD SI 1.1//EN');
|
||||
define('DPI_DTD_SL_1_0', '-//WAPFORUM//DTD SL 1.0//EN');
|
||||
define('DPI_DTD_CO_1_0', '-//WAPFORUM//DTD CO 1.0//EN');
|
||||
define('DPI_DTD_CHANNEL_1_1', '-//WAPFORUM//DTD CHANNEL 1.1//EN');
|
||||
define('DPI_DTD_WML_1_2', '-//WAPFORUM//DTD WML 1.2//EN');
|
||||
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.
|
||||
*/
|
||||
define('CHARSET_US_ASCII', 'US-ASCII');
|
||||
define('CHARSET_ISO_8859_1', 'ISO-8859-1');
|
||||
define('CHARSET_UTF_8', 'UTF-8');
|
||||
define('CHARSET_UTF_16BE', 'UTF-16BE');
|
||||
define('CHARSET_UTF_16LE', 'UTF-16LE');
|
||||
define('CHARSET_UTF_16', 'UTF-16');
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML.php,v 1.13.12.11 2008/01/02 11:31:02 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 {
|
||||
|
||||
/**
|
||||
* Decoding Multi-byte Integers from Section 5.1
|
||||
*
|
||||
* Use long because it is unsigned.
|
||||
*/
|
||||
function MBUInt32ToInt($in, &$pos)
|
||||
{
|
||||
$val = 0;
|
||||
|
||||
do {
|
||||
$b = ord($in[$pos++]);
|
||||
$val <<= 7; // Bitshift left 7 bits.
|
||||
$val += ($b & 127);
|
||||
} while (($b & 128) != 0);
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoding Multi-byte Integers from Section 5.1
|
||||
*/
|
||||
function intToMBUInt32(&$out, $i)
|
||||
{
|
||||
if ($i > 268435455) {
|
||||
$bytes0 = 0 | XML_WBXML::getBits(0, $i);
|
||||
$bytes1 = 128 | XML_WBXML::getBits(1, $i);
|
||||
$bytes2 = 128 | XML_WBXML::getBits(2, $i);
|
||||
$bytes3 = 128 | XML_WBXML::getBits(3, $i);
|
||||
$bytes4 = 128 | XML_WBXML::getBits(4, $i);
|
||||
|
||||
$out .= chr($bytes4) . chr($bytes3) . chr($bytes2) . chr($bytes1) . chr($bytes0);
|
||||
} elseif ($i > 2097151) {
|
||||
$bytes0 = 0 | XML_WBXML::getBits(0, $i);
|
||||
$bytes1 = 128 | XML_WBXML::getBits(1, $i);
|
||||
$bytes2 = 128 | XML_WBXML::getBits(2, $i);
|
||||
$bytes3 = 128 | XML_WBXML::getBits(3, $i);
|
||||
|
||||
$out .= chr($bytes3) . chr($bytes2) . chr($bytes1) . chr($bytes0);
|
||||
} elseif ($i > 16383) {
|
||||
$bytes0 = 0 | XML_WBXML::getBits(0, $i);
|
||||
$bytes1 = 128 | XML_WBXML::getBits(1, $i);
|
||||
$bytes2 = 128 | XML_WBXML::getBits(2, $i);
|
||||
|
||||
$out .= chr($bytes2) . chr($bytes1) . chr($bytes0);
|
||||
} elseif ($i > 127) {
|
||||
$bytes0 = 0 | XML_WBXML::getBits(0, $i);
|
||||
$bytes1 = 128 | XML_WBXML::getBits(1, $i);
|
||||
|
||||
$out .= chr($bytes1) . chr($bytes0);
|
||||
} else {
|
||||
$bytes0 = 0 | XML_WBXML::getBits(0, $i);
|
||||
|
||||
$out .= chr($bytes0);
|
||||
}
|
||||
}
|
||||
|
||||
function getBits($num, $l)
|
||||
{
|
||||
switch ($num) {
|
||||
case 0:
|
||||
return $l & 127; // 0x7F
|
||||
|
||||
case 1:
|
||||
return ($l >> 7) & 127; // 0x7F
|
||||
|
||||
case 2:
|
||||
return ($l >> 14) & 127; // 0x7F
|
||||
|
||||
case 3:
|
||||
return ($l >> 21) & 127; // 0x7F
|
||||
|
||||
case 4:
|
||||
return ($l >> 28) & 127; // 0x7F
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getDPIString($i)
|
||||
{
|
||||
/**
|
||||
* ADD CHAPTER
|
||||
*/
|
||||
$DPIString = array(2 => DPI_DTD_WML_1_0,
|
||||
3 => DPI_DTD_WTA_1_0,
|
||||
4 => DPI_DTD_WML_1_1,
|
||||
5 => DPI_DTD_SI_1_1,
|
||||
6 => DPI_DTD_SL_1_0,
|
||||
7 => DPI_DTD_CO_1_0,
|
||||
8 => DPI_DTD_CHANNEL_1_1,
|
||||
9 => DPI_DTD_WML_1_2,
|
||||
10 => DPI_DTD_WML_1_3,
|
||||
11 => DPI_DTD_PROV_1_0,
|
||||
12 => DPI_DTD_WTA_WML_1_2,
|
||||
13 => DPI_DTD_CHANNEL_1_2,
|
||||
|
||||
// Not all SyncML clients know this, so we
|
||||
// should use the string table.
|
||||
// 0xFD1 => DPI_DTD_SYNCML_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;
|
||||
}
|
||||
|
||||
function getDPIInt($dpi)
|
||||
{
|
||||
/**
|
||||
* ADD CHAPTER
|
||||
*/
|
||||
$DPIInt = array(DPI_DTD_WML_1_0 => 2,
|
||||
DPI_DTD_WTA_1_0 => 3,
|
||||
DPI_DTD_WML_1_1 => 4,
|
||||
DPI_DTD_SI_1_1 => 5,
|
||||
DPI_DTD_SL_1_0 => 6,
|
||||
DPI_DTD_CO_1_0 => 7,
|
||||
DPI_DTD_CHANNEL_1_1 => 8,
|
||||
DPI_DTD_WML_1_2 => 9,
|
||||
DPI_DTD_WML_1_3 => 10,
|
||||
DPI_DTD_PROV_1_0 => 11,
|
||||
DPI_DTD_WTA_WML_1_2 => 12,
|
||||
DPI_DTD_CHANNEL_1_2 => 13,
|
||||
|
||||
// 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,
|
||||
);
|
||||
|
||||
return isset($DPIInt[$dpi]) ? $DPIInt[$dpi] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character encoding.
|
||||
* only default character encodings from J2SE are supported
|
||||
* from http://www.iana.org/assignments/character-sets
|
||||
* and http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Charset.html
|
||||
*/
|
||||
function getCharsetString($cs)
|
||||
{
|
||||
/**
|
||||
* From http://www.iana.org/assignments/character-sets
|
||||
*/
|
||||
$charsetString = array(3 => 'US-ASCII',
|
||||
4 => 'ISO-8859-1',
|
||||
106 => 'UTF-8',
|
||||
1013 => 'UTF-16BE',
|
||||
1014 => 'UTF-16LE',
|
||||
1015 => 'UTF-16');
|
||||
|
||||
return isset($charsetString[$cs]) ? $charsetString[$cs] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character encoding.
|
||||
*
|
||||
* Only default character encodings from J2SE are supported.
|
||||
*
|
||||
* From http://www.iana.org/assignments/character-sets and
|
||||
* http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Charset.html
|
||||
*/
|
||||
function getCharsetInt($cs)
|
||||
{
|
||||
/**
|
||||
* From http://www.iana.org/assignments/character-sets
|
||||
*/
|
||||
$charsetInt = array('US-ASCII' => 3,
|
||||
'ISO-8859-1' => 4,
|
||||
'UTF-8' => 106,
|
||||
'UTF-16BE' => 1013,
|
||||
'UTF-16LE' => 1014,
|
||||
'UTF-16' => 1015);
|
||||
|
||||
return isset($charsetInt[$cs]) ? $charsetInt[$cs] : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_HashTable {
|
||||
|
||||
var $_h;
|
||||
|
||||
function set($k, $v)
|
||||
{
|
||||
$this->_h[$k] = $v;
|
||||
}
|
||||
|
||||
function get($k)
|
||||
{
|
||||
return isset($this->_h[$k]) ? $this->_h[$k] : null;
|
||||
}
|
||||
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
var $_currentUri;
|
||||
var $_output = '';
|
||||
|
||||
var $_opaqueHandler;
|
||||
|
||||
/**
|
||||
* Charset.
|
||||
*/
|
||||
var $_charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* WBXML Version.
|
||||
* 0, 1 or 2 supported
|
||||
*/
|
||||
var $_wbxmlVersion = 2;
|
||||
|
||||
function XML_WBXML_ContentHandler()
|
||||
{
|
||||
$this->_currentUri = new XML_WBXML_LifoQueue();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function raiseError($error)
|
||||
{
|
||||
if (!class_exists('PEAR')) {
|
||||
require 'PEAR.php';
|
||||
}
|
||||
return PEAR::raiseError($error);
|
||||
}
|
||||
|
||||
function getCharsetStr()
|
||||
{
|
||||
return $this->_charset;
|
||||
}
|
||||
|
||||
function setCharset($cs)
|
||||
{
|
||||
$this->_charset = $cs;
|
||||
}
|
||||
|
||||
function getVersion()
|
||||
{
|
||||
return $this->_wbxmlVersion;
|
||||
}
|
||||
|
||||
function setVersion($v)
|
||||
{
|
||||
$this->_wbxmlVersion = $v;
|
||||
}
|
||||
|
||||
function getOutput()
|
||||
{
|
||||
return $this->_output;
|
||||
}
|
||||
|
||||
function getOutputSize()
|
||||
{
|
||||
return strlen($this->_output);
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs = array())
|
||||
{
|
||||
$this->_output .= '<' . $element;
|
||||
|
||||
$currentUri = $this->_currentUri->top();
|
||||
|
||||
if (((!$currentUri) || ($currentUri != $uri)) && $uri) {
|
||||
$this->_output .= ' xmlns="' . $uri . '"';
|
||||
}
|
||||
|
||||
$this->_currentUri->push($uri);
|
||||
|
||||
foreach ($attrs as $attr) {
|
||||
$this->_output .= ' ' . $attr['attribute'] . '="' . $attr['value'] . '"';
|
||||
}
|
||||
|
||||
$this->_output .= '>';
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
$this->_output .= '</' . $element . '>';
|
||||
|
||||
$this->_currentUri->pop();
|
||||
}
|
||||
|
||||
function characters($str)
|
||||
{
|
||||
$this->_output .= $str;
|
||||
}
|
||||
|
||||
function opaque($o)
|
||||
{
|
||||
$this->_output .= $o;
|
||||
}
|
||||
|
||||
function setOpaqueHandler($opaqueHandler)
|
||||
{
|
||||
$this->_opaqueHandler = $opaqueHandler;
|
||||
}
|
||||
|
||||
function removeOpaqueHandler()
|
||||
{
|
||||
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 {
|
||||
|
||||
var $_queue = array();
|
||||
|
||||
function XML_WBXML_LifoQueue()
|
||||
{
|
||||
}
|
||||
|
||||
function push($obj)
|
||||
{
|
||||
$this->_queue[] = $obj;
|
||||
}
|
||||
|
||||
function pop()
|
||||
{
|
||||
if (count($this->_queue)) {
|
||||
return array_pop($this->_queue);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function top()
|
||||
{
|
||||
if ($count = count($this->_queue)) {
|
||||
return $this->_queue[$count - 1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD.php,v 1.6.12.8 2008/01/02 11:31:02 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 {
|
||||
|
||||
var $version;
|
||||
var $intTags;
|
||||
var $intAttributes;
|
||||
var $strTags;
|
||||
var $strAttributes;
|
||||
var $intCodePages;
|
||||
var $strCodePages;
|
||||
var $strCodePagesURI;
|
||||
var $URI;
|
||||
var $XMLNS;
|
||||
var $DPI;
|
||||
|
||||
function XML_WBXML_DTD($v)
|
||||
{
|
||||
$this->version = $v;
|
||||
$this->init();
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
}
|
||||
|
||||
function setAttribute($intAttribute, $strAttribute)
|
||||
{
|
||||
$this->strAttributes[$strAttribute] = $intAttribute;
|
||||
$this->intAttributes[$intAttribute] = $strAttribute;
|
||||
}
|
||||
|
||||
function setTag($intTag, $strTag)
|
||||
{
|
||||
$this->strTags[$strTag] = $intTag;
|
||||
$this->intTags[$intTag] = $strTag;
|
||||
}
|
||||
|
||||
function setCodePage($intCodePage, $strCodePage, $strCodePageURI)
|
||||
{
|
||||
$this->strCodePagesURI[$strCodePageURI] = $intCodePage;
|
||||
$this->strCodePages[$strCodePage] = $intCodePage;
|
||||
$this->intCodePages[$intCodePage] = $strCodePage;
|
||||
}
|
||||
|
||||
function toTagStr($tag)
|
||||
{
|
||||
return isset($this->intTags[$tag]) ? $this->intTags[$tag] : false;
|
||||
}
|
||||
|
||||
function toAttributeStr($attribute)
|
||||
{
|
||||
return isset($this->intTags[$attribute]) ? $this->intTags[$attribute] : false;
|
||||
}
|
||||
|
||||
function toCodePageStr($codePage)
|
||||
{
|
||||
return isset($this->intCodePages[$codePage]) ? $this->intCodePages[$codePage] : false;
|
||||
}
|
||||
|
||||
function toTagInt($tag)
|
||||
{
|
||||
return isset($this->strTags[$tag]) ? $this->strTags[$tag] : false;
|
||||
}
|
||||
|
||||
function toAttributeInt($attribute)
|
||||
{
|
||||
return isset($this->strAttributes[$attribute]) ? $this->strAttributes[$attribute] : false;
|
||||
}
|
||||
|
||||
function toCodePageInt($codePage)
|
||||
{
|
||||
return isset($this->strCodePages[$codePage]) ? $this->strCodePages[$codePage] : false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for property version.
|
||||
* @return Value of property version.
|
||||
*/
|
||||
function getVersion()
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property version.
|
||||
* @param integer $v New value of property version.
|
||||
*/
|
||||
function setVersion($v)
|
||||
{
|
||||
$this->version = $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for property URI.
|
||||
* @return Value of property URI.
|
||||
*/
|
||||
function getURI()
|
||||
{
|
||||
return $this->URI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property URI.
|
||||
* @param string $u New value of property URI.
|
||||
*/
|
||||
function setURI($u)
|
||||
{
|
||||
$this->URI = $u;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for property DPI.
|
||||
* @return Value of property DPI.
|
||||
*/
|
||||
function getDPI()
|
||||
{
|
||||
return $this->DPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property DPI.
|
||||
* @param DPI New value of property DPI.
|
||||
*/
|
||||
function setDPI($d)
|
||||
{
|
||||
$this->DPI = $d;
|
||||
}
|
||||
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
<?php
|
||||
|
||||
include_once 'XML/WBXML/DTD.php';
|
||||
|
||||
/**
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncML.php,v 1.6.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_SyncML extends XML_WBXML_DTD {
|
||||
|
||||
function init()
|
||||
{
|
||||
/* this code table has been extracted from libwbxml
|
||||
* (see http://libwbxml.aymerick.com/) by using
|
||||
*
|
||||
* grep '\"[^\"]*\", *0x.., 0x.. },' wbxml_tables.c
|
||||
* | sed -e 's#^.*\"\([^\"]*\)\", *\(0x..\), \(0x..\) },.*$# \$this->setTag\(\3, \"\1\"\); // \2#g'
|
||||
*/
|
||||
|
||||
$this->setTag(0x05, "Add"); // 0x00
|
||||
$this->setTag(0x06, "Alert"); // 0x00
|
||||
$this->setTag(0x07, "Archive"); // 0x00
|
||||
$this->setTag(0x08, "Atomic"); // 0x00
|
||||
$this->setTag(0x09, "Chal"); // 0x00
|
||||
$this->setTag(0x0a, "Cmd"); // 0x00
|
||||
$this->setTag(0x0b, "CmdID"); // 0x00
|
||||
$this->setTag(0x0c, "CmdRef"); // 0x00
|
||||
$this->setTag(0x0d, "Copy"); // 0x00
|
||||
$this->setTag(0x0e, "Cred"); // 0x00
|
||||
$this->setTag(0x0f, "Data"); // 0x00
|
||||
$this->setTag(0x10, "Delete"); // 0x00
|
||||
$this->setTag(0x11, "Exec"); // 0x00
|
||||
$this->setTag(0x12, "Final"); // 0x00
|
||||
$this->setTag(0x13, "Get"); // 0x00
|
||||
$this->setTag(0x14, "Item"); // 0x00
|
||||
$this->setTag(0x15, "Lang"); // 0x00
|
||||
$this->setTag(0x16, "LocName"); // 0x00
|
||||
$this->setTag(0x17, "LocURI"); // 0x00
|
||||
$this->setTag(0x18, "Map"); // 0x00
|
||||
$this->setTag(0x19, "MapItem"); // 0x00
|
||||
$this->setTag(0x1a, "Meta"); // 0x00
|
||||
$this->setTag(0x1b, "MsgID"); // 0x00
|
||||
$this->setTag(0x1c, "MsgRef"); // 0x00
|
||||
$this->setTag(0x1d, "NoResp"); // 0x00
|
||||
$this->setTag(0x1e, "NoResults"); // 0x00
|
||||
$this->setTag(0x1f, "Put"); // 0x00
|
||||
$this->setTag(0x20, "Replace"); // 0x00
|
||||
$this->setTag(0x21, "RespURI"); // 0x00
|
||||
$this->setTag(0x22, "Results"); // 0x00
|
||||
$this->setTag(0x23, "Search"); // 0x00
|
||||
$this->setTag(0x24, "Sequence"); // 0x00
|
||||
$this->setTag(0x25, "SessionID"); // 0x00
|
||||
$this->setTag(0x26, "SftDel"); // 0x00
|
||||
$this->setTag(0x27, "Source"); // 0x00
|
||||
$this->setTag(0x28, "SourceRef"); // 0x00
|
||||
$this->setTag(0x29, "Status"); // 0x00
|
||||
$this->setTag(0x2a, "Sync"); // 0x00
|
||||
$this->setTag(0x2b, "SyncBody"); // 0x00
|
||||
$this->setTag(0x2c, "SyncHdr"); // 0x00
|
||||
$this->setTag(0x2d, "SyncML"); // 0x00
|
||||
$this->setTag(0x2e, "Target"); // 0x00
|
||||
$this->setTag(0x2f, "TargetRef"); // 0x00
|
||||
$this->setTag(0x30, "Reserved for future use"); // 0x00
|
||||
$this->setTag(0x31, "VerDTD"); // 0x00
|
||||
$this->setTag(0x32, "VerProto"); // 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 == 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');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
include_once 'XML/WBXML/DTD.php';
|
||||
|
||||
/**
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* $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 {
|
||||
|
||||
function init()
|
||||
{
|
||||
/* this code table has been extracted from libwbxml
|
||||
* (see http://libwbxml.aymerick.com/) by using
|
||||
*
|
||||
* grep '\"[^\"]*\", *0x.., 0x.. },' wbxml_tables.c
|
||||
* | 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
|
||||
$this->setTag(0x08, "DataType"); // 0x00
|
||||
$this->setTag(0x09, "DevID"); // 0x00
|
||||
$this->setTag(0x0a, "DevInf"); // 0x00
|
||||
$this->setTag(0x0b, "DevTyp"); // 0x00
|
||||
$this->setTag(0x0c, "DisplayName"); // 0x00
|
||||
$this->setTag(0x0d, "DSMem"); // 0x00
|
||||
$this->setTag(0x0e, "Ext"); // 0x00
|
||||
$this->setTag(0x0f, "FwV"); // 0x00
|
||||
$this->setTag(0x10, "HwV"); // 0x00
|
||||
$this->setTag(0x11, "Man"); // 0x00
|
||||
$this->setTag(0x12, "MaxGUIDSize"); // 0x00
|
||||
$this->setTag(0x13, "MaxID"); // 0x00
|
||||
$this->setTag(0x14, "MaxMem"); // 0x00
|
||||
$this->setTag(0x15, "Mod"); // 0x00
|
||||
$this->setTag(0x16, "OEM"); // 0x00
|
||||
$this->setTag(0x17, "ParamName"); // 0x00
|
||||
$this->setTag(0x18, "PropName"); // 0x00
|
||||
$this->setTag(0x19, "Rx"); // 0x00
|
||||
$this->setTag(0x1a, "Rx-Pref"); // 0x00
|
||||
$this->setTag(0x1b, "SharedMem"); // 0x00
|
||||
$this->setTag(0x1c, "Size"); // 0x00
|
||||
$this->setTag(0x1d, "SourceRef"); // 0x00
|
||||
$this->setTag(0x1e, "SwV"); // 0x00
|
||||
$this->setTag(0x1f, "SyncCap"); // 0x00
|
||||
$this->setTag(0x20, "SyncType"); // 0x00
|
||||
$this->setTag(0x21, "Tx"); // 0x00
|
||||
$this->setTag(0x22, "Tx-Pref"); // 0x00
|
||||
$this->setTag(0x23, "ValEnum"); // 0x00
|
||||
$this->setTag(0x24, "VerCT"); // 0x00
|
||||
$this->setTag(0x25, "VerDTD"); // 0x00
|
||||
$this->setTag(0x26, "XNam"); // 0x00
|
||||
$this->setTag(0x27, "XVal"); // 0x00
|
||||
$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 == 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');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
include_once 'XML/WBXML/DTD.php';
|
||||
|
||||
/**
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* $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 {
|
||||
|
||||
function init()
|
||||
{
|
||||
/* this code table has been extracted from libwbxml
|
||||
* (see http://libwbxml.aymerick.com/) by using
|
||||
*
|
||||
* grep '\"[^\"]*\", *0x.., 0x.. },' wbxml_tables.c
|
||||
* | sed -e 's#^.*\"\([^\"]*\)\", *\(0x..\), \(0x..\) },.*$# \$this->setTag\(\3, \"\1\"\); // \2#g'
|
||||
*/
|
||||
|
||||
$this->setTag(0x05, "Anchor"); // 0x01
|
||||
$this->setTag(0x06, "EMI"); // 0x01
|
||||
$this->setTag(0x07, "Format"); // 0x01
|
||||
$this->setTag(0x08, "FreeID"); // 0x01
|
||||
$this->setTag(0x09, "FreeMem"); // 0x01
|
||||
$this->setTag(0x0a, "Last"); // 0x01
|
||||
$this->setTag(0x0b, "Mark"); // 0x01
|
||||
$this->setTag(0x0c, "MaxMsgSize"); // 0x01
|
||||
$this->setTag(0x15, "MaxObjSize"); // 0x01
|
||||
$this->setTag(0x0d, "Mem"); // 0x01
|
||||
$this->setTag(0x0e, "MetInf"); // 0x01
|
||||
$this->setTag(0x0f, "Next"); // 0x01
|
||||
$this->setTag(0x10, "NextNonce"); // 0x01
|
||||
$this->setTag(0x11, "SharedMem"); // 0x01
|
||||
$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 == 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');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
<?php
|
||||
|
||||
include_once 'XML/WBXML/DTD/SyncML.php';
|
||||
include_once 'XML/WBXML/DTD/SyncMLMetInf.php';
|
||||
include_once 'XML/WBXML/DTD/SyncMLDevInf.php';
|
||||
|
||||
/**
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTDManager.php,v 1.3.12.14 2008/01/02 11:31:02 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_DTDManager {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
var $_strDTD = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
var $_strDTDURI = array();
|
||||
|
||||
/**
|
||||
*/
|
||||
function XML_WBXML_DTDManager()
|
||||
{
|
||||
$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(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(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)
|
||||
{
|
||||
$publicIdentifier = strtolower($publicIdentifier);
|
||||
if (isset($this->_strDTD[$publicIdentifier])) {
|
||||
$dtd = &$this->_strDTD[$publicIdentifier];
|
||||
} else {
|
||||
$dtd = null;
|
||||
}
|
||||
return $dtd;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function &getInstanceURI($uri)
|
||||
{
|
||||
$uri = strtolower($uri);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
@ -1,688 +0,0 @@
|
||||
<?php
|
||||
|
||||
include_once 'XML/WBXML.php';
|
||||
include_once 'XML/WBXML/DTDManager.php';
|
||||
include_once 'XML/WBXML/ContentHandler.php';
|
||||
|
||||
/**
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* $Horde: framework/XML_WBXML/WBXML/Decoder.php,v 1.22.10.11 2008/01/02 11:31:02 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_Decoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
/**
|
||||
* Document Public Identifier type
|
||||
* 1 mb_u_int32 well known type
|
||||
* 2 string table
|
||||
* from spec but converted into a string.
|
||||
*
|
||||
* Document Public Identifier
|
||||
* Used with dpiType.
|
||||
*/
|
||||
var $_dpi;
|
||||
|
||||
/**
|
||||
* String table as defined in 5.7
|
||||
*/
|
||||
var $_stringTable = array();
|
||||
|
||||
/**
|
||||
* Content handler.
|
||||
* Currently just outputs raw XML.
|
||||
*/
|
||||
var $_ch;
|
||||
|
||||
var $_tagDTD;
|
||||
|
||||
var $_prevAttributeDTD;
|
||||
|
||||
var $_attributeDTD;
|
||||
|
||||
/**
|
||||
* State variables.
|
||||
*/
|
||||
var $_tagStack = array();
|
||||
var $_isAttribute;
|
||||
var $_isData = false;
|
||||
|
||||
var $_error = false;
|
||||
|
||||
/**
|
||||
* The DTD Manager.
|
||||
*
|
||||
* @var XML_WBXML_DTDManager
|
||||
*/
|
||||
var $_dtdManager;
|
||||
|
||||
/**
|
||||
* The string position.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_strpos;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
function XML_WBXML_Decoder()
|
||||
{
|
||||
$this->_dtdManager = new XML_WBXML_DTDManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the contentHandler that will receive the output of the
|
||||
* decoding.
|
||||
*
|
||||
* @param XML_WBXML_ContentHandler $ch The contentHandler
|
||||
*/
|
||||
function setContentHandler(&$ch)
|
||||
{
|
||||
$this->_ch = &$ch;
|
||||
}
|
||||
/**
|
||||
* Return one byte from the input stream.
|
||||
*
|
||||
* @param string $input The WBXML input string.
|
||||
*/
|
||||
function getByte($input)
|
||||
{
|
||||
$value = $input{$this->_strpos++};
|
||||
$value = ord($value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a WBXML input document and returns decoded XML.
|
||||
* However the preferred and more effecient method is to
|
||||
* use decode() rather than decodeToString() and have an
|
||||
* appropriate contentHandler deal with the decoded data.
|
||||
*
|
||||
* @param string $wbxml The WBXML document to decode.
|
||||
*
|
||||
* @return string The decoded XML document.
|
||||
*/
|
||||
function decodeToString($wbxml)
|
||||
{
|
||||
$this->_ch = new XML_WBXML_ContentHandler();
|
||||
|
||||
$r = $this->decode($wbxml);
|
||||
if (is_a($r, 'PEAR_Error')) {
|
||||
return $r;
|
||||
}
|
||||
return $this->_ch->getOutput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a WBXML input document and decodes it.
|
||||
* Decoding result is directly passed to the contentHandler.
|
||||
* A contenthandler must be set using setContentHandler
|
||||
* prior to invocation of this method
|
||||
*
|
||||
* @param string $wbxml The WBXML document to decode.
|
||||
*
|
||||
* @return mixed True on success or PEAR_Error.
|
||||
*/
|
||||
function decode($wbxml)
|
||||
{
|
||||
$this->_error = false; // reset state
|
||||
|
||||
$this->_strpos = 0;
|
||||
|
||||
if (empty($this->_ch)) {
|
||||
return $this->raiseError('No Contenthandler defined.');
|
||||
}
|
||||
|
||||
// Get Version Number from Section 5.4
|
||||
// version = u_int8
|
||||
// currently 0, 1 or 2
|
||||
$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)
|
||||
// zero = u_int8
|
||||
// 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
|
||||
$this->retrieveStringTable($wbxml);
|
||||
|
||||
// Get Document Public Idetifier from Section 5.5.
|
||||
$this->_dpi = $this->getDocumentPublicIdentifierImpl($dpiStruct['dpiType'],
|
||||
$dpiStruct['dpiNumber']);
|
||||
#$this->_stringTable);
|
||||
|
||||
// Now the real fun begins.
|
||||
// From Sections 5.2 and 5.8
|
||||
|
||||
|
||||
// Default content handler.
|
||||
$this->_dtdManager = new XML_WBXML_DTDManager();
|
||||
|
||||
// Get the starting DTD.
|
||||
$this->_tagDTD = $this->_dtdManager->getInstance($this->_dpi);
|
||||
|
||||
if (!$this->_tagDTD) {
|
||||
return $this->raiseError('No DTD found for '
|
||||
. $this->_dpi . '/'
|
||||
. $dpiStruct['dpiNumber']);
|
||||
}
|
||||
|
||||
$this->_attributeDTD = $this->_tagDTD;
|
||||
|
||||
while (empty($this->_error) && $this->_strpos < strlen($wbxml)) {
|
||||
$this->_decode($wbxml);
|
||||
}
|
||||
if (!empty($this->_error)) {
|
||||
return $this->_error;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getVersionNumber($input)
|
||||
{
|
||||
return $this->getByte($input);
|
||||
}
|
||||
|
||||
function getDocumentPublicIdentifier($input)
|
||||
{
|
||||
$i = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
|
||||
if ($i == 0) {
|
||||
return array('dpiType' => 2,
|
||||
'dpiNumber' => $this->getByte($input));
|
||||
} else {
|
||||
return array('dpiType' => 1,
|
||||
'dpiNumber' => $i);
|
||||
}
|
||||
}
|
||||
|
||||
function getDocumentPublicIdentifierImpl($dpiType, $dpiNumber)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character encoding. Only default character
|
||||
* encodings from J2SE are supported. From
|
||||
* http://www.iana.org/assignments/character-sets and
|
||||
* http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Charset.html
|
||||
*/
|
||||
function getCharset($input)
|
||||
{
|
||||
$cs = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
return XML_WBXML::getCharsetString($cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* starting position of the (null terminated)
|
||||
* string in this table.
|
||||
*/
|
||||
function retrieveStringTable($input)
|
||||
{
|
||||
$size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
$this->_stringTable = $this->_substr($input, $this->_strpos, $size);
|
||||
$this->_strpos += $size;
|
||||
// print "stringtable($size):" . $this->_stringTable ."\n";
|
||||
}
|
||||
|
||||
function getStringTableEntry($index)
|
||||
{
|
||||
if ($index >= strlen($this->_stringTable)) {
|
||||
$this->_error =
|
||||
$this->raiseError('Invalid offset ' . $index
|
||||
. ' value encountered around position '
|
||||
. $this->_strpos
|
||||
. '. Broken wbxml?');
|
||||
return '';
|
||||
}
|
||||
|
||||
// copy of method termstr but without modification of this->_strpos
|
||||
|
||||
$str = '#'; // must start with nonempty string to allow array access
|
||||
|
||||
$i = 0;
|
||||
$ch = $this->_stringTable[$index++];
|
||||
if (ord($ch) == 0) {
|
||||
return ''; // don't return '#'
|
||||
}
|
||||
|
||||
while (ord($ch) != 0) {
|
||||
$str[$i++] = $ch;
|
||||
if ($index >= strlen($this->_stringTable)) {
|
||||
break;
|
||||
}
|
||||
$ch = $this->_stringTable[$index++];
|
||||
}
|
||||
// print "string table entry: $str\n";
|
||||
return $str;
|
||||
|
||||
}
|
||||
|
||||
function _decode($input)
|
||||
{
|
||||
$token = $this->getByte($input);
|
||||
$str = '';
|
||||
|
||||
// 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:
|
||||
// Section 5.8.4.1
|
||||
$str = $this->termstr($input);
|
||||
$this->_ch->characters($str);
|
||||
// print "str:$str\n"; // @TODO Remove debug code
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_STR_T:
|
||||
// Section 5.8.4.1
|
||||
$x = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
$str = $this->getStringTableEntry($x);
|
||||
$this->_ch->characters($str);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_I_0:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_I_1:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_I_2:
|
||||
// Section 5.8.4.2
|
||||
$str = $this->termstr($input);
|
||||
$this->_ch->characters($str);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_T_0:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_T_1:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_T_2:
|
||||
// Section 5.8.4.2
|
||||
$str = $this->getStringTableEnty(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
$this->_ch->characters($str);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_0:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_1:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_2:
|
||||
// Section 5.8.4.2
|
||||
$extension = $this->getByte($input);
|
||||
$this->_ch->characters($extension);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_ENTITY:
|
||||
// Section 5.8.4.3
|
||||
// UCS-4 chracter encoding?
|
||||
$entity = $this->entity(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
|
||||
$this->_ch->characters('&#' . $entity . ';');
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_PI:
|
||||
// Section 5.8.4.4
|
||||
// throw new IOException
|
||||
// die("WBXML global token processing instruction(PI, " + token + ") is unsupported!\n");
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_LITERAL:
|
||||
// Section 5.8.4.5
|
||||
$str = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
$this->parseTag($input, $str, false, false);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_LITERAL_A:
|
||||
// Section 5.8.4.5
|
||||
$str = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
$this->parseTag($input, $str, true, false);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_LITERAL_AC:
|
||||
// Section 5.8.4.5
|
||||
$str = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
$this->parseTag($input, $string, true, true);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_LITERAL_C:
|
||||
// Section 5.8.4.5
|
||||
$str = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
$this->parseTag($input, $str, false, true);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_OPAQUE:
|
||||
// Section 5.8.4.6
|
||||
$size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
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.
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
// 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) {
|
||||
// ((OpaqueContentHandler)contentHandler).opaque(b);
|
||||
// } else {
|
||||
// String str = new String(b, 0, size, charset);
|
||||
// char[] chars = str.toCharArray();
|
||||
|
||||
// contentHandler.characters(chars, 0, chars.length);
|
||||
// }
|
||||
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_END:
|
||||
// Section 5.8.4.7.1
|
||||
$str = $this->endTag();
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_SWITCH_PAGE:
|
||||
// Section 5.8.4.7.2
|
||||
$codePage = $this->getByte($input);
|
||||
// print "switch to codepage $codePage\n"; // @todo: remove debug code
|
||||
$this->switchElementCodePage($codePage);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Section 5.8.2
|
||||
// Section 5.8.3
|
||||
$hasAttributes = (($token & 0x80) != 0);
|
||||
$hasContent = (($token & 0x40) != 0);
|
||||
$realToken = $token & 0x3F;
|
||||
$str = $this->getTag($realToken);
|
||||
|
||||
// print "element:$str\n"; // @TODO Remove debug code
|
||||
$this->parseTag($input, $str, $hasAttributes, $hasContent);
|
||||
|
||||
if ($realToken == 0x0f) {
|
||||
// store if we're inside a Data tag. This may contain
|
||||
// an additional enclosed wbxml document on which we have
|
||||
// to run a seperate encoder
|
||||
$this->_isData = true;
|
||||
} else {
|
||||
$this->_isData = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function parseTag($input, $tag, $hasAttributes, $hasContent)
|
||||
{
|
||||
$attrs = array();
|
||||
if ($hasAttributes) {
|
||||
$attrs = $this->getAttributes($input);
|
||||
}
|
||||
|
||||
$this->_ch->startElement($this->getCurrentURI(), $tag, $attrs);
|
||||
|
||||
if ($hasContent) {
|
||||
// FIXME I forgot what does this does. Not sure if this is
|
||||
// right?
|
||||
$this->_tagStack[] = $tag;
|
||||
} else {
|
||||
$this->_ch->endElement($this->getCurrentURI(), $tag);
|
||||
}
|
||||
}
|
||||
|
||||
function endTag()
|
||||
{
|
||||
if (count($this->_tagStack)) {
|
||||
$tag = array_pop($this->_tagStack);
|
||||
} else {
|
||||
$tag = 'Unknown';
|
||||
}
|
||||
|
||||
$this->_ch->endElement($this->getCurrentURI(), $tag);
|
||||
|
||||
return $tag;
|
||||
}
|
||||
|
||||
function getAttributes($input)
|
||||
{
|
||||
$this->startGetAttributes();
|
||||
$hasMoreAttributes = true;
|
||||
|
||||
$attrs = array();
|
||||
$attr = null;
|
||||
$value = null;
|
||||
$token = null;
|
||||
|
||||
while ($hasMoreAttributes) {
|
||||
$token = $this->getByte($input);
|
||||
|
||||
switch ($token) {
|
||||
// Attribute specified.
|
||||
case XML_WBXML_GLOBAL_TOKEN_LITERAL:
|
||||
// Section 5.8.4.5
|
||||
if (isset($attr)) {
|
||||
$attrs[] = array('attribute' => $attr,
|
||||
'value' => $value);
|
||||
}
|
||||
|
||||
$attr = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
break;
|
||||
|
||||
// Value specified.
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_I_0:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_I_1:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_I_2:
|
||||
// Section 5.8.4.2
|
||||
$value .= $this->termstr($input);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_T_0:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_T_1:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_T_2:
|
||||
// Section 5.8.4.2
|
||||
$value .= $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_0:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_1:
|
||||
case XML_WBXML_GLOBAL_TOKEN_EXT_2:
|
||||
// Section 5.8.4.2
|
||||
$value .= $input[$this->_strpos++];
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_ENTITY:
|
||||
// Section 5.8.4.3
|
||||
$value .= $this->entity(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_STR_I:
|
||||
// Section 5.8.4.1
|
||||
$value .= $this->termstr($input);
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_STR_T:
|
||||
// Section 5.8.4.1
|
||||
$value .= $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_OPAQUE:
|
||||
// Section 5.8.4.6
|
||||
$size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
$b = $this->_substr($input, $this->_strpos, $this->_strpos + $size);
|
||||
$this->_strpos += $size;
|
||||
|
||||
$value .= $b;
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_END:
|
||||
// Section 5.8.4.7.1
|
||||
$hasMoreAttributes = false;
|
||||
if (isset($attr)) {
|
||||
$attrs[] = array('attribute' => $attr,
|
||||
'value' => $value);
|
||||
}
|
||||
break;
|
||||
|
||||
case XML_WBXML_GLOBAL_TOKEN_SWITCH_PAGE:
|
||||
// Section 5.8.4.7.2
|
||||
$codePage = $this->getByte($input);
|
||||
if (!$this->_prevAttributeDTD) {
|
||||
$this->_prevAttributeDTD = $this->_attributeDTD;
|
||||
}
|
||||
|
||||
$this->switchAttributeCodePage($codePage);
|
||||
break;
|
||||
|
||||
default:
|
||||
if ($token > 128) {
|
||||
if (isset($attr)) {
|
||||
$attrs[] = array('attribute' => $attr,
|
||||
'value' => $value);
|
||||
}
|
||||
$attr = $this->_attributeDTD->toAttribute($token);
|
||||
} else {
|
||||
// Value.
|
||||
$value .= $this->_attributeDTD->toAttribute($token);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->_prevAttributeDTD) {
|
||||
$this->_attributeDTD = $this->_prevAttributeDTD;
|
||||
$this->_prevAttributeDTD = false;
|
||||
}
|
||||
|
||||
$this->stopGetAttributes();
|
||||
}
|
||||
|
||||
function startGetAttributes()
|
||||
{
|
||||
$this->_isAttribute = true;
|
||||
}
|
||||
|
||||
function stopGetAttributes()
|
||||
{
|
||||
$this->_isAttribute = false;
|
||||
}
|
||||
|
||||
function getCurrentURI()
|
||||
{
|
||||
if ($this->_isAttribute) {
|
||||
return $this->_tagDTD->getURI();
|
||||
} else {
|
||||
return $this->_attributeDTD->getURI();
|
||||
}
|
||||
}
|
||||
|
||||
function writeString($str)
|
||||
{
|
||||
$this->_ch->characters($str);
|
||||
}
|
||||
|
||||
function getTag($tag)
|
||||
{
|
||||
// Should know which state it is in.
|
||||
return $this->_tagDTD->toTagStr($tag);
|
||||
}
|
||||
|
||||
function getAttribute($attribute)
|
||||
{
|
||||
// Should know which state it is in.
|
||||
$this->_attributeDTD->toAttributeInt($attribute);
|
||||
}
|
||||
|
||||
function switchElementCodePage($codePage)
|
||||
{
|
||||
$this->_tagDTD = &$this->_dtdManager->getInstance($this->_tagDTD->toCodePageStr($codePage));
|
||||
$this->switchAttributeCodePage($codePage);
|
||||
}
|
||||
|
||||
function switchAttributeCodePage($codePage)
|
||||
{
|
||||
$this->_attributeDTD = &$this->_dtdManager->getInstance($this->_attributeDTD->toCodePageStr($codePage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hex version of the base 10 $entity.
|
||||
*/
|
||||
function entity($entity)
|
||||
{
|
||||
return dechex($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a null terminated string.
|
||||
*/
|
||||
function termstr($input)
|
||||
{
|
||||
$str = '#'; // must start with nonempty string to allow array access
|
||||
$i = 0;
|
||||
$ch = $input[$this->_strpos++];
|
||||
if (ord($ch) == 0) {
|
||||
return ''; // don't return '#'
|
||||
}
|
||||
while (ord($ch) != 0) {
|
||||
$str[$i++] = $ch;
|
||||
$ch = $input[$this->_strpos++];
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* imitate substr()
|
||||
* This circumvents a bug in the mbstring overloading in some distributions,
|
||||
* where the mbstring.func_overload=0 INI-setting does not work, if mod_php
|
||||
* has another value for that setting in another directory-context
|
||||
*/
|
||||
function _substr($input,$start,$size)
|
||||
{
|
||||
$ret = "";
|
||||
if (!$input) return $ret;
|
||||
for ($i = $start; $i < $start+$size; $i++) {
|
||||
$ret .= $input[$i];
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
@ -1,425 +0,0 @@
|
||||
<?php
|
||||
|
||||
include_once 'XML/WBXML.php';
|
||||
include_once 'XML/WBXML/ContentHandler.php';
|
||||
include_once 'XML/WBXML/DTDManager.php';
|
||||
include_once 'Horde/String.php';
|
||||
|
||||
/**
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* $Horde: framework/XML_WBXML/WBXML/Encoder.php,v 1.25.10.17 2008/08/26 15:41:21 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_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
var $_strings = array();
|
||||
|
||||
var $_stringTable;
|
||||
|
||||
var $_hasWrittenHeader = false;
|
||||
|
||||
var $_dtd;
|
||||
|
||||
var $_output = '';
|
||||
|
||||
var $_uris = array();
|
||||
|
||||
var $_uriNums = array();
|
||||
|
||||
var $_currentURI;
|
||||
|
||||
var $_subParser = null;
|
||||
var $_subParserStack = 0;
|
||||
|
||||
/**
|
||||
* The XML parser.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
var $_parser;
|
||||
|
||||
/**
|
||||
* The DTD Manager.
|
||||
*
|
||||
* @var XML_WBXML_DTDManager
|
||||
*/
|
||||
var $_dtdManager;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
function XML_WBXML_Encoder()
|
||||
{
|
||||
$this->_dtdManager = new XML_WBXML_DTDManager();
|
||||
$this->_stringTable = new XML_WBXML_HashTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the input $xml and turn it into WBXML. This is _not_ the
|
||||
* intended way of using this class. It is derived from
|
||||
* Contenthandler and one should use it as a ContentHandler and
|
||||
* produce the XML-structure with startElement(), endElement(),
|
||||
* and characters().
|
||||
*/
|
||||
function encode($xml)
|
||||
{
|
||||
// Create the XML parser and set method references.
|
||||
$this->_parser = xml_parser_create_ns($this->_charset);
|
||||
xml_set_object($this->_parser, $this);
|
||||
xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
|
||||
xml_set_element_handler($this->_parser, '_startElement', '_endElement');
|
||||
xml_set_character_data_handler($this->_parser, '_characters');
|
||||
xml_set_processing_instruction_handler($this->_parser, '');
|
||||
xml_set_external_entity_ref_handler($this->_parser, '');
|
||||
|
||||
if (!xml_parse($this->_parser, $xml)) {
|
||||
return $this->raiseError(sprintf('XML error: %s at line %d',
|
||||
xml_error_string(xml_get_error_code($this->_parser)),
|
||||
xml_get_current_line_number($this->_parser)));
|
||||
}
|
||||
|
||||
xml_parser_free($this->_parser);
|
||||
|
||||
return $this->_output;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will write the correct headers.
|
||||
*/
|
||||
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
|
||||
// version = u_int8
|
||||
// currently 1, 2 or 3
|
||||
$this->writeVersionNumber($this->_wbxmlVersion);
|
||||
|
||||
// Set Document Public Idetifier from Section 5.5
|
||||
// publicid = mb_u_int32 | ( zero index )
|
||||
// zero = u_int8
|
||||
// containing the value zero (0)
|
||||
// The actual DPI is determined after the String Table is read.
|
||||
$this->writeDocumentPublicIdentifier($dpiString, $this->_strings);
|
||||
|
||||
// Set Charset from 5.6
|
||||
// charset = mb_u_int32
|
||||
$this->writeCharset($this->_charset);
|
||||
|
||||
// Set String Table from 5.7
|
||||
// strb1 = length *byte
|
||||
$this->writeStringTable($this->_strings, $this->_charset, $this->_stringTable);
|
||||
|
||||
$this->_currentURI = $uri;
|
||||
|
||||
$this->_hasWrittenHeader = true;
|
||||
}
|
||||
|
||||
function writeVersionNumber($version)
|
||||
{
|
||||
$this->_output .= chr($version);
|
||||
}
|
||||
|
||||
function writeDocumentPublicIdentifier($dpiString, &$strings)
|
||||
{
|
||||
$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;
|
||||
$this->_output .= chr(0);
|
||||
$this->_output .= chr(0);
|
||||
} else {
|
||||
XML_WBXML::intToMBUInt32($this->_output, $i);
|
||||
}
|
||||
}
|
||||
|
||||
function writeCharset($charset)
|
||||
{
|
||||
$cs = XML_WBXML::getCharsetInt($charset);
|
||||
|
||||
if ($cs == 0) {
|
||||
return $this->raiseError('Unsupported Charset: ' . $charset);
|
||||
} else {
|
||||
XML_WBXML::intToMBUInt32($this->_output, $cs);
|
||||
}
|
||||
}
|
||||
|
||||
function writeStringTable($strings, $charset, $stringTable)
|
||||
{
|
||||
$stringBytes = array();
|
||||
$count = 0;
|
||||
foreach ($strings as $str) {
|
||||
$bytes = $this->_getBytes($str, $charset);
|
||||
$stringBytes = array_merge($stringBytes, $bytes);
|
||||
$nullLength = $this->_addNullByte($bytes);
|
||||
$this->_stringTable->set($str, $count);
|
||||
$count += count($bytes) + $nullLength;
|
||||
}
|
||||
|
||||
XML_WBXML::intToMBUInt32($this->_output, count($stringBytes));
|
||||
$this->_output .= implode('', $stringBytes);
|
||||
}
|
||||
|
||||
function writeString($str, $cs)
|
||||
{
|
||||
$bytes = $this->_getBytes($str, $cs);
|
||||
$this->_output .= implode('', $bytes);
|
||||
$this->writeNull($cs);
|
||||
}
|
||||
|
||||
function writeNull($charset)
|
||||
{
|
||||
$this->_output .= chr(0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
function _addNullByte(&$bytes)
|
||||
{
|
||||
$bytes[] = chr(0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
function _getBytes($string, $cs)
|
||||
{
|
||||
$string = String::convertCharset($string, $cs, 'utf-8');
|
||||
$nbytes = strlen($string);
|
||||
|
||||
$bytes = array();
|
||||
for ($i = 0; $i < $nbytes; $i++) {
|
||||
$bytes[] = $string{$i};
|
||||
}
|
||||
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
function _splitURI($tag)
|
||||
{
|
||||
$parts = explode(':', $tag);
|
||||
$name = array_pop($parts);
|
||||
$uri = implode(':', $parts);
|
||||
return array($uri, $name);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if ($this->_currentURI != $uri) {
|
||||
$this->changecodepage($uri);
|
||||
}
|
||||
if ($this->_subParser == null) {
|
||||
$this->writeTag($name, $attributes, true, $this->_charset);
|
||||
} else {
|
||||
$this->_subParser->startElement($uri, $name, $attributes);
|
||||
}
|
||||
} else {
|
||||
$this->_subParserStack++;
|
||||
$this->_subParser->startElement($uri, $name, $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
function _startElement($parser, $tag, $attributes)
|
||||
{
|
||||
list($uri, $name) = $this->_splitURI($tag);
|
||||
|
||||
$this->startElement($uri, $name, $attributes);
|
||||
}
|
||||
|
||||
function opaque($o)
|
||||
{
|
||||
if ($this->_subParser == null) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_OPAQUE);
|
||||
XML_WBXML::intToMBUInt32($this->_output, strlen($o));
|
||||
$this->_output .= $o;
|
||||
}
|
||||
}
|
||||
|
||||
function characters($chars)
|
||||
{
|
||||
$chars = trim($chars);
|
||||
|
||||
if (strlen($chars)) {
|
||||
/* We definitely don't want any whitespace. */
|
||||
if ($this->_subParser == null) {
|
||||
$i = $this->_stringTable->get($chars);
|
||||
if ($i != null) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_STR_T);
|
||||
XML_WBXML::intToMBUInt32($this->_output, $i);
|
||||
} else {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_STR_I);
|
||||
$this->writeString($chars, $this->_charset);
|
||||
}
|
||||
} else {
|
||||
$this->_subParser->characters($chars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _characters($parser, $chars)
|
||||
{
|
||||
$this->characters($chars);
|
||||
}
|
||||
|
||||
function writeTag($name, $attrs, $hasContent, $cs)
|
||||
{
|
||||
if ($attrs != null && !count($attrs)) {
|
||||
$attrs = null;
|
||||
}
|
||||
|
||||
$t = $this->_dtd->toTagInt($name);
|
||||
if ($t == -1) {
|
||||
$i = $this->_stringTable->get($name);
|
||||
if ($i == null) {
|
||||
return $this->raiseError($name . ' is not found in String Table or DTD');
|
||||
} else {
|
||||
if ($attrs == null && !$hasContent) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL);
|
||||
} elseif ($attrs == null && $hasContent) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL_A);
|
||||
} elseif ($attrs != null && $hasContent) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL_C);
|
||||
} elseif ($attrs != null && !$hasContent) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL_AC);
|
||||
}
|
||||
|
||||
XML_WBXML::intToMBUInt32($this->_output, $i);
|
||||
}
|
||||
} else {
|
||||
if ($attrs == null && !$hasContent) {
|
||||
$this->_output .= chr($t);
|
||||
} elseif ($attrs == null && $hasContent) {
|
||||
$this->_output .= chr($t | 64);
|
||||
} elseif ($attrs != null && $hasContent) {
|
||||
$this->_output .= chr($t | 128);
|
||||
} elseif ($attrs != null && !$hasContent) {
|
||||
$this->_output .= chr($t | 192);
|
||||
}
|
||||
}
|
||||
|
||||
if ($attrs != null && is_array($attrs) && count($attrs) > 0) {
|
||||
$this->writeAttributes($attrs, $cs);
|
||||
}
|
||||
}
|
||||
|
||||
function writeAttributes($attrs, $cs)
|
||||
{
|
||||
foreach ($attrs as $name => $value) {
|
||||
$this->writeAttribute($name, $value, $cs);
|
||||
}
|
||||
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_END);
|
||||
}
|
||||
|
||||
function writeAttribute($name, $value, $cs)
|
||||
{
|
||||
$a = $this->_dtd->toAttribute($name);
|
||||
if ($a == -1) {
|
||||
$i = $this->_stringTable->get($name);
|
||||
if ($i == null) {
|
||||
return $this->raiseError($name . ' is not found in String Table or DTD');
|
||||
} else {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL);
|
||||
XML_WBXML::intToMBUInt32($this->_output, $i);
|
||||
}
|
||||
} else {
|
||||
$this->_output .= $a;
|
||||
}
|
||||
|
||||
$i = $this->_stringTable->get($name);
|
||||
if ($i != null) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_STR_T);
|
||||
XML_WBXML::intToMBUInt32($this->_output, $i);
|
||||
} else {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_STR_I);
|
||||
$this->writeString($value, $cs);
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $name)
|
||||
{
|
||||
if ($this->_subParser == null) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_END);
|
||||
} else {
|
||||
$this->_subParser->endElement($uri, $name);
|
||||
$this->_subParserStack--;
|
||||
|
||||
if ($this->_subParserStack == 0) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_OPAQUE);
|
||||
|
||||
XML_WBXML::intToMBUInt32($this->_output,
|
||||
strlen($this->_subParser->getOutput()));
|
||||
$this->_output .= $this->_subParser->getOutput();
|
||||
|
||||
$this->_subParser = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _endElement($parser, $tag)
|
||||
{
|
||||
list($uri, $name) = $this->_splitURI($tag);
|
||||
$this->endElement($uri, $name);
|
||||
}
|
||||
|
||||
function changecodepage($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);
|
||||
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_SWITCH_PAGE);
|
||||
$this->_output .= chr($cp);
|
||||
$this->_currentURI = $uri;
|
||||
|
||||
} else {
|
||||
$this->_subParser = new XML_WBXML_Encoder(true);
|
||||
$this->_subParserStack = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for property output.
|
||||
*/
|
||||
function getOutput()
|
||||
{
|
||||
return $this->_output;
|
||||
}
|
||||
|
||||
function getOutputSize()
|
||||
{
|
||||
return strlen($this->_output);
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
/* CONFIG START. DO NOT CHANGE ANYTHING IN OR AFTER THIS LINE. */
|
||||
// $Horde: horde/config/conf.xml,v 1.79 2005/02/16 15:42:35 jan Exp $
|
||||
$conf['debug_level'] = E_ERROR | E_WARNING | E_PARSE;
|
||||
$conf['max_exec_time'] = 0;
|
||||
$conf['use_ssl'] = 2;
|
||||
$conf['server']['name'] = $_SERVER['SERVER_NAME'];
|
||||
$conf['server']['port'] = $_SERVER['SERVER_PORT'];
|
||||
$conf['compress_pages'] = true;
|
||||
$conf['umask'] = 077;
|
||||
$conf['session']['name'] = 'Horde';
|
||||
$conf['session']['cache_limiter'] = 'nocache';
|
||||
$conf['session']['timeout'] = 0;
|
||||
$conf['cookie']['domain'] = $_SERVER['SERVER_NAME'];
|
||||
$conf['cookie']['path'] = '/horde';
|
||||
$conf['auth']['admins'] = array('Administrator');
|
||||
$conf['auth']['checkip'] = true;
|
||||
$conf['auth']['params']['username'] = 'Administrator';
|
||||
$conf['auth']['params']['requestuser'] = false;
|
||||
$conf['auth']['driver'] = 'auto';
|
||||
$conf['log']['priority'] = PEAR_LOG_DEBUG;
|
||||
$conf['log']['ident'] = 'EGWSYNC';
|
||||
$conf['log']['params'] = array();
|
||||
$conf['log']['name'] = '/tmp/egroupware_syncml-1.6.log';
|
||||
$conf['log']['params']['append'] = true;
|
||||
$conf['log']['type'] = 'error_log';
|
||||
$conf['log']['enabled'] = false;
|
||||
$conf['log_accesskeys'] = false;
|
||||
$conf['prefs']['driver'] = 'none';
|
||||
$conf['datatree']['params']['driverconfig'] = 'horde';
|
||||
$conf['datatree']['driver'] = 'sql';
|
||||
$conf['group']['driver'] = 'datatree';
|
||||
#$conf['cache']['default_lifetime'] = 1800;
|
||||
#$conf['cache']['params']['dir'] = Horde::getTempDir();
|
||||
#$conf['cache']['driver'] = 'file';
|
||||
$conf['token']['driver'] = 'none';
|
||||
$conf['sessionhandler']['type'] = 'none';
|
||||
$conf['problems']['email'] = 'webmaster@example.com';
|
||||
$conf['hooks']['username'] = false;
|
||||
$conf['hooks']['preauthenticate'] = false;
|
||||
$conf['hooks']['postauthenticate'] = false;
|
||||
$conf['hooks']['authldap'] = false;
|
||||
$conf['kolab']['enabled'] = false;
|
||||
/* CONFIG END. DO NOT CHANGE ANYTHING IN OR BEFORE THIS LINE. */
|
@ -1,594 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* NLS (National Language Support) configuration file.
|
||||
*
|
||||
* $Horde: horde/config/nls.php.dist,v 1.59 2004/09/01 09:59:24 jan Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
** Defaults
|
||||
**/
|
||||
|
||||
/* The language to fall back on if we cannot determine one any other
|
||||
way (user choice or preferences). If empty, we will try to negotiate
|
||||
with the browser using HTTP_ACCEPT_LANGUAGE. */
|
||||
$nls['defaults']['language'] = '';
|
||||
|
||||
/* The charset to fall back on if we cannot determine one any other
|
||||
way (chosen language, HTTP_ACCEPT_CHARSETS). */
|
||||
$nls['defaults']['charset'] = 'ISO-8859-1';
|
||||
|
||||
|
||||
/**
|
||||
** Language
|
||||
**/
|
||||
|
||||
$nls['languages']['ar_OM'] = 'Arabic (Oman) (العربية)';
|
||||
$nls['languages']['ar_SY'] = 'Arabic (Syria) (العربية)';
|
||||
$nls['languages']['id_ID'] = 'Bahasa Indonesia';
|
||||
$nls['languages']['bg_BG'] = 'Bulgarian (Български)';
|
||||
$nls['languages']['ca_ES'] = 'Català';
|
||||
$nls['languages']['zh_CN'] = 'Chinese (Simplified) (简体中文)';
|
||||
$nls['languages']['zh_TW'] = 'Chinese (Traditional) (正體中文)';
|
||||
$nls['languages']['cs_CZ'] = 'Czech (Česky)';
|
||||
$nls['languages']['da_DK'] = 'Dansk';
|
||||
$nls['languages']['de_DE'] = 'Deutsch';
|
||||
$nls['languages']['en_US'] = 'English (American)';
|
||||
$nls['languages']['en_GB'] = 'English (British)';
|
||||
$nls['languages']['en_CA'] = 'English (Canadian)';
|
||||
$nls['languages']['es_ES'] = 'Español';
|
||||
$nls['languages']['et_EE'] = 'Eesti';
|
||||
$nls['languages']['fr_FR'] = 'Français';
|
||||
$nls['languages']['gl_ES'] = 'Galego';
|
||||
$nls['languages']['el_GR'] = 'Greek (Ελληνικά)';
|
||||
$nls['languages']['is_IS'] = 'Íslenska';
|
||||
$nls['languages']['it_IT'] = 'Italiano';
|
||||
$nls['languages']['ja_JP'] = 'Japanese (日本語)';
|
||||
$nls['languages']['ko_KR'] = 'Korean (한국어)';
|
||||
$nls['languages']['lv_LV'] = 'Latviešu';
|
||||
$nls['languages']['lt_LT'] = 'Lietuvių';
|
||||
$nls['languages']['mk_MK'] = 'Macedonian (Македонски)';
|
||||
$nls['languages']['hu_HU'] = 'Magyar';
|
||||
$nls['languages']['nl_NL'] = 'Nederlands';
|
||||
$nls['languages']['nb_NO'] = 'Norsk bokmål';
|
||||
$nls['languages']['nn_NO'] = 'Norsk nynorsk';
|
||||
$nls['languages']['fa_IR'] = 'Persian (Western) (فارسى)';
|
||||
$nls['languages']['pl_PL'] = 'Polski';
|
||||
$nls['languages']['pt_PT'] = 'Português';
|
||||
$nls['languages']['pt_BR'] = 'Português Brasileiro';
|
||||
$nls['languages']['ro_RO'] = 'Românä';
|
||||
$nls['languages']['ru_RU'] = 'Russian (Русский)';
|
||||
$nls['languages']['sk_SK'] = 'Slovak (Slovenčina)';
|
||||
$nls['languages']['sl_SI'] = 'Slovenian (Slovenščina)';
|
||||
$nls['languages']['fi_FI'] = 'Suomi';
|
||||
$nls['languages']['sv_SE'] = 'Svenska';
|
||||
$nls['languages']['th_TH'] = 'Thai (ไทย)';
|
||||
$nls['languages']['tr_TR'] = 'Türkçe';
|
||||
$nls['languages']['uk_UA'] = 'Ukrainian (Українська)';
|
||||
|
||||
|
||||
/**
|
||||
** Aliases for languages with different browser and gettext codes
|
||||
**/
|
||||
|
||||
$nls['aliases']['ar'] = 'ar_SY';
|
||||
$nls['aliases']['bg'] = 'bg_BG';
|
||||
$nls['aliases']['ca'] = 'ca_ES';
|
||||
$nls['aliases']['cs'] = 'cs_CZ';
|
||||
$nls['aliases']['da'] = 'da_DK';
|
||||
$nls['aliases']['de'] = 'de_DE';
|
||||
$nls['aliases']['el'] = 'el_GR';
|
||||
$nls['aliases']['en'] = 'en_US';
|
||||
$nls['aliases']['es'] = 'es_ES';
|
||||
$nls['aliases']['et'] = 'et_EE';
|
||||
$nls['aliases']['fa'] = 'fa_IR';
|
||||
$nls['aliases']['fi'] = 'fi_FI';
|
||||
$nls['aliases']['fr'] = 'fr_FR';
|
||||
$nls['aliases']['gl'] = 'gl_ES';
|
||||
$nls['aliases']['hu'] = 'hu_HU';
|
||||
$nls['aliases']['id'] = 'id_ID';
|
||||
$nls['aliases']['is'] = 'is_IS';
|
||||
$nls['aliases']['it'] = 'it_IT';
|
||||
$nls['aliases']['ja'] = 'ja_JP';
|
||||
$nls['aliases']['ko'] = 'ko_KR';
|
||||
$nls['aliases']['lt'] = 'lt_LT';
|
||||
$nls['aliases']['lv'] = 'lv_LV';
|
||||
$nls['aliases']['mk'] = 'mk_MK';
|
||||
$nls['aliases']['nl'] = 'nl_NL';
|
||||
$nls['aliases']['nn'] = 'nn_NO';
|
||||
$nls['aliases']['no'] = 'nb_NO';
|
||||
$nls['aliases']['pl'] = 'pl_PL';
|
||||
$nls['aliases']['pt'] = 'pt_PT';
|
||||
$nls['aliases']['ro'] = 'ro_RO';
|
||||
$nls['aliases']['ru'] = 'ru_RU';
|
||||
$nls['aliases']['sk'] = 'sk_SK';
|
||||
$nls['aliases']['sl'] = 'sl_SI';
|
||||
$nls['aliases']['sv'] = 'sv_SE';
|
||||
$nls['aliases']['th'] = 'th_TH';
|
||||
$nls['aliases']['tr'] = 'tr_TR';
|
||||
$nls['aliases']['uk'] = 'uk_UA';
|
||||
|
||||
|
||||
/**
|
||||
** Charsets
|
||||
**/
|
||||
|
||||
$nls['charsets']['ar_OM'] = 'windows-1256';
|
||||
$nls['charsets']['ar_SY'] = 'windows-1256';
|
||||
$nls['charsets']['bg_BG'] = 'windows-1251';
|
||||
$nls['charsets']['cs_CZ'] = 'ISO-8859-2';
|
||||
$nls['charsets']['el_GR'] = 'ISO-8859-7';
|
||||
$nls['charsets']['fa_IR'] = 'UTF-8';
|
||||
$nls['charsets']['hu_HU'] = 'ISO-8859-2';
|
||||
$nls['charsets']['ja_JP'] = 'SHIFT_JIS';
|
||||
$nls['charsets']['ko_KR'] = 'EUC-KR';
|
||||
$nls['charsets']['lt_LT'] = 'ISO-8859-13';
|
||||
$nls['charsets']['lv_LV'] = 'windows-1257';
|
||||
$nls['charsets']['mk_MK'] = 'ISO-8859-5';
|
||||
$nls['charsets']['pl_PL'] = 'ISO-8859-2';
|
||||
$nls['charsets']['ru_RU'] = 'windows-1251';
|
||||
$nls['charsets']['ru_RU.KOI8-R'] = 'KOI8-R';
|
||||
$nls['charsets']['sk_SK'] = 'ISO-8859-2';
|
||||
$nls['charsets']['sl_SI'] = 'ISO-8859-2';
|
||||
$nls['charsets']['th_TH'] = 'TIS-620';
|
||||
$nls['charsets']['tr_TR'] = 'ISO-8859-9';
|
||||
$nls['charsets']['uk_UA'] = 'KOI8-U';
|
||||
$nls['charsets']['zh_CN'] = 'GB2312';
|
||||
$nls['charsets']['zh_TW'] = 'BIG5';
|
||||
|
||||
|
||||
/**
|
||||
** Multibyte charsets
|
||||
**/
|
||||
|
||||
$nls['multibyte']['BIG5'] = true;
|
||||
$nls['multibyte']['EUC-KR'] = true;
|
||||
$nls['multibyte']['GB2312'] = true;
|
||||
$nls['multibyte']['SHIFT_JIS'] = true;
|
||||
$nls['multibyte']['UTF-8'] = true;
|
||||
|
||||
|
||||
/**
|
||||
** Right-to-left languages
|
||||
**/
|
||||
|
||||
$nls['rtl']['ar_OM'] = true;
|
||||
$nls['rtl']['ar_SY'] = true;
|
||||
$nls['rtl']['fa_IR'] = true;
|
||||
|
||||
|
||||
/**
|
||||
** Preferred charsets for email traffic if not the languages' default charsets.
|
||||
**/
|
||||
|
||||
$nls['emails']['ja_JP'] = 'ISO-2022-JP';
|
||||
|
||||
|
||||
/**
|
||||
** Available charsets for outgoing email traffic.
|
||||
**/
|
||||
|
||||
$nls['encodings']['windows-1256'] = _("Arabic (Windows-1256)");
|
||||
$nls['encodings']['ARMSCII-8'] = _("Armenian (ARMSCII-8)");
|
||||
$nls['encodings']['ISO-8859-13'] = _("Baltic (ISO-8859-13)");
|
||||
$nls['encodings']['ISO-8859-14'] = _("Celtic (ISO-8859-14)");
|
||||
$nls['encodings']['ISO-8859-2'] = _("Central European (ISO-8859-2)");
|
||||
$nls['encodings']['GB2312'] = _("Chinese Simplified (GB2312)");
|
||||
$nls['encodings']['BIG5'] = _("Chinese Traditional (Big5)");
|
||||
$nls['encodings']['KOI8-R'] = _("Cyrillic (KOI8-R)");
|
||||
$nls['encodings']['windows-1251'] = _("Cyrillic (Windows-1251)");
|
||||
$nls['encodings']['KOI8-U'] = _("Cyrillic/Ukrainian (KOI8-U)");
|
||||
$nls['encodings']['ISO-8859-7'] = _("Greek (ISO-8859-7)");
|
||||
$nls['encodings']['ISO-8859-8-I'] = _("Hebrew (ISO-8859-8-I)");
|
||||
$nls['encodings']['ISO-2022-JP'] = _("Japanese (ISO-2022-JP)");
|
||||
$nls['encodings']['EUC-KR'] = _("Korean (EUC-KR)");
|
||||
$nls['encodings']['ISO-8859-10'] = _("Nordic (ISO-8859-10)");
|
||||
$nls['encodings']['ISO-8859-3'] = _("South European (ISO-8859-3)");
|
||||
$nls['encodings']['TIS-620'] = _("Thai (TIS-620)");
|
||||
$nls['encodings']['ISO-8859-9'] = _("Turkish (ISO-8859-9)");
|
||||
$nls['encodings']['UTF-8'] = _("Unicode (UTF-8)");
|
||||
$nls['encodings']['VISCII'] = _("Vietnamese (VISCII)");
|
||||
$nls['encodings']['ISO-8859-1'] = _("Western (ISO-8859-1)");
|
||||
$nls['encodings']['ISO-8859-15'] = _("Western (ISO-8859-15)");
|
||||
asort($nls['encodings']);
|
||||
|
||||
|
||||
/**
|
||||
** Multi-language spelling support
|
||||
**/
|
||||
|
||||
$nls['spelling']['cs_CZ'] = '-T latin2 -d czech';
|
||||
$nls['spelling']['da_DK'] = '-d dansk';
|
||||
$nls['spelling']['de_DE'] = '-T latin1 -d deutsch';
|
||||
$nls['spelling']['el_GR'] = '-T latin1 -d ellinika';
|
||||
$nls['spelling']['en_CA'] = '-d canadian';
|
||||
$nls['spelling']['en_GB'] = '-d british';
|
||||
$nls['spelling']['en_US'] = '-d american';
|
||||
$nls['spelling']['es_ES'] = '-d espanol';
|
||||
$nls['spelling']['fr_FR'] = '-d francais';
|
||||
$nls['spelling']['it_IT'] = '-T latin1 -d italian';
|
||||
$nls['spelling']['nl_NL'] = '-d nederlands';
|
||||
$nls['spelling']['pl_PL'] = '-d polish';
|
||||
$nls['spelling']['pt_BR'] = '-d br';
|
||||
$nls['spelling']['pt_PT'] = '-T latin1 -d portuguese';
|
||||
$nls['spelling']['ru_RU'] = '-d russian';
|
||||
$nls['spelling']['sl_SI'] = '-d slovensko';
|
||||
$nls['spelling']['sv_SE'] = '-d svenska';
|
||||
|
||||
$GLOBALS['nls'] = &$nls;
|
||||
|
||||
|
||||
/**
|
||||
** Timezones
|
||||
**/
|
||||
|
||||
$tz['Africa/Abidjan'] = 'Africa/Abidjan';
|
||||
$tz['Africa/Accra'] = 'Africa/Accra';
|
||||
$tz['Africa/Addis_Ababa'] = 'Africa/Addis Ababa';
|
||||
$tz['Africa/Algiers'] = 'Africa/Algiers';
|
||||
$tz['Africa/Asmera'] = 'Africa/Asmera';
|
||||
$tz['Africa/Bamako'] = 'Africa/Bamako';
|
||||
$tz['Africa/Bangui'] = 'Africa/Bangui';
|
||||
$tz['Africa/Banjul'] = 'Africa/Banjul';
|
||||
$tz['Africa/Bissau'] = 'Africa/Bissau';
|
||||
$tz['Africa/Blantyre'] = 'Africa/Blantyre';
|
||||
$tz['Africa/Brazzaville'] = 'Africa/Brazzaville';
|
||||
$tz['Africa/Bujumbura'] = 'Africa/Bujumbura';
|
||||
$tz['Africa/Cairo'] = 'Africa/Cairo';
|
||||
$tz['Africa/Casablanca'] = 'Africa/Casablanca';
|
||||
$tz['Africa/Ceuta'] = 'Africa/Ceuta';
|
||||
$tz['Africa/Conakry'] = 'Africa/Conakry';
|
||||
$tz['Africa/Dakar'] = 'Africa/Dakar';
|
||||
$tz['Africa/Dar_es_Salaam'] = 'Africa/Dar es Salaam';
|
||||
$tz['Africa/Djibouti'] = 'Africa/Djibouti';
|
||||
$tz['Africa/Douala'] = 'Africa/Douala';
|
||||
$tz['Africa/El_Aaiun'] = 'Africa/El Aaiun';
|
||||
$tz['Africa/Freetown'] = 'Africa/Freetown';
|
||||
$tz['Africa/Gaborone'] = 'Africa/Gaborone';
|
||||
$tz['Africa/Harare'] = 'Africa/Harare';
|
||||
$tz['Africa/Johannesburg'] = 'Africa/Johannesburg';
|
||||
$tz['Africa/Kampala'] = 'Africa/Kampala';
|
||||
$tz['Africa/Khartoum'] = 'Africa/Khartoum';
|
||||
$tz['Africa/Kigali'] = 'Africa/Kigali';
|
||||
$tz['Africa/Kinshasa'] = 'Africa/Kinshasa';
|
||||
$tz['Africa/Lagos'] = 'Africa/Lagos';
|
||||
$tz['Africa/Libreville'] = 'Africa/Libreville';
|
||||
$tz['Africa/Lome'] = 'Africa/Lome';
|
||||
$tz['Africa/Luanda'] = 'Africa/Luanda';
|
||||
$tz['Africa/Lubumbashi'] = 'Africa/Lubumbashi';
|
||||
$tz['Africa/Lusaka'] = 'Africa/Lusaka';
|
||||
$tz['Africa/Malabo'] = 'Africa/Malabo';
|
||||
$tz['Africa/Maputo'] = 'Africa/Maputo';
|
||||
$tz['Africa/Maseru'] = 'Africa/Maseru';
|
||||
$tz['Africa/Mbabane'] = 'Africa/Mbabane';
|
||||
$tz['Africa/Mogadishu'] = 'Africa/Mogadishu';
|
||||
$tz['Africa/Monrovia'] = 'Africa/Monrovia';
|
||||
$tz['Africa/Nairobi'] = 'Africa/Nairobi';
|
||||
$tz['Africa/Ndjamena'] = 'Africa/Ndjamena';
|
||||
$tz['Africa/Niamey'] = 'Africa/Niamey';
|
||||
$tz['Africa/Nouakchott'] = 'Africa/Nouakchott';
|
||||
$tz['Africa/Ouagadougou'] = 'Africa/Ouagadougou';
|
||||
$tz['Africa/Porto-Novo'] = 'Africa/Porto-Novo';
|
||||
$tz['Africa/Sao_Tome'] = 'Africa/Sao Tome';
|
||||
$tz['Africa/Timbuktu'] = 'Africa/Timbuktu';
|
||||
$tz['Africa/Tripoli'] = 'Africa/Tripoli';
|
||||
$tz['Africa/Tunis'] = 'Africa/Tunis';
|
||||
$tz['Africa/Windhoek'] = 'Africa/Windhoek';
|
||||
$tz['America/Adak'] = 'America/Adak';
|
||||
$tz['America/Anchorage'] = 'America/Anchorage';
|
||||
$tz['America/Anguilla'] = 'America/Anguilla';
|
||||
$tz['America/Antigua'] = 'America/Antigua';
|
||||
$tz['America/Araguaina'] = 'America/Araguaina';
|
||||
$tz['America/Aruba'] = 'America/Aruba';
|
||||
$tz['America/Asuncion'] = 'America/Asuncion';
|
||||
$tz['America/Barbados'] = 'America/Barbados';
|
||||
$tz['America/Belem'] = 'America/Belem';
|
||||
$tz['America/Belize'] = 'America/Belize';
|
||||
$tz['America/Boa_Vista'] = 'America/Boa Vista';
|
||||
$tz['America/Bogota'] = 'America/Bogota';
|
||||
$tz['America/Boise'] = 'America/Boise';
|
||||
$tz['America/Buenos_Aires'] = 'America/Buenos Aires';
|
||||
$tz['America/Cambridge_Bay'] = 'America/Cambridge Bay';
|
||||
$tz['America/Cancun'] = 'America/Cancun';
|
||||
$tz['America/Caracas'] = 'America/Caracas';
|
||||
$tz['America/Catamarca'] = 'America/Catamarca';
|
||||
$tz['America/Cayenne'] = 'America/Cayenne';
|
||||
$tz['America/Cayman'] = 'America/Cayman';
|
||||
$tz['America/Chicago'] = 'America/Chicago';
|
||||
$tz['America/Chihuahua'] = 'America/Chihuahua';
|
||||
$tz['America/Cordoba'] = 'America/Cordoba';
|
||||
$tz['America/Costa_Rica'] = 'America/Costa Rica';
|
||||
$tz['America/Cuiaba'] = 'America/Cuiaba';
|
||||
$tz['America/Curacao'] = 'America/Curacao';
|
||||
$tz['America/Dawson'] = 'America/Dawson';
|
||||
$tz['America/Dawson_Creek'] = 'America/Dawson Creek';
|
||||
$tz['America/Denver'] = 'America/Denver';
|
||||
$tz['America/Detroit'] = 'America/Detroit';
|
||||
$tz['America/Dominica'] = 'America/Dominica';
|
||||
$tz['America/Edmonton'] = 'America/Edmonton';
|
||||
$tz['America/Eirunepe'] = 'America/Eirunepe';
|
||||
$tz['America/El_Salvador'] = 'America/El Salvador';
|
||||
$tz['America/Fortaleza'] = 'America/Fortaleza';
|
||||
$tz['America/Glace_Bay'] = 'America/Glace Bay';
|
||||
$tz['America/Godthab'] = 'America/Godthab';
|
||||
$tz['America/Goose_Bay'] = 'America/Goose Bay';
|
||||
$tz['America/Grand_Turk'] = 'America/Grand Turk';
|
||||
$tz['America/Grenada'] = 'America/Grenada';
|
||||
$tz['America/Guadeloupe'] = 'America/Guadeloupe';
|
||||
$tz['America/Guatemala'] = 'America/Guatemala';
|
||||
$tz['America/Guayaquil'] = 'America/Guayaquil';
|
||||
$tz['America/Guyana'] = 'America/Guyana';
|
||||
$tz['America/Halifax'] = 'America/Halifax';
|
||||
$tz['America/Havana'] = 'America/Havana';
|
||||
$tz['America/Hermosillo'] = 'America/Hermosillo';
|
||||
$tz['America/Indiana/Knox'] = 'America/Indiana/Knox';
|
||||
$tz['America/Indiana/Marengo'] = 'America/Indiana/Marengo';
|
||||
$tz['America/Indiana/Vevay'] = 'America/Indiana/Vevay';
|
||||
$tz['America/Indianapolis'] = 'America/Indianapolis';
|
||||
$tz['America/Inuvik'] = 'America/Inuvik';
|
||||
$tz['America/Iqaluit'] = 'America/Iqaluit';
|
||||
$tz['America/Jamaica'] = 'America/Jamaica';
|
||||
$tz['America/Jujuy'] = 'America/Jujuy';
|
||||
$tz['America/Juneau'] = 'America/Juneau';
|
||||
$tz['America/Kentucky/Monticello'] = 'America/Kentucky/Monticello';
|
||||
$tz['America/La_Paz'] = 'America/La Paz';
|
||||
$tz['America/Lima'] = 'America/Lima';
|
||||
$tz['America/Los_Angeles'] = 'America/Los Angeles';
|
||||
$tz['America/Louisville'] = 'America/Louisville';
|
||||
$tz['America/Maceio'] = 'America/Maceio';
|
||||
$tz['America/Managua'] = 'America/Managua';
|
||||
$tz['America/Manaus'] = 'America/Manaus';
|
||||
$tz['America/Martinique'] = 'America/Martinique';
|
||||
$tz['America/Mazatlan'] = 'America/Mazatlan';
|
||||
$tz['America/Mendoz'] = 'America/Mendoz';
|
||||
$tz['America/Menominee'] = 'America/Menominee';
|
||||
$tz['America/Merida'] = 'America/Merida';
|
||||
$tz['America/Mexico_City'] = 'America/Mexico City';
|
||||
$tz['America/Miquelon'] = 'America/Miquelon';
|
||||
$tz['America/Monterrey'] = 'America/Monterrey';
|
||||
$tz['America/Montevideo'] = 'America/Montevideo';
|
||||
$tz['America/Montreal'] = 'America/Montreal';
|
||||
$tz['America/Montserrat'] = 'America/Montserrat';
|
||||
$tz['America/Nassau'] = 'America/Nassau';
|
||||
$tz['America/New_York'] = 'America/New York';
|
||||
$tz['America/Nipigon'] = 'America/Nipigon';
|
||||
$tz['America/Nome'] = 'America/Nome';
|
||||
$tz['America/Noronha'] = 'America/Noronha';
|
||||
$tz['America/Panama'] = 'America/Panama';
|
||||
$tz['America/Pangnirtung'] = 'America/Pangnirtung';
|
||||
$tz['America/Paramaribo'] = 'America/Paramaribo';
|
||||
$tz['America/Phoenix'] = 'America/Phoenix';
|
||||
$tz['America/Port-au-Prince'] = 'America/Port-au-Prince';
|
||||
$tz['America/Porto_Velho'] = 'America/Porto Velho';
|
||||
$tz['America/Port_of_Spain'] = 'America/Port of Spain';
|
||||
$tz['America/Puerto_Rico'] = 'America/Puerto Rico';
|
||||
$tz['America/Rainy_River'] = 'America/Rainy River';
|
||||
$tz['America/Rankin_Inlet'] = 'America/Rankin Inlet';
|
||||
$tz['America/Recife'] = 'America/Recife';
|
||||
$tz['America/Regina'] = 'America/Regina';
|
||||
$tz['America/Rio_Branco'] = 'America/Rio Branco';
|
||||
$tz['America/Rosario'] = 'America/Rosario';
|
||||
$tz['America/Santiago'] = 'America/Santiago';
|
||||
$tz['America/Santo_Domingo'] = 'America/Santo Domingo';
|
||||
$tz['America/Sao_Paulo'] = 'America/Sao Paulo';
|
||||
$tz['America/Scoresbysund'] = 'America/Scoresbysund';
|
||||
$tz['America/Shiprock'] = 'America/Shiprock';
|
||||
$tz['America/St_Johns'] = 'America/St Johns';
|
||||
$tz['America/St_Kitts'] = 'America/St Kitts';
|
||||
$tz['America/St_Lucia'] = 'America/St Lucia';
|
||||
$tz['America/St_Thomas'] = 'America/St Thomas';
|
||||
$tz['America/St_Vincent'] = 'America/St Vincent';
|
||||
$tz['America/Swift_Current'] = 'America/Swift Current';
|
||||
$tz['America/Tegucigalpa'] = 'America/Tegucigalpa';
|
||||
$tz['America/Thule'] = 'America/Thule';
|
||||
$tz['America/Thunder_Bay'] = 'America/Thunder Bay';
|
||||
$tz['America/Tijuana'] = 'America/Tijuana';
|
||||
$tz['America/Tortola'] = 'America/Tortola';
|
||||
$tz['America/Vancouver'] = 'America/Vancouver';
|
||||
$tz['America/Whitehorse'] = 'America/Whitehorse';
|
||||
$tz['America/Winnipeg'] = 'America/Winnipeg';
|
||||
$tz['America/Yakutat'] = 'America/Yakutat';
|
||||
$tz['America/Yellowknife'] = 'America/Yellowknife';
|
||||
$tz['Antarctica/Casey'] = 'Antarctica/Casey';
|
||||
$tz['Antarctica/Davis'] = 'Antarctica/Davis';
|
||||
$tz['Antarctica/DumontDUrville'] = 'Antarctica/DumontDUrville';
|
||||
$tz['Antarctica/Mawson'] = 'Antarctica/Mawson';
|
||||
$tz['Antarctica/McMurdo'] = 'Antarctica/McMurdo';
|
||||
$tz['Antarctica/Palmer'] = 'Antarctica/Palmer';
|
||||
$tz['Antarctica/South_Pole'] = 'Antarctica/South Pole';
|
||||
$tz['Antarctica/Syowa'] = 'Antarctica/Syowa';
|
||||
$tz['Antarctica/Vostok'] = 'Antarctica/Vostok';
|
||||
$tz['Arctic/Longyearbyen'] = 'Arctic/Longyearbyen';
|
||||
$tz['Asia/Aden'] = 'Asia/Aden';
|
||||
$tz['Asia/Almaty'] = 'Asia/Almaty';
|
||||
$tz['Asia/Amman'] = 'Asia/Amman';
|
||||
$tz['Asia/Anadyr'] = 'Asia/Anadyr';
|
||||
$tz['Asia/Aqtau'] = 'Asia/Aqtau';
|
||||
$tz['Asia/Aqtobe'] = 'Asia/Aqtobe';
|
||||
$tz['Asia/Ashgabat'] = 'Asia/Ashgabat';
|
||||
$tz['Asia/Baghdad'] = 'Asia/Baghdad';
|
||||
$tz['Asia/Bahrain'] = 'Asia/Bahrain';
|
||||
$tz['Asia/Baku'] = 'Asia/Baku';
|
||||
$tz['Asia/Bangkok'] = 'Asia/Bangkok';
|
||||
$tz['Asia/Beirut'] = 'Asia/Beirut';
|
||||
$tz['Asia/Bishkek'] = 'Asia/Bishkek';
|
||||
$tz['Asia/Brunei'] = 'Asia/Brunei';
|
||||
$tz['Asia/Calcutta'] = 'Asia/Calcutta';
|
||||
$tz['Asia/Chungking'] = 'Asia/Chungking';
|
||||
$tz['Asia/Colombo'] = 'Asia/Colombo';
|
||||
$tz['Asia/Damascus'] = 'Asia/Damascus';
|
||||
$tz['Asia/Dhaka'] = 'Asia/Dhaka';
|
||||
$tz['Asia/Dili'] = 'Asia/Dili';
|
||||
$tz['Asia/Dubai'] = 'Asia/Dubai';
|
||||
$tz['Asia/Dushanbe'] = 'Asia/Dushanbe';
|
||||
$tz['Asia/Gaza'] = 'Asia/Gaza';
|
||||
$tz['Asia/Harbin'] = 'Asia/Harbin';
|
||||
$tz['Asia/Hong_Kong'] = 'Asia/Hong Kong';
|
||||
$tz['Asia/Hovd'] = 'Asia/Hovd';
|
||||
$tz['Asia/Irkutsk'] = 'Asia/Irkutsk';
|
||||
$tz['Asia/Jakarta'] = 'Asia/Jakarta';
|
||||
$tz['Asia/Jayapura'] = 'Asia/Jayapura';
|
||||
$tz['Asia/Jerusalem'] = 'Asia/Jerusalem';
|
||||
$tz['Asia/Kabul'] = 'Asia/Kabul';
|
||||
$tz['Asia/Kamchatka'] = 'Asia/Kamchatka';
|
||||
$tz['Asia/Karachi'] = 'Asia/Karachi';
|
||||
$tz['Asia/Kashgar'] = 'Asia/Kashgar';
|
||||
$tz['Asia/Katmandu'] = 'Asia/Katmandu';
|
||||
$tz['Asia/Krasnoyarsk'] = 'Asia/Krasnoyarsk';
|
||||
$tz['Asia/Kuala_Lumpur'] = 'Asia/Kuala Lumpur';
|
||||
$tz['Asia/Kuching'] = 'Asia/Kuching';
|
||||
$tz['Asia/Kuwait'] = 'Asia/Kuwait';
|
||||
$tz['Asia/Macao'] = 'Asia/Macao';
|
||||
$tz['Asia/Magadan'] = 'Asia/Magadan';
|
||||
$tz['Asia/Manila'] = 'Asia/Manila';
|
||||
$tz['Asia/Muscat'] = 'Asia/Muscat';
|
||||
$tz['Asia/Nicosia'] = 'Asia/Nicosia';
|
||||
$tz['Asia/Novosibirsk'] = 'Asia/Novosibirsk';
|
||||
$tz['Asia/Omsk'] = 'Asia/Omsk';
|
||||
$tz['Asia/Phnom_Penh'] = 'Asia/Phnom Penh';
|
||||
$tz['Asia/Pyongyang'] = 'Asia/Pyongyang';
|
||||
$tz['Asia/Qatar'] = 'Asia/Qatar';
|
||||
$tz['Asia/Rangoon'] = 'Asia/Rangoon';
|
||||
$tz['Asia/Riyadh'] = 'Asia/Riyadh';
|
||||
$tz['Asia/Saigon'] = 'Asia/Saigon';
|
||||
$tz['Asia/Samarkand'] = 'Asia/Samarkand';
|
||||
$tz['Asia/Seoul'] = 'Asia/Seoul';
|
||||
$tz['Asia/Shanghai'] = 'Asia/Shanghai';
|
||||
$tz['Asia/Singapore'] = 'Asia/Singapore';
|
||||
$tz['Asia/Taipei'] = 'Asia/Taipei';
|
||||
$tz['Asia/Tashkent'] = 'Asia/Tashkent';
|
||||
$tz['Asia/Tbilisi'] = 'Asia/Tbilisi';
|
||||
$tz['Asia/Tehran'] = 'Asia/Tehran';
|
||||
$tz['Asia/Thimphu'] = 'Asia/Thimphu';
|
||||
$tz['Asia/Tokyo'] = 'Asia/Tokyo';
|
||||
$tz['Asia/Ujung_Pandang'] = 'Asia/Ujung Pandang';
|
||||
$tz['Asia/Ulaanbaatar'] = 'Asia/Ulaanbaatar';
|
||||
$tz['Asia/Urumqi'] = 'Asia/Urumqi';
|
||||
$tz['Asia/Vientiane'] = 'Asia/Vientiane';
|
||||
$tz['Asia/Vladivostok'] = 'Asia/Vladivostok';
|
||||
$tz['Asia/Yakutsk'] = 'Asia/Yakutsk';
|
||||
$tz['Asia/Yekaterinburg'] = 'Asia/Yekaterinburg';
|
||||
$tz['Asia/Yerevan'] = 'Asia/Yerevan';
|
||||
$tz['Atlantic/Azores'] = 'Atlantic/Azores';
|
||||
$tz['Atlantic/Bermuda'] = 'Atlantic/Bermuda';
|
||||
$tz['Atlantic/Canary'] = 'Atlantic/Canary';
|
||||
$tz['Atlantic/Cape_Verde'] = 'Atlantic/Cape Verde';
|
||||
$tz['Atlantic/Faeroe'] = 'Atlantic/Faeroe';
|
||||
$tz['Atlantic/Jan_Mayen'] = 'Atlantic/Jan Mayen';
|
||||
$tz['Atlantic/Madeira'] = 'Atlantic/Madeira';
|
||||
$tz['Atlantic/Reykjavik'] = 'Atlantic/Reykjavik';
|
||||
$tz['Atlantic/South_Georgia'] = 'Atlantic/South Georgia';
|
||||
$tz['Atlantic/Stanley'] = 'Atlantic/Stanley';
|
||||
$tz['Atlantic/St_Helena'] = 'Atlantic/St Helena';
|
||||
$tz['Australia/Adelaide'] = 'Australia/Adelaide';
|
||||
$tz['Australia/Brisbane'] = 'Australia/Brisbane';
|
||||
$tz['Australia/Broken_Hill'] = 'Australia/Broken Hill';
|
||||
$tz['Australia/Darwin'] = 'Australia/Darwin';
|
||||
$tz['Australia/Hobart'] = 'Australia/Hobart';
|
||||
$tz['Australia/Lindeman'] = 'Australia/Lindeman';
|
||||
$tz['Australia/Lord_Howe'] = 'Australia/Lord Howe';
|
||||
$tz['Australia/Melbourne'] = 'Australia/Melbourne';
|
||||
$tz['Australia/Perth'] = 'Australia/Perth';
|
||||
$tz['Australia/Sydney'] = 'Australia/Sydney';
|
||||
$tz['Europe/Amsterdam'] = 'Europe/Amsterdam';
|
||||
$tz['Europe/Andorra'] = 'Europe/Andorra';
|
||||
$tz['Europe/Athens'] = 'Europe/Athens';
|
||||
$tz['Europe/Belfast'] = 'Europe/Belfast';
|
||||
$tz['Europe/Belgrade'] = 'Europe/Belgrade';
|
||||
$tz['Europe/Berlin'] = 'Europe/Berlin';
|
||||
$tz['Europe/Bratislava'] = 'Europe/Bratislava';
|
||||
$tz['Europe/Brussels'] = 'Europe/Brussels';
|
||||
$tz['Europe/Bucharest'] = 'Europe/Bucharest';
|
||||
$tz['Europe/Budapest'] = 'Europe/Budapest';
|
||||
$tz['Europe/Chisinau'] = 'Europe/Chisinau';
|
||||
$tz['Europe/Copenhagen'] = 'Europe/Copenhagen';
|
||||
$tz['Europe/Dublin'] = 'Europe/Dublin';
|
||||
$tz['Europe/Gibraltar'] = 'Europe/Gibraltar';
|
||||
$tz['Europe/Helsinki'] = 'Europe/Helsinki';
|
||||
$tz['Europe/Istanbul'] = 'Europe/Istanbul';
|
||||
$tz['Europe/Kaliningrad'] = 'Europe/Kaliningrad';
|
||||
$tz['Europe/Kiev'] = 'Europe/Kiev';
|
||||
$tz['Europe/Lisbon'] = 'Europe/Lisbon';
|
||||
$tz['Europe/Ljubljana'] = 'Europe/Ljubljana';
|
||||
$tz['Europe/London'] = 'Europe/London';
|
||||
$tz['Europe/Luxembourg'] = 'Europe/Luxembourg';
|
||||
$tz['Europe/Madrid'] = 'Europe/Madrid';
|
||||
$tz['Europe/Malta'] = 'Europe/Malta';
|
||||
$tz['Europe/Minsk'] = 'Europe/Minsk';
|
||||
$tz['Europe/Monaco'] = 'Europe/Monaco';
|
||||
$tz['Europe/Moscow'] = 'Europe/Moscow';
|
||||
$tz['Europe/Oslo'] = 'Europe/Oslo';
|
||||
$tz['Europe/Paris'] = 'Europe/Paris';
|
||||
$tz['Europe/Prague'] = 'Europe/Prague';
|
||||
$tz['Europe/Riga'] = 'Europe/Riga';
|
||||
$tz['Europe/Rome'] = 'Europe/Rome';
|
||||
$tz['Europe/Samara'] = 'Europe/Samara';
|
||||
$tz['Europe/San_Marino'] = 'Europe/San Marino';
|
||||
$tz['Europe/Sarajevo'] = 'Europe/Sarajevo';
|
||||
$tz['Europe/Simferopol'] = 'Europe/Simferopol';
|
||||
$tz['Europe/Skopje'] = 'Europe/Skopje';
|
||||
$tz['Europe/Sofia'] = 'Europe/Sofia';
|
||||
$tz['Europe/Stockholm'] = 'Europe/Stockholm';
|
||||
$tz['Europe/Tallinn'] = 'Europe/Tallinn';
|
||||
$tz['Europe/Tirane'] = 'Europe/Tirane';
|
||||
$tz['Europe/Uzhgorod'] = 'Europe/Uzhgorod';
|
||||
$tz['Europe/Vaduz'] = 'Europe/Vaduz';
|
||||
$tz['Europe/Vatican'] = 'Europe/Vatican';
|
||||
$tz['Europe/Vienna'] = 'Europe/Vienna';
|
||||
$tz['Europe/Vilnius'] = 'Europe/Vilnius';
|
||||
$tz['Europe/Warsaw'] = 'Europe/Warsaw';
|
||||
$tz['Europe/Zagreb'] = 'Europe/Zagreb';
|
||||
$tz['Europe/Zaporozhye'] = 'Europe/Zaporozhye';
|
||||
$tz['Europe/Zurich'] = 'Europe/Zurich';
|
||||
$tz['Indian/Antananarivo'] = 'Indian/Antananarivo';
|
||||
$tz['Indian/Chagos'] = 'Indian/Chagos';
|
||||
$tz['Indian/Christmas'] = 'Indian/Christmas';
|
||||
$tz['Indian/Cocos'] = 'Indian/Cocos';
|
||||
$tz['Indian/Comoro'] = 'Indian/Comoro';
|
||||
$tz['Indian/Kerguelen'] = 'Indian/Kerguelen';
|
||||
$tz['Indian/Mahe'] = 'Indian/Mahe';
|
||||
$tz['Indian/Maldives'] = 'Indian/Maldives';
|
||||
$tz['Indian/Mauritius'] = 'Indian/Mauritius';
|
||||
$tz['Indian/Mayotte'] = 'Indian/Mayotte';
|
||||
$tz['Indian/Reunion'] = 'Indian/Reunion';
|
||||
$tz['Pacific/Apia'] = 'Pacific/Apia';
|
||||
$tz['Pacific/Auckland'] = 'Pacific/Auckland';
|
||||
$tz['Pacific/Chatham'] = 'Pacific/Chatham';
|
||||
$tz['Pacific/Easter'] = 'Pacific/Easter';
|
||||
$tz['Pacific/Efate'] = 'Pacific/Efate';
|
||||
$tz['Pacific/Enderbury'] = 'Pacific/Enderbury';
|
||||
$tz['Pacific/Fakaofo'] = 'Pacific/Fakaofo';
|
||||
$tz['Pacific/Fiji'] = 'Pacific/Fiji';
|
||||
$tz['Pacific/Funafuti'] = 'Pacific/Funafuti';
|
||||
$tz['Pacific/Galapagos'] = 'Pacific/Galapagos';
|
||||
$tz['Pacific/Gambier'] = 'Pacific/Gambier';
|
||||
$tz['Pacific/Guadalcanal'] = 'Pacific/Guadalcanal';
|
||||
$tz['Pacific/Guam'] = 'Pacific/Guam';
|
||||
$tz['Pacific/Honolulu'] = 'Pacific/Honolulu';
|
||||
$tz['Pacific/Johnston'] = 'Pacific/Johnston';
|
||||
$tz['Pacific/Kiritimati'] = 'Pacific/Kiritimati';
|
||||
$tz['Pacific/Kosrae'] = 'Pacific/Kosrae';
|
||||
$tz['Pacific/Kwajalein'] = 'Pacific/Kwajalein';
|
||||
$tz['Pacific/Majuro'] = 'Pacific/Majuro';
|
||||
$tz['Pacific/Marquesas'] = 'Pacific/Marquesas';
|
||||
$tz['Pacific/Midway'] = 'Pacific/Midway';
|
||||
$tz['Pacific/Nauru'] = 'Pacific/Nauru';
|
||||
$tz['Pacific/Niue'] = 'Pacific/Niue';
|
||||
$tz['Pacific/Norfolk'] = 'Pacific/Norfolk';
|
||||
$tz['Pacific/Noumea'] = 'Pacific/Noumea';
|
||||
$tz['Pacific/Pago_Pago'] = 'Pacific/Pago Pago';
|
||||
$tz['Pacific/Palau'] = 'Pacific/Palau';
|
||||
$tz['Pacific/Pitcairn'] = 'Pacific/Pitcairn';
|
||||
$tz['Pacific/Ponape'] = 'Pacific/Ponape';
|
||||
$tz['Pacific/Port_Moresby'] = 'Pacific/Port Moresby';
|
||||
$tz['Pacific/Rarotonga'] = 'Pacific/Rarotonga';
|
||||
$tz['Pacific/Saipan'] = 'Pacific/Saipan';
|
||||
$tz['Pacific/Tahiti'] = 'Pacific/Tahiti';
|
||||
$tz['Pacific/Tarawa'] = 'Pacific/Tarawa';
|
||||
$tz['Pacific/Tongatapu'] = 'Pacific/Tongatapu';
|
||||
$tz['Pacific/Truk'] = 'Pacific/Truk';
|
||||
$tz['Pacific/Wake'] = 'Pacific/Wake';
|
||||
$tz['Pacific/Wallis'] = 'Pacific/Wallis';
|
||||
$tz['Pacific/Yap'] = 'Pacific/Yap';
|
||||
|
||||
$GLOBALS['tz'] = &$tz;
|
@ -1,163 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* registry.php -- Horde application registry.
|
||||
*
|
||||
* $Horde: horde/config/registry.php.dist,v 1.243 2004/10/05 20:08:13 chuck Exp $
|
||||
*
|
||||
* This configuration file is used by Horde to determine which Horde
|
||||
* applications are installed and where, as well as how they interact.
|
||||
*
|
||||
* Application registry
|
||||
* --------------------
|
||||
* The following settings register installed Horde applications.
|
||||
* By default, Horde assumes that the application directories live
|
||||
* inside the horde directory.
|
||||
*
|
||||
* Attribute Type Description
|
||||
* --------- ---- -----------
|
||||
* fileroot string The base filesystem path for the module's files
|
||||
* webroot string The base URI for the module
|
||||
* graphics string The base URI for the module images
|
||||
* icon string The URI for an icon to show in menus for the module
|
||||
* name string The name used in menus and descriptions for a module
|
||||
* status string 'inactive', 'hidden', 'notoolbar', 'heading',
|
||||
* 'block', 'admin', or 'active'.
|
||||
* provides string Service types the module provides.
|
||||
* initial_page string The initial (default) page (filename) for the module
|
||||
* templates string The filesystem path to the templates directory
|
||||
* menu_parent string The name of the 'heading' group that this app should
|
||||
* show up under.
|
||||
* target string The (optional) target frame for the link.
|
||||
*/
|
||||
|
||||
// We try to automatically determine the proper webroot for Horde
|
||||
// here. This still assumes that applications live under horde/. If
|
||||
// this results in incorrect results for you, simply change the two
|
||||
// uses of the $webroot variable in the 'horde' stanza below.
|
||||
//
|
||||
// Note for Windows users: the below assumes that your PHP_SELF
|
||||
// variable uses forward slashes. If it does not, you'll have to tweak
|
||||
// this.
|
||||
if (isset($_SERVER['PHP_SELF'])) {
|
||||
$parts = preg_split(';/;', $_SERVER['PHP_SELF'], 2, PREG_SPLIT_NO_EMPTY);
|
||||
$webroot = strstr(dirname(__FILE__), '/' . array_shift($parts));
|
||||
if ($webroot !== false) {
|
||||
$webroot = preg_replace(';/config$;', '', $webroot);
|
||||
} else {
|
||||
$webroot = '/horde';
|
||||
}
|
||||
} else {
|
||||
$webroot = '/horde';
|
||||
}
|
||||
|
||||
$this->applications['horde'] = array(
|
||||
'fileroot' => dirname(__FILE__) . '/..',
|
||||
'webroot' => $webroot,
|
||||
'initial_page' => 'login.php',
|
||||
'icon' => $webroot . '/graphics/horde.png',
|
||||
'name' => _("Horde"),
|
||||
'status' => 'active',
|
||||
'templates' => dirname(__FILE__) . '/../templates',
|
||||
'provides' => 'horde'
|
||||
);
|
||||
|
||||
#$this->applications['mnemo'] = array(
|
||||
# 'fileroot' => dirname(__FILE__) . '/../mnemo',
|
||||
# 'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
# 'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
# 'name' => _("Notes"),
|
||||
# 'status' => 'active',
|
||||
# 'provides' => 'notes',
|
||||
# 'menu_parent' => 'organizing'
|
||||
#);
|
||||
|
||||
$this->applications['egwnotessync'] = array(
|
||||
'fileroot' => EGW_SERVER_ROOT.'/syncml/notes',
|
||||
'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
'name' => _("Notes"),
|
||||
'status' => 'active',
|
||||
'provides' => array('notes', 'sifnotes', 'snote'),
|
||||
'menu_parent' => 'organizing'
|
||||
);
|
||||
|
||||
$this->applications['egwcontactssync'] = array(
|
||||
'fileroot' => EGW_SERVER_ROOT.'/syncml/contacts',
|
||||
'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
'name' => _("Contacts"),
|
||||
'status' => 'active',
|
||||
'provides' => array('contacts', 'sifcontacts', 'scard', 'card'),
|
||||
'menu_parent' => 'organizing'
|
||||
);
|
||||
|
||||
#$this->applications['egwsifcontactssync'] = array(
|
||||
# 'fileroot' => EGW_SERVER_ROOT.'/syncml/sifcontacts',
|
||||
# 'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
# 'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
# 'name' => _("SIF Contacts"),
|
||||
# 'status' => 'active',
|
||||
# 'provides' => 'sifcontacts',
|
||||
# 'menu_parent' => 'organizing'
|
||||
#);
|
||||
|
||||
$this->applications['egwcalendarsync'] = array(
|
||||
'fileroot' => EGW_SERVER_ROOT.'/syncml/calendar',
|
||||
'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
'name' => _("Calendar"),
|
||||
'status' => 'active',
|
||||
'provides' => array('calendar', 'sifcalendar', 'scal', 'events'),
|
||||
'menu_parent' => 'organizing'
|
||||
);
|
||||
|
||||
#$this->applications['egwsifcalendarsync'] = array(
|
||||
# 'fileroot' => EGW_SERVER_ROOT.'/syncml/sifcalendar',
|
||||
# 'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
# 'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
# 'name' => _("Calendar"),
|
||||
# 'status' => 'active',
|
||||
# 'provides' => 'sifcalendar',
|
||||
# 'menu_parent' => 'organizing'
|
||||
#);
|
||||
|
||||
$this->applications['egwtaskssync'] = array(
|
||||
'fileroot' => EGW_SERVER_ROOT.'/syncml/tasks',
|
||||
'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
'name' => _("Tasks"),
|
||||
'status' => 'active',
|
||||
'provides' => array('tasks', 'siftasks', 'stask', 'jobs'),
|
||||
'menu_parent' => 'organizing'
|
||||
);
|
||||
|
||||
#$this->applications['egwsiftaskssync'] = array(
|
||||
# 'fileroot' => EGW_SERVER_ROOT.'/syncml/siftasks',
|
||||
# 'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
# 'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
# 'name' => _("SIFTasks"),
|
||||
# 'status' => 'active',
|
||||
# 'provides' => array('siftasks', 'stask'),
|
||||
# 'menu_parent' => 'organizing'
|
||||
#);
|
||||
|
||||
$this->applications['egwcaltaskssync'] = array(
|
||||
'fileroot' => EGW_SERVER_ROOT.'/syncml/caltasks',
|
||||
'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
'name' => _("Calendar and Tasks"),
|
||||
'status' => 'active',
|
||||
'provides' => 'caltasks',
|
||||
'menu_parent' => 'organizing'
|
||||
);
|
||||
|
||||
$this->applications['egwconfigurationsync'] = array(
|
||||
'fileroot' => EGW_SERVER_ROOT.'/syncml/configuration',
|
||||
'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
|
||||
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
|
||||
'name' => _("Funambol Configurations"),
|
||||
'status' => 'active',
|
||||
'provides' => array('configuration'),
|
||||
'menu_parent' => 'organizing'
|
||||
);
|
||||
|
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Horde base inclusion file.
|
||||
*
|
||||
* This file brings in all of the dependencies that Horde
|
||||
* framework-level scripts will need, and sets up objects that all
|
||||
* scripts use.
|
||||
*
|
||||
* Note: This base file does _not_ check authentication, so as to
|
||||
* avoid an infinite loop on the Horde login page. You'll need to do
|
||||
* it yourself in framework-level pages.
|
||||
*
|
||||
* $Horde: horde/lib/base.php,v 1.41 2005/01/03 14:35:14 jan Exp $
|
||||
*
|
||||
* Copyright 1999-2005 Chuck Hagenbuch <chuck@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.
|
||||
*/
|
||||
|
||||
// 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', dirname(__FILE__) . '/..');
|
||||
#}
|
||||
|
||||
// Load the Horde Framework core, and set up inclusion paths.
|
||||
#require_once HORDE_BASE . '/lib/core.php';
|
||||
|
||||
// Registry.
|
||||
if (Util::nonInputVar('session_control') == 'none') {
|
||||
$registry = &Registry::singleton(HORDE_SESSION_NONE);
|
||||
} else {
|
||||
$registry = &Registry::singleton();
|
||||
}
|
||||
#if (is_a(($pushed = $registry->pushApp('horde', !defined('AUTH_HANDLER'))), 'PEAR_Error')) {
|
||||
# if ($pushed->getCode() == 'permission_denied') {
|
||||
# Horde::authenticationFailureRedirect();
|
||||
# }
|
||||
# Horde::fatal($pushed, __FILE__, __LINE__, false);
|
||||
#}
|
||||
$conf = &$GLOBALS['conf'];
|
||||
#@define('HORDE_TEMPLATES', $registry->get('templates'));
|
||||
|
||||
// Notification System.
|
||||
#$notification = &Notification::singleton();
|
||||
#$notification->attach('status');
|
||||
|
||||
/* Set up the menu. */
|
||||
#require_once 'Horde/Menu.php';
|
||||
#$menu = new Menu();
|
||||
|
||||
// Compress output
|
||||
#Horde::compressOutput();
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Horde Application Framework core services file.
|
||||
*
|
||||
* This file sets up any necessary include path variables and includes
|
||||
* the minimum required Horde libraries.
|
||||
*
|
||||
* $Horde: horde/lib/core.php,v 1.27 2005/01/03 14:35:14 jan Exp $
|
||||
*
|
||||
* Copyright 1999-2005 Chuck Hagenbuch <chuck@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.
|
||||
*/
|
||||
|
||||
/* Turn PHP stuff off that can really screw things up. */
|
||||
ini_set('magic_quotes_sybase', 0);
|
||||
ini_set('magic_quotes_runtime', 0);
|
||||
|
||||
/* If the Horde Framework packages are not installed in PHP's global
|
||||
* 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());
|
||||
|
||||
@define('EGW_BASE', realpath(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/');
|
||||
}
|
||||
|
||||
$save_include_path = set_include_path(HORDE_BASE . PATH_SEPARATOR . get_include_path());
|
||||
/* PEAR base class. */
|
||||
include_once 'PEAR.php';
|
||||
|
||||
/* Horde core classes. */
|
||||
include_once 'Horde.php';
|
||||
include_once 'Horde/Registry.php';
|
||||
#include_once 'Horde/DataTree.php';
|
||||
include_once 'Horde/String.php';
|
||||
include_once 'Horde/Date.php';
|
||||
include_once 'Horde/NLS.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();
|
||||
}
|
||||
*/
|
||||
// restore EGroupware include path to NOT conflict with new Horde code installed in include-path
|
||||
set_include_path($save_include_path);
|
Loading…
Reference in New Issue
Block a user