mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-02-17 19:01:04 +01:00
Merge SyncML Extensions with 1.6
This commit is contained in:
parent
781048414b
commit
18ff8a6fa7
@ -5,6 +5,7 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @author Cornelius Weiss <egw@von-und-zu-weiss.de>
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @package addressbook
|
||||
* @copyright (c) 2005-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de>
|
||||
@ -246,6 +247,49 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the availible addressbooks of the user
|
||||
*
|
||||
* @param int $required=EGW_ACL_READ required rights on the addressbook or multiple rights or'ed together,
|
||||
* to return only addressbooks fullfilling all the given rights
|
||||
* @param string $extra_label first label if given (already translated)
|
||||
* @return array with owner => label pairs
|
||||
*/
|
||||
function get_addressbooks($required=EGW_ACL_READ,$extra_label=null)
|
||||
{
|
||||
//echo "uicontacts::get_addressbooks($required,$include_all) grants="; _debug_array($this->grants);
|
||||
|
||||
$addressbooks = array();
|
||||
if ($extra_label) $addressbooks[''] = $extra_label;
|
||||
$addressbooks[$this->user] = lang('Personal');
|
||||
// add all group addressbooks the user has the necessary rights too
|
||||
foreach($this->grants as $uid => $rights)
|
||||
{
|
||||
if (($rights & $required) == $required && $GLOBALS['egw']->accounts->get_type($uid) == 'g')
|
||||
{
|
||||
$addressbooks[$uid] = lang('Group %1',$GLOBALS['egw']->accounts->id2name($uid));
|
||||
}
|
||||
}
|
||||
if (($this->grants[0] & $required) == $required && !$GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'])
|
||||
{
|
||||
$addressbooks[0] = lang('Accounts');
|
||||
}
|
||||
// add all other user addressbooks the user has the necessary rights too
|
||||
foreach($this->grants as $uid => $rights)
|
||||
{
|
||||
if ($uid != $this->user && ($rights & $required) == $required && $GLOBALS['egw']->accounts->get_type($uid) == 'u')
|
||||
{
|
||||
$addressbooks[$uid] = $GLOBALS['egw']->common->grab_owner_name($uid);
|
||||
}
|
||||
}
|
||||
if ($this->private_addressbook)
|
||||
{
|
||||
$addressbooks[$this->user.'p'] = lang('Private');
|
||||
}
|
||||
//_debug_array($addressbooks);
|
||||
return $addressbooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate the file_as string from the contact and the file_as type
|
||||
*
|
||||
@ -265,8 +309,8 @@ class addressbook_bo extends addressbook_so
|
||||
$contact['n_fn'],$contact['org_name'],$contact['org_unit'],$contact['adr_one_locality']),$type);
|
||||
|
||||
// removing empty delimiters, caused by empty contact fields
|
||||
$fileas = str_replace(array(', , : ',', : ',': , ',', , ',': : '),array(': ',': ',': ',', ',': '),$fileas);
|
||||
while ($fileas{0} == ':' || $fileas{0} == ',') $fileas = substr($fileas,2);
|
||||
$fileas = str_replace(array(', , : ',', : ',': , ',', , ',': : ',' ()'),array(': ',': ',': ',', ',': ',''),$fileas);
|
||||
while ($fileas[0] == ':' || $fileas[0] == ',') $fileas = substr($fileas,2);
|
||||
while (substr($fileas,-2) == ': ' || substr($fileas,-2) == ', ') $fileas = substr($fileas,0,-2);
|
||||
|
||||
//echo "<p align=right>bocontacts::fileas(,$type)='$fileas'</p>\n";
|
||||
@ -327,6 +371,70 @@ class addressbook_bo extends addressbook_so
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set n_fileas (and n_fn) in contacts of all users (called by Admin >> Addressbook >> Site configuration (Admin only)
|
||||
*
|
||||
* If $all all fileas fields will be set, if !$all only empty ones
|
||||
*
|
||||
* @param string $fileas_type '' or type of $this->fileas_types
|
||||
* @param int $all=false update all contacts or only ones with empty values
|
||||
* @param int &$errors=null on return number of errors
|
||||
* @return int|boolean number of contacts updated, false for wrong fileas type
|
||||
*/
|
||||
function set_all_fileas($fileas_type,$all=false,&$errors=null,$ignore_acl=false)
|
||||
{
|
||||
if ($type != '' && !in_array($type,$this->fileas_types))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ($ignore_acl)
|
||||
{
|
||||
unset($this->somain->grants); // to NOT limit search to contacts readable by current user
|
||||
}
|
||||
// to be able to work on huge contact repositories we read the contacts in chunks of 100
|
||||
for($n = $updated = $errors = 0; ($contacts = parent::search($all ? array() : array(
|
||||
'n_fileas IS NULL',
|
||||
"n_fileas=''",
|
||||
'n_fn IS NULL',
|
||||
"n_fn=''",
|
||||
),false,'','','',false,'OR',array($n*100,100))); ++$n)
|
||||
{
|
||||
foreach($contacts as $contact)
|
||||
{
|
||||
$old_fn = $contact['n_fn'];
|
||||
$old_fileas = $contact['n_fileas'];
|
||||
$contact['n_fn'] = $this->fullname($contact);
|
||||
// only update fileas if type is given AND (all should be updated or n_fileas is empty)
|
||||
if ($fileas_type && ($all || empty($contact['n_fileas'])))
|
||||
{
|
||||
$contact['n_fileas'] = $this->fileas($contact,$fileas_type);
|
||||
}
|
||||
if ($old_fileas != $contact['n_fileas'] || $old_fn != $contact['n_fn'])
|
||||
{
|
||||
//echo "<p>('$old_fileas' != '{$contact['n_fileas']}' || '$old_fn' != '{$contact['n_fn']}')=".array2string($old_fileas != $contact['n_fileas'] || $old_fn != $contact['n_fn'])."</p>\n";
|
||||
// only specify/write updated fields plus "keys"
|
||||
$contact = array_intersect_key($contact,array(
|
||||
'id' => true,
|
||||
'owner' => true,
|
||||
'private' => true,
|
||||
'account_id' => true,
|
||||
'uid' => true,
|
||||
)+($old_fileas != $contact['n_fileas'] ? array('n_fileas' => true) : array())+($old_fn != $contact['n_fn'] ? array('n_fn' => true) : array()));
|
||||
if ($this->save($contact,$ignore_acl))
|
||||
{
|
||||
$updated++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $updated;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get full name from the name-parts
|
||||
*
|
||||
@ -335,8 +443,13 @@ class addressbook_bo extends addressbook_so
|
||||
*/
|
||||
function fullname($contact)
|
||||
{
|
||||
if (empty($contact['n_family']) && empty($contact['n_given'])) {
|
||||
$cpart = array('org_name');
|
||||
} else {
|
||||
$cpart = array('n_prefix','n_given','n_middle','n_family','n_suffix');
|
||||
}
|
||||
$parts = array();
|
||||
foreach(array('n_prefix','n_given','n_middle','n_family','n_suffix') as $n)
|
||||
foreach($cpart as $n)
|
||||
{
|
||||
if ($contact[$n]) $parts[] = $contact[$n];
|
||||
}
|
||||
@ -498,14 +611,15 @@ class addressbook_bo extends addressbook_so
|
||||
return false;
|
||||
}
|
||||
// convert categories
|
||||
if (is_array($contact['cat_id'])) {
|
||||
if (is_array($contact['cat_id']))
|
||||
{
|
||||
$contact['cat_id'] = implode(',',$contact['cat_id']);
|
||||
}
|
||||
// last modified
|
||||
$contact['modifier'] = $this->user;
|
||||
$contact['modified'] = $this->now_su;
|
||||
// set full name and fileas from the content
|
||||
if (isset($contact['n_family']) && isset($contact['n_given']))
|
||||
if (!isset($contact['n_fn']))
|
||||
{
|
||||
$contact['n_fn'] = $this->fullname($contact);
|
||||
if (isset($contact['org_name'])) $contact['n_fileas'] = $this->fileas($contact);
|
||||
@ -610,7 +724,7 @@ class addressbook_bo extends addressbook_so
|
||||
function read_org($org_id)
|
||||
{
|
||||
if (!$org_id) return false;
|
||||
|
||||
if (strpos($org_id,'*AND*')!== false) $org_id = str_replace('*AND*','&',$org_id);
|
||||
$org = array();
|
||||
foreach(explode('|||',$org_id) as $part)
|
||||
{
|
||||
@ -985,7 +1099,7 @@ class addressbook_bo extends addressbook_so
|
||||
{
|
||||
foreach($event['participants'] as $uid => $status)
|
||||
{
|
||||
if ($uid{0} != 'c' || ($status == 'R' && !$GLOBALS['egw_info']['user']['preferences']['calendar']['show_rejected']))
|
||||
if ($uid[0] != 'c' || ($status == 'R' && !$GLOBALS['egw_info']['user']['preferences']['calendar']['show_rejected']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1326,7 +1440,7 @@ class addressbook_bo extends addressbook_so
|
||||
{
|
||||
$cat_name = substr($cat_name, 2);
|
||||
}
|
||||
$cat_id = $this->categories->add(array('name' => $cat_name,'descr' => $cat_name));
|
||||
$cat_id = $this->categories->add(array('name' => $cat_name, 'descr' => $cat_name, 'access' => 'private'));
|
||||
}
|
||||
|
||||
if ($cat_id)
|
||||
@ -1357,9 +1471,9 @@ class addressbook_bo extends addressbook_so
|
||||
$cat_list = array();
|
||||
foreach($cat_id_list as $cat_id)
|
||||
{
|
||||
if ($cat_data = $this->categories->return_single($cat_id))
|
||||
if ($cat_id && ($cat_name = $this->categories->id2name($cat_id)) && $cat_name != '--')
|
||||
{
|
||||
$cat_list[] = $cat_data[0]['name'];
|
||||
$cat_list[] = $cat_name;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1368,15 +1482,276 @@ class addressbook_bo extends addressbook_so
|
||||
|
||||
function fixup_contact(&$contact)
|
||||
{
|
||||
if (!isset($contact['n_fn']) || empty($contact['n_fn']))
|
||||
if (empty($contact['n_fn']))
|
||||
{
|
||||
$contact['n_fn'] = $this->fullname($contact);
|
||||
}
|
||||
|
||||
if (!isset($contact['n_fileas']) || empty($contact['n_fileas']))
|
||||
if (empty($contact['n_fileas']))
|
||||
{
|
||||
$contact['n_fileas'] = $this->fileas($contact);
|
||||
}
|
||||
}
|
||||
|
||||
function all_empty(&$_contact, &$fields)
|
||||
{
|
||||
$retval = true;
|
||||
foreach ($fields as $field) {
|
||||
if (isset($_contact[$field]) && !empty($_contact[$field])) {
|
||||
$retval = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to find a matching db entry
|
||||
*
|
||||
* @param array $contact the contact data we try to find
|
||||
* @param boolean $relax=false if asked to relax, we only match against some key fields
|
||||
* @return the contact_id of the matching entry or false (if none matches)
|
||||
*/
|
||||
function find_contact($contact, $relax=false)
|
||||
{
|
||||
if ($contact['id'] && ($found = $this->read($contact['id'])))
|
||||
{
|
||||
// We only do a simple consistency check
|
||||
if ((empty($found['n_family']) || $found['n_family'] == $contact['n_family'])
|
||||
&& (empty($found['n_given']) || $found['n_given'] == $contact['n_given'])
|
||||
&& (empty($found['org_name']) || $found['org_name'] == $contact['org_name']))
|
||||
{
|
||||
return $found['id'];
|
||||
}
|
||||
}
|
||||
unset($contact['id']);
|
||||
|
||||
$columns_to_search = array('contact_id',
|
||||
'n_family', 'n_given', 'n_middle', 'n_prefix', 'n_suffix',
|
||||
'bday', 'org_name', 'org_unit', 'title', 'role',
|
||||
'email', 'email_home');
|
||||
$tolerance_fields = array('contact_id',
|
||||
'n_middle', 'n_prefix', 'n_suffix',
|
||||
'bday', 'org_unit', 'title', 'role',
|
||||
'email', 'email_home');
|
||||
$addr_one_fields = array('adr_one_street',
|
||||
'adr_one_locality', 'adr_one_region',
|
||||
'adr_one_postalcode', 'adr_one_countryname');
|
||||
$addr_two_fields = array('adr_two_street',
|
||||
'adr_two_locality', 'adr_two_region',
|
||||
'adr_two_postalcode', 'adr_two_countryname');
|
||||
$no_addr_one = array();
|
||||
$no_addr_two = array();
|
||||
|
||||
if (!empty($contact['owner']))
|
||||
{
|
||||
$columns_to_search += array('owner');
|
||||
}
|
||||
|
||||
$backend =& $this->get_backend();
|
||||
|
||||
// define filter for empty address one
|
||||
foreach ($addr_one_fields as $field)
|
||||
{
|
||||
if (!($db_col = array_search($field, $backend->db_cols)))
|
||||
{
|
||||
$db_col = $field;
|
||||
}
|
||||
$no_addr_one[] = "(" . $db_col . " IS NULL OR " . $db_col . " = '')";
|
||||
}
|
||||
|
||||
// define filter for empty address two
|
||||
foreach ($addr_two_fields as $field)
|
||||
{
|
||||
if (!($db_col = array_search($field, $backend->db_cols)))
|
||||
{
|
||||
$db_col = $field;
|
||||
}
|
||||
$no_addr_two[] = "(" . $db_col . " IS NULL OR " . $db_col . " = '')";
|
||||
}
|
||||
|
||||
$result = false;
|
||||
|
||||
$criteria = array();
|
||||
$empty_columns = array();
|
||||
foreach ($columns_to_search as $field)
|
||||
{
|
||||
if (!isset($contact[$field]) || empty($contact[$field])) {
|
||||
// Not every device supports all fields
|
||||
if (!in_array($field, $tolerance_fields))
|
||||
{
|
||||
if (!($db_col = array_search($field, $backend->db_cols)))
|
||||
{
|
||||
$db_col = $field;
|
||||
}
|
||||
$empty_columns[] = "(" . $db_col . " IS NULL OR " . $db_col . " = '')";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$relax || !in_array($field, $tolerance_fields))
|
||||
{
|
||||
$criteria[$field] = $contact[$field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$filter = $empty_columns;
|
||||
|
||||
if (!$relax)
|
||||
{
|
||||
// We use addresses only for strong matching
|
||||
|
||||
if ($this->all_empty($contact, $addr_one_fields))
|
||||
{
|
||||
$filter = $filter + $no_addr_one;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($addr_one_fields as $field)
|
||||
{
|
||||
if (!isset($contact[$field]) || empty($contact[$field]))
|
||||
{
|
||||
if (!($db_col = array_search($field, $backend->db_cols)))
|
||||
{
|
||||
$db_col = $field;
|
||||
}
|
||||
$filter[] = "(" . $db_col . " IS NULL OR " . $db_col . " = '')";
|
||||
}
|
||||
else
|
||||
{
|
||||
$criteria[$field] = $contact[$field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->all_empty($contact, $addr_two_fields))
|
||||
{
|
||||
$filter = $filter + $no_addr_two;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($addr_two_fields as $field)
|
||||
{
|
||||
if (!isset($contact[$field]) || empty($contact[$field]))
|
||||
{
|
||||
if (!($db_col = array_search($field, $backend->db_cols)))
|
||||
{
|
||||
$db_col = $field;
|
||||
}
|
||||
$filter[] = "(" . $db_col . " IS NULL OR " . $db_col . " = '')";
|
||||
}
|
||||
else
|
||||
{
|
||||
$criteria[$field] = $contact[$field];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage("Addressbook find step 1:\n" . print_r($criteria, true) .
|
||||
"filter:\n" . print_r($filter, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// first try full match
|
||||
if (($foundContacts = parent::search($criteria, true, '', '', '', False, 'AND', false, $filter)))
|
||||
{
|
||||
$result = $foundContacts[0]['id'];
|
||||
}
|
||||
|
||||
// No need for more searches for relaxed matching
|
||||
if (!$relax && !$result && !$this->all_empty($contact, $addr_one_fields)
|
||||
&& $this->all_empty($contact, $addr_two_fields))
|
||||
{
|
||||
// try given address and ignore the second one in EGW
|
||||
$filter = array_diff($filter, $no_addr_two);
|
||||
|
||||
Horde::logMessage("Addressbook find step 2:\n" . print_r($criteria, true) .
|
||||
"filter:\n" . print_r($filter, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (($foundContacts = parent::search($criteria, true, '', '', '', False, 'AND', false, $filter)))
|
||||
{
|
||||
$result = $foundContacts[0]['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// try address as home address -- some devices don't qualify addresses
|
||||
$filter = $empty_columns;
|
||||
foreach ($addr_two_fields as $key => $field)
|
||||
{
|
||||
if (isset($criteria[$addr_one_fields[$key]]))
|
||||
{
|
||||
$criteria[$field] = $criteria[$addr_one_fields[$key]];
|
||||
unset($criteria[$addr_one_fields[$key]]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!($db_col = array_search($field,$backend->db_cols)))
|
||||
{
|
||||
$db_col = $field;
|
||||
}
|
||||
$filter[] = "(" . $db_col . " IS NULL OR " . $db_col . " = '')";
|
||||
}
|
||||
}
|
||||
|
||||
$filter = $filter + $no_addr_one;
|
||||
|
||||
Horde::logMessage("Addressbook find step 3:\n" . print_r($criteria, true) .
|
||||
"filter:\n" . print_r($filter, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (($foundContacts = parent::search($criteria, true, '', '', '', False, 'AND', false, $filter)))
|
||||
{
|
||||
$result = $foundContacts[0]['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!$relax && !$result)
|
||||
{ // No more searches for relaxed matching, try again after address swap
|
||||
|
||||
$filter = $empty_columns;
|
||||
|
||||
foreach ($addr_one_fields as $key => $field)
|
||||
{
|
||||
$_temp_set = false;
|
||||
if (isset($criteria[$field]))
|
||||
{
|
||||
$_temp = $criteria[$field];
|
||||
$_temp_set = true;
|
||||
unset($criteria[$field]);
|
||||
}
|
||||
if (isset($criteria[$addr_two_fields[$key]]))
|
||||
{
|
||||
$criteria[$field] = $criteria[$addr_two_fields[$key]];
|
||||
unset($criteria[$addr_two_fields[$key]]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!($db_col = array_search($field,$backend->db_cols)))
|
||||
{
|
||||
$db_col = $field;
|
||||
}
|
||||
$filter[] = "(" . $db_col . " IS NULL OR " . $db_col . " = '')";
|
||||
}
|
||||
if ($_temp_set)
|
||||
{
|
||||
$criteria[$addr_two_fields[$key]] = $_temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!($db_col = array_search($addr_two_fields[$key],$backend->db_cols)))
|
||||
{
|
||||
$db_col = $field;
|
||||
}
|
||||
$filter[] = "(" . $db_col . " IS NULL OR " . $db_col . " = '')";
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage("Addressbook find step 4:\n" . print_r($criteria, true) .
|
||||
"filter:\n" . print_r($filter, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if(($foundContacts = parent::search($criteria, true, '', '', '', False, 'AND', false, $filter)))
|
||||
{
|
||||
$result = $foundContacts[0]['id'];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ class addressbook_merge // extends bo_merge
|
||||
switch($field['type'])
|
||||
{
|
||||
case 'select-account':
|
||||
if ($value) $value = $GLOBALS['egw']->common->grab_owner_name($value);
|
||||
if ($value) $value = common::grab_owner_name($value);
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
@ -139,8 +139,8 @@ class addressbook_merge // extends bo_merge
|
||||
{
|
||||
$format = $field['len'] ? $field['len'] : ($field['type'] == 'date' ? 'Y-m-d' : 'Y-m-d H:i:s');
|
||||
$date = array_combine(preg_split('/[\\/. :-]/',$format),preg_split('/[\\/. :-]/',$value));
|
||||
$value = $GLOBALS['egw']->common->dateformatorder($date['Y'],$date['m'],$date['d'],true);
|
||||
if (isset($date['H'])) $value .= ' '.$GLOBALS['egw']->common->formattime($date['H'],$date['i']);
|
||||
$value = common::dateformatorder($date['Y'],$date['m'],$date['d'],true);
|
||||
if (isset($date['H'])) $value .= ' '.common::formattime($date['H'],$date['i']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
* @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
|
||||
@ -94,6 +95,10 @@ class addressbook_sif extends addressbook_bo
|
||||
'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) {
|
||||
}
|
||||
|
||||
@ -108,13 +113,12 @@ class addressbook_sif extends addressbook_bo
|
||||
$this->sifData .= $_data;
|
||||
}
|
||||
|
||||
function siftoegw($_sifdata) {
|
||||
$sifData = base64_decode($_sifdata);
|
||||
function siftoegw($sifData) {
|
||||
|
||||
#$tmpfname = tempnam('/tmp/sync/contents','sifc_');
|
||||
|
||||
#$handle = fopen($tmpfname, "w");
|
||||
#fwrite($handle, $sifdata);
|
||||
#fwrite($handle, $sifData);
|
||||
#fclose($handle);
|
||||
|
||||
$this->xml_parser = xml_parser_create('UTF-8');
|
||||
@ -131,6 +135,7 @@ class addressbook_sif extends addressbook_bo
|
||||
}
|
||||
|
||||
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':
|
||||
@ -164,25 +169,17 @@ class addressbook_sif extends addressbook_bo
|
||||
* @param string $_sifdata
|
||||
* @return boolean/int/string contact-id or false, if not found
|
||||
*/
|
||||
function search($_sifdata,$contentID=null)
|
||||
function search($_sifdata, $contentID=null, $relax=false)
|
||||
{
|
||||
if(!$contact = $this->siftoegw($_sifdata))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ($contentID) {
|
||||
$contact['contact_id'] = $contentID;
|
||||
}
|
||||
// patch from Di Guest says: we need to ignore the n_fileas
|
||||
unset($contact['n_fileas']);
|
||||
// we probably need to ignore even more as we do in vcaladdressbook
|
||||
$result = false;
|
||||
|
||||
if(($foundContacts = addressbook_bo::search($contact)))
|
||||
{
|
||||
error_log(print_r($foundContacts,true));
|
||||
return $foundContacts[0]['id'];
|
||||
if($contact = $this->siftoegw($_sifdata)) {
|
||||
if ($contentID) {
|
||||
$contact['contact_id'] = $contentID;
|
||||
}
|
||||
$result = $this->find_contact($contact, $relax);
|
||||
}
|
||||
return false;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,8 +188,9 @@ class addressbook_sif extends addressbook_bo
|
||||
* @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)
|
||||
function addSIF($_sifdata, $_abID=null, $merge=false)
|
||||
{
|
||||
#error_log('ABID: '.$_abID);
|
||||
#error_log(base64_decode($_sifdata));
|
||||
@ -209,24 +207,25 @@ class addressbook_sif extends addressbook_bo
|
||||
}
|
||||
|
||||
/**
|
||||
* return a vcard
|
||||
* return a sifc
|
||||
*
|
||||
* @param int $_id the id of the contact
|
||||
* @param int $_vcardProfile profile id for mapping from vcard values to egw addressbook
|
||||
* @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)))
|
||||
{
|
||||
if(!($entry = $this->read($_id))) {
|
||||
return false;
|
||||
}
|
||||
$sifContact = '<contact>';
|
||||
|
||||
$sifContact = self::xml_decl . "\n<contact>" . self::SIF_decl;
|
||||
|
||||
#error_log(print_r($entry,true));
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
|
||||
// fillup some defaults such as n_fn and n_fileas is needed
|
||||
$this->fixup_contact($entry);
|
||||
@ -242,15 +241,6 @@ class addressbook_sif extends addressbook_bo
|
||||
|
||||
switch($sifField)
|
||||
{
|
||||
// TODO handle multiple categories
|
||||
case 'Categories':
|
||||
if(!empty($value)) {
|
||||
$value = implode("; ", $this->get_categories($value));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
$sifContact .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Sensitivity':
|
||||
$value = 2 * $value; // eGW private is 0 (public) or 1 (private)
|
||||
$sifContact .= "<$sifField>$value</$sifField>";
|
||||
@ -261,13 +251,22 @@ class addressbook_sif extends addressbook_bo
|
||||
#$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:
|
||||
$sifContact .= "<$sifField>".trim($value)."</$sifField>";
|
||||
$value = @htmlspecialchars(trim($value), ENT_QUOTES, 'utf-8');
|
||||
$sifContact .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sifContact .= "</contact>";
|
||||
|
||||
return base64_encode($sifContact);
|
||||
return $sifContact;
|
||||
}
|
||||
}
|
||||
|
@ -872,7 +872,8 @@ class addressbook_so
|
||||
/**
|
||||
* Get the availible distribution lists for a user
|
||||
*
|
||||
* @param int $required=EGW_ACL_READ required rights on the list
|
||||
* @param int $required=EGW_ACL_READ required rights on the list or multiple rights or'ed together,
|
||||
* to return only lists fullfilling all the given rights
|
||||
* @param string $extra_labels=null first labels if given (already translated)
|
||||
* @return array with id => label pairs or false if backend does not support lists
|
||||
*/
|
||||
@ -883,7 +884,7 @@ class addressbook_so
|
||||
$uids = array();
|
||||
foreach($this->grants as $uid => $rights)
|
||||
{
|
||||
if ($rights & $required)
|
||||
if (($rights & $required) == $required)
|
||||
{
|
||||
$uids[] = $uid;
|
||||
}
|
||||
|
@ -30,6 +30,16 @@ class addressbook_sql extends so_sql
|
||||
var $contact_repository = 'sql';
|
||||
var $grants;
|
||||
|
||||
/**
|
||||
* join to show only active account (and not already expired ones)
|
||||
*/
|
||||
const ACOUNT_ACTIVE_JOIN = ' LEFT JOIN egw_accounts ON egw_addressbook.account_id=egw_accounts.account_id';
|
||||
/**
|
||||
* filter to show only active account (and not already expired ones)
|
||||
* UNIX_TIMESTAMP(NOW()) gets replaced with value of time() in the code!
|
||||
*/
|
||||
const ACOUNT_ACTIVE_FILTER = '(account_expires IS NULL OR account_expires = -1 OR account_expires > UNIX_TIMESTAMP(NOW()))';
|
||||
|
||||
/**
|
||||
* internal name of the id, gets mapped to uid
|
||||
*
|
||||
@ -277,7 +287,7 @@ class addressbook_sql extends so_sql
|
||||
{
|
||||
foreach($criteria as $col => $val)
|
||||
{
|
||||
if ($col[0] == '#') // search for a value in a certain custom field
|
||||
if ($col[0] === '#') // search for a value in a certain custom field
|
||||
{
|
||||
$valarray=array();
|
||||
# val may be a list of values, constructed by multiple select fields, to be able to do the contains feature of adv-search
|
||||
@ -298,12 +308,12 @@ class addressbook_sql extends so_sql
|
||||
}
|
||||
$search_customfields = true;
|
||||
}
|
||||
elseif($col == 'cat_id') // search in comma-sep. cat-column
|
||||
elseif($col === 'cat_id') // search in comma-sep. cat-column
|
||||
{
|
||||
$criteria = array_merge($criteria,$this->_cat_search($val));
|
||||
unset($criteria[$col]);
|
||||
}
|
||||
elseif($col == 'contact_value')
|
||||
elseif($col === 'contact_value')
|
||||
{
|
||||
if ($order_by[0] == '#')
|
||||
{
|
||||
@ -390,12 +400,20 @@ class addressbook_sql extends so_sql
|
||||
unset($criteria['owner']);
|
||||
}
|
||||
// postgres requires that expressions in order by appear in the columns of a distinct select
|
||||
if ($this->db->Type != 'mysql' && preg_match("/(\w+<>'')/",$order_by,$matches))
|
||||
if ($this->db->Type != 'mysql' && preg_match("/([a-zA-Z_.]+)<>''/",$order_by,$matches))
|
||||
{
|
||||
if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array();
|
||||
$extra_cols[] = $matches[1];
|
||||
$extra_cols[] = $matches[1]."<>''";
|
||||
}
|
||||
}
|
||||
// add join to show only active accounts (only if accounts are shown and in sql and we not already join the accounts table, eg. used by admin)
|
||||
if (!$owner && substr($this->account_repository,0,3) == 'sql' &&
|
||||
strpos($join,$GLOBALS['egw']->accounts->backend->table) === false && !array_key_exists('account_id',$filter))
|
||||
{
|
||||
$join .= self::ACOUNT_ACTIVE_JOIN;
|
||||
$filter[] = str_replace('UNIX_TIMESTAMP(NOW())',time(),self::ACOUNT_ACTIVE_FILTER);
|
||||
}
|
||||
$rows =& parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
|
||||
|
||||
if ($start === false) $this->total = is_array($rows) ? count($rows) : 0; // so_sql sets total only for $start !== false!
|
||||
@ -589,11 +607,23 @@ class addressbook_sql extends so_sql
|
||||
*/
|
||||
function read($keys,$extra_cols='',$join='')
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (!is_array($keys) && !is_numeric($keys))
|
||||
{
|
||||
$keys = array('contact_uid' => $keys);
|
||||
}
|
||||
return parent::read($keys,$extra_cols,$join);
|
||||
$contact = parent::read($keys,$extra_cols,$join);
|
||||
// enforce a minium uid strength
|
||||
if (is_array($contact) && (!isset($contact['uid'])
|
||||
|| strlen($contact['uid']) < $minimum_uid_length)) {
|
||||
parent::update(array('uid' => common::generate_uid('addressbook',$contact['id'])));
|
||||
}
|
||||
return $contact;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -605,6 +635,12 @@ class addressbook_sql extends so_sql
|
||||
*/
|
||||
function save($keys=null)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (is_array($keys) && count($keys)) $this->data_merge($keys);
|
||||
|
||||
$new_entry = !$this->data['id'];
|
||||
@ -631,8 +667,8 @@ class addressbook_sql extends so_sql
|
||||
}
|
||||
}
|
||||
// enforce a minium uid strength
|
||||
if (!$err && ($new_entry || isset($this->data['uid'])) && (strlen($this->data['uid']) < 20 || is_numeric($this->data['uid'])))
|
||||
{
|
||||
if (!$err && (!isset($this->data['uid'])
|
||||
|| strlen($this->data['uid']) < $minimum_uid_length)) {
|
||||
parent::update(array('uid' => common::generate_uid('addressbook',$this->data['id'])));
|
||||
//echo "<p>set uid={$this->data['uid']}, etag={$this->data['etag']}</p>";
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @link www.egroupware.org
|
||||
* @author Cornelius Weiss <egw@von-und-zu-weiss.de>
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de>
|
||||
* @package addressbook
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
@ -71,7 +71,7 @@ class addressbook_ui extends addressbook_bo
|
||||
$this->config =& $GLOBALS['egw_info']['server'];
|
||||
|
||||
// check if a contact specific export limit is set, if yes use it also for etemplate's csv export
|
||||
if (!$this->config['contact_export_limit'])
|
||||
if ($this->config['contact_export_limit'])
|
||||
{
|
||||
$this->config['export_limit'] = $this->config['contact_export_limit'];
|
||||
}
|
||||
@ -260,6 +260,9 @@ class addressbook_ui extends addressbook_bo
|
||||
'vcard' => lang('Export as VCard'), // ToDo: move this to importexport framework
|
||||
);
|
||||
}
|
||||
// if there is any export limit set, pass it on to the nextmatch, to be evaluated by the export
|
||||
if (isset($this->config['contact_export_limit']) && (int)$this->config['contact_export_limit']) $content['nm']['export_limit']=$this->config['contact_export_limit'];
|
||||
|
||||
$sel_options['action'] += array(
|
||||
'merge' => lang('Merge into first or account, deletes all other!'),
|
||||
'cat_add' => lang('Add or delete Categoies'), // add a categirie to multible addresses
|
||||
@ -318,6 +321,7 @@ class addressbook_ui extends addressbook_bo
|
||||
if (!isset($sel_options['org_view'][(string) $content['nm']['org_view']]))
|
||||
{
|
||||
$org_name = array();
|
||||
if (strpos($content['nm']['org_view'],'*AND*')!== false) $content['nm']['org_view'] = str_replace('*AND*','&',$content['nm']['org_view']);
|
||||
foreach(explode('|||',$content['nm']['org_view']) as $part)
|
||||
{
|
||||
list(,$name) = explode(':',$part,2);
|
||||
@ -397,6 +401,7 @@ class addressbook_ui extends addressbook_bo
|
||||
if (count($checked) > 1) // use a nicely formatted org-name as title in infolog
|
||||
{
|
||||
$parts = array();
|
||||
if (strpos($org,'*AND*')!== false) $org = str_replace('*AND*','&',$org);
|
||||
foreach(explode('|||',$org) as $part)
|
||||
{
|
||||
list(,$part) = explode(':',$part,2);
|
||||
@ -422,7 +427,7 @@ class addressbook_ui extends addressbook_bo
|
||||
$query['filter2'] = (int)$list;
|
||||
$this->action($email_type,array(),true,$success,$failed,$action_msg,$query,$msg);
|
||||
|
||||
$response =& new xajaxResponse();
|
||||
$response = new xajaxResponse();
|
||||
|
||||
if ($success) $response->addScript($GLOBALS['egw']->js->body['onLoad']);
|
||||
|
||||
@ -884,6 +889,7 @@ class addressbook_ui extends addressbook_bo
|
||||
}
|
||||
if ($query['org_view']) // view the contacts of one organisation only
|
||||
{
|
||||
if (strpos($query['org_view'],'*AND*')!== false) $query['org_view'] = str_replace('*AND*','&',$query['org_view']);
|
||||
foreach(explode('|||',$query['org_view']) as $part)
|
||||
{
|
||||
list($name,$value) = explode(':',$part,2);
|
||||
@ -1072,11 +1078,8 @@ class addressbook_ui extends addressbook_bo
|
||||
if (($row['addr_format'] = $this->addr_format_by_country($row['adr_one_countryname']))=='postcode_city') unset($row['adr_one_region']);
|
||||
if (($row['addr_format2'] = $this->addr_format_by_country($row['adr_two_countryname']))=='postcode_city') unset($row['adr_two_region']);
|
||||
}
|
||||
if ($show_distributionlist) {
|
||||
$readonlys['no_distrib_lists'] =true;
|
||||
} else {
|
||||
$readonlys['no_distrib_lists'] =false;
|
||||
}
|
||||
$readonlys['no_distrib_lists'] = (bool)$show_distributionlist;
|
||||
|
||||
if (!$this->prefs['no_auto_hide'])
|
||||
{
|
||||
// disable photo column, if view contains no photo(s)
|
||||
@ -1089,6 +1092,9 @@ class addressbook_ui extends addressbook_bo
|
||||
// disable customfields column, if we have no customefield(s)
|
||||
if (!$this->customfields/* || !$this->prefs['no_auto_hide'] && !$customfields*/) $rows['no_customfields'] = true;
|
||||
|
||||
// disable filemanger icon if user has no access to filemanager
|
||||
$readonlys['filemanager/navbar'] = !isset($GLOBALS['egw_info']['user']['apps']['filemanager']);
|
||||
|
||||
$rows['order'] = $order;
|
||||
$rows['call_popup'] = $this->config['call_popup'];
|
||||
$rows['customfields'] = array_values($this->customfields);
|
||||
@ -1109,7 +1115,7 @@ class addressbook_ui extends addressbook_bo
|
||||
}
|
||||
if($query['advanced_search'])
|
||||
{
|
||||
$GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Advanced search');
|
||||
$GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Advanced search');
|
||||
}
|
||||
if ($query['cat_id'])
|
||||
{
|
||||
@ -1167,7 +1173,7 @@ class addressbook_ui extends addressbook_bo
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the availible addressbooks of the user
|
||||
* Get the available addressbooks of the user
|
||||
*
|
||||
* @param int $required=EGW_ACL_READ required rights on the addressbook
|
||||
* @param string $extra_label first label if given (already translated)
|
||||
@ -1244,6 +1250,12 @@ class addressbook_ui extends addressbook_bo
|
||||
{
|
||||
$old_org_entry = $this->read($content['id']);
|
||||
}
|
||||
if (isset($contact['n_family']) && isset($contact['n_given'])
|
||||
&& $contact['n_family'] != $old_org_entry['n_family']
|
||||
&& $contact['n_given'] != $old_org_entry['n_given'])
|
||||
{
|
||||
unset($content['n_fn']);
|
||||
}
|
||||
if ($this->save($content))
|
||||
{
|
||||
$content['msg'] = lang('Contact saved');
|
||||
@ -1549,7 +1561,7 @@ class addressbook_ui extends addressbook_bo
|
||||
'n_suffix' => $n_suffix,
|
||||
'org_name' => $org_name,
|
||||
);
|
||||
$response =& new xajaxResponse();
|
||||
$response = new xajaxResponse();
|
||||
$response->addScript("setOptions('".addslashes(implode("\b",$this->fileas_options($names)))."');");
|
||||
|
||||
return $response->getXML();
|
||||
@ -2025,7 +2037,7 @@ $readonlys['button[vcard]'] = true;
|
||||
return lang("Document '%1' does not exist or is not readable for you!",$document);
|
||||
}
|
||||
require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.addressbook_merge.inc.php');
|
||||
$document_merge =& new addressbook_merge();
|
||||
$document_merge = new addressbook_merge();
|
||||
|
||||
return $document_merge->download($document,$ids);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -487,7 +487,7 @@ abstract class admin_cmd
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
function __set($property,$value)
|
||||
protected function __set($property,$value)
|
||||
{
|
||||
$this->data[$property] = $value;
|
||||
}
|
||||
@ -497,7 +497,7 @@ abstract class admin_cmd
|
||||
*
|
||||
* @param string $property
|
||||
*/
|
||||
function __unset($property)
|
||||
protected function __unset($property)
|
||||
{
|
||||
unset($this->data[$property]);
|
||||
}
|
||||
@ -795,7 +795,7 @@ abstract class admin_cmd
|
||||
return admin_cmd::run_queued_jobs();
|
||||
}
|
||||
include_once(EGW_API_INC.'/class.asyncservice.inc.php');
|
||||
$async = new asyncservice();
|
||||
$async =& new asyncservice();
|
||||
|
||||
// we cant use this class as callback, as it's abstract and ExecMethod used by the async service instanciated the class!
|
||||
list($app) = explode('_',$class=$next['type']);
|
||||
|
@ -183,6 +183,8 @@
|
||||
$this->template->set_var('sort_name',$this->nextmatchs->show_sort_order($this->sort,'cat_name',$this->order,'/index.php',lang('Name'),$link_data));
|
||||
$this->template->set_var('sort_description',$this->nextmatchs->show_sort_order($this->sort,'cat_description',$this->order,'/index.php',lang('Description'),$link_data));
|
||||
|
||||
$accountId = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
foreach($cats as $cat)
|
||||
{
|
||||
$data = unserialize($cat['data']);
|
||||
@ -192,8 +194,6 @@
|
||||
$this->template->set_var('td_color',$data['color']);
|
||||
$gray = (hexdec(substr($data['color'],1,2))+hexdec(substr($data['color'],3,2))+hexdec(substr($data['color'],5,2)))/3;
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
{
|
||||
$this->template->set_var('td_color','');
|
||||
@ -206,7 +206,7 @@
|
||||
$this->nextmatchs->template_alternate_row_color($this->template);
|
||||
$gray = 255;
|
||||
// }
|
||||
|
||||
|
||||
$this->template->set_var('color',$gray < 128 ? 'style="color: white;"' : '');
|
||||
|
||||
$id = $cat['id'];
|
||||
@ -233,6 +233,10 @@
|
||||
{
|
||||
$appendix = '<' . lang('Global') . '>';
|
||||
}
|
||||
elseif ($cat['owner'] != $accountId)
|
||||
{
|
||||
$appendix = '<' . $GLOBALS['egw']->accounts->id2name($cat['owner'], 'account_fullname') . '>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$appendix = '';
|
||||
@ -291,7 +295,7 @@
|
||||
$data = unserialize($cat['data']);
|
||||
$icon = $data['icon'];
|
||||
$dir_img = $GLOBALS['egw_info']['server']['webserver_url'] . SEP . 'phpgwapi' . SEP . 'images' . SEP;
|
||||
|
||||
|
||||
if (strlen($icon) > 0)
|
||||
$this->template->set_var('icon', "<img src='". $dir_img . $icon ."'>");
|
||||
else
|
||||
@ -318,7 +322,7 @@
|
||||
$cat_description = $_POST['cat_description'];
|
||||
$cat_data = $_POST['cat_data'];
|
||||
$old_parent = (int)$_POST['old_parent'];
|
||||
|
||||
|
||||
if ($new_parent)
|
||||
{
|
||||
$cat_parent = $new_parent;
|
||||
@ -396,7 +400,7 @@
|
||||
'<input type="hidden" name="old_parent" value="' . $cat['parent'] . '">' . "\n";
|
||||
|
||||
$link_data['menuaction'] = 'admin.uicategories.edit';
|
||||
$link_data['cat_id'] = $this->cat_id;
|
||||
$link_data['cat_id'] = $this->cat_id;
|
||||
$this->template->set_var('action_url',$GLOBALS['egw']->link('/index.php',$link_data));
|
||||
|
||||
if ($this->acl_delete)
|
||||
@ -518,7 +522,7 @@
|
||||
|
||||
$cats = $this->bo->cats->return_single($this->cat_id);
|
||||
$this->template->set_var('cat_name',$cat['name']);
|
||||
|
||||
|
||||
if ($apps_cats)
|
||||
{
|
||||
$this->template->set_block('category_delete','delete','deletehandle');
|
||||
|
@ -35,7 +35,7 @@ class bocalendar
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->cal =& new calendar_boupdate();
|
||||
$this->cal = new calendar_boupdate();
|
||||
|
||||
if (is_object($GLOBALS['server']) && $GLOBALS['server']->simpledate)
|
||||
{
|
||||
|
@ -301,7 +301,7 @@
|
||||
// reading the holidayfile from egroupware.org via network::gethttpsocketfile contains all the headers!
|
||||
foreach($lines as $n => $line)
|
||||
{
|
||||
$fields = split("[\t\n ]+",$line);
|
||||
$fields = preg_split("/[\t\n ]+/",$line);
|
||||
|
||||
if ($fields[0] == 'charset' && $fields[1])
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ class calendar_ajax {
|
||||
|
||||
$conflicts=$this->calendar->update($event);
|
||||
|
||||
$response =& new xajaxResponse();
|
||||
$response = new xajaxResponse();
|
||||
if(!is_array($conflicts))
|
||||
{
|
||||
$response->addRedirect('');
|
||||
|
@ -5,6 +5,7 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) 2004-8 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
@ -21,9 +22,10 @@ define('WEEK_s',7*DAY_s);
|
||||
|
||||
/**
|
||||
* Gives read access to the calendar, but all events the user is not participating are private!
|
||||
* Used be the addressbook.
|
||||
* Used by addressbook.
|
||||
*/
|
||||
define('EGW_ACL_READ_FOR_PARTICIPANTS',EGW_ACL_CUSTOM_1);
|
||||
define('EGW_ACL_FREEBUSY',EGW_ACL_CUSTOM_2);
|
||||
|
||||
/**
|
||||
* Required (!) include, as we use the MCAL_* constants, BEFORE instanciating (and therefore autoloading) the class
|
||||
@ -61,7 +63,7 @@ class calendar_bo
|
||||
var $debug=false;
|
||||
|
||||
/**
|
||||
* @var int $tz_offset_s offset in secconds between user and server-time,
|
||||
* @var int $tz_offset_s offset in seconds between user and server-time,
|
||||
* it need to be add to a server-time to get the user-time or substracted from a user-time to get the server-time
|
||||
*/
|
||||
var $tz_offset_s;
|
||||
@ -124,6 +126,17 @@ class calendar_bo
|
||||
MCAL_M_SATURDAY => 'Saturday',
|
||||
MCAL_M_SUNDAY => 'Sunday',
|
||||
);
|
||||
/**
|
||||
* Standard iCal attendee roles
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $roles = array(
|
||||
'REQ-PARTICIPANT' => 'Requested',
|
||||
'CHAIR' => 'Chair',
|
||||
'OPT-PARTICIPANT' => 'Optional',
|
||||
'NON-PARTICIPANT' => 'None',
|
||||
);
|
||||
/**
|
||||
* @var array $resources registered scheduling resources of the calendar (gets chached in the session for performance reasons)
|
||||
*/
|
||||
@ -133,6 +146,7 @@ class calendar_bo
|
||||
*/
|
||||
protected static $cached_event = array();
|
||||
protected static $cached_event_date_format = false;
|
||||
protected static $cached_event_date = 0;
|
||||
/**
|
||||
* @var array $cached_holidays holidays plus birthdays (gets cached in the session for performance reasons)
|
||||
*/
|
||||
@ -140,7 +154,7 @@ class calendar_bo
|
||||
/**
|
||||
* Instance of the socal class
|
||||
*
|
||||
* @var socal
|
||||
* @var calendar_so
|
||||
*/
|
||||
var $so;
|
||||
/**
|
||||
@ -200,7 +214,7 @@ class calendar_bo
|
||||
/**
|
||||
* returns info about email addresses as participants
|
||||
*
|
||||
* @param int/array $ids single contact-id or array of id's
|
||||
* @param int|array $ids single contact-id or array of id's
|
||||
* @return array
|
||||
*/
|
||||
static function email_info($ids)
|
||||
@ -259,13 +273,13 @@ class calendar_bo
|
||||
/**
|
||||
* Searches / lists calendar entries, including repeating ones
|
||||
*
|
||||
* @param params array with the following keys
|
||||
* @param array $params array with the following keys
|
||||
* start date startdate of the search/list, defaults to today
|
||||
* end date enddate of the search/list, defaults to start + one day
|
||||
* users mixed integer user-id or array of user-id's to use, defaults to the current user
|
||||
* cat_id mixed category-id or array of cat-id's, defaults to all if unset, 0 or False
|
||||
* Please note: only a single cat-id, will include all sub-cats (if the common-pref 'cats_no_subs' is False)
|
||||
* filter string filter-name, atm. 'all' or 'hideprivate'
|
||||
* filter string all (not rejected), accepted, unknown, tentative, rejected or hideprivate
|
||||
* query string pattern so search for, if unset or empty all matching entries are returned (no search)
|
||||
* Please Note: a search never returns repeating events more then once AND does not honor start+end date !!!
|
||||
* dayswise boolean on True it returns an array with YYYYMMDD strings as keys and an array with events
|
||||
@ -277,16 +291,29 @@ class calendar_bo
|
||||
* otherwise the original recuring event (with the first start- + enddate) is returned
|
||||
* num_rows int number of entries to return, default or if 0, max_entries from the prefs
|
||||
* order column-names plus optional DESC|ASC separted by comma
|
||||
* show_rejected if set rejected invitation are shown only when true, otherwise it depends on the cal-pref or a running query
|
||||
* ignore_acl if set and true no check_perms for a general EGW_ACL_READ grants is performed
|
||||
* enum_groups boolean if set and true, group-members will be added as participants with status 'G'
|
||||
* @return array of events or array with YYYYMMDD strings / array of events pairs (depending on $daywise param)
|
||||
* or false if there are no read-grants from _any_ of the requested users
|
||||
* cols string|array columns to select, if set an iterator will be returned
|
||||
* append string to append to the query, eg. GROUP BY
|
||||
* cfs array if set, query given custom fields or all for empty array, none are returned, if not set (default)
|
||||
* @return iterator|array|boolean array of events or array with YYYYMMDD strings / array of events pairs (depending on $daywise param)
|
||||
* or false if there are no read-grants from _any_ of the requested users or iterator/recordset if cols are given
|
||||
*/
|
||||
function &search($params)
|
||||
{
|
||||
$params_in = $params;
|
||||
|
||||
unset($params['sql_filter']); // dont allow to set it via UI or xmlrpc
|
||||
|
||||
// check if any resource wants to hook into
|
||||
foreach($this->resources as $app => $data)
|
||||
{
|
||||
if (isset($data['search_filter']))
|
||||
{
|
||||
$params = ExecMethod($data['search_filter'],$params);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($params['users']) || !$params['users'] ||
|
||||
count($params['users']) == 1 && isset($params['users'][0]) && !$params['users'][0]) // null or '' casted to an array
|
||||
{
|
||||
@ -301,7 +328,7 @@ class calendar_bo
|
||||
$users = array();
|
||||
foreach($params['users'] as $user)
|
||||
{
|
||||
if ($params['ignore_acl'] || $this->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS,0,$user))
|
||||
if ($params['ignore_acl'] || $this->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS|EGW_ACL_FREEBUSY,0,$user))
|
||||
{
|
||||
if ($user && !in_array($user,$users)) // already added?
|
||||
{
|
||||
@ -325,7 +352,7 @@ class calendar_bo
|
||||
{
|
||||
// use only members which gave the user a read-grant
|
||||
if (!in_array($member['account_id'],$users) &&
|
||||
($params['ignore_acl'] || $this->check_perms(EGW_ACL_READ,0,$member['account_id'])))
|
||||
($params['ignore_acl'] || $this->check_perms(EGW_ACL_READ|EGW_ACL_FREEBUSY,0,$member['account_id'])))
|
||||
{
|
||||
$users[] = $member['account_id'];
|
||||
}
|
||||
@ -373,7 +400,12 @@ class calendar_bo
|
||||
}
|
||||
// date2ts(,true) converts to server time, db2data converts again to user-time
|
||||
$events =& $this->so->search(isset($start) ? $this->date2ts($start,true) : null,isset($end) ? $this->date2ts($end,true) : null,
|
||||
$users,$cat_id,$filter,$params['query'],$offset,(int)$params['num_rows'],$params['order'],$show_rejected);
|
||||
$users,$cat_id,$filter,$params['query'],$offset,(int)$params['num_rows'],$params['order'],$show_rejected,$params['cols'],$params['append'],$params['cfs']);
|
||||
|
||||
if (isset($params['cols']))
|
||||
{
|
||||
return $events;
|
||||
}
|
||||
$this->total = $this->so->total;
|
||||
$this->db2data($events,isset($params['date_format']) ? $params['date_format'] : 'ts');
|
||||
|
||||
@ -484,8 +516,8 @@ class calendar_bo
|
||||
'title' => lang('private'),
|
||||
'participants' => array_intersect_key($event['participants'],array_flip($allowed_participants)),
|
||||
'public'=> 0,
|
||||
'category' => $event['category'], // category is visible anyway, eg. by using planner by cat
|
||||
'non_blocking' => $event['non_blocking'],
|
||||
'category' => $event['category'], // category is visible anyway, eg. by using planner by cat
|
||||
'non_blocking' => $event['non_blocking'],
|
||||
);
|
||||
}
|
||||
|
||||
@ -534,7 +566,7 @@ class calendar_bo
|
||||
}
|
||||
}
|
||||
// update the horizont
|
||||
$config =& CreateObject('phpgwapi.config','calendar');
|
||||
$config = CreateObject('phpgwapi.config','calendar');
|
||||
$config->save_value('horizont',$this->config['horizont'],'calendar');
|
||||
|
||||
if ($this->debug == 'check_move_horizont') $this->debug_message('bocal::check_move_horizont(%1) new horizont=%2, exiting',true,$new_horizont,$this->config['horizont']);
|
||||
@ -562,10 +594,18 @@ class calendar_bo
|
||||
|
||||
$events = array();
|
||||
$this->insert_all_repetitions($event,$start,$this->date2ts($this->config['horizont'],true),$events,null);
|
||||
|
||||
$days = $this->so->get_recurrence_exceptions($event); // content of array is in server-time!
|
||||
$days = is_array($days) ? $days : array();
|
||||
//error_log('set_recurrences: days=' . array2string($days) );
|
||||
foreach($events as $event)
|
||||
{
|
||||
$this->so->recurrence($event['id'],$this->date2ts($event['start'],true),$this->date2ts($event['end'],true),$event['participants']);
|
||||
$start_servertime = $this->date2ts($event['start'],true);
|
||||
if (in_array($start_servertime, (array)$days))
|
||||
{
|
||||
// we don't change the stati of recurrence exceptions
|
||||
$event['participants'] = array();
|
||||
}
|
||||
$this->so->recurrence($event['id'],$start_servertime,$this->date2ts($event['end'],true),$event['participants']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -578,29 +618,29 @@ class calendar_bo
|
||||
function db2data(&$events,$date_format='ts')
|
||||
{
|
||||
if (!is_array($events)) echo "<p>bocal::db2data(\$events,$date_format) \$events is no array<br />\n".function_backtrace()."</p>\n";
|
||||
foreach($events as $id => $event)
|
||||
foreach($events as &$event)
|
||||
{
|
||||
// we convert here from the server-time timestamps to user-time and (optional) to a different date-format!
|
||||
foreach(array('start','end','modified','recur_enddate') as $ts)
|
||||
foreach(array('start','end','modified','recur_enddate','reference') as $ts)
|
||||
{
|
||||
if (empty($event[$ts])) continue;
|
||||
|
||||
$events[$id][$ts] = $this->date2usertime($event[$ts],$date_format);
|
||||
$event[$ts] = $this->date2usertime($event[$ts],$date_format);
|
||||
}
|
||||
// same with the recur exceptions
|
||||
if (isset($event['recur_exception']) && is_array($event['recur_exception']))
|
||||
{
|
||||
foreach($event['recur_exception'] as $n => $date)
|
||||
foreach($event['recur_exception'] as &$date)
|
||||
{
|
||||
$events[$id]['recur_exception'][$n] = $this->date2usertime($date,$date_format);
|
||||
$date = $this->date2usertime($date,$date_format);
|
||||
}
|
||||
}
|
||||
// same with the alarms
|
||||
if (isset($event['alarm']) && is_array($event['alarm']))
|
||||
{
|
||||
foreach($event['alarm'] as $n => $alarm)
|
||||
foreach($event['alarm'] as &$alarm)
|
||||
{
|
||||
$events[$id]['alarm'][$n]['time'] = $this->date2usertime($alarm['time'],$date_format);
|
||||
$alarm['time'] = $this->date2usertime($alarm['time'],$date_format);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -650,7 +690,7 @@ class calendar_bo
|
||||
{
|
||||
if (is_array($ids) || !isset(self::$cached_event['id']) || self::$cached_event['id'] != $ids ||
|
||||
self::$cached_event_date_format != $date_format ||
|
||||
self::$cached_event['recur_type'] != MCAL_RECUR_NONE && !is_null($date) && (!$date || self::$cached_event['start'] < $date))
|
||||
self::$cached_event['recur_type'] != MCAL_RECUR_NONE && !is_null($date) && self::$cached_event_date != $date || (!$date || self::$cached_event['start'] < $date))
|
||||
{
|
||||
$events = $this->so->read($ids,$date ? $this->date2ts($date,true) : 0);
|
||||
|
||||
@ -666,6 +706,7 @@ class calendar_bo
|
||||
{
|
||||
self::$cached_event = array_shift($events);
|
||||
self::$cached_event_date_format = $date_format;
|
||||
self::$cached_event_date = $date;
|
||||
$return =& self::$cached_event;
|
||||
}
|
||||
}
|
||||
@ -745,6 +786,8 @@ class calendar_bo
|
||||
{
|
||||
$search_date_ymd = (int)$this->date2string($ts);
|
||||
|
||||
//error_log('insert_all_repetitions search_date = ' . $search_date_ymd . ' => ' . print_r($recur_exceptions, true));
|
||||
|
||||
$have_exception = !is_null($recur_exceptions) && isset($recur_exceptions[$search_date_ymd]);
|
||||
|
||||
if (!$have_exception) // no execption by an edited event => check the deleted ones
|
||||
@ -910,7 +953,7 @@ class calendar_bo
|
||||
* We do some caching here, as the resource itself might not do it.
|
||||
*
|
||||
* @param string $uid string with one-letter resource-type and numerical resource-id, eg. "r19"
|
||||
* @return array/boolean array with keys res_id,cat_id,name,useable (name definied by max_quantity in $this->resources),rights,responsible or false if $uid is not found
|
||||
* @return array|boolean array with keys res_id,cat_id,name,useable (name definied by max_quantity in $this->resources),rights,responsible or false if $uid is not found
|
||||
*/
|
||||
function resource_info($uid)
|
||||
{
|
||||
@ -924,7 +967,7 @@ class calendar_bo
|
||||
'res_id' => $uid,
|
||||
'email' => $GLOBALS['egw']->accounts->id2name($uid,'account_email'),
|
||||
'name' => trim($GLOBALS['egw']->accounts->id2name($uid,'account_firstname'). ' ' .
|
||||
$GLOBALS['egw']->accounts->id2name($uid,'account_lastname')),
|
||||
$GLOBALS['egw']->accounts->id2name($uid,'account_lastname')),
|
||||
'type' => $GLOBALS['egw']->accounts->get_type($uid),
|
||||
);
|
||||
}
|
||||
@ -970,7 +1013,6 @@ class calendar_bo
|
||||
if ($other && !is_numeric($other))
|
||||
{
|
||||
$resource = $this->resource_info($other);
|
||||
|
||||
return $needed & $resource['rights'];
|
||||
}
|
||||
if (is_int($event) && $event == 0)
|
||||
@ -981,7 +1023,7 @@ class calendar_bo
|
||||
{
|
||||
if (!is_array($event))
|
||||
{
|
||||
$event = $this->read($event,$date_to_read,True,$date_format); // = no ACL check !!!
|
||||
$event = $this->read($event,$date_to_read,true,$date_format); // = no ACL check !!!
|
||||
}
|
||||
if (!is_array($event))
|
||||
{
|
||||
@ -994,9 +1036,7 @@ class calendar_bo
|
||||
$owner = $event['owner'];
|
||||
$private = !$event['public'];
|
||||
}
|
||||
$user = $GLOBALS['egw_info']['user']['account_id'];
|
||||
$grants = $this->grants[$owner];
|
||||
|
||||
if (is_array($event) && $needed == EGW_ACL_READ)
|
||||
{
|
||||
// Check if the $user is one of the participants or has a read-grant from one of them
|
||||
@ -1006,7 +1046,7 @@ class calendar_bo
|
||||
{
|
||||
foreach($event['participants'] as $uid => $accept)
|
||||
{
|
||||
if ($uid == $user || $uid < 0 && in_array($user,$GLOBALS['egw']->accounts->members($uid,true)))
|
||||
if ($uid == $this->user || $uid < 0 && in_array($this->user,$GLOBALS['egw']->accounts->members($uid,true)))
|
||||
{
|
||||
// if we are a participant, we have an implicite READ and PRIVAT grant
|
||||
$grants |= EGW_ACL_READ | EGW_ACL_PRIVATE;
|
||||
@ -1031,14 +1071,13 @@ class calendar_bo
|
||||
error_log(__METHOD__." no participants for event:".print_r($event,true));
|
||||
}
|
||||
}
|
||||
|
||||
if ($GLOBALS['egw']->accounts->get_type($owner) == 'g' && $needed == EGW_ACL_ADD)
|
||||
{
|
||||
$access = False; // a group can't be the owner of an event
|
||||
$access = false; // a group can't be the owner of an event
|
||||
}
|
||||
else
|
||||
{
|
||||
$access = $user == $owner || $grants & $needed && (!$private || $grants & EGW_ACL_PRIVATE);
|
||||
$access = ($this->user == $owner) || $grants & $needed && (!$private || $grants & EGW_ACL_PRIVATE);
|
||||
}
|
||||
if ($this->debug && ($this->debug > 2 || $this->debug == 'check_perms'))
|
||||
{
|
||||
@ -1063,54 +1102,54 @@ class calendar_bo
|
||||
switch(gettype($date))
|
||||
{
|
||||
case 'string': // YYYYMMDD or iso8601 YYYY-MM-DDThh:mm:ss[Z|[+-]hh:mm] string
|
||||
if (is_numeric($date) && $date > 21000000)
|
||||
if (is_numeric($date) && $date > 21000000)
|
||||
{
|
||||
$date = (int) $date; // this is already as timestamp
|
||||
break;
|
||||
}
|
||||
// evaluate evtl. added timezone
|
||||
if (strlen($date) > 12)
|
||||
{
|
||||
if (substr($date,-1) == 'Z')
|
||||
{
|
||||
$date = (int) $date; // this is already as timestamp
|
||||
break;
|
||||
$time_offset = date('Z');
|
||||
}
|
||||
// evaluate evtl. added timezone
|
||||
if (strlen($date) > 12)
|
||||
elseif(preg_match('/([+-]{1})([0-9]{2}):?([0-9]{2})$/',$date,$matches))
|
||||
{
|
||||
if (substr($date,-1) == 'Z')
|
||||
{
|
||||
$time_offset = date('Z');
|
||||
}
|
||||
elseif(preg_match('/([+-]{1})([0-9]{2}):?([0-9]{2})$/',$date,$matches))
|
||||
{
|
||||
$time_offset = date('Z')-($matches[1] == '+' ? 1 : -1)*(3600*$matches[2]+60*$matches[3]);
|
||||
}
|
||||
$time_offset = date('Z')-($matches[1] == '+' ? 1 : -1)*(3600*$matches[2]+60*$matches[3]);
|
||||
}
|
||||
// removing all non-nummerical chars, gives YYYYMMDDhhmmss, independent of the iso8601 format
|
||||
$date = str_replace(array('-',':','T','Z',' ','+'),'',$date);
|
||||
$date = array(
|
||||
'year' => (int) substr($date,0,4),
|
||||
'month' => (int) substr($date,4,2),
|
||||
'day' => (int) substr($date,6,2),
|
||||
'hour' => (int) substr($date,8,2),
|
||||
'minute' => (int) substr($date,10,2),
|
||||
'second' => (int) substr($date,12,2),
|
||||
);
|
||||
// fall-through
|
||||
}
|
||||
// removing all non-nummerical chars, gives YYYYMMDDhhmmss, independent of the iso8601 format
|
||||
$date = str_replace(array('-',':','T','Z',' ','+'),'',$date);
|
||||
$date = array(
|
||||
'year' => (int) substr($date,0,4),
|
||||
'month' => (int) substr($date,4,2),
|
||||
'day' => (int) substr($date,6,2),
|
||||
'hour' => (int) substr($date,8,2),
|
||||
'minute' => (int) substr($date,10,2),
|
||||
'second' => (int) substr($date,12,2),
|
||||
);
|
||||
// fall-through
|
||||
case 'array': // day, month and year keys
|
||||
if (isset($date['raw']) && $date['raw']) // we already have a timestamp
|
||||
{
|
||||
$date = $date['raw'];
|
||||
break;
|
||||
}
|
||||
if (!isset($date['year']) && isset($date['full']))
|
||||
{
|
||||
$date['year'] = (int) substr($date['full'],0,4);
|
||||
$date['month'] = (int) substr($date['full'],4,2);
|
||||
$date['day'] = (int) substr($date['full'],6,2);
|
||||
}
|
||||
$date = adodb_mktime((int)$date['hour'],(int)$date['minute'],(int)$date['second'],(int)$date['month'],
|
||||
(int) (isset($date['day']) ? $date['day'] : $date['mday']),(int)$date['year']);
|
||||
if (isset($date['raw']) && $date['raw']) // we already have a timestamp
|
||||
{
|
||||
$date = $date['raw'];
|
||||
break;
|
||||
}
|
||||
if (!isset($date['year']) && isset($date['full']))
|
||||
{
|
||||
$date['year'] = (int) substr($date['full'],0,4);
|
||||
$date['month'] = (int) substr($date['full'],4,2);
|
||||
$date['day'] = (int) substr($date['full'],6,2);
|
||||
}
|
||||
$date = adodb_mktime((int)$date['hour'],(int)$date['minute'],(int)$date['second'],(int)$date['month'],
|
||||
(int) (isset($date['day']) ? $date['day'] : $date['mday']),(int)$date['year']);
|
||||
break;
|
||||
case 'integer': // already a timestamp
|
||||
break;
|
||||
break;
|
||||
default: // eg. boolean, means now in user-time (!)
|
||||
$date = $this->now_su;
|
||||
break;
|
||||
$date = $this->now_su;
|
||||
break;
|
||||
}
|
||||
if ($time_offset)
|
||||
{
|
||||
@ -1261,6 +1300,7 @@ class calendar_bo
|
||||
EGW_ACL_EDIT => 'ACL_EDIT',
|
||||
EGW_ACL_DELETE => 'ACL_DELETE',
|
||||
EGW_ACL_PRIVATE => 'ACL_PRIVATE',
|
||||
EGW_ACL_FREEBUSY => 'ACL_FREEBUSY',
|
||||
);
|
||||
for($i = 2; $i < func_num_args(); ++$i)
|
||||
{
|
||||
@ -1430,7 +1470,7 @@ class calendar_bo
|
||||
/**
|
||||
* Converts a participant into a (readable) user- or resource-name
|
||||
*
|
||||
* @param $id string/int id of user or resource
|
||||
* @param $id string|int id of user or resource
|
||||
* @return string with name
|
||||
*/
|
||||
function participant_name($id,$use_type=false)
|
||||
@ -1471,11 +1511,13 @@ class calendar_bo
|
||||
$names = array();
|
||||
foreach($event['participants'] as $id => $status)
|
||||
{
|
||||
calendar_so::split_status($status,$quantity,$role);
|
||||
|
||||
if ($status == 'G' && !$show_group_invitation) continue; // dont show group-invitation
|
||||
|
||||
if (!$long_status)
|
||||
{
|
||||
switch($status)
|
||||
switch($status[0])
|
||||
{
|
||||
case 'A': // accepted
|
||||
$status = html::image('calendar','agt_action_success',$this->verbose_status[$status]);
|
||||
@ -1499,7 +1541,26 @@ class calendar_bo
|
||||
{
|
||||
$status = '('.$this->verbose_status[$status].')';
|
||||
}
|
||||
$names[$id] = $this->participant_name($id).' '.$status;
|
||||
$names[$id] = $this->participant_name($id).($quantity > 1 ? ' ('.$quantity.')' : '').' '.$status;
|
||||
|
||||
// add role, if not a regular participant
|
||||
if ($role != 'REQ-PARTICIPANT')
|
||||
{
|
||||
if (isset($this->roles[$role]))
|
||||
{
|
||||
$role = lang($this->roles[$role]);
|
||||
}
|
||||
// allow to use cats as roles (beside regular iCal ones)
|
||||
elseif (substr($role,0,6) == 'X-CAT-' && ($cat_id = (int)substr($role,6)) > 0)
|
||||
{
|
||||
$role = $GLOBALS['egw']->categories->id2name($cat_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
$role = lang(str_replace('X-','',$role));
|
||||
}
|
||||
$names[$id] .= ' '.$role;
|
||||
}
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
@ -1518,7 +1579,7 @@ class calendar_bo
|
||||
$color = 0;
|
||||
if (!is_object($this->cats))
|
||||
{
|
||||
$this->cats =& CreateObject('phpgwapi.categories','','calendar');
|
||||
$this->cats = CreateObject('phpgwapi.categories','','calendar');
|
||||
}
|
||||
foreach(explode(',',$category) as $cat_id)
|
||||
{
|
||||
@ -1540,7 +1601,9 @@ class calendar_bo
|
||||
return $cats;
|
||||
}
|
||||
|
||||
/* This is called only by list_cals(). It was moved here to remove fatal error in php5 beta4 */
|
||||
/**
|
||||
* This is called only by list_cals(). It was moved here to remove fatal error in php5 beta4
|
||||
*/
|
||||
function _list_cals_add($id,&$users,&$groups)
|
||||
{
|
||||
$name = $GLOBALS['egw']->common->grab_owner_name($id);
|
||||
@ -1560,9 +1623,10 @@ class calendar_bo
|
||||
}
|
||||
|
||||
/**
|
||||
* generate list of user- / group-calendars for the selectbox in the header
|
||||
* @return alphabeticaly sorted array with groups first and then users
|
||||
*/
|
||||
* generate list of user- / group-calendars for the selectbox in the header
|
||||
*
|
||||
* @return array alphabeticaly sorted array with groups first and then users: $name => array('grantor'=>$id,'value'=>['g_'.]$id,'name'=>$name)
|
||||
*/
|
||||
function list_cals()
|
||||
{
|
||||
$users = $groups = array();
|
||||
@ -1667,7 +1731,7 @@ class calendar_bo
|
||||
{
|
||||
if (!is_object($this->holidays))
|
||||
{
|
||||
$this->holidays =& CreateObject('calendar.boholiday');
|
||||
$this->holidays = CreateObject('calendar.boholiday');
|
||||
}
|
||||
$this->holidays->prepare_read_holidays($year);
|
||||
$this->cached_holidays[$year] = $this->holidays->read_holiday();
|
||||
@ -1675,7 +1739,7 @@ class calendar_bo
|
||||
// search for birthdays
|
||||
if ($GLOBALS['egw_info']['server']['hide_birthdays'] != 'yes')
|
||||
{
|
||||
$contacts =& CreateObject('phpgwapi.contacts');
|
||||
$contacts = CreateObject('phpgwapi.contacts');
|
||||
$bdays =& $contacts->read(0,0,array('id','n_family','n_given','n_prefix','n_middle','bday'),'',"bday=!'',n_family=!''",'ASC','bday');
|
||||
if ($bdays)
|
||||
{
|
||||
@ -1831,4 +1895,20 @@ class calendar_bo
|
||||
$GLOBALS['egw_info']['server']['webserver_url'].'/calendar/freebusy.php?user='.urlencode($user).
|
||||
($pw ? '&password='.urlencode($pw) : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the event is the whole day
|
||||
*
|
||||
* @param event
|
||||
* @return boolean true for whole day events
|
||||
*/
|
||||
function isWholeDay($event)
|
||||
{
|
||||
// check if the event is the whole day
|
||||
$start = $this->date2array($event['start']);
|
||||
$end = $this->date2array($event['end']);
|
||||
$result = (!$start['hour'] && !$start['minute']
|
||||
&& $end['hour'] == 23 && $end['minute'] == 59);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,13 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005-8 by RalfBecker-At-outdoor-training.de
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) 2005-9 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
// types of messsages send by bocalupdate::send_update
|
||||
// types of messsages send by calendar_boupdate::send_update
|
||||
define('MSG_DELETED',0);
|
||||
define('MSG_MODIFIED',1);
|
||||
define('MSG_ADDED',2);
|
||||
@ -51,7 +52,7 @@ class calendar_boupdate extends calendar_bo
|
||||
var $debug;
|
||||
|
||||
/**
|
||||
* @var string/boolean $log_file filename to enable the login or false for no update-logging
|
||||
* @var string|boolean $log_file filename to enable the login or false for no update-logging
|
||||
*/
|
||||
var $log_file = false;
|
||||
|
||||
@ -60,11 +61,11 @@ class calendar_boupdate extends calendar_bo
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
if ($this->debug > 0) $this->debug_message('bocalupdate::bocalupdate() started',True);
|
||||
if ($this->debug > 0) $this->debug_message('calendar_boupdate::__construct() started',True);
|
||||
|
||||
parent::__construct(); // calling the parent constructor
|
||||
|
||||
if ($this->debug > 0) $this->debug_message('bocalupdate::bocalupdate() finished',True);
|
||||
if ($this->debug > 0) $this->debug_message('calendar_boupdate::__construct() finished',True);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,16 +74,17 @@ class calendar_boupdate extends calendar_bo
|
||||
* @param array &$event event-array, on return some values might be changed due to set defaults
|
||||
* @param boolean $ignore_conflicts=false just ignore conflicts or do a conflict check and return the conflicting events
|
||||
* @param boolean $touch_modified=true touch modificatin time and set modifing user, default true=yes
|
||||
* @param boolean $ignore_acl=flase should we ignore the acl
|
||||
* @param boolean $ignore_acl=false should we ignore the acl
|
||||
* @param boolean $updateTS=true update the content history of the event
|
||||
* @return mixed on success: int $cal_id > 0, on error false or array with conflicting events (only if $check_conflicts)
|
||||
* Please note: the events are not garantied to be readable by the user (no read grant or private)!
|
||||
*/
|
||||
function update(&$event,$ignore_conflicts=false,$touch_modified=true,$ignore_acl=false)
|
||||
function update(&$event,$ignore_conflicts=false,$touch_modified=true,$ignore_acl=false,$updateTS=true)
|
||||
{
|
||||
//error_log(__METHOD__."(".array2string($event).",$ignore_conflicts,$touch_modified,$ignore_acl)");
|
||||
if ($this->debug > 1 || $this->debug == 'update')
|
||||
{
|
||||
$this->debug_message('bocalupdate::update(%1,ignore_conflict=%2,touch_modified=%3,ignore_acl=%4)',
|
||||
$this->debug_message('calendar_boupdate::update(%1,ignore_conflict=%2,touch_modified=%3,ignore_acl=%4)',
|
||||
false,$event,$ignore_conflicts,$touch_modified,$ignore_acl);
|
||||
}
|
||||
// check some minimum requirements:
|
||||
@ -100,14 +102,14 @@ class calendar_boupdate extends calendar_bo
|
||||
// if no owner given, set user to owner
|
||||
if (!$event['owner']) $event['owner'] = $this->user;
|
||||
// set owner as participant if none is given
|
||||
if (!$event['id'] && (!is_array($event['participants']) || !count($event['participants'])))
|
||||
if (!is_array($event['participants']) || !count($event['participants']))
|
||||
{
|
||||
$event['participants'][$event['owner']] = 'U';
|
||||
$event['participants'] = array($event['owner'] => 'U');
|
||||
}
|
||||
// set the status of the current user to 'A' = accepted
|
||||
if (isset($event['participants'][$this->user]) && $event['participants'][$this->user] != 'A')
|
||||
if (isset($event['participants'][$this->user]) && $event['participants'][$this->user][0] != 'A')
|
||||
{
|
||||
$event['participants'][$this->user] = 'A';
|
||||
$event['participants'][$this->user][0] = 'A';
|
||||
}
|
||||
}
|
||||
// check if user has the permission to update / create the event
|
||||
@ -130,6 +132,7 @@ class calendar_boupdate extends calendar_bo
|
||||
$quantity = $users = array();
|
||||
foreach($event['participants'] as $uid => $status)
|
||||
{
|
||||
calendar_so::split_status($status,$q,$r);
|
||||
if ($status[0] == 'R') continue; // ignore rejected participants
|
||||
|
||||
if ($uid < 0) // group, check it's members too
|
||||
@ -140,7 +143,7 @@ class calendar_boupdate extends calendar_bo
|
||||
$users[] = $uid;
|
||||
if (in_array($uid[0],$types_with_quantity))
|
||||
{
|
||||
$quantity[$uid] = max(1,(int) substr($status,2));
|
||||
$quantity[$uid] = $q;
|
||||
}
|
||||
}
|
||||
$overlapping_events =& $this->search(array(
|
||||
@ -152,7 +155,7 @@ class calendar_boupdate extends calendar_bo
|
||||
));
|
||||
if ($this->debug > 2 || $this->debug == 'update')
|
||||
{
|
||||
$this->debug_message('bocalupdate::update() checking for potential overlapping events for users %1 from %2 to %3',false,$users,$event['start'],$event['end']);
|
||||
$this->debug_message('calendar_boupdate::update() checking for potential overlapping events for users %1 from %2 to %3',false,$users,$event['start'],$event['end']);
|
||||
}
|
||||
$max_quantity = $possible_quantity_conflicts = $conflicts = array();
|
||||
foreach((array) $overlapping_events as $k => $overlap)
|
||||
@ -165,7 +168,7 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
if ($this->debug > 3 || $this->debug == 'update')
|
||||
{
|
||||
$this->debug_message('bocalupdate::update() checking overlapping event %1',false,$overlap);
|
||||
$this->debug_message('calendar_boupdate::update() checking overlapping event %1',false,$overlap);
|
||||
}
|
||||
// check if the overlap is with a rejected participant or within the allowed quantity
|
||||
$common_parts = array_intersect($users,array_keys($overlap['participants']));
|
||||
@ -198,7 +201,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
if ($this->debug > 3 || $this->debug == 'update')
|
||||
{
|
||||
$this->debug_message('bocalupdate::update() conflicts with the following participants found %1',false,$common_parts);
|
||||
$this->debug_message('calendar_boupdate::update() conflicts with the following participants found %1',false,$common_parts);
|
||||
}
|
||||
$conflicts[$overlap['id'].'-'.$this->date2ts($overlap['start'])] =& $overlapping_events[$k];
|
||||
}
|
||||
@ -221,12 +224,13 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
foreach($conflicts as $key => $conflict)
|
||||
{
|
||||
$conflict['participants'] = array_intersect_key($conflict['participants'],$event['participants']);
|
||||
if (!$this->check_perms(EGW_ACL_READ,$conflict))
|
||||
{
|
||||
$conflicts[$key] = array(
|
||||
'id' => $conflict['id'],
|
||||
'title' => lang('busy'),
|
||||
'participants' => array_intersect_key($conflict['participants'],$event['participants']),
|
||||
'participants' => $conflict['participants'],
|
||||
'start' => $conflict['start'],
|
||||
'end' => $conflict['end'],
|
||||
);
|
||||
@ -234,7 +238,7 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
if ($this->debug > 2 || $this->debug == 'update')
|
||||
{
|
||||
$this->debug_message('bocalupdate::update() %1 conflicts found %2',false,count($conflicts),$conflicts);
|
||||
$this->debug_message('calendar_boupdate::update() %1 conflicts found %2',false,count($conflicts),$conflicts);
|
||||
}
|
||||
return $conflicts;
|
||||
}
|
||||
@ -253,10 +257,11 @@ class calendar_boupdate extends calendar_bo
|
||||
if (!isset($event['participants'])) $event['participants'] = $old_event['participants'];
|
||||
//echo "old $event[id]="; _debug_array($old_event);
|
||||
}
|
||||
|
||||
//echo "saving $event[id]="; _debug_array($event);
|
||||
$event2save = $event;
|
||||
|
||||
if (!($cal_id = $this->save($event)))
|
||||
if (!($cal_id = $this->save($event, $ignore_acl, $updateTS)))
|
||||
{
|
||||
return $cal_id;
|
||||
}
|
||||
@ -285,7 +290,7 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for added, modified or deleted participants
|
||||
* Check for added, modified or deleted participants AND notify them
|
||||
*
|
||||
* @param array $new_event the updated event
|
||||
* @param array $old_event the event before the update
|
||||
@ -294,7 +299,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
$modified = $added = $deleted = array();
|
||||
|
||||
//echo "<p>bocalupdate::check4update() new participants = ".print_r($new_event['participants'],true).", old participants =".print_r($old_event['participants'],true)."</p>\n";
|
||||
//echo "<p>calendar_boupdate::check4update() new participants = ".print_r($new_event['participants'],true).", old participants =".print_r($old_event['participants'],true)."</p>\n";
|
||||
|
||||
// Find modified and deleted participants ...
|
||||
foreach($old_event['participants'] as $old_userid => $old_status)
|
||||
@ -316,7 +321,7 @@ class calendar_boupdate extends calendar_bo
|
||||
$added[$new_userid] = 'U';
|
||||
}
|
||||
}
|
||||
//echo "<p>bocalupdate::check4update() added=".print_r($added,true).", modified=".print_r($modified,true).", deleted=".print_r($deleted,true)."</p>\n";
|
||||
//echo "<p>calendar_boupdate::check4update() added=".print_r($added,true).", modified=".print_r($modified,true).", deleted=".print_r($deleted,true)."</p>\n";
|
||||
if(count($added) || count($modified) || count($deleted))
|
||||
{
|
||||
if(count($added))
|
||||
@ -387,7 +392,7 @@ class calendar_boupdate extends calendar_bo
|
||||
case 'no':
|
||||
break;
|
||||
}
|
||||
//echo "<p>bocalupdate::update_requested(user=$userid,pref=".$part_prefs['calendar']['receive_updates'] .",msg_type=$msg_type,".($old_event?$old_event['title']:'False').",".($old_event?$old_event['title']:'False').") = $want_update</p>\n";
|
||||
//echo "<p>calendar_boupdate::update_requested(user=$userid,pref=".$part_prefs['calendar']['receive_updates'] .",msg_type=$msg_type,".($old_event?$old_event['title']:'False').",".($old_event?$old_event['title']:'False').") = $want_update</p>\n";
|
||||
return $want_update > 0;
|
||||
}
|
||||
|
||||
@ -403,6 +408,7 @@ class calendar_boupdate extends calendar_bo
|
||||
*/
|
||||
function send_update($msg_type,$to_notify,$old_event,$new_event=null,$user=0)
|
||||
{
|
||||
//echo "<p>".__METHOD__."($msg_type,".array2string($to_notify).",,$new_event[title],$user)</p>\n";
|
||||
if (!is_array($to_notify))
|
||||
{
|
||||
$to_notify = array();
|
||||
@ -527,7 +533,7 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
if($userid != $GLOBALS['egw_info']['user']['account_id'] || $msg_type == MSG_ALARM)
|
||||
{
|
||||
$preferences =& CreateObject('phpgwapi.preferences',$userid);
|
||||
$preferences = CreateObject('phpgwapi.preferences',$userid);
|
||||
$part_prefs = $preferences->read_repository();
|
||||
|
||||
if (!$this->update_requested($userid,$part_prefs,$msg_type,$old_event,$new_event))
|
||||
@ -553,7 +559,18 @@ class calendar_boupdate extends calendar_bo
|
||||
|
||||
switch($part_prefs['calendar']['update_format'])
|
||||
{
|
||||
case 'extended':
|
||||
case 'ical':
|
||||
if ($method == 'REQUEST')
|
||||
{
|
||||
$ics = ExecMethod2('calendar.calendar_ical.exportVCal',$event['id'],'2.0',$method);
|
||||
$attachment = array( 'string' => $ics,
|
||||
'filename' => 'cal.ics',
|
||||
'encoding' => '8bit',
|
||||
'type' => 'text/calendar; method='.$method,
|
||||
);
|
||||
}
|
||||
// fall through
|
||||
case 'extended':
|
||||
$body .= "\n\n".lang('Event Details follow').":\n";
|
||||
foreach($event_arr as $key => $val)
|
||||
{
|
||||
@ -570,18 +587,6 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ical':
|
||||
$ics = ExecMethod2('calendar.calendar_ical.exportVCal',$event['id'],'2.0',$method,false);
|
||||
if ($method == 'REQUEST')
|
||||
{
|
||||
$attachment = array( 'string' => $ics,
|
||||
'filename' => 'cal.ics',
|
||||
'encoding' => '8bit',
|
||||
'type' => 'text/calendar; method='.$method,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// send via notification_app
|
||||
if($GLOBALS['egw_info']['apps']['notifications']['enabled']) {
|
||||
@ -661,20 +666,23 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
|
||||
/**
|
||||
* saves an event to the database, does NOT do any notifications, see bocalupdate::update for that
|
||||
* saves an event to the database, does NOT do any notifications, see calendar_boupdate::update for that
|
||||
*
|
||||
* This methode converts from user to server time and handles the insertion of users and dates of repeating events
|
||||
*
|
||||
* @param array $event
|
||||
* @return int/boolean $cal_id > 0 or false on error (eg. permission denied)
|
||||
* @param boolean $ignore_acl=false should we ignore the acl
|
||||
* @param boolean $updateTS=true update the content history of the event
|
||||
* @return int|boolean $cal_id > 0 or false on error (eg. permission denied)
|
||||
*/
|
||||
function save($event)
|
||||
function save($event,$ignore_acl=false,$updateTS=true)
|
||||
{
|
||||
//error_log(__METHOD__."(".str_replace(array("\n",' '),'',print_r($event,true)).",$etag)");
|
||||
//echo '<p>'.__METHOD__.'('.array2string($event).",$ignore_acl)</p>\n";
|
||||
//error_log(__METHOD__.'('.array2string($event).",$etag)");
|
||||
// check if user has the permission to update / create the event
|
||||
if ($event['id'] && !$this->check_perms(EGW_ACL_EDIT,$event['id']) ||
|
||||
if (!$ignore_acl && ($event['id'] && !$this->check_perms(EGW_ACL_EDIT,$event['id']) ||
|
||||
!$event['id'] && !$this->check_perms(EGW_ACL_EDIT,0,$event['owner']) &&
|
||||
!$this->check_perms(EGW_ACL_ADD,0,$event['owner']))
|
||||
!$this->check_perms(EGW_ACL_ADD,0,$event['owner'])))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -684,7 +692,7 @@ class calendar_boupdate extends calendar_bo
|
||||
|
||||
$save_event = $event;
|
||||
// we run all dates through date2ts, to adjust to server-time and the possible date-formats
|
||||
foreach(array('start','end','modified','recur_enddate') as $ts)
|
||||
foreach(array('start','end','modified','recur_enddate','reference') as $ts)
|
||||
{
|
||||
// we convert here from user-time to timestamps in server-time!
|
||||
if (isset($event[$ts])) $event[$ts] = $event[$ts] ? $this->date2ts($event[$ts],true) : 0;
|
||||
@ -705,12 +713,16 @@ class calendar_boupdate extends calendar_bo
|
||||
$event['alarm'][$id]['time'] = $this->date2ts($alarm['time'],true);
|
||||
}
|
||||
}
|
||||
if (($cal_id = $this->so->save($event,$set_recurrences,NULL,$event['etag'])) && $set_recurrences && $event['recur_type'] != MCAL_RECUR_NONE)
|
||||
$set_recurrences = false;
|
||||
$set_recurrences_start = 0;
|
||||
if (($cal_id = $this->so->save($event,$set_recurrences,$set_recurrences_start,0,$event['etag'])) && $set_recurrences && $event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
$save_event['id'] = $cal_id;
|
||||
$this->set_recurrences($save_event);
|
||||
// unset participants to enforce the default stati for all added recurrences
|
||||
unset($save_event['participants']);
|
||||
$this->set_recurrences($save_event, $set_recurrences_start);
|
||||
}
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,$event['id'] ? 'modify' : 'add',time());
|
||||
if ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,$event['id'] ? 'modify' : 'add',time());
|
||||
|
||||
return $cal_id;
|
||||
}
|
||||
@ -720,8 +732,8 @@ class calendar_boupdate extends calendar_bo
|
||||
*
|
||||
* For contacts we use edit rights of the owner of the event (aka. edit rights of the event).
|
||||
*
|
||||
* @param int/string $uid account_id or 1-char type-identifer plus id (eg. c15 for addressbook entry #15)
|
||||
* @param array/int $event event array or id of the event
|
||||
* @param int|string $uid account_id or 1-char type-identifer plus id (eg. c15 for addressbook entry #15)
|
||||
* @param array|int $event event array or id of the event
|
||||
* @return boolean
|
||||
*/
|
||||
function check_status_perms($uid,$event)
|
||||
@ -745,23 +757,25 @@ class calendar_boupdate extends calendar_bo
|
||||
/**
|
||||
* set the status of one participant for a given recurrence or for all recurrences since now (includes recur_date=0)
|
||||
*
|
||||
* @param int/array $event event-array or id of the event
|
||||
* @param string/int $uid account_id or 1-char type-identifer plus id (eg. c15 for addressbook entry #15)
|
||||
* @param int/char $status numeric status (defines) or 1-char code: 'R', 'U', 'T' or 'A'
|
||||
* @param int|array $event event-array or id of the event
|
||||
* @param string|int $uid account_id or 1-char type-identifer plus id (eg. c15 for addressbook entry #15)
|
||||
* @param int|char $status numeric status (defines) or 1-char code: 'R', 'U', 'T' or 'A'
|
||||
* @param int $recur_date=0 date to change, or 0 = all since now
|
||||
* @param boolean $ignore_acl=false do not check the permisions for the $uid, if true
|
||||
* @param boolean $updateTS=true update the content history of the event
|
||||
* @return int number of changed recurrences
|
||||
*/
|
||||
function set_status($event,$uid,$status,$recur_date=0)
|
||||
function set_status($event,$uid,$status,$recur_date=0,$ignore_acl=false,$updateTS=true)
|
||||
{
|
||||
$cal_id = is_array($event) ? $event['id'] : $event;
|
||||
//echo "<p>bocalupdate::set_status($cal_id,$uid,$status,$recur_date)</p>\n";
|
||||
if (!$cal_id || !$this->check_status_perms($uid,$event))
|
||||
//echo "<p>calendar_boupdate::set_status($cal_id,$uid,$status,$recur_date)</p>\n";
|
||||
if (!$cal_id || (!$ignore_acl && !$this->check_status_perms($uid,$event)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (($Ok = $this->so->set_status($cal_id,is_numeric($uid)?'u':$uid[0],is_numeric($uid)?$uid:substr($uid,1),$status,$recur_date ? $this->date2ts($recur_date,true) : 0)))
|
||||
{
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time());
|
||||
if ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time());
|
||||
|
||||
static $status2msg = array(
|
||||
'R' => MSG_REJECTED,
|
||||
@ -783,14 +797,15 @@ class calendar_boupdate extends calendar_bo
|
||||
*
|
||||
* @param int $cal_id id of the event to delete
|
||||
* @param int $recur_date=0 if a single event from a series should be deleted, its date
|
||||
* @param boolean $ignore_acl=false true for no ACL check, default do ACL check
|
||||
* @return boolean true on success, false on error (usually permission denied)
|
||||
*/
|
||||
function delete($cal_id,$recur_date=0)
|
||||
function delete($cal_id,$recur_date=0,$ignore_acl=false)
|
||||
{
|
||||
$event = $this->read($cal_id,$recur_date);
|
||||
|
||||
if (!($event = $this->read($cal_id,$recur_date)) ||
|
||||
!$this->check_perms(EGW_ACL_DELETE,$event))
|
||||
!$ignore_acl && !$this->check_perms(EGW_ACL_DELETE,$event))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -811,6 +826,10 @@ class calendar_boupdate extends calendar_bo
|
||||
unset($event['end']);
|
||||
$this->save($event); // updates the content-history
|
||||
}
|
||||
if ($event['reference'])
|
||||
{
|
||||
// evtl. delete recur_exception $event['recurrence'] from event with cal_id=$event['reference']
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1006,7 +1025,9 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
$alarm['time'] = $this->date2ts($alarm['time'],true); // user to server-time
|
||||
|
||||
return $this->so->save_alarm($cal_id,$alarm);
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id, 'modify', time());
|
||||
|
||||
return $this->so->save_alarm($cal_id,$alarm, $this->now_su);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1023,7 +1044,10 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
return false; // no rights to delete the alarm
|
||||
}
|
||||
return $this->so->delete_alarm($id);
|
||||
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id, 'modify', time());
|
||||
|
||||
return $this->so->delete_alarm($id, $this->now_su);
|
||||
}
|
||||
|
||||
var $categories;
|
||||
@ -1032,7 +1056,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
if (!is_object($this->categories))
|
||||
{
|
||||
$this->categories =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'calendar');
|
||||
$this->categories = CreateObject('phpgwapi.categories',$this->user,'calendar');
|
||||
}
|
||||
|
||||
$cat_id_list = array();
|
||||
@ -1046,7 +1070,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
$cat_name = substr($cat_name, 2);
|
||||
}
|
||||
$cat_id = $this->categories->add(array('name' => $cat_name,'descr' => $cat_name));
|
||||
$cat_id = $this->categories->add(array('name' => $cat_name, 'descr' => $cat_name, 'access' => 'private'));
|
||||
}
|
||||
|
||||
if ($cat_id)
|
||||
@ -1067,7 +1091,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
if (!is_object($this->categories))
|
||||
{
|
||||
$this->categories =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'calendar');
|
||||
$this->categories = CreateObject('phpgwapi.categories',$this->user,'calendar');
|
||||
}
|
||||
|
||||
if (!is_array($cat_id_list))
|
||||
@ -1086,4 +1110,110 @@ class calendar_boupdate extends calendar_bo
|
||||
|
||||
return $cat_list;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a matching db entry
|
||||
*
|
||||
* @param array $event the vCalendar data we try to find
|
||||
* @param boolean $relax=false if asked to relax, we only match against some key fields
|
||||
* @return the calendar_id of the matching entry or false (if none matches)
|
||||
*/
|
||||
function find_event($event, $relax=false)
|
||||
{
|
||||
$query = array(
|
||||
'cal_start='.$event['start'],
|
||||
'cal_end='.$event['end'],
|
||||
);
|
||||
|
||||
foreach (array('title', 'location',
|
||||
'public', 'non_blocking', 'category') as $key)
|
||||
{
|
||||
if (!empty($event[$key])) $query['cal_'.$key] = $event[$key];
|
||||
}
|
||||
|
||||
if ($event['uid'] && ($uidmatch = $this->read($event['uid'])))
|
||||
{
|
||||
if ($event['reference'])
|
||||
{
|
||||
// Let's try to find a real exception first
|
||||
$query['cal_uid'] = $event['uid'];
|
||||
$query['cal_reference'] = $event['reference'];
|
||||
|
||||
if ($foundEvents = parent::search(array(
|
||||
'query' => $query,
|
||||
)))
|
||||
{
|
||||
if(is_array($foundEvents))
|
||||
{
|
||||
$event = array_shift($foundEvents);
|
||||
return $event['id'];
|
||||
}
|
||||
}
|
||||
// Let's try the "status only" (pseudo) exceptions now
|
||||
if (($egw_event = $this->read($uidmatch['id'], $event['reference'])))
|
||||
{
|
||||
// Do we work with a pseudo exception here?
|
||||
$match = true;
|
||||
foreach (array('start', 'end', 'title', 'description', 'priority',
|
||||
'location', 'public', 'non_blocking') as $key)
|
||||
{
|
||||
if (isset($event[$key])
|
||||
&& $event[$key] != $egw_event[$key])
|
||||
{
|
||||
$match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($match && is_array($event['participants']))
|
||||
{
|
||||
foreach ($event['participants'] as $attendee => $status)
|
||||
{
|
||||
if (!isset($egw_event['participants'][$attendee])
|
||||
|| $egw_event['participants'][$attendee] != $status)
|
||||
{
|
||||
$match = false;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($egw_event['participants'][$attendee]);
|
||||
}
|
||||
}
|
||||
if ($match && !empty($egw_event['participants'])) $match = false;
|
||||
}
|
||||
if ($match) return ($uidmatch['id'] . ':' . $event['reference']);
|
||||
|
||||
return false; // We need to create a new pseudo exception
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $uidmatch['id'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($event['id'] && ($found = $this->read($event['id'])))
|
||||
{
|
||||
// We only do a simple consistency check
|
||||
if ($found['title'] == $event['title']
|
||||
&& $found['start'] == $event['start']
|
||||
&& $found['end'] == $event['end'])
|
||||
{
|
||||
return $found['id'];
|
||||
}
|
||||
}
|
||||
unset($event['id']);
|
||||
|
||||
if($foundEvents = parent::search(array(
|
||||
'query' => $query,
|
||||
)))
|
||||
{
|
||||
if(is_array($foundEvents))
|
||||
{
|
||||
$event = array_shift($foundEvents);
|
||||
return $event['id'];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
* @package calendar
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007/8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
@ -33,7 +33,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
//'RDATE' => 'cal_start',
|
||||
//'EXRULE'
|
||||
//'EXDATE'
|
||||
//'RECURRENCE-ID'
|
||||
'RECURRENCE-ID' => 'cal_reference',
|
||||
);
|
||||
|
||||
/**
|
||||
@ -43,11 +43,11 @@ class calendar_groupdav extends groupdav_handler
|
||||
* @param int $debug=null debug-level to set
|
||||
* @param string $base_uri=null base url of handler
|
||||
*/
|
||||
function __construct($app,$debug=null,$base_uri=null)
|
||||
function __construct($app,$debug=null, $base_uri=null)
|
||||
{
|
||||
parent::__construct($app,$debug,$base_uri);
|
||||
|
||||
$this->bo =& new calendar_boupdate();
|
||||
$this->bo = new calendar_boupdate();
|
||||
}
|
||||
|
||||
const PATH_ATTRIBUTE = 'id';
|
||||
@ -85,18 +85,20 @@ class calendar_groupdav extends groupdav_handler
|
||||
function propfind($path,$options,&$files,$user,$id='')
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user,$id)");
|
||||
|
||||
//error_log(__METHOD__."($path,".array2string($options).",,$user,$id)");//njv:
|
||||
// ToDo: add parameter to only return id & etag
|
||||
//error_log( __FILE__ . __METHOD__ ." :$user ". print_r($options,true));
|
||||
$st = microtime(true);
|
||||
$cal_filters = array(
|
||||
'users' => $user,
|
||||
'start' => time()-30*24*3600, // default one month back
|
||||
'end' => time()+365*24*3600, // default one year into the future
|
||||
'start' => time()-100*24*3600, // default one month back -30 breaks all sync recurrences
|
||||
'end' => time()+365*24*3600, // default one year into the future +365
|
||||
'enum_recuring' => false,
|
||||
'daywise' => false,
|
||||
'date_format' => 'server',
|
||||
);
|
||||
if ($this->debug > 1) error_log(__METHOD__."($path,,,$user,$id) cal_filters=".array2string($cal_filters));
|
||||
|
||||
//error_log(__METHOD__."($path,,,$user,$id) cal_filters=".array2string($cal_filters));//njv
|
||||
// process REPORT filters or multiget href's
|
||||
if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$cal_filters,$id))
|
||||
{
|
||||
@ -114,6 +116,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
}
|
||||
}
|
||||
}
|
||||
//error_log(__FILE__ . __METHOD__ ."Filters:" .print_r($cal_filters,true));
|
||||
if (($events = $this->bo->search($cal_filters)))
|
||||
{
|
||||
foreach($events as $event)
|
||||
@ -127,6 +130,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
HTTP_WebDAV_Server::mkprop('getlastmodified', $event['modified']),
|
||||
HTTP_WebDAV_Server::mkprop('resourcetype',''), // iPhone requires that attribute!
|
||||
);
|
||||
//error_log(__FILE__ . __METHOD__ . "Calendar Data : $calendar_data");
|
||||
if ($calendar_data)
|
||||
{
|
||||
if (is_null($handler)) $handler = $this->_get_handler();
|
||||
@ -144,6 +148,8 @@ class calendar_groupdav extends groupdav_handler
|
||||
);
|
||||
}
|
||||
}
|
||||
$end = microtime(true) - $st;
|
||||
if ($this->debug) error_log(__FILE__ . __METHOD__ . "Function took : $end");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -170,6 +176,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
{
|
||||
case 'comp-filter':
|
||||
if ($this->debug > 1) error_log(__METHOD__."($path,...) comp-filter='{$filter['attrs']['name']}'");
|
||||
|
||||
switch($filter['attrs']['name'])
|
||||
{
|
||||
case 'VTODO':
|
||||
@ -178,7 +185,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
$infolog_handler = new groupdav_infolog();
|
||||
return $infolog_handler->propfind($path,$options,$files,$user,$method);
|
||||
case 'VCALENDAR':
|
||||
CASE 'VEVENT':
|
||||
case 'VEVENT':
|
||||
break; // that's our default anyway
|
||||
}
|
||||
break;
|
||||
@ -202,7 +209,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
if ($this->debug) error_log(__METHOD__."($path,...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!");
|
||||
break;
|
||||
case 'time-range':
|
||||
if ($this->debug > 1) error_log(__METHOD__."($path,...) time-range={$filter['attrs']['start']}-{$filter['attrs']['end']}");
|
||||
if ($this->debug > 1) error_log(__FILE__ . __METHOD__."($path,...) time-range={$filter['attrs']['start']}-{$filter['attrs']['end']}");
|
||||
$cal_filters['start'] = $filter['attrs']['start'];
|
||||
$cal_filters['end'] = $filter['attrs']['end'];
|
||||
break;
|
||||
@ -218,6 +225,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
}
|
||||
}
|
||||
// multiget or propfind on a given id
|
||||
//error_log(__FILE__ . __METHOD__ . "multiget of propfind:");
|
||||
if ($options['root']['name'] == 'calendar-multiget' || $id)
|
||||
{
|
||||
// no standard time-range!
|
||||
@ -253,7 +261,8 @@ class calendar_groupdav extends groupdav_handler
|
||||
{
|
||||
$cal_filters['query'][] = 'egw_cal.cal_id IN ('.implode(',',array_map(create_function('$n','return (int)$n;'),$ids)).')';
|
||||
}
|
||||
if ($this->debug) error_log(__METHOD__."($path,,,$user,$id) calendar-multiget: ids=".implode(',',$ids));
|
||||
|
||||
if ($this->debug > 1) error_log(__FILE__ . __METHOD__ ."($path,,,$user,$id) calendar-multiget: ids=".implode(',',$ids));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -289,10 +298,13 @@ class calendar_groupdav extends groupdav_handler
|
||||
*/
|
||||
function put(&$options,$id,$user=null)
|
||||
{
|
||||
if($this->debug) error_log(__METHOD__."($id, $user)".print_r($options,true));
|
||||
$return_no_access=true; // as handled by importVCal anyway and allows it to set the status for participants
|
||||
$event = $this->_common_get_put_delete('PUT',$options,$id,$return_no_access);
|
||||
|
||||
if (!is_null($event) && !is_array($event))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__.print_r($event,true).function_backtrace());
|
||||
return $event;
|
||||
}
|
||||
$handler = $this->_get_handler();
|
||||
@ -347,6 +359,8 @@ class calendar_groupdav extends groupdav_handler
|
||||
*/
|
||||
function read($id)
|
||||
{
|
||||
//$cal_read = $this->bo->read($id,null,false,'server');//njv: do we actually get anything
|
||||
if ($this->debug > 1) error_log("bo-ical read :$id:");//njv:
|
||||
return $this->bo->read($id,null,false,'server');
|
||||
}
|
||||
|
||||
@ -363,12 +377,15 @@ class calendar_groupdav extends groupdav_handler
|
||||
{
|
||||
$entry = $this->read($entry);
|
||||
}
|
||||
if (!$entry['id'] || !isset($entry['etag']) || !isset($entry['participants'])) error_log(__METHOD__."($e_in): id=$entry[id], etag=$entry[etag], isset(participants)=".(int)isset($entry['participants']).", title=$entry[title]: id, etag or participants not set!!!");
|
||||
if (!$entry['id'] || !isset($entry['etag']) || !isset($entry['participants']))
|
||||
{
|
||||
if ($this->debug > 1) error_log(__FILE__ . __METHOD__."($e_in): id=$entry[id], etag=$entry[etag], isset(participants)=".(int)isset($entry['participants']).", title=$entry[title]: id, etag or participants not set!!!");
|
||||
}
|
||||
$etag = $entry['id'].':'.$entry['etag'];
|
||||
// add a hash over the participants and their stati
|
||||
ksort($entry['participants']); // create a defined order
|
||||
$etag .= ':'.md5(serialize($entry['participants']));
|
||||
//error_log(__METHOD__."($entry[id] ($entry[etag]): $entry[title] --> etag=$etag");
|
||||
//error_log(__FILE__ .__METHOD__ . "($entry[id] ($entry[etag]): $entry[title] --> etag=$etag");
|
||||
return $etag;
|
||||
}
|
||||
|
||||
@ -412,9 +429,10 @@ class calendar_groupdav extends groupdav_handler
|
||||
*/
|
||||
private function _get_handler()
|
||||
{
|
||||
$handler =& new calendar_ical();
|
||||
$handler = new calendar_ical();
|
||||
$handler->setSupportedFields('GroupDAV',$this->agent);
|
||||
|
||||
if ($this->debug > 1) error_log("ical Handler called:" . $this->agent);
|
||||
return $handler;
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,13 +4,14 @@
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke <lkneschke@egroupware.org>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package calendar
|
||||
* @subpackage export
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar.php';
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
|
||||
/**
|
||||
* SIF Parser for SyncML
|
||||
@ -21,6 +22,7 @@ class calendar_sif extends calendar_boupdate
|
||||
'Start' => 'start',
|
||||
'End' => 'end',
|
||||
'AllDayEvent' => 'alldayevent',
|
||||
'Attendees' => '',
|
||||
'BillingInformation' => '',
|
||||
'Body' => 'description',
|
||||
'BusyStatus' => '',
|
||||
@ -33,6 +35,11 @@ class calendar_sif extends calendar_boupdate
|
||||
'Mileage' => '',
|
||||
'ReminderMinutesBeforeStart' => 'reminderstart',
|
||||
'ReminderSet' => 'reminderset',
|
||||
'ReminderSoundFile' => '',
|
||||
'ReminderOptions' => '',
|
||||
'ReminderInterval' => '',
|
||||
'ReminderRepeatCount' => '',
|
||||
'Exceptions' => '',
|
||||
'ReplyTime' => '',
|
||||
'Sensitivity' => 'public',
|
||||
'Subject' => 'title',
|
||||
@ -51,6 +58,11 @@ class calendar_sif extends calendar_boupdate
|
||||
// the calendar event array
|
||||
var $event;
|
||||
|
||||
// device specific settings
|
||||
var $productName = 'mozilla plugin';
|
||||
var $productSoftwareVersion = '0.3';
|
||||
var $uidExtension = false;
|
||||
|
||||
// constants for recurence type
|
||||
const olRecursDaily = 0;
|
||||
const olRecursWeekly = 1;
|
||||
@ -68,33 +80,41 @@ class calendar_sif extends calendar_boupdate
|
||||
const olFriday = 32;
|
||||
const olSaturday = 64;
|
||||
|
||||
function startElement($_parser, $_tag, $_attributes) {
|
||||
// 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) {
|
||||
function endElement($_parser, $_tag)
|
||||
{
|
||||
//error_log('endElem: ' . $_tag .' => '. trim($this->sifData));
|
||||
if(!empty($this->sifMapping[$_tag])) {
|
||||
if(!empty($this->sifMapping[$_tag]))
|
||||
{
|
||||
$this->event[$this->sifMapping[$_tag]] = trim($this->sifData);
|
||||
}
|
||||
unset($this->sifData);
|
||||
}
|
||||
|
||||
function characterData($_parser, $_data) {
|
||||
function characterData($_parser, $_data)
|
||||
{
|
||||
$this->sifData .= $_data;
|
||||
}
|
||||
|
||||
function siftoegw($_sifdata) {
|
||||
$vcal = &new Horde_iCalendar;
|
||||
function siftoegw($sifData)
|
||||
{
|
||||
$vcal = new Horde_iCalendar;
|
||||
$finalEvent = array();
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
$sifData = base64_decode($_sifdata);
|
||||
#error_log($sifData);
|
||||
|
||||
$tmpfname = tempnam('/tmp/sync/contents','sife_');
|
||||
#$tmpfname = tempnam('/tmp/sync/contents','sife_');
|
||||
|
||||
$handle = fopen($tmpfname, "w");
|
||||
fwrite($handle, $sifData);
|
||||
fclose($handle);
|
||||
#$handle = fopen($tmpfname, "w");
|
||||
#fwrite($handle, $sifData);
|
||||
#fclose($handle);
|
||||
|
||||
$this->xml_parser = xml_parser_create('UTF-8');
|
||||
xml_set_object($this->xml_parser, $this);
|
||||
@ -102,7 +122,8 @@ class calendar_sif extends calendar_boupdate
|
||||
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) {
|
||||
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)));
|
||||
@ -110,16 +131,29 @@ class calendar_sif extends calendar_boupdate
|
||||
}
|
||||
#error_log(print_r($this->event, true));
|
||||
|
||||
foreach($this->event as $key => $value) {
|
||||
foreach ($this->event as $key => $value)
|
||||
{
|
||||
$value = preg_replace('/<\!\[CDATA\[(.+)\]\]>/Usim', '$1', $value);
|
||||
$value = $GLOBALS['egw']->translation->convert($value, 'utf-8', $sysCharSet);
|
||||
#error_log("$key => $value");
|
||||
switch($key) {
|
||||
switch ($key)
|
||||
{
|
||||
case 'alldayevent':
|
||||
if($value == 1) {
|
||||
if ($value == 1)
|
||||
{
|
||||
$finalEvent['whole_day'] = true;
|
||||
$startParts = explode('-',$this->event['start']);
|
||||
$finalEvent['start'] = mktime(0, 0, 0, $startParts[1], $startParts[2], $startParts[0]);
|
||||
$finalEvent['start']['hour'] = $finalEvent['start']['minute'] = $finalEvent['start']['second'] = 0;
|
||||
$finalEvent['start']['year'] = $startParts[0];
|
||||
$finalEvent['start']['month'] = $startParts[1];
|
||||
$finalEvent['start']['day'] = $startParts[2];
|
||||
$finalEvent['start'] = $this->date2ts($finalEvent['start']);
|
||||
$endParts = explode('-',$this->event['end']);
|
||||
$finalEvent['end'] = mktime(23, 59, 59, $endParts[1], $endParts[2], $endParts[0]);
|
||||
$finalEvent['end']['hour'] = 23; $finalEvent['end']['minute'] = $finalEvent['end']['second'] = 59;
|
||||
$finalEvent['end']['year'] = $endParts[0];
|
||||
$finalEvent['end']['month'] = $endParts[1];
|
||||
$finalEvent['end']['day'] = $endParts[2];
|
||||
$finalEvent['end'] = $this->date2ts($finalEvent['end']);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -128,26 +162,31 @@ class calendar_sif extends calendar_boupdate
|
||||
break;
|
||||
|
||||
case 'category':
|
||||
if(!empty($value)) {
|
||||
if (!empty($value))
|
||||
{
|
||||
$finalEvent[$key] = implode(',',$this->find_or_add_categories(explode(';', $value)));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'end':
|
||||
case 'start':
|
||||
if($this->event['alldayevent'] < 1) {
|
||||
if ($this->event['alldayevent'] < 1)
|
||||
{
|
||||
$finalEvent[$key] = $vcal->_parseDateTime($value);
|
||||
error_log("event ".$key." val=".$value.", parsed=".$finalEvent[$key]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'isrecurring':
|
||||
if($value == 1) {
|
||||
if ($value == 1)
|
||||
{
|
||||
$finalEvent['recur_interval'] = $this->event['recur_interval'];
|
||||
if($this->event['recur_noenddate'] == 0) {
|
||||
if ($this->event['recur_noenddate'] == 0)
|
||||
{
|
||||
$finalEvent['recur_enddate'] = $vcal->_parseDateTime($this->event['recur_enddate']);
|
||||
}
|
||||
switch($this->event['recur_type']) {
|
||||
switch ($this->event['recur_type'])
|
||||
{
|
||||
case self::olRecursDaily:
|
||||
$finalEvent['recur_type'] = MCAL_RECUR_DAILY;
|
||||
break;
|
||||
@ -174,11 +213,12 @@ class calendar_sif extends calendar_boupdate
|
||||
break;
|
||||
|
||||
case 'priority':
|
||||
$finalEvent[$key] = $value+1;
|
||||
$finalEvent[$key] = $value + 1;
|
||||
break;
|
||||
|
||||
case 'reminderset':
|
||||
if($value == 1) {
|
||||
if ($value == 1)
|
||||
{
|
||||
$finalEvent['alarm'] = $this->event['reminderstart'];
|
||||
}
|
||||
break;
|
||||
@ -191,6 +231,12 @@ class calendar_sif extends calendar_boupdate
|
||||
// do nothing, get's handled in isrecuring clause
|
||||
break;
|
||||
|
||||
case 'description':
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
$finalEvent['uid'] = $matches[1];
|
||||
}
|
||||
|
||||
default:
|
||||
$finalEvent[$key] = $value;
|
||||
break;
|
||||
@ -205,97 +251,74 @@ class calendar_sif extends calendar_boupdate
|
||||
return $finalEvent;
|
||||
}
|
||||
|
||||
function search($_sifdata, $contentID=null) {
|
||||
if(!$event = $this->siftoegw($_sifdata)) {
|
||||
return false;
|
||||
}
|
||||
function search($_sifdata, $contentID=null, $relax=false)
|
||||
{
|
||||
$result = false;
|
||||
|
||||
$query = array(
|
||||
'cal_start='.$this->date2ts($event['start'],true), // true = Server-time
|
||||
'cal_end='.$this->date2ts($event['end'],true),
|
||||
);
|
||||
|
||||
if ($contentID) {
|
||||
$query[] = 'egw_cal.cal_id='.(int)$contentID;
|
||||
}
|
||||
|
||||
#foreach(array('title','location','priority','public','non_blocking') as $name) {
|
||||
foreach(array('title','location','public','non_blocking') as $name) {
|
||||
if (isset($event[$name])) $query['cal_'.$name] = $event[$name];
|
||||
}
|
||||
|
||||
if($foundEvents = parent::search(array(
|
||||
'user' => $this->user,
|
||||
'query' => $query,
|
||||
))) {
|
||||
if(is_array($foundEvents)) {
|
||||
$event = array_shift($foundEvents);
|
||||
return $event['id'];
|
||||
if ($event = $this->siftoegw($_sifdata))
|
||||
{
|
||||
if ($contentID) {
|
||||
$event['id'] = $contentID;
|
||||
}
|
||||
$result = $this->find_event($event, $relax);
|
||||
}
|
||||
return false;
|
||||
|
||||
$search['start'] = $event['start'];
|
||||
$search['end'] = $event['end'];
|
||||
|
||||
unset($event['description']);
|
||||
unset($event['start']);
|
||||
unset($event['end']);
|
||||
|
||||
foreach($event as $key => $value) {
|
||||
if (substr($key,0,6) != 'recur_' && substr($key,0,5) != 'alarm') {
|
||||
$search['query']['cal_'.$key] = $value;
|
||||
} else {
|
||||
#$search['query'][$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if($foundEvents = parent::search($search)) {
|
||||
if(is_array($foundEvents)) {
|
||||
$event = array_shift($foundEvents);
|
||||
return $event['id'];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int contact id
|
||||
* @param string $_vcard the vcard
|
||||
* @param int $_abID the internal addressbook id
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
* @desc import a vard into addressbook
|
||||
*/
|
||||
function addSIF($_sifdata, $_calID)
|
||||
function addSIF($_sifdata, $_calID, $merge=false)
|
||||
{
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
$calID = false;
|
||||
|
||||
#error_log('ABID: '.$_abID);
|
||||
#error_log(base64_decode($_sifdata));
|
||||
|
||||
if(!$event = $this->siftoegw($_sifdata)) {
|
||||
if (!$event = $this->siftoegw($_sifdata))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isset($event['alarm'])) {
|
||||
if (isset($event['alarm']))
|
||||
{
|
||||
$alarm = $event['alarm'];
|
||||
unset($event['alarm']);
|
||||
}
|
||||
|
||||
if($_calID > 0)
|
||||
if ($_calID > 0)
|
||||
{
|
||||
// update entry
|
||||
$event['id'] = $_calID;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($event['whole_day']) && $event['whole_day']
|
||||
&& isset ($deviceInfo) && is_array($deviceInfo)
|
||||
&& isset($deviceInfo['nonBlockingAllday'])
|
||||
&& $deviceInfo['nonBlockingAllday'])
|
||||
{
|
||||
$event['non_blocking'] = '1';
|
||||
}
|
||||
}
|
||||
|
||||
if($eventID = $this->update($event, TRUE)) {
|
||||
if ($eventID = $this->update($event, TRUE))
|
||||
{
|
||||
$updatedEvent = $this->read($eventID);
|
||||
foreach($updatedEvent['alarm'] as $alarmID => $alarmData)
|
||||
foreach ($updatedEvent['alarm'] as $alarmID => $alarmData)
|
||||
{
|
||||
$this->delete_alarm($alarmID);
|
||||
}
|
||||
|
||||
if(isset($alarm)) {
|
||||
if (isset($alarm))
|
||||
{
|
||||
$alarmData['time'] = $event['start'] - ($alarm*60);
|
||||
$alarmData['offset'] = $alarm*60;
|
||||
$alarmData['all'] = 1;
|
||||
@ -308,46 +331,48 @@ class calendar_sif extends calendar_boupdate
|
||||
}
|
||||
|
||||
/**
|
||||
* return a vcard
|
||||
* return a sife
|
||||
*
|
||||
* @param int $_id the id of the contact
|
||||
* @param int $_vcardProfile profile id for mapping from vcard values to egw addressbook
|
||||
* @param int $_id the id of the event
|
||||
* @return string containing the vcard
|
||||
*/
|
||||
function getSIF($_id)
|
||||
{
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
|
||||
$fields = array_unique(array_values($this->sifMapping));
|
||||
sort($fields);
|
||||
|
||||
#$event = $this->read($_id,null,false,'server');
|
||||
#error_log("FOUND EVENT: ". print_r($event, true));
|
||||
|
||||
if($event = $this->read($_id,null,false,'server')) {
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
$vcal = &new Horde_iCalendar;
|
||||
if (($event = $this->read($_id,null,false,'server')))
|
||||
{
|
||||
|
||||
|
||||
$sifEvent = '<appointment>';
|
||||
|
||||
foreach($this->sifMapping as $sifField => $egwField)
|
||||
if ($this->uidExtension)
|
||||
{
|
||||
if(empty($egwField)) continue;
|
||||
if (!preg_match('/\[UID:.+\]/m', $event['description']))
|
||||
{
|
||||
$event['description'] .= "\n[UID:" . $event['uid'] . "]";
|
||||
}
|
||||
}
|
||||
|
||||
$vcal = new Horde_iCalendar('1.0');
|
||||
|
||||
|
||||
$sifEvent = self::xml_decl . "\n<appointment>" . self::SIF_decl;
|
||||
|
||||
foreach ($this->sifMapping as $sifField => $egwField)
|
||||
{
|
||||
if (empty($egwField)) continue;
|
||||
|
||||
#error_log("$sifField => $egwField");
|
||||
#error_log('VALUE1: '.$event[$egwField]);
|
||||
$value = $GLOBALS['egw']->translation->convert($event[$egwField], $sysCharSet, 'utf-8');
|
||||
#error_log('VALUE2: '.$value);
|
||||
|
||||
switch($sifField)
|
||||
switch ($sifField)
|
||||
{
|
||||
case 'Categories':
|
||||
if(!empty($value)) {
|
||||
$value = implode('; ', $this->get_categories(explode(',',$value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
$sifEvent .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Importance':
|
||||
$value = $value-1;
|
||||
$sifEvent .= "<$sifField>$value</$sifField>";
|
||||
@ -362,10 +387,26 @@ class calendar_sif extends calendar_boupdate
|
||||
break;
|
||||
|
||||
case 'IsRecurring':
|
||||
switch($event['recur_type']) {
|
||||
case MCAL_RECUR_NONE:
|
||||
$sifEvent .= "<$sifField>0</$sifField>";
|
||||
break;
|
||||
if ($event['recur_type'] == MCAL_RECUR_NONE)
|
||||
{
|
||||
$sifEvent .= "<$sifField>0</$sifField>";
|
||||
break;
|
||||
}
|
||||
if ($event['recur_enddate'] == 0)
|
||||
{
|
||||
$sifEvent .= '<NoEndDate>1</NoEndDate>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$recurEndDate = mktime(24 , 0, 0,
|
||||
date('m',$event['recur_enddate']),
|
||||
date('d', $event['recur_enddate']),
|
||||
date('Y', $event['recur_enddate']));
|
||||
$sifEvent .= '<NoEndDate>0</NoEndDate>';
|
||||
$sifEvent .= '<PatternEndDate>'. $vcal->_exportDateTime($recurEndDate) .'</PatternEndDate>';
|
||||
}
|
||||
switch ($event['recur_type'])
|
||||
{
|
||||
|
||||
case MCAL_RECUR_DAILY:
|
||||
$eventInterval = ($event['recur_interval'] > 1 ? $event['recur_interval'] : 1);
|
||||
@ -375,13 +416,8 @@ class calendar_sif extends calendar_boupdate
|
||||
$sifEvent .= '<RecurrenceType>'. self::olRecursDaily .'</RecurrenceType>';
|
||||
$sifEvent .= '<Interval>'. $eventInterval .'</Interval>';
|
||||
$sifEvent .= '<PatternStartDate>'. $vcal->_exportDateTime($recurStartDate) .'</PatternStartDate>';
|
||||
if($event['recur_enddate'] == 0) {
|
||||
$sifEvent .= '<NoEndDate>1</NoEndDate>';
|
||||
} else {
|
||||
$recurEndDate = mktime(24,0,0,date('m',$event['recur_enddate']), date('d', $event['recur_enddate']), date('Y', $event['recur_enddate']));
|
||||
|
||||
$sifEvent .= '<NoEndDate>0</NoEndDate>';
|
||||
$sifEvent .= '<PatternEndDate>'. $vcal->_exportDateTime($recurEndDate) .'</PatternEndDate>';
|
||||
if ($event['recur_enddate'])
|
||||
{
|
||||
$totalDays = ($recurEndDate - $recurStartDate) / 86400;
|
||||
$occurrences = ceil($totalDays / $eventInterval);
|
||||
$sifEvent .= '<Occurrences>'. $occurrences .'</Occurrences>';
|
||||
@ -397,46 +433,73 @@ class calendar_sif extends calendar_boupdate
|
||||
$sifEvent .= '<Interval>'. $eventInterval .'</Interval>';
|
||||
$sifEvent .= '<PatternStartDate>'. $vcal->_exportDateTime($recurStartDate) .'</PatternStartDate>';
|
||||
$sifEvent .= '<DayOfWeekMask>'. $event['recur_data'] .'</DayOfWeekMask>';
|
||||
if($event['recur_enddate'] == 0) {
|
||||
$sifEvent .= '<NoEndDate>1</NoEndDate>';
|
||||
} else {
|
||||
$recurEndDate = mktime(24, 0, 0, date('m',$event['recur_enddate']), date('d', $event['recur_enddate']), date('Y', $event['recur_enddate']));
|
||||
|
||||
if ($event['recur_enddate'])
|
||||
{
|
||||
$daysPerWeek = substr_count(decbin($event['recur_data']),'1');
|
||||
$sifEvent .= '<NoEndDate>0</NoEndDate>';
|
||||
$sifEvent .= '<PatternEndDate>'. $vcal->_exportDateTime($recurEndDate) .'</PatternEndDate>';
|
||||
$totalWeeks = floor(($recurEndDate - $recurStartDate) / (86400*7));
|
||||
#error_log("AAA: $daysPerWeek $totalWeeks");
|
||||
$occurrences = ($totalWeeks / $eventInterval) * $daysPerWeek;
|
||||
for($i = $recurEndDate; $i > $recurStartDate + ($totalWeeks * 86400*7); $i = $i - 86400) {
|
||||
switch(date('w', $i-1)) {
|
||||
for($i = $recurEndDate; $i > $recurStartDate + ($totalWeeks * 86400*7); $i = $i - 86400)
|
||||
{
|
||||
switch (date('w', $i-1))
|
||||
{
|
||||
case 0:
|
||||
if($event['recur_data'] & 1) $occurrences++;
|
||||
if ($event['recur_data'] & 1) $occurrences++;
|
||||
break;
|
||||
// monday
|
||||
case 1:
|
||||
if($event['recur_data'] & 2) $occurrences++;
|
||||
if ($event['recur_data'] & 2) $occurrences++;
|
||||
break;
|
||||
case 2:
|
||||
if($event['recur_data'] & 4) $occurrences++;
|
||||
if ($event['recur_data'] & 4) $occurrences++;
|
||||
break;
|
||||
case 3:
|
||||
if($event['recur_data'] & 8) $occurrences++;
|
||||
if ($event['recur_data'] & 8) $occurrences++;
|
||||
break;
|
||||
case 4:
|
||||
if($event['recur_data'] & 16) $occurrences++;
|
||||
if ($event['recur_data'] & 16) $occurrences++;
|
||||
break;
|
||||
case 5:
|
||||
if($event['recur_data'] & 32) $occurrences++;
|
||||
if ($event['recur_data'] & 32) $occurrences++;
|
||||
break;
|
||||
case 6:
|
||||
if($event['recur_data'] & 64) $occurrences++;
|
||||
if ($event['recur_data'] & 64) $occurrences++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sifEvent .= '<Occurrences>'. $occurrences .'</Occurrences>';
|
||||
}
|
||||
break;
|
||||
|
||||
case MCAL_RECUR_MONTHLY_MDAY:
|
||||
$eventInterval = ($event['recur_interval'] > 1 ? $event['recur_interval'] : 1);
|
||||
$recurStartDate = mktime(0,0,0,date('m',$event['start']), date('d', $event['start']), date('Y', $event['start']));
|
||||
|
||||
$sifEvent .= "<$sifField>1</$sifField>";
|
||||
$sifEvent .= '<RecurrenceType>'. self::olRecursMonthly .'</RecurrenceType>';
|
||||
$sifEvent .= '<Interval>'. $eventInterval .'</Interval>';
|
||||
$sifEvent .= '<PatternStartDate>'. $vcal->_exportDateTime($recurStartDate) .'</PatternStartDate>';
|
||||
break;
|
||||
|
||||
case MCAL_RECUR_MONTHLY_WDAY:
|
||||
$weekMaskMap = array('Sun' => self::olSunday, 'Mon' => self::olMonday, 'Tue' => self::olTuesday,
|
||||
'Wed' => self::olWednesday, 'Thu' => self::olThursday, 'Fri' => self::olFriday,
|
||||
'Sat' => self::olSaturday);
|
||||
$eventInterval = ($event['recur_interval'] > 1 ? $event['recur_interval'] : 1);
|
||||
$recurStartDate = mktime(0,0,0,date('m',$event['start']), date('d', $event['start']), date('Y', $event['start']));
|
||||
|
||||
$sifEvent .= "<$sifField>1</$sifField>";
|
||||
$sifEvent .= '<RecurrenceType>'. self::olRecursMonthNth .'</RecurrenceType>';
|
||||
$sifEvent .= '<Interval>'. $eventInterval .'</Interval>';
|
||||
$sifEvent .= '<PatternStartDate>'. $vcal->_exportDateTime($recurStartDate) .'</PatternStartDate>';
|
||||
$sifEvent .= '<Instance>' . (1 + (int) ((date('d',$event['start'])-1) / 7)) . '</Instance>';
|
||||
$sifEvent .= '<DayOfWeekMask>' . $weekMaskMap[date('D',$event['start'])] . '</DayOfWeekMask>';
|
||||
break;
|
||||
|
||||
case MCAL_RECUR_YEARLY:
|
||||
$sifEvent .= "<$sifField>1</$sifField>";
|
||||
$sifEvent .= '<RecurrenceType>'. self::olRecursYearly .'</RecurrenceType>';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -456,12 +519,16 @@ class calendar_sif extends calendar_boupdate
|
||||
break;
|
||||
|
||||
case 'Start':
|
||||
if($event['end'] - $event['start'] == 86399 && date('Y-m-d', $event['end']) == date('Y-m-d', $event['start'])) {
|
||||
if ($this->isWholeDay($event))
|
||||
{
|
||||
$value = date('Y-m-d', $event['start']);
|
||||
$sifEvent .= "<Start>$value</Start>";
|
||||
$vaule = date('Y-m-d', $event['end']);
|
||||
$sifEvent .= "<End>$value</End>";
|
||||
$sifEvent .= "<AllDayEvent>1</AllDayEvent>";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $vcal->_exportDateTime($event['start']);
|
||||
$sifEvent .= "<Start>$value</Start>";
|
||||
$value = $vcal->_exportDateTime($event['end']);
|
||||
@ -474,27 +541,42 @@ class calendar_sif extends calendar_boupdate
|
||||
break;
|
||||
|
||||
case 'ReminderSet':
|
||||
if(count((array)$event['alarm']) > 0) {
|
||||
if (count((array)$event['alarm']) > 0)
|
||||
{
|
||||
$sifEvent .= "<$sifField>1</$sifField>";
|
||||
foreach($event['alarm'] as $alarmID => $alarmData)
|
||||
foreach ($event['alarm'] as $alarmID => $alarmData)
|
||||
{
|
||||
$sifEvent .= '<ReminderMinutesBeforeStart>'. $alarmData['offset']/60 .'</ReminderMinutesBeforeStart>';
|
||||
// lets take only the first alarm
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sifEvent .= "<$sifField>0</$sifField>";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = implode('; ', $this->get_categories(explode(',',$value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_QUOTES, 'utf-8');
|
||||
$sifEvent .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sifEvent .= '</appointment>';
|
||||
|
||||
return base64_encode($sifEvent);
|
||||
return $sifEvent;
|
||||
}
|
||||
|
||||
if($this->xmlrpc)
|
||||
@ -504,4 +586,35 @@ class calendar_sif extends calendar_boupdate
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,9 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005-8 by RalfBecker-At-outdoor-training.de
|
||||
* @author Christian Binder <christian-AT-jaytraxx.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) 2005-9 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -13,7 +15,7 @@
|
||||
/**
|
||||
* some necessary defines used by the calendar
|
||||
*/
|
||||
if(extension_loaded('mcal') == False)
|
||||
if(!extension_loaded('mcal'))
|
||||
{
|
||||
define('MCAL_RECUR_NONE',0);
|
||||
define('MCAL_RECUR_DAILY',1);
|
||||
@ -43,6 +45,10 @@ define('NO_RESPONSE',1);
|
||||
define('TENTATIVE',2);
|
||||
define('ACCEPTED',3);
|
||||
|
||||
define('HOUR_s',60*60);
|
||||
define('DAY_s',24*HOUR_s);
|
||||
define('WEEK_s',7*DAY_s);
|
||||
|
||||
/**
|
||||
* Class to store all calendar data (storage object)
|
||||
*
|
||||
@ -67,7 +73,7 @@ class calendar_so
|
||||
var $extra_table,$repeats_table,$user_table,$dates_table,$all_tables;
|
||||
|
||||
/**
|
||||
* internal copy of the global db-object
|
||||
* reference to global db-object
|
||||
*
|
||||
* @var egw_db
|
||||
*/
|
||||
@ -105,12 +111,21 @@ class calendar_so
|
||||
*
|
||||
* All times (start, end and modified) are returned as timesstamps in servertime!
|
||||
*
|
||||
* @param int/array/string $ids id or array of id's of the entries to read, or string with a single uid
|
||||
* @param int|array|string $ids id or array of id's of the entries to read, or string with a single uid
|
||||
* @param int $recur_date=0 if set read the next recurrance at or after the timestamp, default 0 = read the initital one
|
||||
* @return array/boolean array with id => data pairs or false if entry not found
|
||||
* @return array|boolean array with id => data pairs or false if entry not found
|
||||
*/
|
||||
function read($ids,$recur_date=0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//echo "<p>socal::read(".print_r($ids,true).",$recur_date)<br />\n".function_backtrace()."<p>\n";
|
||||
|
||||
$table_def = $this->db->get_table_definitions('calendar',$this->cal_table);
|
||||
@ -131,7 +146,9 @@ class calendar_so
|
||||
}
|
||||
else
|
||||
{
|
||||
// We want only the parents to match
|
||||
$where['cal_uid'] = $ids;
|
||||
$where['cal_reference'] = 0;
|
||||
}
|
||||
if ((int) $recur_date)
|
||||
{
|
||||
@ -153,6 +170,17 @@ class calendar_so
|
||||
}
|
||||
if (!$events) return false;
|
||||
|
||||
foreach ($events as &$event)
|
||||
{
|
||||
if (!isset($event['uid']) || strlen($event['uid']) < $minimum_uid_length)
|
||||
{
|
||||
// event (without uid), not strong enough uid => create new uid
|
||||
$event['uid'] = $GLOBALS['egw']->common->generate_uid('calendar',$event['id']);
|
||||
$this->db->update($this->cal_table, array('cal_uid' => $event['uid']),
|
||||
array('cal_id' => $event['id']),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have a real recurance, if not set $recur_date=0
|
||||
if (is_array($ids) || $events[(int)$ids]['recur_type'] == MCAL_RECUR_NONE)
|
||||
{
|
||||
@ -173,20 +201,12 @@ class calendar_so
|
||||
'cal_recur_date' => $recur_date,
|
||||
),__LINE__,__FILE__,false,'ORDER BY cal_user_type DESC,'.self::STATUS_SORT,'calendar') as $row) // DESC puts users before resources and contacts
|
||||
{
|
||||
// if the type is not an ordinary user (eg. contact or resource)...
|
||||
if ($row['cal_user_type'] && $row['cal_user_type'] != 'u')
|
||||
{
|
||||
// prefix the id with the type
|
||||
$user_id = $row['cal_user_type'].$row['cal_user_id'];
|
||||
// and append quantity
|
||||
$row['cal_status'] .= $row['cal_quantity'] == 1 ? '' : $row['cal_quantity'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$user_id = (int) $row['cal_user_id'];
|
||||
}
|
||||
$events[$row['cal_id']]['participants'][$user_id] = $row['cal_status'];
|
||||
$events[$row['cal_id']]['participant_types'][$row['cal_user_type']][$row['cal_user_id']] = $row['cal_status'];
|
||||
// combine all participant data in uid and status values
|
||||
$uid = self::combine_user($row['cal_user_type'],$row['cal_user_id']);
|
||||
$status = self::combine_status($row['cal_status'],$row['cal_quantity'],$row['cal_role']);
|
||||
|
||||
$events[$row['cal_id']]['participants'][$uid] = $status;
|
||||
$events[$row['cal_id']]['participant_types'][$row['cal_user_type']][$row['cal_user_id']] = $status;
|
||||
}
|
||||
|
||||
// custom fields
|
||||
@ -214,7 +234,7 @@ class calendar_so
|
||||
/**
|
||||
* generate SQL to filter after a given category (evtl. incl. subcategories)
|
||||
*
|
||||
* @param array/int $cat_id cat-id or array of cat-ids, or !$cat_id for none
|
||||
* @param array|int $cat_id cat-id or array of cat-ids, or !$cat_id for none
|
||||
* @return string SQL to include in the query
|
||||
*/
|
||||
function cat_filter($cat_id)
|
||||
@ -247,25 +267,35 @@ class calendar_so
|
||||
*
|
||||
* @param int $start startdate of the search/list (servertime)
|
||||
* @param int $end enddate of the search/list (servertime)
|
||||
* @param int/array $users user-id or array of user-id's, !$users means all entries regardless of users
|
||||
* @param int|array $users user-id or array of user-id's, !$users means all entries regardless of users
|
||||
* @param int $cat_id=0 mixed category-id or array of cat-id's, default 0 = all
|
||||
* Please note: only a single cat-id, will include all sub-cats (if the common-pref 'cats_no_subs' is False)
|
||||
* @param string $filter='' string filter-name, atm. all or hideprivate
|
||||
* @param string $filter='all' string filter-name: all (not rejected), accepted, unknown, tentative, rejected or hideprivate (handled elsewhere!)
|
||||
* @param string $query='' pattern so search for, if unset or empty all matching entries are returned (no search)
|
||||
* Please Note: a search never returns repeating events more then once AND does not honor start+end date !!!
|
||||
* @param int/bool $offset=False offset for a limited query or False (default)
|
||||
* @param int|boolean $offset=False offset for a limited query or False (default)
|
||||
* @param int $num_rows=0 number of rows to return if offset set, default 0 = use default in user prefs
|
||||
* @param string $order='cal_start' column-names plus optional DESC|ASC separted by comma
|
||||
* @param boolean $show_rejected=true should the search return rejected invitations
|
||||
* @param string $sql_filter='' sql to be and'ed into query (fully quoted)
|
||||
* @param string|array $_cols=null what to select, default "$this->repeats_table.*,$this->cal_table.*,cal_start,cal_end,cal_recur_date",
|
||||
* if specified and not false an iterator for the rows is returned
|
||||
* @param string $append='' SQL to append to the query before $order, eg. for a GROUP BY clause
|
||||
* @param array $cfs=null custom fields to query, null = none, array() = all, or array with cfs names
|
||||
* @return array of cal_ids, or false if error in the parameters
|
||||
*
|
||||
* ToDo: search custom-fields too
|
||||
*/
|
||||
function &search($start,$end,$users,$cat_id=0,$filter='',$query='',$offset=False,$num_rows=0,$order = 'cal_start',$show_rejected=true)
|
||||
function &search($start,$end,$users,$cat_id=0,$filter='all',$query='',$offset=False,$num_rows=0,$order='cal_start',$sql_filter='',$_cols=null,$append='',$cfs=null)
|
||||
{
|
||||
//echo '<p>socal::search('.($start ? date('Y-m-d H:i',$start) : '').','.($end ? date('Y-m-d H:i',$end) : '').','.print_r($users,true).','.print_r($cat_id,true).",'$filter',".print_r($query,true).",$offset,$num_rows)</p>\n";
|
||||
//echo '<p>'.__METHOD__.'('.($start ? date('Y-m-d H:i',$start) : '').','.($end ? date('Y-m-d H:i',$end) : '').','.array2string($users).','.array2string($cat_id).",'$filter',".array2string($query).",$offset,$num_rows,$order,$show_rejected,".array2string($_cols).",$append,".array2string($cfs).")</p>\n";
|
||||
|
||||
$cols = !is_null($_cols) ? $_cols : "$this->repeats_table.*,$this->cal_table.*,cal_start,cal_end,cal_recur_date";
|
||||
|
||||
$where = array();
|
||||
if (!empty($sql_filter) && is_string($sql_filter))
|
||||
{
|
||||
$where[] = $sql_filter;
|
||||
}
|
||||
if (is_array($query))
|
||||
{
|
||||
$where = $query;
|
||||
@ -281,7 +311,7 @@ class calendar_so
|
||||
if ($users)
|
||||
{
|
||||
$users_by_type = array();
|
||||
foreach(is_array($users) ? $users : array($users) as $user)
|
||||
foreach((array)$users as $user)
|
||||
{
|
||||
if (is_numeric($user))
|
||||
{
|
||||
@ -289,7 +319,7 @@ class calendar_so
|
||||
}
|
||||
elseif (is_numeric(substr($user,1)))
|
||||
{
|
||||
$users_by_type[$user{0}][] = (int) substr($user,1);
|
||||
$users_by_type[$user[0]][] = (int) substr($user,1);
|
||||
}
|
||||
}
|
||||
$to_or = array();
|
||||
@ -300,10 +330,31 @@ class calendar_so
|
||||
'cal_user_type' => $type,
|
||||
'cal_user_id' => $ids,
|
||||
));
|
||||
if ($type == 'u' && $filter == 'owner')
|
||||
{
|
||||
$cal_table_def = $this->db->get_table_definitions('calendar',$this->cal_table);
|
||||
$to_or[] = $this->db->expression($cal_table_def,array('cal_owner' => $ids));
|
||||
}
|
||||
}
|
||||
$where[] = '('.implode(' OR ',$to_or).')';
|
||||
|
||||
if (!$show_rejected) $where[] = "cal_status != 'R'";
|
||||
switch($filter)
|
||||
{
|
||||
case 'unknown':
|
||||
$where[] = "cal_status='U'"; break;
|
||||
case 'accepted':
|
||||
$where[] = "cal_status='A'"; break;
|
||||
case 'tentative':
|
||||
$where[] = "cal_status='T'"; break;
|
||||
case 'rejected':
|
||||
$where[] = "cal_status='R'"; break;
|
||||
case 'all':
|
||||
break;
|
||||
default:
|
||||
//if (!$show_rejected) // not longer used
|
||||
$where[] = "cal_status != 'R'";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($cat_id)
|
||||
{
|
||||
@ -320,9 +371,10 @@ class calendar_so
|
||||
$select = array(
|
||||
'table' => $this->cal_table,
|
||||
'join' => "JOIN $this->dates_table ON $this->cal_table.cal_id=$this->dates_table.cal_id JOIN $this->user_table ON $this->cal_table.cal_id=$this->user_table.cal_id LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id",
|
||||
'cols' => "$this->repeats_table.*,$this->cal_table.*,cal_start,cal_end,cal_recur_date",
|
||||
'cols' => $cols,
|
||||
'where' => $where,
|
||||
'app' => 'calendar',
|
||||
'append'=> $append,
|
||||
);
|
||||
$selects = array($select,$select);
|
||||
$selects[0]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
|
||||
@ -337,6 +389,7 @@ class calendar_so
|
||||
|
||||
$selects[0]['cols'] = $selects[1]['cols'] = $select['cols']; // restore the original cols
|
||||
}
|
||||
// error_log("calendar_so_search:\n" . print_r($selects, true));
|
||||
$rs = $this->db->union($selects,__LINE__,__FILE__,$order,$offset,$num_rows);
|
||||
}
|
||||
else // MsSQL oder MySQL 3.23
|
||||
@ -351,11 +404,14 @@ class calendar_so
|
||||
$where,__LINE__,__FILE__,false,'','calendar',0,
|
||||
"JOIN $this->dates_table ON $this->cal_table.cal_id=$this->dates_table.cal_id JOIN $this->user_table ON $this->cal_table.cal_id=$this->user_table.cal_id LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id")->NumRows();
|
||||
}
|
||||
$rs = $this->db->select($this->cal_table,($this->db->capabilities['distinct_on_text'] ? 'DISTINCT ' : '').
|
||||
"$this->repeats_table.*,$this->cal_table.*,cal_start,cal_end,cal_recur_date",
|
||||
$where,__LINE__,__FILE__,$offset,'ORDER BY '.$order,'calendar',$num_rows,
|
||||
$rs = $this->db->select($this->cal_table,($this->db->capabilities['distinct_on_text'] ? 'DISTINCT ' : '').$cols,
|
||||
$where,__LINE__,__FILE__,$offset,$append.' ORDER BY '.$order,'calendar',$num_rows,
|
||||
"JOIN $this->dates_table ON $this->cal_table.cal_id=$this->dates_table.cal_id JOIN $this->user_table ON $this->cal_table.cal_id=$this->user_table.cal_id LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id");
|
||||
}
|
||||
if (!is_null($_cols))
|
||||
{
|
||||
return $rs; // if colums are specified we return the recordset / iterator
|
||||
}
|
||||
$events = $ids = $recur_dates = $recur_ids = array();
|
||||
foreach($rs as $row)
|
||||
{
|
||||
@ -375,33 +431,41 @@ class calendar_so
|
||||
// now ready all users with the given cal_id AND (cal_recur_date=0 or the fitting recur-date)
|
||||
// This will always read the first entry of each recuring event too, we eliminate it later
|
||||
$recur_dates[] = 0;
|
||||
foreach($this->db->select($this->user_table,'*',array(
|
||||
'cal_id' => array_unique($ids),
|
||||
'cal_recur_date' => $recur_dates,
|
||||
),__LINE__,__FILE__,false,'ORDER BY cal_id,cal_user_type DESC,'.self::STATUS_SORT,'calendar') as $row) // DESC puts users before resources and contacts
|
||||
$utcal_id_view = " (SELECT * FROM ".$this->user_table." WHERE cal_id IN (".implode(',',array_unique($ids)).")) utcalid ";
|
||||
//$utrecurdate_view = " (select * from ".$this->user_table." where cal_recur_date in (".implode(',',array_unique($recur_dates)).")) utrecurdates ";
|
||||
foreach($this->db->select($utcal_id_view,'*',array(
|
||||
//'cal_id' => array_unique($ids),
|
||||
'cal_recur_date' => $recur_dates,
|
||||
),__LINE__,__FILE__,false,'ORDER BY cal_id,cal_user_type DESC,'.self::STATUS_SORT,'calendar',$num_rows=0,$join='',
|
||||
$this->db->get_table_definitions('calendar',$this->user_table)) as $row) // DESC puts users before resources and contacts
|
||||
{
|
||||
$id = $row['cal_id'];
|
||||
if ($row['cal_recur_date']) $id .= '-'.$row['cal_recur_date'];
|
||||
if (!in_array($id,(array)$recur_ids[$row['cal_id']])) $recur_ids[$row['cal_id']][] = $id;
|
||||
|
||||
if (!isset($events[$id])) continue; // not needed first entry of recuring event
|
||||
|
||||
$events[$id]['participants'][$this->combine_user($row['cal_user_type'],$row['cal_user_id'])] = $row['cal_status'];
|
||||
// combine all participant data in uid and status values
|
||||
$events[$id]['participants'][self::combine_user($row['cal_user_type'],$row['cal_user_id'])] =
|
||||
self::combine_status($row['cal_status'],$row['cal_quantity'],$row['cal_role']);
|
||||
}
|
||||
/* custom fields are not shown in the regular views, so we can ignore them here for the moment
|
||||
foreach($this->db->select($this->extra_table,'*',array('cal_id'=>$ids),__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
//custom fields are not shown in the regular views, so we only query them, if explicitly required
|
||||
if (!is_null($cfs))
|
||||
{
|
||||
$set_ids = array($row['cal_id']);
|
||||
if (isset($recur_ids[$row['cal_id']])) $set_ids += $recur_ids[$row['cal_id']];
|
||||
|
||||
foreach($set_ids as $id)
|
||||
$where = array('cal_id' => $ids);
|
||||
if ($cfs) $where['cal_extra_name'] = $cfs;
|
||||
foreach($this->db->select($this->extra_table,'*',$where,
|
||||
__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
{
|
||||
if (isset($events[$cal_id]))
|
||||
foreach((array)$recur_ids[$row['cal_id']] as $id)
|
||||
{
|
||||
$events[$id]['#'.$row['cal_extra_name']] = $row['cal_extra_value'];
|
||||
if (isset($events[$id]))
|
||||
{
|
||||
$events[$id]['#'.$row['cal_extra_name']] = $row['cal_extra_value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
// alarms, atm. we read all alarms in the system, as this can be done in a single query
|
||||
foreach((array)$this->async->read('cal'.(is_array($ids) ? '' : ':'.(int)$ids).':%') as $id => $job)
|
||||
{
|
||||
@ -468,14 +532,24 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
*
|
||||
* @param array $event
|
||||
* @param boolean &$set_recurrences on return: true if the recurrences need to be written, false otherwise
|
||||
* @param int &$set_recurrences_start=0 on return: time from which on the recurrences should be rebuilt, default 0=all
|
||||
* @param int $change_since=0 time from which on the repetitions should be changed, default 0=all
|
||||
* @param int &$etag etag=null etag to check or null, on return new etag
|
||||
* @return boolean/int false on error, 0 if etag does not match, cal_id otherwise
|
||||
* @return boolean|int false on error, 0 if etag does not match, cal_id otherwise
|
||||
*/
|
||||
function save($event,&$set_recurrences,$change_since=0,&$etag=null)
|
||||
function save($event,&$set_recurrences,&$set_recurrences_start=0,$change_since=0,&$etag=null)
|
||||
{
|
||||
//echo "<p>socal::save(,$change_since) event="; _debug_array($event);
|
||||
//error_log(__METHOD__."(".str_replace(array("\n",' '),'',print_r($event,true)).",$set_recurrences,$change_since,$etag)");
|
||||
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;
|
||||
}
|
||||
|
||||
//echo '<p>'.__METHOD__.'('.array2string($event).",$change_since) event="; _debug_array($event);
|
||||
//error_log(__METHOD__.'('.array2string($event).",$set_recurrences,$change_since,$etag)");
|
||||
|
||||
$cal_id = (int) $event['id'];
|
||||
unset($event['id']);
|
||||
@ -484,7 +558,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
// add colum prefix 'cal_' if there's not already a 'recur_' prefix
|
||||
foreach($event as $col => $val)
|
||||
{
|
||||
if ($col{0} != '#' && substr($col,0,6) != 'recur_' && $col != 'alarm')
|
||||
if ($col[0] != '#' && substr($col,0,6) != 'recur_' && $col != 'alarm')
|
||||
{
|
||||
$event['cal_'.$col] = $val;
|
||||
unset($event[$col]);
|
||||
@ -510,6 +584,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
else
|
||||
{
|
||||
// new event
|
||||
if (!$event['cal_owner']) $event['cal_owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
if (!$event['cal_id'] && !isset($event['cal_uid'])) $event['cal_uid'] = ''; // uid is NOT NULL!
|
||||
@ -519,45 +594,102 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// new event (without uid), not strong enough uid or new created referencing event => create new uid
|
||||
if (strlen($event['cal_uid']) < 20 || is_numeric($event['cal_uid']) ||
|
||||
$event['cal_reference'] && strpos($event['cal_uid'],'cal-'.$event['calreference'].'-') !== false)
|
||||
{
|
||||
$event['cal_uid'] = $GLOBALS['egw']->common->generate_uid('calendar',$cal_id);
|
||||
$this->db->update($this->cal_table,array('cal_uid' => $event['cal_uid']),array('cal_id' => $cal_id),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
$etag = 0;
|
||||
// new events need to have at least one participant, default to the owner
|
||||
if (!isset($event['cal_participants']))
|
||||
{
|
||||
$event['cal_participants'] = array($event['cal_owner'] => 'A');
|
||||
}
|
||||
}
|
||||
if (!isset($event['cal_uid']) || strlen($event['cal_uid']) < $minimum_uid_length)
|
||||
{
|
||||
// event (without uid), not strong enough uid
|
||||
$event['cal_uid'] = $GLOBALS['egw']->common->generate_uid('calendar',$cal_id);
|
||||
$this->db->update($this->cal_table, array('cal_uid' => $event['cal_uid']),
|
||||
array('cal_id' => $event['cal_id']),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
// write information about recuring event, if recur_type is present in the array
|
||||
if (isset($event['recur_type']))
|
||||
{
|
||||
if (isset($event['recur_exception']) && is_array($event['recur_exception']) && count($event['recur_exception']))
|
||||
{
|
||||
// delete execeptions from the user and dates table, it could be the first time
|
||||
$this->db->delete($this->user_table,array('cal_id' => $cal_id,'cal_recur_date' => $event['recur_exception']),__LINE__,__FILE__,'calendar');
|
||||
$this->db->delete($this->dates_table,array('cal_id' => $cal_id,'cal_start' => $event['recur_exception']),__LINE__,__FILE__,'calendar');
|
||||
// fetch information about the currently saved (old) event
|
||||
$old_min = (int) $this->db->select($this->dates_table,'MIN(cal_start)',array('cal_id'=>$cal_id),__LINE__,__FILE__,false,'','calendar')->fetchColumn();
|
||||
$old_duration = (int) $this->db->select($this->dates_table,'MIN(cal_end)',array('cal_id'=>$cal_id),__LINE__,__FILE__,false,'','calendar')->fetchColumn() - $old_min;
|
||||
$old_repeats = $this->db->select($this->repeats_table,'*',array('cal_id' => $cal_id),__LINE__,__FILE__,false,'','calendar')->fetch();
|
||||
$old_exceptions = $old_repeats['recur_exception'] ? explode(',',$old_repeats['recur_exception']) : array();
|
||||
|
||||
$event['recur_exception'] = implode(',',$event['recur_exception']);
|
||||
$event['recur_exception'] = is_array($event['recur_exception']) ? $event['recur_exception'] : array();
|
||||
|
||||
// re-check: did so much recurrence data change that we have to rebuild it from scratch?
|
||||
if (!$set_recurrences)
|
||||
{
|
||||
$set_recurrences = (isset($event['cal_start']) && (int)$old_min != (int) $event['cal_start']) ||
|
||||
$event['recur_type'] != $old_repeats['recur_type'] || $event['recur_data'] != $old_repeats['recur_data'] ||
|
||||
(int)$event['recur_interval'] != (int)$old_repeats['recur_interval'];
|
||||
}
|
||||
|
||||
if ($set_recurrences)
|
||||
{
|
||||
// too much recurrence data has changed, we have to do a rebuild from scratch
|
||||
// delete all, but the lowest dates record
|
||||
$this->db->delete($this->dates_table,array(
|
||||
'cal_id' => $cal_id,
|
||||
'cal_start > '.(int)$old_min,
|
||||
),__LINE__,__FILE__,'calendar');
|
||||
|
||||
// delete all user-records, with recur-date != 0
|
||||
$this->db->delete($this->user_table,array(
|
||||
'cal_id' => $cal_id,
|
||||
'cal_recur_date != 0',
|
||||
),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
else
|
||||
{
|
||||
$event['recur_exception'] = null;
|
||||
}
|
||||
if (!$set_recurrences)
|
||||
{
|
||||
// check if the recure-information changed
|
||||
$old_recur = $this->db->select($this->repeats_table,'*',array('cal_id' => $cal_id),__LINE__,__FILE__,false,'','calendar')->fetch();
|
||||
$old_exceptions = $old_recur['recur_exception'] ? explode(',',$old_recur['recur_exception']) : array();
|
||||
$exceptions = $event['recur_exception'] ? explode(',',$event['recur_exception']) : array();
|
||||
$set_recurrences = $event['recur_type'] != $old_recur['recur_type'] || $event['recur_data'] != $old_recur['recur_data'] ||
|
||||
$event['recur_interval'] != $old_recur['recur_interval'] || $event['recur_enddate'] != $old_recur['recur_enddate'] ||
|
||||
count(array_diff($old_exceptions,$exceptions)); // exception deleted or added
|
||||
// we adjust some possibly changed recurrences manually
|
||||
// deleted exceptions: re-insert recurrences into the user and dates table
|
||||
if(count($deleted_exceptions = array_diff($old_exceptions,$event['recur_exception'])))
|
||||
{
|
||||
foreach($deleted_exceptions as $id => $deleted_exception)
|
||||
{
|
||||
// rebuild participants for the re-inserted recurrence
|
||||
$participants = array();
|
||||
$participants_only = $this->get_participants($cal_id); // participants without states
|
||||
foreach($participants_only as $id => $participant_only)
|
||||
{
|
||||
$states = $this->get_recurrences($cal_id, $participant_only['uid']);
|
||||
$participants[$participant_only['uid']] = $states[0]; // insert main status as default
|
||||
}
|
||||
$this->recurrence($cal_id, $deleted_exception, $deleted_exception + $old_duration, $participants);
|
||||
}
|
||||
}
|
||||
|
||||
// check if recurrence enddate was adjusted
|
||||
if(isset($event['recur_enddate']))
|
||||
{
|
||||
// recurrences need to be truncated
|
||||
if((int)$event['recur_enddate'] > 0 &&
|
||||
((int)$old_repeats['recur_enddate'] == 0 || (int)$old_repeats['recur_enddate'] > (int)$event['recur_enddate'])
|
||||
)
|
||||
{
|
||||
$this->db->delete($this->user_table,array('cal_id' => $cal_id,'cal_recur_date > '.($event['recur_enddate'] + 1*DAY_s)),__LINE__,__FILE__,'calendar');
|
||||
$this->db->delete($this->dates_table,array('cal_id' => $cal_id,'cal_start > '.($event['recur_enddate'] + 1*DAY_s)),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
|
||||
// recurrences need to be expanded
|
||||
if(((int)$event['recur_enddate'] == 0 && (int)$old_repeats['recur_enddate'] > 0)
|
||||
|| ((int)$event['recur_enddate'] > 0 && (int)$old_repeats['recur_enddate'] > 0 && (int)$old_repeats['recur_enddate'] < (int)$event['recur_enddate'])
|
||||
)
|
||||
{
|
||||
$set_recurrences = true;
|
||||
$set_recurrences_start = ($old_repeats['recur_enddate'] + 1*DAY_s);
|
||||
}
|
||||
}
|
||||
|
||||
// truncate recurrences by given exceptions
|
||||
if (count($event['recur_exception']))
|
||||
{
|
||||
// added and existing exceptions: delete the execeptions from the user and dates table, it could be the first time
|
||||
$this->db->delete($this->user_table,array('cal_id' => $cal_id,'cal_recur_date' => $event['recur_exception']),__LINE__,__FILE__,'calendar');
|
||||
$this->db->delete($this->dates_table,array('cal_id' => $cal_id,'cal_start' => $event['recur_exception']),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
}
|
||||
|
||||
// write the repeats table
|
||||
$event['recur_exception'] = empty($event['recur_exception']) ? null : implode(',',$event['recur_exception']);
|
||||
unset($event[0]); // unset the 'etag=etag+1', as it's not in the repeats table
|
||||
if($event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
@ -567,21 +699,6 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
{
|
||||
$this->db->delete($this->repeats_table,array('cal_id' => $cal_id),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
if ($set_recurrences)
|
||||
{
|
||||
// delete all, but the lowest dates record
|
||||
$min = (int) $this->db->select($this->dates_table,'MIN(cal_start)',array('cal_id'=>$cal_id),__LINE__,__FILE__,false,'','calendar')->fetchSingle();
|
||||
|
||||
$this->db->delete($this->dates_table,array(
|
||||
'cal_id' => $cal_id,
|
||||
'cal_start > '.(int)$min,
|
||||
),__LINE__,__FILE__,'calendar');
|
||||
// delete all user-records, with recur-date != 0
|
||||
$this->db->delete($this->user_table,array(
|
||||
'cal_id' => $cal_id,
|
||||
'cal_recur_date != 0',
|
||||
),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
}
|
||||
// update start- and endtime if present in the event-array, evtl. we need to move all recurrences
|
||||
if (isset($event['cal_start']) && isset($event['cal_end']))
|
||||
@ -634,17 +751,17 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
|
||||
//pgoerzen: don't add an alarm if it is before the current date.
|
||||
if ($event['recur_type'] && ($tmp_event = $this->read($eventID, time() + $alarm['offset'])))
|
||||
/*if ($event['recur_type'] && ($tmp_event = $this->read($eventID, time() + $alarm['offset'])))
|
||||
{
|
||||
$alarm['time'] = $tmp_event['cal_start'] - $alarm['offset'];
|
||||
}
|
||||
} */
|
||||
|
||||
$this->save_alarm($cal_id,$alarm);
|
||||
}
|
||||
}
|
||||
if (is_null($etag))
|
||||
{
|
||||
$etag = $this->db->select($this->cal_table,'cal_etag',array('cal_id' => $cal_id),__LINE__,__FILE__,false,'','calendar')->fetchSingle();
|
||||
$etag = $this->db->select($this->cal_table,'cal_etag',array('cal_id' => $cal_id),__LINE__,__FILE__,false,'','calendar')->fetchColumn();
|
||||
}
|
||||
return $cal_id;
|
||||
}
|
||||
@ -655,10 +772,10 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
* @param int $cal_id
|
||||
* @param int $start new starttime
|
||||
* @param int $end new endtime
|
||||
* @param int/boolean $change_since=0 false=new entry, > 0 time from which on the repetitions should be changed, default 0=all
|
||||
* @param int|boolean $change_since=0 false=new entry, > 0 time from which on the repetitions should be changed, default 0=all
|
||||
* @param int $old_start=0 old starttime or (default) 0, to query it from the db
|
||||
* @param int $old_end=0 old starttime or (default) 0
|
||||
* @return int/boolean number of moved recurrences or false on error
|
||||
* @return int|boolean number of moved recurrences or false on error
|
||||
*/
|
||||
function move($cal_id,$start,$end,$change_since=0,$old_start=0,$old_end=0)
|
||||
{
|
||||
@ -713,7 +830,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
* @param string|int $user_id id
|
||||
* @return string|int combined id
|
||||
*/
|
||||
function combine_user($user_type,$user_id)
|
||||
static function combine_user($user_type,$user_id)
|
||||
{
|
||||
if (!$user_type || $user_type == 'u')
|
||||
{
|
||||
@ -729,7 +846,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
* @param string &$user_type 1-char type: 'u' = user, ...
|
||||
* @param string|int &$user_id id
|
||||
*/
|
||||
function split_user($uid,&$user_type,&$user_id)
|
||||
static function split_user($uid,&$user_type,&$user_id)
|
||||
{
|
||||
if (is_numeric($uid))
|
||||
{
|
||||
@ -743,23 +860,61 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine status, quantity and role into one value
|
||||
*
|
||||
* @param string $status
|
||||
* @param int $quantity=1
|
||||
* @param string $role='REQ-PARTICIPANT'
|
||||
* @return string
|
||||
*/
|
||||
static function combine_status($status,$quantity=1,$role='REQ-PARTICIPANT')
|
||||
{
|
||||
if ((int)$quantity > 1) $status .= (int)$quantity;
|
||||
//if ($role != 'REQ-PARTICIPANT') $status .= $role;
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* splits the combined status, quantity and role
|
||||
*
|
||||
* @param string &$status I: combined value, O: status letter: U, T, A, R
|
||||
* @param int &$quantity only O: quantity
|
||||
* @param string &$role only O: role
|
||||
*/
|
||||
static function split_status(&$status,&$quantity,&$role)
|
||||
{
|
||||
$quantity = 1;
|
||||
$role = 'REQ-PARTICIPANT';
|
||||
|
||||
if (strlen($status) > 1 && preg_match('/^.([0-9]*)(.*)$/',$status,$matches))
|
||||
{
|
||||
if ((int)$matches[1] > 0) $quantity = (int)$matches[1];
|
||||
if ($matches[2]) $role = $matches[2];
|
||||
$status = $status[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the participants of an event, taken into account the evtl. recurrences of the event(!)
|
||||
* this method just adds new participants or removes not longer set participants
|
||||
* this method does never overwrite existing entries (except for delete)
|
||||
*
|
||||
* @param int $cal_id
|
||||
* @param array $participants id => status pairs
|
||||
* @param int/boolean $change_since=0 false=new entry, > 0 time from which on the repetitions should be changed, default 0=all
|
||||
* @param int $recur_date=0 time of which repetitions should be updated, default 0=all
|
||||
* @return int/boolean number of updated recurrences or false on error
|
||||
* @param array $participants uid => status pairs
|
||||
* @param int|boolean $change_since=0, false=new entry, 0=all, > 0 time from which on the repetitions should be changed
|
||||
* @param boolean $add_only=false
|
||||
* false = add AND delete participants if needed (full list of participants required in $participants)
|
||||
* true = only add participants if needed, no participant will be deleted (participants to check/add required in $participants)
|
||||
* @return int|boolean number of updated recurrences or false on error
|
||||
*/
|
||||
function participants($cal_id,$participants,$change_since=0)
|
||||
function participants($cal_id,$participants,$change_since=0,$add_only=false)
|
||||
{
|
||||
//echo "<p>socal::participants($cal_id,".print_r($participants,true).",$change_since)</p>\n";
|
||||
|
||||
// remove group-invitations, they are NOT stored in the db
|
||||
foreach($participants as $uid => $status)
|
||||
{
|
||||
if ($status == 'G')
|
||||
if ($status[0] == 'G')
|
||||
{
|
||||
unset($participants[$uid]);
|
||||
}
|
||||
@ -768,27 +923,40 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
|
||||
if ((int) $change_since)
|
||||
{
|
||||
$where[] = '(cal_recur_date=0 OR cal_recur_date >= '.(int)$change_since.')';
|
||||
$where[0] = '(cal_recur_date=0 OR cal_recur_date >= '.(int)$change_since.')';
|
||||
}
|
||||
if ($change_since !== false) // existing entries only
|
||||
|
||||
if ($change_since !== false) // update existing entries
|
||||
{
|
||||
// delete not longer set participants
|
||||
$deleted = array();
|
||||
foreach($this->db->select($this->user_table,'DISTINCT cal_user_type,cal_user_id,cal_quantity',$where,
|
||||
__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
$existing_entries = $this->db->select($this->user_table,'DISTINCT cal_user_type,cal_user_id',$where,__LINE__,__FILE__,false,'','calendar');
|
||||
|
||||
// create a full list of participants which already exist in the db
|
||||
$old_participants = array();
|
||||
foreach($existing_entries as $row)
|
||||
{
|
||||
$uid = $this->combine_user($row['cal_user_type'],$row['cal_user_id']);
|
||||
if (!isset($participants[$uid])) // delete group-invitations
|
||||
$old_participants[self::combine_user($row['cal_user_type'],$row['cal_user_id'])] = true;
|
||||
}
|
||||
|
||||
// tag participants which should be deleted
|
||||
if($add_only === false)
|
||||
{
|
||||
$deleted = array();
|
||||
foreach($existing_entries as $row)
|
||||
{
|
||||
$deleted[$row['cal_user_type']][] = $row['cal_user_id'];
|
||||
}
|
||||
elseif($row['cal_quantity'] == (substr($participants[$uid],1) ? substr($participants[$uid],1) : 1))
|
||||
{
|
||||
unset($participants[$uid]); // we dont touch them
|
||||
$uid = self::combine_user($row['cal_user_type'],$row['cal_user_id']);
|
||||
// delete not longer set participants
|
||||
if (!isset($participants[$uid]))
|
||||
{
|
||||
$deleted[$row['cal_user_type']][] = $row['cal_user_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($deleted))
|
||||
// only keep added participants for further steps - we do not touch existing ones
|
||||
$participants = array_diff_key($participants,$old_participants);
|
||||
|
||||
// delete participants tagged for delete
|
||||
if ($add_only === false && count($deleted))
|
||||
{
|
||||
$to_or = array();
|
||||
$table_def = $this->db->get_table_definitions('calendar',$this->user_table);
|
||||
@ -799,14 +967,17 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
'cal_user_id' => $ids,
|
||||
));
|
||||
}
|
||||
$this->db->delete($this->user_table,$where + array('('.implode(' OR ',$to_or).')'),__LINE__,__FILE__,'calendar');
|
||||
$where[1] = '('.implode(' OR ',$to_or).')';
|
||||
$this->db->delete($this->user_table,$where,__LINE__,__FILE__,'calendar');
|
||||
unset($where[1]);
|
||||
}
|
||||
}
|
||||
if (count($participants)) // these are NEW participants now
|
||||
|
||||
if (count($participants)) // participants which need to be added
|
||||
{
|
||||
// find all recurrences, as they all need the new parts to be added
|
||||
$recurrences = array();
|
||||
if ($change_since !== false) // existing entries only
|
||||
if ($change_since !== false) // existing entries
|
||||
{
|
||||
foreach($this->db->select($this->user_table,'DISTINCT cal_recur_date',$where,__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
{
|
||||
@ -815,15 +986,20 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
if (!count($recurrences)) $recurrences[] = 0; // insert the default one
|
||||
|
||||
// update participants
|
||||
foreach($participants as $uid => $status)
|
||||
{
|
||||
$this->split_user($uid,$type,$id);
|
||||
$id = null;
|
||||
self::split_user($uid,$type,$id);
|
||||
self::split_status($status,$quantity,$role);
|
||||
$set = array(
|
||||
'cal_status' => $status,
|
||||
'cal_quantity' => $quantity,
|
||||
'cal_role' => $role,
|
||||
);
|
||||
foreach($recurrences as $recur_date)
|
||||
{
|
||||
$this->db->insert($this->user_table,array(
|
||||
'cal_status' => $status !== true ? $status{0} : 'U',
|
||||
'cal_quantity' => substr($status,1) ? substr($status,1) : 1,
|
||||
),array(
|
||||
$this->db->insert($this->user_table,$set,array(
|
||||
'cal_id' => $cal_id,
|
||||
'cal_recur_date' => $recur_date,
|
||||
'cal_user_type' => $type,
|
||||
@ -841,11 +1017,12 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
* @param int $cal_id
|
||||
* @param char $user_type 'u' regular user, 'r' resource, 'c' contact
|
||||
* @param int $user_id
|
||||
* @param int/char $status numeric status (defines) or 1-char code: 'R', 'U', 'T' or 'A'
|
||||
* @param int|char $status numeric status (defines) or 1-char code: 'R', 'U', 'T' or 'A'
|
||||
* @param int $recur_date=0 date to change, or 0 = all since now
|
||||
* @param string $role=null role to set if !is_null($role)
|
||||
* @return int number of changed recurrences
|
||||
*/
|
||||
function set_status($cal_id,$user_type,$user_id,$status,$recur_date=0)
|
||||
function set_status($cal_id,$user_type,$user_id,$status,$recur_date=0,$role=null)
|
||||
{
|
||||
static $status_code_short = array(
|
||||
REJECTED => 'R',
|
||||
@ -873,15 +1050,20 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
{
|
||||
$where[] = '(cal_recur_date=0 OR cal_recur_date >= '.time().')';
|
||||
}
|
||||
|
||||
// check if the user has any status database entries and create the default set if needed
|
||||
// a status update before having the necessary entries happens on e.g. group invitations
|
||||
$this->participants($cal_id,array(self::combine_user($user_type,$user_id) => 'U'),0,true);
|
||||
|
||||
if ($status == 'G') // remove group invitations, as we dont store them in the db
|
||||
{
|
||||
$this->db->delete($this->user_table,$where,__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->db->insert($this->user_table,array(
|
||||
'cal_status' => $status,
|
||||
),$where,__LINE__,__FILE__,'calendar');
|
||||
$set = array('cal_status' => $status);
|
||||
if (!is_null($role)) $set['cal_role'] = $role;
|
||||
$this->db->insert($this->user_table,$set,$where,__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
$ret = $this->db->affected_rows();
|
||||
//error_log(__METHOD__."($cal_id,$user_type,$user_id,$status,$recur_date) = $ret");
|
||||
@ -910,9 +1092,11 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
{
|
||||
if ($status == 'G') continue; // dont save group-invitations
|
||||
|
||||
$type = '';
|
||||
$id = null;
|
||||
$this->split_user($uid,$type,$id);
|
||||
$this->db->insert($this->user_table,array(
|
||||
'cal_status' => $status !== true ? $status{0} : 'U',
|
||||
'cal_status' => $status !== true ? $status[0] : 'U',
|
||||
'cal_quantity' => substr($status,1) ? substr($status,1) : 1,
|
||||
),array(
|
||||
'cal_id' => $cal_id,
|
||||
@ -1011,9 +1195,10 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
*
|
||||
* @param int $cal_id Id of the calendar-entry
|
||||
* @param array $alarm array with fields: text, owner, enabled, ..
|
||||
* @param timestamp $now_su=0 timestamp for modification of related event
|
||||
* @return string id of the alarm
|
||||
*/
|
||||
function save_alarm($cal_id,$alarm)
|
||||
function save_alarm($cal_id, $alarm, $now_su = 0)
|
||||
{
|
||||
//echo "<p>save_alarm(cal_id=$cal_id, alarm="; print_r($alarm); echo ")</p>\n";
|
||||
if (!($id = $alarm['id']))
|
||||
@ -1037,6 +1222,14 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
// update the modification information of the related event
|
||||
$datetime = $GLOBALS['egw']->datetime;
|
||||
$now = ($now_su ? $now_su : time() + $datetime->this->tz_offset);
|
||||
$modifier = $GLOBALS['egw_info']['user']['account_id'];
|
||||
$this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier),
|
||||
array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar');
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
@ -1061,10 +1254,21 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
* delete one alarms identified by its id
|
||||
*
|
||||
* @param string $id alarm-id is a string of 'cal:'.$cal_id.':'.$alarm_nr, it is used as the job-id too
|
||||
* @param timestamp $now_su=0 timestamp for modification of related event
|
||||
* @return int number of alarms deleted
|
||||
*/
|
||||
function delete_alarm($id)
|
||||
function delete_alarm($id, $now_su = 0)
|
||||
{
|
||||
// update the modification information of the related event
|
||||
list(,$cal_id) = explode(':',$id);
|
||||
if ($cal_id)
|
||||
{
|
||||
$datetime = $GLOBALS['egw']->datetime;
|
||||
$now = ($now_su ? $now_su : time() + $datetime->this->tz_offset);
|
||||
$modifier = $GLOBALS['egw_info']['user']['account_id'];
|
||||
$this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier),
|
||||
array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar');
|
||||
}
|
||||
return $this->async->cancel_timer($id);
|
||||
}
|
||||
|
||||
@ -1074,7 +1278,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
* @param array|int $old_user integer old user or array with keys 'account_id' and 'new_owner' as the deleteaccount hook uses it
|
||||
* @param int $new_user=null
|
||||
*/
|
||||
function deleteaccount($data)
|
||||
function deleteaccount($old_user, $newuser=null)
|
||||
{
|
||||
if (is_array($old_user))
|
||||
{
|
||||
@ -1083,6 +1287,8 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
if (!(int)$new_user)
|
||||
{
|
||||
$user_type = '';
|
||||
$user_id = null;
|
||||
$this->split_user($old_user,$user_type,$user_id);
|
||||
|
||||
if ($user_type == 'u') // only accounts can be owners of events
|
||||
@ -1131,4 +1337,133 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get stati of all recurrences of an event for a specific participant
|
||||
*
|
||||
* @param int $cal_id
|
||||
* @param int $uid participant uid
|
||||
* @return array recur_date => status pairs (index 0 => main status)
|
||||
*/
|
||||
function get_recurrences($cal_id, $uid)
|
||||
{
|
||||
$user_type = $user_id = null;
|
||||
$this->split_user($uid, $user_type, $user_id);
|
||||
$participant_status = array();
|
||||
$where = array('cal_id' => $cal_id);
|
||||
foreach($this->db->select($this->user_table,'DISTINCT cal_recur_date',$where,__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
{
|
||||
// inititalize the array
|
||||
$participant_status[$row['cal_recur_date']] = null;
|
||||
}
|
||||
$where = array(
|
||||
'cal_id' => $cal_id,
|
||||
'cal_user_type' => $user_type ? $user_type : 'u',
|
||||
'cal_user_id' => $user_id,
|
||||
);
|
||||
foreach ($this->db->select($this->user_table,'cal_recur_date,cal_status',$where,
|
||||
__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
{
|
||||
$participant_status[$row['cal_recur_date']] = $row['cal_status'];
|
||||
}
|
||||
return $participant_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all participants of an event
|
||||
*
|
||||
* @param int $cal_id
|
||||
* @param int $recur_date=0 gives participants of this recurrence, default 0=all
|
||||
*
|
||||
* @return array participants
|
||||
*/
|
||||
function get_participants($cal_id, $recur_date=0)
|
||||
{
|
||||
$participants = array();
|
||||
$where = array('cal_id' => $cal_id);
|
||||
if ($recur_date)
|
||||
{
|
||||
$where['cal_recur_date'] = $recur_date;
|
||||
}
|
||||
|
||||
foreach ($this->db->select($this->user_table,'DISTINCT cal_user_type,cal_user_id', $where,
|
||||
__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
{
|
||||
$uid = $this->combine_user($row['cal_user_type'], $row['cal_user_id']);
|
||||
$id = $row['cal_user_type'] . $row['cal_user_id'];
|
||||
$participants[$id]['type'] = $row['cal_user_type'];
|
||||
$participants[$id]['id'] = $row['cal_user_id'];
|
||||
$participants[$id]['uid'] = $uid;
|
||||
}
|
||||
return $participants;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all releated events
|
||||
*
|
||||
* @param int $uid UID of the series
|
||||
*
|
||||
* @return array of event exception ids for all events which share $uid
|
||||
*/
|
||||
function get_related($uid)
|
||||
{
|
||||
$where = array(
|
||||
'cal_uid' => $uid,
|
||||
);
|
||||
$related = array();
|
||||
foreach ($this->db->select($this->cal_table,'cal_id,cal_reference',$where,
|
||||
__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
{
|
||||
if ($row['cal_reference'])
|
||||
{
|
||||
// not the series entry itself
|
||||
$related[$row['cal_id']] = $row['cal_reference'];
|
||||
}
|
||||
}
|
||||
return $related;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exception days of a given recurring event caused by
|
||||
* irregular participant stati
|
||||
*
|
||||
* @param array $event Recurring Event.
|
||||
*
|
||||
* @return array Array of exception days (false for non-recurring events).
|
||||
*/
|
||||
function get_recurrence_exceptions(&$event)
|
||||
{
|
||||
$cal_id = (int) $event['id'];
|
||||
if (!$cal_id || $event['recur_type'] == MCAL_RECUR_NONE) return false;
|
||||
|
||||
$days = array();
|
||||
|
||||
$participants = $this->get_participants($event['id'], 0);
|
||||
|
||||
// Check if the stati for all participants are identical for all recurrences
|
||||
foreach ($participants as $uid => $attendee)
|
||||
{
|
||||
switch ($attendee['type'])
|
||||
{
|
||||
case 'u': // account
|
||||
case 'c': // contact
|
||||
case 'e': // email address
|
||||
$recurrences = $this->get_recurrences($event['id'], $uid);
|
||||
foreach ($recurrences as $recur_date => $recur_status)
|
||||
{
|
||||
if ($recur_date && $recur_status != $recurrences[0])
|
||||
{
|
||||
// Every distinct status results in an exception
|
||||
$days[] = $recur_date;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: // We don't handle the rest
|
||||
break;
|
||||
}
|
||||
}
|
||||
$days = array_unique($days);
|
||||
sort($days);
|
||||
return $days;
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ class calendar_ui
|
||||
/**
|
||||
* @var array $states_to_save all states that will be saved to the user prefs
|
||||
*/
|
||||
var $states_to_save = array('owner');
|
||||
var $states_to_save = array('owner','filter');
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -188,13 +188,13 @@ class calendar_ui
|
||||
foreach($GLOBALS['egw']->accounts->member($owner) as $member)
|
||||
{
|
||||
$member = $member['account_id'];
|
||||
if (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS,0,$member))
|
||||
if (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS|EGW_ACL_FREEBUSY,0,$member))
|
||||
{
|
||||
$no_access_group[$member] = $this->bo->participant_name($member);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS,0,$owner))
|
||||
elseif (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS|EGW_ACL_FREEBUSY,0,$owner))
|
||||
{
|
||||
$no_access[$owner] = $this->bo->participant_name($owner);
|
||||
}
|
||||
@ -247,7 +247,7 @@ class calendar_ui
|
||||
* - filter: the used filter: all or hideprivate
|
||||
* - sortby: category or user of planner
|
||||
* - view: the actual view, where dialogs should return to or which they refresh
|
||||
* @param set_states array to manualy set / change one of the states, default NULL = use $_REQUEST
|
||||
* @param array $set_states array to manualy set / change one of the states, default NULL = use $_REQUEST
|
||||
*/
|
||||
function manage_states($set_states=NULL)
|
||||
{
|
||||
@ -381,16 +381,19 @@ class calendar_ui
|
||||
// save defined states into the user-prefs
|
||||
if(!empty($states) && is_array($states))
|
||||
{
|
||||
$saved_states = array_intersect_key($states,array_flip($this->states_to_save));
|
||||
$GLOBALS['egw']->preferences->add('calendar','saved_states',serialize($saved_states));
|
||||
$GLOBALS['egw']->preferences->save_repository(false,'user',false);
|
||||
$saved_states = serialize(array_intersect_key($states,array_flip($this->states_to_save)));
|
||||
if ($saved_states != $this->cal_prefs['saved_states'])
|
||||
{
|
||||
$GLOBALS['egw']->preferences->add('calendar','saved_states',$saved_states);
|
||||
$GLOBALS['egw']->preferences->save_repository(false,'user',false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the icons displayed for a given event
|
||||
*
|
||||
* @param $event array
|
||||
* @param array $event
|
||||
* @return array of 'img' / 'title' pairs
|
||||
*/
|
||||
function event_icons($event)
|
||||
@ -509,8 +512,8 @@ class calendar_ui
|
||||
function popup($link,$target='_blank',$width=750,$height=410,$Link_confirm_abort='',$Link_confirm_text='')
|
||||
{
|
||||
//Handle Exception for Calandar
|
||||
if (($Link_confirm_abort) && ($Link_confirm_text))
|
||||
{
|
||||
if ($Link_confirm_abort && $Link_confirm_text)
|
||||
{
|
||||
$returnvalue = 'javascript:var check=confirm(\''.$Link_confirm_text.'\');';
|
||||
$returnvalue .=' if (check==true) {';
|
||||
// open confirm =0kay
|
||||
@ -524,14 +527,9 @@ class calendar_ui
|
||||
$returnvalue .= '}';
|
||||
|
||||
return $returnvalue;
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
return 'egw_openWindowCentered2('.($link == 'this.href' ? $link : "'".$link."'").','.
|
||||
($target == 'this.target' ? $target : "'".$target."'").",$width,$height,'yes')";
|
||||
|
||||
}
|
||||
return 'egw_openWindowCentered2('.($link == 'this.href' ? $link : "'".$link."'").','.
|
||||
($target == 'this.target' ? $target : "'".$target."'").",$width,$height,'yes')";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -692,10 +690,21 @@ class calendar_ui
|
||||
$this->cats->formatted_list('select','all',$this->cat_id,'True'),$baseurl ? $baseurl.'&cat_id=' : '');
|
||||
|
||||
// Filter all or hideprivate
|
||||
$file[] = $this->_select_box('Filter','filter',
|
||||
'<option value="all"'.($this->filter=='all'?' selected="selected"':'').'>'.lang('No filter').'</option>'."\n".
|
||||
'<option value="hideprivate"'.($this->filter=='hideprivate'?' selected="selected"':'').'>'.lang('Hide private infos').'</option>'."\n",
|
||||
$baseurl ? $baseurl.'&filter=' : '');
|
||||
$options = '';
|
||||
foreach(array(
|
||||
'default' => lang('Not rejected'),
|
||||
'accepted' => lang('Accepted'),
|
||||
'unknown' => lang('Invitations'),
|
||||
'tentative' => lang('Tentative'),
|
||||
'rejected' => lang('Rejected'),
|
||||
'owner' => lang('Owner too'),
|
||||
'all' => lang('All incl. rejected'),
|
||||
'hideprivate' => lang('Hide private infos'),
|
||||
) as $value => $label)
|
||||
{
|
||||
$options .= '<option value="'.$value.'"'.($this->filter == $value ? ' selected="selected"' : '').'>'.$label.'</options>'."\n";
|
||||
}
|
||||
$file[] = $this->_select_box('Filter','filter',$options,$baseurl ? $baseurl.'&filter=' : '');
|
||||
|
||||
// Calendarselection: User or Group
|
||||
if(count($this->bo->grants) > 0 && $this->accountsel->account_selection != 'none')
|
||||
|
@ -25,7 +25,7 @@
|
||||
class calendar_uiforms extends calendar_ui
|
||||
{
|
||||
var $public_functions = array(
|
||||
'freetimesearch' => True,
|
||||
'freetimesearch' => true,
|
||||
'edit' => true,
|
||||
'export' => true,
|
||||
'import' => true,
|
||||
@ -52,6 +52,15 @@ class calendar_uiforms extends calendar_ui
|
||||
*/
|
||||
var $locktime_default=1;
|
||||
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $log = false;
|
||||
var $logfile="/tmp/calendar-edit";
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
@ -63,6 +72,7 @@ class calendar_uiforms extends calendar_ui
|
||||
{
|
||||
$this->durations[$n*60] = sprintf('%d:%02d',$n/60,$n%60);
|
||||
}
|
||||
if ($this->log) $this->logfile = $GLOBALS['egw_info']['server']['temp_dir'].'/calendar-edit';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,19 +133,17 @@ class calendar_uiforms extends calendar_ui
|
||||
|
||||
if (is_numeric($uid))
|
||||
{
|
||||
$participants[$uid] = $participant_types['u'][$uid] = $uid == $this->user ? 'A' : 'U';
|
||||
$participants[$uid] = $participant_types['u'][$uid] =
|
||||
calendar_so::combine_status($uid == $this->user ? 'A' : 'U',1,$uid == $this->user ? 'CHAIR' : 'REQ-PARTICIPANT');
|
||||
}
|
||||
elseif (is_array($this->bo->resources[$uid[0]]))
|
||||
{
|
||||
$res_data = $this->bo->resources[$uid[0]];
|
||||
list($id,$quantity) = explode(':',substr($uid,1));
|
||||
$participants[$uid] = $participant_types[$uid[0]][$id] = ($res_data['new_status'] ? ExecMethod($res_data['new_status'],$id) : 'U').
|
||||
((int) $quantity > 1 ? (int)$quantity : '');
|
||||
// if new_status == 'x', resource is not bookable
|
||||
if(strpos($participant_types[$uid[0]][$id],'x') !== false)
|
||||
if (($status = $res_data['new_status'] ? ExecMethod($res_data['new_status'],$id) : 'U'))
|
||||
{
|
||||
unset($participant_types[$uid[0]][$id]);
|
||||
unset($participants[$uid]);
|
||||
$participants[$uid] = $participant_types[$uid[0]][$id] =
|
||||
calendar_so::combine_status($status,$quantity,'REQ-PARTICIPANT');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,6 +166,7 @@ class calendar_uiforms extends calendar_ui
|
||||
*/
|
||||
function process_edit($content)
|
||||
{
|
||||
if ($this->log) error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n".array2string($content)."\n",3,$this->logfile);
|
||||
$referer=$this->view_menuaction;
|
||||
list($button) = @each($content['button']);
|
||||
if (!$button && $content['action']) $button = $content['action']; // action selectbox
|
||||
@ -233,12 +242,14 @@ class calendar_uiforms extends calendar_ui
|
||||
$event['recur_data'] = 1 << (int)date('w',$event['start']);
|
||||
}
|
||||
$event['participants'] = $event['participant_types'] = array();
|
||||
|
||||
foreach($content['participants'] as $key => $data)
|
||||
{
|
||||
switch($key)
|
||||
{
|
||||
case 'delete': // handled in default
|
||||
case 'quantity': // handled in new_resource
|
||||
case 'role': // handled in add, account or resource
|
||||
case 'cal_resources':
|
||||
break;
|
||||
|
||||
@ -248,21 +259,22 @@ class calendar_uiforms extends calendar_ui
|
||||
if (($email = $_POST['exec']['participants']['resource']['query']) &&
|
||||
(preg_match('/^(.*<)?([a-z0-9_.-]+@[a-z0-9_.-]{5,})>?$/i',$email,$matches)))
|
||||
{
|
||||
$status = calendar_so::combine_status('U',$content['participants']['quantity'],$content['participants']['role']);
|
||||
// check if email belongs to account or contact --> prefer them over just emails
|
||||
if (($data = $GLOBALS['egw']->accounts->name2id($matches[2],'account_email')))
|
||||
{
|
||||
$event['participants'][$data] = $event['participant_types']['u'][$data] = 'U';
|
||||
$event['participants'][$data] = $event['participant_types']['u'][$data] = $status;
|
||||
}
|
||||
elseif ((list($data) = ExecMethod2('addressbook.addressbook_bo.search',array(
|
||||
'email' => $matches[2],
|
||||
'email_home' => $matches[2],
|
||||
),true,'','','',false,'OR')))
|
||||
{
|
||||
$event['participants']['c'.$data['id']] = $event['participant_types']['c'][$data['id']] = 'U';
|
||||
$event['participants']['c'.$data['id']] = $event['participant_types']['c'][$data['id']] = $status;
|
||||
}
|
||||
else
|
||||
{
|
||||
$event['participants']['e'.$email] = $event['participant_types']['e'][$email] = 'U';
|
||||
$event['participants']['e'.$email] = $event['participant_types']['e'][$email] = $status;
|
||||
}
|
||||
}
|
||||
elseif (!$content['participants']['account'] && !$content['participants']['resource'])
|
||||
@ -305,7 +317,7 @@ class calendar_uiforms extends calendar_ui
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($uid && $id)
|
||||
if ($uid && $id)
|
||||
{
|
||||
$status = isset($this->bo->resources[$type]['new_status']) ? ExecMethod($this->bo->resources[$type]['new_status'],$id) : 'U';
|
||||
$event['participants'][$uid] = $event['participant_types'][$type][$id] = $status.((int) $quantity > 1 ? (int)$quantity : '');
|
||||
@ -320,16 +332,20 @@ class calendar_uiforms extends calendar_ui
|
||||
case 'account':
|
||||
foreach(is_array($data) ? $data : explode(',',$data) as $uid)
|
||||
{
|
||||
if ($uid) $event['participants'][$uid] = $event['participant_types']['u'][$uid] =
|
||||
$uid == $this->bo->user ? 'A' : 'U';
|
||||
if ($uid)
|
||||
{
|
||||
$event['participants'][$uid] = $event['participant_types']['u'][$uid] =
|
||||
calendar_so::combine_status($uid == $this->bo->user ? 'A' : 'U',1,$content['participants']['role']);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: // existing participant row
|
||||
foreach(array('uid','status','status_recurrence','quantity') as $name)
|
||||
foreach(array('uid','status','status_recurrence','quantity','role') as $name)
|
||||
{
|
||||
$$name = $data[$name];
|
||||
}
|
||||
if (!$status) $status = $data['old_status']; // fix etemplate bug
|
||||
if ($content['participants']['delete'][$uid])
|
||||
{
|
||||
$uid = false; // entry has been deleted
|
||||
@ -348,10 +364,33 @@ class calendar_uiforms extends calendar_ui
|
||||
}
|
||||
if ($data['old_status'] != $status)
|
||||
{
|
||||
if ($this->bo->set_status($event['id'],$uid,$status,$event['recur_type'] != MCAL_RECUR_NONE && !$status_recurrence ? $content['participants']['status_date'] : 0))
|
||||
if ($content['edit_single'] ||
|
||||
$event['recur_type'] != MCAL_RECUR_NONE && !$status_recurrence )
|
||||
{
|
||||
$recur_date = $content['participants']['status_date'];
|
||||
}
|
||||
else $recur_date = 0;
|
||||
if ($this->bo->set_status($event['id'],$uid,$status,$recur_date))
|
||||
{
|
||||
// refreshing the calendar-view with the changed participant-status
|
||||
$msg = lang('Status changed');
|
||||
if($event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
$msg = lang('Status for all future scheduled days changed');
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($content['edit_single']))
|
||||
{
|
||||
$msg = lang('Status for this particular day changed');
|
||||
// prevent accidentally creating a real exception afterwards
|
||||
$view = true;
|
||||
$hide_delete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$msg = lang('Status changed');
|
||||
}
|
||||
}
|
||||
if (!$preserv['no_popup'])
|
||||
{
|
||||
$js = 'opener.location.href=\''.addslashes($GLOBALS['egw']->link('/index.php',array(
|
||||
@ -364,7 +403,7 @@ class calendar_uiforms extends calendar_ui
|
||||
if ($uid && $status != 'G')
|
||||
{
|
||||
$event['participants'][$uid] = $event['participant_types'][$type][$id] =
|
||||
$status.((int) $quantity > 1 ? (int)$quantity : '');
|
||||
calendar_so::combine_status($status,$quantity,$role);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -373,6 +412,7 @@ class calendar_uiforms extends calendar_ui
|
||||
}
|
||||
$preserv = array(
|
||||
'view' => $view,
|
||||
'hide_delete' => $hide_delete,
|
||||
'edit_single' => $content['edit_single'],
|
||||
'actual_date' => $content['actual_date'],
|
||||
'referer' => $referer,
|
||||
@ -408,21 +448,38 @@ class calendar_uiforms extends calendar_ui
|
||||
// fall through
|
||||
case 'mail':
|
||||
case 'save':
|
||||
//case 'print':
|
||||
case 'apply':
|
||||
if ($event['id'] && !$this->bo->check_perms(EGW_ACL_EDIT,$event))
|
||||
unset($old_event);
|
||||
if ($event['id'])
|
||||
{
|
||||
switch ($button)
|
||||
$old_event = $this->bo->read($event['id']);
|
||||
|
||||
if (!$this->bo->check_perms(EGW_ACL_EDIT, $old_event))
|
||||
{
|
||||
case 'mail': // just mail without edit-rights is ok
|
||||
if ($button == 'mail') // just mail without edit-rights is ok
|
||||
{
|
||||
$js = $this->custom_mail($event,false);
|
||||
break 2;
|
||||
case 'print': // just print without edit-rights is ok
|
||||
break;
|
||||
}
|
||||
if ($button == 'print') // just print without edit-rights is ok
|
||||
{
|
||||
$js = $this->custom_print($event,false);
|
||||
break 2;
|
||||
break;
|
||||
}
|
||||
// now we can handle a possible status update
|
||||
$uid = $this->bo->user;
|
||||
$recur_date = ($content['edit_single'] ? $content['edit_single'] : 0);
|
||||
$old_status = $this->bo->so->get_recurrences($event['id'], $uid);
|
||||
if (isset($old_status[$recur_date]) && $old_status[$recur_date] == $event['participants'][$uid]) break;
|
||||
$msg = lang('Status updated');
|
||||
$this->bo->set_status($event['id'], $uid, $event['participants'][$uid][0], $recur_date);
|
||||
$js = 'opener.location.href=\''.addslashes($GLOBALS['egw']->link('/index.php',array(
|
||||
'menuaction' => $referer,
|
||||
'msg' => $msg,
|
||||
))).'\';';
|
||||
break;
|
||||
}
|
||||
$msg = lang('Permission denied');
|
||||
$button = '';
|
||||
break;
|
||||
}
|
||||
if ($event['start'] > $event['end'])
|
||||
{
|
||||
@ -457,30 +514,99 @@ class calendar_uiforms extends calendar_ui
|
||||
}
|
||||
if ($content['edit_single']) // we edited a single event from a series
|
||||
{
|
||||
$event['reference'] = $event['id'];
|
||||
unset($event['id']);
|
||||
unset($event['uid']);
|
||||
$conflicts = $this->bo->update($event,$ignore_conflicts);
|
||||
if (!is_array($conflicts) && $conflicts)
|
||||
// let's compare with the original instance
|
||||
$old_event = $this->bo->read($event['id'], $content['edit_single']);
|
||||
$event['non_blocking'] = empty($event['non_blocking']) ? 0: $event['non_blocking'];
|
||||
$categories = $event['category'];
|
||||
$event['category'] = implode(',', $event['category']);
|
||||
$participants = $event['participants']; // save the status information
|
||||
|
||||
$unchanged = true;
|
||||
foreach (array('start','end','owner','title','description','category',
|
||||
'alarm','location','priority','public','special','non_blocking') as $key)
|
||||
{
|
||||
//error_log('edit_event test ' . $key . ': '. $old_event[$key] . ' == ' .$event[$key]);
|
||||
if ((isset($old_event[$key]) || isset($event[$key]))
|
||||
&& $old_event[$key] != $event[$key]) $unchanged = false;
|
||||
}
|
||||
// only update the stati of the exception
|
||||
if ($unchanged)
|
||||
{
|
||||
foreach ($participants as $uid => $status)
|
||||
{
|
||||
if (!isset($old_event['participants'][$uid])
|
||||
|| !$old_event['participants'][$uid]
|
||||
|| $old_event['participants'][$uid][0] != $status)
|
||||
{
|
||||
$this->bo->set_status($old_event['id'], $uid, $status, $content['edit_single']);
|
||||
$unchanged = false;
|
||||
}
|
||||
unset($old_event['participants'][$uid]);
|
||||
}
|
||||
foreach ($old_event['participants'] as $uid => $status)
|
||||
{
|
||||
// delete the removed participants
|
||||
$this->bo->set_status($old_event['id'], $uid, 'G', $content['edit_single']);
|
||||
$unchanged = false;
|
||||
}
|
||||
if (!$unchanged)
|
||||
{
|
||||
$msg = lang('Status updated');
|
||||
$js = 'opener.location.href=\''.addslashes($GLOBALS['egw']->link('/index.php',array(
|
||||
'menuaction' => $referer,
|
||||
'msg' => $msg,
|
||||
))).'\';';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// now we make a true exception
|
||||
$event['category'] = $categories;
|
||||
$event['reference'] = $content['edit_single'];
|
||||
|
||||
$id = 1;
|
||||
$alarms = array();
|
||||
foreach ($event['alarm'] as $alarm)
|
||||
{
|
||||
// get a temporary non-conflicting, numeric id
|
||||
$alarm['id'] = $id;
|
||||
$alarm['time'] = $event['start'] - $alarm['offset'];
|
||||
unset($alarm['cal_id']);
|
||||
$alarms[$id] = $alarm;
|
||||
$id++;
|
||||
}
|
||||
$event['alarm'] = $alarms;
|
||||
unset($event['id']);
|
||||
$conflicts = $this->bo->update($event, $ignore_conflicts);
|
||||
if (!is_array($conflicts) && $conflicts ||
|
||||
count($conflicts) == 1 && ($conflict = array_pop($conflicts))
|
||||
&& $conflict['id'] == $old_event['id'])
|
||||
{
|
||||
if (is_array($conflicts))
|
||||
{
|
||||
$this->bo->update($event, true);
|
||||
}
|
||||
// now we need to add the original start as recur-execption to the series
|
||||
$recur_event = $this->bo->read($event['reference']);
|
||||
$recur_event['recur_exception'][] = $content['edit_single'];
|
||||
$recur_event = $this->bo->read($old_event['id']);
|
||||
$recur_event['recur_exception'][] = $event['reference'];
|
||||
unset($recur_event['start']); unset($recur_event['end']); // no update necessary
|
||||
$this->bo->update($recur_event,true); // no conflict check here
|
||||
$this->bo->update($recur_event, true); // no conflict check here
|
||||
unset($recur_event);
|
||||
unset($event['edit_single']); // if we further edit it, it's just a single event
|
||||
unset($preserv['edit_single']);
|
||||
$conflicts = $event['id'];
|
||||
unset($old_event);
|
||||
}
|
||||
else // conflict or error, we need to reset everything to the state befor we tried to save it
|
||||
{
|
||||
$event['id'] = $event['reference'];
|
||||
$event['id'] = $old_event['id'];
|
||||
$event['uid'] = $old_event['uid'];
|
||||
unset($event['reference']);
|
||||
$event['uid'] = $content['uid'];
|
||||
}
|
||||
}
|
||||
else // we edited a non-reccuring event or the whole series
|
||||
{
|
||||
$participants = $event['participants']; // save the status information
|
||||
$conflicts = $this->bo->update($event,$ignore_conflicts);
|
||||
unset($event['ignore']);
|
||||
}
|
||||
@ -489,7 +615,7 @@ class calendar_uiforms extends calendar_ui
|
||||
$event['button_was'] = $button; // remember for ignore
|
||||
return $this->conflicts($event,$conflicts,$preserv);
|
||||
}
|
||||
elseif ($conflicts ===0)
|
||||
elseif ($conflicts === 0)
|
||||
{
|
||||
$msg .= ($msg ? ', ' : '') .lang('Error: the entry has been updated since you opened it for editing!').'<br />'.
|
||||
lang('Copy your changes to the clipboard, %1reload the entry%2 and merge them.','<a href="'.
|
||||
@ -501,8 +627,53 @@ class calendar_uiforms extends calendar_ui
|
||||
$noerror=false;
|
||||
|
||||
}
|
||||
elseif ($conflicts>0)
|
||||
elseif ($conflicts > 0)
|
||||
{
|
||||
if (isset($old_event))
|
||||
{
|
||||
if (is_array($old_event['alarm']))
|
||||
{
|
||||
// remove deleted alarms
|
||||
foreach ($old_event['alarm'] as $id => $alarm)
|
||||
{
|
||||
if (!isset($content['alarm'][$id]) ||
|
||||
$alarm != $content['alarm'][$id])
|
||||
{
|
||||
$this->bo->delete_alarm($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update the stati
|
||||
foreach ($participants as $uid => $status)
|
||||
{
|
||||
if (!isset($old_event['participants'][$uid])
|
||||
|| !$old_event['participants'][$uid]
|
||||
|| $old_event['participants'][$uid][0] != $status)
|
||||
{
|
||||
$this->bo->set_status($old_event['id'], $uid, $status, $content['edit_single']);
|
||||
}
|
||||
unset($old_event['participants'][$uid]);
|
||||
}
|
||||
foreach ($old_event['participants'] as $uid => $status)
|
||||
{
|
||||
// delete the removed participants
|
||||
$this->bo->set_status($old_event['id'], $uid, 'G', $content['edit_single']);
|
||||
}
|
||||
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
// remove deleted exception
|
||||
$recur_exceptions = $this->bo->so->get_related($event['uid']);
|
||||
|
||||
foreach ($recur_exceptions as $id => $recur_date)
|
||||
{
|
||||
if (!in_array($recur_date, $event['recur_exception']))
|
||||
{
|
||||
$this->bo->delete($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$msg .= ($msg ? ', ' : '') . lang('Event saved');
|
||||
|
||||
// writing links for new entry, existing ones are handled by the widget itself
|
||||
@ -515,6 +686,10 @@ class calendar_uiforms extends calendar_ui
|
||||
'msg' => $msg,
|
||||
))).'\';';
|
||||
|
||||
if ($button == 'print')
|
||||
{
|
||||
$js = $this->custom_print($event,!$content['id'])."\n".$js; // first open the new window and then update the view
|
||||
}
|
||||
if ($button == 'mail')
|
||||
{
|
||||
$js = $this->custom_mail($event,!$content['id'])."\n".$js; // first open the new window and then update the view
|
||||
@ -527,7 +702,7 @@ class calendar_uiforms extends calendar_ui
|
||||
break;
|
||||
|
||||
case 'cancel':
|
||||
if($content['cancel_needs_refresh'])
|
||||
if ($content['cancel_needs_refresh'])
|
||||
{
|
||||
$js = 'opener.location.href=\''.addslashes($GLOBALS['egw']->link('/index.php',array(
|
||||
'menuaction' => $referer,
|
||||
@ -539,6 +714,15 @@ class calendar_uiforms extends calendar_ui
|
||||
case 'delete':
|
||||
if ($this->bo->delete($event['id'],(int)$content['edit_single']))
|
||||
{
|
||||
if (!$content['edit_single'])
|
||||
{
|
||||
// We may delete a whole series
|
||||
$recur_exceptions = $this->bo->so->get_related($event['uid']);
|
||||
foreach ($recur_exceptions as $id => $recur_date)
|
||||
{
|
||||
$this->bo->delete($id);
|
||||
}
|
||||
}
|
||||
$msg = lang('Event deleted');
|
||||
$js = 'opener.location.href=\''.addslashes($GLOBALS['egw']->link('/index.php',array(
|
||||
'menuaction' => $referer,
|
||||
@ -607,7 +791,7 @@ class calendar_uiforms extends calendar_ui
|
||||
}
|
||||
$js .= 'window.close();';
|
||||
echo "<html><body onload=\"$js\"></body></html>\n";
|
||||
$GLOBALS['egw']->common->egw_exit();
|
||||
common::egw_exit();
|
||||
}
|
||||
return $this->edit($event,$preserv,$msg,$js,$event['id'] ? $event['id'] : $content['link_to']['to_id']);
|
||||
}
|
||||
@ -646,6 +830,8 @@ class calendar_uiforms extends calendar_ui
|
||||
|
||||
foreach($event['participants'] as $uid => $status)
|
||||
{
|
||||
$toadd = '';
|
||||
|
||||
if ($status == 'R' || $uid == $this->user) continue;
|
||||
|
||||
if (is_numeric($uid) && $GLOBALS['egw']->accounts->get_type($uid) == 'u')
|
||||
@ -654,7 +840,8 @@ class calendar_uiforms extends calendar_ui
|
||||
|
||||
$GLOBALS['egw']->accounts->get_account_name($uid,$lid,$firstname,$lastname);
|
||||
|
||||
$to[] = $firstname.' '.$lastname.' <'.$email.'>';
|
||||
$toadd = $firstname.' '.$lastname.' <'.$email.'>';
|
||||
if (!in_array($toadd,$to)) $to[] = $toadd;
|
||||
}
|
||||
elseif ($uid < 0)
|
||||
{
|
||||
@ -664,7 +851,9 @@ class calendar_uiforms extends calendar_ui
|
||||
|
||||
$GLOBALS['egw']->accounts->get_account_name($uid,$lid,$firstname,$lastname);
|
||||
|
||||
$to[] = $firstname.' '.$lastname.' <'.$email.'>';
|
||||
$toadd = $firstname.' '.$lastname.' <'.$email.'>';
|
||||
// dont add groupmembers if they already rejected the event, or are the current user
|
||||
if (!in_array($toadd,$to) && ($event['participants'][$uid] !== 'R' && $uid != $this->user)) $to[] = $toadd;
|
||||
}
|
||||
}
|
||||
elseif(($info = $this->bo->resource_info($uid)))
|
||||
@ -675,7 +864,7 @@ class calendar_uiforms extends calendar_ui
|
||||
list($subject,$body) = $this->bo->get_update_message($event,$added ? MSG_ADDED : MSG_MODIFIED); // update-message is in TZ of the user
|
||||
|
||||
$boical = new calendar_ical();
|
||||
$ics = $boical->exportVCal(array($event),'2.0','request',false);
|
||||
$ics = $boical->exportVCal(array($event),'2.0','REQUEST');
|
||||
|
||||
$ics_file = tempnam($GLOBALS['egw_info']['server']['temp_dir'],'ics');
|
||||
if(($f = fopen($ics_file,'w')))
|
||||
@ -696,6 +885,23 @@ class calendar_uiforms extends calendar_ui
|
||||
return "window.open('".$GLOBALS['egw']->link('/index.php',$vars)."','_blank','width=700,height=700,scrollbars=yes,status=no');";
|
||||
}
|
||||
|
||||
/**
|
||||
* return javascript to open compose window to print the event
|
||||
*
|
||||
* @param array $event
|
||||
* @param boolean $added
|
||||
* @return string javascript window.open command
|
||||
*/
|
||||
function custom_print($event,$added)
|
||||
{
|
||||
$vars = array(
|
||||
'menuaction' => 'calendar.calendar_uiforms.edit',
|
||||
'cal_id' => $event['id'],
|
||||
'print' => true,
|
||||
);
|
||||
return "window.open('".$GLOBALS['egw']->link('/index.php',$vars)."','_blank','width=700,height=700,scrollbars=yes,status=no');";
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a calendar event
|
||||
*
|
||||
@ -711,7 +917,8 @@ class calendar_uiforms extends calendar_ui
|
||||
*/
|
||||
function edit($event=null,$preserv=null,$msg='',$js = 'window.focus();',$link_to_id='')
|
||||
{
|
||||
$etpl =& CreateObject('etemplate.etemplate','calendar.edit');
|
||||
$template = $_REQUEST['print'] ? 'calendar.print' : 'calendar.edit';
|
||||
$etpl =& CreateObject('etemplate.etemplate',$template);
|
||||
$sel_options = array(
|
||||
'recur_type' => &$this->bo->recur_types,
|
||||
'status' => $this->bo->verbose_status,
|
||||
@ -719,6 +926,7 @@ class calendar_uiforms extends calendar_ui
|
||||
'action' => array(
|
||||
'copy' => array('label' => 'Copy', 'title' => 'Copy this event'),
|
||||
'ical' => array('label' => 'Export', 'title' => 'Download this event as iCal'),
|
||||
//'print' => array('label' => 'Print', 'title' => 'Print this event'),
|
||||
'mail' => array('label' => 'Mail all participants', 'title' => 'compose a mail to all participants after the event is saved'),
|
||||
),
|
||||
'status_recurrence' => array('' => 'for this event', 'A' => 'for all future events'),
|
||||
@ -766,9 +974,7 @@ class calendar_uiforms extends calendar_ui
|
||||
if(isset($_GET['start'])) { $event['start'] = $_GET['start']; }
|
||||
if(isset($_GET['end'])) { $event['end'] = $_GET['end']; }
|
||||
// check if the event is the whole day
|
||||
$start = $this->bo->date2array($event['start']);
|
||||
$end = $this->bo->date2array($event['end']);
|
||||
$event['whole_day'] = !$start['hour'] && !$start['minute'] && $end['hour'] == 23 && $end['minute'] == 59;
|
||||
$event['whole_day'] = $this->bo->isWholeDay($event);
|
||||
|
||||
$link_to_id = $event['id'];
|
||||
if (!$add_link && !$event['id'] && isset($_GET['link_app']) && isset($_GET['link_id']) &&
|
||||
@ -874,7 +1080,11 @@ class calendar_uiforms extends calendar_ui
|
||||
'uid' => $member,
|
||||
'status' => 'G',
|
||||
);
|
||||
// read access is enought to invite participants, but you edit rights to change status
|
||||
$readonlys[$row.'[quantity]'] = $readonlys["delete[$member]"] = true;
|
||||
$content['participants'][$row++]['title'] =
|
||||
$GLOBALS['egw']->common->grab_owner_name($member);
|
||||
// read access is enought to invite participants
|
||||
// but you edit rights to change status
|
||||
if (!$this->bo->check_perms(EGW_ACL_EDIT,0,$member))
|
||||
{
|
||||
$readonlys[$row.'[quantity]'] = $readonlys["delete[$member]"] =$readonlys[$row]['status']= true;
|
||||
@ -883,7 +1093,6 @@ class calendar_uiforms extends calendar_ui
|
||||
{
|
||||
$readonlys[$row.'[quantity]'] = $readonlys["delete[$member]"] = true;
|
||||
}
|
||||
$content['participants'][$row++]['title'] = $GLOBALS['egw']->common->grab_owner_name($member);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -970,7 +1179,18 @@ class calendar_uiforms extends calendar_ui
|
||||
// the call to set_style_by_class has to be in onload, to make sure the function and the element is already created
|
||||
$GLOBALS['egw']->js->set_onload("set_style_by_class('table','end_hide','visibility','".($content['duration'] && isset($sel_options['duration'][$content['duration']]) ? 'hidden' : 'visible')."');");
|
||||
|
||||
$readonlys['recur_exception'] = !count($content['recur_exception']); // otherwise we get a delete button
|
||||
if ($content['reference'])
|
||||
{
|
||||
// recurrence exceptions can not be recurring events
|
||||
foreach (array('recur_enddate','recur_interval','recur_exception','recur_type','recur_date','recur_data') as $name)
|
||||
{
|
||||
$readonlys[$name] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$readonlys['recur_exception'] = !count($content['recur_exception']); // otherwise we get a delete button
|
||||
}
|
||||
}
|
||||
// disabling the custom fields tab, if there are none
|
||||
$readonlys[$this->tabs] = array(
|
||||
@ -1107,7 +1327,7 @@ class calendar_uiforms extends calendar_ui
|
||||
*/
|
||||
function freetimesearch($content = null)
|
||||
{
|
||||
$etpl =& CreateObject('etemplate.etemplate','calendar.freetimesearch');
|
||||
$etpl = new etemplate('calendar.freetimesearch');
|
||||
|
||||
$sel_options['search_window'] = array(
|
||||
7*DAY_s => lang('one week'),
|
||||
@ -1412,15 +1632,17 @@ class calendar_uiforms extends calendar_ui
|
||||
/**
|
||||
* Export events as vCalendar version 2.0 files (iCal)
|
||||
*
|
||||
* @param int/array $content=0 numeric cal_id or submitted content from etempalte::exec
|
||||
* @param int|array $content=0 numeric cal_id or submitted content from etempalte::exec
|
||||
* @param boolean $return_error=false should an error-msg be returned or a regular page with it generated (default)
|
||||
* @return string error-msg if $return_error
|
||||
*/
|
||||
function export($content=0,$return_error=false)
|
||||
{
|
||||
$boical = new calendar_ical();
|
||||
#error_log(__METHOD__.print_r($content,true));
|
||||
if (is_numeric($cal_id = $content ? $content : $_REQUEST['cal_id']))
|
||||
{
|
||||
if (!($ical =& ExecMethod2('calendar.calendar_ical.exportVCal',$cal_id,'2.0','PUBLISH',false)))
|
||||
if (!($ical =& $boical->exportVCal(array($cal_id),'2.0','PUBLISH')))
|
||||
{
|
||||
$msg = lang('Permission denied');
|
||||
|
||||
@ -1428,9 +1650,9 @@ class calendar_uiforms extends calendar_ui
|
||||
}
|
||||
else
|
||||
{
|
||||
$GLOBALS['egw']->browser->content_header('event.ics','text/calendar',bytes($ical));
|
||||
html::content_header('event.ics','text/calendar',bytes($ical));
|
||||
echo $ical;
|
||||
$GLOBALS['egw']->common->egw_exit();
|
||||
common::egw_exit();
|
||||
}
|
||||
}
|
||||
if (is_array($content))
|
||||
@ -1449,10 +1671,10 @@ class calendar_uiforms extends calendar_ui
|
||||
}
|
||||
else
|
||||
{
|
||||
$ical =& ExecMethod2('calendar.calendar_ical.exportVCal',$events,'2.0'/*$content['version']*/,'PUBLISH',false);
|
||||
$GLOBALS['egw']->browser->content_header($content['file'] ? $content['file'] : 'event.ics','text/calendar',bytes($ical));
|
||||
$ical =& $boical->exportVCal($events,'2.0','PUBLISH');
|
||||
html::content_header($content['file'] ? $content['file'] : 'event.ics','text/calendar',bytes($ical));
|
||||
echo $ical;
|
||||
$GLOBALS['egw']->common->egw_exit();
|
||||
common::egw_exit();
|
||||
}
|
||||
}
|
||||
if (!is_array($content))
|
||||
@ -1469,7 +1691,7 @@ class calendar_uiforms extends calendar_ui
|
||||
$content['msg'] = $msg;
|
||||
|
||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('calendar') . ' - ' . lang('iCal Export');
|
||||
$etpl =& CreateObject('etemplate.etemplate','calendar.export');
|
||||
$etpl = new etemplate('calendar.export');
|
||||
|
||||
$etpl->exec('calendar.calendar_uiforms.export',$content);
|
||||
}
|
||||
@ -1503,8 +1725,8 @@ class calendar_uiforms extends calendar_ui
|
||||
'msg' => $msg,
|
||||
);
|
||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('calendar') . ' - ' . lang('iCal Import');
|
||||
$etpl =& CreateObject('etemplate.etemplate','calendar.import');
|
||||
$etpl = new etemplate('calendar.import');
|
||||
|
||||
$etpl->exec('calendar.calendar_uiforms.import',$content);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005-8 by RalfBecker-At-outdoor-training.de
|
||||
* @copyright (c) 2005-9 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -82,7 +82,7 @@ class calendar_uilist extends calendar_ui
|
||||
'multiple' => 0,
|
||||
'view' => $this->bo->cal_prefs['defaultcalendar'],
|
||||
));
|
||||
$GLOBALS['egw']->session->appsession('calendar_list','calendar',''); // in case there's already something set
|
||||
egw_session::appsession('calendar_list','calendar',''); // in case there's already something set
|
||||
|
||||
return $this->listview(null,'',true);
|
||||
}
|
||||
@ -95,7 +95,7 @@ class calendar_uilist extends calendar_ui
|
||||
if ($_GET['msg']) $msg .= $_GET['msg'];
|
||||
if ($this->group_warning) $msg .= $this->group_warning;
|
||||
|
||||
$etpl =& CreateObject('etemplate.etemplate','calendar.list');
|
||||
$etpl = new etemplate('calendar.list');
|
||||
|
||||
if (is_array($content) && $content['nm']['rows']['delete'])
|
||||
{
|
||||
@ -120,7 +120,7 @@ class calendar_uilist extends calendar_ui
|
||||
}
|
||||
}
|
||||
$content = array(
|
||||
'nm' => $GLOBALS['egw']->session->appsession('calendar_list','calendar'),
|
||||
'nm' => egw_session::appsession('calendar_list','calendar'),
|
||||
'msg' => $msg,
|
||||
);
|
||||
if (!is_array($content['nm']))
|
||||
@ -201,7 +201,7 @@ class calendar_uilist extends calendar_ui
|
||||
$this->manage_states(array('date' => $this->bo->date2string($params['startdate'])));
|
||||
}
|
||||
}
|
||||
$old_params = $GLOBALS['egw']->session->appsession('calendar_list','calendar');
|
||||
$old_params = egw_session::appsession('calendar_list','calendar');
|
||||
if ($old_params['filter'] && $old_params['filter'] != $params['filter']) // filter changed => order accordingly
|
||||
{
|
||||
$params['order'] = 'cal_start';
|
||||
@ -211,8 +211,18 @@ class calendar_uilist extends calendar_ui
|
||||
{
|
||||
$this->adjust_for_search($params['search'],$params);
|
||||
}
|
||||
$GLOBALS['egw']->session->appsession('calendar_list','calendar',$params);
|
||||
if (!$params['csv_export']) egw_session::appsession('calendar_list','calendar',$params);
|
||||
|
||||
// do we need to query custom fields and which
|
||||
$select_cols = explode(',',$params['selectcols']);
|
||||
if (in_array('cfs',$select_cols))
|
||||
{
|
||||
$cfs = array();
|
||||
foreach($select_cols as $col)
|
||||
{
|
||||
if ($col[0] == '#') $cfs[] = substr($col,1);
|
||||
}
|
||||
}
|
||||
$search_params = array(
|
||||
'cat_id' => $this->cat_id,
|
||||
'filter' => $this->filter,
|
||||
@ -220,6 +230,7 @@ class calendar_uilist extends calendar_ui
|
||||
'offset' => (int) $params['start'],
|
||||
'num_rows'=> $params['num_rows'],
|
||||
'order' => $params['order'] ? $params['order'].' '.$params['sort'] : 'cal_start',
|
||||
'cfs' => $params['csv_explort'] ? array() : $cfs,
|
||||
);
|
||||
switch($params['filter'])
|
||||
{
|
||||
@ -289,11 +300,19 @@ class calendar_uilist extends calendar_ui
|
||||
$readonlys['view['.$event['id'].']'] = !($readonlys['edit['.$event['id'].']'] = !$this->bo->check_perms(EGW_ACL_EDIT,$event));
|
||||
$readonlys['delete['.$event['id'].']'] = !$this->bo->check_perms(EGW_ACL_DELETE,$event);
|
||||
|
||||
$event['parts'] = implode(",\n",$this->bo->participants($event,true));
|
||||
$event['recure'] = $this->bo->recure2string($event);
|
||||
$event['date'] = $this->bo->date2string($event['start']);
|
||||
if ($params['csv_export'])
|
||||
{
|
||||
$event['participants'] = implode(",\n",$this->bo->participants($event,true));
|
||||
}
|
||||
else
|
||||
{
|
||||
$event['parts'] = implode(",\n",$this->bo->participants($event,true));
|
||||
$event['date'] = $this->bo->date2string($event['start']);
|
||||
}
|
||||
if (empty($event['description'])) $event['description'] = ' '; // no description screws the titles horz. alignment
|
||||
if (empty($event['location'])) $event['location'] = ' '; // no location screws the owner horz. alignment
|
||||
|
||||
$rows[] = $event;
|
||||
}
|
||||
$wv=0;
|
||||
@ -310,7 +329,7 @@ class calendar_uilist extends calendar_ui
|
||||
$rows['format'] = '16';
|
||||
$dv=1;
|
||||
}
|
||||
if ($wv&&$dv)
|
||||
if ($wv && $dv)
|
||||
{
|
||||
$rows['format'] = '64';
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2004-8 by RalfBecker-At-outdoor-training.de
|
||||
* @copyright (c) 2004-9 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -115,6 +115,12 @@ class calendar_uiviews extends calendar_ui
|
||||
*/
|
||||
var $wholeDayPosCounter=1;
|
||||
|
||||
/**
|
||||
* Switch to disable private data and possibility to view and edit events
|
||||
* in case of a public view (sitemgr)
|
||||
*/
|
||||
var $allowEdit = true;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -155,7 +161,7 @@ class calendar_uiviews extends calendar_ui
|
||||
$this->dragdrop = new dragdrop();
|
||||
// if the object would auto-disable itself unset object
|
||||
// to avoid unneccesary dragdrop calls later
|
||||
if(!$this->dragdrop->validateBrowser()) { $this->dragdrop = false; }
|
||||
if(!$this->dragdrop->validateBrowser()) $this->dragdrop = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,7 +350,10 @@ class calendar_uiviews extends calendar_ui
|
||||
'date' => $this->bo->date2string($week_start),
|
||||
);
|
||||
$title = lang('Wk').' '.adodb_date('W',$week_start);
|
||||
$title = html::a_href($title,$week_view,'',' title="'.lang('Weekview').'"');
|
||||
if ($this->allowEdit)
|
||||
{
|
||||
$title = html::a_href($title,$week_view,'',' title="'.lang('Weekview').'"');
|
||||
}
|
||||
|
||||
$content .= $this->timeGridWidget($this->tagWholeDayOnTop($week),$weeks == 2 ? 30 : 60,200,'',$title,0,$week_start+WEEK_s >= $this->last);
|
||||
}
|
||||
@ -452,19 +461,19 @@ class calendar_uiviews extends calendar_ui
|
||||
|
||||
# temporarly disabled, because it collides with the title for the website
|
||||
#
|
||||
# // add navigation for previous and next
|
||||
# // prev. week
|
||||
# $GLOBALS['egw_info']['flags']['app_header'] = html::a_href(html::image('phpgwpai','first',lang('previous'),$options=' alt="<<"'),array(
|
||||
# 'menuaction' => $this->view_menuaction,
|
||||
# 'date' => date('Ymd',$this->first-$days*DAY_s),
|
||||
# )) . ' <b>'.$GLOBALS['egw_info']['flags']['app_header'];
|
||||
# // next week
|
||||
# $GLOBALS['egw_info']['flags']['app_header'] .= '</b> '.html::a_href(html::image('phpgwpai','last',lang('next'),$options=' alt=">>"'),array(
|
||||
# 'menuaction' => $this->view_menuaction,
|
||||
# 'date' => date('Ymd',$this->last+$days*DAY_s),
|
||||
# ));
|
||||
#
|
||||
# $class = $class == 'row_on' ? 'th' : 'row_on';
|
||||
# // add navigation for previous and next
|
||||
# // prev. week
|
||||
# $GLOBALS['egw_info']['flags']['app_header'] = html::a_href(html::image('phpgwapi','first',lang('previous'),$options=' alt="<<"'),array(
|
||||
# 'menuaction' => $this->view_menuaction,
|
||||
# 'date' => date('Ymd',$this->first-$days*DAY_s),
|
||||
# )) . ' <b>'.$GLOBALS['egw_info']['flags']['app_header'];
|
||||
# // next week
|
||||
# $GLOBALS['egw_info']['flags']['app_header'] .= '</b> '.html::a_href(html::image('phpgwapi','last',lang('next'),$options=' alt=">>"'),array(
|
||||
# 'menuaction' => $this->view_menuaction,
|
||||
# 'date' => date('Ymd',$this->last+$days*DAY_s),
|
||||
# ));
|
||||
#
|
||||
# $class = $class == 'row_on' ? 'th' : 'row_on';
|
||||
//echo "<p>weekdaystarts='".$this->cal_prefs['weekdaystarts']."', get_weekday_start($this->year,$this->month,$this->day)=".date('l Y-m-d',$wd_start).", first=".date('l Y-m-d',$this->first)."</p>\n";
|
||||
|
||||
$search_params = array(
|
||||
@ -933,16 +942,33 @@ class calendar_uiviews extends calendar_ui
|
||||
|
||||
if ($short_title === true)
|
||||
{
|
||||
$title = html::a_href($title,$day_view,'',
|
||||
!isset($this->holidays[$day_ymd])?' title="'.lang('Dayview').'"':'');
|
||||
if ($this->allowEdit)
|
||||
{
|
||||
$title = html::a_href($title,$day_view,'',
|
||||
!isset($this->holidays[$day_ymd])?' title="'.lang('Dayview').'"':'');
|
||||
}
|
||||
}
|
||||
elseif ($short_title === false)
|
||||
{
|
||||
// add arrows to go to the previous and next day (dayview only)
|
||||
$day_view['date'] = $this->bo->date2string($ts -= 12*HOUR_s);
|
||||
$title = html::a_href(html::image('phpgwapi','left',$this->bo->long_date($ts)),$day_view).' '.$title;
|
||||
if ($this->allowEdit)
|
||||
{
|
||||
$title = html::a_href(html::image('phpgwapi','left',$this->bo->long_date($ts)),$day_view).' '.$title;
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = $day_view.' '.$title;
|
||||
}
|
||||
$day_view['date'] = $this->bo->date2string($ts += 48*HOUR_s);
|
||||
$title .= ' '.html::a_href(html::image('phpgwapi','right',$this->bo->long_date($ts)),$day_view);
|
||||
if ($this->allowEdit)
|
||||
{
|
||||
$title .= ' '.html::a_href(html::image('phpgwapi','right',$this->bo->long_date($ts)),$day_view);
|
||||
}
|
||||
else
|
||||
{
|
||||
$title .= ' '.$day_view;
|
||||
}
|
||||
}
|
||||
$html .= $indent."\t".'<div style="height: '. $this->rowHeight .'%;" class="calDayColHeader '.$class.'"'.($holidays ? ' title="'.$holidays.'"':'').'>'.
|
||||
$title."</div>\n";
|
||||
@ -978,8 +1004,12 @@ class calendar_uiviews extends calendar_ui
|
||||
$droppableID='drop_'.$droppableDateTime.'_O'.$owner;
|
||||
|
||||
$html .= $indent."\t".'<div id="' . $droppableID . '" style="height:'. $this->rowHeight .'%; top: '. $i*$this->rowHeight .
|
||||
'%;" class="calAddEvent" onclick="'.$this->popup($GLOBALS['egw']->link('/index.php',$linkData)).';return false;"></div>'."\n";
|
||||
|
||||
'%;" class="calAddEvent"';
|
||||
if ($this->allowEdit)
|
||||
{
|
||||
$html .= ' onclick="'.$this->popup($GLOBALS['egw']->link('/index.php',$linkData)).';return false;"';
|
||||
}
|
||||
$html .= '></div>'."\n";
|
||||
if(is_object($this->dragdrop) && $dropPermission)
|
||||
{
|
||||
$this->dragdrop->addDroppable(
|
||||
@ -1098,7 +1128,7 @@ class calendar_uiviews extends calendar_ui
|
||||
{
|
||||
if ($this->debug > 1 || $this->debug==='eventWidget') $this->bo->debug_message('uiviews::eventWidget(%1,width=%2)',False,$event,$width);
|
||||
|
||||
if($this->use_time_grid && $event['whole_day_on_top']) { $block='event_widget_wholeday_on_top'; }
|
||||
if($this->use_time_grid && $event['whole_day_on_top']) $block = 'event_widget_wholeday_on_top';
|
||||
|
||||
static $tpl = False;
|
||||
if (!$tpl)
|
||||
@ -1147,21 +1177,24 @@ class calendar_uiviews extends calendar_ui
|
||||
|
||||
// seperate each participant types
|
||||
$part_array = array();
|
||||
foreach($this->bo->participants($event) as $part_key => $participant)
|
||||
{
|
||||
if(is_numeric($part_key))
|
||||
{
|
||||
$part_array[lang('Participants')][$part_key] = $participant;
|
||||
}
|
||||
elseif(isset($this->bo->resources[$part_key{0}]))
|
||||
{
|
||||
$part_array[((isset($this->bo->resources[$part_key{0}]['participants_header'])) ? $this->bo->resources[$part_key{0}]['participants_header'] : lang($this->bo->resources[$part_key{0}]['app']))][$part_key] = $participant;
|
||||
}
|
||||
}
|
||||
foreach($part_array as $part_group => $participant)
|
||||
{
|
||||
$participants .= $this->add_nonempty($participant,$part_group,True,False);
|
||||
}
|
||||
if ($this->allowEdit)
|
||||
{
|
||||
foreach($this->bo->participants($event) as $part_key => $participant)
|
||||
{
|
||||
if(is_numeric($part_key))
|
||||
{
|
||||
$part_array[lang('Participants')][$part_key] = $participant;
|
||||
}
|
||||
elseif(isset($this->bo->resources[$part_key[0]]))
|
||||
{
|
||||
$part_array[((isset($this->bo->resources[$part_key[0]]['participants_header'])) ? $this->bo->resources[$part_key[0]]['participants_header'] : lang($this->bo->resources[$part_key[0]]['app']))][$part_key] = $participant;
|
||||
}
|
||||
}
|
||||
foreach($part_array as $part_group => $participant)
|
||||
{
|
||||
$participants .= $this->add_nonempty($participant,$part_group,True,False);
|
||||
}
|
||||
}
|
||||
// as we only deal with percentual widht, we consider only the full dayview (1 colum) as NOT small
|
||||
$small = $this->view != 'day' || $width < 50;
|
||||
// $small = $width <= $small_trigger_width
|
||||
@ -1231,12 +1264,11 @@ class calendar_uiviews extends calendar_ui
|
||||
{
|
||||
$view_link_confirm_abort = $GLOBALS['egw']->link('/index.php',array('menuaction'=>'calendar.calendar_uiforms.edit','cal_id'=>$event['id'],'date'=>$this->bo->date2string($event['start']),'exception'=>1));
|
||||
$view_link_confirm_text=lang('do you want to edit serialevent als exception? - Ok = Edit Exception, Abort = Edit Serial');
|
||||
$popup = $is_private ? '' : ' onclick="'.$this->popup($view_link_confirm_abort,null,750,410,$view_link,$view_link_confirm_text).'; return false;"';
|
||||
|
||||
$popup = ($is_private || ! $this->allowEdit) ? '' : ' onclick="'.$this->popup($view_link_confirm_abort,null,750,410,$view_link,$view_link_confirm_text).'; return false;"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$popup = $is_private ? '' : ' onclick="'.$this->popup($view_link).'; return false;"';
|
||||
$popup = ($is_private || ! $this->allowEdit) ? '' : ' onclick="'.$this->popup($view_link).'; return false;"';
|
||||
}
|
||||
//_debug_array($event);
|
||||
//echo $event['id']."?<br>";
|
||||
@ -1602,11 +1634,11 @@ class calendar_uiviews extends calendar_ui
|
||||
if ($this->day >= 15) $prev = $t_arr; // we stay in the same month
|
||||
$prev['day'] = $this->day < 15 ? 15 : 1;
|
||||
$half = $this->bo->date2string($prev);
|
||||
$title = html::a_href(html::image('phpgwpai','first',lang('back one month'),$options=' alt="<<"'),array(
|
||||
$title = html::a_href(html::image('phpgwapi','first',lang('back one month'),$options=' alt="<<"'),array(
|
||||
'menuaction' => $this->view_menuaction,
|
||||
'date' => $full,
|
||||
)) . ' '.
|
||||
html::a_href(html::image('phpgwpai','left',lang('back half a month'),$options=' alt="<"'),array(
|
||||
html::a_href(html::image('phpgwapi','left',lang('back half a month'),$options=' alt="<"'),array(
|
||||
'menuaction' => $this->view_menuaction,
|
||||
'date' => $half,
|
||||
)) . ' '.$title;
|
||||
@ -1628,11 +1660,11 @@ class calendar_uiviews extends calendar_ui
|
||||
if ($this->day < 15) $next = $t_arr; // we stay in the same month
|
||||
$next['day'] = $this->day < 15 ? 15 : 1;
|
||||
$half = $this->bo->date2string($next);
|
||||
$title .= ' '.html::a_href(html::image('phpgwpai','right',lang('forward half a month'),$options=' alt=">>"'),array(
|
||||
$title .= ' '.html::a_href(html::image('phpgwapi','right',lang('forward half a month'),$options=' alt=">>"'),array(
|
||||
'menuaction' => $this->view_menuaction,
|
||||
'date' => $half,
|
||||
)). ' '.
|
||||
html::a_href(html::image('phpgwpai','last',lang('forward one month'),$options=' alt=">>"'),array(
|
||||
html::a_href(html::image('phpgwapi','last',lang('forward one month'),$options=' alt=">>"'),array(
|
||||
'menuaction' => $this->view_menuaction,
|
||||
'date' => $full,
|
||||
));
|
||||
@ -1678,12 +1710,12 @@ class calendar_uiviews extends calendar_ui
|
||||
else
|
||||
{
|
||||
// prev. week
|
||||
$title = html::a_href(html::image('phpgwpai','first',lang('previous'),$options=' alt="<<"'),array(
|
||||
$title = html::a_href(html::image('phpgwapi','first',lang('previous'),$options=' alt="<<"'),array(
|
||||
'menuaction' => $this->view_menuaction,
|
||||
'date' => date('Ymd',$t-7*DAY_s),
|
||||
)) . ' <b>'.$title;
|
||||
// next week
|
||||
$title .= '</b> '.html::a_href(html::image('phpgwpai','last',lang('next'),$options=' alt=">>"'),array(
|
||||
$title .= '</b> '.html::a_href(html::image('phpgwapi','last',lang('next'),$options=' alt=">>"'),array(
|
||||
'menuaction' => $this->view_menuaction,
|
||||
'date' => date('Ymd',$t+7*DAY_s),
|
||||
));
|
||||
@ -1737,14 +1769,14 @@ class calendar_uiviews extends calendar_ui
|
||||
{
|
||||
if (!$i) // prev. day only for the first day
|
||||
{
|
||||
$title = html::a_href(html::image('phpgwpai','first',lang('previous'),$options=' alt="<<"'),array(
|
||||
$title = html::a_href(html::image('phpgwapi','first',lang('previous'),$options=' alt="<<"'),array(
|
||||
'menuaction' => $this->view_menuaction,
|
||||
'date' => date('Ymd',$start-DAY_s),
|
||||
)) . ' '.$title;
|
||||
}
|
||||
if ($i == $days-1) // next day only for the last day
|
||||
{
|
||||
$title .= ' '.html::a_href(html::image('phpgwpai','last',lang('next'),$options=' alt=">>"'),array(
|
||||
$title .= ' '.html::a_href(html::image('phpgwapi','last',lang('next'),$options=' alt=">>"'),array(
|
||||
'menuaction' => $this->view_menuaction,
|
||||
'date' => date('Ymd',$start+DAY_s),
|
||||
));
|
||||
|
@ -265,7 +265,7 @@
|
||||
"group" => "Group public"
|
||||
);
|
||||
|
||||
if (ereg(",", $selected))
|
||||
if (strpos($selected,",") !== false)
|
||||
{
|
||||
$selected = "group";
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ class soholiday
|
||||
echo 'HOLIDAY_TOTAL : '.$where.'<br>'."\n";
|
||||
}
|
||||
|
||||
$retval = $this->db->select($this->table,'count(*)',$where,__LINE__,__FILE__,false,'','calendar')->fetchSingle();
|
||||
$retval = $this->db->select($this->table,'count(*)',$where,__LINE__,__FILE__,false,'','calendar')->fetchColumn();
|
||||
|
||||
if($this->debug)
|
||||
{
|
||||
|
@ -45,14 +45,14 @@
|
||||
$this->bo =& CreateObject('calendar.boholiday');
|
||||
$this->bo->check_admin();
|
||||
$this->base_url = $this->bo->base_url;
|
||||
$this->template_dir = $GLOBALS['egw']->common->get_tpl_dir('calendar');
|
||||
$this->template_dir = common::get_tpl_dir('calendar');
|
||||
$this->sb =& CreateObject('calendar.sbox');
|
||||
|
||||
// calendar does not work with hidden sidebox atm.
|
||||
unset($GLOBALS['egw_info']['user']['preferences']['common']['auto_hide_sidebox']);
|
||||
|
||||
$GLOBALS['egw_info']['flags']['app_header'] = $GLOBALS['egw_info']['apps']['calendar']['title'].' - '.lang('Holiday Management');
|
||||
|
||||
|
||||
$GLOBALS['egw']->template->set_var('help_msg',lang('<b>Please note</b>: The calendar use the holidays of your country, which is set to %1. You can change it in your %2.<br />Holidays are %3 automatic installed from %4. You can changed it in %5.',
|
||||
'<b>'.$GLOBALS['egw_info']['user']['preferences']['common']['country'].'</b>','<a href="'.$GLOBALS['egw']->link('/index.php',array(
|
||||
'menuaction' => 'preferences.uisettings.index',
|
||||
@ -71,7 +71,7 @@
|
||||
unset($GLOBALS['egw_info']['flags']['noheader']);
|
||||
unset($GLOBALS['egw_info']['flags']['nonavbar']);
|
||||
$GLOBALS['egw_info']['flags']['noappfooter'] = True;
|
||||
$GLOBALS['egw']->common->egw_header();
|
||||
common::egw_header();
|
||||
|
||||
$p = &$GLOBALS['egw']->template;
|
||||
$p->set_file(Array('locales'=>'locales.tpl'));
|
||||
@ -157,7 +157,7 @@
|
||||
unset($GLOBALS['egw_info']['flags']['noheader']);
|
||||
unset($GLOBALS['egw_info']['flags']['nonavbar']);
|
||||
$GLOBALS['egw_info']['flags']['noappfooter'] = True;
|
||||
$GLOBALS['egw']->common->egw_header();
|
||||
common::egw_header();
|
||||
$p =& $GLOBALS['egw']->template;
|
||||
$p->set_file(Array('locale'=>'locales.tpl'));
|
||||
$p->set_block('locale','list','list');
|
||||
@ -210,7 +210,7 @@
|
||||
{
|
||||
$holidays[$i]['name'] = ' ';
|
||||
}
|
||||
|
||||
|
||||
$var = Array(
|
||||
'tr_color' => $tr_color,
|
||||
'header_delete'=> lang('Delete'),
|
||||
@ -268,7 +268,7 @@
|
||||
unset($GLOBALS['egw_info']['flags']['nonavbar']);
|
||||
$GLOBALS['egw_info']['flags']['noappfooter'] = True;
|
||||
$GLOBALS['egw_info']['flags']['app_header'] = $GLOBALS['egw_info']['apps']['calendar']['title'].' - '.($this->bo->id ? lang('Edit') : lang('Add')).' '.lang('Holiday');
|
||||
$GLOBALS['egw']->common->egw_header();
|
||||
common::egw_header();
|
||||
|
||||
$t = &$GLOBALS['egw']->template;
|
||||
$t->set_file(Array('holiday'=>'holiday.tpl','form_button'=>'form_button_script.tpl'));
|
||||
@ -277,13 +277,13 @@
|
||||
|
||||
if (@count($error))
|
||||
{
|
||||
$message = $GLOBALS['egw']->common->error_list($error);
|
||||
$message = common::error_list($error);
|
||||
}
|
||||
else
|
||||
{
|
||||
$message = '';
|
||||
}
|
||||
|
||||
|
||||
$var = Array(
|
||||
'title_holiday' => ($this->bo->id ? lang('Edit') : lang('Add')).' '.lang('Holiday'),
|
||||
'message' => $message,
|
||||
@ -300,7 +300,7 @@
|
||||
$this->display_item($t,lang('title'),'<input name="holiday[name]" size="60" maxlength="50" value="'.$holiday['name'].'">');
|
||||
|
||||
// Date
|
||||
$this->display_item($t,lang('Date'),$GLOBALS['egw']->common->dateformatorder($this->sb->getYears('holiday[year]',$holiday['occurence']>1900?$holiday['occurence']:0),$this->sb->getMonthText('holiday[month_num]',$holiday['month']),$this->sb->getDays('holiday[mday]',$holiday['day'])).
|
||||
$this->display_item($t,lang('Date'),common::dateformatorder($this->sb->getYears('holiday[year]',$holiday['occurence']>1900?$holiday['occurence']:0),$this->sb->getMonthText('holiday[month_num]',$holiday['month']),$this->sb->getDays('holiday[mday]',$holiday['day'])).
|
||||
' '.lang('Set a Year only for one-time / non-regular holidays.'));
|
||||
|
||||
// Occurence
|
||||
@ -357,7 +357,7 @@
|
||||
'menuaction' => 'calendar.uiholiday.admin'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$t->set_var(Array(
|
||||
'action_url_button' => $GLOBALS['egw']->link($this->base_url,$link_params),
|
||||
'action_text_button' => lang('Cancel'),
|
||||
@ -365,7 +365,7 @@
|
||||
'action_extra_field' => ''
|
||||
));
|
||||
$t->parse('cancel_button','form_button');
|
||||
|
||||
|
||||
if ($this->bo->id)
|
||||
{
|
||||
$link_params = Array(
|
||||
@ -396,7 +396,7 @@
|
||||
|
||||
$p =& CreateObject('phpgwapi.Template',$this->template_dir);
|
||||
$p->set_file(Array('form'=>'delete_common.tpl','form_button'=>'form_button_script.tpl'));
|
||||
|
||||
|
||||
$p->set_var('messages',lang('Are you sure you want to delete this Country ?')."<br>".$this->bo->locales[0]);
|
||||
|
||||
$var = Array(
|
||||
@ -428,15 +428,15 @@
|
||||
{
|
||||
return $this->edit_locale();
|
||||
}
|
||||
|
||||
|
||||
unset($GLOBALS['egw_info']['flags']['noheader']);
|
||||
unset($GLOBALS['egw_info']['flags']['nonavbar']);
|
||||
$GLOBALS['egw_info']['flags']['noappfooter'] = True;
|
||||
$GLOBALS['egw']->common->egw_header();
|
||||
common::egw_header();
|
||||
|
||||
$p =& CreateObject('phpgwapi.Template',$this->template_dir);
|
||||
$p->set_file(Array('form'=>'delete_common.tpl','form_button'=>'form_button_script.tpl'));
|
||||
|
||||
|
||||
$p->set_var('messages',lang('Are you sure you want to delete this holiday ?')."<br>".$holiday['name'].' ('.$this->bo->locales[0].') '.$this->bo->rule_string($holiday));
|
||||
|
||||
$var = Array(
|
||||
@ -468,7 +468,7 @@
|
||||
}
|
||||
$this->bo->year = 0; // for a complete list with all years
|
||||
$holidays = $this->bo->get_holiday_list();
|
||||
|
||||
|
||||
if (!is_array($holidays) || !count($holidays))
|
||||
{
|
||||
$this->admin();
|
||||
@ -479,11 +479,9 @@
|
||||
if (isset($_GET['download']))
|
||||
{
|
||||
$locale = $this->bo->locales[0];
|
||||
$browser =& CreateObject('phpgwapi.browser');
|
||||
$browser->content_header("holidays.$locale.csv",'text/text');
|
||||
unset($browser);
|
||||
html::content_header("holidays.$locale.csv",'text/text');
|
||||
|
||||
echo "charset\t".$GLOBALS['egw']->translation->charset()."\n";
|
||||
echo "charset\t".translation::charset()."\n";
|
||||
$last_year = -1;
|
||||
foreach($holidays as $holiday)
|
||||
{
|
||||
@ -495,7 +493,7 @@
|
||||
}
|
||||
echo "$locale\t$holiday[name]\t$holiday[day]\t$holiday[month]\t$holiday[occurence]\t$holiday[dow]\t$holiday[observance_rule]\n";
|
||||
}
|
||||
$GLOBALS['egw']->common->egw_exit();
|
||||
common::egw_exit();
|
||||
}
|
||||
if($this->debug)
|
||||
{
|
||||
@ -508,13 +506,13 @@
|
||||
$GLOBALS['egw_info']['flags']['noappheader'] = True;
|
||||
$GLOBALS['egw_info']['flags']['noappfooter'] = True;
|
||||
$GLOBALS['egw_info']['flags']['nofooter'] = True;
|
||||
$GLOBALS['egw']->common->egw_header();
|
||||
common::egw_header();
|
||||
|
||||
echo '<body onLoad="document.submitform.submit()">'."\n";
|
||||
echo '<form action="'.$action.'" method="post" name="submitform">'."\n";
|
||||
|
||||
echo '<input type="hidden" name="locale" value="'.$this->bo->locales[0].'">'."\n";
|
||||
echo '<input type="hidden" name="charset" value="'.$GLOBALS['egw']->translation->charset().'">'."\n";
|
||||
echo '<input type="hidden" name="charset" value="'.translation::charset().'">'."\n";
|
||||
foreach($holidays as $holiday)
|
||||
{
|
||||
echo '<input type="hidden" name="name[]" value="'.htmlspecialchars($holiday['name']).'">'."\n"
|
||||
|
@ -1,31 +1,17 @@
|
||||
<?php
|
||||
/**************************************************************************\
|
||||
* eGroupWare - calendar: rounded corners *
|
||||
* http://www.egroupware.org *
|
||||
* Written by RalfBecker@outdoor-training.de *
|
||||
* -------------------------------------------- *
|
||||
* This program is free software; you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU General Public License as published by the *
|
||||
* Free Software Foundation; either version 2 of the License, or (at your *
|
||||
* option) any later version. *
|
||||
\**************************************************************************/
|
||||
/**
|
||||
* eGroupWare Calendar: rounded corners
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package calendar
|
||||
* @copyright (c) 2004-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
// some constanst for pre php4.3
|
||||
if (!defined('PHP_SHLIB_SUFFIX'))
|
||||
{
|
||||
define('PHP_SHLIB_SUFFIX',strtoupper(substr(PHP_OS, 0,3)) == 'WIN' ? 'dll' : 'so');
|
||||
}
|
||||
if (!defined('PHP_SHLIB_PREFIX'))
|
||||
{
|
||||
define('PHP_SHLIB_PREFIX',PHP_SHLIB_SUFFIX == 'dll' ? 'php_' : '');
|
||||
}
|
||||
|
||||
if (!extension_loaded('gd') && !@dl(PHP_SHLIB_PREFIX.'gd.'.PHP_SHLIB_SUFFIX))
|
||||
{
|
||||
die("Can't load the needed php-extension 'gd' !!!");
|
||||
}
|
||||
include_once('../../phpgwapi/inc/common_functions.inc.php');
|
||||
check_load_extension('gd',true); // true = throw exception if not loadable
|
||||
|
||||
foreach(array('width'=>1,'height'=>1,'color1'=>'000080','color2'=>'ffffff') as $name => $default)
|
||||
{
|
||||
@ -84,4 +70,3 @@ else
|
||||
imagepng($image);
|
||||
}
|
||||
imagedestroy($image);
|
||||
?>
|
||||
|
@ -1,31 +1,17 @@
|
||||
<?php
|
||||
/**************************************************************************\
|
||||
* eGroupWare - calendar: rounded corners *
|
||||
* http://www.egroupware.org *
|
||||
* Written by RalfBecker@outdoor-training.de *
|
||||
* -------------------------------------------- *
|
||||
* This program is free software; you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU General Public License as published by the *
|
||||
* Free Software Foundation; either version 2 of the License, or (at your *
|
||||
* option) any later version. *
|
||||
\**************************************************************************/
|
||||
/**
|
||||
* eGroupWare Calendar: rounded corners
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package calendar
|
||||
* @copyright (c) 2004-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
// some constanst for pre php4.3
|
||||
if (!defined('PHP_SHLIB_SUFFIX'))
|
||||
{
|
||||
define('PHP_SHLIB_SUFFIX',strtoupper(substr(PHP_OS, 0,3)) == 'WIN' ? 'dll' : 'so');
|
||||
}
|
||||
if (!defined('PHP_SHLIB_PREFIX'))
|
||||
{
|
||||
define('PHP_SHLIB_PREFIX',PHP_SHLIB_SUFFIX == 'dll' ? 'php_' : '');
|
||||
}
|
||||
|
||||
if (!extension_loaded('gd') && !@dl(PHP_SHLIB_PREFIX.'gd.'.PHP_SHLIB_SUFFIX))
|
||||
{
|
||||
die("Can't load the needed php-extension 'gd' !!!");
|
||||
}
|
||||
include_once('../../phpgwapi/inc/common_functions.inc.php');
|
||||
check_load_extension('gd',true); // true = throw exception if not loadable
|
||||
|
||||
foreach(array('width'=>-20,'height'=>40,'border'=>1,'color'=>'000080','bgcolor'=>'0000FF') as $name => $default)
|
||||
{
|
||||
@ -85,4 +71,3 @@ else
|
||||
imagepng($image);
|
||||
}
|
||||
imagedestroy($image);
|
||||
?>
|
||||
|
@ -22,7 +22,7 @@
|
||||
*/
|
||||
class select_widget
|
||||
{
|
||||
/**
|
||||
/**
|
||||
* exported methods of this class
|
||||
* @var array
|
||||
*/
|
||||
@ -95,7 +95,7 @@
|
||||
*
|
||||
* @param string $name form-name of the control
|
||||
* @param mixed &$value value / existing content, can be modified
|
||||
* @param array &$cell array with the widget, can be modified for ui-independent widgets
|
||||
* @param array &$cell array with the widget, can be modified for ui-independent widgets
|
||||
* @param array &$readonlys names of widgets as key, to be made readonly
|
||||
* @param mixed &$extension_data data the extension can store persisten between pre- and post-process
|
||||
* @param object &$tmpl reference to the template we belong too
|
||||
@ -184,6 +184,7 @@
|
||||
{
|
||||
$categories =& new categories('',$type3);
|
||||
}
|
||||
$accountId = $GLOBALS['egw_info']['user']['account_id'];
|
||||
foreach((array)$categories->return_sorted_array(0,False,'','','',!$type) as $cat)
|
||||
{
|
||||
$s = str_repeat(' ',$cat['level']) . stripslashes($cat['name']);
|
||||
@ -192,6 +193,14 @@
|
||||
{
|
||||
$s .= ' ♦';
|
||||
}
|
||||
elseif ($cat['owner'] != $accountId)
|
||||
{
|
||||
$s .= '<' . $GLOBALS['egw']->accounts->id2name($cat['owner'], 'account_fullname') . '>';
|
||||
}
|
||||
elseif ($cat['access'] == 'private')
|
||||
{
|
||||
$s .= ' ♥';
|
||||
}
|
||||
if (!$tmpl->xslt)
|
||||
{
|
||||
$cell['sel_options'][$cat['id']] = $s; // 0.9.14 only
|
||||
@ -212,7 +221,7 @@
|
||||
|
||||
case 'select-account': // options: #rows,{accounts(default)|both|groups|owngroups},{0(=lid)|1(default=name)|2(=lid+name),expand-multiselect-rows,not-to-show-accounts,...)}
|
||||
//echo "<p>select-account widget: name=$cell[name], type='$type', rows=$rows, readonly=".(int)($cell['readonly'] || $readonlys)."</p>\n";
|
||||
if($type == 'owngroups')
|
||||
if($type == 'owngroups')
|
||||
{
|
||||
$type = 'groups';
|
||||
$owngroups = true;
|
||||
@ -298,7 +307,7 @@
|
||||
$cell['sel_options'] = $this->monthnames;
|
||||
$value = intval($value);
|
||||
break;
|
||||
|
||||
|
||||
case 'select-dow': // options: rows[,0=summaries befor days, 1=summaries after days, 2=no summaries[,extraStyleMultiselect]]
|
||||
if (!defined('MCAL_M_SUNDAY'))
|
||||
{
|
||||
@ -309,14 +318,14 @@
|
||||
define('MCAL_M_THURSDAY',16);
|
||||
define('MCAL_M_FRIDAY',32);
|
||||
define('MCAL_M_SATURDAY',64);
|
||||
|
||||
|
||||
define('MCAL_M_WEEKDAYS',62);
|
||||
define('MCAL_M_WEEKEND',65);
|
||||
define('MCAL_M_ALLDAYS',127);
|
||||
}
|
||||
$weekstart = $GLOBALS['egw_info']['user']['preferences']['calendar']['weekdaystarts'];
|
||||
$cell['sel_options'] = array();
|
||||
if ($rows >= 2 && !$type)
|
||||
if ($rows >= 2 && !$type)
|
||||
{
|
||||
$cell['sel_options'] = array(
|
||||
MCAL_M_ALLDAYS => 'all days',
|
||||
@ -335,7 +344,7 @@
|
||||
);
|
||||
if ($weekstart != 'Saturday') $cell['sel_options'][MCAL_M_SATURDAY] = 'saturday';
|
||||
if ($weekstart == 'Monday') $cell['sel_options'][MCAL_M_SUNDAY] = 'sunday';
|
||||
if ($rows >= 2 && $type == 1)
|
||||
if ($rows >= 2 && $type == 1)
|
||||
{
|
||||
$cell['sel_options'] += array(
|
||||
MCAL_M_ALLDAYS => 'all days',
|
||||
@ -350,13 +359,13 @@
|
||||
if (($value_in & $val) == $val)
|
||||
{
|
||||
$value[] = $val;
|
||||
|
||||
if ($val == MCAL_M_ALLDAYS ||
|
||||
|
||||
if ($val == MCAL_M_ALLDAYS ||
|
||||
$val == MCAL_M_WEEKDAYS && $value_in == MCAL_M_WEEKDAYS ||
|
||||
$val == MCAL_M_WEEKEND && $value_in == MCAL_M_WEEKEND)
|
||||
{
|
||||
break; // dont set the others
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$readonly)
|
||||
@ -371,7 +380,7 @@
|
||||
$type2 = 31;
|
||||
$type3 = 1;
|
||||
// fall-through
|
||||
|
||||
|
||||
case 'select-number': // options: rows,min,max,decrement,suffix
|
||||
$type = $type === '' ? 1 : intval($type); // min
|
||||
$type2 = $type2 === '' ? 10 : intval($type2); // max
|
||||
@ -392,17 +401,17 @@
|
||||
}
|
||||
$cell['no_lang'] = True;
|
||||
break;
|
||||
|
||||
|
||||
case 'select-hour':
|
||||
for ($h = 0; $h <= 23; ++$h)
|
||||
{
|
||||
$cell['sel_options'][$h] = $GLOBALS['egw_info']['user']['preferences']['common']['timeformat'] == 12 ?
|
||||
(($h % 12 ? $h % 12 : 12).' '.($h < 12 ? lang('am') : lang('pm'))) :
|
||||
(($h % 12 ? $h % 12 : 12).' '.($h < 12 ? lang('am') : lang('pm'))) :
|
||||
sprintf('%02d',$h);
|
||||
}
|
||||
$cell['no_lang'] = True;
|
||||
break;
|
||||
|
||||
|
||||
case 'select-app': // type2: ''=users enabled apps, 'installed', 'all' = not installed ones too
|
||||
$apps = array();
|
||||
foreach ($GLOBALS['egw_info']['apps'] as $app => $data)
|
||||
@ -468,7 +477,7 @@
|
||||
}
|
||||
}
|
||||
$info = $show_type ? '('.$acc['account_type'].') ' : '';
|
||||
|
||||
|
||||
if ($acc['account_type'] == 'g')
|
||||
{
|
||||
$longnames = 1;
|
||||
@ -492,7 +501,7 @@
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* postprocessing method, called after the submission of the form
|
||||
*
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
class tree_widget
|
||||
{
|
||||
/**
|
||||
/**
|
||||
* exported methods of this class
|
||||
* @var array
|
||||
*/
|
||||
@ -49,7 +49,7 @@ class tree_widget
|
||||
*
|
||||
* @param string $name form-name of the control
|
||||
* @param mixed &$value value / existing content, can be modified
|
||||
* @param array &$cell array with the widget, can be modified for ui-independent widgets
|
||||
* @param array &$cell array with the widget, can be modified for ui-independent widgets
|
||||
* @param array &$readonlys names of widgets as key, to be made readonly
|
||||
* @param mixed &$extension_data data the extension can store persisten between pre- and post-process
|
||||
* @param etemplate &$tmpl reference to the template we belong too
|
||||
@ -83,6 +83,7 @@ class tree_widget
|
||||
{
|
||||
$categories =& new categories('',$type3);
|
||||
}
|
||||
$accountId = $GLOBALS['egw_info']['user']['account_id'];
|
||||
$cat2path=array();
|
||||
foreach((array)$categories->return_sorted_array(0,False,'','','',!$type) as $cat)
|
||||
{
|
||||
@ -92,6 +93,13 @@ class tree_widget
|
||||
{
|
||||
$s .= ' ♦';
|
||||
}
|
||||
elseif ($cat['owner'] != $accountId)
|
||||
{
|
||||
$s .= '<' . $GLOBALS['egw']->accounts->id2name($cat['owner'], 'account_fullname') . '>';
|
||||
}
|
||||
elseif ($cat['access'] == 'private') {
|
||||
$s .= ' ♥';
|
||||
}
|
||||
$cat2path[$cat['id']] = $path = ($cat['parent'] ? $cat2path[$cat['parent']].'/' : '').(string)$cat['id'];
|
||||
$cell['sel_options'][$path] = $s;
|
||||
}
|
||||
@ -134,10 +142,10 @@ class tree_widget
|
||||
$onCheck = 'onCheck_'.$tree_id;
|
||||
$script .= "
|
||||
function $onCheck(id) {
|
||||
document.getElementsByName('$name')[0].value=$tree_id.getAllChecked();
|
||||
document.getElementsByName('$name')[0].value=$tree_id.getAllChecked();
|
||||
$onclick;
|
||||
}
|
||||
function $onNodeSelect(id) {
|
||||
function $onNodeSelect(id) {
|
||||
$tree_id.setCheck(id,$tree_id.isItemChecked(id) ? 0 : 1);
|
||||
$onCheck(id);
|
||||
}
|
||||
@ -146,7 +154,7 @@ class tree_widget
|
||||
else // single selection
|
||||
{
|
||||
$script .= "
|
||||
function $onNodeSelect(id) {
|
||||
function $onNodeSelect(id) {
|
||||
document.getElementsByName('$name')[0].value=id;
|
||||
$onclick;
|
||||
}
|
||||
@ -161,7 +169,7 @@ class tree_widget
|
||||
|
||||
return True; // extra Label Ok
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* postprocessing method, called after the submission of the form
|
||||
*
|
||||
@ -182,7 +190,7 @@ class tree_widget
|
||||
function post_process($name,&$value,&$extension_data,&$loop,&$tmpl,$value_in)
|
||||
{
|
||||
//echo "value_in"; _debug_array($value_in);
|
||||
|
||||
|
||||
if (!preg_match('/^[0-9\\/'.($extension_data['multiple']?',':'').']*$/',$value_in)) return false; // guard against xss and other malious content
|
||||
|
||||
$value = $extension_data['multiple'] ? explode(',',$value_in) : $value_in;
|
||||
|
@ -4,6 +4,7 @@
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @package infolog
|
||||
* @copyright (c) 2003-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
@ -95,6 +96,31 @@ class infolog_bo
|
||||
*/
|
||||
var $max_line_chars = 40;
|
||||
|
||||
/**
|
||||
* Available filters
|
||||
*
|
||||
* @var array filter => label pairs
|
||||
*/
|
||||
var $filters = array(
|
||||
'none' => 'no Filter',
|
||||
'done' => 'done',
|
||||
'responsible' => 'responsible',
|
||||
'responsible-open-today' => 'responsible open',
|
||||
'responsible-open-overdue' => 'responsible overdue',
|
||||
'responsible-upcoming' => 'responsible upcoming',
|
||||
'delegated' => 'delegated',
|
||||
'delegated-open-today' => 'delegated open',
|
||||
'delegated-open-overdue' => 'delegated overdue',
|
||||
'delegated-upcoming' => 'delegated upcomming',
|
||||
'own' => 'own',
|
||||
'own-open-today' => 'own open',
|
||||
'own-open-overdue' => 'own overdue',
|
||||
'own-upcoming' => 'own upcoming',
|
||||
'open-today' => 'open',
|
||||
'open-overdue' => 'overdue',
|
||||
'upcoming' => 'upcoming',
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor Infolog BO
|
||||
*
|
||||
@ -129,7 +155,7 @@ class infolog_bo
|
||||
'billed' => 'billed', // --> DONE
|
||||
'template' => 'template', // --> cancelled
|
||||
'nonactive' => 'nonactive', // --> cancelled
|
||||
'archive' => 'archive' ), // --> cancelled
|
||||
'archive' => 'archive' ), // --> cancelled
|
||||
'phone' => array(
|
||||
'not-started' => 'call', // iCal NEEDS-ACTION
|
||||
'ongoing' => 'will-call', // iCal IN-PROCESS
|
||||
@ -211,7 +237,7 @@ class infolog_bo
|
||||
$this->user_time_now = time() + $this->tz_offset_s;
|
||||
|
||||
$this->grants = $GLOBALS['egw']->acl->get_grants('infolog',$this->group_owners ? $this->group_owners : true);
|
||||
$this->so =& new infolog_so($this->grants);
|
||||
$this->so = new infolog_so($this->grants);
|
||||
|
||||
if ($info_id)
|
||||
{
|
||||
@ -488,10 +514,9 @@ class infolog_bo
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('infolog_'.$info['info_type'], $info_id, 'delete', time());
|
||||
|
||||
// send email notifications and do the history logging
|
||||
require_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.infolog_tracking.inc.php');
|
||||
if (!is_object($this->tracking))
|
||||
{
|
||||
$this->tracking =& new infolog_tracking($this);
|
||||
$this->tracking = new infolog_tracking($this);
|
||||
}
|
||||
$this->tracking->track($deleted,$info,$this->user,true);
|
||||
}
|
||||
@ -508,7 +533,7 @@ class infolog_bo
|
||||
* @param boolean $touch_modified=true touch the modification data and sets the modiefier's user-id
|
||||
* @return int/boolean info_id on a successfull write or false
|
||||
*/
|
||||
function write(&$values,$check_defaults=True,$touch_modified=True)
|
||||
function write(&$values, $check_defaults=True, $touch_modified=True)
|
||||
{
|
||||
//echo "boinfolog::write()values="; _debug_array($values);
|
||||
if ($status_only = $values['info_id'] && !$this->check_access($values['info_id'],EGW_ACL_EDIT))
|
||||
@ -522,9 +547,9 @@ class infolog_bo
|
||||
{
|
||||
$responsible =& $values['info_responsible'];
|
||||
}
|
||||
if (!($status_only = in_array($this->user, $responsible))) // responsible has implicit right to change status
|
||||
if (!($status_only = in_array($this->user, (array)$responsible))) // responsible has implicit right to change status
|
||||
{
|
||||
$status_only = !!array_intersect($responsible,array_keys($GLOBALS['egw']->accounts->memberships($this->user)));
|
||||
$status_only = !!array_intersect((array)$responsible,array_keys($GLOBALS['egw']->accounts->memberships($this->user)));
|
||||
}
|
||||
if (!$status_only && $values['info_status'] != 'deleted')
|
||||
{
|
||||
@ -553,8 +578,24 @@ class infolog_bo
|
||||
if ($set_completed)
|
||||
{
|
||||
$values['info_datecompleted'] = $this->user_time_now;
|
||||
$values['info_percent'] = '100%';
|
||||
if (!in_array($values['info_status'],array('done','billed','cancelled'))) $values['info_status'] = 'done';
|
||||
$values['info_percent'] = 100;
|
||||
$forcestatus = true;
|
||||
$status = 'done';
|
||||
if (isset($values['info_type']) && !in_array($values['info_status'],array('done','billed','cancelled'))) {
|
||||
$forcestatus = false;
|
||||
echo "set_completed:"; _debug_array($this->status[$values['info_type']]);
|
||||
if (isset($this->status[$values['info_type']]['done'])) {
|
||||
$forcestatus = true;
|
||||
$status = 'done';
|
||||
} elseif (isset($this->status[$values['info_type']]['billed'])) {
|
||||
$forcestatus = true;
|
||||
$status = 'billed';
|
||||
} elseif (isset($this->status[$values['info_type']]['cancelled'])) {
|
||||
$forcestatus = true;
|
||||
$status = 'cancelled';
|
||||
}
|
||||
}
|
||||
if ($forcestatus && !in_array($values['info_status'],array('done','billed','cancelled'))) $values['info_status'] = $status;
|
||||
}
|
||||
$check_defaults = False;
|
||||
}
|
||||
@ -567,11 +608,26 @@ class infolog_bo
|
||||
}
|
||||
if (in_array($values['info_status'],array('done','billed')))
|
||||
{
|
||||
$values['info_percent'] == '100%';
|
||||
$values['info_percent'] = 100;
|
||||
}
|
||||
if ((int)$values['info_percent'] == 100 && !in_array($values['info_status'],array('done','billed','cancelled')))
|
||||
{
|
||||
$values['info_status'] = 'done';
|
||||
//echo "check_defaults:"; _debug_array($this->status[$values['info_type']]);
|
||||
//$values['info_status'] = 'done';
|
||||
$status = 'done';
|
||||
if (isset($values['info_type'])) {
|
||||
if (isset($this->status[$values['info_type']]['done'])) {
|
||||
$status = 'done';
|
||||
} elseif (isset($this->status[$values['info_type']]['billed'])) {
|
||||
$status = 'billed';
|
||||
} elseif (isset($this->status[$values['info_type']]['cancelled'])) {
|
||||
$status = 'cancelled';
|
||||
} else {
|
||||
// since the comlete stati above do not exist for that type, dont change it
|
||||
$status = $values['info_status'];
|
||||
}
|
||||
}
|
||||
$values['info_status'] = $status;
|
||||
}
|
||||
if ($values['info_responsible'] && $values['info_status'] == 'offer')
|
||||
{
|
||||
@ -603,7 +659,7 @@ class infolog_bo
|
||||
// Should only an entry be updated which includes the original modification date?
|
||||
// Used in the web-GUI to check against a modification by an other user while editing the entry.
|
||||
// It's now disabled for xmlrpc, as otherwise the xmlrpc code need to be changed!
|
||||
$xmprpc = is_object($GLOBALS['server']) && $GLOBALS['server']->last_method;
|
||||
$xmlrpc = is_object($GLOBALS['server']) && $GLOBALS['server']->last_method;
|
||||
$check_modified = $values['info_datemodified'] && !$xmlrpc ? $values['info_datemodified']-$this->tz_offset_s : false;
|
||||
$values['info_datemodified'] = $this->user_time_now;
|
||||
}
|
||||
@ -611,6 +667,7 @@ class infolog_bo
|
||||
{
|
||||
$values['info_modifier'] = $this->so->user;
|
||||
}
|
||||
//_debug_array($values);
|
||||
$to_write = $values;
|
||||
if ($status_only && !$undelete) $values = array_merge($backup_values,$values);
|
||||
// convert user- to system-time
|
||||
@ -663,7 +720,7 @@ class infolog_bo
|
||||
// send email notifications and do the history logging
|
||||
if (!is_object($this->tracking))
|
||||
{
|
||||
$this->tracking =& new infolog_tracking($this);
|
||||
$this->tracking = new infolog_tracking($this);
|
||||
}
|
||||
$this->tracking->track($values,$old,$this->user,$values['info_status'] == 'deleted' || $old['info_status'] == 'deleted');
|
||||
}
|
||||
@ -796,7 +853,12 @@ class infolog_bo
|
||||
{
|
||||
foreach ($_attachments as $attachment)
|
||||
{
|
||||
if(is_readable($attachment['tmp_name']))
|
||||
$is_vfs = false;
|
||||
if (parse_url($attachment['tmp_name'],PHP_URL_SCHEME) == 'vfs' && egw_vfs::is_readable($attachment['tmp_name']))
|
||||
{
|
||||
$is_vfs = true;
|
||||
}
|
||||
if(is_readable($attachment['tmp_name']) || $is_vfs)
|
||||
{
|
||||
egw_link::link('infolog',$info['link_to']['to_id'],'file',$attachment);
|
||||
}
|
||||
@ -1018,7 +1080,7 @@ class infolog_bo
|
||||
$cat_id = $this->categories->name2id($cat_name, 'X-');
|
||||
if (!$cat_id)
|
||||
{
|
||||
$cat_id = $this->categories->add(array('name' => $cat_name,'descr' => $cat_name));
|
||||
$cat_id = $this->categories->add(array('name' => $cat_name, 'descr' => $cat_name, 'access' => 'private'));
|
||||
}
|
||||
|
||||
if ($cat_id)
|
||||
@ -1089,7 +1151,7 @@ class infolog_bo
|
||||
$GLOBALS['egw']->acl->acl($user);
|
||||
$GLOBALS['egw']->acl->read_repository();
|
||||
$this->grants = $GLOBALS['egw']->acl->get_grants('infolog',$this->group_owners ? $this->group_owners : true);
|
||||
$this->so =& new infolog_so($this->grants); // so caches it's filters
|
||||
$this->so = new infolog_so($this->grants); // so caches it's filters
|
||||
|
||||
$notified_info_ids = array();
|
||||
foreach(array(
|
||||
@ -1110,32 +1172,32 @@ class infolog_bo
|
||||
// check if we already send a notification for that infolog entry, eg. starting and due on same day
|
||||
if (in_array($info['info_id'],$notified_info_ids)) continue;
|
||||
|
||||
if (is_null($tracking) || $tracking->user != $user)
|
||||
if (is_null($this->tracking) || $this->tracking->user != $user)
|
||||
{
|
||||
require_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.infolog_tracking.inc.php');
|
||||
$tracking = new infolog_tracking($this);
|
||||
$this->tracking = new infolog_tracking($this);
|
||||
}
|
||||
switch($pref)
|
||||
{
|
||||
case 'notify_due_responsible':
|
||||
$info['message'] = lang('%1 you are responsible for is due at %2',$this->enums['type'][$info['info_type']],
|
||||
$tracking->datetime($info['info_enddate']-$this->tz_offset_s,false));
|
||||
$this->tracking->datetime($info['info_enddate']-$this->tz_offset_s,false));
|
||||
break;
|
||||
case 'notify_due_delegated':
|
||||
$info['message'] = lang('%1 you delegated is due at %2',$this->enums['type'][$info['info_type']],
|
||||
$tracking->datetime($info['info_enddate']-$this->tz_offset_s,false));
|
||||
$this->tracking->datetime($info['info_enddate']-$this->tz_offset_s,false));
|
||||
break;
|
||||
case 'notify_start_responsible':
|
||||
$info['message'] = lang('%1 you are responsible for is starting at %2',$this->enums['type'][$info['info_type']],
|
||||
$tracking->datetime($info['info_startdate']-$this->tz_offset_s,null));
|
||||
$this->tracking->datetime($info['info_startdate']-$this->tz_offset_s,null));
|
||||
break;
|
||||
case 'notify_start_delegated':
|
||||
$info['message'] = lang('%1 you delegated is starting at %2',$this->enums['type'][$info['info_type']],
|
||||
$tracking->datetime($info['info_startdate']-$this->tz_offset_s,null));
|
||||
$this->tracking->datetime($info['info_startdate']-$this->tz_offset_s,null));
|
||||
break;
|
||||
}
|
||||
error_log("notifiying $user($email) about $info[info_subject]: $info[message]");
|
||||
$tracking->send_notification($info,null,$email,$user,$pref);
|
||||
$this->tracking->send_notification($info,null,$email,$user,$pref);
|
||||
|
||||
$notified_info_ids[] = $info['info_id'];
|
||||
}
|
||||
@ -1159,6 +1221,8 @@ class infolog_bo
|
||||
'template' => 'CANCELLED',
|
||||
'nonactive' => 'CANCELLED',
|
||||
'archive' => 'CANCELLED',
|
||||
'deferred' => 'NEEDS-ACTION',
|
||||
'waiting' => 'IN-PROCESS',
|
||||
);
|
||||
|
||||
/** conversion of vtodo status to infolog status
|
||||
@ -1167,7 +1231,9 @@ class infolog_bo
|
||||
*/
|
||||
var $_vtodo2status = array(
|
||||
'NEEDS-ACTION' => 'not-started',
|
||||
'NEEDS ACTION' => 'not-started',
|
||||
'IN-PROCESS' => 'ongoing',
|
||||
'IN PROCESS' => 'ongoing',
|
||||
'COMPLETED' => 'done',
|
||||
'CANCELLED' => 'cancelled',
|
||||
);
|
||||
@ -1223,4 +1289,128 @@ class infolog_bo
|
||||
}
|
||||
return 'ongoing';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Parent ID of an InfoLog entry
|
||||
*
|
||||
* @param string $_guid
|
||||
* @return string parentID
|
||||
*/
|
||||
function getParentID($_guid)
|
||||
{
|
||||
#Horde::logMessage("getParentID($_guid)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$parentID = False;
|
||||
$myfilter = array('col_filter' => array('info_uid'=>$_guid)) ;
|
||||
if ($_guid && ($found=$this->search($myfilter)) && ($uidmatch = array_shift($found))) {
|
||||
$parentID = $uidmatch['info_id'];
|
||||
};
|
||||
return $parentID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a matching db entry
|
||||
*
|
||||
* @param array $egwData the vTODO data we try to find
|
||||
* @param boolean $relax=false if asked to relax, we only match against some key fields
|
||||
* @return the infolog_id of the matching entry or false (if none matches)
|
||||
*/
|
||||
function findVTODO($egwData, $relax=false)
|
||||
{
|
||||
$myfilter = array('col_filter' => array('info_uid'=>$egwData['info_uid'])) ;
|
||||
if ($egwData['info_uid']
|
||||
&& ($found = $this->search($myfilter))
|
||||
&& ($uidmatch = array_shift($found)))
|
||||
{
|
||||
return $uidmatch['info_id'];
|
||||
};
|
||||
unset($egwData['info_uid']);
|
||||
|
||||
$filter = array();
|
||||
|
||||
$description = '';
|
||||
if (!empty($egwData['info_des'])) {
|
||||
$description = trim(preg_replace("/\r?\n?\\[[A-Z_]+:.*\\]/i", '', $egwData['info_des']));
|
||||
unset($egwData['info_des']);
|
||||
// Avoid quotation problems
|
||||
$description = preg_replace("/[^\x20-\x7F].*/", '', $description);
|
||||
if (strlen($description)) {
|
||||
$filter['search'] = $description;
|
||||
}
|
||||
}
|
||||
|
||||
if ($egwData['info_id']
|
||||
&& ($found = $this->read($egwData['info_id'])))
|
||||
{
|
||||
// We only do a simple consistency check
|
||||
if ($found['info_subject'] == $egwData['info_subject']
|
||||
&& strpos($found['info_des'], $description) === 0)
|
||||
{
|
||||
return $found['info_id'];
|
||||
}
|
||||
}
|
||||
unset($egwData['info_id']);
|
||||
|
||||
// priority does not need to match
|
||||
unset($egwData['info_priority']);
|
||||
|
||||
$filter['col_filter'] = $egwData;
|
||||
|
||||
if($foundItems = $this->search($filter)) {
|
||||
if(count($foundItems) > 0) {
|
||||
$itemIDs = array_keys($foundItems);
|
||||
return $itemIDs[0];
|
||||
}
|
||||
}
|
||||
|
||||
$filter = array();
|
||||
|
||||
if (!$relax && strlen($description)) {
|
||||
$filter['search'] = $description;
|
||||
}
|
||||
|
||||
$filter['col_filter'] = $egwData;
|
||||
|
||||
// search for date only match
|
||||
unset($filter['col_filter']['info_startdate']);
|
||||
unset($filter['col_filter']['info_datecompleted']);
|
||||
|
||||
// try tasks without category
|
||||
unset($filter['col_filter']['info_cat']);
|
||||
|
||||
#Horde::logMessage("findVTODO Filter\n"
|
||||
# . print_r($filter, true),
|
||||
# __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
foreach ($this->search($filter) as $itemID => $taskData) {
|
||||
# Horde::logMessage("findVTODO Trying\n"
|
||||
# . print_r($taskData, true),
|
||||
# __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (isset($egwData['info_cat'])
|
||||
&& isset($taskData['info_cat']) && $taskData['info_cat']
|
||||
&& $egwData['info_cat'] != $taskData['info_cat']) continue;
|
||||
if (isset($egwData['info_startdate'])
|
||||
&& isset($taskData['info_startdate']) && $taskData['info_startdate']) {
|
||||
$parts = @getdate($taskData['info_startdate']);
|
||||
$startdate = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
if ($egwData['info_startdate'] != $startdate) continue;
|
||||
}
|
||||
// some clients don't support DTSTART
|
||||
if (isset($egwData['info_startdate'])
|
||||
&& (!isset($taskData['info_startdate']) || !$taskData['info_startdate'])
|
||||
&& !$relax) continue;
|
||||
if (isset($egwData['info_datecompleted'])
|
||||
&& isset($taskData['info_datecompleted']) && $taskData['info_datecompleted']) {
|
||||
$parts = @getdate($taskData['info_datecompleted']);
|
||||
$enddate = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
if ($egwData['info_datecompleted'] != $enddate) continue;
|
||||
}
|
||||
if ((isset($egwData['info_datecompleted'])
|
||||
&& (!isset($taskData['info_datecompleted']) || !$taskData['info_datecompleted'])) ||
|
||||
(!isset($egwData['info_datecompleted'])
|
||||
&& isset($taskData['info_datecompleted']) && $taskData['info_datecompleted'])
|
||||
&& !$relax) continue;
|
||||
return($itemID);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package infolog
|
||||
* @copyright (c) 2003-6 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2003-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -111,15 +111,17 @@ class infolog_hooks
|
||||
}
|
||||
|
||||
/**
|
||||
* populates $GLOBALS['settings'] for the preferences
|
||||
* populates $settings for the preferences
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function settings()
|
||||
{
|
||||
/* Setup some values to fill the array of this app's settings below */
|
||||
$ui = new infolog_ui(); // need some labels from
|
||||
$info = new infolog_bo(); // need some labels from
|
||||
$filters = $show_home = array();
|
||||
$show_home[] = lang("DON'T show InfoLog");
|
||||
foreach($ui->filters as $key => $label)
|
||||
foreach($info->filters as $key => $label)
|
||||
{
|
||||
$show_home[$key] = $filters[$key] = lang($label);
|
||||
}
|
||||
@ -144,7 +146,7 @@ class infolog_hooks
|
||||
);
|
||||
|
||||
/* Settings array for this app */
|
||||
$GLOBALS['settings'] = array(
|
||||
$settings = array(
|
||||
'defaultFilter' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Default Filter for InfoLog',
|
||||
@ -206,6 +208,15 @@ class infolog_hooks
|
||||
'xmlrpc' => True,
|
||||
'admin' => False
|
||||
),
|
||||
'limit_des_lines' => array(
|
||||
'type' => 'input',
|
||||
'size' => 5,
|
||||
'label' => 'Limit number of description lines (default 5, 0 for no limit)',
|
||||
'name' => 'limit_des_lines',
|
||||
'help' => 'How many describtion lines should be directly visible. Further lines are available via a scrollbar.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False
|
||||
),
|
||||
'set_start' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Startdate for new entries',
|
||||
@ -223,14 +234,14 @@ class infolog_hooks
|
||||
'type' => 'multiselect',
|
||||
'label' => 'Which types should the calendar show',
|
||||
'name' => 'cal_show',
|
||||
'values' => $ui->bo->enums['type'],
|
||||
'values' => $info->enums['type'],
|
||||
'help' => 'Can be used to show further InfoLog types in the calendar or limit it to show eg. only tasks.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False
|
||||
),
|
||||
'cat_add_default' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Default category for new Infolog entries',
|
||||
'label' => 'Default categorie for new Infolog entries',
|
||||
'name' => 'cat_add_default',
|
||||
'values' => self::all_cats(),
|
||||
'help' => 'You can choose a categorie to be preselected, when you create a new Infolog entry',
|
||||
@ -241,7 +252,7 @@ class infolog_hooks
|
||||
);
|
||||
|
||||
// notification preferences
|
||||
$GLOBALS['settings']['notify_creator'] = array(
|
||||
$settings['notify_creator'] = array(
|
||||
'type' => 'check',
|
||||
'label' => 'Receive notifications about own items',
|
||||
'name' => 'notify_creator',
|
||||
@ -249,7 +260,7 @@ class infolog_hooks
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
);
|
||||
$GLOBALS['settings']['notify_assigned'] = array(
|
||||
$settings['notify_assigned'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about items assigned to you',
|
||||
'name' => 'notify_assigned',
|
||||
@ -272,7 +283,7 @@ class infolog_hooks
|
||||
'2d' => lang('%1 days in advance',2),
|
||||
'3d' => lang('%1 days in advance',3),
|
||||
);
|
||||
$GLOBALS['settings']['notify_due_delegated'] = array(
|
||||
$settings['notify_due_delegated'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about due entries you delegated',
|
||||
'name' => 'notify_due_delegated',
|
||||
@ -281,7 +292,7 @@ class infolog_hooks
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
);
|
||||
$GLOBALS['settings']['notify_due_responsible'] = array(
|
||||
$settings['notify_due_responsible'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about due entries you are responsible for',
|
||||
'name' => 'notify_due_responsible',
|
||||
@ -290,7 +301,7 @@ class infolog_hooks
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
);
|
||||
$GLOBALS['settings']['notify_start_delegated'] = array(
|
||||
$settings['notify_start_delegated'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about starting entries you delegated',
|
||||
'name' => 'notify_start_delegated',
|
||||
@ -299,7 +310,7 @@ class infolog_hooks
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
);
|
||||
$GLOBALS['settings']['notify_start_responsible'] = array(
|
||||
$settings['notify_start_responsible'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about starting entries you are responsible for',
|
||||
'name' => 'notify_start_responsible',
|
||||
@ -309,7 +320,7 @@ class infolog_hooks
|
||||
'admin' => False,
|
||||
);
|
||||
|
||||
return true; // otherwise prefs say it cant find the file ;-)
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -320,6 +331,7 @@ class infolog_hooks
|
||||
private static function all_cats()
|
||||
{
|
||||
$categories = new categories('','infolog');
|
||||
$accountId = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
foreach((array)$categories->return_sorted_array(0,False,'','','',true) as $cat)
|
||||
{
|
||||
@ -329,6 +341,14 @@ class infolog_hooks
|
||||
{
|
||||
$s .= ' ♦';
|
||||
}
|
||||
elseif ($cat['owner'] != $accountId)
|
||||
{
|
||||
$s .= '<' . $GLOBALS['egw']->accounts->id2name($cat['owner'], 'account_fullname') . '>';
|
||||
}
|
||||
elseif ($cat['access'] == 'private')
|
||||
{
|
||||
$s .= ' ♥';
|
||||
}
|
||||
$sel_options[$cat['id']] = $s; // 0.9.14 only
|
||||
}
|
||||
return $sel_options;
|
||||
@ -346,10 +366,7 @@ class infolog_hooks
|
||||
if ($data['prefs']['notify_due_delegated'] || $data['prefs']['notify_due_responsible'] ||
|
||||
$data['prefs']['notify_start_delegated'] || $data['prefs']['notify_start_responsible'])
|
||||
{
|
||||
require_once(EGW_API_INC.'/class.asyncservice.inc.php');
|
||||
|
||||
$async =& new asyncservice();
|
||||
//$async->cancel_timer('infolog-async-notification');
|
||||
$async = new asyncservice();
|
||||
|
||||
if (!$async->read('infolog-async-notification'))
|
||||
{
|
||||
|
@ -4,13 +4,14 @@
|
||||
*
|
||||
* @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_API_INC.'/horde/Horde/iCalendar.php';
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
|
||||
/**
|
||||
* InfoLog: Create and parse iCal's
|
||||
@ -18,17 +19,24 @@ require_once EGW_API_INC.'/horde/Horde/iCalendar.php';
|
||||
*/
|
||||
class infolog_ical extends infolog_bo
|
||||
{
|
||||
/**
|
||||
* @var array conversion of the priority egw => ical
|
||||
*/
|
||||
var $egw_priority2vcal_priority = array(
|
||||
0 => 3,
|
||||
1 => 2,
|
||||
2 => 1,
|
||||
3 => 1,
|
||||
0 => 9, // low
|
||||
1 => 5, // normal
|
||||
2 => 3, // high
|
||||
3 => 1, // urgent
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array conversion of the priority ical => egw
|
||||
*/
|
||||
var $vcal_priority2egw_priority = array(
|
||||
1 => 2,
|
||||
2 => 1,
|
||||
3 => 0,
|
||||
9 => 0, 8 => 0, 7 => 0, // low
|
||||
6 => 1, 5 => 1, 4 => 1, 0 => 1, // normal
|
||||
3 => 2, 2 => 2, // high
|
||||
1 => 3, // urgent
|
||||
);
|
||||
|
||||
/**
|
||||
@ -39,6 +47,32 @@ class infolog_ical extends infolog_bo
|
||||
var $productManufacturer = 'file';
|
||||
var $productName = '';
|
||||
|
||||
/**
|
||||
* Shall we use the UID extensions of the description field?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $uidExtension = false;
|
||||
|
||||
/**
|
||||
* Client CTCap Properties
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $clientProperties;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $_clientProperties client properties
|
||||
*/
|
||||
function __construct(&$_clientProperties = array())
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->clientProperties = $_clientProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports one InfoLog tast to an iCalendar VTODO
|
||||
*
|
||||
@ -51,53 +85,137 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
$taskData = $this->read($_taskID);
|
||||
|
||||
$taskData = $GLOBALS['egw']->translation->convert($taskData, $GLOBALS['egw']->translation->charset(), 'UTF-8');
|
||||
if ($taskData['info_id_parent'])
|
||||
{
|
||||
$parent = $this->read($taskData['info_id_parent']);
|
||||
$taskData['info_id_parent'] = $parent['info_uid'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_id_parent'] = '';
|
||||
}
|
||||
|
||||
$taskGUID = $GLOBALS['egw']->common->generate_uid('infolog_task',$_taskID);
|
||||
if ($this->uidExtension)
|
||||
{
|
||||
if (!preg_match('/\[UID:.+\]/m', $taskData['info_des']))
|
||||
{
|
||||
$taskData['info_des'] .= "\n[UID:" . $taskData['info_uid'] . "]";
|
||||
if ($taskData['info_id_parent'] != '')
|
||||
{
|
||||
$taskData['info_des'] .= "\n[PARENT_UID:" . $taskData['info_id_parent'] . "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$vcal = &new Horde_iCalendar;
|
||||
if (!empty($taskData['info_cat']))
|
||||
{
|
||||
$cats = $this->get_categories(array($taskData['info_cat']));
|
||||
$taskData['info_cat'] = $cats[0];
|
||||
}
|
||||
|
||||
$taskData = $GLOBALS['egw']->translation->convert($taskData,
|
||||
$GLOBALS['egw']->translation->charset(), 'UTF-8');
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal->setAttribute('VERSION',$_version);
|
||||
$vcal->setAttribute('METHOD',$_method);
|
||||
|
||||
$vevent = Horde_iCalendar::newComponent('VTODO',$vcal);
|
||||
|
||||
// set fields that may contain non-ascii chars and encode them if necessary
|
||||
foreach(array(
|
||||
'SUMMARY' => $taskData['info_subject'],
|
||||
'DESCRIPTION' => $taskData['info_des'],
|
||||
'LOCATION' => $taskData['info_location'],
|
||||
) as $field => $value)
|
||||
if (!isset($this->clientProperties['SUMMARY']['Size']))
|
||||
{
|
||||
$vevent->setAttribute($field,$value);
|
||||
$options = array();
|
||||
if($this->productManufacturer != 'GroupDAV' && preg_match('/([\000-\012\015\016\020-\037\075])/',$value))
|
||||
// make SUMMARY a required field
|
||||
$this->clientProperties['SUMMARY']['Size'] = 0xFFFF;
|
||||
$this->clientProperties['SUMMARY']['NoTruncate'] = false;
|
||||
}
|
||||
// set fields that may contain non-ascii chars and encode them if necessary
|
||||
foreach (array(
|
||||
'SUMMARY' => $taskData['info_subject'],
|
||||
'DESCRIPTION' => $taskData['info_des'],
|
||||
'LOCATION' => $taskData['info_location'],
|
||||
'RELATED-TO' => $taskData['info_id_parent'],
|
||||
'UID' => $taskData['info_uid'],
|
||||
'CATEGORIES' => $taskData['info_cat'],
|
||||
) as $field => $value)
|
||||
{
|
||||
if (isset($this->clientProperties[$field]['Size']))
|
||||
{
|
||||
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
||||
$size = $this->clientProperties[$field]['Size'];
|
||||
$noTruncate = $this->clientProperties[$field]['NoTruncate'];
|
||||
#Horde::logMessage("VTODO $field Size: $size, NoTruncate: " .
|
||||
# ($noTruncate ? 'TRUE' : 'FALSE'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
if($this->productManufacturer != 'GroupDAV' && preg_match('/([\177-\377])/',$value))
|
||||
else
|
||||
{
|
||||
$size = -1;
|
||||
$noTruncate = false;
|
||||
}
|
||||
$cursize = strlen($value);
|
||||
if (($size > 0) && $cursize > $size)
|
||||
{
|
||||
if ($noTruncate)
|
||||
{
|
||||
Horde::logMessage("VTODO $field omitted due to maximum size $size",
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue; // skip field
|
||||
}
|
||||
// truncate the value to size
|
||||
$value = substr($value, 0, $size -1);
|
||||
#Horde::logMessage("VTODO $field truncated to maximum size $size",
|
||||
# __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
}
|
||||
|
||||
if (empty($value) && ($size < 0 || $noTruncate)) continue;
|
||||
|
||||
if ($field == 'RELATED-TO')
|
||||
{
|
||||
$options = array('RELTYPE' => 'PARENT');
|
||||
}
|
||||
else
|
||||
{
|
||||
$options = array();
|
||||
}
|
||||
|
||||
/*if(preg_match('/([\000-\012\015\016\020-\037\075])/', $value)) {
|
||||
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
||||
}*/
|
||||
if ($this->productManufacturer != 'groupdav'
|
||||
&& preg_match('/([\177-\377])/',$value))
|
||||
{
|
||||
$options['CHARSET'] = 'UTF-8';
|
||||
}
|
||||
if ($options) $vevent->setParameter($field, $options);
|
||||
$vevent->setAttribute($field, $value, $options);
|
||||
}
|
||||
|
||||
$dateOnly = false;
|
||||
|
||||
if ($taskData['info_startdate'])
|
||||
{
|
||||
self::setDateOrTime($vevent,'DTSTART',$taskData['info_startdate']);
|
||||
$dateOnly = self::setDateOrTime($vevent, 'DTSTART', $taskData['info_startdate']);
|
||||
}
|
||||
|
||||
if ($taskData['info_enddate'])
|
||||
{
|
||||
self::setDateOrTime($vevent,'DUE',$taskData['info_enddate']);
|
||||
$parts = @getdate($taskData['info_enddate']);
|
||||
if ($dateOnly)
|
||||
{
|
||||
$value = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = @mktime(12, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
}
|
||||
self::setDateOrTime($vevent, 'DUE', $taskData['info_enddate']);
|
||||
}
|
||||
|
||||
if ($taskData['info_datecompleted'])
|
||||
{
|
||||
self::setDateOrTime($vevent,'COMPLETED',$taskData['info_datecompleted']);
|
||||
self::setDateOrTime($vevent, 'COMPLETED', $taskData['info_datecompleted']);
|
||||
}
|
||||
|
||||
$vevent->setAttribute('DTSTAMP',time());
|
||||
$vevent->setAttribute('CREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$_taskID,'add'));
|
||||
$vevent->setAttribute('LAST-MODIFIED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$_taskID,'modify'));
|
||||
$vevent->setAttribute('UID',$taskData['info_uid']);
|
||||
$vevent->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE');
|
||||
$vevent->setAttribute('STATUS',$this->status2vtodo($taskData['info_status']));
|
||||
// we try to preserv the original infolog status as X-INFOLOG-STATUS, so we can restore it, if the user does not modify STATUS
|
||||
@ -105,38 +223,12 @@ class infolog_ical extends infolog_bo
|
||||
$vevent->setAttribute('PERCENT-COMPLETE',$taskData['info_percent']);
|
||||
$vevent->setAttribute('PRIORITY',$this->egw_priority2vcal_priority[$taskData['info_priority']]);
|
||||
|
||||
if (!empty($taskData['info_cat']))
|
||||
{
|
||||
$cats = $this->get_categories(array($taskData['info_cat']));
|
||||
$vevent->setAttribute('CATEGORIES', $cats[0]);
|
||||
}
|
||||
|
||||
$vcal->addComponent($vevent);
|
||||
|
||||
return $vcal->exportvCalendar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if use set a date or date+time and export it as such
|
||||
*
|
||||
* @param Horde_iCalendar_* $vevent
|
||||
* @param string $attr attribute name
|
||||
* @param int $value timestamp
|
||||
*/
|
||||
static function setDateOrTime($vevent,$attr,$value)
|
||||
{
|
||||
// check if use set only a date --> export it as such
|
||||
if (date('H:i',$value) == '00:00')
|
||||
{
|
||||
$vevent->setAttribute($attr,array(
|
||||
'year' => date('Y',$value),
|
||||
'month' => date('m',$value),
|
||||
'mday' => date('d',$value),
|
||||
),array('VALUE' => 'DATE'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$vevent->setAttribute($attr,$value);
|
||||
}
|
||||
$retval = $vcal->exportvCalendar();
|
||||
Horde::logMessage("exportVTODO:\n" . print_r($retval, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,102 +236,143 @@ class infolog_ical extends infolog_bo
|
||||
*
|
||||
* @param string $_vcalData
|
||||
* @param int $_taskID=-1 info_id, default -1 = new entry
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
* @return int|boolean integer info_id or false on error
|
||||
*/
|
||||
function importVTODO(&$_vcalData, $_taskID=-1)
|
||||
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false)
|
||||
{
|
||||
if(!$taskData = $this->vtodotoegw($_vcalData,$_taskID))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!$taskData = $this->vtodotoegw($_vcalData,$_taskID)) return false;
|
||||
|
||||
// we suppose that a not set status in a vtodo means that the task did not started yet
|
||||
if(empty($taskData['info_status']))
|
||||
if (empty($taskData['info_status']))
|
||||
{
|
||||
$taskData['info_status'] = 'not-started';
|
||||
}
|
||||
|
||||
if (empty($taskData['info_datecompleted']))
|
||||
{
|
||||
$taskData['info_datecompleted'] = 0;
|
||||
}
|
||||
|
||||
return $this->write($taskData);
|
||||
}
|
||||
|
||||
function searchVTODO($_vcalData, $contentID=null)
|
||||
{
|
||||
if(!$egwData = $this->vtodotoegw($_vcalData)) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
* @return infolog_id of a matching entry or false, if nothing was found
|
||||
*/
|
||||
function searchVTODO($_vcalData, $contentID=null, $relax=false) {
|
||||
$result = false;
|
||||
|
||||
$myfilter = array('col_filter' => array('info_uid'=>$egwData['info_uid'])) ;
|
||||
if ($egwData['info_uid'] && ($found=parent::search($myfilter)) && ($uidmatch = array_shift($found)))
|
||||
if (($egwData = $this->vtodotoegw($_vcalData)))
|
||||
{
|
||||
return $uidmatch['info_id'];
|
||||
};
|
||||
unset($egwData['info_uid']);
|
||||
|
||||
if ($contentID) {
|
||||
$egwData['info_id'] = $contentID;
|
||||
}
|
||||
|
||||
#unset($egwData['info_priority']);
|
||||
|
||||
$filter = array('col_filter' => $egwData);
|
||||
if($foundItems = $this->search($filter)) {
|
||||
if(count($foundItems) > 0) {
|
||||
$itemIDs = array_keys($foundItems);
|
||||
return $itemIDs[0];
|
||||
if ($contentID)
|
||||
{
|
||||
$egwData['info_id'] = $contentID;
|
||||
}
|
||||
$result = $this->findVTODO($egwData, $relax);
|
||||
}
|
||||
|
||||
return false;
|
||||
return $result;
|
||||
}
|
||||
|
||||
function vtodotoegw($_vcalData,$_taskID=-1)
|
||||
/**
|
||||
* Convert VTODO into a eGW infolog entry
|
||||
*
|
||||
* @param string $_vcalData VTODO data
|
||||
* @param int $_taskID=-1 infolog_id of the entry
|
||||
* @return array infolog entry or false on error
|
||||
*/
|
||||
function vtodotoegw($_vcalData, $_taskID=-1)
|
||||
{
|
||||
$vcal = &new Horde_iCalendar;
|
||||
if(!$vcal->parsevCalendar($_vcalData))
|
||||
$vcal = new Horde_iCalendar;
|
||||
if (!($vcal->parsevCalendar($_vcalData))) return false;
|
||||
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
return FALSE;
|
||||
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$minimum_uid_length = 8;
|
||||
}
|
||||
|
||||
$components = $vcal->getComponents();
|
||||
foreach($components as $component)
|
||||
|
||||
foreach ($components as $component)
|
||||
{
|
||||
if(is_a($component, 'Horde_iCalendar_vtodo'))
|
||||
if (is_a($component, 'Horde_iCalendar_vtodo'))
|
||||
{
|
||||
$taskData = array();
|
||||
if($_taskID > 0)
|
||||
$taskData['info_type'] = 'task';
|
||||
|
||||
if ($_taskID > 0)
|
||||
{
|
||||
$taskData['info_id'] = $_taskID;
|
||||
}
|
||||
foreach($component->_attributes as $attributes)
|
||||
foreach ($component->_attributes as $attributes)
|
||||
{
|
||||
switch($attributes['name'])
|
||||
//$attributes['value'] = trim($attributes['value']);
|
||||
if (empty($attributes['value'])) continue;
|
||||
switch ($attributes['name'])
|
||||
{
|
||||
case 'CLASS':
|
||||
$taskData['info_access'] = strtolower($attributes['value']);
|
||||
$taskData['info_access'] = strtolower($attributes['value']);
|
||||
break;
|
||||
|
||||
case 'DESCRIPTION':
|
||||
$taskData['info_des'] = $attributes['value'];
|
||||
$value = $attributes['value'];
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (!isset($taskData['info_uid'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_uid'] = $matches[1];
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
if (preg_match('/\s*\[PARENT_UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (!isset($taskData['info_id_parent'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_id_parent'] = $this->getParentID($matches[1]);
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
$taskData['info_des'] = $value;
|
||||
break;
|
||||
|
||||
case 'LOCATION':
|
||||
$taskData['info_location'] = $attributes['value'];
|
||||
$taskData['info_location'] = $attributes['value'];
|
||||
break;
|
||||
|
||||
case 'DUE':
|
||||
$taskData['info_enddate'] = $attributes['value'];
|
||||
// eGroupWare uses date only
|
||||
$parts = @getdate($attributes['value']);
|
||||
$value = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
$taskData['info_enddate'] = $value;
|
||||
break;
|
||||
|
||||
case 'COMPLETED':
|
||||
$taskData['info_datecompleted'] = $attributes['value'];
|
||||
break;
|
||||
|
||||
case 'DTSTART':
|
||||
$taskData['info_startdate'] = $attributes['value'];
|
||||
$taskData['info_startdate'] = $attributes['value'];
|
||||
break;
|
||||
|
||||
case 'PRIORITY':
|
||||
if (1 <= $attributes['value'] && $attributes['value'] <= 3)
|
||||
{
|
||||
$taskData['info_priority'] = $this->vcal_priority2egw_priority[$attributes['value']];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_priority'] = 1; // default = normal
|
||||
if (1 <= $attributes['value'] && $attributes['value'] <= 3) {
|
||||
$taskData['info_priority'] = $this->vcal_priority2egw_priority[$attributes['value']];
|
||||
} else {
|
||||
$taskData['info_priority'] = 1; // default = normal
|
||||
}
|
||||
break;
|
||||
|
||||
case 'STATUS':
|
||||
// check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user)
|
||||
foreach($component->_attributes as $attr)
|
||||
@ -249,28 +382,26 @@ class infolog_ical extends infolog_bo
|
||||
$taskData['info_status'] = $this->vtodo2status($attributes['value'],
|
||||
$attr['name'] == 'X-INFOLOG-STATUS' ? $attr['value'] : null);
|
||||
break;
|
||||
|
||||
case 'SUMMARY':
|
||||
$taskData['info_subject'] = $attributes['value'];
|
||||
$taskData['info_subject'] = $attributes['value'];
|
||||
break;
|
||||
|
||||
case 'RELATED-TO':
|
||||
$taskData['info_id_parent'] = $this->getParentID($attributes['value']);
|
||||
break;
|
||||
|
||||
case 'CATEGORIES':
|
||||
$cats = $this->find_or_add_categories(explode(',', $attributes['value']));
|
||||
$taskData['info_cat'] = $cats[0];
|
||||
break;
|
||||
case 'UID':
|
||||
$taskData['info_uid'] = $attributes['value'];
|
||||
if ($_taskID <= 0 && !empty($attributes['value']) && ($uid_task = $this->read($attributes['value'])))
|
||||
{
|
||||
$taskData['info_id'] = $uid_task['id'];
|
||||
unset($uid_task);
|
||||
}
|
||||
// not use weak uids that might come from syncml clients
|
||||
if (isset($event['uid']) && (strlen($event['uid']) < 20 || is_numeric($event['uid'])))
|
||||
{
|
||||
unset ($event['uid']);
|
||||
}
|
||||
|
||||
case 'UID':
|
||||
if (strlen($attributes['value']) >= $minimum_uid_length) {
|
||||
$taskData['info_uid'] = $attributes['value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PERCENT-COMPLETE':
|
||||
$taskData['info_percent'] = (int) $attributes['value'];
|
||||
break;
|
||||
@ -280,18 +411,28 @@ class infolog_ical extends infolog_bo
|
||||
# do NOT convert here
|
||||
#$taskData = $GLOBALS['egw']->translation->convert($taskData, 'UTF-8');
|
||||
|
||||
Horde::logMessage("vtodotoegw:\n" . print_r($taskData, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
return $taskData;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export an infolog entry as VNOTE
|
||||
*
|
||||
* @param int $_noteID the infolog_id of the entry
|
||||
* @param string $_type content type (e.g. text/plain)
|
||||
* @return string VNOTE representation of the infolog entry
|
||||
*/
|
||||
function exportVNOTE($_noteID, $_type)
|
||||
{
|
||||
$note = $this->read($_noteID);
|
||||
$note = $GLOBALS['egw']->translation->convert($note, $GLOBALS['egw']->translation->charset(), 'UTF-8');
|
||||
$note = $GLOBALS['egw']->translation->convert($note,
|
||||
$GLOBALS['egw']->translation->charset(), 'UTF-8');
|
||||
|
||||
switch($_type)
|
||||
switch ($_type)
|
||||
{
|
||||
case 'text/plain':
|
||||
$txt = $note['info_subject']."\n\n".$note['info_des'];
|
||||
@ -299,66 +440,128 @@ class infolog_ical extends infolog_bo
|
||||
break;
|
||||
|
||||
case 'text/x-vnote':
|
||||
$noteGUID = $GLOBALS['egw']->common->generate_uid('infolog_note',$_noteID);
|
||||
$vnote = &new Horde_iCalendar_vnote();
|
||||
$vnote = new Horde_iCalendar_vnote();
|
||||
$options = array('CHARSET' => 'UTF-8');
|
||||
$vNote->setAttribute('VERSION', '1.1');
|
||||
$vnote->setAttribute('SUMMARY',$note['info_subject']);
|
||||
$vnote->setAttribute('BODY',$note['info_des']);
|
||||
if($note['info_startdate'])
|
||||
foreach (array( 'SUMMARY' => $note['info_subject'],
|
||||
'BODY' => $note['info_des'],
|
||||
) as $field => $value)
|
||||
{
|
||||
$vnote->setAttribute($field, $value);
|
||||
if ($this->productManufacturer != 'groupdav'
|
||||
&& preg_match('/([\177-\377])/', $value))
|
||||
{
|
||||
$vevent->setParameter($field, $options);
|
||||
}
|
||||
}
|
||||
if ($note['info_startdate'])
|
||||
{
|
||||
$vnote->setAttribute('DCREATED',$note['info_startdate']);
|
||||
}
|
||||
$vnote->setAttribute('DCREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'add'));
|
||||
$vnote->setAttribute('LAST-MODIFIED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'modify'));
|
||||
|
||||
if (!empty($note['info_cat']))
|
||||
{
|
||||
$cats = $this->get_categories(array($note['info_cat']));
|
||||
$vnote->setAttribute('CATEGORIES', $cats[0]);
|
||||
$value = $cats[0];
|
||||
$vnote->setAttribute('CATEGORIES', $value);
|
||||
if ($this->productManufacturer != 'groupdav'
|
||||
&& preg_match('/([\177-\377])/', $value))
|
||||
{
|
||||
$vevent->setParameter('CATEGORIES', $options);
|
||||
}
|
||||
}
|
||||
|
||||
#$vnote->setAttribute('UID',$noteGUID);
|
||||
#$vnote->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE');
|
||||
|
||||
#$options = array('CHARSET' => 'UTF-8','ENCODING' => 'QUOTED-PRINTABLE');
|
||||
#$vnote->setParameter('SUMMARY', $options);
|
||||
#$vnote->setParameter('DESCRIPTION', $options);
|
||||
|
||||
return $vnote->exportvCalendar();
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function importVNOTE(&$_vcalData, $_type, $_noteID = -1)
|
||||
/**
|
||||
* Check whether to export a date or date+time
|
||||
*
|
||||
* @param Horde_iCalendar_* $vevent
|
||||
* @param string $attr attribute name
|
||||
* @param int $value timestamp
|
||||
* @return boolean true, if date only
|
||||
*/
|
||||
static function setDateOrTime($vevent,$attr,$value)
|
||||
{
|
||||
if(!$note = $this->vnotetoegw($_vcalData, $_type))
|
||||
if (date('Hi',$value) == '0000')
|
||||
{
|
||||
return false;
|
||||
$vevent->setAttribute($attr, array(
|
||||
'year' => date('Y',$value),
|
||||
'month' => date('m',$value),
|
||||
'mday' => date('d',$value),
|
||||
), array('VALUE' => 'DATE'));
|
||||
return true;
|
||||
}
|
||||
|
||||
if($_noteID > 0)
|
||||
else
|
||||
{
|
||||
$note['info_id'] = $_noteID;
|
||||
$vevent->setAttribute($attr, $value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if(empty($note['info_status'])) {
|
||||
$note['info_status'] = 'done';
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a VNOTE component of an iCal
|
||||
*
|
||||
* @param string $_vcalData
|
||||
* @param string $_type content type (eg.g text/plain)
|
||||
* @param int $_taskID=-1 info_id, default -1 = new entry
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
* @return int|boolean integer info_id or false on error
|
||||
*/
|
||||
function importVNOTE(&$_vcalData, $_type, $_noteID = -1, $merge=false)
|
||||
{
|
||||
if (!($note = $this->vnotetoegw($_vcalData, $_type))) return false;
|
||||
|
||||
if($_noteID > 0) $note['info_id'] = $_noteID;
|
||||
|
||||
if (empty($note['info_status'])) $note['info_status'] = 'done';
|
||||
|
||||
#_debug_array($taskData);exit;
|
||||
return $this->write($note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search a matching infolog entry for the VNOTE data
|
||||
*
|
||||
* @param string $_vcalData VNOTE
|
||||
* @param int $contentID=null infolog_id (or null, if unkown)
|
||||
* @return infolog_id of a matching entry or false, if nothing was found
|
||||
*/
|
||||
function searchVNOTE($_vcalData, $_type, $contentID=null)
|
||||
{
|
||||
if(!$note = $this->vnotetoegw($_vcalData,$_type)) {
|
||||
return false;
|
||||
}
|
||||
if ($contentID) {
|
||||
$note['info_id'] = $contentID;
|
||||
if (!($note = $this->vnotetoegw($_vcalData,$_type))) return false;
|
||||
|
||||
if ($contentID) $note['info_id'] = $contentID;
|
||||
|
||||
unset($note['info_startdate']);
|
||||
|
||||
$filter = array();
|
||||
|
||||
if (!empty($note['info_des']))
|
||||
{
|
||||
$description = trim(preg_replace("/\r?\n?\\[[A-Z_]+:.*\\]/i", '', $note['info_des']));
|
||||
unset($note['info_des']);
|
||||
if (strlen($description))
|
||||
{
|
||||
$filter['search'] = $description;
|
||||
}
|
||||
}
|
||||
|
||||
$filter = array('col_filter' => $note);
|
||||
if($foundItems = $this->search($filter)) {
|
||||
if(count($foundItems) > 0) {
|
||||
$filter['col_filter'] = $note;
|
||||
|
||||
if (($foundItems = $this->search($filter)))
|
||||
{
|
||||
if (count($foundItems) > 0)
|
||||
{
|
||||
$itemIDs = array_keys($foundItems);
|
||||
return $itemIDs[0];
|
||||
}
|
||||
@ -367,9 +570,16 @@ class infolog_ical extends infolog_bo
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert VTODO into a eGW infolog entry
|
||||
*
|
||||
* @param string $_data VNOTE data
|
||||
* @param string $_type content type (eg.g text/plain)
|
||||
* @return array infolog entry or false on error
|
||||
*/
|
||||
function vnotetoegw($_data, $_type)
|
||||
{
|
||||
switch($_type)
|
||||
switch ($_type)
|
||||
{
|
||||
case 'text/plain':
|
||||
$note = array();
|
||||
@ -394,35 +604,32 @@ class infolog_ical extends infolog_bo
|
||||
break;
|
||||
|
||||
case 'text/x-vnote':
|
||||
$vnote = &new Horde_iCalendar;
|
||||
if (!$vcal->parsevCalendar($_data))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
$vnote = new Horde_iCalendar;
|
||||
if (!$vcal->parsevCalendar($_data)) return false;
|
||||
|
||||
$components = $vnote->getComponent();
|
||||
if(count($components) > 0)
|
||||
foreach ($components as $component)
|
||||
{
|
||||
$component = $components[0];
|
||||
if(is_a($component, 'Horde_iCalendar_vnote'))
|
||||
if (is_a($component, 'Horde_iCalendar_vnote'))
|
||||
{
|
||||
$note = array();
|
||||
$note['info_type'] = 'note';
|
||||
|
||||
foreach($component->_attributes as $attribute)
|
||||
foreach ($component->_attributes as $attribute)
|
||||
{
|
||||
switch ($attribute['name'])
|
||||
{
|
||||
case 'BODY':
|
||||
$note['info_des'] = $attribute['value'];
|
||||
break;
|
||||
|
||||
case 'SUMMARY':
|
||||
$note['info_subject'] = $attribute['value'];
|
||||
break;
|
||||
|
||||
case 'CATEGORIES':
|
||||
{
|
||||
$cats = $this->find_or_add_categories(explode(',', $attribute['value']));
|
||||
$note['info_cat'] = $cats[0];
|
||||
}
|
||||
$cats = $this->find_or_add_categories(explode(',', $attribute['value']));
|
||||
$note['info_cat'] = $cats[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -430,7 +637,7 @@ class infolog_ical extends infolog_bo
|
||||
return $note;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -441,11 +648,41 @@ class infolog_ical extends infolog_bo
|
||||
* @param string $_productManufacturer
|
||||
* @param string $_productName
|
||||
*/
|
||||
function setSupportedFields($_productManufacturer='file', $_productName='')
|
||||
function setSupportedFields($_productManufacturer='', $_productName='')
|
||||
{
|
||||
// save them vor later use
|
||||
$this->productManufacturer = $_productManufacturer;
|
||||
$this->productName = $_productName;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
if (isset($state))
|
||||
{
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
}
|
||||
|
||||
// store product manufacturer and name, to be able to use it elsewhere
|
||||
if ($_productManufacturer)
|
||||
{
|
||||
$this->productManufacturer = strtolower($_productManufacturer);
|
||||
$this->productName = strtolower($_productName);
|
||||
}
|
||||
|
||||
if (isset($deviceInfo) && is_array($deviceInfo))
|
||||
{
|
||||
if (!isset($this->productManufacturer)
|
||||
|| $this->productManufacturer == ''
|
||||
|| $this->productManufacturer == 'file')
|
||||
{
|
||||
$this->productManufacturer = strtolower($deviceInfo['manufacturer']);
|
||||
}
|
||||
if (!isset($this->productName) || $this->productName == '')
|
||||
{
|
||||
$this->productName = strtolower($deviceInfo['model']);
|
||||
}
|
||||
if (isset($deviceInfo['uidExtension'])
|
||||
&& $deviceInfo['uidExtension'])
|
||||
{
|
||||
$this->uidExtension = true;
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage('setSupportedFields(' . $this->productManufacturer . ', ' . $this->productName .')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,14 @@
|
||||
*
|
||||
* @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_API_INC.'/horde/Horde/iCalendar.php';
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
|
||||
/**
|
||||
* InfoLog: Create and parse SIF
|
||||
@ -38,58 +39,88 @@ class infolog_sif extends infolog_bo
|
||||
|
||||
// mappings for SIFTask to InfologTask
|
||||
var $_sifTaskMapping = array(
|
||||
'ActualWork' => '',
|
||||
'ActualWork' => '',
|
||||
'BillingInformation' => '',
|
||||
'Body' => 'info_des',
|
||||
'Categories' => 'info_cat',
|
||||
'Companies' => '',
|
||||
'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' => '',
|
||||
'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;
|
||||
|
||||
|
||||
function startElement($_parser, $_tag, $_attributes) {
|
||||
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])) {
|
||||
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) {
|
||||
function characterData($_parser, $_data)
|
||||
{
|
||||
$this->sifData .= $_data;
|
||||
}
|
||||
|
||||
function siftoegw($_sifData, $_sifType) {
|
||||
/**
|
||||
* Convert SIF data into a eGW infolog entry
|
||||
*
|
||||
* @param string $sifData the SIF data
|
||||
* @param string $_sifType type (note/task)
|
||||
* @return array infolog entry or false on error
|
||||
*/
|
||||
function siftoegw($sifData, $_sifType)
|
||||
{
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
$sifData = base64_decode($_sifData);
|
||||
|
||||
#$tmpfname = tempnam('/tmp/sync/contents','sift_');
|
||||
|
||||
@ -115,29 +146,44 @@ class infolog_sif extends infolog_bo
|
||||
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) {
|
||||
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
if (!array($this->_extractedSIFData)) return false;
|
||||
|
||||
switch($_sifType) {
|
||||
switch ($_sifType)
|
||||
{
|
||||
case 'task':
|
||||
$taskData = array();
|
||||
$vcal = &new Horde_iCalendar;
|
||||
$vcal = new Horde_iCalendar;
|
||||
|
||||
$taskData['info_type'] = 'task';
|
||||
$taskData['info_status'] = 'not-started';
|
||||
|
||||
foreach($this->_extractedSIFData as $key => $value) {
|
||||
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");
|
||||
#error_log("infolog key=$key => value=$value");
|
||||
if (empty($value)) continue;
|
||||
|
||||
switch($key) {
|
||||
switch($key)
|
||||
{
|
||||
case 'info_access':
|
||||
$taskData[$key] = ((int)$value > 0) ? 'private' : 'public';
|
||||
break;
|
||||
@ -145,19 +191,18 @@ class infolog_sif extends infolog_bo
|
||||
case 'info_datecompleted':
|
||||
case 'info_enddate':
|
||||
case 'info_startdate':
|
||||
if(!empty($value)) {
|
||||
if (!empty($value))
|
||||
{
|
||||
$taskData[$key] = $vcal->_parseDateTime($value);
|
||||
// somehow the client always deliver a timestamp about 3538 seconds, when no startdate set.
|
||||
if($taskData[$key] < 10000)
|
||||
$taskData[$key] = '';
|
||||
} else {
|
||||
$taskData[$key] = '';
|
||||
if ($taskData[$key] < 10000) unset($taskData[$key]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'info_cat':
|
||||
if (!empty($value)) {
|
||||
if (!empty($value))
|
||||
{
|
||||
$categories = $this->find_or_add_categories(explode(';', $value));
|
||||
$taskData['info_cat'] = $categories[0];
|
||||
}
|
||||
@ -168,8 +213,8 @@ class infolog_sif extends infolog_bo
|
||||
break;
|
||||
|
||||
case 'info_status':
|
||||
$taskData[$key] = ((int)$value == 2) ? 'done' : 'ongoing';
|
||||
switch($value) {
|
||||
switch ($value)
|
||||
{
|
||||
case '0':
|
||||
$taskData[$key] = 'not-started';
|
||||
break;
|
||||
@ -178,9 +223,20 @@ class infolog_sif extends infolog_bo
|
||||
break;
|
||||
case '2':
|
||||
$taskData[$key] = 'done';
|
||||
$taskData['info_percent'] = 100;
|
||||
break;
|
||||
case '3':
|
||||
$taskData[$key] = 'waiting';
|
||||
break;
|
||||
case '4':
|
||||
$taskData[$key] = 'cancelled';
|
||||
if ($this->productName == 'blackberry plug-in')
|
||||
{
|
||||
$taskData[$key] = 'deferred';
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData[$key] = 'cancelled';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$taskData[$key] = 'ongoing';
|
||||
@ -188,11 +244,35 @@ class infolog_sif extends infolog_bo
|
||||
}
|
||||
break;
|
||||
|
||||
case 'complete':
|
||||
$taskData['info_status'] = 'done';
|
||||
$taskData['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)
|
||||
{
|
||||
$taskData['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)
|
||||
{
|
||||
$taskData['info_id_parent'] = $this->getParentID($matches[1]);
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
|
||||
default:
|
||||
$taskData[$key] = $value;
|
||||
break;
|
||||
}
|
||||
error_log("infolog task key=$key => value=".$taskData[$key]);
|
||||
#error_log("infolog task key=$key => value=" . $taskData[$key]);
|
||||
}
|
||||
|
||||
return $taskData;
|
||||
@ -201,30 +281,34 @@ class infolog_sif extends infolog_bo
|
||||
case 'note':
|
||||
$noteData = array();
|
||||
$noteData['info_type'] = 'note';
|
||||
$vcal = &new Horde_iCalendar;
|
||||
$vcal = new Horde_iCalendar;
|
||||
|
||||
foreach($this->_extractedSIFData as $key => $value)
|
||||
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);
|
||||
#error_log("infolog client key=$key => value=" . $value);
|
||||
switch ($key)
|
||||
{
|
||||
case 'info_startdate':
|
||||
if(!empty($value)) {
|
||||
if (!empty($value))
|
||||
{
|
||||
$noteData[$key] = $vcal->_parseDateTime($value);
|
||||
// somehow the client always deliver a timestamp about 3538 seconds, when no startdate set.
|
||||
if($noteData[$key] < 10000)
|
||||
$noteData[$key] = '';
|
||||
} else {
|
||||
if ($noteData[$key] < 10000) $noteData[$key] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$noteData[$key] = '';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'info_cat':
|
||||
if (!empty($value)) {
|
||||
if (!empty($value))
|
||||
{
|
||||
$categories = $this->find_or_add_categories(explode(';', $value));
|
||||
$taskData['info_cat'] = $categories[0];
|
||||
$noteData['info_cat'] = $categories[0];
|
||||
}
|
||||
break;
|
||||
|
||||
@ -232,7 +316,7 @@ class infolog_sif extends infolog_bo
|
||||
$noteData[$key] = $value;
|
||||
break;
|
||||
}
|
||||
error_log("infolog note key=$key => value=".$noteData[$key]);
|
||||
#error_log("infolog note key=$key => value=".$noteData[$key]);
|
||||
}
|
||||
return $noteData;
|
||||
break;
|
||||
@ -243,17 +327,33 @@ class infolog_sif extends infolog_bo
|
||||
}
|
||||
}
|
||||
|
||||
function searchSIF($_sifData, $_sifType, $contentID=null) {
|
||||
if(!$egwData = $this->siftoegw($_sifData, $_sifType)) {
|
||||
return false;
|
||||
}
|
||||
if ($contentID) {
|
||||
$egwData['info_id'] = $contentID;
|
||||
}
|
||||
/**
|
||||
* 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))) return false;
|
||||
|
||||
$filter = array('col_filter' => $egwData);
|
||||
if($foundItems = $this->search($filter)) {
|
||||
if(count($foundItems) > 0) {
|
||||
if ($contentID) $egwData['info_id'] = $contentID;
|
||||
|
||||
if ($_sifType == 'task') return $this->findVTODO($egwData, $relax);
|
||||
|
||||
if ($_sifType == 'note') unset($egwData['info_startdate']);
|
||||
|
||||
$filter = array();
|
||||
|
||||
$filter['col_filter'] = $egwData;
|
||||
|
||||
if ($foundItems = $this->search($filter))
|
||||
{
|
||||
if (count($foundItems) > 0)
|
||||
{
|
||||
$itemIDs = array_keys($foundItems);
|
||||
return $itemIDs[0];
|
||||
}
|
||||
@ -262,46 +362,119 @@ class infolog_sif extends infolog_bo
|
||||
return false;
|
||||
}
|
||||
|
||||
function addSIF($_sifData, $_id, $_sifType) {
|
||||
if(!$egwData = $this->siftoegw($_sifData, $_sifType)) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 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 (!($egwData = $this->siftoegw($_sifData, $_sifType))) return false;
|
||||
|
||||
if($_id > 0)
|
||||
$egwData['info_id'] = $_id;
|
||||
if ($_id > 0) $egwData['info_id'] = $_id;
|
||||
|
||||
if (empty($taskData['info_datecompleted']))
|
||||
{
|
||||
$taskData['info_datecompleted'] = 0;
|
||||
}
|
||||
|
||||
$egwID = $this->write($egwData, false);
|
||||
|
||||
return $egwID;
|
||||
}
|
||||
|
||||
function getSIF($_id, $_sifType) {
|
||||
switch($_sifType) {
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
switch($_sifType)
|
||||
{
|
||||
case 'task':
|
||||
if($taskData = $this->read($_id)) {
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
$vcal = &new Horde_iCalendar;
|
||||
if (($taskData = $this->read($_id)))
|
||||
{
|
||||
$vcal = new Horde_iCalendar('1.0');
|
||||
|
||||
$sifTask = '<task>';
|
||||
|
||||
foreach($this->_sifTaskMapping as $sifField => $egwField)
|
||||
if ($taskData['info_id_parent'])
|
||||
{
|
||||
if(empty($egwField)) continue;
|
||||
$parent = $this->read($taskData['info_id_parent']);
|
||||
$taskData['info_id_parent'] = $parent['info_uid'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_id_parent'] = '';
|
||||
}
|
||||
|
||||
if (!preg_match('/\[UID:.+\]/m', $taskData['info_des']))
|
||||
{
|
||||
$taskData['info_des'] .= "\r\n[UID:" . $taskData['info_uid'] . "]";
|
||||
if ($taskData['info_id_parent'] != '')
|
||||
{
|
||||
$taskData['info_des'] .= "\r\n[PARENT_UID:" . $taskData['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($taskData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
switch($sifField) {
|
||||
switch ($sifField)
|
||||
{
|
||||
|
||||
case 'Complete':
|
||||
// is handled with DateCompleted
|
||||
break;
|
||||
|
||||
case 'DateCompleted':
|
||||
case 'DueDate':
|
||||
case 'StartDate':
|
||||
if(!empty($value)) {
|
||||
$value = $vcal->_exportDateTime($value);
|
||||
if ($taskData[info_status] == 'done')
|
||||
{
|
||||
$sifTask .= "<Complete>1</Complete>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sifTask .= "<DateCompleted></DateCompleted><Complete>0</Complete>";
|
||||
continue;
|
||||
}
|
||||
case 'DueDate':
|
||||
if (!empty($value))
|
||||
{
|
||||
$hdate = new Horde_Date($value);
|
||||
$value = $vcal->_exportDate($hdate, '000000Z');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sifTask .= "<$sifField></$sifField>";
|
||||
}
|
||||
break;
|
||||
case 'StartDate':
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = $vcal->_exportDateTime($value);
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sifTask .= "<$sifField></$sifField>";
|
||||
}
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Importance':
|
||||
if($value > 3) $value = 3;
|
||||
if ($value > 3) $value = 3;
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
@ -311,20 +484,26 @@ class infolog_sif extends infolog_bo
|
||||
break;
|
||||
|
||||
case 'Status':
|
||||
switch($value) {
|
||||
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;
|
||||
case 'ongoing':
|
||||
$value = '1';
|
||||
break;
|
||||
default:
|
||||
default: //ongoing
|
||||
$value = 1;
|
||||
break;
|
||||
}
|
||||
@ -332,102 +511,69 @@ class infolog_sif extends infolog_bo
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value))
|
||||
if (!empty($value) && $value)
|
||||
{
|
||||
$value = implode('; ', $this->get_categories(array($value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_QUOTES, 'utf-8');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$sifTask .= '<ActualWork>0</ActualWork><IsRecurring>0</IsRecurring>';
|
||||
return base64_encode($sifTask);
|
||||
|
||||
/* return base64_encode("<task>
|
||||
<ActualWork>0</ActualWork>
|
||||
<BillingInformation></BillingInformation>
|
||||
<Body></Body>
|
||||
<Categories></Categories>
|
||||
<Companies></Companies>
|
||||
<Complete>0</Complete>
|
||||
<DateCompleted></DateCompleted>
|
||||
<DueDate></DueDate>
|
||||
<Importance>1</Importance>
|
||||
<IsRecurring>0</IsRecurring>
|
||||
<Mileage></Mileage>
|
||||
<PercentComplete>0</PercentComplete>
|
||||
<ReminderSet>0</ReminderSet>
|
||||
<ReminderTime></ReminderTime>
|
||||
<Sensitivity>0</Sensitivity>
|
||||
<StartDate>45001231T230000Z</StartDate>
|
||||
<Status>3</Status>
|
||||
<Subject>TARAAA3</Subject>
|
||||
<TeamTask>0</TeamTask>
|
||||
<TotalWork>0</TotalWork>
|
||||
<RecurrenceType>1</RecurrenceType>
|
||||
<Interval>1</Interval>
|
||||
<MonthOfYear>0</MonthOfYear>
|
||||
<DayOfMonth>0</DayOfMonth>
|
||||
<DayOfWeekMask>4</DayOfWeekMask>
|
||||
<Instance>0</Instance>
|
||||
<PatternStartDate>20060320T230000Z</PatternStartDate>
|
||||
<NoEndDate>1</NoEndDate>
|
||||
<PatternEndDate></PatternEndDate>
|
||||
<Occurrences>10</Occurrences>
|
||||
</task>
|
||||
"); */
|
||||
$sifTask .= '<ActualWork>0</ActualWork><IsRecurring>0</IsRecurring></task>';
|
||||
return $sifTask;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'note':
|
||||
if($taskData = $this->read($_id)) {
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
$vcal = &new Horde_iCalendar;
|
||||
if (($taskData = $this->read($_id)))
|
||||
{
|
||||
$vcal = new Horde_iCalendar('1.0');
|
||||
|
||||
$sifNote = '<note>';
|
||||
$sifNote = self::xml_decl . "\n<note>" . self::SIF_decl;
|
||||
|
||||
foreach($this->_sifNoteMapping as $sifField => $egwField)
|
||||
foreach ($this->_sifNoteMapping as $sifField => $egwField)
|
||||
{
|
||||
if(empty($egwField)) continue;
|
||||
|
||||
$value = $GLOBALS['egw']->translation->convert($taskData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
switch($sifField) {
|
||||
switch ($sifField)
|
||||
{
|
||||
case 'Date':
|
||||
if(!empty($value)) {
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = $vcal->_exportDateTime($value);
|
||||
}
|
||||
$sifNote .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Body':
|
||||
$value = $GLOBALS['egw']->translation->convert($taskData['info_subject'], $sysCharSet, 'utf-8') . "\n" . $value;
|
||||
$sifNote .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = implode('; ', $this->get_categories(array($value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
$sifNote .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_QUOTES, 'utf-8');
|
||||
$sifNote .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return base64_encode($sifNote);
|
||||
$sifNote .= '</note>';
|
||||
return $sifNote;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -437,116 +583,35 @@ class infolog_sif extends infolog_bo
|
||||
|
||||
}
|
||||
|
||||
function exportVTODO($_taskID, $_version)
|
||||
/**
|
||||
* 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='')
|
||||
{
|
||||
$taskData = $this->read($_taskID);
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
$taskData = $GLOBALS['egw']->translation->convert($taskData,$GLOBALS['egw']->translation->charset(),'UTF-8');
|
||||
|
||||
//_debug_array($taskData);
|
||||
|
||||
$taskGUID = $GLOBALS['phpgw']->common->generate_uid('infolog_task',$_taskID);
|
||||
|
||||
$vcal = &new Horde_iCalendar;
|
||||
$vcal->setAttribute('VERSION',$_version);
|
||||
$vcal->setAttribute('METHOD','PUBLISH');
|
||||
|
||||
$vevent = Horde_iCalendar::newComponent('VTODO',$vcal);
|
||||
|
||||
$options = array();
|
||||
|
||||
$vevent->setAttribute('SUMMARY',$taskData['info_subject']);
|
||||
$vevent->setAttribute('DESCRIPTION',$taskData['info_des']);
|
||||
if($taskData['info_startdate'])
|
||||
$vevent->setAttribute('DTSTART',$taskData['info_startdate']);
|
||||
if($taskData['info_enddate'])
|
||||
$vevent->setAttribute('DUE',$taskData['info_enddate']);
|
||||
$vevent->setAttribute('DTSTAMP',time());
|
||||
$vevent->setAttribute('CREATED',$GLOBALS['phpgw']->contenthistory->getTSforAction('infolog_task',$_taskID,'add'));
|
||||
$vevent->setAttribute('LAST-MODIFIED',$GLOBALS['phpgw']->contenthistory->getTSforAction('infolog_task',$_taskID,'modify'));
|
||||
$vevent->setAttribute('UID',$taskGUID);
|
||||
$vevent->setAttribute('CLASS',(($taskData['info_access'] == 'public')?'PUBLIC':'PRIVATE'));
|
||||
$vevent->setAttribute('STATUS',(($taskData['info_status'] == 'completed')?'COMPLETED':'NEEDS-ACTION'));
|
||||
// 3=urgent => 1, 2=high => 2, 1=normal => 3, 0=low => 4
|
||||
$vevent->setAttribute('PRIORITY',4-$taskData['info_priority']);
|
||||
|
||||
#$vevent->setAttribute('TRANSP','OPAQUE');
|
||||
# status
|
||||
# ATTENDEE
|
||||
|
||||
$options = array('CHARSET' => 'UTF-8','ENCODING' => 'QUOTED-PRINTABLE');
|
||||
$vevent->setParameter('SUMMARY', $options);
|
||||
$vevent->setParameter('DESCRIPTION', $options);
|
||||
|
||||
$vcal->addComponent($vevent);
|
||||
|
||||
#print "<pre>";
|
||||
#print $vcal->exportvCalendar();
|
||||
#print "</pre>";
|
||||
|
||||
return $vcal->exportvCalendar();
|
||||
}
|
||||
|
||||
function importVTODO(&$_vcalData, $_taskID=-1)
|
||||
{
|
||||
$botranslation = CreateObject('phpgwapi.translation');
|
||||
|
||||
$vcal = &new Horde_iCalendar;
|
||||
if(!$vcal->parsevCalendar($_vcalData))
|
||||
if (isset($deviceInfo) && is_array($deviceInfo))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
$components = $vcal->getComponents();
|
||||
if(count($components) > 0)
|
||||
{
|
||||
$component = $components[0];
|
||||
if(is_a($component, 'Horde_iCalendar_vtodo'))
|
||||
if (isset($deviceInfo['uidExtension']) &&
|
||||
$deviceInfo['uidExtension'])
|
||||
{
|
||||
if($_taskID>0)
|
||||
$taskData['info_id'] = $_taskID;
|
||||
|
||||
foreach($component->_attributes as $attributes)
|
||||
{
|
||||
#print $attributes['name'].' - '.$attributes['value'].'<br>';
|
||||
#$attributes['value'] = $GLOBALS['egw']->translation->convert($attributes['value'],'UTF-8');
|
||||
switch($attributes['name'])
|
||||
{
|
||||
case 'CLASS':
|
||||
$taskData['info_access'] = strtolower($attributes['value']);
|
||||
break;
|
||||
case 'DESCRIPTION':
|
||||
$taskData['info_des'] = $attributes['value'];
|
||||
break;
|
||||
case 'DUE':
|
||||
$taskData['info_enddate'] = $attributes['value'];
|
||||
break;
|
||||
case 'DTSTART':
|
||||
$taskData['info_startdate'] = $attributes['value'];
|
||||
break;
|
||||
case 'PRIORITY':
|
||||
// 1 => 3=urgent, 2 => 2=high, 3 => 1=normal, 4 => 0=low
|
||||
if (1 <= $attributes['value'] && $attributes['value'] <= 4)
|
||||
{
|
||||
$taskData['info_priority'] = 4 - $attributes['value'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_priority'] = 1; // default = normal
|
||||
}
|
||||
break;
|
||||
case 'STATUS':
|
||||
$taskData['info_status'] = (strtolower($attributes['value']) == 'completed') ? 'done' : 'ongoing';
|
||||
break;
|
||||
case 'SUMMARY':
|
||||
$taskData['info_subject'] = $attributes['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
#_debug_array($eventData);exit;
|
||||
return $this->write($taskData);
|
||||
$this->uidExtension = true;
|
||||
}
|
||||
}
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -91,13 +91,13 @@ class infolog_so
|
||||
$user_and_memberships = $GLOBALS['egw']->accounts->memberships($this->user,true);
|
||||
$user_and_memberships[] = $this->user;
|
||||
}
|
||||
return $info['info_responsible'] && array_intersect($info['info_responsible'],$user_and_memberships);
|
||||
return $info['info_responsible'] && array_intersect((array)$info['info_responsible'],$user_and_memberships);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if user has the $required_rights to access $info_id (private access is handled too)
|
||||
*
|
||||
* @param array/int $info data or info_id of InfoLog entry
|
||||
* @param array|int $info data or info_id of InfoLog entry
|
||||
* @param int $required_rights EGW_ACL_xyz anded together
|
||||
* @param boolean $implicit_edit=false responsible has only implicit read and add rigths, unless this is set to true
|
||||
* @return boolean True if access is granted else False
|
||||
@ -284,7 +284,7 @@ class infolog_so
|
||||
preg_match('/(upcoming|today|overdue|date|enddate)([-\\/.0-9]*)/',$filter,$vars);
|
||||
$filter = $vars[1];
|
||||
|
||||
if (isset($vars[2]) && !empty($vars[2]) && ($date = split('[-/.]',$vars[2])))
|
||||
if (isset($vars[2]) && !empty($vars[2]) && ($date = preg_split('/[-\\/.]/',$vars[2])))
|
||||
{
|
||||
$today = mktime(-$this->tz_offset,0,0,intval($date[1]),intval($date[2]),intval($date[0]));
|
||||
$tomorrow = mktime(-$this->tz_offset,0,0,intval($date[1]),intval($date[2])+1,intval($date[0]));
|
||||
@ -339,11 +339,17 @@ class infolog_so
|
||||
*
|
||||
* some cacheing is done to prevent multiple reads of the same entry
|
||||
*
|
||||
* @param $info_id id or uid of entry
|
||||
* @return array/boolean the entry as array or False on error (eg. entry not found)
|
||||
* @param int|string $info_id id or uid of entry
|
||||
* @return array|boolean the entry as array or False on error (eg. entry not found)
|
||||
*/
|
||||
function read($info_id) // did _not_ ensure ACL
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//echo "<p>read($info_id) ".function_backtrace()."</p>\n";
|
||||
if ($info_id && ((int)$info_id == $this->data['info_id'] || $info_id == $this->data['info_uid']))
|
||||
{
|
||||
@ -356,6 +362,14 @@ class infolog_so
|
||||
$this->init( );
|
||||
return False;
|
||||
}
|
||||
if (!$this->data['info_uid'] || strlen($this->data['info_uid']) < $minimum_uid_length) {
|
||||
// entry without uid --> create one based on our info_id and save it
|
||||
|
||||
$this->data['info_uid'] = $GLOBALS['egw']->common->generate_uid('infolog', $info_id);
|
||||
$this->db->update($this->info_table,
|
||||
array('info_uid' => $this->data['info_uid']),
|
||||
array('info_id' => $this->data['info_id']), __LINE__,__FILE__);
|
||||
}
|
||||
if (!is_array($this->data['info_responsible']))
|
||||
{
|
||||
$this->data['info_responsible'] = $this->data['info_responsible'] ? explode(',',$this->data['info_responsible']) : array();
|
||||
@ -399,7 +413,7 @@ class infolog_so
|
||||
* delete InfoLog entry $info_id AND the links to it
|
||||
*
|
||||
* @param int $info_id id of log-entry
|
||||
* @param bool $delete_children delete the children, if not set there parent-id to $new_parent
|
||||
* @param boolean $delete_children delete the children, if not set there parent-id to $new_parent
|
||||
* @param int $new_parent new parent-id to set for subs
|
||||
*/
|
||||
function delete($info_id,$delete_children=True,$new_parent=0) // did _not_ ensure ACL
|
||||
@ -495,10 +509,16 @@ class infolog_so
|
||||
*
|
||||
* @param array $values with the data of the log-entry
|
||||
* @param int $check_modified=0 old modification date to check before update (include in WHERE)
|
||||
* @return int/boolean info_id, false on error or 0 if the entry has been updated in the meantime
|
||||
* @return int|boolean info_id, false on error or 0 if the entry has been updated in the meantime
|
||||
*/
|
||||
function write($values,$check_modified=0) // did _not_ ensure ACL
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//echo "soinfolog::write(,$check_modified) values="; _debug_array($values);
|
||||
$info_id = (int) $values['info_id'];
|
||||
|
||||
@ -540,12 +560,17 @@ class infolog_so
|
||||
$this->db->insert($this->info_table,$to_write,false,__LINE__,__FILE__);
|
||||
$info_id = $this->data['info_id'] = $this->db->get_last_insert_id($this->info_table,'info_id');
|
||||
|
||||
if (!$this->data['info_uid']) // new entry without uid --> create one based on our info_id and save it
|
||||
{
|
||||
$this->data['info_uid'] = $GLOBALS['egw']->common->generate_uid('infolog',$info_id);
|
||||
$this->db->update($this->info_table,array('info_uid'=>$this->data['info_uid']),array('info_id'=>$info_id),__LINE__,__FILE__);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->data['info_uid'] || strlen($this->data['info_uid']) < $minimum_uid_length) {
|
||||
// entry without uid --> create one based on our info_id and save it
|
||||
|
||||
$this->data['info_uid'] = $GLOBALS['egw']->common->generate_uid('infolog', $info_id);
|
||||
$this->db->update($this->info_table,
|
||||
array('info_uid' => $this->data['info_uid']),
|
||||
array('info_id' => $info_id), __LINE__,__FILE__);
|
||||
}
|
||||
|
||||
//echo "<p>soinfolog.write values= "; _debug_array($values);
|
||||
|
||||
// write customfields now
|
||||
@ -616,17 +641,19 @@ class infolog_so
|
||||
/**
|
||||
* searches InfoLog for a certain pattern in $query
|
||||
*
|
||||
* @param $query[order] column-name to sort after
|
||||
* @param $query[sort] sort-order DESC or ASC
|
||||
* @param $query[filter] string with combination of acl-, date- and status-filters, eg. 'own-open-today' or ''
|
||||
* @param $query[cat_id] category to use or 0 or unset
|
||||
* @param $query[search] pattern to search, search is done in info_from, info_subject and info_des
|
||||
* @param $query[action] / $query[action_id] if only entries linked to a specified app/entry show be used
|
||||
* @param &$query[start], &$query[total] nextmatch-parameters will be used and set if query returns less entries
|
||||
* @param $query[col_filter] array with column-name - data pairs, data == '' means no filter (!)
|
||||
* @param $query[subs] boolean return subs or not, if unset the user preference is used
|
||||
* @param $query[num_rows] number of rows to return if $query[start] is set, default is to use the value from the general prefs
|
||||
* @return array with id's as key of the matching log-entries
|
||||
* @param string $query[order] column-name to sort after
|
||||
* @param string $query[sort] sort-order DESC or ASC
|
||||
* @param string $query[filter] string with combination of acl-, date- and status-filters, eg. 'own-open-today' or ''
|
||||
* @param int $query[cat_id] category to use or 0 or unset
|
||||
* @param string $query[search] pattern to search, search is done in info_from, info_subject and info_des
|
||||
* @param string $query[action] / $query[action_id] if only entries linked to a specified app/entry show be used
|
||||
* @param int &$query[start], &$query[total] nextmatch-parameters will be used and set if query returns less entries
|
||||
* @param array $query[col_filter] array with column-name - data pairs, data == '' means no filter (!)
|
||||
* @param boolean $query[subs] return subs or not, if unset the user preference is used
|
||||
* @param int $query[num_rows] number of rows to return if $query[start] is set, default is to use the value from the general prefs
|
||||
* @param string|array $query[cols]=null what to query, if set the recordset / iterator get's returned
|
||||
* @param string $query[append]=null get's appended to sql query, eg. for GROUP BY
|
||||
* @return array|iterator with id's as key of the matching log-entries or recordset/iterator if cols is set
|
||||
*/
|
||||
function search(&$query)
|
||||
{
|
||||
@ -661,7 +688,9 @@ class infolog_so
|
||||
}
|
||||
else
|
||||
{
|
||||
$val = (substr($val,0,5) != 'info_' ? 'info_' : '').$val;
|
||||
static $table_def;
|
||||
if (is_null($table_def)) $table_def = $this->db->get_table_definitions('infolog',$this->info_table);
|
||||
if (substr($val,0,5) != 'info_' && isset($table_def['fd']['info_'.$val])) $val = 'info_'.$val;
|
||||
if ($val == 'info_des' && $this->db->capabilities['order_on_text'] !== true)
|
||||
{
|
||||
if (!$this->db->capabilities['order_on_text']) continue;
|
||||
@ -685,6 +714,11 @@ class infolog_so
|
||||
{
|
||||
foreach($query['col_filter'] as $col => $data)
|
||||
{
|
||||
if (is_int($col))
|
||||
{
|
||||
$filtermethod .= ' AND '.$data;
|
||||
continue;
|
||||
}
|
||||
if (substr($col,0,5) != 'info_' && substr($col,0,1)!='#') $col = 'info_'.$col;
|
||||
if (!empty($data) && preg_match('/^[a-z_0-9]+$/i',$col))
|
||||
{
|
||||
@ -766,6 +800,7 @@ class infolog_so
|
||||
if ($action == '' || $action == 'sp' || count($links))
|
||||
{
|
||||
$sql_query = "FROM $this->info_table main $join WHERE ($filtermethod $pid $sql_query) $link_extra";
|
||||
#error_log("infolog.so.search:\n" . print_r($sql_query, true));
|
||||
|
||||
if ($this->db->Type == 'mysql' && $this->db->ServerInfo['version'] >= 4.0)
|
||||
{
|
||||
@ -788,7 +823,9 @@ class infolog_so
|
||||
{
|
||||
$query['start'] = 0;
|
||||
}
|
||||
$rs = $this->db->query($sql="SELECT $mysql_calc_rows $distinct main.* $info_customfield $sql_query $ordermethod",__LINE__,__FILE__,
|
||||
$cols = isset($query['cols']) ? $query['cols'] : 'main.*';
|
||||
if (is_array($cols)) $cols = implode(',',$cols);
|
||||
$rs = $this->db->query($sql='SELECT '.$mysql_calc_rows.' '.$distinct.' '.$cols.' '.$info_customfield.' '.$sql_query.$query['append'].' '.$ordermethod,__LINE__,__FILE__,
|
||||
(int) $query['start'],isset($query['start']) ? (int) $query['num_rows'] : -1,false,egw_db::FETCH_ASSOC);
|
||||
//echo "<p>db::query('$sql',,,".(int)$query['start'].','.(isset($query['start']) ? (int) $query['num_rows'] : -1).")</p>\n";
|
||||
|
||||
@ -800,6 +837,10 @@ class infolog_so
|
||||
// check if start is behind total --> loop to set start=0
|
||||
while (isset($query['start']) && $query['start'] > $query['total']);
|
||||
|
||||
if (isset($query['cols']))
|
||||
{
|
||||
return $rs;
|
||||
}
|
||||
foreach($rs as $info)
|
||||
{
|
||||
$info['info_responsible'] = $info['info_responsible'] ? explode(',',$info['info_responsible']) : array();
|
||||
|
@ -65,7 +65,8 @@ class infolog_ui
|
||||
'edit' => 'edit.gif', 'edit_alt' => 'Edit',
|
||||
'addfile' => 'addfile.gif', 'addfile_alt' => 'Add a file',
|
||||
'delete' => 'delete.gif', 'delete_alt' => 'Delete',
|
||||
'close' => 'done.gif', 'close_alt' => 'Close' ),
|
||||
'close' => 'done.gif', 'close_alt' => 'Close' ,
|
||||
'close_all' => 'done_all.gif', 'close_all_alt' => 'Close' ),
|
||||
'status' => array(
|
||||
'billed' => 'billed.gif', 'billed_alt' => 'billed',
|
||||
'done' => 'done.gif', 'done_alt' => 'done',
|
||||
@ -74,25 +75,7 @@ class infolog_ui
|
||||
'ongoing' => 'ongoing.gif', 'ongoing_alt' => 'ongoing',
|
||||
'offer' => 'offer.gif', 'offer_alt' => 'offer' )
|
||||
);
|
||||
var $filters = array(
|
||||
'none' => 'no Filter',
|
||||
'done' => 'done',
|
||||
'responsible' => 'responsible',
|
||||
'responsible-open-today' => 'responsible open',
|
||||
'responsible-open-overdue' => 'responsible overdue',
|
||||
'responsible-upcoming' => 'responsible upcoming',
|
||||
'delegated' => 'delegated',
|
||||
'delegated-open-today' => 'delegated open',
|
||||
'delegated-open-overdue' => 'delegated overdue',
|
||||
'delegated-upcoming' => 'delegated upcomming',
|
||||
'own' => 'own',
|
||||
'own-open-today' => 'own open',
|
||||
'own-open-overdue' => 'own overdue',
|
||||
'own-upcoming' => 'own upcoming',
|
||||
'open-today' => 'open',
|
||||
'open-overdue' => 'overdue',
|
||||
'upcoming' => 'upcoming',
|
||||
);
|
||||
var $filters;
|
||||
var $messages = array(
|
||||
'edit' => 'InfoLog - Edit',
|
||||
'add' => 'InfoLog - New',
|
||||
@ -109,7 +92,7 @@ class infolog_ui
|
||||
function __construct()
|
||||
{
|
||||
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'infolog') $GLOBALS['egw']->translation->add_app('infolog');
|
||||
$this->bo =& new infolog_bo();
|
||||
$this->bo = new infolog_bo();
|
||||
|
||||
$this->tmpl = new etemplate();
|
||||
|
||||
@ -124,6 +107,7 @@ class infolog_ui
|
||||
$this->duration_format = str_replace(',','',$pm_config['duration_units']).','.$pm_config['hours_per_workday'];
|
||||
unset($pm_config);
|
||||
}
|
||||
$this->filters =& $this->bo->filters;
|
||||
/* these are just for testing of the notifications
|
||||
for($i = -1; $i <= 3; ++$i)
|
||||
{
|
||||
@ -163,7 +147,10 @@ class infolog_ui
|
||||
$info = $this->bo->read($info);
|
||||
}
|
||||
$id = $info['info_id'];
|
||||
$done = $info['info_status'] == 'done' || $info['info_status'] == 'billed';
|
||||
$done = $info['info_status'] == 'done' || $info['info_status'] == 'billed' || $info['info_status'] == 'cancelled'; //cancelled is regarded as a completed status as well in bo
|
||||
// regard an infolog as done/billed/cancelled if its percentage is 100% when there is to status like the above for that type
|
||||
if (!$done && !isset($this->bo->status[$info['info_type']]['done']) && !isset($this->bo->status[$info['info_type']]['billed']) &&
|
||||
!isset($this->bo->status[$info['info_type']]['cancelled']) && (int)$info['info_percent']==100) $done = true ;
|
||||
$info['sub_class'] = $this->bo->enums['priority'][$info['info_priority']] . ($done ? '_done' : '');
|
||||
if (!$done && $info['info_enddate'] < $this->bo->user_time_now)
|
||||
{
|
||||
@ -172,13 +159,18 @@ class infolog_ui
|
||||
if (!isset($info['info_anz_subs'])) $info['info_anz_subs'] = $this->bo->anzSubs($id);
|
||||
$this->bo->link_id2from($info,$action,$action_id); // unset from for $action:$action_id
|
||||
$info['info_percent'] = (int) $info['info_percent'].'%';
|
||||
|
||||
$readonlys["edit[$id]"] = !($this->bo->check_access($info,EGW_ACL_EDIT) || // edit rights or more then standard responsible rights
|
||||
$this->bo->is_responsible($info) && array_diff($this->bo->responsible_edit,array('info_status','info_percent','info_datecompleted')));
|
||||
$editrights = $this->bo->check_access($info,EGW_ACL_EDIT);
|
||||
$isresposible = $this->bo->is_responsible($info);
|
||||
$readonlys["edit[$id]"] = !($editrights || // edit rights or more then standard responsible rights
|
||||
$isresposible && array_diff($this->bo->responsible_edit,array('info_status','info_percent','info_datecompleted')));
|
||||
$readonlys["close[$id]"] = $done || ($readonlys["edit_status[$id]"] =
|
||||
!($this->bo->check_access($info,EGW_ACL_EDIT) || $this->bo->is_responsible($info)));
|
||||
!($editrights || $isresposible));
|
||||
$readonlys["close_all[$id]"] = ($done) || !$info['info_anz_subs'] || ($readonlys["edit_status[$id]"] =
|
||||
!($editrights || $isresposible)); // this one is supressed, when you are not allowed to edit, or not responsible, or the entry is closed
|
||||
// and has no children. If you want that this one is shown if there are children regardless of the status of the current or its childs,
|
||||
// then modify ($done) to ($done && !$info['info_anz_subs'])
|
||||
$readonlys["edit_status[$id]"] = $readonlys["edit_percent[$id]"] =
|
||||
!$this->bo->check_access($info,EGW_ACL_EDIT) && !$this->bo->is_responsible($info) &&
|
||||
!$editrights && !$isresposible &&
|
||||
!$this->bo->check_access($info,EGW_ACL_UNDELETE); // undelete is handled like status edit
|
||||
$readonlys["delete[$id]"] = !$this->bo->check_access($info,EGW_ACL_DELETE);
|
||||
$readonlys["sp[$id]"] = !$this->bo->check_access($info,EGW_ACL_ADD);
|
||||
@ -187,6 +179,7 @@ class infolog_ui
|
||||
$readonlys["timesheet[$id]"] = !isset($GLOBALS['egw_info']['user']['apps']['timesheet']);
|
||||
|
||||
if (!$show_links) $show_links = $this->prefs['show_links'];
|
||||
|
||||
if (($show_links != 'none' && $show_links != 'no_describtion' ||
|
||||
$this->prefs['show_times'] || isset($GLOBALS['egw_info']['user']['apps']['timesheet'])) &&
|
||||
(isset($info['links']) || ($info['links'] = egw_link::get_links('infolog',$info['info_id']))))
|
||||
@ -310,7 +303,7 @@ class infolog_ui
|
||||
unset($query['custom_fields']);
|
||||
if ($query['col_filter']['info_type'])
|
||||
{
|
||||
$tpl =& new etemplate;
|
||||
$tpl = new etemplate;
|
||||
if ($tpl->read('infolog.index.rows.'.$query['col_filter']['info_type']))
|
||||
{
|
||||
$query['template'] =& $tpl;
|
||||
@ -320,7 +313,7 @@ class infolog_ui
|
||||
}
|
||||
// do we need to read the custom fields, depends on the column is enabled and customfields exist, prefs are filter specific
|
||||
// so we have to check that as well
|
||||
$details = $query['filter2'] == 'all';
|
||||
$details = $query['filter2'] == 'all';
|
||||
$columselection = $this->prefs['nextmatch-infolog.index.rows'.($details?'-details':'')];
|
||||
//_debug_array($columselection);
|
||||
if ($columselection)
|
||||
@ -345,15 +338,15 @@ class infolog_ui
|
||||
if ($details)
|
||||
{
|
||||
$query['columnselection_pref'] = (is_object($query['template'])?$query['template']->name:'infolog.index.rows').'-details';
|
||||
$query['default_cols'] = '!cat_id,info_used_time_info_planned_time_info_replanned_time,info_id';
|
||||
$query['default_cols'] = '!cat_id,info_used_time_info_planned_time,info_used_time_info_planned_time_info_replanned_time,info_id';
|
||||
}
|
||||
else
|
||||
{
|
||||
$query['columnselection_pref'] = 'infolog.index.rows';
|
||||
$query['default_cols'] = '!cat_id,info_datemodified,info_used_time_info_planned_time_info_replanned_time,info_id';
|
||||
$query['default_cols'] = '!cat_id,info_datemodified,info_used_time_info_planned_time,info_used_time_info_planned_time_info_replanned_time,info_id';
|
||||
}
|
||||
// set old show_times pref, that get_info calculates the cumulated time of the timesheets (we only check used&planned to work for both time cols)
|
||||
$this->prefs['show_times'] = strpos($this->prefs['nextmatch-'.$query['columnselection_pref']],'info_used_time_info_planned_time') !== false;
|
||||
// set old show_times pref, that get_info calculates the cumulated time of the timesheets
|
||||
$this->prefs['show_times'] = strpos($this->prefs['nextmatch-'.$query['columnselection_pref']],'info_used_time_info_planned_time_info_replanned_time') !== false;
|
||||
|
||||
// query all links and sub counts in one go
|
||||
if ($infos && !$query['csv_export'])
|
||||
@ -428,6 +421,9 @@ class infolog_ui
|
||||
$GLOBALS['egw_info']['flags']['app_header'] .= ': '.$title;
|
||||
}
|
||||
}
|
||||
// disable filemanager icon, if user has no access to it
|
||||
$readonlys['filemanager/navbar'] = !isset($GLOBALS['egw_info']['user']['apps']['filemanager']);
|
||||
|
||||
return $query['total'];
|
||||
}
|
||||
|
||||
@ -553,7 +549,9 @@ class infolog_ui
|
||||
}
|
||||
break;
|
||||
case 'close':
|
||||
$this->close($do_id,$called_as);
|
||||
$closesingle=true;
|
||||
case 'close_all':
|
||||
$this->close($do_id,$called_as,$closesingle);
|
||||
break;
|
||||
case 'sp':
|
||||
return $this->edit(0,'sp',$do_id,'',$called_as);
|
||||
@ -639,6 +637,13 @@ class infolog_ui
|
||||
{
|
||||
$values['css'] = '<style type="text/css">@import url('.$GLOBALS['egw_info']['server']['webserver_url'].'/infolog/templates/default/app.css);'."</style>";
|
||||
}
|
||||
// add scrollbar to long describtion, if user choose so in his prefs
|
||||
if ($this->prefs['limit_des_lines'] > 0 || (string)$this->prefs['limit_des_lines'] == '')
|
||||
{
|
||||
$values['css'] .= '<style type="text/css">@media screen { .infoDes { max-height: '.
|
||||
(($this->prefs['limit_des_lines'] ? $this->prefs['limit_des_lines'] : 5) * 1.35). // dono why em is not real lines
|
||||
'em; overflow: auto; }}</style>';
|
||||
}
|
||||
return $this->tmpl->exec('infolog.infolog_ui.index',$values,array(
|
||||
'info_type' => $this->bo->enums['type'],
|
||||
),$readonlys,$persist,$return_html ? -1 : 0);
|
||||
@ -649,29 +654,45 @@ class infolog_ui
|
||||
*
|
||||
* @param int|array $values=0 info_id (default _GET[info_id])
|
||||
* @param string $referer=''
|
||||
* @param boolean $closesingle=false
|
||||
*/
|
||||
function close($values=0,$referer='')
|
||||
function close($values=0,$referer='',$closesingle=false)
|
||||
{
|
||||
//echo "<p>".__METHOD__."($values,$referer)</p>\n";
|
||||
//echo "<p>".__METHOD__."($values,$referer,$closeall)</p>\n";
|
||||
$info_id = (int) (is_array($values) ? $values['info_id'] : ($values ? $values : $_GET['info_id']));
|
||||
$referer = is_array($values) ? $values['referer'] : $referer;
|
||||
|
||||
if ($info_id)
|
||||
{
|
||||
$info = $this->bo->read($info_id);
|
||||
#_debug_array($info);
|
||||
$status = $info['info_status'];
|
||||
// closed stati assumed array('done','billed','cancelled')
|
||||
if (isset($this->bo->status[$info['info_type']]['done'])) {
|
||||
$status ='done';
|
||||
} elseif (isset($this->bo->status[$info['info_type']]['billed'])) {
|
||||
$status ='billed';
|
||||
} elseif (isset($this->bo->status[$info['info_type']]['cancelled'])) {
|
||||
$status ='cancelled';
|
||||
}
|
||||
#_debug_array($status);
|
||||
$values = array(
|
||||
'info_id' => $info_id,
|
||||
'info_status' => 'done',
|
||||
'info_type' => $info['info_type'],
|
||||
'info_status' => $status,
|
||||
'info_percent'=> 100,
|
||||
'info_datecompleted' => $this->bo->now_su,
|
||||
);
|
||||
$this->bo->write($values);
|
||||
|
||||
$query = array('action'=>'sp','action_id'=>$info_id);
|
||||
foreach((array)$this->bo->search($query) as $info)
|
||||
{
|
||||
if ($info['info_id_parent'] == $info_id) // search also returns linked entries!
|
||||
if (!$closesingle) {
|
||||
foreach((array)$this->bo->search($query) as $info)
|
||||
{
|
||||
$this->close($info['info_id'],$referer); // we call ourselfs recursive to process subs from subs too
|
||||
if ($info['info_id_parent'] == $info_id) // search also returns linked entries!
|
||||
{
|
||||
$this->close($info['info_id'],$referer,$closeall); // we call ourselfs recursive to process subs from subs too
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -953,6 +974,7 @@ class infolog_ui
|
||||
}
|
||||
$parent = $this->bo->so->data;
|
||||
$content['info_id'] = $info_id = 0;
|
||||
$content['info_uid'] = ''; // ensure that we have our own UID
|
||||
$content['info_owner'] = $this->user;
|
||||
$content['info_id_parent'] = $parent['info_id'];
|
||||
/*
|
||||
@ -1281,10 +1303,9 @@ class infolog_ui
|
||||
|
||||
if ($_POST['responsible_edit'])
|
||||
{
|
||||
$extra = array_intersect((array)$_POST['responsible_edit'],array_keys($fields));
|
||||
$this->bo->responsible_edit = array_merge($this->bo->responsible_edit,$extra);
|
||||
$extra = array_intersect($_POST['responsible_edit'],array_keys($fields));
|
||||
config::save_value('responsible_edit',$this->bo->responsible_edit = array_merge($this->bo->responsible_edit,$extra),'infolog');
|
||||
}
|
||||
config::save_value('responsible_edit',$this->bo->responsible_edit,'infolog');
|
||||
config::save_value('implicit_rights',$this->bo->implicit_rights = $_POST['implicit_rights'] == 'edit' ? 'edit' : 'read','infolog');
|
||||
config::save_value('history',$this->bo->history = $_POST['history'],'infolog');
|
||||
}
|
||||
@ -1413,7 +1434,6 @@ class infolog_ui
|
||||
#continue;
|
||||
}
|
||||
$message .= $bofelamimail->wordwrap($value,75,"\n");
|
||||
#$message .= $bodyAppend;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1496,7 +1516,7 @@ class infolog_ui
|
||||
|
||||
$GLOBALS['egw']->translation->add_app('infolog');
|
||||
|
||||
$GLOBALS['egw_info']['etemplate']['hooked'] = True;
|
||||
$GLOBALS['egw_info']['etemplate']['hooked'] = true;
|
||||
$this->index(0,$app,$args[$view_id],array(
|
||||
'menuaction' => $view,
|
||||
isset($view_id2) ? $view_id2 : $view_id => $args[$view_id]
|
||||
|
@ -148,11 +148,11 @@ class categories
|
||||
|
||||
if (!empty($order) && preg_match('/^[a-zA-Z_(), ]+$/',$order) && (empty($sort) || preg_match('/^(ASC|DESC|asc|desc)$/',$sort)))
|
||||
{
|
||||
$ordermethod = 'ORDER BY '.$order.' '.$sort;
|
||||
$ordermethod = 'ORDER BY '.$order.' '.$sort . ', cat_access ASC';
|
||||
}
|
||||
else
|
||||
{
|
||||
$ordermethod = 'ORDER BY cat_main, cat_level, cat_name ASC';
|
||||
$ordermethod = 'ORDER BY cat_main, cat_level, cat_name, cat_access ASC';
|
||||
}
|
||||
|
||||
if ($this->account_id == '-1')
|
||||
@ -167,7 +167,7 @@ class categories
|
||||
}
|
||||
else
|
||||
{
|
||||
$grant_cats = ' cat_owner=' . $this->account_id . ' OR cat_owner=-1 ';
|
||||
$grant_cats = ' (cat_owner=' . $this->account_id . ' OR cat_owner=-1) ';
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,11 +235,11 @@ class categories
|
||||
|
||||
if (!empty($order) && preg_match('/^[a-zA-Z_, ]+$/',$order) && (empty($sort) || preg_match('/^(ASC|DESC|asc|desc)$/',$sort)))
|
||||
{
|
||||
$ordermethod = 'ORDER BY '.$order.' '.$sort;
|
||||
$ordermethod = 'ORDER BY '.$order.' '.$sort . ', cat_access ASC';
|
||||
}
|
||||
else
|
||||
{
|
||||
$ordermethod = ' ORDER BY cat_name ASC';
|
||||
$ordermethod = ' ORDER BY cat_name ASC, cat_access ASC';
|
||||
}
|
||||
|
||||
if ($this->account_id == '-1')
|
||||
@ -254,7 +254,7 @@ class categories
|
||||
}
|
||||
else
|
||||
{
|
||||
$grant_cats = " cat_owner='" . $this->account_id . "' OR cat_owner='-1' ";
|
||||
$grant_cats = " (cat_owner='" . $this->account_id . "' OR cat_owner='-1') ";
|
||||
}
|
||||
}
|
||||
$parent_select = ' AND cat_parent=' . (int)$parent_id;
|
||||
@ -403,6 +403,14 @@ class categories
|
||||
{
|
||||
$s .= ' ♦';
|
||||
}
|
||||
elseif ($cat['owner'] != $this->account_id)
|
||||
{
|
||||
$s .= '<' . $GLOBALS['egw']->accounts->id2name($cat['owner'], 'account_fullname') . '>';
|
||||
}
|
||||
elseif ($cat['access'] == 'private')
|
||||
{
|
||||
$s .= ' ♥';
|
||||
}
|
||||
$s .= '</option>' . "\n";
|
||||
}
|
||||
break;
|
||||
@ -494,6 +502,7 @@ class categories
|
||||
if ($modify_subs)
|
||||
{
|
||||
$new_parent = $this->id2name($cat_id,'parent');
|
||||
$new_main = 0;
|
||||
|
||||
foreach ((array) $this->return_sorted_array('',False,'','','',False, $cat_id) as $cat)
|
||||
{
|
||||
@ -683,17 +692,18 @@ class categories
|
||||
/**
|
||||
* check if a category id and/or name exists, if id AND name are given the check is for a category with same name and different id (!)
|
||||
*
|
||||
* @param string $type subs or mains
|
||||
* @param string $cat_name='' category name
|
||||
* @param int $cat_id=0 category id
|
||||
* @param int $parent=0 category id of parent
|
||||
* @param string $type subs or mains
|
||||
* @param string $cat_name='' category name
|
||||
* @param int $cat_id=0 category id
|
||||
* @param int $parent=0 category id of parent
|
||||
* @param boolean $private=false limit to private categories
|
||||
* @return int/boolean cat_id or false if cat not exists
|
||||
*/
|
||||
function exists($type,$cat_name = '',$cat_id = 0,$parent = 0)
|
||||
function exists($type,$cat_name = '',$cat_id = 0,$parent = 0, $private = false)
|
||||
{
|
||||
static $cache = array(); // a litle bit of caching
|
||||
|
||||
if (isset($cache[$type][$cat_name][$cat_id])) return $cache[$type][$cat_name][$cat_id];
|
||||
if (isset($cache[$type][$cat_name][$cat_id][$private])) return $cache[$type][$cat_name][$cat_id][$private];
|
||||
|
||||
$where = array($this->filter($type));
|
||||
|
||||
@ -707,9 +717,21 @@ class categories
|
||||
{
|
||||
$where['cat_id'] = $cat_id;
|
||||
}
|
||||
if ($parent) $where['cat_parent'] = $parent;
|
||||
|
||||
return $cache[$type][$cat_name][$cat_id] = $this->db->select($this->table,'cat_id',$where,__LINE__,__FILE__)->fetchSingle();
|
||||
if ($parent){
|
||||
$where['cat_parent'] = $parent;
|
||||
}
|
||||
$grant_cats = "(";
|
||||
if ($private) {
|
||||
$grant_cats .= "cat_owner='" . $this->account_id . "' AND cat_access='private'";
|
||||
} else {
|
||||
$grant_cats .= "cat_owner='" . $this->account_id
|
||||
. "' OR cat_owner='-1' OR cat_access='public'";
|
||||
if (is_array($this->grants)) {
|
||||
$grant_cats .= " AND cat_owner IN (" . implode(',',array_keys($this->grants)) . ")";
|
||||
}
|
||||
}
|
||||
$where[] = $grant_cats . ")";
|
||||
return $cache[$type][$cat_name][$cat_id][$private] = $this->db->select($this->table,'cat_id',$where,__LINE__,__FILE__)->fetchSingle();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* eGW API - content history class
|
||||
*
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke [lkneschke@linux-at-work.de]
|
||||
* @copyright Lars Kneschke 2005
|
||||
@ -30,7 +30,7 @@ class contenthistory
|
||||
{
|
||||
$this->db = $GLOBALS['egw']->db;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mark mapping as expired
|
||||
*
|
||||
@ -39,7 +39,7 @@ class contenthistory
|
||||
*
|
||||
* @param string $_appName the appname example: infolog_notes
|
||||
* @param int $_id the internal egwapp content id
|
||||
* @return bool
|
||||
* @return bool
|
||||
*/
|
||||
function expireMapping($_appName, $_id)
|
||||
{
|
||||
@ -57,13 +57,13 @@ class contenthistory
|
||||
*
|
||||
* @param string$_appName the appname example: infolog_notes
|
||||
* @param string $_action can be modify, add or delete
|
||||
* @param string $_ts timestamp where to start searching from
|
||||
* @param string $_ts timestamp where to start searching from
|
||||
* @return array containing contentIds with changes
|
||||
*/
|
||||
function getHistory($_appName, $_action, $_ts)
|
||||
{
|
||||
$where = array('sync_appname' => $_appName);
|
||||
|
||||
|
||||
switch($_action)
|
||||
{
|
||||
case 'modify':
|
||||
@ -84,10 +84,10 @@ class contenthistory
|
||||
{
|
||||
$idList[] = $row['sync_contentid'];
|
||||
}
|
||||
|
||||
|
||||
return $idList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* when got a entry last added/modified/deleted
|
||||
*
|
||||
@ -122,14 +122,14 @@ class contenthistory
|
||||
}
|
||||
return $ts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update a timestamp for action
|
||||
*
|
||||
* @param string $_appName the appname example: infolog_notes
|
||||
* @param int $_id the app internal content id
|
||||
* @param string $_action can be modify, add or delete
|
||||
* @param string $_ts timestamp where to start searching from
|
||||
* @param string $_ts timestamp where to start searching from
|
||||
* @return boolean returns allways true
|
||||
*/
|
||||
function updateTimeStamp($_appName, $_id, $_action, $_ts)
|
||||
@ -146,7 +146,7 @@ class contenthistory
|
||||
case 'add':
|
||||
$this->db->insert(self::TABLE,$newData,array(),__LINE__,__FILE__);
|
||||
break;
|
||||
|
||||
|
||||
case 'modify':
|
||||
case 'delete':
|
||||
// first check that this entry got ever added to database already
|
||||
@ -163,7 +163,7 @@ class contenthistory
|
||||
// now update the time stamp
|
||||
$newData = array (
|
||||
'sync_changedby' => $GLOBALS['egw_info']['user']['account_id'],
|
||||
$_action == 'modify' ? 'sync_modified' : 'sync_deleted' => $_ts ,
|
||||
$_action == 'delete' ? 'sync_deleted' : 'sync_modified' => $this->db->to_timestamp($_ts),
|
||||
);
|
||||
$this->db->update(self::TABLE, $newData, $where,__LINE__,__FILE__);
|
||||
break;
|
||||
|
@ -1453,13 +1453,14 @@ class egw_session
|
||||
* @param int $start
|
||||
* @param string $sort='session_dla' session_lid, session_id, session_started, session_logintime, session_action, or (default) session_dla
|
||||
* @param string $order='DESC' ASC or DESC
|
||||
* @param boolean $all_no_sort=false skip sorting and limiting to maxmatchs if set to true
|
||||
* @return array with sessions (values for keys as in $sort) or array() if not supported by session-handler
|
||||
*/
|
||||
public static function session_list($start,$sort='DESC',$order='session_dla')
|
||||
{
|
||||
if (method_exists(self::$session_handler,'session_list'))
|
||||
{
|
||||
return call_user_func(array(self::$session_handler,'session_list'),$start,$sort,$order);
|
||||
return call_user_func(array(self::$session_handler,'session_list'),$start,$sort,$order,$all_no_sort);
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
@ -34,9 +34,10 @@ class egw_session_files
|
||||
* @param int $start
|
||||
* @param string $sort='session_dla' session_lid, session_id, session_started, session_logintime, session_action, or (default) session_dla
|
||||
* @param string $order='DESC' ASC or DESC
|
||||
* @param boolean $all_no_sort=false skip sorting and limiting to maxmatchs if set to true
|
||||
* @return array with sessions (values for keys as in $sort) or array() if not supported by session-handler
|
||||
*/
|
||||
public static function session_list($start,$sort='DESC',$order='session_dla',$all_no_sort = False)
|
||||
public static function session_list($start,$sort='DESC',$order='session_dla',$all_no_sort=false)
|
||||
{
|
||||
if (session_module_name() != 'files')
|
||||
{
|
||||
|
@ -289,14 +289,13 @@ class Browser_imode {
|
||||
var $_manufacturer;
|
||||
var $_httpversion;
|
||||
var $_cache = 5;
|
||||
var $_extra;
|
||||
|
||||
/**
|
||||
* 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']);
|
||||
* $ua = new Browser_imode($_SERVEr['HTTP_USER_AGENT']);
|
||||
*
|
||||
* @param string $input The user agent to match.
|
||||
*/
|
||||
|
769
phpgwapi/inc/horde/Horde/Date.php
Normal file
769
phpgwapi/inc/horde/Horde/Date.php
Normal file
@ -0,0 +1,769 @@
|
||||
<?php
|
||||
|
||||
define('HORDE_DATE_SUNDAY', 0);
|
||||
define('HORDE_DATE_MONDAY', 1);
|
||||
define('HORDE_DATE_TUESDAY', 2);
|
||||
define('HORDE_DATE_WEDNESDAY', 3);
|
||||
define('HORDE_DATE_THURSDAY', 4);
|
||||
define('HORDE_DATE_FRIDAY', 5);
|
||||
define('HORDE_DATE_SATURDAY', 6);
|
||||
|
||||
define('HORDE_DATE_MASK_SUNDAY', 1);
|
||||
define('HORDE_DATE_MASK_MONDAY', 2);
|
||||
define('HORDE_DATE_MASK_TUESDAY', 4);
|
||||
define('HORDE_DATE_MASK_WEDNESDAY', 8);
|
||||
define('HORDE_DATE_MASK_THURSDAY', 16);
|
||||
define('HORDE_DATE_MASK_FRIDAY', 32);
|
||||
define('HORDE_DATE_MASK_SATURDAY', 64);
|
||||
define('HORDE_DATE_MASK_WEEKDAYS', 62);
|
||||
define('HORDE_DATE_MASK_WEEKEND', 65);
|
||||
define('HORDE_DATE_MASK_ALLDAYS', 127);
|
||||
|
||||
define('HORDE_DATE_MASK_SECOND', 1);
|
||||
define('HORDE_DATE_MASK_MINUTE', 2);
|
||||
define('HORDE_DATE_MASK_HOUR', 4);
|
||||
define('HORDE_DATE_MASK_DAY', 8);
|
||||
define('HORDE_DATE_MASK_MONTH', 16);
|
||||
define('HORDE_DATE_MASK_YEAR', 32);
|
||||
define('HORDE_DATE_MASK_ALLPARTS', 63);
|
||||
|
||||
/**
|
||||
* Horde Date wrapper/logic class, including some calculation
|
||||
* functions.
|
||||
*
|
||||
* $Horde: framework/Date/Date.php,v 1.8.10.18 2008/09/17 08:46:04 jan Exp $
|
||||
*
|
||||
* @package Horde_Date
|
||||
*/
|
||||
class Horde_Date {
|
||||
|
||||
/**
|
||||
* Year
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $year;
|
||||
|
||||
/**
|
||||
* Month
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $month;
|
||||
|
||||
/**
|
||||
* Day
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $mday;
|
||||
|
||||
/**
|
||||
* Hour
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $hour = 0;
|
||||
|
||||
/**
|
||||
* Minute
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $min = 0;
|
||||
|
||||
/**
|
||||
* Second
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $sec = 0;
|
||||
|
||||
/**
|
||||
* Internally supported strftime() specifiers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_supportedSpecs = '%CdDeHImMnRStTyY';
|
||||
|
||||
/**
|
||||
* Build a new date object. If $date contains date parts, use them to
|
||||
* initialize the object.
|
||||
*
|
||||
* Recognized formats:
|
||||
* - arrays with keys 'year', 'month', 'mday', 'day' (since Horde 3.2),
|
||||
* 'hour', 'min', 'minute' (since Horde 3.2), 'sec'
|
||||
* - objects with properties 'year', 'month', 'mday', 'hour', 'min', 'sec'
|
||||
* - yyyy-mm-dd hh:mm:ss (since Horde 3.1)
|
||||
* - yyyymmddhhmmss (since Horde 3.1)
|
||||
* - yyyymmddThhmmssZ (since Horde 3.1.4)
|
||||
* - unix timestamps
|
||||
*/
|
||||
function Horde_Date($date = null)
|
||||
{
|
||||
if (function_exists('nl_langinfo')) {
|
||||
$this->_supportedSpecs .= 'bBpxX';
|
||||
}
|
||||
|
||||
if (is_array($date) || is_object($date)) {
|
||||
foreach ($date as $key => $val) {
|
||||
if (in_array($key, array('year', 'month', 'mday', 'hour', 'min', 'sec'))) {
|
||||
$this->$key = (int)$val;
|
||||
}
|
||||
}
|
||||
|
||||
// If $date['day'] is present and numeric we may have been passed
|
||||
// a Horde_Form_datetime array.
|
||||
if (is_array($date) && isset($date['day']) &&
|
||||
is_numeric($date['day'])) {
|
||||
$this->mday = (int)$date['day'];
|
||||
}
|
||||
// 'minute' key also from Horde_Form_datetime
|
||||
if (is_array($date) && isset($date['minute'])) {
|
||||
$this->min = $date['minute'];
|
||||
}
|
||||
} elseif (!is_null($date)) {
|
||||
// Match YYYY-MM-DD HH:MM:SS, YYYYMMDDHHMMSS and YYYYMMDD'T'HHMMSS'Z'.
|
||||
if (preg_match('/(\d{4})-?(\d{2})-?(\d{2})T? ?(\d{2}):?(\d{2}):?(\d{2})Z?/', $date, $parts)) {
|
||||
$this->year = (int)$parts[1];
|
||||
$this->month = (int)$parts[2];
|
||||
$this->mday = (int)$parts[3];
|
||||
$this->hour = (int)$parts[4];
|
||||
$this->min = (int)$parts[5];
|
||||
$this->sec = (int)$parts[6];
|
||||
} else {
|
||||
// Try as a timestamp.
|
||||
$parts = @getdate($date);
|
||||
if ($parts) {
|
||||
$this->year = $parts['year'];
|
||||
$this->month = $parts['mon'];
|
||||
$this->mday = $parts['mday'];
|
||||
$this->hour = $parts['hours'];
|
||||
$this->min = $parts['minutes'];
|
||||
$this->sec = $parts['seconds'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
*/
|
||||
function isLeapYear($year)
|
||||
{
|
||||
if (strlen($year) != 4 || preg_match('/\D/', $year)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the day of the year (1-366) that corresponds to the
|
||||
* first day of the given week.
|
||||
*
|
||||
* TODO: with PHP 5.1+, see http://derickrethans.nl/calculating_start_and_end_dates_of_a_week.php
|
||||
*
|
||||
* @param integer $week The week of the year to find the first day of.
|
||||
* @param integer $year The year to calculate for.
|
||||
*
|
||||
* @return integer The day of the year of the first day of the given week.
|
||||
*/
|
||||
function firstDayOfWeek($week, $year)
|
||||
{
|
||||
$jan1 = new Horde_Date(array('year' => $year, 'month' => 1, 'mday' => 1));
|
||||
$start = $jan1->dayOfWeek();
|
||||
if ($start > HORDE_DATE_THURSDAY) {
|
||||
$start -= 7;
|
||||
}
|
||||
return (($week * 7) - (7 + $start)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
*/
|
||||
function daysInMonth($month, $year)
|
||||
{
|
||||
if ($month == 2) {
|
||||
if (Horde_Date::isLeapYear($year)) {
|
||||
return 29;
|
||||
} else {
|
||||
return 28;
|
||||
}
|
||||
} elseif ($month == 4 || $month == 6 || $month == 9 || $month == 11) {
|
||||
return 30;
|
||||
} else {
|
||||
return 31;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the day of the week (0 = Sunday, 6 = Saturday) of this
|
||||
* object's date.
|
||||
*
|
||||
* @return integer The day of the week.
|
||||
*/
|
||||
function dayOfWeek()
|
||||
{
|
||||
if ($this->month > 2) {
|
||||
$month = $this->month - 2;
|
||||
$year = $this->year;
|
||||
} else {
|
||||
$month = $this->month + 10;
|
||||
$year = $this->year - 1;
|
||||
}
|
||||
|
||||
$day = (floor((13 * $month - 1) / 5) +
|
||||
$this->mday + ($year % 100) +
|
||||
floor(($year % 100) / 4) +
|
||||
floor(($year / 100) / 4) - 2 *
|
||||
floor($year / 100) + 77);
|
||||
|
||||
return (int)($day - 7 * floor($day / 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the day number of the year (1 to 365/366).
|
||||
*
|
||||
* @return integer The day of the year.
|
||||
*/
|
||||
function dayOfYear()
|
||||
{
|
||||
$monthTotals = array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
|
||||
$dayOfYear = $this->mday + $monthTotals[$this->month - 1];
|
||||
if (Horde_Date::isLeapYear($this->year) && $this->month > 2) {
|
||||
++$dayOfYear;
|
||||
}
|
||||
|
||||
return $dayOfYear;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the week of the month.
|
||||
*
|
||||
* @since Horde 3.2
|
||||
*
|
||||
* @return integer The week number.
|
||||
*/
|
||||
function weekOfMonth()
|
||||
{
|
||||
return ceil($this->mday / 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the week of the year, first Monday is first day of first week.
|
||||
*
|
||||
* @return integer The week number.
|
||||
*/
|
||||
function weekOfYear()
|
||||
{
|
||||
return $this->format('W');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of weeks in the given year (52 or 53).
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param integer $year The year to count the number of weeks in.
|
||||
*
|
||||
* @return integer $numWeeks The number of weeks in $year.
|
||||
*/
|
||||
function weeksInYear($year)
|
||||
{
|
||||
// Find the last Thursday of the year.
|
||||
$day = 31;
|
||||
$date = new Horde_Date(array('year' => $year, 'month' => 12, 'mday' => $day, 'hour' => 0, 'min' => 0, 'sec' => 0));
|
||||
while ($date->dayOfWeek() != HORDE_DATE_THURSDAY) {
|
||||
--$date->mday;
|
||||
}
|
||||
return $date->weekOfYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date of this object to the $nth weekday of $weekday.
|
||||
*
|
||||
* @param integer $weekday The day of the week (0 = Sunday, etc).
|
||||
* @param integer $nth The $nth $weekday to set to (defaults to 1).
|
||||
*/
|
||||
function setNthWeekday($weekday, $nth = 1)
|
||||
{
|
||||
if ($weekday < HORDE_DATE_SUNDAY || $weekday > HORDE_DATE_SATURDAY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->mday = 1;
|
||||
$first = $this->dayOfWeek();
|
||||
if ($weekday < $first) {
|
||||
$this->mday = 8 + $weekday - $first;
|
||||
} else {
|
||||
$this->mday = $weekday - $first + 1;
|
||||
}
|
||||
$this->mday += 7 * $nth - 7;
|
||||
|
||||
$this->correct();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function dump($prefix = '')
|
||||
{
|
||||
echo ($prefix ? $prefix . ': ' : '') . $this->year . '-' . $this->month . '-' . $this->mday . "<br />\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the date currently represented by this object a valid date?
|
||||
*
|
||||
* @return boolean Validity, counting leap years, etc.
|
||||
*/
|
||||
function isValid()
|
||||
{
|
||||
if ($this->year < 0 || $this->year > 9999) {
|
||||
return false;
|
||||
}
|
||||
return checkdate($this->month, $this->mday, $this->year);
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct any over- or underflows in any of the date's members.
|
||||
*
|
||||
* @param integer $mask We may not want to correct some overflows.
|
||||
*/
|
||||
function correct($mask = HORDE_DATE_MASK_ALLPARTS)
|
||||
{
|
||||
if ($mask & HORDE_DATE_MASK_SECOND) {
|
||||
while ($this->sec < 0) {
|
||||
--$this->min;
|
||||
$this->sec += 60;
|
||||
}
|
||||
while ($this->sec > 59) {
|
||||
++$this->min;
|
||||
$this->sec -= 60;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mask & HORDE_DATE_MASK_MINUTE) {
|
||||
while ($this->min < 0) {
|
||||
--$this->hour;
|
||||
$this->min += 60;
|
||||
}
|
||||
while ($this->min > 59) {
|
||||
++$this->hour;
|
||||
$this->min -= 60;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mask & HORDE_DATE_MASK_HOUR) {
|
||||
while ($this->hour < 0) {
|
||||
--$this->mday;
|
||||
$this->hour += 24;
|
||||
}
|
||||
while ($this->hour > 23) {
|
||||
++$this->mday;
|
||||
$this->hour -= 24;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mask & HORDE_DATE_MASK_MONTH) {
|
||||
while ($this->month > 12) {
|
||||
++$this->year;
|
||||
$this->month -= 12;
|
||||
}
|
||||
while ($this->month < 1) {
|
||||
--$this->year;
|
||||
$this->month += 12;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mask & HORDE_DATE_MASK_DAY) {
|
||||
while ($this->mday > Horde_Date::daysInMonth($this->month, $this->year)) {
|
||||
$this->mday -= Horde_Date::daysInMonth($this->month, $this->year);
|
||||
++$this->month;
|
||||
$this->correct(HORDE_DATE_MASK_MONTH);
|
||||
}
|
||||
while ($this->mday < 1) {
|
||||
--$this->month;
|
||||
$this->correct(HORDE_DATE_MASK_MONTH);
|
||||
$this->mday += Horde_Date::daysInMonth($this->month, $this->year);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this date to another date object to see which one is
|
||||
* greater (later). Assumes that the dates are in the same
|
||||
* timezone.
|
||||
*
|
||||
* @param mixed $date The date to compare to.
|
||||
*
|
||||
* @return integer == 0 if the dates are equal
|
||||
* >= 1 if this date is greater (later)
|
||||
* <= -1 if the other date is greater (later)
|
||||
*/
|
||||
function compareDate($date)
|
||||
{
|
||||
if (!is_a($date, 'Horde_Date')) {
|
||||
$date = new Horde_Date($date);
|
||||
}
|
||||
|
||||
if ($this->year != $date->year) {
|
||||
return $this->year - $date->year;
|
||||
}
|
||||
if ($this->month != $date->month) {
|
||||
return $this->month - $date->month;
|
||||
}
|
||||
|
||||
return $this->mday - $date->mday;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this to another date object by time, to see which one
|
||||
* is greater (later). Assumes that the dates are in the same
|
||||
* timezone.
|
||||
*
|
||||
* @param mixed $date The date to compare to.
|
||||
*
|
||||
* @return integer == 0 if the dates are equal
|
||||
* >= 1 if this date is greater (later)
|
||||
* <= -1 if the other date is greater (later)
|
||||
*/
|
||||
function compareTime($date)
|
||||
{
|
||||
if (!is_a($date, 'Horde_Date')) {
|
||||
$date = new Horde_Date($date);
|
||||
}
|
||||
|
||||
if ($this->hour != $date->hour) {
|
||||
return $this->hour - $date->hour;
|
||||
}
|
||||
if ($this->min != $date->min) {
|
||||
return $this->min - $date->min;
|
||||
}
|
||||
|
||||
return $this->sec - $date->sec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this to another date object, including times, to see
|
||||
* which one is greater (later). Assumes that the dates are in the
|
||||
* same timezone.
|
||||
*
|
||||
* @param mixed $date The date to compare to.
|
||||
*
|
||||
* @return integer == 0 if the dates are equal
|
||||
* >= 1 if this date is greater (later)
|
||||
* <= -1 if the other date is greater (later)
|
||||
*/
|
||||
function compareDateTime($date)
|
||||
{
|
||||
if (!is_a($date, 'Horde_Date')) {
|
||||
$date = new Horde_Date($date);
|
||||
}
|
||||
|
||||
if ($diff = $this->compareDate($date)) {
|
||||
return $diff;
|
||||
}
|
||||
|
||||
return $this->compareTime($date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time offset for local time zone.
|
||||
*
|
||||
* @param boolean $colon Place a colon between hours and minutes?
|
||||
*
|
||||
* @return string Timezone offset as a string in the format +HH:MM.
|
||||
*/
|
||||
function tzOffset($colon = true)
|
||||
{
|
||||
$secs = $this->format('Z');
|
||||
|
||||
if ($secs < 0) {
|
||||
$sign = '-';
|
||||
$secs = -$secs;
|
||||
} else {
|
||||
$sign = '+';
|
||||
}
|
||||
$colon = $colon ? ':' : '';
|
||||
$mins = intval(($secs + 30) / 60);
|
||||
return sprintf('%s%02d%s%02d',
|
||||
$sign, $mins / 60, $colon, $mins % 60);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unix timestamp representation of this date.
|
||||
*
|
||||
* @return integer A unix timestamp.
|
||||
*/
|
||||
function timestamp()
|
||||
{
|
||||
if (class_exists('DateTime')) {
|
||||
return $this->format('U');
|
||||
} else {
|
||||
return Horde_Date::_mktime($this->hour, $this->min, $this->sec, $this->month, $this->mday, $this->year);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unix timestamp representation of this date, 12:00am.
|
||||
*
|
||||
* @return integer A unix timestamp.
|
||||
*/
|
||||
function datestamp()
|
||||
{
|
||||
if (class_exists('DateTime')) {
|
||||
$dt = new DateTime();
|
||||
$dt->setDate($this->year, $this->month, $this->mday);
|
||||
$dt->setTime(0, 0, 0);
|
||||
return $dt->format('U');
|
||||
} else {
|
||||
return Horde_Date::_mktime(0, 0, 0, $this->month, $this->mday, $this->year);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time using the specifiers available in date() or in the DateTime
|
||||
* class' format() method.
|
||||
*
|
||||
* @since Horde 3.3
|
||||
*
|
||||
* @param string $format
|
||||
*
|
||||
* @return string Formatted time.
|
||||
*/
|
||||
function format($format)
|
||||
{
|
||||
if (class_exists('DateTime')) {
|
||||
$dt = new DateTime();
|
||||
$dt->setDate($this->year, $this->month, $this->mday);
|
||||
$dt->setTime($this->hour, $this->min, $this->sec);
|
||||
return $dt->format($format);
|
||||
} else {
|
||||
return date($format, $this->timestamp());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time in ISO-8601 format. Works correctly since Horde 3.2.
|
||||
*
|
||||
* @return string Date and time in ISO-8601 format.
|
||||
*/
|
||||
function iso8601DateTime()
|
||||
{
|
||||
return $this->rfc3339DateTime() . $this->tzOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time in RFC 2822 format.
|
||||
*
|
||||
* @return string Date and time in RFC 2822 format.
|
||||
*/
|
||||
function rfc2822DateTime()
|
||||
{
|
||||
return $this->format('D, j M Y H:i:s') . ' ' . $this->tzOffset(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time in RFC 3339 format.
|
||||
*
|
||||
* @since Horde 3.1
|
||||
*
|
||||
* @return string Date and time in RFC 3339 format. The seconds part has
|
||||
* been added with Horde 3.2.
|
||||
*/
|
||||
function rfc3339DateTime()
|
||||
{
|
||||
return $this->format('Y-m-d\TH:i:s');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time to standard 'ctime' format.
|
||||
*
|
||||
* @return string Date and time.
|
||||
*/
|
||||
function cTime()
|
||||
{
|
||||
return $this->format('D M j H:i:s Y');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date and time using strftime() format.
|
||||
*
|
||||
* @since Horde 3.1
|
||||
*
|
||||
* @return string strftime() formatted date and time.
|
||||
*/
|
||||
function strftime($format)
|
||||
{
|
||||
if (preg_match('/%[^' . $this->_supportedSpecs . ']/', $format)) {
|
||||
return strftime($format, $this->timestamp());
|
||||
} else {
|
||||
return $this->_strftime($format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date and time using a limited set of the strftime() format.
|
||||
*
|
||||
* @return string strftime() formatted date and time.
|
||||
*/
|
||||
function _strftime($format)
|
||||
{
|
||||
if (preg_match('/%[bBpxX]/', $format)) {
|
||||
require_once 'Horde/NLS.php';
|
||||
}
|
||||
|
||||
return preg_replace(
|
||||
array('/%b/e',
|
||||
'/%B/e',
|
||||
'/%C/e',
|
||||
'/%d/e',
|
||||
'/%D/e',
|
||||
'/%e/e',
|
||||
'/%H/e',
|
||||
'/%I/e',
|
||||
'/%m/e',
|
||||
'/%M/e',
|
||||
'/%n/',
|
||||
'/%p/e',
|
||||
'/%R/e',
|
||||
'/%S/e',
|
||||
'/%t/',
|
||||
'/%T/e',
|
||||
'/%x/e',
|
||||
'/%X/e',
|
||||
'/%y/e',
|
||||
'/%Y/',
|
||||
'/%%/'),
|
||||
array('$this->_strftime(NLS::getLangInfo(constant(\'ABMON_\' . (int)$this->month)))',
|
||||
'$this->_strftime(NLS::getLangInfo(constant(\'MON_\' . (int)$this->month)))',
|
||||
'(int)($this->year / 100)',
|
||||
'sprintf(\'%02d\', $this->mday)',
|
||||
'$this->_strftime(\'%m/%d/%y\')',
|
||||
'sprintf(\'%2d\', $this->mday)',
|
||||
'sprintf(\'%02d\', $this->hour)',
|
||||
'sprintf(\'%02d\', $this->hour == 0 ? 12 : ($this->hour > 12 ? $this->hour - 12 : $this->hour))',
|
||||
'sprintf(\'%02d\', $this->month)',
|
||||
'sprintf(\'%02d\', $this->min)',
|
||||
"\n",
|
||||
'$this->_strftime(NLS::getLangInfo($this->hour < 12 ? AM_STR : PM_STR))',
|
||||
'$this->_strftime(\'%H:%M\')',
|
||||
'sprintf(\'%02d\', $this->sec)',
|
||||
"\t",
|
||||
'$this->_strftime(\'%H:%M:%S\')',
|
||||
'$this->_strftime(NLS::getLangInfo(D_FMT))',
|
||||
'$this->_strftime(NLS::getLangInfo(T_FMT))',
|
||||
'substr(sprintf(\'%04d\', $this->year), -2)',
|
||||
(int)$this->year,
|
||||
'%'),
|
||||
$format);
|
||||
}
|
||||
|
||||
/**
|
||||
* mktime() implementation that supports dates outside of 1970-2038,
|
||||
* from http://phplens.com/phpeverywhere/adodb_date_library.
|
||||
*
|
||||
* @TODO remove in Horde 4
|
||||
*
|
||||
* This does NOT work with pre-1970 daylight saving times.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
function _mktime($hr, $min, $sec, $mon = false, $day = false,
|
||||
$year = false, $is_dst = false, $is_gmt = false)
|
||||
{
|
||||
if ($mon === false) {
|
||||
return $is_gmt
|
||||
? @gmmktime($hr, $min, $sec)
|
||||
: @mktime($hr, $min, $sec);
|
||||
}
|
||||
|
||||
if ($year > 1901 && $year < 2038 &&
|
||||
($year >= 1970 || version_compare(PHP_VERSION, '5.0.0', '>='))) {
|
||||
return $is_gmt
|
||||
? @gmmktime($hr, $min, $sec, $mon, $day, $year)
|
||||
: @mktime($hr, $min, $sec, $mon, $day, $year);
|
||||
}
|
||||
|
||||
$gmt_different = $is_gmt
|
||||
? 0
|
||||
: (mktime(0, 0, 0, 1, 2, 1970, 0) - gmmktime(0, 0, 0, 1, 2, 1970, 0));
|
||||
|
||||
$mon = intval($mon);
|
||||
$day = intval($day);
|
||||
$year = intval($year);
|
||||
|
||||
if ($mon > 12) {
|
||||
$y = floor($mon / 12);
|
||||
$year += $y;
|
||||
$mon -= $y * 12;
|
||||
} elseif ($mon < 1) {
|
||||
$y = ceil((1 - $mon) / 12);
|
||||
$year -= $y;
|
||||
$mon += $y * 12;
|
||||
}
|
||||
|
||||
$_day_power = 86400;
|
||||
$_hour_power = 3600;
|
||||
$_min_power = 60;
|
||||
|
||||
$_month_table_normal = array('', 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
|
||||
$_month_table_leaf = array('', 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
|
||||
|
||||
$_total_date = 0;
|
||||
if ($year >= 1970) {
|
||||
for ($a = 1970; $a <= $year; $a++) {
|
||||
$leaf = Horde_Date::isLeapYear($a);
|
||||
if ($leaf == true) {
|
||||
$loop_table = $_month_table_leaf;
|
||||
$_add_date = 366;
|
||||
} else {
|
||||
$loop_table = $_month_table_normal;
|
||||
$_add_date = 365;
|
||||
}
|
||||
if ($a < $year) {
|
||||
$_total_date += $_add_date;
|
||||
} else {
|
||||
for ($b = 1; $b < $mon; $b++) {
|
||||
$_total_date += $loop_table[$b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ($_total_date + $day - 1) * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;
|
||||
}
|
||||
|
||||
for ($a = 1969 ; $a >= $year; $a--) {
|
||||
$leaf = Horde_Date::isLeapYear($a);
|
||||
if ($leaf == true) {
|
||||
$loop_table = $_month_table_leaf;
|
||||
$_add_date = 366;
|
||||
} else {
|
||||
$loop_table = $_month_table_normal;
|
||||
$_add_date = 365;
|
||||
}
|
||||
if ($a > $year) {
|
||||
$_total_date += $_add_date;
|
||||
} else {
|
||||
for ($b = 12; $b > $mon; $b--) {
|
||||
$_total_date += $loop_table[$b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$_total_date += $loop_table[$mon] - $day;
|
||||
$_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
|
||||
$_day_time = $_day_power - $_day_time;
|
||||
$ret = -($_total_date * $_day_power + $_day_time - $gmt_different);
|
||||
if ($ret < -12220185600) {
|
||||
// If earlier than 5 Oct 1582 - gregorian correction.
|
||||
return $ret + 10 * 86400;
|
||||
} elseif ($ret < -12219321600) {
|
||||
// If in limbo, reset to 15 Oct 1582.
|
||||
return -12219321600;
|
||||
} else {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -206,7 +206,7 @@ class Horde_RPC {
|
||||
}
|
||||
$class = 'Horde_RPC_' . $driver;
|
||||
if (class_exists($class)) {
|
||||
$rpc = &new $class($params);
|
||||
$rpc = new $class($params);
|
||||
} else {
|
||||
require_once 'PEAR.php';
|
||||
$rpc = PEAR::raiseError('Class definition of ' . $class . ' not found.');
|
||||
|
@ -89,7 +89,7 @@ class Horde_RPC_syncml extends Horde_RPC {
|
||||
}
|
||||
|
||||
require_once 'XML/WBXML/ContentHandler.php';
|
||||
$this->_output = &new XML_WBXML_ContentHandler();
|
||||
$this->_output = new XML_WBXML_ContentHandler();
|
||||
|
||||
$this->_parse($request);
|
||||
$response = $this->_output->getOutput();
|
||||
@ -200,7 +200,7 @@ class Horde_RPC_syncml extends Horde_RPC {
|
||||
// Either <SyncML><SyncHdr> or <SyncML><SyncBody>
|
||||
if (!isset($this->_contentHandler)) {
|
||||
// If not defined then create SyncHdr.
|
||||
$this->_contentHandler = &new Horde_SyncML_SyncmlHdr();
|
||||
$this->_contentHandler = new Horde_SyncML_SyncmlHdr();
|
||||
$this->_contentHandler->setOutput($this->_output);
|
||||
}
|
||||
|
||||
@ -233,7 +233,7 @@ class Horde_RPC_syncml extends Horde_RPC {
|
||||
|
||||
unset($this->_contentHandler);
|
||||
|
||||
$this->_contentHandler = &new Horde_SyncML_SyncmlBody();
|
||||
$this->_contentHandler = new Horde_SyncML_SyncmlBody();
|
||||
$this->_contentHandler->setOutput($this->_output);
|
||||
} else {
|
||||
// No longer used.
|
||||
|
@ -51,8 +51,8 @@ class Horde_RPC_syncml_wbxml extends Horde_RPC_syncml {
|
||||
}
|
||||
|
||||
|
||||
$decoder = &new XML_WBXML_Decoder();
|
||||
$this->_output = &new XML_WBXML_Encoder();
|
||||
$decoder = new XML_WBXML_Decoder();
|
||||
$this->_output = new XML_WBXML_Encoder();
|
||||
|
||||
$decoder->setContentHandler($this);
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
<?php
|
||||
|
||||
require_once 'Horde/Util.php';
|
||||
|
||||
$GLOBALS['_HORDE_STRING_CHARSET'] = 'iso-8859-1';
|
||||
|
||||
/**
|
||||
* The String:: class provides static methods for charset and locale safe
|
||||
* string manipulation.
|
||||
*
|
||||
* $Horde: framework/Util/String.php,v 1.50 2005/02/10 17:09:44 jan Exp $
|
||||
* $Horde: framework/Util/String.php,v 1.43.6.31 2008/10/23 21:28:38 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2005 Jan Schneider <jan@horde.org>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
@ -21,18 +19,40 @@ $GLOBALS['_HORDE_STRING_CHARSET'] = 'iso-8859-1';
|
||||
*/
|
||||
class String {
|
||||
|
||||
/**
|
||||
* Caches the result of extension_loaded() calls.
|
||||
*
|
||||
* @param string $ext The extension name.
|
||||
*
|
||||
* @return boolean Is the extension loaded?
|
||||
*
|
||||
* @see Util::extensionExists()
|
||||
*/
|
||||
function extensionExists($ext)
|
||||
{
|
||||
static $cache = array();
|
||||
|
||||
if (!isset($cache[$ext])) {
|
||||
$cache[$ext] = extension_loaded($ext);
|
||||
}
|
||||
|
||||
return $cache[$ext];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default charset that the String:: methods will use if none is
|
||||
* explicitely specified.
|
||||
* explicitly specified.
|
||||
*
|
||||
* @param string $charset The charset to use as the default one.
|
||||
*/
|
||||
function setDefaultCharset($charset)
|
||||
{
|
||||
$GLOBALS['_HORDE_STRING_CHARSET'] = $charset;
|
||||
if (Util::extensionExists('mbstring') &&
|
||||
if (String::extensionExists('mbstring') &&
|
||||
function_exists('mb_regex_encoding')) {
|
||||
@mb_regex_encoding($charset);
|
||||
$old_error = error_reporting(0);
|
||||
mb_regex_encoding(String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,44 +64,53 @@ class String {
|
||||
* The original string is returned if conversion failed or none
|
||||
* of the extensions were available.
|
||||
*
|
||||
* @param mixed $input The data to be converted. If $input is an an
|
||||
* array, the array's values get converted
|
||||
* recursively.
|
||||
* @param string $from The string's current charset.
|
||||
* @param string $to The charset to convert the string to. If not
|
||||
* specified, the global variable
|
||||
* $_HORDE_STRING_CHARSET will be used.
|
||||
* @param bool $recursion Internally used.
|
||||
* @param mixed $input The data to be converted. If $input is an an array,
|
||||
* the array's values get converted recursively.
|
||||
* @param string $from The string's current charset.
|
||||
* @param string $to The charset to convert the string to. If not
|
||||
* specified, the global variable
|
||||
* $_HORDE_STRING_CHARSET will be used.
|
||||
*
|
||||
* @return string The converted string.
|
||||
* @return mixed The converted input data.
|
||||
*/
|
||||
function convertCharset($input, $from, $to = null, $recursion = false)
|
||||
function convertCharset($input, $from, $to = null)
|
||||
{
|
||||
/* Don't bother converting numbers. */
|
||||
if (is_numeric($input)) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
/* Get the user's default character set if none passed in. */
|
||||
if (is_null($to)) {
|
||||
$to = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
|
||||
/* If the from and to character sets are identical, return now. */
|
||||
if (!$recursion) {
|
||||
$from = String::lower($from);
|
||||
$to = String::lower($to);
|
||||
}
|
||||
$from = String::lower($from);
|
||||
$to = String::lower($to);
|
||||
if ($from == $to) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
if (is_array($input)) {
|
||||
$tmp = array();
|
||||
foreach ($input as $key => $val) {
|
||||
$tmp[String::convertCharset($key, $from, $to, true)] = String::convertCharset($val, $from, $to, true);
|
||||
while (list($key, $val) = each($input)) {
|
||||
$tmp[String::_convertCharset($key, $from, $to)] = String::convertCharset($val, $from, $to);
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
if (is_object($input)) {
|
||||
// PEAR_Error objects are almost guaranteed to contain recursion,
|
||||
// which will cause a segfault in PHP. We should never reach
|
||||
// this line, but add a check and a log message to help the devs
|
||||
// track down and fix this issue.
|
||||
if (is_a($input, 'PEAR_Error')) {
|
||||
Horde::logMessage('Called convertCharset() on a PEAR_Error object. ' . print_r($input, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return '';
|
||||
}
|
||||
$vars = get_object_vars($input);
|
||||
foreach ($vars as $key => $val) {
|
||||
$input->$key = String::convertCharset($val, $from, $to, true);
|
||||
while (list($key, $val) = each($vars)) {
|
||||
$input->$key = String::convertCharset($val, $from, $to);
|
||||
}
|
||||
return $input;
|
||||
}
|
||||
@ -90,43 +119,62 @@ class String {
|
||||
return $input;
|
||||
}
|
||||
|
||||
$output = false;
|
||||
return String::_convertCharset($input, $from, $to);
|
||||
}
|
||||
|
||||
/* Use utf8_[en|de]code() if possible. */
|
||||
/**
|
||||
* Internal function used to do charset conversion.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param string $input See String::convertCharset().
|
||||
* @param string $from See String::convertCharset().
|
||||
* @param string $to See String::convertCharset().
|
||||
*
|
||||
* @return string The converted string.
|
||||
*/
|
||||
function _convertCharset($input, $from, $to)
|
||||
{
|
||||
$output = '';
|
||||
$from_check = (($from == 'iso-8859-1') || ($from == 'us-ascii'));
|
||||
if ($from_check && ($to == 'utf-8')) {
|
||||
return utf8_encode($input);
|
||||
}
|
||||
|
||||
$to_check = (($to == 'iso-8859-1') || ($to == 'us-ascii'));
|
||||
if (($from == 'utf-8') && $to_check) {
|
||||
return utf8_decode($input);
|
||||
|
||||
/* Use utf8_[en|de]code() if possible and if the string isn't too
|
||||
* large (less than 16 MB = 16 * 1024 * 1024 = 16777216 bytes) - these
|
||||
* functions use more memory. */
|
||||
if (strlen($input) < 16777216 || !(String::extensionExists('iconv') || String::extensionExists('mbstring'))) {
|
||||
if ($from_check && ($to == 'utf-8')) {
|
||||
return utf8_encode($input);
|
||||
}
|
||||
|
||||
if (($from == 'utf-8') && $to_check) {
|
||||
return utf8_decode($input);
|
||||
}
|
||||
}
|
||||
|
||||
/* First try iconv with transliteration. */
|
||||
if ($from != 'utf7-imap' &&
|
||||
$to != 'utf7-imap' &&
|
||||
Util::extensionExists('iconv')) {
|
||||
ini_set('track_errors', 1);
|
||||
/* We need to tack an extra character temporarily because
|
||||
* of a bug in iconv() if the last character is not a 7
|
||||
* bit ASCII character. */
|
||||
if (($from != 'utf7-imap') &&
|
||||
($to != 'utf7-imap') &&
|
||||
String::extensionExists('iconv')) {
|
||||
/* We need to tack an extra character temporarily because of a bug
|
||||
* in iconv() if the last character is not a 7 bit ASCII
|
||||
* character. */
|
||||
$oldTrackErrors = ini_set('track_errors', 1);
|
||||
unset($php_errormsg);
|
||||
$output = @iconv($from, $to . '//TRANSLIT', $input . 'x');
|
||||
if (isset($php_errormsg)) {
|
||||
$output = false;
|
||||
} else {
|
||||
$output = String::substr($output, 0, -1, $to);
|
||||
}
|
||||
ini_restore('track_errors');
|
||||
$output = (isset($php_errormsg)) ? false : String::substr($output, 0, -1, $to);
|
||||
ini_set('track_errors', $oldTrackErrors);
|
||||
}
|
||||
|
||||
/* Next try mbstring. */
|
||||
if (!$output && Util::extensionExists('mbstring')) {
|
||||
$output = @mb_convert_encoding($input, $to, $from);
|
||||
if (!$output && String::extensionExists('mbstring')) {
|
||||
$old_error = error_reporting(0);
|
||||
$output = mb_convert_encoding($input, $to, String::_mbstringCharset($from));
|
||||
error_reporting($old_error);
|
||||
}
|
||||
|
||||
/* At last try imap_utf7_[en|de]code if appropriate. */
|
||||
if (!$output && Util::extensionExists('imap')) {
|
||||
if (!$output && String::extensionExists('imap')) {
|
||||
if ($from_check && ($to == 'utf7-imap')) {
|
||||
return @imap_utf7_encode($input);
|
||||
}
|
||||
@ -135,7 +183,7 @@ class String {
|
||||
}
|
||||
}
|
||||
|
||||
return !$output ? $input : $output;
|
||||
return (!$output) ? $input : $output;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,12 +203,14 @@ class String {
|
||||
|
||||
if ($locale) {
|
||||
/* The existence of mb_strtolower() depends on the platform. */
|
||||
if (Util::extensionExists('mbstring') &&
|
||||
if (String::extensionExists('mbstring') &&
|
||||
function_exists('mb_strtolower')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$ret = @mb_strtolower($string, $charset);
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strtolower($string, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
@ -173,7 +223,7 @@ class String {
|
||||
}
|
||||
if (!isset($lowers[$string])) {
|
||||
$language = setlocale(LC_CTYPE, 0);
|
||||
setlocale(LC_CTYPE, 'en_US');
|
||||
setlocale(LC_CTYPE, 'C');
|
||||
$lowers[$string] = strtolower($string);
|
||||
setlocale(LC_CTYPE, $language);
|
||||
}
|
||||
@ -203,7 +253,9 @@ class String {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$ret = @mb_strtoupper($string, $charset);
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strtoupper($string, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
@ -216,7 +268,7 @@ class String {
|
||||
}
|
||||
if (!isset($uppers[$string])) {
|
||||
$language = setlocale(LC_CTYPE, 0);
|
||||
setlocale(LC_CTYPE, 'en_US');
|
||||
setlocale(LC_CTYPE, 'C');
|
||||
$uppers[$string] = strtoupper($string);
|
||||
setlocale(LC_CTYPE, $language);
|
||||
}
|
||||
@ -251,31 +303,34 @@ class String {
|
||||
/**
|
||||
* Returns part of a string.
|
||||
*
|
||||
* @param string $string The string to be converted.
|
||||
* @param int $start The part's start position, zero based.
|
||||
* @param int $length The part's length.
|
||||
* @param string $charset The charset to use when calculating the part's
|
||||
* position and length, defaults to current charset.
|
||||
* @param string $string The string to be converted.
|
||||
* @param integer $start The part's start position, zero based.
|
||||
* @param integer $length The part's length.
|
||||
* @param string $charset The charset to use when calculating the part's
|
||||
* position and length, defaults to current
|
||||
* charset.
|
||||
*
|
||||
* @return string The string's part.
|
||||
*/
|
||||
function substr($string, $start, $length = null, $charset = null)
|
||||
{
|
||||
if (Util::extensionExists('mbstring')) {
|
||||
if (is_null($length)) {
|
||||
$length = String::length($string, $charset) - $start;
|
||||
}
|
||||
if ($length == 0) {
|
||||
return '';
|
||||
}
|
||||
if (String::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
if (is_null($length)) {
|
||||
$length = String::length($string, $charset);
|
||||
}
|
||||
$ret = @mb_substr($string, $start, $length, $charset);
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_substr($string, $start, $length, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
if (is_null($length)) {
|
||||
$length = String::length($string);
|
||||
}
|
||||
return substr($string, $start, $length);
|
||||
}
|
||||
|
||||
@ -290,11 +345,17 @@ class String {
|
||||
*/
|
||||
function length($string, $charset = null)
|
||||
{
|
||||
if (Util::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$ret = @mb_strlen($string, $charset);
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$charset = String::lower($charset);
|
||||
if ($charset == 'utf-8' || $charset == 'utf8') {
|
||||
return strlen(utf8_decode($string));
|
||||
}
|
||||
if (String::extensionExists('mbstring')) {
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strlen($string, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
@ -308,22 +369,24 @@ class String {
|
||||
*
|
||||
* @param string $haystack The string to search through.
|
||||
* @param string $needle The string to search for.
|
||||
* @param int $offset Allows to specify which character in haystack
|
||||
* @param integer $offset Allows to specify which character in haystack
|
||||
* to start searching.
|
||||
* @param string $charset The charset to use when searching for the
|
||||
* $needle string.
|
||||
*
|
||||
* @return int The position of first occurrence.
|
||||
* @return integer The position of first occurrence.
|
||||
*/
|
||||
function pos($haystack, $needle, $offset = 0, $charset = null)
|
||||
{
|
||||
if (Util::extensionExists('mbstring')) {
|
||||
if (String::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
ini_set('track_errors', 1);
|
||||
$ret = @mb_strpos($haystack, $needle, $offset, $charset);
|
||||
ini_restore('track_errors');
|
||||
$track_errors = ini_set('track_errors', 1);
|
||||
$old_error = error_reporting(0);
|
||||
$ret = mb_strpos($haystack, $needle, $offset, String::_mbstringCharset($charset));
|
||||
error_reporting($old_error);
|
||||
ini_set('track_errors', $track_errors);
|
||||
if (!isset($php_errormsg)) {
|
||||
return $ret;
|
||||
}
|
||||
@ -337,7 +400,7 @@ class String {
|
||||
* This method behaves exactly like str_pad but is multibyte safe.
|
||||
*
|
||||
* @param string $input The string to be padded.
|
||||
* @param int $length The length of the resulting string.
|
||||
* @param integer $length The length of the resulting string.
|
||||
* @param string $pad The string to pad the input string with. Must
|
||||
* be in the same charset like the input string.
|
||||
* @param const $type The padding type. One of STR_PAD_LEFT,
|
||||
@ -388,22 +451,89 @@ class String {
|
||||
/**
|
||||
* Wraps the text of a message.
|
||||
*
|
||||
* @todo Make multibyte-save.
|
||||
* @since Horde 3.2
|
||||
*
|
||||
* @access public
|
||||
* @param string $string String containing the text to wrap.
|
||||
* @param integer $width Wrap the string at this number of
|
||||
* characters.
|
||||
* @param string $break Character(s) to use when breaking lines.
|
||||
* @param boolean $cut Whether to cut inside words if a line
|
||||
* can't be wrapped.
|
||||
* @param string $charset Character set to use when breaking lines.
|
||||
* @param boolean $line_folding Whether to apply line folding rules per
|
||||
* RFC 822 or similar. The correct break
|
||||
* characters including leading whitespace
|
||||
* have to be specified too.
|
||||
*
|
||||
* @param string $text String containing the text to wrap.
|
||||
* @param optional integer $length Wrap $text at this number of
|
||||
* characters.
|
||||
* @param optional string $break_char Character(s) to use when breaking
|
||||
* lines.
|
||||
* @param optional string $charset Character set to use when breaking
|
||||
* lines.
|
||||
* @param optional boolean $quote Ignore lines that are wrapped with
|
||||
* the '>' character (RFC 2646)? If
|
||||
* true, we don't remove any padding
|
||||
* whitespace at the end of the
|
||||
* string.
|
||||
* @return string String containing the wrapped text.
|
||||
*/
|
||||
function wordwrap($string, $width = 75, $break = "\n", $cut = false,
|
||||
$charset = null, $line_folding = false)
|
||||
{
|
||||
/* Get the user's default character set if none passed in. */
|
||||
if (is_null($charset)) {
|
||||
$charset = $GLOBALS['_HORDE_STRING_CHARSET'];
|
||||
}
|
||||
$charset = String::_mbstringCharset($charset);
|
||||
$string = String::convertCharset($string, $charset, 'utf-8');
|
||||
$wrapped = '';
|
||||
|
||||
while (String::length($string, 'utf-8') > $width) {
|
||||
$line = String::substr($string, 0, $width, 'utf-8');
|
||||
$string = String::substr($string, String::length($line, 'utf-8'), null, 'utf-8');
|
||||
// Make sure didn't cut a word, unless we want hard breaks anyway.
|
||||
if (!$cut && preg_match('/^(.+?)(\s|\r?\n)/u', $string, $match)) {
|
||||
$line .= $match[1];
|
||||
$string = String::substr($string, String::length($match[1], 'utf-8'), null, 'utf-8');
|
||||
}
|
||||
// Wrap at existing line breaks.
|
||||
if (preg_match('/^(.*?)(\r?\n)(.*)$/u', $line, $match)) {
|
||||
$wrapped .= $match[1] . $match[2];
|
||||
$string = $match[3] . $string;
|
||||
continue;
|
||||
}
|
||||
// Wrap at the last colon or semicolon followed by a whitespace if
|
||||
// doing line folding.
|
||||
if ($line_folding &&
|
||||
preg_match('/^(.*?)(;|:)(\s+.*)$/u', $line, $match)) {
|
||||
$wrapped .= $match[1] . $match[2] . $break;
|
||||
$string = $match[3] . $string;
|
||||
continue;
|
||||
}
|
||||
// Wrap at the last whitespace of $line.
|
||||
if ($line_folding) {
|
||||
$sub = '(.+[^\s])';
|
||||
} else {
|
||||
$sub = '(.*)';
|
||||
}
|
||||
if (preg_match('/^' . $sub . '(\s+)(.*)$/u', $line, $match)) {
|
||||
$wrapped .= $match[1] . $break;
|
||||
$string = ($line_folding ? $match[2] : '') . $match[3] . $string;
|
||||
continue;
|
||||
}
|
||||
// Hard wrap if necessary.
|
||||
if ($cut) {
|
||||
$wrapped .= String::substr($line, 0, $width, 'utf-8') . $break;
|
||||
$string = String::substr($line, $width, null, 'utf-8') . $string;
|
||||
continue;
|
||||
}
|
||||
$wrapped .= $line;
|
||||
}
|
||||
|
||||
return String::convertCharset($wrapped . $string, 'utf-8', $charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the text of a message.
|
||||
*
|
||||
* @param string $text String containing the text to wrap.
|
||||
* @param integer $length Wrap $text at this number of characters.
|
||||
* @param string $break_char Character(s) to use when breaking lines.
|
||||
* @param string $charset Character set to use when breaking lines.
|
||||
* @param boolean $quote Ignore lines that are wrapped with the '>'
|
||||
* character (RFC 2646)? If true, we don't
|
||||
* remove any padding whitespace at the end of
|
||||
* the string.
|
||||
*
|
||||
* @return string String containing the wrapped text.
|
||||
*/
|
||||
@ -422,7 +552,7 @@ class String {
|
||||
if ($input != '-- ') {
|
||||
$input = rtrim($input);
|
||||
}
|
||||
$line = wordwrap($input, $length, $break_char);
|
||||
$line = String::wordwrap($input, $length, $break_char, false, $charset);
|
||||
}
|
||||
|
||||
$paragraphs[] = $line;
|
||||
@ -432,9 +562,8 @@ class String {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the every character in the parameter is an
|
||||
* alphabetic character. This method doesn't work with any charset
|
||||
* other than the current charset yet.
|
||||
* Returns true if the every character in the parameter is an alphabetic
|
||||
* character.
|
||||
*
|
||||
* @param $string The string to test.
|
||||
* @param $charset The charset to use when testing the string.
|
||||
@ -443,26 +572,30 @@ class String {
|
||||
*/
|
||||
function isAlpha($string, $charset = null)
|
||||
{
|
||||
if (Util::extensionExists('mbstring')) {
|
||||
$old_charset = mb_regex_encoding();
|
||||
if ($charset != $old_charset) {
|
||||
@mb_regex_encoding($charset);
|
||||
}
|
||||
$alpha = !mb_ereg_match('[^[:alpha:]]', $string);
|
||||
if ($charset != $old_charset) {
|
||||
@mb_regex_encoding($old_charset);
|
||||
}
|
||||
return $alpha;
|
||||
if (!String::extensionExists('mbstring')) {
|
||||
return ctype_alpha($string);
|
||||
}
|
||||
|
||||
return ctype_alpha($string);
|
||||
$charset = String::_mbstringCharset($charset);
|
||||
$old_charset = mb_regex_encoding();
|
||||
$old_error = error_reporting(0);
|
||||
|
||||
if ($charset != $old_charset) {
|
||||
mb_regex_encoding($charset);
|
||||
}
|
||||
$alpha = !mb_ereg_match('[^[:alpha:]]', $string);
|
||||
if ($charset != $old_charset) {
|
||||
mb_regex_encoding($old_charset);
|
||||
}
|
||||
|
||||
error_reporting($old_error);
|
||||
|
||||
return $alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if every character in the parameter is a lowercase
|
||||
* letter in the current locale.
|
||||
*
|
||||
* @access public
|
||||
* Returns true if ever character in the parameter is a lowercase letter in
|
||||
* the current locale.
|
||||
*
|
||||
* @param $string The string to test.
|
||||
* @param $charset The charset to use when testing the string.
|
||||
@ -476,10 +609,8 @@ class String {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if every character in the parameter is an
|
||||
* uppercase letter in the current locale.
|
||||
*
|
||||
* @access public
|
||||
* Returns true if every character in the parameter is an uppercase letter
|
||||
* in the current locale.
|
||||
*
|
||||
* @param string $string The string to test.
|
||||
* @param string $charset The charset to use when testing the string.
|
||||
@ -493,63 +624,59 @@ class String {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a regex match search on the text provided. Will correctly
|
||||
* handle text with multibyte characters if the mbstring extensions and
|
||||
* the mbregex functions are available. Will use the preg_match()
|
||||
* function if possible or if the mbregex ereg function is not available.
|
||||
* Performs a multibyte safe regex match search on the text provided.
|
||||
*
|
||||
* @access public
|
||||
* @since Horde 3.1
|
||||
*
|
||||
* @param string $text The text to search.
|
||||
* @param array $regex The regular expressions to use. These
|
||||
* expressions should conform to ereg() rules -
|
||||
* extended perl rules are NOT supported.
|
||||
* Additionally, do NOT add perl regex delimiters
|
||||
* (e.g. '/' or '|') to the beginning/end.
|
||||
* @param array $regex The regular expressions to use, without perl
|
||||
* regex delimiters (e.g. '/' or '|').
|
||||
* @param string $charset The character set of the text.
|
||||
*
|
||||
* @return array The matches array from the first regex that matches.
|
||||
*/
|
||||
function regexMatch($text, $regex, $charset = null)
|
||||
{
|
||||
static $mbregex;
|
||||
if (!isset($mbregex)) {
|
||||
$mbregex = function_exists('mb_ereg');
|
||||
}
|
||||
|
||||
$use_mb = false;
|
||||
|
||||
if ($mbregex && !is_null($charset) &&
|
||||
(String::lower($charset) != 'utf-8')) {
|
||||
$old_charset = mb_regex_encoding();
|
||||
if ($charset != $old_charset) {
|
||||
@mb_regex_encoding($charset);
|
||||
} else {
|
||||
unset($old_charset);
|
||||
}
|
||||
$use_mb = true;
|
||||
if (!empty($charset)) {
|
||||
$regex = String::convertCharset($regex, $charset, 'utf-8');
|
||||
$text = String::convertCharset($text, $charset, 'utf-8');
|
||||
}
|
||||
|
||||
$matches = array();
|
||||
|
||||
foreach ($regex as $val) {
|
||||
if ($use_mb) {
|
||||
if (mb_ereg($val, $text, $matches)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (preg_match('/' . $val . '/u', $text, $matches)) {
|
||||
break;
|
||||
}
|
||||
if (preg_match('/' . $val . '/u', $text, $matches)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($old_charset)) {
|
||||
@mb_regex_encoding($old_charset);
|
||||
|
||||
if (!empty($charset)) {
|
||||
$matches = String::convertCharset($matches, 'utf-8', $charset);
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround charsets that don't work with mbstring functions.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param string $charset The original charset.
|
||||
*
|
||||
* @return string The charset to use with mbstring functions.
|
||||
*/
|
||||
function _mbstringCharset($charset)
|
||||
{
|
||||
/* mbstring functions do not handle the 'ks_c_5601-1987' &
|
||||
* 'ks_c_5601-1989' charsets. However, these charsets are used, for
|
||||
* example, by various versions of Outlook to send Korean characters.
|
||||
* Use UHC (CP949) encoding instead. See, e.g.,
|
||||
* http://lists.w3.org/Archives/Public/ietf-charsets/2001AprJun/0030.html */
|
||||
if (in_array(String::lower($charset), array('ks_c_5601-1987', 'ks_c_5601-1989'))) {
|
||||
$charset = 'UHC';
|
||||
}
|
||||
|
||||
return $charset;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,32 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3.0
|
||||
*
|
||||
* The Horde_SyncML_SyncHdr and Horde_SyncML_SyncBody classes provides
|
||||
* a SyncHdr and SyncBody in SyncML Representation Protocol, version
|
||||
* 1.1 5.2.2 and 5.2.3. Most of the work is passed on to
|
||||
* Horde_SyncML_Command_Alert and Horde_SyncML_Command_Sync.
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
include_once 'Horde/SyncML/Command/Status.php';
|
||||
include_once 'Horde/SyncML/Command/Alert.php';
|
||||
include_once 'Horde/SyncML/Command/Final.php';
|
||||
include_once 'Horde/SyncML/Command/Sync.php';
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElementItem.php';
|
||||
|
||||
/**
|
||||
* The Horde_SyncML_SyncHdr and Horde_SyncML_SyncBody classes provides
|
||||
* a SyncHdr and SyncBody in SyncML Representation Protocol, version
|
||||
* 1.1 5.2.2 and 5.2.3. Most of the work is passed on to
|
||||
* Horde_SyncML_Command_Alert and Horde_SyncML_Command_Sync.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML.php,v 1.21 2004/07/21 19:26:36 karsten Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
*
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_ContentHandler {
|
||||
|
||||
/**
|
||||
@ -108,7 +108,7 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
|
||||
/**
|
||||
* Defined in SyncML Representation Protocol, version 1.1. Must
|
||||
* be 1.0 (0) or 1.1 (1).
|
||||
* be 1.0 (0), 1.1 (1) or 1.2(2).
|
||||
*
|
||||
* @var string $_version
|
||||
*/
|
||||
@ -144,41 +144,52 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
|
||||
var $_credType;
|
||||
|
||||
var $_maxMsgSize;
|
||||
|
||||
function getStateFromSession($sourceURI, $locName, $sessionID)
|
||||
{
|
||||
// Remove any existing session since we'll be contructing a
|
||||
// custom session id.
|
||||
session_regenerate_id();
|
||||
session_destroy();
|
||||
|
||||
// we need to (re-)load the eGW session-handler, as session_destroy unloads custom session-handlers
|
||||
if (function_exists('init_session_handler'))
|
||||
{
|
||||
init_session_handler();
|
||||
if (function_exists('init_session_handler')) {
|
||||
init_session_handler();
|
||||
}
|
||||
// Reload the Horde SessionHandler if necessary.
|
||||
|
||||
// Reload the Horde SessionHandler if necessary.
|
||||
Horde::setupSessionHandler();
|
||||
|
||||
// It would seem multisync does not send the user name once it
|
||||
// has been authorized. Make sure we have a valid session id.
|
||||
if(!empty($_GET['syncml_sessionid'])) {
|
||||
session_id($_GET['syncml_sessionid']);
|
||||
Horde::logMessage('SyncML['. session_id() .']: reusing existing session', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() .']: reusing existing session',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
#session_id('syncml' . preg_replace('/[^a-zA-Z0-9]/', '', $sourceURI . $sessionID));
|
||||
session_id('syncml-' . md5(uniqid(rand(), true)));
|
||||
Horde::logMessage('SyncML['. session_id() .']: starting new session for '.$this->_locName, __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
Horde::logMessage('SyncML['. session_id() .']: starting new session for '
|
||||
. $this->_locName, __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
}
|
||||
|
||||
@session_start();
|
||||
|
||||
if (!isset($_SESSION['SyncML.state'])) {
|
||||
// Create a new state if one does not already exist.
|
||||
Horde::logMessage('SyncML['. session_id() .']: create new session state variable', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() .']: create new session state variable for '
|
||||
. $sourceURI, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
# LK $_SESSION['SyncML.state'] = &new Horde_SyncML_State($sourceURI, $locName, $sessionID);
|
||||
$_SESSION['SyncML.state'] = &new EGW_SyncML_State($sourceURI, $locName, $sessionID);
|
||||
}
|
||||
#if($_SESSION['SyncML.state']->_isAuthorized)
|
||||
# Horde::logMessage('SyncML['. session_id() .']: is session authorized', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$_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'];
|
||||
}
|
||||
@ -216,18 +227,26 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
#Horde::logMessage('SymcML: SyncHdr done. Try to load state from session.', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state = $this->getStateFromSession($this->_sourceURI, $this->_locName, $this->_sessionID);
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: package '.$this->_msgID.' +++++++++++++++++++++ started', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() .']: package '
|
||||
. $this->_msgID.' +++++++++++++++++++++ started',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->setVersion($this->_version);
|
||||
$state->setMsgID($this->_msgID);
|
||||
$state->setTargetURI($this->_targetURI);
|
||||
$state->setWBXML(is_a($this->_output, 'XML_WBXML_Encoder'));
|
||||
if(isset($this->_credData) && isset($this->_locName) && !$state->isAuthorized())
|
||||
{
|
||||
|
||||
if(isset($this->_credData)
|
||||
&& isset($this->_locName)
|
||||
&& !$state->isAuthorized()) {
|
||||
$state->setPassword($this->_credData);
|
||||
$state->setLocName($this->_locName);
|
||||
}
|
||||
|
||||
if (isset($this->_maxMsgSize)) {
|
||||
$state->setMaxMsgSize($this->_maxMsgSize);
|
||||
}
|
||||
|
||||
#$str = 'authorized=' . $state->isAuthorized();
|
||||
#$str .= ' version=' . $state->getVersion();
|
||||
#$str .= ' msgid=' . $state->getMsgID();
|
||||
@ -246,11 +265,17 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
case 3:
|
||||
if ($element == 'VerProto') {
|
||||
// </VerProto></SyncHdr></SyncML>
|
||||
if (trim($this->_chars) == 'SyncML/1.1') {
|
||||
$this->_version = 1;
|
||||
} else {
|
||||
$this->_version = 0;
|
||||
}
|
||||
switch (strtolower(trim($this->_chars))) {
|
||||
case 'syncml/1.2':
|
||||
$this->_version = 2;
|
||||
break;
|
||||
case 'syncml/1.1':
|
||||
$this->_version = 1;
|
||||
break;
|
||||
default:
|
||||
$this->_version = 0;
|
||||
break;
|
||||
}
|
||||
} elseif ($element == 'SessionID') {
|
||||
// </SessionID></SyncHdr></SyncML>
|
||||
$this->_sessionID = trim($this->_chars);
|
||||
@ -269,10 +294,9 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
$this->_credData = base64_decode($this->_credData);
|
||||
//}
|
||||
|
||||
$tmp = split(':', $this->_credData, 2);
|
||||
$tmp = explode(':', $this->_credData, 2);
|
||||
// set only if not set by LocName already
|
||||
if(!isset($this->_locName))
|
||||
{
|
||||
if(!isset($this->_locName)) {
|
||||
$this->_locName = $tmp[0];
|
||||
}
|
||||
$this->_credData = $tmp[1];
|
||||
@ -282,26 +306,34 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_isSource) {
|
||||
// </LocURI></Source></SyncHdr></SyncML>
|
||||
$this->_sourceURI = trim($this->_chars);
|
||||
} else {
|
||||
// </LocURI></Target></SyncHdr></SyncML>
|
||||
$this->_targetURI = trim($this->_chars);
|
||||
}
|
||||
} elseif ($element == 'LocName') {
|
||||
if ($this->_isSource) {
|
||||
// </LocName></Source></SyncHdr></SyncML>
|
||||
$this->_locName = trim($this->_chars);
|
||||
}
|
||||
} elseif ($element == 'Data') {
|
||||
// </Data></Cred></SyncHdr></SyncML>
|
||||
if ($this->_isCred) {
|
||||
$this->_credData = trim($this->_chars);
|
||||
}
|
||||
}
|
||||
break;
|
||||
switch ($element) {
|
||||
case 'LocURI':
|
||||
if ($this->_isSource) {
|
||||
// </LocURI></Source></SyncHdr></SyncML>
|
||||
$this->_sourceURI = trim($this->_chars);
|
||||
} else {
|
||||
// </LocURI></Target></SyncHdr></SyncML>
|
||||
$this->_targetURI = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'LocName':
|
||||
if ($this->_isSource) {
|
||||
// </LocName></Source></SyncHdr></SyncML>
|
||||
$this->_locName = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'Data':
|
||||
// </Data></Cred></SyncHdr></SyncML>
|
||||
if ($this->_isCred) {
|
||||
$this->_credData = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'MaxMsgSize':
|
||||
//</MaxMsgSize></Meta></SyncHdr></SyncML>
|
||||
$this->_maxMsgSize = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if ($this->_isCred) {
|
||||
@ -323,19 +355,31 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
{
|
||||
$attrs = array();
|
||||
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$uri = $state->getURI();
|
||||
$uriMeta = $state->getURIMeta();
|
||||
$output->startElement($uri, 'SyncHdr', $attrs);
|
||||
|
||||
$output->startElement($uri, 'VerDTD', $attrs);
|
||||
$chars = ($this->_version == 1) ? '1.1' : '1.0';
|
||||
if ($this->_version == 2) {
|
||||
$chars = '1.2';
|
||||
} elseif ($this->_version == 1) {
|
||||
$chars = '1.1';
|
||||
} else {
|
||||
$chars = '1.0';
|
||||
}
|
||||
$output->characters($chars);
|
||||
$output->endElement($uri, 'VerDTD');
|
||||
|
||||
$output->startElement($uri, 'VerProto', $attrs);
|
||||
$chars = ($this->_version == 1) ? 'SyncML/1.1' : 'SyncML/1.0';
|
||||
if ($this->_version == 2) {
|
||||
$chars = 'SyncML/1.2';
|
||||
} elseif ($this->_version == 1) {
|
||||
$chars = 'SyncML/1.1';
|
||||
} else {
|
||||
$chars = 'SyncML/1.0';
|
||||
}
|
||||
$output->characters($chars);
|
||||
$output->endElement($uri, 'VerProto');
|
||||
|
||||
@ -359,37 +403,40 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler {
|
||||
$output->endElement($uri, 'LocURI');
|
||||
$output->endElement($uri, 'Source');
|
||||
|
||||
if(session_id() != '' && !strpos($this->_targetURI,'syncml_sessionid')) {
|
||||
$output->startElement($uri, 'RespURI', $attrs);
|
||||
if (session_id() != '' && !strpos($this->_targetURI,'syncml_sessionid')) {
|
||||
$output->startElement($uri, 'RespURI', $attrs);
|
||||
|
||||
// some clients don't send the whole URL as targetURI
|
||||
if (strpos($this->_targetURI,$_SERVER['PHP_SELF']) === false) {
|
||||
$output->characters($this->_targetURI . $_SERVER['PHP_SELF'] . '?syncml_sessionid=' . session_id());
|
||||
} else {
|
||||
$output->characters($this->_targetURI . '?syncml_sessionid=' . session_id());
|
||||
// some clients don't send the whole URL as targetURI
|
||||
if (strpos($this->_targetURI,$_SERVER['PHP_SELF']) === false) {
|
||||
$output->characters($this->_targetURI . $_SERVER['PHP_SELF'] . '?syncml_sessionid=' . session_id());
|
||||
} else {
|
||||
$output->characters($this->_targetURI . '?syncml_sessionid=' . session_id());
|
||||
}
|
||||
$output->endElement($uri, 'RespURI');
|
||||
}
|
||||
$output->endElement($uri, 'RespURI');
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
$output->startElement($uri, 'Meta', $attrs);
|
||||
|
||||
// Dummy Max MsqSize, this is just put in to make the packet
|
||||
// work, it is not a real value.
|
||||
if (!($maxMsgSize = $state->getMaxMsgSizeClient())) {
|
||||
// Dummy MaxMsqSize, this is just put in to make the packet
|
||||
// work, it is not our real value.
|
||||
$maxMsgSize = 50000;
|
||||
}
|
||||
$output->startElement($uriMeta, 'MaxMsgSize', $attrs);
|
||||
$chars = '50000';
|
||||
$output->characters($chars);
|
||||
$output->characters($maxMsgSize);
|
||||
$output->endElement($uriMeta, 'MaxMsgSize');
|
||||
|
||||
// Dummy MaxObjSize, this is just put in to make the packet
|
||||
// work, it is not a real value.
|
||||
$output->startElement($uriMeta, 'MaxObjSize', $attrs);
|
||||
$chars = '4000000';
|
||||
$output->characters($chars);
|
||||
$output->endElement($uriMeta, 'MaxObjSize');
|
||||
#// Dummy MaxObjSize, this is just put in to make the packet
|
||||
#// work, it is not our real value.
|
||||
#if ($this->_version > 0) {
|
||||
# // Don't send this to old devices
|
||||
# $output->startElement($uriMeta, 'MaxObjSize', $attrs);
|
||||
# $output->characters('4000000');
|
||||
# $output->endElement($uriMeta, 'MaxObjSize');
|
||||
#}
|
||||
|
||||
$output->endElement($uri, 'Meta');
|
||||
*/
|
||||
|
||||
$output->endElement($uri, 'SyncHdr');
|
||||
}
|
||||
@ -448,33 +495,35 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
|
||||
$this->_actionCommands = false; // so far, we have not seen commands that require action from our side
|
||||
$state->_sendFinal = false;
|
||||
|
||||
// <SyncML><SyncBody>
|
||||
$this->_output->startElement($uri, $element, $attrs);
|
||||
|
||||
if($state->getLocName())
|
||||
{
|
||||
// Right our status about the header.
|
||||
$status = &new Horde_SyncML_Command_Status(($state->isAuthorized()) ?
|
||||
RESPONSE_AUTHENTICATION_ACCEPTED : RESPONSE_INVALID_CREDENTIALS, 'SyncHdr');
|
||||
}
|
||||
else
|
||||
{
|
||||
if($state->getLocName()) {
|
||||
if($state->isAuthConfirmed()) {
|
||||
// Right our status about the header
|
||||
$status = new Horde_SyncML_Command_Status(($state->isAuthorized()) ?
|
||||
RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS, 'SyncHdr');
|
||||
} else {
|
||||
// Right our status about the header.
|
||||
$status = new Horde_SyncML_Command_Status(($state->isAuthorized()) ?
|
||||
RESPONSE_AUTHENTICATION_ACCEPTED : RESPONSE_INVALID_CREDENTIALS, 'SyncHdr');
|
||||
}
|
||||
} else {
|
||||
// Request credentials if not sent so far
|
||||
$status = &new Horde_SyncML_Command_Status(RESPONSE_MISSING_CREDENTIALS, 'SyncHdr');
|
||||
$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();
|
||||
@ -483,11 +532,12 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
$str .= ' target=' . $state->getTargetURI();
|
||||
*/
|
||||
$this->_currentCmdID = $status->output($this->_currentCmdID, $this->_output);
|
||||
if ($state->isAuthorized()) {
|
||||
$state->AuthConfirmed();
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
// <SyncML><SyncBody><[Command]>
|
||||
#Horde::logMessage('SyncML['. session_id() ."]: found command $element ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$this->_currentCommand = Horde_SyncML_Command::factory($element);
|
||||
@ -497,7 +547,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
// We've got to do something! This can't be the last
|
||||
// packet.
|
||||
$this->_actionCommands = true;
|
||||
Horde::logMessage('SyncML['. session_id() ."]: found action commands <$element> " . $this->_actionCommands, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() ."]: found action commands <$element> ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
switch($element)
|
||||
@ -516,43 +566,49 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element) {
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
// </SyncBody></SyncML>
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: package ----------------------- done', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if($state->getSyncStatus() == CLIENT_SYNC_FINNISHED && $state->getAlert222Received() == true) {
|
||||
$state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED);
|
||||
if ($state->getAlert222Received() == true) {
|
||||
// the Funambol specialty
|
||||
if ($state->getSyncStatus() == CLIENT_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED);
|
||||
}
|
||||
$state->setAlert222Received(false);
|
||||
}
|
||||
|
||||
|
||||
// send the sync reply
|
||||
// we do still have some data to send OR
|
||||
// we should reply to the Sync command
|
||||
if($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED) {
|
||||
$sync = &new Horde_SyncML_Command_Sync();
|
||||
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();
|
||||
$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, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus = '. $state->getSyncStatus() .', actionCommands = '.
|
||||
($this->_actionCommands ? 'True' : 'False'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if (!$this->_actionCommands && $state->getSyncStatus() == SERVER_SYNC_FINNISHED) {
|
||||
// this packet did not contain any real actions, just status and map.
|
||||
// This means, we're through! The session can be closed and
|
||||
// the Anchors saved for the next Sync
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$state->writeSyncSummary();
|
||||
$log = $state->getLog();
|
||||
@ -560,6 +616,9 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
foreach($log as $k => $v) {
|
||||
$s .= " $k=$v";
|
||||
}
|
||||
if (strlen(trim($s)) == 0) {
|
||||
$s = ' Both parties were already in sync';
|
||||
}
|
||||
Horde::logMessage('SyncML['. session_id() .']: summary:' . $s, __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
# Horde::logMessage('SyncML['. session_id() .']: destroying sync session '.session_id(), __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
# // session can be closed here!
|
||||
@ -571,7 +630,6 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
// this packet did not contain any real actions, just status and map.
|
||||
// This means, we're through! The session can be closed and
|
||||
// the Anchors saved for the next Sync
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$state->writeSyncSummary();
|
||||
$log = $state->getLog();
|
||||
@ -579,6 +637,9 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
foreach($log as $k => $v) {
|
||||
$s .= " $k=$v";
|
||||
}
|
||||
if (strlen(trim($s)) == 0) {
|
||||
$s = ' Both parties were already in sync';
|
||||
}
|
||||
Horde::logMessage('SyncML['. session_id() .']: summary:' . $s, __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: destroying sync session '.session_id(), __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
@ -586,75 +647,53 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler {
|
||||
session_unset();
|
||||
session_destroy();
|
||||
}
|
||||
if($state->getSyncStatus() == CLIENT_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED);
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus(client sync acknowledged) '.$state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// </[Command]></SyncBody></SyncML>
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
// this should be moved to case 2:
|
||||
if($element == 'Final')
|
||||
{
|
||||
// make sure that we request devinfo, if we not have them already
|
||||
|
||||
/* if(!$state->getClientDeviceInfo())
|
||||
{
|
||||
$attrs = array();
|
||||
$this->_output->startElement($state->getURI(), 'Get', $attrs);
|
||||
$this->_output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$this->_output->characters($this->_currentCmdID);
|
||||
$this->_currentCmdID++;
|
||||
$this->_output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$this->_output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$this->_output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
if(is_a($this->_output, 'XML_WBXML_Encoder'))
|
||||
$this->_output->characters('application/vnd.syncml-devinf+wbxml');
|
||||
else
|
||||
$this->_output->characters('application/vnd.syncml-devinf+xml');
|
||||
$this->_output->endElement($state->getURIMeta(), 'Type');
|
||||
$this->_output->endElement($state->getURI(), 'Meta');
|
||||
|
||||
$this->_output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$this->_output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$this->_output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$this->_output->characters(($state->getVersion() == 0) ? './devinf10' : './devinf11');
|
||||
$this->_output->endElement($state->getURI(), 'LocURI');
|
||||
$this->_output->endElement($state->getURI(), 'Target');
|
||||
$this->_output->endElement($state->getURI(), 'Item');
|
||||
|
||||
$this->_output->endElement($state->getURI(), 'Get');
|
||||
} */
|
||||
}
|
||||
|
||||
$this->_currentCommand->endElement($uri, $element);
|
||||
|
||||
switch($element) {
|
||||
case 'Final':
|
||||
if($state->getSyncStatus() == CLIENT_SYNC_STARTED) {
|
||||
$state->setSyncStatus(CLIENT_SYNC_FINNISHED);
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus(client sync finnished) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
case 'Final':
|
||||
$this->_actionCommands = false;
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
if($state->getSyncStatus() == SERVER_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(SERVER_SYNC_ACKNOWLEDGED);
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus(server sync acknowledged) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
if ($state->getSyncStatus() == CLIENT_SYNC_STARTED) {
|
||||
if (strtolower($deviceInfo['manufacturer']) == 'funambol'
|
||||
&& isset($deviceInfo['softwareVersion'])) {
|
||||
$swversion = $deviceInfo['softwareVersion'];
|
||||
if ($swversion < 1.0) {
|
||||
// e.g. Mozilla plugin uses this range
|
||||
$swversion = $swversion * 10;
|
||||
}
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_clientSentFinal = true;
|
||||
#Horde::logMessage('SyncML['. session_id() .']: Sync _syncTag = '. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
if ($state->getSyncStatus() == SERVER_SYNC_FINNISHED) {
|
||||
$state->setSyncStatus(SERVER_SYNC_ACKNOWLEDGED);
|
||||
}
|
||||
|
||||
break;
|
||||
$this->_clientSentFinal = true;
|
||||
Horde::logMessage('SyncML['. session_id() .']: syncStatus(server sync acknowledged) '
|
||||
. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->_currentCmdID = $this->_currentCommand->output($this->_currentCmdID, $this->_output);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
$this->_currentCmdID = $this->_currentCommand->output($this->_currentCmdID, $this->_output);
|
||||
break;
|
||||
}
|
||||
|
||||
unset($this->_currentCommand);
|
||||
break;
|
||||
|
@ -1,80 +1,166 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
|
||||
/**
|
||||
* The Horde_SyncML_Command class provides a super class fo SyncBody commands.
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command.php,v 1.4 2004/07/03 15:26:46 chuck Exp $
|
||||
* The SyncML_Command class provides a base class for handling all <SyncBody>
|
||||
* commands.
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* A SyncML command is a protocol primitive. Each SyncML command specifies to
|
||||
* a recipient an individual operation that is to be performed.
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* The SyncML_Command objects are hooked into the XML parser of the
|
||||
* SyncML_ContentHandler class and are reponsible for parsing a single command
|
||||
* inside the SyncBody section of a SyncML message. All actions that must be
|
||||
* executed for a single SyncML command are handled by these objects, by means
|
||||
* of the handleCommand() method.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Jan Schneider <jan@horde.org>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State_egw.php';
|
||||
|
||||
class Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command, like 'Put'.
|
||||
*
|
||||
* Must be overwritten by a sub class.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName;
|
||||
|
||||
/**
|
||||
* The command ID (<CmdID>).
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_cmdID;
|
||||
|
||||
var $_xmlStack;
|
||||
/**
|
||||
* Stack for holding the XML elements during creation of the object from
|
||||
* the XML event flow.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_stack = array();
|
||||
|
||||
var $_chars;
|
||||
/**
|
||||
* Buffer for the parsed character data.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_chars = '';
|
||||
|
||||
function &factory($command, $params = null)
|
||||
/**
|
||||
* Start element handler for the XML parser, delegated from
|
||||
* SyncML_ContentHandler::startElement().
|
||||
*
|
||||
* @param string $uri The namespace URI of the element.
|
||||
* @param string $element The element tag name.
|
||||
* @param array $attrs A hash with the element's attributes.
|
||||
*/
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
include_once 'Horde/SyncML/Command/' . $command . '.php';
|
||||
$class = 'Horde_SyncML_Command_' . $command;
|
||||
if (class_exists($class)) {
|
||||
return $cmd = &new $class($params);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Class definition of ' . $class . ' not found.', __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::raiseError('Class definition of ' . $class . ' not found.');
|
||||
}
|
||||
}
|
||||
|
||||
function output($currentCmdID, $output)
|
||||
{
|
||||
}
|
||||
|
||||
function startElement($uri, $localName, $attrs)
|
||||
{
|
||||
$this->_xmlStack++;
|
||||
$this->_stack[] = $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* End element handler for the XML parser, delegated from
|
||||
* SyncML_ContentHandler::endElement().
|
||||
*
|
||||
* @param string $uri The namespace URI of the element.
|
||||
* @param string $element The element tag name.
|
||||
*/
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
if ($element == 'CmdID') {
|
||||
$this->_cmdID = intval(trim($this->_chars));
|
||||
}
|
||||
break;
|
||||
if (count($this->_stack) == 2 &&
|
||||
$element == 'CmdID') {
|
||||
$this->_cmdID = intval(trim($this->_chars));
|
||||
}
|
||||
|
||||
if (isset($this->_chars)) {
|
||||
unset($this->_chars);
|
||||
if (strlen($this->_chars)) {
|
||||
$this->_chars = '';
|
||||
}
|
||||
|
||||
$this->_xmlStack--;
|
||||
array_pop($this->_stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Character data handler for the XML parser, delegated from
|
||||
* SyncML_ContentHandler::characters().
|
||||
*
|
||||
* @param string $str The data string.
|
||||
*/
|
||||
function characters($str)
|
||||
{
|
||||
$tempValue = trim($str);
|
||||
|
||||
if(empty($tempValue)) return;
|
||||
|
||||
if (isset($this->_chars)) {
|
||||
$this->_chars = $this->_chars . $str;
|
||||
$this->_chars .= $str;
|
||||
} else {
|
||||
$this->_chars = $str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command name this instance is reponsible for.
|
||||
*
|
||||
* @return string The command name this object is handling.
|
||||
*/
|
||||
function getCommandName()
|
||||
{
|
||||
return $this->_cmdName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is supposed to implement the actual business logic of the
|
||||
* command once the XML parsing is complete.
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to return a concrete Horde_SyncML_Command instance based on
|
||||
* $command.
|
||||
*
|
||||
* @param string $command The type of the concrete
|
||||
* SyncML_Comment subclass to
|
||||
* return.
|
||||
* @param $params Optional Parameter.
|
||||
*
|
||||
* @return SyncML_Command The newly created concrete SyncML_Command
|
||||
* instance, or false on error.
|
||||
*/
|
||||
function &factory($command, $params = null)
|
||||
{
|
||||
$command = basename($command);
|
||||
$class = 'Horde_SyncML_Command_' . $command;
|
||||
|
||||
if (!class_exists($class)) {
|
||||
include_once 'Horde/SyncML/Command/' . $command . '.php';
|
||||
}
|
||||
if (class_exists($class)) {
|
||||
$cmd = new $class($params);
|
||||
} else {
|
||||
$msg = 'SyncML: Class definition of ' . $class . ' not found.';
|
||||
Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
require_once 'PEAR.php';
|
||||
$cmd = PEAR::raiseError($msg);
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,56 +1,87 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* The Horde_SyncML_Alert class provides a SyncML implementation of
|
||||
* the Alert command as defined in SyncML Representation Protocol,
|
||||
* version 1.1 5.5.2.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command/Alert.php,v 1.18 2004/07/03 15:21:14 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State_egw.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* @var integer $_alert
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Alert';
|
||||
|
||||
/**
|
||||
* The alert type. Should be one of the ALERT_* constants.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_alert;
|
||||
|
||||
/**
|
||||
* @var string $_sourceURI
|
||||
* Source database of the Alert command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceLocURI;
|
||||
|
||||
/**
|
||||
* @var string $_targetURI
|
||||
* Target database of the Alert command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
|
||||
/**
|
||||
* @var string $_metaAnchorNext
|
||||
* Optional parameter for the Target database.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetLocURIParameters;
|
||||
|
||||
/**
|
||||
* The current time this synchronization happens, from the <Meta><Next>
|
||||
* element.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_metaAnchorNext;
|
||||
|
||||
/**
|
||||
* @var integer $_metaAnchorLast
|
||||
* The last time when synchronization happened, from the <Meta><Last>
|
||||
* element.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_metaAnchorLast;
|
||||
|
||||
/**
|
||||
* Use in xml tag.
|
||||
* The filter expression the client provided
|
||||
* (e.g. the time range for calendar synchronization)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_isInSource;
|
||||
var $_filterExpression = '';
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of Alert.
|
||||
@ -64,335 +95,403 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
||||
|
||||
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 = 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_RESULT_ALERT) {
|
||||
if ($this->_alert == ALERT_TWO_WAY ||
|
||||
$this->_alert == ALERT_ONE_WAY_FROM_CLIENT ||
|
||||
$this->_alert == ALERT_ONE_WAY_FROM_SERVER) {
|
||||
// Check if we have information about previous sync.
|
||||
$info = $state->getSyncSummary($this->_targetLocURI);
|
||||
if (is_a($info, 'DataTreeObject')) {
|
||||
$x = $info->get('ClientAnchor');
|
||||
$clientlast = $x[$type];
|
||||
$x = $info->get('ServerAnchor');
|
||||
$serverAnchorLast = $x[$type];
|
||||
} elseif (is_array($info)) {
|
||||
$clientlast = $info['ClientAnchor'];
|
||||
$serverAnchorLast = $info['ServerAnchor'];
|
||||
} else {
|
||||
$clientlast = false;
|
||||
$serverAnchorLast = 0;
|
||||
}
|
||||
$state->setServerAnchorLast($type, $serverAnchorLast);
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
if ($clientlast !== false){
|
||||
// Info about previous successful sync sessions found.
|
||||
Horde::logMessage('SyncML: Previous sync found for target ' . $type
|
||||
. '; client timestamp: ' . $clientlast,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Store client's Next Anchor in State. After successful sync
|
||||
// this is then written to persistence for negotiation of
|
||||
// further syncs.
|
||||
$state->setClientAnchorNext($type, $this->_metaAnchorNext);
|
||||
// Check if anchor sent from client matches our own stored
|
||||
// data.
|
||||
if ($clientlast == $this->_metaAnchorLast) {
|
||||
// Last sync anchors matche, TwoWaySync will do.
|
||||
$anchormatch = true;
|
||||
Horde::logMessage('SyncML: Anchor timestamps match, TwoWaySync possible. Syncing data since '
|
||||
. date('Y-m-d H:i:s', $serverAnchorLast),
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
// Server and client have different anchors, enforce
|
||||
// SlowSync/RefreshSync
|
||||
Horde::logMessage('SyncML: Client requested sync with anchor timestamp '
|
||||
. $this->_metaAnchorLast
|
||||
. ' but server has recorded timestamp '
|
||||
. $clientlast . '. Enforcing SlowSync',
|
||||
__FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$anchormatch = false;
|
||||
$clientlast = 0;
|
||||
}
|
||||
} else {
|
||||
// No info about previous sync, use SlowSync or RefreshSync.
|
||||
Horde::logMessage('SyncML: No info about previous syncs found for device ' .
|
||||
$state->getSourceURI() . ' and target ' . $type,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$clientlast = 0;
|
||||
$serverAnchorLast = 0;
|
||||
$anchormatch = false;
|
||||
}
|
||||
} else {
|
||||
// SlowSync requested, no anchor check required.
|
||||
$anchormatch = true;
|
||||
}
|
||||
|
||||
$info = $state->getSyncSummary($this->_targetLocURI);
|
||||
#Horde::logMessage("SyncML: Anchor match, TwoWaySync sinceee " . $clientlast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (is_a($info, 'DataTreeObject')) {
|
||||
$x = $info->get('ClientAnchor');
|
||||
$clientlast = $x[$type];
|
||||
$x = $info->get('ServerAnchor');
|
||||
$state->setServerAnchorLast($type, $x[$type]);
|
||||
} elseif (is_array($info)) {
|
||||
$clientlast = $info['ClientAnchor'];
|
||||
$state->setServerAnchorLast($type, $info['ServerAnchor']);
|
||||
} else {
|
||||
$clientlast = false;
|
||||
$state->setServerAnchorLast($type, 0);
|
||||
}
|
||||
|
||||
Horde::logMessage('SyncML: checking anchor targetLocURI: clientlast: ' . $clientlast .' / '. $this->_metaAnchorLast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Set Server Anchor for this sync to current time.
|
||||
$state->setServerAnchorNext($type,time());
|
||||
if ($clientlast !== false && $clientlast == $this->_metaAnchorLast) {
|
||||
// Last Sync Anchor matches, TwoWaySync will do.
|
||||
$code = RESPONSE_OK;
|
||||
Horde::logMessage("SyncML: Anchor match, TwoWaySync since " . $clientlast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
Horde::logMessage("SyncML: Anchor mismatch, enforcing SlowSync clientlast $clientlast serverlast ".$this->_metaAnchorLast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Mismatch, enforce slow sync. 508=RESPONSE_REFRESH_REQUIRED 201=ALERT_SLOW_SYNC
|
||||
$this->_alert = 201;
|
||||
$code = 508;
|
||||
// create new synctype
|
||||
$sync = &Horde_SyncML_Sync::factory($this->_alert);
|
||||
$sync->_targetLocURI = $this->_targetLocURI;
|
||||
$sync->_sourceLocURI = $this->_sourceLocURI;
|
||||
if(isset($this->_targetLocURIParameters))
|
||||
$sync->_targetLocURIParameters = $this->_targetLocURIParameters;
|
||||
$state->setSync($this->_targetLocURI, $sync);
|
||||
// PH : no longer delete entire content_map entries for client before SlowSync,
|
||||
// use content_map to verify if content is mapped correctly
|
||||
//$state->removeAllUID($this->_targetLocURI);
|
||||
}
|
||||
// Determine sync type and status response code.
|
||||
Horde::logMessage("SyncML: Alert " . $this->_alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
switch ($this->_alert) {
|
||||
case ALERT_NEXT_MESSAGE:
|
||||
$state->setAlert222Received(true);
|
||||
case ALERT_RESULT_ALERT:
|
||||
case ALERT_NO_END_OF_DATA:
|
||||
// Nothing to do on our side
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
if ($this->_alert == ALERT_NEXT_MESSAGE) {
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setItemSourceLocURI($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
}
|
||||
}
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
return $currentCmdID;
|
||||
case ALERT_TWO_WAY:
|
||||
if ($anchormatch) {
|
||||
$synctype = ALERT_TWO_WAY;
|
||||
$response = RESPONSE_OK;
|
||||
} else {
|
||||
$synctype = ALERT_SLOW_SYNC;
|
||||
$response = RESPONSE_REFRESH_REQUIRED;
|
||||
}
|
||||
break;
|
||||
|
||||
$status = &new Horde_SyncML_Command_Status($code, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
case ALERT_SLOW_SYNC:
|
||||
$synctype = ALERT_SLOW_SYNC;
|
||||
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
|
||||
break;
|
||||
|
||||
// Mirror Next Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorNext)) {
|
||||
$status->setItemDataAnchorNext($this->_metaAnchorNext);
|
||||
}
|
||||
case ALERT_ONE_WAY_FROM_CLIENT:
|
||||
if ($anchormatch) {
|
||||
$synctype = ALERT_ONE_WAY_FROM_CLIENT;
|
||||
$response = RESPONSE_OK;
|
||||
} else {
|
||||
$synctype = ALERT_REFRESH_FROM_CLIENT;
|
||||
$response = RESPONSE_REFRESH_REQUIRED;
|
||||
}
|
||||
break;
|
||||
|
||||
// Mirror Last Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorLast)) {
|
||||
$status->setItemDataAnchorLast($this->_metaAnchorLast);
|
||||
}
|
||||
case ALERT_REFRESH_FROM_CLIENT:
|
||||
$synctype = ALERT_REFRESH_FROM_CLIENT;
|
||||
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
// We will erase the current server content,
|
||||
// then we can add the client's contents.
|
||||
|
||||
if ($state->isAuthorized()) {
|
||||
$output->startElement($state->getURI(), 'Alert', $attrs);
|
||||
$hordeType = $state->getHordeType($this->_targetLocURI);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
$state->setTargetURI($this->_targetLocURI);
|
||||
$deletes = $state->getClientItems();
|
||||
if (is_array($deletes)) {
|
||||
foreach ($deletes as $delete) {
|
||||
$registry->call($hordeType . '/delete', array($delete));
|
||||
}
|
||||
Horde::logMessage("SyncML: RefreshFromClient " . count($deletes) . " entries deleted for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
$anchormatch = false;
|
||||
break;
|
||||
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
$chars = $this->_alert;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
case ALERT_ONE_WAY_FROM_SERVER:
|
||||
if ($anchormatch) {
|
||||
$synctype = ALERT_ONE_WAY_FROM_SERVER;
|
||||
$response = RESPONSE_OK;
|
||||
} else {
|
||||
$synctype = ALERT_REFRESH_FROM_SERVER;
|
||||
$response = RESPONSE_REFRESH_REQUIRED;
|
||||
}
|
||||
break;
|
||||
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
case ALERT_REFRESH_FROM_SERVER:
|
||||
$synctype = ALERT_REFRESH_FROM_SERVER;
|
||||
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
|
||||
break;
|
||||
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $this->_sourceLocURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
|
||||
if ($this->_targetLocURI != null) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = (isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
case ALERT_RESUME:
|
||||
// @TODO: Suspend and Resume is not supported yet
|
||||
$synctype = ALERT_SLOW_SYNC;
|
||||
$response = RESPONSE_REFRESH_REQUIRED;
|
||||
break;
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
default:
|
||||
// We can't handle this one
|
||||
Horde::logMessage('SyncML: Unknown sync type ' . $this->_alert,
|
||||
__FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_BAD_REQUEST, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Anchor', $attrs);
|
||||
// Store client's Next Anchor in State and
|
||||
// set server's Next Anchor. After successful sync
|
||||
// this is then written to persistence for negotiation of
|
||||
// further syncs.
|
||||
$state->setClientAnchorNext($type, $this->_metaAnchorNext);
|
||||
$serverAnchorNext = time();
|
||||
$state->setServerAnchorNext($type, $serverAnchorNext);
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Last', $attrs);
|
||||
$chars = $state->getServerAnchorLast($type);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURIMeta(), 'Last');
|
||||
// Now set interval to retrieve server changes from, defined by
|
||||
// ServerAnchor [Last,Next]
|
||||
if ($synctype != ALERT_TWO_WAY &&
|
||||
$synctype != ALERT_ONE_WAY_FROM_CLIENT &&
|
||||
$synctype != ALERT_ONE_WAY_FROM_SERVER) {
|
||||
$serverAnchorLast = 0;
|
||||
#if (!$anchormatch) {
|
||||
// Erase existing map:
|
||||
$state->removeAllUID($this->_targetLocURI);
|
||||
#}
|
||||
}
|
||||
// Now create the actual SyncML_Sync object, if it doesn't exist yet.
|
||||
$sync = &$state->getSync($this->_targetLocURI);
|
||||
if (!$sync) {
|
||||
Horde::logMessage('SyncML: Creating SyncML_Sync object for target '
|
||||
. $this->_targetLocURI . '; sync type ' . $synctype,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$sync = &Horde_SyncML_Sync::factory($synctype);
|
||||
$state->clearConflictItems($this->_targetLocURI);
|
||||
}
|
||||
$sync->setTargetLocURI($this->_targetLocURI);
|
||||
$sync->setSourceLocURI($this->_sourceLocURI);
|
||||
$sync->setLocName($state->getLocName()); // We need it for conflict handling
|
||||
$sync->setsyncType($synctype);
|
||||
$sync->setFilterExpression($this->_filterExpression);
|
||||
$state->setSync($this->_targetLocURI, $sync);
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Next', $attrs);
|
||||
$chars = $state->getServerAnchorNext($type);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURIMeta(), 'Next');
|
||||
$status = new Horde_SyncML_Command_Status($response, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
|
||||
$output->endElement($state->getURIMeta(), 'Anchor');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
$output->endElement($state->getURI(), 'Alert');
|
||||
// Mirror Next Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorNext)) {
|
||||
$status->setItemDataAnchorNext($this->_metaAnchorNext);
|
||||
}
|
||||
|
||||
// still needed? lars
|
||||
$state->_sendFinal = true;
|
||||
|
||||
$currentCmdID++;
|
||||
// Mirror Last Anchor from client back to client.
|
||||
if (isset($this->_metaAnchorLast)) {
|
||||
$status->setItemDataAnchorLast($this->_metaAnchorLast);
|
||||
}
|
||||
|
||||
if($state->_devinfoRequested == false &&
|
||||
$this->_sourceLocURI != null &&
|
||||
is_a($state->getPreferedContentTypeClient($this->_sourceLocURI), 'PEAR_Error')) {
|
||||
|
||||
$output->startElement($state->getURI(), 'Get', $attrs);
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$output->characters($currentCmdID);
|
||||
$currentCmdID++;
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
if(is_a($output, 'XML_WBXML_Encoder')) {
|
||||
$output->characters('application/vnd.syncml-devinf+wbxml');
|
||||
} else {
|
||||
$output->characters('application/vnd.syncml-devinf+xml');
|
||||
}
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters(($state->getVersion() == 0) ? './devinf10' : './devinf11');
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
|
||||
$output->endElement($state->getURI(), 'Get');
|
||||
|
||||
$state->_devinfoRequested = true;
|
||||
}
|
||||
}
|
||||
$output->startElement($state->getURI(), 'Alert', $attrs);
|
||||
|
||||
} elseif ($this->_alert == ALERT_NEXT_MESSAGE) {
|
||||
$status = &new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
$status->setItemSourceLocURI($this->_sourceLocURI);
|
||||
$status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$state->setAlert222Received(true);
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
$chars = $synctype;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
|
||||
} else {
|
||||
$status = &new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$status->setSourceRef($this->_sourceLocURI);
|
||||
}
|
||||
if ($this->_targetLocURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
|
||||
}
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
}
|
||||
if ($this->_sourceLocURI != null) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $this->_sourceLocURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
|
||||
if ($this->_targetLocURI != null) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = (isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Anchor', $attrs);
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Last', $attrs);
|
||||
$chars = $state->getServerAnchorLast($type);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURIMeta(), 'Last');
|
||||
|
||||
$output->startElement($state->getURIMeta(), 'Next', $attrs);
|
||||
$chars = $state->getServerAnchorNext($type);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURIMeta(), 'Next');
|
||||
|
||||
$output->endElement($state->getURIMeta(), 'Anchor');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
$output->endElement($state->getURI(), 'Alert');
|
||||
|
||||
// Final packet of this message
|
||||
$state->_sendFinal = true;
|
||||
|
||||
$currentCmdID++;
|
||||
|
||||
if ($state->_devinfoRequested == false &&
|
||||
$this->_sourceLocURI != null &&
|
||||
is_a($state->getPreferedContentTypeClient($this->_sourceLocURI), 'PEAR_Error')) {
|
||||
|
||||
Horde::logMessage("SyncML: PreferedContentTypeClient missing, sending <Get>", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$output->startElement($state->getURI(), 'Get', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$output->characters($currentCmdID);
|
||||
$currentCmdID++;
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
if (is_a($output, 'XML_WBXML_Encoder')) {
|
||||
$output->characters('application/vnd.syncml-devinf+wbxml');
|
||||
} else {
|
||||
$output->characters('application/vnd.syncml-devinf+xml');
|
||||
}
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
if ($state->getVersion() == 2) {
|
||||
$output->characters('./devinf12');
|
||||
} elseif ($state->getVersion() == 1) {
|
||||
$output->characters('./devinf11');
|
||||
} else {
|
||||
$output->characters('./devinf10');
|
||||
}
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
|
||||
$output->endElement($state->getURI(), 'Get');
|
||||
|
||||
$state->_devinfoRequested = true;
|
||||
}
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property sourceURI.
|
||||
* End element handler for the XML parser, delegated from
|
||||
* SyncML_ContentHandler::endElement().
|
||||
*
|
||||
* @param string $sourceURI New value of property sourceURI.
|
||||
* @param string $uri The namespace URI of the element.
|
||||
* @param string $element The element tag name.
|
||||
*/
|
||||
function setSourceLocURI($sourceURI)
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
$this->_sourceLocURI = $sourceURI;
|
||||
}
|
||||
|
||||
function getTargetLocURI()
|
||||
{
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property targetURI.
|
||||
*
|
||||
* @param string $targetURI New value of property targetURI.
|
||||
*/
|
||||
// is this function still used???
|
||||
function setTargetURI($targetURI)
|
||||
{
|
||||
$this->_targetLocURI = $targetURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property targetURI.
|
||||
*
|
||||
* @param string $targetURI New value of property targetURI.
|
||||
*/
|
||||
function setTargetLocURI($targetURI)
|
||||
{
|
||||
$this->_targetLocURI = $targetURI;
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 3:
|
||||
if ($element == 'Target') {
|
||||
$this->_isInSource = false;
|
||||
} else {
|
||||
$this->_isInSource = true;
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'Data') {
|
||||
$this->_alert = intval(trim($this->_chars));
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI') {
|
||||
switch ($this->_stack[2]) {
|
||||
case 'Source':
|
||||
$this->_sourceLocURI = trim($this->_chars);
|
||||
break;
|
||||
case 'Target':
|
||||
$targetLocURIData = explode('?/',trim($this->_chars));
|
||||
|
||||
$this->_targetLocURI = $targetLocURIData[0];
|
||||
|
||||
if (isset($targetLocURIData[1])) {
|
||||
$this->_targetLocURIParameters = $targetLocURIData[1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
switch ($element) {
|
||||
case 'Next':
|
||||
$this->_metaAnchorNext = trim($this->_chars);
|
||||
break;
|
||||
case 'Last':
|
||||
$this->_metaAnchorLast = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
if ($element == 'Data'
|
||||
&& $this->_stack[2] == 'Target'
|
||||
&& $this->_stack[3] == 'Filter'
|
||||
&& $this->_stack[4] == 'Record'
|
||||
&& $this->_stack[5] == 'Item') {
|
||||
$this->_filterExpression = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 1:
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
$sync = $state->getSync($this->_targetLocURI);
|
||||
|
||||
if (!$sync && $this->_alert < ALERT_RESULT_ALERT) {
|
||||
Horde::logMessage('SyncML: create new sync for ' . $this->_targetLocURI . ' ' . $this->_alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$sync = &Horde_SyncML_Sync::factory($this->_alert);
|
||||
|
||||
$sync->_targetLocURI = $this->_targetLocURI;
|
||||
$sync->_sourceLocURI = $this->_sourceLocURI;
|
||||
if(isset($this->_targetLocURIParameters)) {
|
||||
$sync->_targetLocURIParameters = $this->_targetLocURIParameters;
|
||||
}
|
||||
|
||||
$state->setSync($this->_targetLocURI, $sync);
|
||||
|
||||
if($this->_alert == ALERT_SLOW_SYNC || $this->_alert == ALERT_REFRESH_FROM_SERVER) {
|
||||
$state->removeAllUID($this->_targetLocURI);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ($element == 'Data') {
|
||||
$this->_alert = intval(trim($this->_chars));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_isInSource) {
|
||||
$this->_sourceLocURI = trim($this->_chars);
|
||||
} else {
|
||||
$targetLocURIData = explode('?/',trim($this->_chars));
|
||||
|
||||
$this->_targetLocURI = $targetLocURIData[0];
|
||||
|
||||
if(isset($targetLocURIData[1])) {
|
||||
$this->_targetLocURIParameters = $targetLocURIData[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if ($element == 'Next') {
|
||||
$this->_metaAnchorNext = trim($this->_chars);
|
||||
} else if ($element == 'Last') {
|
||||
$this->_metaAnchorLast = trim($this->_chars);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
function getAlert()
|
||||
{
|
||||
return $this->_alert;
|
||||
}
|
||||
|
||||
function setAlert($alert)
|
||||
{
|
||||
$this->_alert = $alert;
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,24 +1,31 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* The Horde_SyncML_Command_Final class.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command/Final.php,v 1.10 2004/05/26 17:41:30 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
class Horde_SyncML_Command_Final extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Final';
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
@ -1,34 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
include_once 'Horde/SyncML/Command/Results.php';
|
||||
|
||||
/**
|
||||
* The Horde_SyncML_Command_Get class.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command/Get.php,v 1.14 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
$ref = ($state->getVersion() == 0) ? './devinf10' : './devinf11';
|
||||
if ($state->getVersion() == 2) {
|
||||
$ref = './devinf12';
|
||||
} elseif ($state->getVersion() == 1) {
|
||||
$ref = './devinf11';
|
||||
} else {
|
||||
$ref = './devinf10';
|
||||
}
|
||||
|
||||
$status = &new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), 'Get');
|
||||
$status = new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), 'Get');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
$status->setTargetRef($ref);
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
@ -74,7 +79,13 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'DevInf', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'VerDTD', $attrs);
|
||||
$output->characters(($state->getVersion() == 0) ? '1.0' : '1.1');
|
||||
if ($state->getVersion() == 2) {
|
||||
$output->characters('1.2');
|
||||
} elseif($state->getVersion() == 1) {
|
||||
$output->characters('1.1');
|
||||
} else {
|
||||
$output->characters('1.0');
|
||||
}
|
||||
$output->endElement($state->getURIDevInf() , 'VerDTD', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'Man', $attrs);
|
||||
$output->characters('www.egroupware.org');
|
||||
@ -85,12 +96,24 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
$output->startElement($state->getURIDevInf() , 'DevTyp', $attrs);
|
||||
$output->characters('server');
|
||||
$output->endElement($state->getURIDevInf() , 'DevTyp', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'UTC', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'UTC', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SupportNumberOfChanges', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'SupportNumberOfChanges', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SupportLargeObjs', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'SupportLargeObjs', $attrs);
|
||||
$this->_writeDataStore('./notes', 'text/x-vnote', '1.1', $output,
|
||||
array('text/plain' => '1.0'));
|
||||
$this->_writeDataStore('./contacts', 'text/x-vcard', '2.1', $output);
|
||||
$this->_writeDataStore('./tasks', 'text/x-vcalendar', '1.0', $output);
|
||||
$this->_writeDataStore('./calendar', 'text/x-vcalendar', '1.0', $output);
|
||||
$this->_writeDataStore('./caltasks', 'text/x-vcalendar', '1.0', $output);
|
||||
$this->_writeDataStore('./contacts', 'text/vcard', '3.0', $output,
|
||||
array('text/x-vcard' => '2.1'));
|
||||
$this->_writeDataStore('./tasks', 'text/calendar', '2.0', $output,
|
||||
array('text/x-vcalendar' => '1.0'));
|
||||
$this->_writeDataStore('./calendar', 'text/calendar', '2.0', $output,
|
||||
array('text/x-vcalendar' => '1.0'));
|
||||
$this->_writeDataStore('./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'));
|
||||
$output->endElement($state->getURIDevInf() , 'DevInf', $attrs);
|
||||
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
@ -111,7 +134,7 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
* @param string $version: data for <(R|T)x-Pref><VerCT>
|
||||
* @param string &$output contenthandler that will received the output.
|
||||
* @param array $additionaltypes: array of additional types for Tx and Rx;
|
||||
* format array('text/vcard' => '2.0')
|
||||
* format array('text/vcard' => '3.0')
|
||||
*/
|
||||
function _writeDataStore($sourceref, $mimetype, $version, &$output,
|
||||
$additionaltypes = false)
|
||||
@ -124,6 +147,9 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
$output->startElement($state->getURIDevInf() , 'SourceRef', $attrs);
|
||||
$output->characters($sourceref);
|
||||
$output->endElement($state->getURIDevInf() , 'SourceRef', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'MaxGUIDSize', $attrs);
|
||||
$output->characters(255);
|
||||
$output->endElement($state->getURIDevInf() , 'MaxGUIDSize', $attrs);
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'Rx-Pref', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'CTType', $attrs);
|
||||
@ -170,12 +196,13 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command {
|
||||
}
|
||||
|
||||
$output->startElement($state->getURIDevInf() , 'SyncCap', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SyncType', $attrs);
|
||||
$output->characters('1');
|
||||
$output->endElement($state->getURIDevInf() , 'SyncType', $attrs);
|
||||
$output->startElement($state->getURIDevInf() , 'SyncType', $attrs);
|
||||
$output->characters('2');
|
||||
$output->endElement($state->getURIDevInf() , 'SyncType', $attrs);
|
||||
// We support all sync Types from 1-6: two way, slow, refresh|update
|
||||
// from client|server
|
||||
for ($i = 1; $i <= 6; ++$i) {
|
||||
$output->startElement($state->getURIDevInf(), 'SyncType', $attrs);
|
||||
$output->characters($i);
|
||||
$output->endElement($state->getURIDevInf(), 'SyncType', $attrs);
|
||||
}
|
||||
$output->endElement($state->getURIDevInf() , 'SyncCap', $attrs);
|
||||
$output->endElement($state->getURIDevInf() , 'DataStore', $attrs);
|
||||
}
|
||||
|
@ -1,43 +1,60 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* The Horde_SyncML_Map class provides a SyncML implementation of
|
||||
* the Map command as defined in SyncML Representation Protocol,
|
||||
* version 1.0.1 5.5.8.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Command/Map.php,v 1.1 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2004 Karsten Fourmont <fourmont@gmx.de>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
class Horde_SyncML_Command_Map extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* @var string $_sourceURI
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Map';
|
||||
|
||||
/**
|
||||
* Source database of the Map command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceLocURI;
|
||||
|
||||
/**
|
||||
* @var string $_targetURI
|
||||
* Target database of the Map command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
|
||||
/**
|
||||
* Use in xml tag.
|
||||
* Recipient map item specifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_isInSource;
|
||||
|
||||
var $_mapTarget;
|
||||
|
||||
/**
|
||||
* Originator map item specifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_mapSource;
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
@ -46,7 +63,7 @@ class Horde_SyncML_Command_Map extends Horde_SyncML_Command {
|
||||
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
$status = &new Horde_SyncML_Command_Status($state->isAuthorized() ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS, 'Map');
|
||||
$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);
|
||||
@ -60,76 +77,25 @@ class Horde_SyncML_Command_Map extends Horde_SyncML_Command {
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property sourceURI.
|
||||
*
|
||||
* @param string $sourceURI New value of property sourceURI.
|
||||
*/
|
||||
function setSourceLocURI($sourceURI)
|
||||
{
|
||||
$this->_sourceURI = $sourceURI;
|
||||
}
|
||||
|
||||
function getTargetLocURI()
|
||||
{
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property targetURI.
|
||||
*
|
||||
* @param string $targetURI New value of property targetURI.
|
||||
*/
|
||||
function setTargetURI($targetURI)
|
||||
{
|
||||
$this->_targetURI = $targetURI;
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
if ($element == 'Target') {
|
||||
$this->_isInSource = false;
|
||||
}
|
||||
if ($element == 'Source') {
|
||||
$this->_isInSource = true;
|
||||
}
|
||||
if ($element == 'MapItem') {
|
||||
unset($this->_mapTarget);
|
||||
unset($this->_mapSource);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if ($element == 'Target') {
|
||||
$this->_isInSource = false;
|
||||
}
|
||||
if ($element == 'Source') {
|
||||
$this->_isInSource = true;
|
||||
}
|
||||
break;
|
||||
if (count($this->_stack) == 2 &&
|
||||
$element == 'MapItem') {
|
||||
unset($this->_mapTarget);
|
||||
unset($this->_mapSource);
|
||||
}
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 1:
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
$sync = $state->getSync($this->_targetLocURI);
|
||||
|
||||
if (!$sync) {
|
||||
}
|
||||
|
||||
$_SESSION['SyncML.state'] = $state;
|
||||
break;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'MapItem') {
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
$sync = $state->getSync($this->_targetLocURI);
|
||||
if (!$state->isAuthorized()) {
|
||||
Horde::logMessage('SyncML: Not Authorized in the middle of MapItem!', __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
@ -149,26 +115,20 @@ class Horde_SyncML_Command_Map extends Horde_SyncML_Command {
|
||||
|
||||
case 3:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_isInSource) {
|
||||
if ($this->_stack[1] == 'Source') {
|
||||
$this->_sourceLocURI = trim($this->_chars);
|
||||
} else {
|
||||
} elseif ($this->_stack[1] == 'Target') {
|
||||
$targetLocURIData = explode('?/',trim($this->_chars));
|
||||
|
||||
$this->_targetLocURI = $targetLocURIData[0];
|
||||
|
||||
if(isset($targetLocURIData[1]))
|
||||
{
|
||||
$this->_targetLocURIParameters = $targetLocURIData[1];
|
||||
}
|
||||
$this->_targetLocURI = $targetLocURIData[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI') {
|
||||
if ($this->_isInSource) {
|
||||
if ($this->_stack[2] == 'Source') {
|
||||
$this->_mapSource = trim($this->_chars);
|
||||
} else {
|
||||
} elseif ($this->_stack[2] == 'Target') {
|
||||
$this->_mapTarget = trim($this->_chars);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Put.php,v 1.12 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Put';
|
||||
|
||||
/**
|
||||
* @var string $_manufacturer
|
||||
*/
|
||||
@ -36,6 +44,12 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
|
||||
var $_oem;
|
||||
|
||||
/**
|
||||
* @var array $_deviceInfo
|
||||
*/
|
||||
|
||||
var $_deviceInfo;
|
||||
|
||||
/**
|
||||
* @var string $_softwareVersion
|
||||
*/
|
||||
@ -43,62 +57,63 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
var $_softwareVersion;
|
||||
|
||||
function endElement($uri, $element) {
|
||||
switch ($this->_xmlStack) {
|
||||
switch (count($this->_stack)) {
|
||||
case 5:
|
||||
switch($element) {
|
||||
switch ($element) {
|
||||
case 'DataStore':
|
||||
$this->_deviceInfo['dataStore'][$this->_sourceReference] = array(
|
||||
$this->_deviceInfo['dataStore'][$this->_sourceReference] = array (
|
||||
'maxGUIDSize' => $this->_maxGUIDSize,
|
||||
'rxPreference' => $this->_rxPreference,
|
||||
'txPreference' => $this->_txPreference,
|
||||
'syncCapabilities' => $this->_syncCapabilities,
|
||||
'properties' => $this->_properties,
|
||||
);
|
||||
break;
|
||||
|
||||
|
||||
case 'DevID':
|
||||
$this->_deviceInfo['deviceID'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'DevTyp':
|
||||
$this->_deviceInfo['deviceType'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'FwV':
|
||||
$this->_deviceInfo['firmwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'HwV':
|
||||
$this->_deviceInfo['hardwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'Man':
|
||||
$this->_deviceInfo['manufacturer'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'Mod':
|
||||
$this->_deviceInfo['model'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'OEM':
|
||||
$this->_deviceInfo['oem'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'SwV':
|
||||
$this->_deviceInfo['softwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'SupportLargeObjs':
|
||||
$this->_deviceInfo['supportLargeObjs'] = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'SupportNumberOfChanges':
|
||||
$this->_deviceInfo['supportNumberOfChanges'] = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'UTC':
|
||||
$this->_deviceInfo['UTC'] = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'VerDTD':
|
||||
$this->_deviceInfo['DTDVersion'] = trim($this->_chars);
|
||||
break;
|
||||
@ -109,18 +124,18 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
case 'MaxGUIDSize':
|
||||
$this->_maxGUIDSize = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'Rx-Pref':
|
||||
$this->_rxPreference = array(
|
||||
'contentType' => $this->_contentType,
|
||||
'contentVersion' => $this->_contentVersion,
|
||||
);
|
||||
break;
|
||||
|
||||
|
||||
case 'SourceRef':
|
||||
$this->_sourceReference = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'Tx-Pref':
|
||||
$this->_txPreference = array(
|
||||
'contentType' => $this->_contentType,
|
||||
@ -129,7 +144,7 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 7:
|
||||
switch($element) {
|
||||
case 'CTType':
|
||||
@ -178,87 +193,165 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'SyncType':
|
||||
$this->_syncCapabilities[] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
|
||||
case 'VerCT':
|
||||
$this->_contentVersion = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Property':
|
||||
if (isset($this->_PropName)) {
|
||||
$this->_properties[$this->_contentType][$this->_contentVersion][$this->_PropName] = array(
|
||||
'Size' => $this->_PropSize,
|
||||
'NoTruncate' => $this->_PropNoTruncate,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
switch($element) {
|
||||
case 'PropName':
|
||||
$this->_PropName = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Size':
|
||||
$this->_PropSize = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'NoTruncate':
|
||||
$this->_PropNoTruncate = true;
|
||||
break;
|
||||
}
|
||||
beak;
|
||||
}
|
||||
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
|
||||
function finalizeDeviceInfo()
|
||||
{
|
||||
// get some more information about the device from out of band data
|
||||
|
||||
$ua = $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
if (preg_match("/^\s*Funambol (.*) (\d+\.\d+\.\d+)\s*$/i", $ua, $matches))
|
||||
{
|
||||
if (!isset($this->_deviceInfo['manufacturer']))
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
if (!isset($this->_deviceInfo['model']))
|
||||
$this->_deviceInfo['model'] = 'Funambol ' . trim($matches[1]);
|
||||
if (!isset($this->_deviceInfo['softwareVersion']))
|
||||
$this->_deviceInfo['softwareVersion'] = $matches[2];
|
||||
if (preg_match("/^\s*Funambol (.*) [^\d]*(\d+\.?\d*)[\.|\d]*\s*$/i", $ua, $matches)) {
|
||||
// Funambol uses the hardware Manufacturer we don't care about
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
$this->_deviceInfo['model'] = trim($matches[1]);
|
||||
$this->_deviceInfo['softwareVersion'] = floatval($matches[2]);
|
||||
|
||||
if (!isset($this->_deviceInfo['deviceType']))
|
||||
{
|
||||
switch (strtolower(trim($matches[1])))
|
||||
{
|
||||
case 'outlook plug-in':
|
||||
default:
|
||||
$this->_deviceInfo['deviceType'] = 'workstation';
|
||||
break;
|
||||
if (!isset($this->_deviceInfo['deviceType'])) {
|
||||
switch (strtolower(trim($matches[1]))) {
|
||||
case 'pocket pc plug-in':
|
||||
$this->_deviceInfo['deviceType'] = 'windowsmobile';
|
||||
break;
|
||||
case 'outlook plug-in':
|
||||
default:
|
||||
$this->_deviceInfo['deviceType'] = 'workstation';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$devid = $this->_deviceInfo['deviceID'];
|
||||
switch (strtolower($devid))
|
||||
{
|
||||
switch (strtolower($this->_deviceInfo['deviceID'])) {
|
||||
case 'fmz-thunderbird-plugin':
|
||||
if (empty($this->_devinceInfo['manufacturer']))
|
||||
if (empty($this->_devinceInfo['manufacturer'])) {
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
if (empty($this->_devinceInfo['model']))
|
||||
}
|
||||
if (empty($this->_devinceInfo['model'])) {
|
||||
$this->_deviceInfo['model'] = 'ThunderBird';
|
||||
if (empty($this->_devinceInfo['softwareVersion']))
|
||||
$this->_deviceInfo['softwareVersion'] = '0.3';
|
||||
}
|
||||
if (empty($this->_devinceInfo['softwareVersion'])) {
|
||||
$this->_deviceInfo['softwareVersion'] = '3.0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (preg_match('/Funambol.*/i', $this->_deviceInfo['manufacturer'])) {
|
||||
$this->_deviceInfo['supportLargeObjs'] = true;
|
||||
}
|
||||
|
||||
switch (strtolower($this->_deviceInfo['manufacturer'])) {
|
||||
case 'sonyericsson':
|
||||
case 'sony ericsson':
|
||||
if (strtolower($this->_deviceInfo['model']) == 'w890i') {
|
||||
$this->_deviceInfo['supportLargeObjs'] = false;
|
||||
}
|
||||
break;
|
||||
case 'synthesis ag':
|
||||
foreach ($this->_deviceInfo['dataStore'] as &$ctype) {
|
||||
$ctype['maxGUIDSize'] = 255;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function output($currentCmdID, &$output ) {
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$status = &new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), 'Put');
|
||||
|
||||
$status = new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), $this->_cmdName);
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
$ref = ($state->getVersion() == 0) ? './devinf10' : './devinf11';
|
||||
|
||||
|
||||
if ($state->getVersion() == 2) {
|
||||
$ref = './devinf12';
|
||||
} elseif ($state->getVersion() == 1) {
|
||||
$ref = './devinf11';
|
||||
} else {
|
||||
$ref = './devinf10';
|
||||
}
|
||||
|
||||
$status->setSourceRef($ref);
|
||||
|
||||
|
||||
if($state->isAuthorized()) {
|
||||
$this->finalizeDeviceInfo();
|
||||
|
||||
if(count((array)$this->_deviceInfo) > 0) {
|
||||
$state->setClientDeviceInfo($this->_deviceInfo);
|
||||
$devInfo = $state->getClientDeviceInfo();
|
||||
if (is_array($devInfo['dataStore'])
|
||||
&& $devInfo['softwareVersion'] == $this->_deviceInfo['softwareVersion']) {
|
||||
// merge with existing information
|
||||
$devInfo['dataStore'] =
|
||||
array_merge($devInfo['dataStore'],
|
||||
$this->_deviceInfo['dataStore']);
|
||||
} else {
|
||||
// new device
|
||||
$devInfo = $this->_deviceInfo;
|
||||
}
|
||||
#Horde::logMessage("SyncML: Put DeviceInfo:\n" . print_r($this->_deviceInfo, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setClientDeviceInfo($devInfo);
|
||||
$state->writeClientDeviceInfo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs) {
|
||||
#Horde::logMessage("SyncML: startElement[" . count($this->_stack) . "] $uri $element", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
switch (count($this->_stack)) {
|
||||
case 4:
|
||||
switch ($element) {
|
||||
case 'DataStore':
|
||||
$this->_properties = array();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
switch ($element) {
|
||||
case 'Property':
|
||||
unset($this->_PropName);
|
||||
$this->_PropSize = -1;
|
||||
$this->_PropNoTruncate = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Replace.php,v 1.7 2004/05/26 17:41:30 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Final extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Replace';
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
return $currentCmdID;
|
||||
|
@ -1,291 +1,36 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Results.php,v 1.11 2004/07/02 19:24:44 chuck Exp $
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* The SyncML_Command_Results class provides a SyncML implementation of the
|
||||
* Results command as defined in SyncML Representation Protocol, version 1.1,
|
||||
* section 5.5.12.
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* The Results command is used to return the results of a Search or Get
|
||||
* command. Currently SyncML_Command_Results behaves the same as
|
||||
* SyncML_Command_Put. The only results we get is the same DevInf as for the
|
||||
* Put command.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
class Horde_SyncML_Command_Results extends Horde_SyncML_Command {
|
||||
include_once 'Horde/SyncML/Command/Put.php';
|
||||
|
||||
var $_cmdRef;
|
||||
var $_type;
|
||||
var $_data;
|
||||
var $_locSourceURI;
|
||||
var $_deviceInfo;
|
||||
|
||||
function endElement($uri, $element) {
|
||||
#Horde::logMessage('SyncML: put endelement ' . $element . ' chars ' . $this->_chars, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 5:
|
||||
switch($element) {
|
||||
case 'DataStore':
|
||||
$this->_deviceInfo['dataStore'][$this->_sourceReference] = array (
|
||||
'maxGUIDSize' => $this->_maxGUIDSize,
|
||||
'rxPreference' => $this->_rxPreference,
|
||||
'txPreference' => $this->_txPreference,
|
||||
'syncCapabilities' => $this->_syncCapabilities,
|
||||
);
|
||||
break;
|
||||
|
||||
case 'DevID':
|
||||
$this->_deviceInfo['deviceID'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'DevTyp':
|
||||
$this->_deviceInfo['deviceType'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'FwV':
|
||||
$this->_deviceInfo['firmwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'HwV':
|
||||
$this->_deviceInfo['hardwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Man':
|
||||
$this->_deviceInfo['manufacturer'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Mod':
|
||||
$this->_deviceInfo['model'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'OEM':
|
||||
$this->_deviceInfo['oem'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'SwV':
|
||||
$this->_deviceInfo['softwareVersion'] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'SupportLargeObjs':
|
||||
$this->_deviceInfo['supportLargeObjs'] = true;
|
||||
break;
|
||||
|
||||
case 'SupportNumberOfChanges':
|
||||
$this->_deviceInfo['supportNumberOfChanges'] = true;
|
||||
break;
|
||||
|
||||
case 'UTC':
|
||||
$this->_deviceInfo['UTC'] = true;
|
||||
break;
|
||||
|
||||
case 'VerDTD':
|
||||
$this->_deviceInfo['DTDVersion'] = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
class Horde_SyncML_Command_Results extends Horde_SyncML_Command_Put {
|
||||
|
||||
case 6:
|
||||
switch($element) {
|
||||
case 'MaxGUIDSize':
|
||||
$this->_maxGUIDSize = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Rx-Pref':
|
||||
$this->_rxPreference = array (
|
||||
'contentType' => $this->_contentType,
|
||||
'contentVersion' => $this->_contentVersion,
|
||||
);
|
||||
break;
|
||||
|
||||
case 'SourceRef':
|
||||
$this->_sourceReference = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'Tx-Pref':
|
||||
$this->_txPreference = array(
|
||||
'contentType' => $this->_contentType,
|
||||
'contentVersion' => $this->_contentVersion,
|
||||
);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
switch($element) {
|
||||
case 'CTType':
|
||||
$this->_contentType = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'SyncType':
|
||||
$this->_syncCapabilities[] = trim($this->_chars);
|
||||
break;
|
||||
|
||||
case 'VerCT':
|
||||
$this->_contentVersion = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Results';
|
||||
|
||||
function finalizeDeviceInfo()
|
||||
{
|
||||
// get some more information about the device from out of band data
|
||||
|
||||
$ua = $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
if (preg_match("/^\s*Funambol (.*) (\d+\.\d+\.\d+)\s*$/i", $ua, $matches))
|
||||
{
|
||||
if (!isset($this->_deviceInfo['manufacturer']))
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
if (!isset($this->_deviceInfo['model']))
|
||||
$this->_deviceInfo['model'] = 'Funambol ' . trim($matches[1]);
|
||||
if (!isset($this->_deviceInfo['softwareVersion']))
|
||||
$this->_deviceInfo['softwareVersion'] = $matches[2];
|
||||
|
||||
if (!isset($this->_deviceInfo['deviceType']))
|
||||
{
|
||||
switch (strtolower(trim($matches[1])))
|
||||
{
|
||||
case 'outlook plug-in':
|
||||
default:
|
||||
$this->_deviceInfo['deviceType'] = 'workstation';
|
||||
break;
|
||||
case 'pocket pc plug-in':
|
||||
$this->_deviceInfo['deviceType'] = 'windowsmobile';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$devid = $this->_deviceInfo['deviceID'];
|
||||
switch (strtolower($devid))
|
||||
{
|
||||
case 'fmz-thunderbird-plugin':
|
||||
if (empty($this->_devinceInfo['manufacturer']))
|
||||
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
||||
if (empty($this->_devinceInfo['model']))
|
||||
$this->_deviceInfo['model'] = 'ThunderBird';
|
||||
if (empty($this->_devinceInfo['softwareVersion']))
|
||||
$this->_deviceInfo['softwareVersion'] = '0.3';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function output($currentCmdID, &$output) {
|
||||
if(!isset($this->_locSourceURI)) {
|
||||
#Horde::logMessage('SyncML: BIG TODO!!!!!!!!!!!!!!!!!! parse reply', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$status = &new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), 'Results');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
$ref = ($state->getVersion() == 0) ? './devinf10' : './devinf11';
|
||||
|
||||
$status->setSourceRef($ref);
|
||||
|
||||
if($state->isAuthorized()) {
|
||||
$this->finalizeDeviceInfo();
|
||||
if(count((array)$this->_deviceInfo) > 0) {
|
||||
$state->setClientDeviceInfo($this->_deviceInfo);
|
||||
$state->writeClientDeviceInfo();
|
||||
}
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
} else {
|
||||
#Horde::logMessage('SyncML: BIG TODO!!!!!!!!!!!!!!!!!! generate reponse', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
$attrs = array();
|
||||
$output->startElement($state->getURI(), 'Results', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'MsgRef', $attrs);
|
||||
$chars = $state->getMsgID();
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'MsgRef');
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdRef', $attrs);
|
||||
$chars = $this->_cmdRef;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdRef');
|
||||
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
$output->characters($this->_type);
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $this->_locSourceURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
|
||||
// Need to send this information as opaque data so the WBXML
|
||||
// will understand it.
|
||||
$output->opaque($this->_data);
|
||||
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
|
||||
$output->endElement($state->getURI(), 'Results');
|
||||
|
||||
$currentCmdID++;
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property cmdRef.
|
||||
*
|
||||
* @param string $cmdRef New value of property cmdRef.
|
||||
*/
|
||||
function setCmdRef($cmdRef) {
|
||||
$this->_cmdRef = $cmdRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property Type.
|
||||
*
|
||||
* @param string $type New value of property type.
|
||||
*/
|
||||
function setType($type) {
|
||||
$this->_type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property data.
|
||||
*
|
||||
* @param string $data New value of property data.
|
||||
*/
|
||||
function setData($data) {
|
||||
$this->_data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property locSourceURI.
|
||||
*
|
||||
* @param string $locSourceURI New value of property locSourceURI.
|
||||
*/
|
||||
function setlocSourceURI($locSourceURI) {
|
||||
$this->_locSourceURI = $locSourceURI;
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Status.php,v 1.15 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Status';
|
||||
|
||||
/**
|
||||
* The Response code of the command sent to the client, that this
|
||||
* Status response refers to.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_response;
|
||||
|
||||
/**
|
||||
* The command ID (CmdID) of the command sent to the client, that this
|
||||
* Status response refers to.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_cmdRef;
|
||||
|
||||
/**
|
||||
* Must be present.
|
||||
* The command (Add, Replace, etc) sent to the client, that this Status
|
||||
* response refers to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmd;
|
||||
|
||||
/**
|
||||
* Must if not null (what does this mean?).
|
||||
* The server ID of the sent object, that this Status response refers to.
|
||||
*
|
||||
* This element is optional. If specified, Status response refers to a
|
||||
* single Item in the command sent to the client. It refers to all Items in
|
||||
* the sent command otherwise.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceRef;
|
||||
|
||||
|
||||
/**
|
||||
* The client ID of the sent object, that this Status response refers to.
|
||||
*
|
||||
* This element is optional. If specified, Status response refers to a
|
||||
* single Item in the command sent to the client. It refers to all Items in
|
||||
* the sent command otherwise.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetRef;
|
||||
|
||||
var $_chalMetaFormat;
|
||||
@ -48,6 +87,15 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
|
||||
var $_itemSourceLocURI;
|
||||
|
||||
var $_syncItems;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param integer $response The response code.
|
||||
* @param string $cmd The command sent to the client,
|
||||
* that this Status response refers to.
|
||||
*/
|
||||
function Horde_SyncML_Command_Status($response = null, $cmd = null)
|
||||
{
|
||||
if ($response != null) {
|
||||
@ -61,12 +109,11 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$attrs = array();
|
||||
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
if ($this->_cmd != null) {
|
||||
$attrs = array();
|
||||
$output->startElement($state->getURI(), 'Status', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
@ -174,61 +221,41 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
|
||||
if (isset($this->_itemTargetLocURI) && isset($this->_itemSourceLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
if (isset($this->_syncItems)) {
|
||||
// Support multible items per command
|
||||
foreach ($this->_syncItems as $locURI => &$syncItem) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($locURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
} elseif (isset($this->_itemTargetLocURI) || isset($this->_itemSourceLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemTargetLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemSourceLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
if (isset($this->_itemTargetLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemTargetLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
if (isset($this->_itemSourceLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemSourceLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
|
||||
$output->endElement($state->getURI(), 'Status');
|
||||
|
||||
$currentCmdID++;
|
||||
|
||||
// moredata pending request them
|
||||
/* if($this->_response == RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED) {
|
||||
$output->startElement($state->getURI(), 'Alert', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
$output->characters(ALERT_NEXT_MESSAGE);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
|
||||
if (isset($this->_itemTargetLocURI) && isset($this->_itemSourceLocURI)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemTargetLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$output->characters($this->_itemSourceLocURI);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
|
||||
$output->endElement($state->getURI(), 'Alert');
|
||||
|
||||
$currentCmdID++;
|
||||
} */
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
@ -323,4 +350,14 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command {
|
||||
{
|
||||
$this->_itemTargetLocURI = $itemTargetLocURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the the list of handled SyncItems
|
||||
*
|
||||
* @param array $syncItems The Items of the command
|
||||
*/
|
||||
function setSyncItems(&$syncItems)
|
||||
{
|
||||
$this->_syncItems = $syncItems;
|
||||
}
|
||||
}
|
||||
|
@ -1,220 +1,259 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
include_once 'Horde/SyncML/Sync/SlowSync.php';
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromServerSync.php';
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromClientSync.php';
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromServerSync.php';
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromClientSync.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync.php,v 1.17 2004/07/03 15:21:14 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync extends Horde_Syncml_Command {
|
||||
class Horde_SyncML_Command_Sync extends Horde_SyncML_Command {
|
||||
|
||||
var $_isInSource;
|
||||
var $_currentSyncElement;
|
||||
var $_syncElements = array();
|
||||
|
||||
function output($currentCmdID, &$output) {
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$attrs = array();
|
||||
|
||||
Horde::logMessage('SyncML: $this->_targetURI = ' . $this->_targetURI, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$status = &new Horde_SyncML_Command_Status(RESPONSE_OK, 'Sync');
|
||||
|
||||
// $status->setState($state);
|
||||
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if ($this->_targetURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetURIParameters) ? $this->_targetURI.'?/'.$this->_targetURIParameters : $this->_targetURI));
|
||||
}
|
||||
|
||||
if ($this->_sourceURI != null) {
|
||||
$status->setSourceRef($this->_sourceURI);
|
||||
}
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
|
||||
if($sync = $state->getSync($this->_targetURI)) {
|
||||
$currentCmdID = $sync->startSync($currentCmdID, $output);
|
||||
|
||||
foreach ($this->_syncElements as $element) {
|
||||
$currentCmdID = $sync->nextSyncCommand($currentCmdID, $element, $output);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Name of the command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_cmdName = 'Sync';
|
||||
|
||||
/**
|
||||
* Source database of the <Sync> command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_sourceURI;
|
||||
|
||||
/**
|
||||
* Target database of the <Sync> command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetURI;
|
||||
|
||||
/**
|
||||
* Optional parameter for the Target.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_targetURIParameters;
|
||||
|
||||
/**
|
||||
* SyncML_SyncElement object for the currently parsed sync command.
|
||||
*
|
||||
* @var SyncML_SyncElement
|
||||
*/
|
||||
var $_curItem;
|
||||
|
||||
/**
|
||||
* List of all SyncML_SyncElement objects that have parsed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_syncElements = array();
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
Horde::logMessage('SyncML: $this->_targetURI = ' . $this->_targetURI, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$status = new Horde_SyncML_Command_Status(RESPONSE_OK, 'Sync');
|
||||
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if ($this->_targetURI != null) {
|
||||
$status->setTargetRef((isset($this->_targetURIParameters) ? $this->_targetURI.'?/'.$this->_targetURIParameters : $this->_targetURI));
|
||||
}
|
||||
|
||||
if ($this->_sourceURI != null) {
|
||||
$status->setSourceRef($this->_sourceURI);
|
||||
}
|
||||
|
||||
$currentCmdID = $status->output($currentCmdID, $output);
|
||||
|
||||
if ($this->_targetURI != "configuration" && // Fix Funambol issue
|
||||
($sync = &$state->getSync($this->_targetURI))) {
|
||||
$currentCmdID = $sync->startSync($currentCmdID, $output);
|
||||
|
||||
foreach ($this->_syncElements as $element) {
|
||||
$currentCmdID = $sync->nextSyncCommand($currentCmdID, $element, $output);
|
||||
}
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function getTargetURI() {
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
{
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'Replace' || $element == 'Add' || $element == 'Delete') {
|
||||
$this->_currentSyncElement = &Horde_SyncML_Command_Sync_SyncElement::factory($element);
|
||||
// $this->_currentSyncElement->setVersion($this->_version);
|
||||
// $this->_currentSyncElement->setCmdRef($this->_cmdID);
|
||||
// $this->_currentSyncElement->setMsgID($this->_msgID);
|
||||
} elseif ($element == 'Target') {
|
||||
$this->_isInSource = false;
|
||||
} else {
|
||||
$this->_isInSource = true;
|
||||
if ($element == 'Replace' ||
|
||||
$element == 'Add' ||
|
||||
$element == 'Delete') {
|
||||
Horde::logMessage("SyncML: sync element $element found", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$this->_curItem = &Horde_SyncML_Command_Sync_SyncElement::factory($element);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($this->_currentSyncElement)) {
|
||||
$this->_currentSyncElement->startElement($uri, $element, $attrs);
|
||||
if (isset($this->_curItem)) {
|
||||
$this->_curItem->startElement($uri, $element, $attrs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// We create a seperate Sync Element for the Sync Data sent
|
||||
// from the Server to the client as we want to process the
|
||||
// client sync information before.
|
||||
|
||||
function syncToClient($currentCmdID, &$output)
|
||||
{
|
||||
Horde::logMessage('SyncML: starting sync to client', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML: starting sync to client', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
if($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED)
|
||||
{
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
$targets = $state->getTargets();
|
||||
Horde::logMessage('SyncML: starting sync to client '.$targets[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$attrs = array();
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
if($state->getSyncStatus() >= CLIENT_SYNC_FINNISHED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED)
|
||||
{
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
$targets = $state->getTargets();
|
||||
foreach($targets as $target)
|
||||
{
|
||||
$sync = $state->getSync($target);
|
||||
|
||||
// make sure that the state reflects what is currently being done
|
||||
$state->_currentSourceURI = $sync->_sourceLocURI;
|
||||
$state->_currentTargetURI = $sync->_targetLocURI;
|
||||
|
||||
$output->startElement($state->getURI(), 'Sync', $attrs);
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$output->characters($currentCmdID);
|
||||
$currentCmdID++;
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $sync->_sourceLocURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
#$chars = $sync->_targetLocURI;
|
||||
$chars = (isset($sync->_targetLocURIParameters) ? $sync->_targetLocURI.'?/'.$sync->_targetLocURIParameters : $sync->_targetLocURI);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
|
||||
if(!$sync->_syncDataLoaded)
|
||||
{
|
||||
$numberOfItems = $sync->loadData();
|
||||
if($deviceInfo['supportNumberOfChanges'])
|
||||
$sync = &$state->getSync($target);
|
||||
Horde::logMessage('SyncML['. session_id() .']: sync alerttype '. $sync->_syncType .' found for target ' . $target, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync->_syncType == ALERT_ONE_WAY_FROM_CLIENT ||
|
||||
$sync->_syncType == ALERT_REFRESH_FROM_CLIENT) {
|
||||
|
||||
Horde::logMessage('SyncML['. session_id() .']: From client Sync, no sync of '. $target .' to client', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->clearSync($target);
|
||||
|
||||
} else if ($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED) {
|
||||
|
||||
Horde::logMessage("SyncML: starting sync to client $target", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$attrs = array();
|
||||
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
|
||||
$output->startElement($state->getURI(), 'Sync', $attrs);
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$output->characters($currentCmdID);
|
||||
$currentCmdID++;
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $sync->_sourceLocURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = (isset($sync->_targetLocURIParameters) ? $sync->_targetLocURI.'?/'.$sync->_targetLocURIParameters : $sync->_targetLocURI);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
|
||||
if(!$sync->_syncDataLoaded)
|
||||
{
|
||||
$output->startElement($state->getURI(), 'NumberOfChanged', $attrs);
|
||||
$output->characters($numberOfItems);
|
||||
$output->endElement($state->getURI(), 'NumberOfChanged');
|
||||
$numberOfItems = $sync->loadData();
|
||||
if($deviceInfo['supportNumberOfChanges'])
|
||||
{
|
||||
$output->startElement($state->getURI(), 'NumberOfChanges', $attrs);
|
||||
$output->characters($numberOfItems);
|
||||
$output->endElement($state->getURI(), 'NumberOfChanges');
|
||||
}
|
||||
}
|
||||
|
||||
$currentCmdID = $sync->endSync($currentCmdID, $output);
|
||||
|
||||
$output->endElement($state->getURI(), 'Sync');
|
||||
|
||||
if (isset($state->curSyncItem) ||
|
||||
$state->getNumberOfElements() === false) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Horde::logMessage("SyncML: Waiting for client ACKNOWLEDGE for $target", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
$currentCmdID = $sync->endSync($currentCmdID, $output);
|
||||
|
||||
$output->endElement($state->getURI(), 'Sync');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// no syncs left
|
||||
if($state->getTargets() === FALSE)
|
||||
if($state->getTargets() === FALSE &&
|
||||
!isset($state->curSyncItem)) {
|
||||
$state->setSyncStatus(SERVER_SYNC_FINNISHED);
|
||||
|
||||
Horde::logMessage('SyncML: syncStatus(server_sync_finnished) '. $state->getSyncStatus, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage('SyncML: syncStatus(syncToClient) = '. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
if (isset($this->_currentSyncElement)) {
|
||||
$this->_currentSyncElement->endElement($uri, $element);
|
||||
if (isset($this->_curItem)) {
|
||||
$this->_curItem->endElement($uri, $element);
|
||||
}
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
switch (count($this->_stack)) {
|
||||
case 2:
|
||||
if ($element == 'Replace' || $element == 'Add' || $element == 'Delete') {
|
||||
$this->_syncElements[] = $this->_currentSyncElement;
|
||||
unset($this->_currentSyncElement);
|
||||
if ($element == 'Replace' ||
|
||||
$element == 'Add' ||
|
||||
$element == 'Delete') {
|
||||
$this->_syncElements[] = &$this->_curItem;
|
||||
unset($this->_curItem);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
if ($element == 'LocURI' && !isset($this->_currentSyncElement)) {
|
||||
if ($this->_isInSource) {
|
||||
if ($element == 'LocURI' && !isset($this->_curItem)) {
|
||||
if ($this->_stack[1] == 'Source') {
|
||||
$this->_sourceURI = trim($this->_chars);
|
||||
$state->_currentSourceURI = $this->_sourceURI;
|
||||
} else {
|
||||
$this->_targetURI = trim($this->_chars);
|
||||
|
||||
} elseif ($this->_stack[1] == 'Target') {
|
||||
$targetURIData = explode('?/',trim($this->_chars));
|
||||
|
||||
$this->_targetURI = $targetURIData[0];
|
||||
$state->_currentTargetURI = $this->_targetURI;
|
||||
|
||||
if(isset($targetURIData[1]))
|
||||
{
|
||||
$this->_targetURIParameters = $targetURIData[1];
|
||||
$state->_currentTargetURIParameters = $this->_targetURIParameters;
|
||||
}
|
||||
|
||||
$this->_targetURI = $targetURIData[0];
|
||||
|
||||
if (isset($targetURIData[1])) {
|
||||
$this->_targetURIParameters = $targetURIData[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function characters($str)
|
||||
{
|
||||
if (isset($this->_currentSyncElement)) {
|
||||
$this->_currentSyncElement->characters($str);
|
||||
if (isset($this->_curItem)) {
|
||||
$this->_curItem->characters($str);
|
||||
} else {
|
||||
if (isset($this->_chars)) {
|
||||
$this->_chars = $this->_chars . $str;
|
||||
$this->_chars .= $str;
|
||||
} else {
|
||||
$this->_chars = $str;
|
||||
}
|
||||
|
@ -1,32 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/Add.php,v 1.10 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_Add extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
|
||||
var $_status = RESPONSE_ITEM_ADDED;
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$status = &new Horde_SyncML_Command_Status($this->_status, 'Add');
|
||||
$status = new Horde_SyncML_Command_Status($this->_status, 'Add');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if (isset($this->_luid)) {
|
||||
$status->setSourceRef($this->_luid);
|
||||
if (!empty($this->_items)) {
|
||||
$status->setSyncItems($this->_items);
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
|
@ -1,106 +1,44 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/ContentSyncElement.php,v 1.12 2004/07/02 19:24:44 chuck Exp $
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElementItem.php';
|
||||
|
||||
/**
|
||||
* The content: vcard data, etc.
|
||||
*/
|
||||
var $_content;
|
||||
|
||||
/**
|
||||
* Local to server: our Horde guid.
|
||||
*/
|
||||
var $_locURI;
|
||||
|
||||
var $_targetURI;
|
||||
var $_contentType;
|
||||
|
||||
function setSourceURI($uri)
|
||||
{
|
||||
$this->_locURI = $uri;
|
||||
}
|
||||
|
||||
function getSourceURI()
|
||||
{
|
||||
return $this->_locURI;
|
||||
}
|
||||
|
||||
function setTargetURI($uri)
|
||||
{
|
||||
$this->_targetURI = $uri;
|
||||
}
|
||||
|
||||
function getTargetURI()
|
||||
{
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
function setContentType($c)
|
||||
{
|
||||
$this->_contentType = $c;
|
||||
}
|
||||
|
||||
function setContentFormat($_format)
|
||||
{
|
||||
$this->_contentFormat = $_format;
|
||||
}
|
||||
|
||||
function getContentType()
|
||||
{
|
||||
return $this->_contentType;
|
||||
}
|
||||
|
||||
function getContent()
|
||||
{
|
||||
return $this->_content;
|
||||
}
|
||||
|
||||
function setContent($content)
|
||||
{
|
||||
$this->_content = $content;
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
if ($element == 'Data') {
|
||||
$this->_content = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
class Horde_SyncML_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_Sync_SyncElementItem {
|
||||
|
||||
function outputCommand($currentCmdID, &$output, $command)
|
||||
{
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
$maxMsgSize = $state->getMaxMsgSizeClient();
|
||||
$maxGUIDSize = $state->getMaxGUIDSizeClient();
|
||||
|
||||
if ($this->_moreData) {
|
||||
$command = $this->_command;
|
||||
} else {
|
||||
$this->_command = $command;
|
||||
}
|
||||
|
||||
$attrs = array();
|
||||
$output->startElement($state->getURI(), $command, $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->characters($currentCmdID);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
/*
|
||||
if (isset($this->_contentType)) {
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
@ -108,43 +46,100 @@ class Horde_SyncML_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
}
|
||||
*/
|
||||
if (isset($this->_content) && !$this->_moreData) {
|
||||
$this->_content = trim($this->_content);
|
||||
$this->_contentSize = strlen($this->_content);
|
||||
if (strtolower($this->_contentFormat) == 'b64') {
|
||||
$this->_content = base64_encode($this->_content);
|
||||
}
|
||||
} else {
|
||||
$this->_contentSize = 0;
|
||||
}
|
||||
|
||||
if (isset($this->_content)
|
||||
|| isset($this->_locURI) || isset($this->targetURI)) {
|
||||
// <command><Meta>
|
||||
if ($this->_contentSize || isset($this->_contentType) || isset($this->_contentFormat)) {
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
if (isset($this->_contentType)) {
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
$output->characters($this->_contentType);
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
}
|
||||
if (isset($this->_contentFormat)) {
|
||||
$output->startElement($state->getURIMeta(), 'Format', $attrs);
|
||||
$output->characters($this->_contentFormat);
|
||||
$output->endElement($state->getURIMeta(), 'Format');
|
||||
}
|
||||
if ($this->_contentSize) {
|
||||
$output->startElement($state->getURIMeta(), 'Size', $attrs);
|
||||
$output->characters(($this->_contentSize));
|
||||
$output->endElement($state->getURIMeta(), 'Size');
|
||||
}
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
}
|
||||
|
||||
if (isset($this->_content) || isset($this->_luid) || isset($this->_guid)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
// send only when sending adds
|
||||
if ($this->_locURI != null && (strtolower($command) == 'add')) {
|
||||
|
||||
// <command><Item><Source><LocURI>
|
||||
if (isset($this->_guid)) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = substr($this->_locURI,0,39);
|
||||
$state->setUIDMapping($this->_locURI, $chars);
|
||||
$chars = substr($this->_guid, 0, $maxGUIDSize);
|
||||
$state->setUIDMapping($this->_guid, $chars);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
|
||||
if(isset($this->_contentFormat)) {
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Format', $attrs);
|
||||
$output->characters($this->_contentFormat);
|
||||
$output->endElement($state->getURIMeta(), 'Format');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
}
|
||||
|
||||
if ($this->_targetURI != null) {
|
||||
// <command><Item><Target><LocURI>
|
||||
if (isset($this->_luid)) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $this->_targetURI;
|
||||
$output->characters($chars);
|
||||
$output->characters($this->_luid);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
|
||||
|
||||
// <command><Item><Data>
|
||||
if (isset($this->_content)) {
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
#$chars = '<![CDATA['.$this->_content.']]>';
|
||||
$chars = $this->_content;
|
||||
$output->characters($chars);
|
||||
$currentSize = $output->getOutputSize();
|
||||
Horde::logMessage("SyncML: $command: current = $currentSize, max = $maxMsgSize", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (!$maxMsgSize ||
|
||||
(($currentSize + MIN_MSG_LEFT + $this->_contentSize) <= $maxMsgSize)) {
|
||||
$chars = $this->_content;
|
||||
unset($this->_content);
|
||||
$this->_moreData = false;
|
||||
} else {
|
||||
$sizeLeft = $maxMsgSize - $currentSize - MIN_MSG_LEFT;
|
||||
if ($sizeLeft < 0) {
|
||||
Horde::logMessage("SyncML: $command: split with $currentSize for $maxMsgSize, increase MIN_MSG_LEFT!", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$sizeLeft = 0;
|
||||
}
|
||||
// don't let us loose characters by trimming
|
||||
while (($this->_contentSize > $sizeLeft) &&
|
||||
(strlen(trim(substr($this->_content, $sizeLeft - 1, 2))) < 2)) {
|
||||
Horde::logMessage("SyncML: $command: split at $sizeLeft hit WS!", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$sizeLeft++;
|
||||
}
|
||||
$chars = substr($this->_content, 0, $sizeLeft);
|
||||
$this->_content = substr($this->_content, $sizeLeft, $this->_contentSize - $sizeLeft);
|
||||
Horde::logMessage("SyncML: $command: "
|
||||
. $this->_contentSize . " split at $sizeLeft:\n"
|
||||
. $chars, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$this->_moreData = true;
|
||||
}
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
|
||||
// <command><Item><MoreData/>
|
||||
if ($this->_moreData) {
|
||||
$output->startElement($state->getURI(), 'MoreData', $attrs);
|
||||
$output->endElement($state->getURI(), 'MoreData');
|
||||
}
|
||||
}
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
|
@ -1,29 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/Delete.php,v 1.9 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_Delete extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
|
||||
function output($currentCmdID, &$output)
|
||||
{
|
||||
$status = &new Horde_SyncML_Command_Status($this->_status, 'Delete');
|
||||
$status = new Horde_SyncML_Command_Status($this->_status, 'Delete');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if (isset($this->_luid)) {
|
||||
$status->setSourceRef($this->_luid);
|
||||
if (!empty($this->_items)) {
|
||||
$status->setSyncItems($this->_items);
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
|
@ -1,32 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/Replace.php,v 1.9 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_Replace extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
|
||||
function output($currentCmdID, &$output) {
|
||||
$status = &new Horde_SyncML_Command_Status($this->_status, 'Replace');
|
||||
$status = new Horde_SyncML_Command_Status($this->_status, 'Replace');
|
||||
$status->setCmdRef($this->_cmdID);
|
||||
|
||||
if (isset($this->_luid)) {
|
||||
$status->setSourceRef($this->_luid);
|
||||
}
|
||||
|
||||
#$status->setItemSourceLocURI($this->_sourceLocURI);
|
||||
#$status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
|
||||
|
||||
|
||||
if (!empty($this->_items)) {
|
||||
$status->setSyncItems($this->_items);
|
||||
}
|
||||
|
||||
return $status->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
|
@ -1,40 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/SyncElement.php,v 1.11 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Copyright 2005-2006 Lars Kneschke <l.kneschke@metaways.de>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_SyncElement extends Horde_SyncML_Command {
|
||||
|
||||
var $_luid;
|
||||
var $_guid;
|
||||
var $_isSource;
|
||||
var $_content;
|
||||
var $_contentSize;
|
||||
var $_contentType;
|
||||
var $_contentFormat;
|
||||
var $_status = RESPONSE_OK;
|
||||
var $_items;
|
||||
|
||||
var $_curItem;
|
||||
var $_items = array();
|
||||
var $_moreData = false;
|
||||
var $_command = false;
|
||||
|
||||
function &factory($command, $params = null) {
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElementItem.php';
|
||||
@include_once 'Horde/SyncML/Command/Sync/' . $command . '.php';
|
||||
|
||||
|
||||
$class = 'Horde_SyncML_Command_Sync_' . $command;
|
||||
|
||||
|
||||
if (class_exists($class)) {
|
||||
#Horde::logMessage('SyncML: Class definition of ' . $class . ' found in SyncElement::factory.', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $element = &new $class($params);
|
||||
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';
|
||||
@ -44,78 +47,122 @@ class Horde_SyncML_Command_Sync_SyncElement extends Horde_SyncML_Command {
|
||||
|
||||
function startElement($uri, $element, $attrs) {
|
||||
parent::startElement($uri, $element, $attrs);
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
case 3:
|
||||
if ($element == 'Source') {
|
||||
$this->_isSource = true;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
switch (count($this->_stack)) {
|
||||
case 1:
|
||||
$this->_command = $element;
|
||||
break;
|
||||
case 2:
|
||||
if ($element == 'Item') {
|
||||
if (isset($state->curSyncItem)) {
|
||||
// Copy from state in case of <MoreData>.
|
||||
$this->_curItem = &$state->curSyncItem;
|
||||
if (isset($this->_luid) &&
|
||||
($this->_luid != $this->_curItem->_luid)) {
|
||||
Horde::logMessage('SyncML: moreData mismatch for LocURI ' .
|
||||
$this->_curItem->_luid . ' (' . $this->_luid . ')', __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: moreData item found for LocURI ' . $this->_curItem->_luid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
unset($state->curSyncItem);
|
||||
} else {
|
||||
$this->_curItem = new Horde_SyncML_Command_Sync_SyncElementItem();
|
||||
}
|
||||
$this->_moreData = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function endElement($uri, $element) {
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$search = array('/ *\n/','/ *$/m');
|
||||
$replace = array('','');
|
||||
|
||||
switch ($this->_xmlStack) {
|
||||
|
||||
switch (count($this->_stack)) {
|
||||
case 1:
|
||||
$this->_command = false;
|
||||
// Need to add sync elements to the Sync method?
|
||||
#error_log('total # of items: '.count($this->_items));
|
||||
#error_log(print_r($this->_items[10], true));
|
||||
break;
|
||||
case 2;
|
||||
if($element == 'Item') {
|
||||
$item = new Horde_SyncML_Command_Sync_SyncElementItem();
|
||||
|
||||
if($this->_luid) {
|
||||
$item->setLocURI($this->_luid);
|
||||
$item->setContent($this->_content);
|
||||
$item->setContentType($this->_contentType);
|
||||
|
||||
$this->_curItem->setLocURI($this->_luid);
|
||||
$this->_curItem->setContentType($this->_contentType);
|
||||
$this->_curItem->setContentFormat($this->_contentFormat);
|
||||
$this->_curItem->setCommand($this->_command);
|
||||
|
||||
if($this->_contentSize)
|
||||
$item->setContentType($this->_contentSize);
|
||||
if($this->_moreData)
|
||||
$item->setMoreData($this->_moreData);
|
||||
|
||||
$this->_items[$this->_luid] = $item;
|
||||
$this->_curItem->setContentSize($this->_contentSize);
|
||||
if($this->_moreData) {
|
||||
$state->curSyncItem = &$this->_curItem;
|
||||
Horde::logMessage('SyncML: moreData item saved for LocURI ' . $this->_curItem->_luid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
if (strtolower($this->_curItem->getContentFormat()) == 'b64') {
|
||||
$content = $this->_curItem->getContent();
|
||||
$content = ($content ? base64_decode($content) : '');
|
||||
$this->_curItem->setContent($content);
|
||||
#Horde::logMessage('SyncML: BASE64 encoded item for LocURI '
|
||||
# . $this->_curItem->_luid . ":\n $content", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
$this->_items[$this->_luid] = $this->_curItem;
|
||||
}
|
||||
}
|
||||
|
||||
unset($this->_content);
|
||||
unset($this->_contentSize);
|
||||
unset($this->_luid);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if ($element == 'Source') {
|
||||
$this->_isSource = false;
|
||||
} elseif ($element == 'Data') {
|
||||
$this->_content = $this->_chars;
|
||||
} elseif ($element == 'MoreData') {
|
||||
$this->_moreData = TRUE;
|
||||
} elseif ($element == 'Type') {
|
||||
if(empty($this->_contentType))
|
||||
$this->_contentType = trim($this->_chars);
|
||||
switch ($element) {
|
||||
case 'Data':
|
||||
$this->_curItem->_content .= $this->_chars;
|
||||
break;
|
||||
case 'MoreData':
|
||||
$this->_moreData = true;
|
||||
break;
|
||||
case 'Type':
|
||||
if(empty($this->_contentType)) {
|
||||
$this->_contentType = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'Format':
|
||||
$this->_contentFormat = strtolower(trim($this->_chars));
|
||||
break;
|
||||
case 'Size':
|
||||
$this->_contentSize = $this->_chars;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 4:
|
||||
if ($element == 'LocURI' && $this->_isSource) {
|
||||
$this->_luid = trim($this->_chars);
|
||||
} elseif ($element == 'Type') {
|
||||
$this->_contentType = trim($this->_chars);
|
||||
} elseif ($element == 'Size') {
|
||||
$this->_contentSize = trim($this->_chars);
|
||||
switch ($element) {
|
||||
case 'LocURI':
|
||||
if ($this->_stack[2] == 'Source') {
|
||||
$this->_luid = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
case 'Type':
|
||||
$this->_contentType = trim($this->_chars);
|
||||
break;
|
||||
case 'Format':
|
||||
$this->_contentFormat = strtolower(trim($this->_chars));
|
||||
break;
|
||||
case 'Size':
|
||||
$this->_contentSize = trim($this->_chars);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
function getSyncElementItems() {
|
||||
return (array)$this->_items;
|
||||
}
|
||||
|
||||
function getSyncElementItems() {
|
||||
return (array)$this->_items;
|
||||
}
|
||||
|
||||
function getLocURI()
|
||||
{
|
||||
@ -149,14 +196,17 @@ class Horde_SyncML_Command_Sync_SyncElement extends Horde_SyncML_Command {
|
||||
|
||||
function getContent()
|
||||
{
|
||||
return $this->_content;
|
||||
if ($this->_curItem) {
|
||||
return $this->_curItem->getcontent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function setContent($content)
|
||||
function hasMoreData()
|
||||
{
|
||||
$this->_content = $content;
|
||||
return $this->_moreData;
|
||||
}
|
||||
|
||||
|
||||
function setStatus($_status)
|
||||
{
|
||||
$this->_status = $_status;
|
||||
|
@ -1,67 +1,95 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Command.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/SyncElement.php,v 1.11 2004/07/02 19:24:44 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Copyright 2005-2006 Lars Kneschke <l.kneschke@metaways.de>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Command_Sync_SyncElementItem {
|
||||
|
||||
var $_luid;
|
||||
var $_guid;
|
||||
var $_content;
|
||||
var $_content = '';
|
||||
var $_contentSize;
|
||||
var $_contentType;
|
||||
var $_contentFormat;
|
||||
var $_command;
|
||||
var $_moreData = false;
|
||||
|
||||
|
||||
function getLocURI() {
|
||||
return $this->_luid;
|
||||
}
|
||||
|
||||
|
||||
function getGUID() {
|
||||
return $this->_guid;
|
||||
}
|
||||
|
||||
|
||||
function getContentType() {
|
||||
return $this->_contentType;
|
||||
}
|
||||
|
||||
|
||||
function getContentFormat() {
|
||||
return $this->_contentFormat;
|
||||
}
|
||||
|
||||
function getContent() {
|
||||
return $this->_content;
|
||||
}
|
||||
|
||||
|
||||
function getContentSize() {
|
||||
if (isset($this->_contentSize)) {
|
||||
return $this->_contentSize;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getCommand() {
|
||||
return $this->_command;
|
||||
}
|
||||
|
||||
function setLocURI($luid) {
|
||||
$this->_luid = $luid;
|
||||
}
|
||||
|
||||
|
||||
function setGUID($guid) {
|
||||
$this->_guid = $guid;
|
||||
}
|
||||
|
||||
function setContent($content) {
|
||||
$this->_content = $content;
|
||||
|
||||
function setContent($_content) {
|
||||
$this->_content = $_content;
|
||||
}
|
||||
|
||||
function setContentSize($_size) {
|
||||
$this->_contentSize = $_size;
|
||||
}
|
||||
|
||||
function setContentType($_contentType) {
|
||||
$this->_contentType = $_contentType;
|
||||
function setContentType($_type) {
|
||||
$this->_contentType = $_type;
|
||||
}
|
||||
|
||||
function setContentFormat($_format) {
|
||||
$this->_contentFormat = $_format;
|
||||
}
|
||||
|
||||
function setMoreData($_status) {
|
||||
$this->_moreData = $_status;
|
||||
}
|
||||
|
||||
function hasMoreData() {
|
||||
return $this->_moreData;
|
||||
}
|
||||
|
||||
function setCommand($_command) {
|
||||
$this->_command = $_command;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
define('ALERT_DISPLAY', 100);
|
||||
|
||||
@ -21,6 +35,10 @@ define('ALERT_RESULT_ALERT', 221);
|
||||
define('ALERT_NEXT_MESSAGE', 222);
|
||||
define('ALERT_NO_END_OF_DATA', 223);
|
||||
|
||||
// Not (really) implemented.
|
||||
define('ALERT_SUSPEND', 224); // New in SyncML 1.2
|
||||
define('ALERT_RESUME', 225); // New in SyncML 1.2
|
||||
|
||||
define('MIME_SYNCML_XML', 'application/vnd.syncml+xml');
|
||||
define('MIME_SYNCML_WBXML', 'application/vnd.syncml+wbxml');
|
||||
|
||||
@ -107,7 +125,7 @@ define('RESPONSE_COMMAND_FAILED', 500);
|
||||
// define('RESPONSE_COMMAND_FAILED', 505);
|
||||
// define('RESPONSE_COMMAND_FAILED', 506);
|
||||
// define('RESPONSE_COMMAND_FAILED', 507);
|
||||
// define('RESPONSE_COMMAND_FAILED', 508);
|
||||
define('RESPONSE_REFRESH_REQUIRED', 508);
|
||||
// define('RESPONSE_COMMAND_FAILED', 509);
|
||||
// define('RESPONSE_COMMAND_FAILED', 510);
|
||||
// define('RESPONSE_COMMAND_FAILED', 511);
|
||||
@ -117,12 +135,15 @@ define('RESPONSE_COMMAND_FAILED', 500);
|
||||
// define('RESPONSE_COMMAND_FAILED', 515);
|
||||
define('RESPONSE_ATOMIC_ROLL_BACK_FAILED', 516);
|
||||
|
||||
define('NAME_SPACE_URI_SYNCML', 'syncml:syncml1.0');
|
||||
define('NAME_SPACE_URI_SYNCML_1_0', 'syncml:syncml1.0');
|
||||
define('NAME_SPACE_URI_SYNCML_1_1', 'syncml:syncml1.1');
|
||||
define('NAME_SPACE_URI_METINF', 'syncml:metinf');
|
||||
define('NAME_SPACE_URI_SYNCML_1_2', 'syncml:syncml1.2');
|
||||
define('NAME_SPACE_URI_METINF_1_0', 'syncml:metinf1.0');
|
||||
define('NAME_SPACE_URI_METINF_1_1', 'syncml:metinf1.1');
|
||||
define('NAME_SPACE_URI_DEVINF', 'syncml:devinf');
|
||||
define('NAME_SPACE_URI_METINF_1_2', 'syncml:metinf1.2');
|
||||
define('NAME_SPACE_URI_DEVINF_1_0', 'syncml:devinf1.0');
|
||||
define('NAME_SPACE_URI_DEVINF_1_1', 'syncml:devinf1.1');
|
||||
define('NAME_SPACE_URI_DEVINF_1_2', 'syncml:devinf1.2');
|
||||
|
||||
define('CLIENT_SYNC_STARTED', 1);
|
||||
define('CLIENT_SYNC_FINNISHED', 2);
|
||||
@ -131,8 +152,18 @@ define('SERVER_SYNC_DATA_PENDING', 4);
|
||||
define('SERVER_SYNC_FINNISHED', 5);
|
||||
define('SERVER_SYNC_ACKNOWLEDGED', 6);
|
||||
|
||||
// conflict management
|
||||
define('CONFLICT_CLIENT_WINNING', 0);
|
||||
define('CONFLICT_SERVER_WINNING', 1);
|
||||
define('CONFLICT_MERGE_DATA', 2);
|
||||
define('CONFLICT_RESOLVED_WITH_DUPLICATE', 3);
|
||||
define('CONFLICT_CLIENT_CHANGES_IGNORED', 4);
|
||||
define('CONFLICT_CLIENT_REFRESH_ENFORCED', 5);
|
||||
|
||||
define('MAX_DATA', 19);
|
||||
define('MAX_ENTRIES', 10);
|
||||
define('MAX_ENTRIES', 10); // default
|
||||
define('MAX_GUID_SIZE', 64);
|
||||
define('MIN_MSG_LEFT', 200); // Overhead
|
||||
|
||||
/**
|
||||
* The Horde_SyncML_State class provides a SyncML state object.
|
||||
@ -148,6 +179,7 @@ define('MAX_ENTRIES', 10);
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @modified Joerg Lehrke <jlehrke@noc.de> 2009/01/20, support all syn types
|
||||
*/
|
||||
class Horde_SyncML_State {
|
||||
|
||||
@ -157,6 +189,10 @@ class Horde_SyncML_State {
|
||||
|
||||
var $_msgID;
|
||||
|
||||
var $_maxMsgSize;
|
||||
|
||||
var $_maxGUIDSize;
|
||||
|
||||
var $_targetURI;
|
||||
|
||||
var $_sourceURI;
|
||||
@ -169,6 +205,8 @@ class Horde_SyncML_State {
|
||||
|
||||
var $_isAuthorized;
|
||||
|
||||
var $_AuthConfirmed;
|
||||
|
||||
var $_uri;
|
||||
|
||||
var $_uriMeta;
|
||||
@ -181,7 +219,7 @@ class Horde_SyncML_State {
|
||||
|
||||
var $_serverAnchorNext = array(); // written to db after successful sync
|
||||
|
||||
var $_clientDeviceInfo = array();
|
||||
var $_clientDeviceInfo;
|
||||
|
||||
// array list of changed items, which need to be synced to the client
|
||||
var $_changedItems;
|
||||
@ -192,8 +230,11 @@ class Horde_SyncML_State {
|
||||
// array list of added items, which need to be synced to the client
|
||||
var $_addedItems;
|
||||
|
||||
// bool flag that we need to more data
|
||||
var $_syncStatus;
|
||||
// array list of items, which need to be refreshed at the client
|
||||
var $_conflictItems;
|
||||
|
||||
// current session status
|
||||
var $_syncStatus = 0;
|
||||
|
||||
var $_log = array();
|
||||
|
||||
@ -208,6 +249,22 @@ class Horde_SyncML_State {
|
||||
*/
|
||||
var $_uidMappings = array();
|
||||
|
||||
/**
|
||||
* Current sync element sent from client.
|
||||
*
|
||||
* Stored in state if one element is split into multiple message packets.
|
||||
*
|
||||
* @var SyncML_SyncElement
|
||||
*/
|
||||
var $curSyncItem;
|
||||
|
||||
/**
|
||||
* Number of sync elements sent to client within current message.
|
||||
*
|
||||
* @var _numberOfElements
|
||||
*/
|
||||
var $_numberOfElements;
|
||||
|
||||
/**
|
||||
* Creates a new instance of Horde_SyncML_State.
|
||||
*/
|
||||
@ -220,7 +277,8 @@ class Horde_SyncML_State {
|
||||
$this->setPassword($password);
|
||||
}
|
||||
|
||||
$this->isAuthorized = false;
|
||||
$this->_isAuthorized = false;
|
||||
$this->_isAuthConfirmed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,7 +292,7 @@ class Horde_SyncML_State {
|
||||
* retrieve the real egw uid for a given send uid
|
||||
*/
|
||||
function getUIDMapping($_sentEgwUid) {
|
||||
if(isset($this->_uidMappings[$_sentEgwUid])) {
|
||||
if(strlen("$_sentEgwUid") && isset($this->_uidMappings[$_sentEgwUid])) {
|
||||
return $this->_uidMappings[$_sentEgwUid];
|
||||
}
|
||||
|
||||
@ -311,6 +369,16 @@ class Horde_SyncML_State {
|
||||
return false;
|
||||
}
|
||||
|
||||
function &getConflictItems($_type)
|
||||
{
|
||||
if(isset($this->_conflictItems[$_type]))
|
||||
{
|
||||
return $this->_conflictItems[$_type];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getMoreDataPending()
|
||||
{
|
||||
return $this->_moreDataPending;
|
||||
@ -321,6 +389,14 @@ class Horde_SyncML_State {
|
||||
return $this->_msgID;
|
||||
}
|
||||
|
||||
function getMaxMsgSizeClient()
|
||||
{
|
||||
if (isset($this->_maxMsgSize)) {
|
||||
return $this->_maxMsgSize;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function setWBXML($wbxml)
|
||||
{
|
||||
$this->_wbxml = $wbxml;
|
||||
@ -341,11 +417,39 @@ class Horde_SyncML_State {
|
||||
$this->_addedItems[$_type] = $_addedItems;
|
||||
}
|
||||
|
||||
function mergeAddedItems($_type, $_addedItems)
|
||||
{
|
||||
if (is_array($this->_addedItems[$_type])) {
|
||||
$this->_addedItems[$_type] = array_merge($this->_addedItems[$_type], $_addedItems);
|
||||
} else {
|
||||
$this->_addedItems[$_type] = $_addedItems;
|
||||
}
|
||||
}
|
||||
|
||||
function pushAddedItem($_type, $_addedItem)
|
||||
{
|
||||
$this->_addedItems[$_type][] = $_addedItem;
|
||||
}
|
||||
|
||||
function setChangedItems($_type, $_changedItems)
|
||||
{
|
||||
$this->_changedItems[$_type] = $_changedItems;
|
||||
}
|
||||
|
||||
function mergeChangedItems($_type, $_changedItems)
|
||||
{
|
||||
if (is_array($this->_changedItems[$_type])) {
|
||||
$this->_changedItems[$_type] = array_merge($this->_changedItems[$_type], $_changedItems);
|
||||
} else {
|
||||
$this->_changedItems[$_type] = $_changedItems;
|
||||
}
|
||||
}
|
||||
|
||||
function pushChangedItem($_type, $_changedItem)
|
||||
{
|
||||
$this->_changedItems[$_type][] = $_changedItem;
|
||||
}
|
||||
|
||||
function setClientDeviceInfo($clientDeviceInfo)
|
||||
{
|
||||
$this->_clientDeviceInfo = $clientDeviceInfo;
|
||||
@ -356,9 +460,14 @@ class Horde_SyncML_State {
|
||||
$this->_deletedItems[$_type] = $_deletedItems;
|
||||
}
|
||||
|
||||
function setMoreDataPending($_state)
|
||||
function addConflictItem($_type, $_conflict)
|
||||
{
|
||||
$this->_moreDataPending = $_state;
|
||||
$this->_conflictItems[$_type][] = $_conflict;
|
||||
}
|
||||
|
||||
function clearConflictItems($_type)
|
||||
{
|
||||
$this->_conflictItems[$_type] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -370,6 +479,15 @@ class Horde_SyncML_State {
|
||||
$this->_msgID = $msgID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property maxMsgSize.
|
||||
* @param size New value of property maxMsgSize.
|
||||
*/
|
||||
function setMaxMsgSize($size)
|
||||
{
|
||||
$this->_maxMsgSize = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property locName.
|
||||
* @param locName New value of property locName.
|
||||
@ -408,15 +526,20 @@ class Horde_SyncML_State {
|
||||
{
|
||||
$this->_version = $version;
|
||||
|
||||
if ($version == 0) {
|
||||
$this->_uri = NAME_SPACE_URI_SYNCML;
|
||||
$this->_uriMeta = NAME_SPACE_URI_METINF;
|
||||
$this->_uriDevInf = NAME_SPACE_URI_DEVINF;
|
||||
} else {
|
||||
if ($version == 2) {
|
||||
$this->_uri = NAME_SPACE_URI_SYNCML_1_2;
|
||||
$this->_uriMeta = NAME_SPACE_URI_METINF_1_2;
|
||||
$this->_uriDevInf = NAME_SPACE_URI_DEVINF_1_2;
|
||||
} elseif ($version == 1) {
|
||||
$this->_uri = NAME_SPACE_URI_SYNCML_1_1;
|
||||
$this->_uriMeta = NAME_SPACE_URI_METINF_1_1;
|
||||
$this->_uriDevInf = NAME_SPACE_URI_DEVINF_1_1;
|
||||
}
|
||||
} else {
|
||||
$this->_uri = NAME_SPACE_URI_SYNCML_1_0;
|
||||
$this->_uriMeta = NAME_SPACE_URI_METINF_1_0;
|
||||
$this->_uriDevInf = NAME_SPACE_URI_DEVINF_1_0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function setSessionID($sessionID)
|
||||
@ -457,6 +580,16 @@ class Horde_SyncML_State {
|
||||
return $this->_isAuthorized;
|
||||
}
|
||||
|
||||
function isAuthConfirmed()
|
||||
{
|
||||
return $this->_AuthConfirmed;
|
||||
}
|
||||
|
||||
function AuthConfirmed()
|
||||
{
|
||||
$this->_AuthConfirmed = true;
|
||||
}
|
||||
|
||||
function clearSync($target)
|
||||
{
|
||||
unset($this->_syncs[$target]);
|
||||
@ -486,6 +619,9 @@ class Horde_SyncML_State {
|
||||
$targets[] = $target;
|
||||
}
|
||||
|
||||
// Make sure we keep the order
|
||||
sort($targets);
|
||||
|
||||
return $targets;
|
||||
}
|
||||
|
||||
@ -502,6 +638,7 @@ class Horde_SyncML_State {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function getURIMeta()
|
||||
{
|
||||
return $this->_uriMeta;
|
||||
@ -548,16 +685,18 @@ class Horde_SyncML_State {
|
||||
* this->_locName . $this->_sourceURI . $type . $locid so you can
|
||||
* have different syncs with different devices. If an entry
|
||||
* already exists, it is overwritten.
|
||||
* Expired entries can be deleted at the next session start.
|
||||
*/
|
||||
function setUID($type, $locid, $guid, $ts=0)
|
||||
function setUID($type, $locid, $guid, $ts=0, $expired=0)
|
||||
{
|
||||
$dt = &$this->getDataTree();
|
||||
|
||||
// Set $locid.
|
||||
$gid = &new DataTreeObject($this->_locName . $this->_sourceURI . $type . $guid);
|
||||
$gid = new DataTreeObject($this->_locName . $this->_sourceURI . $type . $guid);
|
||||
$gid->set('type', $type);
|
||||
$gid->set('locid', $locid);
|
||||
$gid->set('ts', $ts);
|
||||
$gid->set('expired', $expired);
|
||||
|
||||
$r = $dt->add($gid);
|
||||
if (is_a($r, 'PEAR_Error')) {
|
||||
@ -567,7 +706,7 @@ class Horde_SyncML_State {
|
||||
$this->dieOnError($r, __FILE__, __LINE__);
|
||||
|
||||
// Set $globaluid
|
||||
$lid = &new DataTreeObject($this->_locName . $this->_sourceURI . $type . $locid);
|
||||
$lid = new DataTreeObject($this->_locName . $this->_sourceURI . $type . $locid);
|
||||
$lid->set('globaluid', $guid);
|
||||
$r = $dt->add($lid);
|
||||
if (is_a($r, 'PEAR_Error')) {
|
||||
@ -657,54 +796,41 @@ class Horde_SyncML_State {
|
||||
*/
|
||||
function adjustContentType($type, $target = null)
|
||||
{
|
||||
$ctype;
|
||||
if (is_array($type))
|
||||
{
|
||||
if (is_array($type)) {
|
||||
$ctype = $type['ContentType'];
|
||||
$res = $type;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$ctype = $type;
|
||||
$res = array();
|
||||
$res['ContentType'] = $ctype;
|
||||
}
|
||||
|
||||
$deviceInfo = $this->getClientDeviceInfo();
|
||||
$deviceInfo = $this->getClientDeviceInfo();
|
||||
$manufacturer = isset($deviceInfo['manufacturer']) ? strtolower($deviceInfo['manufacturer']) : 'unknown';
|
||||
switch ($manufacturer) {
|
||||
case 'funambol':
|
||||
switch (strtolower($deviceInfo['model'])) {
|
||||
case 'thunderbird':
|
||||
case 'mozilla plugin':
|
||||
$res['mayFragment'] = 1;
|
||||
break;
|
||||
default:
|
||||
if (isset($deviceInfo['softwareVersion'])
|
||||
&& $deviceInfo['softwareVersion'] < 4.0) {
|
||||
$res['mayFragment'] = 0;
|
||||
} else {
|
||||
$res['mayFragment'] = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$res['mayFragment'] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($deviceInfo['manufacturer']))
|
||||
{
|
||||
switch (strtolower($deviceInfo['manufacturer']))
|
||||
{
|
||||
case 'funambol':
|
||||
if (strtolower($deviceInfo['model']) == 'thunderbird')
|
||||
{
|
||||
$res['mayFragment'] = 1;
|
||||
}
|
||||
|
||||
if (isset($deviceInfo['softwareVersion'])
|
||||
&& $deviceInfo['softwareVersion']{0} == '3')
|
||||
{
|
||||
// anything beyond 6.0 supports fragmentation
|
||||
$res['mayFragment'] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$res['mayFragment'] = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($res['mayFragment']))
|
||||
{
|
||||
$res['mayFragment'] = 1;
|
||||
}
|
||||
|
||||
|
||||
// the funambol specific types need to be encoded in base 64
|
||||
switch(strtolower($ctype))
|
||||
{
|
||||
// the funambol specific types need to be encoded in base64
|
||||
switch (strtolower($ctype)) {
|
||||
case 'text/x-s4j-sifc':
|
||||
case 'text/x-s4j-sife':
|
||||
case 'text/x-s4j-sift':
|
||||
@ -712,17 +838,15 @@ class Horde_SyncML_State {
|
||||
$res['ContentFormat'] = 'b64';
|
||||
break;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function getPreferedContentType($type)
|
||||
{
|
||||
$_type = str_replace('./','',$type);
|
||||
switch(strtolower($_type))
|
||||
{
|
||||
switch (strtolower($_type)) {
|
||||
case 'contacts':
|
||||
return 'text/x-vcard';
|
||||
return 'text/vcard';
|
||||
break;
|
||||
|
||||
case 'notes':
|
||||
@ -730,9 +854,10 @@ class Horde_SyncML_State {
|
||||
break;
|
||||
|
||||
case 'calendar':
|
||||
case 'events':
|
||||
case 'tasks':
|
||||
case 'caltasks':
|
||||
return 'text/x-vcalendar';
|
||||
return 'text/calendar';
|
||||
break;
|
||||
|
||||
case 'sifcalendar':
|
||||
@ -778,6 +903,7 @@ class Horde_SyncML_State {
|
||||
return 'tasks';
|
||||
break;
|
||||
|
||||
case 'events':
|
||||
case 'calendar':
|
||||
return 'calendar';
|
||||
break;
|
||||
@ -815,7 +941,6 @@ class Horde_SyncML_State {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the preferred contenttype of the client for the given
|
||||
* sync data type (database).
|
||||
@ -826,12 +951,33 @@ class Horde_SyncML_State {
|
||||
function getPreferedContentTypeClient($_sourceLocURI, $_targetLocURI = null) {
|
||||
$deviceInfo = $this->getClientDeviceInfo();
|
||||
|
||||
if(isset($deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType']))
|
||||
{
|
||||
return $this->adjustContentType($deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType'], $_targetLocURI);
|
||||
if(isset($deviceInfo['dataStore'][$_sourceLocURI]['maxGUIDSize']['contentType'])) {
|
||||
$this->_maxGUIDSize = $deviceInfo['dataStore'][$this->_sourceURI]['maxGUIDSize']['contentType'];
|
||||
}
|
||||
|
||||
Horde::logMessage('SyncML: sourceLocURI ' . $_sourceLocURI .' not found', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if(isset($deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType']))
|
||||
{
|
||||
$ctype = $deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType'];
|
||||
$cvers = $deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentVersion'];
|
||||
$cfrmt = $deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentFormat'];
|
||||
$cprops = $deviceInfo['dataStore'][$_sourceLocURI]['properties'][$ctype][$cvers];
|
||||
if (isset($deviceInfo['dataStore'][$_sourceLocURI]['maxGUIDSize'])) {
|
||||
// get UID properties from maxGUIDSize
|
||||
$cprops['UID']['Size'] = $deviceInfo['dataStore'][$_sourceLocURI]['maxGUIDSize'];
|
||||
$cprops['UID']['NoTruncate'] = true;
|
||||
}
|
||||
$clientPrefs = array(
|
||||
'ContentType' => $ctype,
|
||||
'ContentFormat' => $cfrmt,
|
||||
'mayFragment' => 1,
|
||||
'Properties' => $cprops,
|
||||
);
|
||||
#Horde::logMessage('SyncML: sourceLocURI ' . $_sourceLocURI . " clientPrefs:\n"
|
||||
# . print_r($clientPrefs, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $this->adjustContentType($clientPrefs, $_targetLocURI);
|
||||
}
|
||||
|
||||
Horde::logMessage('SyncML: sourceLocURI ' . $_sourceLocURI . " not found:\n" . print_r($deviceInfo, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if ($_targetLocURI != null)
|
||||
{
|
||||
@ -841,6 +987,19 @@ class Horde_SyncML_State {
|
||||
return PEAR::raiseError(_('sourceLocURI not found'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MaxGUIDSize of the client
|
||||
*/
|
||||
|
||||
function getMaxGUIDSizeClient() {
|
||||
$maxGUIDSize = MAX_GUID_SIZE;
|
||||
|
||||
if (isset($this->_maxGUIDSize)) {
|
||||
$maxGUIDSize = $this->_maxGUIDSize;
|
||||
}
|
||||
return $maxGUIDSize;
|
||||
}
|
||||
|
||||
function setClientAnchorNext($type, $a)
|
||||
{
|
||||
$this->_clientAnchorNext[$type] = $a;
|
||||
@ -900,6 +1059,11 @@ class Horde_SyncML_State {
|
||||
*/
|
||||
function getClientDeviceInfo()
|
||||
{
|
||||
if (isset($this->_clientDeviceInfo) && is_array($this->_clientDeviceInfo)) {
|
||||
// use cached information
|
||||
return $this->_clientDeviceInfo;
|
||||
}
|
||||
|
||||
$dt = &$this->getDataTree();
|
||||
|
||||
$id = $dt->getId($this->_locName . $this->_sourceURI . 'deviceInfo');
|
||||
@ -907,7 +1071,7 @@ class Horde_SyncML_State {
|
||||
return false;
|
||||
}
|
||||
|
||||
$info = $dt->getObjectById($id);
|
||||
$info = $dt->getObjectById($id);
|
||||
|
||||
return $info->get('ClientDeviceInfo');
|
||||
}
|
||||
@ -926,7 +1090,7 @@ class Horde_SyncML_State {
|
||||
$s = $this->_locName . $this->_sourceURI . 'deviceInfo';
|
||||
|
||||
// Set $locid.
|
||||
$info = &new DataTreeObject($s);
|
||||
$info = new DataTreeObject($s);
|
||||
$info->set('ClientDeviceInfo', $this->_clientDeviceInfo);
|
||||
$r = $dt->add($info);
|
||||
if (is_a($r, 'PEAR_Error')) {
|
||||
@ -952,7 +1116,7 @@ class Horde_SyncML_State {
|
||||
$s = $this->_locName . $this->_sourceURI . $type . 'syncSummary';
|
||||
|
||||
// Set $locid.
|
||||
$info = &new DataTreeObject($s);
|
||||
$info = new DataTreeObject($s);
|
||||
$info->set('ClientAnchor', $this->_clientAnchorNext);
|
||||
$info->set('ServerAnchor', $this->_serverAnchorNext);
|
||||
$r = $dt->add($info);
|
||||
@ -1070,4 +1234,23 @@ class Horde_SyncML_State {
|
||||
$this->_receivedAlert222 = (bool)$_status;
|
||||
}
|
||||
|
||||
function incNumberOfElements() {
|
||||
$this->_numberOfElements++;
|
||||
}
|
||||
|
||||
function clearNumberOfElements() {
|
||||
$this->_numberOfElements = 0;
|
||||
}
|
||||
|
||||
function getNumberOfElements() {
|
||||
if (isset($this->_numberOfElements)) {
|
||||
return $this->_numberOfElements;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function maxNumberOfElements() {
|
||||
unset($this->_numberOfElements);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare SyncML
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke
|
||||
* @package syncml
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Lars Kneschke <lkneschke@egroupware.org>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
include_once dirname(__FILE__).'/State.php';
|
||||
|
||||
/**
|
||||
@ -17,45 +21,42 @@ include_once dirname(__FILE__).'/State.php';
|
||||
class EGW_SyncML_State extends Horde_SyncML_State
|
||||
{
|
||||
var $table_devinfo = 'egw_syncmldevinfo';
|
||||
|
||||
|
||||
/*
|
||||
* store the mappings of egw uids to client uids
|
||||
*/
|
||||
var $uidMappings = array();
|
||||
|
||||
|
||||
/**
|
||||
* get the local content id from a syncid
|
||||
*
|
||||
* @param sting $_syncid id used in syncml
|
||||
* @return int local egw content id
|
||||
*/
|
||||
function get_egwID($_syncid)
|
||||
{
|
||||
/**
|
||||
* get the local content id from a syncid
|
||||
*
|
||||
* @param sting $_syncid id used in syncml
|
||||
* @return int local egw content id
|
||||
*/
|
||||
function get_egwID($_syncid) {
|
||||
$syncIDParts = explode('-',$_syncid);
|
||||
array_shift($syncIDParts);
|
||||
$_id = implode ('', $syncIDParts);
|
||||
return $_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* when got a entry last added/modified/deleted
|
||||
*
|
||||
* @param $_syncid containing appName-contentid
|
||||
* @param $_action string can be add, delete or modify
|
||||
* @return string the last timestamp
|
||||
*/
|
||||
function getSyncTSforAction($_syncid, $_action)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* when got a entry last added/modified/deleted
|
||||
*
|
||||
* @param $_syncid containing appName-contentid
|
||||
* @param $_action string can be add, delete or modify
|
||||
* @return string the last timestamp
|
||||
*/
|
||||
function getSyncTSforAction($_syncid, $_action) {
|
||||
$syncIDParts = explode('-',$_syncid);
|
||||
$_appName = array_shift($syncIDParts);
|
||||
$_id = implode ('', $syncIDParts);
|
||||
|
||||
|
||||
$ts = $GLOBALS['egw']->contenthistory->getTSforAction($_appName, $_id, $_action);
|
||||
|
||||
|
||||
return $ts;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* get the timestamp for action
|
||||
*
|
||||
@ -63,57 +64,94 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
*
|
||||
* @param string$_appName the appname example: infolog_notes
|
||||
* @param string $_action can be modify, add or delete
|
||||
* @param string $_ts timestamp where to start searching from
|
||||
* @param string $_ts timestamp where to start searching from
|
||||
* @return array containing syncIDs with changes
|
||||
*/
|
||||
function getHistory($_appName, $_action, $_ts)
|
||||
{
|
||||
function getHistory($_appName, $_action, $_ts) {
|
||||
$guidList = array ();
|
||||
$syncIdList = array ();
|
||||
$idList = $GLOBALS['egw']->contenthistory->getHistory($_appName, $_action, $_ts);
|
||||
foreach ($idList as $idItem)
|
||||
{
|
||||
$syncIdList[] = $_appName . '-' . $idItem;
|
||||
if ($idItem) // ignore inconsistent entries
|
||||
{
|
||||
$syncIdList[] = $_appName . '-' . $idItem;
|
||||
}
|
||||
}
|
||||
return $syncIdList;
|
||||
return $syncIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp (if set) of the last change to the
|
||||
* obj:guid, that was caused by the client. This is stored to
|
||||
* avoid mirroring these changes back to the client.
|
||||
*/
|
||||
function getChangeTS($type, $guid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
#Horde::logMessage('SyncML: getChangeTS for ' . $mapID .' / '. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if ($ts = $GLOBALS['egw']->db->select('egw_contentmap', 'map_timestamp', array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchSingle())
|
||||
{
|
||||
#Horde::logMessage('SyncML: getChangeTS changets is ' . $GLOBALS['egw']->db->from_timestamp($ts), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $GLOBALS['egw']->db->from_timestamp($ts);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about the clients device info if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* a array containing all available infos about the device
|
||||
*/
|
||||
function getClientDeviceInfo()
|
||||
{
|
||||
if(($deviceID = $GLOBALS['egw']->db->select('egw_syncmldeviceowner', 'owner_devid',array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchSingle()))
|
||||
* Returns the timestamp (if set) of the last change to the
|
||||
* obj:guid, that was caused by the client. This is stored to
|
||||
* avoid mirroring these changes back to the client.
|
||||
*/
|
||||
function getChangeTS($type, $guid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
#Horde::logMessage('SyncML: getChangeTS for ' . $mapID
|
||||
# . ' / '. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if ($ts = $GLOBALS['egw']->db->select('egw_contentmap', 'map_timestamp',
|
||||
array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn()) {
|
||||
#Horde::logMessage('SyncML: getChangeTS changets is '
|
||||
# . $GLOBALS['egw']->db->from_timestamp($ts),
|
||||
# __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $GLOBALS['egw']->db->from_timestamp($ts);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exceptions for a GUID which the client knows of
|
||||
*/
|
||||
function getGUIDExceptions($type, $guid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
#Horde::logMessage('SyncML: getChangeTS for ' . $mapID
|
||||
# . ' / '. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$guid_exceptions = array();
|
||||
$where = array ('map_id' => $mapID,);
|
||||
$where[] = "map_guid LIKE '$guid" . ":%'";
|
||||
|
||||
// Fetch all exceptions which the client knows of
|
||||
foreach ($GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', $where,
|
||||
__LINE__,__FILE__, false, '', 'syncml') as $row)
|
||||
{
|
||||
$parts = preg_split('/:/', $row['map_guid']);
|
||||
$Id = $parts[0];
|
||||
$extension = $parts[1];
|
||||
$guid_exceptions[$extension] = $row['map_guid'];
|
||||
}
|
||||
return $guid_exceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about the clients device info if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* a array containing all available infos about the device
|
||||
*/
|
||||
function getClientDeviceInfo() {
|
||||
#Horde::logMessage("SyncML: getClientDeviceInfo " . $this->_locName
|
||||
# . ", " . $this->_sourceURI, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (isset($this->_clientDeviceInfo)
|
||||
&& is_array($this->_clientDeviceInfo)) {
|
||||
// use cached information
|
||||
return $this->_clientDeviceInfo;
|
||||
}
|
||||
|
||||
if (($deviceID = $GLOBALS['egw']->db->select('egw_syncmldeviceowner',
|
||||
'owner_devid',
|
||||
array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
$cols = array(
|
||||
'dev_dtdversion',
|
||||
'dev_numberofchanges',
|
||||
@ -129,156 +167,161 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
'dev_utc',
|
||||
);
|
||||
|
||||
#Horde::logMessage("SyncML: getClientDeviceInfo $deviceID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$where = array(
|
||||
'dev_id' => $deviceID,
|
||||
'dev_id' => $deviceID,
|
||||
);
|
||||
|
||||
if (($row = $GLOBALS['egw']->db->select('egw_syncmldevinfo', $cols, $where, __LINE__, __FILE__, false, '', 'syncml')->fetch()))
|
||||
{
|
||||
return array (
|
||||
'DTDVersion' => $row['dev_dtdversion'],
|
||||
'supportNumberOfChanges'=> $row['dev_numberofchanges'],
|
||||
'supportLargeObjs' => $row['dev_largeobjs'],
|
||||
'UTC' => $row['dev_utc'],
|
||||
'softwareVersion' => $row['dev_swversion'],
|
||||
'hardwareVersion' => $row['dev_hwversion'],
|
||||
'firmwareVersion' => $row['dev_fwversion'],
|
||||
'oem' => $row['dev_oem'],
|
||||
'model' => $row['dev_model'],
|
||||
'manufacturer' => $row['dev_manufacturer'],
|
||||
'deviceType' => $row['dev_devicetype'],
|
||||
'dataStore' => unserialize($row['dev_datastore']),
|
||||
if (($row = $GLOBALS['egw']->db->select('egw_syncmldevinfo',
|
||||
$cols, $where, __LINE__, __FILE__, false, '', 'syncml')->fetch())) {
|
||||
$deviceMaxEntries = 'maxEntries-' . $this->_sourceURI;
|
||||
$deviceUIDExtension = 'uidExtension-' . $this->_sourceURI;
|
||||
$deviceNonBlockingAllday = 'nonBlockingAllday-' . $this->_sourceURI;
|
||||
$deviceTimezone = 'tzid-' . $this->_sourceURI;
|
||||
$syncml_prefs = $GLOBALS['egw_info']['user']['preferences']['syncml'];
|
||||
$this->_clientDeviceInfo = array (
|
||||
'DTDVersion' => $row['dev_dtdversion'],
|
||||
'supportNumberOfChanges' => $row['dev_numberofchanges'],
|
||||
'supportLargeObjs' => $row['dev_largeobjs'],
|
||||
'UTC' => $row['dev_utc'],
|
||||
'softwareVersion' => $row['dev_swversion'],
|
||||
'hardwareVersion' => $row['dev_hwversion'],
|
||||
'firmwareVersion' => $row['dev_fwversion'],
|
||||
'oem' => $row['dev_oem'],
|
||||
'model' => $row['dev_model'],
|
||||
'manufacturer' => $row['dev_manufacturer'],
|
||||
'deviceType' => $row['dev_devicetype'],
|
||||
'maxMsgSize' => $this->_maxMsgSize,
|
||||
'maxEntries' => $syncml_prefs[$deviceMaxEntries],
|
||||
'uidExtension' => $syncml_prefs[$deviceUIDExtension],
|
||||
'nonBlockingAllday' => $syncml_prefs[$deviceNonBlockingAllday],
|
||||
'tzid' => $syncml_prefs[$deviceTimezone],
|
||||
'dataStore' => unserialize($row['dev_datastore']),
|
||||
);
|
||||
return $this->_clientDeviceInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns GUIDs of all client items
|
||||
*/
|
||||
function _getClientItems($type)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
* returns GUIDs of all client items
|
||||
*/
|
||||
function getClientItems() {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $this->_targetURI;
|
||||
|
||||
$guids = array();
|
||||
foreach($GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_expired' => 0,
|
||||
), __LINE__, __FILE__, false, '', 'syncml') as $row)
|
||||
{
|
||||
$guids[] = $row['map_guid'];
|
||||
}
|
||||
return $guids ? $guids : false;
|
||||
$guids = array();
|
||||
foreach($GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_expired' => false,
|
||||
), __LINE__, __FILE__, false, '', 'syncml') as $row) {
|
||||
$guids[] = $row['map_guid'];
|
||||
}
|
||||
return $guids ? $guids : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Horde server guid (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) for a given client
|
||||
* locid. Returns false if no such id is stored yet.
|
||||
*
|
||||
* Opposite of getLocId which returns the locid for a given guid.
|
||||
*/
|
||||
function getGlobalUID($type, $locid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
/**
|
||||
* Retrieves the Horde server guid (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) for a given client
|
||||
* locid. Returns false if no such id is stored yet.
|
||||
*
|
||||
* Opposite of getLocId which returns the locid for a given guid.
|
||||
*/
|
||||
function getGlobalUID($type, $locid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
#Horde::logMessage('SyncML: search GlobalUID for ' . $mapID .' / '.$locid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
#Horde::logMessage('SyncML: search GlobalUID for ' . $mapID .' / '.$locid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
return $GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
'map_expired' => 0,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchSingle();
|
||||
}
|
||||
return $GLOBALS['egw']->db->select('egw_contentmap', 'map_guid',
|
||||
array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
'map_expired' => false,
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a EGW GUID (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) to a client ID as
|
||||
* used by the sync client (like 12) returns false if no such id
|
||||
* is stored yet.
|
||||
*/
|
||||
function getLocID($type, $guid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
/**
|
||||
* Converts a EGW GUID (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) to a client ID as
|
||||
* used by the sync client (like 12) returns false if no such id
|
||||
* is stored yet.
|
||||
*/
|
||||
function getLocID($type, $guid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
Horde::logMessage('SyncML: search LocID for ' . $mapID .' / '.$guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage('SyncML: search LocID for ' . $mapID . ' / ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if (($locuid = $GLOBALS['egw']->db->select('egw_contentmap', 'map_locuid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchSingle()))
|
||||
{
|
||||
Horde::logMessage('SyncML: found LocID: '.$locuid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
return $locuid;
|
||||
}
|
||||
if (($locuid = $GLOBALS['egw']->db->select('egw_contentmap', 'map_locuid', array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
Horde::logMessage('SyncML: found LocID: '.$locuid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
return $locuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about the previous sync if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* ClientAnchor: the clients Next Anchor of the previous sync.
|
||||
* ServerAnchor: the Server Next Anchor of the previous sync.
|
||||
*/
|
||||
function getSyncSummary($type)
|
||||
{
|
||||
/**
|
||||
* Retrieves information about the previous sync if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* ClientAnchor: the clients Next Anchor of the previous sync.
|
||||
* ServerAnchor: the Server Next Anchor of the previous sync.
|
||||
*/
|
||||
function getSyncSummary($type) {
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
|
||||
#Horde::logMessage("SyncML: get SYNCSummary for $deviceID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: getSyncSummary for $deviceID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if (($row = $GLOBALS['egw']->db->select('egw_syncmlsummary', array('sync_serverts','sync_clientts'), array(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetch()))
|
||||
{
|
||||
#Horde::logMessage("SyncML: get SYNCSummary for $deviceID serverts: ".$row['sync_serverts']." clients: ".$row['sync_clientts'], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return array(
|
||||
'ClientAnchor' => $row['sync_clientts'],
|
||||
'ServerAnchor' => $row['sync_serverts'],
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (($row = $GLOBALS['egw']->db->select('egw_syncmlsummary', array('sync_serverts','sync_clientts'), array(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type
|
||||
), __LINE__, __FILE__, false, '', 'syncml')->fetch())) {
|
||||
Horde::logMessage("SyncML: getSyncSummary for $deviceID serverts: ".$row['sync_serverts']." clients: ".$row['sync_clientts'], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return array(
|
||||
'ClientAnchor' => $row['sync_clientts'],
|
||||
'ServerAnchor' => $row['sync_serverts'],
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isAuthorized()
|
||||
{
|
||||
if (!$this->_isAuthorized)
|
||||
{
|
||||
if(!isset($this->_locName) && !isset($this->_password))
|
||||
{
|
||||
function isAuthorized() {
|
||||
if (!$this->_isAuthorized) {
|
||||
if(!isset($this->_locName) && !isset($this->_password)) {
|
||||
Horde::logMessage('SyncML: Authentication not yet possible currently. Username and password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!isset($this->_password))
|
||||
{
|
||||
if(!isset($this->_password)) {
|
||||
Horde::logMessage('SyncML: Authentication not yet possible currently. Password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(strpos($this->_locName,'@') === False)
|
||||
{
|
||||
if(strpos($this->_locName,'@') === False) {
|
||||
$this->_locName .= '@'.$GLOBALS['egw_info']['server']['default_domain'];
|
||||
} else {
|
||||
$parts = explode('@',$this->_locName);
|
||||
$GLOBALS['egw_info']['user']['domain'] = array_pop($parts);
|
||||
}
|
||||
|
||||
#Horde::logMessage('SyncML: authenticate with username: ' . $this->_locName . ' and password: ' . $this->_password, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if($GLOBALS['sessionid'] = $GLOBALS['egw']->session->create($this->_locName,$this->_password,'text'))
|
||||
{
|
||||
$this->_isAuthorized = true;
|
||||
Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
else
|
||||
{
|
||||
if($GLOBALS['sessionid'] = $GLOBALS['egw']->session->create($this->_locName,$this->_password,'text')) {
|
||||
|
||||
if ($GLOBALS['egw_info']['user']['apps']['syncml']) {
|
||||
$this->_isAuthorized = true;
|
||||
Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
$this->_isAuthorized = false;
|
||||
Horde::logMessage('SyncML is not enabled for this user', __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
}
|
||||
} else {
|
||||
$this->_isAuthorized = false;
|
||||
Horde::logMessage('SyncML: Authentication of ' . $this->_locName . ' failed' , __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// store sessionID in a variable, because ->verify maybe resets that value
|
||||
$sessionID = session_id();
|
||||
if(!$GLOBALS['egw']->session->verify($sessionID, 'staticsyncmlkp3')) {
|
||||
@ -290,11 +333,10 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all locid<->guid mappings for the given type.
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeAllUID($type)
|
||||
{
|
||||
* Removes all locid<->guid mappings for the given type.
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeAllUID($type) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
Horde::logMessage("SyncML: state->removeAllUID(type=$type)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
@ -302,17 +344,16 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', array('map_id' => $mapID), __LINE__, __FILE__, 'syncml');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in SlowSync
|
||||
* Removes all locid<->guid mappings for the given type,
|
||||
* that are older than $ts.
|
||||
*
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeOldUID($type, $ts)
|
||||
{
|
||||
* Used in SlowSync
|
||||
* Removes all locid<->guid mappings for the given type,
|
||||
* that are older than $ts.
|
||||
*
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeOldUID($type, $ts) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
$where[] = "map_id = '".$mapID."' AND map_timestamp < '".$GLOBALS['egw']->db->to_timestamp($ts)."'";
|
||||
|
||||
@ -324,102 +365,151 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the locid<->guid mapping for the given locid. Returns
|
||||
* the guid that was removed or false if no mapping entry was
|
||||
* found.
|
||||
*/
|
||||
function removeUID($type, $locid)
|
||||
{
|
||||
* Used at session end to cleanup expired entries
|
||||
* Removes all locid<->guid mappings for the given type,
|
||||
* that are marked as expired and older than $ts.
|
||||
*
|
||||
* Returns always true.
|
||||
*/
|
||||
function removeExpiredUID($type, $ts) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$where['map_id'] = $mapID;
|
||||
$where['map_expired'] = true;
|
||||
$where[] = "map_timestamp <= '".$GLOBALS['egw']->db->to_timestamp($ts)."'";
|
||||
|
||||
Horde::logMessage("SyncML: state->removeExpiredUID(type=$type)",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an entry is already expired
|
||||
*
|
||||
* Returns true for expired mappings.
|
||||
*/
|
||||
function isExpiredUID($type, $locid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
$expired = false;
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
);
|
||||
if (($expired = $GLOBALS['egw']->db->select('egw_contentmap', 'map_expired',
|
||||
$where, __LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
Horde::logMessage('SyncML: found LocID: '. $locid,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
return $expired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the locid<->guid mapping for the given locid. Returns
|
||||
* the guid that was removed or false if no mapping entry was
|
||||
* found.
|
||||
*/
|
||||
function removeUID($type, $locid) {
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$where = array (
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid
|
||||
);
|
||||
|
||||
if (!($guid = $GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', $where, __LINE__, __FILE__, false, '', 'syncml')->fetchSingle()))
|
||||
{
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid) : nothing to remove", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
if (!($guid = $GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', $where,
|
||||
__LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid)"
|
||||
. " nothing to remove", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
return false;
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid) : removing guid:$guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid): "
|
||||
. "removing guid $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where, __LINE__, __FILE__, 'syncml');
|
||||
|
||||
return $guid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a given client $locid and Horde server $guid pair into the
|
||||
* map table to allow mapping between the client's and server's
|
||||
* IDs. Actually there are two maps: from the localid to the guid
|
||||
* and vice versa. The localid is converted to a key as follows:
|
||||
* this->_locName . $this->_sourceURI . $type . $locid so you can
|
||||
* have different syncs with different devices. If an entry
|
||||
* already exists, it is overwritten.
|
||||
*/
|
||||
function setUID($type, $locid, $_guid, $ts=0)
|
||||
{
|
||||
#Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
#Horde::logMessage("SyncML: setUID ". $this->getUIDMapping($guid), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// problem: entries created from client, come here with the (long) server guid,
|
||||
// but getUIDMapping does not know them and can not map server-guid <--> client guid
|
||||
$guid = $this->getUIDMapping($_guid);
|
||||
if($guid === false)
|
||||
{
|
||||
// this message is not really usefull here because setUIDMapping is only called when adding content to the client,
|
||||
// however setUID is called also when adding content from the client. So in all other conditions this
|
||||
// message will be logged.
|
||||
Horde::logMessage("SyncML: setUID $type, $locid, $guid something went wrong!!! Mapping not found.", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$guid = $_guid;
|
||||
//return false;
|
||||
}
|
||||
Horde::logMessage("SyncML: setUID $_guid => $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
/**
|
||||
* Puts a given client $locid and Horde server $guid pair into the
|
||||
* map table to allow mapping between the client's and server's
|
||||
* IDs. Actually there are two maps: from the localid to the guid
|
||||
* and vice versa. The localid is converted to a key as follows:
|
||||
* this->_locName . $this->_sourceURI . $type . $locid so you can
|
||||
* have different syncs with different devices. If an entry
|
||||
* already exists, it is overwritten.
|
||||
* Expired entries can be deleted at the next session start.
|
||||
*/
|
||||
function setUID($type, $locid, $_guid, $ts=0, $expired=false) {
|
||||
#Horde::logMessage("SyncML: setUID $type, $locid, $_guid, $ts ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if(!$ts) $ts = time();
|
||||
if (!strlen("$_guid")) {
|
||||
// We can't handle this case otherwise
|
||||
return;
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// problem: entries created from client, come here with the (long) server guid,
|
||||
// but getUIDMapping does not know them and can not map server-guid <--> client guid
|
||||
$guid = $this->getUIDMapping($_guid);
|
||||
if($guid === false) {
|
||||
// this message is not really usefull here because setUIDMapping is only called when adding content to the client,
|
||||
// however setUID is called also when adding content from the client. So in all other conditions this
|
||||
// message will be logged.
|
||||
//Horde::logMessage("SyncML: setUID $type, $locid, $guid something went wrong!!! Mapping not found.", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$guid = $_guid;
|
||||
//return false;
|
||||
}
|
||||
#Horde::logMessage("SyncML: setUID $_guid => $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
if(!$ts) $ts = time();
|
||||
|
||||
// delete all client id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where, __LINE__, __FILE__, 'syncml');
|
||||
Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// delete all egw id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where, __LINE__, __FILE__, 'syncml');
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$data = $where + array(
|
||||
'map_locuid' => $locid,
|
||||
'map_timestamp' => $ts,
|
||||
'map_expired' => 0,
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_contentmap', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
// expire all client id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
);
|
||||
$data = array (
|
||||
'map_expired' => true,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
|
||||
#Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts $mapID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
// delete all egw id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
);
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
|
||||
$data = $where + array(
|
||||
'map_locuid' => $locid,
|
||||
'map_timestamp' => $ts,
|
||||
'map_expired' => ($expired ? true : false),
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_contentmap', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
|
||||
/**
|
||||
* writes clients deviceinfo into database
|
||||
*/
|
||||
function writeClientDeviceInfo()
|
||||
{
|
||||
if (!isset($this->_clientDeviceInfo) || !is_array($this->_clientDeviceInfo))
|
||||
{
|
||||
* writes clients deviceinfo into database
|
||||
*/
|
||||
function writeClientDeviceInfo() {
|
||||
if (!isset($this->_clientDeviceInfo)
|
||||
|| !is_array($this->_clientDeviceInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isset($this->size_dev_hwversion))
|
||||
{
|
||||
if(!isset($this->size_dev_hwversion)) {
|
||||
$tableDefDevInfo = $GLOBALS['egw']->db->get_table_definitions('syncml',$this->table_devinfo);
|
||||
$this->size_dev_hwversion = $tableDefDevInfo['fd']['dev_hwversion']['precision'];
|
||||
unset($tableDefDevInfo);
|
||||
@ -437,77 +527,89 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
'dev_fwversion' => $firmwareVersion,
|
||||
);
|
||||
|
||||
if (($deviceID = $GLOBALS['egw']->db->select('egw_syncmldevinfo', 'dev_id', $where, __LINE__, __FILE__, false, '', 'syncml')->fetchSingle()))
|
||||
{
|
||||
if (($deviceID = $GLOBALS['egw']->db->select('egw_syncmldevinfo', 'dev_id', $where,
|
||||
__LINE__, __FILE__, false, '', 'syncml')->fetchColumn())) {
|
||||
$data = array (
|
||||
'dev_datastore' => serialize($this->_clientDeviceInfo['dataStore']),
|
||||
);
|
||||
$GLOBALS['egw']->db->update('egw_syncmldevinfo', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
else
|
||||
{
|
||||
$GLOBALS['egw']->db->update('egw_syncmldevinfo', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
} else {
|
||||
$data = array (
|
||||
'dev_dtdversion' => $this->_clientDeviceInfo['DTDVersion'],
|
||||
'dev_numberofchanges' => $this->_clientDeviceInfo['supportNumberOfChanges'] ? true : false,
|
||||
'dev_largeobjs' => $this->_clientDeviceInfo['supportLargeObjs'] ? true : false,
|
||||
'dev_utc' => $this->_clientDeviceInfo['UTC'] ? true : false,
|
||||
'dev_swversion' => $softwareVersion,
|
||||
'dev_hwversion' => $hardwareVersion,
|
||||
'dev_fwversion' => $firmwareVersion,
|
||||
'dev_oem' => $this->_clientDeviceInfo['oem'],
|
||||
'dev_model' => $this->_clientDeviceInfo['model'],
|
||||
'dev_manufacturer' => $this->_clientDeviceInfo['manufacturer'],
|
||||
'dev_devicetype' => $this->_clientDeviceInfo['deviceType'],
|
||||
'dev_datastore' => serialize($this->_clientDeviceInfo['dataStore']),
|
||||
'dev_dtdversion' => $this->_clientDeviceInfo['DTDVersion'],
|
||||
'dev_numberofchanges' => ($this->_clientDeviceInfo['supportNumberOfChanges'] ? true : false),
|
||||
'dev_largeobjs' => ($this->_clientDeviceInfo['supportLargeObjs'] ? true : false),
|
||||
'dev_utc' => ($this->_clientDeviceInfo['UTC'] ? true : false),
|
||||
'dev_swversion' => $softwareVersion,
|
||||
'dev_hwversion' => $hardwareVersion,
|
||||
'dev_fwversion' => $firmwareVersion,
|
||||
'dev_oem' => $this->_clientDeviceInfo['oem'],
|
||||
'dev_model' => $this->_clientDeviceInfo['model'],
|
||||
'dev_manufacturer' => $this->_clientDeviceInfo['manufacturer'],
|
||||
'dev_devicetype' => $this->_clientDeviceInfo['deviceType'],
|
||||
'dev_datastore' => serialize($this->_clientDeviceInfo['dataStore']),
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_syncmldevinfo', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
|
||||
$deviceID = $GLOBALS['egw']->db->get_last_insert_id('egw_syncmldevinfo', 'dev_id');
|
||||
}
|
||||
|
||||
$data = array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
'owner_devid' => $deviceID,
|
||||
);
|
||||
$where = array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_syncmldeviceowner', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
|
||||
if ($GLOBALS['egw']->db->select('egw_syncmldeviceowner', 'owner_devid', $where,
|
||||
__LINE__, __FILE__, false, '', 'syncml')->fetchColumn()) {
|
||||
$data = array (
|
||||
'owner_devid' => $deviceID,
|
||||
);
|
||||
$GLOBALS['egw']->db->update('egw_syncmldeviceowner', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
} else {
|
||||
$data = array (
|
||||
'owner_locname' => $this->_locName,
|
||||
'owner_deviceid' => $this->_sourceURI,
|
||||
'owner_devid' => $deviceID,
|
||||
);
|
||||
$GLOBALS['egw']->db->insert('egw_syncmldeviceowner', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After a successful sync, the client and server's Next Anchors
|
||||
* are written to the database so they can be used to negotiate
|
||||
* upcoming syncs.
|
||||
*/
|
||||
function writeSyncSummary()
|
||||
{
|
||||
#parent::writeSyncSummary();
|
||||
/**
|
||||
* After a successful sync, the client and server's Next Anchors
|
||||
* are written to the database so they can be used to negotiate
|
||||
* upcoming syncs.
|
||||
*/
|
||||
function writeSyncSummary() {
|
||||
#parent::writeSyncSummary();
|
||||
|
||||
if (!isset($this->_serverAnchorNext) || !is_array($this->_serverAnchorNext))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!isset($this->_serverAnchorNext)
|
||||
|| !is_array($this->_serverAnchorNext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
|
||||
foreach((array)$this->_serverAnchorNext as $type => $a)
|
||||
{
|
||||
Horde::logMessage("SyncML: write SYNCSummary for $deviceID $type serverts: $a clients: ".$this->_clientAnchorNext[$type], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
foreach((array)$this->_serverAnchorNext as $type => $a) {
|
||||
Horde::logMessage("SyncML: write SYNCSummary for $deviceID "
|
||||
. "$type serverts: $a clients: "
|
||||
. $this->_clientAnchorNext[$type],
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$where = array(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type,
|
||||
);
|
||||
$where = array(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type,
|
||||
);
|
||||
|
||||
$data = array(
|
||||
'sync_serverts' => $a,
|
||||
'sync_clientts' => $this->_clientAnchorNext[$type]
|
||||
);
|
||||
$data = array(
|
||||
'sync_serverts' => $a,
|
||||
'sync_clientts' => $this->_clientAnchorNext[$type]
|
||||
);
|
||||
|
||||
$GLOBALS['egw']->db->insert('egw_syncmlsummary', $data, $where, __LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
}
|
||||
$GLOBALS['egw']->db->insert('egw_syncmlsummary', $data, $where,
|
||||
__LINE__, __FILE__, 'syncml');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,230 +1,466 @@
|
||||
<?php
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Sync.php,v 1.7 2004/09/14 04:27:05 chuck Exp $
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
class Horde_SyncML_Sync {
|
||||
|
||||
/**
|
||||
* Target, either contacts, notes, events,
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
/**
|
||||
* Target, either contacts, notes, events,
|
||||
*/
|
||||
var $_targetLocURI;
|
||||
|
||||
var $_sourceLocURI;
|
||||
var $_sourceLocURI;
|
||||
|
||||
/**
|
||||
* Return if all commands success.
|
||||
*/
|
||||
var $globalSuccess;
|
||||
|
||||
/**
|
||||
* This is the content type to use to export data.
|
||||
*/
|
||||
var $preferedContentType;
|
||||
|
||||
/**
|
||||
* Do have the sync data loaded from the database already?
|
||||
*/
|
||||
var $syncDataLoaded;
|
||||
|
||||
function &factory($alert)
|
||||
{
|
||||
Horde::logMessage('SyncML: new sync for alerttype ' . $alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
switch ($alert) {
|
||||
case ALERT_TWO_WAY:
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
return $sync = &new Horde_SyncML_Sync_TwoWaySync();
|
||||
|
||||
case ALERT_SLOW_SYNC:
|
||||
include_once 'Horde/SyncML/Sync/SlowSync.php';
|
||||
return $sync = &new Horde_SyncML_Sync_SlowSync();
|
||||
|
||||
case ALERT_ONE_WAY_FROM_CLIENT:
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromClientSync.php';
|
||||
return $sync = &new Horde_SyncML_Sync_OneWayFromClientSync();
|
||||
|
||||
case ALERT_REFRESH_FROM_CLIENT:
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromClientSync.php';
|
||||
return $sync = &new Horde_SyncML_Sync_RefreshFromClientSync();
|
||||
|
||||
case ALERT_ONE_WAY_FROM_SERVER:
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromServerSync.php';
|
||||
return $sync = &new Horde_SyncML_Sync_OneWayFromServerSync();
|
||||
|
||||
case ALERT_REFRESH_FROM_SERVER:
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromServerSync.php';
|
||||
return $sync = &new Horde_SyncML_Sync_RefreshFromServerSync();
|
||||
}
|
||||
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::raiseError('Alert ' . $alert . ' not found.');
|
||||
}
|
||||
|
||||
function nextSyncCommand($currentCmdID, &$syncCommand, &$output)
|
||||
{
|
||||
$result = $this->runSyncCommand($syncCommand);
|
||||
return $syncCommand->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
function startSync($currentCmdID, &$output)
|
||||
{
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function endSync($currentCmdID, &$output)
|
||||
{
|
||||
return $currentCmdID;
|
||||
}
|
||||
var $_locName;
|
||||
|
||||
/**
|
||||
* Here's where the actual processing of a client-sent Sync
|
||||
* Command takes place. Entries are added, deleted or replaced
|
||||
* from the server database by using Horde API (Registry) calls.
|
||||
*/
|
||||
* The synchronization method, one of the ALERT_* constants.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_syncType;
|
||||
|
||||
/**
|
||||
* Return if all commands success.
|
||||
*/
|
||||
var $globalSuccess;
|
||||
|
||||
/**
|
||||
* This is the content type to use to export data.
|
||||
*/
|
||||
var $preferedContentType;
|
||||
|
||||
/**
|
||||
* Optional filter expression for this content.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_filterExpression = '';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Do have the sync data loaded from the database already?
|
||||
*/
|
||||
var $syncDataLoaded;
|
||||
|
||||
function &factory($alert) {
|
||||
Horde::logMessage('SyncML: new sync for alerttype ' . $alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
switch ($alert) {
|
||||
case ALERT_TWO_WAY:
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
return $sync = new Horde_SyncML_Sync_TwoWaySync();
|
||||
|
||||
case ALERT_SLOW_SYNC:
|
||||
include_once 'Horde/SyncML/Sync/SlowSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_SlowSync();
|
||||
|
||||
case ALERT_ONE_WAY_FROM_CLIENT:
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromClientSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_OneWayFromClientSync();
|
||||
|
||||
case ALERT_REFRESH_FROM_CLIENT:
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromClientSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_RefreshFromClientSync();
|
||||
|
||||
case ALERT_ONE_WAY_FROM_SERVER:
|
||||
include_once 'Horde/SyncML/Sync/OneWayFromServerSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_OneWayFromServerSync();
|
||||
|
||||
case ALERT_REFRESH_FROM_SERVER:
|
||||
include_once 'Horde/SyncML/Sync/RefreshFromServerSync.php';
|
||||
return $sync = new Horde_SyncML_Sync_RefreshFromServerSync();
|
||||
}
|
||||
|
||||
require_once 'PEAR.php';
|
||||
return PEAR::raiseError('Alert ' . $alert . ' not found.');
|
||||
}
|
||||
|
||||
function nextSyncCommand($currentCmdID, &$syncCommand, &$output) {
|
||||
$result = $this->runSyncCommand($syncCommand);
|
||||
return $syncCommand->output($currentCmdID, $output);
|
||||
}
|
||||
|
||||
function startSync($currentCmdID, &$output) {
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function endSync($currentCmdID, &$output) {
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property sourceURI.
|
||||
*
|
||||
* @param string $sourceURI New value of property sourceLocURI.
|
||||
*/
|
||||
function setSourceLocURI($sourceURI) {
|
||||
$this->_sourceLocURI = $sourceURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property targetURI.
|
||||
*
|
||||
* @param string $targetURI New value of property targetLocURI.
|
||||
*/
|
||||
function setTargetLocURI($targetURI) {
|
||||
$this->_targetLocURI = $targetURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property syncType.
|
||||
*
|
||||
* @param integer $syncType New value of property syncType.
|
||||
*/
|
||||
function setSyncType($syncType) {
|
||||
$this->_syncType = $syncType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property locName.
|
||||
*
|
||||
* @param string $locName New value of property locName.
|
||||
*/
|
||||
function setLocName($locName) {
|
||||
$this->_locName = $locName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property filterExpression.
|
||||
*
|
||||
* @param string $expression New value of property filterExpression.
|
||||
*/
|
||||
function setFilterExpression($expression) {
|
||||
$this->_filterExpression = $expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Here's where the actual processing of a client-sent Sync
|
||||
* Command takes place. Entries are added, deleted or replaced
|
||||
* from the server database by using Horde API (Registry) calls.
|
||||
*/
|
||||
function runSyncCommand(&$command) {
|
||||
#Horde::logMessage('SyncML: content type is ' . $command->getContentType() .' moreData '. $command->_moreData, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
global $registry;
|
||||
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
if(isset($state->_moreData['luid'])) {
|
||||
if(($command->_luid == $state->_moreData['luid'])) {
|
||||
Horde::logMessage('SyncML: got next moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$lastChunks = implode('',$state->_moreData['chunks']);
|
||||
$command->_content = $lastChunks.$command->_content;
|
||||
$stringlen1 = strlen($lastChunks);
|
||||
$stringlen2 = strlen($command->_content);
|
||||
|
||||
if(!$command->_moreData && strlen($command->_content) != $state->_moreData['contentSize']) {
|
||||
$command->_status = RESPONSE_SIZE_MISMATCH;
|
||||
$state->_moreData = array();
|
||||
|
||||
return;
|
||||
} elseif(!$command->_moreData && strlen($command->_content) == $state->_moreData['contentSize']) {
|
||||
$state->_moreData = array();
|
||||
Horde::logMessage('SyncML: chunk ended successful type is ' . $command->getContentType() .' content is '. $command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
} else {
|
||||
// alert 223 needed too
|
||||
#$command->_status = ALERT_NO_END_OF_DATA;
|
||||
|
||||
$state->_moreData = array();
|
||||
|
||||
return;
|
||||
|
||||
if ($command->hasMoreData()) {
|
||||
Horde::logMessage('SyncML: moreData: TRUE', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$command->setStatus(RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED);
|
||||
return true;
|
||||
}
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
|
||||
$syncml_prefs = $GLOBALS['egw_info']['user']['preferences']['syncml'];
|
||||
if (isset($syncml_prefs[$type])) {
|
||||
$sync_conflicts = $syncml_prefs[$type];
|
||||
} else {
|
||||
$sync_conflicts = CONFLICT_SERVER_WINNING;
|
||||
}
|
||||
|
||||
$state->setLocName($this->_locName);
|
||||
$locName = $state->getLocName();
|
||||
$sourceURI = $state->getSourceURI();
|
||||
$hordeType = $state->getHordeType($type);
|
||||
$serverAnchorLast = $state->getServerAnchorLast($type);
|
||||
$state->setTargetURI($type);
|
||||
$changes = array();
|
||||
// First we get all changes done after the previous sync start
|
||||
foreach ($registry->call($hordeType. '/listBy',
|
||||
array('action' => 'modify',
|
||||
'timestamp' => $serverAnchorLast,
|
||||
'type' => $type,
|
||||
'filter' => $this->_filterExpression)) as $change) {
|
||||
// now we have to remove the ones
|
||||
// that came from the last sync with this client
|
||||
$guid_ts = $state->getSyncTSforAction($change, 'modify');
|
||||
$sync_ts = $state->getChangeTS($type, $change);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
Horde::logMessage("SyncML: change: $change ignored, " .
|
||||
"came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
$changes[] = $change;
|
||||
}
|
||||
|
||||
// don't add/replace the data currently, they are not yet complete
|
||||
if($command->_moreData == TRUE) {
|
||||
$state->_moreData['chunks'][] = $command->_content;
|
||||
$state->_moreData['luid'] = $command->_luid;
|
||||
|
||||
// gets only set with the first chunk of data
|
||||
if(isset($command->_contentSize))
|
||||
$state->_moreData['contentSize'] = $command->_contentSize;
|
||||
|
||||
$command->_status = RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED;
|
||||
Horde::logMessage('SyncML: added moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$hordeType = $type = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($hordeType);
|
||||
|
||||
Horde::logMessage('SyncML: runSyncCommand found ' . count($changes) .
|
||||
" possible conflicts for $type", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if(!$contentType = $command->getContentType()) {
|
||||
$contentType = $state->getPreferedContentType($type);
|
||||
}
|
||||
|
||||
|
||||
if (($contentType == 'text/x-vcalendar' || $contentType == 'text/calendar')
|
||||
&& strpos($command->getContent(), 'BEGIN:VTODO') !== false)
|
||||
{
|
||||
&& strpos($command->getContent(), 'BEGIN:VTODO') !== false) {
|
||||
$hordeType = 'tasks';
|
||||
}
|
||||
|
||||
$syncElementItems = $command->getSyncElementItems();
|
||||
|
||||
|
||||
foreach($syncElementItems as $syncItem) {
|
||||
|
||||
|
||||
$guid = false;
|
||||
|
||||
|
||||
$contentSize = strlen($syncItem->_content);
|
||||
if ((($size = $syncItem->getContentSize()) !== false) &&
|
||||
($contentSize != $size) &&
|
||||
($contentSize + 1 != $size)) {
|
||||
Horde::logMessage('SyncML: content size missmatch for LocURI '
|
||||
. $syncItem->getLocURI() . ": $contentSize ($size)",
|
||||
__FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$command->setStatus(RESPONSE_SIZE_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_a($command, 'Horde_SyncML_Command_Sync_Add')) {
|
||||
if ($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
// We enforce the client not to change anything
|
||||
if ($sync_conflicts > CONFLICT_CLIENT_CHANGES_IGNORED) {
|
||||
// delete this item from client
|
||||
Horde::logMessage('SyncML: Server RO! REMOVE '
|
||||
. $syncItem->getLocURI() . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, $syncItem->getLocURI());
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Server RO! '
|
||||
. 'REJECT all client changes',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->log('Client-AddReplaceIgnored');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
|
||||
if (!is_a($guid, 'PEAR_Error') && $guid != false) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-Add");
|
||||
Horde::logMessage('SyncML: added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->log('Client-Add');
|
||||
Horde::logMessage('SyncML: added client entry as '
|
||||
. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
$state->log("Client-AddFailure");
|
||||
Horde::logMessage('SyncML: Error in adding client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log('Client-AddFailure');
|
||||
Horde::logMessage('SyncML: Error in adding client entry: '
|
||||
. $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
}
|
||||
} elseif (is_a($command, 'Horde_SyncML_Command_Sync_Delete')) {
|
||||
// We can't remove the mapping entry as we need to keep
|
||||
// the timestamp information.
|
||||
$guid = $state->removeUID($type, $syncItem->getLocURI());
|
||||
#$guid = $state->getGlobalUID($type, $syncItem->getLocURI());
|
||||
Horde::logMessage('SyncML: about to delete entry ' . $type .' / '. $guid . ' due to client request '.$syncItem->getLocURI(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if (!$guid) {
|
||||
// the entry is no longer on the server
|
||||
$state->log('Client-DeleteFailure');
|
||||
Horde::logMessage('SyncML: Failure deleting client entry, '
|
||||
. 'gone already on server!',
|
||||
__FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
continue;
|
||||
}
|
||||
if ($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
// We enforce the client not to change anything
|
||||
if ($sync_conflicts > CONFLICT_CLIENT_CHANGES_IGNORED) {
|
||||
Horde::logMessage('SyncML: Server RO! ADD '
|
||||
. $guid . ' to client again',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->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, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-Delete");
|
||||
Horde::logMessage('SyncML: deleted entry ' . $guid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$ts = $state->getSyncTSforAction($guid, 'delete');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts, 1);
|
||||
$state->log('Client-Delete');
|
||||
Horde::logMessage('SyncML: deleted entry '
|
||||
. $guid . ' due to client request',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
$state->log("Client-DeleteFailure");
|
||||
Horde::logMessage('SyncML: Failure deleting client entry, maybe gone already on server. msg:'. $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log('Client-DeleteFailure');
|
||||
Horde::logMessage('SyncML: Failure deleting client entry, '
|
||||
. 'maybe gone already on server. msg: '
|
||||
. $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
}
|
||||
} elseif (is_a($command, 'Horde_SyncML_Command_Sync_Replace')) {
|
||||
$guid = $state->getGlobalUID($type, $syncItem->getLocURI());
|
||||
$replace = true;
|
||||
$ok = false;
|
||||
if ($guid) {
|
||||
Horde::logMessage('SyncML: locuri'. $syncItem->getLocURI() . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
// Entry exists: replace current one.
|
||||
$ok = $registry->call($hordeType . '/replace',
|
||||
array($guid, $state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
if (!is_a($ok, 'PEAR_Error')) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
Horde::logMessage('SyncML: replaced entry due to client request guid: ' .$guid. ' ts: ' .$ts, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->log("Client-Replace");
|
||||
$ok = true;
|
||||
} else {
|
||||
// Entry may have been deleted; try adding it.
|
||||
$ok = false;
|
||||
$merge = false;
|
||||
if ($guid)
|
||||
{
|
||||
Horde::logMessage('SyncML: locuri '. $syncItem->getLocURI() . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) || in_array($guid, $changes))
|
||||
{
|
||||
Horde::logMessage('SyncML: CONFLICT for locuri '. $syncItem->getLocURI() . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
switch ($sync_conflicts)
|
||||
{
|
||||
case CONFLICT_CLIENT_WINNING:
|
||||
$command->setStatus(RESPONSE_CONFLICT_RESOLVED_WITH_CLIENT_WINNING);
|
||||
break;
|
||||
case CONFLICT_SERVER_WINNING:
|
||||
Horde::logMessage('SyncML: REJECT client change for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$ok = true;
|
||||
$replace = false;
|
||||
$state->log('Client-AddReplaceIgnored');
|
||||
break;
|
||||
case CONFLICT_MERGE_DATA:
|
||||
Horde::logMessage('SyncML: Merge server and client data for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$merge = true;
|
||||
break;
|
||||
case CONFLICT_RESOLVED_WITH_DUPLICATE:
|
||||
$replace = false;
|
||||
break;
|
||||
case CONFLICT_CLIENT_CHANGES_IGNORED:
|
||||
Horde::logMessage('SyncML: Server RO! REJECT client change for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$ok = true;
|
||||
$replace = false;
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log('Client-AddReplaceIgnored');
|
||||
break;
|
||||
default: // We enforce our data on client
|
||||
Horde::logMessage('SyncML: Server RO! UNDO client change for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->pushChangedItem($type, $guid);
|
||||
$ok = true;
|
||||
$replace = false;
|
||||
}
|
||||
}
|
||||
elseif ($sync_conflicts == CONFLICT_MERGE_DATA)
|
||||
{
|
||||
Horde::logMessage('SyncML: Merge server and client data for locuri ' .
|
||||
$syncItem->getLocURI() . ' guid ' . $guid ,
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$merge = true;
|
||||
}
|
||||
|
||||
if ($replace)
|
||||
{
|
||||
// Entry exists: replace/merge with current one.
|
||||
$ok = $registry->call($hordeType . '/replace',
|
||||
array($guid, $state->convertClient2Server($syncItem->getContent(),
|
||||
$contentType), $contentType, $type, $merge));
|
||||
if (!is_a($ok, 'PEAR_Error') && $ok != false)
|
||||
{
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
if ($merge)
|
||||
{
|
||||
Horde::logMessage('SyncML: Merged entry due to client request guid: ' .
|
||||
$guid . ' ts: ' . $ts, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
else
|
||||
{
|
||||
Horde::logMessage('SyncML: replaced entry due to client request guid: ' .
|
||||
$guid . ' ts: ' . $ts, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
$state->log('Client-Replace');
|
||||
$ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Entry may have been deleted; try adding it.
|
||||
$ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!$ok) {
|
||||
// Entry does not exist in map or database: add a new one.
|
||||
Horde::logMessage('SyncML: try to add contentype ' . $contentType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Entry does either not exist in map or database, or should be added due to a conflict
|
||||
|
||||
if ($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
// We enforce the client not to change anything
|
||||
if ($sync_conflicts > CONFLICT_CLIENT_CHANGES_IGNORED) {
|
||||
// delete this item from client
|
||||
Horde::logMessage('SyncML: Server RO! REMOVE ' . $syncItem->getLocURI() . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, $syncItem->getLocURI());
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Server RO! REJECT all client changes',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Horde::logMessage('SyncML: try to add contentype '
|
||||
. $contentType . ' for locuri ' . $syncItem->getLocURI(),
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
//continue;
|
||||
$oguid = $guid;
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType, $guid));
|
||||
if (!is_a($guid, 'PEAR_Error')) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
if ($oguid != $guid) {
|
||||
// We add a new entry
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
Horde::logMessage('SyncML: added entry '
|
||||
. $guid . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->log('Client-Add');
|
||||
} else {
|
||||
// We replaced an entry
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
Horde::logMessage('SyncML: replaced entry '
|
||||
. $guid . ' from client',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->log('Client-Replace');
|
||||
}
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-AddReplace");
|
||||
Horde::logMessage('SyncML: r/ added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Error in replacing/add client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log("Client-AddFailure");
|
||||
Horde::logMessage('SyncML: Error in replacing/'
|
||||
. 'add client entry:' . $guid->message,
|
||||
__FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log('Client-AddFailure');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $guid;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
include_once 'Horde/SyncML/Sync/SlowSync.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Sync/RefreshFromClientSync.php,v 1.8 2004/09/14 04:27:06 chuck Exp $
|
||||
@ -15,20 +15,9 @@ include_once 'Horde/SyncML/Sync.php';
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Sync_RefreshFromClientSync extends Horde_SyncML_Sync {
|
||||
|
||||
class Horde_SyncML_Sync_RefreshFromClientSync extends Horde_SyncML_Sync_SlowSync {
|
||||
/**
|
||||
* We need to erase the current server contents, then we can add
|
||||
* We needed to erase the current server contents, then we can add
|
||||
* the client's contents.
|
||||
*/
|
||||
function startSync($currentCmdID, &$output)
|
||||
{
|
||||
$deletes = $registry->call($this->targetLocURI, '/list', array());
|
||||
foreach ($delete as $deletes) {
|
||||
$registry->call($this->targetLocURI . '/delete', array($delete));
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,87 +1,167 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Sync/RefreshFromServerSync.php,v 1.9 2004/07/03 15:21:15 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Sync_RefreshFromServerSync extends Horde_SyncML_Sync_TwoWaySync {
|
||||
function handleSync($currentCmdID, $hordeType, $syncType, &$output, $refts) {
|
||||
global $registry;
|
||||
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
|
||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$maxMsgSize = $state->getMaxMsgSizeClient();
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
if (isset($deviceInfo['maxEntries'])) {
|
||||
$maxEntries = $deviceInfo['maxEntries'];
|
||||
if (!$maxMsgSize && !$maxEntries) {
|
||||
// fallback to default
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
} else {
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
|
||||
$serverAnchorNext = $state->getServerAnchorNext($syncType);
|
||||
$counter = 0;
|
||||
|
||||
|
||||
if (isset($state->curSyncItem)) {
|
||||
// Finish the pending sync item
|
||||
$cmd = &$state->curSyncItem;
|
||||
unset($state->curSyncItem);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Sync');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = &$cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
|
||||
$adds = &$state->getAddedItems($syncType);
|
||||
Horde::logMessage("SyncML: ".count($adds).
|
||||
' added items found for '.$syncType ,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if(is_array($adds)) {
|
||||
while($guid = array_shift($adds)) {
|
||||
$currentSize = $output->getOutputSize();
|
||||
// return if we have to much data
|
||||
if (($maxEntries && ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
|| ($maxMsgSize
|
||||
&& (($currentSize + MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
if ($locID = $state->getLocID($syncType, $guid)) {
|
||||
Horde::logMessage("SyncML: RefreshFromServerSync add to client: $guid ignored, already at client($locID)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'add');
|
||||
if ($guid_ts > $serverAnchorNext) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde::logMessage("SyncML: RefreshFromServerSync add $guid is in our future", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType));
|
||||
Horde::logMessage("SyncML: slowsync add $guid to client ". print_r($c, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat']))
|
||||
{
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
|
||||
$cmd->setSourceURI($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
Horde::logMessage("SyncML: refresh failed to export guid $guid:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->log("Server-ExportFailed");
|
||||
continue;
|
||||
}
|
||||
|
||||
$size = strlen($c);
|
||||
// return if we have to much data
|
||||
if ($maxMsgSize && !$deviceInfo['supportLargeObjs']) {
|
||||
if (($size + MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
Horde::logMessage("SyncML: refresh failed to export guid $guid due to size $size", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$state->log("Server-ExportFailed");
|
||||
continue;
|
||||
}
|
||||
if (($currentSize + $size + MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: refresh add $guid to client\n$c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
|
||||
$cmd->setContent($c);
|
||||
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat'])) {
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
|
||||
$cmd->setGUID($guid);
|
||||
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// moreData split; put the guid back in the list and return
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = &$cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
|
||||
#Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
|
||||
Horde::logMessage("SyncML: All items handled for sync $syncType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->removeExpiredUID($syncType, $serverAnchorNext);
|
||||
$state->clearSync($syncType);
|
||||
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
|
||||
function loadData() {
|
||||
global $registry;
|
||||
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
|
||||
$state->setTargetURI($syncType);
|
||||
$future = $state->getServerAnchorNext($syncType);
|
||||
$delta_add = 0;
|
||||
|
||||
Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setAddedItems($hordeType, $registry->call($hordeType. '/list', array()));
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
$state->setAddedItems($syncType, $registry->call($hordeType. '/listBy',
|
||||
array('action' => 'add',
|
||||
'timestamp' => $future,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression)));
|
||||
$delta_add = count($state->getAddedItems($hordeType));
|
||||
$state->setAddedItems($syncType, $registry->call($hordeType. '/list', array('filter' => $this->_filterExpression)));
|
||||
$this->_syncDataLoaded = TRUE;
|
||||
|
||||
return count($state->getAddedItems($hordeType));
|
||||
|
||||
return count($state->getAddedItems($syncType)) - $delta_add;
|
||||
}
|
||||
}
|
||||
|
@ -1,194 +1,282 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
* Slow sync may just work; I think most of the work is going to be
|
||||
* done by the API.
|
||||
*
|
||||
* $Horde: framework/SyncML/SyncML/Sync/SlowSync.php,v 1.7 2004/05/26 17:32:50 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
||||
|
||||
class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
|
||||
|
||||
function handleSync($currentCmdID, $hordeType, $syncType, &$output, $refts) {
|
||||
global $registry;
|
||||
|
||||
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$maxMsgSize = $state->getMaxMsgSizeClient();
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
if (isset($deviceInfo['maxEntries'])) {
|
||||
$maxEntries = $deviceInfo['maxEntries'];
|
||||
if (!$maxMsgSize && !$maxEntries) {
|
||||
// fallback to default
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
} else {
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
|
||||
$serverAnchorNext = $state->getServerAnchorNext($syncType);
|
||||
|
||||
|
||||
// now we remove all UID from contentmap that have not been verified in this slowsync
|
||||
$state->removeOldUID($syncType, $serverAnchorNext);
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$counter = 0;
|
||||
|
||||
|
||||
if (isset($state->curSyncItem)) {
|
||||
// Finish the pending sync item
|
||||
$cmd = &$state->curSyncItem;
|
||||
unset($state->curSyncItem);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Sync');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = &$cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
|
||||
$adds = &$state->getAddedItems($syncType);
|
||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$syncType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if(is_array($adds)) {
|
||||
while($guid = array_shift($adds)) {
|
||||
|
||||
$currentSize = $output->getOutputSize();
|
||||
|
||||
// return if we have to much data
|
||||
if (($maxEntries && ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment']) ||
|
||||
($maxMsgSize && (($currentSize + MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
if ($locID = $state->getLocID($syncType, $guid)) {
|
||||
Horde::logMessage("SyncML: slowsync add to client: $guid ignored, already at client($locID)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'add');
|
||||
if ($guid_ts > $serverAnchorNext) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde::logMessage("SyncML: slowsync add $guid is in our future", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType));
|
||||
#Horde::logMessage("SyncML: slowsync add guid $guid to client ". print_r($c, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat']))
|
||||
{
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
Horde::logMessage("SyncML: slowsync failed to export guid $guid:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
$size = strlen($c);
|
||||
// return if we have to much data
|
||||
if ($maxMsgSize && !$deviceInfo['supportLargeObjs']) {
|
||||
if (($size + MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
Horde::logMessage("SyncML: slowsync failed to export guid $guid due to size $size", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
$cmd->setSourceURI($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
if (($currentSize + $size + MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: slowsync add guid $guid to client\n$c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat'])) {
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
$cmd->setGUID($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = &$cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
|
||||
#Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
|
||||
Horde::logMessage("SyncML: All items handled for sync $syncType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->removeExpiredUID($syncType, $serverAnchorNext);
|
||||
$state->clearSync($syncType);
|
||||
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Here's where the actual processing of a client-sent Sync
|
||||
* Command takes place. Entries are added or replaced
|
||||
* from the server database by using Horde API (Registry) calls.
|
||||
*/
|
||||
function runSyncCommand(&$command) {
|
||||
#Horde::logMessage('SyncML: content type is ' . $command->getContentType() .' moreData '. $command->_moreData, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
global $registry;
|
||||
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
if(isset($state->_moreData['luid'])) {
|
||||
if(($command->_luid == $state->_moreData['luid'])) {
|
||||
Horde::logMessage('SyncML: got next moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$lastChunks = implode('',$state->_moreData['chunks']);
|
||||
$command->_content = $lastChunks.$command->_content;
|
||||
$stringlen1 = strlen($lastChunks);
|
||||
$stringlen2 = strlen($command->_content);
|
||||
|
||||
if(!$command->_moreData && strlen($command->_content) != $state->_moreData['contentSize']) {
|
||||
$command->_status = RESPONSE_SIZE_MISMATCH;
|
||||
$state->_moreData = array();
|
||||
|
||||
return;
|
||||
} elseif(!$command->_moreData && strlen($command->_content) == $state->_moreData['contentSize']) {
|
||||
$state->_moreData = array();
|
||||
Horde::logMessage('SyncML: chunk ended successful type is ' . $command->getContentType() .' content is '. $command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
} else {
|
||||
// alert 223 needed too
|
||||
#$command->_status = ALERT_NO_END_OF_DATA;
|
||||
|
||||
$state->_moreData = array();
|
||||
|
||||
|
||||
if ($command->hasMoreData()) {
|
||||
Horde::logMessage('SyncML: moreData: TRUE', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$command->setStatus(RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED);
|
||||
return true;
|
||||
}
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
|
||||
$syncml_prefs = $GLOBALS['egw_info']['user']['preferences']['syncml'];
|
||||
if (isset($syncml_prefs[$type])) {
|
||||
$sync_conflicts = $syncml_prefs[$type];
|
||||
} else {
|
||||
$sync_conflicts = CONFLICT_SERVER_WINNING;
|
||||
}
|
||||
|
||||
$hordeType = $state->getHordeType($type);
|
||||
|
||||
$syncElementItems = $command->getSyncElementItems();
|
||||
|
||||
foreach($syncElementItems as $syncItem) {
|
||||
|
||||
$contentSize = strlen($syncItem->_content);
|
||||
if ((($size = $syncItem->getContentSize()) !== false) &&
|
||||
($contentSize != $size) &&
|
||||
($contentSize + 1 != $size)) {
|
||||
Horde::logMessage('SyncML: content size missmatch for LocURI ' . $syncItem->_luid .
|
||||
": $contentSize ($size)", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$command->setStatus(RESPONSE_SIZE_MISMATCH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// don't add/replace the data currently, they are not yet complete
|
||||
if($command->_moreData == TRUE) {
|
||||
$state->_moreData['chunks'][] = $command->_content;
|
||||
$state->_moreData['luid'] = $command->_luid;
|
||||
|
||||
// gets only set with the first chunk of data
|
||||
if(isset($command->_contentSize))
|
||||
$state->_moreData['contentSize'] = $command->_contentSize;
|
||||
|
||||
$command->_status = RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED;
|
||||
Horde::logMessage('SyncML: added moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($type);
|
||||
|
||||
$syncElementItems = $command->getSyncElementItems();
|
||||
|
||||
foreach($syncElementItems as $syncItem) {
|
||||
|
||||
if(!$contentType = $syncItem->getContentType()) {
|
||||
$contentType = $state->getPreferedContentType($type);
|
||||
}
|
||||
|
||||
|
||||
if (($contentType == 'text/x-vcalendar' || $contentType == 'text/calendar')
|
||||
&& strpos($syncItem->getContent(), 'BEGIN:VTODO') !== false)
|
||||
{
|
||||
&& strpos($syncItem->getContent(), 'BEGIN:VTODO') !== false) {
|
||||
$hordeType = 'tasks';
|
||||
}
|
||||
|
||||
|
||||
$guid = false;
|
||||
|
||||
|
||||
$guid = $registry->call($hordeType . '/search',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType, $state->getGlobalUID($type, $syncItem->getLocURI()) ));
|
||||
|
||||
|
||||
if ($guid) {
|
||||
# entry exists in database already. Just update the mapping
|
||||
Horde::logMessage('SyncML: adding mapping for locuri:'. $syncItem->getLocURI() . ' and guid:' . $guid , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, mktime());
|
||||
$state->log("Client-Replace");
|
||||
} else {
|
||||
# Entry does not exist in database: add a new one.
|
||||
$state->removeUID($type, $syncItem->getLocURI());
|
||||
Horde::logMessage('SyncML: try to add contentype ' . $contentType .' to '. $hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
if (!is_a($guid, 'PEAR_Error') && $guid != false) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-AddReplace");
|
||||
Horde::logMessage('SyncML: r/ added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Check if the found entry came from the client
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'add');
|
||||
$sync_ts = $state->getChangeTS($type, $guid);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Entry came from the client, so we get a duplicate here
|
||||
Horde::logMessage('SyncML: CONFLICT for locuri ' . $syncItem->getLocURI()
|
||||
. ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
if ($sync_conflicts != CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
$state->log("Client-AddReplaceIgnored");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Error in replacing/add client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log("Client-AddFailure");
|
||||
# Entry exists in database already. Just update the mapping
|
||||
Horde::logMessage('SyncML: adding mapping for locuri:'
|
||||
. $syncItem->getLocURI() . ' and guid:' . $guid,
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, mktime());
|
||||
$state->log("Client-Map");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($sync_conflicts > CONFLICT_RESOLVED_WITH_DUPLICATE) {
|
||||
// We enforce the client not to change anything
|
||||
if ($sync_conflicts > CONFLICT_CLIENT_CHANGES_IGNORED) {
|
||||
// delete this item from client
|
||||
Horde::logMessage('SyncML: Server RO! REMOVE ' . $syncItem->getLocURI()
|
||||
. ' from client', __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->addConflictItem($type, $syncItem->getLocURI());
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Server RO! REJECT all client changes',
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
$state->log("Client-AddReplaceIgnored");
|
||||
}
|
||||
$command->setStatus(RESPONSE_NO_EXECUTED);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add entry to the database.
|
||||
$state->removeUID($type, $syncItem->getLocURI());
|
||||
Horde::logMessage('SyncML: try to add contentype ' . $contentType .' to '. $hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||
if (!is_a($guid, 'PEAR_Error') && $guid != false) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
if (!$ts) {
|
||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||
}
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-AddReplace");
|
||||
Horde::logMessage('SyncML: r/ added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
Horde::logMessage('SyncML: Error in replacing/add client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
||||
$state->log("Client-AddFailure");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function loadData() {
|
||||
global $registry;
|
||||
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
|
||||
$state->setTargetURI($syncType);
|
||||
$future = $state->getServerAnchorNext($syncType);
|
||||
$delta_add = 0;
|
||||
|
||||
Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setAddedItems($hordeType, $registry->call($hordeType. '/list', array()));
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
$delta_add = count($registry->call($hordeType. '/listBy',
|
||||
array('action' => 'add',
|
||||
'timestamp' => $future,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression)));
|
||||
$state->mergeAddedItems($syncType, $registry->call($hordeType. '/list', array('filter' => $this->_filterExpression)));
|
||||
$this->_syncDataLoaded = TRUE;
|
||||
|
||||
return count($state->getAddedItems($hordeType));
|
||||
|
||||
return count($state->getAddedItems($syncType)) - $delta_add;
|
||||
}
|
||||
}
|
||||
|
@ -1,175 +1,323 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* eGroupWare - SyncML based on Horde 3
|
||||
*
|
||||
*
|
||||
* Using the PEAR Log class (which need to be installed!)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage horde
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) The Horde Project (http://www.horde.org/)
|
||||
* @version $Id$
|
||||
*/
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/ContentSyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Sync/TwoWaySync.php,v 1.12 2004/07/26 09:24:38 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
*
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
|
||||
|
||||
function endSync($currentCmdID, &$output) {
|
||||
function endSync($currentCmdID, & $output) {
|
||||
global $registry;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
|
||||
$syncType = $this->_targetLocURI;
|
||||
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
|
||||
$refts = $state->getServerAnchorLast($syncType);
|
||||
$currentCmdID = $this->handleSync($currentCmdID,
|
||||
$hordeType,
|
||||
$syncType,
|
||||
$output,
|
||||
$refts);
|
||||
$currentCmdID = $this->handleSync($currentCmdID, $hordeType, $syncType, $output, $refts);
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function handleSync($currentCmdID, $hordeType, $syncType,&$output, $refts) {
|
||||
function handleSync($currentCmdID, $hordeType, $syncType, & $output, $refts) {
|
||||
global $registry;
|
||||
|
||||
// array of Items which got modified, but got never send to the client before
|
||||
$missedAdds = array();
|
||||
$missedAdds = array ();
|
||||
// array of Items which the client wanted to add, but must be deleted due to
|
||||
// user's sync policy
|
||||
$remoteDeletes = array ();
|
||||
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$counter = 0;
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
$maxMsgSize = $state->getMaxMsgSizeClient();
|
||||
$deviceInfo = $state->getClientDeviceInfo();
|
||||
|
||||
$changes = &$state->getChangedItems($hordeType);
|
||||
$deletes = &$state->getDeletedItems($hordeType);
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
if (isset($deviceInfo['maxEntries'])) {
|
||||
$maxEntries = $deviceInfo['maxEntries'];
|
||||
if (!$maxMsgSize && !$maxEntries) {
|
||||
// fallback to default
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
} else {
|
||||
$maxEntries = MAX_ENTRIES;
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: ".count($changes).' changed items found for '.$hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: ".count($deletes).' deleted items found for '.$hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$serverAnchorNext = $state->getServerAnchorNext($syncType);
|
||||
|
||||
|
||||
if (isset ($state->curSyncItem)) {
|
||||
// Finish the pending sync item
|
||||
$cmd = & $state->curSyncItem;
|
||||
unset ($state->curSyncItem);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Sync');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = & $cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
|
||||
$changes = & $state->getChangedItems($syncType);
|
||||
$deletes = & $state->getDeletedItems($syncType);
|
||||
$adds = & $state->getAddedItems($syncType);
|
||||
$conflicts = & $state->getConflictItems($syncType);
|
||||
|
||||
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)) {
|
||||
if (is_array($changes)) {
|
||||
while ($guid = array_shift($changes)) {
|
||||
$currentSize = $output->getOutputSize();
|
||||
// return if we have to much data
|
||||
if (($maxEntries
|
||||
&& ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset ($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
|| ($maxMsgSize
|
||||
&& (($currentSize +MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$changes[] = $guid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'modify');
|
||||
$sync_ts = $state->getChangeTS($syncType, $guid);
|
||||
Horde::logMessage("SyncML: timestamp modify guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: timestamp modify $guid guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
// Don't mirror that back to the client.
|
||||
Horde::logMessage("SyncML: change: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: change: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
if ($guid_ts > $serverAnchorNext) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde :: logMessage("SyncML: change $guid is in our future: $serverAnchorNext", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
Horde::logMessage("SyncML: change $guid hs_ts:$guid_ts dt_ts:" . $state->getChangeTS($syncType, $guid), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$locid = $state->getLocID($syncType, $guid);
|
||||
if (!$locid) {
|
||||
// somehow we missed to add, lets store the uid, so we add this entry later
|
||||
$missedAdds[] = $guid;
|
||||
Horde::logMessage("SyncML: unable to create change for $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
Horde :: logMessage("SyncML: unable to create change for $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a replace request for client.
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
$c = $registry->call($hordeType. '/export',
|
||||
array('guid' => $guid, 'contentType' => $contentType));
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
$c = $registry->call($hordeType . '/export', array (
|
||||
'guid' => $guid,
|
||||
'contentType' => $contentType
|
||||
));
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
// Item in history but not in database. Strange, but can happen.
|
||||
Horde::logMessage("SyncML: change: $guid export content: $c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
# LK $cmd->setContent($state->convertServer2Client($c, $contentType));
|
||||
$cmd->setContent($c);
|
||||
$cmd->setSourceURI($guid);
|
||||
$cmd->setTargetURI($locid);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat']))
|
||||
{
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
Horde :: logMessage("SyncML: change: export of guid $guid failed:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
$size = strlen($c);
|
||||
// return if we have to much data
|
||||
if ($maxMsgSize && !$deviceInfo['supportLargeObjs']) {
|
||||
if (($size +MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
Horde :: logMessage("SyncML: change: export of guid $guid failed due to size $size", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$state->log('Server-ExportFailed');
|
||||
continue;
|
||||
}
|
||||
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Replace');
|
||||
$state->log('Server-Replace');
|
||||
|
||||
// return if we have to much data
|
||||
if (++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
if (($currentSize + $size +MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
// put the item back in the queue
|
||||
$changes[] = $guid;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
Horde :: logMessage("SyncML: change: export guid $guid, content:\n$c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
# LK $cmd->setContent($state->convertServer2Client($c, $contentType));
|
||||
$cmd->setContent($c);
|
||||
$cmd->setLocURI($locid);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset ($contentType['ContentFormat'])) {
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Replace');
|
||||
$state->log('Server-Replace');
|
||||
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = & $cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
Horde::logMessage("SyncML: handling sync (changes done) ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: handling sync (changes done) " . $currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// handle deletes
|
||||
if(is_array($deletes)) {
|
||||
while($guid = array_shift($deletes)) {
|
||||
if (is_array($deletes)) {
|
||||
while ($guid = array_shift($deletes)) {
|
||||
$currentSize = $output->getOutputSize();
|
||||
// return if we have to much data
|
||||
if (($maxEntries && ($state->getNumberOfElements() >= $maxEntries)
|
||||
&& isset ($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
|| ($maxMsgSize
|
||||
&& (($currentSize +MIN_MSG_LEFT * 2) > $maxMsgSize))) {
|
||||
// put the item back in the queue
|
||||
$deletes[] = $guid;
|
||||
$state->maxNumberOfElements();
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'delete');
|
||||
$sync_ts = $state->getChangeTS($syncType, $guid);
|
||||
Horde::logMessage("SyncML: timestamp delete guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: timestamp delete guid_ts: $guid_ts sync_ts: $sync_ts",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
// Don't mirror that back to the client.
|
||||
Horde::logMessage("SyncML: delete $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: delete $guid ignored, came from client",
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts < $serverAnchorNext
|
||||
&& ($locid = $state->getLocID($syncType, $guid))) {
|
||||
// Now we can remove the past
|
||||
$state->removeUID($syncType, $locid);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($guid_ts > $serverAnchorNext) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde :: logMessage("SyncML: delete $guid is in our future: $serverAnchorNext", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
$locid = $state->getLocID($syncType, $guid);
|
||||
if (!$locid) {
|
||||
Horde::logMessage("SyncML: unable to create delete for $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
Horde :: logMessage("SyncML: unable to delete $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
$state->log("Server-DeleteFailure");
|
||||
continue;
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: delete: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: delete: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Create a Delete request for client.
|
||||
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$cmd->setTargetURI($locid);
|
||||
$cmd->setSourceURI($guid);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$cmd->setLocURI($locid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Delete');
|
||||
$state->log('Server-Delete');
|
||||
$state->removeUID($syncType, $locid);
|
||||
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
// moreData split; save in session state and end current message
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = & $cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
|
||||
// handle remote deletes due to conflicts
|
||||
if (count($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);
|
||||
$state->setAddedItems($hordeType, array_merge($adds, $missedAdds));
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
Horde::logMessage("SyncML: merged adds counter ".count($adds).' / '.$adds[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (count($missedAdds) > 0) {
|
||||
Horde :: logMessage("SyncML: add missed changes as adds " . count($adds) . ' / ' . $missedAdds[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$adds = array_merge($adds, $missedAdds);
|
||||
Horde :: logMessage("SyncML: merged adds counter " . count($adds) . ' / ' . $adds[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
if(is_array($adds)) {
|
||||
while($guid = array_shift($adds)) {
|
||||
$guid_ts = $state->getSyncTSforAction($guid, 'add');
|
||||
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);
|
||||
Horde :: logMessage("SyncML: timestamp add $guid guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
// Don't mirror that back to the client.
|
||||
Horde::logMessage("SyncML: add: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: add: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
if ($guid_ts > $serverAnchorNext && !in_array($guid, $conflicts)) {
|
||||
// Change was made after we started this sync.
|
||||
// Don't sent this now to the client.
|
||||
Horde :: logMessage("SyncML: add $guid is in our future: $serverAnchorNext", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -179,47 +327,65 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
|
||||
// For slow sync (ts=0): do not add data for which we
|
||||
// have a locid again. This is a heuristic to avoid
|
||||
// duplication of entries.
|
||||
Horde::logMessage("SyncML: skipping add of guid $guid as there already is a locid $locid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: skipping add of guid $guid as there already is a locid $locid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
Horde::logMessage("SyncML: add: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde :: logMessage("SyncML: add: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Create an Add request for client.
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
|
||||
|
||||
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$c = $registry->call($hordeType . '/export',
|
||||
array(
|
||||
'guid' => $guid ,
|
||||
'contentType' => $contentType ,
|
||||
)
|
||||
);
|
||||
$c = $registry->call($hordeType . '/export', array (
|
||||
'guid' => $guid,
|
||||
'contentType' => $contentType,
|
||||
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
));
|
||||
|
||||
if (is_a($c, 'PEAR_Error')) {
|
||||
// Item in history but not in database. Strange, but can happen.
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset($contentType['ContentFormat']))
|
||||
{
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
$cmd->setSourceURI($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
Horde :: logMessage("SyncML: add: export of guid $guid failed:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES
|
||||
&& isset($contentType['mayFragment'])
|
||||
&& $contentType['mayFragment'])
|
||||
{
|
||||
$size = strlen($c);
|
||||
// return if we have to much data
|
||||
if ($maxMsgSize && !$deviceInfo['supportLargeObjs']) {
|
||||
if (($size +MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
Horde :: logMessage("SyncML: add: export of guid $guid failed due to size $size", __FILE__, __LINE__, PEAR_LOG_ERROR);
|
||||
$state->log("Server-ExportFailed");
|
||||
continue;
|
||||
}
|
||||
if (($currentSize + $size +MIN_MSG_LEFT * 2) > $maxMsgSize) {
|
||||
// put the item back in the queue
|
||||
$adds[] = $guid;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
|
||||
Horde :: logMessage("SyncML: add guid $guid to client\n$c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$cmd->setContent($c);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if (isset ($contentType['ContentFormat'])) {
|
||||
$cmd->setContentFormat($contentType['ContentFormat']);
|
||||
}
|
||||
$cmd->setGUID($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// moreData split; put the guid back in the list and return
|
||||
if ($cmd->hasMoreData()) {
|
||||
$state->curSyncItem = & $cmd;
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
$state->incNumberOfElements();
|
||||
}
|
||||
}
|
||||
#Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: All items handled for sync $syncType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->removeExpiredUID($syncType, time());
|
||||
$state->clearSync($syncType);
|
||||
|
||||
return $currentCmdID;
|
||||
@ -228,24 +394,53 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
|
||||
function loadData() {
|
||||
global $registry;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$state = & $_SESSION['SyncML.state'];
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = $state->getHordeType($syncType);
|
||||
$state->setTargetURI($syncType);
|
||||
$refts = $state->getServerAnchorLast($syncType);
|
||||
$future = $state->getServerAnchorNext($syncType);
|
||||
$delta_mod = 0;
|
||||
$delta_add = 0;
|
||||
|
||||
Horde::logMessage("SyncML: reading changed items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setChangedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'modify', 'timestamp' => $refts)));
|
||||
Horde :: logMessage("SyncML: reading changed items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$delta_mod = count($registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'modify',
|
||||
'timestamp' => $future,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
$state->mergeChangedItems($syncType, $registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'modify',
|
||||
'timestamp' => $refts,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
|
||||
Horde::logMessage("SyncML: reading deleted items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setDeletedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'delete', 'timestamp' => $refts)));
|
||||
Horde :: logMessage("SyncML: reading deleted items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setDeletedItems($syncType, $registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'delete',
|
||||
'timestamp' => $refts,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
|
||||
Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setAddedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'add', 'timestamp' => $refts)));
|
||||
Horde :: logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$delta_add = count($registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'add',
|
||||
'timestamp' => $future,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
$state->mergeAddedItems($syncType, $registry->call($hordeType . '/listBy', array (
|
||||
'action' => 'add',
|
||||
'timestamp' => $refts,
|
||||
'type' => $syncType,
|
||||
'filter' => $this->_filterExpression
|
||||
)));
|
||||
|
||||
$this->_syncDataLoaded = TRUE;
|
||||
|
||||
return count($state->getChangedItems($hordeType)) +
|
||||
count($state->getDeletedItems($hordeType)) +
|
||||
count($state->getAddedItems($hordeType));
|
||||
return count($state->getChangedItems($syncType)) - $delta_mod + count($state->getDeletedItems($syncType)) + count($state->getAddedItems($syncType)) - $delta_add +count($state->getConflictItems($syncType));
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vAlarms.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/valarm.php,v 1.8 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/valarm.php,v 1.8.10.8 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,11 +20,6 @@ class Horde_iCalendar_valarm extends Horde_iCalendar {
|
||||
return 'vAlarm';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VALARM');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VALARM');
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
require_once EGW_API_INC.'/horde/Horde/iCalendar.php';
|
||||
|
||||
|
||||
// The following were shamelessly yoinked from Contact_Vcard_Build
|
||||
// Part numbers for N components.
|
||||
define('VCARD_N_FAMILY', 0);
|
||||
@ -27,45 +26,47 @@ define('VCARD_GEO_LON', 1);
|
||||
/**
|
||||
* Class representing vCard entries.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vcard.php,v 1.2 2004/08/18 03:16:24 chuck Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vcard.php,v 1.3.10.16 2008/09/22 04:16:30 chuck Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Karsten Fourmont (karsten@horde.org)
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Karsten Fourmont <karsten@horde.org>
|
||||
* @version $Revision$
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_vcard extends Horde_iCalendar {
|
||||
|
||||
function Horde_iCalendar_vcard($version = '2.1')
|
||||
{
|
||||
return parent::Horde_iCalendar($version);
|
||||
}
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'vcard';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
return parent::parsevCalendar($data, 'vcard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike vevent and vtodo, a vcard is normally not enclosed in an
|
||||
* iCalendar container. (BEGIN..END)
|
||||
*/
|
||||
function exportvCalendar()
|
||||
{
|
||||
#$requiredAttributes['BODY'] = '';
|
||||
$requiredAttributes['VERSION'] = '2.1';
|
||||
$requiredAttributes['VERSION'] = $this->_version;
|
||||
$requiredAttributes['N'] = ';;;;;;';
|
||||
if ($this->_version == '3.0') {
|
||||
$requiredAttributes['FN'] = '';
|
||||
}
|
||||
|
||||
foreach ($requiredAttributes as $name => $default_value) {
|
||||
if (is_a($this->getattribute($name), 'PEAR_Error')) {
|
||||
if (is_a($this->getAttribute($name), 'PEAR_Error')) {
|
||||
$this->setAttribute($name, $default_value);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_exportvData('VCARD') . $this->_newline;
|
||||
return $this->_exportvData('VCARD');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,8 +77,7 @@ class Horde_iCalendar_vcard extends Horde_iCalendar {
|
||||
* to
|
||||
* "Professor Dagobert T Duck Sen"
|
||||
*
|
||||
* @return string Full name of vcard "N" tag
|
||||
* or null if no N tag.
|
||||
* @return string Full name of vcard "N" tag or null if no N tag.
|
||||
*/
|
||||
function printableName()
|
||||
{
|
||||
@ -86,6 +86,8 @@ class Horde_iCalendar_vcard extends Horde_iCalendar {
|
||||
return null;
|
||||
}
|
||||
|
||||
$name_arr = array();
|
||||
|
||||
if (!empty($name_parts[VCARD_N_PREFIX])) {
|
||||
$name_arr[] = $name_parts[VCARD_N_PREFIX];
|
||||
}
|
||||
@ -114,16 +116,22 @@ class Horde_iCalendar_vcard extends Horde_iCalendar {
|
||||
*/
|
||||
function getBareEmail($address)
|
||||
{
|
||||
// Empty values are still empty.
|
||||
if (!$address) {
|
||||
return $address;
|
||||
}
|
||||
|
||||
require_once 'Mail/RFC822.php';
|
||||
require_once 'Horde/MIME.php';
|
||||
|
||||
static $rfc822;
|
||||
if (is_null($rfc822)) {
|
||||
$rfc822 = &new Mail_RFC822();
|
||||
$rfc822 = new Mail_RFC822();
|
||||
}
|
||||
|
||||
$rfc822->validateMailbox($address);
|
||||
|
||||
if (!$rfc822->validateMailbox($address)) {
|
||||
return $address;
|
||||
}
|
||||
return MIME::rfc822WriteAddress($address->mailbox, $address->host);
|
||||
}
|
||||
|
||||
|
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vEvents.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vevent.php,v 1.31 2004/08/18 03:16:24 chuck Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vevent.php,v 1.31.10.15 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,32 +20,30 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
return 'vEvent';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VEVENT');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
// Default values.
|
||||
$requiredAttributes = array();
|
||||
$requiredAttributes['DTSTAMP'] = time();
|
||||
#$requiredAttributes['ORGANIZER'] = 'Unknown Organizer';
|
||||
$requiredAttributes['UID'] = $this->_exportDateTime(time()) . '@' . $_SERVER['SERVER_NAME'];
|
||||
/* 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'] = '';
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
break;
|
||||
|
||||
case 'REQUEST':
|
||||
$requiredAttributes['ATTENDEE'] = '';
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
break;
|
||||
|
||||
case 'REPLY':
|
||||
@ -54,9 +51,9 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
break;
|
||||
|
||||
case 'ADD':
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['DTSTART'] = time();
|
||||
$requiredAttributes['SEQUENCE'] = 1;
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
$requiredAttributes['SUMMARY'] = '';
|
||||
break;
|
||||
|
||||
case 'CANCEL':
|
||||
@ -88,7 +85,8 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
function updateAttendee($email, $status, $fullname = '')
|
||||
{
|
||||
foreach ($this->_attributes as $key => $attribute) {
|
||||
if ($attribute['name'] == 'ATTENDEE' && $attribute['value'] == 'MAILTO:' . $email) {
|
||||
if ($attribute['name'] == 'ATTENDEE' &&
|
||||
$attribute['value'] == 'mailto:' . $email) {
|
||||
$this->_attributes[$key]['params']['PARTSTAT'] = $status;
|
||||
if (!empty($fullname)) {
|
||||
$this->_attributes[$key]['params']['CN'] = $fullname;
|
||||
@ -101,7 +99,7 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
if (!empty($fullname)) {
|
||||
$params['CN'] = $fullname;
|
||||
}
|
||||
$this->setAttribute('ATTENDEE', 'MAILTO:' . $email, $params);
|
||||
$this->setAttribute('ATTENDEE', 'mailto:' . $email, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,7 +111,7 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
{
|
||||
$organizer = $this->getAttribute('ORGANIZER', true);
|
||||
if (is_a($organizer, 'PEAR_Error')) {
|
||||
return null;
|
||||
return _("An unknown person");
|
||||
}
|
||||
|
||||
if (isset($organizer[0]['CN'])) {
|
||||
@ -128,7 +126,7 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
/**
|
||||
* Update this event with details from another event.
|
||||
*
|
||||
* @param object Horde_iCalendar_vEvent $vevent The vEvent with latest details.
|
||||
* @param Horde_iCalendar_vEvent $vevent The vEvent with latest details.
|
||||
*/
|
||||
function updateFromvEvent($vevent)
|
||||
{
|
||||
@ -137,7 +135,9 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
$currentValue = $this->getAttribute($newAttribute['name']);
|
||||
if (is_a($currentValue, 'PEAR_error')) {
|
||||
// Already exists so just add it.
|
||||
$this->setAttribute($newAttribute['name'], $newAttribute['value'], $newAttribute['params']);
|
||||
$this->setAttribute($newAttribute['name'],
|
||||
$newAttribute['value'],
|
||||
$newAttribute['params']);
|
||||
} else {
|
||||
// Already exists so locate and modify.
|
||||
$found = false;
|
||||
@ -178,19 +178,21 @@ class Horde_iCalendar_vevent extends Horde_iCalendar {
|
||||
* Update just the attendess of event with details from another
|
||||
* event.
|
||||
*
|
||||
* @param object Horde_iCalendar_vEvent $vevent The vEvent with latest details
|
||||
* @param Horde_iCalendar_vEvent $vevent The vEvent with latest details
|
||||
*/
|
||||
function updateAttendeesFromvEvent($vevent)
|
||||
{
|
||||
$newAttributes = $vevent->getAllAttributes();
|
||||
foreach ($newAttributes as $newAttribute) {
|
||||
if (!$newAttribute['name'] == 'ATTENDEE') {
|
||||
if ($newAttribute['name'] != 'ATTENDEE') {
|
||||
continue;
|
||||
}
|
||||
$currentValue = $this->getAttribute($newAttribute['name']);
|
||||
if (is_a($currentValue, 'PEAR_error')) {
|
||||
// Already exists so just add it.
|
||||
$this->setAttribute($newAttribute['name'], $newAttribute['value'], $newAttribute['params']);
|
||||
$this->setAttribute($newAttribute['name'],
|
||||
$newAttribute['value'],
|
||||
$newAttribute['params']);
|
||||
} else {
|
||||
// Already exists so locate and modify.
|
||||
$found = false;
|
||||
|
@ -1,52 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* Class representing vFreebusys.
|
||||
* Class representing vFreebusy components.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vfreebusy.php,v 1.16 2004/08/18 03:16:24 chuck Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vfreebusy.php,v 1.16.10.17 2008/09/17 08:46:57 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @todo Don't use timestamps
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
|
||||
var $_busyPeriods = array();
|
||||
var $_extraParams = array();
|
||||
|
||||
/**
|
||||
* Returns the type of this calendar component.
|
||||
*
|
||||
* @return string The type of this component.
|
||||
*/
|
||||
function getType()
|
||||
{
|
||||
return 'vFreebusy';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
/**
|
||||
* Parses a string containing vFreebusy data.
|
||||
*
|
||||
* @param string $data The data to parse.
|
||||
*/
|
||||
function parsevCalendar($data, $type = null, $charset = null)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VFREEBUSY');
|
||||
parent::parsevCalendar($data, 'VFREEBUSY', $charset);
|
||||
|
||||
// Do something with all the busy periods.
|
||||
foreach ($this->_attributes as $key => $attribute) {
|
||||
if ($attribute['name'] == 'FREEBUSY') {
|
||||
foreach ($attribute['value'] as $value) {
|
||||
if (array_key_exists('duration', $attribute['value'])) {
|
||||
$this->addBusyPeriod('BUSY', $value['start'], null, $value['duration']);
|
||||
} else {
|
||||
$this->addBusyPeriod('BUSY', $value['start'], $value['end']);
|
||||
}
|
||||
}
|
||||
unset($this->_attributes[$key]);
|
||||
if ($attribute['name'] != 'FREEBUSY') {
|
||||
continue;
|
||||
}
|
||||
foreach ($attribute['values'] as $value) {
|
||||
$params = isset($attribute['params'])
|
||||
? $attribute['params']
|
||||
: array();
|
||||
if (isset($value['duration'])) {
|
||||
$this->addBusyPeriod('BUSY', $value['start'], null,
|
||||
$value['duration'], $params);
|
||||
} else {
|
||||
$this->addBusyPeriod('BUSY', $value['start'],
|
||||
$value['end'], null, $params);
|
||||
}
|
||||
}
|
||||
unset($this->_attributes[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component exported as string.
|
||||
*
|
||||
* @return string The exported vFreeBusy information according to the
|
||||
* iCalender format specification.
|
||||
*/
|
||||
function exportvCalendar()
|
||||
{
|
||||
foreach ($this->_busyPeriods as $start => $end) {
|
||||
$periods = array(array('start' => $start, 'end' => $end));
|
||||
$this->setAttribute('FREEBUSY', $periods);
|
||||
$this->setAttribute('FREEBUSY', $periods,
|
||||
isset($this->_extraParams[$start])
|
||||
? $this->_extraParams[$start] : array());
|
||||
}
|
||||
|
||||
$res = parent::_exportvData('VFREEBUSY');
|
||||
@ -61,7 +87,9 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a display name for this object.
|
||||
* Returns a display name for this object.
|
||||
*
|
||||
* @return string A clear text name for displaying this object.
|
||||
*/
|
||||
function getName()
|
||||
{
|
||||
@ -71,12 +99,12 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
|
||||
if (is_a($method, 'PEAR_Error') || $method == 'PUBLISH') {
|
||||
$attr = 'ORGANIZER';
|
||||
} else if ($method == 'REPLY') {
|
||||
} elseif ($method == 'REPLY') {
|
||||
$attr = 'ATTENDEE';
|
||||
}
|
||||
|
||||
$name = $this->getAttribute($attr, true);
|
||||
if (array_key_exists('CN', $name[0])) {
|
||||
if (!is_a($name, 'PEAR_Error') && isset($name[0]['CN'])) {
|
||||
return $name[0]['CN'];
|
||||
}
|
||||
|
||||
@ -90,7 +118,9 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email address for this object.
|
||||
* Returns the email address for this object.
|
||||
*
|
||||
* @return string The email address of this object's owner.
|
||||
*/
|
||||
function getEmail()
|
||||
{
|
||||
@ -100,7 +130,7 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
|
||||
if (is_a($method, 'PEAR_Error') || $method == 'PUBLISH') {
|
||||
$attr = 'ORGANIZER';
|
||||
} else if ($method == 'REPLY') {
|
||||
} elseif ($method == 'REPLY') {
|
||||
$attr = 'ATTENDEE';
|
||||
}
|
||||
|
||||
@ -113,13 +143,34 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the busy periods.
|
||||
*
|
||||
* @return array All busy periods.
|
||||
*/
|
||||
function getBusyPeriods()
|
||||
{
|
||||
return $this->_busyPeriods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the free periods of time in a given period.
|
||||
* Returns any additional freebusy parameters.
|
||||
*
|
||||
* @return array Additional parameters of the freebusy periods.
|
||||
*/
|
||||
function getExtraParams()
|
||||
{
|
||||
return $this->_extraParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the free periods of time in a given period.
|
||||
*
|
||||
* @param integer $startStamp The start timestamp.
|
||||
* @param integer $endStamp The end timestamp.
|
||||
*
|
||||
* @return array A hash with free time periods, the start times as the
|
||||
* keys and the end times as the values.
|
||||
*/
|
||||
function getFreePeriods($startStamp, $endStamp)
|
||||
{
|
||||
@ -131,21 +182,21 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
return $periods;
|
||||
}
|
||||
|
||||
// Locate the first time in the requested period we have data
|
||||
// for.
|
||||
// Locate the first time in the requested period we have data for.
|
||||
$nextstart = max($startStamp, $this->getStart());
|
||||
|
||||
// Check each busy period and add free periods in between.
|
||||
foreach ($this->_busyPeriods as $start => $end) {
|
||||
if ($start <= $endStamp && $end >= $nextstart) {
|
||||
$periods[$nextstart] = min($start, $endStamp);
|
||||
if ($nextstart <= $start) {
|
||||
$periods[$nextstart] = min($start, $endStamp);
|
||||
}
|
||||
$nextstart = min($end, $endStamp);
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't read the end of the requested period but still
|
||||
// have data then mark as free to the end of the period or
|
||||
// available data.
|
||||
// If we didn't read the end of the requested period but still have
|
||||
// data then mark as free to the end of the period or available data.
|
||||
if ($nextstart < $endStamp && $nextstart < $this->getEnd()) {
|
||||
$periods[$nextstart] = min($this->getEnd(), $endStamp);
|
||||
}
|
||||
@ -154,16 +205,29 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a busy period to the info.
|
||||
* Adds a busy period to the info.
|
||||
*
|
||||
* This function may throw away data in case you add a period with a start
|
||||
* date that already exists. The longer of the two periods will be chosen
|
||||
* (and all information associated with the shorter one will be removed).
|
||||
*
|
||||
* @param string $type The type of the period. Either 'FREE' or
|
||||
* 'BUSY'; only 'BUSY' supported at the moment.
|
||||
* @param integer $start The start timestamp of the period.
|
||||
* @param integer $end The end timestamp of the period.
|
||||
* @param integer $duration The duration of the period. If specified, the
|
||||
* $end parameter will be ignored.
|
||||
* @param array $extra Additional parameters for this busy period.
|
||||
*/
|
||||
function addBusyPeriod($type, $start, $end = null, $duration = null)
|
||||
function addBusyPeriod($type, $start, $end = null, $duration = null,
|
||||
$extra = array())
|
||||
{
|
||||
if ($type == "FREE") {
|
||||
if ($type == 'FREE') {
|
||||
// Make sure this period is not marked as busy.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the end time is duration was specified.
|
||||
// Calculate the end time if duration was specified.
|
||||
$tempEnd = is_null($duration) ? $end : $start + $duration;
|
||||
|
||||
// Make sure the period length is always positive.
|
||||
@ -171,26 +235,35 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
$start = min($start, $tempEnd);
|
||||
|
||||
if (isset($this->_busyPeriods[$start])) {
|
||||
// Already a period starting at this time. Extend to the
|
||||
// length of the longest of the two.
|
||||
$this->_busyPeriods[$start] = max($end, $this->_busyPeriods[$start]);
|
||||
// Already a period starting at this time. Change the current
|
||||
// period only if the new one is longer. This might be a problem
|
||||
// if the callee assumes that there is no simplification going
|
||||
// on. But since the periods are stored using the start time of
|
||||
// the busy periods we have to throw away data here.
|
||||
if ($end > $this->_busyPeriods[$start]) {
|
||||
$this->_busyPeriods[$start] = $end;
|
||||
$this->_extraParams[$start] = $extra;
|
||||
}
|
||||
} else {
|
||||
// Add a new busy period.
|
||||
$this->_busyPeriods[$start] = $end;
|
||||
$this->_extraParams[$start] = $extra;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp of the start of the time period this free
|
||||
* busy information covers.
|
||||
* Returns the timestamp of the start of the time period this free busy
|
||||
* information covers.
|
||||
*
|
||||
* @return integer A timestamp.
|
||||
*/
|
||||
function getStart()
|
||||
{
|
||||
if (!is_a($this->getAttribute('DTSTART'), 'PEAR_Error')) {
|
||||
return $this->getAttribute('DTSTART');
|
||||
} else if (count($this->_busyPeriods)) {
|
||||
} elseif (count($this->_busyPeriods)) {
|
||||
return min(array_keys($this->_busyPeriods));
|
||||
} else {
|
||||
return false;
|
||||
@ -198,14 +271,16 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp of the end of the time period this free busy
|
||||
* Returns the timestamp of the end of the time period this free busy
|
||||
* information covers.
|
||||
*
|
||||
* @return integer A timestamp.
|
||||
*/
|
||||
function getEnd()
|
||||
{
|
||||
if (!is_a($this->getAttribute('DTEND'), 'PEAR_Error')) {
|
||||
return $this->getAttribute('DTEND');
|
||||
} else if (count($this->_busyPeriods)) {
|
||||
} elseif (count($this->_busyPeriods)) {
|
||||
return max(array_values($this->_busyPeriods));
|
||||
} else {
|
||||
return false;
|
||||
@ -213,7 +288,16 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the busy periods of another VFreebusy into this one.
|
||||
* Merges the busy periods of another Horde_iCalendar_vfreebusy object
|
||||
* into this one.
|
||||
*
|
||||
* This might lead to simplification no matter what you specify for the
|
||||
* "simplify" flag since periods with the same start date will lead to the
|
||||
* shorter period being removed (see addBusyPeriod).
|
||||
*
|
||||
* @param Horde_iCalendar_vfreebusy $freebusy A freebusy object.
|
||||
* @param boolean $simplify If true, simplify() will
|
||||
* called after the merge.
|
||||
*/
|
||||
function merge($freebusy, $simplify = true)
|
||||
{
|
||||
@ -221,70 +305,155 @@ class Horde_iCalendar_vfreebusy extends Horde_iCalendar {
|
||||
return false;
|
||||
}
|
||||
|
||||
$extra = $freebusy->getExtraParams();
|
||||
foreach ($freebusy->getBusyPeriods() as $start => $end) {
|
||||
$this->addBusyPeriod('BUSY', $start, $end);
|
||||
// This might simplify the busy periods without taking the
|
||||
// "simplify" flag into account.
|
||||
$this->addBusyPeriod('BUSY', $start, $end, null,
|
||||
isset($extra[$start])
|
||||
? $extra[$start] : array());
|
||||
}
|
||||
|
||||
$thisattr = $this->getAttribute('DTSTART');
|
||||
$thatattr = $freebusy->getAttribute('DTSTART');
|
||||
if (is_a($thisattr, 'PEAR_Error') && !is_a($thatattr, 'PEAR_Error')) {
|
||||
$this->setAttribute('DTSTART', $thatattr);
|
||||
$this->setAttribute('DTSTART', $thatattr, array(), false);
|
||||
} elseif (!is_a($thatattr, 'PEAR_Error')) {
|
||||
if ($thatattr > $thisattr) {
|
||||
$this->setAttribute('DTSTART', $thatattr);
|
||||
if ($thatattr < $thisattr) {
|
||||
$this->setAttribute('DTSTART', $thatattr, array(), false);
|
||||
}
|
||||
}
|
||||
|
||||
$thisattr = $this->getAttribute('DTEND');
|
||||
$thatattr = $freebusy->getAttribute('DTEND');
|
||||
if (is_a($thisattr, 'PEAR_Error') && !is_a($thatattr, 'PEAR_Error')) {
|
||||
$this->setAttribute('DTEND', $thatattr);
|
||||
$this->setAttribute('DTEND', $thatattr, array(), false);
|
||||
} elseif (!is_a($thatattr, 'PEAR_Error')) {
|
||||
if ($thatattr < $thisattr) {
|
||||
$this->setAttribute('DTEND', $thatattr);
|
||||
if ($thatattr > $thisattr) {
|
||||
$this->setAttribute('DTEND', $thatattr, array(), false);
|
||||
}
|
||||
}
|
||||
|
||||
if ($simplify) {
|
||||
$this->simplify();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all overlaps and simplify the busy periods array as much
|
||||
* as possible.
|
||||
* Removes all overlaps and simplifies the busy periods array as much as
|
||||
* possible.
|
||||
*/
|
||||
function simplify()
|
||||
{
|
||||
$clean = false;
|
||||
$busy = array($this->_busyPeriods, $this->_extraParams);
|
||||
while (!$clean) {
|
||||
$result = $this->_simplify($busy[0], $busy[1]);
|
||||
$clean = $result === $busy;
|
||||
$busy = $result;
|
||||
}
|
||||
|
||||
ksort($result[1], SORT_NUMERIC);
|
||||
$this->_extraParams = $result[1];
|
||||
|
||||
ksort($result[0], SORT_NUMERIC);
|
||||
$this->_busyPeriods = $result[0];
|
||||
}
|
||||
|
||||
function _simplify($busyPeriods, $extraParams = array())
|
||||
{
|
||||
$checked = array();
|
||||
$checkedExtra = array();
|
||||
$checkedEmpty = true;
|
||||
foreach ($this->_busyPeriods as $start => $end) {
|
||||
|
||||
foreach ($busyPeriods as $start => $end) {
|
||||
if ($checkedEmpty) {
|
||||
$checked[$start] = $end;
|
||||
$checkedExtra[$start] = isset($extraParams[$start])
|
||||
? $extraParams[$start] : array();
|
||||
$checkedEmpty = false;
|
||||
} else {
|
||||
$added = false;
|
||||
foreach ($checked as $testStart => $testEnd) {
|
||||
if ($start == $testStart) {
|
||||
$checked[$testStart] = max($testEnd, $end);
|
||||
$added = true;
|
||||
} else if ($end <= $testEnd && $end >= $testStart) {
|
||||
// Replace old period if the new period lies around the
|
||||
// old period.
|
||||
if ($start <= $testStart && $end >= $testEnd) {
|
||||
// Remove old period entry.
|
||||
unset($checked[$testStart]);
|
||||
$checked[min($testStart, $start)] = max($testEnd, $end);
|
||||
unset($checkedExtra[$testStart]);
|
||||
// Add replacing entry.
|
||||
$checked[$start] = $end;
|
||||
$checkedExtra[$start] = isset($extraParams[$start])
|
||||
? $extraParams[$start] : array();
|
||||
$added = true;
|
||||
} elseif ($start >= $testStart && $end <= $testEnd) {
|
||||
// The new period lies fully within the old
|
||||
// period. Just forget about it.
|
||||
$added = true;
|
||||
} elseif (($end <= $testEnd && $end >= $testStart) ||
|
||||
($start >= $testStart && $start <= $testEnd)) {
|
||||
// Now we are in trouble: Overlapping time periods. If
|
||||
// we allow for additional parameters we cannot simply
|
||||
// choose one of the two parameter sets. It's better
|
||||
// to leave two separated time periods.
|
||||
$extra = isset($extraParams[$start])
|
||||
? $extraParams[$start] : array();
|
||||
$testExtra = isset($checkedExtra[$testStart])
|
||||
? $checkedExtra[$testStart] : array();
|
||||
// Remove old period entry.
|
||||
unset($checked[$testStart]);
|
||||
unset($checkedExtra[$testStart]);
|
||||
// We have two periods overlapping. Are their
|
||||
// additional parameters the same or different?
|
||||
$newStart = min($start, $testStart);
|
||||
$newEnd = max($end, $testEnd);
|
||||
if ($extra === $testExtra) {
|
||||
// Both periods have the same information. So we
|
||||
// can just merge.
|
||||
$checked[$newStart] = $newEnd;
|
||||
$checkedExtra[$newStart] = $extra;
|
||||
} else {
|
||||
// Extra parameters are different. Create one
|
||||
// period at the beginning with the params of the
|
||||
// first period and create a trailing period with
|
||||
// the params of the second period. The break
|
||||
// point will be the end of the first period.
|
||||
$break = min($end, $testEnd);
|
||||
$checked[$newStart] = $break;
|
||||
$checkedExtra[$newStart] =
|
||||
isset($extraParams[$newStart])
|
||||
? $extraParams[$newStart] : array();
|
||||
$checked[$break] = $newEnd;
|
||||
$highStart = max($start, $testStart);
|
||||
$checkedExtra[$break] =
|
||||
isset($extraParams[$highStart])
|
||||
? $extraParams[$highStart] : array();
|
||||
|
||||
// Ensure we also have the extra data in the
|
||||
// extraParams.
|
||||
$extraParams[$break] =
|
||||
isset($extraParams[$highStart])
|
||||
? $extraParams[$highStart] : array();
|
||||
}
|
||||
$added = true;
|
||||
}
|
||||
|
||||
if ($added) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$added) {
|
||||
$checked[$start] = $end;
|
||||
$checkedExtra[$start] = isset($extraParams[$start])
|
||||
? $extraParams[$start] : array();
|
||||
}
|
||||
}
|
||||
}
|
||||
ksort($checked, SORT_NUMERIC);
|
||||
$this->_busyPeriods = $checked;
|
||||
|
||||
return array($checked, $checkedExtra);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vJournals.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vjournal.php,v 1.8 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vjournal.php,v 1.8.10.8 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,11 +20,6 @@ class Horde_iCalendar_vjournal extends Horde_iCalendar {
|
||||
return 'vJournal';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VJOURNAL');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VJOURNAL');
|
||||
|
@ -5,29 +5,29 @@ require_once EGW_API_INC.'/horde/Horde/iCalendar.php';
|
||||
/**
|
||||
* Class representing vNotes.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vnote.php,v 1.2 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vnote.php,v 1.3.10.9 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
* @version $Revision$
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
class Horde_iCalendar_vnote extends Horde_iCalendar {
|
||||
|
||||
function Horde_iCalendar_vnote($version = '1.1')
|
||||
{
|
||||
return parent::Horde_iCalendar($version);
|
||||
}
|
||||
|
||||
function getType()
|
||||
{
|
||||
return 'vNote';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
return parent::parsevCalendar($data, 'VNOTE');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike vevent and vtodo, a vnote is normally not enclosed in an
|
||||
* iCalendar container. (BEGIN..END)
|
||||
@ -43,7 +43,7 @@ class Horde_iCalendar_vnote extends Horde_iCalendar {
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_exportvData('VNOTE') . $this->_newline;
|
||||
return $this->_exportvData('VNOTE');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vTimezones.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vtimezone.php,v 1.8 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vtimezone.php,v 1.8.10.9 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,16 +20,178 @@ class Horde_iCalendar_vtimezone extends Horde_iCalendar {
|
||||
return 'vTimeZone';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VTIMEZONE');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VTIMEZONE');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse child components of the vTimezone component. Returns an
|
||||
* array with the exact time of the time change as well as the
|
||||
* 'from' and 'to' offsets around the change. Time is arbitrarily
|
||||
* based on UTC for comparison.
|
||||
*/
|
||||
function parseChild(&$child, $year)
|
||||
{
|
||||
// Make sure 'time' key is first for sort().
|
||||
$result['time'] = 0;
|
||||
$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;
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,15 +2,14 @@
|
||||
/**
|
||||
* Class representing vTodos.
|
||||
*
|
||||
* $Horde: framework/iCalendar/iCalendar/vtodo.php,v 1.13 2004/08/13 19:11:35 karsten Exp $
|
||||
* $Horde: framework/iCalendar/iCalendar/vtodo.php,v 1.13.10.8 2008/07/03 08:42:58 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_iCalendar
|
||||
*/
|
||||
@ -21,11 +20,6 @@ class Horde_iCalendar_vtodo extends Horde_iCalendar {
|
||||
return 'vTodo';
|
||||
}
|
||||
|
||||
function parsevCalendar($data)
|
||||
{
|
||||
parent::parsevCalendar($data, 'VTODO');
|
||||
}
|
||||
|
||||
function exportvCalendar()
|
||||
{
|
||||
return parent::_exportvData('VTODO');
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Constants are from Binary XML Content Format Specification Version
|
||||
* 1.3, 25 July 2001 found at http://www.wapforum.org
|
||||
* Constants are from Binary XML Content Format Specification Version 1.3, 25
|
||||
* July 2001 found at http://www.wapforum.org
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -49,8 +49,16 @@ define('DPI_DTD_WML_1_3', '-//WAPFORUM//DTD WML 1.3//EN');
|
||||
define('DPI_DTD_PROV_1_0', '-//WAPFORUM//DTD PROV 1.0//EN');
|
||||
define('DPI_DTD_WTA_WML_1_2', '-//WAPFORUM//DTD WTA-WML 1.2//EN');
|
||||
define('DPI_DTD_CHANNEL_1_2', '-//WAPFORUM//DTD CHANNEL 1.2//EN');
|
||||
|
||||
define('DPI_DTD_SYNCML_1_0', '-//SYNCML//DTD SyncML 1.0//EN');
|
||||
define('DPI_DTD_DEVINF_1_0', '-//SYNCML//DTD DevInf 1.0//EN');
|
||||
define('DPI_DTD_METINF_1_0', '-//SYNCML//DTD MetInf 1.0//EN');
|
||||
define('DPI_DTD_SYNCML_1_1', '-//SYNCML//DTD SyncML 1.1//EN');
|
||||
define('DPI_DTD_DEVINF_1_1', '-//SYNCML//DTD DevInf 1.1//EN');
|
||||
define('DPI_DTD_METINF_1_1', '-//SYNCML//DTD MetInf 1.1//EN');
|
||||
define('DPI_DTD_SYNCML_1_2', '-//SYNCML//DTD SyncML 1.2//EN');
|
||||
define('DPI_DTD_DEVINF_1_2', '-//SYNCML//DTD DevInf 1.2//EN');
|
||||
define('DPI_DTD_METINF_1_2', '-//SYNCML//DTD MetInf 1.2//EN');
|
||||
|
||||
/**
|
||||
* Only default character encodings from J2SE are currently supported.
|
||||
@ -63,13 +71,14 @@ define('CHARSET_UTF_16LE', 'UTF-16LE');
|
||||
define('CHARSET_UTF_16', 'UTF-16');
|
||||
|
||||
/**
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML.php,v 1.13.12.11 2008/01/02 11:31:02 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* $Horde: framework/XML_WBXML/WBXML.php,v 1.18 2006/01/01 21:10:25 jan Exp $
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML {
|
||||
@ -173,8 +182,17 @@ class XML_WBXML {
|
||||
// Not all SyncML clients know this, so we
|
||||
// should use the string table.
|
||||
// 0xFD1 => DPI_DTD_SYNCML_1_1,
|
||||
4051 => DPI_DTD_SYNCML_1_1,
|
||||
4052 => DPI_DTD_DEVINF_1_1,
|
||||
// These codes are taken from libwbxml wbxml_tables.h:
|
||||
4049 => DPI_DTD_SYNCML_1_0, // 0x0fd1
|
||||
4050 => DPI_DTD_DEVINF_1_0, // 0x0fd2
|
||||
4051 => DPI_DTD_SYNCML_1_1, // 0x0fd3
|
||||
4052 => DPI_DTD_DEVINF_1_1, // 0x0fd4
|
||||
4609 => DPI_DTD_SYNCML_1_2, // 0x1201
|
||||
//@todo: verify this:
|
||||
4611 => DPI_DTD_DEVINF_1_2 // 0x1203
|
||||
// taken from libxml but might be wrong:
|
||||
// 4610 => DPI_DTD_DEVINF_1_2, // 0x1202
|
||||
// 4611 => DPI_DTD_METINF_1_2 // 0x1203
|
||||
);
|
||||
return isset($DPIString[$i]) ? $DPIString[$i] : null;
|
||||
}
|
||||
@ -197,8 +215,18 @@ class XML_WBXML {
|
||||
DPI_DTD_WTA_WML_1_2 => 12,
|
||||
DPI_DTD_CHANNEL_1_2 => 13,
|
||||
|
||||
// Not all SyncML clients know this, so we
|
||||
// Not all SyncML clients know this, so maybe we
|
||||
// should use the string table.
|
||||
// These codes are taken from libwbxml wbxml_tables.h:
|
||||
DPI_DTD_SYNCML_1_0 => 4049,
|
||||
DPI_DTD_DEVINF_1_0 => 4050,
|
||||
DPI_DTD_SYNCML_1_1 => 4051,
|
||||
DPI_DTD_DEVINF_1_1 => 4052,
|
||||
DPI_DTD_SYNCML_1_2 => 4609, // 0x1201
|
||||
// DPI_DTD_DEVINF_1_2 => 4610, // 0x1202
|
||||
// DPI_DTD_METINF_1_2 => 4611 // 0x1203
|
||||
//@todo: verify this
|
||||
DPI_DTD_DEVINF_1_2 => 4611 // 0x1203
|
||||
// DPI_DTD_SYNCML_1_1 => 0xFD1,
|
||||
// DPI_DTD_DEVINF_1_1 => 0xFD2,
|
||||
);
|
||||
|
@ -1,15 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/ContentHandler.php,v 1.15 2006/01/01 21:10:25 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* $Horde: framework/XML_WBXML/WBXML/ContentHandler.php,v 1.9.10.11 2008/08/26 15:41:13 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_ContentHandler {
|
||||
@ -32,12 +33,16 @@ class XML_WBXML_ContentHandler {
|
||||
|
||||
function XML_WBXML_ContentHandler()
|
||||
{
|
||||
$this->_currentUri = &new XML_WBXML_LifoQueue();
|
||||
$this->_currentUri = new XML_WBXML_LifoQueue();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function raiseError($error)
|
||||
{
|
||||
include_once 'PEAR.php';
|
||||
if (!class_exists('PEAR')) {
|
||||
require 'PEAR.php';
|
||||
}
|
||||
return PEAR::raiseError($error);
|
||||
}
|
||||
|
||||
@ -71,7 +76,7 @@ class XML_WBXML_ContentHandler {
|
||||
return strlen($this->_output);
|
||||
}
|
||||
|
||||
function startElement($uri, $element, $attrs)
|
||||
function startElement($uri, $element, $attrs = array())
|
||||
{
|
||||
$this->_output .= '<' . $element;
|
||||
|
||||
@ -104,12 +109,7 @@ class XML_WBXML_ContentHandler {
|
||||
|
||||
function opaque($o)
|
||||
{
|
||||
// I can check the first chanracter and see if it is WBXML.
|
||||
if (ord($o[0]) < 10) {
|
||||
// Should decode this, I really need a call back function.
|
||||
} else {
|
||||
$this->_output .= $o;
|
||||
}
|
||||
$this->_output .= $o;
|
||||
}
|
||||
|
||||
function setOpaqueHandler($opaqueHandler)
|
||||
@ -122,6 +122,15 @@ class XML_WBXML_ContentHandler {
|
||||
unset($this->_opaqueHandler);
|
||||
}
|
||||
|
||||
function createSubHandler()
|
||||
{
|
||||
$name = get_class($this); // clone current class
|
||||
$sh = new $name();
|
||||
$sh->setCharset($this->getCharsetStr());
|
||||
$sh->setVersion($this->getVersion());
|
||||
return $sh;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class XML_WBXML_LifoQueue {
|
||||
|
@ -1,15 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD.php,v 1.8 2006/01/01 21:10:25 jan Exp $
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD.php,v 1.6.12.8 2008/01/02 11:31:02 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTD {
|
||||
@ -88,6 +89,11 @@ class XML_WBXML_DTD {
|
||||
function toCodePageURI($uri)
|
||||
{
|
||||
$uri = strtolower($uri);
|
||||
if (!isset($this->strCodePagesURI[$uri])) {
|
||||
//Horde::logMessage("WBXML unable to find codepage for $uri!", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
//die("unable to find codepage for $uri!\n");
|
||||
}
|
||||
|
||||
$ret = isset($this->strCodePagesURI[$uri]) ? $this->strCodePagesURI[$uri] : false;
|
||||
|
||||
return $ret;
|
||||
|
@ -3,16 +3,17 @@
|
||||
include_once 'XML/WBXML/DTD.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncML.php,v 1.11 2006/01/01 21:10:26 jan Exp $
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncML.php,v 1.6.12.8 2008/01/02 11:31:03 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTD_SyncML extends XML_WBXML_DTD {
|
||||
@ -72,17 +73,29 @@ class XML_WBXML_DTD_SyncML extends XML_WBXML_DTD {
|
||||
$this->setTag(0x30, "Reserved for future use"); // 0x00
|
||||
$this->setTag(0x31, "VerDTD"); // 0x00
|
||||
$this->setTag(0x32, "VerProto"); // 0x00
|
||||
$this->setTag(0x33, "NumberOfChanged"); // 0x00
|
||||
$this->setTag(0x33, "NumberOfChanges"); // 0x00
|
||||
$this->setTag(0x34, "MoreData"); // 0x00
|
||||
$this->setTag(0x35, "Field"); // 0x00
|
||||
$this->setTag(0x36, "Filter"); // 0x00
|
||||
$this->setTag(0x37, "Record"); // 0x00
|
||||
$this->setTag(0x38, "FilterType"); // 0x00
|
||||
$this->setTag(0x39, "SourceParent"); // 0x00
|
||||
$this->setTag(0x3a, "TargetParent"); // 0x00
|
||||
$this->setTag(0x3b, "Move"); // 0x00
|
||||
$this->setTag(0x3c, "Correlator"); // 0x00
|
||||
|
||||
if ($this->version == 0) {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml1.0');
|
||||
$this->setCodePage(1, '-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf');
|
||||
$this->setURI('syncml:syncml1.0');
|
||||
} else {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1');
|
||||
$this->setCodePage(1, '-//SYNCML//DTD MetInf 1.1//EN', 'syncml:metinf1.1');
|
||||
if ($this->version == 1) {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_1, 'syncml:syncml1.1');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_1, 'syncml:metinf1.1');
|
||||
$this->setURI('syncml:syncml1.1');
|
||||
} elseif ($this->version == 2) {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_2, 'syncml:syncml1.2');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_2, 'syncml:metinf1.2');
|
||||
$this->setURI('syncml:syncml1.2');
|
||||
} else {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_0, 'syncml:syncml1.0');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_0, 'syncml:metinf1.0');
|
||||
$this->setURI('syncml:syncml1.0');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,17 @@
|
||||
include_once 'XML/WBXML/DTD.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLDevInf.php,v 1.11 2006/01/01 21:10:26 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLDevInf.php,v 1.4.12.8 2008/01/02 11:31:03 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTD_SyncMLDevInf extends XML_WBXML_DTD {
|
||||
@ -26,6 +27,8 @@ class XML_WBXML_DTD_SyncMLDevInf extends XML_WBXML_DTD {
|
||||
* | sed -e 's#^.*\"\([^\"]*\)\", *\(0x..\), \(0x..\) },.*$# \$this->setTag\(\3, \"\1\"\); // \2#g'
|
||||
*/
|
||||
|
||||
#Horde::logMessage("XML_WBXML_DTD_SyncMLDevInf version=" . $this->version, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$this->setTag(0x05, "CTCap"); // 0x00
|
||||
$this->setTag(0x06, "CTType"); // 0x00
|
||||
$this->setTag(0x07, "DataStore"); // 0x00
|
||||
@ -64,13 +67,25 @@ class XML_WBXML_DTD_SyncMLDevInf extends XML_WBXML_DTD {
|
||||
$this->setTag(0x28, "UTC"); // 0x00
|
||||
$this->setTag(0x29, "SupportNumberOfChanges"); // 0x00
|
||||
$this->setTag(0x2a, "SupportLargeObjs"); // 0x00
|
||||
$this->setTag(0x2b, "Property"); // 0x00
|
||||
$this->setTag(0x2c, "PropParam"); // 0x00
|
||||
$this->setTag(0x2d, "MaxOccur"); // 0x00
|
||||
$this->setTag(0x2e, "NoTruncate"); // 0x00
|
||||
$this->setTag(0x30, "Filter-Rx"); // 0x00
|
||||
$this->setTag(0x31, "FilterCap"); // 0x00
|
||||
$this->setTag(0x32, "FilterKeyword"); // 0x00
|
||||
$this->setTag(0x33, "FieldLevel"); // 0x00
|
||||
$this->setTag(0x34, "SupportHierarchicalSync"); // 0x00
|
||||
|
||||
if ($this->version == 0) {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD DevInf 1.0//EN', 'syncml:devinf');
|
||||
$this->setURI('syncml:devinf');
|
||||
} else {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD DevInf 1.1//EN', 'syncml:devinf1.1');
|
||||
if ($this->version == 1) {
|
||||
$this->setCodePage(0, DPI_DTD_DEVINF_1_1, 'syncml:devinf1.1');
|
||||
$this->setURI('syncml:devinf1.1');
|
||||
} elseif ($this->version == 2) {
|
||||
$this->setCodePage(0, DPI_DTD_DEVINF_1_2, 'syncml:devinf1.2');
|
||||
$this->setURI('syncml:devinf1.2');
|
||||
} else {
|
||||
$this->setCodePage(0, DPI_DTD_DEVINF_1_0, 'syncml:devinf1.0');
|
||||
$this->setURI('syncml:devinf1.0');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,17 @@
|
||||
include_once 'XML/WBXML/DTD.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLMetInf.php,v 1.9 2006/01/01 21:10:26 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLMetInf.php,v 1.4.12.8 2008/01/02 11:31:03 jan Exp $
|
||||
*
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTD_SyncMLMetInf extends XML_WBXML_DTD {
|
||||
@ -43,17 +44,22 @@ class XML_WBXML_DTD_SyncMLMetInf extends XML_WBXML_DTD {
|
||||
$this->setTag(0x12, "Size"); // 0x01
|
||||
$this->setTag(0x13, "Type"); // 0x01
|
||||
$this->setTag(0x14, "Version"); // 0x01
|
||||
$this->setTag(0x15, "MaxObjSize"); // 0x01
|
||||
$this->setTag(0x16, "FieldLevel"); // 0x01
|
||||
|
||||
if ($this->version == 0) {
|
||||
#$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:SYNCML1.0');
|
||||
$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml1.0');
|
||||
$this->setCodePage(1, '-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf');
|
||||
$this->setURI('syncml:metinf');
|
||||
} else {
|
||||
$this->setCodePage(0, '-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1');
|
||||
$this->setCodePage(1, '-//SYNCML//DTD MetInf 1.1//EN', 'syncml:metinf1.1');
|
||||
if ($this->version == 1) {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_1, 'syncml:syncml1.1');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_1, 'syncml:metinf1.1');
|
||||
$this->setURI('syncml:metinf1.1');
|
||||
//$this->setURI('syncml:metinf'); // for some funny reason, libwbxml produces no :metinf1.1 here
|
||||
} elseif ($this->version == 2) {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_2, 'syncml:syncml1.2');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_2, 'syncml:metinf1.2');
|
||||
$this->setURI('syncml:metinf1.2');
|
||||
} else {
|
||||
$this->setCodePage(0, DPI_DTD_SYNCML_1_0, 'syncml:syncml1.0');
|
||||
$this->setCodePage(1, DPI_DTD_METINF_1_0, 'syncml:metinf1.0');
|
||||
$this->setURI('syncml:metinf1.0');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,50 +5,94 @@ include_once 'XML/WBXML/DTD/SyncMLMetInf.php';
|
||||
include_once 'XML/WBXML/DTD/SyncMLDevInf.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTDManager.php,v 1.7 2006/01/01 21:10:25 jan Exp $
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/DTDManager.php,v 1.3.12.14 2008/01/02 11:31:02 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July
|
||||
* 2001 found at http://www.wapforum.org
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_DTDManager {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
var $_strDTD = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
var $_strDTDURI = array();
|
||||
|
||||
/**
|
||||
*/
|
||||
function XML_WBXML_DTDManager()
|
||||
{
|
||||
$this->registerDTD('-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml1.0', new XML_WBXML_DTD_SyncML(0));
|
||||
$this->registerDTD('-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1', new XML_WBXML_DTD_SyncML(1));
|
||||
$this->registerDTD(DPI_DTD_SYNCML_1_0, 'syncml:syncml1.0', new XML_WBXML_DTD_SyncML(0));
|
||||
$this->registerDTD(DPI_DTD_SYNCML_1_1, 'syncml:syncml1.1', new XML_WBXML_DTD_SyncML(1));
|
||||
$this->registerDTD(DPI_DTD_SYNCML_1_2, 'syncml:syncml1.2', new XML_WBXML_DTD_SyncML(2));
|
||||
|
||||
$this->registerDTD('-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf', new XML_WBXML_DTD_SyncMLMetInf(0));
|
||||
$this->registerDTD('-//SYNCML//DTD MetInf 1.1//EN', 'syncml:metinf1.1', new XML_WBXML_DTD_SyncMLMetInf(1));
|
||||
$this->registerDTD(DPI_DTD_METINF_1_0, 'syncml:metinf1.0', new XML_WBXML_DTD_SyncMLMetInf(0));
|
||||
$this->registerDTD(DPI_DTD_METINF_1_1, 'syncml:metinf1.1', new XML_WBXML_DTD_SyncMLMetInf(1));
|
||||
$this->registerDTD(DPI_DTD_METINF_1_2, 'syncml:metinf1.2', new XML_WBXML_DTD_SyncMLMetInf(2));
|
||||
|
||||
$this->registerDTD('-//SYNCML//DTD DevInf 1.0//EN', 'syncml:devinf', new XML_WBXML_DTD_SyncMLDevInf(0));
|
||||
$this->registerDTD('-//SYNCML//DTD DevInf 1.1//EN', 'syncml:devinf1.1', new XML_WBXML_DTD_SyncMLDevInf(1));
|
||||
$this->registerDTD(DPI_DTD_DEVINF_1_0, 'syncml:devinf1.0', new XML_WBXML_DTD_SyncMLDevInf(0));
|
||||
$this->registerDTD(DPI_DTD_DEVINF_1_1, 'syncml:devinf1.1', new XML_WBXML_DTD_SyncMLDevInf(1));
|
||||
$this->registerDTD(DPI_DTD_DEVINF_1_2, 'syncml:devinf1.2', new XML_WBXML_DTD_SyncMLDevInf(2));
|
||||
}
|
||||
|
||||
function getInstance($publicIdentifier)
|
||||
/**
|
||||
*/
|
||||
function &getInstance($publicIdentifier)
|
||||
{
|
||||
return isset($this->_strDTD[$publicIdentifier]) ? $this->_strDTD[$publicIdentifier] : null;
|
||||
$publicIdentifier = strtolower($publicIdentifier);
|
||||
if (isset($this->_strDTD[$publicIdentifier])) {
|
||||
$dtd = &$this->_strDTD[$publicIdentifier];
|
||||
} else {
|
||||
$dtd = null;
|
||||
}
|
||||
return $dtd;
|
||||
}
|
||||
|
||||
function getInstanceURI($uri)
|
||||
/**
|
||||
*/
|
||||
function &getInstanceURI($uri)
|
||||
{
|
||||
$uri = strtolower($uri);
|
||||
return isset($this->_strDTDURI[$uri]) ? $this->_strDTDURI[$uri] : null;
|
||||
|
||||
// some manual hacks:
|
||||
if ($uri == 'syncml:syncml') {
|
||||
$uri = 'syncml:syncml1.0';
|
||||
}
|
||||
if ($uri == 'syncml:metinf') {
|
||||
$uri = 'syncml:metinf1.0';
|
||||
}
|
||||
if ($uri == 'syncml:devinf') {
|
||||
$uri = 'syncml:devinf1.0';
|
||||
}
|
||||
|
||||
if (isset($this->_strDTDURI[$uri])) {
|
||||
$dtd = &$this->_strDTDURI[$uri];
|
||||
} else {
|
||||
$dtd = null;
|
||||
}
|
||||
return $dtd;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function registerDTD($publicIdentifier, $uri, &$dtd)
|
||||
{
|
||||
$dtd->setDPI($publicIdentifier);
|
||||
|
||||
$publicIdentifier = strtolower($publicIdentifier);
|
||||
|
||||
$this->_strDTD[$publicIdentifier] = $dtd;
|
||||
$this->_strDTDURI[strtolower($uri)] = $dtd;
|
||||
}
|
||||
|
@ -5,16 +5,17 @@ include_once 'XML/WBXML/DTDManager.php';
|
||||
include_once 'XML/WBXML/ContentHandler.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/Decoder.php,v 1.36 2006/01/01 21:10:25 jan Exp $
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/Decoder.php,v 1.22.10.11 2008/01/02 11:31:02 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July
|
||||
* 2001 found at http://www.wapforum.org
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
@ -75,7 +76,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
*/
|
||||
function XML_WBXML_Decoder()
|
||||
{
|
||||
$this->_dtdManager = &new XML_WBXML_DTDManager();
|
||||
$this->_dtdManager = new XML_WBXML_DTDManager();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,7 +85,8 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
*
|
||||
* @param XML_WBXML_ContentHandler $ch The contentHandler
|
||||
*/
|
||||
function setContentHandler(&$ch) {
|
||||
function setContentHandler(&$ch)
|
||||
{
|
||||
$this->_ch = &$ch;
|
||||
}
|
||||
/**
|
||||
@ -96,7 +98,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
{
|
||||
$value = $input{$this->_strpos++};
|
||||
$value = ord($value);
|
||||
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
@ -112,7 +114,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
*/
|
||||
function decodeToString($wbxml)
|
||||
{
|
||||
$this->_ch = &new XML_WBXML_ContentHandler();
|
||||
$this->_ch = new XML_WBXML_ContentHandler();
|
||||
|
||||
$r = $this->decode($wbxml);
|
||||
if (is_a($r, 'PEAR_Error')) {
|
||||
@ -133,12 +135,8 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
*/
|
||||
function decode($wbxml)
|
||||
{
|
||||
// fix for Nokia Series 60 which seem to send empty data block sometimes
|
||||
if(strlen($wbxml) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->_error = false; // reset state
|
||||
|
||||
$this->_strpos = 0;
|
||||
|
||||
if (empty($this->_ch)) {
|
||||
@ -149,6 +147,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
// version = u_int8
|
||||
// currently 1, 2 or 3
|
||||
$this->_wbxmlVersion = $this->getVersionNumber($wbxml);
|
||||
#Horde::logMessage("WBXML[" . $this->_strpos . "] version " . $this->_wbxmlVersion, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Get Document Public Idetifier from Section 5.5
|
||||
// publicid = mb_u_int32 | (zero index)
|
||||
@ -156,9 +155,11 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
// Containing the value zero (0)
|
||||
// The actual DPI is determined after the String Table is read.
|
||||
$dpiStruct = $this->getDocumentPublicIdentifier($wbxml);
|
||||
|
||||
// Get Charset from 5.6
|
||||
// charset = mb_u_int32
|
||||
$this->_charset = $this->getCharset($wbxml);
|
||||
#Horde::logMessage("WBXML[" . $this->_strpos . "] charset " . $this->_charset, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Get String Table from 5.7
|
||||
// strb1 = length *byte
|
||||
@ -166,22 +167,22 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
// Get Document Public Idetifier from Section 5.5.
|
||||
$this->_dpi = $this->getDocumentPublicIdentifierImpl($dpiStruct['dpiType'],
|
||||
$dpiStruct['dpiNumber'],
|
||||
$this->_stringTable);
|
||||
$dpiStruct['dpiNumber']);
|
||||
#$this->_stringTable);
|
||||
|
||||
// Now the real fun begins.
|
||||
// From Sections 5.2 and 5.8
|
||||
|
||||
|
||||
// Default content handler.
|
||||
$this->_dtdManager = &new XML_WBXML_DTDManager();
|
||||
$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 . '/'
|
||||
return $this->raiseError('No DTD found for '
|
||||
. $this->_dpi . '/'
|
||||
. $dpiStruct['dpiNumber']);
|
||||
}
|
||||
|
||||
@ -204,6 +205,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
function getDocumentPublicIdentifier($input)
|
||||
{
|
||||
$i = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
|
||||
if ($i == 0) {
|
||||
return array('dpiType' => 2,
|
||||
'dpiNumber' => $this->getByte($input));
|
||||
@ -218,6 +220,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
if ($dpiType == 1) {
|
||||
return XML_WBXML::getDPIString($dpiNumber);
|
||||
} else {
|
||||
#Horde::logMessage("WBXML string table $dpiNumber:\n" . print_r($this->_stringTable, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $this->getStringTableEntry($dpiNumber);
|
||||
}
|
||||
}
|
||||
@ -235,7 +238,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the string table.
|
||||
* Retrieves the string table.
|
||||
* The string table consists of an mb_u_int32 length
|
||||
* and then length bytes forming the table.
|
||||
* References to the string table refer to the
|
||||
@ -254,10 +257,10 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
{
|
||||
if ($index >= strlen($this->_stringTable)) {
|
||||
$this->_error =
|
||||
$this->_ch->raiseError('Invalid offset ' . $index
|
||||
. ' value encountered around position '
|
||||
. $this->_strpos
|
||||
. '. Broken wbxml?');
|
||||
$this->raiseError('Invalid offset ' . $index
|
||||
. ' value encountered around position '
|
||||
. $this->_strpos
|
||||
. '. Broken wbxml?');
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -270,17 +273,17 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
if (ord($ch) == 0) {
|
||||
return ''; // don't return '#'
|
||||
}
|
||||
|
||||
|
||||
while (ord($ch) != 0) {
|
||||
$str[$i++] = $ch;
|
||||
if ($index >= strlen($this->_stringTable)) {
|
||||
break;
|
||||
break;
|
||||
}
|
||||
$ch = $this->_stringTable[$index++];
|
||||
}
|
||||
// print "string table entry: $str\n";
|
||||
return $str;
|
||||
|
||||
|
||||
}
|
||||
|
||||
function _decode($input)
|
||||
@ -288,7 +291,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
$token = $this->getByte($input);
|
||||
$str = '';
|
||||
|
||||
#print "position: " . $this->_strpos . " token: " . $token . " str10: " . substr($input, $this->_strpos, 10) . "\n"; // @todo: remove debug output
|
||||
// print "position: " . $this->_strpos . " token: " . $token . " str10: " . substr($input, $this->_strpos, 10) . "\n"; // @todo: remove debug output
|
||||
|
||||
switch ($token) {
|
||||
case XML_WBXML_GLOBAL_TOKEN_STR_I:
|
||||
@ -370,34 +373,36 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
case XML_WBXML_GLOBAL_TOKEN_OPAQUE:
|
||||
// Section 5.8.4.6
|
||||
$size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
|
||||
// print "opaque of size $size\n"; // @todo remove debug
|
||||
$b = $this->_substr($input, $this->_strpos, $size);
|
||||
#$b = mb_substr($input, $this->_strpos, $size, 'ISO-8859-1');
|
||||
$this->_strpos += $size;
|
||||
if ($size > 0) {
|
||||
#Horde::logMessage("WBXML opaque document size=$size, next=" . ord($input{$this->_strpos}), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$b = $this->_substr($input, $this->_strpos, $size);
|
||||
// print "opaque of size $size: ($b)\n"; // @todo remove debug
|
||||
$this->_strpos += $size;
|
||||
// opaque data inside a <data> element may or may not be
|
||||
// a nested wbxml document (for example devinf data).
|
||||
// We find out by checking the first byte of the data: if it's
|
||||
// 1, 2 or 3 we expect it to be the version number of a wbxml
|
||||
// document and thus start a new wbxml decoder instance on it.
|
||||
|
||||
// opaque data inside a <data> element may or may not be
|
||||
// a nested wbxml document (for example devinf data).
|
||||
// We find out by checking the first byte of the data: if it's
|
||||
// 1, 2 or 3 we expect it to be the version number of a wbxml
|
||||
// document and thus start a new wbxml decoder instance on it.
|
||||
|
||||
if ($this->_isData && ord($b) <= 10) {
|
||||
$decoder = &new XML_WBXML_Decoder(true);
|
||||
$decoder->setContentHandler($this->_ch);
|
||||
$s = $decoder->decode($b);
|
||||
// /* // @todo: FIXME currently we can't decode Nokia
|
||||
// DevInf data. So ignore error for the time beeing.
|
||||
if (is_a($s, 'PEAR_Error')) {
|
||||
$this->_error = $s;
|
||||
return;
|
||||
if ($this->_isData && ord($b) < 10) {
|
||||
#Horde::logMessage("WBXML opaque document size=$size, \$b[0]=" . ord($b), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$decoder = new XML_WBXML_Decoder(true);
|
||||
$decoder->setContentHandler($this->_ch);
|
||||
$s = $decoder->decode($b);
|
||||
// /* // @todo: FIXME currently we can't decode Nokia
|
||||
// DevInf data. So ignore error for the time beeing.
|
||||
if (is_a($s, 'PEAR_Error')) {
|
||||
$this->_error = $s;
|
||||
return;
|
||||
}
|
||||
// */
|
||||
// $this->_ch->characters($s);
|
||||
} else {
|
||||
/* normal opaque behaviour: just copy the raw data: */
|
||||
// print "opaque handled as string=$b\n"; // @todo remove debug
|
||||
$this->_ch->characters($b);
|
||||
}
|
||||
// */
|
||||
// $this->_ch->characters($s);
|
||||
} else {
|
||||
/* normal opaque behaviour: just copy the raw data: */
|
||||
$this->_ch->characters( $b);
|
||||
}
|
||||
|
||||
// old approach to deal with opaque data inside ContentHandler:
|
||||
// FIXME Opaque is used by SYNCML. Opaque data that depends on the context
|
||||
// if (contentHandler instanceof OpaqueContentHandler) {
|
||||
@ -650,7 +655,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
*/
|
||||
function termstr($input)
|
||||
{
|
||||
$str = '#'; // must start with nonempty string to allow array access
|
||||
$str = '#'; // must start with nonempty string to allow array access
|
||||
$i = 0;
|
||||
$ch = $input[$this->_strpos++];
|
||||
if (ord($ch) == 0) {
|
||||
@ -679,6 +684,5 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -6,16 +6,17 @@ include_once 'XML/WBXML/DTDManager.php';
|
||||
include_once 'Horde/String.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/XML_WBXML/WBXML/Encoder.php,v 1.39 2006/01/01 21:10:25 jan Exp $
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July 2001
|
||||
* found at http://www.wapforum.org
|
||||
*
|
||||
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
||||
* $Horde: framework/XML_WBXML/WBXML/Encoder.php,v 1.25.10.17 2008/08/26 15:41:21 jan Exp $
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* Copyright 2003-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||||
*
|
||||
* From Binary XML Content Format Specification Version 1.3, 25 July
|
||||
* 2001 found at http://www.wapforum.org
|
||||
*
|
||||
* @author Anthony Mills <amills@pyramid6.com>
|
||||
* @package XML_WBXML
|
||||
*/
|
||||
class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
@ -38,7 +39,7 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
var $_subParser = null;
|
||||
var $_subParserStack = 0;
|
||||
|
||||
|
||||
/**
|
||||
* The XML parser.
|
||||
*
|
||||
@ -58,8 +59,8 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
*/
|
||||
function XML_WBXML_Encoder()
|
||||
{
|
||||
$this->_dtdManager = &new XML_WBXML_DTDManager();
|
||||
$this->_stringTable = &new XML_WBXML_HashTable();
|
||||
$this->_dtdManager = new XML_WBXML_DTDManager();
|
||||
$this->_stringTable = new XML_WBXML_HashTable();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,7 +98,10 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
function writeHeader($uri)
|
||||
{
|
||||
$this->_dtd = &$this->_dtdManager->getInstanceURI($uri);
|
||||
|
||||
if (!$this->_dtd) {
|
||||
// TODO: proper error handling
|
||||
die('Unable to find dtd for ' . $uri);
|
||||
}
|
||||
$dpiString = $this->_dtd->getDPI();
|
||||
|
||||
// Set Version Number from Section 5.4
|
||||
@ -132,7 +136,11 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
function writeDocumentPublicIdentifier($dpiString, &$strings)
|
||||
{
|
||||
$i = XML_WBXML::getDPIInt($dpiString);
|
||||
$i = 0;
|
||||
|
||||
// The OMA test suite doesn't like DPI as integer code.
|
||||
// So don't try lookup and always send full DPI string.
|
||||
// $i = XML_WBXML::getDPIInt($dpiString);
|
||||
|
||||
if ($i == 0) {
|
||||
$strings[0] = $dpiString;
|
||||
@ -191,7 +199,7 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
function _getBytes($string, $cs)
|
||||
{
|
||||
$string = String::convertCharset($string, $cs, 'utf-8');
|
||||
$string = String::convertCharset($string, $cs, 'utf-8');
|
||||
$nbytes = strlen($string);
|
||||
|
||||
$bytes = array();
|
||||
@ -210,8 +218,10 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
return array($uri, $name);
|
||||
}
|
||||
|
||||
function startElement($uri, $name, $attributes)
|
||||
function startElement($uri, $name, $attributes = array())
|
||||
{
|
||||
#Horde::logMessage("WBXML Encoder $uri, " . ($this->_hasWrittenHeader ? 'true' : 'false'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if ($this->_subParser == null) {
|
||||
if (!$this->_hasWrittenHeader) {
|
||||
$this->writeHeader($uri);
|
||||
@ -222,11 +232,11 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
if ($this->_subParser == null) {
|
||||
$this->writeTag($name, $attributes, true, $this->_charset);
|
||||
} else {
|
||||
$this->_subParser->startElement($uri,$name, $attributes);
|
||||
$this->_subParser->startElement($uri, $name, $attributes);
|
||||
}
|
||||
} else {
|
||||
$this->_subParserStack++;
|
||||
$this->_subParser->startElement($uri,$name,$attributes);
|
||||
$this->_subParser->startElement($uri, $name, $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,12 +247,12 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
$this->startElement($uri, $name, $attributes);
|
||||
}
|
||||
|
||||
function opaque($bytes)
|
||||
function opaque($o)
|
||||
{
|
||||
if ($this->_subParser == null) {
|
||||
$this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_OPAQUE);
|
||||
XML_WBXML::intToMBUInt32($this->_output, count($bytes));
|
||||
$this->_output .= $bytes;
|
||||
XML_WBXML::intToMBUInt32($this->_output, strlen($o));
|
||||
$this->_output .= $o;
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,7 +284,6 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
function writeTag($name, $attrs, $hasContent, $cs)
|
||||
{
|
||||
|
||||
if ($attrs != null && !count($attrs)) {
|
||||
$attrs = null;
|
||||
}
|
||||
@ -309,7 +318,7 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if ($attrs != null && is_array($attrs) && count($attrs) > 0 ) {
|
||||
if ($attrs != null && is_array($attrs) && count($attrs) > 0) {
|
||||
$this->writeAttributes($attrs, $cs);
|
||||
}
|
||||
}
|
||||
@ -376,11 +385,16 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
|
||||
function changecodepage($uri)
|
||||
{
|
||||
// @todo: this is a hack!
|
||||
// what's the reason for this hack???? Lars
|
||||
if ($uri != 'syncml:devinf' && $uri != 'syncml:metinf' && $uri != 'syncml:syncml1.0' && !preg_match('/1\.1$/', $uri)) {
|
||||
if ($this->_dtd->getVersion() == 2 && !preg_match('/1\.2$/', $uri)) {
|
||||
$uri .= '1.2';
|
||||
}
|
||||
if ($this->_dtd->getVersion() == 1 && !preg_match('/1\.1$/', $uri)) {
|
||||
$uri .= '1.1';
|
||||
}
|
||||
if ($this->_dtd->getVersion() == 0 && !preg_match('/1\.0$/', $uri)) {
|
||||
$uri .= '1.0';
|
||||
}
|
||||
|
||||
$cp = $this->_dtd->toCodePageURI($uri);
|
||||
if (strlen($cp)) {
|
||||
$this->_dtd = &$this->_dtdManager->getInstanceURI($uri);
|
||||
@ -390,7 +404,7 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {
|
||||
$this->_currentURI = $uri;
|
||||
|
||||
} else {
|
||||
$this->_subParser = &new XML_WBXML_Encoder(true);
|
||||
$this->_subParser = new XML_WBXML_Encoder(true);
|
||||
$this->_subParserStack = 1;
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,10 @@ $conf['auth']['driver'] = 'auto';
|
||||
$conf['log']['priority'] = PEAR_LOG_DEBUG;
|
||||
$conf['log']['ident'] = 'EGWSYNC';
|
||||
$conf['log']['params'] = array();
|
||||
$conf['log']['name'] = '/tmp/egroupware_syncml.log';
|
||||
$conf['log']['name'] = '/tmp/egroupware_syncml-1.6.log';
|
||||
$conf['log']['params']['append'] = true;
|
||||
$conf['log']['type'] = 'error_log';
|
||||
$conf['log']['enabled'] = true;
|
||||
$conf['log']['enabled'] = false;
|
||||
$conf['log_accesskeys'] = false;
|
||||
$conf['prefs']['driver'] = 'none';
|
||||
$conf['datatree']['params']['driverconfig'] = 'horde';
|
||||
|
@ -48,7 +48,7 @@ $conf = &$GLOBALS['conf'];
|
||||
|
||||
/* Set up the menu. */
|
||||
#require_once 'Horde/Menu.php';
|
||||
#$menu = &new Menu();
|
||||
#$menu = new Menu();
|
||||
|
||||
// Compress output
|
||||
#Horde::compressOutput();
|
||||
|
@ -21,8 +21,16 @@ ini_set('magic_quotes_runtime', 0);
|
||||
* include_path, you must add an ini_set() call here to add their location to
|
||||
* the include_path. */
|
||||
// ini_set('include_path', dirname(__FILE__) . PATH_SEPARATOR . ini_get('include_path'));
|
||||
set_include_path(dirname(__FILE__). '/../../horde/' . PATH_SEPARATOR . dirname(__FILE__). '/../../../../egw-pear/' . PATH_SEPARATOR . get_include_path());
|
||||
//set_include_path(dirname(__FILE__). '/../../horde/' . PATH_SEPARATOR . dirname(__FILE__). '/../../../../egw-pear/' . PATH_SEPARATOR . get_include_path());
|
||||
|
||||
@define('EGW_BASE', dirname(dirname(__FILE__) . '/../../../../rpc.php'));
|
||||
// Check for a prior definition of HORDE_BASE (perhaps by an
|
||||
// auto_prepend_file definition for site customization).
|
||||
if (!defined('HORDE_BASE')) {
|
||||
@define('HORDE_BASE', EGW_BASE . '/phpgwapi/inc/horde/');
|
||||
}
|
||||
|
||||
set_include_path(HORDE_BASE . PATH_SEPARATOR . EGW_BASE . '/egw-pear/' . PATH_SEPARATOR . get_include_path());
|
||||
/* PEAR base class. */
|
||||
include_once 'PEAR.php';
|
||||
|
||||
@ -30,14 +38,17 @@ include_once 'PEAR.php';
|
||||
include_once 'Horde.php';
|
||||
include_once 'Horde/Registry.php';
|
||||
#include_once 'Horde/DataTree.php';
|
||||
#include_once 'Horde/String.php';
|
||||
include_once 'Horde/String.php';
|
||||
include_once 'Horde/Date.php';
|
||||
include_once 'Horde/NLS.php';
|
||||
#include_once 'Horde/Notification.php';
|
||||
#include_once 'Horde/Auth.php';
|
||||
#include_once 'Horde/Browser.php';
|
||||
#include_once 'Horde/Perms.php';
|
||||
include_once 'Horde/iCalendar.php';
|
||||
//include_once 'Horde/Notification.php';
|
||||
//include_once 'Horde/Auth.php';
|
||||
//include_once 'Horde/Browser.php';
|
||||
//include_once 'Horde/Perms.php';
|
||||
|
||||
#/* Browser detection object. */
|
||||
#if (class_exists('Browser')) {
|
||||
# $browser = &Browser::singleton();
|
||||
#}
|
||||
/* Browser detection object. *
|
||||
if (class_exists('Browser')) {
|
||||
$browser = &Browser::singleton();
|
||||
}
|
||||
*/
|
@ -96,7 +96,7 @@
|
||||
{
|
||||
$data['type'] = $data['type'] ? $data['type'] : '';
|
||||
$data['cat_id'] = $data['cat_id'] ? $data['cat_id'] : '';
|
||||
return $this->cats->exists($data['type'],$data['cat_name'],$data['type'] == 'subs' ? 0 : $data['cat_id'],$data['type'] != 'subs' ? 0 : $data['cat_id']);
|
||||
return $this->cats->exists($data['type'],$data['cat_name'],$data['type'] == 'subs' ? 0 : $data['cat_id'],$data['type'] != 'subs' ? 0 : $data['cat_id'], $data['cat_access']);
|
||||
}
|
||||
|
||||
function formatted_list($format,$type,$cat_parent,$global_cats)
|
||||
@ -126,18 +126,20 @@
|
||||
{
|
||||
$exists = $this->exists(array
|
||||
(
|
||||
'type' => 'appandmains',
|
||||
'cat_name' => $values['name'],
|
||||
'cat_id' => $values['id']
|
||||
'type' => 'appandmains',
|
||||
'cat_name' => $values['name'],
|
||||
'cat_id' => $values['id'],
|
||||
'cat_access' => $values['access']
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
$exists = $this->exists(array
|
||||
(
|
||||
'type' => 'appandsubs',
|
||||
'cat_name' => $values['name'],
|
||||
'cat_id' => $values['id']
|
||||
'type' => 'appandsubs',
|
||||
'cat_name' => $values['name'],
|
||||
'cat_id' => $values['id'],
|
||||
'cat_access' => $values['access']
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@
|
||||
|
||||
// ------------------------------ end nextmatch ------------------------------------------
|
||||
|
||||
//------------------- list header variable template-declarations -------------------------
|
||||
//------------------- list header variable template-declarations -------------------------
|
||||
|
||||
$GLOBALS['egw']->template->set_var('sort_name',$this->nextmatchs->show_sort_order($this->sort,'cat_name',$this->order,'/index.php',lang('Name'),$link_data));
|
||||
$GLOBALS['egw']->template->set_var('sort_description',$this->nextmatchs->show_sort_order($this->sort,'cat_description',$this->order,'/index.php',lang('Description'),$link_data));
|
||||
@ -215,6 +215,8 @@
|
||||
}
|
||||
$GLOBALS['egw']->template->set_var('color',$gray < 128 ? 'style="color: white;"' : '');
|
||||
|
||||
$accountId = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
if ($cat['app_name'] == 'phpgw')
|
||||
{
|
||||
$appendix = '<' . lang('Global') . '>';
|
||||
@ -223,6 +225,10 @@
|
||||
{
|
||||
$appendix = '<' . lang('Global') . ' ' . $GLOBALS['egw_info']['apps'][$cats_app]['title'] . '>';
|
||||
}
|
||||
elseif ($cat['owner'] != $accountId)
|
||||
{
|
||||
$appendix = '<' . $GLOBALS['egw']->accounts->id2name($cat['owner'], 'account_fullname') . '>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$appendix = '';
|
||||
|
Loading…
Reference in New Issue
Block a user