mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-27 00:58:55 +01:00
SyncML Content Handling
* Improved find-methods * Timezone support for InfoLog * SyncML Preferences - addressbook and address list are now joined - Primary User Group for addressbook and calendar * SlowSync uses old mapping information (can be disabled within the preferences)
This commit is contained in:
parent
9bf462d616
commit
b6097fa156
@ -18,12 +18,6 @@
|
||||
*/
|
||||
class addressbook_bo extends addressbook_so
|
||||
{
|
||||
/**
|
||||
* @var int $tz_offset_s offset in secconds 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;
|
||||
|
||||
/**
|
||||
* @var int $now_su actual user (!) time
|
||||
*/
|
||||
@ -95,6 +89,13 @@ class addressbook_bo extends addressbook_so
|
||||
var $business_contact_fields = array();
|
||||
var $home_contact_fields = array();
|
||||
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $log = false;
|
||||
|
||||
/**
|
||||
* Number and message of last error or false if no error, atm. only used for saving
|
||||
*
|
||||
@ -137,8 +138,7 @@ class addressbook_bo extends addressbook_so
|
||||
{
|
||||
parent::__construct($contact_app);
|
||||
|
||||
$this->tz_offset_s = 3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
|
||||
$this->now_su = time() + $this->tz_offset_s;
|
||||
$this->now_su = new egw_time('now');
|
||||
|
||||
$this->prefs =& $GLOBALS['egw_info']['user']['preferences']['addressbook'];
|
||||
// get the default addressbook from the users prefs
|
||||
@ -400,7 +400,7 @@ class addressbook_bo extends addressbook_so
|
||||
*/
|
||||
function set_all_fileas($fileas_type,$all=false,&$errors=null,$ignore_acl=false)
|
||||
{
|
||||
if ($type != '' && !in_array($type,$this->fileas_types))
|
||||
if ($fileas_type != '' && !in_array($fileas_type, $this->fileas_types))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -572,15 +572,18 @@ class addressbook_bo extends addressbook_so
|
||||
* This function needs to be reimplemented in the derived class
|
||||
*
|
||||
* @param array $data
|
||||
* @param $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time, 'array'=array or string with date-format
|
||||
*
|
||||
* @return array updated data
|
||||
*/
|
||||
function db2data($data)
|
||||
function db2data($data, $date_format='ts')
|
||||
{
|
||||
// convert timestamps from server-time in the db to user-time
|
||||
foreach ($this->timestamps as $name)
|
||||
{
|
||||
if (isset($data[$name]))
|
||||
{
|
||||
$data[$name] += $this->tz_offset_s;
|
||||
$data[$name] = egw_time::server2user($data[$name], $date_format);
|
||||
}
|
||||
}
|
||||
$data['photo'] = $this->photo_src($data['id'],$data['jpegphoto']);
|
||||
@ -618,15 +621,18 @@ class addressbook_bo extends addressbook_so
|
||||
* this needs to be reimplemented in the derived class
|
||||
*
|
||||
* @param array $data
|
||||
* @param $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time, 'array'=array or string with date-format
|
||||
*
|
||||
* @return array upated data
|
||||
*/
|
||||
function data2db($data)
|
||||
function data2db($data, $date_format='ts')
|
||||
{
|
||||
// convert timestamps from user-time to server-time in the db
|
||||
foreach ($this->timestamps as $name)
|
||||
{
|
||||
if (isset($data[$name]))
|
||||
{
|
||||
$data[$name] -= $this->tz_offset_s;
|
||||
$data[$name] = egw_time::server2user($data[$name], $date_format);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
@ -748,7 +754,7 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
|
||||
// Get old record for tracking changes
|
||||
$old = $this->read($contact['id']);
|
||||
$old = $this->data2db($this->read($contact['id']));
|
||||
|
||||
// we dont update the content-history, if we run inside setup (admin-account-creation)
|
||||
if(!($this->error = parent::save($to_write)) && is_object($GLOBALS['egw']->contenthistory))
|
||||
@ -1308,6 +1314,7 @@ class addressbook_bo extends addressbook_so
|
||||
function merge($ids)
|
||||
{
|
||||
$this->error = false;
|
||||
$account = null;
|
||||
foreach(parent::search(array('id'=>$ids),false) as $contact) // $this->search calls the extended search from ui!
|
||||
{
|
||||
if ($contact['account_id'])
|
||||
@ -1661,38 +1668,55 @@ class addressbook_bo extends addressbook_so
|
||||
*
|
||||
* @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)
|
||||
* @return array od matching contact_ids
|
||||
*/
|
||||
function find_contact($contact, $relax=false)
|
||||
{
|
||||
if (!empty($contact['uid']))
|
||||
if ($this->log)
|
||||
{
|
||||
// Try the given UID first
|
||||
Horde::logMessage('Addressbook find UID: '. $contact['uid'],
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$criteria = array ('contact_uid' => $contact['uid']);
|
||||
if (($found = parent::search($criteria))
|
||||
&& ($uidmatch = array_shift($found)))
|
||||
{
|
||||
return $uidmatch['contact_id'];
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '('. ($relax ? 'RELAX': 'EXACT') . ')[ContactData]:'
|
||||
. array2string($contact));
|
||||
}
|
||||
}
|
||||
unset($contact['uid']);
|
||||
|
||||
$matchingContacts = array();
|
||||
if ($contact['id'] && ($found = $this->read($contact['id'])))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[ContactID]: ' . $contact['id']);
|
||||
}
|
||||
// We only do a simple consistency check
|
||||
Horde::logMessage('Addressbook find ID: '. $contact['id'],
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
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'];
|
||||
return array($found['id']);
|
||||
}
|
||||
}
|
||||
unset($contact['id']);
|
||||
|
||||
if (!$relax && !empty($contact['uid']))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[ContactUID]: ' . $contact['uid']);
|
||||
}
|
||||
// Try the given UID first
|
||||
$criteria = array ('contact_uid' => $contact['uid']);
|
||||
if (($foundContacts = parent::search($criteria)))
|
||||
{
|
||||
foreach ($foundContacts as $egwContact)
|
||||
{
|
||||
$matchingContacts[] = $egwContact['id'];
|
||||
}
|
||||
}
|
||||
return $matchingContacts;
|
||||
}
|
||||
unset($contact['uid']);
|
||||
|
||||
$columns_to_search = array('n_family', 'n_given', 'n_middle', 'n_prefix', 'n_suffix',
|
||||
'bday', 'org_name', 'org_unit', 'title', 'role',
|
||||
'email', 'email_home');
|
||||
@ -1813,28 +1837,47 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage("Addressbook find step 1:\n" . print_r($criteria, true) .
|
||||
"filter:\n" . print_r($filter, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[Addressbook FIND Step 1]: '
|
||||
. 'FILTER:' . array2string($filter)
|
||||
. 'CRITERIA' . array2string($criteria));
|
||||
}
|
||||
|
||||
// first try full match
|
||||
if (($foundContacts = parent::search($criteria, true, '', '', '', False, 'AND', false, $filter)))
|
||||
{
|
||||
$result = $foundContacts[0]['id'];
|
||||
foreach ($foundContacts as $egwContact)
|
||||
{
|
||||
$matchingContacts[] = $egwContact['id'];
|
||||
}
|
||||
}
|
||||
|
||||
// No need for more searches for relaxed matching
|
||||
if (!$relax && !$result && !$this->all_empty($contact, $addr_one_fields)
|
||||
if (!$relax || count($matchingContacts)) return $matchingContacts;
|
||||
|
||||
|
||||
if (!$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 ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[Addressbook FIND Step 2]: '
|
||||
. 'FILTER:' . array2string($filter)
|
||||
. 'CRITERIA' . array2string($criteria));
|
||||
}
|
||||
|
||||
if (($foundContacts = parent::search($criteria, true, '', '', '', False, 'AND', false, $filter)))
|
||||
{
|
||||
$result = $foundContacts[0]['id'];
|
||||
foreach ($foundContacts as $egwContact)
|
||||
{
|
||||
$matchingContacts[] = $egwContact['id'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1859,16 +1902,25 @@ class addressbook_bo extends addressbook_so
|
||||
|
||||
$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 ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[Addressbook FIND Step 3]: '
|
||||
. 'FILTER:' . array2string($filter)
|
||||
. 'CRITERIA' . array2string($criteria));
|
||||
}
|
||||
|
||||
if (($foundContacts = parent::search($criteria, true, '', '', '', False, 'AND', false, $filter)))
|
||||
{
|
||||
$result = $foundContacts[0]['id'];
|
||||
foreach ($foundContacts as $egwContact)
|
||||
{
|
||||
$matchingContacts[] = $egwContact['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!$relax && !$result)
|
||||
{ // No more searches for relaxed matching, try again after address swap
|
||||
}
|
||||
else
|
||||
{ // try again after address swap
|
||||
|
||||
$filter = $empty_columns;
|
||||
|
||||
@ -1907,15 +1959,26 @@ class addressbook_bo extends addressbook_so
|
||||
$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 ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[Addressbook FIND Step 4]: '
|
||||
. 'FILTER:' . array2string($filter)
|
||||
. 'CRITERIA' . array2string($criteria));
|
||||
}
|
||||
if(($foundContacts = parent::search($criteria, true, '', '', '', False, 'AND', false, $filter)))
|
||||
{
|
||||
$result = $foundContacts[0]['id'];
|
||||
foreach ($foundContacts as $egwContact)
|
||||
{
|
||||
$matchingContacts[] = $egwContact['id'];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[FOUND]:' . array2string($matchingContacts));
|
||||
}
|
||||
return $matchingContacts;
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ class addressbook_contactform
|
||||
require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.addressbook_tracking.inc.php');
|
||||
$tracking = new addressbook_tracking($contact);
|
||||
}
|
||||
if ($tracking->do_notifications($content,null))
|
||||
if ($tracking->do_notifications($contact->data2db($content),null))
|
||||
{
|
||||
return '<p align="center">'.$content['msg'].'</p>';
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ class addressbook_sif extends addressbook_bo
|
||||
break;
|
||||
|
||||
default:
|
||||
$finalContact[$key] = $value;
|
||||
$finalContact[$key] = str_replace("\r\n", "\n", $value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -173,14 +173,16 @@ class addressbook_sif extends addressbook_bo
|
||||
* Search an exactly matching entry (used for slow sync)
|
||||
*
|
||||
* @param string $_sifdata
|
||||
* @return boolean/int/string contact-id or false, if not found
|
||||
* @return array of matching contact-ids
|
||||
*/
|
||||
function search($_sifdata, $contentID=null, $relax=false)
|
||||
{
|
||||
$result = false;
|
||||
$result = array();
|
||||
|
||||
if($contact = $this->siftoegw($_sifdata, $contentID)) {
|
||||
if ($contentID) {
|
||||
if($contact = $this->siftoegw($_sifdata, $contentID))
|
||||
{
|
||||
if ($contentID)
|
||||
{
|
||||
$contact['contact_id'] = $contentID;
|
||||
}
|
||||
$result = $this->find_contact($contact, $relax);
|
||||
@ -198,22 +200,44 @@ class addressbook_sif extends addressbook_bo
|
||||
*/
|
||||
function addSIF($_sifdata, $_abID=null, $merge=false)
|
||||
{
|
||||
#error_log('ABID: '.$_abID);
|
||||
#error_log(base64_decode($_sifdata));
|
||||
|
||||
if(!$contact = $this->siftoegw($_sifdata, $_abID)) {
|
||||
if(!$contact = $this->siftoegw($_sifdata, $_abID))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if($_abID) {
|
||||
if($_abID)
|
||||
{
|
||||
if (($old_contact = $this->read($_abID)))
|
||||
{
|
||||
if ($merge)
|
||||
{
|
||||
foreach ($contact as $key => $value)
|
||||
{
|
||||
if (!empty($old_contact[$key]))
|
||||
{
|
||||
$contact[$key] = $old_contact[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($old_contact['account_id']))
|
||||
{
|
||||
$contact['account_id'] = $old_contact['account_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
// update entry
|
||||
$contact['id'] = $_abID;
|
||||
}
|
||||
elseif (array_key_exists('filter_addressbook', $GLOBALS['egw_info']['user']['preferences']['syncml']))
|
||||
{
|
||||
$contact['owner'] = (int) $GLOBALS['egw_info']['user']['preferences']['syncml']['filter_addressbook'];
|
||||
if ($contact['owner'] == -1)
|
||||
{
|
||||
$contact['owner'] = $GLOBALS['egw_info']['user']['account_primary_group'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->save($contact);
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,8 @@ class addressbook_tracking extends bo_tracking
|
||||
|
||||
$this->contacts =& $bocontacts;
|
||||
|
||||
if(is_object($bocontacts->somain)) {
|
||||
if (is_object($bocontacts->somain))
|
||||
{
|
||||
$this->field2history = array_combine($bocontacts->somain->db_cols, $bocontacts->somain->db_cols);
|
||||
unset($this->field2history['modified']);
|
||||
unset($this->field2history['modifier']);
|
||||
@ -156,8 +157,7 @@ class addressbook_tracking extends bo_tracking
|
||||
* Get the details of an entry
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $datetime_format of user to notify, eg. 'Y-m-d H:i'
|
||||
* @param int $tz_offset_s offset in sec to be add to server-time to get the user-time of the user to notify
|
||||
*
|
||||
* @return array of details as array with values for keys 'label','value','type'
|
||||
*/
|
||||
function get_details($data)
|
||||
|
@ -130,10 +130,9 @@ class addressbook_vcal extends addressbook_bo
|
||||
|
||||
if($_abID)
|
||||
{
|
||||
if ($merge)
|
||||
if (($old_contact = $this->read($_abID)))
|
||||
{
|
||||
$old_contact = $this->read($_abID);
|
||||
if ($old_contact)
|
||||
if ($merge)
|
||||
{
|
||||
foreach ($contact as $key => $value)
|
||||
{
|
||||
@ -143,6 +142,13 @@ class addressbook_vcal extends addressbook_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($old_contact['account_id']))
|
||||
{
|
||||
$contact['account_id'] = $old_contact['account_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
// update entry
|
||||
$contact['id'] = $_abID;
|
||||
@ -150,6 +156,10 @@ class addressbook_vcal extends addressbook_bo
|
||||
elseif (array_key_exists('filter_addressbook', $GLOBALS['egw_info']['user']['preferences']['syncml']))
|
||||
{
|
||||
$contact['owner'] = (int) $GLOBALS['egw_info']['user']['preferences']['syncml']['filter_addressbook'];
|
||||
if ($contact['owner'] == -1)
|
||||
{
|
||||
$contact['owner'] = $GLOBALS['egw_info']['user']['account_primary_group'];
|
||||
}
|
||||
}
|
||||
return $this->save($contact);
|
||||
}
|
||||
@ -443,7 +453,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
|
||||
function search($_vcard, $contentID=null, $relax=false)
|
||||
{
|
||||
$result = false;
|
||||
$result = array();
|
||||
|
||||
if (($contact = $this->vcardtoegw($_vcard, $contentID)))
|
||||
{
|
||||
@ -887,8 +897,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
break;
|
||||
|
||||
case 'note':
|
||||
// note may contain ','s but maybe this needs to be fixed in vcard parser...
|
||||
$contact[$fieldName] = $vcardValues[$vcardKey]['value'];
|
||||
$contact[$fieldName] = str_replace("\r\n", "\n", $vcardValues[$vcardKey]['value']);
|
||||
break;
|
||||
|
||||
case 'uid':
|
||||
|
@ -67,6 +67,13 @@ class calendar_boupdate extends calendar_bo
|
||||
*/
|
||||
var $log = false;
|
||||
|
||||
/**
|
||||
* Cached timezone data
|
||||
*
|
||||
* @var array id => data
|
||||
*/
|
||||
protected static $tz_cache = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
@ -1417,7 +1424,7 @@ class calendar_boupdate extends calendar_bo
|
||||
* @param string filter='exact' exact -> check for identical matches
|
||||
* relax -> be more tolerant
|
||||
* master -> try to find a releated series master
|
||||
* @return array calendar_id's of matching entries
|
||||
* @return array calendar_ids of matching entries
|
||||
*/
|
||||
function find_event($event, $filter='exact')
|
||||
{
|
||||
@ -1432,22 +1439,20 @@ class calendar_boupdate extends calendar_bo
|
||||
|
||||
if ($filter == 'master')
|
||||
{
|
||||
if (empty($event['uid']) || !isset($event['recurrence']))
|
||||
{
|
||||
$recur_date = $event['start']; // without UID we ignore RECURRENCE-IDs
|
||||
}
|
||||
else
|
||||
if (isset($event['recurrence']))
|
||||
{
|
||||
$recur_date = $event['recurrence'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$recur_date = $event['start'];
|
||||
}
|
||||
|
||||
$recur_date = $this->date2usertime($recur_date);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$recur_date = 0;
|
||||
}
|
||||
|
||||
if ($event['id'])
|
||||
{
|
||||
@ -1465,9 +1470,7 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
// Just a simple consistency check
|
||||
if ($filter == 'master' && $egwEvent['recur_type'] != MCAL_RECUR_NONE ||
|
||||
$egwEvent['title'] == $event['title'] &&
|
||||
abs($egwEvent['start'] - $event['start']) < 60 &&
|
||||
abs($egwEvent['end'] - $event['end']) < 120)
|
||||
strpos($egwEvent['title'], $event['title']) === 0)
|
||||
{
|
||||
$retval = $egwEvent['id'];
|
||||
if ($egwEvent['recur_type'] != MCAL_RECUR_NONE &&
|
||||
@ -1483,41 +1486,6 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
unset($event['id']);
|
||||
|
||||
if (isset($event['whole_day']) && $event['whole_day'])
|
||||
{
|
||||
if ($filter == 'relax')
|
||||
{
|
||||
$delta = 1800;
|
||||
}
|
||||
else
|
||||
{
|
||||
$delta = 60;
|
||||
}
|
||||
|
||||
// check length with some tolerance
|
||||
$length = $event['end'] - $event['start'] - $delta;
|
||||
$query[] = ('(cal_end-cal_start)>' . $length);
|
||||
$length += 2 * $delta;
|
||||
$query[] = ('(cal_end-cal_start)<' . $length);
|
||||
}
|
||||
elseif (isset($event['start']))
|
||||
{
|
||||
if ($filter != 'master')
|
||||
{
|
||||
if ($filter == 'relax')
|
||||
{
|
||||
$query[] = ('cal_start>' . ($event['start'] - 3600));
|
||||
$query[] = ('cal_start<' . ($event['start'] + 3600));
|
||||
}
|
||||
else
|
||||
{
|
||||
// we accept a tiny tolerance
|
||||
$query[] = ('cal_start>' . ($event['start'] - 2));
|
||||
$query[] = ('cal_start<' . ($event['start'] + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($filter == 'master')
|
||||
{
|
||||
$query[] = 'recur_type!='. MCAL_RECUR_NONE;
|
||||
@ -1574,20 +1542,45 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($event['uid']))
|
||||
if ($filter == 'relax' || empty($event['uid']))
|
||||
{
|
||||
$matchFields = array('title', 'priority', 'public', 'non_blocking');
|
||||
switch ($filter)
|
||||
if (isset($event['whole_day']) && $event['whole_day'])
|
||||
{
|
||||
case 'relax':
|
||||
$matchFields[] = 'location';
|
||||
case 'master':
|
||||
break;
|
||||
default:
|
||||
$matchFields[] = 'description';
|
||||
$matchFields[] = 'location';
|
||||
if ($filter == 'relax')
|
||||
{
|
||||
$delta = 1800;
|
||||
}
|
||||
else
|
||||
{
|
||||
$delta = 60;
|
||||
}
|
||||
|
||||
// check length with some tolerance
|
||||
$length = $event['end'] - $event['start'] - $delta;
|
||||
$query[] = ('(cal_end-cal_start)>' . $length);
|
||||
$length += 2 * $delta;
|
||||
$query[] = ('(cal_end-cal_start)<' . $length);
|
||||
$query[] = ('cal_start>' . ($event['start'] - 86400));
|
||||
$query[] = ('cal_start<' . ($event['start'] + 86400));
|
||||
}
|
||||
elseif (isset($event['start']))
|
||||
{
|
||||
if ($filter != 'master')
|
||||
{
|
||||
if ($filter == 'relax')
|
||||
{
|
||||
$query[] = ('cal_start>' . ($event['start'] - 3600));
|
||||
$query[] = ('cal_start<' . ($event['start'] + 3600));
|
||||
}
|
||||
else
|
||||
{
|
||||
// we accept a tiny tolerance
|
||||
$query[] = ('cal_start>' . ($event['start'] - 2));
|
||||
$query[] = ('cal_start<' . ($event['start'] + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
$matchFields = array('priority', 'public', 'non_blocking', 'recurrence');
|
||||
foreach ($matchFields as $key)
|
||||
{
|
||||
if (!empty($event[$key])) $query['cal_'.$key] = $event[$key];
|
||||
@ -1601,7 +1594,7 @@ class calendar_boupdate extends calendar_bo
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
'(' . $event['uid'] . ')[EventUID]');
|
||||
}
|
||||
if ($filter != 'relax' && isset($event['recurrence']))
|
||||
if (isset($event['recurrence']))
|
||||
{
|
||||
$query['cal_recurrence'] = $event['recurrence'];
|
||||
}
|
||||
@ -1635,6 +1628,12 @@ class calendar_boupdate extends calendar_bo
|
||||
'[FOUND]: ' . array2string($egwEvent));
|
||||
}
|
||||
|
||||
if ($filter == 'exact' && !empty($event['uid']))
|
||||
{
|
||||
$matchingEvents[] = $egwEvent['id']; // UID found
|
||||
continue;
|
||||
}
|
||||
|
||||
// convert timezone id of event to tzid (iCal id like 'Europe/Berlin')
|
||||
if (!$egwEvent['tz_id'] || !($egwEvent['tzid'] = calendar_timezones::id2tz($egwEvent['tz_id'])))
|
||||
{
|
||||
@ -1671,10 +1670,35 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
}
|
||||
|
||||
if ($filter != 'master')
|
||||
// check for real match
|
||||
$matchFields = array('title');
|
||||
switch ($filter)
|
||||
{
|
||||
case 'master':
|
||||
break;
|
||||
case 'relax':
|
||||
$matchFields[] = 'location';
|
||||
default:
|
||||
$matchFields[] = 'description';
|
||||
}
|
||||
foreach ($matchFields as $key)
|
||||
{
|
||||
if (!empty($event[$key]) && (empty($egwEvent[$key])
|
||||
|| strpos($egwEvent[$key], $event[$key]) !== 0))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
"() event[$key] differ: '" . $event[$key] .
|
||||
"' <> '" . $egwEvent[$key]) . "'";
|
||||
}
|
||||
continue 2; // next foundEvent
|
||||
}
|
||||
}
|
||||
|
||||
if ($filter != 'master' && is_array($event['category']))
|
||||
{
|
||||
// check categories
|
||||
if (!is_array($event['category'])) $event['category'] = array();
|
||||
$egwCategories = explode(',', $egwEvent['category']);
|
||||
foreach ($egwCategories as $cat_id)
|
||||
{
|
||||
@ -1700,24 +1724,6 @@ class calendar_boupdate extends calendar_bo
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
// check information
|
||||
$matchFields = array();
|
||||
foreach ($matchFields as $key)
|
||||
{
|
||||
if (isset($event[$key])
|
||||
&& $event[$key] != $egwEvent[$key])
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
"() events[$key] differ: " . $event[$key] .
|
||||
' <> ' . $egwEvent[$key]);
|
||||
}
|
||||
continue 2; // next foundEvent
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if ($filter != 'relax' && $filter != 'master')
|
||||
{
|
||||
@ -1924,6 +1930,7 @@ class calendar_boupdate extends calendar_bo
|
||||
in_array($event['recurrence'], $master_event['recur_exception']))
|
||||
{
|
||||
$type = 'SERIES-PSEUDO-EXCEPTION'; // could also be a real one
|
||||
$recurrence_event = $event;
|
||||
break;
|
||||
}
|
||||
elseif (in_array($event['start'], $master_event['recur_exception']))
|
||||
@ -2028,7 +2035,7 @@ class calendar_boupdate extends calendar_bo
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Translates all timestamps for a given event from server-time to user-time.
|
||||
* The update() and save() methods expect timestamps in user-time.
|
||||
* @param &$event the event we are working on
|
||||
|
@ -128,13 +128,6 @@ class calendar_ical extends calendar_boupdate
|
||||
*/
|
||||
var $tzid = null;
|
||||
|
||||
/**
|
||||
* Cached timezone data
|
||||
*
|
||||
* @var array id => data
|
||||
*/
|
||||
protected static $tz_cache = array();
|
||||
|
||||
/**
|
||||
* Device CTCap Properties
|
||||
*
|
||||
@ -257,7 +250,7 @@ class calendar_ical extends calendar_boupdate
|
||||
// explicit device timezone
|
||||
$tzid = $this->tzid;
|
||||
}
|
||||
else
|
||||
elseif ($this->tzid === false)
|
||||
{
|
||||
// use event's timezone
|
||||
$tzid = $event['tzid'];
|
||||
@ -334,6 +327,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
error_log(__METHOD__."() unknown TZID='$tzid', defaulting to user timezone '".egw_time::$user_timezone->getName()."'!");
|
||||
$vtimezone = calendar_timezones::tz2id($tzid=egw_time::$user_timezone->getName(),'component');
|
||||
$tzid = null;
|
||||
}
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
{
|
||||
@ -525,7 +519,6 @@ class calendar_ical extends calendar_boupdate
|
||||
foreach (array('start' => 'DTSTART','end-nextday' => 'DTEND') as $f => $t)
|
||||
{
|
||||
$time = new egw_time($event[$f],egw_time::$server_timezone);
|
||||
$time->setTimezone(self::$tz_cache[$event['tzid']]);
|
||||
$arr = egw_time::to($time,'array');
|
||||
$vevent->setAttribute($t, array('year' => $arr['year'],'month' => $arr['month'],'mday' => $arr['day']),
|
||||
array('VALUE' => 'DATE'));
|
||||
@ -1005,6 +998,10 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$event['uid'] = $event_info['stored_event']['uid']; // restore the UID if it was not delivered
|
||||
}
|
||||
elseif (empty($event['id']))
|
||||
{
|
||||
$event['id'] = $event_info['stored_event']['id']; // CalDAV does only provide UIDs
|
||||
}
|
||||
if ($merge)
|
||||
{
|
||||
if ($this->log)
|
||||
@ -1246,7 +1243,6 @@ class calendar_ical extends calendar_boupdate
|
||||
if ($event_info['acl_edit'])
|
||||
{
|
||||
// Force SINGLE
|
||||
unset($event['recurrence']);
|
||||
$event['reference'] = 0;
|
||||
$event_to_store = $event; // prevent $event from being changed by the update method
|
||||
$this->server2usertime($event_to_store);
|
||||
@ -1515,9 +1511,8 @@ class calendar_ical extends calendar_boupdate
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
$recur_date = $this->date2usertime($event_info['stored_event']['start']);
|
||||
$event_info['stored_event'] = $this->read($event_info['stored_event']['id'], $recur_date);
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
$event_info['stored_event'] = $this->read($event_info['stored_event']['id']);
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()[$updated_id]\n" .
|
||||
array2string($event_info['stored_event'])."\n",3,$this->logfile);
|
||||
}
|
||||
}
|
||||
@ -1630,11 +1625,25 @@ class calendar_ical extends calendar_boupdate
|
||||
if (isset($deviceInfo['tzid']) &&
|
||||
$deviceInfo['tzid'])
|
||||
{
|
||||
switch ($deviceInfo['tzid'])
|
||||
{
|
||||
case 1:
|
||||
$this->tzid = false;
|
||||
break;
|
||||
case 2:
|
||||
$this->tzid = null;
|
||||
break;
|
||||
default:
|
||||
$this->tzid = $deviceInfo['tzid'];
|
||||
}
|
||||
}
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['calendar_owner']))
|
||||
{
|
||||
$owner = $GLOBALS['egw_info']['user']['preferences']['syncml']['calendar_owner'];
|
||||
if ($owner == 0)
|
||||
{
|
||||
$owner = $GLOBALS['egw_info']['user']['account_primary_group'];
|
||||
}
|
||||
if (0 < (int)$owner && $this->check_perms(EGW_ACL_EDIT,0,$owner))
|
||||
{
|
||||
$this->calendarOwner = $owner;
|
||||
@ -1656,11 +1665,15 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
'(' . $this->productManufacturer .
|
||||
', '. $this->productName . ")\n",3,$this->logfile);
|
||||
', '. $this->productName .', ' .
|
||||
($this->tzid ? $this->tzid : egw_time::$user_timezone->getName()) .
|
||||
")\n" , 3, $this->logfile);
|
||||
}
|
||||
|
||||
//Horde::logMessage('setSupportedFields(' . $this->productManufacturer
|
||||
// . ', ' . $this->productName .')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
//Horde::logMessage('setSupportedFields(' . $this->productManufacturer . ', '
|
||||
// . $this->productName .', ' .
|
||||
// ($this->tzid ? $this->tzid : egw_time::$user_timezone->getName()) .')',
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$defaultFields['minimal'] = array(
|
||||
'public' => 'public',
|
||||
@ -1863,8 +1876,14 @@ class calendar_ical extends calendar_boupdate
|
||||
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($this->tzid);
|
||||
$tzid = $this->tzid;
|
||||
}
|
||||
else
|
||||
{
|
||||
$tzid = egw_time::$user_timezone->getName();
|
||||
}
|
||||
|
||||
date_default_timezone_set($tzid);
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
if (!$vcal->parsevCalendar($_vcalData))
|
||||
@ -1912,20 +1931,21 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
}
|
||||
$event['alarm'] = $alarms;
|
||||
if ($this->tzid || empty($event['tzid']))
|
||||
{
|
||||
$event['tzid'] = $tzid;
|
||||
}
|
||||
|
||||
$events[] = $event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
|
||||
// if cal_id, etag or recur_date is given, use/set it for 1. event
|
||||
if ($cal_id > 0) $events[0]['id'] = $cal_id;
|
||||
if (!is_null($etag)) $events[0]['etag'] = $etag;
|
||||
if (!is_null($etag)) $events[0]['etag'] = (int) $etag;
|
||||
if ($recur_date) $events[0]['recurrence'] = $recur_date;
|
||||
|
||||
return $events;
|
||||
@ -1974,15 +1994,18 @@ class calendar_ical extends calendar_boupdate
|
||||
$dtstart_ts = is_numeric($attributes['value']) ? $attributes['value'] : $this->date2ts($attributes['value']);
|
||||
$vcardData['start'] = $dtstart_ts;
|
||||
|
||||
|
||||
if ($this->tzid)
|
||||
{
|
||||
// enforce device settings
|
||||
$event['tzid'] = $this->tzid;
|
||||
}
|
||||
elseif (!empty($attributes['params']['TZID']))
|
||||
else
|
||||
{
|
||||
// import TZID, if PHP understands it (we only care about TZID of starttime, as we store only a TZID for the whole event)
|
||||
$event['tzid'] = date_default_timezone_get();
|
||||
|
||||
if (!empty($attributes['params']['TZID']))
|
||||
{
|
||||
// import TZID, if PHP understands it (we only care about TZID of starttime,
|
||||
// as we store only a TZID for the whole event)
|
||||
try
|
||||
{
|
||||
$tz = calendar_timezones::DateTimeZone($attributes['params']['TZID']);
|
||||
@ -1990,16 +2013,15 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
error_log(__METHOD__."() unknown TZID='{$attributes['params']['TZID']}', defaulting to user timezone '".egw_time::$user_timezone->getName()."'!");
|
||||
$tz = egw_time::$user_timezone;
|
||||
$event['tzid'] = egw_time::$user_timezone->getName(); // default to user timezone
|
||||
error_log(__METHOD__ . '() unknown TZID='
|
||||
. $attributes['params']['TZID'] . ', defaulting to timezone "'
|
||||
. date_default_timezone_get() . '".');
|
||||
$event['tzid'] = date_default_timezone_get(); // default to current timezone
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$event['tzid'] = egw_time::$user_timezone->getName(); // default to user timezone
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DTEND':
|
||||
$dtend_ts = is_numeric($attributes['value']) ? $attributes['value'] : $this->date2ts($attributes['value']);
|
||||
if (date('H:i:s',$dtend_ts) == '00:00:00')
|
||||
@ -2028,7 +2050,6 @@ class calendar_ical extends calendar_boupdate
|
||||
break;
|
||||
case 'DESCRIPTION':
|
||||
$vcardData['description'] = str_replace("\r\n", "\n", $attributes['value']);
|
||||
$vcardData['description'] = str_replace("\r", "\n", $vcardData['description']);
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $attributes['value'], $matches))
|
||||
{
|
||||
if (!isset($vCardData['uid'])
|
||||
@ -2044,7 +2065,6 @@ class calendar_ical extends calendar_boupdate
|
||||
break;
|
||||
case 'LOCATION':
|
||||
$vcardData['location'] = str_replace("\r\n", "\n", $attributes['value']);
|
||||
$vcardData['location'] = str_replace("\r", "\n", $vcardData['location']);
|
||||
break;
|
||||
case 'RRULE':
|
||||
$recurence = $attributes['value'];
|
||||
@ -2301,7 +2321,6 @@ class calendar_ical extends calendar_boupdate
|
||||
break;
|
||||
case 'SUMMARY':
|
||||
$vcardData['title'] = str_replace("\r\n", "\n", $attributes['value']);
|
||||
$vcardData['title'] = str_replace("\r", "\n", $vcardData['title']);
|
||||
break;
|
||||
case 'UID':
|
||||
if (strlen($attributes['value']) >= $minimum_uid_length)
|
||||
@ -2457,11 +2476,16 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$attributes['params']['ROLE'] = 'CHAIR';
|
||||
}
|
||||
if (!isset($event['participants'][$uid]) ||
|
||||
$event['participants'][$uid][0] != 'A')
|
||||
{
|
||||
// for multiple entries the ACCEPT wins
|
||||
// add quantity and role
|
||||
$event['participants'][$uid] =
|
||||
calendar_so::combine_status($status,
|
||||
$attributes['params']['X-EGROUPWARE-QUANTITY'],
|
||||
$attributes['params']['ROLE']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ORGANIZER':
|
||||
@ -2575,6 +2599,8 @@ class calendar_ical extends calendar_boupdate
|
||||
|
||||
if ($this->calendarOwner) $event['owner'] = $this->calendarOwner;
|
||||
|
||||
if ($cal_id > 0) $event['id'] = $cal_id;
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
@ -2595,6 +2621,7 @@ class calendar_ical extends calendar_boupdate
|
||||
$filter = $relax ? 'relax' : 'exact';
|
||||
$event = array_shift($events);
|
||||
if ($this->so->isWholeDay($event)) $event['whole_day'] = true;
|
||||
if ($contentID) $event['id'] = $contentID;
|
||||
return $this->find_event($event, $filter);
|
||||
}
|
||||
if ($this->log)
|
||||
|
@ -96,13 +96,6 @@ class calendar_sif extends calendar_boupdate
|
||||
*/
|
||||
var $tzid = null;
|
||||
|
||||
/**
|
||||
* Cached timezone data
|
||||
*
|
||||
* @var array id => data
|
||||
*/
|
||||
protected static $tz_cache = array();
|
||||
|
||||
/**
|
||||
* Device CTCap Properties
|
||||
*
|
||||
@ -211,7 +204,7 @@ class calendar_sif extends calendar_boupdate
|
||||
}
|
||||
$time->setTimezone(self::$tz_cache[$tzid]);
|
||||
|
||||
return $this->vCalendar->_exportDateTime($time->format('Ymd\THis'));
|
||||
return $time->format('Ymd\THis');
|
||||
}
|
||||
|
||||
function siftoegw($sifData, $_calID=-1)
|
||||
@ -220,13 +213,18 @@ class calendar_sif extends calendar_boupdate
|
||||
$this->event = array();
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
|
||||
|
||||
if ($this->tzid)
|
||||
{
|
||||
// enforce device settings
|
||||
date_default_timezone_set($this->tzid);
|
||||
$finalEvent['tzid'] = $this->tzid;
|
||||
$tzid = $this->tzid;
|
||||
}
|
||||
else
|
||||
{
|
||||
$tzid = egw_time::$user_timezone->getName();
|
||||
}
|
||||
|
||||
date_default_timezone_set($tzid);
|
||||
$finalEvent['tzid'] = $tzid;
|
||||
|
||||
$this->xml_parser = xml_parser_create('UTF-8');
|
||||
xml_set_object($this->xml_parser, $this);
|
||||
@ -239,10 +237,7 @@ class calendar_sif extends calendar_boupdate
|
||||
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)));
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -379,17 +374,14 @@ class calendar_sif extends calendar_boupdate
|
||||
}
|
||||
|
||||
default:
|
||||
$finalEvent[$key] = $value;
|
||||
$finalEvent[$key] = str_replace("\r\n", "\n", $value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->calendarOwner) $finalEvent['owner'] = $this->calendarOwner;
|
||||
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
|
||||
if ($_calID > 0) $finalEvent['id'] = $_calID;
|
||||
|
||||
@ -862,7 +854,7 @@ class calendar_sif extends calendar_boupdate
|
||||
// explicit device timezone
|
||||
$tzid = $this->tzid;
|
||||
}
|
||||
else
|
||||
elseif ($this->tzid === false)
|
||||
{
|
||||
// use event's timezone
|
||||
$tzid = $event['tzid'];
|
||||
@ -1203,11 +1195,25 @@ class calendar_sif extends calendar_boupdate
|
||||
if (isset($deviceInfo['tzid']) &&
|
||||
$deviceInfo['tzid'])
|
||||
{
|
||||
switch ($deviceInfo['tzid'])
|
||||
{
|
||||
case 1:
|
||||
$this->tzid = false;
|
||||
break;
|
||||
case 2:
|
||||
$this->tzid = null;
|
||||
break;
|
||||
default:
|
||||
$this->tzid = $deviceInfo['tzid'];
|
||||
}
|
||||
}
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['calendar_owner']))
|
||||
{
|
||||
$owner = $GLOBALS['egw_info']['user']['preferences']['syncml']['calendar_owner'];
|
||||
if ($owner == 0)
|
||||
{
|
||||
$owner = $GLOBALS['egw_info']['user']['account_primary_group'];
|
||||
}
|
||||
if (0 < (int)$owner && $this->check_perms(EGW_ACL_EDIT,0,$owner))
|
||||
{
|
||||
$this->calendarOwner = $owner;
|
||||
|
@ -31,6 +31,21 @@ class infolog_bo
|
||||
var $link_pathes = array();
|
||||
var $send_file_ips = array();
|
||||
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $log = false;
|
||||
|
||||
|
||||
/**
|
||||
* Cached timezone data
|
||||
*
|
||||
* @var array id => data
|
||||
*/
|
||||
protected static $tz_cache = array();
|
||||
|
||||
/**
|
||||
* current time as timestamp in user-time and server-time
|
||||
*
|
||||
@ -403,6 +418,85 @@ class infolog_bo
|
||||
return substr($des,0,60).' ...';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the timestamps from given timezone to another and keep dates.
|
||||
* The timestamps are mostly expected to be in server-time
|
||||
* and $fromTZId is only used to qualify dates.
|
||||
*
|
||||
* @param array $values to modify
|
||||
* @param string $fromTZId=null
|
||||
* @param string $toTZId=false
|
||||
* TZID timezone name e.g. 'UTC'
|
||||
* or NULL for timestamps in user-time
|
||||
* or false for timestamps in server-time
|
||||
*/
|
||||
function time2time(&$values, $fromTZId=false, $toTZId=null)
|
||||
{
|
||||
|
||||
if ($fromTZId === $toTZId) return;
|
||||
|
||||
$tz = egw_time::$server_timezone;
|
||||
|
||||
if ($fromTZId)
|
||||
{
|
||||
if (!isset(self::$tz_cache[$fromTZId]))
|
||||
{
|
||||
self::$tz_cache[$fromTZId] = calendar_timezones::DateTimeZone($fromTZId);
|
||||
}
|
||||
$fromTZ = self::$tz_cache[$fromTZId];
|
||||
}
|
||||
elseif (is_null($fromTZId))
|
||||
{
|
||||
$tz = egw_time::$user_timezone;
|
||||
$fromTZ = egw_time::$user_timezone;
|
||||
}
|
||||
else
|
||||
{
|
||||
$fromTZ = egw_time::$server_timezone;
|
||||
}
|
||||
if ($toTZId)
|
||||
{
|
||||
if (!isset(self::$tz_cache[$toTZId]))
|
||||
{
|
||||
self::$tz_cache[$toTZId] = calendar_timezones::DateTimeZone($toTZId);
|
||||
}
|
||||
$toTZ = self::$tz_cache[$toTZId];
|
||||
}
|
||||
elseif (is_null($toTZId))
|
||||
{
|
||||
$toTZ = egw_time::$user_timezone;
|
||||
}
|
||||
else
|
||||
{
|
||||
$toTZ = egw_time::$server_timezone;
|
||||
}
|
||||
|
||||
foreach($this->timestamps as $key)
|
||||
{
|
||||
if ($values[$key])
|
||||
{
|
||||
$time = new egw_time($values[$key], $tz);
|
||||
$time->setTimezone($fromTZ);
|
||||
if ($key == 'info_enddate')
|
||||
{
|
||||
// Set due date to 00:00
|
||||
$time->setTime(0, 0, 0);
|
||||
}
|
||||
if ($time->format('Hi') == '0000')
|
||||
{
|
||||
// we keep dates the same in new timezone
|
||||
$arr = egw_time::to($time,'array');
|
||||
$time = new egw_time($arr, $toTZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
$time->setTimezone($toTZ);
|
||||
}
|
||||
$values[$key] = egw_time::to($time,'ts');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a date from server to user-time
|
||||
*
|
||||
@ -452,30 +546,21 @@ class infolog_bo
|
||||
}
|
||||
if ($run_link_id2from) $this->link_id2from($data);
|
||||
|
||||
if ($data['info_enddate'])
|
||||
{
|
||||
// Set due date to 00:00
|
||||
$due = new egw_time($data['info_enddate'], egw_time::$server_timezone);
|
||||
$due->setTime(0, 0, 0);
|
||||
if ($date_format != 'server')
|
||||
{
|
||||
$arr = egw_time::to($due,'array');
|
||||
$due = new egw_time($arr, egw_time::$user_timezone);
|
||||
}
|
||||
$data['info_enddate'] = egw_time::to($due,'server');
|
||||
}
|
||||
|
||||
// convert system- to user-time
|
||||
foreach($this->timestamps as $time)
|
||||
{
|
||||
if ($data[$time]) $data[$time] = $this->date2usertime($data[$time],$date_format);
|
||||
}
|
||||
|
||||
// convert server- to user-time
|
||||
if ($date_format == 'ts')
|
||||
{
|
||||
$this->time2time($data);
|
||||
|
||||
// pre-cache title and file access
|
||||
self::set_link_cache($data);
|
||||
}
|
||||
else
|
||||
{
|
||||
$time = new egw_time($data['info_enddate'], egw_time::$server_timezone);
|
||||
// Set due date to 00:00
|
||||
$time->setTime(0, 0,0 );
|
||||
$data['info_enddate'] = egw_time::to($time,'ts');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
@ -696,37 +781,21 @@ class infolog_bo
|
||||
$to_write = $values;
|
||||
if ($user2server)
|
||||
{
|
||||
// convert user- to system-time
|
||||
foreach($this->timestamps as $time)
|
||||
{
|
||||
if ($to_write[$time]) $to_write[$time] = egw_time::user2server($to_write[$time],'ts');
|
||||
}
|
||||
if ($values['info_enddate'])
|
||||
{
|
||||
// convert user- to server-time
|
||||
$this->time2time($to_write, null, false);
|
||||
$time = new egw_time($values['info_enddate'], egw_time::$user_timezone);
|
||||
// Set due date to 00:00
|
||||
$due = new egw_time($values['info_enddate'], egw_time::$user_timezone);
|
||||
$due->setTime(0, 0, 0);
|
||||
$values['info_enddate'] = egw_time::to($due,'ts');
|
||||
$arr = egw_time::to($due,'array');
|
||||
$to_write['info_enddate'] = mktime(0, 0, 0, $arr['month'], $arr['day'], $arr['year']);
|
||||
}
|
||||
$time->setTime(0, 0, 0);
|
||||
$values['info_enddate'] = egw_time::to($time,'ts');
|
||||
}
|
||||
else
|
||||
{
|
||||
$time = new egw_time($values['info_enddate'], egw_time::$user_timezone);
|
||||
// Set due date to 00:00
|
||||
$time->setTime(0, 0, 0);
|
||||
$to_write['info_enddate'] = egw_time::to($time,'ts');
|
||||
// convert server- to user-time
|
||||
foreach($this->timestamps as $time)
|
||||
{
|
||||
if ($values[$time]) $values[$time] = egw_time::server2user($values[$time],'ts');
|
||||
}
|
||||
if ($to_write['info_enddate'])
|
||||
{
|
||||
$due = new egw_time($to_write['info_enddate'], egw_time::$server_timezone);
|
||||
$due->setTime(0, 0, 0);
|
||||
$to_write['info_enddate'] = egw_time::to($due,'ts');
|
||||
$arr = egw_time::to($due,'array');
|
||||
$due = new egw_time($arr, egw_time::$user_timezone);
|
||||
$values['info_enddate'] = egw_time::to($due,'ts');
|
||||
}
|
||||
$this->time2time($values);
|
||||
}
|
||||
|
||||
if ($touch_modified || !$values['info_datemodified'])
|
||||
@ -776,7 +845,7 @@ class infolog_bo
|
||||
}
|
||||
$values['info_id'] = $info_id;
|
||||
$to_write['info_id'] = $info_id;
|
||||
// if the info responsible array is not passed, fetch it from old.
|
||||
// if the info responbsible array is not passed, fetch it from old.
|
||||
if (!array_key_exists('info_responsible',$values)) $values['info_responsible'] = $old['info_responsible'];
|
||||
if (!is_array($values['info_responsible'])) // this should not happen, bug it does ;-)
|
||||
{
|
||||
@ -843,25 +912,35 @@ class infolog_bo
|
||||
}
|
||||
$ret = $this->so->search($query);
|
||||
|
||||
// convert system- to user-time
|
||||
if (is_array($ret))
|
||||
{
|
||||
foreach($ret as $id => &$data)
|
||||
{
|
||||
if ($data['info_enddate'])
|
||||
if (!$this->check_access($data,EGW_ACL_READ))
|
||||
{
|
||||
// Set due date to 00:00 in user-time
|
||||
$due = new egw_time($data['info_enddate'], egw_time::$server_timezone);
|
||||
$due->setTime(0, 0, 0);
|
||||
$arr = egw_time::to($due,'array');
|
||||
$due = new egw_time($arr, egw_time::$user_timezone);
|
||||
$data['info_enddate'] = egw_time::to($due,'server');
|
||||
unset($ret[$id]);
|
||||
continue;
|
||||
}
|
||||
foreach($this->timestamps as $time)
|
||||
// convert system- to user-time
|
||||
foreach($this->timestamps as $key)
|
||||
{
|
||||
if ($data[$time]) $data[$time] = $this->date2usertime($data[$time]);
|
||||
if ($data[$key])
|
||||
{
|
||||
$time = new egw_time($data[$key], egw_time::$server_timezone);
|
||||
if ($key == 'info_enddate') $time->setTime(0, 0,0 ); // Set due date to 00:00
|
||||
if ($time->format('Hi') == '0000')
|
||||
{
|
||||
// we keep dates the same in user-time
|
||||
$arr = egw_time::to($time,'array');
|
||||
$time = new egw_time($arr, egw_time::$user_timezone);
|
||||
}
|
||||
else
|
||||
{
|
||||
$time->setTimezone(egw_time::$user_timezone);
|
||||
}
|
||||
$data[$key] = egw_time::to($time,'ts');
|
||||
}
|
||||
}
|
||||
|
||||
// pre-cache title and file access
|
||||
self::set_link_cache($data);
|
||||
}
|
||||
@ -1177,13 +1256,12 @@ class infolog_bo
|
||||
{
|
||||
$this->categories = new categories($this->user,'infolog');
|
||||
}
|
||||
|
||||
$old_cats_preserve = array();
|
||||
if ($info_id && $info_id > 0)
|
||||
{
|
||||
// preserve categories without users read access
|
||||
$old_infolog = $this->read($info_id);
|
||||
$old_categories = explode(',',$old_infolog['info_cat']);
|
||||
$old_cats_preserve = array();
|
||||
if(is_array($old_categories) && count($old_categories) > 0)
|
||||
{
|
||||
foreach($old_categories as $cat_id)
|
||||
@ -1218,7 +1296,7 @@ class infolog_bo
|
||||
}
|
||||
}
|
||||
|
||||
if(is_array($old_cats_preserve) && count($old_cats_preserve) > 0)
|
||||
if (count($old_cats_preserve) > 0)
|
||||
{
|
||||
$cat_id_list = array_merge($old_cats_preserve, $cat_id_list);
|
||||
}
|
||||
@ -1448,74 +1526,158 @@ class infolog_bo
|
||||
|
||||
/**
|
||||
* Try to find a matching db entry
|
||||
* This method is working completely in server-time and
|
||||
* expects all time entriey to be 00:00 normalized.
|
||||
* This expects timestamps to be in server-time.
|
||||
*
|
||||
* @param array $egwData the vTODO data we try to find
|
||||
* @param array $infoData the infolog 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)
|
||||
* @param string $tzid=null timezone, null => user time
|
||||
*
|
||||
* @return array of infolog_ids of matching entries
|
||||
*/
|
||||
function findVTODO($egwData, $relax=false)
|
||||
function findInfo($infoData, $relax=false, $tzid=null)
|
||||
{
|
||||
if (!empty($egwData['info_uid']))
|
||||
{
|
||||
$filter = array('col_filter' => array('info_uid' => $egwData['info_uid']));
|
||||
if (($found = $this->so->search($filter))
|
||||
&& ($uidmatch = array_shift($found)))
|
||||
{
|
||||
return $uidmatch['info_id'];
|
||||
}
|
||||
}
|
||||
unset($egwData['info_uid']);
|
||||
|
||||
$foundInfoLogs = array();
|
||||
$filter = array();
|
||||
|
||||
$description = '';
|
||||
if (!empty($egwData['info_des'])) {
|
||||
$description = trim(preg_replace("/\r?\n?\\[[A-Z_]+:.*\\]/i", '', $egwData['info_des']));
|
||||
unset($egwData['info_des']);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '('. ($relax ? 'RELAX, ': 'EXACT, ') . $tzid . ')[InfoData]:'
|
||||
. array2string($infoData));
|
||||
}
|
||||
|
||||
if ($infoData['info_id']
|
||||
&& ($egwData = $this->read($infoData['info_id'], true, 'server')))
|
||||
{
|
||||
// we only do a simple consistency check
|
||||
if (strpos($egwData['info_subject'], $infoData['info_subject']) === 0)
|
||||
{
|
||||
return array($egwData['info_id']);
|
||||
}
|
||||
if (!$relax) return array();
|
||||
}
|
||||
unset($infoData['info_id']);
|
||||
|
||||
if (!$relax && !empty($infoData['info_uid']))
|
||||
{
|
||||
$filter = array('col_filter' => array('info_uid' => $infoData['info_uid']));
|
||||
foreach($this->so->search($filter) as $egwData)
|
||||
{
|
||||
if (!$this->check_access($egwData,EGW_ACL_READ)) continue;
|
||||
$foundInfoLogs[$egwData['info_id']] = $egwData['info_id'];
|
||||
}
|
||||
return $foundInfoLogs;
|
||||
}
|
||||
unset($infoData['info_uid']);
|
||||
|
||||
if (empty($infoData['info_des']))
|
||||
{
|
||||
$description = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignore meta information appendices
|
||||
$description = trim(preg_replace('/\s*\[[A-Z_]+:.*\].*/im', '', $infoData['info_des']));
|
||||
$text = trim(preg_replace('/\s*\[[A-Z_]+:.*\]/im', '', $infoData['info_des']));
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "()[description]: $description");
|
||||
}
|
||||
// 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'])))
|
||||
if (preg_match_all('/[\x20-\x7F]*/m', $text, $matches, PREG_SET_ORDER))
|
||||
{
|
||||
// We only do a simple consistency check
|
||||
if ($found['info_subject'] == $egwData['info_subject']
|
||||
&& strpos($found['info_des'], $description) === 0)
|
||||
$text = '';
|
||||
foreach ($matches as $chunk)
|
||||
{
|
||||
return $found['info_id'];
|
||||
if (strlen($text) < strlen($chunk[0]))
|
||||
{
|
||||
$text = $chunk[0];
|
||||
}
|
||||
}
|
||||
unset($egwData['info_id']);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "()[search]: $text");
|
||||
}
|
||||
$filter['search'] = $text;
|
||||
}
|
||||
}
|
||||
$this->time2time($infoData, $tzid, false);
|
||||
|
||||
$filter['col_filter'] = $infoData;
|
||||
// priority does not need to match
|
||||
unset($egwData['info_priority']);
|
||||
unset($filter['col_filter']['info_priority']);
|
||||
// we ignore description and location first
|
||||
unset($filter['col_filter']['info_des']);
|
||||
unset($filter['col_filter']['info_location']);
|
||||
|
||||
$filter['col_filter'] = $egwData;
|
||||
foreach ($this->so->search($filter) as $itemID => $egwData)
|
||||
{
|
||||
if (!$this->check_access($egwData,EGW_ACL_READ)) continue;
|
||||
|
||||
if($foundItems = $this->so->search($filter)) {
|
||||
if(count($foundItems) > 0) {
|
||||
$itemIDs = array_keys($foundItems);
|
||||
return $itemIDs[0];
|
||||
switch ($infoData['info_type'])
|
||||
{
|
||||
case 'task':
|
||||
if (!empty($egwData['info_location']))
|
||||
{
|
||||
$egwData['info_location'] = str_replace("\r\n", "\n", $egwData['info_location']);
|
||||
}
|
||||
if (!$relax &&
|
||||
!empty($infoData['info_location']) && (empty($egwData['info_location'])
|
||||
|| strpos($egwData['info_location'], $infoData['info_location']) !== 0))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[location mismatch]: '
|
||||
. $infoData['info_location'] . ' <> ' . $egwData['info_location']);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
if (!empty($egwData['info_des']))
|
||||
{
|
||||
$egwData['info_des'] = str_replace("\r\n", "\n", $egwData['info_des']);
|
||||
}
|
||||
if (!$relax && ($description && empty($egwData['info_des'])
|
||||
|| !empty($egwData['info_des']) && empty($infoData['info_des'])
|
||||
|| strpos($egwData['info_des'], $description) === false))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[description mismatch]: '
|
||||
. $infoData['info_des'] . ' <> ' . $egwData['info_des']);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// no further criteria to match
|
||||
$foundInfoLogs[$egwData['info_id']] = $egwData['info_id'];
|
||||
}
|
||||
}
|
||||
|
||||
$filter = array();
|
||||
|
||||
if (!$relax && strlen($description)) {
|
||||
$filter['search'] = $description;
|
||||
if (!$relax && !empty($foundInfoLogs))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[FOUND]:' . array2string($foundInfoLogs));
|
||||
}
|
||||
return $foundInfoLogs;
|
||||
}
|
||||
|
||||
$filter['col_filter'] = $egwData;
|
||||
if ($relax)
|
||||
{
|
||||
unset($filter['search']);
|
||||
}
|
||||
|
||||
// search for date only match
|
||||
// search for matches by date only
|
||||
unset($filter['col_filter']['info_startdate']);
|
||||
unset($filter['col_filter']['info_enddate']);
|
||||
unset($filter['col_filter']['info_datecompleted']);
|
||||
// Some devices support lesser stati
|
||||
unset($filter['col_filter']['info_status']);
|
||||
|
||||
// try tasks without category
|
||||
unset($filter['col_filter']['info_cat']);
|
||||
@ -1523,41 +1685,144 @@ class infolog_bo
|
||||
// Horde::logMessage("findVTODO Filter\n"
|
||||
// . print_r($filter, true),
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
foreach ($this->so->search($filter) as $itemID => $taskData)
|
||||
foreach ($this->so->search($filter) as $itemID => $egwData)
|
||||
{
|
||||
if (!$this->check_access($egwData,EGW_ACL_READ)) continue;
|
||||
// Horde::logMessage("findVTODO Trying\n"
|
||||
// . print_r($taskData, true),
|
||||
// . print_r($egwData, 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'])
|
||||
if (isset($infoData['info_cat'])
|
||||
&& isset($egwData['info_cat']) && $egwData['info_cat']
|
||||
&& $infoData['info_cat'] != $egwData['info_cat'])
|
||||
{
|
||||
$time = new egw_time($taskData['info_startdate'],egw_time::$server_timezone);
|
||||
$time->setTime(0, 0, 0);
|
||||
$startdate = egw_time::to($time,'server');
|
||||
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'])
|
||||
if ($this->log)
|
||||
{
|
||||
$time = new egw_time($taskData['info_datecompleted'],egw_time::$server_timezone);
|
||||
$time->setTime(0, 0, 0);
|
||||
$enddate = egw_time::to($time,'server');
|
||||
if ($egwData['info_datecompleted'] != $enddate) continue;
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[category mismatch]: '
|
||||
. $infoData['info_cat'] . ' <> ' . $egwData['info_cat']);
|
||||
}
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
if (isset($infoData['info_startdate']) && $infoData['info_startdate'])
|
||||
{
|
||||
// We got a startdate from client
|
||||
if (isset($egwData['info_startdate']) && $egwData['info_startdate'])
|
||||
{
|
||||
// We compare the date only
|
||||
$taskTime = new egw_time($infoData['info_startdate'],egw_time::$server_timezone);
|
||||
$egwTime = new egw_time($egwData['info_startdate'],egw_time::$server_timezone);
|
||||
if ($taskTime->format('Ymd') != $egwTime->format('Ymd'))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[start mismatch]: '
|
||||
. $taskTime->format('Ymd') . ' <> ' . $egwTime->format('Ymd'));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
elseif (!$relax)
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[start mismatch]');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($infoData['info_type'] == 'task')
|
||||
{
|
||||
if (isset($infoData['info_status']) && isset($egwData['info_status'])
|
||||
&& $egwData['info_status'] == 'done'
|
||||
&& $infoData['info_status'] != 'done' ||
|
||||
$egwData['info_status'] != 'done'
|
||||
&& $infoData['info_status'] == 'done')
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[status mismatch]: '
|
||||
. $infoData['info_status'] . ' <> ' . $egwData['info_status']);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isset($infoData['info_enddate']) && $infoData['info_enddate'])
|
||||
{
|
||||
// We got a enddate from client
|
||||
if (isset($egwData['info_enddate']) && $egwData['info_enddate'])
|
||||
{
|
||||
// We compare the date only
|
||||
$taskTime = new egw_time($infoData['info_enddate'],egw_time::$server_timezone);
|
||||
$egwTime = new egw_time($egwData['info_enddate'],egw_time::$server_timezone);
|
||||
if ($taskTime->format('Ymd') != $egwTime->format('Ymd'))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[DUE mismatch]: '
|
||||
. $taskTime->format('Ymd') . ' <> ' . $egwTime->format('Ymd'));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
elseif (!$relax)
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[DUE mismatch]');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (isset($infoData['info_datecompleted']) && $infoData['info_datecompleted'])
|
||||
{
|
||||
// We got a completed date from client
|
||||
if (isset($egwData['info_datecompleted']) && $egwData['info_datecompleted'])
|
||||
{
|
||||
// We compare the date only
|
||||
$taskTime = new egw_time($infoData['info_datecompleted'],egw_time::$server_timezone);
|
||||
$egwTime = new egw_time($egwData['info_datecompleted'],egw_time::$server_timezone);
|
||||
if ($taskTime->format('Ymd') != $egwTime->format('Ymd'))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[completed mismatch]: '
|
||||
. $taskTime->format('Ymd') . ' <> ' . $egwTime->format('Ymd'));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
elseif (!$relax)
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[completed mismatch]');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
elseif (!$relax && isset($egwData['info_datecompleted']) && $egwData['info_datecompleted'])
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[completed mismatch]');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$foundInfoLogs[$itemID] = $itemID;
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[FOUND]:' . array2string($foundInfoLogs));
|
||||
}
|
||||
return $foundInfoLogs;
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,13 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
var $uidExtension = false;
|
||||
|
||||
/**
|
||||
* user preference: Use this timezone for import from and export to device
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $tzid = null;
|
||||
|
||||
/**
|
||||
* Client CTCap Properties
|
||||
*
|
||||
@ -148,6 +155,39 @@ class infolog_ical extends infolog_bo
|
||||
$vcal->setAttribute('VERSION',$_version);
|
||||
$vcal->setAttribute('METHOD',$_method);
|
||||
|
||||
$tzid = $this->tzid;
|
||||
|
||||
if ($tzid && $tzid != 'UTC')
|
||||
{
|
||||
// check if we have vtimezone component data for tzid of event, if not default to user timezone (default to server tz)
|
||||
if (!($vtimezone = calendar_timezones::tz2id($tzid,'component')))
|
||||
{
|
||||
error_log(__METHOD__."() unknown TZID='$tzid', defaulting to user timezone '".egw_time::$user_timezone->getName()."'!");
|
||||
$vtimezone = calendar_timezones::tz2id($tzid=egw_time::$user_timezone->getName(),'component');
|
||||
$tzid = null;
|
||||
}
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
{
|
||||
self::$tz_cache[$tzid] = calendar_timezones::DateTimeZone($tzid);
|
||||
}
|
||||
// $vtimezone is a string with a single VTIMEZONE component, afaik Horde_iCalendar can not add it directly
|
||||
// --> we have to parse it and let Horde_iCalendar add it again
|
||||
$horde_vtimezone = Horde_iCalendar::newComponent('VTIMEZONE',$container=false);
|
||||
$horde_vtimezone->parsevCalendar($vtimezone,'VTIMEZONE');
|
||||
// DTSTART must be in local time!
|
||||
$standard = $horde_vtimezone->findComponent('STANDARD');
|
||||
$dtstart = $standard->getAttribute('DTSTART');
|
||||
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
|
||||
$dtstart->setTimezone(self::$tz_cache[$tzid]);
|
||||
$standard->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
|
||||
$daylight = $horde_vtimezone->findComponent('DAYLIGHT');
|
||||
$dtstart = $daylight->getAttribute('DTSTART');
|
||||
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
|
||||
$dtstart->setTimezone(self::$tz_cache[$tzid]);
|
||||
$daylight->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
|
||||
$vcal->addComponent($horde_vtimezone);
|
||||
}
|
||||
|
||||
$vevent = Horde_iCalendar::newComponent('VTODO',$vcal);
|
||||
|
||||
if (!isset($this->clientProperties['SUMMARY']['Size']))
|
||||
@ -253,15 +293,15 @@ class infolog_ical extends infolog_bo
|
||||
|
||||
if ($taskData['info_startdate'])
|
||||
{
|
||||
self::setDateOrTime($vevent,'DTSTART',$taskData['info_startdate']);
|
||||
self::setDateOrTime($vevent, 'DTSTART', $taskData['info_startdate'], $tzid);
|
||||
}
|
||||
if ($taskData['info_enddate'])
|
||||
{
|
||||
self::setDateOrTime($vevent,'DUE',$taskData['info_enddate']);
|
||||
self::setDateOrTime($vevent, 'DUE', $taskData['info_enddate'], false); // export always as date
|
||||
}
|
||||
if ($taskData['info_datecompleted'])
|
||||
{
|
||||
self::setDateOrTime($vevent,'COMPLETED',$taskData['info_datecompleted']);
|
||||
self::setDateOrTime($vevent, 'COMPLETED', $taskData['info_datecompleted'], $tzid);
|
||||
}
|
||||
|
||||
$vevent->setAttribute('DTSTAMP',time());
|
||||
@ -298,27 +338,67 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if use set a date or date+time and export it as such
|
||||
* set date-time attribute to DATE or DATE-TIME depending on value
|
||||
* 00:00 uses DATE else DATE-TIME
|
||||
*
|
||||
* @param Horde_iCalendar_* $vevent
|
||||
* @param string $attr attribute name
|
||||
* @param int $value timestamp
|
||||
* @param int $time timestamp in server-time
|
||||
* @param string $tzid timezone to use for client, null for user-time, false for server-time
|
||||
*/
|
||||
static function setDateOrTime($vevent,$attr,$value)
|
||||
static function setDateOrTime(&$vevent, $attr, $time, $tzid)
|
||||
{
|
||||
// check if use set only a date --> export it as such
|
||||
if (date('H:i',$value) == '00:00')
|
||||
$params = array();
|
||||
|
||||
if ($tzid)
|
||||
{
|
||||
$vevent->setAttribute($attr,array(
|
||||
'year' => date('Y',$value),
|
||||
'month' => date('m',$value),
|
||||
'mday' => date('d',$value),
|
||||
),array('VALUE' => 'DATE'));
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
{
|
||||
self::$tz_cache[$tzid] = calendar_timezones::DateTimeZone($tzid);
|
||||
}
|
||||
$tz = self::$tz_cache[$tzid];
|
||||
}
|
||||
elseif(is_null($tzid))
|
||||
{
|
||||
$tz = egw_time::$user_timezone;
|
||||
}
|
||||
else
|
||||
{
|
||||
$vevent->setAttribute($attr,$value);
|
||||
$tz = egw_time::$server_timezone;
|
||||
}
|
||||
if (!is_a($time,'DateTime'))
|
||||
{
|
||||
$time = new egw_time($time,egw_time::$server_timezone);
|
||||
}
|
||||
$time->setTimezone($tz);
|
||||
|
||||
// check for date --> export it as such
|
||||
if ($time->format('Hi') == '0000')
|
||||
{
|
||||
$arr = egw_time::to($time, 'array');
|
||||
$value = array(
|
||||
'year' => $arr['year'],
|
||||
'month' => $arr['month'],
|
||||
'mday' => $arr['day']);
|
||||
$params['VALUE'] = 'DATE';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($tzid == 'UTC')
|
||||
{
|
||||
$value = $time->format('Ymd\THis\Z');
|
||||
}
|
||||
elseif ($tzid)
|
||||
{
|
||||
$value = $time->format('Ymd\THis');
|
||||
$params['TZID'] = $tzid;
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = egw_time::to($time, 'ts');
|
||||
}
|
||||
}
|
||||
$vevent->setAttribute($attr, $value, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -331,7 +411,21 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false)
|
||||
{
|
||||
if (!($taskData = $this->vtodotoegw($_vcalData,$_taskID))) return false;
|
||||
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($this->tzid);
|
||||
}
|
||||
$taskData = $this->vtodotoegw($_vcalData,$_taskID);
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
|
||||
if (!$taskData) return false;
|
||||
|
||||
// keep the dates
|
||||
$this->time2time($taskData, $this->tzid, false);
|
||||
|
||||
// we suppose that a not set status in a vtodo means that the task did not started yet
|
||||
if (empty($taskData['info_status']))
|
||||
@ -359,18 +453,29 @@ class infolog_ical extends infolog_bo
|
||||
* @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
|
||||
*
|
||||
* @return array of infolog_ids of matching entries
|
||||
*/
|
||||
function searchVTODO($_vcalData, $contentID=null, $relax=false) {
|
||||
$result = false;
|
||||
function searchVTODO($_vcalData, $contentID=null, $relax=false)
|
||||
{
|
||||
$result = array();
|
||||
|
||||
if (($egwData = $this->vtodotoegw($_vcalData,$contentID)))
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($this->tzid);
|
||||
}
|
||||
$taskData = $this->vtodotoegw($_vcalData,$contentID);
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
if ($taskData)
|
||||
{
|
||||
if ($contentID)
|
||||
{
|
||||
$egwData['info_id'] = $contentID;
|
||||
$taskData['info_id'] = $contentID;
|
||||
}
|
||||
$result = $this->findVTODO($egwData, $relax);
|
||||
$result = $this->findInfo($taskData, $relax, $this->tzid);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@ -386,7 +491,7 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_taskID)\n" .
|
||||
array2string($_vcalData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
@ -412,13 +517,10 @@ class infolog_ical extends infolog_bo
|
||||
$minimum_uid_length = 8;
|
||||
}
|
||||
|
||||
$taskData = false;
|
||||
|
||||
foreach ($vcal->getComponents() as $component)
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($component)."\n",3,$this->logfile);
|
||||
}
|
||||
if (!is_a($component, 'Horde_iCalendar_vtodo'))
|
||||
{
|
||||
if ($this->log)
|
||||
@ -426,9 +528,9 @@ class infolog_ical extends infolog_bo
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
"(): Not a vTODO container, skipping...\n",3,$this->logfile);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
$taskData = array();
|
||||
$taskData['info_type'] = 'task';
|
||||
|
||||
@ -436,19 +538,19 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
$taskData['info_id'] = $_taskID;
|
||||
}
|
||||
foreach ($component->_attributes as $attributes)
|
||||
foreach ($component->_attributes as $attribute)
|
||||
{
|
||||
//$attributes['value'] = trim($attributes['value']);
|
||||
if (!strlen($attributes['value'])) continue;
|
||||
//$attribute['value'] = trim($attribute['value']);
|
||||
if (!strlen($attribute['value'])) continue;
|
||||
|
||||
switch ($attributes['name'])
|
||||
switch ($attribute['name'])
|
||||
{
|
||||
case 'CLASS':
|
||||
$taskData['info_access'] = strtolower($attributes['value']);
|
||||
$taskData['info_access'] = strtolower($attribute['value']);
|
||||
break;
|
||||
|
||||
case 'DESCRIPTION':
|
||||
$value = $attributes['value'];
|
||||
$value = str_replace("\r\n", "\n", $attribute['value']);
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (!isset($taskData['info_uid'])
|
||||
@ -471,37 +573,40 @@ class infolog_ical extends infolog_bo
|
||||
break;
|
||||
|
||||
case 'LOCATION':
|
||||
$taskData['info_location'] = $attributes['value'];
|
||||
$taskData['info_location'] = str_replace("\r\n", "\n", $attribute['value']);
|
||||
break;
|
||||
|
||||
case 'DUE':
|
||||
// eGroupWare uses date only
|
||||
$parts = @getdate($attributes['value']);
|
||||
$parts = @getdate($attribute['value']);
|
||||
$value = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
$taskData['info_enddate'] = $value;
|
||||
break;
|
||||
|
||||
case 'COMPLETED':
|
||||
$taskData['info_datecompleted'] = $attributes['value'];
|
||||
$taskData['info_datecompleted'] = $attribute['value'];
|
||||
break;
|
||||
|
||||
case 'DTSTART':
|
||||
$taskData['info_startdate'] = $attributes['value'];
|
||||
$taskData['info_startdate'] = $attribute['value'];
|
||||
break;
|
||||
|
||||
case 'PRIORITY':
|
||||
if (0 <= $attributes['value'] && $attributes['value'] <= 9) {
|
||||
if (0 <= $attribute['value'] && $attribute['value'] <= 9)
|
||||
{
|
||||
if ($this->productManufacturer == 'funambol' &&
|
||||
(strpos($this->productName, 'outlook') !== false
|
||||
|| strpos($this->productName, 'pocket pc') !== false))
|
||||
{
|
||||
$taskData['info_priority'] = (int) $this->priority_funambol2egw[$attributes['value']];
|
||||
$taskData['info_priority'] = (int) $this->priority_funambol2egw[$attribute['value']];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_priority'] = (int) $this->priority_ical2egw[$attributes['value']];
|
||||
$taskData['info_priority'] = (int) $this->priority_ical2egw[$attribute['value']];
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_priority'] = 1; // default = normal
|
||||
}
|
||||
break;
|
||||
@ -512,55 +617,47 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
if ($attr['name'] == 'X-INFOLOG-STATUS') break;
|
||||
}
|
||||
$taskData['info_status'] = $this->vtodo2status($attributes['value'],
|
||||
$taskData['info_status'] = $this->vtodo2status($attribute['value'],
|
||||
$attr['name'] == 'X-INFOLOG-STATUS' ? $attr['value'] : null);
|
||||
break;
|
||||
|
||||
case 'SUMMARY':
|
||||
$taskData['info_subject'] = $attributes['value'];
|
||||
$taskData['info_subject'] = str_replace("\r\n", "\n", $attribute['value']);
|
||||
break;
|
||||
|
||||
case 'RELATED-TO':
|
||||
$taskData['info_id_parent'] = $this->getParentID($attributes['value']);
|
||||
$taskData['info_id_parent'] = $this->getParentID($attribute['value']);
|
||||
break;
|
||||
|
||||
case 'CATEGORIES':
|
||||
if ($attributes['value'])
|
||||
if (!empty($attribute['value']))
|
||||
{
|
||||
if($version == '1.0')
|
||||
{
|
||||
$vcats = $this->find_or_add_categories(explode(';',$attributes['value']), $_taskID);
|
||||
}
|
||||
else
|
||||
{
|
||||
$cats = $this->find_or_add_categories(explode(',',$attributes['value']), $_taskID);
|
||||
}
|
||||
$cats = $this->find_or_add_categories(explode(',',$attribute['value']), $_taskID);
|
||||
$taskData['info_cat'] = $cats[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'UID':
|
||||
if (strlen($attributes['value']) >= $minimum_uid_length) {
|
||||
$taskData['info_uid'] = $attributes['value'];
|
||||
if (strlen($attribute['value']) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_uid'] = $attribute['value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PERCENT-COMPLETE':
|
||||
$taskData['info_percent'] = (int) $attributes['value'];
|
||||
$taskData['info_percent'] = (int) $attribute['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
# the horde ical class does already convert in parsevCalendar
|
||||
# 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);
|
||||
|
||||
break;
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_taskID)\n" .
|
||||
($taskData ? array2string($taskData) : 'FALSE') . "\n",3,$this->logfile);
|
||||
}
|
||||
return $taskData;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export an infolog entry as VNOTE
|
||||
@ -580,7 +677,6 @@ class infolog_ical extends infolog_bo
|
||||
case 'text/plain':
|
||||
$txt = $note['info_subject']."\n\n".$note['info_des'];
|
||||
return $txt;
|
||||
break;
|
||||
|
||||
case 'text/x-vnote':
|
||||
if (!empty($note['info_cat']))
|
||||
@ -631,7 +727,10 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
$vnote->setAttribute('DCREATED',$note['info_startdate']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$vnote->setAttribute('DCREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'add'));
|
||||
}
|
||||
$vnote->setAttribute('LAST-MODIFIED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'modify'));
|
||||
|
||||
#$vnote->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE');
|
||||
@ -684,40 +783,19 @@ class infolog_ical extends infolog_bo
|
||||
*
|
||||
* @param string $_vcalData VNOTE
|
||||
* @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 searchVNOTE($_vcalData, $_type, $contentID=null)
|
||||
function searchVNOTE($_vcalData, $_type, $contentID=null, $relax=false)
|
||||
{
|
||||
if (!($note = $this->vnotetoegw($_vcalData,$_type,$contentID))) return false;
|
||||
if (!($note = $this->vnotetoegw($_vcalData,$_type,$contentID))) return array();
|
||||
|
||||
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['col_filter'] = $note;
|
||||
|
||||
if (($foundItems = $this->search($filter)))
|
||||
{
|
||||
if (count($foundItems) > 0)
|
||||
{
|
||||
$itemIDs = array_keys($foundItems);
|
||||
return $itemIDs[0];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return $this->findInfo($note, $relax, $this->tzid);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -730,6 +808,13 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
function vnotetoegw($_data, $_type, $_noteID=-1)
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_type, $_noteID)\n" .
|
||||
array2string($_data)."\n",3,$this->logfile);
|
||||
}
|
||||
$note = false;
|
||||
|
||||
switch ($_type)
|
||||
{
|
||||
case 'text/plain':
|
||||
@ -739,19 +824,15 @@ class infolog_ical extends infolog_bo
|
||||
$txt = $botranslation->convert($_data, 'utf-8');
|
||||
$txt = str_replace("\r\n", "\n", $txt);
|
||||
|
||||
if (preg_match("/^(^\n)\n\n(.*)$/", $txt, $match))
|
||||
if (preg_match('/([^\n]+)\n\n(.*)/m', $txt, $match))
|
||||
{
|
||||
$note['info_subject'] = $match[0];
|
||||
$note['info_des'] = $match[1];
|
||||
$note['info_subject'] = $match[1];
|
||||
$note['info_des'] = $match[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
// should better be imported as subject, but causes duplicates
|
||||
// TODO: should be examined
|
||||
$note['info_des'] = $txt;
|
||||
$note['info_subject'] = $txt;
|
||||
}
|
||||
|
||||
return $note;
|
||||
break;
|
||||
|
||||
case 'text/x-vnote':
|
||||
@ -772,35 +853,32 @@ class infolog_ical extends infolog_bo
|
||||
switch ($attribute['name'])
|
||||
{
|
||||
case 'BODY':
|
||||
$note['info_des'] = $attribute['value'];
|
||||
$note['info_des'] = str_replace("\r\n", "\n", $attribute['value']);
|
||||
break;
|
||||
|
||||
case 'SUMMARY':
|
||||
$note['info_subject'] = $attribute['value'];
|
||||
$note['info_subject'] = str_replace("\r\n", "\n", $attribute['value']);
|
||||
break;
|
||||
|
||||
case 'CATEGORIES':
|
||||
if ($attribute['value'])
|
||||
{
|
||||
if($version == '1.0')
|
||||
{
|
||||
$cats = $this->find_or_add_categories(explode(';',$attribute['value']), $_noteID);
|
||||
}
|
||||
else
|
||||
{
|
||||
$cats = $this->find_or_add_categories(explode(',',$attribute['value']), $_noteID);
|
||||
}
|
||||
$note['info_cat'] = $cats[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_type, $_noteID)\n" .
|
||||
($note ? array2string($note) : 'FALSE') ."\n",3,$this->logfile);
|
||||
}
|
||||
return $note;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the supported fields
|
||||
@ -842,9 +920,36 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
$this->uidExtension = true;
|
||||
}
|
||||
if (isset($deviceInfo['tzid']) &&
|
||||
$deviceInfo['tzid'])
|
||||
{
|
||||
switch ($deviceInfo['tzid'])
|
||||
{
|
||||
case 1:
|
||||
$this->tzid = false;
|
||||
break;
|
||||
case 2:
|
||||
$this->tzid = null;
|
||||
break;
|
||||
default:
|
||||
$this->tzid = $deviceInfo['tzid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage('setSupportedFields(' . $this->productManufacturer . ', ' . $this->productName .')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
'(' . $this->productManufacturer .
|
||||
', '. $this->productName .', ' .
|
||||
($this->tzid ? $this->tzid : egw_time::$user_timezone->getName()) .
|
||||
")\n" , 3, $this->logfile);
|
||||
}
|
||||
|
||||
Horde::logMessage('setSupportedFields(' . $this->productManufacturer . ', '
|
||||
. $this->productName .', ' .
|
||||
($this->tzid ? $this->tzid : egw_time::$user_timezone->getName()) .')',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,65 @@ class infolog_sif extends infolog_bo
|
||||
*/
|
||||
var $uidExtension = false;
|
||||
|
||||
/**
|
||||
* user preference: Use this timezone for import from and export to device
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $tzid = null;
|
||||
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $log = false;
|
||||
var $logfile="/tmp/log-infolog-sif";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
if ($this->log) $this->logfile = $GLOBALS['egw_info']['server']['temp_dir']."/log-infolog-sif";
|
||||
$this->vCalendar = new Horde_iCalendar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DateTime value for a given time and timezone
|
||||
*
|
||||
* @param int|string|DateTime $time in server-time as returned by calendar_bo for $data_format='server'
|
||||
* @param string $tzid TZID of event or 'UTC' or NULL for palmos timestamps in usertime
|
||||
* @return mixed attribute value to set: integer timestamp if $tzid == 'UTC' otherwise Ymd\THis string IN $tzid
|
||||
*/
|
||||
function getDateTime($time, $tzid)
|
||||
{
|
||||
if (empty($tzid) || $tzid == 'UTC')
|
||||
{
|
||||
return $this->vCalendar->_exportDateTime(egw_time::to($time,'ts'));
|
||||
}
|
||||
if (!is_a($time,'DateTime'))
|
||||
{
|
||||
$time = new egw_time($time,egw_time::$server_timezone);
|
||||
}
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
{
|
||||
self::$tz_cache[$tzid] = calendar_timezones::DateTimeZone($tzid);
|
||||
}
|
||||
// check for date --> export it as such
|
||||
if ($time->format('Hi') == '0000')
|
||||
{
|
||||
$arr = egw_time::to($time, 'array');
|
||||
$time = new egw_time($arr, self::$tz_cache[$tzid]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$time->setTimezone(self::$tz_cache[$tzid]);
|
||||
}
|
||||
return $time->format('Ymd\THis');
|
||||
}
|
||||
|
||||
function startElement($_parser, $_tag, $_attributes)
|
||||
{
|
||||
@ -121,14 +180,15 @@ class infolog_sif extends infolog_bo
|
||||
*/
|
||||
function siftoegw($sifData, $_sifType, $_id=-1)
|
||||
{
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_sifType, $_id)\n" .
|
||||
array2string($sifData) . "\n", 3, $this->logfile);
|
||||
}
|
||||
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
|
||||
#$tmpfname = tempnam('/tmp/sync/contents','sift_');
|
||||
|
||||
#$handle = fopen($tmpfname, "w");
|
||||
#fwrite($handle, $sifData);
|
||||
#fclose($handle);
|
||||
|
||||
switch ($_sifType)
|
||||
{
|
||||
case 'note':
|
||||
@ -136,9 +196,12 @@ class infolog_sif extends infolog_bo
|
||||
break;
|
||||
|
||||
case 'task':
|
||||
default:
|
||||
$this->_currentSIFMapping = $this->_sifTaskMapping;
|
||||
break;
|
||||
|
||||
default:
|
||||
// we don't know how to handle this
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->xml_parser = xml_parser_create('UTF-8');
|
||||
@ -156,16 +219,22 @@ class infolog_sif extends infolog_bo
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!array($this->_extractedSIFData)) return false;
|
||||
if (!array($this->_extractedSIFData))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()[PARSER FAILD]\n",
|
||||
3, $this->logfile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$infoData = array();
|
||||
|
||||
switch ($_sifType)
|
||||
{
|
||||
case 'task':
|
||||
$taskData = array();
|
||||
$vcal = new Horde_iCalendar;
|
||||
|
||||
$taskData['info_type'] = 'task';
|
||||
$taskData['info_status'] = 'not-started';
|
||||
$infoData['info_type'] = 'task';
|
||||
$infoData['info_status'] = 'not-started';
|
||||
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
@ -186,7 +255,7 @@ class infolog_sif extends infolog_bo
|
||||
switch($key)
|
||||
{
|
||||
case 'info_access':
|
||||
$taskData[$key] = ((int)$value > 0) ? 'private' : 'public';
|
||||
$infoData[$key] = ((int)$value > 0) ? 'private' : 'public';
|
||||
break;
|
||||
|
||||
case 'info_datecompleted':
|
||||
@ -194,9 +263,9 @@ class infolog_sif extends infolog_bo
|
||||
case 'info_startdate':
|
||||
if (!empty($value))
|
||||
{
|
||||
$taskData[$key] = $vcal->_parseDateTime($value);
|
||||
$infoData[$key] = $this->vCalendar->_parseDateTime($value);
|
||||
// somehow the client always deliver a timestamp about 3538 seconds, when no startdate set.
|
||||
if ($taskData[$key] < 10000) unset($taskData[$key]);
|
||||
if ($infoData[$key] < 10000) unset($infoData[$key]);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -205,49 +274,48 @@ class infolog_sif extends infolog_bo
|
||||
if (!empty($value))
|
||||
{
|
||||
$categories = $this->find_or_add_categories(explode(';', $value), $_id);
|
||||
$taskData['info_cat'] = $categories[0];
|
||||
$infoData['info_cat'] = $categories[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'info_priority':
|
||||
$taskData[$key] = (int)$value;
|
||||
$infoData[$key] = (int)$value;
|
||||
break;
|
||||
|
||||
case 'info_status':
|
||||
switch ($value)
|
||||
{
|
||||
case '0':
|
||||
$taskData[$key] = 'not-started';
|
||||
$infoData[$key] = 'not-started';
|
||||
break;
|
||||
case '1':
|
||||
$taskData[$key] = 'ongoing';
|
||||
$infoData[$key] = 'ongoing';
|
||||
break;
|
||||
case '2':
|
||||
$taskData[$key] = 'done';
|
||||
$taskData['info_percent'] = 100;
|
||||
$infoData[$key] = 'done';
|
||||
$infoData['info_percent'] = 100;
|
||||
break;
|
||||
case '3':
|
||||
$taskData[$key] = 'waiting';
|
||||
$infoData[$key] = 'waiting';
|
||||
break;
|
||||
case '4':
|
||||
if ($this->productName == 'blackberry plug-in')
|
||||
{
|
||||
$taskData[$key] = 'deferred';
|
||||
$infoData[$key] = 'deferred';
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData[$key] = 'cancelled';
|
||||
$infoData[$key] = 'cancelled';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$taskData[$key] = 'ongoing';
|
||||
break;
|
||||
$infoData[$key] = 'ongoing';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'complete':
|
||||
$taskData['info_status'] = 'done';
|
||||
$taskData['info_percent'] = 100;
|
||||
$infoData['info_status'] = 'done';
|
||||
$infoData['info_percent'] = 100;
|
||||
break;
|
||||
|
||||
case 'info_des':
|
||||
@ -256,7 +324,7 @@ class infolog_sif extends infolog_bo
|
||||
{
|
||||
if (strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_uid'] = $matches[1];
|
||||
$infoData['info_uid'] = $matches[1];
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
@ -264,25 +332,28 @@ class infolog_sif extends infolog_bo
|
||||
{
|
||||
if (strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_id_parent'] = $this->getParentID($matches[1]);
|
||||
$infoData['info_id_parent'] = $this->getParentID($matches[1]);
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
|
||||
default:
|
||||
$taskData[$key] = $value;
|
||||
break;
|
||||
$infoData[$key] = str_replace("\r\n", "\n", $value);
|
||||
}
|
||||
#error_log("infolog task key=$key => value=" . $taskData[$key]);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
"key=$key => value=" . $infoData[$key] . "\n", 3, $this->logfile);
|
||||
}
|
||||
}
|
||||
if (empty($infoData['info_datecompleted']))
|
||||
{
|
||||
$infoData['info_datecompleted'] = 0;
|
||||
}
|
||||
|
||||
return $taskData;
|
||||
break;
|
||||
|
||||
case 'note':
|
||||
$noteData = array();
|
||||
$noteData['info_type'] = 'note';
|
||||
$vcal = new Horde_iCalendar;
|
||||
$infoData['info_type'] = 'note';
|
||||
|
||||
foreach ($this->_extractedSIFData as $key => $value)
|
||||
{
|
||||
@ -295,13 +366,13 @@ class infolog_sif extends infolog_bo
|
||||
case 'info_startdate':
|
||||
if (!empty($value))
|
||||
{
|
||||
$noteData[$key] = $vcal->_parseDateTime($value);
|
||||
$infoData[$key] = $this->vCalendar->_parseDateTime($value);
|
||||
// somehow the client always deliver a timestamp about 3538 seconds, when no startdate set.
|
||||
if ($noteData[$key] < 10000) $noteData[$key] = '';
|
||||
if ($infoData[$key] < 10000) $infoData[$key] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$noteData[$key] = '';
|
||||
$infoData[$key] = '';
|
||||
}
|
||||
break;
|
||||
|
||||
@ -309,24 +380,27 @@ class infolog_sif extends infolog_bo
|
||||
if (!empty($value))
|
||||
{
|
||||
$categories = $this->find_or_add_categories(explode(';', $value), $_id);
|
||||
$noteData['info_cat'] = $categories[0];
|
||||
$infoData['info_cat'] = $categories[0];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$noteData[$key] = $value;
|
||||
break;
|
||||
$infoData[$key] = str_replace("\r\n", "\n", $value);
|
||||
}
|
||||
#error_log("infolog note key=$key => value=".$noteData[$key]);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
"key=$key => value=" . $infoData[$key] . "\n", 3, $this->logfile);
|
||||
}
|
||||
return $noteData;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($infoData) . "\n", 3, $this->logfile);
|
||||
}
|
||||
return $infoData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for SIF data a matching infolog entry
|
||||
@ -339,28 +413,13 @@ class infolog_sif extends infolog_bo
|
||||
*/
|
||||
function searchSIF($_sifData, $_sifType, $contentID=null, $relax=false)
|
||||
{
|
||||
if (!($egwData = $this->siftoegw($_sifData, $_sifType, $contentID))) return false;
|
||||
if (!($egwData = $this->siftoegw($_sifData, $_sifType, $contentID))) return array();
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return $this->findInfo($egwData, $relax, $this->tzid);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -373,18 +432,20 @@ class infolog_sif extends infolog_bo
|
||||
*/
|
||||
function addSIF($_sifData, $_id, $_sifType, $merge=false)
|
||||
{
|
||||
if (!($egwData = $this->siftoegw($_sifData, $_sifType, $_id))) return false;
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($this->tzid);
|
||||
}
|
||||
$egwData = $this->siftoegw($_sifData, $_sifType, $_id);
|
||||
if ($this->tzid)
|
||||
{
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
if (!$egwData) return false;
|
||||
|
||||
if ($_id > 0) $egwData['info_id'] = $_id;
|
||||
|
||||
if (empty($taskData['info_datecompleted']))
|
||||
{
|
||||
$taskData['info_datecompleted'] = 0;
|
||||
}
|
||||
|
||||
$egwID = $this->write($egwData, false, true, false);
|
||||
|
||||
return $egwID;
|
||||
return $this->write($egwData, true, true, false);
|
||||
}
|
||||
|
||||
|
||||
@ -399,29 +460,27 @@ class infolog_sif extends infolog_bo
|
||||
{
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
|
||||
if (!($infoData = $this->read($_id, true, 'server'))) return false;
|
||||
|
||||
switch($_sifType)
|
||||
{
|
||||
case 'task':
|
||||
if (($taskData = $this->read($_id, true, 'server')))
|
||||
if ($infoData['info_id_parent'])
|
||||
{
|
||||
$vcal = new Horde_iCalendar('1.0');
|
||||
|
||||
if ($taskData['info_id_parent'])
|
||||
{
|
||||
$parent = $this->read($taskData['info_id_parent']);
|
||||
$taskData['info_id_parent'] = $parent['info_uid'];
|
||||
$parent = $this->read($infoData['info_id_parent']);
|
||||
$infoData['info_id_parent'] = $parent['info_uid'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_id_parent'] = '';
|
||||
$infoData['info_id_parent'] = '';
|
||||
}
|
||||
|
||||
if (!preg_match('/\[UID:.+\]/m', $taskData['info_des']))
|
||||
if (!preg_match('/\[UID:.+\]/m', $infoData['info_des']))
|
||||
{
|
||||
$taskData['info_des'] .= "\r\n[UID:" . $taskData['info_uid'] . "]";
|
||||
if ($taskData['info_id_parent'] != '')
|
||||
$infoData['info_des'] .= "\r\n[UID:" . $infoData['info_uid'] . "]";
|
||||
if ($infoData['info_id_parent'] != '')
|
||||
{
|
||||
$taskData['info_des'] .= "\r\n[PARENT_UID:" . $taskData['info_id_parent'] . "]";
|
||||
$infoData['info_des'] .= "\r\n[PARENT_UID:" . $infoData['info_id_parent'] . "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,7 +490,7 @@ class infolog_sif extends infolog_bo
|
||||
{
|
||||
if (empty($egwField)) continue;
|
||||
|
||||
$value = $GLOBALS['egw']->translation->convert($taskData[$egwField], $sysCharSet, 'utf-8');
|
||||
$value = $GLOBALS['egw']->translation->convert($infoData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
switch ($sifField)
|
||||
{
|
||||
@ -441,37 +500,21 @@ class infolog_sif extends infolog_bo
|
||||
break;
|
||||
|
||||
case 'DateCompleted':
|
||||
if ($taskData[info_status] == 'done')
|
||||
{
|
||||
$sifTask .= "<Complete>1</Complete>";
|
||||
}
|
||||
else
|
||||
if ($infoData[info_status] != 'done')
|
||||
{
|
||||
$sifTask .= "<DateCompleted></DateCompleted><Complete>0</Complete>";
|
||||
continue;
|
||||
}
|
||||
$sifTask .= "<Complete>1</Complete>";
|
||||
|
||||
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':
|
||||
$sifTask .= '<$sifField>';
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = $vcal->_exportDateTime($value);
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sifTask .= "<$sifField></$sifField>";
|
||||
$sifTask .= $this->getDateTime($value, $this->tzid);
|
||||
}
|
||||
$sifTask .= '</$sifField>';
|
||||
break;
|
||||
|
||||
case 'Importance':
|
||||
@ -530,30 +573,25 @@ class infolog_sif extends infolog_bo
|
||||
}
|
||||
$sifTask .= '<ActualWork>0</ActualWork><IsRecurring>0</IsRecurring></task>';
|
||||
return $sifTask;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'note':
|
||||
if (($taskData = $this->read($_id, true, 'server')))
|
||||
{
|
||||
$vcal = new Horde_iCalendar('1.0');
|
||||
|
||||
$sifNote = self::xml_decl . "\n<note>" . self::SIF_decl;
|
||||
|
||||
foreach ($this->_sifNoteMapping as $sifField => $egwField)
|
||||
{
|
||||
if(empty($egwField)) continue;
|
||||
|
||||
$value = $GLOBALS['egw']->translation->convert($taskData[$egwField], $sysCharSet, 'utf-8');
|
||||
$value = $GLOBALS['egw']->translation->convert($infoData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
switch ($sifField)
|
||||
{
|
||||
case 'Date':
|
||||
$sifNote .= '<$sifField>';
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = $vcal->_exportDateTime($value);
|
||||
$sifNote .= $this->getDateTime($value, $this->tzid);
|
||||
}
|
||||
$sifNote .= "<$sifField>$value</$sifField>";
|
||||
$sifNote .= '</$sifField>';
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
@ -576,14 +614,9 @@ class infolog_sif extends infolog_bo
|
||||
$sifNote .= '</note>';
|
||||
return $sifNote;
|
||||
}
|
||||
break;
|
||||
|
||||
default;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the supported fields
|
||||
*
|
||||
@ -604,6 +637,21 @@ class infolog_sif extends infolog_bo
|
||||
{
|
||||
$this->uidExtension = true;
|
||||
}
|
||||
if (isset($deviceInfo['tzid']) &&
|
||||
$deviceInfo['tzid'])
|
||||
{
|
||||
switch ($deviceInfo['tzid'])
|
||||
{
|
||||
case 1:
|
||||
$this->tzid = false;
|
||||
break;
|
||||
case 2:
|
||||
$this->tzid = null;
|
||||
break;
|
||||
default:
|
||||
$this->tzid = $deviceInfo['tzid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
// store product name and version, to be able to use it elsewhere
|
||||
if ($_productName)
|
||||
|
Loading…
Reference in New Issue
Block a user