mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-05 21:49:28 +01:00
Infolog synchronization backport
This commit is contained in:
parent
1c6ca4eb7a
commit
19472152e6
@ -30,16 +30,27 @@ class infolog_bo
|
||||
var $vfs_basedir='/infolog';
|
||||
var $link_pathes = array();
|
||||
var $send_file_ips = array();
|
||||
|
||||
var $tz_offset = 0;
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $log = false;
|
||||
/**
|
||||
* 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 int
|
||||
*/
|
||||
var $tz_offset = 0;
|
||||
var $tz_offset_s = 0;
|
||||
/**
|
||||
* current time as timestamp in user-time and server-time
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
var $user_time_now;
|
||||
var $now;
|
||||
/**
|
||||
* name of timestamps in an InfoLog entry
|
||||
*
|
||||
@ -235,7 +246,8 @@ class infolog_bo
|
||||
|
||||
$this->tz_offset = $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
|
||||
$this->tz_offset_s = 60*60*$this->tz_offset;
|
||||
$this->user_time_now = time() + $this->tz_offset_s;
|
||||
$this->now = time();
|
||||
$this->user_time_now = $this->now + $this->tz_offset_s;
|
||||
|
||||
$this->grants = $GLOBALS['egw']->acl->get_grants('infolog',$this->group_owners ? $this->group_owners : true);
|
||||
$this->so = new infolog_so($this->grants);
|
||||
@ -411,9 +423,12 @@ class infolog_bo
|
||||
* @param int/array $info_id integer id or array with key 'info_id' of the entry to read
|
||||
* @param boolean $run_link_id2from=true should link_id2from run, default yes,
|
||||
* need to be set to false if called from link-title to prevent an infinit recursion
|
||||
* @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time,
|
||||
* 'array'=array or string with date-format
|
||||
*
|
||||
* @return array/boolean infolog entry, null if not found or false if no permission to read it
|
||||
*/
|
||||
function &read($info_id,$run_link_id2from=true)
|
||||
function &read($info_id,$run_link_id2from=true,$date_format='ts')
|
||||
{
|
||||
if (is_array($info_id))
|
||||
{
|
||||
@ -437,13 +452,32 @@ class infolog_bo
|
||||
}
|
||||
if ($run_link_id2from) $this->link_id2from($data);
|
||||
|
||||
// convert system- to user-time
|
||||
foreach($this->timestamps as $time)
|
||||
if ($data['info_enddate'])
|
||||
{
|
||||
if ($data[$time]) $data[$time] += $this->tz_offset_s;
|
||||
// Set due date to 00:00
|
||||
$data['info_enddate'] = mktime(0, 0, 0,
|
||||
date('m', $data['info_enddate']),
|
||||
date('d', $data['info_enddate']),
|
||||
date('Y', $data['info_enddate']));
|
||||
}
|
||||
|
||||
// convert server- to user-time
|
||||
if ($date_format == 'ts' && $this->tz_offset_s)
|
||||
{
|
||||
foreach ($this->timestamps as $time)
|
||||
{
|
||||
// we keep dates the same in user-time
|
||||
if ($data[$time] && date('Hi', $data[$time]) != '0000')
|
||||
{
|
||||
$data[$time] += $this->tz_offset_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($date_format == 'ts' || !$this->tz_offset_s)
|
||||
{
|
||||
// pre-cache title and file access
|
||||
self::set_link_cache($data);
|
||||
}
|
||||
// pre-cache title and file access
|
||||
self::set_link_cache($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
@ -488,7 +522,7 @@ class infolog_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!($info = $this->read($info_id))) return false; // should not happen
|
||||
if (!($info = $this->read($info_id, true, 'server'))) return false; // should not happen
|
||||
|
||||
$deleted = $info;
|
||||
$deleted['info_status'] = 'deleted';
|
||||
@ -532,9 +566,11 @@ class infolog_bo
|
||||
* @param array &$values values to write
|
||||
* @param boolean $check_defaults=true check and set certain defaults
|
||||
* @param boolean $touch_modified=true touch the modification data and sets the modiefier's user-id
|
||||
* @param boolean $user2server=true conversion between user- and server-time necessary
|
||||
*
|
||||
* @return int/boolean info_id on a successfull write or false
|
||||
*/
|
||||
function write(&$values, $check_defaults=True, $touch_modified=True)
|
||||
function write(&$values, $check_defaults=true, $touch_modified=true, $user2server=true)
|
||||
{
|
||||
//echo "boinfolog::write()values="; _debug_array($values);
|
||||
if ($status_only = $values['info_id'] && !$this->check_access($values['info_id'],EGW_ACL_EDIT))
|
||||
@ -572,13 +608,13 @@ class infolog_bo
|
||||
'info_id' => $values['info_id'],
|
||||
'info_datemodified' => $values['info_datemodified'],
|
||||
);
|
||||
foreach($this->responsible_edit as $name)
|
||||
foreach ($this->responsible_edit as $name)
|
||||
{
|
||||
if (isset($backup_values[$name])) $values[$name] = $backup_values[$name];
|
||||
}
|
||||
if ($set_completed)
|
||||
{
|
||||
$values['info_datecompleted'] = $this->user_time_now;
|
||||
$values['info_datecompleted'] = $user2server ? $this->user_time_now : $this->now;
|
||||
$values['info_percent'] = 100;
|
||||
$forcestatus = true;
|
||||
$status = 'done';
|
||||
@ -605,7 +641,7 @@ class infolog_bo
|
||||
if (!$values['info_datecompleted'] &&
|
||||
(in_array($values['info_status'],array('done','billed')) || (int)$values['info_percent'] == 100))
|
||||
{
|
||||
$values['info_datecompleted'] = $this->user_time_now; // set date completed to today if status == done
|
||||
$values['info_datecompleted'] = $user2server ? $this->user_time_now : $this->now; // set date completed to today if status == done
|
||||
}
|
||||
if (in_array($values['info_status'],array('done','billed')))
|
||||
{
|
||||
@ -651,43 +687,78 @@ class infolog_bo
|
||||
{
|
||||
$values['info_owner'] = $this->so->user;
|
||||
}
|
||||
|
||||
if ($info_from_set = ($values['info_link_id'] && isset($values['info_from']) && empty($values['info_from'])))
|
||||
{
|
||||
$values['info_from'] = $this->link_id2from($values);
|
||||
}
|
||||
|
||||
if ($status_only && !$undelete) $values = array_merge($backup_values,$values);
|
||||
|
||||
|
||||
if (isset($values['info_enddate']) && $values['info_enddate'])
|
||||
{
|
||||
// Set due date to 00:00
|
||||
$values['info_enddate'] = mktime(0, 0, 0,
|
||||
date('m', $values['info_enddate']),
|
||||
date('d', $values['info_enddate']),
|
||||
date('Y', $values['info_enddate']));
|
||||
}
|
||||
|
||||
$to_write = $values;
|
||||
if ($user2server)
|
||||
{
|
||||
// convert user- to server-time
|
||||
foreach ($this->timestamps as $time)
|
||||
{
|
||||
if ($to_write[$time] && date('Hi', $to_write[$time]) != '0000')
|
||||
{
|
||||
$to_write[$time] -= $this->tz_offset_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// convert server- to user-time
|
||||
foreach ($this->timestamps as $time)
|
||||
{
|
||||
if ($values[$time] && date('Hi', $values[$time]) != '0000')
|
||||
{
|
||||
$values[$time] += $this->tz_offset_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($touch_modified || !$values['info_datemodified'])
|
||||
{
|
||||
// Should only an entry be updated which includes the original modification date?
|
||||
// Used in the web-GUI to check against a modification by an other user while editing the entry.
|
||||
// It's now disabled for xmlrpc, as otherwise the xmlrpc code need to be changed!
|
||||
$xmlrpc = is_object($GLOBALS['server']) && $GLOBALS['server']->last_method;
|
||||
$check_modified = $values['info_datemodified'] && !$xmlrpc ? $values['info_datemodified']-$this->tz_offset_s : false;
|
||||
$check_modified = $values['info_datemodified'] && !$xmlrpc ? $to_write['info_datemodified'] : false;
|
||||
$values['info_datemodified'] = $this->user_time_now;
|
||||
$to_write['info_datemodified'] = $this->now;
|
||||
}
|
||||
if ($touch_modified || !$values['info_modifier'])
|
||||
{
|
||||
$values['info_modifier'] = $this->so->user;
|
||||
$to_write['info_modifier'] = $this->so->user;
|
||||
}
|
||||
//_debug_array($values);
|
||||
$to_write = $values;
|
||||
if ($status_only && !$undelete) $values = array_merge($backup_values,$values);
|
||||
// convert user- to system-time
|
||||
foreach($this->timestamps as $time)
|
||||
{
|
||||
if ($to_write[$time]) $to_write[$time] -= $this->tz_offset_s;
|
||||
}
|
||||
// error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n".array2string($values)."\n",3,'/tmp/infolog');
|
||||
|
||||
// we need to get the old values to update the links in customfields and for the tracking
|
||||
if ($values['info_id'])
|
||||
{
|
||||
$old = $this->read($values['info_id'],false);
|
||||
$old = $this->read($values['info_id'], false, 'server');
|
||||
}
|
||||
if(($info_id = $this->so->write($to_write,$check_modified)))
|
||||
if (($info_id = $this->so->write($to_write,$check_modified)))
|
||||
{
|
||||
if (!isset($values['info_type']) || $status_only)
|
||||
{
|
||||
$values = $this->read($info_id);
|
||||
$values = $this->read($info_id, true, 'server');
|
||||
}
|
||||
if($values['info_id'] && $old['info_status'] != 'deleted')
|
||||
if ($values['info_id'] && $old['info_status'] != 'deleted')
|
||||
{
|
||||
// update
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp(
|
||||
@ -704,11 +775,13 @@ class infolog_bo
|
||||
);
|
||||
}
|
||||
$values['info_id'] = $info_id;
|
||||
$to_write['info_id'] = $info_id;
|
||||
// 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 ;-)
|
||||
{
|
||||
$values['info_responsible'] = $values['info_responsible'] ? explode(',',$values['info_responsible']) : array();
|
||||
$to_write['info_responsible'] = $values['info_responsible'];
|
||||
}
|
||||
// create (and remove) links in custom fields
|
||||
customfields_widget::update_customfield_links('infolog',$values,$old,'info_id');
|
||||
@ -725,11 +798,12 @@ class infolog_bo
|
||||
$this->tracking = new infolog_tracking($this);
|
||||
}
|
||||
|
||||
if (($missing_fields = array_diff_key($old,$values)))
|
||||
if ($old && ($missing_fields = array_diff_key($old,$values)))
|
||||
{
|
||||
$values = array_merge($values,$missing_fields);
|
||||
$to_write = array_merge($to_write,$missing_fields);
|
||||
}
|
||||
$this->tracking->track($values,$old,$this->user,$values['info_status'] == 'deleted' || $old['info_status'] == 'deleted');
|
||||
$this->tracking->track($to_write,$old,$this->user,$values['info_status'] == 'deleted' || $old['info_status'] == 'deleted');
|
||||
}
|
||||
if ($info_from_set) $values['info_from'] = '';
|
||||
|
||||
@ -763,18 +837,43 @@ class infolog_bo
|
||||
function &search(&$query)
|
||||
{
|
||||
//echo "<p>boinfolog::search(".print_r($query,True).")</p>\n";
|
||||
if (!empty($query['start']))
|
||||
{
|
||||
$query['start'] -= $this->tz_offset_s;
|
||||
}
|
||||
|
||||
$ret = $this->so->search($query);
|
||||
|
||||
// convert system- to user-time
|
||||
|
||||
if (is_array($ret))
|
||||
{
|
||||
foreach($ret as $id => &$data)
|
||||
foreach ($ret as $id => &$data)
|
||||
{
|
||||
if($this->tz_offset_s)
|
||||
if (!$this->check_access($data,EGW_ACL_READ))
|
||||
{
|
||||
foreach($this->timestamps as $time)
|
||||
unset($ret[$id]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($data['info_enddate'])
|
||||
{
|
||||
// Set due date to 00:00
|
||||
$data['info_enddate'] = mktime(0, 0, 0,
|
||||
date('m', $data['info_enddate']),
|
||||
date('d', $data['info_enddate']),
|
||||
date('Y', $data['info_enddate']));
|
||||
}
|
||||
|
||||
if ($this->tz_offset_s)
|
||||
{
|
||||
// convert system- to user-time
|
||||
foreach ($this->timestamps as $time)
|
||||
{
|
||||
if ($data[$time]) $data[$time] += $this->tz_offset_s;
|
||||
// we keep dates the same in user-time
|
||||
if ($data[$time] && date('Hi', $data[$time]) != '0000')
|
||||
{
|
||||
$data[$time] += $this->tz_offset_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
// pre-cache title and file access
|
||||
@ -882,7 +981,7 @@ class infolog_bo
|
||||
* @param int/array $info int info_id or array with infolog entry
|
||||
* @return string/boolean string with the title, null if $info not found, false if no perms to view
|
||||
*/
|
||||
function link_title( $info )
|
||||
function link_title($info)
|
||||
{
|
||||
if (!is_array($info))
|
||||
{
|
||||
@ -901,16 +1000,16 @@ class infolog_bo
|
||||
*
|
||||
* @param array $ids
|
||||
*/
|
||||
function link_titles( array $ids )
|
||||
function link_titles(array $ids)
|
||||
{
|
||||
$titles = array();
|
||||
foreach($this->search($params=array(
|
||||
foreach ($this->search($params=array(
|
||||
'col_filter' => array('info_id' => $ids),
|
||||
)) as $info)
|
||||
{
|
||||
$titles[$info['info_id']] = $this->link_title($info);
|
||||
}
|
||||
foreach(array_diff($ids,array_keys($titles)) as $id)
|
||||
foreach (array_diff($ids,array_keys($titles)) as $id)
|
||||
{
|
||||
$titles[$id] = false; // we assume every not returned entry to be not readable, as we notify the link class about all deletes
|
||||
}
|
||||
@ -925,7 +1024,7 @@ class infolog_bo
|
||||
* @param string $pattern pattern to search
|
||||
* @return array with info_id - title pairs of the matching entries
|
||||
*/
|
||||
function link_query( $pattern )
|
||||
function link_query($pattern)
|
||||
{
|
||||
$query = array(
|
||||
'search' => $pattern,
|
||||
@ -936,7 +1035,7 @@ class infolog_bo
|
||||
$content = array();
|
||||
if (is_array($ids))
|
||||
{
|
||||
foreach($ids as $id => $info )
|
||||
foreach ($ids as $id => $info )
|
||||
{
|
||||
$content[$id] = $this->link_title($id);
|
||||
}
|
||||
@ -1006,7 +1105,7 @@ class infolog_bo
|
||||
}
|
||||
while ($infos = $this->search($query))
|
||||
{
|
||||
foreach($infos as $info)
|
||||
foreach ($infos as $info)
|
||||
{
|
||||
$time = (int) adodb_date('Hi',$info['info_startdate']);
|
||||
$date = adodb_date('Y/m/d',$info['info_startdate']);
|
||||
@ -1021,7 +1120,7 @@ class infolog_bo
|
||||
$info['info_subject'];
|
||||
$view = egw_link::view('infolog',$info['info_id']);
|
||||
$content=array();
|
||||
foreach($icons = array(
|
||||
foreach ($icons = array(
|
||||
$info['info_type'] => 'infolog',
|
||||
$this->status[$info['info_type']][$info['info_status']] => 'infolog',
|
||||
) as $name => $app)
|
||||
@ -1088,18 +1187,17 @@ class infolog_bo
|
||||
{
|
||||
$this->categories = new categories($this->user,'infolog');
|
||||
}
|
||||
|
||||
if($info_id && $info_id > 0)
|
||||
$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)
|
||||
if (is_array($old_categories) && count($old_categories) > 0)
|
||||
{
|
||||
foreach($old_categories as $cat_id)
|
||||
{
|
||||
if(!$this->categories->check_perms(EGW_ACL_READ, $cat_id))
|
||||
if ($cat_id && !$this->categories->check_perms(EGW_ACL_READ, $cat_id))
|
||||
{
|
||||
$old_cats_preserve[] = $cat_id;
|
||||
}
|
||||
@ -1108,7 +1206,7 @@ class infolog_bo
|
||||
}
|
||||
|
||||
$cat_id_list = array();
|
||||
foreach($catname_list as $cat_name)
|
||||
foreach ((array)$catname_list as $cat_name)
|
||||
{
|
||||
$cat_name = trim($cat_name);
|
||||
$cat_id = $this->categories->name2id($cat_name, 'X-');
|
||||
@ -1129,7 +1227,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);
|
||||
}
|
||||
@ -1230,19 +1328,19 @@ class infolog_bo
|
||||
{
|
||||
case 'notify_due_responsible':
|
||||
$info['message'] = lang('%1 you are responsible for is due at %2',$this->enums['type'][$info['info_type']],
|
||||
$this->tracking->datetime($info['info_enddate']-$this->tz_offset_s,false));
|
||||
$this->tracking->datetime($info['info_enddate'],false));
|
||||
break;
|
||||
case 'notify_due_delegated':
|
||||
$info['message'] = lang('%1 you delegated is due at %2',$this->enums['type'][$info['info_type']],
|
||||
$this->tracking->datetime($info['info_enddate']-$this->tz_offset_s,false));
|
||||
$this->tracking->datetime($info['info_enddate'],false));
|
||||
break;
|
||||
case 'notify_start_responsible':
|
||||
$info['message'] = lang('%1 you are responsible for is starting at %2',$this->enums['type'][$info['info_type']],
|
||||
$this->tracking->datetime($info['info_startdate']-$this->tz_offset_s,null));
|
||||
$this->tracking->datetime($info['info_startdate'],null));
|
||||
break;
|
||||
case 'notify_start_delegated':
|
||||
$info['message'] = lang('%1 you delegated is starting at %2',$this->enums['type'][$info['info_type']],
|
||||
$this->tracking->datetime($info['info_startdate']-$this->tz_offset_s,null));
|
||||
$this->tracking->datetime($info['info_startdate'],null));
|
||||
break;
|
||||
}
|
||||
//error_log("notifiying $user($email) about $info[info_subject]: $info[message]");
|
||||
@ -1359,109 +1457,319 @@ class infolog_bo
|
||||
|
||||
/**
|
||||
* Try to find a matching db entry
|
||||
* 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 boolean $user2server=true conversion between user- and server-time necessary
|
||||
*
|
||||
* @return array of infolog_ids of matching entries
|
||||
*/
|
||||
function findVTODO($egwData, $relax=false)
|
||||
function findInfo($infoData, $relax=false, $user2server=true)
|
||||
{
|
||||
if (!empty($egwData['info_uid']))
|
||||
{
|
||||
$filter = array('col_filter' => array('info_uid' => $egwData['info_uid']));
|
||||
if (($found = $this->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, ')
|
||||
. ($user2server ? 'USERTIME': 'SERVERTIME'). ')[InfoData]:'
|
||||
. array2string($infoData));
|
||||
}
|
||||
|
||||
if ($infoData['info_id']
|
||||
&& ($egwData = $this->read($infoData['info_id'], true, 'server')))
|
||||
{
|
||||
// we only do a simple consistency check
|
||||
if (!$relax || 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'])))
|
||||
{
|
||||
// We only do a simple consistency check
|
||||
if ($found['info_subject'] == $egwData['info_subject']
|
||||
&& strpos($found['info_des'], $description) === 0)
|
||||
if (preg_match_all('/[\x20-\x7F]*/m', $text, $matches, PREG_SET_ORDER))
|
||||
{
|
||||
return $found['info_id'];
|
||||
$text = '';
|
||||
foreach ($matches as $chunk)
|
||||
{
|
||||
if (strlen($text) < strlen($chunk[0]))
|
||||
{
|
||||
$text = $chunk[0];
|
||||
}
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "()[search]: $text");
|
||||
}
|
||||
$filter['search'] = $text;
|
||||
}
|
||||
}
|
||||
unset($egwData['info_id']);
|
||||
|
||||
// Set due date to 00:00
|
||||
$infoData['info_enddate'] = mktime(0, 0, 0,
|
||||
date('m', $infoData['info_enddate']),
|
||||
date('d', $infoData['info_enddate']),
|
||||
date('Y', $infoData['info_enddate']));
|
||||
|
||||
$filter['col_filter'] = $infoData;
|
||||
|
||||
if ($user2server)
|
||||
{
|
||||
// convert user- to server-time
|
||||
foreach($this->timestamps as $time)
|
||||
{
|
||||
if (isset($infoData[$time]) &&
|
||||
$infoData[$time] &&
|
||||
date('Hi', $infoData[$time]) != '0000')
|
||||
{
|
||||
$filter['col_filter'][$time] -= $this->tz_offset_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$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->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']);
|
||||
|
||||
#Horde::logMessage("findVTODO Filter\n"
|
||||
# . print_r($filter, true),
|
||||
# __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
foreach ($this->search($filter) as $itemID => $taskData) {
|
||||
# Horde::logMessage("findVTODO Trying\n"
|
||||
# . print_r($taskData, true),
|
||||
# __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (isset($egwData['info_cat'])
|
||||
&& isset($taskData['info_cat']) && $taskData['info_cat']
|
||||
&& $egwData['info_cat'] != $taskData['info_cat']) continue;
|
||||
if (isset($egwData['info_startdate'])
|
||||
&& isset($taskData['info_startdate']) && $taskData['info_startdate']) {
|
||||
$parts = @getdate($taskData['info_startdate']);
|
||||
$startdate = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
if ($egwData['info_startdate'] != $startdate) continue;
|
||||
// Horde::logMessage("findVTODO Filter\n"
|
||||
// . print_r($filter, true),
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
foreach ($this->so->search($filter) as $itemID => $egwData)
|
||||
{
|
||||
if (!$this->check_access($egwData,EGW_ACL_READ)) continue;
|
||||
// Horde::logMessage("findVTODO Trying\n"
|
||||
// . print_r($egwData, true),
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (isset($infoData['info_cat'])
|
||||
&& isset($egwData['info_cat']) && $egwData['info_cat']
|
||||
&& $infoData['info_cat'] != $egwData['info_cat'])
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[category mismatch]: '
|
||||
. $infoData['info_cat'] . ' <> ' . $egwData['info_cat']);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// some clients don't support DTSTART
|
||||
if (isset($egwData['info_startdate'])
|
||||
&& (!isset($taskData['info_startdate']) || !$taskData['info_startdate'])
|
||||
&& !$relax) continue;
|
||||
if (isset($egwData['info_datecompleted'])
|
||||
&& isset($taskData['info_datecompleted']) && $taskData['info_datecompleted']) {
|
||||
$parts = @getdate($taskData['info_datecompleted']);
|
||||
$enddate = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
if ($egwData['info_datecompleted'] != $enddate) continue;
|
||||
if (isset($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
|
||||
if (date('Ymd', $infoData['info_startdate']) != date('Ymd', $egwData['info_startdate']))
|
||||
{
|
||||
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 ((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);
|
||||
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
|
||||
if (date('Ymd', $infoData['info_enddate']) != date('Ymd', $egwData['info_enddate']))
|
||||
{
|
||||
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
|
||||
if (date('Ymd', $infoData['info_datecompleted']) != date('Ymd', $egwData['info_datecompleted']))
|
||||
{
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[FOUND]:' . array2string($foundInfoLogs));
|
||||
}
|
||||
return $foundInfoLogs;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* @package infolog
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007/8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
@ -70,6 +70,8 @@ class infolog_groupdav extends groupdav_handler
|
||||
*/
|
||||
function propfind($path,$options,&$files,$user,$id='')
|
||||
{
|
||||
$starttime = microtime(true);
|
||||
|
||||
// todo add a filter to limit how far back entries from the past get synced
|
||||
$filter = array(
|
||||
'info_type' => 'task',
|
||||
@ -77,7 +79,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
if ($id) $filter['info_id'] = $id; // propfind on a single id
|
||||
|
||||
// ToDo: add parameter to only return id & etag
|
||||
if (($tasks = $this->bo->search($params=array(
|
||||
if (($tasks =& $this->bo->search($params=array(
|
||||
'order' => 'info_datemodified',
|
||||
'sort' => 'DESC',
|
||||
'filter' => 'own', // filter my: entries user is responsible for,
|
||||
@ -85,7 +87,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
'col_filter' => $filter,
|
||||
))))
|
||||
{
|
||||
foreach($tasks as $task)
|
||||
foreach($tasks as &$task)
|
||||
{
|
||||
$files['files'][] = array(
|
||||
'path' => self::get_path($task),
|
||||
@ -100,6 +102,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($this->debug) error_log(__METHOD__."($path) took ".(microtime(true) - $starttime).' to return '.count($files['files']).' items');
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -178,7 +181,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
*/
|
||||
function read($id)
|
||||
{
|
||||
return $this->bo->read($id,false);
|
||||
return $this->bo->read($id,false,'server');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,7 +206,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
{
|
||||
if (!is_array($info))
|
||||
{
|
||||
$info = $this->bo->read($info);
|
||||
$info = $this->bo->read($info,true,'server');
|
||||
}
|
||||
if (!is_array($info) || !isset($info['info_id']) || !isset($info['info_datemodified']))
|
||||
{
|
||||
|
@ -241,7 +241,7 @@ class infolog_hooks
|
||||
),
|
||||
'cat_add_default' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Default categorie for new Infolog entries',
|
||||
'label' => 'Default category for new Infolog entries',
|
||||
'name' => 'cat_add_default',
|
||||
'values' => self::all_cats(),
|
||||
'help' => 'You can choose a categorie to be preselected, when you create a new Infolog entry',
|
||||
|
@ -20,23 +20,42 @@ require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
class infolog_ical extends infolog_bo
|
||||
{
|
||||
/**
|
||||
* @var array conversion of the priority egw => ical
|
||||
* @var array $priority_egw2ical conversion of the priority egw => ical
|
||||
*/
|
||||
var $egw_priority2vcal_priority = array(
|
||||
0 => 9, // low
|
||||
1 => 5, // normal
|
||||
2 => 3, // high
|
||||
3 => 1, // urgent
|
||||
var $priority_egw2ical = array(
|
||||
0 => 9, // low
|
||||
1 => 5, // normal
|
||||
2 => 3, // high
|
||||
3 => 1, // urgent
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array conversion of the priority ical => egw
|
||||
* @var array $priority_ical2egw conversion of the priority ical => egw
|
||||
*/
|
||||
var $vcal_priority2egw_priority = array(
|
||||
9 => 0, 8 => 0, 7 => 0, // low
|
||||
6 => 1, 5 => 1, 4 => 1, 0 => 1, // normal
|
||||
3 => 2, 2 => 2, // high
|
||||
1 => 3, // urgent
|
||||
var $priority_ical2egw = array(
|
||||
9 => 0, 8 => 0, 7 => 0, // low
|
||||
6 => 1, 5 => 1, 4 => 1, 0 => 1, // normal
|
||||
3 => 2, 2 => 2, // high
|
||||
1 => 3, // urgent
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array $priority_egw2funambol conversion of the priority egw => funambol
|
||||
*/
|
||||
var $priority_egw2funambol = array(
|
||||
0 => 0, // low
|
||||
1 => 1, // normal
|
||||
2 => 2, // high
|
||||
3 => 2, // urgent
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array $priority_funambol2egw conversion of the priority funambol => egw
|
||||
*/
|
||||
var $priority_funambol2egw = array(
|
||||
0 => 0, // low
|
||||
1 => 1, // normal
|
||||
2 => 3, // high
|
||||
);
|
||||
|
||||
/**
|
||||
@ -54,6 +73,13 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
var $uidExtension = false;
|
||||
|
||||
/**
|
||||
* user preference: use server timezone for exports to device
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $useServerTZ = false;
|
||||
|
||||
/**
|
||||
* Client CTCap Properties
|
||||
*
|
||||
@ -61,6 +87,15 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
var $clientProperties;
|
||||
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $log = false;
|
||||
var $logfile="/tmp/log-infolog-vcal";
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -69,7 +104,7 @@ class infolog_ical extends infolog_bo
|
||||
function __construct(&$_clientProperties = array())
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if ($this->log) $this->logfile = $GLOBALS['egw_info']['server']['temp_dir']."/log-infolog-vcal";
|
||||
$this->clientProperties = $_clientProperties;
|
||||
}
|
||||
|
||||
@ -83,7 +118,15 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
function exportVTODO($_taskID, $_version='2.0',$_method='PUBLISH')
|
||||
{
|
||||
$taskData = $this->read($_taskID);
|
||||
if ($this->useServerTZ)
|
||||
{
|
||||
$date_format = 'server';
|
||||
}
|
||||
else
|
||||
{
|
||||
$date_format = 'ts';
|
||||
}
|
||||
if (!($taskData = $this->read($_taskID, true, $date_format))) return false;
|
||||
|
||||
if ($taskData['info_id_parent'])
|
||||
{
|
||||
@ -116,10 +159,27 @@ class infolog_ical extends infolog_bo
|
||||
$taskData = $GLOBALS['egw']->translation->convert($taskData,
|
||||
$GLOBALS['egw']->translation->charset(), 'UTF-8');
|
||||
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($taskData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal->setAttribute('VERSION',$_version);
|
||||
$vcal->setAttribute('METHOD',$_method);
|
||||
|
||||
if ($this->useServerTZ)
|
||||
{
|
||||
$event = array('start' => $taskData['info_startdate'] ? $taskData['info_startdate'] : time());
|
||||
$serverTZ = calendar_ical::generate_vtimezone($event, $vcal);
|
||||
}
|
||||
else
|
||||
{
|
||||
$serverTZ = false;
|
||||
}
|
||||
|
||||
$vevent = Horde_iCalendar::newComponent('VTODO',$vcal);
|
||||
|
||||
if (!isset($this->clientProperties['SUMMARY']['Size']))
|
||||
@ -142,8 +202,14 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
$size = $this->clientProperties[$field]['Size'];
|
||||
$noTruncate = $this->clientProperties[$field]['NoTruncate'];
|
||||
#Horde::logMessage("VTODO $field Size: $size, NoTruncate: " .
|
||||
# ($noTruncate ? 'TRUE' : 'FALSE'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($this->log && $size > 0)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ .
|
||||
"() $field Size: $size, NoTruncate: " .
|
||||
($noTruncate ? 'TRUE' : 'FALSE') . "\n",3,$this->logfile);
|
||||
}
|
||||
//Horde::logMessage("VTODO $field Size: $size, NoTruncate: " .
|
||||
// ($noTruncate ? 'TRUE' : 'FALSE'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -155,55 +221,79 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
if ($noTruncate)
|
||||
{
|
||||
Horde::logMessage("VTODO $field omitted due to maximum size $size",
|
||||
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ .
|
||||
"() $field omitted due to maximum size $size\n",3,$this->logfile);
|
||||
}
|
||||
//Horde::logMessage("VTODO $field omitted due to maximum size $size",
|
||||
// __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue; // skip field
|
||||
}
|
||||
// truncate the value to size
|
||||
$value = substr($value, 0, $size -1);
|
||||
#Horde::logMessage("VTODO $field truncated to maximum size $size",
|
||||
# __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ .
|
||||
"() $field truncated to maximum size $size\n",3,$this->logfile);
|
||||
}
|
||||
//Horde::logMessage("VTODO $field truncated to maximum size $size",
|
||||
// __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
}
|
||||
|
||||
if (empty($value) && ($size < 0 || $noTruncate)) continue;
|
||||
|
||||
if ($field == 'RELATED-TO')
|
||||
{
|
||||
$options = array('RELTYPE' => 'PARENT');
|
||||
$options = array('RELTYPE' => 'PARENT');
|
||||
}
|
||||
else
|
||||
{
|
||||
$options = array();
|
||||
}
|
||||
|
||||
/*if(preg_match('/([\000-\012\015\016\020-\037\075])/', $value)) {
|
||||
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
||||
}*/
|
||||
if ($this->productManufacturer != 'groupdav'
|
||||
&& preg_match('/([\177-\377])/',$value))
|
||||
if (preg_match('/[^\x20-\x7F]/', $value))
|
||||
{
|
||||
$options['CHARSET'] = 'UTF-8';
|
||||
$options['CHARSET'] = 'UTF-8';
|
||||
switch ($this->productManufacturer)
|
||||
{
|
||||
case 'groupdav':
|
||||
if ($this->productName == 'kde')
|
||||
{
|
||||
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
||||
}
|
||||
else
|
||||
{
|
||||
$options['CHARSET'] = '';
|
||||
|
||||
if (preg_match('/([\000-\012\015\016\020-\037\075])/', $value))
|
||||
{
|
||||
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
||||
}
|
||||
else
|
||||
{
|
||||
$options['ENCODING'] = '';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'funambol':
|
||||
$options['ENCODING'] = 'FUNAMBOL-QP';
|
||||
}
|
||||
}
|
||||
$vevent->setAttribute($field, $value, $options);
|
||||
}
|
||||
|
||||
$dateOnly = false;
|
||||
|
||||
if ($taskData['info_startdate'])
|
||||
{
|
||||
$dateOnly = self::setDateOrTime($vevent, 'DTSTART', $taskData['info_startdate']);
|
||||
self::setDateOrTime($vevent, 'DTSTART', $taskData['info_startdate'], $serverTZ);
|
||||
}
|
||||
|
||||
if ($taskData['info_enddate'])
|
||||
{
|
||||
$parts = @getdate($taskData['info_enddate']);
|
||||
$value = @mktime(12, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
self::setDateOrTime($vevent, 'DUE', $value, $dateOnly);
|
||||
self::setDateOrTime($vevent, 'DUE', $taskData['info_enddate'], $serverTZ);
|
||||
}
|
||||
|
||||
if ($taskData['info_datecompleted'])
|
||||
{
|
||||
self::setDateOrTime($vevent, 'COMPLETED', $taskData['info_datecompleted']);
|
||||
self::setDateOrTime($vevent, 'COMPLETED', $taskData['info_datecompleted'], $serverTZ);
|
||||
}
|
||||
|
||||
$vevent->setAttribute('DTSTAMP',time());
|
||||
@ -214,16 +304,69 @@ class infolog_ical extends infolog_bo
|
||||
// we try to preserv the original infolog status as X-INFOLOG-STATUS, so we can restore it, if the user does not modify STATUS
|
||||
$vevent->setAttribute('X-INFOLOG-STATUS',$taskData['info_status']);
|
||||
$vevent->setAttribute('PERCENT-COMPLETE',$taskData['info_percent']);
|
||||
$vevent->setAttribute('PRIORITY',$this->egw_priority2vcal_priority[$taskData['info_priority']]);
|
||||
|
||||
if ($this->productManufacturer == 'funambol' &&
|
||||
(strpos($this->productName, 'outlook') !== false
|
||||
|| strpos($this->productName, 'pocket pc') !== false))
|
||||
{
|
||||
$priority = (int) $this->priority_egw2funambol[$taskData['info_priority']];
|
||||
}
|
||||
else
|
||||
{
|
||||
$priority = (int) $this->priority_egw2ical[$taskData['info_priority']];
|
||||
}
|
||||
$vevent->setAttribute('PRIORITY', $priority);
|
||||
|
||||
$vcal->addComponent($vevent);
|
||||
|
||||
$retval = $vcal->exportvCalendar();
|
||||
Horde::logMessage("exportVTODO:\n" . print_r($retval, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($retval)."\n",3,$this->logfile);
|
||||
}
|
||||
// Horde::logMessage("exportVTODO:\n" . print_r($retval, true),
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $time as timestamp
|
||||
* @param string $tzid=false timezone to use for client, false for user-time
|
||||
*/
|
||||
static function setDateOrTime(&$vevent, $attr, $time, $tzid=false)
|
||||
{
|
||||
$params = array();
|
||||
|
||||
// check for date --> export it as such
|
||||
if (date('Hi', $time) == '0000')
|
||||
{
|
||||
$value = array(
|
||||
'year' => date('Y', $time),
|
||||
'month' => date('m', $time),
|
||||
'mday' => date('d', $time));
|
||||
$params['VALUE'] = 'DATE';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$tzid || $tzid == 'UTC')
|
||||
{
|
||||
$value = $time;
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = date('Ymd\THis', $time);
|
||||
$params['TZID'] = $tzid;
|
||||
}
|
||||
|
||||
}
|
||||
$vevent->setAttribute($attr, $value, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a VTODO component of an iCal
|
||||
*
|
||||
@ -234,7 +377,7 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false)
|
||||
{
|
||||
if (!$taskData = $this->vtodotoegw($_vcalData,$_taskID)) return false;
|
||||
if (!($taskData = $this->vtodotoegw($_vcalData,$_taskID))) return false;
|
||||
|
||||
// we suppose that a not set status in a vtodo means that the task did not started yet
|
||||
if (empty($taskData['info_status']))
|
||||
@ -247,7 +390,13 @@ class infolog_ical extends infolog_bo
|
||||
$taskData['info_datecompleted'] = 0;
|
||||
}
|
||||
|
||||
return $this->write($taskData);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($taskData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
return $this->write($taskData, true, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -256,18 +405,22 @@ 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)))
|
||||
$taskData = $this->vtodotoegw($_vcalData,$contentID);
|
||||
|
||||
if ($taskData)
|
||||
{
|
||||
if ($contentID)
|
||||
{
|
||||
$egwData['info_id'] = $contentID;
|
||||
$taskData['info_id'] = $contentID;
|
||||
}
|
||||
$result = $this->findVTODO($egwData, $relax);
|
||||
$result = $this->findInfo($taskData, $relax, !$this->useServerTZ);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@ -281,8 +434,24 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
function vtodotoegw($_vcalData, $_taskID=-1)
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_taskID)\n" .
|
||||
array2string($_vcalData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
if (!($vcal->parsevCalendar($_vcalData))) return false;
|
||||
if (!($vcal->parsevCalendar($_vcalData)))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
"(): No vCalendar Container found!\n",3,$this->logfile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$version = $vcal->getAttribute('VERSION');
|
||||
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
@ -293,126 +462,146 @@ class infolog_ical extends infolog_bo
|
||||
$minimum_uid_length = 8;
|
||||
}
|
||||
|
||||
$components = $vcal->getComponents();
|
||||
$taskData = false;
|
||||
|
||||
foreach ($components as $component)
|
||||
foreach ($vcal->getComponents() as $component)
|
||||
{
|
||||
if (is_a($component, 'Horde_iCalendar_vtodo'))
|
||||
if (!is_a($component, 'Horde_iCalendar_vtodo'))
|
||||
{
|
||||
$taskData = array();
|
||||
$taskData['info_type'] = 'task';
|
||||
|
||||
if ($_taskID > 0)
|
||||
if ($this->log)
|
||||
{
|
||||
$taskData['info_id'] = $_taskID;
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
"(): Not a vTODO container, skipping...\n",3,$this->logfile);
|
||||
}
|
||||
foreach ($component->_attributes as $attributes)
|
||||
continue;
|
||||
}
|
||||
|
||||
$taskData = array();
|
||||
$taskData['info_type'] = 'task';
|
||||
|
||||
if ($_taskID > 0)
|
||||
{
|
||||
$taskData['info_id'] = $_taskID;
|
||||
}
|
||||
foreach ($component->_attributes as $attribute)
|
||||
{
|
||||
//$attribute['value'] = trim($attribute['value']);
|
||||
if (!strlen($attribute['value'])) continue;
|
||||
|
||||
switch ($attribute['name'])
|
||||
{
|
||||
//$attributes['value'] = trim($attributes['value']);
|
||||
if (empty($attributes['value'])) continue;
|
||||
switch ($attributes['name'])
|
||||
{
|
||||
case 'CLASS':
|
||||
$taskData['info_access'] = strtolower($attributes['value']);
|
||||
break;
|
||||
case 'CLASS':
|
||||
$taskData['info_access'] = strtolower($attribute['value']);
|
||||
break;
|
||||
|
||||
case 'DESCRIPTION':
|
||||
$value = $attributes['value'];
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $value, $matches))
|
||||
case 'DESCRIPTION':
|
||||
$value = str_replace("\r\n", "\n", $attribute['value']);
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (!isset($taskData['info_uid'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
if (!isset($taskData['info_uid'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_uid'] = $matches[1];
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
$taskData['info_uid'] = $matches[1];
|
||||
}
|
||||
if (preg_match('/\s*\[PARENT_UID:(.+)?\]/Usm', $value, $matches))
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
if (preg_match('/\s*\[PARENT_UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (!isset($taskData['info_id_parent'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
if (!isset($taskData['info_id_parent'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_id_parent'] = $this->getParentID($matches[1]);
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
$taskData['info_id_parent'] = $this->getParentID($matches[1]);
|
||||
}
|
||||
$taskData['info_des'] = $value;
|
||||
break;
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
$taskData['info_des'] = $value;
|
||||
break;
|
||||
|
||||
case 'LOCATION':
|
||||
$taskData['info_location'] = $attributes['value'];
|
||||
break;
|
||||
case 'LOCATION':
|
||||
$taskData['info_location'] = str_replace("\r\n", "\n", $attribute['value']);
|
||||
break;
|
||||
|
||||
case 'DUE':
|
||||
// eGroupWare uses date only
|
||||
$parts = @getdate($attributes['value']);
|
||||
$value = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
$taskData['info_enddate'] = $value;
|
||||
break;
|
||||
case 'DUE':
|
||||
// eGroupWare uses date only
|
||||
$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'];
|
||||
break;
|
||||
case 'COMPLETED':
|
||||
$taskData['info_datecompleted'] = $attribute['value'];
|
||||
break;
|
||||
|
||||
case 'DTSTART':
|
||||
$taskData['info_startdate'] = $attributes['value'];
|
||||
break;
|
||||
case 'DTSTART':
|
||||
$taskData['info_startdate'] = $attribute['value'];
|
||||
break;
|
||||
|
||||
case 'PRIORITY':
|
||||
if (1 <= $attributes['value'] && $attributes['value'] <= 9)
|
||||
case 'PRIORITY':
|
||||
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'] = $this->vcal_priority2egw_priority[$attributes['value']];
|
||||
$taskData['info_priority'] = (int) $this->priority_funambol2egw[$attribute['value']];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_priority'] = 1; // default = normal
|
||||
$taskData['info_priority'] = (int) $this->priority_ical2egw[$attribute['value']];
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_priority'] = 1; // default = normal
|
||||
}
|
||||
break;
|
||||
|
||||
case 'STATUS':
|
||||
// check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user)
|
||||
foreach($component->_attributes as $attr)
|
||||
{
|
||||
if ($attr['name'] == 'X-INFOLOG-STATUS') break;
|
||||
}
|
||||
$taskData['info_status'] = $this->vtodo2status($attributes['value'],
|
||||
$attr['name'] == 'X-INFOLOG-STATUS' ? $attr['value'] : null);
|
||||
break;
|
||||
case 'STATUS':
|
||||
// check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user)
|
||||
foreach ($component->_attributes as $attr)
|
||||
{
|
||||
if ($attr['name'] == 'X-INFOLOG-STATUS') break;
|
||||
}
|
||||
$taskData['info_status'] = $this->vtodo2status($attribute['value'],
|
||||
$attr['name'] == 'X-INFOLOG-STATUS' ? $attr['value'] : null);
|
||||
break;
|
||||
|
||||
case 'SUMMARY':
|
||||
$taskData['info_subject'] = $attributes['value'];
|
||||
break;
|
||||
case 'SUMMARY':
|
||||
$taskData['info_subject'] = str_replace("\r\n", "\n", $attribute['value']);
|
||||
break;
|
||||
|
||||
case 'RELATED-TO':
|
||||
$taskData['info_id_parent'] = $this->getParentID($attributes['value']);
|
||||
break;
|
||||
case 'RELATED-TO':
|
||||
$taskData['info_id_parent'] = $this->getParentID($attribute['value']);
|
||||
break;
|
||||
|
||||
case 'CATEGORIES':
|
||||
$cats = $this->find_or_add_categories(explode(',', $attributes['value']), $_taskID);
|
||||
case 'CATEGORIES':
|
||||
if (!empty($attribute['value']))
|
||||
{
|
||||
$cats = $this->find_or_add_categories(explode(',',$attribute['value']), $_taskID);
|
||||
$taskData['info_cat'] = $cats[0];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'UID':
|
||||
if (strlen($attributes['value']) >= $minimum_uid_length) {
|
||||
$taskData['info_uid'] = $attributes['value'];
|
||||
}
|
||||
break;
|
||||
case 'UID':
|
||||
if (strlen($attribute['value']) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_uid'] = $attribute['value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PERCENT-COMPLETE':
|
||||
$taskData['info_percent'] = (int) $attributes['value'];
|
||||
break;
|
||||
}
|
||||
case 'PERCENT-COMPLETE':
|
||||
$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);
|
||||
|
||||
return $taskData;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_taskID)\n" .
|
||||
($taskData ? array2string($taskData) : 'FALSE') . "\n",3,$this->logfile);
|
||||
}
|
||||
return $taskData;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -424,7 +613,8 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
function exportVNOTE($_noteID, $_type)
|
||||
{
|
||||
$note = $this->read($_noteID);
|
||||
if(!($note = $this->read($_noteID, true, 'server'))) return false;
|
||||
|
||||
$note = $GLOBALS['egw']->translation->convert($note,
|
||||
$GLOBALS['egw']->translation->charset(), 'UTF-8');
|
||||
|
||||
@ -433,78 +623,75 @@ 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']))
|
||||
{
|
||||
$cats = $this->get_categories(array($note['info_cat']));
|
||||
$note['info_cat'] = $GLOBALS['egw']->translation->convert($cats[0],
|
||||
$GLOBALS['egw']->translation->charset(), 'UTF-8');
|
||||
}
|
||||
$vnote = new Horde_iCalendar_vnote();
|
||||
$options = array('CHARSET' => 'UTF-8');
|
||||
$vNote->setAttribute('VERSION', '1.1');
|
||||
foreach (array( 'SUMMARY' => $note['info_subject'],
|
||||
'BODY' => $note['info_des'],
|
||||
foreach (array( 'SUMMARY' => $note['info_subject'],
|
||||
'BODY' => $note['info_des'],
|
||||
'CATEGORIES' => $note['info_cat'],
|
||||
) as $field => $value)
|
||||
{
|
||||
$vnote->setAttribute($field, $value);
|
||||
if ($this->productManufacturer != 'groupdav'
|
||||
&& preg_match('/([\177-\377])/', $value))
|
||||
$options = array();
|
||||
if (preg_match('/[^\x20-\x7F]/', $value))
|
||||
{
|
||||
$vevent->setParameter($field, $options);
|
||||
$options['CHARSET'] = 'UTF-8';
|
||||
switch ($this->productManufacturer)
|
||||
{
|
||||
case 'groupdav':
|
||||
if ($this->productName == 'kde')
|
||||
{
|
||||
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
||||
}
|
||||
else
|
||||
{
|
||||
$options['CHARSET'] = '';
|
||||
|
||||
if (preg_match('/([\000-\012\015\016\020-\037\075])/', $value))
|
||||
{
|
||||
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
||||
}
|
||||
else
|
||||
{
|
||||
$options['ENCODING'] = '';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'funambol':
|
||||
$options['ENCODING'] = 'FUNAMBOL-QP';
|
||||
}
|
||||
}
|
||||
$vevent->setAttribute($field, $value, $options);
|
||||
}
|
||||
if ($note['info_startdate'])
|
||||
{
|
||||
$vnote->setAttribute('DCREATED',$note['info_startdate']);
|
||||
}
|
||||
$vnote->setAttribute('DCREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'add'));
|
||||
$vnote->setAttribute('LAST-MODIFIED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'modify'));
|
||||
|
||||
if (!empty($note['info_cat']))
|
||||
else
|
||||
{
|
||||
$cats = $this->get_categories(array($note['info_cat']));
|
||||
$value = $cats[0];
|
||||
$vnote->setAttribute('CATEGORIES', $value);
|
||||
if ($this->productManufacturer != 'groupdav'
|
||||
&& preg_match('/([\177-\377])/', $value))
|
||||
{
|
||||
$vevent->setParameter('CATEGORIES', $options);
|
||||
}
|
||||
$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');
|
||||
|
||||
return $vnote->exportvCalendar();
|
||||
break;
|
||||
$retval = $vnote->exportvCalendar();
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($retval)."\n",3,$this->logfile);
|
||||
}
|
||||
return $retval;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether to export a date or date+time
|
||||
*
|
||||
* @param Horde_iCalendar_* $vevent
|
||||
* @param string $attr attribute name
|
||||
* @param int $value timestamp
|
||||
* @param boolean $force=false, set DATE in any case
|
||||
* @return boolean true, if date only
|
||||
*/
|
||||
static function setDateOrTime($vevent,$attr,$value,$force=false)
|
||||
{
|
||||
if ($force || date('Hi', $value) == '0000')
|
||||
{
|
||||
$vevent->setAttribute($attr, array(
|
||||
'year' => date('Y', $value),
|
||||
'month' => date('m', $value),
|
||||
'mday' => date('d', $value),
|
||||
), array('VALUE' => 'DATE'));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$vevent->setAttribute($attr, $value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Import a VNOTE component of an iCal
|
||||
*
|
||||
@ -516,14 +703,25 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
function importVNOTE(&$_vcalData, $_type, $_noteID=-1, $merge=false)
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($_vcalData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
if (!($note = $this->vnotetoegw($_vcalData, $_type, $_noteID))) return false;
|
||||
|
||||
if($_noteID > 0) $note['info_id'] = $_noteID;
|
||||
|
||||
if (empty($note['info_status'])) $note['info_status'] = 'done';
|
||||
|
||||
#_debug_array($taskData);exit;
|
||||
return $this->write($note);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($note)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
return $this->write($note, true, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -531,40 +729,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->useServerTZ);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -577,6 +754,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':
|
||||
@ -586,24 +770,21 @@ 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':
|
||||
$vnote = new Horde_iCalendar;
|
||||
if (!$vcal->parsevCalendar($_data)) return false;
|
||||
$version = $vcal->getAttribute('VERSION');
|
||||
|
||||
$components = $vnote->getComponent();
|
||||
foreach ($components as $component)
|
||||
@ -618,24 +799,31 @@ 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':
|
||||
$cats = $this->find_or_add_categories(explode(',', $attribute['value']), $_noteID);
|
||||
$note['info_cat'] = $cats[0];
|
||||
if ($attribute['value'])
|
||||
{
|
||||
$cats = $this->find_or_add_categories(explode(',',$attribute['value']), $_noteID);
|
||||
$note['info_cat'] = $cats[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $note;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_type, $_noteID)\n" .
|
||||
($note ? array2string($note) : 'FALSE') ."\n",3,$this->logfile);
|
||||
}
|
||||
return $note;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -678,9 +866,31 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
$this->uidExtension = true;
|
||||
}
|
||||
if (isset($deviceInfo['tzid']) &&
|
||||
$deviceInfo['tzid'])
|
||||
{
|
||||
$this->useServerTZ = ($deviceInfo['tzid'] == 1);
|
||||
}
|
||||
}
|
||||
|
||||
Horde::logMessage('setSupportedFields(' . $this->productManufacturer . ', ' . $this->productName .')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (in_array($this->productManufacturer,array('file','groupdav')))
|
||||
{
|
||||
$this->useServerTZ = true;
|
||||
}
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
'(' . $this->productManufacturer .
|
||||
', '. $this->productName .', ' .
|
||||
($this->useServerTZ ? 'SERVERTIME' : 'USERTIME') .
|
||||
")\n" , 3, $this->logfile);
|
||||
}
|
||||
|
||||
Horde::logMessage('setSupportedFields(' . $this->productManufacturer . ', '
|
||||
. $this->productName .', ' .
|
||||
($this->useServerTZ ? 'SERVERTIME' : 'USERTIME') .')',
|
||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,59 @@ class infolog_sif extends infolog_bo
|
||||
*/
|
||||
var $uidExtension = false;
|
||||
|
||||
/**
|
||||
* user preference: use server timezone for exports to device
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $useServerTZ = false;
|
||||
|
||||
/**
|
||||
* 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 $servertime=false if true => export in server-time
|
||||
*
|
||||
*/
|
||||
function getDateTime($time, $servertime=false)
|
||||
{
|
||||
// check for date --> export it as such
|
||||
if (date('Hi', $time) == '0000')
|
||||
{
|
||||
$value = date('Y-m-d', $time);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($servertime)
|
||||
{
|
||||
$value = date('Ymd\THis', $time);
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $this->vCalendar->_exportDateTime($time);
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
function startElement($_parser, $_tag, $_attributes)
|
||||
{
|
||||
@ -121,14 +174,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 +190,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 +213,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 +249,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 +257,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;
|
||||
|
||||
@ -204,53 +267,49 @@ class infolog_sif extends infolog_bo
|
||||
case 'info_cat':
|
||||
if (!empty($value))
|
||||
{
|
||||
$categories1 = explode(',', $value);
|
||||
$categories2 = explode(';', $value);
|
||||
$categories = count($categories1) > count($categories2) ? $categories1 : $categories2;
|
||||
$categories = $this->find_or_add_categories($categories, $_id);
|
||||
$taskData['info_cat'] = $categories[0];
|
||||
$categories = $this->find_or_add_categories(explode(';', $value), $_id);
|
||||
$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':
|
||||
@ -259,7 +318,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);
|
||||
}
|
||||
@ -267,25 +326,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);
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
"key=$key => value=" . $infoData[$key] . "\n", 3, $this->logfile);
|
||||
}
|
||||
#error_log("infolog task key=$key => value=" . $taskData[$key]);
|
||||
}
|
||||
|
||||
return $taskData;
|
||||
if (empty($infoData['info_datecompleted']))
|
||||
{
|
||||
$infoData['info_datecompleted'] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'note':
|
||||
$noteData = array();
|
||||
$noteData['info_type'] = 'note';
|
||||
$vcal = new Horde_iCalendar;
|
||||
$infoData['info_type'] = 'note';
|
||||
|
||||
foreach ($this->_extractedSIFData as $key => $value)
|
||||
{
|
||||
@ -298,40 +360,40 @@ 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;
|
||||
|
||||
case 'info_cat':
|
||||
if (!empty($value))
|
||||
{
|
||||
$categories1 = explode(',', $value);
|
||||
$categories2 = explode(';', $value);
|
||||
$categories = count($categories1) > count($categories2) ? $categories1 : $categories2;
|
||||
$categories = $this->find_or_add_categories($categories, $_id);
|
||||
$noteData['info_cat'] = $categories[0];
|
||||
$categories = $this->find_or_add_categories(explode(';', $value), $_id);
|
||||
$infoData['info_cat'] = $categories[0];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$noteData[$key] = $value;
|
||||
break;
|
||||
$infoData[$key] = str_replace("\r\n", "\n", $value);
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
"key=$key => value=" . $infoData[$key] . "\n", 3, $this->logfile);
|
||||
}
|
||||
#error_log("infolog note key=$key => value=".$noteData[$key]);
|
||||
}
|
||||
return $noteData;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($infoData) . "\n", 3, $this->logfile);
|
||||
}
|
||||
return $infoData;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -345,28 +407,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -379,18 +426,12 @@ class infolog_sif extends infolog_bo
|
||||
*/
|
||||
function addSIF($_sifData, $_id, $_sifType, $merge=false)
|
||||
{
|
||||
|
||||
if (!($egwData = $this->siftoegw($_sifData, $_sifType, $_id))) return false;
|
||||
|
||||
if ($_id > 0) $egwData['info_id'] = $_id;
|
||||
|
||||
if (empty($taskData['info_datecompleted']))
|
||||
{
|
||||
$taskData['info_datecompleted'] = 0;
|
||||
}
|
||||
|
||||
$egwID = $this->write($egwData, false);
|
||||
|
||||
return $egwID;
|
||||
return $this->write($egwData, true, true, false);
|
||||
}
|
||||
|
||||
|
||||
@ -405,189 +446,161 @@ 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)))
|
||||
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'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_id_parent'] = '';
|
||||
}
|
||||
|
||||
if (!preg_match('/\[UID:.+\]/m', $taskData['info_des']))
|
||||
{
|
||||
$taskData['info_des'] .= "\r\n[UID:" . $taskData['info_uid'] . "]";
|
||||
if ($taskData['info_id_parent'] != '')
|
||||
{
|
||||
$taskData['info_des'] .= "\r\n[PARENT_UID:" . $taskData['info_id_parent'] . "]";
|
||||
}
|
||||
}
|
||||
|
||||
$sifTask = self::xml_decl . "\n<task>" . self::SIF_decl;
|
||||
|
||||
foreach ($this->_sifTaskMapping as $sifField => $egwField)
|
||||
{
|
||||
if (empty($egwField)) continue;
|
||||
|
||||
$value = $GLOBALS['egw']->translation->convert($taskData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
switch ($sifField)
|
||||
{
|
||||
|
||||
case 'Complete':
|
||||
// is handled with DateCompleted
|
||||
break;
|
||||
|
||||
case 'DateCompleted':
|
||||
if ($taskData[info_status] == 'done')
|
||||
{
|
||||
$sifTask .= "<Complete>1</Complete>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sifTask .= "<DateCompleted></DateCompleted><Complete>0</Complete>";
|
||||
continue;
|
||||
}
|
||||
case 'DueDate':
|
||||
if (!empty($value))
|
||||
{
|
||||
$hdate = new Horde_Date($value);
|
||||
$value = $vcal->_exportDate($hdate, '000000Z');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sifTask .= "<$sifField></$sifField>";
|
||||
}
|
||||
break;
|
||||
case 'StartDate':
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = $vcal->_exportDateTime($value);
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sifTask .= "<$sifField></$sifField>";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Importance':
|
||||
if ($value > 3) $value = 3;
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Sensitivity':
|
||||
$value = ($value == 'private' ? '2' : '0');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Status':
|
||||
switch ($value)
|
||||
{
|
||||
case 'cancelled':
|
||||
case 'deferred':
|
||||
$value = '4';
|
||||
break;
|
||||
case 'waiting':
|
||||
case 'nonactive':
|
||||
$value = '3';
|
||||
break;
|
||||
case 'done':
|
||||
case 'archive':
|
||||
case 'billed':
|
||||
$value = '2';
|
||||
break;
|
||||
case 'not-started':
|
||||
case 'template':
|
||||
$value = '0';
|
||||
break;
|
||||
default: //ongoing
|
||||
$value = 1;
|
||||
break;
|
||||
}
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value) && $value)
|
||||
{
|
||||
$value = implode(', ', $this->get_categories(array($value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_QUOTES, 'utf-8');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sifTask .= '<ActualWork>0</ActualWork><IsRecurring>0</IsRecurring></task>';
|
||||
return $sifTask;
|
||||
$parent = $this->read($infoData['info_id_parent']);
|
||||
$infoData['info_id_parent'] = $parent['info_uid'];
|
||||
}
|
||||
break;
|
||||
else
|
||||
{
|
||||
$infoData['info_id_parent'] = '';
|
||||
}
|
||||
|
||||
if (!preg_match('/\[UID:.+\]/m', $infoData['info_des']))
|
||||
{
|
||||
$infoData['info_des'] .= "\r\n[UID:" . $infoData['info_uid'] . "]";
|
||||
if ($infoData['info_id_parent'] != '')
|
||||
{
|
||||
$infoData['info_des'] .= "\r\n[PARENT_UID:" . $infoData['info_id_parent'] . "]";
|
||||
}
|
||||
}
|
||||
|
||||
$sifTask = self::xml_decl . "\n<task>" . self::SIF_decl;
|
||||
|
||||
foreach ($this->_sifTaskMapping as $sifField => $egwField)
|
||||
{
|
||||
if (empty($egwField)) continue;
|
||||
|
||||
$value = $GLOBALS['egw']->translation->convert($infoData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
switch ($sifField)
|
||||
{
|
||||
|
||||
case 'Complete':
|
||||
// is handled with DateCompleted
|
||||
break;
|
||||
|
||||
case 'DateCompleted':
|
||||
if ($infoData[info_status] != 'done')
|
||||
{
|
||||
$sifTask .= "<DateCompleted></DateCompleted><Complete>0</Complete>";
|
||||
continue;
|
||||
}
|
||||
$sifTask .= "<Complete>1</Complete>";
|
||||
|
||||
case 'DueDate':
|
||||
case 'StartDate':
|
||||
$sifTask .= "<$sifField>";
|
||||
if (!empty($value))
|
||||
{
|
||||
$sifTask .= $this->getDateTime($value, $this->useServerTZ);
|
||||
}
|
||||
$sifTask .= "</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Importance':
|
||||
if ($value > 3) $value = 3;
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Sensitivity':
|
||||
$value = ($value == 'private' ? '2' : '0');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Status':
|
||||
switch ($value)
|
||||
{
|
||||
case 'cancelled':
|
||||
case 'deferred':
|
||||
$value = '4';
|
||||
break;
|
||||
case 'waiting':
|
||||
case 'nonactive':
|
||||
$value = '3';
|
||||
break;
|
||||
case 'done':
|
||||
case 'archive':
|
||||
case 'billed':
|
||||
$value = '2';
|
||||
break;
|
||||
case 'not-started':
|
||||
case 'template':
|
||||
$value = '0';
|
||||
break;
|
||||
default: //ongoing
|
||||
$value = 1;
|
||||
break;
|
||||
}
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value) && $value)
|
||||
{
|
||||
$value = implode('; ', $this->get_categories(array($value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_QUOTES, 'utf-8');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sifTask .= '<ActualWork>0</ActualWork><IsRecurring>0</IsRecurring></task>';
|
||||
return $sifTask;
|
||||
|
||||
case 'note':
|
||||
if (($taskData = $this->read($_id)))
|
||||
$sifNote = self::xml_decl . "\n<note>" . self::SIF_decl;
|
||||
|
||||
foreach ($this->_sifNoteMapping as $sifField => $egwField)
|
||||
{
|
||||
$vcal = new Horde_iCalendar('1.0');
|
||||
if(empty($egwField)) continue;
|
||||
|
||||
$sifNote = self::xml_decl . "\n<note>" . self::SIF_decl;
|
||||
$value = $GLOBALS['egw']->translation->convert($infoData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
foreach ($this->_sifNoteMapping as $sifField => $egwField)
|
||||
switch ($sifField)
|
||||
{
|
||||
if(empty($egwField)) continue;
|
||||
case 'Date':
|
||||
$sifNote .= '<$sifField>';
|
||||
if (!empty($value))
|
||||
{
|
||||
$sifNote .= $this->getDateTime($value, $this->useServerTZ);
|
||||
}
|
||||
$sifNote .= '</$sifField>';
|
||||
break;
|
||||
|
||||
$value = $GLOBALS['egw']->translation->convert($taskData[$egwField], $sysCharSet, 'utf-8');
|
||||
|
||||
switch ($sifField)
|
||||
{
|
||||
case 'Date':
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = $vcal->_exportDateTime($value);
|
||||
}
|
||||
$sifNote .= "<$sifField>$value</$sifField>";
|
||||
case 'Categories':
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = implode('; ', $this->get_categories(array($value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value))
|
||||
{
|
||||
$value = implode('; ', $this->get_categories(array($value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_QUOTES, 'utf-8');
|
||||
$sifNote .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_QUOTES, 'utf-8');
|
||||
$sifNote .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
}
|
||||
$sifNote .= '</note>';
|
||||
return $sifNote;
|
||||
}
|
||||
break;
|
||||
|
||||
default;
|
||||
return false;
|
||||
$sifNote .= '</note>';
|
||||
return $sifNote;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -610,6 +623,11 @@ class infolog_sif extends infolog_bo
|
||||
{
|
||||
$this->uidExtension = true;
|
||||
}
|
||||
if (isset($deviceInfo['tzid']) &&
|
||||
$deviceInfo['tzid'])
|
||||
{
|
||||
$this->useServerTZ = ($deviceInfo['tzid'] == 1);
|
||||
}
|
||||
}
|
||||
// store product name and version, to be able to use it elsewhere
|
||||
if ($_productName)
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package infolog
|
||||
* @copyright (c) 2003-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2003-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -139,19 +139,27 @@ class infolog_so
|
||||
/**
|
||||
* Filter for a given responsible user: info_responsible either contains a the user or one of his memberships
|
||||
*
|
||||
* @param int $user
|
||||
* @param int|array $users one or more account_ids
|
||||
* @return string
|
||||
*
|
||||
* @todo make the responsible a second table and that filter a join with the responsible table
|
||||
*/
|
||||
function responsible_filter($user)
|
||||
function responsible_filter($users)
|
||||
{
|
||||
if (!$user) return '0';
|
||||
if (!$users) return '0';
|
||||
|
||||
$responsible = $user > 0 ? $GLOBALS['egw']->accounts->memberships($user,true) :
|
||||
$GLOBALS['egw']->accounts->members($user,true);
|
||||
|
||||
$responsible[] = $user;
|
||||
$responsible = array();
|
||||
foreach((array)$users as $user)
|
||||
{
|
||||
$responsible = array_merge($responsible,
|
||||
$user > 0 ? $GLOBALS['egw']->accounts->memberships($user,true) :
|
||||
$GLOBALS['egw']->accounts->members($user,true));
|
||||
$responsible[] = $user;
|
||||
}
|
||||
if (is_array($users))
|
||||
{
|
||||
$responsible = array_unique($responsible);
|
||||
}
|
||||
foreach($responsible as $key => $uid)
|
||||
{
|
||||
$responsible[$key] = $this->db->concat("','",'info_responsible',"','")." LIKE '%,$uid,%'";
|
||||
@ -171,14 +179,18 @@ class infolog_so
|
||||
*/
|
||||
function aclFilter($filter = False)
|
||||
{
|
||||
preg_match('/(my|responsible|delegated|own|privat|private|all|none|user)([0-9]*)/',$filter_was=$filter,$vars);
|
||||
preg_match('/(my|responsible|delegated|own|privat|private|all|none|user)([0-9,-]*)/',$filter_was=$filter,$vars);
|
||||
$filter = $vars[1];
|
||||
$f_user = intval($vars[2]);
|
||||
$f_user = $vars[2];
|
||||
|
||||
if (isset($this->acl_filter[$filter.$f_user]))
|
||||
{
|
||||
return $this->acl_filter[$filter.$f_user]; // used cached filter if found
|
||||
}
|
||||
if ($f_user && strpos($f_user,',') !== false)
|
||||
{
|
||||
$f_user = explode(',',$f_user);
|
||||
}
|
||||
|
||||
$filtermethod = " (info_owner=$this->user"; // user has all rights
|
||||
|
||||
@ -236,9 +248,11 @@ class infolog_so
|
||||
}
|
||||
$filtermethod .= ') ';
|
||||
|
||||
if ($filter == 'user' && $f_user > 0)
|
||||
if ($filter == 'user' && $f_user)
|
||||
{
|
||||
$filtermethod .= " AND (info_owner=$f_user AND info_responsible='0' OR ".$this->responsible_filter($f_user).')';
|
||||
$filtermethod .= $this->db->expression($this->info_table,' AND (',array(
|
||||
'info_owner' => $f_user,
|
||||
)," AND info_responsible='0' OR ",$this->responsible_filter($f_user),')');
|
||||
}
|
||||
}
|
||||
//echo "<p>aclFilter(filter='$filter_was',user='$user') = '$filtermethod', privat_user_list=".print_r($privat_user_list,True).", public_user_list=".print_r($public_user_list,True)."</p>\n";
|
||||
@ -724,18 +738,24 @@ class infolog_so
|
||||
if (substr($col,0,5) != 'info_' && substr($col,0,1)!='#') $col = 'info_'.$col;
|
||||
if (!empty($data) && preg_match('/^[a-z_0-9]+$/i',$col))
|
||||
{
|
||||
if ($col == 'info_responsible')
|
||||
switch ($col)
|
||||
{
|
||||
$data = (int) $data;
|
||||
if (!$data) continue;
|
||||
$filtermethod .= " AND (".$this->responsible_filter($data)." OR info_responsible='0' AND ".
|
||||
$this->db->expression($this->info_table,array(
|
||||
'info_owner' => $data > 0 ? $data : $GLOBALS['egw']->accounts->members($data,true)
|
||||
)).')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$filtermethod .= ' AND '.$this->db->expression($this->info_table,array($col => $data));
|
||||
case 'info_responsible':
|
||||
$data = (int) $data;
|
||||
if (!$data) continue;
|
||||
$filtermethod .= ' AND ('.$this->responsible_filter($data)." OR info_responsible='0' AND ".
|
||||
$this->db->expression($this->info_table,array(
|
||||
'info_owner' => $data > 0 ? $data : $GLOBALS['egw']->accounts->members($data,true)
|
||||
)).')';
|
||||
break;
|
||||
|
||||
case 'info_id': // info_id itself is ambigous
|
||||
$filtermethod .= ' AND '.$this->db->expression($this->info_table,'main.',array('info_id' => $data));
|
||||
break;
|
||||
|
||||
default:
|
||||
$filtermethod .= ' AND '.$this->db->expression($this->info_table,array($col => $data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($col[0] == '#' && $query['custom_fields'] && $data)
|
||||
|
@ -169,11 +169,11 @@ class infolog_tracking extends bo_tracking
|
||||
{
|
||||
return lang('%1 deleted by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]),
|
||||
$GLOBALS['egw']->common->grab_owner_name($data['info_modifier']),
|
||||
$this->datetime($data['info_datemodified']-$this->infolog->tz_offset_s));
|
||||
$this->datetime($data['info_datemodified']));
|
||||
}
|
||||
return lang('%1 modified by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]),
|
||||
$GLOBALS['egw']->common->grab_owner_name($data['info_modifier']),
|
||||
$this->datetime($data['info_datemodified']-$this->infolog->tz_offset_s));
|
||||
$this->datetime($data['info_datemodified']));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,10 +207,10 @@ class infolog_tracking extends bo_tracking
|
||||
'info_owner' => $GLOBALS['egw']->common->grab_owner_name($data['info_owner']),
|
||||
'info_status' => lang($data['info_status']=='deleted'?'deleted':$this->infolog->status[$data['info_type']][$data['info_status']]),
|
||||
'info_percent' => (int)$data['info_percent'].'%',
|
||||
'info_datecompleted' => $data['info_datecomplete'] ? $this->datetime($data['info_datecompleted']-$this->infolog->tz_offset_s) : '',
|
||||
'info_datecompleted' => $data['info_datecomplete'] ? $this->datetime($data['info_datecompleted']) : '',
|
||||
'info_location' => $data['info_location'],
|
||||
'info_startdate' => $data['info_startdate'] ? $this->datetime($data['info_startdate']-$this->infolog->tz_offset_s,null) : '',
|
||||
'info_enddate' => $data['info_enddate'] ? $this->datetime($data['info_enddate']-$this->infolog->tz_offset_s,false) : '',
|
||||
'info_startdate' => $data['info_startdate'] ? $this->datetime($data['info_startdate'],null) : '',
|
||||
'info_enddate' => $data['info_enddate'] ? $this->datetime($data['info_enddate'],false) : '',
|
||||
'info_responsible' => implode(', ',$responsible),
|
||||
'info_subject' => $data['info_subject'],
|
||||
) as $name => $value)
|
||||
|
Loading…
Reference in New Issue
Block a user