Files
server/usr/share/psa-horde/turba/lib/Application.php
2026-01-07 20:52:11 +01:00

962 lines
34 KiB
PHP

<?php
/**
* Copyright 2010-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (ASL). If you did
* did not receive this file, see http://www.horde.org/licenses/apache.
*
* @category Horde
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/apache ASL
* @package Turba
*/
/**
* Turba application API.
*
* This file defines Horde's core API interface. Other core Horde libraries
* can interact with Turba through this API.
*
* @author Michael Slusarz <slusarz@horde.org?
* @category Horde
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/apache ASL
* @package Turba
*/
/* Determine the base directories. */
if (!defined('TURBA_BASE')) {
define('TURBA_BASE', realpath(__DIR__ . '/..'));
}
if (!defined('HORDE_BASE')) {
/* If Horde does not live directly under the app directory, the HORDE_BASE
* constant should be defined in config/horde.local.php. */
if (file_exists(TURBA_BASE . '/config/horde.local.php')) {
include TURBA_BASE . '/config/horde.local.php';
} else {
define('HORDE_BASE', realpath(TURBA_BASE . '/..'));
}
}
/* Load the Horde Framework core (needed to autoload
* Horde_Registry_Application::). */
require_once HORDE_BASE . '/lib/core.php';
use Sabre\CalDAV;
use Sabre\CardDAV;
class Turba_Application extends Horde_Registry_Application
{
/**
*/
public $features = array(
'smartmobileView' => true,
'modseq' => true,
);
/**
*/
public $version = 'H5 (4.2.29)';
/**
*/
protected function _bootstrap()
{
/* Add Turba-specific factories. */
$factories = array(
'Turba_Shares' => 'Turba_Factory_Shares',
'Turba_Tagger' => 'Turba_Factory_Tagger'
);
foreach ($factories as $key => $val) {
$GLOBALS['injector']->bindFactory($key, $val, 'create');
}
}
/**
* Global variables defined:
* $addSources - TODO
* $attributes - (array) Attribute data from the config/attributes.php
* file.
* $browse_source_count - TODO
* $cfgSources - TODO
* $copymoveSources - TODO
*/
protected function _init()
{
global $conf, $injector, $registry, $session;
if ($conf['tags']['enabled']) {
/* For now, autoloading the Content_* classes depend on there being
* a registry entry for the 'content' application that contains at
* least the fileroot entry. */
$injector->getInstance('Horde_Autoloader')
->addClassPathMapper(
new Horde_Autoloader_ClassPathMapper_Prefix('/^Content_/', $registry->get('fileroot', 'content') . '/lib/'));
if (!class_exists('Content_Tagger')) {
throw new Horde_Exception(_("The Content_Tagger class could not be found. Make sure the Content application is installed."));
}
}
// Turba source and attribute configuration.
$attributes = $registry->loadConfigFile('attributes.php', 'attributes', 'turba')->config['attributes'];
$cfgSources = Turba::availableSources();
/* UGLY UGLY UGLY - we should NOT be using this as a global
* variable all over the place. */
$GLOBALS['cfgSources'] = &$cfgSources;
// See if any of our sources are configured to use Horde_Share.
foreach ($cfgSources as $key => $cfg) {
if (!empty($cfg['use_shares'])) {
// Create a share instance.
$session->set('turba', 'has_share', true);
$cfgSources = Turba::getConfigFromShares($cfgSources);
break;
}
}
$GLOBALS['attributes'] = $attributes;
$cfgSources = Turba::permissionsFilter($cfgSources);
// Build the directory sources select widget.
if (empty(Turba::$source)) {
if (!(Turba::$source = $session->get('turba', 'source'))) {
Turba::$source = Turba::getDefaultAddressbook();
}
Turba::$source = Horde_Util::getFormData('source', Turba::$source);
}
$GLOBALS['browse_source_count'] = 0;
foreach (Turba::getAddressBooks() as $key => $curSource) {
if (!empty($curSource['browse'])) {
$GLOBALS['browse_source_count']++;
if (empty(Turba::$source)) {
Turba::$source = $key;
}
}
}
if (empty($cfgSources[Turba::$source]['browse'])) {
Turba::$source = Turba::getDefaultAddressbook();
}
$session->set('turba', 'source', Turba::$source);
$GLOBALS['addSources'] = Turba::getAddressBooks(Horde_Perms::EDIT, array('require_add' => true));
$GLOBALS['copymoveSources'] = $GLOBALS['addSources'];
unset($GLOBALS['copymoveSources'][Turba::$source]);
}
/**
*/
public function perms()
{
$cfgSources = Turba::availableSources();
$perms = array(
'sources' => array(
'title' => _("Sources")
)
);
// Run through every contact source.
foreach ($cfgSources as $source => $curSource) {
$perms['sources:' . $source] = array(
'title' => $curSource['title']
);
$perms['sources:' . $source . ':max_contacts'] = array(
'title' => _("Maximum Number of Contacts"),
'type' => 'int'
);
}
return $perms;
}
/**
*/
public function getInitialPage()
{
global $registry;
switch ($registry->getView()) {
case $registry::VIEW_SMARTMOBILE:
return strval(Horde::url('smartmobile.php')->setRaw(true));
break;
default:
return null;
}
}
/**
*/
public function menu($menu)
{
if ($GLOBALS['browse_source_count']) {
$menu->add(Horde::url('browse.php'), _("_Browse"), 'turba-browse', null, null, null, (($GLOBALS['prefs']->getValue('initial_page') == 'browse.php' && basename($_SERVER['PHP_SELF']) == 'index.php' && basename(dirname($_SERVER['PHP_SELF'])) != 'addressbooks') || (basename($_SERVER['PHP_SELF']) == 'browse.php' && Horde_Util::getFormData('key') != '**search')) ? 'current' : '__noselection');
}
$menu->add(Horde::url('search.php'), _("_Search"), 'turba-search', null, null, null, (($GLOBALS['prefs']->getValue('initial_page') == 'search.php' && basename($_SERVER['PHP_SELF']) == 'index.php' && strpos($_SERVER['PHP_SELF'], 'addressbooks/index.php') === false) || (basename($_SERVER['PHP_SELF']) == 'browse.php' && Horde_Util::getFormData('key') == '**search')) ? 'current' : null);
/* Import/Export */
if ($GLOBALS['conf']['menu']['import_export']) {
$menu->add(Horde::url('data.php'), _("_Import/Export"), 'horde-data');
}
}
/**
* Add additional items to the sidebar.
*
* @param Horde_View_Sidebar $sidebar The sidebar object.
*/
public function sidebar($sidebar)
{
if (count($GLOBALS['addSources'])) {
$sidebar->addNewButton(_("_New Contact"), Horde::url('add.php'));
}
$user = $GLOBALS['registry']->getAuth();
$edit = Horde::url('addressbooks/edit.php');
$url = Horde::url('');
$sidebar->containers['my'] = array(
'header' => array(
'id' => 'turba-toggle-my',
'label' => _("My Address Books"),
'collapsed' => false,
),
);
if ($GLOBALS['registry']->getAuth() &&
$GLOBALS['session']->get('turba', 'has_share') &&
!empty($GLOBALS['conf']['shares']['source'])) {
$create = true;
$sidebar->containers['my']['header']['add'] = array(
'url' => Horde::url('addressbooks/create.php'),
'label' => _("Create a new Address Book"),
);
}
$shares = array();
$shared = array();
foreach (Turba::listShares(false, Horde_Perms::SHOW) as $id => $abook) {
$row = array(
'selected' => $id == Turba::$source,
'url' => $url->copy()->add('source', $id),
'label' => $abook->get('name'),
'edit' => $edit->copy()->add('a', $abook->getName()),
'type' => 'radiobox',
);
if ($abook->get('owner') && $abook->get('owner') == $user) {
$sidebar->addRow($row, 'my');
if ($row['selected']) {
$sidebar->containers['my']['header']['collapsed'] = false;
}
} else {
if ($abook->get('owner')) {
$row['label'] .= ' [' . $GLOBALS['registry']->convertUsername($abook->get('owner'), false) . ']';
}
$shared[] = $row;
}
$shares[$id] = true;
}
if (!empty($create) || count($shared)) {
$sidebar->containers['shared'] = array(
'header' => array(
'id' => 'turba-toggle-shared',
'label' => _("Shared Address Books"),
'collapsed' => true,
),
);
foreach ($shared as $row) {
$sidebar->addRow($row, 'shared');
if ($row['selected']) {
$sidebar->containers['shared']['header']['collapsed'] = false;
}
}
}
$sidebar->containers['other'] = array(
'header' => array(
'id' => 'turba-toggle-other',
'label' => _("Other Address Books"),
'collapsed' => true,
),
);
foreach (Turba::getAddressBooks(Horde_Perms::SHOW) as $id => $abook) {
if (isset($shares[$id])) {
continue;
}
$row = array(
'selected' => $id == Turba::$source,
'url' => $url->copy()->add('source', $id),
'label' => $abook['title'],
'type' => 'radiobox',
);
$sidebar->addRow($row, 'other');
if ($row['selected']) {
$sidebar->containers['other']['header']['collapsed'] = false;
}
}
}
/**
* Returns values for <configspecial> configuration settings.
*
* @param string $what Either 'client-fields' or 'sources'.
*
* @return array The values for the requested configuration setting.
*/
public function configSpecialValues($what)
{
switch ($what) {
case 'client-fields':
try {
$fields = $GLOBALS['registry']->call('clients/clientFields');
} catch (Horde_Exception $e) {
return array();
}
$f = array();
foreach ($fields as $field) {
$f[$field['name']] = $field['label'];
}
return $f;
case 'sources':
try {
$addressbooks = Turba::getAddressBooks(Horde_Perms::READ);
} catch (Horde_Exception $e) {
return array();
}
foreach ($addressbooks as &$addressbook) {
$addressbook = $addressbook['title'];
}
$addressbooks[''] = _("None");
return $addressbooks;
}
}
/**
*/
public function removeUserData($user)
{
$err = sprintf(
_("There was an error removing an address book for %s"),
$user
);
/* We need a clean copy of the $cfgSources array here.*/
$cfgSources = Turba::availableSources();
foreach ($cfgSources as $sourceId => $source) {
if (empty($source['use_shares'])) {
// Shares not enabled for this source
try {
$driver = $GLOBALS['injector']
->getInstance('Turba_Factory_Driver')
->createFromConfig($source, $sourceId);
} catch (Turba_Exception $e) {
Horde::log($e, 'ERR');
continue;
}
try {
$driver->removeUserData($user);
} catch (Turba_Exception_NotSupported $e) {
continue;
} catch (Turba_Exception $e) {
Horde::log($e, 'ERR');
throw new Turba_Exception($err);
}
}
}
/* Only attempt share removal if we have shares configured */
if (!$GLOBALS['session']->get('turba', 'has_share')) {
return;
}
$turba_shares = $GLOBALS['injector']->getInstance('Turba_Shares');
$shares = $turba_shares->listShares(
$user,
array('attributes' => $user)
);
// Look for the deleted user's shares and remove them
$sources = Turba::getConfigFromShares(
$cfgSources,
true,
array('shares' => $shares, 'auth_user' => $user)
);
foreach ($shares as $share) {
$config = $sources[$share->getName()];
try {
$driver = $GLOBALS['injector']
->getInstance('Turba_Factory_Driver')
->createFromConfig($config, $share->getName(), $sources);
} catch (Turba_Exception $e) {
continue;
}
try {
$driver->removeUserData($user);
} catch (Turba_Exception_NotSupported $e) {
continue;
} catch (Turba_Exception $e) {
Horde::log($e, 'ERR');
throw new Turba_Exception($err);
}
}
/* Get a list of all shares this user has perms to and remove the
* perms. */
try {
$shares = $turba_shares->listShares($user);
foreach ($shares as $share) {
$share->removeUser($user);
}
} catch (Horde_Share_Exception $e) {
Horde::log($e, 'ERR');
throw new Turba_Exception($err);
}
}
/* Topbar method. */
/**
*/
public function topbarCreate(Horde_Tree_Renderer_Base $tree, $parent = null,
array $params = array())
{
$add = Horde::url('add.php');
$browse = Horde::url('browse.php');
if ($GLOBALS['addSources']) {
$newimg = Horde_Themes::img('menu/new.png');
$tree->addNode(array(
'id' => $parent . '__new',
'parent' => $parent,
'label' => _("New Contact"),
'params' => array(
'icon' => $newimg,
'url' => $add
)
));
foreach ($GLOBALS['addSources'] as $addressbook => $config) {
$tree->addNode(array(
'id' => $parent . $addressbook . '__new',
'parent' => $parent . '__new',
'label' => sprintf(_("in %s"), $config['title']),
'expanded' => false,
'params' => array(
'icon' => $newimg,
'url' => $add->copy()->add('source', $addressbook)
)
));
}
}
foreach (Turba::getAddressBooks() as $addressbook => $config) {
if (!empty($config['browse'])) {
$tree->addNode(array(
'id' => $parent . $addressbook,
'parent' => $parent,
'label' => $config['title'],
'expanded' => false,
'params' => array(
'icon' => Horde_Themes::img('menu/browse.png'),
'url' => $browse->copy()->add('source', $addressbook)
)
));
}
}
$tree->addNode(array(
'id' => $parent . '__search',
'parent' => $parent,
'label' => _("Search"),
'expanded' => false,
'params' => array(
'icon' => Horde_Themes::img('search.png'),
'url' => Horde::url('search.php')
)
));
}
/* Download data. */
/**
* @throws Turba_Exception
* @throws Horde_Exception_NotFound
*/
public function download(Horde_Variables $vars)
{
global $attributes, $cfgSources, $injector;
switch ($vars->actionID) {
case 'download_file':
/* Get the object. */
if (!isset($cfgSources[$vars->source])) {
throw new Turba_Exception(_("The contact you requested does not exist."));
}
$object = $injector->getInstance('Turba_Factory_Driver')->create($vars->source)->getObject($vars->key);
/* Check permissions. */
if (!$object->hasPermission(Horde_Perms::READ)) {
throw new Turba_Exception(_("You do not have permission to view this contact."));
}
try {
return array(
'data' => $object->vfsInit()->read(Turba::VFS_PATH . '/' . $object->getValue('__uid'), $vars->file),
'name' => $vars->file
);
} catch (Horde_Vfs_Exception $e) {
Horde::log($e, 'ERR');
throw new Turba_Exception(sprintf(_("Access denied to %s"), $vars->file));
}
case 'export':
$sources = array();
if ($vars->objectkeys) {
foreach ($vars->objectkeys as $objectkey) {
list($source, $key) = explode(':', $objectkey, 2);
if (!isset($sources[$source])) {
$sources[$source] = array();
}
$sources[$source][] = $key;
}
} else {
if (!isset($vars->source) && !empty($cfgSources)) {
reset($cfgSources);
$vars->source = key($cfgSources);
}
$sources[$vars->source] = array();
}
if ($vcard = in_array($vars->exportID, array(Horde_Data::EXPORT_VCARD, 'vcard30'))) {
$version = ($vars->exportID == 'vcard30') ? '3.0' : '2.1';
}
$all_fields = $data = array();
$tfd = $injector->getInstance('Turba_Factory_Driver');
foreach ($sources as $source => $objectkeys) {
/* Create a Turba storage instance. */
$driver = $tfd->create($source);
$blobs = $driver->getBlobs();
/* Get the full, sorted contact list. */
try {
$results = count($objectkeys)
? $driver->getObjects($objectkeys)
: $driver->search(array())->objects;
} catch (Turba_Exception $e) {
throw new Turba_Exception(sprintf(_("Failed to search the directory: %s"), $e->getMessage()));
}
$fields = array_keys($driver->map);
$all_fields = array_merge($all_fields, $fields);
$params = $driver->getParams();
foreach ($results as $ob) {
if ($vcard) {
$data[] = $driver->tovCard($ob, $version, null, true);
} else {
$row = array();
foreach ($fields as $field) {
if (substr($field, 0, 2) == '__' ||
isset($blobs[$field])) {
continue;
}
$attribute = $ob->getValue($field);
if ($attributes[$field]['type'] == 'date') {
$row[$field] = strftime('%Y-%m-%d', $attribute);
} elseif ($attributes[$field]['type'] == 'time') {
$row[$field] = strftime('%R', $attribute);
} elseif ($attributes[$field]['type'] == 'datetime') {
$row[$field] = strftime('%Y-%m-%d %R', $attribute);
} else {
$row[$field] = Horde_String::convertCharset($attribute, 'UTF-8', $params['charset']);
}
}
$data[] = $row;
}
}
}
/* Make sure that all rows have the same columns if exporting from
* different sources. */
if (!$vcard && count($sources) > 1) {
for ($i = 0; $i < count($data); $i++) {
foreach ($all_fields as $field) {
if (!isset($data[$i][$field])) {
$data[$i][$field] = '';
}
}
}
}
switch ($vars->exportID) {
case Horde_Data::EXPORT_CSV:
$injector->getInstance('Horde_Core_Factory_Data')->create('Csv', array('cleanup' => array($this, 'cleanupData')))->exportFile(_("contacts.csv"), $data, true);
exit;
case Horde_Data::EXPORT_OUTLOOKCSV:
$injector->getInstance('Horde_Core_Factory_Data')->create('Outlookcsv', array('cleanup' => array($this, 'cleanupData')))->exportFile(_("contacts.csv"), $data, true, array_flip($this->getOutlookMapping()));
exit;
case Horde_Data::EXPORT_TSV:
$injector->getInstance('Horde_Core_Factory_Data')->create('Tsv', array('cleanup' => array($this, 'cleanupData')))->exportFile(_("contacts.tsv"), $data, true);
exit;
case Horde_Data::EXPORT_VCARD:
case 'vcard30':
$injector->getInstance('Horde_Core_Factory_Data')->create('Vcard', array('cleanup' => array($this, 'cleanupData')))->exportFile(_("contacts.vcf"), $data, true);
exit;
case 'ldif':
$ldif = new Turba_Data_Ldif(
$injector->getInstance('Horde_Core_Data_Storage'),
array(
'browser' => $injector->getInstance('Horde_Browser'),
'vars' => Horde_Variables::getDefaultVariables(),
'cleanup' => array($this, 'cleanupData')
)
);
$ldif->exportFile(_("contacts.ldif"), $data, true);
exit;
}
break;
}
}
/**
*/
public function cleanupData()
{
$GLOBALS['import_step'] = 1;
return Horde_Data::IMPORT_FILE;
}
/**
*/
public function getOutlookMapping()
{
return array(
'Title' => 'namePrefix',
'First Name' => 'firstname',
'Middle Name' => 'middlenames',
'Last Name' => 'lastname',
'Nickname' => 'nickname',
'Suffix' => 'nameSuffix',
'Company' => 'company',
'Department' => 'department',
'Job Title' => 'title',
'Business Street' => 'workStreet',
'Business City' => 'workCity',
'Business State' => 'workProvince',
'Business Postal Code' => 'workPostalCode',
'Business Country' => 'workCountry',
'Home Street' => 'homeStreet',
'Home City' => 'homeCity',
'Home State' => 'homeProvince',
'Home Postal Code' => 'homePostalCode',
'Home Country' => 'homeCountry',
'Business Fax' => 'workFax',
'Business Phone' => 'workPhone',
'Home Phone' => 'homePhone',
'Mobile Phone' => 'cellPhone',
'Pager' => 'pager',
'Anniversary' => 'anniversary',
'Assistant\'s Name' => 'assistant',
'Birthday' => 'birthday',
'Business Address PO Box' => 'workPOBox',
'Categories' => '__tags',
'Children' => 'children',
'E-mail Address' => 'email',
'Home Address PO Box' => 'homePOBox',
'Initials' => 'initials',
'Internet Free Busy' => 'freebusyUrl',
'Language' => 'language',
'Notes' => 'notes',
'Profession' => 'role',
'Office Location' => 'office',
'Spouse' => 'spouse',
'Web Page' => 'website',
);
}
/* DAV methods. */
/**
*/
public function davGetCollections($user)
{
global $injector, $registry;
$hordeUser = $registry->convertUsername($user, true);
$dav = $injector->getInstance('Horde_Dav_Storage');
$factory = $injector->getInstance('Turba_Shares');
$books = array();
foreach (Turba::getAddressBooks(Horde_Perms::SHOW) as $id => $book) {
$readOnly = false;
switch ($book['type']) {
// Ugly hack! There is currently no clean way to retrieve address
// books that the user "owns", or to find out if a SQL/LDAP/Kolab
// address book contains per-user or global contacts.
case 'share':
$share = $factory->getShare($id);
if (($user == '-system-' && strlen($share->get('owner'))) ||
($user != '-system-' &&
$hordeUser != $share->get('owner') &&
$hordeUser != $registry->getAuth())) {
continue 2;
}
$readOnly = !$share->hasPermission($hordeUser, Horde_Perms::EDIT);
break;
case 'facebook':
case 'favourites':
case 'vbook':
if ($user == '-system-') {
continue 2;
}
$readOnly = true;
break;
default:
if (!Turba::permissionsFilter(array($id => $book), Horde_Perms::EDIT)) {
$readOnly = true;
}
break;
}
try {
$id = $dav->getExternalCollectionId($id, 'contacts') ?: $id;
} catch (Horde_Dav_Exception $e) {
}
$books[] = array(
'id' => $id,
'uri' => $id,
'principaluri' => 'principals/' . $user,
'{DAV:}displayname' => $book['title'],
'{' . CardDAV\Plugin::NS_CARDDAV . '}supported-address-data'
=> new CardDAV\Property\SupportedAddressData(
array(
array(
'contentType' => 'text/directory',
'version' => '3.0'
),
array(
'contentType' => 'text/vcard',
'version' => '3.0'
),
array(
'contentType' => 'text/x-vcard',
'version' => '2.1'
),
)
),
'{http://sabredav.org/ns}read-only' => $readOnly
);
}
return $books;
}
/**
*/
public function davGetObjects($collection)
{
$dav = $GLOBALS['injector']
->getInstance('Horde_Dav_Storage');
$internal = $dav->getInternalCollectionId($collection, 'contacts') ?: $collection;
$driver = $GLOBALS['injector']
->getInstance('Turba_Factory_Driver')
->create($internal);
if (!$driver->hasPermission(Horde_Perms::READ)) {
throw new Turba_Exception("Address Book does not exist or no permission to edit");
}
$list = $driver->search(array());
$list->reset();
$contacts = array();
while ($contact = $list->next()) {
$id = $contact->getValue('__key');
$modified = $contact->lastModification();
try {
$id = $dav->getExternalObjectId($id, $internal) ?: $id . '.vcf';
} catch (Horde_Dav_Exception $e) {
}
$contacts[] = array(
'id' => $id,
'uri' => $id,
'lastmodified' => $modified,
'etag' => '"' . md5($contact->getValue('__key') . '|' . $modified) . '"',
);
}
return $contacts;
}
/**
*/
public function davGetObject($collection, $object)
{
$dav = $GLOBALS['injector']
->getInstance('Horde_Dav_Storage');
$internal = $dav->getInternalCollectionId($collection, 'contacts') ?: $collection;
$driver = $GLOBALS['injector']
->getInstance('Turba_Factory_Driver')
->create($internal);
if (!$driver->hasPermission(Horde_Perms::READ)) {
throw new Turba_Exception("Address Book does not exist or no permission to edit");
}
try {
$object = $dav->getInternalObjectId($object, $internal) ?: preg_replace('/\.vcf$/', '', $object);
} catch (Horde_Dav_Exception $e) {
}
$contact = $driver->getObject($object);
$id = $contact->getValue('__key');
$modified = $contact->lastModification();
try {
$id = $dav->getExternalObjectId($id, $internal) ?: $id . '.vcf';
} catch (Horde_Dav_Exception $e) {
}
$data = $driver->tovCard($contact, '3.0', null, true)
->exportvCalendar();
return array(
'id' => $id,
'carddata' => $data,
'uri' => $id,
'lastmodified' => $modified,
'etag' => '"' . md5($contact->getValue('__key') . '|' . $modified) . '"',
'size' => strlen($data),
);
}
/**
*/
public function davPutObject($collection, $object, $data)
{
$dav = $GLOBALS['injector']
->getInstance('Horde_Dav_Storage');
$internal = $dav->getInternalCollectionId($collection, 'contacts') ?: $collection;
$driver = $GLOBALS['injector']
->getInstance('Turba_Factory_Driver')
->create($internal);
if (!$driver->hasPermission(Horde_Perms::EDIT)) {
throw new Turba_Exception("Address Book does not exist or no permission to edit");
}
$ical = new Horde_Icalendar();
if (!$ical->parsevCalendar($data)) {
throw new Turba_Exception(_("There was an error importing the vCard data."));
}
foreach ($ical->getComponents() as $content) {
if (!($content instanceof Horde_Icalendar_Vcard)) {
continue;
}
$contact = $driver->toHash($content);
try {
try {
$existing_id = $dav->getInternalObjectId($object, $internal)
?: preg_replace('/\.vcf$/', '', $object);
} catch (Horde_Dav_Exception $e) {
$existing_id = $object;
}
$existing_contact = $driver->getObject($existing_id);
/* Check if our contact is newer then the existing - get the
* contact's history. */
$modified = $existing_contact->lastModification();
try {
if (!empty($modified) &&
$content->getAttribute('LAST-MODIFIED')->before($modified)) {
/* LAST-MODIFIED timestamp of existing entry is newer:
* don't replace it. */
continue;
}
} catch (Horde_Icalendar_Exception $e) {
}
foreach ($contact as $attribute => $value) {
if ($attribute != '__key') {
$existing_contact->setValue($attribute, $value);
}
}
$existing_contact->store();
} catch (Horde_Exception_NotFound $e) {
$id = $driver->add($contact);
$dav->addObjectMap($id, $object, $internal);
}
}
}
/**
*/
public function davDeleteObject($collection, $object)
{
$dav = $GLOBALS['injector']->getInstance('Horde_Dav_Storage');
$internal = $dav->getInternalCollectionId($collection, 'contacts') ?: $collection;
$driver = $GLOBALS['injector']
->getInstance('Turba_Factory_Driver')
->create($internal);
if (!$driver->hasPermission(Horde_Perms::DELETE)) {
throw new Turba_Exception("Address Book does not exist or no permission to edit");
}
try {
$object = $dav->getInternalObjectId($object, $internal)
?: preg_replace('/\.vcf$/', '', $object);
} catch (Horde_Dav_Exception $e) {
}
$driver->delete($object);
try {
$dav->deleteExternalObjectId($object, $internal);
} catch (Horde_Dav_Exception $e) {
}
}
/**
* Returns the last modification (or creation) date of a contact.
*
* @param string $collection A address book ID.
* @param string $object A contact UID.
*
* @return integer Timestamp of the last modification.
*/
protected function _modified($collection, $uid)
{
$history = $GLOBALS['injector']
->getInstance('Horde_History');
$modified = $history->getActionTimestamp(
'turba:' . $collection . ':' . $uid,
'modify'
);
if (!$modified) {
$modified = $history->getActionTimestamp(
'turba:' . $collection . ':' . $uid,
'add'
);
}
return $modified;
}
}