reworked and restructured LDAP support:

- addressbook now supports contacts in SQL and accounts in LDAP
- added supported objectClasses and a README in new doc dir
- ldap::quote() against LDAP query injection
- got jpegphoto in LDAP working (they are binary)
- we support now mozillaAbPersonAlpha and the older mozillaOrgPerson schema, beside inetOrpPerson and evolutionPerson
- added sorting, letter-search and limited result sets for LDAP
still missing is to disable the organisation stuff in the UI for LDAP
This commit is contained in:
Ralf Becker 2006-06-13 04:30:16 +00:00
parent 346164483e
commit 2201a45d27
9 changed files with 1505 additions and 761 deletions

18
addressbook/doc/README Normal file
View File

@ -0,0 +1,18 @@
eGroupWare Addressbook 1.3+ LDAP support
========================================
The new Addressbook requires only the inetOrgPerson schema.
If you want to use extra attributes availible in the SQL addressbook
like eg. the home-address you need to use some other supported schema:
- evolutionOrgPerson used by evolution
- mozillaAbPersonAlpha used by thunderbird & sunbird 1.5+
- mozillaOrgPerson older mozilla schema (depricated, but mostly compatible to mozillaAbPersonAlpha)
Please note:
You can install the evolutionPerson schema together with ONE
of the mozilla schemas. You can NOT install both mozilla schema!
If the addressbook detects the schemas, it fills the extra fields of each schema.
Ralf

View File

@ -0,0 +1,212 @@
#
# Depends upon
# Definition of an X.500 Attribute Type and an Object Class to Hold
# Uniform Resource Identifiers (URIs) [RFC2079]
# (core.schema)
#
# A Summary of the X.500(96) User Schema for use with LDAPv3 [RFC2256]
# (core.schema)
#
# The COSINE and Internet X.500 Schema [RFC1274] (cosine.schema)
#
# The Internet Organizational Person Schema (inetorgperson)
#
# OIDs are broken up into the following:
# 1.3.6.1.4.1.8506.1.?
# .1 Syntaxes
# .2 Attributes
# .3 Objectclasses
# primaryPhone
attributetype ( 1.3.6.1.4.1.8506.1.2.1
NAME 'primaryPhone'
DESC 'preferred phone number used to contact a person'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
# carPhone
attributetype ( 1.3.6.1.4.1.8506.1.2.2
NAME 'carPhone'
DESC 'car phone telephone number of the person'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50
SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.8506.1.2.3
NAME ( 'homeFacsimileTelephoneNumber' 'homeFax' )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )
attributetype ( 1.3.6.1.4.1.8506.1.2.4
NAME 'otherPhone'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
attributetype ( 1.3.6.1.4.1.8506.1.2.5
NAME 'businessRole'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
attributetype ( 1.3.6.1.4.1.8506.1.2.6
NAME 'managerName'
SUP name )
attributetype ( 1.3.6.1.4.1.8506.1.2.7
NAME 'assistantName'
SUP name )
# spouseName
# single valued (/me smirks)
attributetype ( 1.3.6.1.4.1.8506.1.2.8
NAME 'spouseName'
SUP name
SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.8506.1.2.9
NAME 'otherPostalAddress'
EQUALITY caseIgnoreListMatch
SUBSTR caseIgnoreListSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attributetype ( 1.3.6.1.4.1.8506.1.2.10
NAME ( 'mailer' 'mua' )
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32} )
attributetype ( 1.3.6.1.4.1.8506.1.2.11
NAME ( 'birthDate' 'dob' )
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributetype ( 1.3.6.1.4.1.8506.1.2.12
NAME 'anniversary'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributetype ( 1.3.6.1.4.1.8506.1.2.13
NAME 'note'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
attributetype ( 1.3.6.1.4.1.8506.1.2.14
NAME 'evolutionArbitrary'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{4096} )
)
attributetype ( 1.3.6.1.4.1.8506.1.2.15
NAME 'fileAs'
SUP name )
attributetype ( 1.3.6.1.4.1.8506.1.2.16
NAME 'assistantPhone'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
attributetype ( 1.3.6.1.4.1.8506.1.2.17
NAME 'companyPhone'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
attributetype ( 1.3.6.1.4.1.8506.1.2.18
NAME 'callbackPhone'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
attributetype ( 1.3.6.1.4.1.8506.1.2.19
NAME ( 'otherFacsimileTelephoneNumber' 'otherFax' )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )
attributetype ( 1.3.6.1.4.1.8506.1.2.20
NAME 'radio'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
attributetype ( 1.3.6.1.4.1.8506.1.2.21
NAME 'telex'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
attributetype ( 1.3.6.1.4.1.8506.1.2.22
NAME 'tty'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
# deprecated - use the multivalued category
attributetype ( 1.3.6.1.4.1.8506.1.2.23
NAME 'categories'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{4096} )
attributetype ( 1.3.6.1.4.1.8506.1.2.24
NAME 'contact'
EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
attributetype ( 1.3.6.1.4.1.8506.1.2.25
NAME 'listName'
SUP name
SINGLE-VALUE )
# deprecated - use calEntry and its attributes from RFC 2739
attributetype ( 1.3.6.1.4.1.8506.1.2.26
NAME 'calendarURI'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )
# deprecated - use calEntry and its attributes from RFC 2739
attributetype ( 1.3.6.1.4.1.8506.1.2.27
NAME 'freeBusyURI'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.8506.1.2.28
NAME 'category'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{4096} )
# evolutionPerson
objectclass ( 1.3.6.1.4.1.8506.1.3.1
NAME 'evolutionPerson'
DESC 'Objectclass geared to Evolution Usage'
SUP inetOrgPerson
STRUCTURAL
MAY (
fileAs $ primaryPhone $ carPhone $ homeFacsimileTelephoneNumber $
otherPhone $ businessRole $ managerName $ assistantName $ assistantPhone $
otherPostalAddress $ mailer $ birthDate $ anniversary $ spouseName $
note $ companyPhone $ callbackPhone $ otherFacsimileTelephoneNumber $
radio $ telex $ tty $ categories $ category $ calendarURI $ freeBusyURI )
)
# evolutionPersonList
objectclass ( 1.3.6.1.4.1.8506.1.3.2
NAME 'evolutionPersonList'
DESC 'Objectclass geared to Evolution Contact Lists'
SUP top
STRUCTURAL
MUST (
listName )
MAY (
mail $ contact )
)

View File

@ -0,0 +1,148 @@
# Mozilla: @VERSION@
#
# mozillaAbPersonAlpha
#
# Created initial version --[[User:Standard8|Standard8]] 12:21, 5 Dec 2005 (PST)
#
# This file contains LDAPv3 schema for use with the Mozilla Address Book
# and is intended to ...
# Depends upon
# Definition of an X.500 Attribute Type and an Object Class to Hold
# Uniform Resource Identifiers (URIs) [RFC2079], and A Summary of
# the X.500(96) User Schema for use with LDAPv3 [RFC2256] (core.schema)
#
# The COSINE and Internet X.500 Schema [RFC1274] (cosine.schema)
#
# The InetOrgPerson Schema [RFC2798] (inetorgperson.schema)
# 1.3.6.1.4.1.13769.4.x - Mozilla AB 'Other' tab
attributetype ( 1.3.6.1.4.1.13769.4.1 NAME 'mozillaCustom1'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.4.2 NAME 'mozillaCustom2'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.4.3 NAME 'mozillaCustom3'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.4.4 NAME 'mozillaCustom4'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
# 1.3.6.1.4.1.13769.3.x - Mozilla AB 'Address' tab
attributetype ( 1.3.6.1.4.1.13769.3.1 NAME 'mozillaHomeStreet'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.3.2 NAME 'mozillaHomeStreet2'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.3.3 NAME 'mozillaHomeLocalityName'
SUP name SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.3.4 NAME 'mozillaHomeState'
SUP name SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.3.5 NAME 'mozillaHomePostalCode'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.3.6 NAME 'mozillaHomeCountryName'
SUP name SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.3.7 NAME 'mozillaHomeUrl'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.3.8 NAME 'mozillaWorkStreet2'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.3.9 NAME 'mozillaWorkUrl'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
# 1.3.6.1.4.1.13769.2.x - Mozilla AB 'Contact' tab
attributetype ( 1.3.6.1.4.1.13769.2.1
NAME ( 'mozillaNickname' 'xmozillanickname' )
SUP name )
attributetype ( 1.3.6.1.4.1.13769.2.2
NAME ( 'mozillaSecondEmail' 'xmozillasecondemail' )
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.2.3
NAME ( 'mozillaUseHtmlMail' 'xmozillausehtmlmail' )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
# AOL Instant Messenger (AIM) Identity
attributetype ( 1.3.6.1.4.1.13769.2.4
NAME ( 'nsAIMid' 'nscpaimscreenname' )
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
# 1.3.6.1.4.1.13769.9 - Mozilla AB objectclasses
# The mozillaAddressBookEntry object class is used to define entries
# representing Cards in the Mozilla Address Book. The commonName attribute
# is used for naming entries of this object class, but may not be unique.
# department $
objectclass ( 1.3.6.1.4.1.13769.9.1 NAME 'mozillaAbPersonAlpha'
SUP top AUXILIARY
MUST ( cn )
MAY( c $
description $
displayName $
fax $
givenName $
homePhone $
l $
mail $
mobile $
mozillaCustom1 $
mozillaCustom2 $
mozillaCustom3 $
mozillaCustom4 $
mozillaHomeCountryName $
mozillaHomeLocalityName $
mozillaHomePostalCode $
mozillaHomeState $
mozillaHomeStreet $
mozillaHomeStreet2 $
mozillaHomeUrl $
mozillaNickname $
mozillaSecondEmail $
mozillaUseHtmlMail $
mozillaWorkStreet2 $
mozillaWorkUrl $
nsAIMid $
o $
ou $
pager $
postalCode $
postOfficeBox $
sn $
st $
street $
telephoneNumber $
title ) )

View File

@ -0,0 +1,177 @@
#
# mozillaOrgPerson schema v. 0.6.3
#
# req. core
# req. cosine
# req. inetorgperson
# attribute defs
attributetype ( 1.3.6.1.4.1.13769.2.1.1
NAME ( 'mozillaNickname' )
SUP name )
attributetype ( 1.3.6.1.4.1.13769.2.1.2
NAME ( 'mozillaUseHtmlMail' )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.2.1.3
NAME 'mozillaSecondEmail'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
attributetype ( 1.3.6.1.4.1.13769.2.1.4
NAME 'mozillaHomeLocalityName'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributetype ( 1.3.6.1.4.1.13769.2.1.5
NAME 'mozillaPostalAddress2'
EQUALITY caseIgnoreListMatch
SUBSTR caseIgnoreListSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attributetype ( 1.3.6.1.4.1.13769.2.1.6
NAME 'mozillaHomePostalAddress2'
EQUALITY caseIgnoreListMatch
SUBSTR caseIgnoreListSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attributetype ( 1.3.6.1.4.1.13769.2.1.7
NAME ( 'mozillaHomeState' ) SUP name )
attributetype ( 1.3.6.1.4.1.13769.2.1.8
NAME 'mozillaHomePostalCode'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
attributetype ( 1.3.6.1.4.1.13769.2.1.9
NAME ( 'mozillaHomeCountryName' )
SUP name SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.2.1.10
NAME ( 'mozillaHomeFriendlyCountryName' )
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
attributetype ( 1.3.6.1.4.1.13769.2.1.11
NAME ( 'mozillaHomeUrl' )
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
attributetype ( 1.3.6.1.4.1.13769.2.1.12
NAME ( 'mozillaWorkUrl' )
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
# un-comment for all LDAP server NOT supporting SYNTAX 2.16.840.1.113730.3.7.1
attributetype ( 1.3.6.1.4.1.13769.2.1.13
NAME ( 'nsAIMid' )
DESC 'AOL Instant Messenger (AIM) Identity'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
attributetype ( 1.3.6.1.4.1.13769.2.1.14 NAME ( 'mozillaHomeStreet' )
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
# un-comment for Netscape 6.x and all other LDAP server supporting SYNTAX 2.16.840.1.113730.3.7.1
# attributeTypes ( 2.16.840.1.113730.3.1.2013
# NAME ( 'nsAIMid' )
# DESC 'AOL Instant Messenger (AIM) Identity'
# SYNTAX 2.16.840.1.113730.3.7.1 )
attributetype ( 1.3.6.1.4.1.13769.2.1.96
NAME ( 'mozillaCustom1' )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.2.1.97
NAME ( 'mozillaCustom2' )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.2.1.98
NAME ( 'mozillaCustom3' )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.13769.2.1.99
NAME ( 'mozillaCustom4' )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
# defined in "A Summary of the X.500(96) User Schema for use with LDAPv3" - RFC 2256
#
# attributetype ( 2.5.4.6 NAME ( 'c' 'countryName' )
# DESC 'RFC2256: ISO-3166 country 2-letter code'
# SUP name SINGLE-VALUE )
# defined in "The COSINE and Internet X.500 Schema" - RFC 1274
#
# attributetype ( 0.9.2342.19200300.100.1.43
# NAME ( 'co' 'friendlyCountryName' )
# DESC 'RFC1274: friendly country name'
# EQUALITY caseIgnoreMatch
# SUBSTR caseIgnoreSubstringsMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
# objectClass defs
objectclass ( 1.3.6.1.4.1.13769.2.2.1
NAME 'mozillaOrgPerson'
SUP top
AUXILIARY
MAY (
sn $
givenName $
cn $
displayName $
mozillaNickname $
title $
telephoneNumber $
facsimileTelephoneNumber $
mobile $
pager $
homePhone $
street $
postalCode $
mozillaPostalAddress2 $
mozillaHomeStreet $
mozillaHomePostalAddress2 $
l $
mozillaHomeLocalityName $
st $
mozillaHomeState $
mozillaHomePostalCode $
c $
mozillaHomeCountryName $
co $
mozillaHomeFriendlyCountryName $
ou $
o $
mail $
mozillaSecondEmail $
mozillaUseHtmlMail $
nsAIMid $
mozillaHomeUrl $
mozillaWorkUrl $
description $
mozillaCustom1 $
mozillaCustom2 $
mozillaCustom3 $
mozillaCustom4 ) )
# not part of the official Mozilla schema but read by Mozilla: 'departmentNumber' and 'postOfficeBox'
#

View File

@ -1,17 +1,15 @@
<?php
/**************************************************************************\
* eGroupWare - Adressbook - General business object *
* http://www.egroupware.org *
* Written and (c) 2005 by Cornelius_weiss <egw@von-und-zu-weiss.de> *
* and Ralf Becker <RalfBecker-AT-outdoor-training.de> *
* ------------------------------------------------------------------------ *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
/**
* Addressbook - General business object
*
* @link http://www.egroupware.org
* @author Cornelius Weiss <egw@von-und-zu-weiss.de>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook
* @copyright (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de> and Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.socontacts.inc.php');

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,21 @@
<?php
/**************************************************************************\
* eGroupWare - Adressbook - General storage object *
* http://www.egroupware.org *
* Written and (c) 2005 by Cornelius_weiss <egw@von-und-zu-weiss.de> *
* and Ralf Becker <RalfBecker-AT-outdoor-training.de> *
* ------------------------------------------------------------------------ *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
/**
* Addressbook - General storage object
*
* @link http://www.egroupware.org
* @author Cornelius Weiss <egw-AT-von-und-zu-weiss.de>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook
* @copyright (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de> and Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
/**
* General storage object of the adressbook
*
* @package addressbook
* @author Cornelius Weiss <egw@von-und-zu-weiss.de>
* @author Cornelius Weiss <egw-AT-von-und-zu-weiss.de>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de> and Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
@ -26,90 +24,130 @@
class socontacts
{
/**
* @var string $extra_table name of customefields table
* name of customefields table
*
* @var string
*/
var $extra_table = 'egw_addressbook_extra';
/**
* @var string $extra_id
* @var string
*/
var $extra_id = 'contact_id';
/**
* @var string $extra_owner
* @var string
*/
var $extra_owner = 'contact_owner';
/**
* @var string $extra_key
* @var string
*/
var $extra_key = 'contact_name';
/**
* @var string $extra_value
* @var string
*/
var $extra_value = 'contact_value';
/**
* @var string $contacts_repository 'sql' or 'ldap'
* Contact repository in 'sql' or 'ldap'
*
* @var string
*/
var $contacts_repository = 'sql';
var $contact_repository = 'sql';
/**
* @var array $grants account_id => rights pairs
* Grants as account_id => rights pairs
*
* @var array
*/
var $grants;
/**
* @var int $user userid of current user
*/
* userid of current user
*
* @var int $user
*/
var $user;
/**
* @var array $memberships of the current user
* memberships of the current user
*
* @var array
*/
var $memberships;
/**
* @var array $columns_to_search when we search for a single pattern
* columns to search, if we search for a single pattern
*
* @var array
*/
var $columns_to_search = array();
/**
* @var array $account_extra_search extra columns to search if accounts are included, eg. account_lid
* extra columns to search if accounts are included, eg. account_lid
*
* @var array
*/
var $account_extra_search = array();
/**
* columns to search for accounts, if stored in different repository
*
* @var array
*/
var $account_cols_to_search = array();
/**
* @var array $customfields name => array(...) pairs
* customfields name => array(...) pairs
*
* @var array
*/
var $customfields = array();
/**
* @var array $content_types name => array(...) pairs
* content-types as name => array(...) pairs
*
* @var array
*/
var $content_types = array();
/**
* @var int $total total number of matches of last search
* total number of matches of last search
*
* @var int
*/
var $total;
/**
* @var object $somain sql (socontacts_sql) or ldap (so_ldap) backend class
* storage object: sql (socontacts_sql) or ldap (so_ldap) backend class
*
* @var object
*/
var $somain;
/**
* @var so_sql-object $soextra custom fields backend
* storage object for accounts, if not identical to somain (eg. accounts in ldap, contacts in sql)
*
* @var object
*/
var $so_accounts;
/**
* account repository sql or ldap
*
* @var string
*/
var $account_repository = 'sql';
/**
* custom fields backend
*
* @var so_sql-object
*/
var $soextra;
function socontacts($contact_app='addressbook')
{
$this->user = $GLOBALS['egw_info']['user']['account_id'];
foreach($GLOBALS['egw']->accounts->membership($this->user) as $group)
{
$this->memberships[] = $group['account_id'];
}
$this->memberships = $GLOBALS['egw']->accounts->memberships($this->user,true);
// contacts backend
if($GLOBALS['egw_info']['server']['contact_repository'] == 'ldap')
{
$this->contact_repository = 'ldap';
@ -124,7 +162,6 @@ class socontacts
// LDAP uses a limited set for performance reasons, you NEED an index for that columns, ToDo: make it configurable
// minimum: $this->columns_to_search = array('n_family','n_given','org_name');
$this->columns_to_search = array('n_family','n_middle','n_given','org_name','org_unit','adr_one_location','adr_two_location','note');
$this->account_extra_search = array('uid');
}
else
{
@ -136,7 +173,40 @@ class socontacts
$this->columns_to_search = array_diff(array_values($this->somain->db_cols),array('jpegphoto','owner','tid',
'private','id','cat_id','modified','modifier','creator','created','tz'));
$this->columns_to_search[] = $this->extra_value; // custome fields from extra_table
$this->account_extra_search = array('account_firstname','account_lastname','account_email','account_lid');
}
// account backend
if ($GLOBALS['egw_info']['server']['account_repository'])
{
$this->account_repository = $GLOBALS['egw_info']['server']['account_repository'];
}
elseif ($GLOBALS['egw_info']['server']['auth_type'])
{
$this->account_repository = $GLOBALS['egw_info']['server']['auth_type'];
}
if ($this->account_repository == 'ldap')
{
if ($this->account_repository != $this->contact_repository)
{
$this->so_accounts =& CreateObject('addressbook.so_ldap');
$this->so_accounts->contacts_id = 'id';
$this->account_cols_to_search = array('uid','n_family','n_middle','n_given','org_name','org_unit','adr_one_location','adr_two_location','note');
}
else
{
$this->account_extra_search = array('uid');
}
}
else
{
if ($this->account_repository != $this->contact_repository)
{
// contacts in ldap & accounts in sql is not tested or supported at the moment!!!
$this->so_accounts =& CreateObject('addressbook.socontacts_sql','addressbook','egw_addressbook',null,'contact_');
}
else
{
$this->account_extra_search = array('account_firstname','account_lastname','account_email','account_lid');
}
}
// add grants for accounts: admin --> everything, everyone --> read
$this->grants[0] = EGW_ACL_READ; // everyone read access
@ -149,7 +219,6 @@ class socontacts
// ToDo: it should be the other way arround, the backend should set the grants it uses
$this->somain->grants =& $this->grants;
$this->total =& $this->somain->total;
$this->somain->contacts_id = 'id';
$this->soextra =& CreateObject('etemplate.so_sql');
$this->soextra->so_sql('addressbook',$this->extra_table);
@ -195,8 +264,6 @@ class socontacts
*/
function db2data($data)
{
// do the necessare changes here
return $data;
}
@ -210,8 +277,6 @@ class socontacts
*/
function data2db($data)
{
// do the necessary changes here
return $data;
}
@ -245,9 +310,20 @@ class socontacts
function save(&$contact)
{
// save mainfields
$this->somain->data = $this->data2db($contact);
$error_nr = $this->somain->save();
$contact['id'] = $this->somain->data['id'];
if ($contact['id'] && $this->contact_repository != $this->account_repository && is_object($this->so_accounts) &&
($this->contact_repository == 'sql' && !is_numeric($contact['id']) ||
$this->contact_repository == 'ldap' && is_numeric($contact['id'])))
{
$this->so_accounts->data = $this->data2db($contact);
$error_nr = $this->so_accounts->save();
$contact['id'] = $this->so_accounts->data['id'];
}
else
{
$this->somain->data = $this->data2db($contact);
$error_nr = $this->somain->save();
$contact['id'] = $this->somain->data['id'];
}
if($error_nr) return $error_nr;
// save customfields
@ -283,7 +359,8 @@ class socontacts
function read($contact_id)
{
// read main data
if (!($contact = $this->somain->read($contact_id)))
$backend =& $this->get_backend($contact_id);
if (!($contact = $backend->read($contact_id)))
{
return $contact;
}
@ -517,6 +594,7 @@ class socontacts
{
//echo "<p>socontacts::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')</p>\n";
$backend =& $this->get_backend(null,$filter['owner']);
// single string to search for --> create so_sql conformant search criterial for the standard search columns
if ($criteria && !is_array($criteria))
{
@ -524,10 +602,18 @@ class socontacts
$wildcard = '%';
$search = $criteria;
$criteria = array();
$cols = $this->columns_to_search;
if (!$filter['owner']) // extra columns for search if accounts are included, eg. account_lid
if ($backend === $this->somain)
{
$cols = array_merge($cols,$this->account_extra_search);
$cols = $this->columns_to_search;
if (!$filter['owner']) // extra columns for search if accounts are included, eg. account_lid
{
$cols = array_merge($cols,$this->account_extra_search);
}
}
else
{
$cols = $this->account_cols_to_search;
}
foreach($cols as $col)
{
@ -546,8 +632,10 @@ class socontacts
{
$filter = $filter ? array($filter) : array();
}
$rows =& $this->somain->search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
// get the used backend for the search and call it's search method
$rows = $backend->search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
$this->total = $backend->total;
if ($rows)
{
foreach($rows as $n => $row)
@ -658,4 +746,57 @@ class socontacts
),__LINE__,__FILE__);
}
}
/**
* return the backend, to be used for the given $contact_id
*
* @param mixed $contact_id=null
* @param int $owner=null account_id of owner or 0 for accounts
* @return object
*/
function &get_backend($contact_id=null,$owner=null)
{
if ($this->contact_repository != $this->account_repository && is_object($this->so_accounts) &&
(!is_null($owner) && !$owner || !is_null($contact_id) &&
($this->contact_repository == 'sql' && !is_numeric($contact_id) ||
$this->contact_repository == 'ldap' && is_numeric($contact_id))))
{
return $this->so_accounts;
}
return $this->somain;
}
/**
* Returns the supported, all or unsupported fields of the backend (depends on owner or contact_id)
*
* @param sting $type='all' 'supported', 'unsupported' or 'all'
* @param mixed $contact_id=null
* @param int $owner=null account_id of owner or 0 for accounts
* @return array with eGW contact field names
*/
function get_fields($type='all',$contact_id=null,$owner=null)
{
$def = $this->soextra->db->get_table_definitions('addressbook','egw_addressbook');
$all_fields = array();
foreach($def['fd'] as $field => $data)
{
$all_fields[] = substr($field,0,8) == 'contact_' ? substr($field,8) : $field;
}
if ($type == 'all')
{
return $all_fields;
}
$backend =& $this->get_backend($contact_id,$owner);
$supported_fields = method_exists($backend,supported_fields) ? $backend->supported_fields() : $all_fields;
//echo "supported fields=";_debug_array($supported_fields);
if ($type == 'supported')
{
return $supported_fields;
}
//echo "unsupported fields=";_debug_array(array_diff($all_fields,$supported_fields));
return array_diff($all_fields,$supported_fields);
}
}

View File

@ -1,16 +1,14 @@
<?php
/**************************************************************************\
* eGroupWare - Adressbook - SQL storage object *
* http://www.egroupware.org *
* Written and (c) 2006 by Ralf Becker <RalfBecker-AT-outdoor-training.de> *
* ------------------------------------------------------------------------ *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
/**
* Addressbook - SQL backend
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook
* @copyright (c) 2006 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php');
@ -28,6 +26,21 @@ class socontacts_sql extends so_sql
var $accounts_table = 'egw_accounts';
var $accounts_join = ' JOIN egw_accounts ON person_id=egw_addressbook.contact_id';
var $extra_join = ' LEFT JOIN egw_addressbook_extra ON egw_addressbook.contact_id=egw_addressbook_extra.contact_id';
var $account_repository = 'sql';
function socontacts_sql($app='',$table='',$db=null,$column_prefix='')
{
$this->so_sql($app,$table,$db,$column_prefix); // calling the constructor of the extended class
if ($GLOBALS['egw_info']['server']['account_repository'])
{
$this->account_repository = $GLOBALS['egw_info']['server']['account_repository'];
}
elseif ($GLOBALS['egw_info']['server']['auth_type'])
{
$this->account_repository = $GLOBALS['egw_info']['server']['auth_type'];
}
}
/**
* Query organisations by given parameters
@ -215,7 +228,7 @@ class socontacts_sql extends so_sql
implode(',',array_keys($this->grants)).") OR $this->table_name.contact_owner IS NULL)";
}
}
if (!$owner) // owner not set (=all) or 0 --> include accounts
if (!$owner && $this->account_repository == 'sql') // owner not set (=all) or 0 --> include accounts
{
if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array();
$accounts2contacts = array(
@ -289,27 +302,30 @@ class socontacts_sql extends so_sql
unset($filter['owner']);
}
}
if (is_null($owner)) // search for accounts AND contacts of all addressbooks
if (!$this->account_repository == 'sql')
{
/* only enable that after testing with postgres, I dont want to break more postgres stuff ;-)
if ($this->db->capabilities['outer_join'])
if (is_null($owner)) // search for accounts AND contacts of all addressbooks
{
$join = 'OUTER'.$this->accounts_join.' '.$join;
/* only enable that after testing with postgres, I dont want to break more postgres stuff ;-)
if ($this->db->capabilities['outer_join'])
{
$join = 'OUTER'.$this->accounts_join.' '.$join;
}
else */ // simulate the outer join with a union
{
parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,'UNION',$filter,
'LEFT'.$this->accounts_join.$join,$need_full_no_count);
$filter[] = '(person_id=0 OR person_id IS NULL)'; // unfortunally both is used in eGW
parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,'UNION',$filter,
'RIGHT'.$this->accounts_join.$join,$need_full_no_count);
}
}
else */ // simulate the outer join with a union
elseif (!$owner) // search for accounts only
{
parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,'UNION',$filter,
'LEFT'.$this->accounts_join.$join,$need_full_no_count);
$filter[] = '(person_id=0 OR person_id IS NULL)'; // unfortunally both is used in eGW
parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,'UNION',$filter,
'RIGHT'.$this->accounts_join.$join,$need_full_no_count);
$join = ' RIGHT'.$this->accounts_join.$join;
$filter[] = "account_type='u'"; // no groups
}
}
elseif (!$owner) // search for accounts only
{
$join = ' RIGHT'.$this->accounts_join.$join;
$filter[] = "account_type='u'"; // no groups
}
return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
}

View File

@ -1,17 +1,15 @@
<?php
/**************************************************************************\
* eGroupWare - Adressbook - General user interface object *
* http://www.egroupware.org *
* Written and (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de> *
* and Ralf Becker <RalfBecker-AT-outdoor-training.de> *
* ------------------------------------------------------------------------ *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
/**
* Addressbook - user interface
*
* @link www.egroupware.org
* @author Cornelius Weiss <egw@von-und-zu-weiss.de>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de> and Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.bocontacts.inc.php');
@ -424,7 +422,7 @@ class uicontacts extends bocontacts
}
else // dont show contacts with empty order criteria
{
$query['col_filter'][] = $query['order']."!=''";
$query['col_filter'][$query['order']] = "!''";
}
$rows = parent::search($query['search'],$id_only ? array('id','org_name','n_family','n_given','n_fileas') : false,
$order,'','%',false,'OR',array((int)$query['start'],(int) $query['num_rows']),$query['col_filter']);
@ -833,6 +831,11 @@ class uicontacts extends bocontacts
$readonlys['owner'] = !$content['owner'] || // dont allow to move accounts, as this mean deleting the user incl. all content he owns
!$this->check_perms(EGW_ACL_DELETE,$content); // you need delete rights to move a contact into an other addressbook
}
// set the unsupported fields from the backend to readonly
foreach($this->get_fields('unsupported',$content['id'],$content['owner']) as $field)
{
$readonlys[$field] = true;
}
for($i = -23; $i<=23; $i++) $tz[$i] = ($i > 0 ? '+' : '').$i;
$sel_options['tz'] = $tz;
$content['tz'] = $content['tz'] ? $content['tz'] : 0;
@ -1169,7 +1172,7 @@ $readonlys['button[vcard]'] = true;
if (!ob_get_contents())
{
header('Content-type: image/jpeg');
header('Content-length: '.(extension_loaded(mbstring) ? mb_strlen($contact['jpeg_photo'],'ascii') : strlen($contact['jpeg_photo'])));
header('Content-length: '.(extension_loaded(mbstring) ? mb_strlen($contact['jpegphoto'],'ascii') : strlen($contact['jpegphoto'])));
echo $contact['jpegphoto'];
exit;
}