2005-11-04 00:47:52 +01:00
< ? php
2006-06-13 06:30:16 +02:00
/**
* 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 $
*/
2005-11-04 00:47:52 +01:00
/**
* General storage object of the adressbook
2008-04-22 08:09:02 +02:00
*
2006-06-17 20:50:07 +02:00
* The contact storage has 3 operation modi ( contact_repository ) :
* - sql : contacts are stored in the SQL table egw_addressbook & egw_addressbook_extra ( custom fields )
* - ldap : contacts are stored in LDAP ( accounts have to be stored in LDAP too !!! ) .
* Custom fields are not availible in that case !
* - sql - ldap : contacts are read and searched in SQL , but saved to both SQL and LDAP .
* Other clients ( Thunderbird , ... ) can use LDAP readonly . The get maintained via eGroupWare only .
2008-04-22 08:09:02 +02:00
*
2006-06-17 20:50:07 +02:00
* The accounts can be stored in SQL or LDAP too ( account_repository ) :
* If the account - repository is different from the contacts - repository , the filter all ( no owner set )
* will only search the accounts and NOT the contacts ! Only the filter accounts ( owner = 0 ) shows accounts .
2008-04-22 08:09:02 +02:00
*
2006-06-17 20:50:07 +02:00
* If sql - ldap is used as contact - storage ( LDAP is managed from eGroupWare ) the filter all , searches
* the accounts in the SQL contacts - table too . Change in made in LDAP , are not detected in that case !
2005-11-04 00:47:52 +01:00
*
2005-11-10 13:22:55 +01:00
* @ package addressbook
2006-06-13 06:30:16 +02:00
* @ author Cornelius Weiss < egw - AT - von - und - zu - weiss . de >
2006-04-23 16:40:31 +02:00
* @ 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 >
2005-11-04 00:47:52 +01:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
*/
class socontacts
{
/**
2006-06-13 06:30:16 +02:00
* name of customefields table
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var string
2005-11-04 00:47:52 +01:00
*/
2005-11-13 13:05:35 +01:00
var $extra_table = 'egw_addressbook_extra' ;
2008-01-31 13:52:43 +01:00
2005-11-04 00:47:52 +01:00
/**
2006-06-13 06:30:16 +02:00
* @ var string
2005-11-04 00:47:52 +01:00
*/
var $extra_id = 'contact_id' ;
2008-04-22 08:09:02 +02:00
2005-11-04 00:47:52 +01:00
/**
2006-06-13 06:30:16 +02:00
* @ var string
2005-11-04 00:47:52 +01:00
*/
var $extra_owner = 'contact_owner' ;
/**
2006-06-13 06:30:16 +02:00
* @ var string
2005-11-04 00:47:52 +01:00
*/
var $extra_key = 'contact_name' ;
2008-04-22 08:09:02 +02:00
2005-11-04 00:47:52 +01:00
/**
2006-06-13 06:30:16 +02:00
* @ var string
2005-11-04 00:47:52 +01:00
*/
var $extra_value = 'contact_value' ;
2008-04-22 08:09:02 +02:00
2008-01-31 13:52:43 +01:00
/**
* view for distributionlistsmembership
2008-04-22 08:09:02 +02:00
*
2008-01-31 13:52:43 +01:00
* @ var string
*/
2008-04-22 08:09:02 +02:00
var $distributionlist_view = '(SELECT contact_id, egw_addressbook_lists.list_id as list_id, egw_addressbook_lists.list_name as list_name, egw_addressbook_lists.list_owner as list_owner FROM egw_addressbook_lists, egw_addressbook2list where egw_addressbook_lists.list_id=egw_addressbook2list.list_id) d_view ' ;
2008-01-31 13:52:43 +01:00
/**
* @ var string
*/
var $distri_id = 'contact_id' ;
2008-04-22 08:09:02 +02:00
2008-01-31 13:52:43 +01:00
/**
* @ var string
*/
var $distri_owner = 'list_owner' ;
/**
* @ var string
*/
var $distri_key = 'list_id' ;
2008-04-22 08:09:02 +02:00
2008-01-31 13:52:43 +01:00
/**
* @ var string
*/
var $distri_value = 'list_name' ;
2006-04-23 16:40:31 +02:00
/**
2006-06-13 06:30:16 +02:00
* Contact repository in 'sql' or 'ldap'
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var string
2006-04-23 16:40:31 +02:00
*/
2006-06-13 06:30:16 +02:00
var $contact_repository = 'sql' ;
2008-04-22 08:09:02 +02:00
2006-04-23 16:40:31 +02:00
/**
2006-06-13 06:30:16 +02:00
* Grants as account_id => rights pairs
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var array
2006-04-23 16:40:31 +02:00
*/
var $grants ;
/**
2006-06-13 06:30:16 +02:00
* userid of current user
2008-04-22 08:09:02 +02:00
*
2006-08-29 06:16:00 +02:00
* @ var int
2006-06-13 06:30:16 +02:00
*/
2006-04-23 16:40:31 +02:00
var $user ;
2008-04-22 08:09:02 +02:00
2006-04-23 16:40:31 +02:00
/**
2006-06-13 06:30:16 +02:00
* memberships of the current user
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var array
2006-04-23 16:40:31 +02:00
*/
var $memberships ;
2008-04-22 08:09:02 +02:00
2006-06-24 07:57:13 +02:00
/**
2008-04-22 08:09:02 +02:00
* LDAP searches only a limited set of attributes for performance reasons ,
2006-06-24 07:57:13 +02:00
* you NEED an index for that columns , ToDo : make it configurable
* minimum : $this -> columns_to_search = array ( 'n_family' , 'n_given' , 'org_name' , 'email' );
*/
var $ldap_search_attributes = array (
'n_family' , 'n_middle' , 'n_given' , 'org_name' , 'org_unit' ,
'adr_one_location' , 'adr_two_location' , 'note' ,
'email' , 'mozillasecondemail' ,
);
/**
* In SQL we can search all columns , though a view make on real sense
*/
var $sql_cols_not_to_search = array (
'jpegphoto' , 'owner' , 'tid' , 'private' , 'id' , 'cat_id' ,
'modified' , 'modifier' , 'creator' , 'created' , 'tz' , 'account_id' ,
);
2006-04-23 16:40:31 +02:00
/**
2006-06-13 06:30:16 +02:00
* columns to search , if we search for a single pattern
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var array
2006-04-23 16:40:31 +02:00
*/
var $columns_to_search = array ();
/**
2006-06-13 06:30:16 +02:00
* extra columns to search if accounts are included , eg . account_lid
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var array
2006-04-23 16:40:31 +02:00
*/
var $account_extra_search = array ();
2006-06-13 06:30:16 +02:00
/**
* columns to search for accounts , if stored in different repository
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var array
*/
var $account_cols_to_search = array ();
2008-04-22 08:09:02 +02:00
2006-04-23 16:40:31 +02:00
/**
2006-06-13 06:30:16 +02:00
* customfields name => array ( ... ) pairs
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var array
2006-04-23 16:40:31 +02:00
*/
var $customfields = array ();
/**
2006-06-13 06:30:16 +02:00
* content - types as name => array ( ... ) pairs
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var array
2006-04-23 16:40:31 +02:00
*/
var $content_types = array ();
2008-04-22 08:09:02 +02:00
2006-04-24 22:52:14 +02:00
/**
2006-06-13 06:30:16 +02:00
* total number of matches of last search
2008-04-22 08:09:02 +02:00
*
2006-06-13 06:30:16 +02:00
* @ var int
2006-04-24 22:52:14 +02:00
*/
var $total ;
2008-04-22 08:09:02 +02:00
2006-04-30 11:34:24 +02:00
/**
2006-06-13 06:30:16 +02:00
* storage object : sql ( socontacts_sql ) or ldap ( so_ldap ) backend class
2008-04-22 08:09:02 +02:00
*
2006-08-29 06:16:00 +02:00
* @ var socontacts_sql
2006-04-30 11:34:24 +02:00
*/
var $somain ;
/**
2006-06-13 06:30:16 +02:00
* storage object for accounts , if not identical to somain ( eg . accounts in ldap , contacts in sql )
*
2006-08-29 06:16:00 +02:00
* @ var so_ldap
2006-06-13 06:30:16 +02:00
*/
var $so_accounts ;
/**
* account repository sql or ldap
*
* @ var string
*/
var $account_repository = 'sql' ;
/**
* custom fields backend
2008-04-22 08:09:02 +02:00
*
2006-08-29 06:16:00 +02:00
* @ var so_sql
2006-04-30 11:34:24 +02:00
*/
var $soextra ;
2008-01-31 13:52:43 +01:00
var $sodistrib_list ;
var $backend ;
2008-04-22 08:09:02 +02:00
2005-11-04 00:47:52 +01:00
function socontacts ( $contact_app = 'addressbook' )
{
2008-03-13 21:18:52 +01:00
$this -> db = $GLOBALS [ 'egw' ] -> db ;
2008-01-31 13:52:43 +01:00
2006-04-23 16:40:31 +02:00
$this -> user = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
2006-06-13 06:30:16 +02:00
$this -> memberships = $GLOBALS [ 'egw' ] -> accounts -> memberships ( $this -> user , true );
2006-04-23 16:40:31 +02:00
2006-06-17 20:50:07 +02:00
// account backend used
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' ];
}
// contacts backend (contacts in LDAP require accounts in LDAP!)
if ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'contact_repository' ] == 'ldap' && $this -> account_repository == 'ldap' )
2005-11-04 00:47:52 +01:00
{
2006-04-23 16:40:31 +02:00
$this -> contact_repository = 'ldap' ;
2006-06-17 20:50:07 +02:00
$this -> somain =& CreateObject ( 'addressbook.so_ldap' );
2006-04-23 16:40:31 +02:00
2006-07-08 23:38:54 +02:00
if ( $this -> user ) // not set eg. in setup
2006-04-23 16:40:31 +02:00
{
2006-07-08 23:38:54 +02:00
// static grants from ldap: all rights for the own personal addressbook and the group ones of the meberships
$this -> grants = array ( $this -> user => ~ 0 );
foreach ( $this -> memberships as $gid )
{
$this -> grants [ $gid ] = ~ 0 ;
}
2006-04-23 16:40:31 +02:00
}
2006-06-24 07:57:13 +02:00
$this -> columns_to_search = $this -> ldap_search_attributes ;
2005-11-04 00:47:52 +01:00
}
2006-06-17 20:50:07 +02:00
else // sql or sql->ldap
2005-11-04 00:47:52 +01:00
{
2006-06-17 20:50:07 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'contact_repository' ] == 'sql-ldap' )
{
$this -> contact_repository = 'sql-ldap' ;
}
$this -> somain =& CreateObject ( 'addressbook.socontacts_sql' );
2006-07-08 23:38:54 +02:00
if ( $this -> user ) // not set eg. in setup
2008-04-22 08:09:02 +02:00
{
// group grants are now grants for the group addressbook and NOT grants for all its members,
2006-07-08 23:38:54 +02:00
// therefor the param false!
$this -> grants = $GLOBALS [ 'egw' ] -> acl -> get_grants ( $contact_app , false );
}
2006-04-23 16:40:31 +02:00
// remove some columns, absolutly not necessary to search in sql
2006-06-24 07:57:13 +02:00
$this -> columns_to_search = array_diff ( array_values ( $this -> somain -> db_cols ), $this -> sql_cols_not_to_search );
2006-06-13 06:30:16 +02:00
}
2006-06-17 20:50:07 +02:00
if ( $this -> account_repository == 'ldap' && $this -> contact_repository == 'sql' )
2006-06-13 06:30:16 +02:00
{
if ( $this -> account_repository != $this -> contact_repository )
{
$this -> so_accounts =& CreateObject ( 'addressbook.so_ldap' );
2008-04-22 08:09:02 +02:00
$this -> account_cols_to_search = $this -> ldap_search_attributes ;
2006-06-13 06:30:16 +02:00
}
else
{
$this -> account_extra_search = array ( 'uid' );
}
}
2008-04-22 08:09:02 +02:00
// add grants for accounts: if account_selection not in ('none','groupmembers'): everyone has read access,
2007-04-15 15:06:21 +02:00
// if he has not set the hide_accounts preference
2006-08-22 18:50:32 +02:00
// ToDo: be more specific for 'groupmembers', they should be able to see the groupmembers
2007-04-30 17:18:29 +02:00
if ( ! in_array ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'account_selection' ], array ( 'none' , 'groupmembers' )))
2006-08-22 18:50:32 +02:00
{
$this -> grants [ 0 ] = EGW_ACL_READ ;
}
// add account grants for admins
2006-09-15 09:16:07 +02:00
if ( $this -> is_admin ()) // admin rights can be limited by ACL!
2006-04-23 16:40:31 +02:00
{
2006-08-22 18:50:32 +02:00
$this -> grants [ 0 ] = EGW_ACL_READ ; // admins always have read-access
2006-04-23 16:40:31 +02:00
if ( ! $GLOBALS [ 'egw' ] -> acl -> check ( 'account_access' , 16 , 'admin' )) $this -> grants [ 0 ] |= EGW_ACL_EDIT ;
// no add at the moment if (!$GLOBALS['egw']->acl->check('account_access',4,'admin')) $this->grants[0] |= EGW_ACL_ADD;
if ( ! $GLOBALS [ 'egw' ] -> acl -> check ( 'account_access' , 32 , 'admin' )) $this -> grants [ 0 ] |= EGW_ACL_DELETE ;
2008-04-22 08:09:02 +02:00
}
2006-04-23 16:40:31 +02:00
// ToDo: it should be the other way arround, the backend should set the grants it uses
$this -> somain -> grants =& $this -> grants ;
2008-01-19 06:41:04 +01:00
$this -> soextra = new so_sql ( 'phpgwapi' , $this -> extra_table );
2008-04-22 08:09:02 +02:00
2008-01-19 06:41:04 +01:00
$this -> customfields = config :: get_customfields ( 'addressbook' );
$this -> content_types = config :: get_content_types ( 'addressbook' );
2006-04-25 14:43:41 +02:00
if ( ! $this -> content_types )
{
$this -> content_types = $custom -> content_types = array ( 'n' => array (
'name' => 'contact' ,
'options' => array (
'template' => 'addressbook.edit' ,
'icon' => 'navbar.png'
)));
}
2005-11-04 00:47:52 +01:00
}
2008-04-22 08:09:02 +02:00
2006-09-15 09:16:07 +02:00
/**
* Check if the user is an admin ( can unconditionally edit accounts )
2008-04-22 08:09:02 +02:00
*
2006-09-15 09:16:07 +02:00
* We check now the admin ACL for edit users , as the admin app does it for editing accounts .
*
* @ param array $contact = null for future use , where admins might not be admins for all accounts
* @ return boolean
*/
function is_admin ( $contact = null )
{
return isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ]) && ! $GLOBALS [ 'egw' ] -> acl -> check ( 'account_access' , 16 , 'admin' );
}
2008-04-22 08:09:02 +02:00
2006-04-23 16:40:31 +02:00
/**
* Read all customfields of the given id ' s
*
* @ param int / array $ids
2008-03-30 10:53:40 +02:00
* @ param array $field_names = null custom fields to read , default all
2006-04-23 16:40:31 +02:00
* @ return array id => name => value
*/
2008-03-30 10:53:40 +02:00
function read_customfields ( $ids , $field_names = null )
2006-04-23 16:40:31 +02:00
{
2006-07-08 02:36:23 +02:00
if ( $this -> contact_repository == 'ldap' )
{
return array (); // ldap does not support custom-fields (non-nummeric uid)
}
2008-04-02 10:24:27 +02:00
if ( is_null ( $field_names )) $field_names = array_keys ( $this -> customfields );
2008-03-30 10:53:40 +02:00
2006-06-17 20:50:07 +02:00
foreach ( $ids as $key => $id )
{
if ( ! ( int ) $id ) unset ( $ids [ $key ]);
}
2008-03-30 10:53:40 +02:00
if ( ! $ids || ! $field_names ) return array (); // nothing to do, eg. all these contacts are in ldap
2006-06-17 20:50:07 +02:00
2006-04-23 16:40:31 +02:00
$fields = array ();
2008-01-19 06:41:04 +01:00
foreach (( array ) $this -> soextra -> search ( array (
$this -> extra_id => $ids ,
2008-03-30 10:53:40 +02:00
$this -> extra_key => $field_names ,
2008-01-19 06:41:04 +01:00
), false ) as $data )
2006-04-23 16:40:31 +02:00
{
if ( $data ) $fields [ $data [ $this -> extra_id ]][ $data [ $this -> extra_key ]] = $data [ $this -> extra_value ];
}
return $fields ;
}
2008-01-31 13:52:43 +01:00
/**
* Read all distributionlists of the given id ' s
*
* @ param int / array $ids
* @ return array id => name => value
*/
function read_distributionlist ( $ids , $dl_allowed = array ())
{
if ( $this -> contact_repository == 'ldap' )
{
return array (); // ldap does not support distributionlists
}
foreach ( $ids as $key => $id )
{
if ( ! ( int ) $id ) unset ( $ids [ $key ]);
}
if ( ! $ids ) return array (); // nothing to do, eg. all these contacts are in ldap
$fields = array ();
$filter [ $this -> distri_id ] = $ids ;
if ( count ( $dl_allowed )) $filter [ $this -> distri_key ] = $dl_allowed ;
2008-03-13 21:18:52 +01:00
foreach ( $this -> db -> select ( $this -> distributionlist_view , '*' , $filter , __LINE__ , __FILE__ ) as $row )
2008-01-31 13:52:43 +01:00
{
if (( isset ( $row [ $this -> distri_id ]) && strlen ( $row [ $this -> distri_value ]) > 0 ))
{
$fields [ $row [ $this -> distri_id ]][ $row [ $this -> distri_key ]] = $row [ $this -> distri_value ] . ' (' . $GLOBALS [ 'egw' ] -> common -> grab_owner_name ( $row [ $this -> distri_owner ]) . ')' ;
}
}
return $fields ;
}
2008-04-22 08:09:02 +02:00
2006-03-07 23:43:08 +01:00
/**
* changes the data from the db - format to your work - format
*
* it gets called everytime when data is read from the db
* This function needs to be reimplemented in the derived class
*
2008-04-22 08:09:02 +02:00
* @ param array $data
2006-03-07 23:43:08 +01:00
*/
function db2data ( $data )
{
return $data ;
}
/**
* changes the data from your work - format to the db - format
*
* It gets called everytime when data gets writen into db or on keys for db - searches
* this needs to be reimplemented in the derived class
*
* @ param array $data
*/
function data2db ( $data )
{
return $data ;
}
2005-11-04 00:47:52 +01:00
/**
* deletes contact entry including custom fields
*
2006-06-17 20:50:07 +02:00
* @ param mixed $contact array with id or just the id
2008-05-06 21:58:15 +02:00
* @ param int $check_etag = null
* @ return boolean | int true on success or false on failiure , 0 if etag does not match
2005-11-04 00:47:52 +01:00
*/
2008-05-06 21:58:15 +02:00
function delete ( $contact , $check_etag = null )
2005-11-04 00:47:52 +01:00
{
2006-04-23 16:40:31 +02:00
if ( is_array ( $contact )) $contact = $contact [ 'id' ];
2008-05-06 21:58:15 +02:00
$where = array ( 'id' => $contact );
if ( $check_etag ) $where [ 'etag' ] = $check_etag ;
2005-11-04 00:47:52 +01:00
// delete mainfields
2008-05-06 21:58:15 +02:00
if ( $this -> somain -> delete ( $where ))
2008-04-22 08:09:02 +02:00
{
2006-03-28 13:41:48 +02:00
// delete customfields, can return 0 if there are no customfields
2006-04-23 16:40:31 +02:00
$this -> soextra -> delete ( array ( $this -> extra_id => $contact ));
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
// delete from distribution list(s)
$this -> remove_from_list ( $contact );
2006-06-17 20:50:07 +02:00
if ( $this -> contact_repository == 'sql-ldap' )
{
if ( $contact [ 'account_id' ])
{
2008-04-22 08:09:02 +02:00
// LDAP uses the uid attributes for the contact-id (dn),
2006-06-17 20:50:07 +02:00
// which need to be the account_lid for accounts!
2006-07-08 02:36:23 +02:00
$contact [ 'id' ] = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $contact [ 'account_id' ]);
2006-06-17 20:50:07 +02:00
}
ExecMethod ( 'addressbook.so_ldap.delete' , $contact );
}
2006-04-23 16:40:31 +02:00
return true ;
2006-03-28 13:41:48 +02:00
}
2008-05-06 21:58:15 +02:00
return $check_etag ? 0 : false ; // if etag given, we return 0 on failure, thought it could also mean the whole contact does not exist
2005-11-04 00:47:52 +01:00
}
2008-04-22 08:09:02 +02:00
2005-11-04 00:47:52 +01:00
/**
2008-04-22 08:09:02 +02:00
* saves contact data including custom fields
2005-11-04 00:47:52 +01:00
*
* @ param array & $contact contact data from etemplate :: exec
2006-09-20 06:30:13 +02:00
* @ return bool false on success , errornumber on failure
2005-11-04 00:47:52 +01:00
*/
function save ( & $contact )
{
// save mainfields
2006-06-13 06:30:16 +02:00
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
{
2006-07-08 02:36:23 +02:00
// contact_repository sql-ldap (accounts in ldap) the person_id is the uid (account_lid)
2008-04-22 08:09:02 +02:00
// for the sql write here we need to find out the existing contact_id
if ( $this -> contact_repository == 'sql-ldap' && $contact [ 'id' ] && ! is_numeric ( $contact [ 'id' ]) &&
2006-07-08 02:36:23 +02:00
$contact [ 'account_id' ] && ( $old = $this -> somain -> read ( array ( 'account_id' => $contact [ 'account_id' ]))))
{
$contact [ 'id' ] = $old [ 'id' ];
}
2006-06-13 06:30:16 +02:00
$this -> somain -> data = $this -> data2db ( $contact );
2008-04-22 08:09:02 +02:00
2006-06-17 20:50:07 +02:00
if ( ! ( $error_nr = $this -> somain -> save ()))
{
$contact [ 'id' ] = $this -> somain -> data [ 'id' ];
2008-04-26 10:46:44 +02:00
$contact [ 'uid' ] = $this -> somain -> data [ 'uid' ];
2008-04-25 21:06:15 +02:00
$contact [ 'etag' ] = $this -> somain -> data [ 'etag' ];
2006-06-17 20:50:07 +02:00
if ( $this -> contact_repository == 'sql-ldap' )
{
$data = $this -> somain -> data ;
if ( $contact [ 'account_id' ])
{
2008-04-22 08:09:02 +02:00
// LDAP uses the uid attributes for the contact-id (dn),
2006-06-17 20:50:07 +02:00
// which need to be the account_lid for accounts!
2006-07-08 02:36:23 +02:00
$data [ 'id' ] = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $contact [ 'account_id' ]);
2006-06-17 20:50:07 +02:00
}
ExecMethod ( 'addressbook.so_ldap.save' , $data );
}
}
2006-06-13 06:30:16 +02:00
}
2006-03-14 15:26:55 +01:00
if ( $error_nr ) return $error_nr ;
2006-09-20 06:30:13 +02:00
2005-11-04 00:47:52 +01:00
// save customfields
2006-04-23 16:40:31 +02:00
foreach (( array ) $this -> customfields as $field => $options )
2005-11-04 00:47:52 +01:00
{
2006-04-23 16:40:31 +02:00
if ( ! isset ( $contact [ '#' . $field ])) continue ;
2005-11-04 00:47:52 +01:00
$data = array (
2006-04-23 16:40:31 +02:00
$this -> extra_id => $contact [ 'id' ],
2005-11-04 00:47:52 +01:00
$this -> extra_owner => $contact [ 'owner' ],
2006-04-23 16:40:31 +02:00
$this -> extra_key => $field ,
2005-11-04 00:47:52 +01:00
);
2006-04-23 16:40:31 +02:00
if (( string ) $contact [ '#' . $field ] === '' ) // dont write empty values
{
$this -> soextra -> delete ( $data ); // just delete them, in case they were previously set
continue ;
}
$data [ $this -> extra_value ] = $contact [ '#' . $field ];
if (( $error_nr = $this -> soextra -> save ( $data )))
{
return $error_nr ;
}
2005-11-04 00:47:52 +01:00
}
2006-04-23 16:40:31 +02:00
return false ; // no error
2005-11-04 00:47:52 +01:00
}
2008-04-22 08:09:02 +02:00
2005-11-04 00:47:52 +01:00
/**
* reads contact data including custom fields
*
2006-04-24 22:52:14 +02:00
* @ param int / string $contact_id contact_id or 'a' . account_id
2005-11-04 00:47:52 +01:00
* @ return array / boolean data if row could be retrived else False
*/
function read ( $contact_id )
{
2006-07-08 02:36:23 +02:00
if ( ! is_array ( $contact_id ) && substr ( $contact_id , 0 , 8 ) == 'account:' )
2006-06-17 20:50:07 +02:00
{
2006-07-08 02:36:23 +02:00
$contact_id = array ( 'account_id' => ( int ) substr ( $contact_id , 8 ));
2006-06-17 20:50:07 +02:00
}
2005-11-04 00:47:52 +01:00
// read main data
2006-06-13 06:30:16 +02:00
$backend =& $this -> get_backend ( $contact_id );
if ( ! ( $contact = $backend -> read ( $contact_id )))
2006-03-07 23:43:08 +01:00
{
return $contact ;
}
2006-07-08 02:36:23 +02:00
// try reading customfields only if we have some (none for LDAP!)
if ( $this -> customfields && $this -> contact_repository != 'ldap' )
2005-11-04 00:47:52 +01:00
{
2006-07-08 02:36:23 +02:00
$customfields = $this -> soextra -> search ( array (
$this -> extra_id => $contact [ 'id' ],
2008-01-19 06:41:04 +01:00
$this -> extra_key => array_keys ( $this -> customfields ),
2006-07-08 02:36:23 +02:00
), false );
2006-06-17 20:50:07 +02:00
foreach (( array ) $customfields as $field )
{
$contact [ '#' . $field [ $this -> extra_key ]] = $field [ $this -> extra_value ];
}
2005-11-04 00:47:52 +01:00
}
2008-01-31 13:52:43 +01:00
$dl_list = $this -> read_distributionlist ( array ( $contact [ 'id' ]));
if ( count ( $dl_list )) $contact [ 'distrib_lists' ] = implode ( " \n " , $dl_list [ $contact [ 'id' ]]);
2006-03-07 23:43:08 +01:00
return $this -> db2data ( $contact );
2005-11-04 00:47:52 +01:00
}
2008-04-22 08:09:02 +02:00
2005-12-01 18:21:38 +01:00
/**
2006-04-23 16:40:31 +02:00
* searches db for rows matching searchcriteria
*
* '*' and '?' are replaced with sql - wildcards '%' and '_'
*
2006-04-26 14:23:10 +02:00
* @ param array / string $criteria array of key and data cols , OR string to search over all standard search fields
2006-04-23 16:40:31 +02:00
* @ param boolean / string $only_keys = true True returns only keys , False returns all cols . comma seperated list of keys 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 / 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 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 mixed $start = false if != false , return only maxmatch rows begining with start , or array ( $start , $num )
* @ param array $filter = null if set ( != null ) col - data pairs , to be and - ed ( ! ) into the query without wildcards
2006-06-17 20:50:07 +02:00
* @ param string $join = '' sql to do a join ( only used by sql backend ! ), eg . " RIGHT JOIN egw_accounts USING(account_id) "
2006-04-23 16:40:31 +02:00
* @ return array of matching rows ( the row is an array of the cols ) or False
*/
2006-06-17 20:50:07 +02:00
function & search ( $criteria , $only_keys = True , $order_by = '' , $extra_cols = '' , $wildcard = '' , $empty = False , $op = 'AND' , $start = false , $filter = null , $join = '' )
2006-04-23 16:40:31 +02:00
{
//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";
2006-10-19 10:51:11 +02:00
//error_log("socontacts::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')");
2008-04-22 08:09:02 +02:00
2006-12-11 08:35:49 +01:00
// the nextmatch custom-filter-header country-select returns a 2 letter country-code
if ( isset ( $filter [ 'adr_one_countryname' ]) && strlen ( $filter [ 'adr_one_countryname' ]) == 2 )
{
$filter [ 'adr_one_countryname' ] = $GLOBALS [ 'egw' ] -> country -> get_full_name ( $filter [ 'adr_one_countryname' ]);
}
2006-06-13 06:30:16 +02:00
$backend =& $this -> get_backend ( null , $filter [ 'owner' ]);
2006-04-26 14:23:10 +02:00
// single string to search for --> create so_sql conformant search criterial for the standard search columns
2008-04-22 08:09:02 +02:00
if ( $criteria && ! is_array ( $criteria ))
2006-04-26 14:23:10 +02:00
{
$op = 'OR' ;
$wildcard = '%' ;
$search = $criteria ;
$criteria = array ();
2008-04-22 08:09:02 +02:00
2006-06-13 06:30:16 +02:00
if ( $backend === $this -> somain )
2006-04-26 14:23:10 +02:00
{
2006-06-13 06:30:16 +02:00
$cols = $this -> columns_to_search ;
}
else
{
$cols = $this -> account_cols_to_search ;
2006-04-26 14:23:10 +02:00
}
2006-06-17 20:50:07 +02:00
// search the customfields only if some exist, but only for sql!
if ( get_class ( $backend ) == 'socontacts_sql' && $this -> customfields )
{
$cols [] = $this -> extra_value ;
}
2006-04-26 14:23:10 +02:00
foreach ( $cols as $col )
{
$criteria [ $col ] = $search ;
}
}
2006-04-23 16:40:31 +02:00
if ( is_array ( $criteria ) && count ( $criteria ))
{
$criteria = $this -> data2db ( $criteria );
}
if ( is_array ( $filter ) && count ( $filter ))
{
$filter = $this -> data2db ( $filter );
}
else
{
$filter = $filter ? array ( $filter ) : array ();
}
2006-06-13 06:30:16 +02:00
// 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 ;
2006-04-23 16:40:31 +02:00
if ( $rows )
{
foreach ( $rows as $n => $row )
{
$rows [ $n ] = $this -> db2data ( $row );
}
}
return $rows ;
}
2008-04-22 08:09:02 +02:00
2006-04-30 11:34:24 +02:00
/**
* Query organisations by given parameters
*
* @ var array $param
* @ var string $param [ org_view ] 'org_name' , 'org_name,adr_one_location' , 'org_name,org_unit' how to group
* @ var int $param [ owner ] addressbook to search
* @ var string $param [ search ] search pattern for org_name
* @ var string $param [ searchletter ] letter the org_name need to start with
* @ var int $param [ start ]
* @ var int $param [ num_rows ]
* @ var string $param [ sort ] ASC or DESC
* @ return array or arrays with keys org_name , count and evtl . adr_one_location or org_unit
2008-04-22 08:09:02 +02:00
*/
2006-04-30 11:34:24 +02:00
function organisations ( $param )
{
2006-06-13 17:40:13 +02:00
if ( ! method_exists ( $this -> somain , 'organisations' ))
{
$this -> total = 0 ;
return false ;
}
2008-04-22 08:09:02 +02:00
if ( $param [ 'search' ] && ! is_array ( $param [ 'search' ]))
2006-04-30 11:34:24 +02:00
{
$search = $param [ 'search' ];
$param [ 'search' ] = array ();
foreach ( $this -> columns_to_search as $col )
{
if ( $col != 'contact_value' ) $param [ 'search' ][ $col ] = $search ; // we dont search the customfields
}
}
if ( is_array ( $param [ 'search' ]) && count ( $param [ 'search' ]))
{
$param [ 'search' ] = $this -> data2db ( $param [ 'search' ]);
}
$rows = $this -> somain -> organisations ( $param );
2006-06-13 17:40:13 +02:00
$this -> total = $this -> somain -> total ;
2006-04-30 11:34:24 +02:00
//echo "<p>socontacts::organisations(".print_r($param,true).")<br />".$this->somain->db->Query_ID->sql."</p>\n";
if ( ! $rows ) return array ();
foreach ( $rows as $n => $row )
{
$rows [ $n ][ 'id' ] = 'org_name:' . $row [ 'org_name' ];
foreach ( array (
'org_unit' => lang ( 'departments' ),
'adr_one_locality' => lang ( 'locations' ),
) as $by => $by_label )
{
if ( $row [ $by . '_count' ] > 1 )
{
$rows [ $n ][ $by ] = $row [ $by . '_count' ] . ' ' . $by_label ;
}
else
{
$rows [ $n ][ 'id' ] .= '|||' . $by . ':' . $row [ $by ];
}
}
}
return $rows ;
}
2006-04-23 16:40:31 +02:00
/**
2005-12-01 18:21:38 +01:00
* gets all contact fields from database
2008-04-22 08:09:02 +02:00
*
2006-08-24 18:06:45 +02:00
* @ return array of ( internal ) field - names
2005-12-01 18:21:38 +01:00
*/
2006-04-23 16:40:31 +02:00
function get_contact_columns ()
2005-12-01 18:21:38 +01:00
{
2006-08-24 18:06:45 +02:00
$fields = $this -> get_fields ( 'all' );
2005-12-01 18:21:38 +01:00
foreach (( array ) $this -> customfields as $cfield => $coptions )
{
2006-08-24 18:06:45 +02:00
$fields [] = '#' . $cfield ;
2005-12-01 18:21:38 +01:00
}
return $fields ;
}
2008-04-22 08:09:02 +02:00
2006-04-23 16:40:31 +02:00
/**
* delete / move all contacts of an addressbook
*
* @ param array $data
* @ param int $data [ 'account_id' ] owner to change
* @ param int $data [ 'new_owner' ] new owner or 0 for delete
*/
function deleteaccount ( $data )
{
$account_id = $data [ 'account_id' ];
$new_owner = $data [ 'new_owner' ];
2008-04-22 08:09:02 +02:00
2006-04-23 16:40:31 +02:00
if ( ! $new_owner )
{
$this -> somain -> delete ( array ( 'owner' => $account_id ));
$this -> soextra -> delete ( array ( $this -> extra_owner => $account_id ));
}
else
{
$this -> somain -> change_owner ( $account_id , $new_owner );
2008-03-13 21:18:52 +01:00
$this -> db -> update ( $this -> soextra -> table_name , array (
2006-04-23 16:40:31 +02:00
$this -> extra_owner => $new_owner
), array (
$this -> extra_owner => $account_id
), __LINE__ , __FILE__ );
}
}
2008-04-22 08:09:02 +02:00
2006-06-13 06:30:16 +02:00
/**
* 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 )
{
2007-05-01 11:17:23 +02:00
if ( $owner === '' ) $owner = null ;
2006-06-13 06:30:16 +02:00
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 )
{
2008-03-13 21:18:52 +01:00
$def = $this -> db -> get_table_definitions ( 'phpgwapi' , 'egw_addressbook' );
2008-04-22 08:09:02 +02:00
2006-06-13 06:30:16 +02:00
$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 );
2008-04-22 08:09:02 +02:00
2006-06-13 06:30:16 +02:00
$supported_fields = method_exists ( $backend , supported_fields ) ? $backend -> supported_fields () : $all_fields ;
//echo "supported fields=";_debug_array($supported_fields);
2008-04-22 08:09:02 +02:00
2006-06-13 06:30:16 +02:00
if ( $type == 'supported' )
{
return $supported_fields ;
}
//echo "unsupported fields=";_debug_array(array_diff($all_fields,$supported_fields));
return array_diff ( $all_fields , $supported_fields );
}
2008-04-22 08:09:02 +02:00
2006-07-08 02:36:23 +02:00
/**
* Migrates an SQL contact storage to LDAP or SQL - LDAP
*
* @ param string $type " contacts " ( default ), " contacts+accounts " or " contacts+accounts-back " ( sql - ldap ! )
*/
function migrate2ldap ( $type )
{
$sql_contacts =& CreateObject ( 'addressbook.socontacts_sql' );
$ldap_contacts =& CreateObject ( 'addressbook.so_ldap' );
$start = $n = 0 ;
$num = 100 ;
while (( $contacts = $sql_contacts -> search ( false , false , 'n_family,n_given' , '' , '' , false , 'AND' ,
array ( $start , $num ), $type != 'contacts,accounts' ? array ( 'contact_owner != 0' ) : false )))
{
2006-11-23 07:46:51 +01:00
// very worse hack, until Ralf finds a better solution
// when migrating data, we need to bind as global ldap admin account
// and not as currently logged in user
$ldap_contacts -> ds = $GLOBALS [ 'egw' ] -> ldap -> ldapConnect ();
2006-07-08 02:36:23 +02:00
foreach ( $contacts as $contact )
{
if ( $contact [ 'account_id' ]) $contact [ 'id' ] = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $contact [ 'account_id' ]);
$ldap_contacts -> data = $contact ;
$n ++ ;
if ( ! ( $err = $ldap_contacts -> save ()))
{
echo '<p style="margin: 0px;">' . $n . ': ' . $contact [ 'n_fn' ] .
( $contact [ 'org_name' ] ? ' (' . $contact [ 'org_name' ] . ')' : '' ) . " --> LDAP</p> \n " ;
}
else
{
echo '<p style="margin: 0px; color: red;">' . $n . ': ' . $contact [ 'n_fn' ] .
( $contact [ 'org_name' ] ? ' (' . $contact [ 'org_name' ] . ')' : '' ) . ': ' . $err . " </p> \n " ;
}
}
$start += $num ;
}
if ( $type == 'contacts,accounts-back' ) // migrate the accounts to sql
{
2006-11-23 07:46:51 +01:00
// very worse hack, until Ralf finds a better solution
// when migrating data, we need to bind as global ldap admin account
// and not as currently logged in user
$ldap_contacts -> ds = $GLOBALS [ 'egw' ] -> ldap -> ldapConnect ();
2006-07-08 02:36:23 +02:00
foreach ( $ldap_contacts -> search ( false , false , 'n_family,n_given' , '' , '' , false , 'AND' ,
false , array ( 'owner' => 0 )) as $contact )
{
if ( $contact [ 'jpegphoto' ]) // photo is NOT read by LDAP backend on search, need to do an extra read
{
$contact = $ldap_contacts -> read ( $contact [ 'id' ]);
}
unset ( $contact [ 'id' ]); // ldap uid/account_lid
if ( $contact [ 'account_id' ] && ( $old = $sql_contacts -> read ( array ( 'account_id' => $contact [ 'account_id' ]))))
{
$contact [ 'id' ] = $old [ 'id' ];
}
$sql_contacts -> data = $contact ;
2008-04-22 08:09:02 +02:00
2006-07-08 02:36:23 +02:00
$n ++ ;
if ( ! ( $err = $sql_contacts -> save ()))
{
echo '<p style="margin: 0px;">' . $n . ': ' . $contact [ 'n_fn' ] .
( $contact [ 'org_name' ] ? ' (' . $contact [ 'org_name' ] . ')' : '' ) . " --> SQL ( " . lang ( 'User' ) . " )</p> \n " ;
}
else
{
echo '<p style="margin: 0px; color: red;">' . $n . ': ' . $contact [ 'n_fn' ] .
( $contact [ 'org_name' ] ? ' (' . $contact [ 'org_name' ] . ')' : '' ) . ': ' . $err . " </p> \n " ;
}
}
}
}
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
/**
* Get the availible distribution lists for a user
*
* @ param int $required = EGW_ACL_READ required rights on the list
* @ param string $extra_labels = null first labels if given ( already translated )
* @ return array with id => label pairs or false if backend does not support lists
2008-04-22 08:09:02 +02:00
*/
2007-03-13 14:38:15 +01:00
function get_lists ( $required = EGW_ACL_READ , $extra_labels = null )
{
if ( ! method_exists ( $this -> somain , 'get_lists' )) return false ;
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
$uids = array ();
foreach ( $this -> grants as $uid => $rights )
{
if ( $rights & $required )
{
$uids [] = $uid ;
}
}
$lists = is_array ( $extra_labels ) ? $extra_labels : array ();
foreach ( $this -> somain -> get_lists ( $uids ) as $list_id => $data )
{
$lists [ $list_id ] = $data [ 'list_name' ];
if ( $data [ 'list_owner' ] != $this -> user )
{
$lists [ $list_id ] .= ' (' . $GLOBALS [ 'egw' ] -> common -> grab_owner_name ( $data [ 'list_owner' ]) . ')' ;
}
}
//echo "<p>socontacts_sql::get_lists($required,'$extra_label')</p>\n"; _debug_array($lists);
return $lists ;
}
/**
* Adds a distribution list
*
* @ param string $name list - name
* @ param int $owner user - or group - id
* @ param array $contacts = array () contacts to add
* @ return list_id or false on error
*/
function add_list ( $name , $owner , $contacts = array ())
{
if ( ! method_exists ( $this -> somain , 'add_list' )) return false ;
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
return $this -> somain -> add_list ( $name , $owner , $contacts );
}
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
/**
* Adds one contact to a distribution list
*
* @ param int $contact contact_id
* @ param int $list list - id
* @ return false on error
*/
function add2list ( $contact , $list )
{
if ( ! method_exists ( $this -> somain , 'add2list' )) return false ;
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
return $this -> somain -> add2list ( $contact , $list );
}
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
/**
* Removes one contact from distribution list ( s )
*
* @ param int $contact contact_id
* @ param int $list = null list - id or null to remove from all lists
* @ return false on error
*/
function remove_from_list ( $contact , $list = null )
{
if ( ! method_exists ( $this -> somain , 'remove_from_list' )) return false ;
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
return $this -> somain -> remove_from_list ( $contact , $list );
}
/**
* Deletes a distribution list ( incl . it ' s members )
*
* @ param int / array $list list_id ( s )
* @ return number of members deleted or false if list does not exist
*/
function delete_list ( $list )
{
if ( ! method_exists ( $this -> somain , 'delete_list' )) return false ;
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
return $this -> somain -> delete_list ( $list );
}
2008-04-22 08:09:02 +02:00
2007-03-13 14:38:15 +01:00
/**
* Read data of a distribution list
*
* @ param int $list list_id
* @ return array of data or false if list does not exist
*/
function read_list ( $list )
{
if ( ! method_exists ( $this -> somain , 'read_list' )) return false ;
2008-04-22 08:09:02 +02:00
return $this -> somain -> read_list ( $list );
2007-03-13 14:38:15 +01:00
}
2008-04-22 08:09:02 +02:00
2007-05-01 11:17:23 +02:00
/**
* Check if distribution lists are availible for a given addressbook
*
2007-05-03 07:07:30 +02:00
* @ param int / string $owner = '' addressbook ( eg . 0 = accounts ), default '' = " all " addressbook ( uses the main backend )
2007-05-01 11:17:23 +02:00
* @ return boolean
*/
2007-05-03 07:07:30 +02:00
function lists_available ( $owner = '' )
2007-05-01 11:17:23 +02:00
{
$backend =& $this -> get_backend ( null , $owner );
2008-04-22 08:09:02 +02:00
2007-05-01 11:17:23 +02:00
return method_exists ( $backend , 'read_list' );
}
2005-11-04 00:47:52 +01:00
}