mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-23 00:13:35 +01:00
new ldap backend for addressbook
This commit is contained in:
parent
267015342a
commit
cdd165ef50
@ -12,31 +12,275 @@
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
require_once(EGW_INCLUDE_ROOT.'/phpgwapi/inc/class.contacts.inc.php');
|
||||
require_once(EGW_INCLUDE_ROOT.'/phpgwapi/inc/class.contacts.inc.php');
|
||||
|
||||
define('ADDRESSBOOK_ALL',0);
|
||||
define('ADDRESSBOOK_ACCOUNTS',1);
|
||||
define('ADDRESSBOOK_PERSONAL',2);
|
||||
define('ADDRESSBOOK_GROUP',3);
|
||||
|
||||
/**
|
||||
* Wrapper class for phpgwapi.contacts_ldap
|
||||
* This makes it compatible with vars and parameters of so_sql
|
||||
* Maybe one day this becomes a generalized ldap storage object :-)
|
||||
*
|
||||
* @package addressbook
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
*/
|
||||
class so_ldap extends contacts
|
||||
{
|
||||
var $data;
|
||||
var $db_data_cols;
|
||||
var $db_key_cols;
|
||||
|
||||
/**
|
||||
* constructor of the class
|
||||
* Wrapper class for phpgwapi.contacts_ldap
|
||||
* This makes it compatible with vars and parameters of so_sql
|
||||
* Maybe one day this becomes a generalized ldap storage object :-)
|
||||
*
|
||||
* @package addressbook
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
*/
|
||||
function so_ldap()
|
||||
{
|
||||
parent::contacts();
|
||||
$this->db_data_cols = $this->stock_contact_fields + $this->non_contact_fields;
|
||||
}
|
||||
class so_ldap extends contacts {
|
||||
|
||||
var $data;
|
||||
//var $db_data_cols;
|
||||
//var $db_key_cols;
|
||||
var $groupName = 'Default';
|
||||
|
||||
/**
|
||||
* @var string $accountName holds the accountname of the current user
|
||||
*/
|
||||
var $accountName;
|
||||
|
||||
/**
|
||||
* @var object $ldapServerInfo holds the information about the current used ldap server
|
||||
*/
|
||||
var $ldapServerInfo;
|
||||
|
||||
/**
|
||||
* @var int $ldapLimit how many rows to fetch from ldap server
|
||||
*/
|
||||
var $ldapLimit = 300;
|
||||
|
||||
/**
|
||||
* @var string $personalContactsDN holds the base DN for the personal addressbooks
|
||||
*/
|
||||
var $personalContactsDN;
|
||||
|
||||
/**
|
||||
* @var string $sharedContactsDN holds the base DN for the shared addressbooks
|
||||
*/
|
||||
var $sharedContactsDN;
|
||||
|
||||
/**
|
||||
* @var int $total holds the total count of found rows
|
||||
*/
|
||||
var $total;
|
||||
|
||||
# jpegPhoto
|
||||
var $inetOrgPersonFields = array(
|
||||
'n_fn' => 'cn',
|
||||
'n_given' => 'givenname',
|
||||
'n_family' => 'sn',
|
||||
#'n_middle' => 'phpgwmiddlename',
|
||||
#'n_prefix' => 'phpgwprefix',
|
||||
#'n_suffix' => 'phpgwsuffix',
|
||||
'sound' => 'audio',
|
||||
#'bday' => 'phpgwbirthday',
|
||||
'note' => 'description',
|
||||
#'tz' => 'phpgwtz',
|
||||
#'geo' => 'phpgwgeo',
|
||||
'url' => 'labeleduri',
|
||||
#'pubkey' => 'phpgwpublickey',
|
||||
|
||||
'org_name' => 'o',
|
||||
'org_unit' => 'ou',
|
||||
'title' => 'title',
|
||||
|
||||
'adr_one_street' => 'street',
|
||||
'adr_one_locality' => 'l',
|
||||
'adr_one_region' => 'st',
|
||||
'adr_one_postalcode' => 'postalcode',
|
||||
#'adr_one_countryname' => 'co',
|
||||
#'adr_one_type' => 'phpgwadronetype',
|
||||
#'label' => 'phpgwaddresslabel',
|
||||
|
||||
#'adr_two_street' => 'phpgwadrtwostreet',
|
||||
#'adr_two_locality' => 'phpgwadrtwolocality',
|
||||
#'adr_two_region' => 'phpgwadrtworegion',
|
||||
#'adr_two_postalcode' => 'phpgwadrtwopostalcode',
|
||||
#'adr_two_countryname' => 'phpgwadrtwocountryname',
|
||||
#'adr_two_type' => 'phpgwadrtwotype',
|
||||
|
||||
'tel_work' => 'telephonenumber',
|
||||
'tel_home' => 'homephone',
|
||||
#'tel_voice' => 'phpgwvoicetelephonenumber',
|
||||
'tel_fax' => 'facsimiletelephonenumber',
|
||||
#'tel_msg' => 'phpgwmsgtelephonenumber',
|
||||
#'tel_cell' => 'phpgwcelltelephonenumber',
|
||||
#'tel_pager' => 'phpgwpagertelephonenumber',
|
||||
#'tel_bbs' => 'phpgwbbstelephonenumber',
|
||||
#'tel_modem' => 'phpgwmodemtelephonenumber',
|
||||
#'tel_car' => 'phpgwmobiletelephonenumber',
|
||||
#'tel_isdn' => 'phpgwisdnphonenumber',
|
||||
#'tel_video' => 'phpgwvideophonenumber',
|
||||
#'tel_prefer' => 'phpgwpreferphone',
|
||||
'email' => 'mail',
|
||||
#'email_type' => 'phpgwmailtype',
|
||||
#'email_home' => 'phpgwmailhome',
|
||||
#'email_home_type' => 'phpgwmailhometype',
|
||||
'room' => 'roomnumber',
|
||||
);
|
||||
|
||||
#displayName
|
||||
#mozillaCustom1
|
||||
#mozillaCustom2
|
||||
#mozillaCustom3
|
||||
#mozillaCustom4
|
||||
#mozillaHomeUrl
|
||||
#mozillaNickname
|
||||
#mozillaUseHtmlMail
|
||||
#nsAIMid
|
||||
#postOfficeBox
|
||||
var $mozillaAbPersonFields = array(
|
||||
#'fn' => 'cn',
|
||||
#'n_given' => 'givenname',
|
||||
#'n_family' => 'sn',
|
||||
#'n_middle' => 'phpgwmiddlename',
|
||||
#'n_prefix' => 'phpgwprefix',
|
||||
#'n_suffix' => 'phpgwsuffix',
|
||||
#'sound' => 'phpgwaudio',
|
||||
#'bday' => 'phpgwbirthday',
|
||||
#'note' => 'description',
|
||||
#'tz' => 'phpgwtz',
|
||||
#'geo' => 'phpgwgeo',
|
||||
#'url' => 'mozillaworkurl',
|
||||
#'pubkey' => 'phpgwpublickey',
|
||||
|
||||
#'org_name' => 'o',
|
||||
#'org_unit' => 'ou',
|
||||
#'title' => 'title',
|
||||
|
||||
#'adr_one_street' => 'street',
|
||||
'adr_one_street2' => 'mozillaworkstreet2',
|
||||
#'adr_one_locality' => 'l',
|
||||
#'adr_one_region' => 'st',
|
||||
#'adr_one_postalcode' => 'postalcode',
|
||||
#'adr_one_countryname' => 'c',
|
||||
#'adr_one_type' => 'phpgwadronetype',
|
||||
#'label' => 'phpgwaddresslabel',
|
||||
|
||||
'adr_two_street' => 'mozillahomestreet',
|
||||
'adr_two_street2' => 'mozillahomestreet2',
|
||||
'adr_two_locality' => 'mozillahomelocalityname',
|
||||
'adr_two_region' => 'mozillahomestate',
|
||||
'adr_two_postalcode' => 'mozillahomepostalcode',
|
||||
'adr_two_countryname' => 'mozillahomecountryname',
|
||||
#'adr_two_type' => 'phpgwadrtwotype',
|
||||
|
||||
#'tel_work' => 'telephonenumber',
|
||||
#'tel_home' => 'homephone',
|
||||
#'tel_voice' => 'phpgwvoicetelephonenumber',
|
||||
'tel_fax' => 'fax',
|
||||
#'tel_msg' => 'phpgwmsgtelephonenumber',
|
||||
'tel_cell' => 'mobile',
|
||||
'tel_pager' => 'pager',
|
||||
#'tel_bbs' => 'phpgwbbstelephonenumber',
|
||||
#'tel_modem' => 'phpgwmodemtelephonenumber',
|
||||
#'tel_car' => 'phpgwmobiletelephonenumber',
|
||||
#'tel_isdn' => 'phpgwisdnphonenumber',
|
||||
#'tel_video' => 'phpgwvideophonenumber',
|
||||
#'tel_prefer' => 'phpgwpreferphone',
|
||||
#'email' => 'mail',
|
||||
#'email_type' => 'phpgwmailtype',
|
||||
'email_home' => 'mozillasecondemail',
|
||||
#'email_home_type' => 'phpgwmailhometype',
|
||||
'url_home' => 'mozillahomeurl',
|
||||
);
|
||||
|
||||
# homeFacsimileTelephoneNumber
|
||||
# otherPhone
|
||||
# businessRole
|
||||
# managerName
|
||||
# assistantName
|
||||
# otherPostalAddress
|
||||
# mailer
|
||||
# anniversary
|
||||
# spouseName
|
||||
# companyPhone
|
||||
# callbackPhone
|
||||
# otherFacsimileTelephoneNumber
|
||||
# radio
|
||||
# telex
|
||||
# tty
|
||||
# categories(deprecated)
|
||||
# calendarURI
|
||||
# freeBusyURI
|
||||
var $evolutionPersonFields = array(
|
||||
'fn' => 'fileas',
|
||||
#'n_given' => 'givenname',
|
||||
#'n_family' => 'sn',
|
||||
#'n_middle' => 'phpgwmiddlename',
|
||||
#'n_prefix' => 'phpgwprefix',
|
||||
#'n_suffix' => 'phpgwsuffix',
|
||||
#'sound' => 'phpgwaudio',
|
||||
'bday' => 'birthdate',
|
||||
'note' => 'note',
|
||||
#'tz' => 'phpgwtz',
|
||||
#'geo' => 'phpgwgeo',
|
||||
#'url' => 'mozillaworkurl',
|
||||
#'pubkey' => 'phpgwpublickey',
|
||||
|
||||
#'org_name' => 'o',
|
||||
#'org_unit' => 'ou',
|
||||
#'title' => 'title',
|
||||
|
||||
#'adr_one_street' => 'street',
|
||||
#'adr_one_locality' => 'l',
|
||||
#'adr_one_region' => 'st',
|
||||
#'adr_one_postalcode' => 'postalcode',
|
||||
#'adr_one_countryname' => 'c',
|
||||
#'adr_one_type' => 'phpgwadronetype',
|
||||
#'label' => 'phpgwaddresslabel',
|
||||
|
||||
#'adr_two_street' => 'mozillahomestreet',
|
||||
#'adr_two_locality' => 'mozillahomelocalityname',
|
||||
#'adr_two_region' => 'mozillahomestate',
|
||||
#'adr_two_postalcode' => 'mozillahomepostalcode',
|
||||
#'adr_two_countryname' => 'mozillahomecountryname',
|
||||
#'adr_two_type' => 'phpgwadrtwotype',
|
||||
|
||||
#'tel_work' => 'telephonenumber',
|
||||
#'tel_home' => 'homephone',
|
||||
#'tel_voice' => 'phpgwvoicetelephonenumber',
|
||||
#'tel_fax' => 'fax',
|
||||
#'tel_msg' => 'phpgwmsgtelephonenumber',
|
||||
#'tel_cell' => 'mobile',
|
||||
#'tel_pager' => 'pager',
|
||||
#'tel_bbs' => 'phpgwbbstelephonenumber',
|
||||
#'tel_modem' => 'phpgwmodemtelephonenumber',
|
||||
'tel_car' => 'carphone',
|
||||
#'tel_isdn' => 'phpgwisdnphonenumber',
|
||||
#'tel_video' => 'phpgwvideophonenumber',
|
||||
'tel_prefer' => 'primaryphone',
|
||||
#'email' => 'mail',
|
||||
#'email_type' => 'phpgwmailtype',
|
||||
#'email_home' => 'mozillasecondemail',
|
||||
#'email_home_type' => 'phpgwmailhometype',
|
||||
'cat_id' => 'category',
|
||||
'role' => 'businessrole',
|
||||
'tel_assistent' => 'assistantphone',
|
||||
'assistent' => 'assistantname',
|
||||
'n_fileas' => 'fileas',
|
||||
);
|
||||
|
||||
/**
|
||||
* constructor of the class
|
||||
*
|
||||
*/
|
||||
function so_ldap()
|
||||
{
|
||||
//$this->db_data_cols = $this->stock_contact_fields + $this->non_contact_fields;
|
||||
$this->accountName = $GLOBALS['egw_info']['user']['account_lid'];
|
||||
|
||||
$this->personalContactsDN = 'ou=personal,ou=contacts,'. $GLOBALS['egw_info']['server']['ldap_contact_context'];
|
||||
$this->sharedContactsDN = 'ou=shared,ou=contacts,'. $GLOBALS['egw_info']['server']['ldap_contact_context'];
|
||||
|
||||
$this->ldap = CreateObject('phpgwapi.ldap');
|
||||
$this->ds = $this->ldap->ldapConnect(
|
||||
$GLOBALS['egw_info']['server']['ldap_contact_host'],
|
||||
$GLOBALS['egw_info']['user']['account_dn'],
|
||||
$GLOBALS['egw_info']['user']['passwd']
|
||||
);
|
||||
$this->ldapServerInfo = $this->ldap->getLDAPServerInfo($GLOBALS['egw_info']['server']['ldap_contact_host']);
|
||||
}
|
||||
|
||||
/**
|
||||
* reads row matched by key and puts all cols in the data array
|
||||
@ -48,7 +292,103 @@ class so_ldap extends contacts
|
||||
*/
|
||||
function read($keys,$extra_cols='',$join='')
|
||||
{
|
||||
$contacts = parent::read_single_entry($keys);
|
||||
$attributes = array_unique(array_merge(array_values($this->inetOrgPersonFields),
|
||||
array_values($this->mozillaAbPersonFields),
|
||||
array_values($this->evolutionPersonFields)
|
||||
));
|
||||
|
||||
#$rows = $this->searchLDAP($GLOBALS['egw_info']['server']['ldap_contact_context'], "(|(entryUUID=$keys)(uid=$keys))", $attributes, ADDRESSBOOK_ALL);
|
||||
|
||||
#_debug_array($rows);
|
||||
|
||||
#return $rows[0];
|
||||
|
||||
sort($attributes);
|
||||
$attributes[] = 'entryUUID';
|
||||
$attributes[] = 'objectClass';
|
||||
$attributes[] = 'uid';
|
||||
if($result = ldap_search($this->ds, $GLOBALS['egw_info']['server']['ldap_contact_context'], "(|(entryUUID=$keys)(uid=$keys))", $attributes)) {
|
||||
$entry = ldap_get_entries($this->ds, $result);
|
||||
#_debug_array($entry);
|
||||
$contacts[0]['id'] = $entry[0]['uid'][0] ? $entry[0]['uid'][0] : $entry[0]['entryuuid'][0];
|
||||
for($i=0; $i<$entry[0]['objectclass']['count']; $i++) {
|
||||
switch(strtolower($entry[0]['objectclass'][$i])) {
|
||||
case 'inetorgperson':
|
||||
foreach($this->inetOrgPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(!empty($entry[0][$ldapFieldName][0]) && !isset($contacts[0][$egwFieldName])) {
|
||||
$contacts[0][$egwFieldName] = $GLOBALS['egw']->translation->convert(($entry[0][$ldapFieldName][0]),'utf-8');
|
||||
}
|
||||
}
|
||||
|
||||
#print $entry[0]['cn'][0]."<br>";
|
||||
#print $entry[0]['sn'][0]."<br>";
|
||||
if(empty($entry[0]['givenname'][0])) {
|
||||
$parts = preg_split('/'.$entry[0]['sn'][0].'/', $entry[0]['cn'][0]);
|
||||
$contacts[0]['n_prefix'] = trim($parts[0]);
|
||||
$contacts[0]['n_suffix'] = trim($parts[1]);
|
||||
} else {
|
||||
$parts = preg_split('/'. $entry[0]['givenname'][0] .'.*'. $entry[0]['sn'][0] .'/', $entry[0]['cn'][0]);
|
||||
$contacts[0]['n_prefix'] = trim($parts[0]);
|
||||
$contacts[0]['n_suffix'] = trim($parts[1]);
|
||||
if(preg_match('/'. $entry[0]['givenname'][0] .' (.*) '. $entry[0]['sn'][0] .'/',$entry[0]['cn'][0], $matches)) {
|
||||
$contacts[0]['n_middle'] = $matches[1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'mozillaabpersonalpha':
|
||||
foreach($this->mozillaAbPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(!empty($entry[0][$ldapFieldName][0]) && !isset($contacts[0][$egwFieldName])) {
|
||||
$contacts[0][$egwFieldName] = $GLOBALS['egw']->translation->convert(($entry[0][$ldapFieldName][0]),'utf-8');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'evolutionperson':
|
||||
foreach($this->evolutionPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(!empty($entry[0][$ldapFieldName][0]) && !isset($contacts[0][$egwFieldName])) {
|
||||
switch($egwFieldName) {
|
||||
case 'cat_id':
|
||||
for($ii=0; $ii<$entry[0][$ldapFieldName]['count']; $ii++) {
|
||||
if(!empty($contacts[0][$egwFieldName])) $contacts[0][$egwFieldName] .= ',';
|
||||
$contacts[0][$egwFieldName] .= ExecMethod('phpgwapi.categories.name2id',$entry[0][$ldapFieldName][$ii]);
|
||||
}
|
||||
break;
|
||||
|
||||
# case 'bday':
|
||||
# $bdayParts = explode('-',$entry[0][$ldapFieldName][0]);
|
||||
# $contacts[0][$egwFieldName] = $bdayParts[1]. '/' .$bdayParts[2]. '/' .$bdayParts[0];
|
||||
# break;
|
||||
|
||||
default;
|
||||
if(!empty($entry[0][$ldapFieldName][0]) && !isset($contacts[0][$egwFieldName])) {
|
||||
$contacts[0][$egwFieldName] = $GLOBALS['egw']->translation->convert(($entry[0][$ldapFieldName][0]),'utf-8');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!empty($entry[0]['fileas'][0])) {
|
||||
$contacts[0]['fn'] = $GLOBALS['egw']->translation->convert(($entry[0]['fileas'][0]),'utf-8');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
$contacts[0]['tid'] = 'n';
|
||||
if(strpos($entry[0]['dn'],$this->personalContactsDN)) {
|
||||
$contacts[0]['access'] = 'private';
|
||||
$contacts[0]['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
||||
} else {
|
||||
$contacts[0]['access'] = 'public';
|
||||
$contacts[0]['owner'] = -1000;
|
||||
}
|
||||
# if(strpos($entry[0]['dn'],$this->personalContactsDN)) {
|
||||
# $contacts[0]['access'] = 'private';
|
||||
# } else {
|
||||
# $contacts[0]['access'] = 'public';
|
||||
# }
|
||||
}
|
||||
# _debug_array($contacts);
|
||||
return $contacts[0];
|
||||
}
|
||||
|
||||
@ -60,18 +400,260 @@ class so_ldap extends contacts
|
||||
*/
|
||||
function save($keys=null)
|
||||
{
|
||||
$contactUID = '';
|
||||
|
||||
$isUpdate = false;
|
||||
$newObjectClasses = array();
|
||||
$ldapContact = array();
|
||||
$data =& $this->data;
|
||||
|
||||
// new contact
|
||||
if(empty($this->data[$this->contacts_id]))
|
||||
{
|
||||
$ret = parent::add($data['owner'],$data,$data['access'],$data['cat_id'],$data['tid']);
|
||||
#_debug_array($data);exit;
|
||||
// generate addressbook dn
|
||||
|
||||
if((int)$data['owner'] < 0) {
|
||||
// group address book
|
||||
if(!$groupName = strtolower($GLOBALS['egw']->accounts->id2name((int)$data['owner']))) {
|
||||
return false;
|
||||
}
|
||||
$baseDN = 'cn='. $groupName .','. $this->sharedContactsDN;
|
||||
$cn = $groupName;
|
||||
} elseif((int)$data['owner'] > 0) {
|
||||
// personal addressbook
|
||||
$baseDN = 'cn='. strtolower($this->accountName) .','. $this->personalContactsDN;
|
||||
$cn = strtolower($this->accountName);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret = parent::update($data[$this->contacts_id],$data['owner'],$data);
|
||||
|
||||
// check if $baseDN exists. If not create new one
|
||||
if(!$result = ldap_read($this->ds, $baseDN, 'objectclass=*')) {
|
||||
if(ldap_errno($this->ds) == 32) {
|
||||
// create a admin connection to add the needed DN
|
||||
$adminLDAP = CreateObject('phpgwapi.ldap');
|
||||
$adminDS = $adminLDAP->ldapConnect();
|
||||
|
||||
// emtry does not exist, lets try to create it
|
||||
$baseDNData['objectClass'] = 'organizationalRole';
|
||||
$baseDNData['cn'] = $cn;
|
||||
if(!ldap_add($adminDS, $baseDN, $baseDNData)) {
|
||||
$adminLDAP->ldapDisconnect();
|
||||
return false;
|
||||
}
|
||||
$adminLDAP->ldapDisconnect();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $ret === false ? 1 : 0;
|
||||
|
||||
$attributes = array('dn','cn','objectClass','uid');
|
||||
if(!empty($this->data[$this->contacts_id])) {
|
||||
$contactUID = $this->data[$this->contacts_id];
|
||||
|
||||
$result = ldap_search($this->ds, $GLOBALS['egw_info']['server']['ldap_contact_context'], "(|(entryUUID=$contactUID)(uid=$contactUID))", $attributes);
|
||||
|
||||
$oldContactInfo = ldap_get_entries($this->ds, $result);
|
||||
$oldObjectclass = $oldContactInfo[0]['objectclass'];
|
||||
$isUpdate = true;
|
||||
}
|
||||
|
||||
if(!$contactUID) {
|
||||
$contactUID = md5($GLOBALS['egw']->common->randomstring(15));
|
||||
}
|
||||
|
||||
$ldapContact['uid'] = $contactUID;
|
||||
|
||||
if($this->ldapServerInfo->supportsObjectClass('inetOrgPerson')) {
|
||||
if(!$isUpdate) {
|
||||
$ldapContact['objectclass'][] = 'inetOrgPerson';
|
||||
$ldapContact['objectclass'][] = 'person';
|
||||
} else {
|
||||
if(!in_array('person', $oldObjectclass)) {
|
||||
$newObjectClasses['objectClass'][] = 'person';
|
||||
}
|
||||
if(!in_array('inetOrgPerson', $oldObjectclass) && !in_array('inetorgperson', $oldObjectclass)) {
|
||||
$newObjectClasses['objectClass'][] = 'inetOrgPerson';
|
||||
}
|
||||
}
|
||||
foreach($this->inetOrgPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(!empty($data[$egwFieldName])) {
|
||||
switch($ldapFieldName) {
|
||||
case 'cn':
|
||||
$cneGWFields = array('n_prefix', 'n_given', 'n_middle', 'n_family', 'n_suffix');
|
||||
foreach($cneGWFields as $cn_eGWField) {
|
||||
if(!empty($data[$cn_eGWField])) {
|
||||
$ldapContact[$ldapFieldName] .= $data[$cn_eGWField].' ';
|
||||
}
|
||||
}
|
||||
$ldapContact[$ldapFieldName] = trim($ldapContact[$ldapFieldName]);
|
||||
break;
|
||||
default:
|
||||
$ldapContact[$ldapFieldName] = $GLOBALS['egw']->translation->convert(trim($data[$egwFieldName]),$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
break;
|
||||
}
|
||||
} elseif($isUpdate) {
|
||||
$ldapContact[$ldapFieldName] = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($this->ldapServerInfo->supportsObjectClass('mozillaAbPersonAlpha')) {
|
||||
if(!$isUpdate) {
|
||||
$ldapContact['objectclass'][] = 'mozillaAbPersonAlpha';
|
||||
} else {
|
||||
if(!in_array('mozillaAbPersonAlpha', $oldObjectclass) && !in_array('mozillaabpersonalpha', $oldObjectclass)) {
|
||||
$newObjectClasses['objectClass'][] = 'mozillaAbPersonAlpha';
|
||||
}
|
||||
}
|
||||
foreach($this->mozillaAbPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(empty($ldapContact[$ldapFieldName]) && !empty($data[$egwFieldName])) {
|
||||
$ldapContact[$ldapFieldName] = $GLOBALS['egw']->translation->convert(trim($data[$egwFieldName]),$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
} elseif(empty($ldapContact[$ldapFieldName]) && $isUpdate) {
|
||||
$ldapContact[$ldapFieldName] = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($this->ldapServerInfo->supportsObjectClass('mozillaOrgPerson')) {
|
||||
if(!$isUpdate) {
|
||||
$ldapContact['objectclass'][] = 'mozillaOrgPerson';
|
||||
} else {
|
||||
if(!in_array('mozillaOrgPerson', $oldObjectclass) && !in_array('mozillaorgperson', $oldObjectclass)) {
|
||||
$newObjectClasses['objectClass'][] = 'mozillaOrgPerson';
|
||||
}
|
||||
}
|
||||
foreach($this->mozillaAbPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(empty($ldapContact[$ldapFieldName]) && !empty($data[$egwFieldName])) {
|
||||
$ldapContact[$ldapFieldName] = $GLOBALS['egw']->translation->convert(trim($data[$egwFieldName]),$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
} elseif(empty($ldapContact[$ldapFieldName]) && $isUpdate) {
|
||||
$ldapContact[$ldapFieldName] = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($this->ldapServerInfo->supportsObjectClass('evolutionPerson')) {
|
||||
if(!$isUpdate) {
|
||||
$ldapContact['objectclass'][] = 'evolutionPerson';
|
||||
} else {
|
||||
if(!in_array('evolutionPerson', $oldObjectclass) && !in_array('evolutionperson', $oldObjectclass)) {
|
||||
$newObjectClasses['objectClass'][] = 'evolutionPerson';
|
||||
}
|
||||
}
|
||||
foreach($this->evolutionPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(empty($ldapContact[$ldapFieldName]) && !empty($data[$egwFieldName])) {
|
||||
switch($egwFieldName) {
|
||||
case 'cat_id':
|
||||
if(!empty($data[$egwFieldName])) {
|
||||
$catIDs = explode(',',$data[$egwFieldName]);
|
||||
foreach($catIDs as $value) {
|
||||
$ldapContact[$ldapFieldName][] = $GLOBALS['egw']->translation->convert(ExecMethod('phpgwapi.categories.id2name',$value),$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
# case 'bday':
|
||||
# $dateParts = explode('/',$data[$egwFieldName]);
|
||||
# $bday = $dateParts[2] .'-'. $dateParts[0] .'-'. $dateParts[1];
|
||||
# $ldapContact[$ldapFieldName] = $bday;
|
||||
# break;
|
||||
|
||||
default:
|
||||
$ldapContact[$ldapFieldName] = $GLOBALS['egw']->translation->convert(trim($data[$egwFieldName]),$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
break;
|
||||
}
|
||||
} elseif(empty($ldapContact[$ldapFieldName]) && $isUpdate) {
|
||||
$ldapContact[$ldapFieldName] = array();
|
||||
}
|
||||
$postalAddress = $data['adr_one_street'] .'$'. $data['adr_one_locality'] .', '. $data['adr_one_region'] .'$'. $data['adr_one_postalcode'] .'$$'. $data['adr_one_countryname'];
|
||||
if($postalAddress != '$, $$$') {
|
||||
$ldapContact['postalAddress'] = $GLOBALS['egw']->translation->convert($postalAddress,$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
} elseif($isUpdate) {
|
||||
$ldapContact['postalAddress'] = array();
|
||||
}
|
||||
$homePostalAddress = $data['adr_two_street'] .'$'. $data['adr_two_locality'] .', '. $data['adr_two_region'] .'$'. $data['adr_two_postalcode'] .'$$'. $data['adr_two_countryname'];
|
||||
if($homePostalAddress != '$, $$$') {
|
||||
$ldapContact['homePostalAddress'] = $GLOBALS['egw']->translation->convert($homePostalAddress,$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
} elseif($isUpdate) {
|
||||
$ldapContact['homePostalAddress'] = array();
|
||||
}
|
||||
}
|
||||
#if(!empty($ldapContact['givenname']) && !empty($ldapContact['sn'])) {
|
||||
# $ldapContact['fileas'] = $ldapContact['sn'] .', '. $ldapContact['givenname'];
|
||||
#} else {
|
||||
# $ldapContact['fileas'] = $ldapContact['sn'];
|
||||
#}
|
||||
}
|
||||
|
||||
if($isUpdate) {
|
||||
// update entry
|
||||
$dn = $oldContactInfo[0]['dn'];
|
||||
$needRecreation = false;
|
||||
|
||||
// add missing objectclasses
|
||||
if(count($newObjectClasses) > 0) {
|
||||
$result = @ldap_mod_add($this->ds, $dn, $newObjectClasses);
|
||||
if(!$result) {
|
||||
#print 'class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')';exit;
|
||||
if(ldap_errno($this->ds) == 69) {
|
||||
// need to modify structural objectclass
|
||||
$needRecreation = true;
|
||||
} else {
|
||||
error_log('class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if we need to rename the DN or need to recreate the contact
|
||||
$newRDN = 'uid='. $contactUID;
|
||||
$newDN = $newRDN .','. $baseDN;
|
||||
if(strtolower($dn) != strtolower($newDN) || $needRecreation) {
|
||||
$result = ldap_read($this->ds, $dn, 'objectclass=*');
|
||||
$oldContact = ldap_get_entries($this->ds, $result);
|
||||
foreach($oldContact[0] as $key => $value) {
|
||||
if(is_array($value)) {
|
||||
unset($value['count']);
|
||||
$newContact[$key] = $value;
|
||||
}
|
||||
}
|
||||
$newContact['uid'] = $contactUID;
|
||||
|
||||
if(is_array($newObjectClasses['objectClass']) && count($newObjectClasses['objectClass']) > 0) {
|
||||
$newContact['objectclass'] = array_merge($newContact['objectclass'], $newObjectClasses['objectClass']);
|
||||
}
|
||||
|
||||
if(ldap_delete($this->ds, $dn)) {
|
||||
if(!ldap_add($this->ds, $newDN, $newContact)) {
|
||||
print 'class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')';_debug_array($newContact);exit;
|
||||
}
|
||||
} else {
|
||||
error_log('class.so_ldap.inc.php ('. __LINE__ .') delete of old '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')');
|
||||
return false;
|
||||
}
|
||||
|
||||
$dn = $newDN;
|
||||
}
|
||||
|
||||
#_debug_array($ldapContact);exit;
|
||||
$result = ldap_modify($this->ds, $dn, $ldapContact);
|
||||
if (!$result) {
|
||||
error_log('class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')');
|
||||
#print 'class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')';exit;
|
||||
#_debug_array($ldapContact);exit;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$dn = 'uid='. $ldapContact['uid'] .','. $baseDN;
|
||||
|
||||
#print "Save $dn<bR>";_debug_array($ldapContact);exit;
|
||||
$result = ldap_add($this->ds, $dn, $ldapContact);
|
||||
|
||||
if (!$result) {
|
||||
error_log('class.so_ldap.inc.php ('. __LINE__ .') add of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,17 +666,22 @@ class so_ldap extends contacts
|
||||
{
|
||||
// single entry
|
||||
if($keys[$this->contacts_id]) $keys = array( 0 => $keys);
|
||||
|
||||
if(!is_array($keys)) {
|
||||
$keys = array( 0 => $keys);
|
||||
}
|
||||
|
||||
$ret = 0;
|
||||
|
||||
$attributes = array('dn');
|
||||
|
||||
foreach($keys as $entry)
|
||||
{
|
||||
if(parent::delete($entry[$this->contacts_id]) === false)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret++;
|
||||
if($result = ldap_search($this->ds, $GLOBALS['egw_info']['server']['ldap_contact_context'], "(|(entryUUID=$entry)(uid=$entry))", $attributes)) {
|
||||
$contactInfo = ldap_get_entries($this->ds, $result);
|
||||
if(ldap_delete($this->ds, $contactInfo[0]['dn'])) {
|
||||
$ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
@ -121,14 +708,217 @@ class so_ldap extends contacts
|
||||
*/
|
||||
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)
|
||||
{
|
||||
$order_by = explode(',',$order_by);
|
||||
$order_by = explode(' ',$order_by);
|
||||
$sort = $order_by[0];
|
||||
$order = $order_by[1];
|
||||
$query = $criteria;
|
||||
$fields = $only_keys ? ($only_keys === true ? $this->contacts_id : $only_keys) : '';
|
||||
$limit = $need_full_no_count ? 0 : $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs'];
|
||||
return parent::read($start,$limit,$fields,$query,$filter,$sort,$order);
|
||||
#_debug_array($criteria); print "OrderBY: $order_by";_debug_array($extra_cols);_debug_array($filter);
|
||||
#$order_by = explode(',',$order_by);
|
||||
#$order_by = explode(' ',$order_by);
|
||||
#$sort = $order_by[0];
|
||||
#$order = $order_by[1];
|
||||
#$query = $criteria;
|
||||
#$fields = $only_keys ? ($only_keys === true ? $this->contacts_id : $only_keys) : '';
|
||||
#$limit = $need_full_no_count ? 0 : $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs'];
|
||||
#return parent::read($start,$limit,$fields,$query,$filter,$sort,$order);
|
||||
|
||||
$searchFilter = '';
|
||||
$categoryFilter = '';
|
||||
|
||||
$ownerID = (int)$filter['owner'];
|
||||
|
||||
if($ownerID < 0) {
|
||||
if($groupName = $GLOBALS['egw']->accounts->id2name($ownerID)) {
|
||||
$searchDN = 'cn='. strtolower($groupName) .','. $this->sharedContactsDN;
|
||||
$addressbookType = ADDRESSBOOK_GROUP;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} elseif($ownerID > 0) {
|
||||
$searchDN = 'cn='. strtolower($this->accountName) .','. $this->personalContactsDN;
|
||||
$addressbookType = ADDRESSBOOK_PERSONAL;
|
||||
} else {
|
||||
$searchDN = $GLOBALS['egw_info']['server']['ldap_contact_context'];
|
||||
$addressbookType = ADDRESSBOOK_ALL;
|
||||
}
|
||||
|
||||
// create the search filter
|
||||
switch($addressbookType) {
|
||||
case ADDRESSBOOK_ALL:
|
||||
$objectFilter = '(|(objectclass=inetorgperson)(objectclass=posixaccount))';
|
||||
$attributes = array_unique(array_merge(array_values($this->inetOrgPersonFields),
|
||||
array_values($this->mozillaAbPersonFields),
|
||||
array_values($this->evolutionPersonFields)
|
||||
));
|
||||
break;
|
||||
case ADDRESSBOOK_ACCOUNTS:
|
||||
$objectFilter = '(objectclass=posixaccount)';
|
||||
$attributes = array_unique(array_merge(array_values($this->inetOrgPersonFields),
|
||||
array_values($this->mozillaAbPersonFields),
|
||||
array_values($this->evolutionPersonFields)
|
||||
));
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
$objectFilter = '(objectclass=inetorgperson)';
|
||||
$attributes = array_unique(array_merge(array_values($this->inetOrgPersonFields),
|
||||
array_values($this->mozillaAbPersonFields),
|
||||
array_values($this->evolutionPersonFields)
|
||||
));
|
||||
break;
|
||||
}
|
||||
sort($attributes);
|
||||
|
||||
if($catID = (int)$filter['cat_id']) {
|
||||
$catName = $GLOBALS['egw']->translation->convert(ExecMethod('phpgwapi.categories.id2name',$catID),$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
$categoryFilter = "(category=$catName)";
|
||||
}
|
||||
|
||||
#
|
||||
if(is_array($criteria) && count($criteria) > 0) {
|
||||
$searchFilter = '';
|
||||
foreach($criteria as $egwSearchKey => $searchValue) {
|
||||
$ldapSearchKey = '';
|
||||
if($ldapSearchKey = $this->inetOrgPersonFields[$egwSearchKey]) {
|
||||
#print $ldapSearchKey.$searchValue.'<br>';
|
||||
$searchString = $GLOBALS['egw']->translation->convert($searchValue,$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
$searchFilter .= "($ldapSearchKey=$wildcard$searchString$wildcard)";
|
||||
}
|
||||
}
|
||||
if($op == 'AND') {
|
||||
$searchFilter = "(&$searchFilter)";
|
||||
} else {
|
||||
$searchFilter = "(|$searchFilter)";
|
||||
}
|
||||
}
|
||||
$ldapFilter = "(&$objectFilter$categoryFilter$searchFilter)";
|
||||
|
||||
$rows = $this->searchLDAP($searchDN, $ldapFilter, $attributes, $addressbookType);
|
||||
|
||||
#_debug_array($rows);
|
||||
return $rows;
|
||||
}
|
||||
|
||||
function searchLDAP($_ldapContext, $_filter, $_attributes, $_addressbooktype) {
|
||||
$this->total = 0;
|
||||
|
||||
$_attributes[] = 'entryUUID';
|
||||
$_attributes[] = 'uid';
|
||||
$_attributes[] = 'objectClass';
|
||||
$_attributes[] = 'createTimestamp';
|
||||
$_attributes[] = 'modifyTimestamp';
|
||||
|
||||
if($_addressbooktype == ADDRESSBOOK_ALL) {
|
||||
$result = ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit);
|
||||
} else {
|
||||
$result = ldap_list($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit);
|
||||
}
|
||||
|
||||
#print 'class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')';
|
||||
if($result) {
|
||||
$entries = ldap_get_entries($this->ds, $result);
|
||||
$this->total = $entries['count'];
|
||||
for($i=0; $i<$entries['count']; $i++) {
|
||||
$contacts[$i]['id'] = $entries[$i]['uid'][0] ? $entries[$i]['uid'][0] : $entries[$i]['entryuuid'][0];
|
||||
for($ii=0; $ii<$entries[$i]['objectclass']['count']; $ii++) {
|
||||
switch(strtolower($entries[$i]['objectclass'][$ii])) {
|
||||
case 'inetorgperson':
|
||||
foreach($this->inetOrgPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(!empty($entries[$i][$ldapFieldName][0]) && !isset($contacts[$i][$egwFieldName])) {
|
||||
$contacts[$i][$egwFieldName] = $GLOBALS['egw']->translation->convert(($entries[$i][$ldapFieldName][0]),'utf-8');
|
||||
}
|
||||
}
|
||||
|
||||
#print $entries[$i]['cn'][0]."<br>";
|
||||
#print $entries[$i]['sn'][0]."<br>";
|
||||
if(empty($entries[$i]['givenname'][0])) {
|
||||
$parts = preg_split('/'.$entries[$i]['sn'][0].'/', $entries[$i]['cn'][0]);
|
||||
$contacts[$i]['n_prefix'] = trim($parts[0]);
|
||||
$contacts[$i]['n_suffix'] = trim($parts[1]);
|
||||
} else {
|
||||
$parts = preg_split('/'. $entries[$i]['givenname'][0] .'.*'. $entries[$i]['sn'][0] .'/', $entries[$i]['cn'][0]);
|
||||
$contacts[$i]['n_prefix'] = trim($parts[0]);
|
||||
$contacts[$i]['n_suffix'] = trim($parts[1]);
|
||||
if(preg_match('/'. $entries[$i]['givenname'][0] .' (.*) '. $entries[$i]['sn'][0] .'/',$entries[$i]['cn'][0], $matches)) {
|
||||
$contacts[$i]['n_middle'] = $matches[1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'mozillaabpersonalpha':
|
||||
foreach($this->mozillaAbPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(!empty($entries[$i][$ldapFieldName][0]) && !isset($contacts[$i][$egwFieldName])) {
|
||||
$contacts[$i][$egwFieldName] = $GLOBALS['egw']->translation->convert(($entries[$i][$ldapFieldName][0]),'utf-8');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'evolutionperson':
|
||||
foreach($this->evolutionPersonFields as $egwFieldName => $ldapFieldName) {
|
||||
if(!empty($entries[$i][$ldapFieldName][0]) && !isset($contacts[$i][$egwFieldName])) {
|
||||
switch($egwFieldName) {
|
||||
case 'cat_id':
|
||||
for($iii=0; $iii<$entries[$i][$ldapFieldName]['count']; $iii++) {
|
||||
if(!empty($contacts[$i][$egwFieldName])) $contacts[$i][$egwFieldName] .= ',';
|
||||
$contacts[$i][$egwFieldName] .= ExecMethod('phpgwapi.categories.name2id',$entries[$i][$ldapFieldName][$iii]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'bday':
|
||||
$bdayParts = explode('-',$entries[$i][$ldapFieldName][0]);
|
||||
$contacts[$i][$egwFieldName] = $bdayParts[1]. '/' .$bdayParts[2]. '/' .$bdayParts[0];
|
||||
break;
|
||||
default;
|
||||
if(!empty($entries[$i][$ldapFieldName][0]) && !isset($contacts[$i][$egwFieldName])) {
|
||||
$contacts[$i][$egwFieldName] = $GLOBALS['egw']->translation->convert(($entries[$i][$ldapFieldName][0]),'utf-8');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!empty($entries[$i]['fileas'][0])) {
|
||||
$contacts[$i]['fn'] = $GLOBALS['egw']->translation->convert(($entries[$i]['fileas'][0]),'utf-8');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// the template id for the addressbook
|
||||
$contacts[$i]['tid'] = 'n';
|
||||
|
||||
if(strpos($entries[$i]['dn'],$this->personalContactsDN)) {
|
||||
$contacts[$i]['access'] = 'private';
|
||||
$contacts[$i]['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
||||
} else {
|
||||
$contacts[$i]['access'] = 'public';
|
||||
$contacts[$i]['owner'] = -1000;
|
||||
}
|
||||
|
||||
# modifier
|
||||
# creator
|
||||
if(!empty($entries[$i]['createtimestamp'][0])) {
|
||||
$year = substr($entries[$i]['createtimestamp'][0],0,4);
|
||||
$month = substr($entries[$i]['createtimestamp'][0],4,2);
|
||||
$day = substr($entries[$i]['createtimestamp'][0],6,2);
|
||||
$hour = substr($entries[$i]['createtimestamp'][0],8,2);
|
||||
$minute = substr($entries[$i]['createtimestamp'][0],10,2);
|
||||
$second = substr($entries[$i]['createtimestamp'][0],12,2);
|
||||
$contacts[$i]['created'] = mktime($hour, $minute, $second, $month, $day, $year);
|
||||
}
|
||||
|
||||
if(!empty($entries[$i]['modifytimestamp'][0])) {
|
||||
$year = substr($entries[$i]['modifytimestamp'][0],0,4);
|
||||
$month = substr($entries[$i]['modifytimestamp'][0],4,2);
|
||||
$day = substr($entries[$i]['modifytimestamp'][0],6,2);
|
||||
$hour = substr($entries[$i]['modifytimestamp'][0],8,2);
|
||||
$minute = substr($entries[$i]['modifytimestamp'][0],10,2);
|
||||
$second = substr($entries[$i]['modifytimestamp'][0],12,2);
|
||||
$contacts[$i]['modified'] = mktime($hour, $minute, $second, $month, $day, $year);
|
||||
}
|
||||
}
|
||||
|
||||
#_debug_array($contacts);
|
||||
#exit;
|
||||
return $contacts;
|
||||
}
|
||||
#print 'class.so_ldap.inc.php ('. __LINE__ .') renaming of '. $dn .' to '. $newDN .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')';
|
||||
#print "bad<br>";
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user