mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-02-03 03:50:13 +01:00
Apply InfoLog SyncML and GroupDAV changes
This commit is contained in:
parent
3d482fbcef
commit
3bd935a541
@ -227,8 +227,9 @@ class boinfolog extends infolog_bo
|
||||
/**
|
||||
* Convert an InfoLog entry into its xmlrpc representation, eg. convert timestamps to datetime.iso8601
|
||||
*
|
||||
* @param array $data infolog entry
|
||||
* @param array xmlrpc infolog entry
|
||||
* @param array $data infolog entry in db format
|
||||
*
|
||||
* @return array xmlrpc infolog entry
|
||||
*/
|
||||
function data2xmlrpc($data)
|
||||
{
|
||||
@ -272,8 +273,9 @@ class boinfolog extends infolog_bo
|
||||
/**
|
||||
* Convert an InfoLog xmlrpc representation into the internal one, eg. convert datetime.iso8601 to timestamps
|
||||
*
|
||||
* @param array $data infolog entry
|
||||
* @param array xmlrpc infolog entry
|
||||
* @param array $data infolog entry in xmlrpc representation
|
||||
*
|
||||
* @return array infolog entry in db format
|
||||
*/
|
||||
function xmlrpc2data($data)
|
||||
{
|
||||
|
@ -30,16 +30,25 @@ class infolog_bo
|
||||
var $vfs_basedir='/infolog';
|
||||
var $link_pathes = array();
|
||||
var $send_file_ips = array();
|
||||
|
||||
var $tz_offset = 0;
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
var $tz_offset_s = 0;
|
||||
var $user_time_now;
|
||||
var $now;
|
||||
/**
|
||||
* name of timestamps in an InfoLog entry
|
||||
*
|
||||
@ -233,9 +242,8 @@ class infolog_bo
|
||||
|
||||
$this->user = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
$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 = egw_time::server2user($this->now,'ts');
|
||||
|
||||
$this->grants = $GLOBALS['egw']->acl->get_grants('infolog',$this->group_owners ? $this->group_owners : true);
|
||||
$this->so = new infolog_so($this->grants);
|
||||
@ -275,7 +283,7 @@ class infolog_bo
|
||||
/**
|
||||
* check's if user has the requiered rights on entry $info_id
|
||||
*
|
||||
* @param int/array $info data or info_id of infolog entry to check
|
||||
* @param int|array $info data or info_id of infolog entry to check
|
||||
* @param int $required_rights EGW_ACL_{READ|EDIT|ADD|DELETE}
|
||||
* @return boolean
|
||||
*/
|
||||
@ -405,15 +413,111 @@ 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
|
||||
*
|
||||
* @param int $ts timestamp in server-time
|
||||
* @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time, 'array'=array or string with date-format
|
||||
* @return mixed depending of $date_format
|
||||
*/
|
||||
function date2usertime($ts,$date_format='ts')
|
||||
{
|
||||
if (empty($ts) || $date_format == 'server') return $ts;
|
||||
|
||||
return egw_time::server2user($ts,$date_format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an infolog entry specified by $info_id
|
||||
*
|
||||
* @param int/array $info_id integer id or array with key 'info_id' of the entry to read
|
||||
* @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
|
||||
* @return array/boolean infolog entry, null if not found or false if no permission to read it
|
||||
* @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 +541,21 @@ class infolog_bo
|
||||
}
|
||||
if ($run_link_id2from) $this->link_id2from($data);
|
||||
|
||||
// convert system- to user-time
|
||||
foreach($this->timestamps as $time)
|
||||
// convert server- to user-time
|
||||
if ($date_format == 'ts')
|
||||
{
|
||||
if ($data[$time]) $data[$time] += $this->tz_offset_s;
|
||||
$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');
|
||||
}
|
||||
// pre-cache title and file access
|
||||
self::set_link_cache($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
@ -451,9 +563,9 @@ class infolog_bo
|
||||
/**
|
||||
* Delete an infolog entry, evtl. incl. it's children / subs
|
||||
*
|
||||
* @param int/array $info_id int id
|
||||
* @param int|array $info_id int id
|
||||
* @param boolean $delete_children should the children be deleted
|
||||
* @param int/boolean $new_parent parent to use for not deleted children if > 0
|
||||
* @param int|boolean $new_parent parent to use for not deleted children if > 0
|
||||
* @return boolean True if delete was successful, False otherwise ($info_id does not exist or no rights)
|
||||
*/
|
||||
function delete($info_id,$delete_children=False,$new_parent=False)
|
||||
@ -488,7 +600,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 +644,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 +686,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 +719,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,44 +765,64 @@ 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);
|
||||
|
||||
$to_write = $values;
|
||||
if ($user2server)
|
||||
{
|
||||
// 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
|
||||
$time->setTime(0, 0, 0);
|
||||
$values['info_enddate'] = egw_time::to($time,'ts');
|
||||
}
|
||||
else
|
||||
{
|
||||
$time = new egw_time($values['info_enddate'], egw_time::$server_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
|
||||
$this->time2time($values);
|
||||
}
|
||||
|
||||
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);
|
||||
// error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n".array2string($values)."\n",3,'/tmp/infolog');
|
||||
$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;
|
||||
}
|
||||
|
||||
// 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(
|
||||
@ -705,11 +839,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');
|
||||
@ -729,8 +865,9 @@ class infolog_bo
|
||||
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'] = '';
|
||||
|
||||
@ -764,18 +901,40 @@ class infolog_bo
|
||||
function &search(&$query)
|
||||
{
|
||||
//echo "<p>boinfolog::search(".print_r($query,True).")</p>\n";
|
||||
if (!empty($query['start']))
|
||||
{
|
||||
$query['start'] = egw_time::user2server($query['start'],'ts');
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
// convert system- to user-time
|
||||
foreach ($this->timestamps as $key)
|
||||
{
|
||||
if ($data[$key])
|
||||
{
|
||||
if ($data[$time]) $data[$time] += $this->tz_offset_s;
|
||||
$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
|
||||
@ -880,10 +1039,10 @@ class infolog_bo
|
||||
*
|
||||
* Is called as hook to participate in the linking
|
||||
*
|
||||
* @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
|
||||
* @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))
|
||||
{
|
||||
@ -902,16 +1061,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
|
||||
}
|
||||
@ -927,7 +1086,7 @@ class infolog_bo
|
||||
* @param array $options Array of options for the search
|
||||
* @return array with info_id - title pairs of the matching entries
|
||||
*/
|
||||
function link_query( $pattern, Array &$options = array() )
|
||||
function link_query($pattern, Array &$options = array())
|
||||
{
|
||||
$query = array(
|
||||
'search' => $pattern,
|
||||
@ -940,7 +1099,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);
|
||||
}
|
||||
@ -1010,10 +1169,11 @@ 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']);
|
||||
$start = new egw_time($info['info_startdate'],egw_time::$user_timezone);
|
||||
$time = (int) $start->format('Hi');
|
||||
$date = $start->format('Y/m/d');
|
||||
/* As event-like infologs are not showen in current calendar,
|
||||
we need to present all open infologs to the user! (2006-06-27 nelius)
|
||||
if ($do_events && !$time ||
|
||||
@ -1021,11 +1181,11 @@ class infolog_bo
|
||||
{
|
||||
continue;
|
||||
}*/
|
||||
$title = ($do_events?$GLOBALS['egw']->common->formattime(adodb_date('H',$info['info_startdate']),adodb_date('i',$info['info_startdate'])).' ':'').
|
||||
$title = ($do_events?common::formattime($start->format('H'),$start->format('i')).' ':'').
|
||||
$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)
|
||||
@ -1064,7 +1224,7 @@ class infolog_bo
|
||||
if (isset($args['infolog']) && count($args['infolog']))
|
||||
{
|
||||
$icons = $this->so->get_status($args['infolog']);
|
||||
foreach((array) $icons as $id => $status)
|
||||
foreach ((array) $icons as $id => $status)
|
||||
{
|
||||
if ($status && substr($status,-1) != '%')
|
||||
{
|
||||
@ -1092,18 +1252,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)
|
||||
foreach ($old_categories as $cat_id)
|
||||
{
|
||||
if($cat_id && !$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;
|
||||
}
|
||||
@ -1112,7 +1271,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-');
|
||||
@ -1133,7 +1292,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);
|
||||
}
|
||||
@ -1234,19 +1393,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]");
|
||||
@ -1363,109 +1522,303 @@ 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 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->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 (!$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']);
|
||||
$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->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
|
||||
$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 ((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
|
||||
$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;
|
||||
}
|
||||
return false;
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '()[FOUND]:' . array2string($foundInfoLogs));
|
||||
}
|
||||
return $foundInfoLogs;
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,11 @@ class infolog_groupdav extends groupdav_handler
|
||||
* @param string $app 'calendar', 'addressbook' or 'infolog'
|
||||
* @param int $debug=null debug-level to set
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @param string $principalURL=null pricipal url of handler
|
||||
*/
|
||||
function __construct($app,$debug=null,$base_uri=null)
|
||||
function __construct($app,$debug=null,$base_uri=null,$principalURL=null)
|
||||
{
|
||||
parent::__construct($app,$debug,$base_uri);
|
||||
parent::__construct($app,$debug,$base_uri,$principalURL);
|
||||
|
||||
$this->bo = new infolog_bo();
|
||||
}
|
||||
@ -56,7 +57,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
if (!is_array($info)) $info = $this->bo->read($info);
|
||||
$name = $info[self::PATH_ATTRIBUTE];
|
||||
}
|
||||
return '/infolog/'.$name.'.ics';
|
||||
return $name.'.ics';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,33 +73,88 @@ class infolog_groupdav extends groupdav_handler
|
||||
{
|
||||
$starttime = microtime(true);
|
||||
|
||||
$myself = ($user == $GLOBALS['egw_info']['user']['account_id']);
|
||||
|
||||
if ($options['filters'])
|
||||
{
|
||||
|
||||
foreach($options['filters'] as $filter)
|
||||
{
|
||||
switch($filter['name'])
|
||||
{
|
||||
case 'comp-filter':
|
||||
if ($this->debug > 1) error_log(__METHOD__."($options[path],...) comp-filter='{$filter['attrs']['name']}'");
|
||||
|
||||
switch($filter['attrs']['name'])
|
||||
{
|
||||
case 'VCALENDAR':
|
||||
continue;
|
||||
case 'VTODO':
|
||||
break 3;
|
||||
default: // We don't handle this
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have to return the full calendar data or just the etag's
|
||||
if (!($calendar_data = $options['props'] == 'all' && $options['root']['ns'] == groupdav::CALDAV) && is_array($options['props']))
|
||||
{
|
||||
foreach($options['props'] as $prop)
|
||||
{
|
||||
if ($prop['name'] == 'calendar-data')
|
||||
{
|
||||
$calendar_data = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo add a filter to limit how far back entries from the past get synced
|
||||
$filter = array(
|
||||
'info_type' => 'task',
|
||||
);
|
||||
|
||||
//if (!$myself) $filter['info_owner'] = $user;
|
||||
|
||||
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(
|
||||
'order' => 'info_datemodified',
|
||||
'sort' => 'DESC',
|
||||
'filter' => 'own', // filter my: entries user is responsible for,
|
||||
// filter own: entries the user own or is responsible for
|
||||
'filter' => ($myself ? 'own' : 'own'), // filter my: entries user is responsible for,
|
||||
// filter own: entries the user own or is responsible for
|
||||
'date_format' => 'server',
|
||||
'col_filter' => $filter,
|
||||
))))
|
||||
{
|
||||
foreach($tasks as &$task)
|
||||
{
|
||||
$props = array(
|
||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($task)),
|
||||
HTTP_WebDAV_Server::mkprop('getcontenttype',$this->agent != 'kde' ?
|
||||
'text/calendar; charset=utf-8; component=VTODO' : 'text/calendar'), // Konqueror (3.5) dont understand it otherwise
|
||||
// getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set
|
||||
HTTP_WebDAV_Server::mkprop('getlastmodified', $task['info_datemodified']),
|
||||
HTTP_WebDAV_Server::mkprop('resourcetype',''), // DAVKit requires that attribute!
|
||||
HTTP_WebDAV_Server::mkprop('getcontentlength',''),
|
||||
);
|
||||
if ($calendar_data)
|
||||
{
|
||||
$handler = $this->_get_handler();
|
||||
$content = $handler->exportVTODO($task,'2.0','PUBLISH');
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content));
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data',$content);
|
||||
}
|
||||
else
|
||||
{
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
|
||||
}
|
||||
$files['files'][] = array(
|
||||
'path' => self::get_path($task),
|
||||
'props' => array(
|
||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($task)),
|
||||
HTTP_WebDAV_Server::mkprop('getcontenttype',$this->agent != 'kde' ?
|
||||
'text/calendar; charset=utf-8; component=VTODO' : 'text/calendar'), // Konqueror (3.5) dont understand it otherwise
|
||||
// getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set
|
||||
HTTP_WebDAV_Server::mkprop('getlastmodified', $task['info_datemodified']),
|
||||
HTTP_WebDAV_Server::mkprop('getcontentlength',''),
|
||||
),
|
||||
'path' => $path.self::get_path($task),
|
||||
'props' => $props,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -120,7 +176,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
return $task;
|
||||
}
|
||||
$handler = $this->_get_handler();
|
||||
$options['data'] = $handler->exportVTODO($id,'2.0',false,false); // keep UID the client set and no extra charset attributes
|
||||
$options['data'] = $handler->exportVTODO($id,'2.0','PUBLISH');
|
||||
$options['mimetype'] = 'text/calendar; charset=utf-8';
|
||||
header('Content-Encoding: identity');
|
||||
header('ETag: '.$this->get_etag($task));
|
||||
@ -137,22 +193,61 @@ class infolog_groupdav extends groupdav_handler
|
||||
*/
|
||||
function put(&$options,$id,$user=null)
|
||||
{
|
||||
$ok = $this->_common_get_put_delete('PUT',$options,$id);
|
||||
if (!is_null($ok) && !is_array($ok))
|
||||
if ($this->debug) error_log(__METHOD__."($id, $user)".print_r($options,true));
|
||||
|
||||
$oldTask = $this->_common_get_put_delete('PUT',$options,$id);
|
||||
if (!is_null($oldTask) && !is_array($oldTask))
|
||||
{
|
||||
return $ok;
|
||||
return $oldTask;
|
||||
}
|
||||
|
||||
$handler = $this->_get_handler();
|
||||
if (!($info_id = $handler->importVTODO($options['content'],is_numeric($id) ? $id : -1)))
|
||||
$vTodo = htmlspecialchars_decode($options['content']);
|
||||
|
||||
if (is_array($oldTask))
|
||||
{
|
||||
$taskId = $oldTask['info_id'];
|
||||
$retval = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// new entry?
|
||||
if (($foundTasks = $handler->searchVTODO($vTodo)))
|
||||
{
|
||||
if (($taskId = array_shift($foundTasks)) &&
|
||||
($oldTask = $this->bo->read($taskId)))
|
||||
{
|
||||
$retval = '301 Moved Permanently';
|
||||
}
|
||||
else
|
||||
{
|
||||
// to be safe
|
||||
$taskId = -1;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// new entry
|
||||
$taskId = -1;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
}
|
||||
|
||||
if (!($infoId = $handler->importVTODO($vTodo, $taskId, false, $user)))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(,$id) import_vtodo($options[content]) returned false");
|
||||
return '403 Forbidden';
|
||||
}
|
||||
header('ETag: '.$this->get_etag($info_id));
|
||||
if (is_null($ok) || $id != $info_id)
|
||||
|
||||
if ($infoId != $taskId) $retval = '201 Created';
|
||||
|
||||
header('ETag: '.$this->get_etag($infoId));
|
||||
if ($retval !== true)
|
||||
{
|
||||
header('Location: '.$this->base_uri.self::get_path($info_id));
|
||||
return '201 Created';
|
||||
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
|
||||
header('Location: '.$this->base_uri.$path.self::get_path($infoId));
|
||||
return $retval;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -181,7 +276,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
*/
|
||||
function read($id)
|
||||
{
|
||||
return $this->bo->read($id,false);
|
||||
return $this->bo->read($id,false,'server');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,13 +301,45 @@ 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']))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return '"'.$info['info_id'].':'.$info['info_datemodified'].'"';
|
||||
return 'EGw-'.$info['info_id'].':'.$info['info_datemodified'].'-wGE';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add extra properties for calendar collections
|
||||
*
|
||||
* @param array $props=array() regular props by the groupdav handler
|
||||
* @param string $displayname
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @return array
|
||||
*/
|
||||
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
|
||||
{
|
||||
// calendar description
|
||||
$displayname = $GLOBALS['egw']->translation->convert(lang('Tasks of') . ' ' .
|
||||
$displayname,
|
||||
$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname);
|
||||
// email of the current user, see caldav-sheduling draft
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email'])));
|
||||
// supported components, currently only VEVENT
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array(
|
||||
// HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VEVENT')),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')),
|
||||
));
|
||||
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('supported-report',array(
|
||||
HTTP_WebDAV_Server::mkprop('report',
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget'))))));
|
||||
|
||||
return $props;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
*
|
||||
@ -104,14 +111,21 @@ class infolog_ical extends infolog_bo
|
||||
/**
|
||||
* Exports one InfoLog tast to an iCalendar VTODO
|
||||
*
|
||||
* @param int $_taskID info_id
|
||||
* @param int|array $task infolog_id or infolog-tasks data
|
||||
* @param string $_version='2.0' could be '1.0' too
|
||||
* @param string $_method='PUBLISH'
|
||||
* @return string/boolean string with vCal or false on error (eg. no permission to read the event)
|
||||
*/
|
||||
function exportVTODO($_taskID, $_version='2.0',$_method='PUBLISH')
|
||||
function exportVTODO($task, $_version='2.0',$_method='PUBLISH')
|
||||
{
|
||||
$taskData = $this->read($_taskID);
|
||||
if (is_array($task))
|
||||
{
|
||||
$taskData = $task;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!($taskData = $this->read($task, true, 'server'))) return false;
|
||||
}
|
||||
|
||||
if ($taskData['info_id_parent'])
|
||||
{
|
||||
@ -144,10 +158,49 @@ 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);
|
||||
|
||||
$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 +306,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 +351,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -327,11 +420,26 @@ class infolog_ical extends infolog_bo
|
||||
* @param string $_vcalData
|
||||
* @param int $_taskID=-1 info_id, default -1 = new entry
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
* @param int $user=null delegate new task to this account_id, default null
|
||||
* @return int|boolean integer info_id or false on error
|
||||
*/
|
||||
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false)
|
||||
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false, $user=null)
|
||||
{
|
||||
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']))
|
||||
@ -344,13 +452,18 @@ class infolog_ical extends infolog_bo
|
||||
$taskData['info_datecompleted'] = 0;
|
||||
}
|
||||
|
||||
if (!is_null($user))
|
||||
{
|
||||
$taskData['info_owner'] = $user;
|
||||
}
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($taskData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
return $this->write($taskData);
|
||||
return $this->write($taskData, true, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -359,18 +472,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 +510,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 +536,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,140 +547,135 @@ 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';
|
||||
|
||||
if ($_taskID > 0)
|
||||
{
|
||||
$taskData = array();
|
||||
$taskData['info_type'] = 'task';
|
||||
|
||||
if ($_taskID > 0)
|
||||
{
|
||||
$taskData['info_id'] = $_taskID;
|
||||
}
|
||||
foreach ($component->_attributes as $attributes)
|
||||
{
|
||||
//$attributes['value'] = trim($attributes['value']);
|
||||
if (!strlen($attributes['value'])) continue;
|
||||
|
||||
switch ($attributes['name'])
|
||||
{
|
||||
case 'CLASS':
|
||||
$taskData['info_access'] = strtolower($attributes['value']);
|
||||
break;
|
||||
|
||||
case 'DESCRIPTION':
|
||||
$value = $attributes['value'];
|
||||
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (!isset($taskData['info_uid'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_uid'] = $matches[1];
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
if (preg_match('/\s*\[PARENT_UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (!isset($taskData['info_id_parent'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_id_parent'] = $this->getParentID($matches[1]);
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
$taskData['info_des'] = $value;
|
||||
break;
|
||||
|
||||
case 'LOCATION':
|
||||
$taskData['info_location'] = $attributes['value'];
|
||||
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 'COMPLETED':
|
||||
$taskData['info_datecompleted'] = $attributes['value'];
|
||||
break;
|
||||
|
||||
case 'DTSTART':
|
||||
$taskData['info_startdate'] = $attributes['value'];
|
||||
break;
|
||||
|
||||
case 'PRIORITY':
|
||||
if (0 <= $attributes['value'] && $attributes['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']];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_priority'] = (int) $this->priority_ical2egw[$attributes['value']];
|
||||
}
|
||||
} else {
|
||||
$taskData['info_priority'] = 1; // default = normal
|
||||
}
|
||||
break;
|
||||
|
||||
case 'STATUS':
|
||||
// check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user)
|
||||
foreach($component->_attributes as $attr)
|
||||
{
|
||||
if ($attr['name'] == 'X-INFOLOG-STATUS') break;
|
||||
}
|
||||
$taskData['info_status'] = $this->vtodo2status($attributes['value'],
|
||||
$attr['name'] == 'X-INFOLOG-STATUS' ? $attr['value'] : null);
|
||||
break;
|
||||
|
||||
case 'SUMMARY':
|
||||
$taskData['info_subject'] = $attributes['value'];
|
||||
break;
|
||||
|
||||
case 'RELATED-TO':
|
||||
$taskData['info_id_parent'] = $this->getParentID($attributes['value']);
|
||||
break;
|
||||
|
||||
case 'CATEGORIES':
|
||||
if ($attributes['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);
|
||||
}
|
||||
$taskData['info_cat'] = $cats[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'UID':
|
||||
if (strlen($attributes['value']) >= $minimum_uid_length) {
|
||||
$taskData['info_uid'] = $attributes['value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PERCENT-COMPLETE':
|
||||
$taskData['info_percent'] = (int) $attributes['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
# 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;
|
||||
$taskData['info_id'] = $_taskID;
|
||||
}
|
||||
foreach ($component->_attributes as $attribute)
|
||||
{
|
||||
//$attribute['value'] = trim($attribute['value']);
|
||||
if (!strlen($attribute['value'])) continue;
|
||||
|
||||
switch ($attribute['name'])
|
||||
{
|
||||
case 'CLASS':
|
||||
$taskData['info_access'] = strtolower($attribute['value']);
|
||||
break;
|
||||
|
||||
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)
|
||||
{
|
||||
$taskData['info_uid'] = $matches[1];
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
if (preg_match('/\s*\[PARENT_UID:(.+)?\]/Usm', $value, $matches))
|
||||
{
|
||||
if (!isset($taskData['info_id_parent'])
|
||||
&& strlen($matches[1]) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_id_parent'] = $this->getParentID($matches[1]);
|
||||
}
|
||||
//$value = str_replace($matches[0], '', $value);
|
||||
}
|
||||
$taskData['info_des'] = $value;
|
||||
break;
|
||||
|
||||
case 'LOCATION':
|
||||
$taskData['info_location'] = str_replace("\r\n", "\n", $attribute['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'] = $attribute['value'];
|
||||
break;
|
||||
|
||||
case 'DTSTART':
|
||||
$taskData['info_startdate'] = $attribute['value'];
|
||||
break;
|
||||
|
||||
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'] = (int) $this->priority_funambol2egw[$attribute['value']];
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_priority'] = (int) $this->priority_ical2egw[$attribute['value']];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_priority'] = 1; // default = normal
|
||||
}
|
||||
break;
|
||||
|
||||
case 'STATUS':
|
||||
// check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user)
|
||||
foreach ($component->_attributes as $attr)
|
||||
{
|
||||
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'] = str_replace("\r\n", "\n", $attribute['value']);
|
||||
break;
|
||||
|
||||
case 'RELATED-TO':
|
||||
$taskData['info_id_parent'] = $this->getParentID($attribute['value']);
|
||||
break;
|
||||
|
||||
case 'CATEGORIES':
|
||||
if (!empty($attribute['value']))
|
||||
{
|
||||
$cats = $this->find_or_add_categories(explode(',',$attribute['value']), $_taskID);
|
||||
$taskData['info_cat'] = $cats[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'UID':
|
||||
if (strlen($attribute['value']) >= $minimum_uid_length)
|
||||
{
|
||||
$taskData['info_uid'] = $attribute['value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PERCENT-COMPLETE':
|
||||
$taskData['info_percent'] = (int) $attribute['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_taskID)\n" .
|
||||
($taskData ? array2string($taskData) : 'FALSE') . "\n",3,$this->logfile);
|
||||
}
|
||||
return $taskData;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -571,7 +687,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');
|
||||
|
||||
@ -580,7 +697,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 +747,10 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
$vnote->setAttribute('DCREATED',$note['info_startdate']);
|
||||
}
|
||||
$vnote->setAttribute('DCREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'add'));
|
||||
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');
|
||||
@ -676,7 +795,7 @@ class infolog_ical extends infolog_bo
|
||||
array2string($note)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
return $this->write($note);
|
||||
return $this->write($note, true, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -684,40 +803,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 +828,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 +844,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,34 +873,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':
|
||||
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);
|
||||
}
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -842,9 +940,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,67 @@ 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
|
||||
*
|
||||
*/
|
||||
function getDateTime($time, $tzid)
|
||||
{
|
||||
if (empty($tzid) || $tzid == 'UTC')
|
||||
{
|
||||
return $this->vCalendar->_exportDateTime(egw_time::to($time,'ts'));
|
||||
}
|
||||
if (!is_a($time,'DateTime'))
|
||||
{
|
||||
$time = new egw_time($time,egw_time::$server_timezone);
|
||||
}
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
{
|
||||
self::$tz_cache[$tzid] = calendar_timezones::DateTimeZone($tzid);
|
||||
}
|
||||
// check for date --> export it as such
|
||||
if ($time->format('Hi') == '0000')
|
||||
{
|
||||
$arr = egw_time::to($time, 'array');
|
||||
$time = new egw_time($arr, self::$tz_cache[$tzid]);
|
||||
$value = $time->format('Y-m-d');
|
||||
}
|
||||
else
|
||||
{
|
||||
$time->setTimezone(self::$tz_cache[$tzid]);
|
||||
$value = $time->format('Ymd\THis');
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
function startElement($_parser, $_tag, $_attributes)
|
||||
{
|
||||
@ -121,14 +182,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 +198,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 +221,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 +257,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 +265,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 +276,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 +326,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 +334,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)
|
||||
{
|
||||
@ -295,13 +368,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,23 +382,26 @@ 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -339,28 +415,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 +434,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);
|
||||
|
||||
return $egwID;
|
||||
return $this->write($egwData, true, true, false);
|
||||
}
|
||||
|
||||
|
||||
@ -399,189 +462,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->tzid);
|
||||
}
|
||||
$sifTask .= "</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Importance':
|
||||
if ($value > 3) $value = 3;
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Sensitivity':
|
||||
$value = ($value == 'private' ? '2' : '0');
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Status':
|
||||
switch ($value)
|
||||
{
|
||||
case 'cancelled':
|
||||
case 'deferred':
|
||||
$value = '4';
|
||||
break;
|
||||
case 'waiting':
|
||||
case 'nonactive':
|
||||
$value = '3';
|
||||
break;
|
||||
case 'done':
|
||||
case 'archive':
|
||||
case 'billed':
|
||||
$value = '2';
|
||||
break;
|
||||
case 'not-started':
|
||||
case 'template':
|
||||
$value = '0';
|
||||
break;
|
||||
default: //ongoing
|
||||
$value = 1;
|
||||
break;
|
||||
}
|
||||
$sifTask .= "<$sifField>$value</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Categories':
|
||||
if (!empty($value) && $value)
|
||||
{
|
||||
$value = implode('; ', $this->get_categories(array($value)));
|
||||
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
$value = @htmlspecialchars($value, ENT_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->tzid);
|
||||
}
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -604,6 +639,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)
|
||||
|
@ -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";
|
||||
|
@ -163,17 +163,17 @@ class infolog_tracking extends bo_tracking
|
||||
if (!$old || $old['info_status'] == 'deleted')
|
||||
{
|
||||
return lang('New %1 created by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]),
|
||||
$GLOBALS['egw']->common->grab_owner_name($this->infolog->user),$this->datetime(time()));
|
||||
common::grab_owner_name($this->infolog->user),$this->datetime('now'));
|
||||
}
|
||||
elseif($data['info_status'] == 'deleted')
|
||||
{
|
||||
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));
|
||||
common::grab_owner_name($data['info_modifier']),
|
||||
$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));
|
||||
common::grab_owner_name($data['info_modifier']),
|
||||
$this->datetime($data['info_datemodified']));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -192,7 +192,7 @@ class infolog_tracking extends bo_tracking
|
||||
{
|
||||
foreach($data['info_responsible'] as $uid)
|
||||
{
|
||||
$responsible[] = $GLOBALS['egw']->common->grab_owner_name($uid);
|
||||
$responsible[] = common::grab_owner_name($uid);
|
||||
}
|
||||
}
|
||||
if ($GLOBALS['egw_info']['user']['preferences']['infolog']['show_id'])
|
||||
@ -205,13 +205,13 @@ class infolog_tracking extends bo_tracking
|
||||
'info_addr' => $data['info_addr'],
|
||||
'info_cat' => $data['info_cat'] ? $GLOBALS['egw']->categories->id2name($data['info_cat']) : '',
|
||||
'info_priority' => lang($this->infolog->enums['priority'][$data['info_priority']]),
|
||||
'info_owner' => $GLOBALS['egw']->common->grab_owner_name($data['info_owner']),
|
||||
'info_owner' => 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_datecompleted'] ? $this->datetime($data['info_datecompleted']-$this->infolog->tz_offset_s) : '',
|
||||
'info_datecompleted' => $data['info_datecompleted'] ? $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