* CardDAV/Addressbook/LDAP/ADS: syncing all addressbooks into one now also allows to include accounts not stored like contacts

This commit is contained in:
Ralf Becker 2013-08-22 16:43:11 +00:00
parent 5fcedd5ad7
commit bec93a3ce3
2 changed files with 131 additions and 43 deletions

View File

@ -188,6 +188,7 @@ class addressbook_groupdav extends groupdav_handler
function &propfind_callback($path,array $filter,$start=false)
{
$starttime = microtime(true);
$filter_in = $filter;
if (($address_data = $filter['address_data']))
{
@ -242,51 +243,70 @@ class addressbook_groupdav extends groupdav_handler
$this->sync_collection_token = $contact['modified'];
}
}
// add groups after contacts, but only if enabled and NOT for '/addressbook/' (!isset($filter['owner'])
if (in_array('D',$this->home_set_pref) && (!$start || count($contacts) < $start[1]))
if (!$start || count($contacts) < $start[1])
{
$where = array(
'list_owner' => isset($filter['owner'])?$filter['owner']:array_keys($this->bo->grants)
);
// add sync-token to support sync-collection report
if ($sync_collection_report)
// add accounts after contacts, if enabled and stored in different repository
if ($this->bo->so_accounts && is_array($filter['owner']) && in_array('0', $filter['owner']))
{
list(,$sync_token) = explode('>', $filter[0]);
$where[] = 'list_modified>FROM_UNIXTIME('.(int)$sync_token.')';
}
if (isset($filter[self::$path_attr])) // multiget report?
{
$where['list_'.self::$path_attr] = $filter[self::$path_attr];
}
//error_log(__METHOD__."() filter=".array2string($filter).", do_groups=".in_array('D',$this->home_set_pref).", where=".array2string($where));
if (($lists = $this->bo->read_lists($where,'contact_uid',$where['list_owner']))) // limit to contacts in same AB!
{
foreach($lists as $list)
$accounts_filter = $filter_in;
$accounts_filter['owner'] = '0';
if ($sync_collection_report) $token_was = $this->sync_collection_token;
groupdav_handler::$path_attr = 'id';
groupdav_handler::$path_extension = '.vcf';
$files = array_merge($files, $this->propfind_callback($path, $accounts_filter));
groupdav_handler::$path_attr = 'carddav_name';
groupdav_handler::$path_extension = '';
if ($sync_collection_report && $token_was > $this->sync_collection_token)
{
$list['carddav_name'] = $list['list_carddav_name'];
$etag = $list['list_id'].':'.$list['list_etag'];
// for all-in-one addressbook, add selected ABs to etag
if (isset($filter['owner']) && is_array($filter['owner']))
$this->sync_collection_token = $token_was;
}
}
// add groups after contacts, but only if enabled and NOT for '/addressbook/' (!isset($filter['owner'])
if (in_array('D',$this->home_set_pref) && (string)$filter['owner'] !== '0')
{
$where = array(
'list_owner' => isset($filter['owner'])?$filter['owner']:array_keys($this->bo->grants)
);
// add sync-token to support sync-collection report
if ($sync_collection_report)
{
list(,$sync_token) = explode('>', $filter[0]);
$where[] = 'list_modified>FROM_UNIXTIME('.(int)$sync_token.')';
}
if (isset($filter[self::$path_attr])) // multiget report?
{
$where['list_'.self::$path_attr] = $filter[self::$path_attr];
}
//error_log(__METHOD__."() filter=".array2string($filter).", do_groups=".in_array('D',$this->home_set_pref).", where=".array2string($where));
if (($lists = $this->bo->read_lists($where,'contact_uid',$where['list_owner']))) // limit to contacts in same AB!
{
foreach($lists as $list)
{
$etag .= ':'.implode('-',$filter['owner']);
}
$props = array(
'getcontenttype' => HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'),
'getlastmodified' => egw_time::to($list['list_modified'],'ts'),
'displayname' => $list['list_name'],
'getetag' => '"'.$etag.'"',
);
if ($address_data)
{
$content = $handler->getGroupVCard($list);
$props['getcontentlength'] = bytes($content);
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
}
$files[] = $this->add_resource($path, $list, $props);
$list['carddav_name'] = $list['list_carddav_name'];
$etag = $list['list_id'].':'.$list['list_etag'];
// for all-in-one addressbook, add selected ABs to etag
if (isset($filter['owner']) && is_array($filter['owner']))
{
$etag .= ':'.implode('-',$filter['owner']);
}
$props = array(
'getcontenttype' => HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'),
'getlastmodified' => egw_time::to($list['list_modified'],'ts'),
'displayname' => $list['list_name'],
'getetag' => '"'.$etag.'"',
);
if ($address_data)
{
$content = $handler->getGroupVCard($list);
$props['getcontentlength'] = bytes($content);
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
}
$files[] = $this->add_resource($path, $list, $props);
if ($sync_collection_report && $this->sync_collection_token < ($ts=$GLOBALS['egw']->db->from_timestamp($list['list_modified'])))
{
$this->sync_collection_token = $ts;
if ($sync_collection_report && $this->sync_collection_token < ($ts=$GLOBALS['egw']->db->from_timestamp($list['list_modified'])))
{
$this->sync_collection_token = $ts;
}
}
}
}
@ -729,15 +749,22 @@ class addressbook_groupdav extends groupdav_handler
if ($user && $user == $GLOBALS['egw_info']['user']['account_id'] && in_array('O',$this->home_set_pref))
{
$user = array_merge((array)$user,array_keys($this->get_shared(true))); // true: ignore all-in-one pref
// include accounts ctag, if accounts stored different from contacts (eg.in LDAP or ADS)
if ($this->bo->so_accounts && in_array('0', $user))
{
$accounts_ctag = $this->bo->get_ctag('0');
}
}
$ctag = $this->bo->get_ctag($user);
// include lists-ctag, if enabled
if (in_array('D',$this->home_set_pref))
{
$lists_ctag = $this->bo->lists_ctag($user);
}
//error_log(__METHOD__."('$path', ".array2string($user_in).") --> user=".array2string($user)." --> ctag=$ctag=".date('Y-m-d H:i:s',$ctag).", lists_ctag=".($lists_ctag ? $lists_ctag.'='.date('Y-m-d H:i:s',$lists_ctag) : '').' returning '.max($ctag,$lists_ctag));
return $ctags[$path] = max($ctag,$lists_ctag);
return $ctags[$path] = max($ctag, $accounts_ctag, $lists_ctag);
}
/**
@ -899,6 +926,12 @@ class addressbook_groupdav extends groupdav_handler
}
$contact = $this->bo->read(array(self::$path_attr => $id, 'tid' => $non_deleted_tids));
// if contact not found and accounts stored NOT like contacts, try reading it without path-extension as id
if (is_null($contact) && $this->bo->so_accounts && ($c = $this->bo->read($test=basename($id, '.vcf'))))
{
$contact = $c;
}
// see if we have a distribution-list / group with that id
// bo->read_list(..., true) limits returned uid to same owner's addressbook, as iOS and OS X addressbooks
// only understands/shows that and if return more, save_lists would delete the others ones on update!

View File

@ -716,6 +716,42 @@ class addressbook_ldap
function &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false)
{
//error_log(__METHOD__."(".array2string($criteria).", ".array2string($only_keys).", '$order_by', ".array2string($extra_cols).", '$wildcard', '$empty', '$op', ".array2string($start).", ".array2string($filter).")");
if (is_array($filter['owner']))
{
if (count($filter['owner']) == 1)
{
$filter['owner'] = array_shift($filter['owner']);
}
else
{
// multiple addressbooks happens currently only via CardDAV or eSync
// currently we query all contacts and remove not matching ones (not the most efficient way to do it)
$owner_filter = $filter['owner'];
unset($filter['owner']);
}
}
// search filter for modified date (eg. for CardDAV sync-report)
$datefilter = '';
static $egw2ldap = array(
'created' => 'createtimestamp',
'modified' => 'modifytimestamp',
);
foreach($filter as $key => $value)
{
if (is_int($key) && preg_match('/^(contact_)?(modified|created)([<=>]+)([0-9]+)$/', $value, $matches))
{
$append = '';
if ($matches[3] == '>')
{
$matches['3'] = '<=';
$datefilter .= '(!';
$append = ')';
}
$datefilter .= '('.$egw2ldap[$matches[2]].$matches[3].self::_ts2ldap($matches[4]).')'.$append;
}
}
if((int)$filter['owner'])
{
if (!($accountName = $GLOBALS['egw']->accounts->id2name($filter['owner']))) return false;
@ -790,7 +826,8 @@ class addressbook_ldap
}
}
$colFilter = $this->_colFilter($filter);
$ldapFilter = "(&$objectFilter$searchFilter$colFilter)";
$ldapFilter = "(&$objectFilter$searchFilter$colFilter$datefilter)";
//error_log(__METHOD__."(".array2string($criteria).", ".array2string($only_keys).", '$order_by', ".array2string($extra_cols).", '$wildcard', '$empty', '$op', ".array2string($start).", ".array2string($filter).") --> ldapFilter='$ldapFilter'");
if (!($rows = $this->_searchLDAP($searchDN, $ldapFilter, $this->all_attributes, $addressbookType)))
{
return $rows;
@ -891,6 +928,13 @@ class addressbook_ldap
}
break;
case 'carddav_name':
if (!is_array($value)) $value = array($value);
foreach($value as &$v)
{
$v = basename($v, '.vcf');
}
// fall through
case 'id':
case 'contact_id':
$filters .= $this->ids_filter($value);
@ -1046,12 +1090,23 @@ class addressbook_ldap
* @param string $date YYYYmmddHHiiss
* @return int
*/
function _ldap2ts($date)
static function _ldap2ts($date)
{
return gmmktime(substr($date,8,2),substr($date,10,2),substr($date,12,2),
substr($date,4,2),substr($date,6,2),substr($date,0,4));
}
/**
* Create LDAP date-value from timestamp
*
* @param integer $ts
* @return string
*/
static function _ts2ldap($ts)
{
return gmdate('YmdHis', $ts).'.0Z';
}
/**
* check if $baseDN exists. If not create it
*