From 499ac36bffbb1a9d35dca547e52fa03adf7a8c29 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Sat, 17 May 2008 13:11:46 +0000 Subject: [PATCH] "- fixed charset for Thunderbird/SOGo connector - using uid as filename to improve the support of newer SOGo connectors (>= 0.62), which require the server to remember the path they used to store a new contact --> still not working reliable and causes TB to lock up --> recommended is still version 0.62 of the SOGo connector " --- .../inc/class.addressbook_groupdav.inc.php | 100 +++++++++++------- 1 file changed, 59 insertions(+), 41 deletions(-) diff --git a/addressbook/inc/class.addressbook_groupdav.inc.php b/addressbook/inc/class.addressbook_groupdav.inc.php index 7a2e0faff2..b798e5cbcc 100644 --- a/addressbook/inc/class.addressbook_groupdav.inc.php +++ b/addressbook/inc/class.addressbook_groupdav.inc.php @@ -37,14 +37,32 @@ class addressbook_groupdav extends groupdav_handler */ var $charset = 'utf-8'; - function __construct($debug=null) + /** + * Constructor + * + * @param string $app 'calendar', 'addressbook' or 'infolog' + * @param int $debug=null debug-level to set + * @param string $base_uri=null base url of handler + */ + function __construct($app,$debug=null,$base_uri=null) { - parent::__construct('addressbook',$debug); + parent::__construct($app,$debug,$base_uri); $this->bo =& new addressbook_bo(); - // SoGo Connector for Thunderbird works only with iso-8859-1! - if (strpos($_SERVER['HTTP_USER_AGENT'],'Thunderbird') !== false) $charset = 'iso-8859-1'; + // SOGo Connector for Thunderbird has problems in some fields if charset is other then iso-8859-1! + if (strpos($_SERVER['HTTP_USER_AGENT'],'Thunderbird') !== false) $this->charset = 'iso-8859-1'; + } + + /** + * Create the path for a contact + * + * @param array $contact + * @return string + */ + static function get_path($contact) + { + return '/addressbook/'.$contact['uid'].'.vcf'; } /** @@ -59,16 +77,17 @@ class addressbook_groupdav extends groupdav_handler */ function propfind($path,$options,&$files,$user,$id='') { - if ($user) $filter = array('contact_owner' => $user); + if ($user && $path != '/addressbook/') $filter = array('contact_owner' => $user); // process REPORT filters or multiget href's if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$filter,$id)) { return false; } - error_log(__METHOD__."($path,$options,,$user,$id) filter=".str_replace(array("\n",' '),'',print_r($filter,true))); + 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 (!($address_data = $options['props'] == 'all' && $options['root']['ns'] == groupdav::CARDDAV)) + if (!($address_data = $options['props'] == 'all' && $options['root']['ns'] == groupdav::CARDDAV) && is_array($options['props'])) { foreach($options['props'] as $prop) { @@ -83,7 +102,8 @@ class addressbook_groupdav extends groupdav_handler { $handler = self::_get_handler(); } - if (($contacts =& $this->bo->search(array(),$address_data ? false : array('id','modified','etag'),'contact_id','','',False,'AND',false,$filter))) + // 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',false,$filter))) { foreach($contacts as $contact) { @@ -96,7 +116,7 @@ class addressbook_groupdav extends groupdav_handler $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$handler->getVCard($contact,$this->charset)); } $files['files'][] = array( - 'path' => '/addressbook/'.$contact['id'], + 'path' => self::get_path($contact), 'props' => $props, ); } @@ -120,21 +140,15 @@ class addressbook_groupdav extends groupdav_handler { switch($filter['name']) { - case 'comp-filter': - error_log(__METHOD__."($path,...) comp-filter='{$filter['attrs']['name']}'"); - switch($filter['attrs']['name']) - { - } - break; case 'prop-filter': - error_log(__METHOD__."($path,...) prop-filter='{$filter['attrs']['name']}'"); + if ($this->debug > 1) error_log(__METHOD__."($path,...) prop-filter='{$filter['attrs']['name']}'"); $prop_filter = $filter['attrs']['name']; break; case 'text-match': - error_log(__METHOD__."($path,...) text-match: $prop_filter='{$filter['data']}'"); + if ($this->debug > 1) error_log(__METHOD__."($path,...) text-match: $prop_filter='{$filter['data']}'"); if (!isset($this->filter_prop2cal[strtoupper($prop_filter)])) { - error_log(__METHOD__."($path,".str_replace(array("\n",' '),'',print_r($options,true)).",,$user) unknown property '$prop_filter' --> ignored"); + if ($this->debug) error_log(__METHOD__."($path,".str_replace(array("\n",' '),'',print_r($options,true)).",,$user) unknown property '$prop_filter' --> ignored"); } else { @@ -152,10 +166,10 @@ class addressbook_groupdav extends groupdav_handler unset($prop_filter); break; case 'param-filter': - error_log(__METHOD__."($path,...) param-filter='{$filter['attrs']['name']}'"); + if ($this->debug) error_log(__METHOD__."($path,...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!"); break; default: - error_log(__METHOD__."($path,".str_replace(array("\n",' '),'',print_r($options,true)).",,$user) unknown filter --> ignored"); + if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user) unknown filter --> ignored"); break; } } @@ -169,22 +183,15 @@ class addressbook_groupdav extends groupdav_handler if ($option['name'] == 'href') { $parts = explode('/',$option['data']); - if (is_numeric($id = array_pop($parts))) $ids[] = $id; + if (($id = array_pop($parts))) $ids[] = basename($id,'.vcf'); } } - $filters['id'] = $ids; - //error_log(__METHOD__."($path,,,$user) addressbook-multiget: ids=".implode(',',$ids)); + if ($ids) $filters['uid'] = $ids; + if ($this->debug) error_log(__METHOD__."($path,,,$user) addressbook-multiget: ids=".implode(',',$ids)); } elseif ($id) { - if (is_numeric($id)) - { - $filters['id'] = $id; - } - else - { - $filters['uid'] = basename($id,'.vcf'); - } + $filters['uid'] = basename($id,'.vcf'); } return true; } @@ -203,7 +210,7 @@ class addressbook_groupdav extends groupdav_handler return $contact; } $handler = self::_get_handler(); - $options['data'] = $handler->getVCard($id,$this->charset); + $options['data'] = $handler->getVCard($contact['id'],$this->charset); $options['mimetype'] = 'text/x-vcard; charset='.$this->charset; header('Content-Encoding: identity'); header('ETag: '.$this->get_etag($contact)); @@ -227,30 +234,41 @@ class addressbook_groupdav extends groupdav_handler } $handler = self::_get_handler(); $contact = $handler->vcardtoegw($options['content']); + if (!is_null($ok)) { - $contact['id'] = $id; + $contact['id'] = $ok['id']; + // dont allow the client to overwrite certain values + $contact['uid'] = $ok['uid']; + $contact['owner'] = $ok['owner']; + $contact['private'] = $ok['private']; } - // SoGo does not set the uid attribut, but uses it as id - elseif (strlen($id) > 10 && !$contact['uid']) + // SOGo requires that we keep it's path, but sets a different name-part then the uid + // we use there name-part as UID, to be able to allow it to access the contact again with that path + elseif (strlen($id) > 10 && strpos($_SERVER['HTTP_USER_AGENT'],'Thunderbird')) { $contact['uid'] = basename($id,'.vcf'); } - $contact['etag'] = self::etag2value($this->http_if_match); + if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match); if (!($ok = $this->bo->save($contact))) { + if ($this->debug) error_log(__METHOD__."(,$id) save(".array2string($contact).") failed, Ok=$ok"); if ($ok === 0) { return '412 Precondition Failed'; } return false; } + if (!isset($contact['etag'])) + { + $contact = $this->read($contact['id']); + } header('ETag: '.$this->get_etag($contact)); if (is_null($ok)) { - header($h='Location: '.$this->base_uri.'/addressbook/'.$contact['id']); + header($h='Location: '.$this->base_uri.self::get_path($contact)); error_log(__METHOD__."($method,,$id) header('$h'): 201 Created"); return '201 Created'; } @@ -281,11 +299,11 @@ class addressbook_groupdav extends groupdav_handler */ function delete(&$options,$id) { - if (!is_array($event = $this->_common_get_put_delete('DELETE',$options,$id))) + if (!is_array($contact = $this->_common_get_put_delete('DELETE',$options,$id))) { - return $event; + return $contact; } - if ($this->bo->delete($id,self::etag2value($this->http_if_match)) === 0) + if ($this->bo->delete($contact['id'],self::etag2value($this->http_if_match)) === 0) { return '412 Precondition Failed'; } @@ -300,7 +318,7 @@ class addressbook_groupdav extends groupdav_handler */ function read($id) { - return $this->bo->read($id); + return $this->bo->read(is_numeric($id) ? $id : array('uid' => $id)); } /**