diff --git a/addressbook/inc/class.addressbook_activesync.inc.php b/addressbook/inc/class.addressbook_activesync.inc.php index e0815fb5fb..46b39cd48c 100644 --- a/addressbook/inc/class.addressbook_activesync.inc.php +++ b/addressbook/inc/class.addressbook_activesync.inc.php @@ -46,7 +46,7 @@ class addressbook_activesync implements activesync_plugin_write 'businessfaxnumber' => 'tel_fax', 'businessphonenumber' => 'tel_work', 'carphonenumber' => 'tel_car', - 'categories' => '', + 'categories' => 'cat_id', 'children' => '', 'companyname' => 'org_name', 'department' => 'org_unit', @@ -141,7 +141,7 @@ class addressbook_activesync implements activesync_plugin_write 'parent'=> '0', ); }; - error_log(__METHOD__."() returning ".array2string($folderlist)); + //error_log(__METHOD__."() returning ".array2string($folderlist)); return $folderlist; } @@ -168,7 +168,7 @@ class addressbook_activesync implements activesync_plugin_write { $folderObj->type = SYNC_FOLDER_TYPE_USER_CONTACT; } - error_log(__METHOD__."('$id') returning ".array2string($folderObj)); + //error_log(__METHOD__."('$id') returning ".array2string($folderObj)); return $folderObj; } @@ -195,7 +195,7 @@ class addressbook_activesync implements activesync_plugin_write 'mod' => $this->get_addressbooks($owner), 'parent' => '0', ); - error_log(__METHOD__."('$id') returning ".array2string($stat)); + //error_log(__METHOD__."('$id') returning ".array2string($stat)); return $stat; } @@ -230,7 +230,7 @@ class addressbook_activesync implements activesync_plugin_write $messagelist[] = $this->StatMessage($id, $contact); } } - error_log(__METHOD__."('$id') returning ".count($messagelist).' entries'); + //error_log(__METHOD__."('$id') returning ".count($messagelist).' entries'); return $messagelist; } @@ -284,7 +284,7 @@ class addressbook_activesync implements activesync_plugin_write ''. ''. ''. - str_replace("\n","
",str_replace("\r","
", str_replace("\r\n","
",$contact[$attr]))). + str_replace(array("\n","\r","\r\n"),"
",$contact[$attr]). ''. ''; if (isset($bodypreference[2]["TruncationSize"]) && strlen($html) > $bodypreference[2]["TruncationSize"]) @@ -319,6 +319,18 @@ class addressbook_activesync implements activesync_plugin_write if (!empty($contact[$attr])) $message->$key = base64_encode($contact[$attr]); break; + case 'bday': + if (!empty($contact[$attr])) $message->$key = egw_time::to($contact[$attr],'ts'); + break; + + case 'cat_id': + /*$message->$key = array(); + foreach($contact[$attr] ? explode(',',$contact[$attr]) : array() as $cat_id) + { + $message->categories[] = categories::id2name($cat_id); + }*/ + break; + default: if (!empty($contact[$attr])) $message->$key = $contact[$attr]; } @@ -358,7 +370,7 @@ class addressbook_activesync implements activesync_plugin_write ); } //debugLog (__METHOD__."('$folderid',".array2string($id).") returning ".array2string($stat)); - error_log(__METHOD__."('$folderid',$contact) returning ".array2string($stat)); + //error_log(__METHOD__."('$folderid',$contact) returning ".array2string($stat)); return $stat; } @@ -375,7 +387,7 @@ class addressbook_activesync implements activesync_plugin_write */ public function ChangeFolder($id, $oldid, $displayname, $type) { - debugLog(__METHOD_." not implemented"); + debugLog(__METHOD__." not implemented"); } /** @@ -489,18 +501,33 @@ class addressbook_activesync implements activesync_plugin_write error_log (__METHOD__); } - - /** - * @todo implement using ctag + * Return a changes array + * + * if changes occurr default diff engine computes the actual changes + * + * @param string $folderid + * @param string &$syncstate on call old syncstate, on return new syncstate + * @return array|boolean false if $folderid not found, array() if no changes or array(array("type" => "fakeChange")) */ function AlterPingChanges($folderid, &$syncstate) { - debugLog (__METHOD__." should not see this -not yet implemented"); - return false; + $this->backend->splitID($folderid, $type, $owner); + + if ($type != 'addressbook') return false; + + if (!isset($this->addressbook)) $this->addressbook = new addressbook_bo(); + $ctag = $this->addressbook->get_ctag($owner); + + $changes = array(); // no change + $syncstate_was = $syncstate; + + if ($ctag !== $syncstate) + { + $syncstate = $ctag; + $changes = array(array('type' => 'fakeChange')); + } + //error_log(__METHOD__."('$folderid','$syncstate_was') syncstate='$syncstate' returning ".array2string($changes)); + return $changes; } } - - - - diff --git a/addressbook/inc/class.addressbook_bo.inc.php b/addressbook/inc/class.addressbook_bo.inc.php index a4a1824835..2ee4e4fcb9 100755 --- a/addressbook/inc/class.addressbook_bo.inc.php +++ b/addressbook/inc/class.addressbook_bo.inc.php @@ -2111,4 +2111,40 @@ class addressbook_bo extends addressbook_so } return $matchingContacts; } + + /** + * Get a ctag (collection tag) for one addressbook or all addressbooks readable by a user + * + * Currently implemented as maximum modification date (1 seconde granularity!) + * + * We have to include deleted entries, as otherwise the ctag will not change if an entry gets deleted! + * (Only works if tracking of deleted entries / history is switched on!) + * + * @param int $owner=null 0=accounts, null=all addressbooks or integer account_id of user or group + * @return string + */ + public function get_ctag($owner=null) + { + $filter = array('tid' => null); // tid=null --> use all entries incl. deleted (tid='D') + // show addressbook of a single user? + if (!is_null($owner)) $filter['contact_owner'] = $owner; + + // should we hide the accounts addressbook + if (!$owner && $GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) + { + $filter['account_id'] = null; + } + $result = $this->search(array(),'MAX(contact_modified) AS contact_modified','','','',false,'AND',false,$filter); + + if (!$result || !isset($result[0]['contact_modified'])) + { + $ctag = 'empty'; // ctag for empty addressbook + } + else + { + $ctag = $result[0]['contact_modified']; + } + //error_log(__METHOD__.'('.array2string($owner).') returning '.array2string($ctag)); + return $ctag; + } } diff --git a/addressbook/inc/class.addressbook_groupdav.inc.php b/addressbook/inc/class.addressbook_groupdav.inc.php index b429a7fb0d..e50a5ddb76 100644 --- a/addressbook/inc/class.addressbook_groupdav.inc.php +++ b/addressbook/inc/class.addressbook_groupdav.inc.php @@ -67,8 +67,8 @@ class addressbook_groupdav extends groupdav_handler 'X-ASSISTANT' => array('assistent'), 'X-ASSISTANT-TEL' => array('tel_assistent'), 'UID' => array('uid'), - ); - + ); + /** * Charset for exporting data, as some clients ignore the headers specifying the charset * @@ -333,7 +333,7 @@ class addressbook_groupdav extends groupdav_handler $charset = strtoupper(substr($value,1,-1)); } } - } + } } if (is_array($oldContact)) @@ -387,7 +387,7 @@ class addressbook_groupdav extends groupdav_handler // only set owner, if user is explicitly specified in URL (check via prefix, NOT for /addressbook/ !) if ($prefix) { - // check for modified owners, if user has an add right for the new addressbook and + // check for modified owners, if user has an add right for the new addressbook and // delete rights for the old addressbook (_common_get_put_delete checks for PUT only EGW_ACL_EDIT) if ($oldContact && $user != $oldContact['owner'] && !($this->bo->grants[$user] & EGW_ACL_ADD) && (!$this->bo->grants[$oldContact['owner']] & EGW_ACL_DELETE)) @@ -431,23 +431,11 @@ class addressbook_groupdav extends groupdav_handler */ public function getctag($path,$user) { - $filter = array(); - // show addressbook of a single user? - 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; + // not showing addressbook of a single user? + if (!$user || $path == '/addressbook/') $user = null; + + $ctag = $this->bo->get_ctag($user); - $result = $this->bo->search(array(),'MAX(contact_modified) AS contact_modified','','','',false,'AND',false,$filter); - - if (empty($result)) - { - $ctag = 0; - } - else - { - $ctag = $result[0]['contact_modified']; - } - return 'EGw-'.$ctag.'-wGE'; } diff --git a/addressbook/inc/class.addressbook_so.inc.php b/addressbook/inc/class.addressbook_so.inc.php index d24cfaa4ad..9ee4b2e5a7 100755 --- a/addressbook/inc/class.addressbook_so.inc.php +++ b/addressbook/inc/class.addressbook_so.inc.php @@ -567,7 +567,9 @@ class addressbook_so // Hide deleted items unless type is specifically deleted if(!is_array($filter)) $filter = $filter ? (array) $filter : array(); - if($filter['tid'] !== self::DELETED_TYPE) + + // if no tid set or tid==='' do NOT return deleted entries ($tid === null returns all entries incl. deleted) + if(!array_key_exists('tid', $filter) || $filter['tid'] === '') { if ($join && strpos($join,'RIGHT JOIN') !== false) // used eg. to search for groups { @@ -578,6 +580,10 @@ class addressbook_so $filter[] = 'contact_tid != \'' . self::DELETED_TYPE . '\''; } } + elseif(is_null($filter['tid'])) + { + unset($filter['tid']); // return all entries incl. deleted + } $backend =& $this->get_backend(null,$filter['owner']); // single string to search for --> create so_sql conformant search criterial for the standard search columns @@ -596,16 +602,16 @@ class addressbook_so { $cols = $this->account_cols_to_search; } - if($backend instanceof addressbook_sql) + if($backend instanceof addressbook_sql) { // Keep a string, let the parent handle it $criteria = $search; - foreach($cols as $key => &$col) + foreach($cols as $key => &$col) { - if(!array_key_exists($col, $backend->db_cols)) + if(!array_key_exists($col, $backend->db_cols)) { - if(!($col = array_search($col, $backend->db_cols))) + if(!($col = array_search($col, $backend->db_cols))) { // Can't search this column, it will error if we try unset($cols[$key]); @@ -615,7 +621,7 @@ class addressbook_so } $backend->columns_to_search = $cols; - } + } else { foreach($cols as $col) @@ -750,7 +756,7 @@ class addressbook_so if (!$new_owner) { $this->somain->delete(array('owner' => $account_id)); - if(!($this->somain instanceof addressbook_sql)) + if(!($this->somain instanceof addressbook_sql)) { $this->soextra->delete_customfields(array($this->extra_owner => $account_id)); }