move addresbook_bo to Api\Contacts, ldap to Api\Ldap, ldapserverinfo to Api\Ldap\ServerInfo, bo_tracking to Api\Storage\Tracking, historylog to Api\Storage\History, Api\Customfields to Api\Storage\Customfields

This commit is contained in:
Ralf Becker 2016-03-06 13:45:15 +00:00
parent fcca19cfcf
commit 7ada2354d3
23 changed files with 5858 additions and 4957 deletions

File diff suppressed because it is too large Load Diff

View File

@ -5,11 +5,13 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook * @package addressbook
* @copyright (c) 2007-15 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api;
/** /**
* SiteMgr contact form for the addressbook * SiteMgr contact form for the addressbook
* *
@ -75,7 +77,7 @@ class addressbook_contactform
elseif ($content['submitit']) elseif ($content['submitit'])
{ {
$submitted = true; $submitted = true;
$contact = new addressbook_bo(); $contact = new Api\Contacts();
if ($content['owner']) // save the contact in the addressbook if ($content['owner']) // save the contact in the addressbook
{ {
$content['private'] = 0; // in case default_private is set $content['private'] = 0; // in case default_private is set
@ -90,9 +92,9 @@ class addressbook_contactform
// the anonymous user to have run rights for addressbook AND // the anonymous user to have run rights for addressbook AND
// edit rights for the addressbook used to store the new entry, // edit rights for the addressbook used to store the new entry,
// which is clearly not wanted securitywise // which is clearly not wanted securitywise
egw_vfs::$is_root = true; Api\Vfs::$is_root = true;
egw_link::link('addressbook',$id,egw_link::VFS_APPNAME,$value,$name); egw_link::link('addressbook',$id,egw_link::VFS_APPNAME,$value,$name);
egw_vfs::$is_root = false; Api\Vfs::$is_root = false;
} }
} }
@ -108,8 +110,7 @@ class addressbook_contactform
{ {
if ($content['email_contactform']) if ($content['email_contactform'])
{ {
require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.addressbook_tracking.inc.php'); $tracking = new Api\Contacts\Tracking($contact);
$tracking = new addressbook_tracking($contact);
} }
if ($tracking->do_notifications($contact->data2db($content),null)) if ($tracking->do_notifications($contact->data2db($content),null))
{ {
@ -141,7 +142,7 @@ class addressbook_contactform
static $contact; static $contact;
if (is_null($contact)) if (is_null($contact))
{ {
$contact = new addressbook_bo(); $contact = new Api\Contacts();
} }
$content['show']['custom'.$custom] = true; $content['show']['custom'.$custom] = true;
$content['customfield'][$custom] = $name; $content['customfield'][$custom] = $name;
@ -174,7 +175,7 @@ class addressbook_contactform
if ($name[0] == '#') // custom field if ($name[0] == '#') // custom field
{ {
static $contact; static $contact;
if (is_null($contact)) $contact = new addressbook_bo(); if (is_null($contact)) $contact = new Api\Contacts();
$content['show']['custom'.$custom] = true; $content['show']['custom'.$custom] = true;
$content['customfield'][$custom] = $name; $content['customfield'][$custom] = $name;
$content['customlabel'][$custom] = $contact->customfields[substr($name,1)]['label']; $content['customlabel'][$custom] = $contact->customfields[substr($name,1)]['label'];

View File

@ -7,10 +7,12 @@
* @package addressbook * @package addressbook
* @subpackage groupdav * @subpackage groupdav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-15 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api;
/** /**
* EGroupware: GroupDAV access: addressbook handler * EGroupware: GroupDAV access: addressbook handler
* *
@ -953,7 +955,7 @@ class addressbook_groupdav extends groupdav_handler
if (is_null($non_deleted_tids)) if (is_null($non_deleted_tids))
{ {
$non_deleted_tids = $this->bo->content_types; $non_deleted_tids = $this->bo->content_types;
unset($non_deleted_tids[addressbook_so::DELETED_TYPE]); unset($non_deleted_tids[Api\Contacts::DELETED_TYPE]);
$non_deleted_tids = array_keys($non_deleted_tids); $non_deleted_tids = array_keys($non_deleted_tids);
} }
$contact = $this->bo->read(array(self::$path_attr => $id, 'tid' => $non_deleted_tids)); $contact = $this->bo->read(array(self::$path_attr => $id, 'tid' => $non_deleted_tids));
@ -1000,7 +1002,7 @@ class addressbook_groupdav extends groupdav_handler
$contact = null; $contact = null;
} }
if ($contact && $contact['tid'] == addressbook_so::DELETED_TYPE) if ($contact && $contact['tid'] == Api\Contacts::DELETED_TYPE)
{ {
$contact = null; // handle deleted events, as not existing (404 Not Found) $contact = null; // handle deleted events, as not existing (404 Not Found)
} }

View File

@ -1,15 +1,16 @@
<?php <?php
/** /**
* eGroupWare * EGroupware Addressbook
* *
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package importexport * @package importexport
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Cornelius Weiss <nelius@cwtech.de> * @author Cornelius Weiss <nelius@cwtech.de>
* @copyright Cornelius Weiss <nelius@cwtech.de> * @copyright Cornelius Weiss <nelius@cwtech.de>
* @version $Id: $ * @version $Id$
*/ */
use EGroupware\Api;
/** /**
* class import_csv for addressbook * class import_csv for addressbook
@ -30,6 +31,8 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
/** /**
* For figuring out if a contact has changed * For figuring out if a contact has changed
*
* @var Api\Contacts\Tracking
*/ */
protected $tracking; protected $tracking;
@ -48,10 +51,10 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
public function init(importexport_definition &$_definition ) { public function init(importexport_definition &$_definition ) {
// fetch the addressbook bo // fetch the addressbook bo
$this->bocontacts = new addressbook_bo(); $this->bocontacts = new Api\Contacts();
// Get the tracker for changes // Get the tracker for changes
$this->tracking = new addressbook_tracking($this->bocontacts); $this->tracking = new Api\Contacts\Tracking($this->bocontacts);
$this->lookups = array( $this->lookups = array(
'tid' => array('n'=>'contact') 'tid' => array('n'=>'contact')
@ -138,10 +141,10 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
// Also handle categories in their own field // Also handle categories in their own field
$record_array = $record->get_record_array(); $record_array = $record->get_record_array();
$more_categories = array(); $more_categories = array();
foreach($this->definition->plugin_options['field_mapping'] as $number => $field_name) { foreach($this->definition->plugin_options['field_mapping'] as $field_name) {
if(!array_key_exists($field_name, $record_array) || if(!array_key_exists($field_name, $record_array) ||
substr($field_name,0,3) != 'cat' || !$record->$field_name || $field_name == 'cat_id') continue; substr($field_name,0,3) != 'cat' || !$record->$field_name || $field_name == 'cat_id') continue;
list($cat, $cat_id) = explode('-', $field_name); list(, $cat_id) = explode('-', $field_name);
if(is_numeric($record->$field_name) && $record->$field_name != 1) { if(is_numeric($record->$field_name) && $record->$field_name != 1) {
// Column has a single category ID // Column has a single category ID
$more_categories[] = $record->$field_name; $more_categories[] = $record->$field_name;
@ -175,7 +178,7 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
if($record_array[$condition['string']]) { if($record_array[$condition['string']]) {
$searchcondition = array( $condition['string'] => $record_array[$condition['string']]); $searchcondition = array( $condition['string'] => $record_array[$condition['string']]);
// if we use account_id for the condition, we need to set the owner for filtering, as this // if we use account_id for the condition, we need to set the owner for filtering, as this
// enables addressbook_so to decide what backend is to be used // enables Api\Contacts\Storage to decide what backend is to be used
if ($condition['string']=='account_id') $searchcondition['owner']=0; if ($condition['string']=='account_id') $searchcondition['owner']=0;
$contacts = $this->bocontacts->search( $contacts = $this->bocontacts->search(
//array( $condition['string'] => $record[$condition['string']],), //array( $condition['string'] => $record[$condition['string']],),
@ -204,7 +207,7 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
break; break;
case 'equal': case 'equal':
// Match on field // Match on field
$result = $this->equal($record, $condition, $matches); $result = $this->equal($record, $condition);
if($result) if($result)
{ {
// Apply true action to any matching records found // Apply true action to any matching records found
@ -270,7 +273,8 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
$old = $this->bocontacts->read($_data['id']); $old = $this->bocontacts->read($_data['id']);
// if we get countrycodes as countryname, try to translate them -> the rest should be handled by bo classes. // if we get countrycodes as countryname, try to translate them -> the rest should be handled by bo classes.
foreach(array('adr_one_', 'adr_two_') as $c_prefix) { foreach(array('adr_one_', 'adr_two_') as $c_prefix) {
if (strlen(trim($_data[$c_prefix.'countryname']))==2) $_data[$c_prefix.'countryname'] = $GLOBALS['egw']->country->get_full_name(trim($_data[$c_prefix.'countryname']),$translated=true); if (strlen(trim($_data[$c_prefix.'countryname']))==2)
$_data[$c_prefix.'countryname'] = $GLOBALS['egw']->country->get_full_name(trim($_data[$c_prefix.'countryname']), true);
} }
// Don't change a user account into a contact // Don't change a user account into a contact
if($old['owner'] == 0) { if($old['owner'] == 0) {
@ -412,4 +416,3 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
return $this->results; return $this->results;
} }
} // end of iface_export_plugin } // end of iface_export_plugin
?>

File diff suppressed because it is too large Load Diff

View File

@ -1138,9 +1138,9 @@ window.egw_LAB.wait(function() {
if ($contact['owner'] || // regular contact or if ($contact['owner'] || // regular contact or
empty($contact['account_id']) || // accounts without account_id empty($contact['account_id']) || // accounts without account_id
// already deleted account (should no longer happen, but needed to allow for cleanup) // already deleted account (should no longer happen, but needed to allow for cleanup)
$contact['tid'] == addressbook_so::DELETED_TYPE) $contact['tid'] == self::DELETED_TYPE)
{ {
$Ok = $this->delete($id, $contact['tid'] != addressbook_so::DELETED_TYPE && $contact['account_id']); $Ok = $this->delete($id, $contact['tid'] != self::DELETED_TYPE && $contact['account_id']);
} }
// delete single account --> redirect to admin // delete single account --> redirect to admin
elseif (count($checked) == 1 && $contact['account_id']) elseif (count($checked) == 1 && $contact['account_id'])
@ -1684,7 +1684,7 @@ window.egw_LAB.wait(function() {
{ {
$row['class'] .= 'rowAccount rowNoDelete '; $row['class'] .= 'rowAccount rowNoDelete ';
} }
elseif (!$this->check_perms(EGW_ACL_DELETE,$row) || (!$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge' && $query['col_filter']['tid'] == addressbook_so::DELETED_TYPE)) elseif (!$this->check_perms(EGW_ACL_DELETE,$row) || (!$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge' && $query['col_filter']['tid'] == self::DELETED_TYPE))
{ {
$row['class'] .= 'rowNoDelete '; $row['class'] .= 'rowNoDelete ';
} }
@ -2274,7 +2274,7 @@ window.egw_LAB.wait(function() {
); );
// Links for deleted entries // Links for deleted entries
if($content['tid'] == addressbook_so::DELETED_TYPE) if($content['tid'] == self::DELETED_TYPE)
{ {
$content['link_to']['show_deleted'] = true; $content['link_to']['show_deleted'] = true;
if(!$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge') if(!$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge')
@ -2604,7 +2604,7 @@ window.egw_LAB.wait(function() {
'to_id' => $content['id'], 'to_id' => $content['id'],
); );
// Links for deleted entries // Links for deleted entries
if($content['tid'] == addressbook_so::DELETED_TYPE) if($content['tid'] == self::DELETED_TYPE)
{ {
$content['link_to']['show_deleted'] = true; $content['link_to']['show_deleted'] = true;
} }

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* eGgroupWare admin - UI for adding custom fields * EGgroupware admin - UI for adding custom fields
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
@ -10,6 +10,8 @@
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api;
/** /**
* Customfields class - manages customfield definitions in egw_config table * Customfields class - manages customfield definitions in egw_config table
* *
@ -103,10 +105,10 @@ class customfields
{ {
if (($this->appname = $appname)) if (($this->appname = $appname))
{ {
$this->fields = egw_customfields::get($this->appname,true); $this->fields = Api\Storage\Customfields::get($this->appname,true);
$this->content_types = config::get_content_types($this->appname); $this->content_types = Api\Config::get_content_types($this->appname);
} }
$this->so = new so_sql('phpgwapi','egw_customfields',null,'',true); $this->so = new Api\Storage\Base('phpgwapi','egw_customfields',null,'',true);
} }
/** /**
@ -121,7 +123,7 @@ class customfields
$this->use_private = !isset($_GET['use_private']) || (boolean)$_GET['use_private'] || $content['use_private']; $this->use_private = !isset($_GET['use_private']) || (boolean)$_GET['use_private'] || $content['use_private'];
// Read fields, constructor doesn't always know appname // Read fields, constructor doesn't always know appname
$this->fields = egw_customfields::get($this->appname,true); $this->fields = Api\Storage\Customfields::get($this->appname,true);
$this->tmpl = new etemplate_new(); $this->tmpl = new etemplate_new();
$this->tmpl->read('admin.customfields'); $this->tmpl->read('admin.customfields');
@ -135,7 +137,7 @@ class customfields
{ {
if(count($this->content_types) == 0) if(count($this->content_types) == 0)
{ {
$this->content_types = config::get_content_types($this->appname); $this->content_types = Api\Config::get_content_types($this->appname);
} }
if (count($this->content_types)==0) if (count($this->content_types)==0)
{ {
@ -152,7 +154,7 @@ class customfields
} }
elseif($content['content_types']['create']) elseif($content['content_types']['create'])
{ {
if($new_type = $this->create_content_type($content)) if(($new_type = $this->create_content_type($content)))
{ {
$content['content_types']['types'] = $this->content_type = $new_type; $content['content_types']['types'] = $this->content_type = $new_type;
} }
@ -214,7 +216,6 @@ class customfields
$content['type_template'] = $this->appname . '.admin.types'; $content['type_template'] = $this->appname . '.admin.types';
$content['content_types']['appname'] = $this->appname; $content['content_types']['appname'] = $this->appname;
$content_types = array_keys($this->content_types);
$content['content_type_options'] = $this->content_types[$this->content_type]['options']; $content['content_type_options'] = $this->content_types[$this->content_type]['options'];
$content['content_type_options']['type'] = $this->types2[$this->content_type]; $content['content_type_options']['type'] = $this->types2[$this->content_type];
@ -251,6 +252,7 @@ class customfields
); );
// Allow extending app a change to change content before display // Allow extending app a change to change content before display
$readonlys = null;
static::app_index($content, $sel_options, $readonlys, $preserve); static::app_index($content, $sel_options, $readonlys, $preserve);
// Make sure app css gets loaded, extending app might cause et2 to miss it // Make sure app css gets loaded, extending app might cause et2 to miss it
@ -292,7 +294,7 @@ class customfields
$this->use_private = !isset($_GET['use_private']) || (boolean)$_GET['use_private'] || $content['use_private']; $this->use_private = !isset($_GET['use_private']) || (boolean)$_GET['use_private'] || $content['use_private'];
// Read fields, constructor doesn't always know appname // Read fields, constructor doesn't always know appname
$this->fields = egw_customfields::get($this->appname,true); $this->fields = Api\Storage\Customfields::get($this->appname,true);
// Update based on info returned from template // Update based on info returned from template
if (is_array($content)) if (is_array($content))
@ -328,8 +330,8 @@ class customfields
{ {
foreach(explode("\n",trim($content['cf_values'])) as $line) foreach(explode("\n",trim($content['cf_values'])) as $line)
{ {
list($var,$value) = explode('=',trim($line),2); list($var_raw,$value) = explode('=',trim($line),2);
$var = trim($var); $var = trim($var_raw);
$values[$var] = trim($value)==='' ? $var : $value; $values[$var] = trim($value)==='' ? $var : $value;
} }
} }
@ -343,10 +345,10 @@ class customfields
$update_content[substr($key,3)] = $value; $update_content[substr($key,3)] = $value;
} }
} }
egw_customfields::update($update_content); Api\Storage\Customfields::update($update_content);
if(!$cf_id) if(!$cf_id)
{ {
$this->fields = egw_customfields::get($this->appname,true); $this->fields = Api\Storage\Customfields::get($this->appname,true);
$cf_id = (int)$this->fields[$content['cf_name']]['id']; $cf_id = (int)$this->fields[$content['cf_name']]['id'];
} }
egw_framework::refresh_opener('Saved', 'admin', $cf_id, 'edit'); egw_framework::refresh_opener('Saved', 'admin', $cf_id, 'edit');
@ -415,7 +417,7 @@ class customfields
{ {
if(count($this->content_types) == 0) if(count($this->content_types) == 0)
{ {
$this->content_types = config::get_content_types($this->appname); $this->content_types = Api\Config::get_content_types($this->appname);
} }
if (count($this->content_types)==0) if (count($this->content_types)==0)
{ {
@ -455,6 +457,7 @@ class customfields
*/ */
protected function app_index(&$content, &$sel_options, &$readonlys) protected function app_index(&$content, &$sel_options, &$readonlys)
{ {
unset($content, $sel_options, $readonlys); // not used, as this is a stub
// This is just a stub. // This is just a stub.
} }
@ -494,78 +497,6 @@ class customfields
return $actions; return $actions;
} }
function update_fields(&$content)
{
foreach($content['fields'] as $field)
{
$name = trim($field['name']);
$old_name = $field['old_name'];
if (!empty($delete) && $delete == $old_name)
{
unset($this->fields[$old_name]);
continue;
}
if (isset($field['old_name']))
{
if (empty($name)) // empty name not allowed
{
$content['error_msg'] = lang('Name must not be empty !!!');
$name = $old_name;
}
if (!empty($name) && $old_name != $name) // renamed
{
unset($this->fields[$old_name]);
}
}
elseif (empty($name)) // new item and empty ==> ignore it
{
continue;
}
$values = array();
if (!empty($field['values']))
{
foreach(explode("\n",$field['values']) as $line)
{
list($var,$value) = explode('=',trim($line),2);
$var = trim($var);
$values[$var] = empty($value) ? $var : $value;
}
}
$this->fields[$name] = array(
'type' => $field['type'],
'type2' => $field['type2'],
'label' => empty($field['label']) ? $name : $field['label'],
'help' => $field['help'],
'values'=> $values,
'len' => $field['len'],
'rows' => (int)$field['rows'],
'order' => (int)$field['order'],
'private' => $field['private'],
'needed' => $field['needed'],
);
if(!$this->fields[$name]['type2'] && $this->manage_content_types)
{
$this->fields[$name]['type2'] = (string)0;
}
}
if (!function_exists('sort_by_order'))
{
function sort_by_order($arr1,$arr2)
{
return $arr1['order'] - $arr2['order'];
}
}
uasort($this->fields,sort_by_order);
$n = 0;
foreach($this->fields as $name => $data)
{
$this->fields[$name]['order'] = ($n += 10);
}
}
function update(&$content) function update(&$content)
{ {
$this->content_types[$this->content_type]['options'] = $content['content_type_options']; $this->content_types[$this->content_type]['options'] = $content['content_type_options'];
@ -627,7 +558,7 @@ class customfields
} }
else else
{ {
foreach($this->content_types as $letter => $type) foreach($this->content_types as $type)
{ {
if($type['name'] == $new_name) if($type['name'] == $new_name)
{ {
@ -640,8 +571,8 @@ class customfields
{ {
if (!$this->content_types[chr($i)] && if (!$this->content_types[chr($i)] &&
// skip letter of deleted type for addressbook content-types, as it gives SQL error // skip letter of deleted type for addressbook content-types, as it gives SQL error
// content-type are lowercase, addressbook_so::DELETED_TYPE === 'D', but DB is case-insensitive // content-type are lowercase, Api\Contacts::DELETED_TYPE === 'D', but DB is case-insensitive
($this->appname !== 'addressbook' || chr($i) !== strtolower(addressbook_so::DELETED_TYPE))) ($this->appname !== 'addressbook' || chr($i) !== strtolower(Api\Contacts::DELETED_TYPE)))
{ {
$new_type = chr($i); $new_type = chr($i);
break; break;
@ -664,32 +595,32 @@ class customfields
$config->value('types',$this->content_types); $config->value('types',$this->content_types);
$config->save_repository(); $config->save_repository();
egw_customfields::save($this->appname, $this->fields); Api\Storage\Customfields::save($this->appname, $this->fields);
} }
/** /**
* get customfields of using application * get customfields of using application
* *
* @deprecated use egw_customfields::get() direct, no need to instanciate this UI class * @deprecated use Api\Storage\Customfields::get() direct, no need to instanciate this UI class
* @author Cornelius Weiss * @author Cornelius Weiss
* @param boolean $all_private_too=false should all the private fields be returned too * @param boolean $all_private_too =false should all the private fields be returned too
* @return array with customfields * @return array with customfields
*/ */
function get_customfields($all_private_too=false) function get_customfields($all_private_too=false)
{ {
return egw_customfields::get($this->appname,$all_private_too); return Api\Storage\Customfields::get($this->appname,$all_private_too);
} }
/** /**
* get_content_types of using application * get_content_types of using application
* *
* @deprecated use config::get_content_types() direct, no need to instanciate this UI class * @deprecated use Api\Config::get_content_types() direct, no need to instanciate this UI class
* @author Cornelius Weiss * @author Cornelius Weiss
* @return array with content-types * @return array with content-types
*/ */
function get_content_types() function get_content_types()
{ {
return config::get_content_types($this->appname); return Api\Config::get_content_types($this->appname);
} }
/** /**

View File

@ -228,13 +228,13 @@ class Config
* @param string $app * @param string $app
* @param boolean $all_private_too =false should all the private fields be returned too, default no * @param boolean $all_private_too =false should all the private fields be returned too, default no
* @param string $only_type2 =null if given only return fields of type2 == $only_type2 * @param string $only_type2 =null if given only return fields of type2 == $only_type2
* @deprecated use Api\Customfields::get() * @deprecated use Api\Storage\Customfields::get()
* @return array with customfields * @return array with customfields
*/ */
static function get_customfields($app, $all_private_too=false, $only_type2=null) static function get_customfields($app, $all_private_too=false, $only_type2=null)
{ {
//error_log(__METHOD__."('$app', $all_private_too, $only_type2) deprecated, use Customfields::get() in ". function_backtrace()); //error_log(__METHOD__."('$app', $all_private_too, $only_type2) deprecated, use Storage\Customfields::get() in ". function_backtrace());
return Customfields::get($app, $all_private_too, $only_type2); return Storage\Customfields::get($app, $all_private_too, $only_type2);
} }
/** /**

2402
api/src/Contacts.php Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,22 @@
<?php <?php
/** /**
* Addressbook - ADS Backend * EGroupware API: Contacts ADS Backend
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <rb@stylite.de> * @author Ralf Becker <rb@stylite.de>
* @package addressbook * @package api
* @subpackage contacts
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
namespace EGroupware\Api\Contacts;
use EGroupware\Api;
// explicitly reference classes still in phpgwapi
use accounts_ads;
/** /**
* Active directory backend for accounts (not yet AD contacts) * Active directory backend for accounts (not yet AD contacts)
* *
@ -22,7 +30,7 @@
* All values used to construct filters need to run through ldap::quote(), * All values used to construct filters need to run through ldap::quote(),
* to be save against LDAP query injection!!! * to be save against LDAP query injection!!!
*/ */
class addressbook_ads extends addressbook_ldap class Ads extends Ldap
{ {
/** /**
* LDAP searches only a limited set of attributes for performance reasons, * LDAP searches only a limited set of attributes for performance reasons,
@ -74,11 +82,13 @@ class addressbook_ads extends addressbook_ldap
/** /**
* constructor of the class * constructor of the class
* *
* @param array $ldap_config=null default use from $GLOBALS['egw_info']['server'] * @param array $ldap_config =null default use from $GLOBALS['egw_info']['server']
* @param resource $ds=null ldap connection to use * @param resource $ds =null ldap connection to use
*/ */
function __construct(array $ldap_config=null, $ds=null) function __construct(array $ldap_config=null, $ds=null)
{ {
if (false) parent::__construct (); // quiten IDE warning, we are explicitly NOT calling parrent constructor!
$this->accountName = $GLOBALS['egw_info']['user']['account_lid']; $this->accountName = $GLOBALS['egw_info']['user']['account_lid'];
if ($ldap_config) if ($ldap_config)
@ -103,8 +113,8 @@ class addressbook_ads extends addressbook_ldap
{ {
$this->connect(); $this->connect();
} }
$this->ldapServerInfo = ldapserverinfo::get($this->ds, $this->ldap_config['ads_host']); $this->ldapServerInfo = Api\Ldap\ServerInfo::get($this->ds, $this->ldap_config['ads_host']);
$this->is_samba4 = $this->ldapServerInfo->serverType == SAMBA4_LDAPSERVER; $this->is_samba4 = $this->ldapServerInfo->serverType == Api\Ldap\ServerInfo::SAMBA4;
// AD seems to use user, instead of inetOrgPerson // AD seems to use user, instead of inetOrgPerson
unset($this->schema2egw['posixaccount']); unset($this->schema2egw['posixaccount']);
@ -118,22 +128,24 @@ class addressbook_ads extends addressbook_ldap
unset($this->schema2egw['user']['n_fileas']); unset($this->schema2egw['user']['n_fileas']);
unset($this->schema2egw['inetorgperson']); unset($this->schema2egw['inetorgperson']);
foreach($this->schema2egw as $schema => $attributes) foreach($this->schema2egw as $attributes)
{ {
$this->all_attributes = array_merge($this->all_attributes,array_values($attributes)); $this->all_attributes = array_merge($this->all_attributes,array_values($attributes));
} }
$this->all_attributes = array_values(array_unique($this->all_attributes)); $this->all_attributes = array_values(array_unique($this->all_attributes));
$this->charset = translation::charset(); $this->charset = Api\Translation::charset();
} }
/** /**
* connect to LDAP server * connect to LDAP server
* *
* @param boolean $admin=false true (re-)connect with admin not user credentials, eg. to modify accounts * @param boolean $admin =false true (re-)connect with admin not user credentials, eg. to modify accounts
*/ */
function connect($admin=false) function connect($admin=false)
{ {
unset($admin); // not used, but required by function signature
$this->ds = $this->accounts_ads->ldap_connection(); $this->ds = $this->accounts_ads->ldap_connection();
} }
@ -159,21 +171,21 @@ class addressbook_ads extends addressbook_ldap
/** /**
* reads contact data * reads contact data
* *
* @param string/array $contact_id contact_id or array with values for id or account_id * @param string/array $_contact_id contact_id or array with values for id or account_id
* @return array/boolean data if row could be retrived else False * @return array/boolean data if row could be retrived else False
*/ */
function read($contact_id) function read($_contact_id)
{ {
if (is_array($contact_id) && isset($contact_id['account_id']) || if (is_array($_contact_id) && isset($_contact_id['account_id']) ||
!is_array($contact_id) && substr($contact_id,0,8) == 'account:') !is_array($_contact_id) && substr($_contact_id,0,8) == 'account:')
{ {
$account_id = (int)(is_array($contact_id) ? $contact_id['account_id'] : substr($contact_id,8)); $account_id = (int)(is_array($_contact_id) ? $_contact_id['account_id'] : substr($_contact_id,8));
$contact_id = $GLOBALS['egw']->accounts->id2name($account_id, 'person_id'); $_contact_id = $GLOBALS['egw']->accounts->id2name($account_id, 'person_id');
} }
$contact_id = !is_array($contact_id) ? $contact_id : $contact_id = !is_array($_contact_id) ? $_contact_id :
(isset ($contact_id['id']) ? $contact_id['id'] : $contact_id['uid']); (isset ($_contact_id['id']) ? $_contact_id['id'] : $_contact_id['uid']);
$rows = $this->_searchLDAP($this->allContactsDN, $filter=$this->id_filter($contact_id), $this->all_attributes, ADDRESSBOOK_ALL); $rows = $this->_searchLDAP($this->allContactsDN, $filter=$this->id_filter($contact_id), $this->all_attributes, Ldap::ALL);
//error_log(__METHOD__."('$contact_id') _searchLDAP($this->allContactsDN, '$filter',...)=".array2string($rows)); //error_log(__METHOD__."('$contact_id') _searchLDAP($this->allContactsDN, '$filter',...)=".array2string($rows));
return $rows ? $rows[0] : false; return $rows ? $rows[0] : false;
} }
@ -214,5 +226,4 @@ class addressbook_ads extends addressbook_ldap
parent::sanitize_update($ldapContact); parent::sanitize_update($ldapContact);
} }
} }

View File

@ -1,20 +1,23 @@
<?php <?php
/** /**
* Addressbook - LDAP Backend * EGroupware API: Contacts LDAP Backend
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Cornelius Weiss <egw-AT-von-und-zu-weiss.de> * @author Cornelius Weiss <egw-AT-von-und-zu-weiss.de>
* @author Lars Kneschke <l.kneschke-AT-metaways.de> * @author Lars Kneschke <l.kneschke-AT-metaways.de>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook * @package api
* @subpackage contacts
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
define('ADDRESSBOOK_ALL',0); namespace EGroupware\Api\Contacts;
define('ADDRESSBOOK_ACCOUNTS',1);
define('ADDRESSBOOK_PERSONAL',2); use EGroupware\Api;
define('ADDRESSBOOK_GROUP',3);
// explicitly reference classes still in phpgwapi
use common; // randomstring
/** /**
* LDAP Backend for contacts, compatible with vars and parameters of eTemplate's so_sql. * LDAP Backend for contacts, compatible with vars and parameters of eTemplate's so_sql.
@ -23,8 +26,14 @@ define('ADDRESSBOOK_GROUP',3);
* All values used to construct filters need to run through ldap::quote(), * All values used to construct filters need to run through ldap::quote(),
* to be save against LDAP query injection!!! * to be save against LDAP query injection!!!
*/ */
class addressbook_ldap class Ldap
{ {
const ALL = 0;
const ACCOUNTS = 1;
const PERSONAL = 2;
const GROUP = 3;
var $data; var $data;
/** /**
@ -298,7 +307,7 @@ class addressbook_ldap
} }
$this->all_attributes = array_values(array_unique($this->all_attributes)); $this->all_attributes = array_values(array_unique($this->all_attributes));
$this->charset = translation::charset(); $this->charset = Api\Translation::charset();
} }
/** /**
@ -414,7 +423,7 @@ class addressbook_ldap
$filter = $this->id_filter($contact_id); $filter = $this->id_filter($contact_id);
} }
$rows = $this->_searchLDAP($this->allContactsDN, $rows = $this->_searchLDAP($this->allContactsDN,
$filter, $this->all_attributes, ADDRESSBOOK_ALL, array('_posixaccount2egw')); $filter, $this->all_attributes, self::ALL, array('_posixaccount2egw'));
return $rows ? $rows[0] : false; return $rows ? $rows[0] : false;
} }
@ -508,7 +517,7 @@ class addressbook_ldap
if(empty($contactUID)) if(empty($contactUID))
{ {
$ldapContact[$this->dn_attribute] = $this->data[$this->contacts_id] = $contactUID = md5($GLOBALS['egw']->common->randomstring(15)); $ldapContact[$this->dn_attribute] = $this->data[$this->contacts_id] = $contactUID = md5(common::randomstring(15));
} }
//error_log(__METHOD__."() contactUID='$contactUID', isUpdate=".array2string($isUpdate).", oldContactInfo=".array2string($oldContactInfo)); //error_log(__METHOD__."() contactUID='$contactUID', isUpdate=".array2string($isUpdate).", oldContactInfo=".array2string($oldContactInfo));
// add for all supported objectclasses the objectclass and it's attributes // add for all supported objectclasses the objectclass and it's attributes
@ -537,7 +546,7 @@ class addressbook_ldap
{ {
// dont convert the (binary) jpegPhoto! // dont convert the (binary) jpegPhoto!
$ldapContact[$ldapFieldName] = $ldapFieldName == 'jpegphoto' ? $data[$egwFieldName] : $ldapContact[$ldapFieldName] = $ldapFieldName == 'jpegphoto' ? $data[$egwFieldName] :
translation::convert(trim($data[$egwFieldName]),$this->charset,'utf-8'); Api\Translation::convert(trim($data[$egwFieldName]),$this->charset,'utf-8');
} }
elseif($isUpdate && isset($data[$egwFieldName])) elseif($isUpdate && isset($data[$egwFieldName]))
{ {
@ -593,7 +602,7 @@ class addressbook_ldap
{ {
$result = ldap_read($this->ds, $dn, 'objectclass=*'); $result = ldap_read($this->ds, $dn, 'objectclass=*');
$entries = ldap_get_entries($this->ds, $result); $entries = ldap_get_entries($this->ds, $result);
$oldContact = ldap::result2array($entries[0]); $oldContact = Api\Ldap::result2array($entries[0]);
unset($oldContact['dn']); unset($oldContact['dn']);
$newContact = $oldContact; $newContact = $oldContact;
@ -681,7 +690,7 @@ class addressbook_ldap
foreach($keys as $entry) foreach($keys as $entry)
{ {
$entry = ldap::quote(is_array($entry) ? $entry['id'] : $entry); $entry = Api\Ldap::quote(is_array($entry) ? $entry['id'] : $entry);
if(($result = ldap_search($this->ds, $this->allContactsDN, if(($result = ldap_search($this->ds, $this->allContactsDN,
"(|(entryUUID=$entry)(uid=$entry))", $attributes))) "(|(entryUUID=$entry)(uid=$entry))", $attributes)))
{ {
@ -759,33 +768,33 @@ class addressbook_ldap
{ {
if (!($accountName = $GLOBALS['egw']->accounts->id2name($filter['owner']))) return false; if (!($accountName = $GLOBALS['egw']->accounts->id2name($filter['owner']))) return false;
$searchDN = 'cn='. ldap::quote(strtolower($accountName)) .','; $searchDN = 'cn='. Api\Ldap::quote(strtolower($accountName)) .',';
if ($filter['owner'] < 0) if ($filter['owner'] < 0)
{ {
$searchDN .= $this->sharedContactsDN; $searchDN .= $this->sharedContactsDN;
$addressbookType = ADDRESSBOOK_GROUP; $addressbookType = self::GROUP;
} }
else else
{ {
$searchDN .= $this->personalContactsDN; $searchDN .= $this->personalContactsDN;
$addressbookType = ADDRESSBOOK_PERSONAL; $addressbookType = self::PERSONAL;
} }
} }
elseif (!isset($filter['owner'])) elseif (!isset($filter['owner']))
{ {
$searchDN = $this->allContactsDN; $searchDN = $this->allContactsDN;
$addressbookType = ADDRESSBOOK_ALL; $addressbookType = self::ALL;
} }
else else
{ {
$searchDN = $this->accountContactsDN; $searchDN = $this->accountContactsDN;
$addressbookType = ADDRESSBOOK_ACCOUNTS; $addressbookType = self::ACCOUNTS;
} }
// create the search filter // create the search filter
switch($addressbookType) switch($addressbookType)
{ {
case ADDRESSBOOK_ACCOUNTS: case self::ACCOUNTS:
$objectFilter = $this->accountsFilter; $objectFilter = $this->accountsFilter;
break; break;
default: default:
@ -813,8 +822,8 @@ class addressbook_ldap
{ {
if(($ldapSearchKey = $mapping[$egwSearchKey])) if(($ldapSearchKey = $mapping[$egwSearchKey]))
{ {
$searchString = translation::convert($searchValue,$this->charset,'utf-8'); $searchString = Api\Translation::convert($searchValue,$this->charset,'utf-8');
$searchFilter .= '('.$ldapSearchKey.'='.$wildcard.ldap::quote($searchString).$wildcard.')'; $searchFilter .= '('.$ldapSearchKey.'='.$wildcard.Api\Ldap::quote($searchString).$wildcard.')';
break; break;
} }
} }
@ -915,7 +924,7 @@ class addressbook_ldap
} }
elseif ($value) elseif ($value)
{ {
$filters .= '(uidNumber='.ldap::quote($value).')'; $filters .= '(uidNumber='.Api\Ldap::quote($value).')';
} }
break; break;
@ -935,9 +944,9 @@ class addressbook_ldap
if (count($cats) > 1) $filters .= '(|'; if (count($cats) > 1) $filters .= '(|';
foreach($cats as $cat) foreach($cats as $cat)
{ {
$catName = translation::convert( $catName = Api\Translation::convert(
$GLOBALS['egw']->categories->id2name($cat),$this->charset,'utf-8'); $GLOBALS['egw']->categories->id2name($cat),$this->charset,'utf-8');
$filters .= '(category='.ldap::quote($catName).')'; $filters .= '(category='.Api\Ldap::quote($catName).')';
} }
if (count($cats) > 1) $filters .= ')'; if (count($cats) > 1) $filters .= ')';
} }
@ -965,13 +974,13 @@ class addressbook_ldap
{ {
// todo: value = "!''" // todo: value = "!''"
$filters .= '('.$mapping[$key].'='.($value === "!''" ? '*' : $filters .= '('.$mapping[$key].'='.($value === "!''" ? '*' :
ldap::quote(translation::convert($value,$this->charset,'utf-8'))).')'; Api\Ldap::quote(Api\Translation::convert($value,$this->charset,'utf-8'))).')';
break; break;
} }
} }
} }
// filter for letter-search // filter for letter-search
elseif (preg_match("/^([^ ]+) ".preg_quote($GLOBALS['egw']->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE])." '(.*)%'$/",$value,$matches)) elseif (preg_match("/^([^ ]+) ".preg_quote($GLOBALS['egw']->db->capabilities[Api\Db::CAPABILITY_CASE_INSENSITIV_LIKE])." '(.*)%'$/",$value,$matches))
{ {
list(,$name,$value) = $matches; list(,$name,$value) = $matches;
if (strpos($name,'.') !== false) list(,$name) = explode('.',$name); if (strpos($name,'.') !== false) list(,$name) = explode('.',$name);
@ -979,8 +988,8 @@ class addressbook_ldap
{ {
if (isset($mapping[$name])) if (isset($mapping[$name]))
{ {
$filters .= '('.$mapping[$name].'='.ldap::quote( $filters .= '('.$mapping[$name].'='.Api\Ldap::quote(
translation::convert($value,$this->charset,'utf-8')).'*)'; Api\Translation::convert($value,$this->charset,'utf-8')).'*)';
break; break;
} }
} }
@ -1017,7 +1026,7 @@ class addressbook_ldap
//error_log(__METHOD__."('$_ldapContext', '$_filter', ".array2string($_attributes).", $_addressbooktype)"); //error_log(__METHOD__."('$_ldapContext', '$_filter', ".array2string($_attributes).", $_addressbooktype)");
if($_addressbooktype == ADDRESSBOOK_ALL || $_ldapContext == $this->allContactsDN) if($_addressbooktype == self::ALL || $_ldapContext == $this->allContactsDN)
{ {
$result = ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit); $result = ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit);
} }
@ -1048,7 +1057,7 @@ class addressbook_ldap
{ {
if(!empty($entry[$ldapFieldName][0]) && !is_int($egwFieldName) && !isset($contact[$egwFieldName])) if(!empty($entry[$ldapFieldName][0]) && !is_int($egwFieldName) && !isset($contact[$egwFieldName]))
{ {
$contact[$egwFieldName] = translation::convert($entry[$ldapFieldName][0],'utf-8'); $contact[$egwFieldName] = Api\Translation::convert($entry[$ldapFieldName][0],'utf-8');
} }
} }
$objectclass2egw = '_'.$objectclass.'2egw'; $objectclass2egw = '_'.$objectclass.'2egw';
@ -1206,7 +1215,7 @@ class addressbook_ldap
$ldapContact['category'] = array(); $ldapContact['category'] = array();
foreach(is_array($data['cat_id']) ? $data['cat_id'] : explode(',',$data['cat_id']) as $cat) foreach(is_array($data['cat_id']) ? $data['cat_id'] : explode(',',$data['cat_id']) as $cat)
{ {
$ldapContact['category'][] = translation::convert( $ldapContact['category'][] = Api\Translation::convert(
ExecMethod('phpgwapi.categories.id2name',$cat),$this->charset,'utf-8'); ExecMethod('phpgwapi.categories.id2name',$cat),$this->charset,'utf-8');
} }
} }
@ -1217,7 +1226,7 @@ class addressbook_ldap
{ {
if($value != '$, $$$') if($value != '$, $$$')
{ {
$ldapContact[$attr] = translation::convert($value,$this->charset,'utf-8'); $ldapContact[$attr] = Api\Translation::convert($value,$this->charset,'utf-8');
} }
elseif($isUpdate) elseif($isUpdate)
{ {
@ -1421,6 +1430,6 @@ class addressbook_ldap
*/ */
function change_owner($account_id,$new_owner) function change_owner($account_id,$new_owner)
{ {
error_log("so_ldap::change_owner($account_id,$new_owner) not yet implemented"); error_log(__METHOD__."($account_id,$new_owner) not yet implemented");
} }
} }

View File

@ -1,19 +1,27 @@
<?php <?php
/** /**
* EGroupware : Addressbook - SQL backend * EGroupware API: Contacts - SQL storage
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook * @package api
* @copyright (c) 2006-13 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @subpackage contacts
* @copyright (c) 2006-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
namespace EGroupware\Api\Contacts;
use EGroupware\Api;
// explicitly reference classes still in phpgwapi
use common; // common::generate_uid
/** /**
* SQL storage object of the adressbook * Contacts - SQL storage
*/ */
class addressbook_sql extends so_sql_cf class Sql extends Api\Storage
{ {
/** /**
* name of custom fields table * name of custom fields table
@ -60,15 +68,15 @@ class addressbook_sql extends so_sql_cf
/** /**
* Constructor * Constructor
* *
* @param egw_db $db=null * @param Api\Db $db =null
*/ */
function __construct(egw_db $db=null) function __construct(Api\Db $db=null)
{ {
parent::__construct('phpgwapi', 'egw_addressbook', self::EXTRA_TABLE, 'contact_', parent::__construct('phpgwapi', 'egw_addressbook', self::EXTRA_TABLE,
$extra_key='_name',$extra_value='_value',$extra_id='_id',$db); 'contact_', '_name', '_value', '_id', $db);
// Get custom fields from addressbook instead of phpgwapi // Get custom fields from addressbook instead of phpgwapi
$this->customfields = config::get_customfields('addressbook'); $this->customfields = Api\Storage\Customfields::get('addressbook');
if ($GLOBALS['egw_info']['server']['account_repository']) if ($GLOBALS['egw_info']['server']['account_repository'])
{ {
@ -146,7 +154,7 @@ class addressbook_sql extends so_sql_cf
} }
if ($param['searchletter']) if ($param['searchletter'])
{ {
$filter[] = 'org_name '.$this->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote($param['searchletter'].'%'); $filter[] = 'org_name '.$this->db->capabilities[Api\Db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote($param['searchletter'].'%');
} }
else else
{ {
@ -169,8 +177,8 @@ class addressbook_sql extends so_sql_cf
// org total for more then one $by // org total for more then one $by
$by_expr = $by == 'org_unit_count' ? "COUNT(DISTINCT CASE WHEN org_unit IS NULL THEN '' ELSE org_unit END)" : $by_expr = $by == 'org_unit_count' ? "COUNT(DISTINCT CASE WHEN org_unit IS NULL THEN '' ELSE org_unit END)" :
"COUNT(DISTINCT CASE WHEN adr_one_locality IS NULL THEN '' ELSE adr_one_locality END)"; "COUNT(DISTINCT CASE WHEN adr_one_locality IS NULL THEN '' ELSE adr_one_locality END)";
$append = "GROUP BY org_name HAVING $by_expr > 1 ORDER BY org_name $sort"; parent::search($param['search'],array('org_name'),
parent::search($param['search'],array('org_name'),$append,array( "GROUP BY org_name HAVING $by_expr > 1 ORDER BY org_name $sort", array(
"NULL AS $by", "NULL AS $by",
'1 AS is_main', '1 AS is_main',
'COUNT(DISTINCT egw_addressbook.contact_id) AS org_count', 'COUNT(DISTINCT egw_addressbook.contact_id) AS org_count',
@ -178,8 +186,8 @@ class addressbook_sql extends so_sql_cf
"COUNT(DISTINCT CASE WHEN adr_one_locality IS NULL THEN '' ELSE adr_one_locality END) AS adr_one_locality_count", "COUNT(DISTINCT CASE WHEN adr_one_locality IS NULL THEN '' ELSE adr_one_locality END) AS adr_one_locality_count",
),$wildcard,false,$op/*'OR'*/,'UNION',$filter); ),$wildcard,false,$op/*'OR'*/,'UNION',$filter);
// org by location // org by location
$append = "GROUP BY org_name,$by ORDER BY org_name $sort,$by $sort"; parent::search($param['search'],array('org_name'),
parent::search($param['search'],array('org_name'),$append,array( "GROUP BY org_name,$by ORDER BY org_name $sort,$by $sort", array(
"CASE WHEN $by IS NULL THEN '' ELSE $by END AS $by", "CASE WHEN $by IS NULL THEN '' ELSE $by END AS $by",
'0 AS is_main', '0 AS is_main',
'COUNT(DISTINCT egw_addressbook.contact_id) AS org_count', 'COUNT(DISTINCT egw_addressbook.contact_id) AS org_count',
@ -195,7 +203,7 @@ class addressbook_sql extends so_sql_cf
// query the values for *_count == 1, to display them instead // query the values for *_count == 1, to display them instead
$filter['org_name'] = $orgs = array(); $filter['org_name'] = $orgs = array();
foreach($rows as $n => $row) foreach($rows as $row)
{ {
if ($row['org_unit_count'] == 1 || $row['adr_one_locality_count'] == 1) if ($row['org_unit_count'] == 1 || $row['adr_one_locality_count'] == 1)
{ {
@ -208,7 +216,8 @@ class addressbook_sql extends so_sql_cf
if (count($filter['org_name'])) if (count($filter['org_name']))
{ {
foreach((array) parent::search($criteria,array('org_name','org_unit','adr_one_locality'),'GROUP BY org_name,org_unit,adr_one_locality', foreach((array) parent::search(null, array('org_name','org_unit','adr_one_locality'),
'GROUP BY org_name,org_unit,adr_one_locality',
'',$wildcard,false,$op/*'AND'*/,false,$filter) as $row) '',$wildcard,false,$op/*'AND'*/,false,$filter) as $row)
{ {
$org_key = $row['org_name'].($by ? '|||'.$row[$by] : ''); $org_key = $row['org_name'].($by ? '|||'.$row[$by] : '');
@ -243,19 +252,19 @@ class addressbook_sql extends so_sql_cf
* *
* For a union-query you call search for each query with $start=='UNION' and one more with only $order_by and $start set to run the union-query. * For a union-query you call search for each query with $start=='UNION' and one more with only $order_by and $start set to run the union-query.
* *
* @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!) * @param array|string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!)
* @param boolean/string/array $only_keys=true True returns only keys, False returns all cols. or * @param boolean|string|array $only_keys =true True returns only keys, False returns all cols. or
* comma seperated list or array of columns to return * comma seperated list or array of columns 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 $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 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 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 * @param string $op ='AND' defaults to 'AND', can be set to 'OR' too, then criteria's are OR'ed together
* @param mixed $start=false if != false, return only maxmatch rows begining with start, or array($start,$num), or 'UNION' for a part of a union query * @param mixed $start =false if != false, return only maxmatch rows begining with start, or array($start,$num), or 'UNION' for a part of a union query
* @param array $filter=null if set (!=null) col-data pairs, to be and-ed (!) into the query without wildcards * @param array $filter =null if set (!=null) col-data pairs, to be and-ed (!) into the query without wildcards
* @param string $join='' sql to do a join, added as is after the table-name, eg. ", table2 WHERE x=y" or * @param string $join ='' sql to do a join, added as is after the table-name, eg. ", table2 WHERE x=y" or
* "LEFT JOIN table2 ON (x=y)", Note: there's no quoting done on $join! * "LEFT JOIN table2 ON (x=y)", Note: there's no quoting done on $join!
* @param boolean $need_full_no_count=false If true an unlimited query is run to determine the total number of rows, default false * @param boolean $need_full_no_count =false If true an unlimited query is run to determine the total number of rows, default false
* @return boolean/array of matching rows (the row is an array of the cols) or False * @return boolean/array of matching rows (the row is an array of the cols) or False
*/ */
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) 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)
@ -360,7 +369,9 @@ class addressbook_sql extends so_sql_cf
// fall through // fall through
} }
// postgres requires that expressions in order by appear in the columns of a distinct select // postgres requires that expressions in order by appear in the columns of a distinct select
if ($this->db->Type != 'mysql' && preg_match_all("/(#?[a-zA-Z_.]+) *(<> *''|IS NULL|IS NOT NULL)? *(ASC|DESC)?(,|$)/ui",$order_by,$all_matches,PREG_SET_ORDER)) $all_matches = null;
if ($this->db->Type != 'mysql' && preg_match_all("/(#?[a-zA-Z_.]+) *(<> *''|IS NULL|IS NOT NULL)? *(ASC|DESC)?(,|$)/ui",
$order_by, $all_matches, PREG_SET_ORDER))
{ {
if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array(); if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array();
foreach($all_matches as $matches) foreach($all_matches as $matches)
@ -394,10 +405,12 @@ class addressbook_sql extends so_sql_cf
// Understand search by date with wildcard (????.10.??) according to user date preference // Understand search by date with wildcard (????.10.??) according to user date preference
if(is_string($criteria) && strpos($criteria, '?') !== false) if(is_string($criteria) && strpos($criteria, '?') !== false)
{ {
$date_format = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat'];
// First, check for a 'date', with wildcards, in the user's format // First, check for a 'date', with wildcards, in the user's format
$date_regex = str_replace(array('Y','m','d','.','-'), array('(?P<Y>(?:\?|\Q){4})','(?P<m>(?:\?|\Q){2})','(?P<d>(?:\?|\Q){2})','\.','\-'),$date_format); $date_regex = str_replace('Q','d',
$date_regex = str_replace('Q','d',$date_regex); str_replace(array('Y','m','d','.','-'),
array('(?P<Y>(?:\?|\Q){4})','(?P<m>(?:\?|\Q){2})','(?P<d>(?:\?|\Q){2})','\.','\-'),
$GLOBALS['egw_info']['user']['preferences']['common']['dateformat']));
if(preg_match_all('$'.$date_regex.'$', $criteria, $matches)) if(preg_match_all('$'.$date_regex.'$', $criteria, $matches))
{ {
foreach($matches[0] as $m_id => $match) foreach($matches[0] as $m_id => $match)
@ -467,7 +480,7 @@ class addressbook_sql extends so_sql_cf
{ {
if (!$new_owner) // otherwise we would create an account (contact_owner==0) if (!$new_owner) // otherwise we would create an account (contact_owner==0)
{ {
throw egw_exception_wrong_parameter(__METHOD__."($account_id, $new_owner) new owner must not be 0!"); throw Api\Exception\WrongParameter(__METHOD__."($account_id, $new_owner) new owner must not be 0!");
} }
// contacts // contacts
$this->db->update($this->table_name,array( $this->db->update($this->table_name,array(
@ -496,9 +509,9 @@ class addressbook_sql extends so_sql_cf
* *
* @param array $uids array of user or group id's for $uid_column='list_owners', or values for $uid_column, * @param array $uids array of user or group id's for $uid_column='list_owners', or values for $uid_column,
* or whole where array: column-name => value(s) pairs * or whole where array: column-name => value(s) pairs
* @param string $uid_column='list_owner' column-name or null to use $uids as where array * @param string $uid_column ='list_owner' column-name or null to use $uids as where array
* @param string $member_attr=null null: no members, 'contact_uid', 'contact_id', 'caldav_name' return members as that attribute * @param string $member_attr =null null: no members, 'contact_uid', 'contact_id', 'caldav_name' return members as that attribute
* @param boolean|int|array $limit_in_ab=false if true only return members from the same owners addressbook, * @param boolean|int|array $limit_in_ab =false if true only return members from the same owners addressbook,
* if int|array only return members from the given owners addressbook(s) * if int|array only return members from the given owners addressbook(s)
* @return array with list_id => array(list_id,list_name,list_owner,...) pairs * @return array with list_id => array(list_id,list_name,list_owner,...) pairs
*/ */
@ -547,7 +560,7 @@ class addressbook_sql extends so_sql_cf
* *
* @param string|array $keys list-name or array with column-name => value pairs to specify the list * @param string|array $keys list-name or array with column-name => value pairs to specify the list
* @param int $owner user- or group-id * @param int $owner user- or group-id
* @param array $contacts=array() contacts to add (only for not yet existing lists!) * @param array $contacts =array() contacts to add (only for not yet existing lists!)
* @param array &$data=array() values for keys 'list_uid', 'list_carddav_name', 'list_name' * @param array &$data=array() values for keys 'list_uid', 'list_carddav_name', 'list_name'
* @return int|boolean integer list_id or false on error * @return int|boolean integer list_id or false on error
*/ */
@ -606,7 +619,7 @@ class addressbook_sql extends so_sql_cf
* *
* @param int|array $contact contact_id(s) * @param int|array $contact contact_id(s)
* @param int $list list-id * @param int $list list-id
* @param array $existing=null array of existing contact-id(s) of list, to not reread it, eg. array() * @param array $existing =null array of existing contact-id(s) of list, to not reread it, eg. array()
* @return false on error * @return false on error
*/ */
function add2list($contact,$list,array $existing=null) function add2list($contact,$list,array $existing=null)
@ -648,7 +661,7 @@ class addressbook_sql extends so_sql_cf
* Removes one contact from distribution list(s) * Removes one contact from distribution list(s)
* *
* @param int|array $contact contact_id(s) * @param int|array $contact contact_id(s)
* @param int $list=null list-id or null to remove from all lists * @param int $list =null list-id or null to remove from all lists
* @return false on error * @return false on error
*/ */
function remove_from_list($contact,$list=null) function remove_from_list($contact,$list=null)
@ -690,7 +703,7 @@ class addressbook_sql extends so_sql_cf
/** /**
* Deletes a distribution list (incl. it's members) * 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 * @return number of members deleted or false if list does not exist
*/ */
function delete_list($list) function delete_list($list)
@ -705,7 +718,7 @@ class addressbook_sql extends so_sql_cf
/** /**
* Get ctag (max list_modified as timestamp) for lists * Get ctag (max list_modified as timestamp) for lists
* *
* @param int|array $owner=null null for all lists user has access too * @param int|array $owner =null null for all lists user has access too
* @return int * @return int
*/ */
function lists_ctag($owner=null) function lists_ctag($owner=null)
@ -745,7 +758,7 @@ class addressbook_sql extends so_sql_cf
} }
// catch Illegal mix of collations (ascii_general_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '=' (1267) // catch Illegal mix of collations (ascii_general_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '=' (1267)
// caused by non-ascii chars compared with ascii field uid // caused by non-ascii chars compared with ascii field uid
catch(egw_exception_db $e) { catch(Api\Db\Exception $e) {
_egw_log_exception($e); _egw_log_exception($e);
return false; return false;
} }
@ -762,11 +775,13 @@ class addressbook_sql extends so_sql_cf
* Saves a contact, reimplemented to check a given etag and set a uid * Saves a contact, reimplemented to check a given etag and set a uid
* *
* @param array $keys if given $keys are copied to data before saveing => allows a save as * @param array $keys if given $keys are copied to data before saveing => allows a save as
* @param string|array $extra_where=null extra where clause, eg. to check the etag, returns 'nothing_affected' if not affected rows * @param string|array $extra_where =null extra where clause, eg. to check the etag, returns 'nothing_affected' if not affected rows
* @return int 0 on success and errno != 0 else * @return int 0 on success and errno != 0 else
*/ */
function save($keys = NULL, $extra_where = NULL) function save($keys = NULL, $extra_where = NULL)
{ {
unset($extra_where); // not used, but required by function signature
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'])) { if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'])) {
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']; $minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
} else { } else {

1138
api/src/Contacts/Storage.php Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,27 @@
<?php <?php
/** /**
* Addressbook - history and notifications * EGroupware API - Contacts history and notifications
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook * @package api
* @copyright (c) 2007 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @subpackage contacts
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
namespace EGroupware\Api\Contacts;
use EGroupware\Api;
// explicitly reference classes still in phpgwapi
use common;
/** /**
* Addressbook - tracking object * Contacts history and notifications
*/ */
class addressbook_tracking extends bo_tracking class Tracking extends Api\Storage\Tracking
{ {
/** /**
* Application we are tracking (required!) * Application we are tracking (required!)
@ -64,10 +72,10 @@ class addressbook_tracking extends bo_tracking
/** /**
* Constructor * Constructor
* *
* @param addressbook_bo $bocontacts * @param Api\Contacts $bocontacts
* @return tracker_tracking * @return tracker_tracking
*/ */
function __construct(addressbook_bo $bocontacts) function __construct(Api\Contacts $bocontacts)
{ {
$this->contacts = $bocontacts; $this->contacts = $bocontacts;
@ -93,17 +101,19 @@ class addressbook_tracking extends bo_tracking
/** /**
* Get a notification-config value * Get a notification-config value
* *
* @param string $what * @param string $name
* - 'copy' array of email addresses notifications should be copied too, can depend on $data * - 'copy' array of email addresses notifications should be copied too, can depend on $data
* - 'lang' string lang code for copy mail * - 'lang' string lang code for copy mail
* - 'sender' string send email address * - 'sender' string send email address
* @param array $data current entry * @param array $data current entry
* @param array $old=null old/last state of the entry or null for a new entry * @param array $old =null old/last state of the entry or null for a new entry
* @return mixed * @return mixed
*/ */
function get_config($name,$data,$old=null) function get_config($name,$data,$old=null)
{ {
//echo "<p>addressbook_tracking::get_config($name,".print_r($data,true).",...)</p>\n"; unset($old); // not used, but required by function signature
//echo "<p>".__METHOD__."($name,".print_r($data,true).",...)</p>\n";
switch($name) switch($name)
{ {
case 'copy': case 'copy':
@ -134,9 +144,9 @@ class addressbook_tracking extends bo_tracking
* *
* @internal use only track($data,$old) * @internal use only track($data,$old)
* @param array $data current entry * @param array $data current entry
* @param array $old=null old/last state of the entry or null for a new entry * @param array $old =null old/last state of the entry or null for a new entry
* @param boolean $deleted=null can be set to true to let the tracking know the item got deleted or undelted * @param boolean $deleted =null can be set to true to let the tracking know the item got deleted or undelted
* @param array $changed_fields=null changed fields from ealier call to $this->changed_fields($data,$old), to not compute it again * @param array $changed_fields =null changed fields from ealier call to $this->changed_fields($data,$old), to not compute it again
* @return int number of log-entries made * @return int number of log-entries made
*/ */
protected function save_history(array $data,array $old=null,$deleted=null,array $changed_fields=null) protected function save_history(array $data,array $old=null,$deleted=null,array $changed_fields=null)
@ -180,6 +190,8 @@ class addressbook_tracking extends bo_tracking
*/ */
protected function get_message($data,$old,$receiver=null) protected function get_message($data,$old,$receiver=null)
{ {
unset($receiver); // not used, but required by function signature
if (!$data['modified'] || !$old) if (!$data['modified'] || !$old)
{ {
return lang('New contact submitted by %1 at %2', return lang('New contact submitted by %1 at %2',
@ -196,12 +208,14 @@ class addressbook_tracking extends bo_tracking
* *
* @param array $data * @param array $data
* @param array $old * @param array $old
* @param boolean $deleted=null can be set to true to let the tracking know the item got deleted or undelted * @param boolean $deleted =null can be set to true to let the tracking know the item got deleted or undelted
* @param int|string $receiver nummeric account_id or email address * @param int|string $receiver nummeric account_id or email address
* @return string * @return string
*/ */
protected function get_subject($data,$old,$deleted=null,$receiver=null) protected function get_subject($data,$old,$deleted=null,$receiver=null)
{ {
unset($old, $deleted, $receiver); // not used, but required by function signature
if ($data['is_contactform']) if ($data['is_contactform'])
{ {
$prefix = ($data['subject_contactform'] ? $data['subject_contactform'] : lang('Contactform')).': '; $prefix = ($data['subject_contactform'] ? $data['subject_contactform'] : lang('Contactform')).': ';
@ -218,6 +232,8 @@ class addressbook_tracking extends bo_tracking
*/ */
function get_details($data,$receiver=null) function get_details($data,$receiver=null)
{ {
unset($receiver); // not used, but required by function signature
foreach($this->contacts->contact_fields as $name => $label) foreach($this->contacts->contact_fields as $name => $label)
{ {
if (!$data[$name] && $name != 'owner') continue; if (!$data[$name] && $name != 'owner') continue;

View File

@ -1,20 +1,23 @@
<?php <?php
/** /**
* Addressbook - Univention Backend * EGroupware API: Contacts Univention Backend
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <rb@stylite.de> * @author Ralf Becker <rb@stylite.de>
* @package addressbook * @package api
* @subpackage contacts
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
namespace EGroupware\Api\Contacts;
/** /**
* Univention backend for addressbook * Univention backend for addressbook
* *
* Different mail attribute is only difference to LDAP backend * Different mail attribute is only difference to LDAP backend
*/ */
class addressbook_univention extends addressbook_ldap class Univention extends Ldap
{ {
function __construct($ldap_config = null, $ds = null) function __construct($ldap_config = null, $ds = null)
{ {

263
api/src/Ldap.php Normal file
View File

@ -0,0 +1,263 @@
<?php
/**
* EGroupware API - LDAP connection handling
*
* @link http://www.egroupware.org
* @author Lars Kneschke <l.kneschke@metaways.de>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage ldap
* @version $Id$
*/
namespace EGroupware\Api;
/**
* LDAP connection handling
*
* Please note for SSL or TLS connections hostname has to be:
* - SSL: "ldaps://host[:port]/"
* - TLS: "tls://host[:port]/"
* Both require certificats installed on the webserver, otherwise the connection will fail!
*
* If multiple (space-separated) ldap hosts or urls are given, try them in order and
* move first successful one to first place in session, to try not working ones
* only once per session.
*/
class Ldap
{
/**
* Holds the LDAP link identifier
*
* @var resource $ds
*/
var $ds;
/**
* Holds the detected information about the connected ldap server
*
* @var Ldap\ServerInfo $ldapserverinfo
*/
var $ldapserverinfo;
/**
* Throw Exceptions in ldapConnect instead of echoing error and returning false
*
* @var boolean $exception_on_error
*/
var $exception_on_error=false;
/**
* Constructor
*
* @param boolean $exception_on_error =false true: throw Exceptions in ldapConnect instead of echoing error and returning false
*/
function __construct($exception_on_error=false)
{
$this->exception_on_error = $exception_on_error;
$this->restoreSessionData();
}
/**
* Returns information about connected ldap server
*
* @return Ldap\ServerInfo|null
*/
function getLDAPServerInfo()
{
return $this->ldapserverinfo;
}
/**
* escapes a string for use in searchfilters meant for ldap_search.
*
* Escaped Characters are: '*', '(', ')', ' ', '\', NUL
* It's actually a PHP-Bug, that we have to escape space.
* For all other Characters, refer to RFC2254.
*
* @param string|array $string either a string to be escaped, or an array of values to be escaped
* @return string
*/
static function quote($string)
{
return str_replace(array('\\','*','(',')','\0',' '),array('\\\\','\*','\(','\)','\\0','\20'),$string);
}
/**
* Convert a single ldap result into a associative array
*
* @param array $ldap array with numerical and associative indexes and count's
* @return boolean|array with only associative index and no count's or false on error (parm is no array)
*/
static function result2array($ldap)
{
if (!is_array($ldap)) return false;
$arr = array();
foreach($ldap as $var => $val)
{
if (is_int($var) || $var == 'count') continue;
if (is_array($val) && $val['count'] == 1)
{
$arr[$var] = $val[0];
}
else
{
if (is_array($val)) unset($val['count']);
$arr[$var] = $val;
}
}
return $arr;
}
/**
* Connect to ldap server and return a handle
*
* If multiple (space-separated) ldap hosts or urls are given, try them in order and
* move first successful one to first place in session, to try not working ones
* only once per session.
*
* @param $host ='' ldap host, default $GLOBALS['egw_info']['server']['ldap_host']
* @param $dn ='' ldap dn, default $GLOBALS['egw_info']['server']['ldap_root_dn']
* @param $passwd ='' ldap pw, default $GLOBALS['egw_info']['server']['ldap_root_pw']
* @return resource|boolean resource from ldap_connect() or false on error
* @throws Exception\AssertingFailed 'LDAP support unavailable!' (no ldap extension)
*/
function ldapConnect($host='', $dn='', $passwd='')
{
if(!function_exists('ldap_connect'))
{
if ($this->exception_on_error) throw new Exception\AssertionFailed('LDAP support unavailable!');
printf('<b>Error: LDAP support unavailable</b><br>',$host);
return False;
}
if (empty($host))
{
$host = $GLOBALS['egw_info']['server']['ldap_host'];
}
if (empty($dn))
{
$dn = $GLOBALS['egw_info']['server']['ldap_root_dn'];
$passwd = $GLOBALS['egw_info']['server']['ldap_root_pw'];
}
// if multiple hosts given, try them all, but only once per session!
if (isset($_SESSION) && isset($_SESSION['ldapConnect']) && isset($_SESSION['ldapConnect'][$host]))
{
$host = $_SESSION['ldapConnect'][$host];
}
foreach($hosts=preg_split('/[ ,;]+/', $host) as $h)
{
if ($this->_connect($h, $dn, $passwd))
{
if ($h !== $host)
{
if (isset($_SESSION)) // store working host as first choice in session
{
$_SESSION['ldapConnect'][$host] = implode(' ',array_unique(array_merge(array($h),$hosts)));
}
}
return $this->ds;
}
error_log(__METHOD__."('$h', '$dn', \$passwd) Can't connect/bind to ldap server!".
($this->ds ? ' '.ldap_error($this->ds).' ('.ldap_errno($this->ds).')' : '').
' '.function_backtrace());
}
// give visible error, only if we cant connect to any ldap server
if ($this->exception_on_error) throw new Exception\NoPermission("Can't connect/bind to LDAP server '$host' and dn='$dn'!");
return false;
}
/**
* connect to the ldap server and return a handle
*
* @param string $host ldap host
* @param string $dn ldap dn
* @param string $passwd ldap pw
* @return resource|boolean resource from ldap_connect() or false on error
*/
private function _connect($host, $dn, $passwd)
{
if (($use_tls = substr($host,0,6) == 'tls://'))
{
$port = parse_url($host,PHP_URL_PORT);
$host = parse_url($host,PHP_URL_HOST);
}
// connect to ldap server (never fails, as connection happens in bind!)
if(!($this->ds = !empty($port) ? ldap_connect($host, $port) : ldap_connect($host)))
{
return False;
}
// set network timeout to not block for minutes
ldap_set_option($this->ds, LDAP_OPT_NETWORK_TIMEOUT, 5);
if(ldap_set_option($this->ds, LDAP_OPT_PROTOCOL_VERSION, 3))
{
$supportedLDAPVersion = 3;
}
else
{
$supportedLDAPVersion = 2;
}
if ($use_tls) ldap_start_tls($this->ds);
if (!isset($this->ldapserverinfo) ||
!is_a($this->ldapserverinfo,'EGroupware\Ldap\ServerInfo') ||
$this->ldapserverinfo->host != $host)
{
//error_log("no ldap server info found");
@ldap_bind($this->ds, $GLOBALS['egw_info']['server']['ldap_root_dn'], $GLOBALS['egw_info']['server']['ldap_root_pw']);
$this->ldapserverinfo = Ldap\ServerInfo::get($this->ds, $host, $supportedLDAPVersion);
$this->saveSessionData();
}
if(!@ldap_bind($this->ds, $dn, $passwd))
{
return False;
}
return $this->ds;
}
/**
* disconnect from the ldap server
*/
function ldapDisconnect()
{
if(is_resource($this->ds))
{
ldap_unbind($this->ds);
unset($this->ds);
unset($this->ldapserverinfo);
}
}
/**
* restore the session data
*/
function restoreSessionData()
{
if (isset($GLOBALS['egw']->session)) // no availible in setup
{
$this->ldapserverinfo = Cache::getSession(__CLASS__, 'ldapServerInfo');
}
}
/**
* save the session data
*/
function saveSessionData()
{
if (isset($GLOBALS['egw']->session)) // no availible in setup
{
Cache::getSession(__CLASS__, 'ldapServerInfo', $this->ldapserverinfo);
}
}
}

243
api/src/Ldap/ServerInfo.php Normal file
View File

@ -0,0 +1,243 @@
<?php
/**
* EGroupware API - LDAP server information
*
* @link http://www.egroupware.org
* @author Lars Kneschke <l.kneschke@metaways.de>
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage ldap
* @version $Id$
*/
namespace EGroupware\Api\Ldap;
/**
* Class to store and retrieve information (eg. supported object classes) of a connected ldap server
*/
class ServerInfo
{
/**
* Unknown LDAP server
*/
const UNKNOWN = 0;
/**
* OpenLDAP server
*/
const OPENLDAP = 1;
/**
* Samba4 LDAP server
*/
const SAMBA4 = 2;
/**
* @var array $namingContext holds the supported namingcontexts
*/
var $namingContext = array();
/**
* @var string $version holds the LDAP server version
*/
var $version = 2;
/**
* @var integer $serverType holds the type of LDAP server(OpenLDAP, ADS, NDS, ...)
*/
var $serverType = 0;
/**
* @var string $_subSchemaEntry the subschema entry DN
*/
var $subSchemaEntry = '';
/**
* @var array $supportedObjectClasses the supported objectclasses
*/
var $supportedObjectClasses = array();
/**
* @var array $supportedOIDs the supported OIDs
*/
var $supportedOIDs = array();
/**
* Name of host
*
* @var string
*/
var $host;
/**
* Constructor
*
* @param string $host
*/
function __construct($host)
{
$this->host = $host;
}
/**
* gets the version
*
* @return integer the supported ldap version
*/
function getVersion()
{
return $this->version;
}
/**
* sets the namingcontexts
*
* @param array $_namingContext the supported namingcontexts
*/
function setNamingContexts($_namingContext)
{
$this->namingContext = $_namingContext;
}
/**
* sets the type of the ldap server(OpenLDAP, ADS, NDS, ...)
*
* @param integer $_serverType the type of ldap server
*/
function setServerType($_serverType)
{
$this->serverType = $_serverType;
}
/**
* sets the DN for the subschema entry
*
* @param string $_subSchemaEntry the subschema entry DN
*/
function setSubSchemaEntry($_subSchemaEntry)
{
$this->subSchemaEntry = $_subSchemaEntry;
}
/**
* sets the supported objectclasses
*
* @param array $_supportedObjectClasses the supported objectclasses
*/
function setSupportedObjectClasses($_supportedObjectClasses)
{
$this->supportedOIDs = $_supportedObjectClasses;
$this->supportedObjectClasses = array_flip($_supportedObjectClasses);
}
/**
* sets the version
*
* @param integer $_version the supported ldap version
*/
function setVersion($_version)
{
$this->version = $_version;
}
/**
* checks for supported objectclasses
*
* @return bool returns true if the ldap server supports this objectclass
*/
function supportsObjectClass($_objectClass)
{
if($this->supportedObjectClasses[strtolower($_objectClass)])
{
return true;
}
return false;
}
/**
* Query given ldap connection for available information
*
* @param resource $ds
* @param string $host
* @param int $version 2 or 3
* @return ldapserverinfo
*/
public static function get($ds, $host, $version=3)
{
$filter='(objectclass=*)';
$justthese = array('structuralObjectClass','namingContexts','supportedLDAPVersion','subschemaSubentry','vendorname');
if(($sr = @ldap_read($ds, '', $filter, $justthese)))
{
if(($info = ldap_get_entries($ds, $sr)))
{
$ldapServerInfo = new ServerInfo($host);
$ldapServerInfo->setVersion($version);
// check for naming contexts
if($info[0]['namingcontexts'])
{
for($i=0; $i<$info[0]['namingcontexts']['count']; $i++)
{
$namingcontexts[] = $info[0]['namingcontexts'][$i];
}
$ldapServerInfo->setNamingContexts($namingcontexts);
}
// check for ldap server type
if($info[0]['structuralobjectclass'])
{
switch($info[0]['structuralobjectclass'][0])
{
case 'OpenLDAProotDSE':
$ldapServerType = OPENLDAP_LDAPSERVER;
break;
default:
$ldapServerType = UNKNOWN_LDAPSERVER;
break;
}
$ldapServerInfo->setServerType($ldapServerType);
}
if ($info[0]['vendorname'] && stripos($info[0]['vendorname'][0], 'samba') !== false)
{
$ldapServerInfo->setServerType(SAMBA4_LDAPSERVER);
}
// check for subschema entry dn
if($info[0]['subschemasubentry'])
{
$subschemasubentry = $info[0]['subschemasubentry'][0];
$ldapServerInfo->setSubSchemaEntry($subschemasubentry);
}
// create list of supported objetclasses
if(!empty($subschemasubentry))
{
$filter='(objectclass=*)';
$justthese = array('objectClasses');
if(($sr = ldap_read($ds, $subschemasubentry, $filter, $justthese)))
{
if(($info = ldap_get_entries($ds, $sr)))
{
if($info[0]['objectclasses']) {
for($i=0; $i<$info[0]['objectclasses']['count']; $i++)
{
$matches = null;
if(preg_match('/^\( (.*) NAME \'(\w*)\' /', $info[0]['objectclasses'][$i], $matches))
{
#_debug_array($matches);
if(count($matches) == 3)
{
$supportedObjectClasses[$matches[1]] = strtolower($matches[2]);
}
}
}
$ldapServerInfo->setSupportedObjectClasses($supportedObjectClasses);
}
}
}
}
}
}
return $ldapServerInfo;
}
}

View File

@ -167,7 +167,7 @@ class Storage extends Storage\Base
$this->extra_join_order = " LEFT JOIN $extra_table extra_order ON $table.$this->autoinc_id=extra_order.$this->extra_id"; $this->extra_join_order = " LEFT JOIN $extra_table extra_order ON $table.$this->autoinc_id=extra_order.$this->extra_id";
$this->extra_join_filter = " JOIN $extra_table extra_filter ON $table.$this->autoinc_id=extra_filter.$this->extra_id"; $this->extra_join_filter = " JOIN $extra_table extra_filter ON $table.$this->autoinc_id=extra_filter.$this->extra_id";
$this->customfields = Customfields::get($app, false, null, $db); $this->customfields = Storage\Customfields::get($app, false, null, $db);
} }
/** /**

View File

@ -10,7 +10,9 @@
* @version $Id$ * @version $Id$
*/ */
namespace EGroupware\Api; namespace EGroupware\Api\Storage;
use EGroupware\Api;
// explicitly reference classes still in phpgwapi // explicitly reference classes still in phpgwapi
use common; use common;
@ -28,7 +30,7 @@ class Customfields implements \IteratorAggregate
/** /**
* Reference to the global db class * Reference to the global db class
* *
* @var Db * @var Api\Db
*/ */
static protected $db; static protected $db;
@ -94,13 +96,13 @@ class Customfields implements \IteratorAggregate
*/ */
function getIterator() function getIterator()
{ {
return new Db\CallbackIterator($this->iterator, function($_row) return new Api\Db\CallbackIterator($this->iterator, function($_row)
{ {
$row = Db::strip_array_keys($_row, 'cf_'); $row = Api\Db::strip_array_keys($_row, 'cf_');
$row['private'] = $row['private'] ? explode(',', $row['private']) : array(); $row['private'] = $row['private'] ? explode(',', $row['private']) : array();
$row['type2'] = $row['type2'] ? explode(',', $row['type2']) : array(); $row['type2'] = $row['type2'] ? explode(',', $row['type2']) : array();
$row['values'] = json_decode($row['values'], true); $row['values'] = json_decode($row['values'], true);
$row['needed'] = Db::from_bool($row['needed']); $row['needed'] = Api\Db::from_bool($row['needed']);
return $row; return $row;
}, array(), function($row) }, array(), function($row)
@ -137,18 +139,18 @@ class Customfields implements \IteratorAggregate
public static function get($app, $all_private_too=false, $only_type2=null, egw_db $db=null) public static function get($app, $all_private_too=false, $only_type2=null, egw_db $db=null)
{ {
$cache_key = $app.':'.($all_private_too?'all':$GLOBALS['egw_info']['user']['account_id']).':'.$only_type2; $cache_key = $app.':'.($all_private_too?'all':$GLOBALS['egw_info']['user']['account_id']).':'.$only_type2;
$cfs = Cache::getInstance(__CLASS__, $cache_key); $cfs = Api\Cache::getInstance(__CLASS__, $cache_key);
if (!isset($cfs)) if (!isset($cfs))
{ {
$cfs = iterator_to_array(new Customfields($app, $all_private_too, $only_type2, 0, null, $db)); $cfs = iterator_to_array(new Customfields($app, $all_private_too, $only_type2, 0, null, $db));
Cache::setInstance(__CLASS__, $cache_key, $cfs); Api\Cache::setInstance(__CLASS__, $cache_key, $cfs);
$cached = Cache::getInstance(__CLASS__, $app); $cached = Api\Cache::getInstance(__CLASS__, $app);
if (!in_array($cache_key, (array)$cached)) if (!in_array($cache_key, (array)$cached))
{ {
$cached[] = $cache_key; $cached[] = $cache_key;
Cache::setInstance(__CLASS__, $app, $cached); Api\Cache::setInstance(__CLASS__, $app, $cached);
} }
} }
//error_log(__METHOD__."('$app', $all_private_too, '$only_type2') returning fields: ".implode(', ', array_keys($cfs))); //error_log(__METHOD__."('$app', $all_private_too, '$only_type2') returning fields: ".implode(', ', array_keys($cfs)));
@ -224,7 +226,7 @@ class Customfields implements \IteratorAggregate
case 'date-time': case 'date-time':
if ($value) if ($value)
{ {
$value = DateTime::to($value, $field['type'] == 'date' ? true : ''); $value = Api\DateTime::to($value, $field['type'] == 'date' ? true : '');
} }
break; break;
@ -461,13 +463,13 @@ class Customfields implements \IteratorAggregate
*/ */
protected static function invalidate_cache($app) protected static function invalidate_cache($app)
{ {
if (($cached = Cache::getInstance(__CLASS__, $app))) if (($cached = Api\Cache::getInstance(__CLASS__, $app)))
{ {
foreach($cached as $key) foreach($cached as $key)
{ {
Cache::unsetInstance(__CLASS__, $key); Api\Cache::unsetInstance(__CLASS__, $key);
} }
Cache::unsetInstance(__CLASS__, $app); Api\Cache::unsetInstance(__CLASS__, $app);
} }
} }
@ -532,7 +534,7 @@ class Customfields implements \IteratorAggregate
/** /**
* Initialise our db * Initialise our db
* *
* We use a reference here (no clone), as we no longer use Db::row() or Db::next_record()! * We use a reference here (no clone), as we no longer use Api\Db::row() or Api\Db::next_record()!
* *
*/ */
public static function init_static() public static function init_static()

288
api/src/Storage/History.php Normal file
View File

@ -0,0 +1,288 @@
<?php
/**
* EGroupware API - Storage history logging
*
* @link http://www.egroupware.org
* @author Joseph Engo <jengo@phpgroupware.org>
* @copyright 2001 by Joseph Engo <jengo@phpgroupware.org>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> new DB-methods and search
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage storage
* @access public
* @version $Id$
*/
namespace EGroupware\Api\Storage;
use EGroupware\Api;
/**
* Record history logging service
*
* This class need to be instanciated for EACH app, which wishes to use it!
*/
class History
{
/**
* Reference to the global db object
*
* @var Api\Db
*/
var $db;
const TABLE = 'egw_history_log';
/**
* App.name this class is instanciated for / working on
*
* @var string
*/
var $appname;
var $user;
var $types = array(
'C' => 'Created',
'D' => 'Deleted',
'E' => 'Edited'
);
/**
* Constructor
*
* @param string $appname app name this instance operates on
* @return historylog
*/
function __construct($appname='',$user=null)
{
$this->appname = $appname ? $appname : $GLOBALS['egw_info']['flags']['currentapp'];
$this->user = !is_null($user) ? $user : $GLOBALS['egw_info']['user']['account_id'];
if (is_object($GLOBALS['egw_setup']->db))
{
$this->db = $GLOBALS['egw_setup']->db;
}
else
{
$this->db = $GLOBALS['egw']->db;
}
}
/**
* Delete the history-log of one or multiple records of $this->appname
*
* @param int|array $record_id one or more id's of $this->appname, or null to delete ALL records of $this->appname
* @return int number of deleted records/rows (0 is not necessaryly an error, it can just mean there's no record!)
*/
function delete($record_id)
{
$where = array('history_appname' => $this->appname);
if (is_array($record_id) || is_numeric($record_id))
{
$where['history_record_id'] = $record_id;
}
$this->db->delete(self::TABLE,$where,__LINE__,__FILE__);
return $this->db->affected_rows();
}
/**
* Add a history record, if $new_value != $old_value
*
* @param string $status 2 letter code: eg. $this->types: C=Created, D=Deleted, E=Edited
* @param int $record_id it of the record in $this->appname (set by the constructor)
* @param string $new_value new value
* @param string $old_value old value
*/
function add($status,$record_id,$new_value,$old_value)
{
if ($new_value != $old_value)
{
$this->db->insert(self::TABLE,array(
'history_record_id' => $record_id,
'history_appname' => $this->appname,
'history_owner' => $this->user,
'history_status' => $status,
'history_new_value' => $new_value,
'history_old_value' => $old_value,
'history_timestamp' => time(),
'sessionid' => $GLOBALS['egw']->session->sessionid_access_log,
),false,__LINE__,__FILE__);
}
}
/**
* Static function to add a history record
*/
public static function static_add($appname, $id, $user, $field_code, $new_value, $old_value = '')
{
if ($new_value != $old_value)
{
$GLOBALS['egw']->db->insert(self::TABLE,array(
'history_record_id' => $id,
'history_appname' => $appname,
'history_owner' => (int)$user,
'history_status' => $field_code,
'history_new_value' => $new_value,
'history_old_value' => $old_value,
'history_timestamp' => time(),
'sessionid' => $GLOBALS['egw']->session->sessionid_access_log,
),false,__LINE__,__FILE__);
}
}
/**
* Search history-log
*
* @param array|int $filter array with filters, or int record_id
* @param string $order ='history_id' sorting after history_id is identical to history_timestamp
* @param string $sort ='DESC'
* @param int $limit =null only return this many entries
* @return array of arrays with keys id, record_id, appname, owner (account_id), status, new_value, old_value,
* timestamp (Y-m-d H:i:s in servertime), user_ts (timestamp in user-time)
*/
function search($filter,$order='history_id',$sort='DESC',$limit=null)
{
if (!is_array($filter)) $filter = is_numeric($filter) ? array('history_record_id' => $filter) : array();
if (!$order || !preg_match('/^[a-z0-9_]+$/i',$order) || !preg_match('/^(asc|desc)?$/i',$sort))
{
$orderby = 'ORDER BY history_id DESC';
}
else
{
$orderby = "ORDER BY $order $sort";
}
foreach($filter as $col => $value)
{
if (!is_numeric($col) && substr($col,0,8) != 'history_')
{
$filter['history_'.$col] = $value;
unset($filter[$col]);
}
}
if (!isset($filter['history_appname'])) $filter['history_appname'] = $this->appname;
// do not try to read all history entries of an app
if (!$filter['history_record_id']) return array();
$rows = array();
foreach($this->db->select(self::TABLE, '*', $filter, __LINE__, __FILE__,
isset($limit) ? 0 : false, $orderby, 'phpgwapi', $limit) as $row)
{
$row['user_ts'] = $this->db->from_timestamp($row['history_timestamp']) + 3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
$rows[] = Api\Db::strip_array_keys($row,'history_');
}
return $rows;
}
/**
* Get a slice of history records
*
* Similar to search(), except this one can take a start and a number of records
*
* @see Base::get_rows()
*/
public static function get_rows(&$query, &$rows)
{
$filter = array();
$rows = array();
$filter['history_appname'] = $query['appname'];
$filter['history_record_id'] = $query['record_id'];
if(is_array($query['colfilter'])) {
foreach($query['colfilter'] as $column => $value) {
$filter[$column] = $value;
}
}
if ($GLOBALS['egw']->db->Type == 'mysql' && $GLOBALS['egw']->db->ServerInfo['version'] >= 4.0)
{
$mysql_calc_rows = 'SQL_CALC_FOUND_ROWS ';
}
else
{
$total = $GLOBALS['egw']->db->select(self::TABLE,'COUNT(*)',$filter,__LINE__,__FILE__,false,'','phpgwapi',0)->fetchColumn();
}
// filter out private (or no longer defined) custom fields
if ($filter['history_appname'])
{
$to_or[] = "history_status NOT LIKE '#%'";
// explicitly allow "##" used to store iCal/vCard X-attributes
if (in_array($filter['history_appname'], array('calendar','infolog','addressbook')))
{
$to_or[] = "history_status LIKE '##%'";
}
if (($cfs = Customfields::get($filter['history_appname'])))
{
$to_or[] = 'history_status IN ('.implode(',', array_map(function($str)
{
return $GLOBALS['egw']->db->quote('#'.$str);
}, array_keys($cfs))).')';
}
$filter[] = '('.implode(' OR ', $to_or).')';
}
$_query = array(array(
'table' => self::TABLE,
'cols' => array('history_id', 'history_record_id','history_appname','history_owner','history_status','history_new_value', 'history_timestamp','history_old_value'),
'where' => $filter,
));
// Add in files, if possible
if($GLOBALS['egw_info']['user']['apps']['filemanager'] &&
$file = Api\Vfs\Sqlfs\StreamWrapper::url_stat("/apps/{$query['appname']}/{$query['record_id']}",STREAM_URL_STAT_LINK))
{
$_query[] = array(
'table' => Api\Vfs\Sqlfs\StreamWrapper::TABLE,
'cols' =>array('fs_id', 'fs_dir', "'filemanager'",'COALESCE(fs_modifier,fs_creator)',"'~file~'",'fs_name','fs_modified', 'fs_mime'),
'where' => array('fs_dir' => $file['ino'])
);
}
$new_file_id = array();
foreach($GLOBALS['egw']->db->union(
$_query,
__LINE__, __FILE__,
' ORDER BY ' . ($query['order'] ? $query['order'] : 'history_timestamp') . ' ' . ($query['sort'] ? $query['sort'] : 'DESC'),
$query['start'],
$query['num_rows']
) as $row)
{
$row['user_ts'] = $GLOBALS['egw']->db->from_timestamp($row['history_timestamp']) + 3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
// Explode multi-part values
foreach(array('history_new_value','history_old_value') as $field)
{
if(strpos($row[$field],Tracking::ONE2N_SEPERATOR) !== false)
{
$row[$field] = explode(Tracking::ONE2N_SEPERATOR,$row[$field]);
}
}
// Get information needed for proper display
if($row['history_appname'] == 'filemanager')
{
$new_version = $new_file_id[$row['history_new_value']];
$new_file_id[$row['history_new_value']] = count($rows);
$path = Api\Vfs\Sqlfs\StreamWrapper::id2path($row['history_id']);
// Apparently we don't have to do anything with it, just ask...
// without this, previous versions are not handled properly
Api\Vfs::getExtraInfo($path);
$row['history_new_value'] = array(
'path' => $path,
'name' => Api\Vfs::basename($path),
'mime' => $row['history_old_value']
);
$row['history_old_value'] = '';
if($new_version !== null)
{
$rows[$new_version]['old_value'] = $row['history_new_value'];
}
}
$rows[] = Api\Db::strip_array_keys($row,'history_');
}
if ($mysql_calc_rows)
{
$total = $GLOBALS['egw']->db->query('SELECT FOUND_ROWS()')->fetchColumn();
}
return $total;
}
}

1220
api/src/Storage/Tracking.php Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,11 +5,13 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package setup * @package setup
* @copyright (c) 2007-13 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api;
/** /**
* setup command: test or create the ldap connection and hierarchy * setup command: test or create the ldap connection and hierarchy
* *
@ -121,7 +123,7 @@ class setup_cmd_ldap extends setup_cmd
{ {
if (!empty($this->domain) && !preg_match('/^([a-z0-9_-]+\.)*[a-z0-9]+/i',$this->domain)) if (!empty($this->domain) && !preg_match('/^([a-z0-9_-]+\.)*[a-z0-9]+/i',$this->domain))
{ {
throw new egw_exception_wrong_userinput(lang("'%1' is no valid domain name!",$this->domain)); throw new Api\Exception\WrongUserinput(lang("'%1' is no valid domain name!",$this->domain));
} }
if ($this->remote_id && $check_only && !in_array($this->sub_command, array('set_mailbox', 'sid2uidnumber', 'copy2ad'))) if ($this->remote_id && $check_only && !in_array($this->sub_command, array('set_mailbox', 'sid2uidnumber', 'copy2ad')))
{ {
@ -186,7 +188,7 @@ class setup_cmd_ldap extends setup_cmd
// check if base does exist // check if base does exist
if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*')) if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*'))
{ {
throw new egw_exception_wrong_userinput(lang('Base dn "%1" NOT found!',$this->ldap_base)); throw new Api\Exception\WrongUserinput(lang('Base dn "%1" NOT found!',$this->ldap_base));
} }
if (!($sr = ldap_search($this->test_ldap->ds,$this->ldap_base, if (!($sr = ldap_search($this->test_ldap->ds,$this->ldap_base,
@ -194,7 +196,7 @@ class setup_cmd_ldap extends setup_cmd
array('uidNumber','gidNumber','uid','cn', 'objectClass',self::sambaSID))) || array('uidNumber','gidNumber','uid','cn', 'objectClass',self::sambaSID))) ||
!($entries = ldap_get_entries($this->test_ldap->ds, $sr))) !($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
{ {
throw new egw_exception(lang('Error searching "dn=%1" for "%2"!',$this->ldap_base, $search)); throw new Api\Exception(lang('Error searching "dn=%1" for "%2"!',$this->ldap_base, $search));
} }
$change = $accounts = array(); $change = $accounts = array();
$cmd_change_account_id = 'admin/admin-cli.php --change-account-id <admin>@<domain>,<adminpw>'; $cmd_change_account_id = 'admin/admin-cli.php --change-account-id <admin>@<domain>,<adminpw>';
@ -203,7 +205,7 @@ class setup_cmd_ldap extends setup_cmd
{ {
if ($key === 'count') continue; if ($key === 'count') continue;
$entry = ldap::result2array($entry); $entry = Api\Ldap::result2array($entry);
$accounts[$entry['dn']] = $entry; $accounts[$entry['dn']] = $entry;
//print_r($entry); //print_r($entry);
@ -247,7 +249,7 @@ class setup_cmd_ldap extends setup_cmd
} }
if (!$check_only && $modify && !ldap_modify($this->test_ldap->ds, $dn, $modify)) if (!$check_only && $modify && !ldap_modify($this->test_ldap->ds, $dn, $modify))
{ {
throw new egw_exception("Failed to modify ldap: !ldap_modify({$this->test_ldap->ds}, '$dn', ".array2string($modify).") ".ldap_error($this->test_ldap->ds). throw new Api\Exception("Failed to modify ldap: !ldap_modify({$this->test_ldap->ds}, '$dn', ".array2string($modify).") ".ldap_error($this->test_ldap->ds).
"\n- ".implode("\n- ", $msg)); // EGroupware change already run successful "\n- ".implode("\n- ", $msg)); // EGroupware change already run successful
} }
if ($modify) ++$changed; if ($modify) ++$changed;
@ -313,7 +315,7 @@ class setup_cmd_ldap extends setup_cmd
// check if ads base does exist // check if ads base does exist
if (!@ldap_read($ads->ds, $this->ads_context, 'objectClass=*')) if (!@ldap_read($ads->ds, $this->ads_context, 'objectClass=*'))
{ {
throw new egw_exception_wrong_userinput(lang('Ads dn "%1" NOT found!',$this->ads_context)); throw new Api\Exception\WrongUserInput(lang('Ads dn "%1" NOT found!',$this->ads_context));
} }
// connect to source ldap // connect to source ldap
@ -322,7 +324,7 @@ class setup_cmd_ldap extends setup_cmd
// check if ldap base does exist // check if ldap base does exist
if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*')) if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*'))
{ {
throw new egw_exception_wrong_userinput(lang('Base dn "%1" NOT found!',$this->ldap_base)); throw new Api\Exception\WrongUserInput(lang('Base dn "%1" NOT found!',$this->ldap_base));
} }
if (!($sr = ldap_search($this->test_ldap->ds,$this->ldap_base, if (!($sr = ldap_search($this->test_ldap->ds,$this->ldap_base,
@ -330,7 +332,7 @@ class setup_cmd_ldap extends setup_cmd
'(&(objectClass=posixAccount)('.self::sambaSID.'=*)(!(uid=*$)))', $attrs)) || '(&(objectClass=posixAccount)('.self::sambaSID.'=*)(!(uid=*$)))', $attrs)) ||
!($entries = ldap_get_entries($this->test_ldap->ds, $sr))) !($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
{ {
throw new egw_exception(lang('Error searching "dn=%1" for "%2"!',$this->ldap_base, $search)); throw new Api\Exception(lang('Error searching "dn=%1" for "%2"!',$this->ldap_base, $search));
} }
$changed = 0; $changed = 0;
$utc_diff = null; $utc_diff = null;
@ -338,12 +340,12 @@ class setup_cmd_ldap extends setup_cmd
{ {
if ($key === 'count') continue; if ($key === 'count') continue;
$entry_arr = ldap::result2array($entry); $entry_arr = Api\Ldap::result2array($entry);
$uid = $entry_arr['uid']; $uid = $entry_arr['uid'];
$entry = array_diff_key($entry_arr, $ignore_attr); $entry = array_diff_key($entry_arr, $ignore_attr);
if (!($sr = ldap_search($ads->ds, $this->ads_context, if (!($sr = ldap_search($ads->ds, $this->ads_context,
$search='(&(objectClass=user)(sAMAccountName='.ldap::quote($uid).'))', array('dn'))) || $search='(&(objectClass=user)(sAMAccountName='.Api\Ldap::quote($uid).'))', array('dn'))) ||
!($dest = ldap_get_entries($ads->ds, $sr))) !($dest = ldap_get_entries($ads->ds, $sr)))
{ {
$msg[] = lang('User "%1" not found!', $uid); $msg[] = lang('User "%1" not found!', $uid);
@ -591,7 +593,7 @@ class setup_cmd_ldap extends setup_cmd
// should we run any or some addAccount hooks // should we run any or some addAccount hooks
if ($this->add_account_hook) if ($this->add_account_hook)
{ {
// setting up egw_info array with new ldap information, so hook can use ldap::ldapConnect() // setting up egw_info array with new ldap information, so hook can use Api\Ldap::ldapConnect()
if (!$egw_info_set++) if (!$egw_info_set++)
{ {
foreach(array('ldap_host','ldap_root_dn','ldap_root_pw','ldap_context','ldap_group_context','ldap_search_filter','ldap_encryptin_type','mail_suffix','mail_login_type') as $name) foreach(array('ldap_host','ldap_root_dn','ldap_root_pw','ldap_context','ldap_group_context','ldap_search_filter','ldap_encryptin_type','mail_suffix','mail_login_type') as $name)
@ -798,7 +800,7 @@ class setup_cmd_ldap extends setup_cmd
* @param string $dn =null default $this->ldap_root_dn * @param string $dn =null default $this->ldap_root_dn
* @param string $pw =null default $this->ldap_root_pw * @param string $pw =null default $this->ldap_root_pw
* @param string $host =null default $this->ldap_host, hostname, ip or ldap-url * @param string $host =null default $this->ldap_host, hostname, ip or ldap-url
* @throws egw_exception_wrong_userinput Can not connect to ldap ... * @throws Api\Exception\WrongUserInput Can not connect to ldap ...
*/ */
private function connect($dn=null,$pw=null,$host=null) private function connect($dn=null,$pw=null,$host=null)
{ {
@ -806,9 +808,9 @@ class setup_cmd_ldap extends setup_cmd
if (is_null($pw)) $pw = $this->ldap_root_pw; if (is_null($pw)) $pw = $this->ldap_root_pw;
if (is_null($host)) $host = $this->ldap_host; if (is_null($host)) $host = $this->ldap_host;
if (!$pw) // ldap::ldapConnect use the current eGW's pw otherwise if (!$pw) // Api\Ldap::ldapConnect use the current eGW's pw otherwise
{ {
throw new egw_exception_wrong_userinput(lang('You need to specify a password!')); throw new Api\Exception\WrongUserInput(lang('You need to specify a password!'));
} }
$this->test_ldap = new ldap(); $this->test_ldap = new ldap();
@ -821,7 +823,7 @@ class setup_cmd_ldap extends setup_cmd
if (!$ds) if (!$ds)
{ {
throw new egw_exception_wrong_userinput(lang('Can not connect to LDAP server on host %1 using DN %2!', throw new Api\Exception\WrongUserInput(lang('Can not connect to LDAP server on host %1 using DN %2!',
$host,$dn).($this->test_ldap->ds ? ' ('.ldap_error($this->test_ldap->ds).')' : '')); $host,$dn).($this->test_ldap->ds ? ' ('.ldap_error($this->test_ldap->ds).')' : ''));
} }
return lang('Successful connected to LDAP server on %1 using DN %2.',$this->ldap_host,$dn); return lang('Successful connected to LDAP server on %1 using DN %2.',$this->ldap_host,$dn);
@ -831,7 +833,7 @@ class setup_cmd_ldap extends setup_cmd
* Count active (not expired) users * Count active (not expired) users
* *
* @return int number of active users * @return int number of active users
* @throws egw_exception_wrong_userinput * @throws Api\Exception\WrongUserInput
*/ */
private function users() private function users()
{ {
@ -840,7 +842,7 @@ class setup_cmd_ldap extends setup_cmd
$sr = ldap_list($this->test_ldap->ds,$this->ldap_context,'ObjectClass=posixAccount',array('dn','shadowExpire')); $sr = ldap_list($this->test_ldap->ds,$this->ldap_context,'ObjectClass=posixAccount',array('dn','shadowExpire'));
if (!($entries = ldap_get_entries($this->test_ldap->ds, $sr))) if (!($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
{ {
throw new egw_exception('Error listing "dn=%1"!',$this->ldap_context); throw new Api\Exception('Error listing "dn=%1"!',$this->ldap_context);
} }
$num = 0; $num = 0;
foreach($entries as $n => $entry) foreach($entries as $n => $entry)
@ -856,7 +858,7 @@ class setup_cmd_ldap extends setup_cmd
* Check and if does not yet exist create the new database and user * Check and if does not yet exist create the new database and user
* *
* @return string with success message * @return string with success message
* @throws egw_exception_wrong_userinput * @throws Api\Exception\WrongUserInput
*/ */
private function create() private function create()
{ {
@ -883,7 +885,7 @@ class setup_cmd_ldap extends setup_cmd
* Delete whole LDAP tree of an instance dn=$this->ldap_base using $this->ldap_admin/_pw * Delete whole LDAP tree of an instance dn=$this->ldap_base using $this->ldap_admin/_pw
* *
* @return string with success message * @return string with success message
* @throws egw_exception if dn not found, not listable or delete fails * @throws Api\Exception if dn not found, not listable or delete fails
*/ */
private function delete_base() private function delete_base()
{ {
@ -897,12 +899,12 @@ class setup_cmd_ldap extends setup_cmd
// some precausion to not delete whole ldap tree! // some precausion to not delete whole ldap tree!
if (count(explode(',',$this->ldap_base)) < 2) if (count(explode(',',$this->ldap_base)) < 2)
{ {
throw new egw_exception_assertion_failed(lang('Refusing to delete dn "%1"!',$this->ldap_base)); throw new Api\Exception\AssertionFailed(lang('Refusing to delete dn "%1"!',$this->ldap_base));
} }
// check if base does exist // check if base does exist
if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*')) if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*'))
{ {
throw new egw_exception_wrong_userinput(lang('Base dn "%1" NOT found!',$this->ldap_base)); throw new Api\Exception\WrongUserInput(lang('Base dn "%1" NOT found!',$this->ldap_base));
} }
return lang('LDAP dn="%1" with %2 entries deleted.', return lang('LDAP dn="%1" with %2 entries deleted.',
$this->ldap_base,$this->rdelete($this->ldap_base)); $this->ldap_base,$this->rdelete($this->ldap_base));
@ -913,14 +915,14 @@ class setup_cmd_ldap extends setup_cmd
* *
* @param string $dn * @param string $dn
* @return int integer number of deleted entries * @return int integer number of deleted entries
* @throws egw_exception if dn not listable or delete fails * @throws Api\Exception if dn not listable or delete fails
*/ */
private function rdelete($dn) private function rdelete($dn)
{ {
if (!($sr = ldap_list($this->test_ldap->ds,$dn,'ObjectClass=*',array(''))) || if (!($sr = ldap_list($this->test_ldap->ds,$dn,'ObjectClass=*',array(''))) ||
!($entries = ldap_get_entries($this->test_ldap->ds, $sr))) !($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
{ {
throw new egw_exception(lang('Error listing "dn=%1"!',$dn)); throw new Api\Exception(lang('Error listing "dn=%1"!',$dn));
} }
$deleted = 0; $deleted = 0;
foreach($entries as $n => $entry) foreach($entries as $n => $entry)
@ -930,7 +932,7 @@ class setup_cmd_ldap extends setup_cmd
} }
if (!ldap_delete($this->test_ldap->ds,$dn)) if (!ldap_delete($this->test_ldap->ds,$dn))
{ {
throw new egw_exception(lang('Error deleting "dn=%1"!',$dn)); throw new Api\Exception(lang('Error deleting "dn=%1"!',$dn));
} }
return ++$deleted; return ++$deleted;
} }
@ -944,7 +946,7 @@ class setup_cmd_ldap extends setup_cmd
* @param string $this->mbox_attr ='mailmessagestore' lowercase!!! * @param string $this->mbox_attr ='mailmessagestore' lowercase!!!
* @param string $this->mail_login_type ='email' 'email', 'vmailmgr', 'standard' or 'uidNumber' * @param string $this->mail_login_type ='email' 'email', 'vmailmgr', 'standard' or 'uidNumber'
* @return string with success message N entries modified * @return string with success message N entries modified
* @throws egw_exception if dn not found, not listable or delete fails * @throws Api\Exception if dn not found, not listable or delete fails
*/ */
private function set_mailbox($check_only=false) private function set_mailbox($check_only=false)
{ {
@ -958,7 +960,7 @@ class setup_cmd_ldap extends setup_cmd
// check if base does exist // check if base does exist
if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*')) if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*'))
{ {
throw new egw_exception_wrong_userinput(lang('Base dn "%1" NOT found!',$this->ldap_base)); throw new Api\Exception\WrongUserInput(lang('Base dn "%1" NOT found!',$this->ldap_base));
} }
$object_class = $this->object_class ? $this->object_class : 'qmailUser'; $object_class = $this->object_class ? $this->object_class : 'qmailUser';
$mbox_attr = $this->mbox_attr ? $this->mbox_attr : 'mailmessagestore'; $mbox_attr = $this->mbox_attr ? $this->mbox_attr : 'mailmessagestore';
@ -968,7 +970,7 @@ class setup_cmd_ldap extends setup_cmd
'objectClass='.$object_class,array('mail','uidNumber','uid',$mbox_attr))) || 'objectClass='.$object_class,array('mail','uidNumber','uid',$mbox_attr))) ||
!($entries = ldap_get_entries($this->test_ldap->ds, $sr))) !($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
{ {
throw new egw_exception(lang('Error listing "dn=%1"!',$this->ldap_base)); throw new Api\Exception(lang('Error listing "dn=%1"!',$this->ldap_base));
} }
$modified = 0; $modified = 0;
foreach($entries as $n => $entry) foreach($entries as $n => $entry)
@ -987,7 +989,7 @@ class setup_cmd_ldap extends setup_cmd
$mbox_attr => $mbox, $mbox_attr => $mbox,
))) )))
{ {
throw new egw_exception(lang("Error modifying dn=%1: %2='%3'!",$entry['dn'],$mbox_attr,$mbox)); throw new Api\Exception(lang("Error modifying dn=%1: %2='%3'!",$entry['dn'],$mbox_attr,$mbox));
} }
++$modified; ++$modified;
if ($check_only) echo "$modified: $entry[dn]: $mbox_attr={$entry[$mbox_attr][0]} --> $mbox\n"; if ($check_only) echo "$modified: $entry[dn]: $mbox_attr={$entry[$mbox_attr][0]} --> $mbox\n";
@ -1015,7 +1017,7 @@ class setup_cmd_ldap extends setup_cmd
* @param string $dn dn to create, eg. "cn=admin,dc=local" * @param string $dn dn to create, eg. "cn=admin,dc=local"
* @param array $extra =array() extra attributes to set * @param array $extra =array() extra attributes to set
* @return boolean true if the node was create, false if it was already there * @return boolean true if the node was create, false if it was already there
* @throws egw_exception_wrong_userinput * @throws Api\Exception\WrongUserinput
*/ */
private function _create_node($dn,$extra=array()) private function _create_node($dn,$extra=array())
{ {
@ -1035,7 +1037,7 @@ class setup_cmd_ldap extends setup_cmd
if (!isset(self::$requiredObjectclasses[$name])) if (!isset(self::$requiredObjectclasses[$name]))
{ {
throw new egw_exception_wrong_userinput(lang('Can not create DN %1!',$dn).' '. throw new Api\Exception\WrongUserinput(lang('Can not create DN %1!',$dn).' '.
lang('Supported node types:').implode(', ',array_keys(self::$requiredObjectclasses))); lang('Supported node types:').implode(', ',array_keys(self::$requiredObjectclasses)));
} }
if ($name == 'dc') $extra['o'] = $value; // required by organisation if ($name == 'dc') $extra['o'] = $value; // required by organisation
@ -1046,7 +1048,7 @@ class setup_cmd_ldap extends setup_cmd
'objectClass' => self::$requiredObjectclasses[$name], 'objectClass' => self::$requiredObjectclasses[$name],
)+$extra)) )+$extra))
{ {
throw new egw_exception_wrong_userinput(lang('Can not create DN %1!',$dn). throw new Api\Exception\WrongUserinput(lang('Can not create DN %1!',$dn).
' ('.ldap_error($this->test_ldap->ds).', attributes='.print_r($attr,true).')'); ' ('.ldap_error($this->test_ldap->ds).', attributes='.print_r($attr,true).')');
} }
return true; return true;