forked from extern/egroupware
GroupDAV updates
This commit is contained in:
parent
79824c2e0c
commit
a8804a44ef
@ -824,8 +824,8 @@ class addressbook_bo extends addressbook_so
|
||||
/**
|
||||
* reads contacts matched by key and puts all cols in the data array
|
||||
*
|
||||
* @param int/string $contact_id
|
||||
* @return array/boolean array with contact data, null if not found or false on no view perms
|
||||
* @param int|string $contact_id
|
||||
* @return array|boolean array with contact data, null if not found or false on no view perms
|
||||
*/
|
||||
function read($contact_id)
|
||||
{
|
||||
|
@ -51,10 +51,11 @@ class addressbook_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 addressbook_bo();
|
||||
}
|
||||
@ -67,7 +68,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
*/
|
||||
static function get_path($contact)
|
||||
{
|
||||
return '/addressbook/'.$contact[self::PATH_ATTRIBUTE].'.vcf';
|
||||
return $contact[self::PATH_ATTRIBUTE].'.vcf';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,8 +96,9 @@ class addressbook_groupdav extends groupdav_handler
|
||||
}
|
||||
if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user,$id) filter=".array2string($filter));
|
||||
|
||||
// check if we have to return the full calendar data or just the etag's
|
||||
if (!($filter['address_data'] = $options['props'] == 'all' && $options['root']['ns'] == groupdav::CARDDAV) && is_array($options['props']))
|
||||
// check if we have to return the full contact data or just the etag's
|
||||
if (!($filter['address_data'] = $options['props'] == 'all' &&
|
||||
$options['root']['ns'] == groupdav::CARDDAV) && is_array($options['props']))
|
||||
{
|
||||
foreach($options['props'] as $prop)
|
||||
{
|
||||
@ -108,7 +110,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
}
|
||||
}
|
||||
// return iterator, calling ourself to return result in chunks
|
||||
$files['files'] = new groupdav_propfind_iterator($this,$filter,$files['files']);
|
||||
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -116,11 +118,12 @@ class addressbook_groupdav extends groupdav_handler
|
||||
/**
|
||||
* Callback for profind interator
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $filter
|
||||
* @param array|boolean $start=false false=return all or array(start,num)
|
||||
* @return array with "files" array with values for keys path and props
|
||||
*/
|
||||
function &propfind_callback(array $filter,$start=false)
|
||||
function &propfind_callback($path,array $filter,$start=false)
|
||||
{
|
||||
$starttime = microtime(true);
|
||||
|
||||
@ -129,7 +132,6 @@ class addressbook_groupdav extends groupdav_handler
|
||||
$handler = self::_get_handler();
|
||||
}
|
||||
unset($filter['address_data']);
|
||||
|
||||
$files = array();
|
||||
// we query etag and modified, as LDAP does not have the strong sql etag
|
||||
if (($contacts =& $this->bo->search(array(),$address_data ? false : array('id','uid','etag','modified'),'contact_id','','',False,'AND',$start,$filter)))
|
||||
@ -138,27 +140,27 @@ class addressbook_groupdav extends groupdav_handler
|
||||
{
|
||||
$props = array(
|
||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($contact)),
|
||||
HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/x-vcard'),
|
||||
HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'),
|
||||
// getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set
|
||||
HTTP_WebDAV_Server::mkprop('getlastmodified', $contact['modified']),
|
||||
);
|
||||
if ($address_data)
|
||||
{
|
||||
$content = $handler->getVCard($contact,$this->charset,false);
|
||||
$content = $handler->getVCard($contact['id'],$this->charset,false);
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content));
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content);
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
|
||||
}
|
||||
$files[] = array(
|
||||
'path' => self::get_path($contact),
|
||||
'path' => $path.self::get_path($contact),
|
||||
'props' => $props,
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($this->debug) error_log(__METHOD__.'('.array2string($filter).','.array2string($start).") took ".(microtime(true) - $starttime).' to return '.count($files).' items');
|
||||
if ($this->debug) error_log(__METHOD__."($path,".array2string($filter).','.array2string($start).") took ".(microtime(true) - $starttime).' to return '.count($files).' items');
|
||||
return $files;
|
||||
}
|
||||
|
||||
@ -265,22 +267,70 @@ class addressbook_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))
|
||||
{
|
||||
return $ok;
|
||||
}
|
||||
$handler = self::_get_handler();
|
||||
$contact = $handler->vcardtoegw($options['content']);
|
||||
if ($this->debug) error_log(__METHOD__.'('.array2string($options).",$id,$user)");
|
||||
|
||||
if (!is_null($ok))
|
||||
$oldContact = $this->_common_get_put_delete('PUT',$options,$id);
|
||||
if (!is_null($oldContact) && !is_array($oldContact))
|
||||
{
|
||||
$contact['id'] = $ok['id'];
|
||||
// dont allow the client to overwrite certain values
|
||||
$contact['uid'] = $ok['uid'];
|
||||
$contact['owner'] = $ok['owner'];
|
||||
$contact['private'] = $ok['private'];
|
||||
return $oldContact;
|
||||
}
|
||||
|
||||
$handler = self::_get_handler();
|
||||
$vCard = htmlspecialchars_decode($options['content']);
|
||||
|
||||
if (is_array($oldContact))
|
||||
{
|
||||
$contactId = $oldContact['id'];
|
||||
$retval = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// new entry?
|
||||
if (($foundContacts = $handler->search($vCard)))
|
||||
{
|
||||
if (($contactId = array_shift($foundContacts)) &&
|
||||
($oldContact = $this->bo->read($contactId)))
|
||||
{
|
||||
$retval = '301 Moved Permanently';
|
||||
}
|
||||
else
|
||||
{
|
||||
// to be safe
|
||||
$contactId = -1;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// new entry
|
||||
$contactId = -1;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
}
|
||||
|
||||
$contact = $handler->vcardtoegw($vCard);
|
||||
|
||||
if (is_array($contact['category']))
|
||||
{
|
||||
$contact['category'] = implode(',',$this->bo->find_or_add_categories($contact['category'], $contactId));
|
||||
}
|
||||
elseif ($contactId > 0)
|
||||
{
|
||||
$contact['category'] = $oldContact['category'];
|
||||
}
|
||||
if (is_array($oldContact))
|
||||
{
|
||||
$contact['id'] = $oldContact['id'];
|
||||
// dont allow the client to overwrite certain values
|
||||
$contact['uid'] = $oldContact['uid'];
|
||||
$contact['owner'] = $oldContact['owner'];
|
||||
$contact['private'] = $oldContact['private'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$contact['owner'] = $user;
|
||||
}
|
||||
|
||||
if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match);
|
||||
|
||||
if (!($save_ok = $this->bo->save($contact)))
|
||||
@ -292,24 +342,26 @@ class addressbook_groupdav extends groupdav_handler
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($contact['etag']))
|
||||
{
|
||||
$contact = $this->read($contact['id']);
|
||||
$contact = $this->read($save_ok);
|
||||
}
|
||||
|
||||
header('ETag: '.$this->get_etag($contact));
|
||||
if (is_null($ok))
|
||||
if ($retval !== true)
|
||||
{
|
||||
header($h='Location: '.$this->base_uri.self::get_path($contact));
|
||||
if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): 201 Created");
|
||||
return '201 Created';
|
||||
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
|
||||
header($h='Location: '.$this->base_uri.$path.self::get_path($contact));
|
||||
if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): $retval");
|
||||
return $retval;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query ctag for addressbook
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getctag($path,$user)
|
||||
@ -319,10 +371,40 @@ class addressbook_groupdav extends groupdav_handler
|
||||
if ($user && $path != '/addressbook/') $filter['contact_owner'] = $user;
|
||||
// should we hide the accounts addressbook
|
||||
if ($GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) $filter['account_id'] = null;
|
||||
|
||||
|
||||
$result = $this->bo->search(array(),'MAX(contact_modified) AS contact_modified','','','','','',$filter);
|
||||
|
||||
return '"'.$result[0]['modified'].'"';
|
||||
|
||||
$ctag = 'EGw-'.$result[0]['modified'].'-wGE';
|
||||
return $ctag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the privileges of the current user
|
||||
*
|
||||
* @param array $props=array() regular props by the groupdav handler
|
||||
* @return array
|
||||
*/
|
||||
static function current_user_privilege_set(array $props=array())
|
||||
{
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::DAV,'current-user-privilege-set',
|
||||
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'privilege',
|
||||
array(//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'all',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'read-free-busy',''),
|
||||
//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read-current-user-privilege-set',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'bind',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'unbind',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-properties',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-content',''),
|
||||
))));
|
||||
return $props;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -342,12 +424,19 @@ class addressbook_groupdav extends groupdav_handler
|
||||
* </supported-report>
|
||||
* </D:supported-report-set>
|
||||
* @link http://www.mail-archive.com/calendarserver-users@lists.macosforge.org/msg01156.html
|
||||
*
|
||||
*
|
||||
* @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())
|
||||
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
|
||||
{
|
||||
// addressbook description
|
||||
$displayname = $GLOBALS['egw']->translation->convert(lang('Addressbook of') . ' ' .
|
||||
$displayname,
|
||||
$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-description',$displayname);
|
||||
// supported reports (required property for CardDAV)
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('supported-report',array(
|
||||
@ -357,6 +446,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
HTTP_WebDAV_Server::mkprop('report',
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-multiget','')))),
|
||||
));
|
||||
//$props = self::current_user_privilege_set($props);
|
||||
return $props;
|
||||
}
|
||||
|
||||
@ -390,7 +480,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
{
|
||||
return '412 Precondition Failed';
|
||||
}
|
||||
return $ok;
|
||||
//return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,7 +339,7 @@ class addressbook_so
|
||||
/**
|
||||
* Read all customfields of the given id's
|
||||
*
|
||||
* @param int/array $ids
|
||||
* @param int|array $ids
|
||||
* @param array $field_names=null custom fields to read, default all
|
||||
* @return array id => name => value
|
||||
*/
|
||||
@ -374,7 +374,7 @@ class addressbook_so
|
||||
/**
|
||||
* Read all distributionlists of the given id's
|
||||
*
|
||||
* @param int/array $ids
|
||||
* @param int|array $ids
|
||||
* @return array id => name => value
|
||||
*/
|
||||
function read_distributionlist($ids, $dl_allowed=array())
|
||||
@ -544,8 +544,8 @@ class addressbook_so
|
||||
/**
|
||||
* reads contact data including custom fields
|
||||
*
|
||||
* @param int/string $contact_id contact_id or 'a'.account_id
|
||||
* @return array/boolean data if row could be retrived else False
|
||||
* @param int|string $contact_id contact_id or 'a'.account_id
|
||||
* @return array|boolean data if row could be retrived else False
|
||||
*/
|
||||
function read($contact_id)
|
||||
{
|
||||
@ -581,10 +581,10 @@ class addressbook_so
|
||||
*
|
||||
* '*' and '?' are replaced with sql-wildcards '%' and '_'
|
||||
*
|
||||
* @param array/string $criteria array of key and data cols, OR string to search over all standard search fields
|
||||
* @param boolean/string $only_keys=true True returns only keys, False returns all cols. comma seperated list of keys to return
|
||||
* @param array|string $criteria array of key and data cols, OR string to search over all standard search fields
|
||||
* @param boolean|string $only_keys=true True returns only keys, False returns all cols. comma seperated list of keys to return
|
||||
* @param string $order_by='' fieldnames + {ASC|DESC} separated by colons ',', can also contain a GROUP BY (if it contains ORDER BY)
|
||||
* @param string/array $extra_cols='' string or array of strings to be added to the SELECT, eg. "count(*) as num"
|
||||
* @param string|array $extra_cols='' string or array of strings to be added to the SELECT, eg. "count(*) as num"
|
||||
* @param string $wildcard='' appended befor and after each criteria
|
||||
* @param boolean $empty=false False=empty criteria are ignored in query, True=empty have to be empty in row
|
||||
* @param string $op='AND' defaults to 'AND', can be set to 'OR' too, then criteria's are OR'ed together
|
||||
@ -985,7 +985,7 @@ class addressbook_so
|
||||
/**
|
||||
* Deletes a distribution list (incl. it's members)
|
||||
*
|
||||
* @param int/array $list list_id(s)
|
||||
* @param int|array $list list_id(s)
|
||||
* @return number of members deleted or false if list does not exist
|
||||
*/
|
||||
function delete_list($list)
|
||||
@ -1011,7 +1011,7 @@ class addressbook_so
|
||||
/**
|
||||
* Check if distribution lists are availible for a given addressbook
|
||||
*
|
||||
* @param int/string $owner='' addressbook (eg. 0 = accounts), default '' = "all" addressbook (uses the main backend)
|
||||
* @param int|string $owner='' addressbook (eg. 0 = accounts), default '' = "all" addressbook (uses the main backend)
|
||||
* @return boolean
|
||||
*/
|
||||
function lists_available($owner='')
|
||||
|
@ -123,7 +123,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
*/
|
||||
function addVCard($_vcard, $_abID=null, $merge=false)
|
||||
{
|
||||
if (!($contact = $this->vcardtoegw($_vcard, $_abID))) return false;
|
||||
if (!($contact = $this->vcardtoegw($_vcard))) return false;
|
||||
|
||||
if ($_abID)
|
||||
{
|
||||
@ -145,6 +145,15 @@ class addressbook_vcal extends addressbook_bo
|
||||
{
|
||||
$contact['account_id'] = $old_contact['account_id'];
|
||||
}
|
||||
if (is_array($contact['category']))
|
||||
{
|
||||
$contact['category'] = implode(',',$this->find_or_add_categories($contact['category'], $_abID));
|
||||
}
|
||||
else
|
||||
{
|
||||
// restore from orignal
|
||||
$contact['category'] = $old_contact['category'];
|
||||
}
|
||||
}
|
||||
}
|
||||
// update entry
|
||||
@ -157,6 +166,10 @@ class addressbook_vcal extends addressbook_bo
|
||||
{
|
||||
$contact['owner'] = $GLOBALS['egw_info']['user']['account_primary_group'];
|
||||
}
|
||||
if (is_array($contact['category']))
|
||||
{
|
||||
$contact['category'] = implode(',',$this->find_or_add_categories($contact['category'], -1));
|
||||
}
|
||||
}
|
||||
return $this->save($contact);
|
||||
}
|
||||
@ -452,8 +465,13 @@ class addressbook_vcal extends addressbook_bo
|
||||
{
|
||||
$result = array();
|
||||
|
||||
if (($contact = $this->vcardtoegw($_vcard, $contentID)))
|
||||
if (($contact = $this->vcardtoegw($_vcard)))
|
||||
{
|
||||
if (is_array($contact['category']))
|
||||
{
|
||||
$contact['category'] = implode(',',$this->find_or_add_categories($contact['category'],
|
||||
$contentID ? $contentID : -1));
|
||||
}
|
||||
if ($contentID)
|
||||
{
|
||||
$contact['id'] = $contentID;
|
||||
@ -472,7 +490,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
if (is_array($_supportedFields)) $this->supportedFields = $_supportedFields;
|
||||
}
|
||||
|
||||
function vcardtoegw($_vcard, $_abID=null)
|
||||
function vcardtoegw($_vcard)
|
||||
{
|
||||
// the horde class does the charset conversion. DO NOT CONVERT HERE.
|
||||
// be as flexible as possible
|
||||
@ -886,7 +904,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
break;
|
||||
|
||||
case 'cat_id':
|
||||
$contact[$fieldName] = implode(',',$this->find_or_add_categories($vcardValues[$vcardKey]['values'], $_abID));
|
||||
$contact[$fieldName] = $vcardValues[$vcardKey]['values'];
|
||||
break;
|
||||
|
||||
case 'jpegphoto':
|
||||
|
@ -145,9 +145,6 @@ class calendar_boupdate extends calendar_bo
|
||||
else
|
||||
{
|
||||
$old_event = $this->read((int)$event['id'],null,$ignore_acl);
|
||||
// if no participants are set, set them from the old event, as we might need them to update recuring events
|
||||
if (!isset($event['participants'])) $event['participants'] = $old_event['participants'];
|
||||
//echo "old $event[id]="; _debug_array($old_event);
|
||||
}
|
||||
|
||||
// do we need to check, if user is allowed to invite the invited participants
|
||||
@ -185,7 +182,7 @@ class calendar_boupdate extends calendar_bo
|
||||
self::has_cat_right(self::CAT_ACL_STATUS,$cat_id,$this->user) === false &&
|
||||
(!$old_event || $old_event['start'] != $event['start'] || $old_event['end'] != $event['end']))
|
||||
{
|
||||
foreach($event['participants'] as $uid => $status)
|
||||
foreach((array)$event['participants'] as $uid => $status)
|
||||
{
|
||||
calendar_so::split_status($status,$q,$r);
|
||||
if ($status != 'U')
|
||||
@ -658,8 +655,6 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
//$currentPrefs = CreateObject('phpgwapi.preferences',$GLOBALS['egw_info']['user']['account_id']);
|
||||
//$user_prefs = $currentPrefs->read_repository();
|
||||
$user_prefs = $GLOBALS['egw_info']['user']['preferences'];
|
||||
foreach($to_notify as $userid => $statusid)
|
||||
{
|
||||
@ -676,8 +671,9 @@ class calendar_boupdate extends calendar_bo
|
||||
continue; // dont notify rejected participants or groups
|
||||
}
|
||||
|
||||
if($userid != $GLOBALS['egw_info']['user']['account_id'] ||
|
||||
($userid == $GLOBALS['egw_info']['user']['account_id'] && $user_prefs['calendar']['receive_own_updates']==1) ||
|
||||
if($userid != $GLOBALS['egw_info']['user']['account_id'] ||
|
||||
($userid == $GLOBALS['egw_info']['user']['account_id'] &&
|
||||
$user_prefs['calendar']['receive_own_updates']==1) ||
|
||||
$msg_type == MSG_ALARM)
|
||||
{
|
||||
$preferences = CreateObject('phpgwapi.preferences',$userid);
|
||||
@ -1084,7 +1080,9 @@ class calendar_boupdate extends calendar_bo
|
||||
"($cal_id, $uid, $status, $recur_date)");
|
||||
}
|
||||
$old_event = $this->read($cal_id, $recur_date, false, 'server');
|
||||
if (($Ok = $this->so->set_status($cal_id,is_numeric($uid)?'u':$uid[0],is_numeric($uid)?$uid:substr($uid,1),$status,$recur_date ? $this->date2ts($recur_date,true) : 0,$role)))
|
||||
if (($Ok = $this->so->set_status($cal_id,is_numeric($uid)?'u':$uid[0],
|
||||
is_numeric($uid)?$uid:substr($uid,1),$status,
|
||||
$recur_date?$this->date2ts($recur_date,true):0,$role)))
|
||||
{
|
||||
if ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time());
|
||||
|
||||
@ -1430,27 +1428,24 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
|
||||
$cat_id_list = array();
|
||||
if(is_array($catname_list) && count($catname_list) > 0)
|
||||
foreach ((array)$catname_list as $cat_name)
|
||||
{
|
||||
foreach ($catname_list as $cat_name)
|
||||
$cat_name = trim($cat_name);
|
||||
$cat_id = $this->categories->name2id($cat_name, 'X-');
|
||||
|
||||
if (!$cat_id)
|
||||
{
|
||||
$cat_name = trim($cat_name);
|
||||
$cat_id = $this->categories->name2id($cat_name, 'X-');
|
||||
|
||||
if (!$cat_id)
|
||||
// some SyncML clients (mostly phones) add an X- to the category names
|
||||
if (strncmp($cat_name, 'X-', 2) == 0)
|
||||
{
|
||||
// some SyncML clients (mostly phones) add an X- to the category names
|
||||
if (strncmp($cat_name, 'X-', 2) == 0)
|
||||
{
|
||||
$cat_name = substr($cat_name, 2);
|
||||
}
|
||||
$cat_id = $this->categories->add(array('name' => $cat_name, 'descr' => $cat_name, 'access' => 'private'));
|
||||
$cat_name = substr($cat_name, 2);
|
||||
}
|
||||
$cat_id = $this->categories->add(array('name' => $cat_name, 'descr' => $cat_name, 'access' => 'private'));
|
||||
}
|
||||
|
||||
if ($cat_id)
|
||||
{
|
||||
$cat_id_list[] = $cat_id;
|
||||
}
|
||||
if ($cat_id)
|
||||
{
|
||||
$cat_id_list[] = $cat_id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1501,7 +1496,6 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
$matchingEvents = array();
|
||||
$query = array();
|
||||
$recur_date = 0;
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
@ -1511,16 +1505,12 @@ class calendar_boupdate extends calendar_bo
|
||||
|
||||
if ($filter == 'master')
|
||||
{
|
||||
if (isset($event['recurrence']))
|
||||
{
|
||||
$recur_date = $this->date2usertime($event['recurrence']);
|
||||
}
|
||||
elseif (isset($event['start']))
|
||||
{
|
||||
$recur_date = $this->date2usertime($event['start']);
|
||||
}
|
||||
$query[] = 'recur_type!='. MCAL_RECUR_NONE;
|
||||
$query['cal_recurrence'] = 0;
|
||||
}
|
||||
|
||||
if (!isset($event['recurrence'])) $event['recurrence'] = 0;
|
||||
|
||||
if ($event['id'])
|
||||
{
|
||||
if ($this->log)
|
||||
@ -1528,38 +1518,44 @@ class calendar_boupdate extends calendar_bo
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
'(' . $event['id'] . ")[EventID]");
|
||||
}
|
||||
if (($egwEvent = $this->read($event['id'], $recur_date, false, 'server')))
|
||||
if (($egwEvent = $this->read($event['id'], 0, false, 'server')))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
'()[FOUND]:' . array2string($egwEvent));
|
||||
}
|
||||
// Just a simple consistency check
|
||||
if ($filter == 'exact' ||
|
||||
$filter == 'master' && $egwEvent['recur_type'] != MCAL_RECUR_NONE ||
|
||||
$filter != 'master' && strpos($egwEvent['title'], $event['title']) === 0)
|
||||
if ($egwEvent['recur_type'] != MCAL_RECUR_NONE &&
|
||||
(empty($event['uid']) || $event['uid'] == $egwEvent['uid']))
|
||||
{
|
||||
$retval = $egwEvent['id'];
|
||||
if ($egwEvent['recur_type'] != MCAL_RECUR_NONE &&
|
||||
$event['recur_type'] == MCAL_RECUR_NONE && $event['recurrence'] != 0)
|
||||
if ($filter == 'master')
|
||||
{
|
||||
$retval .= ':' . (int)$event['recurrence'];
|
||||
$matchingEvents[] = $egwEvent['id']; // we found the master
|
||||
}
|
||||
$matchingEvents[] = $retval;
|
||||
return $matchingEvents;
|
||||
if ($event['recur_type'] == $egwEvent['recur_type'])
|
||||
{
|
||||
$matchingEvents[] = $egwEvent['id']; // we found the event
|
||||
}
|
||||
elseif ($event['recur_type'] == MCAL_RECUR_NONE &&
|
||||
$event['recurrence'] != 0)
|
||||
{
|
||||
$exceptions = $this->so->get_recurrence_exceptions($egwEvent, $event['tzid']);
|
||||
if (in_array($event['recurrence'], $exceptions))
|
||||
{
|
||||
$matchingEvents[] = $egwEvent['id'] . ':' . (int)$event['recurrence'];
|
||||
}
|
||||
}
|
||||
} elseif ($event['recur_type'] == $egwEvent['recur_type'] &&
|
||||
$filter != 'master' &&
|
||||
strpos($egwEvent['title'], $event['title']) === 0)
|
||||
{
|
||||
$matchingEvents[] = $egwEvent['id']; // we found the event
|
||||
}
|
||||
}
|
||||
if ($filter == 'exact') return array();
|
||||
if (!empty($matchingEvents) || $filter == 'exact') return $matchingEvents;
|
||||
}
|
||||
unset($event['id']);
|
||||
|
||||
if ($filter == 'master')
|
||||
{
|
||||
$query[] = 'recur_type!='. MCAL_RECUR_NONE;
|
||||
$query['cal_recurrence'] = 0;
|
||||
}
|
||||
|
||||
// only query calendars of users, we have READ-grants from
|
||||
$users = array();
|
||||
foreach(array_keys($this->grants) as $user)
|
||||
@ -1611,6 +1607,7 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($filter != 'master' && ($filter != 'exact' || empty($event['uid'])))
|
||||
{
|
||||
if (isset($event['whole_day']) && $event['whole_day'])
|
||||
@ -1661,10 +1658,6 @@ class calendar_boupdate extends calendar_bo
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
'(' . $event['uid'] . ')[EventUID]');
|
||||
}
|
||||
if ($filter != 'master' && isset($event['recurrence']))
|
||||
{
|
||||
$query['cal_recurrence'] = $event['recurrence'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->log)
|
||||
@ -1694,19 +1687,41 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
if (in_array($egwEvent['id'], $matchingEvents)) continue;
|
||||
|
||||
if (in_array($filter, array('exact', 'master')) && !empty($event['uid']))
|
||||
{
|
||||
$matchingEvents[] = $egwEvent['id']; // UID found
|
||||
if ($filter = 'master') break;
|
||||
continue;
|
||||
}
|
||||
|
||||
// convert timezone id of event to tzid (iCal id like 'Europe/Berlin')
|
||||
if (!$egwEvent['tz_id'] || !($egwEvent['tzid'] = calendar_timezones::id2tz($egwEvent['tz_id'])))
|
||||
{
|
||||
$egwEvent['tzid'] = egw_time::$server_timezone->getName();
|
||||
}
|
||||
|
||||
if (in_array($filter, array('exact', 'master')) && !empty($event['uid']))
|
||||
{
|
||||
// UID found
|
||||
if ($egwEvent['recurrence'] == $event['recurrence'])
|
||||
{
|
||||
// We found the exact match
|
||||
$matchingEvents[] = $egwEvent['id'];
|
||||
break;
|
||||
}
|
||||
if (!$egwEvent['recurrence'] && $event['recurrence'])
|
||||
{
|
||||
// We found the master
|
||||
if ($filter == 'master')
|
||||
{
|
||||
$matchingEvents[] = $egwEvent['id'];
|
||||
break;
|
||||
}
|
||||
$exceptions = $this->so->get_recurrence_exceptions($egwEvent, $event['tzid']);
|
||||
if (in_array($event['recurrence'], $exceptions))
|
||||
{
|
||||
// We found a pseudo exception
|
||||
$matchingEvents[] = $egwEvent['id'] . ':' . (int)$event['recurrence'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($event['uid']) && $filter == 'exact') break;
|
||||
|
||||
// check times
|
||||
if ($filter != 'relax')
|
||||
@ -2129,4 +2144,4 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -58,10 +58,11 @@ class calendar_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 principal 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 calendar_boupdate();
|
||||
}
|
||||
@ -83,7 +84,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
if (!is_array($event)) $event = $this->bo->read($event);
|
||||
$name = $event[self::PATH_ATTRIBUTE];
|
||||
}
|
||||
return '/calendar/'.$name.'.ics';
|
||||
return $name.'.ics';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,7 +172,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
'text/calendar; charset=utf-8; component=VEVENT' : 'text/calendar'),
|
||||
// getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set
|
||||
HTTP_WebDAV_Server::mkprop('getlastmodified', $event['modified']),
|
||||
HTTP_WebDAV_Server::mkprop('resourcetype',''), // iPhone requires that attribute!
|
||||
HTTP_WebDAV_Server::mkprop('resourcetype',''), // DAVKit requires that attribute!
|
||||
);
|
||||
//error_log(__FILE__ . __METHOD__ . "Calendar Data : $calendar_data");
|
||||
if ($calendar_data)
|
||||
@ -185,7 +186,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
|
||||
}
|
||||
$files['files'][] = array(
|
||||
'path' => self::get_path($event),
|
||||
'path' => $path.self::get_path($event),
|
||||
'props' => $props,
|
||||
);
|
||||
}
|
||||
@ -228,7 +229,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
return false; // return nothing for now, todo: check if we can pass it on to the infolog handler
|
||||
// todos are handled by the infolog handler
|
||||
//$infolog_handler = new groupdav_infolog();
|
||||
//return $infolog_handler->propfind($path,$options,$files,$user,$method);
|
||||
//return $infolog_handler->propfind($options['path'],$options,$options['files'],$user,$method);
|
||||
case 'VCALENDAR':
|
||||
case 'VEVENT':
|
||||
break; // that's our default anyway
|
||||
@ -434,34 +435,78 @@ class calendar_groupdav extends groupdav_handler
|
||||
function put(&$options,$id,$user=null)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."($id, $user)".print_r($options,true));
|
||||
|
||||
$return_no_access=true; // as handled by importVCal anyway and allows it to set the status for participants
|
||||
$event = $this->_common_get_put_delete('PUT',$options,$id,$return_no_access);
|
||||
|
||||
if (!is_null($event) && !is_array($event))
|
||||
$oldEvent = $this->_common_get_put_delete('PUT',$options,$id,$return_no_access);
|
||||
if (!is_null($oldEvent) && !is_array($oldEvent))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__.print_r($event,true).function_backtrace());
|
||||
return $event;
|
||||
if ($this->debug) error_log(__METHOD__.print_r($oldEvent,true).function_backtrace());
|
||||
return $oldEvent;
|
||||
}
|
||||
|
||||
if (is_null($oldEvent) && !$this->bo->check_perms(EGW_ACL_ADD, 0, $user))
|
||||
{
|
||||
// we have no add permission on this user's calendar
|
||||
if ($this->debug) error_log(__METHOD__."(,$user) we have not enough rights on this calendar");
|
||||
return '403 Forbidden';
|
||||
}
|
||||
|
||||
$handler = $this->_get_handler();
|
||||
$vCalendar = htmlspecialchars_decode($options['content']);
|
||||
|
||||
if (!is_numeric($id) && ($foundEntries = $handler->find_event($options['content'], 'exact')))
|
||||
if (is_array($oldEvent))
|
||||
{
|
||||
$id = array_shift($foundEntries);
|
||||
$eventId = $oldEvent['id'];
|
||||
if ($return_no_access)
|
||||
{
|
||||
$retval = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// let lightning think the event is added
|
||||
$retval = '201 Created';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// new entry?
|
||||
if (($foundEvents = $handler->search($vCalendar)))
|
||||
{
|
||||
if (($eventId = array_shift($foundEvents)) &&
|
||||
(list($eventId) = explode(':', $eventId)) &&
|
||||
($oldEvent = $this->bo->read($eventId)))
|
||||
{
|
||||
$retval = '301 Moved Permanently';
|
||||
}
|
||||
else
|
||||
{
|
||||
// to be safe
|
||||
$eventId = -1;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// new entry
|
||||
$eventId = -1;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
}
|
||||
|
||||
if (!($cal_id = $handler->importVCal($options['content'],is_numeric($id) ? $id : -1,
|
||||
self::etag2value($this->http_if_match))))
|
||||
if (!($cal_id = $handler->importVCal($vCalendar, $eventId,
|
||||
self::etag2value($this->http_if_match), false, 0, $this->principalURL, $user)))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false");
|
||||
return '403 Forbidden';
|
||||
}
|
||||
|
||||
header('ETag: '.$this->get_etag($cal_id));
|
||||
if (is_null($event) || !$return_no_access) // let lightning think the event is added
|
||||
if ($retval !== true)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(,$id,$user) cal_id=$cal_id, is_null(\$event)=".(int)is_null($event));
|
||||
header('Location: '.$this->base_uri.self::get_path($cal_id));
|
||||
return '201 Created';
|
||||
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
|
||||
if ($this->debug) error_log(__METHOD__."(,$id,$user) cal_id=$cal_id: $retval");
|
||||
header('Location: '.$this->base_uri.$path.self::get_path($cal_id));
|
||||
return $retval;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -574,8 +619,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
*/
|
||||
function read($id)
|
||||
{
|
||||
//$cal_read = $this->bo->read($id,null,false,'server');//njv: do we actually get anything
|
||||
if ($this->debug > 1) error_log("bo-ical read :$id:");//njv:
|
||||
if ($this->debug > 1) error_log("bo-ical read :$id:");
|
||||
return $this->bo->read($id,null,false,'server');
|
||||
}
|
||||
|
||||
@ -616,12 +660,12 @@ class calendar_groupdav extends groupdav_handler
|
||||
{
|
||||
if ($recurrence['reference']) // ignore series master
|
||||
{
|
||||
$etag .= ':'.substr($this->get_etag($recurrence),1,-1);
|
||||
$etag .= ':'.substr($this->get_etag($recurrence),4,-4);
|
||||
}
|
||||
}
|
||||
}
|
||||
//error_log(__METHOD__ . "($entry[id] ($entry[etag]): $entry[title] --> etag=$etag");
|
||||
return '"'.$etag.'"';
|
||||
return 'EGw-'.$etag.'-wGE';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -637,23 +681,74 @@ class calendar_groupdav extends groupdav_handler
|
||||
}
|
||||
|
||||
/**
|
||||
* Add extra properties for calendar collections
|
||||
* Add the privileges of the current user
|
||||
*
|
||||
* @param array $props=array() regular props by the groupdav handler
|
||||
* @return array
|
||||
*/
|
||||
static function extra_properties(array $props=array())
|
||||
static function current_user_privilege_set(array $props=array())
|
||||
{
|
||||
// calendaring URL of the current user
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',$_SERVER['SCRIPT_NAME'].'/');
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::DAV,'current-user-privilege-set',
|
||||
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'privilege',
|
||||
array(//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'all',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'read-free-busy',''),
|
||||
//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read-current-user-privilege-set',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'bind',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'unbind',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-properties',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-content',''),
|
||||
))));
|
||||
return $props;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname);
|
||||
// BOX URLs of the current user
|
||||
/*
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-inbox-URL',
|
||||
array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/')));
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-outbox-URL',
|
||||
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/')));
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-default-calendar-URL',
|
||||
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/')));
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'dropbox-home-URL',
|
||||
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/')));
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'notifications-URL',
|
||||
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/')));
|
||||
*/
|
||||
// email of the current user, see caldav-sheduling draft
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set','MAILTO:'.$GLOBALS['egw_info']['user']['email']);
|
||||
$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[] = $sc = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array(
|
||||
$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')), // not yet supported
|
||||
// HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')), // not yet supported
|
||||
));
|
||||
|
||||
$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'))))));
|
||||
|
||||
//$props = self::current_user_privilege_set($props);
|
||||
return $props;
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ class calendar_ical extends calendar_boupdate
|
||||
'DECLINED' => 'R',
|
||||
'TENTATIVE' => 'T',
|
||||
'DELEGATED' => 'D',
|
||||
'X-UNINVITED' => 'G', // removed
|
||||
);
|
||||
|
||||
/**
|
||||
@ -148,6 +149,13 @@ class calendar_ical extends calendar_boupdate
|
||||
*/
|
||||
var $vCalendar;
|
||||
|
||||
/**
|
||||
* Addressbook BO instance
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $addressbook;
|
||||
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
@ -168,21 +176,29 @@ class calendar_ical extends calendar_boupdate
|
||||
if ($this->log) $this->logfile = $GLOBALS['egw_info']['server']['temp_dir']."/log-vcal";
|
||||
$this->clientProperties = $_clientProperties;
|
||||
$this->vCalendar = new Horde_iCalendar;
|
||||
$this->addressbook = new addressbook_bo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exports one calendar event to an iCalendar item
|
||||
*
|
||||
* @param int/array $events (array of) cal_id or array of the events
|
||||
* @param int|array $events (array of) cal_id or array of the events
|
||||
* @param string $version='1.0' could be '2.0' too
|
||||
* @param string $method='PUBLISH'
|
||||
* @param int $recur_date=0 if set export the next recurrence at or after the timestamp,
|
||||
* default 0 => export whole series (or events, if not recurring)
|
||||
* @return string/boolean string with iCal or false on error (eg. no permission to read the event)
|
||||
* @param string $principalURL='' Used for CalDAV exports
|
||||
* @return string|boolean string with iCal or false on error (eg. no permission to read the event)
|
||||
*/
|
||||
function &exportVCal($events, $version='1.0', $method='PUBLISH', $recur_date=0)
|
||||
function &exportVCal($events, $version='1.0', $method='PUBLISH', $recur_date=0, $principalURL='')
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
"($version, $method, $recur_date, $principalURL)\n",
|
||||
3, $this->logfile);
|
||||
}
|
||||
$egwSupportedFields = array(
|
||||
'CLASS' => 'public',
|
||||
'SUMMARY' => 'title',
|
||||
@ -222,7 +238,7 @@ class calendar_ical extends calendar_boupdate
|
||||
$vtimezones_added = array();
|
||||
foreach ($events as $event)
|
||||
{
|
||||
$mailtoOrganizer = false;
|
||||
$organizerURL = '';
|
||||
$organizerCN = false;
|
||||
$recurrence = $this->date2usertime($recur_date);
|
||||
$tzid = null;
|
||||
@ -453,17 +469,17 @@ class calendar_ical extends calendar_boupdate
|
||||
foreach ((array)$event['participants'] as $uid => $status)
|
||||
{
|
||||
if (!($info = $this->resource_info($uid))) continue;
|
||||
$mailtoParticipant = $info['email'] ? 'MAILTO:'.$info['email'] : '';
|
||||
$participantURL = $info['email'] ? 'MAILTO:'.$info['email'] : '';
|
||||
$participantCN = '"' . ($info['cn'] ? $info['cn'] : $info['name']) . '"';
|
||||
calendar_so::split_status($status, $quantity, $role);
|
||||
if ($role == 'CHAIR' && $uid != $this->user)
|
||||
{
|
||||
$mailtoOrganizer = $mailtoParticipant;
|
||||
$organizerURL = $participantURL;
|
||||
$organizerCN = $participantCN;
|
||||
if ($status == 'U') continue; // saved ORGANIZER
|
||||
$organizerUID = $uid;
|
||||
}
|
||||
// RB: MAILTO href contains only the email-address, NO cn!
|
||||
$attributes['ATTENDEE'][] = $mailtoParticipant;
|
||||
$attributes['ATTENDEE'][] = $participantURL;
|
||||
// RSVP={TRUE|FALSE} // resonse expected, not set in eGW => status=U
|
||||
$rsvp = $status == 'U' ? 'TRUE' : 'FALSE';
|
||||
// PARTSTAT={NEEDS-ACTION|ACCEPTED|DECLINED|TENTATIVE|DELEGATED|COMPLETED|IN-PROGRESS} everything from delegated is NOT used by eGW atm.
|
||||
@ -511,20 +527,32 @@ class calendar_ical extends calendar_boupdate
|
||||
|
||||
case 'ORGANIZER':
|
||||
// according to iCalendar standard, ORGANIZER not used for events in the own calendar
|
||||
if (!$organizerCN &&
|
||||
($event['owner'] != $this->user
|
||||
|| $this->productManufacturer != 'groupdav'
|
||||
|| $this->productName == 'kde'))
|
||||
if (!$organizerCN)
|
||||
{
|
||||
$mailtoOrganizer = $GLOBALS['egw']->accounts->id2name($event['owner'],'account_email');
|
||||
$mailtoOrganizer = $mailtoOrganizer ? 'MAILTO:'.$mailtoOrganizer : '';
|
||||
$organizerURL = $GLOBALS['egw']->accounts->id2name($event['owner'],'account_email');
|
||||
$organizerURL = $organizerURL ? 'MAILTO:'.$organizerURL : '';
|
||||
$organizerCN = '"' . trim($GLOBALS['egw']->accounts->id2name($event['owner'],'account_firstname')
|
||||
. ' ' . $GLOBALS['egw']->accounts->id2name($event['owner'],'account_lastname')) . '"';
|
||||
. ' ' . $GLOBALS['egw']->accounts->id2name($event['owner'],'account_lastname')) . '"';
|
||||
$organizerUID = $event['owner'];
|
||||
if (!isset($event['participants'][$event['owner']]))
|
||||
{
|
||||
$attributes['ATTENDEE'][] = $organizerURL;
|
||||
$parameters['ATTENDEE'][] = array(
|
||||
'CN' => $organizerCN,
|
||||
'ROLE' => 'CHAIR',
|
||||
'PARTSTAT' => 'DELEGATED',
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'RSVP' => 'FALSE',
|
||||
'X-EGROUPWARE-UID' => $event['owner'],
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($organizerCN)
|
||||
if ($this->productManufacturer != 'groupdav'
|
||||
|| !$this->check_perms(EGW_ACL_EDIT,$event['id']))
|
||||
{
|
||||
$attributes['ORGANIZER'] = $mailtoOrganizer;
|
||||
$attributes['ORGANIZER'] = $organizerURL;
|
||||
$parameters['ORGANIZER']['CN'] = $organizerCN;
|
||||
$parameters['ORGANIZER']['X-EGROUPWARE-UID'] = $organizerUID;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -950,13 +978,15 @@ class calendar_ical extends calendar_boupdate
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
* @param int $recur_date=0 if set, import the recurrence at this timestamp,
|
||||
* default 0 => import whole series (or events, if not recurring)
|
||||
* @param string $principalURL='' Used for CalDAV imports
|
||||
* @param int $user=null account_id of owner, default null
|
||||
* @return int|boolean cal_id > 0 on success, false on failure or 0 for a failed etag
|
||||
*/
|
||||
function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0)
|
||||
function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='', $user=null)
|
||||
{
|
||||
if (!is_array($this->supportedFields)) $this->setSupportedFields();
|
||||
|
||||
if (!($events = $this->icaltoegw($_vcalData)))
|
||||
if (!($events = $this->icaltoegw($_vcalData, $principalURL)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1001,8 +1031,9 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
array2string($event)."\n",3,$this->logfile);
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
."($cal_id, $etag, $recur_date, $principalURL, $user)\n"
|
||||
. array2string($event)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1090,7 +1121,7 @@ class calendar_ical extends calendar_boupdate
|
||||
else
|
||||
{
|
||||
// no merge
|
||||
if(!isset($this->supportedFields['category']))
|
||||
if(!isset($this->supportedFields['category']) || !isset($event['category']))
|
||||
{
|
||||
$event['category'] = $event_info['stored_event']['category'];
|
||||
}
|
||||
@ -1192,9 +1223,20 @@ class calendar_ical extends calendar_boupdate
|
||||
$event['non_blocking'] = 1;
|
||||
}
|
||||
|
||||
if (!is_null($user))
|
||||
{
|
||||
if ($this->check_perms(EGW_ACL_ADD, 0, $user))
|
||||
{
|
||||
$event['owner'] = $user;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // no permission
|
||||
}
|
||||
}
|
||||
// check if an owner is set and the current user has add rights
|
||||
// for that owners calendar; if not set the current user
|
||||
if (!isset($event['owner'])
|
||||
elseif (!isset($event['owner'])
|
||||
|| !$this->check_perms(EGW_ACL_ADD, 0, $event['owner']))
|
||||
{
|
||||
$event['owner'] = $this->user;
|
||||
@ -1945,11 +1987,18 @@ class calendar_ical extends calendar_boupdate
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
function icaltoegw($_vcalData)
|
||||
/**
|
||||
* Convert vCalendar data in EGw events
|
||||
*
|
||||
* @param string $_vcalData
|
||||
* @param string $principalURL='' Used for CalDAV imports
|
||||
* @return array|boolean events on success, false on failure
|
||||
*/
|
||||
function icaltoegw($_vcalData, $principalURL='')
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($principalURL)\n" .
|
||||
array2string($_vcalData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
@ -1987,7 +2036,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
if (is_a($component, 'Horde_iCalendar_vevent'))
|
||||
{
|
||||
if (($event = $this->vevent2egw($component, $version, $this->supportedFields)))
|
||||
if (($event = $this->vevent2egw($component, $version, $this->supportedFields, $principalURL)))
|
||||
{
|
||||
//common adjustments
|
||||
if ($this->productManufacturer == '' && $this->productName == ''
|
||||
@ -2020,6 +2069,14 @@ class calendar_ical extends calendar_boupdate
|
||||
$events[] = $event;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.'()' .
|
||||
get_class($component)." found\n",3,$this->logfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
@ -2033,12 +2090,21 @@ class calendar_ical extends calendar_boupdate
|
||||
* @param array $component VEVENT
|
||||
* @param string $version vCal version (1.0/2.0)
|
||||
* @param array $supportedFields supported fields of the device
|
||||
* @param string $principalURL='' Used for CalDAV imports
|
||||
*
|
||||
* @return array|boolean event on success, false on failure
|
||||
*/
|
||||
function vevent2egw(&$component, $version, $supportedFields)
|
||||
function vevent2egw(&$component, $version, $supportedFields, $principalURL='')
|
||||
{
|
||||
if (!is_a($component, 'Horde_iCalendar_vevent')) return false;
|
||||
if (!is_a($component, 'Horde_iCalendar_vevent'))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.'()' .
|
||||
get_class($component)." found\n",3,$this->logfile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'])) {
|
||||
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
|
||||
@ -2106,8 +2172,15 @@ class calendar_ical extends calendar_boupdate
|
||||
$vcardData['end'] = $dtend_ts;
|
||||
}
|
||||
}
|
||||
if (!isset($vcardData['start'])) return false; // not a valid entry
|
||||
|
||||
if (!isset($vcardData['start']))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "() DTSTART missing!\n",3,$this->logfile);
|
||||
}
|
||||
return false; // not a valid entry
|
||||
}
|
||||
// lets see what we can get from the vcard
|
||||
foreach ($component->_attributes as $attributes)
|
||||
{
|
||||
@ -2436,7 +2509,7 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
break;
|
||||
case 'ATTENDEE':
|
||||
case 'ORGANIZER': // will be written direct to the event
|
||||
case 'ORGANIZER':
|
||||
if (isset($attributes['params']['PARTSTAT']))
|
||||
{
|
||||
$attributes['params']['STATUS'] = $attributes['params']['PARTSTAT'];
|
||||
@ -2450,14 +2523,64 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$status = 'X'; // client did not return the status
|
||||
}
|
||||
$cn = '';
|
||||
if (preg_match('/MAILTO:([@.a-z0-9_-]+)|MAILTO:"?([.a-z0-9_ -]*)"?[ ]*<([@.a-z0-9_-]*)>/i',
|
||||
$uid = $email = $cn = '';
|
||||
$quantity = 1;
|
||||
$role = 'REQ-PARTICIPANT';
|
||||
if (!empty($attributes['params']['ROLE']))
|
||||
{
|
||||
$role = $attributes['params']['ROLE'];
|
||||
}
|
||||
// try pricipal url from CalDAV
|
||||
if (strpos($attributes['value'], 'http') === 0)
|
||||
{
|
||||
if (!empty($principalURL) && strstr($attributes['value'], $principalURL) !== false)
|
||||
{
|
||||
$uid = $this->user;
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "(): Found myself: '$uid'\n",3,$this->logfile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '(): Unknown URI: ' . $attributes['value']
|
||||
. "\n",3,$this->logfile);
|
||||
}
|
||||
$attributes['value'] = '';
|
||||
}
|
||||
}
|
||||
// try X-EGROUPWARE-UID
|
||||
if (!$uid && !empty($attributes['params']['X-EGROUPWARE-UID']))
|
||||
{
|
||||
$uid = $attributes['params']['X-EGROUPWARE-UID'];
|
||||
if (!empty($attributes['params']['X-EGROUPWARE-QUANTITY']))
|
||||
{
|
||||
$quantity = $attributes['params']['X-EGROUPWARE-QUANTITY'];
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "(): Found X-EGROUPWARE-UID: '$uid'\n",3,$this->logfile);
|
||||
}
|
||||
}
|
||||
elseif ($attributes['value'] == 'Unknown')
|
||||
{
|
||||
// we use the current user
|
||||
$uid = $this->user;
|
||||
}
|
||||
// try to find an email address
|
||||
elseif (preg_match('/MAILTO:([@.a-z0-9_-]+)|MAILTO:"?([.a-z0-9_ -]*)"?[ ]*<([@.a-z0-9_-]*)>/i',
|
||||
$attributes['value'],$matches))
|
||||
{
|
||||
$email = $matches[1] ? $matches[1] : $matches[3];
|
||||
$cn = isset($matches[2]) ? $matches[2]: '';
|
||||
}
|
||||
elseif (preg_match('/"?([.a-z0-9_ -]*)"?[ ]*<([@.a-z0-9_-]*)>/i',
|
||||
elseif (!empty($attributes['value']) &&
|
||||
preg_match('/"?([.a-z0-9_ -]*)"?[ ]*<([@.a-z0-9_-]*)>/i',
|
||||
$attributes['value'],$matches))
|
||||
{
|
||||
$cn = $matches[1];
|
||||
@ -2467,82 +2590,92 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$email = $attributes['value'];
|
||||
}
|
||||
else
|
||||
if (!$uid && $email && ($uid = $GLOBALS['egw']->accounts->name2id($email, 'account_email')))
|
||||
{
|
||||
$email = false; // no email given
|
||||
}
|
||||
$searcharray = array();
|
||||
if ($email)
|
||||
{
|
||||
$searcharray = array('email' => $email, 'email_home' => $email);
|
||||
}
|
||||
if (isset($attributes['params']['CN']) && $attributes['params']['CN'])
|
||||
{
|
||||
if ($attributes['params']['CN'][0] == '"'
|
||||
&& substr($attributes['params']['CN'],-1) == '"')
|
||||
// we use the account we found
|
||||
if ($this->log)
|
||||
{
|
||||
$attributes['params']['CN'] = substr($attributes['params']['CN'],1,-1);
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "() Found account: '$uid', '$cn', '$email'\n",3,$this->logfile);
|
||||
}
|
||||
$searcharray['n_fn'] = $attributes['params']['CN'];
|
||||
}
|
||||
elseif ($cn)
|
||||
if (!$uid)
|
||||
{
|
||||
$searcharray['n_fn'] = $cn;
|
||||
}
|
||||
if (($uid = $attributes['params']['X-EGROUPWARE-UID'])
|
||||
&& ($info = $this->resource_info($uid))
|
||||
&& (!$email || $info['email'] == $email))
|
||||
{
|
||||
// we use the (checked) X-EGROUPWARE-UID
|
||||
}
|
||||
|
||||
//elseif (//$attributes['params']['CUTYPE'] == 'GROUP'
|
||||
elseif (preg_match('/(.*) Group/', $searcharray['n_fn'], $matches))
|
||||
{
|
||||
if (($uid = $GLOBALS['egw']->accounts->name2id($matches[1], 'account_lid', 'g')))
|
||||
$searcharray = array();
|
||||
// search for provided email address ...
|
||||
if ($email)
|
||||
{
|
||||
//Horde::logMessage("vevent2egw: group participant $uid",
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($status != 'X' && $status != 'U')
|
||||
$searcharray = array('email' => $email, 'email_home' => $email);
|
||||
}
|
||||
// ... and for provided CN
|
||||
if (!empty($attributes['params']['CN']))
|
||||
{
|
||||
if ($attributes['params']['CN'][0] == '"'
|
||||
&& substr($attributes['params']['CN'],-1) == '"')
|
||||
{
|
||||
// User tries to reply to the group invitiation
|
||||
$members = $GLOBALS['egw']->accounts->members($uid, true);
|
||||
if (in_array($this->user, $members))
|
||||
$cn = substr($attributes['params']['CN'],1,-1);
|
||||
}
|
||||
$searcharray['n_fn'] = $cn;
|
||||
}
|
||||
elseif ($cn)
|
||||
{
|
||||
$searcharray['n_fn'] = $cn;
|
||||
}
|
||||
|
||||
//elseif (//$attributes['params']['CUTYPE'] == 'GROUP'
|
||||
if (preg_match('/(.*) Group/', $cn, $matches))
|
||||
{
|
||||
if (($uid = $GLOBALS['egw']->accounts->name2id($matches[1], 'account_lid', 'g')))
|
||||
{
|
||||
//Horde::logMessage("vevent2egw: group participant $uid",
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if (!isset($vcardData['participants'][$this->user]) &&
|
||||
$status != 'X' && $status != 'U')
|
||||
{
|
||||
//Horde::logMessage("vevent2egw: set status to " . $status,
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$vcardData['participants'][$this->user] =
|
||||
calendar_so::combine_status($status);
|
||||
// User tries to reply to the group invitiation
|
||||
$members = $GLOBALS['egw']->accounts->members($uid, true);
|
||||
if (in_array($this->user, $members))
|
||||
{
|
||||
//Horde::logMessage("vevent2egw: set status to " . $status,
|
||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$vcardData['participants'][$this->user] =
|
||||
calendar_so::combine_status($status,$quantity,$role);
|
||||
}
|
||||
}
|
||||
$status = 'U'; // keep the group
|
||||
}
|
||||
else continue; // can't find this group
|
||||
}
|
||||
else continue; // can't find this group
|
||||
}
|
||||
elseif ($attributes['value'] == 'Unknown')
|
||||
{
|
||||
$uid = $this->user;
|
||||
}
|
||||
elseif ($email && ($uid = $GLOBALS['egw']->accounts->name2id($email,'account_email')))
|
||||
{
|
||||
// we use the account we found
|
||||
}
|
||||
elseif (!$searcharray)
|
||||
{
|
||||
continue; // participants without email AND CN --> ignore it
|
||||
}
|
||||
elseif ((list($data) = ExecMethod2('addressbook.addressbook_bo.search',$searcharray,
|
||||
array('id','egw_addressbook.account_id as account_id','n_fn'),'egw_addressbook.account_id IS NOT NULL DESC, n_fn IS NOT NULL DESC','','',false,'OR')))
|
||||
{
|
||||
$uid = $data['account_id'] ? (int)$data['account_id'] : 'c'.$data['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$email)
|
||||
elseif (empty($searcharray))
|
||||
{
|
||||
$email = 'no-email@egroupware.org'; // set dummy email to store the CN
|
||||
continue; // participants without email AND CN --> ignore it
|
||||
}
|
||||
elseif ((list($data) = $this->addressbook->search($searcharray,
|
||||
array('id','egw_addressbook.account_id as account_id','n_fn'),
|
||||
'egw_addressbook.account_id IS NOT NULL DESC, n_fn IS NOT NULL DESC',
|
||||
'','',false,'OR')))
|
||||
{
|
||||
// found an addressbook entry
|
||||
$uid = $data['account_id'] ? (int)$data['account_id'] : 'c'.$data['id'];
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "() Found addressbook entry: '$uid', '$cn', '$email'\n",3,$this->logfile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$email)
|
||||
{
|
||||
$email = 'no-email@egroupware.org'; // set dummy email to store the CN
|
||||
}
|
||||
$uid = 'e'. ($cn ? '"' . $cn . '" <' . $email . '>' : $email);
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "() Not Found, create dummy: '$uid', '$cn', '$email'\n",3,$this->logfile);
|
||||
}
|
||||
}
|
||||
$uid = 'e'.($attributes['params']['CN'] ? $attributes['params']['CN'].' <'.$email.'>' : $email);
|
||||
}
|
||||
switch($attributes['name'])
|
||||
{
|
||||
@ -2558,9 +2691,15 @@ class calendar_ical extends calendar_boupdate
|
||||
// for multiple entries the ACCEPT wins
|
||||
// add quantity and role
|
||||
$vcardData['participants'][$uid] =
|
||||
calendar_so::combine_status($status,
|
||||
$attributes['params']['X-EGROUPWARE-QUANTITY'],
|
||||
$attributes['params']['ROLE']);
|
||||
calendar_so::combine_status($status, $quantity, $role);
|
||||
|
||||
if (!$this->calendarOwner && is_numeric($uid) &&
|
||||
$role == 'CHAIR' &&
|
||||
is_a($component->getAttribute('ORGANIZER'), 'PEAR_Error'))
|
||||
{
|
||||
// we can store the ORGANIZER as event owner
|
||||
$event['owner'] = $uid;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -2572,7 +2711,7 @@ class calendar_ical extends calendar_boupdate
|
||||
$vcardData['participants'][$uid] =
|
||||
calendar_so::combine_status($status, $quantity, 'CHAIR');
|
||||
}
|
||||
if (is_numeric($uid) && ($uid == $this->calendarOwner || !$this->calendarOwner))
|
||||
if (!$this->calendarOwner && is_numeric($uid))
|
||||
{
|
||||
// we can store the ORGANIZER as event owner
|
||||
$event['owner'] = $uid;
|
||||
@ -2585,7 +2724,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
// save the ORGANIZER as event CHAIR
|
||||
$vcardData['participants'][$uid] =
|
||||
calendar_so::combine_status('U', 1, 'CHAIR');
|
||||
calendar_so::combine_status('D', 1, 'CHAIR');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2694,9 +2833,14 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$filter = $relax ? 'relax' : 'check';
|
||||
$event = array_shift($events);
|
||||
$eventId = -1;
|
||||
if ($this->so->isWholeDay($event)) $event['whole_day'] = true;
|
||||
if ($contentID)
|
||||
{
|
||||
$parts = preg_split('/:/', $contentID);
|
||||
$event['id'] = $eventId = $parts[0];
|
||||
}
|
||||
$event['category'] = $this->find_or_add_categories($event['category'], $eventId);
|
||||
if ($contentID) $event['id'] = $contentID;
|
||||
return $this->find_event($event, $filter);
|
||||
}
|
||||
if ($this->log)
|
||||
|
@ -758,15 +758,35 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
array('cal_id' => $event['cal_id']),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
// write information about recuring event, if recur_type is present in the array
|
||||
if (isset($event['recur_type']))
|
||||
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
// fetch information about the currently saved (old) event
|
||||
$old_min = (int) $this->db->select($this->dates_table,'MIN(cal_start)',array('cal_id'=>$cal_id),__LINE__,__FILE__,false,'','calendar')->fetchColumn();
|
||||
$old_duration = (int) $this->db->select($this->dates_table,'MIN(cal_end)',array('cal_id'=>$cal_id),__LINE__,__FILE__,false,'','calendar')->fetchColumn() - $old_min;
|
||||
$old_repeats = $this->db->select($this->repeats_table,'*',array('cal_id' => $cal_id),__LINE__,__FILE__,false,'','calendar')->fetch();
|
||||
$old_exceptions = $old_repeats['recur_exception'] ? explode(',',$old_repeats['recur_exception']) : array();
|
||||
if (!empty($old_exceptions))
|
||||
{
|
||||
sort($old_exceptions);
|
||||
if ($old_min > $old_exceptions[0]) $old_min = $old_exceptions[0];
|
||||
}
|
||||
|
||||
$event['recur_exception'] = is_array($event['recur_exception']) ? $event['recur_exception'] : array();
|
||||
if (!empty($event['recur_exception']))
|
||||
{
|
||||
sort($event['recur_exception']);
|
||||
}
|
||||
|
||||
$where = array('cal_id' => $cal_id,
|
||||
'cal_recur_date' => 0);
|
||||
$old_participants = array();
|
||||
foreach ($this->db->select($this->user_table,'cal_user_type,cal_user_id,cal_status,cal_quantity,cal_role', $where,
|
||||
__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
{
|
||||
$uid = self::combine_user($row['cal_user_type'], $row['cal_user_id']);
|
||||
$status = self::combine_status($row['cal_status'], $row['cal_quantity'], $row['cal_role']);
|
||||
$old_participants[$uid] = $status;
|
||||
}
|
||||
|
||||
// re-check: did so much recurrence data change that we have to rebuild it from scratch?
|
||||
if (!$set_recurrences)
|
||||
@ -795,18 +815,20 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
{
|
||||
// we adjust some possibly changed recurrences manually
|
||||
// deleted exceptions: re-insert recurrences into the user and dates table
|
||||
if(count($deleted_exceptions = array_diff($old_exceptions,$event['recur_exception'])))
|
||||
if (count($deleted_exceptions = array_diff($old_exceptions,$event['recur_exception'])))
|
||||
{
|
||||
if (isset($event['cal_participants']))
|
||||
{
|
||||
$participants = $event['cal_participants'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// use old default
|
||||
$participants = $old_participants;
|
||||
}
|
||||
foreach($deleted_exceptions as $id => $deleted_exception)
|
||||
{
|
||||
// rebuild participants for the re-inserted recurrence
|
||||
$participants = array();
|
||||
$participants_only = $this->get_participants($cal_id); // participants without states
|
||||
foreach($participants_only as $id => $participant_only)
|
||||
{
|
||||
$states = $this->get_recurrences($cal_id, $participant_only['uid']);
|
||||
$participants[$participant_only['uid']] = $states[0]; // insert main status as default
|
||||
}
|
||||
$this->recurrence($cal_id, $deleted_exception, $deleted_exception + $old_duration, $participants);
|
||||
}
|
||||
}
|
||||
@ -1058,11 +1080,12 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
/**
|
||||
* updates the participants of an event, taken into account the evtl. recurrences of the event(!)
|
||||
* this method just adds new participants or removes not longer set participants
|
||||
* this method does never overwrite existing entries (except for delete)
|
||||
* this method does never overwrite existing entries (except the 0-recurrence and for delete)
|
||||
*
|
||||
* @param int $cal_id
|
||||
* @param array $participants uid => status pairs
|
||||
* @param int|boolean $change_since=0, false=new entry, 0=all, > 0 time from which on the repetitions should be changed
|
||||
* @param int|boolean $change_since=0, false=new event,
|
||||
* 0=all, > 0 time from which on the repetitions should be changed
|
||||
* @param boolean $add_only=false
|
||||
* false = add AND delete participants if needed (full list of participants required in $participants)
|
||||
* true = only add participants if needed, no participant will be deleted (participants to check/add required in $participants)
|
||||
@ -1148,7 +1171,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
// update participants
|
||||
foreach($participants as $uid => $status)
|
||||
{
|
||||
$id = null;
|
||||
$type = $id = $quantity = $role = null;
|
||||
self::split_user($uid,$type,$id);
|
||||
self::split_status($status,$quantity,$role);
|
||||
$set = array(
|
||||
|
@ -30,30 +30,25 @@ class infolog_bo
|
||||
var $vfs_basedir='/infolog';
|
||||
var $link_pathes = array();
|
||||
var $send_file_ips = array();
|
||||
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $log = false;
|
||||
|
||||
|
||||
/**
|
||||
* Cached timezone data
|
||||
*
|
||||
* @var array id => data
|
||||
*/
|
||||
protected static $tz_cache = array();
|
||||
|
||||
/**
|
||||
* current time as timestamp in user-time and server-time
|
||||
*
|
||||
* var int
|
||||
* @var int
|
||||
*/
|
||||
var $user_time_now;
|
||||
var $now;
|
||||
|
||||
/**
|
||||
* name of timestamps in an InfoLog entry
|
||||
*
|
||||
@ -288,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
|
||||
*/
|
||||
@ -514,13 +509,13 @@ class infolog_bo
|
||||
/**
|
||||
* 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
|
||||
* @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
|
||||
* @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,$date_format='ts')
|
||||
{
|
||||
@ -558,7 +553,7 @@ class infolog_bo
|
||||
{
|
||||
$time = new egw_time($data['info_enddate'], egw_time::$server_timezone);
|
||||
// Set due date to 00:00
|
||||
$time->setTime(0, 0,0 );
|
||||
$time->setTime(0, 0, 0);
|
||||
$data['info_enddate'] = egw_time::to($time,'ts');
|
||||
}
|
||||
|
||||
@ -568,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)
|
||||
@ -691,7 +686,7 @@ 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];
|
||||
}
|
||||
@ -790,7 +785,7 @@ class infolog_bo
|
||||
}
|
||||
else
|
||||
{
|
||||
$time = new egw_time($values['info_enddate'], egw_time::$user_timezone);
|
||||
$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');
|
||||
@ -821,13 +816,13 @@ class infolog_bo
|
||||
{
|
||||
$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(
|
||||
@ -910,11 +905,12 @@ class infolog_bo
|
||||
{
|
||||
$query['start'] = egw_time::user2server($query['start'],'ts');
|
||||
}
|
||||
|
||||
$ret = $this->so->search($query);
|
||||
|
||||
if (is_array($ret))
|
||||
{
|
||||
foreach($ret as $id => &$data)
|
||||
foreach ($ret as $id => &$data)
|
||||
{
|
||||
if (!$this->check_access($data,EGW_ACL_READ))
|
||||
{
|
||||
@ -922,7 +918,7 @@ class infolog_bo
|
||||
continue;
|
||||
}
|
||||
// convert system- to user-time
|
||||
foreach($this->timestamps as $key)
|
||||
foreach ($this->timestamps as $key)
|
||||
{
|
||||
if ($data[$key])
|
||||
{
|
||||
@ -1043,8 +1039,8 @@ 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)
|
||||
{
|
||||
@ -1068,13 +1064,13 @@ class infolog_bo
|
||||
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
|
||||
}
|
||||
@ -1103,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);
|
||||
}
|
||||
@ -1173,7 +1169,7 @@ class infolog_bo
|
||||
}
|
||||
while ($infos = $this->search($query))
|
||||
{
|
||||
foreach($infos as $info)
|
||||
foreach ($infos as $info)
|
||||
{
|
||||
$start = new egw_time($info['info_startdate'],egw_time::$user_timezone);
|
||||
$time = (int) $start->format('Hi');
|
||||
@ -1189,7 +1185,7 @@ class infolog_bo
|
||||
$info['info_subject'];
|
||||
$view = egw_link::view('infolog',$info['info_id']);
|
||||
$content=array();
|
||||
foreach($icons = array(
|
||||
foreach ($icons = array(
|
||||
$info['info_type'] => 'infolog',
|
||||
$this->status[$info['info_type']][$info['info_status']] => 'infolog',
|
||||
) as $name => $app)
|
||||
@ -1228,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) != '%')
|
||||
{
|
||||
@ -1262,11 +1258,11 @@ class infolog_bo
|
||||
// preserve categories without users read access
|
||||
$old_infolog = $this->read($info_id);
|
||||
$old_categories = explode(',',$old_infolog['info_cat']);
|
||||
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;
|
||||
}
|
||||
@ -1275,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-');
|
||||
@ -1550,7 +1546,7 @@ class infolog_bo
|
||||
&& ($egwData = $this->read($infoData['info_id'], true, 'server')))
|
||||
{
|
||||
// we only do a simple consistency check
|
||||
if (strpos($egwData['info_subject'], $infoData['info_subject']) === 0)
|
||||
if (!$relax || strpos($egwData['info_subject'], $infoData['info_subject']) === 0)
|
||||
{
|
||||
return array($egwData['info_id']);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
@ -212,7 +307,39 @@ class infolog_groupdav extends groupdav_handler
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,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, true, 'server');
|
||||
if (is_array($task))
|
||||
{
|
||||
$taskData = $task;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!($taskData = $this->read($task, true, 'server'))) return false;
|
||||
}
|
||||
|
||||
if ($taskData['info_id_parent'])
|
||||
{
|
||||
@ -151,6 +158,12 @@ 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);
|
||||
@ -407,9 +420,10 @@ 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 ($this->tzid)
|
||||
@ -438,6 +452,11 @@ 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" .
|
||||
@ -615,7 +634,7 @@ class infolog_ical extends infolog_bo
|
||||
// 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;
|
||||
if ($attr['name'] == 'X-INFOLOG-STATUS') break;
|
||||
}
|
||||
$taskData['info_status'] = $this->vtodo2status($attribute['value'],
|
||||
$attr['name'] == 'X-INFOLOG-STATUS' ? $attr['value'] : null);
|
||||
@ -668,7 +687,8 @@ class infolog_ical extends infolog_bo
|
||||
*/
|
||||
function exportVNOTE($_noteID, $_type)
|
||||
{
|
||||
$note = $this->read($_noteID, true, 'server');
|
||||
if(!($note = $this->read($_noteID, true, 'server'))) return false;
|
||||
|
||||
$note = $GLOBALS['egw']->translation->convert($note,
|
||||
$GLOBALS['egw']->translation->charset(), 'UTF-8');
|
||||
|
||||
|
@ -121,7 +121,7 @@ class infolog_sif extends infolog_bo
|
||||
*
|
||||
* @param int|string|DateTime $time in server-time as returned by calendar_bo for $data_format='server'
|
||||
* @param string $tzid TZID of event or 'UTC' or NULL for palmos timestamps in usertime
|
||||
* @return mixed attribute value to set: integer timestamp if $tzid == 'UTC' otherwise Ymd\THis string IN $tzid
|
||||
*
|
||||
*/
|
||||
function getDateTime($time, $tzid)
|
||||
{
|
||||
@ -142,12 +142,14 @@ class infolog_sif extends infolog_bo
|
||||
{
|
||||
$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 $time->format('Ymd\THis');
|
||||
return $value;
|
||||
}
|
||||
|
||||
function startElement($_parser, $_tag, $_attributes)
|
||||
@ -509,12 +511,12 @@ class infolog_sif extends infolog_bo
|
||||
|
||||
case 'DueDate':
|
||||
case 'StartDate':
|
||||
$sifTask .= '<$sifField>';
|
||||
$sifTask .= "<$sifField>";
|
||||
if (!empty($value))
|
||||
{
|
||||
$sifTask .= $this->getDateTime($value, $this->tzid);
|
||||
}
|
||||
$sifTask .= '</$sifField>';
|
||||
$sifTask .= "</$sifField>";
|
||||
break;
|
||||
|
||||
case 'Importance':
|
||||
|
@ -36,6 +36,10 @@ require_once('HTTP/WebDAV/Server.php');
|
||||
*/
|
||||
class groupdav extends HTTP_WebDAV_Server
|
||||
{
|
||||
/**
|
||||
* DAV namespace
|
||||
*/
|
||||
const DAV = 'DAV:';
|
||||
/**
|
||||
* GroupDAV namespace
|
||||
*/
|
||||
@ -70,7 +74,7 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
'component-set' => array(self::GROUPDAV => 'VCARD'),
|
||||
),
|
||||
'infolog' => array(
|
||||
'resourcetype' => array(self::GROUPDAV => 'vtodo-collection'),
|
||||
'resourcetype' => array(self::GROUPDAV => 'vtodo-collection', self::CALDAV => 'calendar'),
|
||||
'component-set' => array(self::GROUPDAV => 'VTODO'),
|
||||
),
|
||||
);
|
||||
@ -81,7 +85,7 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $debug = 0;
|
||||
var $debug = 3;
|
||||
|
||||
/**
|
||||
* eGW's charset
|
||||
@ -101,6 +105,19 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
* @var groupdav_handler
|
||||
*/
|
||||
var $handler;
|
||||
/**
|
||||
* principal URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $principalURL;
|
||||
/**
|
||||
* Reference to the accounts class
|
||||
*
|
||||
* @var accounts
|
||||
*/
|
||||
var $accounts;
|
||||
|
||||
|
||||
function __construct()
|
||||
{
|
||||
@ -115,11 +132,24 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
case 'davkit': // iCal app in OS X 10.6 created wrong request, if full url given
|
||||
$this->client_require_href_as_url = false;
|
||||
break;
|
||||
case 'cfnetwork':
|
||||
$this->crrnd = true; // Apple Addressbook.app does not cope with namespace redundancy
|
||||
}
|
||||
parent::HTTP_WebDAV_Server();
|
||||
|
||||
$this->translation =& $GLOBALS['egw']->translation;
|
||||
$this->egw_charset = $this->translation->charset();
|
||||
if (strpos($this->base_uri, 'http') === 0)
|
||||
{
|
||||
$this->principalURL = $this->_slashify($this->base_uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->principalURL = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:") .
|
||||
'//' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '/';
|
||||
}
|
||||
$this->principalURL .= 'principals/users/'.$GLOBALS['egw_info']['user']['account_lid'].'/';
|
||||
$this->accounts = $GLOBALS['egw']->accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,7 +160,7 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
*/
|
||||
function app_handler($app)
|
||||
{
|
||||
return groupdav_handler::app_handler($app,$this->debug,$this->base_uri);
|
||||
return groupdav_handler::app_handler($app,$this->debug,$this->base_uri,$this->principalURL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,11 +176,24 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
switch($app)
|
||||
{
|
||||
case 'calendar':
|
||||
$dav[] = 2;
|
||||
$dav[] = 'access-control';
|
||||
$dav[] = 'calendar-access';
|
||||
//$dav[] = 'calendar-schedule';
|
||||
//$dav[] = 'calendar-proxy';
|
||||
//$dav[] = 'calendar-avialibility';
|
||||
//$dav[] = 'calendarserver-private-events';
|
||||
break;
|
||||
case 'addressbook':
|
||||
$dav[] = 'addressbook';
|
||||
$dav[] = 2;
|
||||
$dav[] = 3;
|
||||
$dav[] = 'access-control';
|
||||
$dav[] = 'addressbook-access';
|
||||
break;
|
||||
default:
|
||||
$dav[] = 2;
|
||||
$dav[] = 'access-control';
|
||||
$dav[] = 'calendar-access';
|
||||
}
|
||||
// not yet implemented: $dav[] = 'access-control';
|
||||
}
|
||||
@ -162,62 +205,101 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
* @param array return array for file properties
|
||||
* @return bool true on success
|
||||
*/
|
||||
function PROPFIND(&$options, &$files,$method='PROPFIND')
|
||||
function PROPFIND(&$options, &$files, $method='PROPFIND')
|
||||
{
|
||||
if ($this->debug) error_log(__CLASS__."::$method(".array2string($options,true).')');
|
||||
|
||||
|
||||
if (groupdav_handler::get_agent() == 'cfnetwork' && // Apple Addressbook
|
||||
$options['root']['name'] == 'propfind')
|
||||
{
|
||||
foreach ($options['props'] as $props)
|
||||
{
|
||||
if ($props['name'] == 'current-user-privilege-set')
|
||||
{
|
||||
if ($this->debug > 2) error_log(__CLASS__."::$method: current-user-privilege-set not implemented!");
|
||||
return '501 Not Implemented';
|
||||
}
|
||||
}
|
||||
}
|
||||
// parse path in form [/account_lid]/app[/more]
|
||||
if (!self::_parse_path($options['path'],$id,$app,$user,$user_prefix) && $app && !$user)
|
||||
{
|
||||
if ($this->debug > 1) error_log(__CLASS__."::$method: user=$user, app=$app, id=$id: 404 not found!");
|
||||
if ($this->debug > 1) error_log(__CLASS__."::$method: user='$user', app='$app', id='$id': 404 not found!");
|
||||
return '404 Not Found';
|
||||
}
|
||||
if ($this->debug > 1) error_log(__CLASS__."::$method: user=$user, app='$app', id=$id");
|
||||
if ($this->debug > 1) error_log(__CLASS__."::$method: user='$user', app='$app', id='$id'");
|
||||
|
||||
if ($user)
|
||||
{
|
||||
$account_lid = $this->accounts->id2name($user);
|
||||
}
|
||||
else
|
||||
{
|
||||
$account_lid = $GLOBALS['egw_info']['user']['account_lid'];
|
||||
}
|
||||
$account = $this->accounts->read($account_lid);
|
||||
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
|
||||
$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
|
||||
$files = array('files' => array());
|
||||
$path = $user_prefix = $this->_slashify($user_prefix);
|
||||
|
||||
if (!$app) // root folder containing apps
|
||||
if (!$app) // user root folder containing apps
|
||||
{
|
||||
if (empty($user_prefix))
|
||||
{
|
||||
$user_prefix = '/'.$GLOBALS['egw_info']['user']['account_lid'].'/';
|
||||
}
|
||||
if ($options['depth'])
|
||||
{
|
||||
$displayname = 'EGroupware (Cal|Card|Group)DAV server';
|
||||
}
|
||||
// self url
|
||||
$files['files'][] = array(
|
||||
'path' => $user_prefix.'/',
|
||||
'props' => array(
|
||||
self::mkprop('displayname','EGroupware (Cal|Card|Group)DAV server'),
|
||||
self::mkprop('resourcetype','collection'),
|
||||
$props = array(
|
||||
self::mkprop('displayname',$displayname),
|
||||
self::mkprop('resourcetype',array(self::mkprop('collection',''))),
|
||||
// adding the calendar extra property (calendar-home-set, etc.) here, allows apple iCal to "autodetect" the URL
|
||||
self::mkprop(groupdav::CALDAV,'calendar-home-set',$this->base_uri.'/calendar/'),
|
||||
self::mkprop('current-user-principal',array(self::mkprop('href',$this->base_uri.'/principals/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
|
||||
),
|
||||
self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
|
||||
self::mkprop('href',$this->base_uri.$user_prefix.'calendar/'))),
|
||||
self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
|
||||
self::mkprop('href',$this->base_uri.$user_prefix))),
|
||||
self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))),
|
||||
self::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
|
||||
self::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))),
|
||||
//self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
|
||||
//self::mkprop('principal-collection-set',array(self::mkprop('href',$this->base_uri.'/principals/'))),
|
||||
);
|
||||
//$props = self::current_user_privilege_set($props);
|
||||
$files['files'][] = array(
|
||||
'path' => $path,
|
||||
'props' => $props,
|
||||
);
|
||||
if ($options['depth'])
|
||||
{
|
||||
if (empty($user_prefix))
|
||||
if (strlen($path) == 1) // GroupDAV Root
|
||||
{
|
||||
// principals collection
|
||||
$files['files'][] = array(
|
||||
'path' => '/principals/',
|
||||
'props' => array(
|
||||
self::mkprop('displayname',lang('Accounts')),
|
||||
self::mkprop('resourcetype','collection'),
|
||||
self::mkprop('current-user-principal',array(self::mkprop('href',$this->base_uri.'/principals/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
|
||||
),
|
||||
);
|
||||
// groups collection
|
||||
$files['files'][] = array(
|
||||
'path' => '/groups/',
|
||||
'props' => array(
|
||||
self::mkprop('displayname',lang('Groups')),
|
||||
self::mkprop('resourcetype','collection'),
|
||||
self::mkprop('current-user-principal',array(self::mkprop('href',$this->base_uri.'/principals/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
|
||||
),
|
||||
);
|
||||
self::mkprop('displayname',lang('Accounts')),
|
||||
self::mkprop('resourcetype',array(self::mkprop('collection',''))),
|
||||
self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))),
|
||||
self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
|
||||
self::mkprop('href',$this->base_uri.$user_prefix.'calendar/'))),
|
||||
self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
|
||||
self::mkprop('href',$this->base_uri.'/'))),
|
||||
self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
|
||||
),
|
||||
);
|
||||
}
|
||||
foreach($this->root as $app => $data)
|
||||
{
|
||||
if (!$GLOBALS['egw_info']['user']['apps'][$app]) continue; // no rights for the given app
|
||||
|
||||
$files['files'][] = array(
|
||||
'path' => $user_prefix.'/'.$app.'/',
|
||||
'path' => $path.$app.'/',
|
||||
'props' => $this->_properties($app,false,$user),
|
||||
);
|
||||
}
|
||||
@ -234,12 +316,12 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
if ($method != 'REPORT' && !$id) // no self URL for REPORT requests (only PROPFIND) or propfinds on an id
|
||||
{
|
||||
$files['files'][0] = array(
|
||||
'path' => '/'.$app.'/',
|
||||
'path' => $path.$app.'/',
|
||||
// KAddressbook doubles the folder, if the self URL contains the GroupDAV/CalDAV resourcetypes
|
||||
'props' => $this->_properties($app,$app=='addressbook'&&strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') !== false),
|
||||
'props' => $this->_properties($app,$app=='addressbook'&&strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') !== false,$user),
|
||||
);
|
||||
}
|
||||
if (!$options['depth'] && !$id)
|
||||
if (isset($options['depth']) && !$options['depth'] && !$id)
|
||||
{
|
||||
// add ctag if handler implements it (only for depth 0)
|
||||
if (method_exists($handler,'getctag'))
|
||||
@ -249,7 +331,7 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
}
|
||||
return true; // depth 0 --> show only the self url
|
||||
}
|
||||
return $handler->propfind($options['path'],$options,$files,$user,$id);
|
||||
return $handler->propfind($this->_slashify($options['path']),$options,$files,$user,$id);
|
||||
}
|
||||
return '501 Not Implemented';
|
||||
}
|
||||
@ -264,12 +346,54 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
*/
|
||||
function _properties($app,$no_extra_types=false,$user=null)
|
||||
{
|
||||
if (!$user) $user = $GLOBALS['egw_info']['user']['account_fullname'];
|
||||
|
||||
if ($this->debug) error_log(__CLASS__."::$method: user='$user', app='$app'");
|
||||
if ($user)
|
||||
{
|
||||
$account_lid = $this->accounts->id2name($user);
|
||||
}
|
||||
else
|
||||
{
|
||||
$account_lid = $GLOBALS['egw_info']['user']['account_lid'];
|
||||
}
|
||||
$account = $this->accounts->read($account_lid);
|
||||
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
|
||||
$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
$props = array(
|
||||
self::mkprop('displayname',$this->translation->convert(lang($app).' '.common::grab_owner_name($user),$this->egw_charset,'utf-8')),
|
||||
self::mkprop('current-user-principal',array(self::mkprop('href',$this->base_uri.'/principals/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
|
||||
);
|
||||
self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))),
|
||||
self::mkprop('owner',$displayname),
|
||||
self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
|
||||
self::mkprop('alternate-URI-set',array(
|
||||
self::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))),
|
||||
self::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
|
||||
self::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))),
|
||||
self::mkprop('principal-collection-set',array(
|
||||
self::mkprop('href',$this->base_uri.'/principals/users/'),
|
||||
self::mkprop('href',$this->base_uri.'/principals/groups/'),
|
||||
)),
|
||||
);
|
||||
|
||||
switch ($app)
|
||||
{
|
||||
case 'calendar':
|
||||
$props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
|
||||
self::mkprop('href',$this->base_uri.'/'.$account_lid.'/calendar/')));
|
||||
break;
|
||||
case 'infolog':
|
||||
$props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
|
||||
self::mkprop('href',$this->base_uri.'/'.$account_lid.'/infolog/')));
|
||||
$displayname = $this->translation->convert(lang($app).' '.
|
||||
common::grab_owner_name($user),$this->egw_charset,'utf-8');
|
||||
break;
|
||||
default:
|
||||
$props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
|
||||
self::mkprop('href',$this->base_uri.'/'.$account_lid.'/calendar/')));
|
||||
$displayname = $this->translation->convert(lang($app).' '.
|
||||
common::grab_owner_name($user),$this->egw_charset,'utf-8');
|
||||
}
|
||||
$props[] = self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
|
||||
self::mkprop('href',$this->base_uri.'/'.$account_lid.'/')));
|
||||
$props[] = self::mkprop('displayname',$displayname);
|
||||
|
||||
foreach((array)$this->root[$app] as $prop => $values)
|
||||
{
|
||||
if ($prop == 'resourcetype')
|
||||
@ -296,7 +420,9 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
}
|
||||
if (method_exists($app.'_groupdav','extra_properties'))
|
||||
{
|
||||
$props = ExecMethod($app.'_groupdav::extra_properties',$props);
|
||||
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
|
||||
$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
$props = ExecMethod2($app.'_groupdav::extra_properties',$props,$displayname,$this->base_uri);
|
||||
}
|
||||
return $props;
|
||||
}
|
||||
@ -401,8 +527,7 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
$props = $this->props2array($file['props']);
|
||||
//echo $file['path']; _debug_array($props);
|
||||
$class = $class == 'row_on' ? 'row_off' : 'row_on';
|
||||
$name = $this->_slashify(basename($this->_unslashify($file['path'])));
|
||||
/*
|
||||
|
||||
if (substr($file['path'],-1) == '/')
|
||||
{
|
||||
$name = basename(substr($file['path'],0,-1)).'/';
|
||||
@ -411,7 +536,7 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
{
|
||||
$name = basename($file['path']);
|
||||
}
|
||||
*/
|
||||
|
||||
echo "\t<tr class='$class'>\n\t\t<td>$n</td>\n\t\t<td>".html::a_href(htmlspecialchars($name),'/groupdav.php'.$file['path'])."</td>\n";
|
||||
echo "\t\t<td>".$props['DAV:getcontentlength']."</td>\n";
|
||||
echo "\t\t<td>".(!empty($props['DAV:getlastmodified']) ? date('Y-m-d H:i:s',$props['DAV:getlastmodified']) : '')."</td>\n";
|
||||
@ -664,6 +789,34 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
return egw_vfs::checkLock($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* ACL method handler
|
||||
*
|
||||
* @param array general parameter passing array
|
||||
* @return string HTTP status
|
||||
*/
|
||||
function ACL(&$options)
|
||||
{
|
||||
self::_parse_path($options['path'],$id,$app,$user);
|
||||
|
||||
if ($this->debug) error_log(__METHOD__.'('.array2string($options).") path=$path");
|
||||
|
||||
$options['errors'] = array();
|
||||
switch ($app)
|
||||
{
|
||||
case 'calendar':
|
||||
case 'addressbook':
|
||||
case 'infolog':
|
||||
$status = '200 OK'; // grant all
|
||||
break;
|
||||
default:
|
||||
$options['errors'][] = 'no-inherited-ace-conflict';
|
||||
$status = '403 Forbidden';
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a path into it's id, app and user parts
|
||||
*
|
||||
@ -686,7 +839,7 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
}
|
||||
$parts = explode('/', $this->_unslashify($path));
|
||||
|
||||
if ($GLOBALS['egw']->accounts->name2id($parts[0]))
|
||||
if ($this->accounts->name2id($parts[0]))
|
||||
{
|
||||
// /$user/$app/...
|
||||
$user = array_shift($parts);
|
||||
@ -697,7 +850,7 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
if ($user)
|
||||
{
|
||||
$user_prefix = '/'.$user;
|
||||
$user = $GLOBALS['egw']->accounts->name2id($user,'account_lid',$app != 'addressbook' ? 'u' : null);
|
||||
$user = $this->accounts->name2id($user,'account_lid',$app != 'addressbook' ? 'u' : null);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -710,13 +863,39 @@ class groupdav extends HTTP_WebDAV_Server
|
||||
list($id) = explode('.',$id); // remove evtl. .ics extension
|
||||
}
|
||||
|
||||
if (!($ok = $id && in_array($app,array('addressbook','calendar','infolog','principals','groups')) && $user))
|
||||
$ok = $id && $user && in_array($app,array('addressbook','calendar','infolog','principals','groups'));
|
||||
if ($this->debug)
|
||||
{
|
||||
if ($this->debug)
|
||||
{
|
||||
error_log(__METHOD__."('$path') returning false: id=$id, app='$app', user=$user");
|
||||
}
|
||||
error_log(__METHOD__."('$path') returning " . ($ok ? 'true' : 'false') . ": id='$id', app='$app', user='$user', user_prefix='$user_prefix'");
|
||||
}
|
||||
return $ok;
|
||||
}
|
||||
/**
|
||||
* Add the privileges of the current user
|
||||
*
|
||||
* @param array $props=array() regular props by the groupdav handler
|
||||
* @return array
|
||||
*/
|
||||
static function current_user_privilege_set(array $props=array())
|
||||
{
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('current-user-privilege-set',
|
||||
array(HTTP_WebDAV_Server::mkprop('privilege',
|
||||
array(//HTTP_WebDAV_Server::mkprop('all',''),
|
||||
HTTP_WebDAV_Server::mkprop('read',''),
|
||||
HTTP_WebDAV_Server::mkprop('read-free-busy',''),
|
||||
//HTTP_WebDAV_Server::mkprop('read-current-user-privilege-set',''),
|
||||
HTTP_WebDAV_Server::mkprop('bind',''),
|
||||
HTTP_WebDAV_Server::mkprop('unbind',''),
|
||||
HTTP_WebDAV_Server::mkprop('schedule-post',''),
|
||||
HTTP_WebDAV_Server::mkprop('schedule-post-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop('schedule-respond',''),
|
||||
HTTP_WebDAV_Server::mkprop('schedule-respond-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop('schedule-deliver',''),
|
||||
HTTP_WebDAV_Server::mkprop('schedule-deliver-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop('write',''),
|
||||
HTTP_WebDAV_Server::mkprop('write-properties',''),
|
||||
HTTP_WebDAV_Server::mkprop('write-content',''),
|
||||
))));
|
||||
return $props;
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,12 @@ abstract class groupdav_handler
|
||||
* @var translation
|
||||
*/
|
||||
var $translation;
|
||||
/**
|
||||
* Reference to the accounts class
|
||||
*
|
||||
* @var accounts
|
||||
*/
|
||||
var $accounts;
|
||||
/**
|
||||
* Translates method names into ACL bits
|
||||
*
|
||||
@ -59,6 +65,12 @@ abstract class groupdav_handler
|
||||
* @var string
|
||||
*/
|
||||
var $base_uri;
|
||||
/**
|
||||
* principal URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $principalURL;
|
||||
/**
|
||||
* HTTP_IF_MATCH / etag of current request / last call to _common_get_put_delete() method
|
||||
*
|
||||
@ -78,17 +90,29 @@ abstract class 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)
|
||||
{
|
||||
//error_log(__METHOD__." called");
|
||||
$this->app = $app;
|
||||
#if (!is_null($debug)) $this->debug = $debug = 3;
|
||||
if (!is_null($debug)) $this->debug = $debug;
|
||||
$this->base_uri = is_null($base_uri) ? $base_uri : $_SERVER['SCRIPT_NAME'];
|
||||
if (is_null($principalURL))
|
||||
{
|
||||
$this->principalURL = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:") .
|
||||
'//'.$_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->principalURL = $principalURL.'principals/users/'.
|
||||
$GLOBALS['egw_info']['user']['account_lid'].'/';
|
||||
}
|
||||
|
||||
$this->agent = self::get_agent();
|
||||
|
||||
$this->translation =& $GLOBALS['egw']->translation;
|
||||
$this->egw_charset = $this->translation->charset();
|
||||
$this->accounts = $GLOBALS['egw']->accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,12 +129,13 @@ abstract class groupdav_handler
|
||||
/**
|
||||
* Propfind callback, if interator is used
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $filter
|
||||
* @param array|boolean $start false=return all or array(start,num)
|
||||
* @param int &$total
|
||||
* @return array with "files" array with values for keys path and props
|
||||
*/
|
||||
function &propfind_callback(array $filter,$start,&$total) { }
|
||||
function &propfind_callback($path, array $filter,$start,&$total) { }
|
||||
|
||||
/**
|
||||
* Handle get request for an applications entry
|
||||
@ -161,9 +186,11 @@ abstract class groupdav_handler
|
||||
* Add extra properties for 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())
|
||||
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
|
||||
{
|
||||
return $props;
|
||||
}
|
||||
@ -185,7 +212,7 @@ abstract class groupdav_handler
|
||||
// error_log(__METHOD__."(".array2string($entry).") Cant create etag!");
|
||||
return false;
|
||||
}
|
||||
return '"'.$entry['id'].':'.(isset($entry['etag']) ? $entry['etag'] : $entry['modified']).'"';
|
||||
return 'EGw-'.$entry['id'].':'.(isset($entry['etag']) ? $entry['etag'] : $entry['modified']).'-wGE';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,7 +223,7 @@ abstract class groupdav_handler
|
||||
*/
|
||||
static function etag2value($etag)
|
||||
{
|
||||
list(,$val) = explode(':',substr($etag,1,-1),2);
|
||||
list(,$val) = explode(':',substr($etag,4,-4),2);
|
||||
|
||||
return $val;
|
||||
}
|
||||
@ -211,7 +238,7 @@ abstract class groupdav_handler
|
||||
* @param array &$options
|
||||
* @param int $id
|
||||
* @param boolean &$return_no_access=false if set to true on call, instead of '403 Forbidden' the entry is returned and $return_no_access===false
|
||||
* @return array/string entry on success, string with http-error-code on failure, null for PUT on an unknown id
|
||||
* @return array|string entry on success, string with http-error-code on failure, null for PUT on an unknown id
|
||||
*/
|
||||
function _common_get_put_delete($method,&$options,$id,&$return_no_access=false)
|
||||
{
|
||||
@ -260,11 +287,13 @@ abstract class groupdav_handler
|
||||
*
|
||||
* @static
|
||||
* @param string $app 'calendar', 'addressbook' or 'infolog'
|
||||
* @param int $user=null owner of the collection, default current user
|
||||
* @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
|
||||
* @return groupdav_handler
|
||||
*/
|
||||
static function &app_handler($app,$debug=null,$base_uri=null)
|
||||
static function &app_handler($app,$debug=null,$base_uri=null,$principalURL=null)
|
||||
{
|
||||
static $handler_cache = array();
|
||||
|
||||
@ -273,8 +302,14 @@ abstract class groupdav_handler
|
||||
$class = $app.'_groupdav';
|
||||
if (!class_exists($class) && !class_exists($class = 'groupdav_'.$app)) return null;
|
||||
|
||||
$handler_cache[$app] = new $class($app,$debug,$base_uri);
|
||||
$handler_cache[$app] = new $class($app,$debug,$base_uri,$principalURL);
|
||||
}
|
||||
$handler_cache[$app]->$debug = $debug;
|
||||
$handler_cache[$app]->$base_uri = $base_uri;
|
||||
$handler_cache[$app]->$principalURL = $principalURL;
|
||||
|
||||
if ($debug) error_log(__METHOD__."('$app', '$base_uri', '$principalURL')");
|
||||
|
||||
return $handler_cache[$app];
|
||||
}
|
||||
|
||||
@ -294,6 +329,7 @@ abstract class groupdav_handler
|
||||
$user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
|
||||
foreach(array(
|
||||
'davkit' => 'davkit', // Apple iCal
|
||||
'cfnetwork' => 'cfnetwork', // Apple Addressbook
|
||||
'bionicmessage.net' => 'funambol', // funambol GroupDAV connector from bionicmessage.net
|
||||
'zideone' => 'zideone', // zideone outlook plugin
|
||||
'lightning' => 'lightning', // Lighting (SOGo connector for addressbook)
|
||||
@ -333,6 +369,13 @@ abstract class groupdav_handler
|
||||
*/
|
||||
class groupdav_propfind_iterator implements Iterator
|
||||
{
|
||||
/**
|
||||
* current path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Handler to call for entries
|
||||
*
|
||||
@ -352,8 +395,16 @@ class groupdav_propfind_iterator implements Iterator
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $common_files;
|
||||
|
||||
/**
|
||||
* current chunk
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
|
||||
/**
|
||||
* Start value for callback
|
||||
*
|
||||
@ -374,6 +425,8 @@ class groupdav_propfind_iterator implements Iterator
|
||||
*/
|
||||
public $debug = false;
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -381,13 +434,14 @@ class groupdav_propfind_iterator implements Iterator
|
||||
* @param array $filter filter for propfind call
|
||||
* @param array $files=null extra files/responses to return too
|
||||
*/
|
||||
public function __construct(groupdav_handler $handler,array $filter,array &$files=null)
|
||||
public function __construct(groupdav_handler $handler, $path, array $filter,array &$files=null)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(,".array2string($filter).",)");
|
||||
|
||||
if ($this->debug) error_log(__METHOD__."('$path', ".array2string($filter).",)");
|
||||
$this->path = $path;
|
||||
$this->handler = $handler;
|
||||
$this->filter = $filter;
|
||||
$this->files = $files;
|
||||
$this->common_files = $files;
|
||||
reset($this->files);
|
||||
}
|
||||
|
||||
@ -399,7 +453,6 @@ class groupdav_propfind_iterator implements Iterator
|
||||
public function current()
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files)));
|
||||
|
||||
return current($this->files);
|
||||
}
|
||||
|
||||
@ -410,7 +463,7 @@ class groupdav_propfind_iterator implements Iterator
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
$current = $this->current();
|
||||
$current = current($this->files);
|
||||
|
||||
if ($this->debug) error_log(__METHOD__."() returning ".array2string($current['path']));
|
||||
return $current['path']; // we return path as key
|
||||
@ -424,21 +477,20 @@ class groupdav_propfind_iterator implements Iterator
|
||||
if (next($this->files) !== false)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."() returning TRUE");
|
||||
|
||||
return true;
|
||||
}
|
||||
if (is_array($this->files) && count($this->files) < self::CHUNK_SIZE) // less entries then asked --> no further available
|
||||
if (is_array($this->files) && count($this->files) < self::CHUNK_SIZE) // less entries then asked --> no further available
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
|
||||
|
||||
return false; // no further entries
|
||||
}
|
||||
// try query further files via propfind callback of handler and store result in $this->files
|
||||
$this->files = $this->handler->propfind_callback($this->filter,array($this->start,self::CHUNK_SIZE));
|
||||
$this->files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
|
||||
$this->start += self::CHUNK_SIZE;
|
||||
reset($this->files);
|
||||
|
||||
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files) !== false));
|
||||
|
||||
return current($this->files) !== false;
|
||||
}
|
||||
|
||||
@ -451,7 +503,8 @@ class groupdav_propfind_iterator implements Iterator
|
||||
|
||||
// query first set of files via propfind callback of handler and store result in $this->files
|
||||
$this->start = 0;
|
||||
$this->files = $this->handler->propfind_callback($this->filter,array($this->start,self::CHUNK_SIZE));
|
||||
$files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
|
||||
$this->files = $this->common_files + $files;
|
||||
$this->start += self::CHUNK_SIZE;
|
||||
reset($this->files);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* @package api
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2008 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2008-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
@ -16,12 +16,6 @@
|
||||
*/
|
||||
class groupdav_principals extends groupdav_handler
|
||||
{
|
||||
/**
|
||||
* Reference to the accounts class
|
||||
*
|
||||
* @var accounts
|
||||
*/
|
||||
var $accounts;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -29,12 +23,11 @@ class groupdav_principals 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);
|
||||
|
||||
$this->accounts = $GLOBALS['egw']->accounts;
|
||||
parent::__construct($app,$debug,$base_uri,$principalURL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,6 +41,40 @@ class groupdav_principals extends groupdav_handler
|
||||
*/
|
||||
function propfind($path,$options,&$files,$user)
|
||||
{
|
||||
list(,$principals,$type,$name,$rest) = explode('/',$path,5);
|
||||
// /principals/users/$name/
|
||||
// /users/$name/calendar-proxy-read/
|
||||
// /users/$name/calendar-proxy-write/
|
||||
// /groups/$name/
|
||||
// /resources/$resource/
|
||||
// /__uids__/$uid/.../
|
||||
|
||||
switch($type)
|
||||
{
|
||||
case 'users':
|
||||
$files['files'] = $this->propfind_users($name,$rest,$options);
|
||||
break;
|
||||
case 'groups':
|
||||
$files['files'] = $this->propfind_groups($name,$rest,$options);
|
||||
break;
|
||||
case 'resources':
|
||||
$files['files'] = $this->propfind_resources($name,$rest,$options);
|
||||
break;
|
||||
case '__uids__':
|
||||
$files['files'] = $this->propfind_uids($name,$rest,$options);
|
||||
break;
|
||||
case '':
|
||||
$files['files'] = $this->propfind_principals($options);
|
||||
break;
|
||||
default:
|
||||
return '404 Not Found';
|
||||
}
|
||||
if (!is_array($files['files']))
|
||||
{
|
||||
return $files['files'];
|
||||
}
|
||||
return true;
|
||||
|
||||
list(,,$id) = explode('/',$path);
|
||||
if ($id && !($id = $this->accounts->id2name($id)))
|
||||
{
|
||||
@ -55,18 +82,20 @@ class groupdav_principals extends groupdav_handler
|
||||
}
|
||||
foreach($id ? array($this->accounts->read($id)) : $this->accounts->search(array('type' => 'accounts')) as $account)
|
||||
{
|
||||
$props = array(
|
||||
HTTP_WebDAV_Server::mkprop('displayname',trim($account['account_firstname'].' '.$account['account_lastname'])),
|
||||
$displayname = $this->translation->convert($account['account_fullname'],
|
||||
$this->translation->charset(),'utf-8');
|
||||
$props = array(
|
||||
HTTP_WebDAV_Server::mkprop('displayname',$displayname),
|
||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($account)),
|
||||
HTTP_WebDAV_Server::mkprop('resourcetype','principal'),
|
||||
HTTP_WebDAV_Server::mkprop('alternate-URI-set',''),
|
||||
HTTP_WebDAV_Server::mkprop('principal-URL',$_SERVER['SCRIPT_NAME'].'/principals/'.$account['account_lid']),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',$_SERVER['SCRIPT_NAME'].'/'),
|
||||
HTTP_WebDAV_Server::mkprop('principal-URL',$this->base_uri.'/principals/'.$account['account_lid']),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',$this->base_uri.$account['account_lid'].'/calendar/'),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set','MAILTO:'.$account['account_email']),
|
||||
);
|
||||
foreach($this->accounts->memberships($account['account_id']) as $gid => $group)
|
||||
{
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('group-membership',$_SERVER['SCRIPT_NAME'].'/groups/'.$group);
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('group-membership',$this->base_uri.'/groups/'.$group);
|
||||
}
|
||||
$files['files'][] = array(
|
||||
'path' => '/principals/'.$account['account_lid'],
|
||||
@ -74,7 +103,251 @@ class groupdav_principals extends groupdav_handler
|
||||
);
|
||||
if ($this->debug > 1) error_log(__METHOD__."($path) path=/principals/".$account['account_lid'].', props='.array2string($props));
|
||||
}
|
||||
return true;
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do propfind in /pricipals/users
|
||||
*
|
||||
* @param string $name name of account or empty
|
||||
* @param string $rest rest of path behind account-name
|
||||
* @param array $options
|
||||
* @return array|string array with files or HTTP error code
|
||||
*/
|
||||
protected function propfind_users($name,$rest,array $options)
|
||||
{
|
||||
//echo "<p>".__METHOD__."($name,$rest,".array2string($options).")</p>\n";
|
||||
if (empty($name))
|
||||
{
|
||||
$files = array();
|
||||
// add /pricipals/users/ entry
|
||||
$files[] = $this->add_collection('/principals/users/',array(
|
||||
HTTP_WebDAV_Server::mkprop('current-user-principal',array(
|
||||
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/principals/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
|
||||
));
|
||||
if ($options['depth'])
|
||||
{
|
||||
// add all users
|
||||
foreach($this->accounts->search(array('type' => 'accounts')) as $account)
|
||||
{
|
||||
$files[] = $this->add_account($account);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!($id = $this->accounts->name2id($name,'account_lid','u')) ||
|
||||
!($account = $this->accounts->read($id)))
|
||||
{
|
||||
return '404 Not Found';
|
||||
}
|
||||
switch((string)$rest)
|
||||
{
|
||||
case '':
|
||||
$files[] = $this->add_account($account);
|
||||
$files[] = $this->add_collection('/principals/users/'.$account['account_lid'].'/calendar-proxy-read');
|
||||
$files[] = $this->add_collection('/principals/users/'.$account['account_lid'].'/calendar-proxy-write');
|
||||
break;
|
||||
case 'calendar-proxy-read':
|
||||
case 'calendar-proxy-write':
|
||||
$files = array();
|
||||
$files[] = $this->add_collection('/principals/users/'.$account['account_lid'].'/'.$rest);
|
||||
// add proxys
|
||||
break;
|
||||
default:
|
||||
return '404 Not Found';
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do propfind in /pricipals/groups
|
||||
*
|
||||
* @param string $name name of group or empty
|
||||
* @param string $rest rest of path behind account-name
|
||||
* @param array $options
|
||||
* @return array|string array with files or HTTP error code
|
||||
*/
|
||||
protected function propfind_groups($name,$rest,array $options)
|
||||
{
|
||||
//echo "<p>".__METHOD__."($name,$rest,".array2string($options).")</p>\n";
|
||||
if (empty($name))
|
||||
{
|
||||
$files = array();
|
||||
// add /pricipals/users/ entry
|
||||
$files[] = $this->add_collection('/principals/groups/',array(
|
||||
HTTP_WebDAV_Server::mkprop('current-user-principal',array(
|
||||
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/principals/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
|
||||
));
|
||||
if ($options['depth'])
|
||||
{
|
||||
// add all users
|
||||
foreach($this->accounts->search(array('type' => 'groups')) as $account)
|
||||
{
|
||||
$files[] = $this->add_group($account);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!($id = $this->accounts->name2id($name,'account_lid','g')) ||
|
||||
!($account = $this->accounts->read($id)))
|
||||
{
|
||||
return '404 Not Found';
|
||||
}
|
||||
switch((string)$rest)
|
||||
{
|
||||
case '':
|
||||
$files[] = $this->add_group($account);
|
||||
$files[] = $this->add_collection('/principals/groups/'.$account['account_lid'].'/calendar-proxy-read');
|
||||
$files[] = $this->add_collection('/principals/groups/'.$account['account_lid'].'/calendar-proxy-write');
|
||||
break;
|
||||
case 'calendar-proxy-read':
|
||||
case 'calendar-proxy-write':
|
||||
$files = array();
|
||||
$files[] = $this->add_collection('/principals/groups/'.$account['account_lid'].'/'.$rest);
|
||||
// add proxys
|
||||
break;
|
||||
default:
|
||||
return '404 Not Found';
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add collection of a single account to a collection
|
||||
*
|
||||
* @param array $account
|
||||
* @return array with values for keys 'path' and 'props'
|
||||
*/
|
||||
protected function add_account(array $account)
|
||||
{
|
||||
//echo "<p>".__METHOD__."(".array2string($account).")</p>\n";
|
||||
|
||||
$displayname = $this->translation->convert($account['account_fullname'],
|
||||
$this->translation->charset(),'utf-8');
|
||||
$memberships = array();
|
||||
foreach($this->accounts->memberships($account['account_id']) as $gid => $group)
|
||||
{
|
||||
if ($group)
|
||||
{
|
||||
$memberships[] = HTTP_WebDAV_Server::mkprop('href',
|
||||
$this->base_uri.'/principals/groups/'.$group);
|
||||
}
|
||||
}
|
||||
$props = array(
|
||||
HTTP_WebDAV_Server::mkprop('displayname',$displayname),
|
||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($account)),
|
||||
HTTP_WebDAV_Server::mkprop('resourcetype','principal'),
|
||||
HTTP_WebDAV_Server::mkprop('alternate-URI-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$account['account_email']))),
|
||||
HTTP_WebDAV_Server::mkprop('principal-URL',$this->base_uri.'/principals/users/'.$account['account_lid'].'/'),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/calendar/'))),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$account['account_email']))),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
|
||||
HTTP_WebDAV_Server::mkprop('group-member-ship', $memberships),
|
||||
HTTP_WebDAV_Server::mkprop('principal-URL',array(HTTP_WebDAV_Server::mkprop('href',$this->principalURL))),
|
||||
);
|
||||
if ($this->debug > 1) error_log(__METHOD__."($path) path=/principals/users/".$account['account_lid'].', props='.array2string($props));
|
||||
return array(
|
||||
'path' => '/principals/users/'.$account['account_lid'].'/',
|
||||
'props' => $props,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add collection of a single group to a collection
|
||||
*
|
||||
* @param array $account
|
||||
* @return array with values for keys 'path' and 'props'
|
||||
*/
|
||||
protected function add_group(array $account)
|
||||
{
|
||||
$displayname = $this->translation->convert(lang('Group').' '.$account['account_lid'],
|
||||
$this->translation->charset(),'utf-8');
|
||||
$members = array();
|
||||
foreach($this->accounts->members($account['account_id']) as $gid => $user)
|
||||
{
|
||||
if ($user)
|
||||
{
|
||||
$members[] = HTTP_WebDAV_Server::mkprop('href',
|
||||
$this->base_uri.'/principals/users/'.$user);
|
||||
}
|
||||
}
|
||||
$props = array(
|
||||
HTTP_WebDAV_Server::mkprop('displayname',$displayname),
|
||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($account)),
|
||||
HTTP_WebDAV_Server::mkprop('resourcetype','principal'),
|
||||
HTTP_WebDAV_Server::mkprop('alternate-URI-set',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/calendar/'))),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
|
||||
HTTP_WebDAV_Server::mkprop('group-member-set', $members),
|
||||
//HTTP_WebDAV_Server::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
|
||||
);
|
||||
$files['files'][] = array(
|
||||
'path' => '/principals/groups/'.$account['account_lid'].'/',
|
||||
'props' => $props,
|
||||
);
|
||||
if ($this->debug > 1) error_log(__METHOD__."($path) path=/principals/groups/".$account['account_lid'].', props='.array2string($props));
|
||||
return array(
|
||||
'path' => '/principals/groups/'.$account['account_lid'].'/',
|
||||
'props' => $props,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a collection
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $props=array() extra properties 'resourcetype' is added anyway
|
||||
* @return array
|
||||
*/
|
||||
protected function add_collection($path,$props=array())
|
||||
{
|
||||
//echo "<p>".__METHOD__."($path,".array($props).")</p>\n";
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('resourcetype',array(
|
||||
HTTP_WebDAV_Server::mkprop('collection',''),
|
||||
HTTP_WebDAV_Server::mkprop('resourcetype','principal'),
|
||||
));
|
||||
return array(
|
||||
'path' => $path,
|
||||
'props' => $props,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do propfind of /pricipals
|
||||
*
|
||||
* @param string $name name of group or empty
|
||||
* @param string $rest name of rest of path behind group-name
|
||||
* @param array $options
|
||||
* @return array|string array with files or HTTP error code
|
||||
*/
|
||||
protected function propfind_principals(array $options)
|
||||
{
|
||||
//echo "<p>".__METHOD__."(".array($options).")</p>\n";
|
||||
$files = array();
|
||||
$files[] = $this->add_collection('/principals/',array(
|
||||
HTTP_WebDAV_Server::mkprop('current-user-principal',array(
|
||||
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/principals/users/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
|
||||
));
|
||||
|
||||
if ($options['depth'])
|
||||
{
|
||||
$options['depth'] = 0;
|
||||
$files = array_merge($files,$this->propfind_users('','',$options));
|
||||
$files = array_merge($files,$this->propfind_groups('','',$options));
|
||||
//$files = array_merge($this->propfind_resources('','',$options));
|
||||
//$files = array_merge($this->propfind_uids('','',$options));
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,9 +363,12 @@ class groupdav_principals extends groupdav_handler
|
||||
{
|
||||
return $account;
|
||||
}
|
||||
$name = $GLOBALS['egw']->translation->convert(
|
||||
trim($account['account_firstname'].' '.$account['account_lastname']),
|
||||
$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
$options['data'] = 'Principal: '.$account['account_lid'].
|
||||
"\nURL: ".$_SERVER['SCRIPT_NAME'].$options['path'].
|
||||
"\nName: ".$account['account_firstname'].' '.$account['account_lastname'].
|
||||
"\nURL: ".$this->base_uri.$options['path'].
|
||||
"\nName: ".$name.
|
||||
"\nEmail: ".$account['account_email'].
|
||||
"\nMemberships: ".implode(', ',$this->accounts->memberships($id))."\n";
|
||||
$options['mimetype'] = 'text/plain; charset=utf-8';
|
||||
@ -134,7 +410,8 @@ class groupdav_principals extends groupdav_handler
|
||||
*/
|
||||
function read($id)
|
||||
{
|
||||
return $this->accounts->read($id);
|
||||
return false;
|
||||
//return $this->accounts->read($id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,6 +446,6 @@ class groupdav_principals extends groupdav_handler
|
||||
{
|
||||
$account = $this->read($account);
|
||||
}
|
||||
return '"'.$account['account_id'].':'.md5(serialize($account)).'"';
|
||||
return 'EGw-'.$account['account_id'].':'.md5(serialize($account)).'-wGE';
|
||||
}
|
||||
}
|
@ -263,7 +263,8 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
// type and size (caller already made sure that path exists)
|
||||
if (is_dir($fspath)) {
|
||||
// directory (WebDAV collection)
|
||||
$info['props'][] = HTTP_WebDAV_Server::mkprop ('resourcetype', HTTP_WebDAV_Server::mkprop('collection',''));
|
||||
$info['props'][] = HTTP_WebDAV_Server::mkprop ('resourcetype', array(
|
||||
HTTP_WebDAV_Server::mkprop('collection', '')));
|
||||
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontenttype', 'httpd/unix-directory');
|
||||
} else {
|
||||
// plain file (WebDAV resource)
|
||||
@ -471,4 +472,4 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
{
|
||||
return egw_vfs::checkLock($path);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user