first version / step to the new 1.4 addressbook:

- User accounts are an own addressbook now
- every user and group (can) have an own addressbook
- for groups the accessrights no longer depend on the creator
- new acl for adding into an addressbook
- all addressbooks can be displayed together (eg. accounts mixed with personal and group AB's)
- some useful new fields (photo, private cellphone, ...) and some obscure ones have been removed
- db update puts all contacts in the owners personal addressbook (further manual migration tools will follow), thought the UI already allows to mass-move them into a group-addressbook
- group addressbooks in SQL are created by making a group-grant for addressbook (like filemanger)
- Warning: all import/export/xmlrpc/syncml stuff and other apps accessing the addressbook is broken until the contacts class in the API gets fixed!
- it depends on further updates of etemplate, phpgwapi, admin!
==> it's pretty cool (specialy the foto's), but NOT ready for a production server !!!
This commit is contained in:
Ralf Becker 2006-04-23 14:40:31 +00:00
parent 76ff2ee6d1
commit b6b3db5ed4
40 changed files with 2403 additions and 618 deletions

View File

@ -3,7 +3,8 @@
* 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 *
@ -15,25 +16,16 @@
require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.socontacts.inc.php');
/**
* General business object of the adressbook
*
* @package addressbook
* @author Cornelius Weiss <egw@von-und-zu-weiss.de>
* @copyright (c) 2005 by Cornelius Weiss <egw@von-und-zu-weiss.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
* General business object of the adressbook
*
* @package addressbook
* @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>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
class bocontacts extends socontacts
{
/**
* @var $grants array with grants
*/
var $grants;
/**
* @var $user userid of current user
*/
var $user;
/**
* @var int $tz_offset_s offset in secconds between user and server-time,
* it need to be add to a server-time to get the user-time or substracted from a user-time to get the server-time
@ -48,13 +40,33 @@ class bocontacts extends socontacts
/**
* @var array $timestamps timestamps
*/
var $timestamps = array('last_mod');
var $timestamps = array('modified','created');
/**
* @var array $fileas_types
*/
var $fileas_types = array(
'org_name: n_family, n_given',
'org_name: n_family, n_prefix',
'org_name: n_given n_family',
'org_name: n_fn',
'n_family, n_given: org_name',
'n_family, n_prefix: org_name',
'n_given n_family: org_name',
'n_prefix n_family: org_name',
'n_fn: org_name',
'org_name',
'n_given n_family',
'n_prefix n_family',
'n_family, n_given',
'n_family, n_prefix',
'n_fn',
);
function bocontacts($contact_app='addressbook')
{
$this->socontacts($contact_app);
$this->grants = $GLOBALS['egw']->acl->get_grants($contact_app);
$this->user = $GLOBALS['egw_info']['user']['account_id'];
$this->tz_offset_s = 3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
$this->now_su = time() + $this->tz_offset_s;
@ -72,7 +84,92 @@ class bocontacts extends socontacts
}*/
}
/**
* calculate the file_as string from the contact and the file_as type
*
* @param array $contact
* @param string $type=null file_as type, default null to read it from the contact, unknown/not set type default to the first one
* @return string
*/
function fileas($contact,$type=null)
{
if (is_null($type)) $type = $contact['fileas_type'];
if (!$type || !in_array($type,$this->fileas_types)) $type = $this->fileas_types[0];
if (strstr($type,'n_fn')) $contact['n_fn'] = $this->fullname($contact);
return str_replace(array_keys($contact),array_values($contact),$type);
}
/**
* determine the file_as type from the file_as string and the contact
*
* @param array $contact
* @param string $type=null file_as type, default null to read it from the contact, unknown/not set type default to the first one
* @return string
*/
function fileas_type($contact,$file_as=null)
{
if (is_null($file_as)) $file_as = $contact['n_fileas'];
if ($file_as)
{
foreach($this->fileas_types as $type)
{
if ($this->fileas($contact,$type) == $file_as)
{
return $type;
}
}
}
return $this->fileas_types[0];
}
/**
* get selectbox options for the fileas types with translated labels, or real content
*
* @param array $contact=null real content to use, default none
* @return array with options: fileas type => label pairs
*/
function fileas_options($contact=null)
{
$labels = array(
'n_prefix' => lang('prefix'),
'n_given' => lang('first name'),
'n_middle' => lang('middle name'),
'n_family' => lang('last name'),
'n_suffix' => lang('suffix'),
'n_fn' => lang('full name'),
'org_name' => lang('company name'),
);
foreach($labels as $name => $label)
{
if ($contact[$name]) $labels[$name] = $contact[$name];
}
foreach($this->fileas_types as $fileas_type)
{
$options[$fileas_type] = $this->fileas($labels,$fileas_type);
}
return $options;
}
/**
* get full name from the name-parts
*
* @param array $contact
* @return string full name
*/
function fullname($contact)
{
$parts = array();
foreach(array('n_prefix','n_given','n_middle','n_family','n_suffix') as $n)
{
if ($contact[$n]) $parts[] = $contact[$n];
}
return implode(' ',$parts);
}
/**
* changes the data from the db-format to your work-format
*
@ -91,8 +188,25 @@ class bocontacts extends socontacts
$data[$name] += $this->tz_offset_s;
}
}
$data['photo'] = $this->photo_src($data['id'],$data['jpegphoto']);
return $data;
}
/**
* src for photo: returns array with linkparams if jpeg exists or the $default image-name if not
* @param int $id contact_id
* @param boolean $jpeg=false jpeg exists or not
* @param string $default='' image-name to use if !$jpeg, eg. 'template'
* @return string/array
*/
function photo_src($id,$jpeg,$default='')
{
return $jpeg ? array(
'menuaction' => 'addressbook.uicontacts.photo',
'contact_id' => $id,
) : $default;
}
/**
* changes the data from your work-format to the db-format
@ -118,114 +232,78 @@ class bocontacts extends socontacts
/**
* deletes contact in db
*
* @param mixed &contact contact array from etemplate::exec or id
* @return bool false if all went right
* @param mixed &$contact contact array with key id or (array of) id(s)
* @return boolean true on success or false on failiure
*/
function delete(&$contact)
function delete($contact)
{
// multiple delete from advanced search
if(isset($contact[0]))
if (is_array($contact) && isset($contact['id']))
{
foreach($contact as $single)
{
if($this->check_perms(EGW_ACL_DELETE,$single['id']))
{
if(parent::delete($single))
{
$msg .= lang('Something went wrong by deleting %1', $single['n_given'].$single['n_family']);
}
else
{
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $single['id'], 'delete', time());
}
}
else
{
$msg .= lang('You are not permitted to delete contact %1', $single['n_given'].$single['n_family']);
}
}
return $msg;
$contact = array($contact);
}
if((isset($contact['id']) && !$this->check_perms(EGW_ACL_DELETE,$contact['id'])) ||
(is_numeric($contact) && !$this->check_perms(EGW_ACL_DELETE,$contact)))
elseif (!is_array($contact))
{
$contact['msg'] = lang('You are not permittet to delete this contact');
return 1;
$contact = array($contact);
}
if(is_numeric($contact)) $contact = array('id' => $contact);
if(parent::delete($contact))
foreach($contact as $c)
{
$contact['msg'] = lang('Something went wrong by deleting this contact');
return 1;
}
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $contact['id'], 'delete', time());
$id = is_array($c) ? $c['id'] : $c;
return;
if ($this->check_perms(EGW_ACL_DELETE,$c) && parent::delete($id))
{
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $id, 'delete', time());
}
else
{
return false;
}
}
return true;
}
/**
* saves contact to db
*
* @param array &contact contact array from etemplate::exec
* @return array $contact
* @return boolean true on success, false on failure, an error-message is in $contact['msg']
* TODO make fullname format choosable at best with selectbox and javascript in edit dialoge
*/
function save(&$contact)
{
// stores if we add or update a entry
$isUpdate = true;
if($contact['id'] && !$this->check_perms(EGW_ACL_EDIT,$contact['id']))
if (!($isUpdate = $contact['id']))
{
if (!isset($contact['owner'])) $contact['owner'] = $this->user; // write to users personal addressbook
$contact['creator'] = $this->user;
$contact['created'] = $this->now_su;
}
if($contact['id'] && !$this->check_perms(EGW_ACL_EDIT,$contact))
{
$contact['msg'] = lang('You are not permittet to edit this contact');
return $contact;
return false;
}
// new contact
if($contact['id'] == 0)
{
$contact['owner'] = $this->user;
$isUpdate = false;
}
// convert categories
$contact['cat_id'] = $contact['cat_id'] ? implode(',',$contact['cat_id']) : '';
$contact['cat_id'] = is_array($contact['cat_id']) ? implode(',',$contact['cat_id']) : $contact['cat_id'];
// last modified
$contact['last_mod'] = $this->now_su;
// only owner can set access status
$contact['access'] = $contact['owner'] == $this->user ? ($contact['private'] ? 'private': 'public') : $contact['access'];
// create fullname
$contact['fn'] = $contact['prefix'].
($contact['n_given'] ? ' '.$contact['n_given'] : '').
($contact['n_middle'] ? ' '.$contact['n_middle'] : '').
($contact['n_family'] ? ' '.$contact['n_family'] : '').
($contact['n_suffix'] ? ' '.$contact['n_suffix'] : '');
// for some bad historical reasons we mainfileds saved in cf :-(((
$contact['#ophone'] = $contact['ophone']; unset($contact['ophone']);
$contact['#address2'] = $contact['address2']; unset($contact['address2']);
$contact['#address3'] = $contact['address3']; unset($contact['address3']);
$contact['modifier'] = $this->user;
$contact['modified'] = $this->now_su;
// set access if not set or bogus
if ($contact['access'] != 'private') $contact['access'] = 'public';
// set full name and fileas from the content
$contact['n_fn'] = $this->fullname($contact);
$contact['n_fileas'] = $this->fileas($contact);
$error_nr = parent::save($contact);
if(!$error_nr)
{
if($isUpdate) {
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $contact['id'], 'modify', time());
} else {
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $contact['id'], 'add', time());
}
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $contact['id'],$isUpdate ? 'modify' : 'add', time());
}
// for some bad historical reasons we mainfileds saved in cf :-(((
$contact['ophone'] = $contact['#ophone']; unset($contact['#ophone']);
$contact['address2'] = $contact['#address2']; unset($contact['#address2']);
$contact['address3'] = $contact['#address3']; unset($contact['#address3']);
$contact['msg'] = $error_nr ?
lang('Something went wrong by saving this contact. Errorcode %1',$error_nr) :
lang('Contact saved');
return $contact;
return !$error_nr;
}
/**
@ -234,80 +312,125 @@ class bocontacts extends socontacts
* @param array $keys array with keys in form internalName => value, may be a scalar value if only one key
* @param string/array $extra_cols string or array of strings to be added to the SELECT, eg. "count(*) as num"
* @param string $join='' sql to do a join, added as is after the table-name, eg. ", table2 WHERE x=y" or
* @return array with data or errormessage
* @return array/boolean contact data or false on error
*/
function read($keys,$extra_cols='',$join='')
{
$data = parent::read($keys,$extra_cols,$join);
if (!$data)
if (!$data || !$this->check_perms(EGW_ACL_READ,$data))
{
return lang('something went wrong by reading this contact');
return false;
}
if(!$this->check_perms(EGW_ACL_READ,$data))
{
return lang('you are not permittet to view this contact');
}
// convert access into private for historical reasons
$data['private'] = $data['access'] == 'private' ? 1 : 0;
// for some bad historical reasons we mainfileds saved in cf :-(((
$data['ophone'] = $data['#ophone']; unset($data['#ophone']);
$data['address2'] = $data['#address2']; unset($data['#address2']);
$data['address3'] = $data['#address3']; unset($data['#address3']);
// determine the file-as type
$data['fileas_type'] = $this->fileas_type($data);
return $data;
}
/**
* searches contacts for rows matching searchcriteria
*
* @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!)
* @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
* @param string $join='' sql to do a join, added as is after the table-name, eg. ", table2 WHERE x=y" or
* "LEFT JOIN table2 ON (x=y)", Note: there's no quoting done on $join!
* @param boolean $need_full_no_count=false If true an unlimited query is run to determine the total number of rows, default false
* @return array of matching rows (the row is an array of the cols) or False
*/
function search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false)
{
$filter = array(
'owner' => array_keys($this->grants),
);
return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
}
/**
* Checks if the current user has the necessary ACL rights
*
* If the access of a contact is set to private, one need a private grant for a personal addressbook
* or the group membership for a group-addressbook
*
* @param int $needed necessary ACL right: EGW_ACL_{READ|EDIT|DELETE}
* @param mixed $contact contact as array or the contact-id
* @return boolean true permission granted or false for permission denied
*/
function check_perms($needed,&$contact)
{
if (is_array($contact))
if (!is_array($contact) && !($contact = parent::read($contact)))
{
$owner = $contact['owner'];
$access = $contact['access'];
return false;
}
elseif (is_numeric($contact))
{
$read_contact = parent::read($contact);
$owner = $read_contact['owner'];
$access = $read_contact['access'];
}
if($owner == $this->user)
$owner = $contact['owner'];
if (!$owner && $needed == EGW_ACL_EDIT && $contact['account_id'] == $this->user)
{
return true;
}
$access = $access ? $access : 'public';
return $access == 'private' ? false : $this->grants[$owner] & $needed;
return ($this->grants[$owner] & $needed) &&
(!$contact['private'] || ($this->grants[$owner] & EGW_ACL_PRIVATE) || in_array($owner,$this->memberships));
}
/**
* get title for a contact identified by $contact
*
* Is called as hook to participate in the linking
*
* @param int/string/array $contact int/string id or array with contact
* @param string the title
*/
function link_title($contact)
{
if (!is_array($contact) && $contact)
{
$contact = $this->read($contact);
}
if (!is_array($contact))
{
return False;
}
return $contact['n_fileas'];
}
/**
* query addressbook for contacts matching $pattern
*
* Is called as hook to participate in the linking
*
* @param string $pattern pattern to search
* @return array with id - title pairs of the matching entries
*/
function link_query($pattern)
{
$result = $criteria = array();
if ($pattern)
{
foreach($this->columns_to_search as $col)
{
$criteria[$col] = $pattern;
}
}
foreach((array) $this->regular_search($criteria,false,'org_name,n_family,n_given','','%',false,'OR') as $contact)
{
$result[$contact['id']] = $this->link_title($contact);
}
return $result;
}
/**
* Hook called by link-class to include calendar in the appregistry of the linkage
*
* @param array/string $location location and other parameters (not used)
* @return array with method-names
*/
function search_link($location)
{
return array(
'query' => 'addressbook.bocontacts.link_query',
'title' => 'addressbook.bocontacts.link_title',
'view' => array(
'menuaction' => 'addressbook.uicontacts.view'
),
'view_id' => 'contact_id',
);
}
/**
* Called by delete-account hook if an account gets deleted
*
* @param array $data
*/
function deleteaccount($data)
{
// delete/move personal addressbook
parent::deleteaccount($data);
// delete contact linked to account
if (($contact_id = $GLOBALS['egw']->accounts->id2name($data['account_id'],'person_id')))
{
$this->delete($contact_id);
}
}
}

View File

@ -0,0 +1,177 @@
<?php
/**************************************************************************\
* eGroupWare - Addressbook Admin-, Preferences- and SideboxMenu-Hooks *
* http://www.eGroupWare.org *
* Written and (c) 2006 by Ralf Becker <RalfBecker@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$ */
/**
* Class containing admin, preferences and sidebox-menus (used as hooks)
*
* @package addressbook
* @author Ralf Becker <RalfBecker@outdoor-training.de>
* @copyright (c) 2006 by Ralf Becker <RalfBecker@outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
class contacts_admin_prefs
{
var $contacts_repository = 'sql';
/**
* constructor
*/
function contacts_admin_prefs()
{
if($GLOBALS['egw_info']['server']['contact_repository'] == 'ldap') $this->contacts_repository = 'ldap';
}
/**
* hooks to build projectmanager's sidebox-menu plus the admin and preferences sections
*
* @param string/array $args hook args
*/
function all_hooks($args)
{
$appname = 'addressbook';
$location = is_array($args) ? $args['location'] : $args;
//echo "<p>contacts_admin_prefs::all_hooks(".print_r($args,True).") appname='$appname', location='$location'</p>\n";
if ($location == 'sidebox_menu')
{
$file = array(
array(
'text' => '<a class="textSidebox" href="'.$GLOBALS['egw']->link('/index.php',array('menuaction' => 'addressbook.uicontacts.edit')).
'" onclick="window.open(this.href,\'_blank\',\'dependent=yes,width=850,height=440,scrollbars=yes,status=yes\');
return false;">'.lang('Add').'</a>',
'no_lang' => true,
'link' => false
),
// Disabled til they are working again
// 'Advanced search'=>$GLOBALS['egw']->link('/index.php','menuaction=addressbook.uicontacts.search'),
// 'import contacts' => $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiXport.import'),
// 'export contacts' => $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiXport.export')
// 'CSV-Import' => $GLOBALS['egw']->link('/addressbook/csv_import.php')
);
display_sidebox($appname,lang('Addressbook menu'),$file);
}
if ($GLOBALS['egw_info']['user']['apps']['preferences'] && $location != 'admin')
{
$file = array(
'Preferences' => $GLOBALS['egw']->link('/index.php','menuaction=preferences.uisettings.index&appname='.$appname),
'Grant Access' => $GLOBALS['egw']->link('/index.php','menuaction=preferences.uiaclprefs.index&acl_app='.$appname),
'Edit Categories' => $GLOBALS['egw']->link('/index.php','menuaction=preferences.uicategories.index&cats_app=' . $appname . '&cats_level=True&global_cats=True')
);
if ($this->contacts_repository == 'ldap' || $GLOBALS['egw_info']['server']['deny_user_grants_access'])
{
unset($file['Grant Access']);
}
if ($location == 'preferences')
{
display_section($appname,$file);
}
else
{
display_sidebox($appname,lang('Preferences'),$file);
}
}
if ($GLOBALS['egw_info']['user']['apps']['admin'] && $location != 'preferences')
{
$file = Array(
'Site configuration' => $GLOBALS['egw']->link('/index.php',array(
'menuaction' => 'admin.uiconfig.index',
'appname' => $appname,
)),
'Global Categories' => $GLOBALS['egw']->link('/index.php',array(
'menuaction' => 'admin.uicategories.index',
'appname' => $appname,
'global_cats'=> True)),
'Custom fields' => $GLOBALS['egw']->link('/index.php',array(
'menuaction' => 'admin.customfields.edit',
'appname' => $appname,
)),
);
if ($location == 'admin')
{
display_section($appname,$file);
}
else
{
display_sidebox($appname,lang('Admin'),$file);
}
}
}
/**
* populates $GLOBALS['settings'] for the preferences
*/
function settings()
{
$GLOBALS['settings']['mainscreen_showbirthdays'] = array(
'type' => 'check',
'label' => 'Show birthday reminders on main screen',
'name' => 'mainscreen_showbirthdays',
'help' => 'Displays a remider for birthdays happening today or tomorrow on the startpage (page you get when you enter eGroupWare or click on the homepage icon).',
'xmlrpc' => True,
'admin' => False,
);
$column_display_options = array(
'' => lang('only if there is content'),
'always' => lang('always'),
'never' => lang('never'),
);
foreach(array(
'photo_column' => lang('Photo'),
'home_column' => lang('Home address'),
'custom_colum' => lang('custom fields'),
) as $name => $label)
{
$GLOBALS['settings'][$name] = array(
'type' => 'select',
'label' => lang('Show a column for %1',$label),
'run_lang' => -1,
'name' => $name,
'values' => $column_display_options,
'help' => 'When should the contacts list display that colum. "Only if there is content" hides the column, unless there is some content in the view.',
'xmlrpc' => True,
'admin' => false,
);
}
if ($this->contacts_repository == 'sql')
{
$GLOBALS['settings']['private_addressbook'] = array(
'type' => 'check',
'label' => 'Enable an extra private addressbook',
'name' => 'private_addressbook',
'help' => 'Do you want a private addressbook, which can not be viewed by users, you grant access to your personal addressbook?',
'xmlrpc' => True,
'admin' => False,
);
}
return true; // otherwise prefs say it cant find the file ;-)
}
/**
* add an Addressbook tab to Admin >> Edit user
*/
function edit_user()
{
global $menuData;
$menuData[] = array(
'description' => 'Addressbook',
'url' => '/index.php',
'extradata' => 'menuaction=addressbook.uicontacts.edit',
'options' => "onclick=\"window.open(this,'_blank','dependent=yes,width=850,height=440,scrollbars=yes,status=yes'); return false;\"".
' title="'.htmlspecialchars(lang('Edit extra account-data in the addressbook')).'"',
);
}
}

View File

@ -3,7 +3,8 @@
* 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 *
@ -17,7 +18,8 @@
*
* @package addressbook
* @author Cornelius Weiss <egw@von-und-zu-weiss.de>
* @copyright (c) 2005 by 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>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
@ -53,19 +55,93 @@ class socontacts
*/
var $extra_value = 'contact_value';
/**
* @var string $contacts_repository 'sql' or 'ldap'
*/
var $contacts_repository = 'sql';
/**
* @var array $grants account_id => rights pairs
*/
var $grants;
/**
* @var int $user userid of current user
*/
var $user;
/**
* @var array $memberships of the current user
*/
var $memberships;
/**
* @var array $columns_to_search when we search for a single pattern
*/
var $columns_to_search = array();
/**
* @var array $account_extra_search extra columns to search if accounts are included, eg. account_lid
*/
var $account_extra_search = array();
/**
* @var array $customfields name => array(...) pairs
*/
var $customfields = array();
/**
* @var array $content_types name => array(...) pairs
*/
var $content_types = array();
function socontacts($contact_app='addressbook')
{
if($GLOBALS['egw_info']['server']['contact_repository'] == 'sql' || !isset($GLOBALS['egw_info']['server']['contact_repository']))
$this->user = $GLOBALS['egw_info']['user']['account_id'];
foreach($GLOBALS['egw']->accounts->membership($this->user) as $group)
{
$this->somain =& CreateObject('etemplate.so_sql','phpgwapi','egw_addressbook');
$this->memberships[] = $group['account_id'];
}
if($GLOBALS['egw_info']['server']['contact_repository'] == 'ldap')
{
$this->contact_repository = 'ldap';
$this->somain =& CreateObject('addressbook.so_'.$this->contact_repository);
// 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;
}
// 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
{
$this->somain =& CreateObject('addressbook.so_'.$GLOBALS['egw_info']['server']['contact_repository']);
$this->somain =& CreateObject('addressbook.socontacts_sql','addressbook','egw_addressbook',null,'contact_');
// group grants are now grants for the group addressbook and NOT grants for all its members, therefor the param false!
$this->grants = $GLOBALS['egw']->acl->get_grants($contact_app,false);
// remove some columns, absolutly not necessary to search in sql
$this->columns_to_search = array_diff(array_values($this->somain->db_cols),array('jpegphoto','owner','tid','private','id','cat_id','modified','modifier','creator','created'));
$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
if (isset($GLOBALS['egw_info']['user']['apps']['admin'])) // admin rights can be limited by ACL!
{
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;
}
// 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('phpgwapi',$this->extra_table);
$this->soextra->so_sql('addressbook',$this->extra_table);
$custom =& CreateObject('admin.customfields',$contact_app);
$this->customfields = $custom->get_customfields();
@ -75,6 +151,22 @@ class socontacts
if ($this->content_types && !is_array($this->content_types)) $this->content_types = unserialize($this->content_types);
}
/**
* Read all customfields of the given id's
*
* @param int/array $ids
* @return array id => name => value
*/
function read_customfields($ids)
{
$fields = array();
foreach((array)$this->soextra->search(array($this->extra_id => $ids),false) as $data)
{
if ($data) $fields[$data[$this->extra_id]][$data[$this->extra_key]] = $data[$this->extra_value];
}
return $fields;
}
/**
* changes the data from the db-format to your work-format
*
@ -108,20 +200,22 @@ class socontacts
/**
* deletes contact entry including custom fields
*
* @param array &$contact contact data from etemplate::exec
* @return bool false if all went right
* @param mixed $contact array with key id or just the id
* @return boolean true on success or false on failiure
*/
function delete($contact)
{
if (is_array($contact)) $contact = $contact['id'];
// delete mainfields
if ($this->somain->delete(array('id' => $contact['id'])))
if ($this->somain->delete($contact))
{
// delete customfields, can return 0 if there are no customfields
$this->soextra->delete(array($this->extra_id => $contact['id']));
$this->soextra->delete(array($this->extra_id => $contact));
return false;
return true;
}
return true;
return false;
}
/**
@ -139,27 +233,33 @@ class socontacts
if($error_nr) return $error_nr;
// save customfields
foreach ((array)$this->customfields + array('ophone' => '', 'address2' => '' , 'address3' => '') as $field => $options)
foreach ((array)$this->customfields as $field => $options)
{
if(!array_key_exists('#'.$field,$contact)) continue;
$value = $contact['#'.$field];
if (!isset($contact['#'.$field])) continue;
$data = array(
$this->extra_id => $contact['id'],
$this->extra_id => $contact['id'],
$this->extra_owner => $contact['owner'],
$this->extra_key => $field,
$this->extra_value => $value,
$this->extra_key => $field,
);
$this->soextra->data = $data;
$error_nr = $this->soextra->save();
if($error_nr) return $error_nr;
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;
}
}
return;
return false; // no error
}
/**
* reads contact data including custom fields
*
* @param interger $contact_id contact_id
* @param interger/string $contact_id contact_id or 'a'.account_id
* @return array/boolean data if row could be retrived else False
*/
function read($contact_id)
@ -169,8 +269,7 @@ class socontacts
{
return $contact;
}
// read customfilds
// read customfields
$keys = array(
$this->extra_id => $contact['id'],
$this->extra_owner => $contact['owner'],
@ -319,7 +418,7 @@ class socontacts
{
$criteria[$this->main_id] = $resultextra;
}
if (count($criteria) >= 1)
if (count($criteria) >= 0) // RB-CHANGED was 1
{
// We do have to apply wildcard by hand, as the result-ids of extrasearch are included in this search
if($wildcard)
@ -381,9 +480,57 @@ class socontacts
}
/**
* searches db for rows matching searchcriteria
*
* '*' and '?' are replaced with sql-wildcards '%' and '_'
*
* @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!)
* @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
* @param string $join='' sql to do a join, added as is after the table-name, eg. ", table2 WHERE x=y" or
* "LEFT JOIN table2 ON (x=y)", Note: there's no quoting done on $join!
* @param boolean $need_full_no_count=false If true an unlimited query is run to determine the total number of rows, default false
* @return array of matching rows (the row is an array of the cols) or False
*/
function &regular_search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false)
{
//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";
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();
}
$rows =& $this->somain->search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
if ($rows)
{
foreach($rows as $n => $row)
{
$rows[$n] = $this->db2data($row);
}
}
// ToDo: read custom-fields, if displayed in the index page
return $rows;
}
/**
* gets all contact fields from database
*/
function get_contact_conlumns()
function get_contact_columns()
{
$fields = $this->somain->db_data_cols;
foreach ((array)$this->customfields as $cfield => $coptions)
@ -392,4 +539,32 @@ class socontacts
}
return $fields;
}
/**
* 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'];
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);
$this->soextra->db->update($this->soextra->table_name,array(
$this->extra_owner => $new_owner
),array(
$this->extra_owner => $account_id
),__LINE__,__FILE__);
}
}
}

View File

@ -0,0 +1,262 @@
<?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$ */
include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php');
/**
* SQL storage object of the adressbook
*
* @package addressbook
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2006 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
class socontacts_sql extends so_sql
{
var $accounts_join = "JOIN egw_accounts ON person_id=contact_id";
/**
* searches db for rows matching searchcriteria
*
* '*' and '?' are replaced with sql-wildcards '%' and '_'
*
* For a union-query you call search for each query with $start=='UNION' and one more with only $order_by and $start set to run the union-query.
*
* @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!)
* @param 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), or 'UNION' for a part of a union query
* @param array $filter=null if set (!=null) col-data pairs, to be and-ed (!) into the query without wildcards
* @param string $join='' sql to do a join, added as is after the table-name, eg. ", table2 WHERE x=y" or
* "LEFT JOIN table2 ON (x=y)", Note: there's no quoting done on $join!
* @param boolean $need_full_no_count=false If true an unlimited query is run to determine the total number of rows, default false
* @return boolean/array of matching rows (the row is an array of the cols) or False
*/
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)
{
if ((int) $this->debug >= 4) echo "<p>socontacts_sql::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')</p>\n";
$owner = isset($filter['owner']) ? $filter['owner'] : (isset($criteria['owner']) ? $criteria['owner'] : null);
// add filter for read ACL in sql, if user is NOT the owner of the addressbook
if (!(isset($filter['owner']) && $filter['owner'] == $GLOBALS['egw_info']['user']['account_id']))
{
// we have no private grants in addressbook at the moment, they have then to be added here too
if (isset($filter['owner']))
{
if (!$this->grants[(int) $filter['owner']]) return false; // we have no access to that addressbook
$filter['private'] = 0;
}
else // search all addressbooks, incl. accounts
{
$filter[] = '(contact_owner='.(int)$GLOBALS['egw_info']['user']['account_id'].' OR contact_private=0 AND contact_owner IN ('.
implode(',',array_keys($this->grants)).') OR contact_owner IS NULL)';
}
}
if (!$owner) // owner not set (=all) or 0 --> include accounts
{
if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array();
$accounts2contacts = array(
'contact_id' => 'CASE WHEN contact_id IS NULL THEN '.$this->db->concat("'account:'",'account_id').' ELSE contact_id END AS contact_id',
'contact_owner' => 'CASE WHEN contact_owner IS NULL THEN 0 ELSE contact_owner END AS contact_owner',
'contact_tid' => 'CASE WHEN contact_tid IS NULL THEN \'n\' ELSE contact_tid END AS contact_tid',
'n_family' => 'CASE WHEN n_family IS NULL THEN account_lastname ELSE n_family END AS n_family',
'n_given' => 'CASE WHEN n_given IS NULL THEN account_firstname ELSE n_given END AS n_given',
'contact_email' => 'CASE WHEN contact_email IS NULL THEN account_email ELSE contact_email END AS contact_email',
);
$extra_cols = $extra_cols ? array_merge(is_array($extra_cols) ? $extra_cols : implode(',',$extra_cols),array_values($accounts2contacts)) :
array_values($accounts2contacts);
if (!$only_keys)
{
$account_table = $this->db->get_table_definitions('phpgwapi','egw_accounts');
// all addressbook columns, but the ones given with CASE ... AS above plus the account-columns
$only_keys = implode(',',array_merge(array_diff(array_keys($this->db_cols),array_keys($accounts2contacts)),
array_keys($account_table['fd'])));
}
foreach($filter as $col => $value)
{
if (!is_int($col))
{
if (($db_col = array_search($col,$this->db_cols)) !== false && isset($accounts2contacts[$db_col]))
{
unset($filter[$col]);
$filter[] = str_replace(' AS '.$db_col,'',$accounts2contacts[$db_col]).'='.$this->db->quote($value,$this->table_def['fd'][$db_col]['type']);
}
}
elseif (preg_match("/^([a-z0-9_]+) *(=|!=|LIKE|NOT LIKE) *'(.*)'\$/i",$value,$matches))
{
if (($db_col = array_search($matches[1],$this->db_cols)) !== false && isset($accounts2contacts[$db_col]))
{
$filter[$col] = str_replace(' AS '.$db_col,'',$accounts2contacts[$db_col]).' '.$matches[2].' \''.$matches[3].'\'';
}
}
}
// dont list groups
$filter[] = "(account_type!='g' OR account_type IS NULL)";
}
if (is_null($owner)) // search for accounts AND contacts of all addressbooks
{
if ($this->db->capabilities['outer_join'])
{
$join = 'OUTER '.$this->accounts_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,$need_full_no_count);
$filter[] = 'person_id=0';
parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,'UNION',$filter,
'RIGHT '.$this->accounts_join,$need_full_no_count);
}
}
elseif (!$owner) // search for accounts only
{
$join = 'RIGHT '.$this->accounts_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);
}
/**
* reads contact data including custom fields
*
* reimplemented to read/convert accounts and return the account_id for them
*
* @param integer/string $contact_id contact_id or 'account:'.account_id
* @return array/boolean data if row could be retrived else False
*/
function read($contact_id)
{
//echo "<p>socontacts_sql::read($contact_id)</p>\n";
if (substr($contact_id,0,8) == 'account:')
{
$account_id = (int) substr($contact_id,8);
if (!$GLOBALS['egw']->accounts->exists($account_id)) return false; // account does not exist
// check if the account is already linked with a contact, if not create one with the content of the account
if (!($contact_id = $GLOBALS['egw']->accounts->id2name($account_id,'person_id')) &&
!($matching_contact_id = $this->_find_unique_contact(
$GLOBALS['egw']->accounts->id2name($account_id,'account_firstname'),
$GLOBALS['egw']->accounts->id2name($account_id,'account_lastname'))))
{
// as the account object has no function to just read a record and NOT override it's internal data,
// we have to instanciate a new object and can NOT use $GLOBALS['egw']->accounts !!!
$account =& new accounts($account_id,'u');
$account->read();
if (!$account->data['account_id']) return false; // account not found
$this->init();
$this->save(array(
'n_family' => $account->data['lastname'],
'n_given' => $account->data['firstname'],
'n_fn' => $account->data['firstname'].' '.$account->data['lastname'],
'n_fileas' => $account->data['lastname'].', '.$account->data['firstname'],
'email' => $account->data['email'],
'owner' => 0,
'tid' => 'n',
),$account_id);
return $this->data+array('account_id' => $account_id);
}
elseif ($matching_contact_id)
{
//echo "<p>socontacts_sql($contact_id) account_id=$account_id, matching_contact_id=$matching_contact_id</p>\n";
$contact = parent::read($matching_contact_id);
$contact['owner'] = 0;
$this->save($contact,$account_id);
return $this->data+array('account_id' => $account_id);
}
//echo "<p>socontacts_sql::read() account_id='$account_id', contact_id='$contact_id'</p>\n"; exit;
}
if (($contact = parent::read($contact_id)) && !$contact['owner']) // return account_id for accounts
{
$contact['account_id'] = $GLOBALS['egw']->accounts->name2id($contact_id,'person_id');
}
return $contact;
}
function _find_unique_contact($firstname,$lastname)
{
$contacts =& $this->search(array(
'contact_owner != 0',
'n_given' => $firstname,
'n_family' => $lastname,
'private' => 0,
));
//echo "<p>soccontacts_sql::_find_unique_contacts($firstname,$lastname)</p>\n"; _debug_array($contacts);
return $contacts && count($contacts) == 1 ? $contacts[0]['id'] : false;
}
/**
* saves the content of data to the db
*
* reimplemented to write for accounts some of the data to the account too and link it with the contact
*
* @param array $keys if given $keys are copied to data before saveing => allows a save as
* @param int $account_id if called by read account_id of account to save/link with contact (we dont overwrite the account-data in that case),
* otherwise we try getting it by accounts::name2id('person_id',$contact_id)
* @return int 0 on success and errno != 0 else
*/
function save($data=null,$account_id=0)
{
$this->data_merge($data);
// if called by read's automatic conversation --> dont change the email of the account (if set)
if (!$this->data['owner'] && $account_id &&
($email = $GLOBALS['egw']->accounts->id2name($account_id,'account_email')) && $data['email'] != $email)
{
if (!$data['email_home']) $data['email_home'] = $data['email'];
$data['email'] = $email;
}
if (!($error = parent::save()) && !$this->data['owner']) // successfully saved an account --> sync our data in the account-table
{
if (!$account_id && !($account_id = $GLOBALS['egw']->accounts->name2id($this->data['id'],'person_id')) &&
// try find a matching account for migration
!($account_id = $GLOBALS['egw']->accounts->name2id($this->data['n_given'].' '.$this->data['n_family'],'account_fullname')))
{
// ToDo create new account
}
// as the account object has no function to just read a record and NOT override it's internal data,
// we have to instanciate a new object and can NOT use $GLOBALS['egw']->accounts !!!
$account =& new accounts($account_id,'u');
$account->read_repository();
if (!$account->data['account_id']) return false; // account not found
foreach(array(
'n_family' => 'lastname',
'n_given' => 'firstname',
'email' => 'email',
'id' => 'person_id',
) as $c_name => $a_name)
{
$account->data[$a_name] = $this->data[$c_name];
}
$account->save_repository();
}
return $error;
}
}

View File

@ -2,8 +2,9 @@
/**************************************************************************\
* eGroupWare - Adressbook - General user interface object *
* http://www.egroupware.org *
* Written and (c) 2005 by Cornelius_weiss <egw@von-und-zu-weiss.de> *
* -------------------------------------------- *
* 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 *
@ -19,7 +20,8 @@ require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.bocontacts.inc.php');
*
* @package addressbook
* @author Cornelius Weiss <egw@von-und-zu-weiss.de>
* @copyright (c) 2005 by 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>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
class uicontacts extends bocontacts
@ -28,11 +30,19 @@ class uicontacts extends bocontacts
'search' => True,
'edit' => True,
'view' => True,
'index' => True,
'photo' => True,
);
var $prefs;
/**
* var boolean $private_addressbook use a separate private addressbook (former private flag), for contacts not shareable via regular read acl
*/
var $private_addressbook = false;
function uicontacts($contact_app='addressbook')
{
$this->bocontacts($contact_app);
foreach(array(
'tmpl' => 'etemplate.etemplate',
) as $my => $app_class)
@ -45,12 +55,483 @@ class uicontacts extends bocontacts
}
$this->$my = &$GLOBALS['egw']->$class;
}
$this->prefs =& $GLOBALS['egw_info']['user']['preferences']['addressbook'];
$this->private_addressbook = $this->contacts_repository == 'sql' && $this->prefs['private_addressbook'];
// our javascript
// to be moved in a seperate file if rewrite is over
$GLOBALS['egw_info']['flags']['java_script'] .= $this->js();
}
/**
* List contacts of an addressbook
*
* @param array $content=null submitted content
* @param string $msg=null message to show
*/
function index($content=null,$msg=null)
{
if (is_array($content))
{
$msg = $content['msg'];
if (isset($content['nm']['rows']['delete'])) // handle a single delete like delete with the checkboxes
{
list($id) = @each($content['nm']['rows']['delete']);
$content['action'] = 'delete';
$content['nm']['rows']['checked'] = array($id);
}
if ($content['action'] !== '')
{
if (!count($content['nm']['rows']['checked']) && !$content['use_all'])
{
$msg = lang('You need to select some contacts first');
}
else
{
if ($this->action($content['action'],$content['nm']['rows']['checked'],$content['use_all'],$success,$failed,$action_msg))
{
$msg .= lang('%1 contact(s) %2',$success,$action_msg);
}
else
{
$msg .= lang('%1 contact(s) %2, %3 failed because of insufficent rights !!!',$success,$action_msg,$failed);
}
}
}
}
$content = array(
'msg' => $msg ? $msg : $_GET['msg'],
);
$content['nm'] = $GLOBALS['egw']->session->appsession('index','addressbook');
// if (!is_array($content['nm']))
{
$content['nm'] = array(
'get_rows' => 'addressbook.uicontacts.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows'
'header_right' => 'addressbook.index.right', // I template to show right of the range-value, right-aligned (optional)
'bottom_too' => false, // I show the nextmatch-line (arrows, filters, search, ...) again after the rows
'never_hide' => True, // I never hide the nextmatch-line if less then maxmatch entrie
'start' => 0, // IO position in list
'cat_id' => 0, // IO category, if not 'no_cat' => True
'search' => '', // IO search pattern
'order' => 'n_family', // IO name of the column to sort after (optional for the sortheaders)
'sort' => 'ASC', // IO direction of the sort: 'ASC' or 'DESC'
'col_filter' => array(), // IO array of column-name value pairs (optional for the filterheaders)
'filter_label' => 'Addressbook', // I label for filter (optional)
// filter needs to be type string as as int it matches the private addressbook too!
'filter' => (string) $GLOBALS['egw_info']['user']['account_id'], // IO filter, if not 'no_filter' => True
'filter_no_lang' => True, // I set no_lang for filter (=dont translate the options)
'no_filter2' => True, // I disable the 2. filter (params are the same as for filter)
'filter2' => '', // IO filter2, if not 'no_filter2' => True
'filter2_no_lang'=> True, // I set no_lang for filter2 (=dont translate the options)
'lettersearch' => true,
);
// use the state of the last session stored in the user prefs
if (($state = @unserialize($this->prefs['index_state'])))
{
$content['nm'] = array_merge($content['nm'],$state);
}
}
$sel_options = array(
'filter' => $this->get_addressbooks(EGW_ACL_READ,lang('All')),
);
$sel_options['action'] = array(
'delete' => lang('Delete'),
'vcard' => lang('Export as VCard'),
)+$this->get_addressbooks(EGW_ACL_ADD);
foreach($this->content_types as $tid => $data)
{
$sel_options['col_filter[tid]'][$tid] = $data['name'];
}
$this->tmpl->read('addressbook.index');
return $this->tmpl->exec('addressbook.uicontacts.index',$content,$sel_options,$readonlys,$preserv);
}
/**
* apply an action to multiple contacts
*
* @param string/int $action 'delete', 'vcard', 'csv' or nummerical account_id to move contacts to that addessbook
* @param array $checked contact id's to use if !$use_all
* @param boolean $use_all if true use all contacts of the current selection (in the session)
* @param int &$success number of succeded actions
* @param int &$failed number of failed actions (not enought permissions)
* @param string &$action_msg translated verb for the actions, to be used in a message like %1 contacts 'deleted'
* @return boolean true if all actions succeded, false otherwise
*/
function action($action,$checked,$use_all,&$success,&$failed,&$action_msg)
{
//echo "<p>uicontacts::action('$action',".print_r($checked,true).','.(int)$use_all.",...)</p>\n";
$success = $failed = 0;
if ($use_all)
{
// get the whole selection
$query = $GLOBALS['egw']->session->appsession('index','addressbook');
$query['num_rows'] = -1; // all
$this->get_rows($query,$checked,$readonlys,true); // true = only return the id's
}
foreach($checked as $id)
{
switch($action)
{
case 'delete':
$action_msg = lang('deleted');
if (($Ok = ($contact = $this->read($id)) && $this->check_perms(EGW_ACL_DELETE,$contact)))
{
if ($contact['owner']) // regular contact
{
$Ok = $this->delete($id);
}
elseif (count($checked) == 1) // delete single account --> redirect to admin
{
$GLOBALS['egw']->redirect_link('/index.php',array(
'menuaction' => 'admin.uiaccounts.delete_user',
'account_id' => $contact['account_id'],
));
// this does NOT return!
}
else // no mass delete of accounts
{
$Ok = false;
}
}
break;
case 'vcard':
$action_msg = lang('exported');
$Ok = false; // todo
break;
case 'csv':
$action_msg = lang('exported');
$Ok = false; // todo
break;
default: // move to an other addressbook
if (!is_numeric($action) || !($this->grants[(int) $action] & EGW_ACL_EDIT)) // might be ADD in the future
{
return false;
}
$action_msg = lang('moved');
if (($OK = ($contact = $this->read($id)) && $this->check_perms(EGW_ACL_DELETE,$contact)))
{
if (!$contact['owner']) // no mass-change of accounts
{
$Ok = false;
}
elseif ($contact['owner'] != $action) // no need to change
{
$contact['owner'] = (int) $action;
$contact['private'] = 0;
$Ok = $this->save($contact);
}
}
break;
}
if ($Ok)
{
++$success;
}
else
{
++$failed;
}
}
return !$failed;
}
/**
* rows callback for index nextmatch
*
* @internal
* @param array &$query
* @param array &$rows returned rows/cups
* @param array &$readonlys eg. to disable buttons based on acl
* @param boolena $id_only=false if true only return (via $rows) an array of contact-ids, dont save state to session
* @return int total number of contacts matching the selection
*/
function get_rows(&$query,&$rows,&$readonlys,$id_only=false)
{
//echo "<p>uicontacts::get_rows(".print_r($query,true).")</p>\n";
if (!$id_only)
{
$GLOBALS['egw']->session->appsession('index','addressbook',$query);
// save the state of the index in the user prefs
$state = serialize(array(
'filter' => $query['filter'],
'cat_id' => $query['cat_id'],
'order' => $query['order'],
'sort' => $query['sort'],
));
if ($state != $this->prefs['index_state'])
{
$GLOBALS['egw']->preferences->add('addressbook','index_state',$state);
$GLOBALS['egw']->preferences->save_repository();
}
}
if (isset($query['col_filter']['cat_id'])) unset($query['col_filter']['cat_id']);
if ($query['cat_id'])
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories');
}
$cats = $GLOBALS['egw']->categories->return_all_children((int)$query['cat_id']);
$query['col_filter']['cat_id'] = count($cats) > 1 ? $cats : $query['cat_id'];
}
if ($query['filter'] !== '') // not all addressbooks
{
$query['col_filter']['owner'] = (string) (int) $query['filter'];
if ($this->private_addressbook)
{
$query['col_filter']['private'] = substr($query['filter'],-1) == 'p' ? 1 : 0;
}
}
// translate the select order to the realy used over all 3 columns
$sort = $query['sort'];
switch($query['order'])
{
case 'org_name':
$order = "org_name $sort,n_family $sort,n_given $sort";
break;
default:
$query['order'] = 'n_family';
case 'n_family':
$order = "n_family $sort,n_given $sort,org_name $sort";
break;
case 'n_given':
$order = "n_given $sort,n_family $sort,org_name $sort";
break;
case 'n_fileas':
$order = 'n_fileas '.$sort;
break;
}
$criteria = array();
if ($query['search'])
{
$cols = $this->columns_to_search;
if (!$query['filter']) // extra columns for search if accounts are included, eg. account_lid
{
$cols = array_merge($cols,$this->account_extra_search);
}
foreach($cols as $col)
{
$criteria[$col] = $query['search'];
}
}
if ($query['searchletter']) // only show contacts which ordercriteria starts with the given letter
{
$query['col_filter'][] = $query['order'].' LIKE '.$GLOBALS['egw']->db->quote($query['searchletter'].'%');
}
else // dont show contacts with empty order criteria
{
$query['col_filter'][] = $query['order']."!=''";
}
$rows = (array) $this->regular_search($criteria,$id_only,$order,'','%',false,'OR',array((int)$query['start'],(int) $query['num_rows']),$query['col_filter']);
if ($id_only) return $this->total; // no need to set other fields or $readonlys
if ($this->prefs['custom_colum'] != 'never' && $rows) // do we need the custom fields
{
foreach($rows as $n => $val)
{
$ids[] = $val['id'];
}
$customfields = $this->read_customfields($ids);
}
$order = $query['order'];
if (!$rows) $rows = array();
$readonlys = array();
$photos = $homeaddress = false;
foreach($rows as $n => $val)
{
$row =& $rows[$n];
$given = $row['n_given'] ? $row['n_given'] : ($row['n_prefix'] ? $row['n_prefix'] : '');
switch($order)
{
case 'org_name':
$row['first_org'] = $row['n_family'].($given ? ', '.$given : '');
break;
default:
$order = 'n_family';
case 'n_family':
$row['first_family'] = $row['n_family'].($given ? ', '.$given : '');
break;
case 'n_given':
$row['first_given'] = $given.' '.$row['n_family'];
break;
}
$this->type_icon($row['owner'],$row['private'],$row['tid'],$row['type'],$row['type_label']);
static $tel2show = array('tel_work','tel_cell','tel_home');
foreach($tel2show as $name)
{
$row[$name] .= ' '.($row['tel_prefer'] == $name ? '&#9829;' : ''); // .' ' to NOT remove the field
}
// allways show the prefered phone, if not already shown
if (!in_array($row['tel_prefer'],$tel2show) && $row[$row['tel_prefer']])
{
$row['tel_prefered'] = $row[$row['tel_prefer']].' &#9829;';
}
foreach(array('email','email_home') as $name)
{
if ($row[$name])
{
$row[$name.'_link'] = $this->email2link($row[$name]);
if ($GLOBALS['egw_info']['user']['apps']['felamimail'])
{
$row[$name.'_popup'] = '700x750';
}
}
else
{
$row[$name] = ' '; // to NOT remove the field
}
}
$readonlys["delete[$row[id]]"] = !$this->check_perms(EGW_ACL_DELETE,$row);
$readonlys["edit[$row[id]]"] = !$this->check_perms(EGW_ACL_EDIT,$row);
if ($row['photo']) $photos = true;
if (isset($customfields[$row['id']]))
{
foreach($this->customfields as $name => $data)
{
$row['customfields'][] = $customfields[$row['id']][$name];
}
}
if ($this->prefs['home_column'] != 'never' && !$homeaddress)
{
foreach(array('adr_two_countryname','adr_two_locality','adr_two_postalcode','adr_two_street','adr_two_street2') as $name)
{
if ($row[$name]) $homeaddress = true;
}
}
}
// disable photo column, if view contains no photo(s)
if (!$photos || $this->prefs['photo_column'] == 'never') $rows['no_photo'] = '1';
// disable customfields column, if we have no customefield(s)
if (!$customfields || $this->prefs['custom_column'] == 'never') $rows['no_customfields'] = '1';
// disable homeaddress column, if we have no homeaddress(es)
if ($homeaddress && !$this->prefs['home_column'] || $this->prefs['home_column'] == 'always') $rows['show_home'] = '1';
$rows['order'] = $order;
$rows['customfields'] = array_values($this->customfields);
// full app-header with all search criteria for specially for the print
$GLOBALS['egw_info']['flags']['app_header'] = lang('addressbook');
if ($query['filter'] !== '')
{
$GLOBALS['egw_info']['flags']['app_header'] .= ': '.($query['filter'] == '0' ? lang('accounts') :
($GLOBALS['egw']->accounts->get_type($query['filter']) == 'g' ?
lang('Group %1',$GLOBALS['egw']->accounts->id2name($query['filter'])) :
$GLOBALS['egw']->common->grab_owner_name((int)$query['filter']).
(substr($query['filter'],-1) == 'p' ? ' ('.lang('private').')' : '')));
}
if ($query['cat_id'])
{
$GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Category').' '.$GLOBALS['egw']->categories->id2name($query['cat_id']);
}
if ($query['searchletter'])
{
$order = $order == 'org_name' ? lang('company name') : ($order == 'n_given' ? lang('first name') : lang('last name'));
$GLOBALS['egw_info']['flags']['app_header'] .= ' - '.lang("%1 starts with '%2'",$order,$query['searchletter']);
}
if ($query['search'])
{
$GLOBALS['egw_info']['flags']['app_header'] .= ' - '.lang("Search for '%1'",$query['search']);
}
return $this->total;
}
/**
* Get addressbook type icon from owner, private and tid
*
* @param int $owner user- or group-id or 0 for accounts
* @param boolean $private
* @param string $tid 'n' for regular addressbook
* @param string &$icon icon-name
* @param string &$label translated label
*/
function type_icon($owner,$private,$tid,&$icon,&$label)
{
if (!$owner)
{
$icon = 'accounts';
$label = lang('accounts');
}
elseif ($row['private'])
{
$icon = 'private';
$label = lang('private');
}
elseif ($tid != 'n')
{
// ToDo Conny: tid-icons
$icon = '';
$label = $tid;
}
elseif ($GLOBALS['egw']->accounts->get_type($owner) == 'g')
{
$icon = 'group';
$label = lang('group %1',$GLOBALS['egw']->accounts->id2name($owner));
}
else
{
$icon = 'personal';
$label = $owner == $this->user ? lang('personal') : $GLOBALS['egw']->common->grab_owner_name($owner);
}
}
/**
* Get the availible addressbooks of the user
*
* @param int $required=EGW_ACL_READ required rights on the addressbook
* @param string $extra_label first label if given (already translated)
* @return array with owner => label pairs
*/
function get_addressbooks($required=EGW_ACL_READ,$extra_label=null)
{
//echo "uicontacts::get_addressbooks($required,$include_all) grants="; _debug_array($this->grants);
$addressbooks = array();
if ($extra_label) $addressbooks[''] = $extra_label;
$addressbooks[$this->user] = lang('Personal');
// add all group addressbooks the user has the necessary rights too
foreach($this->grants as $uid => $rights)
{
if (($rights & $required) && $GLOBALS['egw']->accounts->get_type($uid) == 'g')
{
$addressbooks[$uid] = lang('Group %1',$GLOBALS['egw']->accounts->id2name($uid));
}
}
if ($this->grants[0] & $required)
{
$addressbooks[0] = lang('Accounts');
}
// add all other user addressbooks the user has the necessary rights too
foreach($this->grants as $uid => $rights)
{
if ($uid != $this->user && ($rights & $required) && $GLOBALS['egw']->accounts->get_type($uid) == 'u')
{
$addressbooks[$uid] = $GLOBALS['egw']->common->grab_owner_name($uid);
}
}
if ($this->private_addressbook)
{
$addressbooks[$this->user.'p'] = lang('Private');
}
//_debug_array($addressbooks);
return $addressbooks;
}
/**
* Edit a contact
*
@ -71,16 +552,26 @@ class uicontacts extends bocontacts
if (is_array($content))
{
list($button) = @each($content['button']);
unset($content['button']);
$content['private'] = (int) ($content['owner'] && substr($content['owner'],-1) == 'p');
$content['owner'] = (string) (int) $content['owner'];
switch($button)
{
case 'save':
case 'apply':
if ($content['delete_photo']) unset($content['jpegphoto']);
if (is_array($content['upload_photo']) && !empty($content['upload_photo']['tmp_name']) &&
$content['upload_photo']['tmp_name'] != 'none')
{
$content['jpegphoto'] = $this->resize_photo($content['upload_photo']);
}
$links = false;
if (!$content['id'] && is_array($content['link_to']['to_id']))
{
$links = $content['link_to']['to_id'];
}
$content = $this->save($content);
$this->save($content);
// writing links for new entry, existing ones are handled by the widget itself
if ($links && $content['id'])
{
@ -88,19 +579,21 @@ class uicontacts extends bocontacts
}
if ($button == 'save')
{
echo "<html><body><script>var referer = opener.location;opener.location.href = referer;window.close();</script></body></html>\n";
echo "<html><body><script>var referer = opener.location;opener.location.href = referer+(referer.search?'&':'?')+'msg=".
addslashes(urlencode(lang('Contact saved')))."'; window.close();</script></body></html>\n";
$GLOBALS['egw']->common->egw_exit();
}
$content['link_to']['to_id'] = $content['id'];
$GLOBALS['egw_info']['flags']['java_script'] .= "<script LANGUAGE=\"JavaScript\">
var referer = opener.location;
opener.location.href = referer;</script>";
opener.location.href = referer+(referer.search?'&':'?')+'msg=".addslashes(urlencode(lang('Contact saved')))."';</script>";
break;
case 'delete':
if(!$this->delete($content));
if($this->delete($content));
{
echo "<html><body><script>var referer = opener.location;opener.location.href = referer;window.close();</script></body></html>\n";
echo "<html><body><script>var referer = opener.location; opener.location.href = referer+(referer.search?'&':'?')+'msg=".
addslashes(urlencode(lang('Contact deleted !!!')))."';window.close();</script></body></html>\n";
$GLOBALS['egw']->common->egw_exit();
}
break;
@ -110,21 +603,38 @@ class uicontacts extends bocontacts
else
{
$content = array();
$contact_id = $_GET['contact_id'] ? $_GET['contact_id'] : 0;
$contact_id = $_GET['contact_id'] ? $_GET['contact_id'] : ((int)$_GET['account_id'] ? 'account:'.(int)$_GET['account_id'] : 0);
$view = $_GET['view'];
if ($contact_id)
// new contact --> set some defaults
if ($contact_id && is_array($content = $this->read($contact_id)))
{
$content = $this->read($contact_id);
$contact_id = $content['id']; // it could have been: "account:$account_id"
}
else // look if we have presets for a new contact
else // not found
{
if (isset($_GET['owner']) && $_GET['owner'] !== '')
{
$content['owner'] = $_GET['owner'];
}
else
{
$state = $GLOBALS['egw']->session->appsession('index','addressbook');
$content['owner'] = $state['filter'];
unset($state);
}
$content['private'] = (int) ($content['owner'] && substr($content['owner'],-1) == 'p');
if (!($this->grants[$content['owner'] = (string) (int) $content['owner']] & EGW_ACL_ADD))
{
$content['owner'] = (string) $this->user;
}
$new_type = array_keys($this->content_types);
$content['tid'] = $_GET['typeid'] ? $_GET['typeid'] : $new_type[0];
foreach($this->get_contact_conlumns() as $field => $data)
foreach($this->get_contact_columns() as $field => $data)
{
if ($_GET['presets'][$field]) $content[$field] = $_GET['presets'][$field];
}
$content['creator'] = $this->user;
$content['created'] = $this->now_su;
}
if($content && $_GET['makecp']) // copy the contact
@ -135,30 +645,34 @@ class uicontacts extends bocontacts
$GLOBALS['egw_info']['user']['account_firstname'],$GLOBALS['egw_info']['user']['account_lastname']),
$content['id']));
unset($content['id']);
$content['creator'] = $this->user;
$content['created'] = $this->now_su;
}
else
{
$content['link_to']['to_id'] = (int) $contact_id;
$content['link_to']['to_id'] = $contact_id;
}
}
//_debug_array($content);
$readonlys['button[delete]'] = !$this->check_perms(EGW_ACL_DELETE,$content);
$readonlys['button[copy]'] = $readonlys['button[edit]'] = $readonlys['button[vcard]'] = true;
$preserv = array(
'id' => $content['id'],
'lid' => $content['lid'],
'owner' => $content['owner'],
'fn' => $content['fn'],
'geo' => $content['geo'],
'access' => $content['access'],
);
$sel_options['fileas_type'] = $this->fileas_options($content);
$sel_options['owner'] = $this->get_addressbooks(EGW_ACL_ADD);
if ((string) $content['owner'] !== '')
{
if (!isset($sel_options['owner'][(int)$content['owner']]))
{
$sel_options['owner'][(int)$content['owner']] = $GLOBALS['egw']->common->grab_owner_name($content['owner']);
}
$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
}
for($i = -23; $i<=23; $i++) $tz[$i] = ($i > 0 ? '+' : '').$i;
$sel_options['tz'] = $tz;
$content['tz'] = $content['tz'] ? $content['tz'] : 0;
foreach($this->content_types as $type => $data) $sel_options['tid'][$type] = $data['name'];
foreach($GLOBALS['egw']->acl->get_all_location_rights($GLOBALS['egw']->acl->account_id,'addressbook',true) as $id => $right)
{
if($id < 0) $sel_options['published_groups'][$id] = $GLOBALS['egw']->accounts->id2name($id);
@ -168,10 +682,76 @@ class uicontacts extends bocontacts
'to_app' => 'addressbook',
'to_id' => $content['link_to']['to_id'],
);
$content['photo'] = $this->photo_src($content['id'],$content['jpegphoto'],'template');
if ($content['private']) $content['owner'] .= 'p';
$GLOBALS['egw_info']['flags']['include_xajax'] = true;
$this->tmpl->read($this->content_types[$content['tid']]['options']['template']);
return $this->tmpl->exec('addressbook.uicontacts.edit',$content,$sel_options,$readonlys,$preserv, 2);
return $this->tmpl->exec('addressbook.uicontacts.edit',$content,$sel_options,$readonlys,$content, 2);
}
function ajax_setFileasOptions($n_prefix,$n_given,$n_middle,$n_family,$n_suffix,$org_name)
{
$names = array(
'n_prefix' => $n_prefix,
'n_given' => $n_given,
'n_middle' => $n_middle,
'n_family' => $n_family,
'n_suffix' => $n_suffix,
'org_name' => $org_name,
);
$response =& new xajaxResponse();
$response->addScript("setOptions('".addslashes(implode("\b",$this->fileas_options($names)))."');");
return $response->getXML();
}
/**
* resizes the uploaded photo to 60*80 pixel and returns it
*
* @param array $file info uploaded file
* @return string with resized jpeg photo
*/
function resize_photo($file)
{
switch($file['type'])
{
case 'image/gif':
$upload = imagecreatefromgif($file['tmp_name']);
break;
case 'image/jpeg':
case 'image/pjpeg':
$upload = imagecreatefromjpeg($file['tmp_name']);
break;
case 'image/png':
case 'image/x-png':
$upload = imagecreatefrompng($file['tmp_name']);
break;
default:
return null;
}
if (!$upload) return null;
list($src_w,$src_h) = getimagesize($file['tmp_name']);
// scale the image to a width of 60 and a height according to the proportion of the source image
$photo = imagecreatetruecolor($dst_w = 60,$dst_h = round($src_h * 60 / $src_w));
imagecopyresized($photo,$upload,0,0,0,0,$dst_w,$dst_h,$src_w,$src_h);
//echo "<p>imagecopyresized(\$photo,\$upload,0,0,0,0,$dst_w,$dst_h,$src_w,$src_h);</p>\n";
ob_start();
imagejpeg($photo,'',90);
$jpeg = ob_get_contents();
ob_end_clean();
imagedestroy($photo);
imagedestroy($upload);
return $jpeg;
}
function view($content=null)
{
if(is_array($content))
@ -183,21 +763,21 @@ class uicontacts extends bocontacts
$GLOBALS['egw']->redirect_link('/index.php','menuaction=addressbook.uivcard.out&ab_id=' .$content['id']);
case 'cancel':
$GLOBALS['egw']->redirect_link('/index.php','menuaction=addressbook.uiaddressbook.index');
$GLOBALS['egw']->redirect_link('/index.php','menuaction=addressbook.uicontacts.index');
case 'delete':
$GLOBALS['egw']->redirect_link('/index.php',array(
'menuaction' => 'addressbook.uiaddressbook.index',
'menuaction' => 'addressbook.uicontacts.index',
'msg' => $this->delete($content) ? lang('Something went wrong by deleting this contact') : lang('Contact deleted !!!'),
));
}
}
else
{
if(!(int)$_GET['contact_id'] || !is_array($content = $this->read((int) $_GET['contact_id'])))
if(!$_GET['contact_id'] || !is_array($content = $this->read($_GET['contact_id'])))
{
$GLOBALS['egw']->redirect_link('/index.php',array(
'menuaction' => 'addressbook.uiaddressbook.index',
'menuaction' => 'addressbook.uicontacts.index',
'msg' => $content,
));
}
@ -217,14 +797,12 @@ class uicontacts extends bocontacts
'to_id' => $content['id'],
);
$readonlys['link_to'] = $readonlys['customfields'] = true;
$readonlys['button[save]'] = $readonlys['button[apply]'] = true;
$readonlys['button[save]'] = $readonlys['button[apply]'] = $readonlys['change_photo'] = true;
$readonlys['button[delete]'] = !$this->check_perms(EGW_ACL_DELETE,$content);
$readonlys['button[edit]'] = !$this->check_perms(EGW_ACL_EDIT,$content);
for($i = -23; $i<=23; $i++) $tz[$i] = ($i > 0 ? '+' : '').$i;
$sel_options['tz'] = $tz;
$content['tz'] = $content['tz'] ? $content['tz'] : 0;
$sel_options['fileas_type'][$content['fileas_type']] = $this->fileas($content);
$sel_options['owner'] = $this->get_addressbooks();
for($i = -23; $i<=23; $i++) $tz[$i] = ($i > 0 ? '+' : '').$i;
$sel_options['tz'] = $tz;
$content['tz'] = $content['tz'] ? $content['tz'] : 0;
@ -247,7 +825,8 @@ class uicontacts extends bocontacts
elseif ($url)
{
$content[$name.'_link'] = $url;
$this->tmpl->set_cell_attribute($name,'size','b,@'.$name.'_link,,,_blank');
$this->tmpl->set_cell_attribute($name,'size','b,@'.$name.'_link,,,_blank'.
($GLOBALS['egw_info']['user']['apps']['felamimail']?',700x750':''));
}
$this->tmpl->set_cell_attribute($name,'type','label');
$this->tmpl->set_cell_attribute($name,'no_lang',true);
@ -375,6 +954,29 @@ class uicontacts extends bocontacts
return $this->tmpl->exec('addressbook.uicontacts.search',$content,$sel_options,$readonlys,$preserv);
}
function photo()
{
ob_start();
$contact_id = isset($_GET['contact_id']) ? $_GET['contact_id'] :
(isset($_GET['account_id']) ? 'account:'.$_GET['account_id'] : 0);
if (substr($contact_id,0,8) == 'account:')
{
$contact_id = $GLOBALS['egw']->accounts->id2name(substr($contact_id,8),'person_id');
}
if (!($contact = $this->read($contact_id)) || !$contact['jpegphoto'])
{
$GLOBALS['egw']->redirect($GLOBALS['egw']->common->image('addressbook','photo'));
}
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'])));
echo $contact['jpegphoto'];
exit;
}
}
function js()
{
return '<script LANGUAGE="JavaScript">
@ -418,6 +1020,29 @@ class uicontacts extends bocontacts
}
}
function setFileasOptions(input)
{
var prefix = document.getElementById("exec[n_prefix]").value;
var given = document.getElementById("exec[n_given]").value;
var middle = document.getElementById("exec[n_middle]").value;
var family = document.getElementById("exec[n_family]").value;
var suffix = document.getElementById("exec[n_suffix]").value;
var org = document.getElementById("exec[org_name]").value;
xajax_doXMLHTTP("addressbook.uicontacts.ajax_setFileasOptions",prefix,given,middle,family,suffix,org);
}
function setOptions(options_str)
{
var options = options_str.split("\\\\b");
var selbox = document.getElementById("exec[fileas_type]");
var i;
for (i=0; i < options.length; i++)
{
selbox.options[i].text = options[i];
}
}
</script>';
}
}

View File

@ -1,19 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare *
* http://www.egroupware.org *
* Written by Joseph Engo <jengo@phpgroupware.org> *
* -------------------------------------------- *
* 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$
$GLOBALS['pref']->change('addressbook','company','addressbook_True');
$GLOBALS['pref']->change('addressbook','lastname','addressbook_True');
$GLOBALS['pref']->change('addressbook','firstname','addressbook_True');
$GLOBALS['pref']->change('addressbook','default_category','');
?>

View File

@ -1,7 +0,0 @@
<?php
global $acl,$account_id;
// Add default acl to allow the new user to access their
// addressbook
// This file is not really needed or used at this time
$acl->add('addressbook','u_'.$account_id,1);
?>

View File

@ -1,25 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare *
* http://www.egroupware.org *
* Written by Joseph Engo <jengo@phpgroupware.org> *
* -------------------------------------------- *
* 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$
// $Source$
// Only Modify the $file and $title variables.....
$title = $appname;
$file = Array(
'Site Configuration' => $GLOBALS['egw']->link('/index.php','menuaction=admin.uiconfig.index&appname=' . $appname),
'Edit custom fields' => $GLOBALS['egw']->link('/index.php','menuaction=admin.customfields.edit&appname='. $appname),
'Global Categories' => $GLOBALS['egw']->link('/index.php','menuaction=admin.uicategories.index&appname=addressbook')
);
//Do not modify below this line
display_section($appname,$title,$file);
?>

View File

@ -1,28 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare *
* http://www.egroupware.org *
* Written by Joseph Engo <jengo@phpgroupware.org> *
* -------------------------------------------- *
* 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$ */
if((int)$GLOBALS['hook_values']['account_id'] > 0)
{
$contacts = CreateObject('phpgwapi.contacts');
if((int)$_POST['new_owner'] == 0)
{
$contacts->delete_all((int)$GLOBALS['hook_values']['account_id']);
}
else
{
$contacts->change_owner((int)$GLOBALS['hook_values']['account_id'],(int)$_POST['new_owner']);
}
}
?>

View File

@ -1,26 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare *
* http://www.egroupware.org *
* Written by Joseph Engo <jengo@phpgroupware.org> *
* -------------------------------------------- *
* 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$ */
{
// Only Modify the $file and $title variables.....
$title = $appname;
$file = array();
$file['Preferences'] = $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiaddressbook.preferences');
if(!$GLOBALS['egw_info']['server']['deny_user_grants_access'])
$file['Grant Access'] = $GLOBALS['egw']->link('/index.php','menuaction=preferences.uiaclprefs.index&acl_app='.$appname);
$file['Edit Categories'] = $GLOBALS['egw']->link('/index.php','menuaction=preferences.uicategories.index&cats_app='.$appname . '&cats_level=True&global_cats=True');
//Do not modify below this line
display_section($appname,$title,$file);
}
?>

View File

@ -1,67 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare - Calendar's Sidebox-Menu for idots-template *
* http://www.egroupware.org *
* Written by Pim Snel <pim@lingewoud.nl> *
* -------------------------------------------- *
* 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$ */
{
/*
This hookfile is for generating an app-specific side menu used in the idots
template set.
$menu_title speaks for itself
$file is the array with link to app functions
display_sidebox can be called as much as you like
*/
$menu_title = $GLOBALS['egw_info']['apps'][$appname]['title'];
$file = Array(
array(
'text' => '<a class="textSidebox" href="'.$GLOBALS['egw']->link('/index.php',array('menuaction' => 'addressbook.uicontacts.edit')).
'" onclick="window.open(this.href,\'_blank\',\'dependent=yes,width=850,height=440,scrollbars=yes,status=yes\');
return false;">'.lang('Add').'</a>',
'no_lang' => true,
'link' => false
),
// 'Add'=>$GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiaddressbook.add'),
'Advanced search'=>$GLOBALS['egw']->link('/index.php','menuaction=addressbook.uicontacts.search'),
'_NewLine_', // give a newline
'import contacts' => $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiXport.import'),
'export contacts' => $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiXport.export')
);
display_sidebox($appname,$menu_title,$file);
if($GLOBALS['egw_info']['user']['apps']['preferences'])
{
$menu_title = lang('Preferences');
$file = array();
$file['Addressbook preferences'] = $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiaddressbook.preferences');
if(!$GLOBALS['egw_info']['server']['deny_user_grants_access'])
$file['Grant Access'] = $GLOBALS['egw']->link('/index.php','menuaction=preferences.uiaclprefs.index&acl_app=addressbook');
$file['Edit Categories'] = $GLOBALS['egw']->link('/index.php','menuaction=preferences.uicategories.index&cats_app=addressbook&cats_level=True&global_cats=True');
display_sidebox($appname,$menu_title,$file);
}
if ($GLOBALS['egw_info']['user']['apps']['admin'])
{
$menu_title = lang('Administration');
$file = Array(
'Configuration'=>$GLOBALS['egw']->link('/index.php','menuaction=admin.uiconfig.index&appname=addressbook'),
'Custom Fields'=>$GLOBALS['egw']->link('/index.php','menuaction=admin.customfields.edit&appname=addressbook'),
'Global Categories' =>$GLOBALS['egw']->link('/index.php','menuaction=admin.uicategories.index&appname=addressbook')
);
display_sidebox($appname,$menu_title,$file);
}
}
?>

View File

@ -11,16 +11,14 @@
/* $Id$ */
$GLOBALS['egw_info'] = array();
$GLOBALS['egw_info']['flags'] = array(
'currentapp' => 'addressbook',
'noheader' => True,
'nonavbar' => True
);
$GLOBALS['egw_info'] = array(
'flags' => array(
'currentapp' => 'addressbook',
'noheader' => True,
'nonavbar' => True
));
include('../header.inc.php');
$obj = CreateObject('addressbook.uiaddressbook');
$obj->index();
ExecMethod('addressbook.uicontacts.index');
$GLOBALS['phpgw']->common->phpgw_footer();
?>
$GLOBALS['egw']->common->egw_footer();

File diff suppressed because one or more lines are too long

View File

@ -1,35 +1,40 @@
%1 contact(s) %2 addressbook de %1 Kontakt(e) %2
%1 contact(s) %2, %3 failed because of insufficent rights !!! addressbook de %1 Kontakt(e) %2, %3 nicht wegen fehlender Rechte !!!
%1 records imported addressbook de %1 Datensätze importiert
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook de %1 Datensätze gelesen (noch nicht importiert, sie können %2zurück%3 gehen und Test-Import auschalten)
%1 starts with '%2' addressbook de %1 beginnt mit '%2'
(e.g. 1969) addressbook de (z.B. 1966)
<b>no conversion type &lt;none&gt; could be located.</b> please choose a conversion type from the list addressbook de <b>Kein Übersetzungstyp <none> konnte gefunden werden.</b> Bitte wählen Sie einen Übersetzungstyp aus der Liste
@-eval() is only availible to admins!!! addressbook de @-eval() ist nur verfügbar für Administratoren!!!
actions addressbook de Befehle
add a new contact addressbook de Neuen Kontakt anlegen
add a single entry by passing the fields. addressbook de Hinzufügen eines einzelnen Eintrags durch Übergeben der Felder.
add custom field addressbook de Benutzerdefiniertes Feld hinzufügen
address book common de Adressbuch
address book - vcard in addressbook de Adressbuch - VCard in
address book - view addressbook de Adressbuch - Anzeigen
address line 2 addressbook de Adresszeile 2
address line 3 addressbook de Adresszeile 3
address type addressbook de Adresstyp
addressbook common de Adressbuch
addressbook preferences addressbook de Adressbuch Einstellungen
addressbook the contact should be saved to addressbook de Adressbuch in das der Kontakt gespeichert werden soll
addressbook-fieldname addressbook de Adressbuch Feldname
addvcard addressbook de VCard hinzufügen
advanced search addressbook de Erweiterte Suche
alt. csv import addressbook de Alt. CSV Import
always addressbook de immer
apply the action on the whole selection, not only the shown contacts!!! addressbook de Wendet den Befehl auf die gesamte Selektion an, NICHT nur auf die angezeigten Kontakte!!!
are you shure you want to delete this contact? addressbook de Diesen Kontakt löschen?
are you sure you want to delete this field? addressbook de Sind Sie sicher, dass Sie dieses Feld löschen wollen?
bbs phone addressbook de BBS
assistent addressbook de Assistent
birthday common de Geburtstag
birthdays common de Geburtstage
blank addressbook de Leer
business common de Geschäftlich
business address type addressbook de Typ der geschäftl. Adresse
business address addressbook de Geschäftsadresse
business city addressbook de Stadt geschäftl.
business country addressbook de Land geschäftl.
business email addressbook de E-Mail geschäftl.
business email type addressbook de Typ der geschäftl. E-Mail
business fax addressbook de Fax geschäftl.
business phone addressbook de Tel. geschäftl.
business state addressbook de Bundesland geschäftl.
@ -38,11 +43,11 @@ business zip code addressbook de PLZ gesch
car phone addressbook de Autotelefon
cell phone addressbook de Mobiltelefon
charset of file addressbook de Zeichensatz der Datei
choose an icon for this contact type addressbook de Wählen Sie ein Icon für diesen Adresstyp
chosse an etemplate for this contact type addressbook de Wählen Sie ein eTemplate für diesen Addresstyp
check all addressbook de Alle auswählen
choose an icon for this contact type admin de Wählen Sie ein Icon für diesen Kontakt Typ
chosse an etemplate for this contact type admin de Wählen Sie ein eTemplate für diesen Kontakt Typ
city common de Stadt
company common de Firma
company name common de Firmenname
configuration common de Konfiguration
contact common de Kontakt
contact application admin de Kontakt Anwendung
@ -51,6 +56,7 @@ contact settings admin de Kontakt Einstellungen
copied by %1, from record #%2. addressbook de Kopiert von %1, vom Datensatz Nr. %2.
country common de Land
create new links addressbook de Neue Verknüpfung erstellen
created addressbook de Angelegt von
credit addressbook de Darlehen
csv-fieldname addressbook de CSV-Feldname
csv-filename addressbook de CSV-Dateiname
@ -59,7 +65,12 @@ custom fields addressbook de Benutzerdefinierte Felder
debug output in browser addressbook de Debugausgaben in Browser
default filter addressbook de Standardfilter
delete a single entry by passing the id. addressbook de Löscht einen einzelnen Eintrag durch Übergabe seiner ID.
delete this contact addressbook de Diesen Kontakt löschen
deleted addressbook de gelöscht
deletes the photo addressbook de Löscht das Foto
department common de Abteilung
displays a remider for birthdays happening today or tomorrow on the startpage (page you get when you enter egroupware or click on the homepage icon). addressbook de Zeigt auf der Startseite eine Geburtstags Erinnerung an, falls heute oder morgen jemand Geburtstag hat. Die Startseite ist die Seite die Sie sehen, wenn Sie eGroupWare betreten oder auf das Startseiten Icon (Haus) klicken.
do you want a private addressbook, which can not be viewed by users, you grant access to your personal addressbook? addressbook de Wollen Sie ein privates Adressbuch, dass nicht von Benutzern einsehbar ist, denen Sie Zugriff auf Ihr persönliches Adressbuch gegeben haben?
do your really want to delete this contact? addressbook de Wollen sie diesen Kontakt wirklich löschen?
doesn't matter addressbook de egal
domestic addressbook de Wohnung
@ -71,12 +82,15 @@ edit custom fields admin de Benutzerdefinierte Felder bearbeiten
edit phonenumbers - addressbook de Telefonnummern bearbeiten
email & internet addressbook de Email & Internet
empty for all addressbook de leer für alle
enable an extra private addressbook addressbook de Privates Adressbuch einschalten
enter the path to the exported file here addressbook de Bitte geben Sie den Pfad für die exportierte Datei an
existing links addressbook de Bestehende Verknüpfungen
export addressbook de Export
export as vcard addressbook de VCard exportieren
export contacts addressbook de Kontakte exportieren
export file name addressbook de Dateiname zum Exportieren
export from addressbook addressbook de Export vom Adressbuch
exported addressbook de exportiert
extra addressbook de Extra
fax addressbook de Telefax
fax number common de Telefaxnummer
@ -89,11 +103,11 @@ full name addressbook de vollst
geo addressbook de GEO
global categories addressbook de Globale Kategorien
grant addressbook access common de Berechtigungen
home address type addressbook de Typ der Privatadresse
group %1 addressbook de Gruppe %1
home address addressbook de Privatadresse
home city addressbook de Stadt privat
home country addressbook de Land privat
home email addressbook de E-Mail privat
home email type addressbook de Typ der privaten E-Mail
home phone addressbook de Tel. privat
home state addressbook de Bundesland privat
home street addressbook de Straße privat
@ -111,7 +125,6 @@ import next set addressbook de N
import_instructions addressbook de In Netscape, öffnen Sie das Adressbuch und wählen Sie <b>Exportieren</b> aus dem Datei Menü aus. Die Dateien werden im LDIF Formaz exportiert.<p> In Outlook wählen Sie den Ordner Kontakte aus, wählen Sie <b>Importieren und Exportieren...</p> aus dem <b>Datei</b> Menü aus und Exportieren Sie die Kontakte als eine CSV Datei.<p> In Palm Desktop 4.0 oder größer, öffnen Sie Ihr Adressbuch und wählen Sie <b>Export</b> aus dem Datei-Menü aus. Die Datei wird im VCard-Format exportiert.
income addressbook de Einkommen
international addressbook de International
isdn phone addressbook de ISDN-Tel.
label addressbook de Adressetikett
last modified addressbook de Letzte Änderung
ldap context for contacts admin de LDAP-Kontext für Kontakte
@ -131,11 +144,13 @@ mobile addressbook de Mobil
mobile phone addressbook de Mobiltelefon
modem phone addressbook de Modem
more ... addressbook de Mehr ...
moved addressbook de verschoben
multiple vcard addressbook de Mehrere VCards
no vcard addressbook de Keine VCard
number addressbook de Nummer
number of records to read (%1) addressbook de Anzahl der einzulesenden Datensätze (%1)
options for type addressbook de Optionen für Typ
only if there is content addressbook de nur wenn etwas angezeigt wird
options for type admin de Optionen für Typ
organisation addressbook de Organisation
other number addressbook de andere Nr.
other phone addressbook de anderes Telefon
@ -143,7 +158,9 @@ pager common de Pager
parcel addressbook de Lieferadresse
phone number common de Telefonnummer
phone numbers common de Telefonnummern
photo addressbook de Foto
please enter a name for that field ! addressbook de Bitte geben sie einen Namen für das Feld an!
please select only one category addressbook de Bitte nur eine Kategorie auswählen
postal common de Postanschrift
pref addressbook de präf
prefix addressbook de Anrede
@ -154,12 +171,18 @@ read a list of entries. addressbook de Liest eine Liste von Eintr
read a single entry by passing the id and fieldlist. addressbook de Liest einen einzelnen Eintrag über seine ID und Feldliste.
record access addressbook de Zugriffsrechte
record owner addressbook de Datensatzeigentümer
retrieve contacts admin de Kontakte laden
role addressbook de Funktion
room addressbook de Raum
search for '%1' addressbook de Suche nach '%1'
select a portrait format jpeg photo. it will be resized to 60 pixel width. addressbook de Wählen Sie ein hochformatiges jpeg Foto. Es wird 60 Pixel breit skaliert.
select addressbook type addressbook de Typ des Adressbuchs auswählen
select all addressbook de Alles auswählen
select an action or addressbook to move to addressbook de Befehl oder Adressbuch zum Verschieben auswählen
select the type of conversion addressbook de Typ der Umwandlung auswählen
select the type of conversion: addressbook de Typ der Umwandlung auswählen:
select where you want to store admin de Auswählen wo Sie speichern wollen
select where you want to store / retrieve contacts admin de Auswählen wo Sie Adressen speichern wollen
show addressbook de Anzeigen
show a column for %1 addressbook de Zeige eine %1 Spalte
show birthday reminders on main screen addressbook de Geburtstagserinnerungen auf der Startseite anzeigen
something went wrong by deleting %1 addressbook de Beim Löschen von %1 trat ein Fehler auf
something went wrong by deleting this contact addressbook de Beim Löschen dieses Kontaktes trat ein Fehler auf
@ -175,25 +198,29 @@ test import (show importable records <u>only</u> in browser) addressbook de Test
that field name has been used already ! addressbook de Dieser Feldname wird bereits benutzt!
this person's first name was not in the address book. addressbook de Der Vorname dieser Person ist nicht im Adressbuch.
this person's last name was not in the address book. addressbook de Der Nachname dieser Person ist nicht im Adressbuch.
timezone addressbook de Zeitzone
to many might exceed your execution-time-limit addressbook de zu viel können ihre Laufzeitbeschränkung überschreiten
today is %1's birthday! common de Heute ist der Geburtstag von %1!
tomorrow is %1's birthday. common de Morgen ist der Geburtstag von %1.
translation addressbook de Übersetzung
update a single entry by passing the fields. addressbook de Aktualisiert einen einzelnen Eintrag durch Übergabe seiner Felder.
upload or delete the photo addressbook de Foto hochladen oder löschen
use country list addressbook de Länderliste benutzen
vcard common de VCard
vcards require a first name entry. addressbook de VCards benötigen einen Vornamen.
vcards require a last name entry. addressbook de VCards benötigen einen Nachnamen.
video phone addressbook de Bildtelefon
voice phone addressbook de Telefon
warning!! ldap is valid only if you are not using contacts for accounts storage! admin de WARNUNG!! LDAP darf nur verwendet werden, wenn sie die Benutzerkonten nicht im Adressbuch speichern!
warning: all contacts found will be deleted! addressbook de WARNUNG: Alle gefundenen Kontakte werden gelöscht!
when should the contacts list display that colum. "only if there is content" hides the column, unless there is some content in the view. addressbook de Wann soll die Adressliste diese Spalte anzeigen. "Nur wenn etwas angezeigt wird" blendet die Spalte aus, wenn Sie in dieser Anzeige leer wäre.
whole selection addressbook de gesamte Selektion
work phone addressbook de Tel dienstl.
write (update or add) a single entry by passing the fields. addressbook de Schreibt (aktualiseren oder zufügen) eines einzelnen Eintrags durch Übergabe der Felder
you are not permitted to delete contact %1 addressbook de Sie haben nicht die Berechtigungen um den Kontakt %1 zu löschen
you are not permittet to delete this contact addressbook de Sie haben nicht die Berechtigung diesen Kontakt zu löschen
you are not permittet to edit this contact addressbook de Sie haben nicht die Berechtigung diesen Kontakt zu bearbeiten
you are not permittet to view this contact addressbook de Sie haben nicht die Berechtigung diesen Kontakt zu betrachen
you must select a vcard. (*.vcf) addressbook de Sie müssen eine VCard auswählen (*.vcf)
you must select at least 1 column to display addressbook de Sie müssen mindestens eine Spalte zum Anzeigen auswählen
you need to select some contacts first addressbook de Sie müssen zuerst Kontakte auswählen
zip code common de PLZ
zip_note addressbook de <p><b>Notiz:</b>Die Datei kann ein zip Archiv sein, bestehend aus .csv, .vcf oder .ldif Dateien. Sie dürfen die Dateitypen pro Import nicht mischen!

View File

@ -1,35 +1,40 @@
%1 contact(s) %2 addressbook en %1 contact(s) %2
%1 contact(s) %2, %3 failed because of insufficent rights !!! addressbook en %1 contact(s) %2, %3 failed because of insufficent rights !!!
%1 records imported addressbook en %1 records imported
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook en %1 records read (not yet imported, you may go %2back%3 and uncheck Test Import)
%1 starts with '%2' addressbook en %1 starts with '%2'
(e.g. 1969) addressbook en (e.g. 1969)
<b>no conversion type &lt;none&gt; could be located.</b> please choose a conversion type from the list addressbook en <b>No conversion type &lt;none&gt; could be located.</b> Please choose a conversion type from the list
@-eval() is only availible to admins!!! addressbook en @-eval() is only availible to admins!!!
actions addressbook en Actions
add a new contact addressbook en Add a new contact
add a single entry by passing the fields. addressbook en Add a single entry by passing the fields.
add custom field addressbook en Add Custom Field
address book common en Address Book
address book - vcard in addressbook en Address book - VCard in
address book - view addressbook en Address book - view
address line 2 addressbook en Address Line 2
address line 3 addressbook en Address Line 3
address type addressbook en Address Type
addressbook common en Addressbook
addressbook preferences addressbook en Addressbook preferences
addressbook the contact should be saved to addressbook en Addressbook the contact should be saved to
addressbook-fieldname addressbook en Addressbook-Fieldname
addvcard addressbook en Add VCard
advanced search addressbook en Advanced search
alt. csv import addressbook en Alt. CSV Import
always addressbook en always
apply the action on the whole selection, not only the shown contacts!!! addressbook en Apply the action on the whole selection, NOT only the shown contacts!!!
are you shure you want to delete this contact? addressbook en Are you shure you want to delete this contact?
are you sure you want to delete this field? addressbook en Are you sure you want to delete this field?
bbs phone addressbook en BBS Phone
assistent addressbook en Assistent
birthday common en Birthday
birthdays common en Birthdays
blank addressbook en Blank
business common en Business
business address type addressbook en Business Address Type
business address addressbook en Business address
business city addressbook en Business City
business country addressbook en Business Country
business email addressbook en Business EMail
business email type addressbook en Business EMail Type
business fax addressbook en Business Fax
business phone addressbook en Business Phone
business state addressbook en Business State
@ -38,11 +43,11 @@ business zip code addressbook en Business Postal Code
car phone addressbook en Car Phone
cell phone addressbook en Mobile phone
charset of file addressbook en Charset of file
choose an icon for this contact type addressbook en Choose an icon for this contact type
chosse an etemplate for this contact type addressbook en Chosse an eTemplate for this contact type
check all addressbook en Check all
choose an icon for this contact type admin en Choose an icon for this contact type
chosse an etemplate for this contact type admin en Chosse an eTemplate for this contact type
city common en City
company common en Company
company name common en Company Name
configuration common en Configuration
contact common en Contact
contact application admin en Contact application
@ -51,6 +56,7 @@ contact settings admin en Contact Settings
copied by %1, from record #%2. addressbook en Copied by %1, from record #%2.
country common en Country
create new links addressbook en Create new links
created addressbook en Created
credit addressbook en Credit
csv-fieldname addressbook en CSV-Fieldname
csv-filename addressbook en CSV-Filename
@ -59,7 +65,12 @@ custom fields addressbook en Custom Fields
debug output in browser addressbook en Debug output in browser
default filter addressbook en Default Filter
delete a single entry by passing the id. addressbook en Delete a single entry by passing the id.
delete this contact addressbook en Delete this contact
deleted addressbook en deleted
deletes the photo addressbook en Deletes the photo
department common en Department
displays a remider for birthdays happening today or tomorrow on the startpage (page you get when you enter egroupware or click on the homepage icon). addressbook en Displays a remider for birthdays happening today or tomorrow on the startpage (page you get when you enter eGroupWare or click on the homepage icon).
do you want a private addressbook, which can not be viewed by users, you grant access to your personal addressbook? addressbook en Do you want a private addressbook, which can not be viewed by users, you grant access to your personal addressbook?
do your really want to delete this contact? addressbook en Do your really want to delete this contact?
doesn't matter addressbook en doesn't matter
domestic addressbook en Domestic
@ -71,12 +82,15 @@ edit custom fields admin en Edit Custom Fields
edit phonenumbers - addressbook en Edit Phonenumbers -
email & internet addressbook en Email & Internet
empty for all addressbook en empty for all
enable an extra private addressbook addressbook en Enable an extra private addressbook
enter the path to the exported file here addressbook en Enter the path to the exported file here
existing links addressbook en Existing links
export addressbook en export
export as vcard addressbook en Export as VCard
export contacts addressbook en Export Contacts
export file name addressbook en Export file name
export from addressbook addressbook en Export from Addressbook
exported addressbook en exported
extra addressbook en Extra
fax addressbook en Fax
fax number common en Fax Number
@ -89,11 +103,11 @@ full name addressbook en Full Name
geo addressbook en GEO
global categories addressbook en Global Categories
grant addressbook access common en Grant Addressbook Access
home address type addressbook en Home Address Type
group %1 addressbook en Group %1
home address addressbook en Home address
home city addressbook en Home City
home country addressbook en Home Country
home email addressbook en Home EMail
home email type addressbook en Home EMail Type
home phone addressbook en Home Phone
home state addressbook en Home State
home street addressbook en Home Street
@ -111,7 +125,6 @@ import next set addressbook en Import next set
import_instructions addressbook en In Netscape, open the Addressbook and select <b>Export</b> from the <b>File</b> menu. The file exported will be in LDIF format.<p>Or, in Outlook, select your Contacts folder, select <b>Import and Export...</b> from the <b>File</b> menu and export your contacts into a comma separated text (CSV) file. <p>Or, in Palm Desktop 4.0 or greater, visit your addressbook and select <b>Export</b> from the <b>File</b> menu. The file exported will be in VCard format.
income addressbook en Income
international addressbook en International
isdn phone addressbook en ISDN Phone
label addressbook en Label
last modified addressbook en last modified
ldap context for contacts admin en LDAP context for contacts
@ -131,11 +144,13 @@ mobile addressbook en Mobile
mobile phone addressbook en Mobile Phone
modem phone addressbook en Modem Phone
more ... addressbook en More ...
moved addressbook en moved
multiple vcard addressbook en Multiple VCard
no vcard addressbook en No VCard
number addressbook en Number
number of records to read (%1) addressbook en Number of records to read (%1)
options for type addressbook en Options for type
only if there is content addressbook en only if there is content
options for type admin en Options for type
organisation addressbook en organisation
other number addressbook en Other Number
other phone addressbook en Other Phone
@ -143,7 +158,9 @@ pager common en Pager
parcel addressbook en Parcel
phone number common en Phone Number
phone numbers common en Phone Numbers
photo addressbook en Photo
please enter a name for that field ! addressbook en Please enter a name for that field !
please select only one category addressbook en Please select only one category
postal common en Postal
pref addressbook en pref
prefix addressbook en Prefix
@ -154,12 +171,18 @@ read a list of entries. addressbook en Read a list of entries.
read a single entry by passing the id and fieldlist. addressbook en Read a single entry by passing the id and fieldlist.
record access addressbook en Record Access
record owner addressbook en Record owner
retrieve contacts admin en retrieve contacts
role addressbook en Role
room addressbook en Room
search for '%1' addressbook en Search for '%1'
select a portrait format jpeg photo. it will be resized to 60 pixel width. addressbook en Select a portrait format jpeg photo. It will be resized to 60 pixel width.
select addressbook type addressbook en Select addressbook type
select all addressbook en Select all
select an action or addressbook to move to addressbook en Select an action or addressbook to move to
select the type of conversion addressbook en Select the type of conversion
select the type of conversion: addressbook en Select the type of conversion:
select where you want to store admin en Select where you want to store
select where you want to store / retrieve contacts admin en Select where you want to store / retrieve contacts
show addressbook en Show
show a column for %1 addressbook en Show a column for %1
show birthday reminders on main screen addressbook en Show birthday reminders on main screen
something went wrong by deleting %1 addressbook en Something went wrong by deleting %1
something went wrong by deleting this contact addressbook en Something went wrong by deleting this contact
@ -175,19 +198,21 @@ test import (show importable records <u>only</u> in browser) addressbook en Test
that field name has been used already ! addressbook en That field name has been used already !
this person's first name was not in the address book. addressbook en This person's first name was not in the address book.
this person's last name was not in the address book. addressbook en This person's last name was not in the address book.
timezone addressbook en Timezone
to many might exceed your execution-time-limit addressbook en to many might exceed your execution-time-limit
today is %1's birthday! common en Today is %1's birthday!
tomorrow is %1's birthday. common en Tomorrow is %1's birthday.
translation addressbook en Translation
update a single entry by passing the fields. addressbook en Update a single entry by passing the fields.
upload or delete the photo addressbook en Upload or delete the photo
use country list addressbook en Use Country List
vcard common en VCard
vcards require a first name entry. addressbook en VCards require a first name entry.
vcards require a last name entry. addressbook en Vcards require a last name entry.
video phone addressbook en Video Phone
voice phone addressbook en Voice Phone
warning!! ldap is valid only if you are not using contacts for accounts storage! admin en WARNING!! LDAP is valid only if you are NOT using contacts for accounts storage!
warning: all contacts found will be deleted! addressbook en WARNING: All contacts found will be deleted!
when should the contacts list display that colum. "only if there is content" hides the column, unless there is some content in the view. addressbook en When should the contacts list display that colum. "Only if there is content" hides the column, unless there is some content in the view.
whole selection addressbook en whole selection
work phone addressbook en Work Phone
write (update or add) a single entry by passing the fields. addressbook en Write (update or add) a single entry by passing the fields.
you are not permitted to delete contact %1 addressbook en You are not permitted to delete contact %1
@ -196,5 +221,6 @@ you are not permittet to edit this contact addressbook en You are not permittet
you are not permittet to view this contact addressbook en you are not permittet to view this contact
you must select a vcard. (*.vcf) addressbook en You must select a vcard. (*.vcf)
you must select at least 1 column to display addressbook en You must select at least 1 column to display
you need to select some contacts first addressbook en You need to select some contacts first
zip code common en ZIP Code
zip_note addressbook en <p><b>Note:</b> The file may be a zip file collection of .csv, .vcf, or .ldif files. However, do not mix file types per import.

View File

@ -2,7 +2,7 @@
/**************************************************************************\
* eGroupWare - Addressbook *
* http://www.egroupware.org *
* -------------------------------------------- *
* ------------------------------------------------------------------------ *
* 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 *
@ -14,11 +14,11 @@
/* Basic information about this app */
$setup_info['addressbook']['name'] = 'addressbook';
$setup_info['addressbook']['title'] = 'Addressbook';
$setup_info['addressbook']['version'] = '1.2';
$setup_info['addressbook']['version'] = '1.3.001';
$setup_info['addressbook']['app_order'] = 4;
$setup_info['addressbook']['enable'] = 1;
$setup_info['addressbook']['author'] = 'Joseph Engo, Miles Lott';
$setup_info['addressbook']['author'] = 'Ralf Becker, Cornelius Weiss, Lars Kneschke';
$setup_info['addressbook']['note'] = 'The phpgwapi manages contact data. Addressbook manages servers for its remote capability.';
$setup_info['addressbook']['license'] = 'GPL';
$setup_info['addressbook']['description'] =
@ -33,17 +33,21 @@
$setup_info['addressbook']['maintainer'] = 'eGroupWare coreteam';
$setup_info['addressbook']['maintainer_email'] = 'egroupware-developers@lists.sourceforge.net';
$setup_info['addressbook']['tables'][] = 'egw_addressbook';
$setup_info['addressbook']['tables'][] = 'egw_addressbook_extra';
/* The hooks this app includes, needed for hooks registration */
$setup_info['addressbook']['hooks'][] = 'admin';
$setup_info['addressbook']['hooks'][] = 'add_def_pref';
$setup_info['addressbook']['hooks']['admin'] = 'addressbook.contacts_admin_prefs.all_hooks';
$setup_info['addressbook']['hooks']['preferences'] = 'addressbook.contacts_admin_prefs.all_hooks';
$setup_info['addressbook']['hooks']['sidebox_menu'] = 'addressbook.contacts_admin_prefs.all_hooks';
$setup_info['addressbook']['hooks']['settings'] = 'addressbook.contacts_admin_prefs.settings';
$setup_info['addressbook']['hooks'][] = 'config_validate';
$setup_info['addressbook']['hooks'][] = 'home';
$setup_info['addressbook']['hooks'][] = 'addaccount';
$setup_info['addressbook']['hooks'][] = 'editaccount';
$setup_info['addressbook']['hooks'][] = 'deleteaccount';
$setup_info['addressbook']['hooks']['editaccount'] = 'addressbook.bocontacts.editaccount';
$setup_info['addressbook']['hooks']['deleteaccount'] = 'addressbook.bocontacts.deleteaccount';
$setup_info['addressbook']['hooks'][] = 'notifywindow';
$setup_info['addressbook']['hooks'][] = 'sidebox_menu';
$setup_info['addressbook']['hooks'][] = 'preferences';
$setup_info['addressbook']['hooks']['search_link'] = 'addressbook.bocontacts.search_link';
$setup_info['addressbook']['hooks']['edit_user'] = 'addressbook.contacts_admin_prefs.edit_user';
/* Dependencies for this app to work */
$setup_info['addressbook']['depends'][] = array(
@ -54,4 +58,4 @@
'appname' => 'etemplate',
'versions' => Array('1.0.0','1.0.1','1.2','1.3')
);
?>

View File

@ -0,0 +1,89 @@
<?php
/**************************************************************************\
* eGroupWare *
* http://www.egroupware.org *
* -------------------------------------------- *
* 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$
// $Source$
$phpgw_baseline = array(
'egw_addressbook' => array(
'fd' => array(
'id' => array('type' => 'auto','nullable' => False),
'lid' => array('type' => 'varchar','precision' => '32'),
'tid' => array('type' => 'char','precision' => '1'),
'owner' => array('type' => 'int','precision' => '8'),
'access' => array('type' => 'varchar','precision' => '7'),
'cat_id' => array('type' => 'varchar','precision' => '32'),
'fn' => array('type' => 'varchar','precision' => '64'),
'n_family' => array('type' => 'varchar','precision' => '64'),
'n_given' => array('type' => 'varchar','precision' => '64'),
'n_middle' => array('type' => 'varchar','precision' => '64'),
'n_prefix' => array('type' => 'varchar','precision' => '64'),
'n_suffix' => array('type' => 'varchar','precision' => '64'),
'sound' => array('type' => 'varchar','precision' => '64'),
'bday' => array('type' => 'varchar','precision' => '32'),
'note' => array('type' => 'text'),
'tz' => array('type' => 'varchar','precision' => '8'),
'geo' => array('type' => 'varchar','precision' => '32'),
'url' => array('type' => 'varchar','precision' => '128'),
'pubkey' => array('type' => 'text'),
'org_name' => array('type' => 'varchar','precision' => '64'),
'org_unit' => array('type' => 'varchar','precision' => '64'),
'title' => array('type' => 'varchar','precision' => '64'),
'adr_one_street' => array('type' => 'varchar','precision' => '64'),
'adr_one_locality' => array('type' => 'varchar','precision' => '64'),
'adr_one_region' => array('type' => 'varchar','precision' => '64'),
'adr_one_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_one_countryname' => array('type' => 'varchar','precision' => '64'),
'adr_one_type' => array('type' => 'varchar','precision' => '32'),
'label' => array('type' => 'text'),
'adr_two_street' => array('type' => 'varchar','precision' => '64'),
'adr_two_locality' => array('type' => 'varchar','precision' => '64'),
'adr_two_region' => array('type' => 'varchar','precision' => '64'),
'adr_two_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_two_countryname' => array('type' => 'varchar','precision' => '64'),
'adr_two_type' => array('type' => 'varchar','precision' => '32'),
'tel_work' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_home' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_voice' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_fax' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_msg' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_cell' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_pager' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_bbs' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_modem' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_car' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_isdn' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_video' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_prefer' => array('type' => 'varchar','precision' => '32'),
'email' => array('type' => 'varchar','precision' => '64'),
'email_type' => array('type' => 'varchar','precision' => '32','default' => 'INTERNET'),
'email_home' => array('type' => 'varchar','precision' => '64'),
'email_home_type' => array('type' => 'varchar','precision' => '32','default' => 'INTERNET'),
'last_mod' => array('type' => 'int','precision' => '8','nullable' => False)
),
'pk' => array('id'),
'fk' => array(),
'ix' => array(array('tid','owner','access','n_family','n_given'),array('tid','cat_id','owner','access','n_family')),
'uc' => array()
),
'egw_addressbook_extra' => array(
'fd' => array(
'contact_id' => array('type' => 'int','precision' => '4','nullable' => False),
'contact_owner' => array('type' => 'int','precision' => '8'),
'contact_name' => array('type' => 'varchar','precision' => '255','nullable' => False),
'contact_value' => array('type' => 'text')
),
'pk' => array('contact_id','contact_name'),
'fk' => array(),
'ix' => array(),
'uc' => array()
),
);

View File

@ -0,0 +1,93 @@
<?php
/**************************************************************************\
* eGroupWare *
* http://www.egroupware.org *
* -------------------------------------------- *
* 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$ */
$phpgw_baseline = array(
'egw_addressbook' => array(
'fd' => array(
'contact_id' => array('type' => 'auto','nullable' => False),
'contact_tid' => array('type' => 'char','precision' => '1','default' => 'n'),
'contact_owner' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_private' => array('type' => 'int','precision' => '1','default' => '0'),
'cat_id' => array('type' => 'varchar','precision' => '32'),
'n_family' => array('type' => 'varchar','precision' => '64'),
'n_given' => array('type' => 'varchar','precision' => '64'),
'n_middle' => array('type' => 'varchar','precision' => '64'),
'n_prefix' => array('type' => 'varchar','precision' => '64'),
'n_suffix' => array('type' => 'varchar','precision' => '64'),
'n_fn' => array('type' => 'varchar','precision' => '128'),
'n_fileas' => array('type' => 'varchar','precision' => '255'),
'contact_bday' => array('type' => 'varchar','precision' => '10'),
'org_name' => array('type' => 'varchar','precision' => '64'),
'org_unit' => array('type' => 'varchar','precision' => '64'),
'contact_title' => array('type' => 'varchar','precision' => '64'),
'contact_role' => array('type' => 'varchar','precision' => '64'),
'contact_assistent' => array('type' => 'varchar','precision' => '64'),
'contact_room' => array('type' => 'varchar','precision' => '64'),
'adr_one_street' => array('type' => 'varchar','precision' => '64'),
'adr_one_street2' => array('type' => 'varchar','precision' => '64'),
'adr_one_locality' => array('type' => 'varchar','precision' => '64'),
'adr_one_region' => array('type' => 'varchar','precision' => '64'),
'adr_one_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_one_countryname' => array('type' => 'varchar','precision' => '64'),
'contact_label' => array('type' => 'text'),
'adr_two_street' => array('type' => 'varchar','precision' => '64'),
'adr_two_street2' => array('type' => 'varchar','precision' => '64'),
'adr_two_locality' => array('type' => 'varchar','precision' => '64'),
'adr_two_region' => array('type' => 'varchar','precision' => '64'),
'adr_two_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_two_countryname' => array('type' => 'varchar','precision' => '64'),
'tel_work' => array('type' => 'varchar','precision' => '40'),
'tel_cell' => array('type' => 'varchar','precision' => '40'),
'tel_fax' => array('type' => 'varchar','precision' => '40'),
'tel_assistent' => array('type' => 'varchar','precision' => '40'),
'tel_car' => array('type' => 'varchar','precision' => '40'),
'tel_pager' => array('type' => 'varchar','precision' => '40'),
'tel_home' => array('type' => 'varchar','precision' => '40'),
'tel_fax_home' => array('type' => 'varchar','precision' => '40'),
'tel_cell_private' => array('type' => 'varchar','precision' => '40'),
'tel_other' => array('type' => 'varchar','precision' => '40'),
'tel_prefer' => array('type' => 'varchar','precision' => '32'),
'contact_email' => array('type' => 'varchar','precision' => '64'),
'contact_email_home' => array('type' => 'varchar','precision' => '64'),
'contact_url' => array('type' => 'varchar','precision' => '128'),
'contact_url_home' => array('type' => 'varchar','precision' => '128'),
'contact_freebusy_uri' => array('type' => 'varchar','precision' => '128'),
'contact_calendar_uri' => array('type' => 'varchar','precision' => '128'),
'contact_note' => array('type' => 'text'),
'contact_tz' => array('type' => 'varchar','precision' => '8'),
'contact_geo' => array('type' => 'varchar','precision' => '32'),
'contact_pubkey' => array('type' => 'text'),
'contact_created' => array('type' => 'int','precision' => '8'),
'contact_creator' => array('type' => 'int','precision' => '4','nullable' => False),
'contact_modified' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_modifier' => array('type' => 'int','precision' => '4'),
'contact_jpegphoto' => array('type' => 'blob'),
),
'pk' => array('contact_id'),
'fk' => array(),
'ix' => array('cat_id','contact_owner','contact_fileas',array('n_family','n_given'),array('n_given','n_family'),array('org_name','n_family','n_given')),
'uc' => array()
),
'egw_addressbook_extra' => array(
'fd' => array(
'contact_id' => array('type' => 'int','precision' => '4','nullable' => False),
'contact_owner' => array('type' => 'int','precision' => '8'),
'contact_name' => array('type' => 'varchar','precision' => '255','nullable' => False),
'contact_value' => array('type' => 'text')
),
'pk' => array('contact_id','contact_name'),
'fk' => array(),
'ix' => array(),
'uc' => array()
)
);

View File

@ -0,0 +1,159 @@
<?php
/**************************************************************************\
* eGroupWare - Setup *
* http://www.eGroupWare.org *
* Created by eTemplates DB-Tools written by ralfbecker@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$ */
$test[] = '1.2';
function addressbook_upgrade1_2()
{
$GLOBALS['egw_setup']->oProc->RefreshTable('egw_addressbook',array(
'fd' => array(
'contact_id' => array('type' => 'auto','nullable' => False),
'contact_tid' => array('type' => 'char','precision' => '1','default' => 'n'),
'contact_owner' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_private' => array('type' => 'int','precision' => '1','default' => '0'),
'cat_id' => array('type' => 'varchar','precision' => '32'),
'n_family' => array('type' => 'varchar','precision' => '64'),
'n_given' => array('type' => 'varchar','precision' => '64'),
'n_middle' => array('type' => 'varchar','precision' => '64'),
'n_prefix' => array('type' => 'varchar','precision' => '64'),
'n_suffix' => array('type' => 'varchar','precision' => '64'),
'n_fn' => array('type' => 'varchar','precision' => '128'),
'n_fileas' => array('type' => 'varchar','precision' => '255'),
'contact_bday' => array('type' => 'varchar','precision' => '10'),
'org_name' => array('type' => 'varchar','precision' => '64'),
'org_unit' => array('type' => 'varchar','precision' => '64'),
'contact_title' => array('type' => 'varchar','precision' => '64'),
'contact_role' => array('type' => 'varchar','precision' => '64'),
'contact_assistent' => array('type' => 'varchar','precision' => '64'),
'contact_room' => array('type' => 'varchar','precision' => '64'),
'adr_one_street' => array('type' => 'varchar','precision' => '64'),
'adr_one_street2' => array('type' => 'varchar','precision' => '64'),
'adr_one_locality' => array('type' => 'varchar','precision' => '64'),
'adr_one_region' => array('type' => 'varchar','precision' => '64'),
'adr_one_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_one_countryname' => array('type' => 'varchar','precision' => '64'),
'contact_label' => array('type' => 'text'),
'adr_two_street' => array('type' => 'varchar','precision' => '64'),
'adr_two_street2' => array('type' => 'varchar','precision' => '64'),
'adr_two_locality' => array('type' => 'varchar','precision' => '64'),
'adr_two_region' => array('type' => 'varchar','precision' => '64'),
'adr_two_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_two_countryname' => array('type' => 'varchar','precision' => '64'),
'tel_work' => array('type' => 'varchar','precision' => '40'),
'tel_cell' => array('type' => 'varchar','precision' => '40'),
'tel_fax' => array('type' => 'varchar','precision' => '40'),
'tel_assistent' => array('type' => 'varchar','precision' => '40'),
'tel_car' => array('type' => 'varchar','precision' => '40'),
'tel_pager' => array('type' => 'varchar','precision' => '40'),
'tel_home' => array('type' => 'varchar','precision' => '40'),
'tel_fax_home' => array('type' => 'varchar','precision' => '40'),
'tel_cell_private' => array('type' => 'varchar','precision' => '40'),
'tel_other' => array('type' => 'varchar','precision' => '40'),
'tel_prefer' => array('type' => 'varchar','precision' => '32'),
'contact_email' => array('type' => 'varchar','precision' => '64'),
'contact_email_home' => array('type' => 'varchar','precision' => '64'),
'contact_url' => array('type' => 'varchar','precision' => '128'),
'contact_url_home' => array('type' => 'varchar','precision' => '128'),
'contact_freebusy_uri' => array('type' => 'varchar','precision' => '128'),
'contact_calendar_uri' => array('type' => 'varchar','precision' => '128'),
'contact_note' => array('type' => 'text'),
'contact_tz' => array('type' => 'varchar','precision' => '8'),
'contact_geo' => array('type' => 'varchar','precision' => '32'),
'contact_pubkey' => array('type' => 'text'),
'contact_created' => array('type' => 'int','precision' => '8'),
'contact_creator' => array('type' => 'int','precision' => '4','nullable' => False),
'contact_modified' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_modifier' => array('type' => 'int','precision' => '4'),
'contact_jpegphoto' => array('type' => 'blob'),
),
'pk' => array('contact_id'),
'fk' => array(),
'ix' => array('cat_id','contact_owner','n_fileas',array('n_family','n_given'),array('n_given','n_family'),array('org_name','n_family','n_given')),
'uc' => array()
),array(
// new colum prefix
'contact_id' => 'id',
'contact_tid' => 'tid',
'contact_owner' => 'owner',
'contact_private' => "CASE access WHEN 'private' THEN 1 ELSE 0 END",
'n_fn' => 'fn',
'contact_title' => 'title',
'contact_bday' => 'bday',
'contact_note' => 'note',
'contact_tz' => 'tz',
'contact_geo' => 'geo',
'contact_url' => 'url',
'contact_pubkey' => 'pubkey',
'contact_label' => 'label',
'contact_email' => 'email',
'contact_email_home' => 'email_home',
'contact_modified' => 'last_mod',
// remove stupid old default values, rename phone-numbers, tel_bbs and tel_video are droped
'tel_work' => "CASE tel_work WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_work END",
'tel_cell' => "CASE tel_cell WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_cell END",
'tel_fax' => "CASE tel_fax WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_fax END",
'tel_assistent' => "CASE tel_msg WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_msg END",
'tel_car' => "CASE tel_car WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_car END",
'tel_pager' => "CASE tel_pager WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_pager END",
'tel_home' => "CASE tel_home WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_home END",
'tel_fax_home' => "CASE tel_modem WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_modem END",
'tel_cell_private' => "CASE tel_isdn WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_isdn END",
'tel_other' => "CASE tel_voice WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_voice END",
'tel_prefer' => "CASE tel_prefer WHEN 'tel_voice' THEN 'tel_other' WHEN 'tel_msg' THEN 'tel_assistent' WHEN 'tel_modem' THEN 'tel_fax_home' WHEN 'tel_isdn' THEN 'tel_cell_private' WHEN 'ophone' THEN 'tel_other' ELSE tel_prefer END",
// set creator from owner
'contact_creator' => 'owner',
// set contact_fileas from org_name, n_family and n_given
'n_fileas' => "CASE WHEN org_name='' THEN (".
($name_sql = "CASE WHEN n_given='' THEN n_family ELSE ".$GLOBALS['egw_setup']->db->concat('n_family',"', '",'n_given').' END').
") ELSE (CASE WHEN n_family='' THEN org_name ELSE ".$GLOBALS['egw_setup']->db->concat('org_name',"': '",$name_sql).' END) END',
));
// migrate values saved in custom fields to the new table
$db2 = clone($GLOBALS['egw_setup']->db);
$GLOBALS['egw_setup']->db->select('egw_addressbook_extra','contact_id,contact_name,contact_value',
"contact_name IN ('ophone','address2','address3','freebusy_url') AND contact_value != '' AND NOT contact_value IS NULL"
,__LINE__,__FILE__,false,'','addressbook');
$old2new = array(
'ophone' => 'tel_other',
'address2' => 'adr_one_street2',
'address3' => 'adr_two_street2',
'freebusy_url' => 'contact_freebusy_uri',
);
while (($row = $GLOBALS['egw_setup']->db->row(true)))
{
$db2->update('egw_addressbook',array($old2new[$row['contact_name']] => $row['contact_value']),array(
'contact_id' => $row['contact_id'],
'('.$old2new[$row['contact_name']].'IS NULL OR '.$old2new[$row['contact_name']]."='')",
),__LINE__,__FILE__,'addressbook');
}
// delete the not longer used custom fields plus rubish from old bugs
$GLOBALS['egw_setup']->db->delete('egw_addressbook_extra',"contact_name IN ('ophone','address2','address3','freebusy_url','cat_id','tid','lid','id','ab_id','access','owner','rights')".
" OR contact_value='' OR contact_value IS NULL".
($db2->capabilities['subqueries'] ? " OR contact_id NOT IN (SELECT contact_id FROM egw_addressbook)" : ''),
__LINE__,__FILE__,'addressbook');
// change the m/d/Y birthday format to Y-m-d
$GLOBALS['egw_setup']->db->select('egw_addressbook','contact_id,contact_bday',"contact_bday != ''",
__LINE__,__FILE__,false,'','addressbook');
while (($row = $GLOBALS['egw_setup']->db->row(true)))
{
list($m,$d,$y) = explode('/',$row['contact_bday']);
$db2->update('egw_addressbook',array(
'contact_bday' => sprintf('%04d-%02d-%02d',$y,$m,$d)
),array(
'contact_id' => $row['contact_id'],
),__LINE__,__FILE__,'addressbook');
}
return $GLOBALS['setup_info']['addressbook']['currentver'] = '1.3.001';
}

View File

@ -1,4 +1,27 @@
.redItalic { color: red; font-style: italic; }
.fixedHeight,.telNumbers { height: 12px; }
.telNumbers { white-space: nowrap; }
.leftPad5 { padding-left: 5px; }
.bold { font-weight: bold; }
.fileas select,.fileas,.owner select,.owner {
width: 100%;
font-weight: bold;
}
.photo img {
width: 60px;
min-height: 80px;
}
.uploadphoto{
position: absolute;
top: 168px;
left: 48px;
display:none;
border: 2px solid black;
background-color: #ffffff;
padding: 4px;
}
.checkAllArrow { padding-right: 5px; }
.typeIcon { height: 16px; width: 16px; }
.editphones{
position: absolute;
top: 10%;
@ -17,7 +40,7 @@
border-bottom: #9c9c9c 1px solid;
}
.phoneGroup fieldset{
margin-top: 18px;
margin-top: 17px;
font-size: 110%;
height: 117px;
border: solid black 2px;
@ -29,7 +52,7 @@
.emailGroup fieldset{
margin-top: 0px;
font-size: 110%;
height: 104px;
height: 112px;
border: solid black 2px;
margin-bottom: 0px;
}

View File

@ -22,7 +22,7 @@
<td align="center" colspan="2">{lang_WARNING!!_LDAP_is_valid_only_if_you_are_NOT_using_contacts_for_accounts_storage!}</td>
</tr> -->
<tr class="row_off">
<td>{lang_Select_where_you_want_to_store}/{lang_retrieve_contacts}.</td>
<td>{lang_Select_where_you_want_to_store_/_retrieve_contacts}.</td>
<td>
<select name="newsettings[contact_repository]">
<option value="sql" {selected_contact_repository_sql}>SQL</option>

View File

@ -1,59 +1,72 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<template id="addressbook.edit.personal" template="" lang="" group="0" version="1.0.1.002">
<grid class="editphones">
<template id="addressbook.edit.personal" template="" lang="" group="0" version="1.3.002">
<grid height="258">
<columns>
<column/>
<column/>
<column/>
</columns>
<rows>
<row>
<image src="personal"/>
<description value="prefix"/>
<textbox id="n_prefix" size="45" maxlength="64"/>
</row>
<row>
<description/>
<description value="first name"/>
<textbox id="n_given" size="45" maxlength="64"/>
</row>
<row>
<description/>
<description value="middle name"/>
<textbox id="n_middle" size="45" maxlength="64"/>
</row>
<row>
<description/>
<description value="last name"/>
<textbox id="n_family" size="45" maxlength="64"/>
</row>
<row>
<description/>
<description value="suffix"/>
<textbox id="n_suffix" size="45" maxlength="64"/>
</row>
<row height="40">
<image src="gohome"/>
<description value="company name" options=",,,org_name"/>
<textbox size="45" maxlength="64" id="org_name"/>
</row>
<row valign="top">
<image src="accounts"/>
<vbox>
<image src="photo" class="photo"/>
<button label="change" id="change_photo" statustext="Upload or delete the photo" onclick="set_style_by_class('table','uploadphoto','display','inline'); return false;"/>
<template id="addressbook.edit"/>
</vbox>
<grid>
<columns>
<column width="20%"/>
<column/>
</columns>
<rows>
<row>
<description options=",,,n_prefix" value="prefix"/>
<textbox id="n_prefix" size="35" maxlength="64" onchange="setFileasOptions(this);"/>
</row>
<row>
<description value="first name" options=",,,n_given"/>
<textbox id="n_given" size="35" maxlength="64" onchange="setFileasOptions(this);"/>
</row>
<row>
<description options=",,,n_middle" value="middle name"/>
<textbox id="n_middle" size="35" maxlength="64" onchange="setFileasOptions(this);"/>
</row>
<row>
<description options=",,,n_family" value="last name"/>
<textbox id="n_family" size="35" maxlength="64" onchange="setFileasOptions(this);"/>
</row>
<row>
<description options=",,,n_suffix" value="suffix"/>
<textbox id="n_suffix" size="35" maxlength="64" onchange="setFileasOptions(this);"/>
</row>
</rows>
</grid>
</row>
<row height="30">
<image src="gohome"/>
<description value="company" options=",,,org_name"/>
<textbox size="45" maxlength="64" id="org_name" onchange="setFileasOptions(this);"/>
</row>
<row valign="top" height="70">
<image src="folder"/>
<description value="category"/>
<listbox type="select-cat" id="cat_id" rows="3" options=",width:99%" span="4"/>
</row>
<row>
<image src="password"/>
<description value="Private" options=",,,private"/>
<checkbox id="private"/>
<image src="private.png"/>
<description value="Addressbook" options=",,,owner"/>
<menulist span=",owner">
<menupopup id="owner" statustext="Addressbook the contact should be saved to" no_lang="1"/>
</menulist>
</row>
</rows>
</grid>
</template>
<template id="addressbook.edit.organisation" template="" lang="" group="0" version="1.0.1.001">
<grid height="320">
<template id="addressbook.edit.organisation" template="" lang="" group="0" version="1.3.001">
<grid height="258">
<columns>
<column/>
<column/>
@ -63,16 +76,25 @@
<rows>
<row>
<image src="gear"/>
<description value="title"/>
<description value="title" options=",,,title"/>
<textbox size="45" maxlength="64" id="title"/>
<description/>
</row>
<row>
<description/>
<description value="department"/>
<description value="department" options=",,,org_unit"/>
<textbox id="org_unit" size="45" maxlength="64"/>
<description/>
</row>
<row>
<description/>
<description options=",,,role" value="Role"/>
<hbox orient=",0,0">
<textbox id="role" size="25" maxlength="64"/>
<textbox size="8" maxlength="64" label="Room" align="right" id="room"/>
</hbox>
<description/>
</row>
<row>
<description/>
<description/>
@ -81,43 +103,37 @@
</row>
<row>
<image src="gohome"/>
<description value="street"/>
<description value="street" options=",,,adr_one_street"/>
<textbox size="45" maxlength="64" id="adr_one_street"/>
<description/>
</row>
<row>
<description/>
<description value="address line 2"/>
<textbox size="45" maxlength="64" id="address2"/>
<description value="address line 2" options=",,,adr_one_street2"/>
<textbox size="45" maxlength="64" id="adr_one_street2"/>
<description/>
</row>
<row>
<description/>
<description value="address line 3"/>
<textbox size="45" maxlength="64" id="address3"/>
<description/>
</row>
<row>
<description/>
<description value="city"/>
<description value="city" options=",,,adr_one_locality"/>
<textbox size="45" maxlength="64" id="adr_one_locality"/>
<description/>
</row>
<row>
<description/>
<description value="zip code"/>
<description value="zip code" options=",,,adr_one_postalcode"/>
<textbox size="45" maxlength="64" id="adr_one_postalcode"/>
<description/>
</row>
<row>
<description/>
<description value="state"/>
<description value="state" options=",,,adr_one_region"/>
<textbox size="45" maxlength="64" id="adr_one_region"/>
<description/>
</row>
<row>
<description/>
<description value="country"/>
<description value="country" options=",,,adr_one_countryname"/>
<textbox size="45" maxlength="64" id="adr_one_countryname"/>
<description/>
</row>
@ -130,8 +146,8 @@
</rows>
</grid>
</template>
<template id="addressbook.edit.home" template="" lang="" group="0" version="1.0.1.001">
<grid width="100%" height="250" overflow="auto">
<template id="addressbook.edit.home" template="" lang="" group="0" version="1.3.001">
<grid height="258">
<columns>
<column/>
<column/>
@ -140,60 +156,63 @@
<rows>
<row>
<image src="gohome"/>
<description value="street"/>
<description value="street" options=",,,adr_two_street"/>
<textbox size="45" maxlength="64" id="adr_two_street"/>
</row>
<row>
<description/>
<description value="city"/>
<description options=",,,adr_two_street2" value="address line 2"/>
<textbox size="45" maxlength="64" id="adr_two_street2"/>
</row>
<row>
<description/>
<description value="city" options=",,,adr_two_locality"/>
<textbox size="45" maxlength="64" id="adr_two_locality"/>
</row>
<row>
<description/>
<description value="zip code"/>
<description value="zip code" options=",,,adr_two_postalcode"/>
<textbox size="45" maxlength="64" id="adr_two_postalcode"/>
</row>
<row>
<description/>
<description value="state"/>
<description value="state" options=",,,adr_two_region"/>
<textbox size="45" maxlength="64" id="adr_two_region"/>
</row>
<row>
<description/>
<description value="country"/>
<description value="country" options=",,,adr_two_countryname"/>
<textbox size="45" maxlength="64" id="adr_two_countryname"/>
</row>
<row height="30">
<description/>
<description options=",,,bday" value="Birthday"/>
<date id="bday" options="m/d/Y"/>
<hbox id="bday" orient=",0,0">
<date options="Y-m-d" id="bday"/>
<menulist>
<menupopup id="tz" no_lang="1" label="Timezone" align="right"/>
</menulist>
</hbox>
</row>
<row>
<description/>
<description options=",,,tz" value="Time zone"/>
<menulist>
<menupopup id="tz" no_lang="1"/>
</menulist>
</row>
<row>
<description/>
<description value="Public key"/>
<textbox multiline="true" rows="2" cols="45" id="pubkey"/>
<image src="private"/>
<description value="Public key" options=",,,pubkey"/>
<textbox multiline="true" rows="2" cols="40" id="pubkey"/>
</row>
</rows>
</grid>
</template>
<template id="addressbook.edit.details" template="" lang="" group="0" version="1.0.1.001">
<grid height="320">
<template id="addressbook.edit.details" template="" lang="" group="0" version="1.3.001">
<grid width="100%" height="258" overflow="auto">
<columns>
<column/>
</columns>
<rows>
<row>
<description value="Notes"/>
<description value="Notes" options=",,,note"/>
</row>
<row valign="top">
<textbox multiline="true" rows="4" cols="56" id="note"/>
<textbox multiline="true" rows="4" cols="50" id="note"/>
</row>
<row class="th">
<description value="Custom fields"/>
@ -204,8 +223,8 @@
</rows>
</grid>
</template>
<template id="addressbook.edit.links" template="" lang="" group="0" version="1.0.1.002">
<grid height="320">
<template id="addressbook.edit.links" template="" lang="" group="0" version="1.3.001">
<grid width="100%" height="258" overflow="auto">
<columns>
<column/>
</columns>
@ -225,8 +244,8 @@
</rows>
</grid>
</template>
<template id="addressbook.editphones" template="" lang="" group="0" version="1.0.1.001">
<grid width="100%">
<template id="addressbook.editphones" template="" lang="" group="0" version="1.3.001">
<grid class="editphones">
<columns>
<column/>
<column/>
@ -244,69 +263,67 @@
<description value="pref"/>
</row>
<row>
<description value="business"/>
<description value="business" options=",,,tel_work2" class="bold"/>
<textbox size="30" id="tel_work2"/>
<radio options="tel_work" id="tel_prefer"/>
</row>
<row>
<description value="mobile phone"/>
<description value="mobile phone" options=",,,tel_cell2"/>
<textbox size="30" id="tel_cell2"/>
<radio options="tel_cell" id="tel_prefer"/>
</row>
<row>
<description value="Private"/>
<textbox size="30" id="tel_home2"/>
<radio options="tel_home" id="tel_prefer"/>
</row>
<row>
<description value="fax"/>
<description value="fax" options=",,,tel_fax"/>
<textbox size="30" id="tel_fax"/>
<radio options="tel_fax" id="tel_prefer"/>
</row>
<row>
<description value="car phone"/>
<description value="car phone" options=",,,tel_car"/>
<textbox size="30" id="tel_car"/>
<radio options="tel_car" id="tel_prefer"/>
</row>
<row>
<description value="video phone"/>
<textbox size="30" id="tel_video"/>
<radio options="tel_video" id="tel_prefer"/>
</row>
<row>
<description value="pager"/>
<description value="pager" options=",,,tel_pager"/>
<textbox size="30" id="tel_pager"/>
<radio options="tel_pager" id="tel_prefer"/>
</row>
<row>
<description value="voice phone"/>
<textbox size="30" id="tel_voice"/>
<radio options="tel_voice" id="tel_prefer"/>
<hrule span="all"/>
</row>
<row>
<description value="message phone"/>
<textbox size="30" id="tel_msg"/>
<description value="Assistent" options=",,,assistent" class="bold"/>
<textbox size="35" id="assistent" span="2"/>
</row>
<row>
<description value="number" options=",,,tel_assistent"/>
<textbox size="30" id="tel_assistent"/>
<radio options="tel_msg" id="tel_prefer"/>
</row>
<row>
<description value="bbs phone"/>
<textbox size="30" id="tel_bbs"/>
<radio options="tel_bbs" id="tel_prefer"/>
<hrule span="all"/>
</row>
<row>
<description value="modem phone"/>
<textbox size="30" id="tel_modem"/>
<radio options="tel_modem" id="tel_prefer"/>
<description value="Private" options=",,,tel_home2" class="bold"/>
<textbox size="30" id="tel_home2"/>
<radio options="tel_home" id="tel_prefer"/>
</row>
<row>
<description value="isdn phone"/>
<textbox size="30" id="tel_isdn"/>
<radio options="tel_isdn" id="tel_prefer"/>
<description value="mobile phone" options=",,,tel_cell_private"/>
<textbox size="30" id="tel_cell_private"/>
<radio options="tel_cell_private" id="tel_prefer"/>
</row>
<row>
<description value=" Other Phone"/>
<textbox size="30" id="ophone"/>
<radio options="ophone" id="tel_prefer"/>
<description value="fax" options=",,,tel_fax_home"/>
<textbox size="30" id="tel_fax_home"/>
<radio options="tel_fax_home" id="tel_prefer"/>
</row>
<row>
<hrule span="all"/>
</row>
<row>
<description value=" Other Phone" options=",,,tel_other"/>
<textbox size="30" id="tel_other"/>
<radio options="tel_other" id="tel_prefer"/>
</row>
<row>
<button label="Ok" onclick="hidephones(this.form); return false;" span="all" align="center"/>
@ -314,8 +331,8 @@
</rows>
</grid>
</template>
<template id="addressbook.edit" template="" lang="" group="0" version="1.0.1.002">
<grid>
<template id="addressbook.edit" template="" lang="" group="0" version="1.3.002">
<grid width="800">
<columns>
<column width="450"/>
<column/>
@ -326,24 +343,12 @@
<description/>
</row>
<row>
<grid>
<columns>
<column disabled="!@org_name"/>
<column disabled="!@org_name"/>
<column/>
</columns>
<rows>
<row>
<textbox id="org_name" readonly="true" no_lang="1"/>
<description value=":"/>
<textbox id="fn" no_lang="1" readonly="true"/>
</row>
</rows>
</grid>
<menulist span=",fileas">
<menupopup data="" rows="1" cols="3" id="fileas_type" no_lang="1"/>
</menulist>
<hbox align="right">
<description value="Type"/>
<menulist>
<menupopup no_lang="1" id="tid" onchange="1"/>
<menulist span=",leftPad5">
<menupopup no_lang="1" id="tid" onchange="1" label="Type"/>
</menulist>
<html class="space" needed="1" label=" " no_lang="1" id="typegfx" readonly="true"/>
</hbox>
@ -376,7 +381,7 @@
</columns>
<rows>
<row>
<image src="kaddressbook"/>
<image src="phone"/>
<description value="business" options=",,,tel_work"/>
<textbox id="tel_work" size="28" maxlength="40"/>
</row>
@ -408,18 +413,23 @@
</columns>
<rows>
<row>
<image src="package_network"/>
<image src="internet"/>
<description value="url" options=",,,url"/>
<textbox id="url" size="28" maxlength="128"/>
</row>
<row>
<image src="email_icon"/>
<description value="business email" options=",,,email"/>
<description/>
<description options=",,,url_home" value="Private"/>
<textbox id="url_home" size="28" maxlength="128"/>
</row>
<row>
<image src="email.png"/>
<description value="email" options=",,,email"/>
<textbox id="email" size="28" maxlength="64"/>
</row>
<row>
<description/>
<description value="home email" options=",,,email_home"/>
<description value="Private" options=",,,email_home"/>
<textbox id="email_home" size="28" maxlength="64"/>
</row>
</rows>
@ -427,13 +437,19 @@
</groupbox>
</vbox>
</row>
<row disabled="!@id">
<menulist>
<menupopup type="select-account" id="owner" readonly="true" label="Owner"/>
</menulist>
<row>
<hbox orient=",0,0">
<menulist span=",leftPad5">
<menupopup type="select-account" id="creator" readonly="true" label="Created"/>
</menulist>
<date-time id="created" class="leftPad5" readonly="true"/>
</hbox>
<hbox align="right">
<description value="Last modified"/>
<date-time id="last_mod" readonly="true"/>
<menulist>
<menupopup type="select-account" id="modifier" readonly="true"/>
</menulist>
<date-time id="modified" readonly="true"/>
</hbox>
</row>
<row disabled="@hidebuttons">

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1015 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 B

View File

Before

Width:  |  Height:  |  Size: 754 B

After

Width:  |  Height:  |  Size: 754 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

After

Width:  |  Height:  |  Size: 753 B

View File

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 299 B

View File

Before

Width:  |  Height:  |  Size: 635 B

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,167 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<template id="addressbook.index.right" template="" lang="" group="0" version="1.3.001">
<menulist>
<menupopup label="Type" id="col_filter[tid]" statustext="Select addressbook type" onchange="1"/>
</menulist>
</template>
<template id="addressbook.index.rows" template="" lang="" group="0" version="1.3.001">
<grid width="100%">
<columns>
<column/>
<column/>
<column width="60" disabled="@no_photo"/>
<column/>
<column disabled="!@show_home"/>
<column/>
<column/>
<column disabled="@no_customfields"/>
<column width="90"/>
</columns>
<rows>
<row class="th">
<description/>
<grid spacing="0" padding="0">
<columns>
<column/>
<column/>
</columns>
<rows>
<row disabled="!@order=n_given">
<nextmatch-sortheader id="n_given" label="Firstname"/>
<nextmatch-sortheader label="Name" id="n_family"/>
</row>
<row disabled="!@order=n_family">
<nextmatch-sortheader label="Name" id="n_family"/>
<nextmatch-sortheader id="n_given" label="Firstname"/>
</row>
<row>
<nextmatch-sortheader id="org_name" label="Company" span="all"/>
</row>
<row disabled="!@order=org_name">
<nextmatch-sortheader id="n_family" label="Name"/>
<nextmatch-sortheader id="n_given" label="Firstname"/>
</row>
</rows>
</grid>
<description value="Photo"/>
<description value="Business address"/>
<description value="Home address"/>
<vbox orient=",0,0">
<description id="tel_work" value="Business phone"/>
<description value="Mobile phone" id="tel_cell"/>
<description id="tel_home" value="Home phone"/>
</vbox>
<vbox orient=",0,0">
<description id="url" value="Url"/>
<description value="Business email" id="email"/>
<description id="email_home" value="Home email"/>
</vbox>
<grid spacing="0" padding="0">
<columns>
<column/>
</columns>
<rows>
<row>
<description no_lang="1" id="customfields[$row][label]"/>
</row>
</rows>
</grid>
<hbox align="center" class="noPrint">
<description value="Actions" align="center"/>
<button image="check" label="Check all" id="check_all" statustext="Check all" onclick="toggle_all(this.form,form::name('checked[]')); return false;" needed="1" align="right"/>
</hbox>
</row>
<row class="row" valign="top">
<image label="$row_cont[type_label]" src="${row}[type]" align="center" no_lang="1"/>
<vbox id="${row}[id]" orient=",0,0">
<description id="${row}[first_given]" no_lang="1"/>
<description id="${row}[first_family]" no_lang="1"/>
<description id="${row}[org_name]" no_lang="1"/>
<description id="${row}[org_unit]" no_lang="1"/>
<description id="${row}[title]" no_lang="1"/>
<description id="${row}[first_org]" no_lang="1"/>
</vbox>
<image src="${row}[photo]"/>
<vbox orient=",0,0">
<description id="${row}[adr_one_countryname]" no_lang="1"/>
<hbox orient="0,0,0">
<description no_lang="1" id="${row}[adr_one_locality]"/>
<description id="${row}[adr_one_postalcode]" class="leftPad5" value=" " no_lang="1"/>
</hbox>
<description no_lang="1" id="${row}[adr_one_street]"/>
<description id="${row}[adr_one_street2]" no_lang="1"/>
</vbox>
<vbox orient=",0,0">
<description id="${row}[adr_two_countryname]" no_lang="1"/>
<hbox orient=",0,0">
<description no_lang="1" id="${row}[adr_two_locality]"/>
<description id="${row}[adr_two_postalcode]" class="leftPad5" value=" " no_lang="1"/>
</hbox>
<description no_lang="1" id="${row}[adr_two_street]"/>
<description id="${row}[adr_two_street2]" no_lang="1"/>
</vbox>
<vbox orient=",0,0">
<description no_lang="1" id="${row}[tel_work]" class="telNumbers"/>
<description id="${row}[tel_cell]" no_lang="1" class="telNumbers"/>
<description id="${row}[tel_home]" no_lang="1" class="telNumbers"/>
<description id="${row}[tel_prefered]" no_lang="1"/>
</vbox>
<vbox orient=",0,0">
<description options=",,1" class="fixedHeight" no_lang="1" id="${row}[url]"/>
<description options=",@${row}[email_link],,,_blank,$row_cont[email_popup]" class="fixedHeight" id="${row}[email]" no_lang="1"/>
<description options=",@${row}[email_home_link],,,_blank,$row_cont[email_home_popup]" class="fixedHeight" id="${row}[email_home]" no_lang="1"/>
</vbox>
<grid height="60" spacing="0" padding="0" overflow="auto">
<columns>
<column/>
</columns>
<rows>
<row>
<description class="fixedHeight" id="$row" no_lang="1"/>
</row>
</rows>
</grid>
<hbox class="noPrint" orient="0,0">
<image options="addressbook.uicontacts.view&amp;contact_id=$row_cont[id]" label="View" src="view"/>
<button image="edit" label="Edit" onclick="window.open(egw::link('/index.php','menuaction=addressbook.uicontacts.edit&amp;contact_id=$row_cont[id]'),'_blank','dependent=yes,width=850,height=440,scrollbars=yes,status=yes'); return false;" id="edit[$row_cont[id]]"/>
<button id="delete[$row_cont[id]]" image="delete" label="Delete" statustext="Delete this contact" onclick="return confirm('Delete this contact');"/>
<checkbox id="checked[]" options="$row_cont[id]" statustext="Select multiple contacts for a further action" align="right"/>
</hbox>
</row>
</rows>
</grid>
</template>
<template id="addressbook.index" template="" lang="" group="0" version="1.3.001">
<grid width="100%">
<columns>
<column/>
<column/>
</columns>
<rows>
<row disabled="!@msg">
<description span="all" class="redItalic" align="center" id="msg" no_lang="1"/>
<description/>
</row>
<row disabled="1">
<description/>
<template align="right" id="addressbook.index.right"/>
</row>
<row>
<nextmatch options="addressbook.index.rows" id="nm" span="all"/>
</row>
<row class="noPrint">
<button id="add" label="Add" statustext="Add a new contact" onclick="window.open(egw::link('/index.php','menuaction=addressbook.uicontacts.edit'),'_blank','dependent=yes,width=850,height=440,scrollbars=yes,status=yes'); return false;"/>
<hbox align="right">
<checkbox id="use_all" label="whole selection" onchange="if (!confirm('Apply the action on the whole selection, NOT only the shown contacts!!!')) this.checked=false;" statustext="Apply the action on the whole selection, NOT only the shown contacts!!!"/>
<menulist>
<menupopup onchange="1" options="Select an action or addressbook to move to..." no_lang="1" id="action" statustext="Select an action or addressbook to move to"/>
</menulist>
<button image="arrow_ltr" label="Check all" id="check_all" statustext="Check all" onclick="toggle_all(this.form,form::name('nm[rows][checked][]')); return false;" needed="1" class="checkAllArrow"/>
</hbox>
</row>
</rows>
</grid>
</template>
</overlay>

View File

@ -3,5 +3,6 @@
<td>{user}</td>
<td align="center"><input type="checkbox" name="{read}" value="Y"{read_selected}></td>
<td align="center"><input type="checkbox" name="{edit}" value="Y"{edit_selected}></td>
<td align="center"><input type="checkbox" name="{add}" value="Y"{add_selected}></td>
<td align="center"><input type="checkbox" name="{delete}" value="Y"{delete_selected}></td>
</tr>

View File

@ -1,6 +1,8 @@
<!-- $Id$ -->
<tr bgcolor="{bg_color}">
<td>{string}</td>
<td align="center">{lang_read}</td>
<td align="center">{lang_edit}</td>
<td align="center">{lang_add}</td>
<td align="center">{lang_delete}</td>
</tr>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -150,16 +150,17 @@
// make this information also in hook available
$lid = $GLOBALS['egw']->accounts->id2name($account_id);
$GLOBALS['hook_values']['account_id'] = $account_id;
$GLOBALS['hook_values']['account_lid'] = $lid;
$singleHookValues = $GLOBALS['hook_values']+array('location' => 'deleteaccount');
$GLOBALS['hook_values'] = array(
'account_id' => $account_id,
'account_lid' => $lid,
'new_owner' => (int)$_POST['new_owner'],
'location' => 'deleteaccount',
);
foreach($GLOBALS['egw_info']['apps'] as $appname => $data)
{
if($appname != 'admin' && $appname != 'preferences')
{
$GLOBALS['egw']->hooks->single($singleHookValues,$appname);
$GLOBALS['egw']->hooks->single($GLOBALS['hook_values'],$appname);
}
}

View File

@ -28,11 +28,12 @@
$this->rowColor[1] = $GLOBALS['egw_info']['theme']['row_off'];
}
function section_item($pref_link='',$pref_text='', $class)
function section_item($pref_link='',$pref_text='', $class='',$options='')
{
$this->t->set_var('row_link',$pref_link);
$this->t->set_var('row_text',$pref_text);
$this->t->set_var('class',$class);
$this->t->set_var('row_options',$options);
$this->t->parse('all_rows','link_row',True);
}
@ -58,7 +59,7 @@
{
$link = $GLOBALS['egw']->link($value['url'],'account_id=' . get_var('account_id',array('GET','POST')));
}
$this->section_item($link,lang($value['description']),($i%2) ? "row_on": "row_off");
$this->section_item($link,lang($value['description']),($i%2) ? "row_on": "row_off",$value['options']);
$i++;
}

View File

@ -14,6 +14,6 @@
<!-- END menu_links -->
<!-- BEGIN link_row -->
<tr class="{class}">
<td>&nbsp;&nbsp;<a href="{row_link}">{row_text}</a></td>
<td>&nbsp;&nbsp;<a href="{row_link}" {row_options}>{row_text}</a></td>
</tr>
<!-- END link_row -->