diff -Nru egroupware-1.4.004-2.dfsg/about.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/about.php
--- egroupware-1.4.004-2.dfsg/about.php 2008-04-15 14:57:39.000000000 +0100
+++ egroupware-1.6.001+dfsg/about.php 2008-11-24 11:42:31.000000000 +0000
@@ -17,7 +17,7 @@
* @author Ralf Becker
contacts_admin_prefs::all_hooks(".print_r($args,True).") appname='$appname', location='$location'
\n"; + + if ($location == 'sidebox_menu') + { + $file = array( + array( + 'text' => ''.lang('Add').'', + 'no_lang' => true, + 'link' => false + ), + array( + 'text' => ''.lang('Advanced search').'', + 'no_lang' => true, + 'link' => false + ), + '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 ($GLOBALS['egw_info']['server']['contact_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 are not availible in LDAP + if ($GLOBALS['egw_info']['server']['contact_repository'] != 'ldap') + { + $file['Custom fields'] = $GLOBALS['egw']->link('/index.php',array( + 'menuaction' => 'admin.customfields.edit', + 'appname' => $appname, + 'use_private'=> 1, + )); + } + if ($location == 'admin') + { + display_section($appname,$file); + } + else + { + display_sidebox($appname,lang('Admin'),$file); + } + } + } + + /** + * populates $GLOBALS['settings'] for the preferences + */ + static function settings() + { + $GLOBALS['settings']['add_default'] = array( + 'type' => 'select', + 'label' => 'Default addressbook for adding contacts', + 'name' => 'add_default', + 'help' => 'Which addressbook should be selected when adding a contact AND you have no add rights to the current addressbook.', + 'values' => ExecMethod('addressbook.addressbook_ui.get_addressbooks',EGW_ACL_ADD), + 'xmlrpc' => True, + 'admin' => False, + ); + $GLOBALS['settings']['mainscreen_showbirthdays'] = array( + 'type' => 'select', + 'label' => 'Show birthday reminders on main screen', + 'name' => 'mainscreen_showbirthdays', + 'help' => 'Displays a remider for birthdays on the startpage (page you get when you enter eGroupWare or click on the homepage icon).', + 'values' => array( + 0 => lang('No'), + 1 => lang('Yes, for today and tomorrow'), + 3 => lang('Yes, for the next three days'), + 7 => lang('Yes, for the next week'), + 14=> lang('Yes, for the next two weeks'), + ), + 'xmlrpc' => True, + 'admin' => False, + ); + $GLOBALS['settings']['no_auto_hide'] = array( + 'type' => 'check', + 'label' => 'Don\'t hide empty columns', + 'name' => 'no_auto_hide', + 'help' => 'Should the columns photo and home address always be displayed, even if they are empty.', + 'xmlrpc' => True, + 'admin' => false, + ); + // CSV Export + $GLOBALS['settings']['csv_fields'] = array( + 'type' => 'select', + 'label' => 'Fields for the CSV export', + 'name' => 'csv_fields', + 'values' => array( + 'all' => lang('All'), + 'business' => lang('Business address'), + 'home' => lang('Home address'), + ), + 'help' => 'Which fields should be exported. All means every field stored in the addressbook incl. the custom fields. The business or home address only contains name, company and the selected address.', + 'xmlrpc' => True, + 'admin' => false, + ); + $GLOBALS['settings']['csv_charset'] = array( + 'type' => 'select', + 'label' => 'Charset for the CSV export', + 'name' => 'csv_charset', + 'values' => $GLOBALS['egw']->translation->get_installed_charsets()+array('utf-8' => 'utf-8 (Unicode)'), + 'help' => 'Which charset should be used for the CSV export. The system default is the charset of this eGroupWare installation.', + 'xmlrpc' => True, + 'admin' => false, + ); + + if ($GLOBALS['egw_info']['server']['contact_repository'] != 'ldap') + { + $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, + ); + } + $GLOBALS['settings']['link_title'] = array( + 'type' => 'select', + 'label' => 'Link title for contacts show', + 'name' => 'link_title', + 'values' => array( + 'n_fileas' => lang('own sorting').' ('.lang('default').': '.lang('Company').': '.lang('lastname').', '.lang('firstname').')', + 'org_name: n_family, n_given' => lang('Company').': '.lang('lastname').', '.lang('firstname'), + 'org_name, org_unit: n_family, n_given' => lang('Company').', '.lang('Department').': '.lang('lastname').', '.lang('firstname'), + 'org_name, adr_one_locality: n_family, n_given' => lang('Company').', '.lang('City').': '.lang('lastname').', '.lang('firstname'), + 'org_name, org_unit, adr_one_locality: n_family, n_given' => lang('Company').', '.lang('Department').', '.lang('City').': '.lang('lastname').', '.lang('firstname'), + ), + 'help' => 'What should links to the addressbook display in other applications. Empty values will be left out. You need to log in anew, if you change this setting!', + 'xmlrpc' => True, + 'admin' => false, + ); + $GLOBALS['settings']['addr_format'] = array( + 'type' => 'select', + 'label' => 'Default address format', + 'name' => 'addr_format', + 'values' => array( + 'postcode_city' => lang('zip code').' '.lang('City'), + 'city_state_postcode' => lang('City').' '.lang('State').' '.lang('zip code'), + ), + 'help' => 'Which address format should the addressbook use for countries it does not know the address format. If the address format of a country is known, it uses it independent of this setting.', + 'xmlrpc' => True, + 'admin' => false, + ); + $GLOBALS['settings']['fileas_default'] = array( + 'type' => 'select', + 'label' => 'Default file as format', + 'name' => 'fileas_default', + 'values' => ExecMethod('addressbook.addressbook_bo.fileas_options'), + 'help' => 'Default format for fileas, eg. for new entries.', + 'xmlrpc' => True, + 'admin' => false, + ); + $GLOBALS['settings']['hide_accounts'] = array( + 'type' => 'check', + 'label' => 'Hide accounts from addressbook', + 'name' => 'hide_accounts', + 'help' => 'Hides accounts completly from the adressbook.', + 'xmlrpc' => True, + 'admin' => false, + ); + $GLOBALS['settings']['distributionListPreferredMail'] = array( + 'type' => 'select', + 'label' => 'Preferred email address to use in distribution lists', + 'name' => 'distributionListPreferredMail', + 'values' => array( + 'email' => lang("Work email if given, else home email"), + 'email_home' => lang("Home email if given, else work email"), + ), + 'help' => 'Defines which email address (business or home) to use as the preferred one for distribution lists in mail.', + 'xmlrpc' => True, + 'admin' => False + ); + if ($GLOBALS['egw_info']['user']['apps']['filemanager']) + { + $link = $GLOBALS['egw']->link('/index.php','menuaction=addressbook.addressbook_merge.show_replacements'); + + $GLOBALS['settings']['default_document'] = array( + 'type' => 'input', + 'size' => 60, + 'label' => 'Default document to insert contacts', + 'name' => 'default_document', + 'help' => lang('If you specify a document (full vfs path) here, addressbook displays an extra document icon for each address. That icon allows to download the specified document with the contact data inserted.').' '. + lang('The document can contain placeholder like $$n_fn$$, to be replaced with the contact data (%1full list of placeholder names%2).','','').' '. + lang('At the moment the following document-types are supported:').'*.rtf, *.txt', + 'run_lang' => false, + 'xmlrpc' => True, + 'admin' => False, + ); + $GLOBALS['settings']['document_dir'] = array( + 'type' => 'input', + 'size' => 60, + 'label' => 'Directory with documents to insert contacts', + 'name' => 'document_dir', + 'help' => lang('If you specify a directory (full vfs path) here, addressbook displays an action for each document. That action allows to download the specified document with the contact data inserted.').' '. + lang('The document can contain placeholder like $$n_fn$$, to be replaced with the contact data (%1full list of placeholder names%2).','','').' '. + lang('At the moment the following document-types are supported:').'*.rtf, *.txt', + 'run_lang' => false, + 'xmlrpc' => True, + 'admin' => False, + ); + } + return true; // otherwise prefs say it cant find the file ;-) + } + + /** + * add an Addressbook tab to Admin >> Edit user + */ + static function edit_user() + { + global $menuData; + + $menuData[] = array( + 'description' => 'Addressbook', + 'url' => '/index.php', + 'extradata' => 'menuaction=addressbook.addressbook_ui.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')).'"', + ); + } + + /** + * 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 + */ + static function search_link($location) + { + return array( + 'query' => 'addressbook.addressbook_bo.link_query', + 'title' => 'addressbook.addressbook_bo.link_title', + 'titles' => 'addressbook.addressbook_bo.link_titles', + 'view' => array( + 'menuaction' => 'addressbook.addressbook_ui.view' + ), + 'view_id' => 'contact_id', + 'add' => array( + 'menuaction' => 'addressbook.addressbook_ui.edit' + ), + 'add_app' => 'link_app', + 'add_id' => 'link_id', + 'add_popup' => '850x440', + 'file_access'=> 'addressbook.addressbook_bo.file_access', + ); + } + + /** + * Register contacts as calendar resources (items which can be sheduled by the calendar) + * + * @param array $args hook-params (not used) + * @return array + */ + static function calendar_resources($args) + { + return array( + 'type' => 'c',// one char type-identifiy for this resources + 'info' => 'addressbook.addressbook_bo.calendar_info',// info method, returns array with id, type & name for a given id + ); + } + + /** + * Register addressbook for group-acl + * + * @param array $args hook-params (not used) + * @return boolean|string true=standard group acl link, of string with link + */ + static function group_acl($args) + { + // addressbook uses group-acl, only if contacts-backend is NOT LDAP, as the ACL can not be modified there + return $GLOBALS['egw_info']['server']['contact_repository'] != 'ldap'; + } +} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_ldap.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_ldap.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_ldap.inc.php 1970-01-01 01:00:00.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_ldap.inc.php 2008-11-24 11:43:08.000000000 +0000 @@ -0,0 +1,1175 @@ + + * @author Lars Kneschkeldap_mod_add($this->ds,'$dn',array(objectClass =>".print_r($ldapContact['objectClass'],true)."))
\n"; + error_log('class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); + return $this->_error(__LINE__); + } + } + } + + // check if we need to rename the DN or need to recreate the contact + $newRDN = 'uid='. ldap::quote($contactUID); + $newDN = $newRDN .','. $baseDN; + if(strtolower($dn) != strtolower($newDN) || $needRecreation) + { + $result = ldap_read($this->ds, $dn, 'objectclass=*'); + $oldContact = ldap_get_entries($this->ds, $result); + foreach($oldContact[0] as $key => $value) + { + if(is_array($value)) + { + unset($value['count']); + $newContact[$key] = $value; + } + } + $newContact['uid'] = $contactUID; + + if(is_array($ldapContact['objectClass']) && count($ldapContact['objectClass']) > 0) + { + $newContact['objectclass'] = array_unique(array_map('strtolower', // objectclasses my have different case + array_merge($newContact['objectclass'], $ldapContact['objectClass']))); + } + + if(!ldap_delete($this->ds, $dn)) + { + error_log('class.so_ldap.inc.php ('. __LINE__ .') delete of old '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); + return $this->_error(__LINE__); + } + if(!@ldap_add($this->ds, $newDN, $newContact)) + { + //echo "recreate: ldap_add($this->ds,'$newDN',".print_r($newContact,true).")
\n"; + //print 'class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')';_debug_array($newContact);exit; + error_log('class.so_ldap.inc.php ('. __LINE__ .') re-create contact as '. $newDN .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); + error_log(print_r($newContact,true)); + return $this->_error(__LINE__); + } + $dn = $newDN; + } + unset($ldapContact['objectClass']); + + if (!@ldap_modify($this->ds, $dn, $ldapContact)) + { + //echo "ldap_modify($this->ds,'$dn',".print_r($ldapContact,true).")
\n"; + error_log('class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); + error_log(print_r($ldapContact,true)); + return $this->_error(__LINE__); + } + } + else + { + $dn = 'uid='. ldap::quote($ldapContact['uid']) .','. $baseDN; + + if (!@ldap_add($this->ds, $dn, $ldapContact)) + { + //echo "ldap_add($this->ds,'$dn',".print_r($ldapContact,true).")
\n"; + error_log('class.so_ldap.inc.php ('. __LINE__ .') add of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); + error_log(print_r($ldapContact,true)); + return $this->_error(__LINE__); + } + } + return 0; // Ok, no error + } + + /** + * deletes row representing keys in internal data or the supplied $keys if != null + * + * @param array $keys if given array with col => value pairs to characterise the rows to delete + * @return int affected rows, should be 1 if ok, 0 if an error + */ + function delete($keys=null) + { + // single entry + if($keys[$this->contacts_id]) $keys = array( 0 => $keys); + + if(!is_array($keys)) + { + $keys = array( $keys); + } + + $ret = 0; + + $attributes = array('dn'); + + foreach($keys as $entry) + { + $entry = ldap::quote(is_array($entry) ? $entry['id'] : $entry); + if($result = ldap_search($this->ds, $GLOBALS['egw_info']['server']['ldap_contact_context'], + "(|(entryUUID=$entry)(uid=$entry))", $attributes)) + { + $contactInfo = ldap_get_entries($this->ds, $result); + if(@ldap_delete($this->ds, $contactInfo[0]['dn'])) + { + $ret++; + } + } + } + return $ret; + } + + /** + * 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 &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false) + { + //_debug_array($criteria); print "OrderBY: $order_by";_debug_array($extra_cols);_debug_array($filter); + #$order_by = explode(',',$order_by); + #$order_by = explode(' ',$order_by); + #$sort = $order_by[0]; + #$order = $order_by[1]; + #$query = $criteria; + #$fields = $only_keys ? ($only_keys === true ? $this->contacts_id : $only_keys) : ''; + #$limit = $need_full_no_count ? 0 : $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs']; + #return parent::read($start,$limit,$fields,$query,$filter,$sort,$order); + + if((int)$filter['owner']) + { + if (!($accountName = $GLOBALS['egw']->accounts->id2name($filter['owner']))) return false; + + $searchDN = 'cn='. ldap::quote(strtolower($accountName)) .','; + + if ($filter['owner'] < 0) + { + $searchDN .= $this->sharedContactsDN; + $addressbookType = ADDRESSBOOK_GROUP; + } + else + { + $searchDN .= $this->personalContactsDN; + $addressbookType = ADDRESSBOOK_PERSONAL; + } + } + elseif (!isset($filter['owner'])) + { + $searchDN = $GLOBALS['egw_info']['server']['ldap_contact_context']; + $addressbookType = ADDRESSBOOK_ALL; + } + else + { + $searchDN = $GLOBALS['egw_info']['server']['ldap_context']; + $addressbookType = ADDRESSBOOK_ACCOUNTS; + } + + // create the search filter + switch($addressbookType) + { + case ADDRESSBOOK_ALL: + $objectFilter = '(|(objectclass=inetorgperson)(objectclass=posixaccount))'; + break; + case ADDRESSBOOK_ACCOUNTS: + $objectFilter = '(objectclass=posixaccount)'; + break; + default: + $objectFilter = '(objectclass=inetorgperson)'; + break; + } + + $searchFilter = ''; + if(is_array($criteria) && count($criteria) > 0) + { + $wildcard = $wildcard === '%' ? '*' : ''; + $searchFilter = ''; + foreach($criteria as $egwSearchKey => $searchValue) + { + foreach($this->schema2egw as $mapping) + { + if(($ldapSearchKey = $mapping[$egwSearchKey])) + { + $searchString = $GLOBALS['egw']->translation->convert($searchValue,$this->charset,'utf-8'); + $searchFilter .= '('.$ldapSearchKey.'='.$wildcard.ldap::quote($searchString).$wildcard.')'; + break; + } + } + } + if($op == 'AND') + { + $searchFilter = "(&$searchFilter)"; + } + else + { + $searchFilter = "(|$searchFilter)"; + } + } + $colFilter = $this->_colFilter($filter); + $ldapFilter = "(&$objectFilter$searchFilter$colFilter)"; + + if (!($rows = $this->_searchLDAP($searchDN, $ldapFilter, $this->all_attributes, $addressbookType))) + { + return $rows; + } + if ($order_by) + { + $order = array(); + $sort = 'ASC'; + foreach(explode(',',$order_by) as $o) + { + if (substr($o,-4) == ' ASC') + { + $sort = 'ASC'; + $order[] = substr($o,0,-4); + } + elseif (substr($o,-5) == ' DESC') + { + $sort = 'DESC'; + $order[] = substr($o,0,-5); + } + elseif ($o) + { + $order[] = $o; + } + } + $rows = ExecMethod2('phpgwapi.arrayfunctions.arfsort',$rows,$order,$sort); + } + // if requested ($start !== false) return only limited resultset + if (is_array($start)) + { + list($start,$offset) = $start; + } + if(is_numeric($start) && is_numeric($offset)) + { + return array_slice($rows, $start, $offset); + } + elseif(is_numeric($start)) + { + return array_slice($rows, $start, $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs']); + } + return $rows; + } + + /** + * Process so_sql like filters (at the moment only a subset used by the addressbook UI + * + * @param array $filter col-name => value pairs or just sql strings + * @return string ldap filter + */ + function _colFilter($filter) + { + if (!is_array($filter)) return ''; + + $filters = ''; + foreach($filter as $key => $value) + { + if ($key != 'cat_id' && $key != 'account_id' && !$value) continue; + + switch((string) $key) + { + case 'owner': // already handled + case 'tid': // ignored + break; + + case 'account_id': + if (is_null($value)) + { + $filters .= '(!(uidNumber=*))'; + } + elseif ($value) + { + $filters .= '(uidNumber='.ldap::quote($value).')'; + + } + break; + + case 'cat_id': + if (is_null($value)) + { + $filters .= '(!(category=*))'; + } + elseif((int)$value) + { + if (!is_object($GLOBALS['egw']->categories)) + { + $GLOBALS['egw']->categories = CreateObject('phpgwapi.categories'); + } + $cats = $GLOBALS['egw']->categories->return_all_children((int)$value); + if (count($cats) > 1) $filters .= '(|'; + foreach($cats as $cat) + { + $catName = $GLOBALS['egw']->translation->convert( + $GLOBALS['egw']->categories->id2name($cat),$this->charset,'utf-8'); + $filters .= '(category='.ldap::quote($catName).')'; + } + if (count($cats) > 1) $filters .= ')'; + } + break; + + default: + if (!is_int($key)) + { + foreach($this->schema2egw as $mapping) + { + if (isset($mapping[$key])) + { + // todo: value = "!''" + $filters .= '('.$mapping[$key].'='.($value === "!''" ? '*' : + ldap::quote($GLOBALS['egw']->translation->convert($value,$this->charset,'utf-8'))).')'; + break; + } + } + } + // filter for letter-search + elseif (preg_match("/^([^ ]+) I?LIKE '(.*)%'$/",$value,$matches)) + { + foreach($this->schema2egw as $mapping) + { + if (isset($mapping[$matches[1]])) + { + $filters .= '('.$mapping[$matches[1]].'='.ldap::quote( + $GLOBALS['egw']->translation->convert($matches[2],$this->charset,'utf-8')).'*)'; + break; + } + } + } + break; + } + } + return $filters; + } + + /** + * Perform the actual ldap-search, retrieve and convert all entries + * + * Used be read and search + * + * @internal + * @param string $_ldapContext + * @param string $_filter + * @param array $_attributes + * @param int $_addressbooktype + * @return array/boolean with eGW contacts or false on error + */ + function _searchLDAP($_ldapContext, $_filter, $_attributes, $_addressbooktype) + { + $this->total = 0; + + $_attributes[] = 'entryUUID'; + $_attributes[] = 'uid'; + $_attributes[] = 'uidNumber'; + $_attributes[] = 'objectClass'; + $_attributes[] = 'createTimestamp'; + $_attributes[] = 'modifyTimestamp'; + $_attributes[] = 'creatorsName'; + $_attributes[] = 'modifiersName'; + + //echo "ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit)
\n"; + if($_addressbooktype == ADDRESSBOOK_ALL) + { + $result = ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit); + } + else + { + $result = @ldap_list($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit); + } + if(!$result) return array(); + + $entries = ldap_get_entries($this->ds, $result); + $this->total = $entries['count']; + foreach($entries as $i => $entry) + { + if (!is_int($i)) continue; // eg. count + + $contact = array( + 'id' => $entry['uid'][0] ? $entry['uid'][0] : $entry['entryuuid'][0], + 'tid' => 'n', // the type id for the addressbook + ); + foreach($entry['objectclass'] as $ii => $objectclass) + { + $objectclass = strtolower($objectclass); + if (!is_int($ii) || !isset($this->schema2egw[$objectclass])) + { + continue; // eg. count or unsupported objectclass + } + foreach($this->schema2egw[$objectclass] as $egwFieldName => $ldapFieldName) + { + if(!empty($entry[$ldapFieldName][0]) && !isset($contact[$egwFieldName])) + { + $contact[$egwFieldName] = $GLOBALS['egw']->translation->convert($entry[$ldapFieldName][0],'utf-8'); + } + } + $objectclass2egw = '_'.$objectclass.'2egw'; + if (method_exists($this,$objectclass2egw)) + { + $this->$objectclass2egw($contact,$entry); + } + } + // read binary jpegphoto only for one result == call by read + if ($this->total == 1 && isset($entry['jpegphoto'][0])) + { + $bin = ldap_get_values_len($this->ds,ldap_first_entry($this->ds,$result),'jpegphoto'); + $contact['jpegphoto'] = $bin[0]; + } + if(preg_match('/cn=([^,]+),'.preg_quote($this->personalContactsDN,'/').'$/i',$entry['dn'],$matches)) + { + // personal addressbook + $contact['owner'] = $GLOBALS['egw']->accounts->name2id($matches[1],'account_lid','u'); + $contact['private'] = 0; + } + elseif(preg_match('/cn=([^,]+),'.preg_quote($this->sharedContactsDN,'/').'$/i',$entry['dn'],$matches)) + { + // group addressbook + $contact['owner'] = $GLOBALS['egw']->accounts->name2id($matches[1],'account_lid','g'); + $contact['private'] = 0; + } + else + { + // accounts + $contact['owner'] = 0; + $contact['private'] = 0; + } + ######################################### + ## this piece of code could never have been working, as the call to $GLOBALS['egw']->accounts->name2id is wrong + ######################################### + #foreach(array( + # 'creatorsname' => 'creator', + # 'modifiersname' => 'modifier', + #) as $ldapFieldName => $egwFieldName) + #{ + # if (!empty($entry[$ldapFieldName][0]) && preg_match('/^cn=([^,]+),/',$entry[$ldapFieldName][0],$matches)) + # { + # $contact[$egwFieldName] = $GLOBALS['egw']->accounts->name2id($matches[1],'u'); + # } + #} + foreach(array( + 'createtimestamp' => 'created', + 'modifytimestamp' => 'modified', + ) as $ldapFieldName => $egwFieldName) + { + if(!empty($entry[$ldapFieldName][0])) + { + $contact[$egwFieldName] = $this->_ldap2ts($entry[$ldapFieldName][0]); + } + } + $contacts[] = $contact; + } + return $contacts; + } + + /** + * Creates a timestamp from the date returned by the ldap server + * + * @internal + * @param string $date YYYYmmddHHiiss + * @return int + */ + function _ldap2ts($date) + { + return gmmktime(substr($date,8,2),substr($date,10,2),substr($date,12,2), + substr($date,4,2),substr($date,6,2),substr($date,0,4)); + } + + /** + * check if $baseDN exists. If not create it + * + * @param string $baseDN cn=xxx,ou=yyy,ou=contacts,$GLOBALS['egw_info']['server']['ldap_contact_context'] + * @return boolean/string false on success or string with error-message + */ + function _check_create_dn($baseDN) + { + // check if $baseDN exists. If not create new one + if(@ldap_read($this->ds, $baseDN, 'objectclass=*')) + { + return false; + } + if(ldap_errno($this->ds) != 32 || substr($baseDN,0,3) != 'cn=') + { + return $this->_error(__LINE__); // baseDN does NOT exist and we cant/wont create it + } + // create a admin connection to add the needed DN + $adminLDAP =& new ldap; + $adminDS = $adminLDAP->ldapConnect(); + + list(,$ou) = explode(',',$baseDN); + foreach(array( + 'ou=contacts,'.$GLOBALS['egw_info']['server']['ldap_contact_context'], + $ou.',ou=contacts,'.$GLOBALS['egw_info']['server']['ldap_contact_context'], + $baseDN, + ) as $dn) + { + if (!@ldap_read($this->ds, $dn, 'objectclass=*') && ldap_errno($this->ds) == 32) + { + // entry does not exist, lets try to create it + list($top) = explode(',',$dn); + list($var,$val) = explode('=',$top); + $data = array( + 'objectClass' => $var == 'cn' ? 'organizationalRole' : 'organizationalUnit', + $var => $val, + ); + if(!@ldap_add($adminDS, $dn, $data)) + { + //echo "ldap_add($adminDS,'$dn',".print_r($data,true).")
\n"; + $err = $this->_error(__LINE__,$adminDS); + $adminLDAP->ldapDisconnect(); + return $err; + } + } + } + $adminLDAP->ldapDisconnect(); + + return false; + } + + /** + * error message for failed ldap operation + * + * @param int $line + * @return string + */ + function _error($line,$ds=null) + { + return ldap_error($ds ? $ds : $this->ds).': so_ldap: '.$line; + } + + /** + * Special handling for mapping of eGW contact-data to the evolutionPerson objectclass + * + * Please note: all regular fields are already copied! + * + * @internal + * @param array &$ldapContact already copied fields according to the mapping + * @param array $data eGW contact data + * @param boolean $isUpdate + */ + function _egw2evolutionperson(&$ldapContact,$data,$isUpdate) + { + if(!empty($data['cat_id'])) + { + $ldapContact['category'] = array(); + foreach(is_array($data['cat_id']) ? $data['cat_id'] : explode(',',$data['cat_id']) as $cat) + { + $ldapContact['category'][] = $GLOBALS['egw']->translation->convert( + ExecMethod('phpgwapi.categories.id2name',$cat),$this->charset,'utf-8'); + } + } + foreach(array( + 'postaladdress' => $data['adr_one_street'] .'$'. $data['adr_one_locality'] .', '. $data['adr_one_region'] .'$'. $data['adr_one_postalcode'] .'$$'. $data['adr_one_countryname'], + 'homepostaladdress' => $data['adr_two_street'] .'$'. $data['adr_two_locality'] .', '. $data['adr_two_region'] .'$'. $data['adr_two_postalcode'] .'$$'. $data['adr_two_countryname'], + ) as $attr => $value) + { + if($value != '$, $$$') + { + $ldapContact[$attr] = $GLOBALS['egw']->translation->convert($value,$this->charset,'utf-8'); + } + elseif($isUpdate) + { + $ldapContact[$attr] = array(); + } + } + // save the phone number of the primary contact and not the eGW internal field-name + if ($data['tel_prefer'] && $data[$data['tel_prefer']]) + { + $ldapContact['primaryphone'] = $data[$data['tel_prefer']]; + } + elseif($isUpdate) + { + $ldapContact['primaryphone'] = array(); + } + } + + /** + * Special handling for mapping data of the evolutionPerson objectclass to eGW contact + * + * Please note: all regular fields are already copied! + * + * @internal + * @param array &$contact already copied fields according to the mapping + * @param array $data eGW contact data + */ + function _evolutionperson2egw(&$contact,$data) + { + if ($data['category'] && is_array($data['category'])) + { + $contact['cat_id'] = array(); + foreach($data['category'] as $iii => $cat) + { + if (!is_int($iii)) continue; + + $contact['cat_id'][] = ExecMethod('phpgwapi.categories.name2id',$cat); + } + if ($contact['cat_id']) $contact['cat_id'] = implode(',',$contact['cat_id']); + } + if ($data['primaryphone']) + { + unset($contact['tel_prefer']); // to not find itself + $contact['tel_prefer'] = array_search($data['primaryphone'][0],$contact); + } + } + + /** + * Special handling for mapping data of the inetOrgPerson objectclass to eGW contact + * + * Please note: all regular fields are already copied! + * + * @internal + * @param array &$contact already copied fields according to the mapping + * @param array $data eGW contact data + */ + function _inetorgperson2egw(&$contact,$data) + { + if(empty($data['givenname'][0])) + { + $parts = explode($data['sn'][0], $data['cn'][0]); + $contact['n_prefix'] = trim($parts[0]); + $contact['n_suffix'] = trim($parts[1]); + } + else + { + $parts = preg_split('/'. preg_quote($data['givenname'][0],'/') .'.*'. preg_quote($data['sn'][0],'/') .'/', $data['cn'][0]); + $contact['n_prefix'] = trim($parts[0]); + $contact['n_suffix'] = trim($parts[1]); + if(preg_match('/'. preg_quote($data['givenname'][0],'/') .' (.*) '. preg_quote($data['sn'][0],'/') .'/',$data['cn'][0], $matches)) + { + $contact['n_middle'] = $matches[1]; + } + } + } + + /** + * Special handling for mapping data of the mozillaAbPersonAlpha objectclass to eGW contact + * + * Please note: all regular fields are already copied! + * + * @internal + * @param array &$contact already copied fields according to the mapping + * @param array $data eGW contact data + */ + function _mozillaabpersonalpha2egw(&$contact,$data) + { + if ($data['c']) + { + $contact['adr_one_countryname'] = ExecMethod('phpgwapi.country.get_full_name',$data['c'][0]); + } + } + + /** + * Special handling for mapping of eGW contact-data to the mozillaAbPersonAlpha objectclass + * + * Please note: all regular fields are already copied! + * + * @internal + * @param array &$ldapContact already copied fields according to the mapping + * @param array $data eGW contact data + * @param boolean $isUpdate + */ + function _egw2mozillaabpersonalpha(&$ldapContact,$data,$isUpdate) + { + if ($data['adr_one_countryname']) + { + $ldapContact['c'] = ExecMethod('phpgwapi.country.country_code',$data['adr_one_countryname']); + } + elseif ($isUpdate) + { + $ldapContact['c'] = array(); + } + } + + /** + * Special handling for mapping data of the mozillaOrgPerson objectclass to eGW contact + * + * Please note: all regular fields are already copied! + * + * @internal + * @param array &$contact already copied fields according to the mapping + * @param array $data eGW contact data + */ + function _mozillaorgperson2egw(&$contact,$data) + { + if ($data['c'] && strlen($contact['adr_one_countryname']) <= 2) // dont overwrite a set human readable name + { + $contact['adr_one_countryname'] = ExecMethod('phpgwapi.country.get_full_name',$data['c'][0]); + } + } + + /** + * Special handling for mapping of eGW contact-data to the mozillaOrgPerson objectclass + * + * Please note: all regular fields are already copied! + * + * @internal + * @param array &$ldapContact already copied fields according to the mapping + * @param array $data eGW contact data + * @param boolean $isUpdate + */ + function _egw2mozillaorgperson(&$ldapContact,$data,$isUpdate) + { + if ($data['adr_one_countryname']) + { + $ldapContact['c'] = ExecMethod('phpgwapi.country.country_code',$data['adr_one_countryname']); + } + elseif ($isUpdate) + { + $ldapContact['c'] = array(); + } + } + + /** + * Change the ownership of contacts owned by a given account + * + * @param int $account_id account-id of the old owner + * @param int $new_owner account-id of the new owner + */ + function change_owner($account_id,$new_owner) + { + error_log("so_ldap::change_owner($account_id,$new_owner) not yet implemented"); + } +} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_merge.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_merge.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_merge.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_merge.inc.php 2008-11-24 11:43:08.000000000 +0000 @@ -5,14 +5,11 @@ * @link http://www.egroupware.org * @author Ralf Beckersocontacts::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')
\n"; + //error_log("socontacts::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')"); + + // the nextmatch custom-filter-header country-select returns a 2 letter country-code + if (isset($filter['adr_one_countryname']) && strlen($filter['adr_one_countryname']) == 2) + { + $filter['adr_one_countryname'] = $GLOBALS['egw']->country->get_full_name($filter['adr_one_countryname']); + } + $backend =& $this->get_backend(null,$filter['owner']); + // single string to search for --> create so_sql conformant search criterial for the standard search columns + if ($criteria && !is_array($criteria)) + { + $op = 'OR'; + $wildcard = '%'; + $search = $criteria; + $criteria = array(); + + if ($backend === $this->somain) + { + $cols = $this->columns_to_search; + } + else + { + $cols = $this->account_cols_to_search; + } + // search the customfields only if some exist, but only for sql! + if (get_class($backend) == 'socontacts_sql' && $this->customfields) + { + $cols[] = $this->extra_value; + } + foreach($cols as $col) + { + $criteria[$col] = $search; + } + } + 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(); + } + // get the used backend for the search and call it's search method + $rows = $backend->search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count); + $this->total = $backend->total; + + if ($rows) + { + foreach($rows as $n => $row) + { + $rows[$n] = $this->db2data($row); + } + } + return $rows; + } + + /** + * Query organisations by given parameters + * + * @var array $param + * @var string $param[org_view] 'org_name', 'org_name,adr_one_location', 'org_name,org_unit' how to group + * @var int $param[owner] addressbook to search + * @var string $param[search] search pattern for org_name + * @var string $param[searchletter] letter the org_name need to start with + * @var int $param[start] + * @var int $param[num_rows] + * @var string $param[sort] ASC or DESC + * @return array or arrays with keys org_name,count and evtl. adr_one_location or org_unit + */ + function organisations($param) + { + if (!method_exists($this->somain,'organisations')) + { + $this->total = 0; + return false; + } + if ($param['search'] && !is_array($param['search'])) + { + $search = $param['search']; + $param['search'] = array(); + foreach($this->columns_to_search as $col) + { + if ($col != 'contact_value') $param['search'][$col] = $search; // we dont search the customfields + } + } + if (is_array($param['search']) && count($param['search'])) + { + $param['search'] = $this->data2db($param['search']); + } + $rows = $this->somain->organisations($param); + $this->total = $this->somain->total; + //echo "socontacts::organisations(".print_r($param,true).")
".$this->somain->db->Query_ID->sql."
'.$n.': '.$contact['n_fn']. + ($contact['org_name'] ? ' ('.$contact['org_name'].')' : '')." --> LDAP
\n"; + } + else + { + echo ''.$n.': '.$contact['n_fn']. + ($contact['org_name'] ? ' ('.$contact['org_name'].')' : '').': '.$err."
\n"; + } + } + $start += $num; + } + if ($type == 'contacts,accounts-back' || $type == 'sql') // migrate the accounts to sql + { + // very worse hack, until Ralf finds a better solution + // when migrating data, we need to bind as global ldap admin account + // and not as currently logged in user + $ldap_contacts->ds = $GLOBALS['egw']->ldap->ldapConnect(); + foreach($ldap_contacts->search(false,false,'n_family,n_given','','',false,'AND', + false,$type == 'sql'?null:array('owner' => 0)) as $contact) + { + if ($contact['jpegphoto']) // photo is NOT read by LDAP backend on search, need to do an extra read + { + $contact = $ldap_contacts->read($contact['id']); + } + unset($contact['id']); // ldap uid/account_lid + if ($type != 'sql' && $contact['account_id'] && ($old = $sql_contacts->read(array('account_id' => $contact['account_id'])))) + { + $contact['id'] = $old['id']; + } + $sql_contacts->data = $contact; + + $n++; + if (!($err = $sql_contacts->save())) + { + echo ''.$n.': '.$contact['n_fn']. + ($contact['org_name'] ? ' ('.$contact['org_name'].')' : '')." --> SQL (". + ($contact['owner']?lang('User'):lang('Contact')).")
\n"; + } + else + { + echo ''.$n.': '.$contact['n_fn']. + ($contact['org_name'] ? ' ('.$contact['org_name'].')' : '').': '.$err."
\n"; + } + } + } + } + + /** + * Get the availible distribution lists for a user + * + * @param int $required=EGW_ACL_READ required rights on the list + * @param string $extra_labels=null first labels if given (already translated) + * @return array with id => label pairs or false if backend does not support lists + */ + function get_lists($required=EGW_ACL_READ,$extra_labels=null) + { + if (!method_exists($this->somain,'get_lists')) return false; + + $uids = array(); + foreach($this->grants as $uid => $rights) + { + if ($rights & $required) + { + $uids[] = $uid; + } + } + $lists = is_array($extra_labels) ? $extra_labels : array(); + + foreach($this->somain->get_lists($uids) as $list_id => $data) + { + $lists[$list_id] = $data['list_name']; + if ($data['list_owner'] != $this->user) + { + $lists[$list_id] .= ' ('.$GLOBALS['egw']->common->grab_owner_name($data['list_owner']).')'; + } + } + //echo "socontacts_sql::get_lists($required,'$extra_label')
\n"; _debug_array($lists); + return $lists; + } + + /** + * Adds a distribution list + * + * @param string $name list-name + * @param int $owner user- or group-id + * @param array $contacts=array() contacts to add + * @return list_id or false on error + */ + function add_list($name,$owner,$contacts=array()) + { + if (!method_exists($this->somain,'add_list')) return false; + + return $this->somain->add_list($name,$owner,$contacts); + } + + /** + * Adds one contact to a distribution list + * + * @param int $contact contact_id + * @param int $list list-id + * @return false on error + */ + function add2list($contact,$list) + { + if (!method_exists($this->somain,'add2list')) return false; + + return $this->somain->add2list($contact,$list); + } + + /** + * Removes one contact from distribution list(s) + * + * @param int $contact contact_id + * @param int $list=null list-id or null to remove from all lists + * @return false on error + */ + function remove_from_list($contact,$list=null) + { + if (!method_exists($this->somain,'remove_from_list')) return false; + + return $this->somain->remove_from_list($contact,$list); + } + + /** + * Deletes a distribution list (incl. it's members) + * + * @param int/array $list list_id(s) + * @return number of members deleted or false if list does not exist + */ + function delete_list($list) + { + if (!method_exists($this->somain,'delete_list')) return false; + + return $this->somain->delete_list($list); + } + + /** + * Read data of a distribution list + * + * @param int $list list_id + * @return array of data or false if list does not exist + */ + function read_list($list) + { + if (!method_exists($this->somain,'read_list')) return false; + + return $this->somain->read_list($list); + } + + /** + * Check if distribution lists are availible for a given addressbook + * + * @param int/string $owner='' addressbook (eg. 0 = accounts), default '' = "all" addressbook (uses the main backend) + * @return boolean + */ + function lists_available($owner='') + { + $backend =& $this->get_backend(null,$owner); + + return method_exists($backend,'read_list'); + } +} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_sql.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_sql.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_sql.inc.php 1970-01-01 01:00:00.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_sql.inc.php 2008-11-24 11:43:08.000000000 +0000 @@ -0,0 +1,655 @@ + + * @package addressbook + * @copyright (c) 2006-8 by Ralf Beckersocontacts_sql::search(".print_r($criteria,true).",".print_r($only_keys,true).",'$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')
\n"; + + $owner = isset($filter['owner']) ? $filter['owner'] : (isset($criteria['owner']) ? $criteria['owner'] : null); + + // fix cat_id filter to search in comma-separated multiple cats and return subcats + if (($cats = $filter['cat_id'])) + { + if ($filter['cat_id'][0] == '!') + { + $filter['cat_id'] = substr($filter['cat_id'],1); + $not = 'NOT'; + } + $filter[] = $this->_cat_filter((int)$filter['cat_id'],$not); + unset($filter['cat_id']); + } + + // add filter for read ACL in sql, if user is NOT the owner of the addressbook + if (isset($this->grants) && !(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 + { + if ($this->account_repository != 'sql' && $this->contact_repository != 'sql-ldap') + { + $filter[] = $this->table_name.'.contact_owner != 0'; // in case there have been accounts in sql previously + } + $filter[] = "($this->table_name.contact_owner=".(int)$GLOBALS['egw_info']['user']['account_id']. + " OR contact_private=0 AND $this->table_name.contact_owner IN (". + implode(',',array_keys($this->grants)).") OR $this->table_name.contact_owner IS NULL)"; + } + } + $search_customfields = isset($criteria['contact_value']) && !empty($criteria['contact_value']); + if (is_array($criteria)) + { + foreach($criteria as $col => $val) + { + if ($col[0] == '#') // search for a value in a certain custom field + { + $valarray=array(); + # val may be a list of values, constructed by multiple select fields, to be able to do the contains feature of adv-search + # we split the value and search for each part individually + if ($wildcard !='') { + $valarray=explode(',',$val); + } else { + $valarray[]=$val; + } + $negate = false; //negate the search funktion + if ($criteria[$col][0] == '!') $negate = True; + unset($criteria[$col]); + foreach ($valarray as $vkey => $part) + { + $criteria[] =$this->table_name.'.contact_id'.($negate ? ' not ' :'').' in (select '.$this->extra_table.'.contact_id from '.$this->extra_table.' where '. + "(".$this->extra_table.".contact_name='".substr($col,1)."' AND ".$this->extra_table.".contact_value".(!$wildcard?' = ':' LIKE ')."'".$wildcard.($negate?substr($part,1):$part).$wildcard."'"."))"; + + } + $search_customfields = true; + } + elseif($col == 'cat_id') // search in comma-sep. cat-column + { + $criteria = array_merge($criteria,$this->_cat_search($val)); + unset($criteria[$col]); + } + elseif($col == 'contact_value') + { + if ($order_by[0] == '#') + { + $criteria =array_merge($criteria,array('extra_order.contact_value'=>$val)); + unset($criteria[$col]); + } + } + } + } + if ($search_customfields) // search the custom-fields + { + $join .= $this->extra_join; + } + // do we order by a cf? + if ($order_by[0] == '#') + { + list($val) = explode("<>''",$order_by); + $order_by = str_replace($val,'extra_order.contact_value',$order_by); + $join .= $this->extra_join_order.' AND extra_order.contact_name='.$this->db->quote(substr($val,1)); + } + // do we filter by a cf? + $extra_filter = ''; + foreach($filter as $name => $val) + { + if ($name[0] == '#') + { + if (!empty($val)) // empty -> dont filter + { + $join .= str_replace('extra_filter','extra_filter'.$extra_filter,$this->extra_join_filter.' AND extra_filter.contact_name='.$this->db->quote(substr($name,1)). + ' AND extra_filter.contact_value='.$this->db->quote($val)); + ++$extra_filter; + } + unset($filter[$name]); + } + elseif($val[0] == '#') // lettersearch: #cfname like 's%' + { + list($cf) = explode(' ',$val); + $join .= str_replace('extra_filter','extra_filter'.$extra_filter,$this->extra_join_filter.' AND extra_filter.contact_name='.$this->db->quote(substr($cf,1)). + ' AND '.str_replace($cf,'extra_filter.contact_value',$val)); + ++$extra_filter; + unset($filter[$name]); + } + } + if (isset($filter['list'])) + { + $join .= " JOIN $this->ab2list_table ON $this->table_name.contact_id=$this->ab2list_table.contact_id AND list_id=".(int)$filter['list']; + unset($filter['list']); + } + if ($join) + { + switch(gettype($only_keys)) + { + case 'boolean': + // only return the egw_addressbook columns, to not generate dublicates by the left join + // and to not return the NULL for contact_{id|owner} of not found custom fields! + $only_keys = (strpos($join,$this->extra_table)!==false?'DISTINCT ':'').$this->table_name.'.'.($only_keys ? 'contact_id AS contact_id' : '*'); + break; + case 'string': + $only_keys = explode(',',$only_keys); + // fall through + case 'array': + foreach($only_keys as $key => $val) + { + switch($key) + { + case 'id': case 'contact_id': + $only_keys[$key] = $this->table_name.'.contact_id'; + break; + case 'owner': case 'contact_owner': + $only_keys[$key] = $this->table_name.'.contact_owner'; + break; + } + } + break; + } + if (isset($filter['owner'])) + { + $filter[] = $this->table_name.'.contact_owner='.(int)$filter['owner']; + unset($filter['owner']); + } + if (isset($criteria['owner'])) + { + $criteria[] = $this->table_name.'.contact_owner='.(int)$criteria['owner']; + unset($criteria['owner']); + } + // postgres requires that expressions in order by appear in the columns of a distinct select + if ($this->db->Type != 'mysql' && preg_match("/(\w+<>'')/",$order_by,$matches)) + { + if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array(); + $extra_cols[] = $matches[1]; + } + } + $rows =& parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count); + + if ($start === false) $this->total = is_array($rows) ? count($rows) : 0; // so_sql sets total only for $start !== false! + + return $rows; + } + + /** + * fix cat_id filter to search in comma-separated multiple cats and return subcats + * + * @internal + * @param int $cat_id + * @return string sql to filter by given cat + */ + function _cat_filter($cat_id, $not='') + { + if (!is_object($GLOBALS['egw']->categories)) + { + $GLOBALS['egw']->categories = CreateObject('phpgwapi.categories'); + } + foreach($GLOBALS['egw']->categories->return_all_children((int)$cat_id) as $cat) + { + $cat_filter[] = $this->db->concat("','",cat_id,"','")." $not LIKE '%,$cat,%'"; + } + $cfilter = '('.implode(' OR ',$cat_filter).')'; + if(!empty($not)) + { + $cfilter = "( $cfilter OR cat_id IS NULL )"; + } + return $cfilter; + } + + /** + * fix cat_id criteria to search in comma-separated multiple cats + * + * @internal + * @param int/array $cats + * @return array of sql-strings to be OR'ed or AND'ed together + */ + function _cat_search($cats) + { + $cat_filter = array(); + foreach(is_array($cats) ? $cats : array($cats) as $cat) + { + if (is_numeric($cat)) $cat_filter[] = $this->db->concat("','",cat_id,"','")." LIKE '%,$cat,%'"; + } + return $cat_filter; + } + + /** + * Change the ownership of contacts owned by a given account + * + * @param int $account_id account-id of the old owner + * @param int $new_owner account-id of the new owner + */ + function change_owner($account_id,$new_owner) + { + if (!$new_owner) // otherwise we would create an account (contact_owner==0) + { + die("socontacts_sql::change_owner($account_id,$new_owner) new owner must not be 0"); + } + $this->db->update($this->table_name,array( + 'contact_owner' => $new_owner, + ),array( + 'contact_owner' => $account_id, + ),__LINE__,__FILE__); + } + + /** + * Get the availible distribution lists for givens users and groups + * + * @param array $uids user or group id's + * @return array with list_id => array(list_id,list_name,list_owner,...) pairs + */ + function get_lists($uids) + { + $user = $GLOBALS['egw_info']['user']['account_id']; + $lists = array(); + foreach($this->db->select($this->lists_table,'*',array('list_owner'=>$uids),__LINE__,__FILE__, + false,'ORDER BY list_owner<>'.(int)$GLOBALS['egw_info']['user']['account_id'].',list_name') as $row) + { + $lists[$row['list_id']] = $row; + } + //echo "socontacts_sql::get_lists(".print_r($uids,true).")
\n"; _debug_array($lists); + return $lists; + } + + /** + * Adds a distribution list + * + * @param string $name list-name + * @param int $owner user- or group-id + * @param array $contacts=array() contacts to add + * @return int/boolean integer list_id, true if the list already exists or false on error + */ + function add_list($name,$owner,$contacts=array()) + { + if (!$name || !(int)$owner) return false; + + if ($this->db->select($this->lists_table,'list_id',array( + 'list_name' => $name, + 'list_owner' => $owner, + ),__LINE__,__FILE__)->fetchSingle()) + { + return true; // return existing list-id + } + if (!$this->db->insert($this->lists_table,array( + 'list_name' => $name, + 'list_owner' => $owner, + 'list_created' => time(), + 'list_creator' => $GLOBALS['egw_info']['user']['account_id'], + ),array(),__LINE__,__FILE__)) return false; + + if ((int)($list_id = $this->db->get_last_insert_id($this->lists_table,'list_id')) && $contacts) + { + foreach($contacts as $contact) + { + $this->add2list($list_id,$contact); + } + } + return $list_id; + } + + /** + * Adds one contact to a distribution list + * + * @param int $contact contact_id + * @param int $list list-id + * @return false on error + */ + function add2list($contact,$list) + { + if (!(int)$list || !(int)$contact) return false; + + if ($this->db->select($this->ab2list_table,'list_id',array( + 'contact_id' => $contact, + 'list_id' => $list, + ),__LINE__,__FILE__)->fetchSingle()) + { + return true; // no need to insert it, would give sql error + } + return $this->db->insert($this->ab2list_table,array( + 'contact_id' => $contact, + 'list_id' => $list, + 'list_added' => time(), + 'list_added_by' => $GLOBALS['egw_info']['user']['account_id'], + ),array(),__LINE__,__FILE__); + } + + /** + * Removes one contact from distribution list(s) + * + * @param int $contact contact_id + * @param int $list=null list-id or null to remove from all lists + * @return false on error + */ + function remove_from_list($contact,$list=null) + { + if (!(int)$list && !is_null($list) || !(int)$contact) return false; + + $where = array( + 'contact_id' => $contact, + ); + if (!is_null($list)) $where['list_id'] = $list; + + return $this->db->delete($this->ab2list_table,$where,__LINE__,__FILE__); + } + + /** + * Deletes a distribution list (incl. it's members) + * + * @param int/array $list list_id(s) + * @return number of members deleted or false if list does not exist + */ + function delete_list($list) + { + if (!$this->db->delete($this->lists_table,array('list_id' => $list),__LINE__,__FILE__)) return false; + + $this->db->delete($this->ab2list_table,array('list_id' => $list),__LINE__,__FILE__); + + return $this->db->affected_rows(); + } + + /** + * Reads a contact, reimplemented to use the uid, if a non-numeric key is given + * + * @param int|string|array $keys + * @param string|array $extra_cols + * @param string $join + * @return array|boolean + */ + function read($keys,$extra_cols='',$join='') + { + if (!is_array($keys) && !is_numeric($keys)) + { + $keys = array('contact_uid' => $keys); + } + return parent::read($keys,$extra_cols,$join); + } + + /** + * Saves a contact, reimplemented to check a given etag and set a uid + * + * @param array $keys if given $keys are copied to data before saveing => allows a save as + * @param string|array $extra_where=null extra where clause, eg. to check the etag, returns 'nothing_affected' if not affected rows + * @return int 0 on success and errno != 0 else + */ + function save($keys=null) + { + if (is_array($keys) && count($keys)) $this->data_merge($keys); + + $new_entry = !$this->data['id']; + + if (isset($this->data['etag'])) // do we have an etag in the data to write + { + $etag = $this->data['etag']; + unset($this->data['etag']); + if (!($err = parent::save(array('contact_etag=contact_etag+1'),array('contact_etag' => $etag)))) + { + $this->data['etag'] = $etag+1; + } + else + { + $this->data['etag'] = $etag; + } + } + else + { + unset($this->data['etag']); + if (!($err = parent::save(array('contact_etag=contact_etag+1'))) && $new_entry) + { + $this->data['etag'] = 0; + } + } + // enforce a minium uid strength + if (!$err && ($new_entry || isset($this->data['uid'])) && (strlen($this->data['uid']) < 20 || is_numeric($this->data['uid']))) + { + parent::update(array('uid' => common::generate_uid('addressbook',$this->data['id']))); + //echo "set uid={$this->data['uid']}, etag={$this->data['etag']}
"; + } + return $err; + } + + + /** + * Read data of a distribution list + * + * @param int $list list_id + * @return array of data or false if list does not exist + */ + function read_list($list) + { + if (!$list) return false; + + return $this->db->select($this->lists_table,'*',array('list_id'=>$list),__LINE__,__FILE__)->fetch(); + } +} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_tracking.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_tracking.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_tracking.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_tracking.inc.php 2008-11-24 11:43:08.000000000 +0000 @@ -7,11 +7,9 @@ * @package addressbook * @copyright (c) 2007 by Ralf Beckeraddressbook_tracking::get_config($name,".print_r($data,true).",...)
\n"; switch($name) @@ -97,7 +95,7 @@ return split(', ?',$data['email_contactform']); } break; - + case 'sender': if ($data['is_contactform']) { @@ -108,10 +106,10 @@ } return null; } - + /** * Get the modified / new message (1. line of mail body) for a given entry, can be reimplemented - * + * * @param array $data * @param array $old * @return string @@ -128,10 +126,10 @@ $GLOBALS['egw']->common->grab_owner_name($data['modifier']), $this->datetime($data['modified']-$this->tracker->tz_offset_s)); } - + /** * Get the subject of the notification - * + * * @param array $data * @param array $old * @return string @@ -144,10 +142,10 @@ } return $prefix.$this->contacts->link_title($data); } - + /** * Get the details of an entry - * + * * @param array $data * @param string $datetime_format of user to notify, eg. 'Y-m-d H:i' * @param int $tz_offset_s offset in sec to be add to server-time to get the user-time of the user to notify @@ -228,7 +226,7 @@ } $details['#'.$name] = array( 'label' => $custom['label'], - 'value' => $data['#'.$name], + 'value' => $custom['type'] == 'select' ? $custom['values'][$data['#'.$name]] : $data['#'.$name], ); } } diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_ui.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_ui.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.addressbook_ui.inc.php 1970-01-01 01:00:00.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.addressbook_ui.inc.php 2008-11-24 11:43:08.000000000 +0000 @@ -0,0 +1,2086 @@ + + * @author Ralf Beckeruicontacts::index(".print_r($content,true).",'$msg')
\n"; + if (($re_submit = is_array($content))) + { + $do_email = $content['do_email']; + + 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 (isset($content['nm']['rows']['document'])) // handle insert in default document button like an action + { + list($id) = @each($content['nm']['rows']['document']); + $content['action'] = 'document'; + $content['nm']['rows']['checked'] = array($id); + } + if ($content['action'] !== '') + { + if (!count($content['nm']['rows']['checked']) && !$content['use_all'] && $content['action'] != 'delete_list') + { + $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,$content['do_email'] ? 'email' : 'index',$msg)) + { + $msg .= lang('%1 contact(s) %2',$success,$action_msg); + } + elseif(is_null($msg)) + { + $msg .= lang('%1 contact(s) %2, %3 failed because of insufficent rights !!!',$success,$action_msg,$failed); + } + } + } + if ($content['nm']['rows']['infolog']) + { + list($org) = each($content['nm']['rows']['infolog']); + return $this->infolog_org_view($org); + } + if ($content['nm']['rows']['view']) // show all contacts of an organisation + { + list($org_view) = each($content['nm']['rows']['view']); + } + else + { + $org_view = $content['nm']['org_view']; + } + $typeselection = $content['nm']['col_filter']['tid']; + } + elseif($_GET['add_list']) + { + $list = $this->add_list($_GET['add_list'],$_GET['owner']?$_GET['owner']:$this->user); + if ($list === true) + { + $msg = lang('List already exists!'); + } + elseif ($list) + { + $msg = lang('List created'); + } + else + { + $msg = lang('List creation failed, no rights!'); + } + } + $preserv = array( + 'do_email' => $do_email, + ); + $to = $content['nm']['to']; + $content = array( + 'msg' => $msg ? $msg : $_GET['msg'], + ); + + $content['nm'] = $GLOBALS['egw']->session->appsession($do_email ? 'email' : 'index','addressbook'); + if (!is_array($content['nm'])) + { + $content['nm'] = array( + 'get_rows' => 'addressbook.addressbook_ui.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' + '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' => '', // IO category, if not 'no_cat' => True + 'options-cat_id' => array(lang('none')), + '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' => lang('Addressbook'), // I label for filter (optional) + 'filter' => '', // =All // 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_label' => lang('Distribution lists'), // IO filter2, if not 'no_filter2' => True + 'filter2' => '', // IO filter2, if not 'no_filter2' => True + 'filter2_no_lang'=> True, // I set no_lang for filter2 (=dont translate the options) + 'lettersearch' => true, + 'do_email' => $do_email, + 'default_cols' => '!cat_id,contact_created_contact_modified,distribution_list', + 'filter2_onchange' => "if(this.value=='add') { add_new_list(document.getElementById(form::name('filter')).value); this.value='';} else this.form.submit();", + 'manual' => $do_email ? ' ' : false, // space for the manual icon + ); + $csv_export = new addressbook_csv($this); + $content['nm']['csv_fields'] = $csv_export->csv_fields(null,true); + + if ($do_email) + { + $content['nm']['filter2_onchange'] = str_replace('this.form.submit();', + "{ if (this.value && confirm('".lang('Add emails of whole distribution list?')."')) add_whole_list(this.value); else this.form.submit(); }", + $content['nm']['filter2_onchange']); + } + // use the state of the last session stored in the user prefs + if (($state = @unserialize($this->prefs[$do_email ? 'email_state' : 'index_state']))) + { + $content['nm'] = array_merge($content['nm'],$state); + } + } + if (isset($typeselection)) $content['nm']['col_filter']['tid'] = $typeselection; + + if ($this->lists_available()) + { + $sel_options['filter2'] = $this->get_lists(EGW_ACL_READ,array('' => lang('none'))); + $sel_options['filter2']['add'] = lang('Add a new list').'...'; // put it at the end + } + if ($do_email) + { + if (!$re_submit) + { + $content['nm']['to'] = 'to'; + $content['nm']['email_type'] = $this->prefs['distributionListPreferredMail'] ? $this->prefs['distributionListPreferredMail'] : 'email'; + $content['nm']['search'] = '@'; + } + else + { + $content['nm']['to'] = $to; + $content['nm']['email_type'] = $this->prefs['distributionListPreferredMail'] ? $this->prefs['distributionListPreferredMail'] : 'email'; + } + $content['nm']['header_left'] = 'addressbook.email.left'; + } + // Organisation stuff is not (yet) availible with ldap + elseif($GLOBALS['egw_info']['server']['contact_repository'] != 'ldap') + { + $content['nm']['header_left'] = 'addressbook.index.left'; + } + $sel_options['filter'] = $this->get_addressbooks(EGW_ACL_READ,lang('All')); + $sel_options['to'] = array( + 'to' => 'To', + 'cc' => 'Cc', + 'bcc' => 'Bcc', + ); + $sel_options['action'] = array(); + if ($do_email) + { + $GLOBALS['egw_info']['flags']['include_xajax'] = true; + $sel_options['action'] = array( + 'email' => lang('Add %1',lang('business email')), + 'email_home' => lang('Add %1',lang('home email')), + ); + } + $sel_options['action'] += array( + 'delete' => lang('Delete'), + ); + // check if user is an admin or the export is not generally turned off (contact_export_limit is non-numerical, eg. no) + if (isset($GLOBALS['egw_info']['user']['apps']['admin']) || !$this->config['contact_export_limit'] || (int)$this->config['contact_export_limit']) + { + $sel_options['action'] += array( + 'csv' => lang('Export as CSV'), + 'vcard' => lang('Export as VCard'), // ToDo: move this to importexport framework + ); + } + $sel_options['action'] += array( + 'merge' => lang('Merge into first or account, deletes all other!'), + 'cat_add' => lang('Add or delete Categoies'), // add a categirie to multible addresses + 'infolog_add' => lang('Add a new Infolog'), + ); + if ($GLOBALS['egw_info']['user']['apps']['infolog']) + { + $sel_options['action']['infolog'] = lang('View linked InfoLog entries'); + } + if (($move2addressbooks=$this->get_addressbooks(EGW_ACL_ADD))) // do we have addressbooks, we should + { + foreach ($move2addressbooks as $m2a_id => $m2alabel) + { + $m2a['move_to_'.$m2a_id] = $m2alabel; + } + $sel_options['action'][lang('Move to addressbook:')] = $m2a; + } + if (($add_lists = $this->get_lists(EGW_ACL_EDIT))) // do we have distribution lists? + { + $lists = array(); + foreach ($add_lists as $list_id => $label) + { + $lists['to_list_'.$list_id] = $label; + } + $sel_options['action'][lang('Add to distribution list:')] = $lists; + unset($lists); + $sel_options['action']['remove_from_list'] = lang('Remove selected contacts from distribution list'); + $sel_options['action']['delete_list'] = lang('Delete selected distribution list!'); + } + + if ($this->prefs['document_dir']) + { + $sel_options['action'][lang('Insert in document').':'] = $this->get_document_actions(); + } + if (!array_key_exists('importexport',$GLOBALS['egw_info']['user']['apps'])) unset($sel_options['action']['export']); + + // dont show tid-selection if we have only one content_type + if (count($this->content_types) <= 1) + { + $content['nm']['col_filter']['tid'] = 'n'; + $content['nm']['header_right'] = 'addressbook.index.right_add'; + } + else + { + if (!isset($content['nm']['col_filter']['tid'])) $content['nm']['col_filter']['tid'] = 'n'; + $content['nm']['header_right'] = 'addressbook.index.right'; + foreach($this->content_types as $tid => $data) + { + $sel_options['col_filter[tid]'][$tid] = $data['name']; + } + } + + // get the availible org-views plus the label of the contacts view of one org + $sel_options['org_view'] = $this->org_views; + if (isset($org_view)) $content['nm']['org_view'] = $org_view; + if (!isset($sel_options['org_view'][(string) $content['nm']['org_view']])) + { + $org_name = array(); + foreach(explode('|||',$content['nm']['org_view']) as $part) + { + list(,$name) = explode(':',$part,2); + if ($name) $org_name[] = $name; + } + $org_name = implode(': ',$org_name); + $sel_options['org_view'][(string) $content['nm']['org_view']] = $org_name; + } + $content['nm']['org_view_label'] = $sel_options['org_view'][(string) $content['nm']['org_view']]; + + $this->tmpl->read(/*$do_email ? 'addressbook.email' :*/ 'addressbook.index'); + return $this->tmpl->exec($do_email ? 'addressbook.addressbook_ui.emailpopup' : 'addressbook.addressbook_ui.index', + $content,$sel_options,$readonlys,$preserv,$do_email ? 2 : 0); + } + + /** + * Email address-selection popup + * + * @param array $content=null submitted content + * @param string $msg=null message to show + */ + function emailpopup($content=null,$msg=null) + { + if (strpos($GLOBALS['egw_info']['flags']['java_script'],'addEmail') === false) + { + if ($_GET['compat']) // 1.2 felamimail or old email + { + $handler = "if (opener.document.doit[to].value != '') + { + opener.document.doit[to].value += ','; + } + opener.document.doit[to].value += email"; + } + else // 1.3+ felamimail + { + $handler = 'opener.addEmail(to,email)'; + } + $GLOBALS['egw_info']['flags']['java_script'].= " + +"; + } + return $this->index($content,$msg,true); + } + + /** + * Show the infologs of an whole organisation + * + * @param string $org + */ + function infolog_org_view($org) + { + $query = $GLOBALS['egw']->session->appsession('index','addressbook'); + $query['num_rows'] = -1; // all + $query['org_view'] = $org; + $query['searchletter'] = ''; + $this->get_rows($query,$checked,$readonlys,true); // true = only return the id's + + if (count($checked) > 1) // use a nicely formatted org-name as title in infolog + { + $parts = array(); + foreach(explode('|||',$org) as $part) + { + list(,$part) = explode(':',$part,2); + if ($part) $parts[] = $part; + } + $org = implode(', ',$parts); + } + else + { + $org = ''; // use infolog default of link-title + } + $GLOBALS['egw']->redirect_link('/index.php',array( + 'menuaction' => 'infolog.infolog_ui.index', + 'action' => 'addressbook', + 'action_id' => implode(',',$checked), + 'action_title' => $org, + )); + } + + function ajax_add_whole_list($list, $email_type = 'email') + { + $query = $GLOBALS['egw']->session->appsession('email','addressbook'); + $query['filter2'] = (int)$list; + $this->action($email_type,array(),true,$success,$failed,$action_msg,$query,$msg); + + $response =& new xajaxResponse(); + + if ($success) $response->addScript($GLOBALS['egw']->js->body['onLoad']); + + // close window only if no errors AND something added + if ($failed || !$success) + { + if (!$msg) $msg = $failed ? lang('%1 contact(s) %2, %3 failed because of insufficent rights !!!',$success,$action_msg,$failed) : + lang('%1 contact(s) %2',$success,$action_msg); + + $response->addScript("alert('".addslashes($msg)."')"); + // reset the filter + $response->addScript("document.getElementById('exec[nm][filter2]').value='';"); + } + else + { + if (!$msg) $msg = lang('%1 contact(s) %2',$success,$action_msg); + $response->addScript("alert('".addslashes($msg)."')"); + $response->addScript('window.close();'); + } + return $response->getXML(); + } + + /** + * 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' + * @param string/array $session_name 'index' or 'email', or array with session-data depending if we are in the main list or the popup + * @return boolean true if all actions succeded, false otherwise + */ + function action($action,$checked,$use_all,&$success,&$failed,&$action_msg,$session_name,&$msg) + { + //echo "uicontacts::action('$action',".print_r($checked,true).','.(int)$use_all.",...)
\n"; + $success = $failed = 0; + if ($use_all || in_array($action,array('remove_from_list','delete_list'))) + { + // get the whole selection + $query = is_array($session_name) ? $session_name : $GLOBALS['egw']->session->appsession($session_name,'addressbook'); + + if ($use_all) + { + @set_time_limit(0); // switch off the execution time limit, as it's for big selections to small + $query['num_rows'] = -1; // all + $this->get_rows($query,$checked,$readonlys,true); // true = only return the id's + } + } + // replace org_name:* id's with all id's of that org + $org_contacts = array(); + foreach((array)$checked as $n => $id) + { + if (substr($id,0,9) == 'org_name:') + { + if (count($checked) == 1 && !count($org_contacts) && $action == 'infolog') + { + return $this->infolog_org_view($id); // uses the org-name, instead of 'selected contacts' + } + unset($checked[$n]); + $query = $GLOBALS['egw']->session->appsession($session_name,'addressbook'); + $query['num_rows'] = -1; // all + $query['org_view'] = $id; + unset($query['filter2']); + $this->get_rows($query,$extra,$readonlys,true); // true = only return the id's + if ($extra[0]) $org_contacts = array_merge($org_contacts,$extra); + } + } + if ($org_contacts) $checked = array_unique($checked ? array_merge($checked,$org_contacts) : $org_contacts); + //_debug_array($checked); exit; + + if (substr($action,0,8) == 'move_to_') + { + $action = (int)substr($action,8).(substr($action,-1) == 'p' ? 'p' : ''); + } + if (substr($action,0,7) == 'to_list') + { + $to_list = (int)substr($action,8); + $action = 'to_list'; + } + if (substr($action,0,9) == 'document-') + { + $document = substr($action,9); + $action = 'document'; + } + // Security: stop non-admins to export more then the configured number of contacts + if (in_array($action,array('csv','vcard')) && $this->config['contact_export_limit'] && + !isset($GLOBALS['egw_info']['user']['apps']['admin']) && + (!is_numeric($this->config['contact_export_limit']) || count($checked) > $this->config['contact_export_limit'])) + { + $action_msg = lang('exported'); + $failed = count($checked); + return false; + } + switch($action) + { + case 'csv': + $action_msg = lang('exported'); + $csv_export = new addressbook_csv($this,$this->prefs['csv_charset']); + $csv_export->export($checked,$csv_export->csv_fields($this->prefs['csv_fields'])); + // does not return! + $Ok = true; + break; + + case 'vcard': + $action_msg = lang('exported'); + ExecMethod('addressbook.addressbook_vcal.export',$checked); + // does not return! + $Ok = false; + break; + + case 'infolog': + $GLOBALS['egw']->redirect_link('/index.php',array( + 'menuaction' => 'infolog.infolog_ui.index', + 'action' => 'addressbook', + 'action_id' => implode(',',$checked), + 'action_title' => count($checked) > 1 ? lang('selected contacts') : '', + )); + break; + + case 'merge': + $success = $this->merge($checked,$error_msg); + $failed = count($checked) - (int)$success; + $action_msg = lang('merged'); + $checked = array(); // to not start the single actions + break; + + case 'delete_list': + if (!$query['filter2']) + { + $msg = lang('You need to select a distribution list'); + } + elseif($this->delete_list($query['filter2']) === false) + { + $msg = lang('Insufficent rights to delete this list!'); + } + else + { + $msg = lang('Distribution list deleted'); + unset($query['filter2']); + $GLOBALS['egw']->session->appsession($session_name,'addressbook',$query); + } + return false; + + case 'document': + $msg = $this->download_document($checked,$document); + return false; + + case 'infolog_add': + if ($use_all) // !$use_all is handled purely in javascript + { + $GLOBALS['egw']->js->set_onload( + "win=window.open('".egw::link('/index.php','menuaction=infolog.infolog_ui.edit&type=task&action=addressbook&action_id=').implode(',',$checked)."','_blank','width=750,height=550,left=100,top=200'); win.focus();"); + } + $msg = lang('New window opened to edit Infolog for your selection '); + return false; + + case 'cat_add': + foreach($checked as $id) + { + if (($Ok = !!($contact = $this->read($id)) && $this->check_perms(EGW_ACL_EDIT,$contact))) + { + $action_msg = lang('categorie'); + $cat_ids = explode(",",$contact['cat_id']); //existing categiries + if (!is_array($cat_ids_new) && $cat_ids_new) $cat_ids_new = explode(",",$cat_ids_new); + //categarie add + if ((!($cat_ids_new = $GLOBALS['egw']->session->appsession('cat_add','addressbook')) && !($cat_ids_new = $GLOBALS['egw']->session->appsession('cat_delete','addressbook')))) + { + $action_msg = lang('no categories selected'); + } + if ($GLOBALS['egw']->session->appsession('cat_add','addressbook')) + { + if (is_array($cat_ids_new) && ($ids_to_add = array_diff($cat_ids_new,$cat_ids))) + { + $cat_ids = array_merge($cat_ids,$ids_to_add); + $contact['cat_id'] = implode(",",$cat_ids); + $Ok = $this->save($contact); + $success++; + $action_msg = lang('categorie added'); + } + else + { + $failed++; + } + } + //categories delete + if ($GLOBALS['egw']->session->appsession('cat_delete','addressbook')) + { + if (is_array($cat_ids_new) && ($ids_to_delete = array_diff($cat_ids,$cat_ids_new)) or ($cat_ids = $cat_ids_new)) + { + $contact['cat_id'] = implode(",",$ids_to_delete); + $action_msg = lang('categorie delete'); + $Ok = $this->save($contact); + $success++; + } + else + { + $failed++; + } + } + } + } + $checked = array(); // to not start the single actions + $GLOBALS['egw']->session->appsession('cat_add','addressbook',''); //delete stored categories to add + $GLOBALS['egw']->session->appsession('cat_delete','addressbook',''); //delete stored categories to delete + break; + } + 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); + } + // delete single account --> redirect to admin + elseif (count($checked) == 1 && $contact['account_id']) + { + $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 'email': + case 'email_home': + $action == 'email' ? $action_fallback = 'email_home' : $action_fallback = 'email'; + $action_msg = lang('added'); + if($contact = $this->read($id)) + { + if(strpos($contact[$action],'@') !== false) + { + $email = $contact[$action]; + } + elseif(strpos($contact[$action_fallback],'@') !== false) + { + $email = $contact[$action_fallback]; + } + else + { + $Ok = $email = false; + } + if($email) + { + $GLOBALS['egw']->js->set_onload("addEmail('".addslashes( + $contact['n_fn'] ? $contact['n_fn'].' <'.$email.'>' : $email)."');"); + $Ok = true; + } + } + break; + + case 'remove_from_list': + $action_msg = lang('removed from distribution list'); + if (!$query['filter2']) + { + $msg = lang('You need to select a distribution list'); + return false; + } + else + { + $Ok = $this->remove_from_list($id,$query['filter2']) !== false; + } + break; + + case 'to_list': + $action_msg = lang('added to distribution list'); + if (!$to_list) + { + $msg = lang('You need to select a distribution list'); + return false; + } + else + { + $Ok = $this->add2list($id,$to_list) !== false; + } + break; + default: // move to an other addressbook + if (!(int)$action || !($this->grants[(string) (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'] != (int)$action || $contact['private'] != (int)(substr($action,-1) == 'p')) + { + $contact['owner'] = (int) $action; + $contact['private'] = (int)(substr($action,-1) == 'p'); + $Ok = $this->save($contact); + } + } + break; + } + if ($Ok) + { + ++$success; + } + elseif ($action != 'email' && $action != 'email_home') + { + ++$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 boolean $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) + { + $do_email = $query['do_email']; + $what = $query['sitemgr_display'] ? $query['sitemgr_display'] : ($do_email ? 'email' : 'index'); + + $old_state = $GLOBALS['egw']->session->appsession($what,'addressbook',$query); + + if (!isset($this->org_views[(string) $query['org_view']])) // we dont have an org view, unset the according col_filters + { + if (isset($query['col_filter']['org_name'])) unset($query['col_filter']['org_name']); + if (isset($query['col_filter']['adr_one_locality'])) unset($query['col_filter']['adr_one_locality']); + if (isset($query['col_filter']['org_unit'])) unset($query['col_filter']['org_unit']); + } + + if (isset($this->org_views[(string) $query['org_view']])) // we have an org view, reset the advanced search + { + if (is_array($query['search'])) unset($query['search']); + unset($query['advanced_search']); + } + elseif(!$query['search'] && $old_state['advanced_search']) // eg. paging in an advanced search + { + $query['advanced_search'] = $old_state['advanced_search']; + } + if ($do_email && $GLOBALS['egw_info']['etemplate']['loop'] && is_object($GLOBALS['egw']->js)) + { // remove previous addEmail() calls, otherwise they will be run again + $GLOBALS['egw']->js->body['onLoad'] = preg_replace('/addEmail\([^)]+\);/','',$GLOBALS['egw']->js->body['onLoad']); + } + //echo "uicontacts::get_rows(".print_r($query,true).")
\n"; + if (!$id_only) + { + // check if accounts are stored in ldap, which does NOT yet support the org-views + if ($this->so_accounts && $query['filter'] === '0' && $query['org_view']) + { + if ($old_state['filter'] === '0') // user changed to org_view + { + $query['filter'] = ''; // --> change filter to all contacts + } + else // user changed to accounts + { + $query['org_view'] = ''; // --> change to regular contacts view + } + } + if ($query['org_view'] && isset($this->org_views[$old_state['org_view']]) && !isset($this->org_views[$query['org_view']])) + { + $query['searchletter'] = ''; // reset lettersearch if viewing the contacts of one organisation + } + // 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'], + 'col_filter' => array('tid' => $query['col_filter']['tid']), + 'org_view' => $query['org_view'], + )); + if ($state != $this->prefs[$what.'_state']) + { + $GLOBALS['egw']->preferences->add('addressbook',$what.'_state',$state); + // save prefs, but do NOT invalid the cache (unnecessary) + $GLOBALS['egw']->preferences->save_repository(false,'user',false); + } + } + unset($old_state); + + if ((string)$query['cat_id'] != '') + { + $query['col_filter']['cat_id'] = $query['cat_id'] ? $query['cat_id'] : null; + } + else + { + unset($query['col_filter']['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; + } + } + if ((int)$query['filter2']) // not no distribution list + { + $query['col_filter']['list'] = (string) (int) $query['filter2']; + } + else + { + unset($query['col_filter']['list']); + } + if ($GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) + { + $query['col_filter']['account_id'] = null; + } + // enable/disable distribution lists depending on backend + $query['no_filter2'] = !$this->lists_available($query['filter']); + + if (isset($this->org_views[(string) $query['org_view']])) // we have an org view + { + unset($query['col_filter']['list']); // does not work together + $query['no_filter2'] = true; // switch the distribution list selection off + + $query['template'] = 'addressbook.index.org_rows'; + + if ($query['order'] != 'org_name') + { + $query['sort'] = 'ASC'; + $query['order'] = 'org_name'; + } + $rows = parent::organisations($query); + + $GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => 'ManualAddressbookIndexOrga'); + } + else // contacts view + { + if ($query['sitemgr_display']) + { + $query['template'] = $query['sitemgr_display'].'.rows'; + } else { + $query['template'] = $do_email ? 'addressbook.email.rows' : 'addressbook.index.rows'; + } + if ($query['org_view']) // view the contacts of one organisation only + { + foreach(explode('|||',$query['org_view']) as $part) + { + list($name,$value) = explode(':',$part,2); + $query['col_filter'][$name] = $value; + } + } + // translate the select order to the really used over all 3 columns + $sort = $query['sort']; + switch($query['order']) // "xxx<>'' DESC" sorts contacts with empty order-criteria always at the end + { // we don't exclude them, as the total would otherwise depend on the order-criteria + case 'org_name': + $order = "org_name<>'' DESC,org_name $sort,n_family $sort,n_given $sort"; + break; + default: + if ($query['order'][0] == '#') // we order by a custom field + { + $order = "$query[order]<>'' DESC,$query[order] $sort,org_name $sort,n_family $sort,n_given $sort"; + break; + } + $query['order'] = 'n_family'; + case 'n_family': + $order = "n_family<>'' DESC,n_family $sort,n_given $sort,org_name $sort"; + break; + case 'n_given': + $order = "n_given<>'' DESC,n_given $sort,n_family $sort,org_name $sort"; + break; + case 'n_fileas': + $order = "n_fileas<>'' DESC,n_fileas $sort"; + break; + case 'adr_one_postalcode': + $order = "adr_one_postalcode<>'' DESC,adr_one_postalcode $sort,org_name $sort,n_family $sort,n_given $sort"; + break; + case 'contact_modified': + case 'contact_created': + $order = "$query[order] IS NULL,$query[order] $sort,org_name $sort,n_family $sort,n_given $sort"; + break; + } + if ($query['searchletter']) // only show contacts if the order-criteria starts with the given letter + { + $query['col_filter'][] = ($query['order'] == 'adr_one_postalcode' ? 'org_name' : $query['order']).' '. + $GLOBALS['egw']->db->capabilities['case_insensitive_like'].' '.$GLOBALS['egw']->db->quote($query['searchletter'].'%'); + } + $wildcard = '%'; + $op = 'OR'; + if ($query['advanced_search']) + { + $op = $query['advanced_search']['operator']; + unset($query['advanced_search']['operator']); + $wildcard = $query['advanced_search']['meth_select']; + unset($query['advanced_search']['meth_select']); + } + $rows = parent::search($query['advanced_search'] ? $query['advanced_search'] : $query['search'],$id_only, + $order,'',$wildcard,false,$op,array((int)$query['start'],(int) $query['num_rows']),$query['col_filter']); + + // do we need to read the custom fields, depends on the column is enabled and customfields exist + $columselection = $this->prefs['nextmatch-addressbook.'.($do_email ? 'email' : 'index').'.rows']; + $available_distib_lists=$this->get_lists(EGW_ACL_READ); + $columselection = $columselection ? explode(',',$columselection) : array(); + if (!$id_only && $rows) + { + $show_custom_fields = (!$columselection || in_array('customfields',$columselection)) && $this->customfields; + $show_calendar = !$columselection || in_array('calendar',$columselection); + $show_distributionlist = !$columselection || in_array('distrib_lists',$columselection) ||count($available_distib_lists); + if ($show_calendar || $show_custom_fields || $show_distributionlist) + { + foreach($rows as $val) + { + $ids[] = $val['id']; + } + if ($show_custom_fields) + { + foreach($columselection as $col) + { + if ($col[0] == '#') $selected_cfs[] = substr($col,1); + } + $customfields = $this->read_customfields($ids,$selected_cfs); + } + if ($show_calendar) $calendar = $this->read_calendar($ids); + // distributionlist memership for the entrys + //_debug_array($this->get_lists(EGW_ACL_EDIT)); + if ($show_distributionlist && $available_distib_lists) + { + $distributionlist = $this->read_distributionlist($ids,array_keys($available_distib_lists)); + } + } + } + } + if (!$rows) $rows = array(); + + if ($id_only) + { + foreach($rows as $n => $row) + { + $rows[$n] = $row['id']; + } + return $this->total; // no need to set other fields or $readonlys + } + $order = $query['order']; + + $readonlys = array(); + $photos = $homeaddress = $roles = false; + foreach($rows as $n => $val) + { + $row =& $rows[$n]; + + $given = $row['n_given'] ? $row['n_given'] : ($row['n_prefix'] ? $row['n_prefix'] : ''); + + switch($order) + { + default: // postalcode, created, modified, ... + case 'org_name': + $row['line1'] = $row['org_name']; + $row['line2'] = $row['n_family'].($given ? ', '.$given : ''); + break; + case 'n_family': + $row['line1'] = $row['n_family'].($given ? ', '.$given : ''); + $row['line2'] = $row['org_name']; + break; + case 'n_given': + $row['line1'] = $given.' '.$row['n_family']; + $row['line2'] = $row['org_name']; + break; + case 'n_fileas': + if (!$row['n_fileas']) $row['n_fileas'] = $this->fileas($row); + list($row['line1'],$row['line2']) = explode(': ',$row['n_fileas']); + break; + } + if (isset($this->org_views[(string) $query['org_view']])) + { + $row['type'] = 'home'; + $row['type_label'] = lang('Organisation'); + + $readonlys["delete[$row[id]]"] = $query['filter'] && !($this->grants[(int)$query['filter']] & EGW_ACL_DELETE); + $readonlys["infolog[$row[id]]"] = !$GLOBALS['egw_info']['user']['apps']['infolog']; + } + else + { + $this->type_icon($row['owner'],$row['private'],$row['tid'],$row['type'],$row['type_label']); + + static $tel2show = array('tel_work','tel_cell','tel_home','tel_fax'); + foreach($tel2show as $name) + { + $row[$name] .= ' '.($row['tel_prefer'] == $name ? '♥' : ''); // .' ' 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']].' ♥'; + } + $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 ($row['role']) $roles = true; + if (isset($customfields[$row['id']])) + { + foreach($this->customfields as $name => $data) + { + $row['#'.$name] = $customfields[$row['id']][$name]; + } + } + if (isset($distributionlist[$row['id']])) + { + $row['distrib_lists'] = implode("\n",array_values($distributionlist[$row['id']])); + //if ($show_distributionlist) $readonlys['distrib_lists'] =true; + } + if (isset($calendar[$row['id']])) + { + foreach($calendar[$row['id']] as $name => $data) + { + $row[$name] = $data; + } + } + 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; + } + } + } + $readonlys["document[$row[id]]"] = !$this->prefs['default_document']; + + // hide region for address format 'postcode_city' + if (($row['addr_format'] = $this->addr_format_by_country($row['adr_one_countryname']))=='postcode_city') unset($row['adr_one_region']); + if (($row['addr_format2'] = $this->addr_format_by_country($row['adr_two_countryname']))=='postcode_city') unset($row['adr_two_region']); + } + if ($show_distributionlist) { + $readonlys['no_distrib_lists'] =true; + } else { + $readonlys['no_distrib_lists'] =false; + } + if (!$this->prefs['no_auto_hide']) + { + // disable photo column, if view contains no photo(s) + if (!$photos) $rows['no_photo'] = true; + // disable homeaddress column, if we have no homeaddress(es) + if (!$homeaddress) $rows['no_home'] = true; + // disable roles column + if (!$roles) $rows['no_role'] = true; + } + // disable customfields column, if we have no customefield(s) + if (!$this->customfields/* || !$this->prefs['no_auto_hide'] && !$customfields*/) $rows['no_customfields'] = true; + + $rows['order'] = $order; + $rows['call_popup'] = $this->config['call_popup']; + $rows['customfields'] = array_values($this->customfields); + + // full app-header with all search criteria specially for the print + $GLOBALS['egw_info']['flags']['app_header'] = lang('addressbook'); + if ($query['filter'] !== '' && !isset($this->org_views[$query['org_view']])) + { + $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['org_view']) + { + $GLOBALS['egw_info']['flags']['app_header'] .= ': '.$query['org_view_label']; + } + if($query['advanced_search']) + { + $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Advanced search'); + } + if ($query['cat_id']) + { + $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Category').' '.$GLOBALS['egw']->categories->id2name($query['cat_id']); + } + if ($query['searchletter']) + { + $order = $order == 'n_given' ? lang('first name') : ($order == 'n_family' ? lang('last name') : lang('Organisation')); + $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 ($private) + { + $icon = 'private'; + $label = lang('private'); + } + 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); + } + // show tid icon for tid!='n' AND only if one is defined + if ($tid != 'n' && $this->content_types[$tid]['options']['icon']) + { + $icon = $this->content_types[$tid]['options']['icon']; + $label = $this->content_types[$tid]['name'].' ('.$label.')'; + } + } + + /** + * 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) && !$GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) + { + $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 + * + * @param array $content=null submitted content + * @param int $_GET['contact_id'] contact_id manly for popup use + * @param bool $_GET['makecp'] ture if you want do copy the contact given by $_GET['contact_id'] + */ + function edit($content=null) + { + 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']) $content['jpegphoto'] = null; + 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']); + unset($content['upload_photo']); + } + $links = false; + if (!$content['id'] && is_array($content['link_to']['to_id'])) + { + $links = $content['link_to']['to_id']; + } + if ($content['id'] && $content['org_name'] && $content['change_org']) + { + $old_org_entry = $this->read($content['id']); + } + if ($this->save($content)) + { + $content['msg'] = lang('Contact saved'); + if ($content['change_org'] && $old_org_entry && ($changed = $this->changed_fields($old_org_entry,$content,true)) && + ($members = $this->org_similar($old_org_entry['org_name'],$changed))) + { + //foreach($changed as $name => $old_value) echo "$name: '$old_value' --> '{$content[$name]}'
\n"; + list($changed_members,$changed_fields,$failed_members) = $this->change_org($old_org_entry['org_name'],$changed,$content,$members); + if ($changed_members) + { + $content['msg'] .= ', '.lang('%1 fields in %2 other organisation member(s) changed',$changed_fields,$changed_members); + } + if ($failed_members) + { + $content['msg'] .= ', '.lang('failed to change %1 organisation member(s) (insufficent rights) !!!',$failed_members); + } + } + } + elseif($this->error === true) + { + $content['msg'] = lang('Error: the entry has been updated since you opened it for editing!').'imagecopyresized(\$photo,\$upload,0,0,0,0,$dst_w,$dst_h,$src_w,$src_h);
\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)) + { + list($button) = each($content['button']); + switch ($button) + { + case 'vcard': + $GLOBALS['egw']->redirect_link('/index.php','menuaction=addressbook.uivcard.out&ab_id=' .$content['id']); + + case 'cancel': + $GLOBALS['egw']->redirect_link('/index.php','menuaction=addressbook.addressbook_ui.index'); + + case 'delete': + $GLOBALS['egw']->redirect_link('/index.php',array( + 'menuaction' => 'addressbook.addressbook_ui.index', + 'msg' => $this->delete($content) ? lang('Contact deleted') : lang('Error deleting the contact !!!'), + )); + } + } + else + { + if(!$_GET['contact_id'] || !is_array($content = $this->read($_GET['contact_id']))) + { + $GLOBALS['egw']->redirect_link('/index.php',array( + 'menuaction' => 'addressbook.addressbook_ui.index', + 'msg' => $content, + )); + } + } + foreach(array_keys($this->contact_fields) as $key) + { + $readonlys[$key] = true; + if (in_array($key,array('tel_home','tel_work','tel_cell','tel_fax'))) + { + $readonlys[$key.'2'] = true; + $content[$key.'2'] = $content[$key]; + } + } + $content['view'] = true; + $content['link_to'] = array( + 'to_app' => 'addressbook', + 'to_id' => $content['id'], + ); + $readonlys['link_to'] = $readonlys['customfields'] = $readonlys['fileas_type'] = true; + $readonlys['button[save]'] = $readonlys['button[apply]'] = $readonlys['change_photo'] = true; + $readonlys['button[delete]'] = !$content['owner'] || !$this->check_perms(EGW_ACL_DELETE,$content); + $readonlys['button[edit]'] = !$this->check_perms(EGW_ACL_EDIT,$content); + $content['disable_change_org'] = true; +// ToDo: fix vCard export +$readonlys['button[vcard]'] = true; + + // how to display addresses + $content['addr_format'] = $this->addr_format_by_country($content['adr_one_countryname']); + $content['addr_format2'] = $this->addr_format_by_country($content['adr_two_countryname']); + + $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; + if (count($this->content_types) > 1) + { + foreach($this->content_types as $type => $data) + { + $sel_options['tid'][$type] = $data['name']; + } + $content['typegfx'] = html::image('addressbook',$this->content_types[$content['tid']]['options']['icon'],'',' width="16px" height="16px"'); + } + else + { + $content['no_tid'] = true; + } + if (!$this->tmpl->read($this->content_types[$content['tid']]['options']['template'] ? $this->content_types[$content['tid']]['options']['template'] : 'addressbook.edit')) + { + $content['msg'] = lang('WARNING: Template "%1" not found, using default template instead.', $this->content_types[$content['tid']]['options']['template'])."\n"; + $content['msg'] .= lang('Please update the templatename in your customfields section!'); + $this->tmpl->read('addressbook.edit'); + } + if ($this->private_addressbook && $content['private'] && $content['owner'] == $this->user) + { + $content['owner'] .= 'p'; + } + // disable not needed tabs + $readonlys[$this->tabs]['cats'] = !($content['cat_tab'] = $this->config['cat_tab']); + $readonlys[$this->tabs]['custom'] = !$this->customfields; + $readonlys[$this->tabs]['custom_private'] = !$this->customfields || !$this->config['private_cf_tab']; + $readonlys[$this->tabs]['distribution_list'] = !$content['distrib_lists'];#false; + if ($this->config['private_cf_tab']) $content['no_private_cfs'] = 0; + + // last and next calendar date + list(,$dates) = each($this->read_calendar(array($content['id']),false)); + if(is_array($dates)) $content += $dates; + + // set id for automatic linking via quick add + $GLOBALS['egw_info']['flags']['currentid'] = $content['id']; + + $this->tmpl->exec('addressbook.addressbook_ui.view',$content,$sel_options,$readonlys,array('id' => $content['id'])); + + $GLOBALS['egw']->hooks->process(array( + 'location' => 'addressbook_view', + 'ab_id' => $content['id'] + )); + } + + /** + * convert email-address in compose link + * + * @param string $email email-addresse + * @return array/string array with get-params or mailto:$email, or '' or no mail addresse + */ + function email2link($email) + { + if (strpos($email,'@') == false) return ''; + + if($GLOBALS['egw_info']['user']['apps']['felamimail']) + { + return array( + 'menuaction' => 'felamimail.uicompose.compose', + 'send_to' => base64_encode($email) + ); + } + if($GLOBALS['egw_info']['user']['apps']['email']) + { + return array( + 'menuaction' => 'email.uicompose.compose', + 'to' => $email, + ); + } + return 'mailto:' . $email; + } + + /** + * Extended search + * + * @param array $_content + * @return string + */ + function search($_content=array()) + { + if(!empty($_content)) { + $response = new xajaxResponse(); + + $query = $GLOBALS['egw']->session->appsession($do_email ? 'email' : 'index','addressbook'); + + $query['advanced_search'] = array_intersect_key($_content,array_flip(array_merge($this->get_contact_columns(),array('operator','meth_select')))); + foreach ($query['advanced_search'] as $key => $value) + { + if(!$value) unset($query['advanced_search'][$key]); + } + $query['start'] = 0; + $query['search'] = ''; + // store the index state in the session + $GLOBALS['egw']->session->appsession($do_email ? 'email' : 'index','addressbook',$query); + + // store the advanced search in the session to call it again + $GLOBALS['egw']->session->appsession('advanced_search','addressbook',$query['advanced_search']); + + $response->addScript(" + var link = opener.location.href; + link = link.replace(/#/,''); + opener.location.href=link.replace(/\#/,''); + xajax_eT_wrapper(); + "); + return $response->getXML(); + } + else { + + } + $GLOBALS['egw_info']['flags']['include_xajax'] = true; + $GLOBALS['egw_info']['flags']['java_script'] .= ""; + $GLOBALS['egw_info']['etemplate']['advanced_search'] = true; + + // initialize etemplate arrays + $sel_options = $readonlys = $preserv = array(); + $content = $GLOBALS['egw']->session->appsession('advanced_search','addressbook'); + + for($i = -23; $i<=23; $i++) $tz[$i] = ($i > 0 ? '+' : '').$i; + $sel_options['tz'] = $tz + array('' => lang('doesn\'t matter')); + $sel_options['tid'][] = lang('all'); + //foreach($this->content_types as $type => $data) $sel_options['tid'][$type] = $data['name']; + + // configure search options + $sel_options['owner'] = $this->get_addressbooks(EGW_ACL_READ,lang('all')); + $sel_options['operator'] = array( + 'AND' => 'AND', + 'OR' => 'OR', + ); + $sel_options['meth_select'] = array( + '%' => lang('contains'), + false => lang('exact'), + ); + if ($this->customfields) + { + foreach($this->customfields as $name => $data) + { + if ($data['type'] == 'select') + { + if (!isset($content['#'.$name])) $content['#'.$name] = ''; + if(!isset($data['values'][''])) $sel_options['#'.$name][''] = lang('Select one'); + } + } + } + // configure edit template as search dialog + $readonlys['change_photo'] = true; + $readonlys['fileas_type'] = true; + $readonlys['creator'] = true; + // this setting will enable (and show) the search and cancel buttons, setting this to true will hide the before mentioned buttons completely + $readonlys['button'] = false; + // disable not needed tabs + $readonlys[$this->tabs]['cats'] = !($content['cat_tab'] = $this->config['cat_tab']); + $readonlys[$this->tabs]['custom'] = !$this->customfields; + $readonlys[$this->tabs]['custom_private'] = !$this->customfields || !$this->config['private_cf_tab']; + $readonlys[$this->tabs]['links'] = true; + $readonlys[$this->tabs]['distribution_list'] = true; + // setting hidebuttons for content will hide the 'normal' addressbook edit dialog buttons + $content['hidebuttons'] = true; + $content['no_tid'] = true; + $content['disable_change_org'] = true; + + $this->tmpl->read('addressbook.search'); + return $this->tmpl->exec('addressbook.addressbook_ui.search',$content,$sel_options,$readonlys,$preserv,2); + } + + /** + * download photo of the given ($_GET['contact_id'] or $_GET['account_id']) contact + */ + 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['jpegphoto'],'ascii') : strlen($contact['jpegphoto']))); + echo $contact['jpegphoto']; + exit; + } + } + + /** + * Add javascript functions + * + * @return string + */ + function js() + { + return ''; + } + + function migrate2ldap() + { + $GLOBALS['egw_info']['flags']['app_header'] = lang('Addressbook').' - '.lang('Migration to LDAP'); + $GLOBALS['egw']->common->egw_header(); + parse_navbar(); + + if (!$this->is_admin()) + { + echo ''.lang('Migration finished')."
\n"; + } + $GLOBALS['egw']->common->egw_footer(); + } + + /** + * Download a document with inserted contact(s) + * + * @param array $ids contact-ids + * @param string $document vfs-path of document + * @return string error-message or error, otherwise the function does NOT return! + */ + function download_document($ids,$document='') + { + if (!$document) + { + $document = $this->prefs['default_document']; + } + else + { + $document = $this->prefs['document_dir'].'/'.$document; + } + if (!@egw_vfs::stat($document)) + { + return lang("Document '%1' does not exist or is not readable for you!",$document); + } + require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.addressbook_merge.inc.php'); + $document_merge =& new addressbook_merge(); + + return $document_merge->download($document,$ids); + } + + /** + * Returning document actions / files from the document_dir + * + * @return array + */ + function get_document_actions() + { + if (!$this->prefs['document_dir']) return array(); + + if (!is_array($actions = $GLOBALS['egw']->session->appsession('document_actions','addressbook'))) + { + $actions = array(); + if (($files = egw_vfs::find($this->prefs['document_dir'],array('need_mime'=>true),true))) + { + foreach($files as $file) + { + // return only the mime-types we support + if (!($file['mime'] == 'application/rtf' || + $file['mime'] == 'application/msword' && !strcasecmp(substr($file['name'],-4),'.rtf') || + substr($file['mime'],0,5) == 'text/')) continue; + // As browsers not always return the right mime_type, you could use a negative list instead + //if ($file['mime'] == egw_vfs::DIR_MIME_TYPE || substr($file['mime'],0,6) == 'image/') continue; + + $actions['document-'.$file['name']] = /*lang('Insert in document').': '.*/$file['name']; + } + } + $GLOBALS['egw']->session->appsession('document_actions','addressbook',$actions); + } + return $actions; + } + + /** + * add a new categorie to any addressbock entry + * + * @author Stefan Becker$_vcard"; + + #error_log(print_r($vcardValues, true)); + + foreach($vcardValues as $key => $vcardRow) + { + $rowName = $vcardRow['name']; + + $vcardElementCount = count($vcardRow['params'],COUNT_RECURSIVE); + + if( $vcardElementCount > 0 ) + { + foreach($vcardRow['params'] as $VKey => $vcardParam) + { + if( ! strlen($vcardParam) ) + { + $rowName .= ';'.$VKey; + } + if( $VKey == 'TYPE' && in_array(strtoupper($vcardParam),array('CELL','FAX','PAGER','WORK','HOME','VOICE','CAR'))) + { + $rowName .= ';'.strtoupper($vcardParam); + } + } + } + $rowNames[$rowName] = $key; + } + + + #error_log(print_r($rowNames, true)); + + // now we have all rowNames the vcard provides + // we just need to map to the right addressbook fieldnames + // we need also to take care about ADR for example. we do not + // support this. We support only ADR;WORK or ADR;HOME + + foreach($rowNames as $rowName => $vcardKey) + { + + switch($rowName) + { + case 'ADR': + case 'TEL': + case 'URL': + case 'TEL;FAX': + case 'TEL;CELL': + case 'TEL;PAGER': + case 'TEL;VOICE': + if(!isset($rowNames[$rowName. ';WORK']) && array_key_exists($rowName. ';WORK', $this->supportedFields) ) + { + $finalRowNames[$rowName. ';WORK'] = $vcardKey; + } + else + { + $InvolvedValues = explode(';',$rowName.';WORK'); + foreach($this->supportedFields as $suppFields => $suppFieldsValue ) + { + $InvolvedHits = 0; + foreach($InvolvedValues as $hlparr => $hlparrKey ) + { + if( ! stristr( $suppFields,$hlparrKey ) === FALSE ) + { + $InvolvedHits++; + } + } + if( count($InvolvedValues) == $InvolvedHits && !isset($finalRowNames[$suppFields]) ) + { + $finalRowNames[$suppFields] = $vcardKey; + break; // if a combination of all words in $InvolvedValues were found + } + } + if( count($InvolvedValues) != $InvolvedHits && ! isset($finalRowNames[$rowName]) && array_key_exists($rowName, $this->supportedFields) ) + { + $finalRowNames[$rowName] = $vcardKey; + } + } + break; + case 'EMAIL': + case 'EMAIL;WORK': + case 'EMAIL;INTERNET': + if(!isset($rowNames['EMAIL;INTERNET;WORK'])) + { + $finalRowNames['EMAIL;INTERNET;WORK'] = $vcardKey; + } + break; + case 'EMAIL;HOME': + if(!isset($rowNames['EMAIL;INTERNET;HOME'])) + { + $finalRowNames['EMAIL;INTERNET;HOME'] = $vcardKey; + } + break; + + case 'VERSION': + break; + + default: + $finalRowNames[$rowName] = $vcardKey; + break; + } + } + #error_log(print_r($finalRowNames, true)); + + $contact = array(); + + foreach($finalRowNames as $key => $vcardKey) + { + if(isset($this->supportedFields[$key])) + { + $fieldNames = $this->supportedFields[$key]; + foreach($fieldNames as $fieldKey => $fieldName) + { + if(!empty($fieldName)) + { + if ($fieldName == 'jpegphoto' || $vcardValues[$vcardKey]['params']['ENCODING'] == 'b') + { + $value = base64_decode($vcardValues[$vcardKey]['values'][$fieldKey]); + } + else + { + $value = trim($vcardValues[$vcardKey]['values'][$fieldKey]); + } + + switch($fieldName) + { + case 'bday': + if(!empty($value)) { + $contact[$fieldName] = date('Y-m-d', $value); + } + break; + + case 'private': + $contact[$fieldName] = (int) ( strtoupper($value) == 'PRIVATE'); + break; + + case 'cat_id': + $contact[$fieldName] = implode(',',$this->find_or_add_categories(explode(',',$value))); + break; + + case 'note': + // note may contain ','s but maybe this needs to be fixed in vcard parser... + //$contact[$fieldName] = trim($vcardValues[$vcardKey]['value']); + //break; + + default: + $contact[$fieldName] = $value; + break; + } + } + } + } + } + + $this->fixup_contact($contact); + return $contact; + } + + /** + * Exports some contacts: download or write to a file + * + * @param array $ids contact-ids + * @param string $file filename or null for download + */ + function export($ids,$file=null) + { + if (!$file) + { + $browser =& CreateObject('phpgwapi.browser'); + $browser->content_header('addressbook.vcf','text/x-vcard'); + } + if (!($fp = fopen($file ? $file : 'php://output','w'))) + { + return false; + } + foreach($ids as $id) + { + fwrite($fp,$this->getVCard($id)); + } + fclose($fp); + + if (!$file) + { + $GLOBALS['egw']->common->egw_exit(); + } + return true; + } +} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.boaddressbook.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.boaddressbook.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.boaddressbook.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.boaddressbook.inc.php 2008-11-24 11:43:08.000000000 +0000 @@ -5,16 +5,16 @@ * The original addressbook xmlrpc interface was written by Joseph Engo
bocontacts::fileas(,$type)='$fileas'
\n"; - return $fileas; - } - - /** - * 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'), - 'org_unit' => lang('department'), - 'adr_one_locality' => lang('city'), - ); - 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 - * - * it gets called everytime when data is read from the db - * This function needs to be reimplemented in the derived class - * - * @param array $data - */ - function db2data($data) - { - // convert timestamps from server-time in the db to user-time - foreach($this->timestamps as $name) - { - if(isset($data[$name])) - { - $data[$name] += $this->tz_offset_s; - } - } - $data['photo'] = $this->photo_src($data['id'],$data['jpegphoto']); - - // set freebusy_uri for accounts - if (!$data['freebusy_uri'] && !$data['owner'] && $data['account_id'] && !is_object($GLOBALS['egw_setup'])) - { - static $fb_url; - if (!$fb_url && @is_dir(EGW_SERVER_ROOT.'/calendar/inc')) $fb_url = ExecMethod('calendar.bocal.freebusy_url',''); - if ($fb_url) $data['freebusy_uri'] = $fb_url.urlencode($GLOBALS['egw']->accounts->id2name($data['account_id'])); - } - 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 - * - * It gets called everytime when data gets writen into db or on keys for db-searches - * this needs to be reimplemented in the derived class - * - * @param array $data - */ - function data2db($data) - { - // convert timestamps from user-time to server-time in the db - foreach($this->timestamps as $name) - { - if(isset($data[$name])) - { - $data[$name] -= $this->tz_offset_s; - } - } - return $data; - } - - /** - * deletes contact in db - * - * @param mixed &$contact contact array with key id or (array of) id(s) - * @param boolean $deny_account_delete=true if true never allow to delete accounts - * @return boolean true on success or false on failiure - */ - function delete($contact,$deny_account_delete=true) - { - if (is_array($contact) && isset($contact['id'])) - { - $contact = array($contact); - } - elseif (!is_array($contact)) - { - $contact = array($contact); - } - if (!is_object($GLOBALS['egw']->link)) - { - require_once(EGW_API_INC.'/class.bolink.inc.php'); - $GLOBALS['egw']->link =& new bolink(); - } - foreach($contact as $c) - { - $id = is_array($c) ? $c['id'] : $c; - - if ($this->check_perms(EGW_ACL_DELETE,$c,$deny_account_delete) && parent::delete($id)) - { - $GLOBALS['egw']->link->unlink(0,'addressbook',$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 - * @param boolean $ignore_acl=false should the acl be checked or not - * @return int/string/boolean id on success, false on failure, the error-message is in $this->error - */ - function save(&$contact,$ignore_acl=false) - { - // remember if we add or update a entry - if (($isUpdate = $contact['id'])) - { - if (!isset($contact['owner']) || !isset($contact['private'])) // owner/private not set on update, eg. SyncML - { - if (($old = $this->read($contact['id']))) // --> try reading the old entry and set it from there - { - if(!isset($contact['owner'])) - { - $contact['owner'] = $old['owner']; - } - if(!isset($contact['private'])) - { - $contact['private'] = $old['private']; - } - } - else // entry not found --> create a new one - { - $isUpdate = $contact['id'] = null; - } - } - } - else - { - // if no owner/addressbook set use the setting of the add_default prefs (if set, otherwise the users personal addressbook) - if (!isset($contact['owner'])) $contact['owner'] = (int)$this->prefs['add_default'] ? (int)$this->prefs['add_default'] : $this->user; - if (!isset($contact['private'])) $contact['private'] = (int)(substr($this->prefs['add_default'],-1) == 'p'); - // allow admins to import contacts with creator / created date set - if (!$contact['creator'] || !$this->is_admin($contact)) $contact['creator'] = $this->user; - if (!$contact['created'] || !$this->is_admin($contact)) $contact['created'] = $this->now_su; - - if (!$contact['tid']) $contact['tid'] = 'n'; - } - if (!$contact['owner']) - { - $contact['private'] = 0; // accounts are never private! - } - if(!$ignore_acl && !$this->check_perms($isUpdate ? EGW_ACL_EDIT : EGW_ACL_ADD,$contact)) - { - $this->error = 'access denied'; - return false; - } - // convert categories - if (is_array($contact['cat_id'])) { - $contact['cat_id'] = implode(',',$contact['cat_id']); - } - // last modified - $contact['modifier'] = $this->user; - $contact['modified'] = $this->now_su; - // set full name and fileas from the content - if (isset($contact['n_family']) && isset($contact['n_given'])) - { - $contact['n_fn'] = $this->fullname($contact); - if (isset($contact['org_name'])) $contact['n_fileas'] = $this->fileas($contact); - } - $to_write = $contact; - // (non-admin) user editing his own account, make sure he does not change fields he is not allowed to (eg. via SyncML or xmlrpc) - if (!$ignore_acl && !$contact['owner'] && !$this->is_admin($contact)) - { - foreach($contact as $field => $value) - { - if (!in_array($field,$this->own_account_acl) && !in_array($field,array('id','owner','account_id','modified','modifier'))) - { - unset($to_write[$field]); // user is now allowed to change that - } - } - } - // we dont update the content-history, if we run inside setup (admin-account-creation) - if(!($this->error = parent::save($to_write)) && is_object($GLOBALS['egw']->contenthistory)) - { - $contact['id'] = $to_write['id']; - $GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $contact['id'],$isUpdate ? 'modify' : 'add', time()); - - if ($contact['account_id']) // invalidate the cache of the accounts class - { - $GLOBALS['egw']->accounts->cache_invalidate($contact['account_id']); - } - // notify interested apps about changes in the account-contact data - if (!$to_write['owner'] && $to_write['account_id']) - { - $to_write['location'] = 'editaccountcontact'; - $GLOBALS['egw']->hooks->process($to_write,False,True); // called for every app now, not only enabled ones)); - } - } - - return $this->error ? false : $contact['id']; - } - - /** - * reads contacts matched by key and puts all cols in the data array - * - * @param int/string $contact_id - * @return array/boolean array with contact data, null if not found or false on no view perms - */ - function read($contact_id) - { - if (!($data = parent::read($contact_id))) - { - return null; // not found - } - if (!$this->check_perms(EGW_ACL_READ,$data)) - { - return false; // no view perms - } - // determine the file-as type - $data['fileas_type'] = $this->fileas_type($data); - - return $data; - } - - /** - * 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 - * @param boolean $deny_account_delete=false if true never allow to delete accounts - * @return boolean true permission granted, false for permission denied, null for contact does not exist - */ - function check_perms($needed,$contact,$deny_account_delete=false) - { - if ((!is_array($contact) || !isset($contact['owner'])) && - !($contact = parent::read(is_array($contact) ? $contact['id'] : $contact))) - { - return null; - } - $owner = $contact['owner']; - - // allow the user to edit his own account - if (!$owner && $needed == EGW_ACL_EDIT && $contact['account_id'] == $this->user && $this->own_account_acl) - { - return true; - } - // dont allow to delete own account (as admin handels it too) - if (!$owner && $needed == EGW_ACL_DELETE && ($deny_account_delete || $contact['account_id'] == $this->user)) - { - return false; - } - return ($this->grants[$owner] & $needed) && - (!$contact['private'] || ($this->grants[$owner] & EGW_ACL_PRIVATE) || in_array($owner,$this->memberships)); - } - - /** - * Read (virtual) org-entry (values "common" for most contacts in the given org) - * - * @param string $org_id org_name:oooooo|||org_unit:uuuuuuuuu|||adr_one_locality:lllllll (org_unit and adr_one_locality are optional) - * @return array/boolean array with common org fields or false if org not found - */ - function read_org($org_id) - { - if (!$org_id) return false; - - $org = array(); - foreach(explode('|||',$org_id) as $part) - { - list($name,$value) = explode(':',$part); - $org[$name] = $value; - } - $contacts = parent::search('',$this->org_fields,'','','',false,'AND',false,$org); - - if (!$contacts) return false; - - // create a statistic about the commonness of each fields values - $fields = array(); - foreach($contacts as $contact) - { - foreach($contact as $name => $value) - { - $fields[$name][$value]++; - } - } - foreach($fields as $name => $values) - { - if (!in_array($name,$this->org_fields)) continue; - - arsort($values,SORT_NUMERIC); - - list($value,$num) = each($values); - //echo "$name: '$value' $num/".count($contacts)."=".($num / (double) count($contacts))." >= $this->org_common_factor = ".($num / (double) count($contacts) >= $this->org_common_factor ? 'true' : 'false')."
\n"; - if ($value && $num / (double) count($contacts) >= $this->org_common_factor) - { - $org[$name] = $value; - } - } - //echo $org_id; _debug_array($org); - - return $org; - } - - /** - * Return all org-members with same content in one or more of the given fields (only org_fields are counting) - * - * @param string $org_name - * @param array $fields field-name => value pairs - * @return array with contacts - */ - function org_similar($org_name,$fields) - { - $criteria = array(); - foreach($this->org_fields as $name) - { - if (isset($fields[$name])) - { - $criteria[$name] = $fields[$name]; - } - } - return parent::search($criteria,false,'n_family,n_given','','',false,'OR',false,array('org_name'=>$org_name)); - } - - /** - * Return the changed fields from two versions of a contact (not modified or modifier) - * - * @param array $from original/old version of the contact - * @param array $to changed/new version of the contact - * @param boolean $onld_org_fields=true check and return only org_fields, default true - * @return array with field-name => value from $from - */ - function changed_fields($from,$to,$only_org_fields=true) - { - $changed = array(); - foreach($only_org_fields ? $this->org_fields : array_keys($this->contact_fields) as $name) - { - if (!isset($from[$name]) || in_array($name,array('modified','modifier'))) // never count these - { - continue; - } - if ((string) $from[$name] != (string) $to[$name]) - { - $changed[$name] = $from[$name]; - } - } - return $changed; - } - - /** - * Change given fields in all members of the org with identical content in the field - * - * @param string $org_name - * @param array $from original/old version of the contact - * @param array $to changed/new version of the contact - * @param array $members=null org-members to change, default null --> function queries them itself - * @return array/boolean (changed-members,changed-fields,failed-members) or false if no org_fields changed or no (other) members matching that fields - */ - function change_org($org_name,$from,$to,$members=null) - { - if (!($changed = $this->changed_fields($from,$to,true))) return false; - - if (is_null($members) || !is_array($members)) - { - $members = $this->org_similar($org_name,$changed); - } - if (!$members) return false; - - $changed_members = $changed_fields = $failed_members = 0; - foreach($members as $member) - { - $fields = 0; - foreach($changed as $name => $value) - { - if ((string)$value == (string)$member[$name]) - { - $member[$name] = $to[$name]; - //echo "$member[n_family], $member[n_given]: $name='{$to[$name]}'
\n"; - ++$fields; - } - } - if ($fields) - { - if (!$this->check_perms(EGW_ACL_EDIT,$member) || !$this->save($member)) - { - ++$failed_members; - } - else - { - ++$changed_members; - $changed_fields += $fields; - } - } - } - return array($changed_members,$changed_fields,$failed_members); - } - - /** - * get title for a contact identified by $contact - * - * Is called as hook to participate in the linking. The format is determined by the link_title preference. - * - * @param int/string/array $contact int/string id or array with contact - * @param string/boolean string with the title, null if contact does not exitst, false if no perms to view it - * @return string - */ - function link_title($contact) - { - if (!is_array($contact) && $contact) - { - $contact = $this->read($contact); - } - if (!is_array($contact)) - { - return $contact; - } - $type = $this->prefs['link_title']; - if (!$type || $type === 'n_fileas') - { - if ($contact['n_fileas']) return $contact['n_fileas']; - $type = null; - } - return $this->fileas($contact,$type); - } - - /** - * 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; - } - } - if (($contacts = parent::search($criteria,false,'org_name,n_family,n_given','','%',false,'OR'))) - { - foreach($contacts 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', - 'add' => array( - 'menuaction' => 'addressbook.uicontacts.edit' - ), - 'add_app' => 'link_app', - 'add_id' => 'link_id', - 'add_popup' => '850x440', - ); - } - - /** - * Register contacts as calendar resources (items which can be sheduled by the calendar) - * - * @param array $args hook-params (not used) - * @return array - */ - function calendar_resources($args) - { - return array( - 'type' => 'c',// one char type-identifiy for this resources - 'info' => 'addressbook.bocontacts.calendar_info',// info method, returns array with id, type & name for a given id - ); - } - - /** - * returns info about contacts for calender - * - * @param int/array $ids single contact-id or array of id's - * @return array - */ - function calendar_info($ids) - { - if (!$ids) return null; - - $data = array(); - foreach(!is_array($ids) ? array($ids) : $ids as $id) - { - if (!($contact = $this->read($id))) continue; - - $data[] = array( - 'res_id' => $id, - 'email' => $contact['email'] ? $contact['email'] : $contact['email_home'], - 'rights' => EGW_ACL_READ_FOR_PARTICIPANTS, - 'name' => $this->link_title($contact), - ); - } - //echo "calendar_info(".print_r($ids,true).")="; _debug_array($data); - return $data; - } - - /** - * Called by delete-account hook, when an account get deleted --> deletes/moves the personal addressbook - * - * @param array $data - */ - function deleteaccount($data) - { - // delete/move personal addressbook - parent::deleteaccount($data); - } - - /** - * Called by edit-account hook, when an account get edited --> not longer used - * - * This function is still there, to not give a fatal error, if the hook still exists. - * Can be removed after the next db-update, which also reloads the hooks. RalfBecker 2006/09/18 - * - * @param array $data - */ - function editaccount($data) - { - // just force a new registration of the addressbook hooks - include(EGW_INCLUDE_ROOT.'/addressbook/setup/setup.inc.php'); - $GLOBALS['egw']->hooks->register_hooks('addressbook',$setup_info['addressbook']['hooks']); - } - - /** - * Merges some given addresses into the first one and delete the others - * - * If one of the other addresses is an account, everything is merged into the account. - * If two accounts are in $ids, the function fails (returns false). - * - * @param array $ids contact-id's to merge - * @return int number of successful merged contacts, false on a fatal error (eg. cant merge two accounts) - */ - function merge($ids) - { - $this->error = false; - foreach(parent::search(array('id'=>$ids),false) as $contact) // $this->search calls the extended search from ui! - { - if ($contact['account_id']) - { - if (!is_null($account)) - { - echo $this->error = 'Can not merge more then one account!'; - return false; // we dont deal with two accounts! - } - $account = $contact; - continue; - } - $pos = array_search($contact['id'],$ids); - $contacts[$pos] = $contact; - } - if (!is_null($account)) // we found an account, so we merge the contacts into it - { - $target = $account; - unset($account); - } - else // we found no account, so we merge all but the first into the first - { - $target = $contacts[0]; - unset($contacts[0]); - } - if (!$this->check_perms(EGW_ACL_EDIT,$target)) - { - echo $this->error = 'No edit permission for the target contact!'; - return 0; - } - foreach($contacts as $contact) - { - foreach($contact as $name => $value) - { - if (!$value) continue; - - switch($name) - { - case 'id': - case 'tid': - case 'owner': - case 'private': - break; // ignored - - case 'cat_id': // cats are all merged together - if (!is_array($target['cat_id'])) $target['cat_id'] = $target['cat_id'] ? explode(',',$target['cat_id']) : array(); - $target['cat_id'] = array_unique(array_merge($target['cat_id'],is_array($value)?$value:explode(',',$value))); - break; - - default: - if (!$target[$name]) $target[$name] = $value; - break; - } - } - } - if (!$this->save($target)) return 0; - - if (!is_object($GLOBALS['egw']->link)) - { - require_once(EGW_API_INC.'/class.bolink.inc.php'); - $GLOBALS['egw']->link =& new bolink(); - } - $success = 1; - foreach($contacts as $contact) - { - if (!$this->check_perms(EGW_ACL_DELETE,$contact)) - { - continue; - } - foreach($GLOBALS['egw']->link->get_links('addressbook',$contact['id']) as $data) - { - $GLOBALS['egw']->link->link('addressbook',$target['id'],$data['app'],$data['id'],$data['remark'],$target['owner']); - } - if ($this->delete($contact['id'])) $success++; - } - return $success; - } - - /** - * Check if user has required rights for a list or list-owner - * - * @param int $list - * @param int $required - * @param int $owner=null - * @return boolean - */ - function check_list($list,$required,$owner=null) - { - if ($list && ($list_data = $this->read_list($list))) - { - $owner = $list_data['list_owner']; - } - return !!($this->grants[$owner] & $required); - } - - /** - * Adds a distribution list - * - * @param string $name list-name - * @param int $owner user- or group-id - * @param array $contacts=array() contacts to add - * @return list_id or false on error - */ - function add_list($name,$owner,$contacts=array()) - { - if (!$this->check_list(null,EGW_ACL_ADD,$owner)) return false; - - return parent::add_list($name,$owner,$contacts); - } - - /** - * Adds one contact to a distribution list - * - * @param int $contact contact_id - * @param int $list list-id - * @return false on error - */ - function add2list($contact,$list) - { - if (!$this->check_list($list,EGW_ACL_EDIT)) return false; - - return parent::add2list($contact,$list); - } - - /** - * Removes one contact from distribution list(s) - * - * @param int $contact contact_id - * @param int $list list-id - * @return false on error - */ - function remove_from_list($contact,$list=null) - { - if ($list && !$this->check_list($list,EGW_ACL_EDIT)) return false; - - return parent::remove_from_list($contact,$list); - } - - /** - * Deletes a distribution list (incl. it's members) - * - * @param int/array $list list_id(s) - * @return number of members deleted or false if list does not exist - */ - function delete_list($list) - { - if (!$this->check_list($list,EGW_ACL_DELETE)) return false; - - return parent::delete_list($list); - } - - /** - * Read data of a distribution list - * - * @param int $list list_id - * @return array of data or false if list does not exist - */ - function read_list($list) - { - static $cache; - - if (isset($cache[$list])) return $cache[$list]; - - return $cache[$list] = parent::read_list($list); - } - - /** - * Get the address-format of a country - * - * This is a good reference where I got nearly all information, thanks to mikaelarhelger-AT-gmail.com - * http://www.bitboost.com/ref/international-address-formats.html - * - * Mail me (RalfBecker-AT-outdoor-training.de) if you want your nation added or fixed. - * - * @param string $country - * @return string 'city_state_postcode' (eg. US) or 'postcode_city' (eg. DE) - */ - function addr_format_by_country($country) - { - if (!is_object($GLOBALS['egw']->country)) - { - require_once(EGW_API_INC.'/class.country.inc.php'); - $GLOBALS['egw']->country =& new country; - } - $code = $GLOBALS['egw']->country->country_code($country); - - switch($code) - { - case 'AU': - case 'CA': - case 'GB': // not exactly right, postcode is in separate line - case 'HK': // not exactly right, they have no postcode - case 'IN': - case 'ID': - case 'IE': // not exactly right, they have no postcode - case 'JP': // not exactly right - case 'KR': - case 'LV': - case 'NZ': - case 'TW': - case 'SA': // not exactly right, postcode is in separate line - case 'SG': - case 'US': - $adr_format = 'city_state_postcode'; - break; - - case 'AR': - case 'AT': - case 'BE': - case 'CH': - case 'CZ': - case 'DK': - case 'EE': - case 'ES': - case 'FI': - case 'FR': - case 'DE': - case 'GL': - case 'IS': - case 'IL': - case 'IT': - case 'LT': - case 'LU': - case 'MY': - case 'MX': - case 'NL': - case 'NO': - case 'PL': - case 'PT': - case 'RO': - case 'RU': - case 'SE': - $adr_format = 'postcode_city'; - break; - - default: - $adr_format = $this->prefs['addr_format'] ? $this->prefs['addr_format'] : 'postcode_city'; - } - //echo "
bocontacts::addr_format_by_country('$country'='$code') = '$adr_format'
\n"; - return $adr_format; - } - - var $categories; - - function find_or_add_categories($catname_list) - { - if (!is_object($this->categories)) - { - $this->categories =& CreateObject('phpgwapi.categories',$this->owner,'addressbook'); - } - - $cat_id_list = array(); - foreach($catname_list as $cat_name) - { - $cat_name = trim($cat_name); - $cat_id = $this->categories->name2id($cat_name, 'X-'); - - if (!$cat_id) - { - // some SyncML clients (mostly phones add an X- to the category names - if (strncmp($cat_name, 'X-', 2) == 0) - { - $cat_name = substr($cat_name, 2); - } - $cat_id = $this->categories->add(array('name' => $cat_name,'descr' => $cat_name)); - } - - if ($cat_id) - { - $cat_id_list[] = $cat_id; - } - } - - if (count($cat_id_list) > 1) - { - $cat_id_list = array_unique($cat_id_list); - sort($cat_id_list, SORT_NUMERIC); - } - return $cat_id_list; - } - - function get_categories($cat_id_list) - { - if (!is_object($this->categories)) - { - $this->categories =& CreateObject('phpgwapi.categories',$this->owner,'addressbook'); - } - - if (!is_array($cat_id_list)) - { - $cat_id_list = explode(',',$cat_id_list); - } - $cat_list = array(); - foreach($cat_id_list as $cat_id) - { - if ($cat_data = $this->categories->return_single($cat_id)) - { - $cat_list[] = $cat_data[0]['name']; - } - } - - return $cat_list; - } - - function fixup_contact(&$contact) - { - if (!isset($contact['n_fn']) || empty($contact['n_fn'])) - { - $contact['n_fn'] = $this->fullname($contact); - } - - if (!isset($contact['n_fileas']) || empty($contact['n_fileas'])) - { - $contact['n_fileas'] = $this->fileas($contact); - } - } - -} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.contacts_admin_prefs.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.contacts_admin_prefs.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.contacts_admin_prefs.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.contacts_admin_prefs.inc.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,274 +0,0 @@ - - * @copyright (c) 2006 by Ralf Beckercontacts_admin_prefs::all_hooks(".print_r($args,True).") appname='$appname', location='$location'
\n"; - - if ($location == 'sidebox_menu') - { - $file = array( - array( - 'text' => ''.lang('Add').'', - 'no_lang' => true, - 'link' => false - ), - array( - 'text' => ''.lang('Advanced search').'', - 'no_lang' => true, - 'link' => false - ), - '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->contact_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 are not availible in LDAP - if ($GLOBALS['egw_info']['server']['contact_repository'] != 'ldap') - { - $file['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']['add_default'] = array( - 'type' => 'select', - 'label' => 'Default addressbook for adding contacts', - 'name' => 'add_default', - 'help' => 'Which addressbook should be selected when adding a contact AND you have no add rights to the current addressbook.', - 'values' => ExecMethod('addressbook.uicontacts.get_addressbooks',EGW_ACL_ADD), - 'xmlrpc' => True, - 'admin' => False, - ); - $GLOBALS['settings']['mainscreen_showbirthdays'] = array( - 'type' => 'select', - 'label' => 'Show birthday reminders on main screen', - 'name' => 'mainscreen_showbirthdays', - 'help' => 'Displays a remider for birthdays on the startpage (page you get when you enter eGroupWare or click on the homepage icon).', - 'values' => array( - 0 => lang('No'), - 1 => lang('Yes, for today and tomorrow'), - 3 => lang('Yes, for the next three days'), - 7 => lang('Yes, for the next week'), - 14=> lang('Yes, for the next two weeks'), - ), - 'xmlrpc' => True, - 'admin' => False, - ); - $GLOBALS['settings']['no_auto_hide'] = array( - 'type' => 'check', - 'label' => 'Don\'t hide empty columns', - 'name' => 'no_auto_hide', - 'help' => 'Should the columns photo and home address always be displayed, even if they are empty.', - 'xmlrpc' => True, - 'admin' => false, - ); - // CSV Export - $GLOBALS['settings']['csv_fields'] = array( - 'type' => 'select', - 'label' => 'Fields for the CSV export', - 'name' => 'csv_fields', - 'values' => array( - 'all' => lang('All'), - 'business' => lang('Business address'), - 'home' => lang('Home address'), - ), - 'help' => 'Which fields should be exported. All means every field stored in the addressbook incl. the custom fields. The business or home address only contains name, company and the selected address.', - 'xmlrpc' => True, - 'admin' => false, - ); - $GLOBALS['settings']['csv_charset'] = array( - 'type' => 'select', - 'label' => 'Charset for the CSV export', - 'name' => 'csv_charset', - 'values' => $GLOBALS['egw']->translation->get_installed_charsets()+array('utf-8' => 'utf-8 (Unicode)'), - 'help' => 'Which charset should be used for the CSV export. The system default is the charset of this eGroupWare installation.', - 'xmlrpc' => True, - 'admin' => false, - ); - - if ($this->contact_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, - ); - } - $GLOBALS['settings']['link_title'] = array( - 'type' => 'select', - 'label' => 'Link title for contacts show', - 'name' => 'link_title', - 'values' => array( - 'n_fileas' => lang('own sorting').' ('.lang('default').': '.lang('Company').': '.lang('lastname').', '.lang('firstname').')', - 'org_name: n_family, n_given' => lang('Company').': '.lang('lastname').', '.lang('firstname'), - 'org_name, org_unit: n_family, n_given' => lang('Company').', '.lang('Department').': '.lang('lastname').', '.lang('firstname'), - 'org_name, adr_one_locality: n_family, n_given' => lang('Company').', '.lang('City').': '.lang('lastname').', '.lang('firstname'), - 'org_name, org_unit, adr_one_locality: n_family, n_given' => lang('Company').', '.lang('Department').', '.lang('City').': '.lang('lastname').', '.lang('firstname'), - ), - 'help' => 'What should links to the addressbook display in other applications. Empty values will be left out. You need to log in anew, if you change this setting!', - 'xmlrpc' => True, - 'admin' => false, - ); - $GLOBALS['settings']['addr_format'] = array( - 'type' => 'select', - 'label' => 'Default address format', - 'name' => 'addr_format', - 'values' => array( - 'postcode_city' => lang('zip code').' '.lang('City'), - 'city_state_postcode' => lang('City').' '.lang('State').' '.lang('zip code'), - ), - 'help' => 'Which address format should the addressbook use for countries it does not know the address format. If the address format of a country is known, it uses it independent of this setting.', - 'xmlrpc' => True, - 'admin' => false, - ); - $GLOBALS['settings']['hide_accounts'] = array( - 'type' => 'check', - 'label' => 'Hide accounts from addressbook', - 'name' => 'hide_accounts', - 'help' => 'Hides accounts completly from the adressbook.', - 'xmlrpc' => True, - 'admin' => false, - ); - if ($GLOBALS['egw_info']['user']['apps']['filemanager']) - { - $link = $GLOBALS['egw']->link('/index.php','menuaction=addressbook.addressbook_merge.show_replacements'); - - $GLOBALS['settings']['default_document'] = array( - 'type' => 'input', - 'size' => 60, - 'label' => 'Default document to insert contacts', - 'name' => 'default_document', - 'help' => lang('If you specify a document (full vfs path) here, addressbook displays an extra document icon for each address. That icon allows to download the specified document with the contact data inserted.').' '. - lang('The document can contain placeholder like $$n_fn$$, to be replaced with the contact data (%1full list of placeholder names%2).','','').' '. - lang('At the moment the following document-types are supported:').'*.rtf, *.txt', - 'run_lang' => false, - 'xmlrpc' => True, - 'admin' => False, - ); - $GLOBALS['settings']['document_dir'] = array( - 'type' => 'input', - 'size' => 60, - 'label' => 'Directory with documents to insert contacts', - 'name' => 'document_dir', - 'help' => lang('If you specify a directory (full vfs path) here, addressbook displays an action for each document. That action allows to download the specified document with the contact data inserted.').' '. - lang('The document can contain placeholder like $$n_fn$$, to be replaced with the contact data (%1full list of placeholder names%2).','','').' '. - lang('At the moment the following document-types are supported:').'*.rtf, *.txt', - 'run_lang' => false, - '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')).'"', - ); - } -} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.csv_export.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.csv_export.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.csv_export.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.csv_export.inc.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,133 +0,0 @@ - - * @copyright (c) 2006 by Ralf Beckersocontacts::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')
\n"; - //error_log("socontacts::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')"); - - // the nextmatch custom-filter-header country-select returns a 2 letter country-code - if (isset($filter['adr_one_countryname']) && strlen($filter['adr_one_countryname']) == 2) - { - if (!is_object($GLOBALS['egw']->country)) - { - $GLOBALS['egw']->country =& CreateObject('phpgwapi.country'); - } - $filter['adr_one_countryname'] = $GLOBALS['egw']->country->get_full_name($filter['adr_one_countryname']); - } - $backend =& $this->get_backend(null,$filter['owner']); - // single string to search for --> create so_sql conformant search criterial for the standard search columns - if ($criteria && !is_array($criteria)) - { - $op = 'OR'; - $wildcard = '%'; - $search = $criteria; - $criteria = array(); - - if ($backend === $this->somain) - { - $cols = $this->columns_to_search; - } - else - { - $cols = $this->account_cols_to_search; - } - // search the customfields only if some exist, but only for sql! - if (get_class($backend) == 'socontacts_sql' && $this->customfields) - { - $cols[] = $this->extra_value; - } - foreach($cols as $col) - { - $criteria[$col] = $search; - } - } - 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(); - } - // get the used backend for the search and call it's search method - $rows = $backend->search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count); - $this->total = $backend->total; - - if ($rows) - { - foreach($rows as $n => $row) - { - $rows[$n] = $this->db2data($row); - } - } - return $rows; - } - - /** - * Query organisations by given parameters - * - * @var array $param - * @var string $param[org_view] 'org_name', 'org_name,adr_one_location', 'org_name,org_unit' how to group - * @var int $param[owner] addressbook to search - * @var string $param[search] search pattern for org_name - * @var string $param[searchletter] letter the org_name need to start with - * @var int $param[start] - * @var int $param[num_rows] - * @var string $param[sort] ASC or DESC - * @return array or arrays with keys org_name,count and evtl. adr_one_location or org_unit - */ - function organisations($param) - { - if (!method_exists($this->somain,'organisations')) - { - $this->total = 0; - return false; - } - if ($param['search'] && !is_array($param['search'])) - { - $search = $param['search']; - $param['search'] = array(); - foreach($this->columns_to_search as $col) - { - if ($col != 'contact_value') $param['search'][$col] = $search; // we dont search the customfields - } - } - if (is_array($param['search']) && count($param['search'])) - { - $param['search'] = $this->data2db($param['search']); - } - $rows = $this->somain->organisations($param); - $this->total = $this->somain->total; - //echo "socontacts::organisations(".print_r($param,true).")
".$this->somain->db->Query_ID->sql."
'.$n.': '.$contact['n_fn']. - ($contact['org_name'] ? ' ('.$contact['org_name'].')' : '')." --> LDAP
\n"; - } - else - { - echo ''.$n.': '.$contact['n_fn']. - ($contact['org_name'] ? ' ('.$contact['org_name'].')' : '').': '.$err."
\n"; - } - } - $start += $num; - } - if ($type == 'contacts,accounts-back') // migrate the accounts to sql - { - // very worse hack, until Ralf finds a better solution - // when migrating data, we need to bind as global ldap admin account - // and not as currently logged in user - $ldap_contacts->ds = $GLOBALS['egw']->ldap->ldapConnect(); - foreach($ldap_contacts->search(false,false,'n_family,n_given','','',false,'AND', - false,array('owner' => 0)) as $contact) - { - if ($contact['jpegphoto']) // photo is NOT read by LDAP backend on search, need to do an extra read - { - $contact = $ldap_contacts->read($contact['id']); - } - unset($contact['id']); // ldap uid/account_lid - if ($contact['account_id'] && ($old = $sql_contacts->read(array('account_id' => $contact['account_id'])))) - { - $contact['id'] = $old['id']; - } - $sql_contacts->data = $contact; - - $n++; - if (!($err = $sql_contacts->save())) - { - echo ''.$n.': '.$contact['n_fn']. - ($contact['org_name'] ? ' ('.$contact['org_name'].')' : '')." --> SQL (".lang('User').")
\n"; - } - else - { - echo ''.$n.': '.$contact['n_fn']. - ($contact['org_name'] ? ' ('.$contact['org_name'].')' : '').': '.$err."
\n"; - } - } - } - } - - /** - * Get the availible distribution lists for a user - * - * @param int $required=EGW_ACL_READ required rights on the list - * @param string $extra_labels=null first labels if given (already translated) - * @return array with id => label pairs or false if backend does not support lists - */ - function get_lists($required=EGW_ACL_READ,$extra_labels=null) - { - if (!method_exists($this->somain,'get_lists')) return false; - - $uids = array(); - foreach($this->grants as $uid => $rights) - { - if ($rights & $required) - { - $uids[] = $uid; - } - } - $lists = is_array($extra_labels) ? $extra_labels : array(); - - foreach($this->somain->get_lists($uids) as $list_id => $data) - { - $lists[$list_id] = $data['list_name']; - if ($data['list_owner'] != $this->user) - { - $lists[$list_id] .= ' ('.$GLOBALS['egw']->common->grab_owner_name($data['list_owner']).')'; - } - } - //echo "socontacts_sql::get_lists($required,'$extra_label')
\n"; _debug_array($lists); - return $lists; - } - - /** - * Adds a distribution list - * - * @param string $name list-name - * @param int $owner user- or group-id - * @param array $contacts=array() contacts to add - * @return list_id or false on error - */ - function add_list($name,$owner,$contacts=array()) - { - if (!method_exists($this->somain,'add_list')) return false; - - return $this->somain->add_list($name,$owner,$contacts); - } - - /** - * Adds one contact to a distribution list - * - * @param int $contact contact_id - * @param int $list list-id - * @return false on error - */ - function add2list($contact,$list) - { - if (!method_exists($this->somain,'add2list')) return false; - - return $this->somain->add2list($contact,$list); - } - - /** - * Removes one contact from distribution list(s) - * - * @param int $contact contact_id - * @param int $list=null list-id or null to remove from all lists - * @return false on error - */ - function remove_from_list($contact,$list=null) - { - if (!method_exists($this->somain,'remove_from_list')) return false; - - return $this->somain->remove_from_list($contact,$list); - } - - /** - * Deletes a distribution list (incl. it's members) - * - * @param int/array $list list_id(s) - * @return number of members deleted or false if list does not exist - */ - function delete_list($list) - { - if (!method_exists($this->somain,'delete_list')) return false; - - return $this->somain->delete_list($list); - } - - /** - * Read data of a distribution list - * - * @param int $list list_id - * @return array of data or false if list does not exist - */ - function read_list($list) - { - if (!method_exists($this->somain,'read_list')) return false; - - return $this->somain->read_list($list); - } - - /** - * Check if distribution lists are availible for a given addressbook - * - * @param int/string $owner='' addressbook (eg. 0 = accounts), default '' = "all" addressbook (uses the main backend) - * @return boolean - */ - function lists_available($owner='') - { - $backend =& $this->get_backend(null,$owner); - - return method_exists($backend,'read_list'); - } -} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.socontacts_sql.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.socontacts_sql.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.socontacts_sql.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.socontacts_sql.inc.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,550 +0,0 @@ - - * @package addressbook - * @copyright (c) 2006 by Ralf Beckersocontacts_sql::search(".print_r($criteria,true).",".print_r($only_keys,true).",'$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')
\n"; - - $owner = isset($filter['owner']) ? $filter['owner'] : (isset($criteria['owner']) ? $criteria['owner'] : null); - - // fix cat_id filter to search in comma-separated multiple cats and return subcats - if (($cats = $filter['cat_id'])) - { - if ($filter['cat_id']{0} == '!') - { - $filter['cat_id'] = substr($filter['cat_id'],1); - $not = 'NOT'; - } - $filter[] = $this->_cat_filter((int)$filter['cat_id'],$not); - unset($filter['cat_id']); - } - - // add filter for read ACL in sql, if user is NOT the owner of the addressbook - if (isset($this->grants) && !(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 - { - if ($this->account_repository != 'sql' && $this->contact_repository != 'sql-ldap') - { - $filter[] = $this->table_name.'.contact_owner != 0'; // in case there have been accounts in sql previously - } - $filter[] = "($this->table_name.contact_owner=".(int)$GLOBALS['egw_info']['user']['account_id']. - " OR contact_private=0 AND $this->table_name.contact_owner IN (". - implode(',',array_keys($this->grants)).") OR $this->table_name.contact_owner IS NULL)"; - } - } - $search_customfields = isset($criteria['contact_value']) && !empty($criteria['contact_value']); - if (is_array($criteria)) - { - foreach($criteria as $col => $val) - { - if ($col{0} == '#') // search for a value in a certain custom field - { - unset($criteria[$col]); - $criteria[] = $this->db->expression($this->extra_table,'(',array('contact_name'=>substr($col,1),'contact_value'=>$val),')'); - $search_customfields = true; - } - elseif($col == 'cat_id') // search in comma-sep. cat-column - { - $criteria = array_merge($criteria,$this->_cat_search($val)); - unset($criteria[$col]); - } - } - } - if ($search_customfields) // search the custom-fields - { - $join .= $this->extra_join; - } - if (isset($filter['list'])) - { - $join .= " JOIN $this->ab2list_table ON $this->table_name.contact_id=$this->ab2list_table.contact_id AND list_id=".(int)$filter['list']; - unset($filter['list']); - } - if ($join) - { - switch(gettype($only_keys)) - { - case 'boolean': - // only return the egw_addressbook columns, to not generate dublicates by the left join - // and to not return the NULL for contact_{id|owner} of not found custom fields! - $only_keys = (strpos($join,$this->extra_table)!==false?'DISTINCT ':'').$this->table_name.'.'.($only_keys ? 'contact_id AS contact_id' : '*'); - break; - case 'string': - $only_keys = explode(',',$only_keys); - // fall through - case 'array': - foreach($only_keys as $key => $val) - { - switch($key) - { - case 'id': case 'contact_id': - $only_keys[$key] = $this->table_name.'.contact_id'; - break; - case 'owner': case 'contact_owner': - $only_keys[$key] = $this->table_name.'.contact_owner'; - break; - } - } - break; - } - if (isset($filter['owner'])) - { - $filter[] = $this->table_name.'.contact_owner='.(int)$filter['owner']; - unset($filter['owner']); - } - if (isset($criteria['owner'])) - { - $criteria[] = $this->table_name.'.contact_owner='.(int)$criteria['owner']; - unset($criteria['owner']); - } - // postgres requires that expressions in order by appear in the columns of a distinct select - if ($this->db->Type != 'mysql' && preg_match("/(\w+<>'')/",$order_by,$matches)) - { - if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array(); - $extra_cols[] = $matches[1]; - } - } - $rows =& parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count); - - if ($start === false) $this->total = is_array($rows) ? count($rows) : 0; // so_sql sets total only for $start !== false! - - return $rows; - } - - /** - * fix cat_id filter to search in comma-separated multiple cats and return subcats - * - * @internal - * @param int $cat_id - * @return string sql to filter by given cat - */ - function _cat_filter($cat_id, $not='') - { - if (!is_object($GLOBALS['egw']->categories)) - { - $GLOBALS['egw']->categories = CreateObject('phpgwapi.categories'); - } - foreach($GLOBALS['egw']->categories->return_all_children((int)$cat_id) as $cat) - { - $cat_filter[] = $this->db->concat("','",cat_id,"','")." $not LIKE '%,$cat,%'"; - } - $cfilter = '('.implode(' OR ',$cat_filter).')'; - if(!empty($not)) - { - $cfilter = "( $cfilter OR cat_id IS NULL )"; - } - return $cfilter; - } - - /** - * fix cat_id criteria to search in comma-separated multiple cats - * - * @internal - * @param int/array $cats - * @return array of sql-strings to be OR'ed or AND'ed together - */ - function _cat_search($cats) - { - $cat_filter = array(); - foreach(is_array($cats) ? $cats : array($cats) as $cat) - { - if (is_numeric($cat)) $cat_filter[] = $this->db->concat("','",cat_id,"','")." LIKE '%,$cat,%'"; - } - return $cat_filter; - } - - /** - * Change the ownership of contacts owned by a given account - * - * @param int $account_id account-id of the old owner - * @param int $new_owner account-id of the new owner - */ - function change_owner($account_id,$new_owner) - { - if (!$new_owner) // otherwise we would create an account (contact_owner==0) - { - die("socontacts_sql::change_owner($account_id,$new_owner) new owner must not be 0"); - } - $this->db->update($this->table_name,array( - 'contact_owner' => $new_owner, - ),array( - 'contact_owner' => $account_id, - ),__LINE__,__FILE__); - } - - /** - * Get the availible distribution lists for givens users and groups - * - * @param array $uids user or group id's - * @return array with list_id => array(list_id,list_name,list_owner,...) pairs - */ - function get_lists($uids) - { - $user = $GLOBALS['egw_info']['user']['account_id']; - $this->db->select($this->lists_table,'*',array('list_owner'=>$uids),__LINE__,__FILE__, - false,'ORDER BY list_owner<>'.(int)$GLOBALS['egw_info']['user']['account_id'].',list_name'); - - $lists = array(); - while(($row = $this->db->row(true))) - { - $lists[$row['list_id']] = $row; - } - //echo "socontacts_sql::get_lists(".print_r($uids,true).")
\n"; _debug_array($lists); - return $lists; - } - - /** - * Adds a distribution list - * - * @param string $name list-name - * @param int $owner user- or group-id - * @param array $contacts=array() contacts to add - * @return int/boolean integer list_id, true if the list already exists or false on error - */ - function add_list($name,$owner,$contacts=array()) - { - if (!$name || !(int)$owner) return false; - - if ($this->db->select($this->lists_table,'list_id',array( - 'list_name' => $name, - 'list_owner' => $owner, - ),__LINE__,__FILE__) && $this->db->next_record()) - { - return true; // return existing list-id - } - if (!$this->db->insert($this->lists_table,array( - 'list_name' => $name, - 'list_owner' => $owner, - 'list_created' => time(), - 'list_creator' => $GLOBALS['egw_info']['user']['account_id'], - ),array(),__LINE__,__FILE__)) return false; - - if ((int)($list_id = $this->db->get_last_insert_id($this->lists_table,'list_id')) && $contacts) - { - foreach($contacts as $contact) - { - $this->add2list($list_id,$contact); - } - } - return $list_id; - } - - /** - * Adds one contact to a distribution list - * - * @param int $contact contact_id - * @param int $list list-id - * @return false on error - */ - function add2list($contact,$list) - { - if (!(int)$list || !(int)$contact) return false; - - if ($this->db->select($this->ab2list_table,'list_id',array( - 'contact_id' => $contact, - 'list_id' => $list, - ),__LINE__,__FILE__) && $this->db->next_record()) - { - return true; // no need to insert it, would give sql error - } - return $this->db->insert($this->ab2list_table,array( - 'contact_id' => $contact, - 'list_id' => $list, - 'list_added' => time(), - 'list_added_by' => $GLOBALS['egw_info']['user']['account_id'], - ),array(),__LINE__,__FILE__); - } - - /** - * Removes one contact from distribution list(s) - * - * @param int $contact contact_id - * @param int $list=null list-id or null to remove from all lists - * @return false on error - */ - function remove_from_list($contact,$list=null) - { - if (!(int)$list && !is_null($list) || !(int)$contact) return false; - - $where = array( - 'contact_id' => $contact, - ); - if (!is_null($list)) $where['list_id'] = $list; - - return $this->db->delete($this->ab2list_table,$where,__LINE__,__FILE__); - } - - /** - * Deletes a distribution list (incl. it's members) - * - * @param int/array $list list_id(s) - * @return number of members deleted or false if list does not exist - */ - function delete_list($list) - { - if (!$this->db->delete($this->lists_table,array('list_id' => $list),__LINE__,__FILE__)) return false; - - $this->db->delete($this->ab2list_table,array('list_id' => $list),__LINE__,__FILE__); - - return $this->db->affected_rows(); - } - - - /** - * Read data of a distribution list - * - * @param int $list list_id - * @return array of data or false if list does not exist - */ - function read_list($list) - { - if (!$list) return false; - - $this->db->select($this->lists_table,'*',array('list_id'=>$list),__LINE__,__FILE__); - - return $this->db->row(true); - } -} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.so_ldap.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.so_ldap.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.so_ldap.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.so_ldap.inc.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,1167 +0,0 @@ - - * @author Lars Kneschkeldap_mod_add($this->ds,'$dn',array(objectClass =>".print_r($ldapContact['objectClass'],true)."))
\n"; - error_log('class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); - return $this->_error(__LINE__); - } - } - } - - // check if we need to rename the DN or need to recreate the contact - $newRDN = 'uid='. ldap::quote($contactUID); - $newDN = $newRDN .','. $baseDN; - if(strtolower($dn) != strtolower($newDN) || $needRecreation) - { - $result = ldap_read($this->ds, $dn, 'objectclass=*'); - $oldContact = ldap_get_entries($this->ds, $result); - foreach($oldContact[0] as $key => $value) - { - if(is_array($value)) - { - unset($value['count']); - $newContact[$key] = $value; - } - } - $newContact['uid'] = $contactUID; - - if(is_array($ldapContact['objectClass']) && count($ldapContact['objectClass']) > 0) - { - $newContact['objectclass'] = array_merge($newContact['objectclass'], $ldapContact['objectClass']); - } - - if(!ldap_delete($this->ds, $dn)) - { - error_log('class.so_ldap.inc.php ('. __LINE__ .') delete of old '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); - return $this->_error(__LINE__); - } - if(!@ldap_add($this->ds, $newDN, $newContact)) - { - //echo "recreate: ldap_add($this->ds,'$newDN',".print_r($newContact,true).")
\n"; - //print 'class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')';_debug_array($newContact);exit; - error_log('class.so_ldap.inc.php ('. __LINE__ .') re-create contact as '. $newDN .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); - error_log(print_r($newContact,true)); - return $this->_error(__LINE__); - } - $dn = $newDN; - } - unset($ldapContact['objectClass']); - - if (!@ldap_modify($this->ds, $dn, $ldapContact)) - { - //echo "ldap_modify($this->ds,'$dn',".print_r($ldapContact,true).")
\n"; - error_log('class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); - error_log(print_r($ldapContact,true)); - return $this->_error(__LINE__); - } - } - else - { - $dn = 'uid='. ldap::quote($ldapContact['uid']) .','. $baseDN; - - if (!@ldap_add($this->ds, $dn, $ldapContact)) - { - //echo "ldap_add($this->ds,'$dn',".print_r($ldapContact,true).")
\n"; - error_log('class.so_ldap.inc.php ('. __LINE__ .') add of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')'); - error_log(print_r($ldapContact,true)); - return $this->_error(__LINE__); - } - } - return 0; // Ok, no error - } - - /** - * deletes row representing keys in internal data or the supplied $keys if != null - * - * @param array $keys if given array with col => value pairs to characterise the rows to delete - * @return int affected rows, should be 1 if ok, 0 if an error - */ - function delete($keys=null) - { - // single entry - if($keys[$this->contacts_id]) $keys = array( 0 => $keys); - - if(!is_array($keys)) - { - $keys = array( $keys); - } - - $ret = 0; - - $attributes = array('dn'); - - foreach($keys as $entry) - { - $entry = ldap::quote($entry); - if($result = ldap_search($this->ds, $GLOBALS['egw_info']['server']['ldap_contact_context'], - "(|(entryUUID=$entry)(uid=$entry))", $attributes)) - { - $contactInfo = ldap_get_entries($this->ds, $result); - if(@ldap_delete($this->ds, $contactInfo[0]['dn'])) - { - $ret++; - } - } - } - return $ret; - } - - /** - * 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 &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false) - { - //_debug_array($criteria); print "OrderBY: $order_by";_debug_array($extra_cols);_debug_array($filter); - #$order_by = explode(',',$order_by); - #$order_by = explode(' ',$order_by); - #$sort = $order_by[0]; - #$order = $order_by[1]; - #$query = $criteria; - #$fields = $only_keys ? ($only_keys === true ? $this->contacts_id : $only_keys) : ''; - #$limit = $need_full_no_count ? 0 : $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs']; - #return parent::read($start,$limit,$fields,$query,$filter,$sort,$order); - - if((int)$filter['owner']) - { - if (!($accountName = $GLOBALS['egw']->accounts->id2name($filter['owner']))) return false; - - $searchDN = 'cn='. ldap::quote(strtolower($accountName)) .','; - - if ($filter['owner'] < 0) - { - $searchDN .= $this->sharedContactsDN; - $addressbookType = ADDRESSBOOK_GROUP; - } - else - { - $searchDN .= $this->personalContactsDN; - $addressbookType = ADDRESSBOOK_PERSONAL; - } - } - elseif (!isset($filter['owner'])) - { - $searchDN = $GLOBALS['egw_info']['server']['ldap_contact_context']; - $addressbookType = ADDRESSBOOK_ALL; - } - else - { - $searchDN = $GLOBALS['egw_info']['server']['ldap_context']; - $addressbookType = ADDRESSBOOK_ACCOUNTS; - } - - // create the search filter - switch($addressbookType) - { - case ADDRESSBOOK_ALL: - $objectFilter = '(|(objectclass=inetorgperson)(objectclass=posixaccount))'; - break; - case ADDRESSBOOK_ACCOUNTS: - $objectFilter = '(objectclass=posixaccount)'; - break; - default: - $objectFilter = '(objectclass=inetorgperson)'; - break; - } - - $searchFilter = ''; - if(is_array($criteria) && count($criteria) > 0) - { - $wildcard = $wildcard === '%' ? '*' : ''; - $searchFilter = ''; - foreach($criteria as $egwSearchKey => $searchValue) - { - foreach($this->schema2egw as $mapping) - { - if(($ldapSearchKey = $mapping[$egwSearchKey])) - { - $searchString = $GLOBALS['egw']->translation->convert($searchValue,$this->charset,'utf-8'); - $searchFilter .= '('.$ldapSearchKey.'='.$wildcard.ldap::quote($searchString).$wildcard.')'; - break; - } - } - } - if($op == 'AND') - { - $searchFilter = "(&$searchFilter)"; - } - else - { - $searchFilter = "(|$searchFilter)"; - } - } - $colFilter = $this->_colFilter($filter); - $ldapFilter = "(&$objectFilter$searchFilter$colFilter)"; - - if (!($rows = $this->_searchLDAP($searchDN, $ldapFilter, $this->all_attributes, $addressbookType))) - { - return $rows; - } - if ($order_by) - { - $order = array(); - $sort = 'ASC'; - foreach(explode(',',$order_by) as $o) - { - if (substr($o,-4) == ' ASC') - { - $sort = 'ASC'; - $order[] = substr($o,0,-4); - } - elseif (substr($o,-5) == ' DESC') - { - $sort = 'DESC'; - $order[] = substr($o,0,-5); - } - elseif ($o) - { - $order[] = $o; - } - } - $rows = ExecMethod2('phpgwapi.arrayfunctions.arfsort',$rows,$order,$sort); - } - // if requested ($start !== false) return only limited resultset - if (is_array($start)) - { - list($start,$offset) = $start; - } - if(is_numeric($start) && is_numeric($offset)) - { - return array_slice($rows, $start, $offset); - } - elseif(is_numeric($start)) - { - return array_slice($rows, $start, $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs']); - } - return $rows; - } - - /** - * Process so_sql like filters (at the moment only a subset used by the addressbook UI - * - * @param array $filter col-name => value pairs or just sql strings - * @return string ldap filter - */ - function _colFilter($filter) - { - if (!is_array($filter)) return ''; - - $filters = ''; - foreach($filter as $key => $value) - { - if ($key != 'cat_id' && $key != 'account_id' && !$value) continue; - - switch((string) $key) - { - case 'owner': // already handled - case 'tid': // ignored - break; - - case 'account_id': - if (is_null($value)) - { - $filters .= '(!(uidNumber=*))'; - } - elseif ($value) - { - $filters .= '(uidNumber='.ldap::quote($value).')'; - - } - break; - - case 'cat_id': - if (is_null($value)) - { - $filters .= '(!(category=*))'; - } - elseif((int)$value) - { - if (!is_object($GLOBALS['egw']->categories)) - { - $GLOBALS['egw']->categories = CreateObject('phpgwapi.categories'); - } - $cats = $GLOBALS['egw']->categories->return_all_children((int)$value); - if (count($cats) > 1) $filters .= '(|'; - foreach($cats as $cat) - { - $catName = $GLOBALS['egw']->translation->convert( - $GLOBALS['egw']->categories->id2name($cat),$this->charset,'utf-8'); - $filters .= '(category='.ldap::quote($catName).')'; - } - if (count($cats) > 1) $filters .= ')'; - } - break; - - default: - if (!is_int($key)) - { - foreach($this->schema2egw as $mapping) - { - if (isset($mapping[$key])) - { - // todo: value = "!''" - $filters .= '('.$mapping[$key].'='.($value === "!''" ? '*' : - ldap::quote($GLOBALS['egw']->translation->convert($value,$this->charset,'utf-8'))).')'; - break; - } - } - } - // filter for letter-search - elseif (preg_match("/^([^ ]+) LIKE '(.*)%'$/",$value,$matches)) - { - foreach($this->schema2egw as $mapping) - { - if (isset($mapping[$matches[1]])) - { - $filters .= '('.$mapping[$matches[1]].'='.ldap::quote( - $GLOBALS['egw']->translation->convert($matches[2],$this->charset,'utf-8')).'*)'; - break; - } - } - } - break; - } - } - return $filters; - } - - /** - * Perform the actual ldap-search, retrieve and convert all entries - * - * Used be read and search - * - * @internal - * @param string $_ldapContext - * @param string $_filter - * @param array $_attributes - * @param int $_addressbooktype - * @return array/boolean with eGW contacts or false on error - */ - function _searchLDAP($_ldapContext, $_filter, $_attributes, $_addressbooktype) - { - $this->total = 0; - - $_attributes[] = 'entryUUID'; - $_attributes[] = 'uid'; - $_attributes[] = 'uidNumber'; - $_attributes[] = 'objectClass'; - $_attributes[] = 'createTimestamp'; - $_attributes[] = 'modifyTimestamp'; - $_attributes[] = 'creatorsName'; - $_attributes[] = 'modifiersName'; - - //echo "ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit)
\n"; - if($_addressbooktype == ADDRESSBOOK_ALL) - { - $result = ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit); - } - else - { - $result = @ldap_list($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit); - } - if(!$result) return array(); - - $entries = ldap_get_entries($this->ds, $result); - $this->total = $entries['count']; - foreach($entries as $i => $entry) - { - if (!is_int($i)) continue; // eg. count - - $contact = array( - 'id' => $entry['uid'][0] ? $entry['uid'][0] : $entry['entryuuid'][0], - 'tid' => 'n', // the type id for the addressbook - ); - foreach($entry['objectclass'] as $ii => $objectclass) - { - $objectclass = strtolower($objectclass); - if (!is_int($ii) || !isset($this->schema2egw[$objectclass])) - { - continue; // eg. count or unsupported objectclass - } - foreach($this->schema2egw[$objectclass] as $egwFieldName => $ldapFieldName) - { - if(!empty($entry[$ldapFieldName][0]) && !isset($contact[$egwFieldName])) - { - $contact[$egwFieldName] = $GLOBALS['egw']->translation->convert($entry[$ldapFieldName][0],'utf-8'); - } - } - $objectclass2egw = '_'.$objectclass.'2egw'; - if (method_exists($this,$objectclass2egw)) - { - $this->$objectclass2egw($contact,$entry); - } - } - // read binary jpegphoto only for one result == call by read - if ($this->total == 1 && isset($entry['jpegphoto'][0])) - { - $bin = ldap_get_values_len($this->ds,ldap_first_entry($this->ds,$result),'jpegphoto'); - $contact['jpegphoto'] = $bin[0]; - } - if(preg_match('/cn=([^,]+),'.preg_quote($this->personalContactsDN,'/').'$/i',$entry['dn'],$matches)) - { - // personal addressbook - $contact['owner'] = $GLOBALS['egw']->accounts->name2id($matches[1],'account_lid','u'); - $contact['private'] = 1; - } - elseif(preg_match('/cn=([^,]+),'.preg_quote($this->sharedContactsDN,'/').'$/i',$entry['dn'],$matches)) - { - // group addressbook - $contact['owner'] = $GLOBALS['egw']->accounts->name2id($matches[1],'account_lid','g'); - $contact['private'] = 0; - } - else - { - // accounts - $contact['owner'] = 0; - $contact['private'] = 0; - } - /* - * this piece of code does not work, as the call accounts->name2id is wrong - foreach(array( - 'creatorsname' => 'creator', - 'modifiersname' => 'modifier', - ) as $ldapFieldName => $egwFieldName) - { - if (!empty($entry[$ldapFieldName][0]) && preg_match('/^cn=([^,]+),/',$entry[$ldapFieldName][0],$matches)) - { - $contact[$egwFieldName] = $GLOBALS['egw']->accounts->name2id($matches[1],'u'); - } - } - */ - foreach(array( - 'createtimestamp' => 'created', - 'modifytimestamp' => 'modified', - ) as $ldapFieldName => $egwFieldName) - { - if(!empty($entry[$ldapFieldName][0])) - { - $contact[$egwFieldName] = $this->_ldap2ts($entry[$ldapFieldName][0]); - } - } - $contacts[] = $contact; - } - return $contacts; - } - - /** - * Creates a timestamp from the date returned by the ldap server - * - * @internal - * @param string $date YYYYmmddHHiiss - * @return int - */ - function _ldap2ts($date) - { - return gmmktime(substr($date,8,2),substr($date,10,2),substr($date,12,2), - substr($date,4,2),substr($date,6,2),substr($date,0,4)); - } - - /** - * check if $baseDN exists. If not create it - * - * @param string $baseDN cn=xxx,ou=yyy,ou=contacts,$GLOBALS['egw_info']['server']['ldap_contact_context'] - * @return boolean/string false on success or string with error-message - */ - function _check_create_dn($baseDN) - { - // check if $baseDN exists. If not create new one - if(@ldap_read($this->ds, $baseDN, 'objectclass=*')) - { - return false; - } - if(ldap_errno($this->ds) != 32 || substr($baseDN,0,3) != 'cn=') - { - return $this->_error(__LINE__); // baseDN does NOT exist and we cant/wont create it - } - // create a admin connection to add the needed DN - $adminLDAP =& new ldap; - $adminDS = $adminLDAP->ldapConnect(); - - list(,$ou) = explode(',',$baseDN); - foreach(array( - 'ou=contacts,'.$GLOBALS['egw_info']['server']['ldap_contact_context'], - $ou.',ou=contacts,'.$GLOBALS['egw_info']['server']['ldap_contact_context'], - $baseDN, - ) as $dn) - { - if (!@ldap_read($this->ds, $dn, 'objectclass=*') && ldap_errno($this->ds) == 32) - { - // entry does not exist, lets try to create it - list($top) = explode(',',$dn); - list($var,$val) = explode('=',$top); - $data = array( - 'objectClass' => $var == 'cn' ? 'organizationalRole' : 'organizationalUnit', - $var => $val, - ); - if(!@ldap_add($adminDS, $dn, $data)) - { - //echo "ldap_add($adminDS,'$dn',".print_r($data,true).")
\n"; - $err = $this->_error(__LINE__,$adminDS); - $adminLDAP->ldapDisconnect(); - return $err; - } - } - } - $adminLDAP->ldapDisconnect(); - - return false; - } - - /** - * error message for failed ldap operation - * - * @param int $line - * @return string - */ - function _error($line,$ds=null) - { - return ldap_error($ds ? $ds : $this->ds).': so_ldap: '.$line; - } - - /** - * Special handling for mapping of eGW contact-data to the evolutionPerson objectclass - * - * Please note: all regular fields are already copied! - * - * @internal - * @param array &$ldapContact already copied fields according to the mapping - * @param array $data eGW contact data - * @param boolean $isUpdate - */ - function _egw2evolutionperson(&$ldapContact,$data,$isUpdate) - { - if(!empty($data['cat_id'])) - { - $ldapContact['category'] = array(); - foreach(is_array($data['cat_id']) ? $data['cat_id'] : explode(',',$data['cat_id']) as $cat) - { - $ldapContact['category'][] = $GLOBALS['egw']->translation->convert( - ExecMethod('phpgwapi.categories.id2name',$cat),$this->charset,'utf-8'); - } - } - foreach(array( - 'postaladdress' => $data['adr_one_street'] .'$'. $data['adr_one_locality'] .', '. $data['adr_one_region'] .'$'. $data['adr_one_postalcode'] .'$$'. $data['adr_one_countryname'], - 'homepostaladdress' => $data['adr_two_street'] .'$'. $data['adr_two_locality'] .', '. $data['adr_two_region'] .'$'. $data['adr_two_postalcode'] .'$$'. $data['adr_two_countryname'], - ) as $attr => $value) - { - if($value != '$, $$$') - { - $ldapContact[$attr] = $GLOBALS['egw']->translation->convert($value,$this->charset,'utf-8'); - } - elseif($isUpdate) - { - $ldapContact[$attr] = array(); - } - } - // save the phone number of the primary contact and not the eGW internal field-name - if ($data['tel_prefer'] && $data[$data['tel_prefer']]) - { - $ldapContact['primaryphone'] = $data[$data['tel_prefer']]; - } - elseif($isUpdate) - { - $ldapContact['primaryphone'] = array(); - } - } - - /** - * Special handling for mapping data of the evolutionPerson objectclass to eGW contact - * - * Please note: all regular fields are already copied! - * - * @internal - * @param array &$contact already copied fields according to the mapping - * @param array $data eGW contact data - */ - function _evolutionperson2egw(&$contact,$data) - { - if ($data['category'] && is_array($data['category'])) - { - $contact['cat_id'] = array(); - foreach($data['category'] as $iii => $cat) - { - if (!is_int($iii)) continue; - - $contact['cat_id'][] = ExecMethod('phpgwapi.categories.name2id',$cat); - } - if ($contact['cat_id']) $contact['cat_id'] = implode(',',$contact['cat_id']); - } - if ($data['primaryphone']) - { - unset($contact['tel_prefer']); // to not find itself - $contact['tel_prefer'] = array_search($data['primaryphone'][0],$contact); - } - } - - /** - * Special handling for mapping data of the inetOrgPerson objectclass to eGW contact - * - * Please note: all regular fields are already copied! - * - * @internal - * @param array &$contact already copied fields according to the mapping - * @param array $data eGW contact data - */ - function _inetorgperson2egw(&$contact,$data) - { - if(empty($data['givenname'][0])) - { - $parts = explode($data['sn'][0], $data['cn'][0]); - $contact['n_prefix'] = trim($parts[0]); - $contact['n_suffix'] = trim($parts[1]); - } - else - { - $parts = preg_split('/'. preg_quote($data['givenname'][0],'/') .'.*'. preg_quote($data['sn'][0],'/') .'/', $data['cn'][0]); - $contact['n_prefix'] = trim($parts[0]); - $contact['n_suffix'] = trim($parts[1]); - if(preg_match('/'. preg_quote($data['givenname'][0],'/') .' (.*) '. preg_quote($data['sn'][0],'/') .'/',$data['cn'][0], $matches)) - { - $contact['n_middle'] = $matches[1]; - } - } - } - - /** - * Special handling for mapping data of the mozillaAbPersonAlpha objectclass to eGW contact - * - * Please note: all regular fields are already copied! - * - * @internal - * @param array &$contact already copied fields according to the mapping - * @param array $data eGW contact data - */ - function _mozillaabpersonalpha2egw(&$contact,$data) - { - if ($data['c']) - { - $contact['adr_one_countryname'] = ExecMethod('phpgwapi.country.get_full_name',$data['c'][0]); - } - } - - /** - * Special handling for mapping of eGW contact-data to the mozillaAbPersonAlpha objectclass - * - * Please note: all regular fields are already copied! - * - * @internal - * @param array &$ldapContact already copied fields according to the mapping - * @param array $data eGW contact data - * @param boolean $isUpdate - */ - function _egw2mozillaabpersonalpha(&$ldapContact,$data,$isUpdate) - { - if ($data['adr_one_countryname']) - { - $ldapContact['c'] = ExecMethod('phpgwapi.country.country_code',$data['adr_one_countryname']); - } - elseif ($isUpdate) - { - $ldapContact['c'] = array(); - } - } - - /** - * Special handling for mapping data of the mozillaOrgPerson objectclass to eGW contact - * - * Please note: all regular fields are already copied! - * - * @internal - * @param array &$contact already copied fields according to the mapping - * @param array $data eGW contact data - */ - function _mozillaorgperson2egw(&$contact,$data) - { - if ($data['c'] && strlen($contact['adr_one_countryname']) <= 2) // dont overwrite a set human readable name - { - $contact['adr_one_countryname'] = ExecMethod('phpgwapi.country.get_full_name',$data['c'][0]); - } - } - - /** - * Special handling for mapping of eGW contact-data to the mozillaOrgPerson objectclass - * - * Please note: all regular fields are already copied! - * - * @internal - * @param array &$ldapContact already copied fields according to the mapping - * @param array $data eGW contact data - * @param boolean $isUpdate - */ - function _egw2mozillaorgperson(&$ldapContact,$data,$isUpdate) - { - if ($data['adr_one_countryname']) - { - $ldapContact['c'] = ExecMethod('phpgwapi.country.country_code',$data['adr_one_countryname']); - } - elseif ($isUpdate) - { - $ldapContact['c'] = array(); - } - } - - /** - * Change the ownership of contacts owned by a given account - * - * @param int $account_id account-id of the old owner - * @param int $new_owner account-id of the new owner - */ - function change_owner($account_id,$new_owner) - { - error_log("so_ldap::change_owner($account_id,$new_owner) not yet implemented"); - } -} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.uicontacts.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.uicontacts.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.uicontacts.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.uicontacts.inc.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,1955 +0,0 @@ - - * @author Ralf Beckeruicontacts::index(".print_r($content,true).",'$msg')
\n"; - if (($re_submit = is_array($content))) - { - $do_email = $content['do_email']; - - 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 (isset($content['nm']['rows']['document'])) // handle insert in default document button like an action - { - list($id) = @each($content['nm']['rows']['document']); - $content['action'] = 'document'; - $content['nm']['rows']['checked'] = array($id); - } - if ($content['action'] !== '') - { - if (!count($content['nm']['rows']['checked']) && !$content['use_all'] && $content['action'] != 'delete_list') - { - $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,$content['do_email'] ? 'email' : 'index',$msg)) - { - $msg .= lang('%1 contact(s) %2',$success,$action_msg); - } - elseif(is_null($msg)) - { - $msg .= lang('%1 contact(s) %2, %3 failed because of insufficent rights !!!',$success,$action_msg,$failed); - } - } - } - if ($content['nm']['rows']['infolog']) - { - list($org) = each($content['nm']['rows']['infolog']); - return $this->infolog_org_view($org); - } - if ($content['nm']['rows']['view']) // show all contacts of an organisation - { - list($org_view) = each($content['nm']['rows']['view']); - } - else - { - $org_view = $content['nm']['org_view']; - } - if ($content['nm']['col_filter']['tid']) - { - $typeselection=$content['nm']['col_filter']['tid'] ; - } else { - $typeselection='n'; - } - } - elseif($_GET['add_list']) - { - $list = $this->add_list($_GET['add_list'],$_GET['owner']?$_GET['owner']:$this->user); - if ($list === true) - { - $msg = lang('List already exists!'); - } - elseif ($list) - { - $msg = lang('List created'); - } - else - { - $msg = lang('List creation failed, no rights!'); - } - } - $preserv = array( - 'do_email' => $do_email, - ); - $to = $content['nm']['to']; - $content = array( - 'msg' => $msg ? $msg : $_GET['msg'], - ); - $content['nm'] = $GLOBALS['egw']->session->appsession($do_email ? 'email' : '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' - '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' => '', // IO category, if not 'no_cat' => True - 'options-cat_id' => array(lang('none')), - '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' => lang('Addressbook'), // I label for filter (optional) - 'filter' => '', // =All // 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_label' => lang('Distribution lists'), // IO filter2, if not 'no_filter2' => True - 'filter2' => '', // IO filter2, if not 'no_filter2' => True - 'filter2_no_lang'=> True, // I set no_lang for filter2 (=dont translate the options) - 'lettersearch' => true, - 'do_email' => $do_email, - 'default_cols' => '!cat_id,contact_created_contact_modified', - 'filter2_onchange' => "if(this.value=='add') { add_new_list(document.getElementById(form::name('filter')).value); this.value='';} else this.form.submit();", - 'manual' => $do_email ? ' ' : false, // space for the manual icon - ); - if ($do_email) - { - $content['nm']['filter2_onchange'] = str_replace('this.form.submit();', - "{ if (this.value && confirm('Add business email of whole distribution list?')) add_whole_list(this.value); else this.form.submit(); }", - $content['nm']['filter2_onchange']); - } - // use the state of the last session stored in the user prefs - if (($state = @unserialize($this->prefs[$do_email ? 'email_state' : 'index_state']))) - { - $content['nm'] = array_merge($content['nm'],$state); - } - } - if ($this->lists_available()) - { - $sel_options['filter2'] = $this->get_lists(EGW_ACL_READ,array('' => lang('none'))); - $sel_options['filter2']['add'] = lang('Add a new list').'...'; // put it at the end - } - if ($do_email) - { - if (!$re_submit) - { - $content['nm']['to'] = 'to'; - $content['nm']['search'] = '@'; - } - else - { - $content['nm']['to'] = $to; - } - $content['nm']['header_left'] = 'addressbook.email.left'; - } - // Organisation stuff is not (yet) availible with ldap - elseif($GLOBALS['egw_info']['server']['contact_repository'] != 'ldap') - { - $content['nm']['header_left'] = 'addressbook.index.left'; - } - $sel_options['filter'] = $this->get_addressbooks(EGW_ACL_READ,lang('All')); - $sel_options['to'] = array( - 'to' => 'To', - 'cc' => 'Cc', - 'bcc' => 'Bcc', - ); - $sel_options['action'] = array(); - if ($do_email) - { - $GLOBALS['egw_info']['flags']['include_xajax'] = true; - $sel_options['action'] = array( - 'email' => lang('Add %1',lang('business email')), - 'email_home' => lang('Add %1',lang('home email')), - ); - } - $sel_options['action'] += array( - 'delete' => lang('Delete'), - 'csv' => lang('Export as CSV'), - 'vcard' => lang('Export as VCard'), // ToDo: move this to importexport framework - 'merge' => lang('Merge into first or account, deletes all other!'), - ); - if ($GLOBALS['egw_info']['user']['apps']['infolog']) - { - $sel_options['action']['infolog'] = lang('View linked InfoLog entries'); - } - //$sel_options['action'] += $this->get_addressbooks(EGW_ACL_ADD); - foreach($this->get_addressbooks(EGW_ACL_ADD) as $uid => $label) - { - $sel_options['action'][$uid] = lang('Move to addressbook:').' '.$label; - } - if (($add_lists = $this->get_lists(EGW_ACL_EDIT))) // do we have distribution lists? - { - foreach ($add_lists as $list_id => $label) - { - $sel_options['action']['to_list_'.$list_id] = lang('Add to distribution list:').' '.$label; - } - $sel_options['action']['remove_from_list'] = lang('Remove selected contacts from distribution list'); - $sel_options['action']['delete_list'] = lang('Delete selected distribution list!'); - } - if ($this->prefs['document_dir']) - { - $sel_options['action'] += $this->get_document_actions(); - } - if (!array_key_exists('importexport',$GLOBALS['egw_info']['user']['apps'])) unset($sel_options['action']['export']); - - // dont show tid-selection if we have only one content_type - if (count($this->content_types) <= 1) - { - $content['nm']['col_filter']['tid'] = 'n'; - $content['nm']['header_right'] = 'addressbook.index.right_add'; - } - else - { - $content['nm']['col_filter']['tid'] = ($typeselection ? $typeselection : 'n'); - $content['nm']['header_right'] = 'addressbook.index.right'; - foreach($this->content_types as $tid => $data) - { - $sel_options['col_filter[tid]'][$tid] = $data['name']; - } - } - // get the availible org-views plus the label of the contacts view of one org - $sel_options['org_view'] = $this->org_views; - if (isset($org_view)) $content['nm']['org_view'] = $org_view; - if (!isset($sel_options['org_view'][(string) $content['nm']['org_view']])) - { - $org_name = array(); - foreach(explode('|||',$content['nm']['org_view']) as $part) - { - list(,$name) = explode(':',$part,2); - if ($name) $org_name[] = $name; - } - $org_name = implode(': ',$org_name); - $sel_options['org_view'][(string) $content['nm']['org_view']] = $org_name; - } - $content['nm']['org_view_label'] = $sel_options['org_view'][(string) $content['nm']['org_view']]; - - $this->tmpl->read(/*$do_email ? 'addressbook.email' :*/ 'addressbook.index'); - return $this->tmpl->exec($do_email ? 'addressbook.uicontacts.emailpopup' : 'addressbook.uicontacts.index', - $content,$sel_options,$readonlys,$preserv,$do_email ? 2 : 0); - } - - /** - * Email address-selection popup - * - * @param array $content=null submitted content - * @param string $msg=null message to show - */ - function emailpopup($content=null,$msg=null) - { - if (strpos($GLOBALS['egw_info']['flags']['java_script'],'addEmail') === false) - { - if ($_GET['compat']) // 1.2 felamimail or old email - { - $handler = "if (opener.document.doit[to].value != '') - { - opener.document.doit[to].value += ','; - } - opener.document.doit[to].value += email"; - } - else // 1.3+ felamimail - { - $handler = 'opener.addEmail(to,email)'; - } - $GLOBALS['egw_info']['flags']['java_script'].= " - -"; - } - return $this->index($content,$msg,true); - } - - /** - * Show the infologs of an whole organisation - * - * @param string $org - */ - function infolog_org_view($org) - { - $query = $GLOBALS['egw']->session->appsession('index','addressbook'); - $query['num_rows'] = -1; // all - $query['org_view'] = $org; - $query['searchletter'] = ''; - $this->get_rows($query,$checked,$readonlys,true); // true = only return the id's - - if (count($checked) > 1) // use a nicely formatted org-name as title in infolog - { - $parts = array(); - foreach(explode('|||',$org) as $part) - { - list(,$part) = explode(':',$part,2); - if ($part) $parts[] = $part; - } - $org = implode(', ',$parts); - } - else - { - $org = ''; // use infolog default of link-title - } - $GLOBALS['egw']->redirect_link('/index.php',array( - 'menuaction' => 'infolog.uiinfolog.index', - 'action' => 'addressbook', - 'action_id' => implode(',',$checked), - 'action_title' => $org, - )); - } - - function ajax_add_whole_list($list) - { - $query = $GLOBALS['egw']->session->appsession('email','addressbook'); - $query['filter2'] = (int)$list; - $action_msg = lang('%1 added',lang('Business email')); - $this->action('email',array(),true,$success,$failed,$action_msg,$query,$msg); - - $response =& new xajaxResponse(); - - if ($success) $response->addScript($GLOBALS['egw']->js->body['onLoad']); - - // close window only if no errors AND something added - if ($failed || !$success) - { - if (!$msg) $msg = $failed ? lang('%1 contact(s) %2, %3 failed because of insufficent rights !!!',$success,$action_msg,$failed) : - lang('%1 contact(s) %2',$success,$action_msg); - - $response->addScript("alert('".addslashes($msg)."')"); - // reset the filter - $response->addScript("document.getElementById('exec[nm][filter2]').value='';"); - } - else - { - $response->addScript('window.close();'); - } - return $response->getXML(); - } - - /** - * 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' - * @param string/array $session_name 'index' or 'email', or array with session-data depending if we are in the main list or the popup - * @return boolean true if all actions succeded, false otherwise - */ - function action($action,$checked,$use_all,&$success,&$failed,&$action_msg,$session_name,&$msg) - { - //echo "uicontacts::action('$action',".print_r($checked,true).','.(int)$use_all.",...)
\n"; - $success = $failed = 0; - - if ($use_all || in_array($action,array('remove_from_list','delete_list'))) - { - // get the whole selection - $query = is_array($session_name) ? $session_name : $GLOBALS['egw']->session->appsession($session_name,'addressbook'); - - if ($use_all) - { - @set_time_limit(0); // switch off the execution time limit, as it's for big selections to small - $query['num_rows'] = -1; // all - $this->get_rows($query,$checked,$readonlys,true); // true = only return the id's - } - } - // replace org_name:* id's with all id's of that org - $org_contacts = array(); - foreach((array)$checked as $n => $id) - { - if (substr($id,0,9) == 'org_name:') - { - if (count($checked) == 1 && !count($org_contacts) && $action == 'infolog') - { - return $this->infolog_org_view($id); // uses the org-name, instead of 'selected contacts' - } - unset($checked[$n]); - $query = $GLOBALS['egw']->session->appsession($session_name,'addressbook'); - $query['num_rows'] = -1; // all - $query['org_view'] = $id; - unset($query['filter2']); - $this->get_rows($query,$extra,$readonlys,true); // true = only return the id's - if ($extra[0]) $org_contacts = array_merge($org_contacts,$extra); - } - } - if ($org_contacts) $checked = array_unique($checked ? array_merge($checked,$org_contacts) : $org_contacts); - //_debug_array($checked); exit; - - if (substr($action,0,7) == 'to_list') - { - $to_list = (int)substr($action,8); - $action = 'to_list'; - } - if (substr($action,0,9) == 'document-') - { - $document = substr($action,9); - $action = 'document'; - } - // Security: stop non-admins to export more then the configured number of contacts - if (in_array($action,array('csv','vcard')) && (int)$this->config['contact_export_limit'] && - !isset($GLOBALS['egw_info']['user']['apps']['admin']) && count($checked) > $this->config['contact_export_limit']) - { - $action_msg = lang('exported'); - $failed = count($checked); - return false; - } - switch($action) - { - case 'csv': - $action_msg = lang('exported'); - $csv_export =& CreateObject('addressbook.csv_export',$this,$this->prefs['csv_charset']); - switch ($this->prefs['csv_fields']) - { - case 'business': - $fields = $this->business_contact_fields; - break; - case 'home': - $fields = $this->home_contact_fields; - break; - default: - $fields = $this->contact_fields; - foreach($this->customfields as $name => $data) - { - $fields['#'.$name] = $data['label']; - } - break; - } - $csv_export->export($checked,$fields); - // does not return! - $Ok = true; - break; - - case 'vcard': - $action_msg = lang('exported'); - ExecMethod('addressbook.vcaladdressbook.export',$checked); - // does not return! - $Ok = false; - break; - - case 'infolog': - $GLOBALS['egw']->redirect_link('/index.php',array( - 'menuaction' => 'infolog.uiinfolog.index', - 'action' => 'addressbook', - 'action_id' => implode(',',$checked), - 'action_title' => count($checked) > 1 ? lang('selected contacts') : '', - )); - break; - - case 'merge': - $success = $this->merge($checked,$error_msg); - $failed = count($checked) - (int)$success; - $action_msg = lang('merged'); - $checked = array(); // to not start the single actions - break; - - case 'delete_list': - if (!$query['filter2']) - { - $msg = lang('You need to select a distribution list'); - } - elseif($this->delete_list($query['filter2']) === false) - { - $msg = lang('Insufficent rights to delete this list!'); - } - else - { - $msg = lang('Distribution list deleted'); - unset($query['filter2']); - $GLOBALS['egw']->session->appsession($session_name,'addressbook',$query); - } - return false; - - case 'document': - $msg = $this->download_document($checked,$document); - return false; - } - 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); - } - // delete single account --> redirect to admin - elseif (count($checked) == 1 && $contact['account_id']) - { - $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 'email': - case 'email_home': - $action_msg = lang('%1 added',$action=='email'?lang('Business email') : lang('Home email')); - if (($Ok = !!($contact = $this->read($id)) && strpos($contact[$action],'@') !== false)) - { - if(!@is_object($GLOBALS['egw']->js)) $GLOBALS['egw']->js =& CreateObject('phpgwapi.javascript'); - - $GLOBALS['egw']->js->set_onload("addEmail('".addslashes( - $contact['n_fn'] ? $contact['n_fn'].' <'.$contact[$action].'>' : $contact[$action])."');"); - } - break; - - case 'remove_from_list': - $action_msg = lang('removed from distribution list'); - if (!$query['filter2']) - { - $msg = lang('You need to select a distribution list'); - return false; - } - else - { - $Ok = $this->remove_from_list($id,$query['filter2']) !== false; - } - break; - - case 'to_list': - $action_msg = lang('added to distribution list'); - if (!$to_list) - { - $msg = lang('You need to select a distribution list'); - return false; - } - else - { - $Ok = $this->add2list($id,$to_list) !== false; - } - break; - - default: // move to an other addressbook - if (!(int)$action || !($this->grants[(string) (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'] != (int)$action || $contact['private'] != (int)(substr($action,-1) == 'p')) - { - $contact['owner'] = (int) $action; - $contact['private'] = (int)(substr($action,-1) == 'p'); - $Ok = $this->save($contact); - } - } - break; - } - if ($Ok) - { - ++$success; - } - elseif ($action != 'email' && $action != 'email_home') - { - ++$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 boolean $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) - { - $do_email = $query['do_email']; - $old_state = $GLOBALS['egw']->session->appsession($do_email ? 'email' : 'index','addressbook'); - if (!isset($this->org_views[(string) $query['org_view']])) // we dont have an org view, unset the according col_filters - { - if (isset($query['col_filter']['org_name'])) unset($query['col_filter']['org_name']); - if (isset($query['col_filter']['adr_one_locality'])) unset($query['col_filter']['adr_one_locality']); - if (isset($query['col_filter']['org_unit'])) unset($query['col_filter']['org_unit']); - } - if (isset($this->org_views[(string) $query['org_view']])) // we have an org view, reset the advanced search - { - if (is_array($query['search'])) unset($query['search']); - unset($query['advanced_search']); - } - elseif(!$query['search'] && $old_state['advanced_search']) // eg. paging in an advanced search - { - $query['advanced_search'] = $old_state['advanced_search']; - } - if ($do_email && $GLOBALS['egw_info']['etemplate']['loop'] && is_object($GLOBALS['egw']->js)) - { // remove previous addEmail() calls, otherwise they will be run again - $GLOBALS['egw']->js->body['onLoad'] = preg_replace('/addEmail\([^)]+\);/','',$GLOBALS['egw']->js->body['onLoad']); - } - //echo "uicontacts::get_rows(".print_r($query,true).")
\n"; - if (!$id_only) - { - // check if accounts are stored in ldap, which does NOT yet support the org-views - if ($this->so_accounts && $query['filter'] === '0' && $query['org_view']) - { - if ($old_state['filter'] === '0') // user changed to org_view - { - $query['filter'] = ''; // --> change filter to all contacts - } - else // user changed to accounts - { - $query['org_view'] = ''; // --> change to regular contacts view - } - } - if ($query['org_view'] && isset($this->org_views[$old_state['org_view']]) && !isset($this->org_views[$query['org_view']])) - { - $query['searchletter'] = ''; // reset lettersearch if viewing the contacts of one organisation - } - $GLOBALS['egw']->session->appsession($do_email ? 'email' : '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'], - 'col_filter' => array('tid' => $query['col_filter']['tid']), - 'org_view' => $query['org_view'], - )); - if ($state != $this->prefs[$do_email ? 'email_state' : 'index_state']) - { - $GLOBALS['egw']->preferences->add('addressbook',$do_email ? 'email_state' : 'index_state',$state); - // save prefs, but do NOT invalid the cache (unnecessary) - $GLOBALS['egw']->preferences->save_repository(false,'user',false); - } - } - unset($old_state); - - if ((string)$query['cat_id'] != '') - { - $query['col_filter']['cat_id'] = $query['cat_id'] ? $query['cat_id'] : null; - } - else - { - unset($query['col_filter']['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; - } - } - if ((int)$query['filter2']) // not no distribution list - { - $query['col_filter']['list'] = (string) (int) $query['filter2']; - } - else - { - unset($query['col_filter']['list']); - } - if ($GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) - { - $query['col_filter']['account_id'] = null; - } - // enable/disable distribution lists depending on backend - $query['no_filter2'] = !$this->lists_available($query['filter']); - - if (isset($this->org_views[(string) $query['org_view']])) // we have an org view - { - unset($query['col_filter']['list']); // does not work together - $query['no_filter2'] = true; // switch the distribution list selection off - - $query['template'] = 'addressbook.index.org_rows'; - - if ($query['order'] != 'org_name') - { - $query['sort'] = 'ASC'; - $query['order'] = 'org_name'; - } - $rows = parent::organisations($query); - - $GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => 'ManualAddressbookIndexOrga'); - } - else // contacts view - { - $query['template'] = $do_email ? 'addressbook.email.rows' : 'addressbook.index.rows'; - - if ($query['org_view']) // view the contacts of one organisation only - { - foreach(explode('|||',$query['org_view']) as $part) - { - list($name,$value) = explode(':',$part,2); - $query['col_filter'][$name] = $value; - } - } - // translate the select order to the really used over all 3 columns - $sort = $query['sort']; - switch($query['order']) // "xxx<>'' DESC" sorts contacts with empty order-criteria always at the end - { // we don't exclude them, as the total would otherwise depend on the order-criteria - case 'org_name': - $order = "org_name<>'' DESC,org_name $sort,n_family $sort,n_given $sort"; - break; - default: - $query['order'] = 'n_family'; - case 'n_family': - $order = "n_family<>'' DESC,n_family $sort,n_given $sort,org_name $sort"; - break; - case 'n_given': - $order = "n_given<>'' DESC,n_given $sort,n_family $sort,org_name $sort"; - break; - case 'n_fileas': - $order = "n_fileas<>'' DESC,n_fileas $sort"; - break; - case 'adr_one_postalcode': - $order = "adr_one_postalcode<>'' DESC,adr_one_postalcode $sort,org_name $sort,n_family $sort,n_given $sort"; - break; - case 'contact_modified': - case 'contact_created': - $order = "$query[order] IS NULL,$query[order] $sort,org_name $sort,n_family $sort,n_given $sort"; - break; - } - if ($query['searchletter']) // only show contacts if the order-criteria starts with the given letter - { - $query['col_filter'][] = ($query['order'] == 'adr_one_postalcode' ? 'org_name' : $query['order']).' '. - $GLOBALS['egw']->db->capabilities['case_insensitive_like'].' '.$GLOBALS['egw']->db->quote($query['searchletter'].'%'); - } - $wildcard = '%'; - $op = 'OR'; - if ($query['advanced_search']) - { - $op = $query['advanced_search']['operator']; - unset($query['advanced_search']['operator']); - $wildcard = $query['advanced_search']['meth_select']; - unset($query['advanced_search']['meth_select']); - } - $rows = parent::search($query['advanced_search'] ? $query['advanced_search'] : $query['search'],$id_only, - $order,'',$wildcard,false,$op,array((int)$query['start'],(int) $query['num_rows']),$query['col_filter']); - - // do we need to read the custom fields, depends on the column is enabled and customfields exist - $columselection = $this->prefs['nextmatch-addressbook.'.($do_email ? 'email' : 'index').'.rows']; - if ($columselection) $columselection = explode(',',$columselection); - if (!$id_only && (!$columselection || in_array('customfields',$columselection)) && $rows && $this->customfields) - { - foreach((array) $rows as $n => $val) - { - if ($val && (int)$val['id']) $ids[] = $val['id']; - } - if ($ids) $customfields = $this->read_customfields($ids); - } - } - if (!$rows) $rows = array(); - - if ($id_only) - { - foreach($rows as $n => $row) - { - $rows[$n] = $row['id']; - } - return $this->total; // no need to set other fields or $readonlys - } - $order = $query['order']; - - $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) - { - default: // postalcode, created, modified, ... - case 'org_name': - $row['line1'] = $row['org_name']; - $row['line2'] = $row['n_family'].($given ? ', '.$given : ''); - break; - case 'n_family': - $row['line1'] = $row['n_family'].($given ? ', '.$given : ''); - $row['line2'] = $row['org_name']; - break; - case 'n_given': - $row['line1'] = $given.' '.$row['n_family']; - $row['line2'] = $row['org_name']; - break; - case 'n_fileas': - if (!$row['n_fileas']) $row['n_fileas'] = $this->fileas($row); - list($row['line1'],$row['line2']) = explode(': ',$row['n_fileas']); - break; - } - if (isset($this->org_views[(string) $query['org_view']])) - { - $row['type'] = 'home'; - $row['type_label'] = lang('Organisation'); - - $readonlys["delete[$row[id]]"] = $query['filter'] && !($this->grants[(int)$query['filter']] & EGW_ACL_DELETE); - $readonlys["infolog[$row[id]]"] = !$GLOBALS['egw_info']['user']['apps']['infolog']; - } - else - { - $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) - { - $this->call_link($row[$name],$row[$name.'_link']); - $row[$name] .= ' '.($row['tel_prefer'] == $name ? '♥' : ''); // .' ' 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']]) - { - $this->call_link($row[$row['tel_prefer']],$row['tel_prefered_link']); - $row['tel_prefered'] = $row[$row['tel_prefer']].' ♥'; - } - 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['#'.$name] = $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; - } - } - } - $readonlys["document[$row[id]]"] = !$this->prefs['default_document']; - - // hide region for address format 'postcode_city' - if (($row['addr_format'] = $this->addr_format_by_country($row['adr_one_countryname']))=='postcode_city') unset($row['adr_one_region']); - if (($row['addr_format2'] = $this->addr_format_by_country($row['adr_two_countryname']))=='postcode_city') unset($row['adr_two_region']); - } - if (!$this->prefs['no_auto_hide']) - { - // disable photo column, if view contains no photo(s) - if (!$photos) $rows['no_photo'] = true; - // disable homeaddress column, if we have no homeaddress(es) - if (!$homeaddress) $rows['no_home'] = true; - } - // disable customfields column, if we have no customefield(s) - if (!$this->customfields || !$this->prefs['no_auto_hide'] && !$customfields) $rows['no_customfields'] = true; - - $rows['order'] = $order; - $rows['call_popup'] = $this->config['call_popup']; - $rows['customfields'] = array_values($this->customfields); - - // full app-header with all search criteria specially for the print - $GLOBALS['egw_info']['flags']['app_header'] = lang('addressbook'); - if ($query['filter'] !== '' && !isset($this->org_views[$query['org_view']])) - { - $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['org_view']) - { - $GLOBALS['egw_info']['flags']['app_header'] .= ': '.$query['org_view_label']; - } - if($query['advanced_search']) - { - $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Advanced search'); - } - if ($query['cat_id']) - { - if (!is_object($GLOBALS['egw']->categories)) - { - $GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories'); - } - $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Category').' '.$GLOBALS['egw']->categories->id2name($query['cat_id']); - } - if ($query['searchletter']) - { - $order = $order == 'n_given' ? lang('first name') : ($order == 'n_family' ? lang('last name') : lang('Organisation')); - $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 ($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) && !$GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) - { - $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 - * - * @param array $content=null submitted content - * @param int $_GET['contact_id'] contact_id manly for popup use - * @param bool $_GET['makecp'] ture if you want do copy the contact given by $_GET['contact_id'] - */ - function edit($content=null) - { - if (!is_object($this->link)) - { - if (!is_object($GLOBALS['egw']->link)) - { - $GLOBALS['egw']->link =& CreateObject('phpgwapi.bolink'); - } - $this->link =& $GLOBALS['egw']->link; - } - 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']) $content['jpegphoto'] = null; - 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']); - unset($content['upload_photo']); - } - $links = false; - if (!$content['id'] && is_array($content['link_to']['to_id'])) - { - $links = $content['link_to']['to_id']; - } - if ($content['id'] && $content['org_name'] && $content['change_org']) - { - $old_org_entry = $this->read($content['id']); - } - if ($this->save($content)) - { - $content['msg'] = lang('Contact saved'); - if ($content['change_org'] && $old_org_entry && ($changed = $this->changed_fields($old_org_entry,$content,true)) && - ($members = $this->org_similar($old_org_entry['org_name'],$changed))) - { - //foreach($changed as $name => $old_value) echo "$name: '$old_value' --> '{$content[$name]}'
\n"; - list($changed_members,$changed_fields,$failed_members) = $this->change_org($old_org_entry['org_name'],$changed,$content,$members); - if ($changed_members) - { - $content['msg'] .= ', '.lang('%1 fields in %2 other organisation member(s) changed',$changed_fields,$changed_members); - } - if ($failed_members) - { - $content['msg'] .= ', '.lang('failed to change %1 organisation member(s) (insufficent rights) !!!',$failed_members); - } - } - } - else - { - $content['msg'] = lang('Error saving the contact !!!'). - ($this->error ? ' '.$this->error : ''); - $button = 'apply'; // to not leave the dialog - } - // writing links for new entry, existing ones are handled by the widget itself - if ($links && $content['id']) - { - $this->link->link('addressbook',$content['id'],$links); - } - if ($button == 'save') - { - echo "\n"; -/* - $link = $GLOBALS['egw']->link('/index.php',array( - 'menuaction' => 'addressbook.uicontacts.view', - 'contact_id' => $content['id'], - )); - echo "\n"; -*/ - $GLOBALS['egw']->common->egw_exit(); - } - $content['link_to']['to_id'] = $content['id']; - $GLOBALS['egw_info']['flags']['java_script'] .= ""; - break; - - case 'delete': - if($this->action('delete',array($content['id']))) - { - echo "\n"; - $GLOBALS['egw']->common->egw_exit(); - } - else - { - $content['msg'] = lang('Error deleting the contact !!!'); - } - break; - } - // type change - } - else - { - $content = array(); - $contact_id = $_GET['contact_id'] ? $_GET['contact_id'] : ((int)$_GET['account_id'] ? 'account:'.(int)$_GET['account_id'] : 0); - $view = $_GET['view']; - // new contact --> set some defaults - if ($contact_id && is_array($content = $this->read($contact_id))) - { - $contact_id = $content['id']; // it could have been: "account:$account_id" - } - else // not found - { - $state = $GLOBALS['egw']->session->appsession('index','addressbook'); - // check if we create the new contact in an existing org - if ($_GET['org']) - { - $content = $this->read_org($_GET['org']); - } - elseif ($state['org_view'] && !isset($this->org_views[$state['org_view']])) - { - $content = $this->read_org($state['org_view']); - } - elseif ($GLOBALS['egw_info']['user']['preferences']['common']['country']) - { - if (!is_object($GLOBALS['egw']->country)) - { - require_once(EGW_API_INC.'/class.country.inc.php'); - $GLOBALS['egw']->country =& new country; - } - $content['adr_one_countryname'] = - $GLOBALS['egw']->country->get_full_name($GLOBALS['egw_info']['user']['preferences']['common']['country']); - } - if (isset($_GET['owner']) && $_GET['owner'] !== '') - { - $content['owner'] = $_GET['owner']; - } - else - { - $content['owner'] = $state['filter']; - } - $content['private'] = (int) ($content['owner'] && substr($content['owner'],-1) == 'p'); - if (!($this->grants[$content['owner'] = (string) (int) $content['owner']] & EGW_ACL_ADD)) - { - $content['owner'] = $this->prefs['add_default']; - $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; - $content['private'] = 0; - } - } - $new_type = array_keys($this->content_types); - $content['tid'] = $_GET['typeid'] ? $_GET['typeid'] : $new_type[0]; - foreach($this->get_contact_columns() as $field) - { - if ($_GET['presets'][$field]) $content[$field] = $_GET['presets'][$field]; - } - $content['creator'] = $this->user; - $content['created'] = $this->now_su; - unset($state); - } - if($content && $_GET['makecp']) // copy the contact - { - $content['link_to']['to_id'] = 0; - $this->link->link('addressbook',$content['link_to']['to_id'],'addressbook',$content['id'], - lang('Copied by %1, from record #%2.',$GLOBALS['egw']->common->display_fullname('', - $GLOBALS['egw_info']['user']['account_firstname'],$GLOBALS['egw_info']['user']['account_lastname']), - $content['id'])); - // create a new contact with the content of the old - foreach(array('id','modified','modifier','account_id') as $key) unset($content[$key]); - $content['owner'] = $this->prefs['add_default'] ? $this->prefs['add_default'] : $this->user; - $content['creator'] = $this->user; - $content['created'] = $this->now_su; - $content['msg'] = lang('Contact copied'); - } - else - { - $content['link_to']['to_id'] = $contact_id; - } - // automatic link new entries to entries specified in the url - if (!$contact_id && isset($_REQUEST['link_app']) && isset($_REQUEST['link_id']) && !is_array($content['link_to']['to_id'])) - { - $link_ids = is_array($_REQUEST['link_id']) ? $_REQUEST['link_id'] : array($_REQUEST['link_id']); - foreach(is_array($_REQUEST['link_app']) ? $_REQUEST['link_app'] : array($_REQUEST['link_app']) as $n => $link_app) - { - $link_id = $link_ids[$n]; - if (preg_match('/^[a-z_0-9-]+:[:a-z_0-9-]+$/i',$link_app.':'.$link_id)) // gard against XSS - { - $this->link->link('addressbook',$content['link_to']['to_id'],$link_app,$link_id); - } - } - } - } - // how to display addresses - $content['addr_format'] = $this->addr_format_by_country($content['adr_one_countryname']); - $content['addr_format2'] = $this->addr_format_by_country($content['adr_two_countryname']); - - $content['disable_change_org'] = $view || !$content['org_name']; - //_debug_array($content); - $readonlys['button[delete]'] = !$content['owner'] || !$this->check_perms(EGW_ACL_DELETE,$content); - $readonlys['button[copy]'] = $readonlys['button[edit]'] = $readonlys['button[vcard]'] = true; - - $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']] = !$content['owner'] ? lang('Accounts') : - $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 - $content['id'] && !$this->check_perms(EGW_ACL_DELETE,$content); // you need delete rights to move an existing contact into an other addressbook - } - // set the unsupported fields from the backend to readonly - foreach($this->get_fields('unsupported',$content['id'],$content['owner']) as $field) - { - $readonlys[$field] = true; - } - // disable not needed tabs - $readonlys[$this->tabs]['cats'] = !($content['cat_tab'] = $this->config['cat_tab']); - $readonlys[$this->tabs]['custom'] = !$this->customfields; - // for editing the own account (by a non-admin), enable only the fields allowed via the "own_account_acl" - if (!$content['owner'] && !$this->is_admin($content)) - { - $this->_set_readonlys_for_own_account_acl($readonlys,$id); - } - for($i = -23; $i<=23; $i++) $tz[$i] = ($i > 0 ? '+' : '').$i; - $sel_options['tz'] = $tz; - $content['tz'] = $content['tz'] ? $content['tz'] : 0; - if (count($this->content_types) > 1) - { - foreach($this->content_types as $type => $data) - { - $sel_options['tid'][$type] = $data['name']; - } - $content['typegfx'] = $GLOBALS['egw']->html->image('addressbook',$this->content_types[$content['tid']]['options']['icon'],'',' width="16px" height="16px"'); - } - else - { - $content['no_tid'] = true; - } - - $content['link_to'] = array( - 'to_app' => 'addressbook', - 'to_id' => $content['link_to']['to_id'], - ); - $content['photo'] = $this->photo_src($content['id'],$content['jpegphoto'],'photo'); - - if ($content['private']) $content['owner'] .= 'p'; - - $GLOBALS['egw_info']['flags']['include_xajax'] = true; - - if (!$this->tmpl->read($this->content_types[$content['tid']]['options']['template'])) - { - $content['msg'] = lang('WARNING: Template "%1" not found, using default template instead.', $this->content_types[$content['tid']]['options']['template'])."\n"; - $content['msg'] .= lang('Please update the templatename in your customfields section!'); - $this->tmpl->read('addressbook.edit'); - } - return $this->tmpl->exec('addressbook.uicontacts.edit',$content,$sel_options,$readonlys,$content, 2); - } - - /** - * Set the readonlys for non-admins editing their own account - * - * @param array &$readonlys - * @param int $id - */ - function _set_readonlys_for_own_account_acl(&$readonlys,$id) - { - // regular fields depending on the backend - foreach($this->get_fields('supported',$id,0) as $field) - { - if (!$this->own_account_acl || !in_array($field,$this->own_account_acl)) - { - $readonlys[$field] = true; - switch($field) - { - case 'tel_work': - case 'tel_cell': - case 'tel_home': - $readonlys[$field.'2'] = true; - break; - case 'n_fileas': - $readonlys['fileas_type'] = true; - break; - } - } - } - // custom fields - if ($this->customfields) - { - foreach($this->customfields as $name => $data) - { - if (!$this->own_account_acl || !in_array('#'.$name,$this->own_account_acl)) - { - $readonlys['#'.$name] = true; - } - } - } - // links - if (!$this->own_account_acl || !in_array('link_to',$this->own_account_acl)) - { - $readonlys['link_to'] = true; - } - } - - 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 "imagecopyresized(\$photo,\$upload,0,0,0,0,$dst_w,$dst_h,$src_w,$src_h);
\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)) - { - list($button) = each($content['button']); - switch ($button) - { - case 'vcard': - $GLOBALS['egw']->redirect_link('/index.php','menuaction=addressbook.uivcard.out&ab_id=' .$content['id']); - - case 'cancel': - $GLOBALS['egw']->redirect_link('/index.php','menuaction=addressbook.uicontacts.index'); - - case 'delete': - $GLOBALS['egw']->redirect_link('/index.php',array( - 'menuaction' => 'addressbook.uicontacts.index', - 'msg' => $this->delete($content) ? lang('Error deleting the contact !!!') : lang('Contact deleted'), - )); - } - } - else - { - if(!$_GET['contact_id'] || !is_array($content = $this->read($_GET['contact_id']))) - { - $GLOBALS['egw']->redirect_link('/index.php',array( - 'menuaction' => 'addressbook.uicontacts.index', - 'msg' => $content, - )); - } - } - foreach(array_keys($this->contact_fields) as $key) - { - $readonlys[$key] = true; - if (in_array($key,array('tel_home','tel_work','tel_cell'))) - { - $readonlys[$key.'2'] = true; - $content[$key.'2'] = $content[$key]; - } - } - $content['view'] = true; - $content['link_to'] = array( - 'to_app' => 'addressbook', - 'to_id' => $content['id'], - ); - $readonlys['link_to'] = $readonlys['customfields'] = $readonlys['fileas_type'] = true; - $readonlys['button[save]'] = $readonlys['button[apply]'] = $readonlys['change_photo'] = true; - $readonlys['button[delete]'] = !$content['owner'] || !$this->check_perms(EGW_ACL_DELETE,$content); - $readonlys['button[edit]'] = !$this->check_perms(EGW_ACL_EDIT,$content); - $content['disable_change_org'] = true; -// ToDo: fix vCard export -$readonlys['button[vcard]'] = true; - - // how to display addresses - $content['addr_format'] = $this->addr_format_by_country($content['adr_one_countryname']); - $content['addr_format2'] = $this->addr_format_by_country($content['adr_two_countryname']); - - $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; - if (count($this->content_types) > 1) - { - foreach($this->content_types as $type => $data) - { - $sel_options['tid'][$type] = $data['name']; - } - $content['typegfx'] = $GLOBALS['egw']->html->image('addressbook',$this->content_types[$content['tid']]['options']['icon'],'',' width="16px" height="16px"'); - } - else - { - $content['no_tid'] = true; - } - if (!$this->tmpl->read($this->content_types[$content['tid']]['options']['template'])) - { - $content['msg'] = lang('WARNING: Template "%1" not found, using default template instead.', $this->content_types[$content['tid']]['options']['template'])."\n"; - $content['msg'] .= lang('Please update the templatename in your customfields section!'); - $this->tmpl->read('addressbook.edit'); - } - foreach(array('email','email_home','url','url_home') as $name) - { - if ($content[$name] ) - { - $url = substr($name,0,3) == 'url' ? $content[$name] : $this->email2link($content[$name]); - if (!is_array($url)) - { - $this->tmpl->set_cell_attribute($name,'size','b,,1'); - } - elseif ($url) - { - $content[$name.'_link'] = $url; - $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); - } - } - if ($this->private_addressbook && $content['private'] && $content['owner'] == $this->user) - { - $content['owner'] .= 'p'; - } - // set id for automatic linking via quick add - $GLOBALS['egw_info']['flags']['currentid'] = $content['id']; - - $this->tmpl->exec('addressbook.uicontacts.view',$content,$sel_options,$readonlys,array('id' => $content['id'])); - - $GLOBALS['egw']->hooks->process(array( - 'location' => 'addressbook_view', - 'ab_id' => $content['id'] - )); - } - - /** - * convert email-address in compose link - * - * @param string $email email-addresse - * @return array/string array with get-params or mailto:$email, or '' or no mail addresse - */ - function email2link($email) - { - if (strpos($email,'@') == false) return ''; - - if($GLOBALS['egw_info']['user']['apps']['felamimail']) - { - return array( - 'menuaction' => 'felamimail.uicompose.compose', - 'send_to' => base64_encode($email) - ); - } - if($GLOBALS['egw_info']['user']['apps']['email']) - { - return array( - 'menuaction' => 'email.uicompose.compose', - 'to' => $email, - ); - } - return 'mailto:' . $email; - } - - /** - * Extended search - * - * @param array $_content - * @return string - */ - function search($_content=array()) - { - if(!empty($_content)) { - $response = new xajaxResponse(); - - $query = $GLOBALS['egw']->session->appsession($do_email ? 'email' : 'index','addressbook'); - - $query['advanced_search'] = array_intersect_key($_content,array_flip(array_merge($this->get_contact_columns(),array('operator','meth_select')))); - foreach ($query['advanced_search'] as $key => $value) - { - if(!$value) unset($query['advanced_search'][$key]); - } - $query['start'] = 0; - $query['search'] = ''; - // store the index state in the session - $GLOBALS['egw']->session->appsession($do_email ? 'email' : 'index','addressbook',$query); - - // store the advanced search in the session to call it again - $GLOBALS['egw']->session->appsession('advanced_search','addressbook',$query['advanced_search']); - - $response->addScript(" - var link = opener.location.href; - link = link.replace(/#/,''); - opener.location.href=link.replace(/\#/,''); - xajax_eT_wrapper(); - "); - return $response->getXML(); - } - else { - - } - $GLOBALS['egw_info']['flags']['include_xajax'] = true; - $GLOBALS['egw_info']['flags']['java_script'] .= ""; - $GLOBALS['egw_info']['etemplate']['advanced_search'] = true; - - // initialize etemplate arrays - $sel_options = $readonlys = $preserv = array(); - $content = $GLOBALS['egw']->session->appsession('advanced_search','addressbook'); - - for($i = -23; $i<=23; $i++) $tz[$i] = ($i > 0 ? '+' : '').$i; - $sel_options['tz'] = $tz + array('' => lang('doesn\'t matter')); - $sel_options['tid'][] = lang('all'); - //foreach($this->content_types as $type => $data) $sel_options['tid'][$type] = $data['name']; - - // configure search options - $sel_options['owner'] = $this->get_addressbooks(EGW_ACL_READ,lang('all')); - $sel_options['operator'] = array( - 'OR' => 'OR', - 'AND' => 'AND' - ); - $sel_options['meth_select'] = array( - '%' => lang('contains'), - false => lang('exact'), - ); - if ($this->customfields) - { - foreach($this->customfields as $name => $data) - { - if ($data['type'] == 'select') - { - if (!isset($content['#'.$name])) $content['#'.$name] = ''; - if(!isset($data['values'][''])) $sel_options['#'.$name][''] = lang('Select one'); - } - } - } - // configure edit template as search dialog - $readonlys['change_photo'] = true; - $readonlys['fileas_type'] = true; - $readonlys['creator'] = true; - $readonlys['button'] = true; - // disable not needed tabs - $readonlys[$this->tabs]['cats'] = !($content['cat_tab'] = $this->config['cat_tab']); - $readonlys[$this->tabs]['custom'] = !$this->customfields; - $readonlys[$this->tabs]['links'] = true; - $content['hidebuttons'] = true; - $content['no_tid'] = true; - $content['disable_change_org'] = true; - - $this->tmpl->read('addressbook.search'); - return $this->tmpl->exec('addressbook.uicontacts.search',$content,$sel_options,$readonlys,$preserv,2); - } - - /** - * download photo of the given ($_GET['contact_id'] or $_GET['account_id']) contact - */ - 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['jpegphoto'],'ascii') : strlen($contact['jpegphoto']))); - echo $contact['jpegphoto']; - exit; - } - } - - /** - * returns link to call the given phonenumber - * - * replaces '%1' with the phonenumber to call, '%u' with the user's account_lid and '%t' with his work-phone-number - * - * @param string $number phone number - * @param string &$link returns the link - * @return boolean true if we have a link, false if not - */ - function call_link($number,&$link) - { - if (!$number || !$this->config['call_link']) return false; - - static $userphone; - if (is_null($userphone)) - { - $user = $this->read('account:'.$GLOBALS['egw_info']['user']['account_id']); - $userphone = is_array($user) ? ($user['tel_work'] ? $user['tel_work'] : $user['tel_home']) : false; - } - $number = str_replace(array(' ','(',')','/','-'),'',$number); // remove number formatting chars messing up the links - - $link = str_replace(array('%1','%u','%t'),array(urlencode($number),$GLOBALS['egw_info']['user']['account_lid'],$userphone), - $this->config['call_link']); - } - - function js() - { - return ''; - } - - function migrate2ldap() - { - $GLOBALS['egw_info']['flags']['app_header'] = lang('Addressbook').' - '.lang('Migration to LDAP'); - $GLOBALS['egw']->common->egw_header(); - parse_navbar(); - - if (!$this->is_admin()) - { - echo ''.lang('Migration finished')."
\n"; - } - $GLOBALS['egw']->common->egw_footer(); - } - - /** - * Download a document with inserted contact(s) - * - * @param array $ids contact-ids - * @param string $document vfs-path of document - * @return string error-message or error, otherwise the function does NOT return! - */ - function download_document($ids,$document='') - { - if (!$document) $document = $this->prefs['default_document']; - - require_once(EGW_API_INC.'/class.vfs.inc.php'); - $vfs =& new vfs(); - if (!$document || $document != $this->prefs['default_document'] && - substr($document,0,1+strlen($this->prefs['document_dir'])) != $this->prefs['document_dir'].'/' || - !$vfs->acl_check(array( - 'string' => $document, - 'relatives' => RELATIVE_ROOT, - 'operation' => EGW_ACL_READ, - 'must_exist' => true, - ))) - { - return lang("Document '%1' does not exist or is not readable for you!",$document); - } - require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.addressbook_merge.inc.php'); - $document_merge =& new addressbook_merge(); - - return $document_merge->download($document,$ids); - } - - /** - * Returning document actions / files from the document_dir - * - * @return array - */ - function get_document_actions() - { - if (!$this->prefs['document_dir']) return array(); - - if (!is_array($actions = $GLOBALS['egw']->session->appsession('document_actions','addressbook'))) - { - require_once(EGW_API_INC.'/class.vfs.inc.php'); - $vfs =& new vfs; - - $actions = array(); - if (($files = $vfs->ls(array( - 'string' => $this->prefs['document_dir'], - 'relatives' => RELATIVE_ROOT, - )))) - { - foreach($files as $file) - { - // return only the mime-types we support - if (!($file['mime_type'] == 'application/rtf' || - $file['mime_type'] == 'application/msword' && !strcasecmp(substr($file['name'],-4),'.rtf') || - substr($file['mime_type'],0,5) == 'text/')) continue; - // As browsers not always return the right mime_type, you could use a negative list instead - //if ($file['mime_type'] == 'Directory' || substr($file['mime_type'],0,6) == 'image/') continue; - - $actions['document-'.$file['directory'].'/'.$file['name']] = lang('Insert in document').': '.$file['name']; - } - } - $GLOBALS['egw']->session->appsession('document_actions','addressbook',$actions); - } - return $actions; - } -} - -if (!function_exists('array_intersect_key')) // php5.1 function -{ - function array_intersect_key($array1,$array2) - { - $intersection = $keys = array(); - foreach(func_get_args() as $arr) - { - $keys[] = array_keys((array)$arr); - } - foreach(call_user_func_array('array_intersect',$keys) as $key) - { - $intersection[$key] = $array1[$key]; - } - return $intersection; - } -} - diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/class.vcaladdressbook.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/class.vcaladdressbook.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/class.vcaladdressbook.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/class.vcaladdressbook.inc.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,691 +0,0 @@ - - * @author Ralf Becker$_vcard"; - - #error_log(print_r($vcardValues, true)); - - foreach($vcardValues as $key => $vcardRow) - { - $rowName = $vcardRow['name']; - - if(isset($vcardRow['params']['INTERNET'])) - { - $rowName .= ";INTERNET"; - } - $type = strtoupper($vcardRow['params']['TYPE']); // vCard3 sets TYPE={work|home|cell|fax}! - - if(isset($vcardRow['params']['CELL']) || $type == 'CELL') - { - $rowName .= ';CELL'; - } - if(isset($vcardRow['params']['FAX']) || $type == 'FAX') - { - $rowName .= ';FAX'; - } - if(isset($vcardRow['params']['PAGER']) || $type == 'PAGER') - { - $rowName .= ';PAGER'; - } - if(isset($vcardRow['params']['WORK']) || $type == 'WORK') - { - $rowName .= ';WORK'; - } - if(isset($vcardRow['params']['HOME']) || $type == 'HOME') - { - $rowName .= ';HOME'; - } - if(isset($vcardRow['params']['VOICE']) || $type == 'VOICE') - { - $rowName .= ';VOICE'; - } - if(isset($vcardRow['params']['CAR']) || $type == 'CAR') - { - $rowName .= ';CAR'; - } - //error_log("key: $key --> $rowName: name=$vcardRow[name], params=".print_r($vcardRow['params'],true)); - $rowNames[$rowName] = $key; - } - - #error_log(print_r($rowNames, true)); - - // now we have all rowNames the vcard provides - // we just need to map to the right addressbook fieldnames - // we need also to take care about ADR for example. we do not - // support this. We support only ADR;WORK or ADR;HOME - - foreach($rowNames as $rowName => $vcardKey) - { - switch($rowName) - { - case 'ADR': - case 'TEL': - case 'URL': - case 'TEL;FAX': - case 'TEL;CELL': - case 'TEL;PAGER': - if(!isset($rowNames[$rowName. ';WORK'])) - { - $finalRowNames[$rowName. ';WORK'] = $vcardKey; - } - break; - case 'EMAIL': - case 'EMAIL;WORK': - case 'EMAIL;INTERNET': - if(!isset($rowNames['EMAIL;INTERNET;WORK'])) - { - $finalRowNames['EMAIL;INTERNET;WORK'] = $vcardKey; - } - break; - case 'EMAIL;HOME': - if(!isset($rowNames['EMAIL;INTERNET;HOME'])) - { - $finalRowNames['EMAIL;INTERNET;HOME'] = $vcardKey; - } - break; - - case 'VERSION': - break; - - default: - $finalRowNames[$rowName] = $vcardKey; - break; - } - } - - #error_log(print_r($finalRowNames, true)); - - $contact = array(); - - foreach($finalRowNames as $key => $vcardKey) - { - if(isset($this->supportedFields[$key])) - { - $fieldNames = $this->supportedFields[$key]; - foreach($fieldNames as $fieldKey => $fieldName) - { - if(!empty($fieldName)) - { - $value = trim($vcardValues[$vcardKey]['values'][$fieldKey]); - //error_log("$fieldName=$vcardKey[$fieldKey]='$value'"); - switch($fieldName) - { - case 'bday': - if(!empty($value)) { - $contact[$fieldName] = date('Y-m-d', $value); - } - break; - - case 'private': - $contact[$fieldName] = (int) ($value == 'PRIVATE'); - break; - - case 'cat_id': - $contact[$fieldName] = implode(',',$this->find_or_add_categories(explode(',',$value))); - break; - - case 'note': - // note may contain ','s but maybe this needs to be fixed in vcard parser... - //$contact[$fieldName] = trim($vcardValues[$vcardKey]['value']); - //break; - - default: - $contact[$fieldName] = $value; - break; - } - } - } - } - } - - $this->fixup_contact($contact); - return $contact; - } - - /** - * Exports some contacts: download or write to a file - * - * @param array $ids contact-ids - * @param string $file filename or null for download - */ - function export($ids,$file=null) - { - if (!$file) - { - $browser =& CreateObject('phpgwapi.browser'); - $browser->content_header('addressbook.vcf','text/x-vcard'); - } - if (!($fp = fopen($file ? $file : 'php://output','w'))) - { - return false; - } - foreach($ids as $id) - { - fwrite($fp,$this->getVCard($id)); - } - fclose($fp); - - if (!$file) - { - $GLOBALS['egw']->common->egw_exit(); - } - return true; - } -} diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/inc/hook_config.inc.php /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/inc/hook_config.inc.php --- egroupware-1.4.004-2.dfsg/addressbook/inc/hook_config.inc.php 2008-04-15 14:59:26.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/inc/hook_config.inc.php 2008-11-24 11:43:08.000000000 +0000 @@ -6,9 +6,9 @@ * @author Ralf Becker
В Outlook, изберете папка Контакти (Contacts), изберете Import and Export... от меню File и експортирайте контактите в CSV файл.
На Palm Desktop 4.0 или по-нов, отворете адресния указател и изберете Export от меню File. Експортирания файл ще бъде във формат VCard. +imports contacts into your addressbook from a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. addressbook bg Импортира контакти в Адресния указател от CSV файл (стойности, разделени със запетая). От таб Опции може да изберете друг разделител. +in %1 days (%2) is %3's birthday. addressbook bg Рожденият ден на %3 е след %1 дни (%2). +income addressbook bg Доход +insert in document addressbook bg Вмъкване в документа +insufficent rights to delete this list! addressbook bg Недостатъчни права за изтриване на списъка! +international addressbook bg Международен +label addressbook bg Етикет +last date addressbook bg Крайна дата +last modified addressbook bg Последно модифициран +last modified by addressbook bg Последно модифициран от +ldap context for contacts admin bg LDAP контекст за контактите +ldap host for contacts admin bg LDAP сървър за контактите +ldap settings for contacts admin bg LDAP настройки за контактите +ldif addressbook bg LDIF +line 2 addressbook bg Ред 2 +links addressbook bg Връзки +list all categories addressbook bg Показване на всички категории +list all customfields addressbook bg Показване на всички полета по избор +list already exists! addressbook bg Списъкът вече съществува! +list created addressbook bg Списъкът е създаден +list creation failed, no rights! addressbook bg Грешка при създаване на списъка: нямате права! +load sample file addressbook bg Зареждане на примерен файл +load vcard addressbook bg Зареждане на VCard +location addressbook bg Местоположение +locations addressbook bg местоположения +manage mapping addressbook bg Управление на съответствията +mark records as private addressbook bg Маркира записите като лични +merged addressbook bg обединени +message after submitting the form addressbook bg Съобщение след предаване на формата +message phone addressbook bg Телефон за съобщения +middle name addressbook bg Презиме +migration finished addressbook bg Миграцията приключи +migration to ldap admin bg Миграция към LDAP +mobile addressbook bg Мобилен +mobile phone addressbook bg Мобилен телефон +modem phone addressbook bg Модем +more ... addressbook bg Още ... +move to addressbook: addressbook bg Преместен(и) в адр. указател: +moved addressbook bg преместен(и) +multiple vcard addressbook bg Множество VCard +name for the distribution list addressbook bg Име на пощенския списък +name of current user, all other contact fields are valid too addressbook bg Име на текущия потребител, останалите полета на контакта също са валидни +name, address addressbook bg Име, Адрес +new contact submitted by %1 at %2 addressbook bg Новият контакт е изпратен от %1 в %2 +new window opened to edit infolog for your selection addressbook bg Отворен е нов прoзoрец за редакция в Дневника на избраните елементи +next date addressbook bg Следваща дата +no categories selected addressbook bg не са избрани категории +no vcard addressbook bg Липсва VCard +number addressbook bg Номер +number of records to read (%1) addressbook bg Брой записи за четене (%1) +options for type admin bg Опции за тип +organisation addressbook bg организация +organisations addressbook bg Организации +organisations by departments addressbook bg Организации по отдели +organisations by location addressbook bg Организации по местоположение +other number addressbook bg Друг номер +other phone addressbook bg Друг телефон +own sorting addressbook bg собствена подредба +pager common bg Пейджър +parcel addressbook bg Колет +participants addressbook bg Участници +permission denied !!! addressbook bg Достъпът отказан !!! +phone number common bg Телефонен номер +phone numbers common bg Телефонни номера +photo addressbook bg Снимка +please enter a name for that field ! addressbook bg Моля въведете име за това поле! +please select only one category addressbook bg Моля, изберете само една категория +please update the templatename in your customfields section! addressbook bg Моля, обновете името на шаблона в секцията за полете по избор! +postal common bg Пощенски +pref addressbook bg предп. +preferred email address to use in distribution lists addressbook bg Предпочитан e-mail адрес за пощенски списъци +preferred phone addressbook bg предпочитан телефон +preferred type of email address to add for distribution lists addressbook bg предпочитан E-Mail адрес за добавяне в пощенски списък +prefix addressbook bg Префикс +public key addressbook bg Публичен ключ +publish into groups: addressbook bg Публикуване в групи: +read a list / search for entries. addressbook bg Четене на списък / търсене на записи. +read a list of entries. addressbook bg Четене на списък със записи. +read a single entry by passing the id and fieldlist. addressbook bg Четене на единичен запис чрез подаване на id и списък с полета +read only addressbook bg само за четене +record access addressbook bg Достъп до записа +record owner addressbook bg Собственик на записа +remove selected contacts from distribution list addressbook bg Премахване на избраните контакти от пощенския списък +removed from distribution list addressbook bg премахнат(и) от пощенския списък +repetition addressbook bg Повторение +required fields * addressbook bg Задължителни полета * +role addressbook bg Роля +room addressbook bg Стая +search for '%1' addressbook bg Търсене на '%1' +select a portrait format jpeg photo. it will be resized to 60 pixel width. addressbook bg Изберете снимка във формат "портрет". Тя ще бъде преоразмерена на 60 пиксела ширина. +select a view addressbook bg Избор на изглед +select addressbook type addressbook bg Избор на тип адресен указател +select all addressbook bg Избиране на всичко +select an action or addressbook to move to addressbook bg Избор на действие или адресен указател, в който да се преместят +select migration type admin bg Избор на тип миграция +select multiple contacts for a further action addressbook bg Избор на множество контакти +select phone number as prefered way of contact addressbook bg изберете телефонния номер за предпочитан +select the type of conversion addressbook bg Избор на тип на конвертирането +select the type of conversion: addressbook bg Изберете тип на конвертирането: +select where you want to store / retrieve contacts admin bg Къде желаете да се пазят / извличат контактите +selected contacts addressbook bg избраните контакти +should the columns photo and home address always be displayed, even if they are empty. addressbook bg Да се показват ли колоните за снимка и личен (домашен) адрес, независимо дали са празни или не. +show addressbook bg Покажи +show birthday reminders on main screen addressbook bg Напомняне за рождени дни на главния екран +show infolog entries for this organisation addressbook bg Показване на записите в Дневника за тази организация +show the contacts of this organisation addressbook bg Показване на контактите на тази организация +size of popup (wxh, eg.400x300, if a popup should be used) admin bg Размер на "изскачащия" прозорец (ШxВ, напр. 400x300), ако ще се използва такъв +start admin bg Старт +startrecord addressbook bg Начален запис +state common bg Област / Щат +street common bg Улица +subject for email addressbook bg Тема на писмото +successfully imported %1 records into your addressbook. addressbook bg Успешно са импортирани %1 запис(а) в адресния Ви указател. +suffix addressbook bg Суфикс +tel home addressbook bg домашен телефон +telephony integration admin bg Интеграция с телефония +test import (show importable records only in browser) addressbook bg Тестов импорт (показва импортируемите записи само в браузъра +thank you for contacting us. addressbook bg Благодарим Ви, че се свързахте с нас. +that field name has been used already ! addressbook bg Това име на поле вече е използвано! +the anonymous user has probably no add rights for this addressbook. addressbook bg Анонимният потребител вероятно няма право да добавя в този адресен указател. +there was an error saving your data :-( addressbook bg Грешка при запис на данните Ви :-( +this module displays a contactform, that stores direct into the addressbook. addressbook bg Този модул показва форма за контакти, която записва директно в адресния указател. +this module displays block from a adddressbook group. addressbook bg Този модул показва Блок от група на Адресния указател. +this person's first name was not in the address book. addressbook bg Това малко име не беше открито в адресника. +this person's last name was not in the address book. addressbook bg Тази фамилия не беше открита в адресника. +timezone addressbook bg Часова зона +to many might exceed your execution-time-limit addressbook bg твърде много може да надвиши ограничението за време на изпълнение +today is %1's birthday! common bg Днес е рожденият ден на %1! +tomorrow is %1's birthday. common bg Утре е рожденият ден на %1! +translation addressbook bg Превод +type addressbook bg Тип +update a single entry by passing the fields. addressbook bg Актуализация на единичен запис чрез предаване на полетата. +updated addressbook bg Актуализиран +upload or delete the photo addressbook bg Запис или изтриване на снимка +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin bg URL за връзка към телефонните номера (използвайте %1 = номер, който да се набере, %u = име на какунт, %t = телефон на акаунт) +use an extra category tab? addressbook bg Използване на допълнителен таб за категории? +use an extra tab for private custom fields? admin bg Допълнителен таб за лични полета по избор? +use country list addressbook bg Използване на списък с държави +use setup for a full account-migration admin bg използвайте Setup за пълна миграция на акаунтите +vcard common bg VCard +vcards require a first name entry. addressbook bg За VCard се изисква въвеждане на първо име. +vcards require a last name entry. addressbook bg За VCard се изисква въвеждане на фамилно име. +verification addressbook bg Проверка +view linked infolog entries addressbook bg Покзване на свързаните записи от Дневника +warning!! ldap is valid only if you are not using contacts for accounts storage! admin bg ВНИМАНИЕ! LDAP е валиден избор само ако НЕ използвате контактите за съхранение и на потребителските акаунти! +warning: all contacts found will be deleted! addressbook bg ВНИМАНИЕ! Всички намерени контакти ще бъдат изтрити! +warning: template "%1" not found, using default template instead. addressbook bg ВНИМАНИЕ: Не е намерен шаблон "%1". Използва се шаблона по подразбиране. +weekday addressbook bg Ден от седмицата +what should links to the addressbook display in other applications. empty values will be left out. you need to log in anew, if you change this setting! addressbook bg Как да се изобразяват връзките към Адресния указател в другите приложения? Празните стойности ще бъдат игнорирани. Ако промените тази настройка следва да излезете и влезете в системата отново. +where to add the email address addressbook bg къде да се добави E-Mail адрес +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook bg Какъв формат за адреса да се използва за държавите, за които не е зададен формат по подразбиране? Ако за дадена държава форматът е известен, той се използва, независимо от тази настройка. +which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook bg Кой адресен указател да се използва при добавяне на контакт АКО нямате право да добавяте в текущия? +which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook bg Кой символен набор (charset) да се използва за експорт в CSV? По подразбиране - символният набор на инсталацията на eGroupWare. +which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook bg Кои полета да бъдат експортирани? Всички означава всички полета на адресния указател, вкл. и тези по избор. Служебния или личния адрес означават име, организация и съответно избрания адрес. +whole query addressbook bg всички резултати +work email if given, else home email addressbook bg Служебен e-mail, ако е посочен, иначе - личен e-mail +work phone addressbook bg Служебен телефон +write (update or add) a single entry by passing the fields. addressbook bg Запис (актуализация или добавяне) на единичен запис чрез предаване на полетата. +wrong - try again ... addressbook bg Грешка - опитайте отново +yes, for the next three days addressbook bg Да, за следващите три дни +yes, for the next two weeks addressbook bg Да, за следващите две седмици +yes, for the next week addressbook bg Да, за следващата седмица +yes, for today and tomorrow addressbook bg Да, за днес и утре +you are not permitted to delete contact %1 addressbook bg Нямате право да изтриете контакта: %1 +you are not permittet to delete this contact addressbook bg Нямате право да изтриете този контакт +you are not permittet to edit this contact addressbook bg Нямате право да редактирате този контакт +you are not permittet to view this contact addressbook bg Нямате право да разглеждате този контакт +you can respond by visiting: addressbook bg За преглед посетете: +you must select a vcard. (*.vcf) addressbook bg Трябва да изберете vcard. (*.vcf) +you must select at least 1 column to display addressbook bg Трябва да изберете поне една колона за показване +you need to select a distribution list addressbook bg Трябва да изберете пощенски списък +you need to select some contacts first addressbook bg Трябва да изберете контакти +zip code common bg Пощенски код +zip_note addressbook bg
Забележка: Файлът може да бъде zip, съдържащ .csv, .vcf, или .ldif файлове. Не смесвайте тези типове при един импорт!
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_ca.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_ca.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_ca.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_ca.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,329 @@
+%1 added addressbook ca %1 afegit
+%1 contact(s) %2 addressbook ca %1 contacte(s) %2
+%1 contact(s) %2, %3 failed because of insufficent rights !!! addressbook ca %1 contacte(s) %2, %3 ha fallat per que no teniu suficients drets !!!
+%1 fields in %2 other organisation member(s) changed addressbook ca %1 camps en %2 altres membres de l'organització han canviat
+%1 records imported addressbook ca %1 registres importats
+%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook ca %1 registres llegits (no importats encara, podeu tornar %2enrere%3 i desmarcar Prova d'Importació)
+%1 starts with '%2' addressbook ca %1 comença amb '%2'
+(e.g. 1969) addressbook ca (p. ex. 1969)
+no conversion type <none> could be located. please choose a conversion type from the list addressbook ca No s'ha trobat el tipus de conversió
O bé, en Outlook, seleccioneu la vostra carpeta de contactes, després, al menú Arxiu, Importar i Exportar... per desar-los en un arxiu separat per comes (CSV).
O també, en Palm Desktop 4.0 o superior, visiteu la vostra llibreta d'adreces i seleccioneu Exportar al menú Arxiu. L'arxiu exportat estarà en format VCard. +in %1 days (%2) is %3's birthday. addressbook ca En %1 dies (%2) es l'aniversari de %3. +income addressbook ca Entrada +insufficent rights to delete this list! addressbook ca Insuficients drets per esborrar aquesta llista! +international addressbook ca Internacional +label addressbook ca Etiqueta +last modified addressbook ca Darrera modificació +last modified by addressbook ca Darrera modificació de +ldap context for contacts admin ca Context LDAP per contactes +ldap host for contacts admin ca Servidor LDAP per contactes +ldap settings for contacts admin ca Paràmetres LDAP per contactes +ldif addressbook ca LDIF +line 2 addressbook ca Línia 2 +link title for contacts show addressbook ca Títol d'enllaç per mostrar contactes +links addressbook ca Enllaços +list all categories addressbook ca Llista totes les categories +list all customfields addressbook ca Llista tots els camps personalitzats +list already exists! addressbook ca La llista ja existeix! +list created addressbook ca Llista crada +list creation failed, no rights! addressbook ca Error en la creació de la llista, falta de drets! +load vcard addressbook ca Carrega VCard +locations addressbook ca Ubicacions +mark records as private addressbook ca Marcar registres com a privats +merge into first or account, deletes all other! addressbook ca Fusiona en el primer o en el compte, esborra els altres! +merged addressbook ca fusionat +message phone addressbook ca Telèfon de missatges +middle name addressbook ca Segon nom +migration finished addressbook ca Migració finalitzada +migration to ldap admin ca Migració a LDAP +mobile addressbook ca Mòbil +mobile phone addressbook ca Telèfon mòbil +modem phone addressbook ca Telèfon de módem +more ... addressbook ca Més ... +move to addressbook: addressbook ca Mou a la llibreta d'adreces: +moved addressbook ca mogut +multiple vcard addressbook ca VCard Múltiple +name for the distribution list addressbook ca Nom per la llista de distribució +name, address addressbook ca Nom, Adreça +no vcard addressbook ca Sense VCard +number addressbook ca Número +number of records to read (%1) addressbook ca Número de registres a llegir (%1) +options for type admin ca Opcions pel tipus +organisation addressbook ca Organització +organisations addressbook ca Organitzacions +organisations by departments addressbook ca Organitzacions per departaments +organisations by location addressbook ca Organitzacions per ubicació +other number addressbook ca Un altre número +other phone addressbook ca Un altre telèfon +own sorting addressbook ca pròpia ordenació +pager common ca Buscapersones +parcel addressbook ca Paquet +permission denied !!! addressbook ca Permís denegat !!! +phone number common ca Número de telèfon +phone numbers common ca Números de telèfon +photo addressbook ca Foto +please enter a name for that field ! addressbook ca Si us plau, entreu un nom per aquest camp ! +please select only one category addressbook ca Siusplau, seleccioneu només una categoria +postal common ca Postal +pref addressbook ca pref +preferred phone addressbook ca telèfon preferit +prefix addressbook ca Prefix +public key addressbook ca Clau pública +publish into groups: addressbook ca Publica dins els grups: +read a list / search for entries. addressbook ca Llegiu una llista / cercau entrades +read a list of entries. addressbook ca Llegir una llista d'entrades +read a single entry by passing the id and fieldlist. addressbook ca Llegir una sola entrada passant l'identificador i la llista de camps +read only addressbook ca només lectura +record access addressbook ca Accés al registre +record owner addressbook ca Propietari del registre +remove selected contacts from distribution list addressbook ca Treu de la llista de distribució els contactes seleccionats +removed from distribution list addressbook ca trets de la llista de distribució +role addressbook ca Càrrec +room addressbook ca Despatx +search for '%1' addressbook ca Busceu per '%1' +select a portrait format jpeg photo. it will be resized to 60 pixel width. addressbook ca Seleccioneu una fotografia en format jpeg. Serà redimensionada a una amplada de 60 píxels. +select a view addressbook ca Seleccioneu una vista +select addressbook type addressbook ca Seleccioneu un tipus de llibreta d'adreces +select all addressbook ca Seleccionar tot +select an action or addressbook to move to addressbook ca Seleccioneu una acció o una llibreta d'adreces per moure a +select migration type admin ca Seleccioneu un tipus de migració +select multiple contacts for a further action addressbook ca Seleccioneu múltiples contactes per una propera acció +select phone number as prefered way of contact addressbook ca Seleccioneu el número de telèfon com a mitjà preferit de contacte +select the type of conversion addressbook ca Seleccioneu el tipus de conversió +select the type of conversion: addressbook ca Seleccioneu el tipus de conversió: +select where you want to store / retrieve contacts admin ca Seleccioneu quan voleu emmagatzemar / recuperar contactes +selected contacts addressbook ca Contactes selecionats +should the columns photo and home address always be displayed, even if they are empty. addressbook ca Les columnes de fotografia i domicili han de mostrar-se sempre, fins i tot si estan buides. +show addressbook ca Mostra +show birthday reminders on main screen addressbook ca Mostrar recordatoris d'aniversaris a la pantalla principal +show infolog entries for this organisation addressbook ca Mostra informació de registre per aquesta organització +show the contacts of this organisation addressbook ca Mostra els contactes d'aquesta organització +size of popup (wxh, eg.400x300, if a popup should be used) admin ca Mida de l'element emergent (WxH, p.ex.400x300, si un element emergent fos usat) +start admin ca Inici +startrecord addressbook ca Registre inicial +state common ca Província +street common ca Carrer +successfully imported %1 records into your addressbook. addressbook ca Importats correctament %1 registres a la llibreta d'adreces. +suffix addressbook ca Sufix +tel home addressbook ca tel casa +telephony integration admin ca Integració telefònica +test import (show importable records only in browser) addressbook ca Prova d'Importació - (mostrar els registres que es poden importar només al navegador) +that field name has been used already ! addressbook ca Aquest nom de camp ja s'ha usat ! +this person's first name was not in the address book. addressbook ca El nom de pila d'aquesta persona no hi era a la llibreta d'adreces. +this person's last name was not in the address book. addressbook ca El cognom d'aquesta persona no hi era a la llibreta d'adreces. +timezone addressbook ca Zona horària +to many might exceed your execution-time-limit addressbook ca quant pot excedir el temps límit d'execució +today is %1's birthday! common ca Avui és l'aniversari de %1! +tomorrow is %1's birthday. common ca Demà és l'aniversari de %1. +translation addressbook ca Traducció +type addressbook ca Tipus +update a single entry by passing the fields. addressbook ca Actualitzar una sola entrada passant els camps +upload or delete the photo addressbook ca Carrega o esborra la foto +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin ca URL per enllaçar-hi números de telèfon (utilitzeu %1 = número per trucar, %u = nom de compte, %t = telèfon de compte) +use an extra category tab? addressbook ca Utilitzeu una pestanya de categoria extra? +use country list addressbook ca Utilitzar llista de països +use setup for a full account-migration admin ca utilitzeu la instal·lació per una migració de compte complerta +used for links and for the own sorting of the list addressbook ca utilitzat per enllaços i per l'ordenació pròpia de la llista +vcard common ca Targeta de visita (VCard) +vcards require a first name entry. addressbook ca VCard necessita el nom. +vcards require a last name entry. addressbook ca VCard necessita el cognom. +view linked infolog entries addressbook ca Veure enllaçades entrades InfoLog +warning!! ldap is valid only if you are not using contacts for accounts storage! admin ca ATENCIÓ!! LDAP és vàlid només si NO feu servir contactes per enmagatzemar comptes! +warning: all contacts found will be deleted! addressbook ca ATENCIÓ: Tots els contacte trobats s'esborraran! +what should links to the addressbook display in other applications. empty values will be left out. you need to log in anew, if you change this setting! addressbook ca Què han de mostrar els enllaços a la llibreta d'adreces en altres aplicacions. Els valors buits no es tindran en compte. Necessiteu iniciar la sessió de nou, si canvieu aquest paràmetre! +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook ca Quin format d'adreça hauria d'utilitzar la llibreta d'adreces per països dels que no sap el format d'adreça. Si el format d'adreça d'un país és conegut, l'utilitza independentment d'aquest paràmetre. +which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook ca Quina llista d'adreces ha de ser seleccionada quan s'afegeix un contacte I no teniu drets afegits a la llibreta d'adreces actual. +which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook ca Quin joc de caràcters ha de ser utilitzat per l'exportació CSV. El sistema per defecte és el joc de caràcters de la instal·lació d'aquest eGroupWare. +which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook ca Quins camps han de ser exportats. Tot significa cada camp guardat en la llista d'adreces incloent els camps personalitzats. Les adreces de la feina o el domicili només contenen nom, empresa i l'adreça seleccionada. +whole query addressbook ca consulta sencera +work phone addressbook ca Telèfon del treball +write (update or add) a single entry by passing the fields. addressbook ca Escriu (actualitza o afegeix) una entrada simple, donant els camps. +yes, for the next three days addressbook ca Sí, pels propers tres dies +yes, for the next two weeks addressbook ca Sí, per les properes dues setmanes +yes, for the next week addressbook ca Sí, per la propera setmana +yes, for today and tomorrow addressbook ca Sí, per avui i demà +you are not permitted to delete contact %1 addressbook ca No tens permís per esborrar el contacte %1 +you are not permittet to delete this contact addressbook ca No tens permís per esborrar aquest contacte +you are not permittet to edit this contact addressbook ca No tens permís per editar aquest contacte +you are not permittet to view this contact addressbook ca No tens permís per veure aquest contacte +you can only use ldap as contact repository if the accounts are stored in ldap too! admin ca Només podeu utilitzar LDAP com a dipòsit de contactes si els comptes estan emmagatzemats en LDAP també! +you must select a vcard. (*.vcf) addressbook ca Heu de seleccionar una targeta vcard (*.vcf) +you must select at least 1 column to display addressbook ca Heu de seleccionar al menys una columna per mostrar +you need to select a distribution list addressbook ca Necessiteu seleccionar una llista de distribució +you need to select some contacts first addressbook ca Necessiteu seleccionar algún contacte, primer +zip code common ca Codi postal +zip_note addressbook ca
Nota: L'arxiu pot ser un arxiu comprimit zip que tingui arxius .csv, .vcf o .ldif. Tanmateix, no barregeu els tipus en cada importació.
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_cs.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_cs.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_cs.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_cs.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,407 @@
+%1 added addressbook cs %1 přidáno
+%1 contact(s) %2 addressbook cs %1 kontakt(ů) %2
+%1 contact(s) %2, %3 failed because of insufficent rights !!! addressbook cs %1 kontakt(ů) %2, %3 selhal(o) z důvodu nedostatečných oprávnění !!!
+%1 fields in %2 other organisation member(s) changed addressbook cs %1 polí u %2 ostatních členů organizace změněno
+%1 records imported addressbook cs %1 záznamů importováno
+%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook cs %1 záznamů načteno (zatím nebyly importovány, můžete se vrátit %2zpět%3 a odškrtnout Testovat Import)
+%1 starts with '%2' addressbook cs %1 začíná s '%2'
+%s please calculate the result addressbook cs %s prosím spočítejte výsledek
+(e.g. 1969) addressbook cs (např. 1969)
+no conversion type <none> could be located. please choose a conversion type from the list addressbook cs Žádný konverzní typ
Nebo v Outlooku vyberte složku s Kontakty, zvolte Import a export z menu Start a vyexportujte své kontakty do souboru typu CSV (text oddělený čárkami).
Nebo v Palm Desktopu 4.0 a vyšším vyberte Export z menu File. Exportovaný soubor bude ve formátu VCard. +imports contacts into your addressbook from a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. addressbook cs Importuje kontakty z CSV souboru do Vašeho adresáře. CSV znamená 'hodnoty oddělené čárkou'. Nicméně v záložce voleb si můžete zvolit jiné oddělovače. +in %1 days (%2) is %3's birthday. addressbook cs Za %1 dní (%2) má %3 narozeniny. +income addressbook cs Hospodářský výsledek +insert in document addressbook cs Vložit do dokumentu +insufficent rights to delete this list! addressbook cs Nemáte dostatečná oprávnění ke smazání seznamu! +international addressbook cs Mezinárodní +label addressbook cs Jmenovka +last date addressbook cs Poslední datum +last modified addressbook cs naposledy změněno +last modified by addressbook cs naposledy změnil(a) +ldap context for contacts admin cs LDAP kontext pro kontakty +ldap host for contacts admin cs LDAP server pro kontakty +ldap settings for contacts admin cs nastavení LDAP pro kontakty +ldif addressbook cs LDIF +line 2 addressbook cs Řádek 2 +link title for contacts show addressbook cs Odkazovat nadpis pro zobrazení kontaktů +links addressbook cs Odkazy +list all categories addressbook cs Vypsat všechny kategorie +list all customfields addressbook cs Vypsat všechny uživatelsky definované položky +list already exists! addressbook cs Seznam už existuje! +list created addressbook cs Seznam vytvořen +list creation failed, no rights! addressbook cs Vytvoření seznamu selhalo, nedostatečná práva! +load sample file addressbook cs Načíst ukázkový soubor +load vcard addressbook cs Nahrát VCard +location addressbook cs Umístění +locations addressbook cs umístění +manage mapping addressbook cs Spravovat mapování +mark records as private addressbook cs Označit záznamy jako soukromé +merge into first or account, deletes all other! addressbook cs Sloučení do prvního nebo do účtu, smaže všechny ostatní! +merged addressbook cs sloučeno +message after submitting the form addressbook cs Zpráva po odeslání formuláře +message phone addressbook cs Telefon pro zprávy +middle name addressbook cs Prostřední jméno +migration finished addressbook cs Migrace ukončena +migration to ldap admin cs Migrace do LDAP +mobile addressbook cs Mobilní +mobile phone addressbook cs Mobilní telefon +modem phone addressbook cs Telefon modemu +more ... addressbook cs Více ... +move to addressbook: addressbook cs Přesunout do adresáře: +moved addressbook cs přesunuto +multiple vcard addressbook cs Více VCard +name for the distribution list addressbook cs Název distribučního seznamu +name of current user, all other contact fields are valid too addressbook cs Jméno aktuálního uživatele, všechny ostatní položky kontaktu jsou také platné +name, address addressbook cs Jméno, adresa +new contact submitted by %1 at %2 addressbook cs Nový kontakt odeslal(a) %1 v %2 +new window opened to edit infolog for your selection addressbook cs Otevřeno nové okno pro editaci Infologu na základě vašeho výběru +next date addressbook cs Následující datum +no categories selected addressbook cs nebyly vybrány žádné kategorie +no vcard addressbook cs Žádná VCard +number addressbook cs Čislo +number of records to read (%1) addressbook cs Počet záznamů k načtení (%1) +options for type admin cs Volby pro typ +organisation addressbook cs Organizace +organisations addressbook cs Organizace +organisations by departments addressbook cs Organizace dle oddělení +organisations by location addressbook cs Organizace dle umístění +other number addressbook cs Jiné číslo +other phone addressbook cs Jiný telefon +own sorting addressbook cs vlastní třídění +pager common cs Pager +parcel addressbook cs Pozemek +participants addressbook cs Účastníci +permission denied !!! addressbook cs Přístup zablokován!!! +phone number common cs Telefonní číslo +phone numbers common cs Telefonní čísla +photo addressbook cs Fotografie +please enter a name for that field ! addressbook cs Zadejte prosím název pro tuto položku! +please select only one category addressbook cs Vyberte prosím jen jednu kategorii +please update the templatename in your customfields section! addressbook cs Zaktualizujte prosím název šablony ve Vaší sekci uživatelsky definovaných položek! +postal common cs PSČ +pref addressbook cs preferovaný +preferred email address to use in distribution lists addressbook cs Preferovaná e-mailová adresa pro použití v distribučních seznamech +preferred phone addressbook cs preferovaný telefon +preferred type of email address to add for distribution lists addressbook cs preferovaný typ e-mailové adresy pro přidávání do distribučních seznamů +prefix addressbook cs Titul/Oslovení +public key addressbook cs Veřejný klíč +publish into groups: addressbook cs Zveřejnit ve skupinách: +read a list / search for entries. addressbook cs Načíst seznam / vyhledat záznamy. +read a list of entries. addressbook cs Načíst seznam záznamů. +read a single entry by passing the id and fieldlist. addressbook cs Načíst záznam zadáním id a seznamu položek. +read only addressbook cs jen ke čtení +record access addressbook cs Přístup k záznamu +record owner addressbook cs Vlastník záznamu +remove selected contacts from distribution list addressbook cs Odstranit vybrané kontakty z distribučního seznamu +removed from distribution list addressbook cs odstraněno z distribučního seznamu +repetition addressbook cs Opakování +replacements for inserting contacts into documents addressbook cs Náhrady pro vkládání kontaktů do dokumentů +required fields * addressbook cs povinné položky * +role addressbook cs Role +room addressbook cs Místnost +search for '%1' addressbook cs Hledat '%1' +select a portrait format jpeg photo. it will be resized to 60 pixel width. addressbook cs Vyberte portrét ve formátu jpeg. Bude upraven na šířku 60 pixelů. +select a view addressbook cs Vybrat pohled +select addressbook type addressbook cs Vybrat typ adresáře +select all addressbook cs Vybrat vše +select an action or addressbook to move to addressbook cs Vybrat akci nebo adresář kam se přesunout +select migration type admin cs Vybrat typ migrace +select multiple contacts for a further action addressbook cs Vybrat více kontaktů pro další akci +select phone number as prefered way of contact addressbook cs vybrat telefonní číslo jako preferovaný způsob kontaktu +select the type of conversion addressbook cs Vybrat typ konverze +select the type of conversion: addressbook cs Vybrat typ konverze: +select where you want to store / retrieve contacts admin cs Vybrat úložiště kontaktů +selected contacts addressbook cs vybrané kontakty +should the columns photo and home address always be displayed, even if they are empty. addressbook cs Mají být sloupce fotografie a domovská adresa vždy zobrazeny i když jsou prázdné +show addressbook cs Zobrazit +show birthday reminders on main screen addressbook cs Zobrazit upomínky na narozeniny na hlavní obrazovce +show infolog entries for this organisation addressbook cs Zobrazit záznamy InfoLogu pro tuto organizaci +show the contacts of this organisation addressbook cs Zobrazit kontakty této organizace +size of popup (wxh, eg.400x300, if a popup should be used) admin cs Velikost překryvného okna (ŠxV, např. 400x300, pokud má být překryvné okno používáno) +start admin cs Start +startrecord addressbook cs První záznam +state common cs Stát +street common cs Ulice +subject for email addressbook cs Předmět e-mailu +successfully imported %1 records into your addressbook. addressbook cs Úspěšně importováno %1 zaznamů do Vačeho adresáře. +suffix addressbook cs Za příjmením +tel home addressbook cs telefon domů +telephony integration admin cs Integrace telefonie +test import (show importable records only in browser) addressbook cs Testovat import (zobrazit importovatelné záznamy jen v prohlížeči) +thank you for contacting us. addressbook cs Děkujeme, že jste nás kontaktoval(a). +that field name has been used already ! addressbook cs Tento název položky je již používán ! +the anonymous user has probably no add rights for this addressbook. addressbook cs Anonymní uživatel patrně nemá práva k přidávání záznamů do adresáře. +the anonymous user needs add rights for it! addressbook cs Anonymní uživatel potřebuje práva k přidávání záznamů. +the anonymous user needs read it! addressbook cs Anonymní uživatel potřebuje právo pro čtení! +the document can contain placeholder like $$n_fn$$, to be replaced with the contact data (%1full list of placeholder names%2). addressbook cs Dokument může obsahovat rezervovaná místa jako $$n_fn$$, která budou nahrazena daty kontaktu (%1kompletní seznam názvů rezervovaných míst%2). +there was an error saving your data :-( addressbook cs Došlo k chybě při ukládání Vašich dat :-( +this module displays a contactform, that stores direct into the addressbook. addressbook cs Tento modul zobrazuje formulář kontaktu, který ukládá data přímo do adresáře. +this module displays block from a adddressbook group. addressbook cs Tento modul zobrazuje blok z adresářové skupiny. +this person's first name was not in the address book. addressbook cs Křestní jméno této osoby nebylo v adresáři. +this person's last name was not in the address book. addressbook cs Příjmení této osoby nebylo v adresáři. +timezone addressbook cs Časová zóna +to many might exceed your execution-time-limit addressbook cs příliš mnoho může překročit nastavený časový limit spuštění +today is %1's birthday! common cs Dnes má narozeniny %1! +tomorrow is %1's birthday. common cs Zítra má narozeniny %1! +translation addressbook cs Překlad +type addressbook cs Typ +update a single entry by passing the fields. addressbook cs Aktualizovat záznam vyplněním položek. +update fields by edited organisations? admin cs Aktualizovat položky editovanými organizacemi? +updated addressbook cs Aktualizováno +upload or delete the photo addressbook cs Upload nebo smazání fotografie +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin cs URL na které má telefonní číslo odkazovat (použijte %1 = vytáčené telefonní číslo, %u = název účtu, %t = telefon účtu) +use an extra category tab? addressbook cs Použít extra založku pro kategorii? +use an extra tab for private custom fields? admin cs Použít extra založku pro soukromé uživatelsky definované položky? +use country list addressbook cs Použít seznam zemí +use setup for a full account-migration admin cs pro kompletní migraci účtů použijte setup +used for links and for the own sorting of the list addressbook cs použito pro odkazy a vlastní třídění seznamu +vcard common cs VCard +vcards require a first name entry. addressbook cs VCard vyžaduje křestní jméno v záznamu +vcards require a last name entry. addressbook cs VCard vyžaduje příjmení v záznamu +verification addressbook cs Ověření +view linked infolog entries addressbook cs Zobrazit odkazované záznamy v InfoLogu +warning!! ldap is valid only if you are not using contacts for accounts storage! admin cs VAROVÁNÍ!! LDAP je použitelný jen v případě, že NEpoužíváte kontakty pro ukládání uživatelských účtů! +warning: all contacts found will be deleted! addressbook cs VAROVÁNÍ: Všechny kontakty budou smazány! +warning: template "%1" not found, using default template instead. addressbook cs VAROVÁNÍ: Šablona "%1" nebyla nalezena, bude použita výchozí. +weekday addressbook cs Pracovní den +what should links to the addressbook display in other applications. empty values will be left out. you need to log in anew, if you change this setting! addressbook cs Co mají odkazy na adresář zobrazovat v ostatních aplikacích. Prázdné hodnoty budou vynechány. Pokud změníte toto nastavení, musíte se znovu přihlásit! +where to add the email address addressbook cs kam přidat e-mailovou adresu +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook cs Jaký formát adres má adresář používat u zemí, jejichž adresní formát nezná. Pokud je formát znám, je použit bez ohledu na toto nastavení. +which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook cs Který adresář má být vybrán v případě, že přidáváte kontakt a pro aktuální adresář nemáte dostatečná práva. +which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook cs Která znaková sada má být použita pro CSV export? Výchozí znakovou sadou je znaková sada použitá pro instalaci eGroupWare. +which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook cs Které položky budou exportovány. Všechny znamená každou položku včetně uživatelsky definovaných. Firemní nebo domácí obsahuje jen jméno, firmu a vybranou adresu. +whole query addressbook cs celý dotaz +work email if given, else home email addressbook cs Pracovní e-mail, je-li definován, jinak domácí +work phone addressbook cs Pracovní telefon +write (update or add) a single entry by passing the fields. addressbook cs Zapsat (aktualizovat nebo přidat) záznam vyplněním položek. +wrong - try again ... addressbook cs Špatně - zkuste znovu ... +yes, for the next three days addressbook cs Ano, po následující tři měsíce +yes, for the next two weeks addressbook cs Ano, po následující dva týdny +yes, for the next week addressbook cs Ano, po následující týden +yes, for today and tomorrow addressbook cs Ano, po dnešní a zítřejší den +you are not permitted to delete contact %1 addressbook cs Nemáte oprávnění ke smazání kontaktu %1 +you are not permittet to delete this contact addressbook cs Nemáte oprávnění ke smazání tohoto kontaktu +you are not permittet to edit this contact addressbook cs Nemáte oprávnění k editaci tohoto kontaktu +you are not permittet to view this contact addressbook cs nemáte oprávnění k prohlížení tohoto kontaktu +you can only use ldap as contact repository if the accounts are stored in ldap too! admin cs LDAP můžete používat jako databázi kontaktů jen v případě, že máte v LDAP uloženy také uživatelské účty! +you can respond by visiting: addressbook cs Pro zobrazení navštivte: +you must select a vcard. (*.vcf) addressbook cs Musíte vybrat vCard. (*.vcf) +you must select at least 1 column to display addressbook cs Musíte vybrat nejméně jeden sloupec k zobrazení +you need to select a distribution list addressbook cs Musíte vybrat distribuční seznam +you need to select some contacts first addressbook cs Nejprve musíte vybrat nějaké kontakty +zip code common cs PSČ +zip_note addressbook cs
Poznámka:Soubor může být zip archiv .csv, .vcf nebo .ldif souborů. Nesmíte však kombinovat různé typy souborů během jednoho importu.
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_da.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_da.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_da.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_da.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,187 @@
+%1 records imported addressbook da %1 posteringer importeret
+%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook da %1 posteringer læst (ikke implamenteret endnu, du skalgå %2tilbage%3 og fravælge Test import
+(e.g. 1969) addressbook da (f.eks 1969)
+no conversion type <none> could be located. please choose a conversion type from the list addressbook da Ingen konverteringstype
Eller i Outlook, vælg din kontakt mappe, vælg Import and Export... fra b>File menuen og eksporter dine kontakt personer til en komma separeret fil (CSV).
Eller, i Palm Desktop 4.0 eller nyere, brug adressebogen og vælg Export fra File menuen. Den eksporteret fil vil være i VCard formatet +international addressbook da International +isdn phone addressbook da ISDN Telefonnummer +label addressbook da Mærkat +last modified addressbook da Sidst opdateret +ldap context for contacts admin da LDAP context til kontakter +ldap host for contacts admin da LDAP vært for kontakter +ldap root dn for contacts admin da LDAP root dn til kontakter +ldap root pw for contacts admin da LDAP root pw til kontakter +ldif addressbook da LDIF +line 2 addressbook da Linie 2 +links addressbook da Links +list all categories addressbook da List alle kategorier +list all customfields addressbook da List alle tilpassede felter +mark records as private addressbook da Markere posteringer som private +message phone addressbook da Meddellelses Telefonnummer +middle name addressbook da Mellemnavn(e) +mobile addressbook da Mobil +mobile phone addressbook da Mobiltelefonnummer +modem phone addressbook da Modem telefonnummer +more ... addressbook da Mere ... +multiple vcard addressbook da Flere VCards +no vcard addressbook da Ingen VCard +number addressbook da Nummer +number of records to read (%1) addressbook da Antal posteringer at læse (%1) +organisation addressbook da Organisation +other number addressbook da Andet nummer +other phone addressbook da Andet Telefonnummer +pager common da Pager +parcel addressbook da Pakke +phone number common da Telefonnummer +phone numbers common da Telefonnumre +please enter a name for that field ! addressbook da Skriv venligst et navn for det felt! +postal common da Post +pref addressbook da foretrukket +prefix addressbook da Prefix +public key addressbook da Offentlig Nøgle +read a list / search for entries. addressbook da Læs liste / søg for elementer +read a list of entries. addressbook da Læs en liste af indtastninger +read a single entry by passing the id and fieldlist. addressbook da Læs et enkelt element ved at give id og fil-liste +record access addressbook da Posterings adgang +record owner addressbook da Posterings ejer +retrieve contacts admin da hent kontakter +select all addressbook da Vælg alle +select the type of conversion addressbook da Vælg type af konvertering +select the type of conversion: addressbook da Vælg type af konvertering: +select where you want to store admin da Vælg hvor du vil gemme +show addressbook da Vis +show birthday reminders on main screen addressbook da Påmind om fødselsdage på forsiden +something went wrong by deleting %1 addressbook da Noget gik galt ved sletning af %1 +something went wrong by deleting this contact addressbook da Noget gik galt med at slette denne kontakt +something went wrong by reading this contact addressbook da Noget gik galt med at læse denne kontakt +something went wrong by saving this contact. errorcode %1 addressbook da Noget gik galt med at gemme denne kontakt. Fejl %1 +startrecord addressbook da Start postering +state common da Land +street common da Vej navn +successfully imported %1 records into your addressbook. addressbook da Importerede %1 posteringer til din adressebog. +suffix addressbook da Suffix +tel home addressbook da Tlf. hjemme +test import (show importable records only in browser) addressbook da Test Import (viser kun importeret posteringer i browser vinduet) +that field name has been used already ! addressbook da Det felt navn er allerede blevet brugt! +this person's first name was not in the address book. addressbook da Denne persons fornavn var ikke i adressebogen. +this person's last name was not in the address book. addressbook da Denne persons efternavn var ikke i adressebogen. +to many might exceed your execution-time-limit addressbook da for mange kan overskride din tildelte tid +today is %1's birthday! common da I dag er det %1's fødselsdag! +tomorrow is %1's birthday. common da I morgen er det %1's fødselsdag. +translation addressbook da Oversættelse +update a single entry by passing the fields. addressbook da opdater et enkelt element ve at sende felter. +use country list addressbook da Brug Lande Liste +vcard common da VCard +vcards require a first name entry. addressbook da VCards kræver et fornavn indtastet. +vcards require a last name entry. addressbook da VCards kræver et efternavn indtastet. +video phone addressbook da Video telefonnummer +voice phone addressbook da Voice telefonnummer +warning!! ldap is valid only if you are not using contacts for accounts storage! admin da ADVARSEL!! LDAP er kun tilgængeligt hvis du ikke bruger kontakter til at gemme kontoer! +warning: all contacts found will be deleted! addressbook da ADVARSEL: Alle fundne kontakter vil blive slettet ! +work phone addressbook da Arbejds telefon +you are not permitted to delete contact %1 addressbook da Du har ikke ret til at slettekontakt %1 +you are not permittet to delete this contact addressbook da Du har ikke tilladelse til at slette denne kontakt. +you are not permittet to edit this contact addressbook da Du har ikke tilladelse til at rette denne kontakt. +you are not permittet to view this contact addressbook da Du har ikke tilladelse til at se denne kontakt. +you must select a vcard. (*.vcf) addressbook da Du skal vælge et vcard. (*.vcf) +you must select at least 1 column to display addressbook da Du skal mindst vælge en kolonne +zip code common da Postnummer +zip_note addressbook da
Note:Filen kan være en zip file med komprimeret .csv, .vcf eller .ldif filer. Men, importer kun en type ad gangen.
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_de.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_de.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_de.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_de.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,410 @@
+%1 added addressbook de %1 hinzugefügt
+%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 fields in %2 other organisation member(s) changed addressbook de %1 Felder in %2 Mitglied(ern) der Organisation geändert
+%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'
+%s please calculate the result addressbook de %s Bitte berechnen Sie das Ergebnis
+(e.g. 1969) addressbook de (z.B. 1966)
+(empty = use global limit, no = no export at all) admin de (leer = globale Begrenzung verwenden, nein = gar kein Export)
+no conversion type <none> could be located. please choose a conversion type from the list addressbook de Kein Übersetzungstyp
In Outlook wählen Sie den Ordner Kontakte aus, wählen Sie Importieren und Exportieren...
aus dem Datei Menü aus und Exportieren Sie die Kontakte als eine CSV Datei.In Palm Desktop 4.0 oder größer, öffnen Sie Ihr Adressbuch und wählen Sie Export aus dem Datei-Menü aus. Die Datei wird im VCard-Format exportiert. +imports contacts into your addressbook from a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. addressbook de Importiert Kontakte aus einer CSV Datei in Ihr Adressbuch. CSV bedeutet Komma getrennte Werte. Sie können in dem Reiter Einstellungen auch ein anderes Trennzeichen wählen. +in %1 days (%2) is %3's birthday. addressbook de In %1 Tagen (%2) ist der Geburtstag von %3. +income addressbook de Einkommen +insert in document addressbook de Einfügen in Dokument +insufficent rights to delete this list! addressbook de Keine Rechte diese Liste zu löschen! +international addressbook de International +label addressbook de Adressetikett +last date addressbook de Letzter Termin +last modified addressbook de Letzte Änderung +last modified by addressbook de Letzte Änderung durch +ldap context for contacts admin de LDAP Kontext für Kontakte +ldap host for contacts admin de LDAP Host für Kontakte +ldap settings for contacts admin de LDAP Einstellungen für Kontakte +ldif addressbook de LDIF +line 2 addressbook de Zeile 2 +link title for contacts show addressbook de Titel der Verknüpfung für Kontakte zeigt +links addressbook de Verknüpfungen +list all categories addressbook de Liste alle Kategorien +list all customfields addressbook de Liste alle benutzerdefinierten Felder +list already exists! addressbook de Die Liste existiert bereits! +list created addressbook de Verteiler erzeugt +list creation failed, no rights! addressbook de Verteiler erzeugen fehlgeschlagen, keine Rechte! +load sample file addressbook de Beispieldatei laden +load vcard addressbook de VCard laden +location addressbook de Standort +locations addressbook de Standorte +manage mapping addressbook de Zuordnungen verwalten +mark records as private addressbook de Eintrag als Privat kennzeichnen +merge into first or account, deletes all other! addressbook de Vereinige im ersten oder Benutzerkonto, löscht alle anderen! +merged addressbook de vereinigt +message after submitting the form addressbook de Nachricht nach dem Abschicken des Formulars +message phone addressbook de Anrufbeantworter +middle name addressbook de Zweiter Vorname +migration finished addressbook de Migration beendet +migration to ldap admin de Migration nach LDAP +mobile addressbook de Mobil +mobile phone addressbook de Mobiltelefon +modem phone addressbook de Modem +more ... addressbook de Mehr ... +move to addressbook: addressbook de Verschiebe ins Adressbuch: +moved addressbook de verschoben +multiple vcard addressbook de Mehrere VCards +name for the distribution list addressbook de Name für die Verteilerliste +name of current user, all other contact fields are valid too addressbook de Name des aktuellen Benutzers, auch alle anderen Kontaktfelder sind erlaubt +name, address addressbook de Name, Adresse +new contact submitted by %1 at %2 addressbook de Neuer Kontakt eingetragen von %1 am %2 +new window opened to edit infolog for your selection addressbook de Es wird ein neues Fenster zum erstellen des Infolog Eintrags geöffnet +next date addressbook de Nächster Termin +no categories selected addressbook de keine Kategorien ausgewählt +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 admin de Optionen für Typ +organisation addressbook de Organisation +organisations addressbook de Organisationen +organisations by departments addressbook de Organisationen nach Abteilungen +organisations by location addressbook de Organisationen nach Standorten +other number addressbook de andere Nr. +other phone addressbook de anderes Telefon +own sorting addressbook de eigene Sortierung +pager common de Pager +parcel addressbook de Lieferadresse +participants addressbook de Teilnehmer +permission denied !!! addressbook de Zugriff verweigert !!! +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 +please update the templatename in your customfields section! addressbook de Passen Sie bitte in der Sektion "Benutzerdefinierte Felder" Ihren Templatenamen an! +postal common de Postanschrift +pref addressbook de präf +preferred email address to use in distribution lists addressbook de Bevorzugte E-Mailadresse für Verteilerlisten +preferred phone addressbook de präferierte Telefonnummer +preferred type of email address to add for distribution lists addressbook de bevorzugter Typ der E-Mailadresse für Verteilerlisten +prefix addressbook de Anrede +public key addressbook de öffentlicher Schlüssel +publish into groups: addressbook de In folgende Gruppen veröffentlichen: +read a list / search for entries. addressbook de Lese die Liste / Suche nach Einträgen +read a list of entries. addressbook de Liest eine Liste von Einträgen. +read a single entry by passing the id and fieldlist. addressbook de Liest einen einzelnen Eintrag über seine ID und Feldliste. +read only addressbook de nur lesend +record access addressbook de Zugriffsrechte +record owner addressbook de Datensatzeigentümer +remove selected contacts from distribution list addressbook de Ausgewählte Kontakte vom Verteiler löschen +removed from distribution list addressbook de vom Verteiler gelöscht +repetition addressbook de Wiederholung +replacements for inserting contacts into documents addressbook de Platzhalter für das Einfügen von Kontakten in Dokumente +required fields * addressbook de unbedingt auszufüllende Felder * +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 a view addressbook de Eine Ansicht auswählen +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 migration type admin de Migrationstyp auswählen +select multiple contacts for a further action addressbook de Mehrere Adressen für weiteren Befehl auswählen +select phone number as prefered way of contact addressbook de Telefonnummer als präferierten Kontaktweg 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 / retrieve contacts admin de Auswählen wo Sie Adressen speichern wollen +selected contacts addressbook de ausgewählte Kontakte +should the columns photo and home address always be displayed, even if they are empty. addressbook de Sollen die Spalten Foto und Privatadresse immer angezeigt werden, auch wenn sie leer sind. +show addressbook de Anzeigen +show birthday reminders on main screen addressbook de Geburtstagserinnerungen auf der Startseite anzeigen +show infolog entries for this organisation addressbook de InfoLog Einträge dieser Organisation anzeigen +show the contacts of this organisation addressbook de Kontakte dieser Organisation anzeigen +size of popup (wxh, eg.400x300, if a popup should be used) admin de Größe des Popup (WxH, zB. 400x300, falls ein Popup verwendet werden soll) +start admin de Starten +startrecord addressbook de Startdatensatz +state common de Bundesland +street common de Straße +subject for email addressbook de Betreff der Email +successfully imported %1 records into your addressbook. addressbook de %1 Kontakte wurden erfolgreich in Ihr Adressbuch importiert +suffix addressbook de Zusatz +tel home addressbook de Telefon privat +telephony integration admin de Telefonie Integration +test import (show importable records only in browser) addressbook de Test-Import (zeigt importierbare Datensätze nur im Browser an) +thank you for contacting us. addressbook de Danke das Sie uns kontaktierten. +that field name has been used already ! addressbook de Dieser Feldname wird bereits benutzt! +the anonymous user has probably no add rights for this addressbook. addressbook de Der anonyme Benutzer hat vermutlich keine Hinzufügen Rechte für diese Adressbuch. +the anonymous user needs add rights for it! addressbook de Der anonyme Benutzer benötigt Hinzufügen Rechte dafür! +the anonymous user needs read it! addressbook de Der Anonymous Benutzer muss dies lesen können +the document can contain placeholder like $$n_fn$$, to be replaced with the contact data (%1full list of placeholder names%2). addressbook de Das Dokument kann Platzhalter wie $$n_fn$$ enthalten, die mit den Kontaktdaten ersetzt werden (%1komplette Liste der Platzhalter%2). +there was an error saving your data :-( addressbook de Beim Speichern ihrer Daten ist ein Fehler aufgetreten :-( +this module displays a contactform, that stores direct into the addressbook. addressbook de Diese Module ist ein Kontaktformular, das direkt in das Adressbuch speichert. +this module displays block from a adddressbook group. addressbook de Dieses Modul zeigt einen Block vom Adressbuch an. +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 +type addressbook de Typ +update a single entry by passing the fields. addressbook de Aktualisiert einen einzelnen Eintrag durch Übergabe seiner Felder. +update fields by edited organisations? admin de Welche Felder sollen beim Bearbeiten von Organisationen aktualisiert werden? +updated addressbook de Aktualisiert +upload or delete the photo addressbook de Foto hochladen oder löschen +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin de URL mit denen Telefonnummern verlinkt werden sollen (verwenden Sie %1 = anzurufende Nummer, %u = Benutzernamen, %t = Telefon des Benutzers) +use an extra category tab? addressbook de Separaten Reiter für Kategorien verwenden? +use an extra tab for private custom fields? admin de Separaten Reiter für private benutzerdefinierte Felder verwenden? +use country list addressbook de Länderliste benutzen +use setup for a full account-migration admin de für eine komplette Benutzer Migration setup verwenden +used for links and for the own sorting of the list addressbook de wird für Verküpfungen und die eigene Sortierung der Liste benützt +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. +verification addressbook de Verifikation +view linked infolog entries addressbook de Verknüpfte InfoLog Einträge anzeigen +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! +warning: template "%1" not found, using default template instead. addressbook de WARNUNG: Template "%1" nicht gefunden, das Standard-Template wird stattdessen benutzt. +weekday addressbook de Wochentag +what should links to the addressbook display in other applications. empty values will be left out. you need to log in anew, if you change this setting! addressbook de Was sollen Verknüpfungen zum Adressbuch in anderen Anwendungen anzeigen. Leere Werte werden ausgelassen. Sie müssen sich neu anmelden, wenn Sie hier eine Änderung vornehmen! +where to add the email address addressbook de wo soll die E-Mailadresse hinzugefügt werden +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook de Welches Format soll das Adressbuch für Adressen verwenden deren landesübliches Adressformat unbekannt ist. Wenn das Adressformat eines Landes dem Adressbuch bekannt ist, wird das unabhängig von dieser Einstellung benutzt. +which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook de Welches Adressbuch soll ausgewählt sein beim Hinzufügen von Kontakten, wenn Sie keine Hinzufügen Rechte zum aktuellen Adressbuch haben. +which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook de Welcher Zeichensatz soll für den CSV Export verwendet werden. Die systemweite Vorgabe ist der Zeichensatz der eGroupWare Installation. +which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook de Welche Felder sollen exportiert werden. Alle bedeutet jedes Feld das im Adressbuch gespeichert ist einschl. der benutzerdefinierten Felder. Die Geschäfts- oder Privatadresse enthält nur Name, Firma und die ausgewählte Adresse. +whole query addressbook de gesamte Abfrage +work email if given, else home email addressbook de Geschäftliche E-Mail wenn vorhanden, ansonsten private E-Mail +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 +wrong - try again ... addressbook de Falsch - nochmal versuchen ... +yes, for the next three days addressbook de Ja, für die nächsten drei Tage +yes, for the next two weeks addressbook de Ja, für die nächsten zwei Wochen +yes, for the next week addressbook de Ja, für die nächste Woche +yes, for today and tomorrow addressbook de Ja, für heute und morgen +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 can only use ldap as contact repository if the accounts are stored in ldap too! admin de Sie können LDAP nur dann zum Speichern von Kontakten verwenden, wenn die Benutzerkonten auch in LDAP gespeichert sind! +you can respond by visiting: addressbook de Link zum Anzeigen: +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 a distribution list addressbook de Sie müssen eine Verteilerliste 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
Notiz:Die Datei kann ein zip Archiv sein, bestehend aus .csv, .vcf oder .ldif Dateien. Sie dürfen die Dateitypen pro Import nicht mischen!
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_el.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_el.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_el.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_el.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,350 @@
+%1 added addressbook el %1 προστέθηκε
+%1 contact(s) %2 addressbook el %1 επαφή(ές) %2
+%1 contact(s) %2, %3 failed because of insufficent rights !!! addressbook el %1 επαφή(ές) %2, %3 απέτυχαν εξαιτίας ανεπαρκών δικαιωμάτων !!!
+%1 fields in %2 other organisation member(s) changed addressbook el %1 πεδία σε %2 άλλου οργανισμού μέλος(η) άλλαξαν
+%1 records imported addressbook el %1 εγγραφές εισήχθησαν
+%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook el %1 εγγραφές αναγνώσθηκαν (δεν εισηχθησαν ακόμη, μπορείτε να %2επιστρέψετε%3 και να ξετσεκάρετε τη Δοκιμαστική Εισαγωγή)
+%1 starts with '%2' addressbook el %1 ξεκινά με '%2'
+%s please calculate the result addressbook el %s παρακαλώ υπολογίστε το αποτέλεσμα
+(e.g. 1969) addressbook el (π.χ. 1969)
+no conversion type <none> could be located. please choose a conversion type from the list addressbook el Κανένας τύπος μετατροπής
Ή, στο Outlook, επιλέξτε το φάκελο Eπαφών, επιλέξτεImport and Export... από το File menu και εξάγετε τις επαφές σας σε ένα CSV αρχείο.
Ή, στο Palm Desktop 4.0 ή μεγαλύτερο, επισκεφθείτε το βιβλίο διευθύνσεων σας και επιλέξτε Export από το File menu.Το εξαγώγιμο αρχείο θα ειναι σε VCard μορφή. +in %1 days (%2) is %3's birthday. addressbook el Σε %1 ημέρες (%2) είναι του/της %3 τα γενέθλια. +income addressbook el Εισόδημα +insufficent rights to delete this list! addressbook el Ανεπαρκή δικαιώματα για διαγραφή αυτής της λίστας! +international addressbook el Διεθνείς +label addressbook el Ετικέττα +last modified addressbook el Τελευταία τροποποίηση +last modified by addressbook el Τελευταία τροποποίηση από +ldap context for contacts admin el LDAP πλαίσιο για τις επαφές +ldap host for contacts admin el LDAP φορέας για τις επαφές +ldap settings for contacts admin el LDAP ρυθμίσεις για τις επαφές +ldif addressbook el LDIF +line 2 addressbook el Γραμμή 2 +link title for contacts show addressbook el Τίτλος συνδέσμου για παρουσίαση επαφών +links addressbook el Σύνδεσμοι +list all categories addressbook el Τοποθέτηση σε λίστα όλων των κατηγοριών +list all customfields addressbook el Τοποθέτηση σε λίστα όλων των προσαρμοσμένων πεδίων +list already exists! addressbook el Η λίστα υπάρχει ήδη +list created addressbook el Η λίστα δημιουργήθηκε +list creation failed, no rights! addressbook el Η δημιουργία της λίστας απέτυχε, δεν έχετε το δικαίωμα! +load vcard addressbook el Φόρτωση VCard +locations addressbook el τοποθεσίες +mark records as private addressbook el Σημείωση εγγραφών ως ιδιωτικές +merge into first or account, deletes all other! addressbook el Συγχώνευση στο πρώτο ή το λογαριασμό,διαγραφή όλων των άλλων +merged addressbook el συγχωνεύτηκε +message after submitting the form addressbook el Μήνυμα μετά την υποβολή της φόρμας +message phone addressbook el Τηλέφωνο μηνυμάτων +middle name addressbook el Μεσαίο όνομα +migration finished addressbook el Ολοκληρώθηκε η μετανάστευση +migration to ldap admin el Μετανάστευση στο LDAP +mobile addressbook el Κινητό +mobile phone addressbook el Κινητό τηλέφωνο +modem phone addressbook el Τηλέφωνο modem +more ... addressbook el Περισσότερα +move to addressbook: addressbook el Μετακίνηση στο βιβλίο διευθύνσεων: +moved addressbook el μετακινήθηκε +multiple vcard addressbook el Πολλαπλή VCard +name for the distribution list addressbook el Όνομα για την λίστα διανομής +name, address addressbook el Όνομα, Διεύθυνση +new contact submitted by %1 at %2 addressbook el Νέα επαφή υπεβλήθει από %1 στις %2 +no vcard addressbook el Οχι VCard +number addressbook el Αριθμός +number of records to read (%1) addressbook el Αριθμός εγγραφών προς ανάγνωση (%1) +options for type admin el Επιλογές για τον τύπο +organisation addressbook el οργανισμός +organisations addressbook el Οργανισμοί +organisations by departments addressbook el Οργανισμοί σύμφωνα με τα τμήματα +organisations by location addressbook el Οργανισμοί σύμφωνα με την τοποθεσία +other number addressbook el Αλλος αριθμός +other phone addressbook el Αλλο τηλέφωνο +own sorting addressbook el προσωπική ταξινόμηση +pager common el Αριθμός μπίπερ +parcel addressbook el Πακέτο +permission denied !!! addressbook el Άδεια απορρίπτεται !!! +phone number common el Αριθμός τηλεφώνου +phone numbers common el Αριθμοί τηλεφώνων +photo addressbook el Φωτογραφία +please enter a name for that field ! addressbook el Παρακαλώ εισάγετε όνομα γι' αυτό το πεδίο ! +please select only one category addressbook el Παρακαλώ επιλέξτε μόνο μία κατηγορία +postal common el Ταχυδρομικός +pref addressbook el Προτιμήσεις +preferred phone addressbook el προτιμητέο τηλέφωνο +prefix addressbook el Πρόθεμα +public key addressbook el Δημόσιο κλειδί +publish into groups: addressbook el Δημοσίευση σε ομάδες: +read a list / search for entries. addressbook el Ανάγνωση μιας λίστας/αναζήτηση για καταχωρήσεις. +read a list of entries. addressbook el Ανάγνωση λίστας καταχωρήσεων +read a single entry by passing the id and fieldlist. addressbook el Ανάγνωση μεμονωμένης καταχώρησης με εισαγωγή id και λίστας πεδίων +read only addressbook el μόνο ανάγνωση +record access addressbook el Πρόσβαση Εγγραφής +record owner addressbook el Ιδιοκτήτης εγγραφής +remove selected contacts from distribution list addressbook el Αφαίρεση επιλεγμένων επαφών από τη λίστα διανομής +removed from distribution list addressbook el Αφαιρέθηκε από τη λίστα διανομής +required fields * addressbook el απαιτούμενα πεδία * +role addressbook el Ρόλος +room addressbook el Γραφείο +search for '%1' addressbook el Αναζήτηση για '%1' +select a portrait format jpeg photo. it will be resized to 60 pixel width. addressbook el Επιλέξτε μια jpeg φωτογραφία σε μορφή πορτραίτου. Θα επαναπροσδιοριστεί σε 60 pixel πλάτος. +select a view addressbook el Επιλέξτε μία προβολή +select addressbook type addressbook el Επιλέξτε τύπο βιβλίου διευθύνσεων +select all addressbook el Επιλογή όλων +select an action or addressbook to move to addressbook el Επιλέξτε μία ενέργεια ή ένα βιβλίο διευθύνσεων για μετακίνηση σε αυτό +select migration type admin el Επιλέξτε τύπο μετανάστευσης +select multiple contacts for a further action addressbook el Επιλέξτε πολλαπλές επαφές για περαιτέρω ενέργειες +select phone number as prefered way of contact addressbook el επιλέξτε τον αριθμό τηλεφώνου ως προτιμότερο τρόπο επικοινωνίας +select the type of conversion addressbook el Επιλέξτε τύπο μετατροπής +select the type of conversion: addressbook el Επιλέξτε τύπο μετατροπής: +select where you want to store / retrieve contacts admin el Επιλέξτε που θέλετε να αποθηκεύετε/ανακτάτε τις επαφές +selected contacts addressbook el επιλεγμένες επαφές +should the columns photo and home address always be displayed, even if they are empty. addressbook el Επιθυμείτε να εμφανίζονται πάντα οι στήλες φωτογραφίας και διεύθυνσης οικίας, ακόμα και αν είναι κενές. +show addressbook el Εμφάνιση +show birthday reminders on main screen addressbook el Εμφάνιση υπενθυμίσεων γενεθλίων στην κεντρική οθόνη +show infolog entries for this organisation addressbook el Παρουσίαση των InfoLog καταχωρήσεων για αυτόν τον οργανισμό +show the contacts of this organisation addressbook el Εμφανίστε τις επαφές αυτού του οργανισμού +start admin el Έναρξη +startrecord addressbook el Αρχική εγγραφή +state common el Νομός +street common el Οδός +subject for email addressbook el Θέμα email +successfully imported %1 records into your addressbook. addressbook el Επιτυχής εισαγωγή %1 εγγραφής(ών) στο βιβλίο Διευθύνσεων +suffix addressbook el Επίθεμα +tel home addressbook el τηλ σπιτιού +telephony integration admin el Τηλεφωνική ενοποίηση +test import (show importable records only in browser) addressbook el Δοκιμαστική Εισαγωγή +thank you for contacting us. addressbook el Ευχαριστούμε που επικοινωνήσατε μαζί μας. +that field name has been used already ! addressbook el Το όνομα πεδίου χρησιμοποιείται ήδη ! +the anonymous user has probably no add rights for this addressbook. addressbook el Ο ανώνυμος χρήστης δεν έχει πιθανότατα δικαίωμα προσθήκης σε αυτό το βιβλίο διευθύνσεων +the anonymous user needs add rights for it! addressbook el Ο ανώνυμος χρήστης χρειάζεται δικαιώματα για να προσθέσει σε αυτό! +there was an error saving your data :-( addressbook el Υπήρξε ένα σφάλμα κατά την αποθήκευση των δεδομένων σας :-( +this module displays a contactform, that stores direct into the addressbook. addressbook el Αυτή η ενότητα εμφανίζει μία φόρμα επαφών, που αποθηκεύεται απευθείας στο βιβλίο διευθύνσεων. +this person's first name was not in the address book. addressbook el Το όνομα αυτού του ατόμου δεν υπάρχει στο βιβλίο διευθύνσεων +this person's last name was not in the address book. addressbook el Το επίθετο αυτού του ατόμου δεν υπάρχει στο βιβλίο διευθύνσεων +timezone addressbook el Ζώνη ώρας +to many might exceed your execution-time-limit addressbook el Πάρα πολλοί. Ενδεχόμενο υπέρβασης ορίου χρόνου εκτέλεσης +today is %1's birthday! common el Σήμερα είναι τα γενέθλια του/της %1 ! +tomorrow is %1's birthday. common el Αύριο είναι τα γενέθλια του/της %1 ! +translation addressbook el Μετάφραση +type addressbook el Τύπος +update a single entry by passing the fields. addressbook el Ενημέρωση συγκεκριμένης καταχώρησης εισάγωντας τα πεδία +upload or delete the photo addressbook el Φορτώστε ή διαγράψτε τη φωτογραφία +use an extra category tab? addressbook el Χρήση μιας επιπλέον ετικέτας κατηγοριών +use country list addressbook el Χρήση καταλόγου χωρών +use setup for a full account-migration admin el χρήση της εγκατάστασης για πλήρη μετανάστευση λογαριασμού +used for links and for the own sorting of the list addressbook el χρησιμοποιείται για συνδέσμους και προσωπικές ταξινομήσεις της λίστας +vcard common el VCard +vcards require a first name entry. addressbook el VCards απαιτούν καταχώρηση ονόματος +vcards require a last name entry. addressbook el VCards απαιτούν καταχώρηση επίθετου +verification addressbook el Επαλήθευση +view linked infolog entries addressbook el Εμφάνιση συνδεδεμένων καταχωρήσεων του InfoLog +warning!! ldap is valid only if you are not using contacts for accounts storage! admin el ΠΡΟΣΟΧΗ!! LDAP ισχύει μόνο εάν ΔΕΝ χρησιμοποιείτε τις επαφές για την αποθήκευση +warning: all contacts found will be deleted! addressbook el ΠΡΟΣΟΧΗ: Όλες οι επαφές που βρέθηκαν θα διαγραφούν! +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook el Ποια μορφή διεύθυνσης θα έπρεπε το βιβλίο διευθύνσεων να χρησιμοποιεί για τις χώρες που δεν γνωρίζει τη μορφή διεύθυνσής τους. Αν η μορφή διεύθυνσης μιας χώρας είναι γνωστή, χρησιμοποιεί την ανεξάρτητη αυτής της διάταξης. +which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook el Ποιο βιβλίο διευθύνσεων πρέπει να επιλέγεται όταν προσθέτετε επαφή χωρίς να έχετε δικαιώματα στο συγκεκριμένο βιβλίο διευθύνσεων. +which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook el Ποια κωδικοσελίδα θα πρέπει να χρησιμοποιέιται για την CSV εξαγωγή.Το προκαθορισμένο σύστημα ειναι η κωδικοσελίδα της εγκατάστασης του eGroupWare. +which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook el Ποια πεδία θα πρέπει να εξάγωνται.Όλα σημαίνει κάθε πεδίο που είναι αποθηκευμένο στο βιβλίο διευθύνσεων συμπεριλαμβανομένου και των προσαρμοσμένων πεδίων.Η διεύθυνση εργασίας ή οικίας περιέχει μόνο το όνομα, την εταιρεία και την επιλεγμένη διεύθυνση. +whole query addressbook el ολόκληρη απορία +work phone addressbook el Τηλέφωνο Εργασίας +write (update or add) a single entry by passing the fields. addressbook el Εγγραφή (ενημέρωση ή προσθήκη) μιας καταχώρησης διαβαίνοντας από τα πεδία. +wrong - try again ... addressbook el Λάθος - προσπαθήστε ξανά ... +yes, for the next three days addressbook el Ναι, για τις επόμενες τρεις ημέρες +yes, for the next two weeks addressbook el Ναι, για τις επόμενες δύο εβδομάδες +yes, for the next week addressbook el Ναι, για την επόμενη εβδομάδα +yes, for today and tomorrow addressbook el Ναι, για σήμερα και αύριο +you are not permitted to delete contact %1 addressbook el Δεν έχετε άδεια να διαγράψετε την επαφή %1 +you are not permittet to delete this contact addressbook el Δεν έχετε άδεια να διαγράψετε αυτήν την επαφή +you are not permittet to edit this contact addressbook el Δεν έχετε άδεια να επεξεργαστείτε αυτήν την επαφή +you are not permittet to view this contact addressbook el Δεν έχετε άδεια να δείτε τα στοιχεία αυτής της επαφής +you can only use ldap as contact repository if the accounts are stored in ldap too! admin el Μπορείτε να χρησιμοποιήσετε το LDAP ως αποθήκη επαφής μόνο αν οι λογαριασμοί αποθηκεύονται στο LDAP επίσης! +you can respond by visiting: addressbook el Για να το δείτε επισκεφθείτε: +you must select a vcard. (*.vcf) addressbook el Πρέπει να επιλέξετε μια VCard (*.vcf) +you must select at least 1 column to display addressbook el Πρέπει να επιλέξετε τουλάχιστο μία στήλη για εμφάνιση +you need to select a distribution list addressbook el Πρέπει να επιλέξετε μια λίστα διανομής +you need to select some contacts first addressbook el Πρέπει να επιλέξετε κάποιες επαφές πρώτα +zip code common el Τ.Κ. +zip_note addressbook el
Σημείωση: Το αρχείο μπορεί να είναι μια συλλογή συμπιεσμένων αρχείων .csv, .vcf, ή .ldif αρχείων. Εντούτοις, μην αναμίξτε τους τύπους αρχείου ανά εισαγωγή. diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_en.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_en.lang --- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_en.lang 1970-01-01 01:00:00.000000000 +0100 +++ egroupware-1.6.001+dfsg/addressbook/setup/egw_en.lang 2008-11-24 11:43:08.000000000 +0000 @@ -0,0 +1,410 @@ +%1 added addressbook en %1 added +%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 fields in %2 other organisation member(s) changed addressbook en %1 fields in %2 other organisation member(s) changed +%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' +%s please calculate the result addressbook en %s please calculate the result +(e.g. 1969) addressbook en (e.g. 1969) +(empty = use global limit, no = no export at all) admin en (empty = use global limit, no = no export at all) +no conversion type <none> could be located. please choose a conversion type from the list addressbook en No conversion type <none> could be located. Please choose a conversion type from the list +@-eval() is only availible to admins!!! addressbook en @-eval() is only availible to admins!!! +account repository admin en Account repository +accounts addressbook en Accounts +actions addressbook en Actions +add %1 addressbook en Add %1 +add a contact to this organisation addressbook en Add a contact to this organisation +add a new contact addressbook en Add a new contact +add a new infolog addressbook en Add a new Infolog +add a new list addressbook en Add a new list +add a single entry by passing the fields. addressbook en Add a single entry by passing the fields. +add business email of whole distribution list? addressbook en Add business email of whole distribution list? +add custom field addressbook en Add Custom Field +add emails of whole distribution list? addressbook en Add emails of whole distribution list? +add or delete categoies addressbook en Add or delete Categoies +add to distribution list: addressbook en Add to distribution list: +added addressbook en added +added by synchronisation addressbook en added by synchronisation +added to distribution list addressbook en added to distribution list +additional information about using ldap as contact repository admin en Additional information about using LDAP as contact repository +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 type addressbook en Address Type +addressbook common en Addressbook +addressbook csv export addressbook en Addressbook CSV export +addressbook menu addressbook en Addressbook menu +addressbook preferences addressbook en Addressbook preferences +addressbook the contact should be saved to addressbook en Addressbook the contact should be saved to +addressbook the contact should be shown addressbook en Addressbook the contact should be shown +addressbook-fieldname addressbook en Addressbook-Fieldname +addvcard addressbook en Add VCard +advanced search addressbook en Advanced search +all contacts addressbook en All contacts +allow users to maintain their own account-data admin en Allow users to maintain their own account-data +alt. csv import addressbook en Alt. CSV Import +always addressbook en always +apply changes to all members, whose fields have the same previous content addressbook en Apply changes to all members, whose fields have the same previous content +apply the action on the whole query, not only the shown contacts!!! addressbook en Apply the action on the whole query, 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? +assistent addressbook en Assistent +assistent phone addressbook en assistent phone +at the moment the following document-types are supported: addressbook en At the moment the following document-types are supported: +birthday common en Birthday +birthdays common en Birthdays +blank addressbook en Blank +business common en Business +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 fax addressbook en Business Fax +business phone addressbook en Business Phone +business state addressbook en Business State +business street addressbook en Business Street +business zip code addressbook en Business Postal Code +calendar fields: addressbook en Calendar fields: +calendar uri addressbook en Calendar URI +can be changed via setup >> configuration admin en Can be changed via Setup >> Configuration +car phone addressbook en Car Phone +categorie addressbook en categorie +categorie added addressbook en categorie added +categorie delete addressbook en categorie delete +categories, notes, ... addressbook en Categories, Notes, ... +category tree admin en Category tree +cell phone addressbook en Mobile phone +change all organisation members addressbook en change all organisation members +charset for the csv export addressbook en Charset for the CSV export +charset of file addressbook en Charset of file +check all addressbook en Check all +choose an icon for this contact type admin en Choose an icon for this contact type +choose owner of imported data addressbook en Choose owner of imported data +choose seperator and charset addressbook en Choose seperator and charset +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 addressbook en company name +configuration common en Configuration +contact common en Contact +contact application admin en Contact application +contact copied addressbook en Contact copied +contact deleted addressbook en Contact deleted +contact fields to show addressbook en Contact fields to show +contact fields: addressbook en Contact fields: +contact id addressbook en Contact ID +contact modified by %1 at %2 addressbook en Contact modified by %1 at %2 +contact not found! addressbook en Contact not found! +contact repository admin en Contact repository +contact saved addressbook en Contact saved +contact settings admin en Contact Settings +contactform addressbook en Contactform +contacts and account contact-data to ldap admin en contacts and account contact-data to LDAP +contacts and account contact-data to sql admin en contacts and account contact-data to SQL +contacts to ldap admin en contacts to LDAP +contacts to ldap, account contact-data to sql admin en contacts to LDAP, account contact-data to SQL +contains addressbook en contains +copied by %1, from record #%2. addressbook en Copied by %1, from record #%2. +copy a contact and edit the copy addressbook en Copy a contact and edit the copy +copy your changes to the clipboard, %1reload the entry%2 and merge them. addressbook en Copy your changes to the clipboard, %1reload the entry%2 and merge them. +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 +custom addressbook en Custom +custom etemplate for the contactform addressbook en Custom eTemplate for the contactform +custom fields addressbook en Custom Fields +debug output in browser addressbook en Debug output in browser +default addressbook en default +default address format addressbook en Default address format +default addressbook for adding contacts addressbook en Default addressbook for adding contacts +default document to insert contacts addressbook en Default document to insert contacts +default file as format addressbook en Default file as format +default filter addressbook en Default Filter +default format for fileas, eg. for new entries. addressbook en Default format for fileas, eg. for new entries. +defines which email address (business or home) to use as the preferred one for distribution lists in mail. addressbook en Defines which email address (business or home) to use as the preferred one for distribution lists in mail. +delete a single entry by passing the id. addressbook en Delete a single entry by passing the id. +delete selected distribution list! addressbook en Delete selected distribution list! +delete this contact addressbook en Delete this contact +delete this organisation including all its contacts addressbook en Delete this organisation including ALL its contacts +deleted addressbook en deleted +deletes the photo addressbook en Deletes the photo +department common en Department +departments addressbook en departments +directory with documents to insert contacts addressbook en Directory with documents to insert contacts +display contact addressbook en Display Contact +displays a remider for birthdays on the startpage (page you get when you enter egroupware or click on the homepage icon). addressbook en Displays a remider for birthdays on the startpage (page you get when you enter eGroupWare or click on the homepage icon). +distribution list deleted addressbook en Distribution list deleted +distribution lists addressbook en Distribution lists +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? +document '%1' does not exist or is not readable for you! addressbook en Document '%1' does not exist or is not readable for you! +doesn't matter addressbook en doesn't matter +domestic addressbook en Domestic +don't hide empty columns addressbook en Don't hide empty columns +download addressbook en Download +download export file (uncheck to debug output in browser) addressbook en Download export file (Uncheck to debug output in browser) +download this contact as vcard file addressbook en download this contact as vCard file +duration addressbook en Duration +edit custom field addressbook en Edit Custom Field +edit custom fields admin en Edit Custom Fields +edit extra account-data in the addressbook admin en Edit extra account-data in the addressbook +edit phonenumbers - addressbook en Edit Phonenumbers - +either the configured email addesses are wrong or the mail configuration. addressbook en Either the configured email addesses are wrong or the mail configuration. +email & internet addressbook en Email & Internet +email addresses (comma separated) to send the contact data addressbook en Email addresses (comma separated) to send the contact data +empty for all addressbook en empty for all +enable an extra private addressbook addressbook en Enable an extra private addressbook +end addressbook en End +enter the path to the exported file here addressbook en Enter the path to the exported file here +error deleting the contact !!! addressbook en Error deleting the contact !!! +error saving the contact !!! addressbook en Error saving the contact !!! +error: the entry has been updated since you opened it for editing! addressbook en Error: the entry has been updated since you opened it for editing! +example $$if n_prefix~mr~hello mr.~hello ms.$$ - search the field "n_prefix", for "mr", if found, write hello mr., else write hello ms. addressbook en Example $$IF n_prefix~Mr~Hello Mr.~Hello Ms.$$ - search the field "n_prefix", for "Mr", if found, write Hello Mr., else write Hello Ms. +existing links addressbook en Existing links +export addressbook en export +export as csv addressbook en Export as CSV +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 +export selection addressbook en Export selection +exported addressbook en exported +exports contacts from your addressbook into a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. addressbook en Exports contacts from your Addressbook into a CSV File. CSV means 'Comma Seperated Values'. However in the options Tab you can also choose other seperators. +extra addressbook en Extra +failed to change %1 organisation member(s) (insufficent rights) !!! addressbook en failed to change %1 organisation member(s) (insufficent rights) !!! +fax addressbook en Fax +fax number common en Fax Number +field %1 has been added ! addressbook en Field %1 has been added ! +field %1 has been updated ! addressbook en Field %1 has been updated ! +field name addressbook en Field Name +fields for the csv export addressbook en Fields for the CSV export +fields the user is allowed to edit himself admin en Fields the user is allowed to edit himself +fields to show in address list addressbook en Fields to show in address list +fieldseparator addressbook en Fieldseparator +for more then one contact in a document use the tag pagerepeat! addressbook en for more then one contact in a document use the tag pagerepeat! +for read only ldap admin en for read only LDAP +for serial letter use this tag. put the content, you want to repeat between two tags. addressbook en For serial letter use this tag. Put the content, you want to repeat between two Tags. +freebusy uri addressbook en Freebusy URI +full name addressbook en Full Name +general addressbook en General +general fields: addressbook en General fields: +geo addressbook en GEO +global categories addressbook en Global Categories +grant addressbook access common en Grant Addressbook Access +group %1 addressbook en Group %1 +h addressbook en h +hide accounts from addressbook addressbook en Hide accounts from addressbook +hides accounts completly from the adressbook. addressbook en Hides accounts completly from the adressbook. +home address addressbook en Home address +home address, birthday, ... addressbook en Home address, Birthday, ... +home city addressbook en Home City +home country addressbook en Home Country +home email addressbook en Home EMail +home email if given, else work email addressbook en Home email if given, else work email +home phone addressbook en Home Phone +home state addressbook en Home State +home street addressbook en Home Street +home zip code addressbook en Home ZIP Code +how many contacts should non-admins be able to export admin en How many contacts should non-admins be able to export +icon addressbook en Icon +if accounts are already in ldap admin en if accounts are already in LDAP +if you specify a directory (full vfs path) here, addressbook displays an action for each document. that action allows to download the specified document with the contact data inserted. addressbook en If you specify a directory (full vfs path) here, addressbook displays an action for each document. That action allows to download the specified document with the contact data inserted. +if you specify a document (full vfs path) here, addressbook displays an extra document icon for each address. that icon allows to download the specified document with the contact data inserted. addressbook en If you specify a document (full vfs path) here, addressbook displays an extra document icon for each address. That icon allows to download the specified document with the contact data inserted. +import addressbook en Import +import contacts addressbook en Import Contacts +import csv-file into addressbook addressbook en Import CSV-File into Addressbook +import file addressbook en Import File +import from addressbook en Import from +import from ldif, csv, or vcard addressbook en Import from LDIF, CSV, or VCard +import from outlook addressbook en Import from Outlook +import multiple vcard addressbook en Import Multiple VCard +import next set addressbook en Import next set +import_instructions addressbook en In Netscape, open the Addressbook and select Export from the File menu. The file exported will be in LDIF format.
Or, in Outlook, select your Contacts folder, select Import and Export... from the File menu and export your contacts into a comma separated text (CSV) file.
Or, in Palm Desktop 4.0 or greater, visit your addressbook and select Export from the File menu. The file exported will be in VCard format. +imports contacts into your addressbook from a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. addressbook en Imports contacts into your Addressbook from a CSV File. CSV means 'Comma Seperated Values'. However in the options Tab you can also choose other seperators. +in %1 days (%2) is %3's birthday. addressbook en In %1 days (%2) is %3's birthday. +income addressbook en Income +insert in document addressbook en Insert in document +insufficent rights to delete this list! addressbook en Insufficent rights to delete this list! +international addressbook en International +label addressbook en Label +last date addressbook en Last date +last modified addressbook en last modified +last modified by addressbook en last modified by +ldap context for contacts admin en LDAP context for contacts +ldap host for contacts admin en LDAP host for contacts +ldap settings for contacts admin en LDAP settings for contacts +ldif addressbook en LDIF +line 2 addressbook en Line 2 +link title for contacts show addressbook en Link title for contacts show +links addressbook en Links +list all categories addressbook en List all categories +list all customfields addressbook en List all customfields +list already exists! addressbook en List already exists! +list created addressbook en List created +list creation failed, no rights! addressbook en List creation failed, no rights! +load sample file addressbook en Load Sample file +load vcard addressbook en Load VCard +location addressbook en Location +locations addressbook en locations +manage mapping addressbook en Manage mapping +mark records as private addressbook en Mark records as private +merge into first or account, deletes all other! addressbook en Merge into first or account, deletes all other! +merged addressbook en merged +message after submitting the form addressbook en Message after submitting the form +message phone addressbook en Message Phone +middle name addressbook en Middle Name +migration finished addressbook en Migration finished +migration to ldap admin en Migration to LDAP +mobile addressbook en Mobile +mobile phone addressbook en Mobile Phone +modem phone addressbook en Modem Phone +more ... addressbook en More ... +move to addressbook: addressbook en Move to addressbook: +moved addressbook en moved +multiple vcard addressbook en Multiple VCard +name for the distribution list addressbook en Name for the distribution list +name of current user, all other contact fields are valid too addressbook en Name of current user, all other contact fields are valid too +name, address addressbook en Name, Address +new contact submitted by %1 at %2 addressbook en New contact submitted by %1 at %2 +new window opened to edit infolog for your selection addressbook en New window opened to edit Infolog for your selection +next date addressbook en Next date +no categories selected addressbook en no categories selected +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 admin en Options for type +organisation addressbook en organisation +organisations addressbook en Organisations +organisations by departments addressbook en Organisations by departments +organisations by location addressbook en Organisations by location +other number addressbook en Other Number +other phone addressbook en Other Phone +own sorting addressbook en own sorting +pager common en Pager +parcel addressbook en Parcel +participants addressbook en Participants +permission denied !!! addressbook en Permission denied !!! +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 +please update the templatename in your customfields section! addressbook en Please update the templatename in your customfields section! +postal common en Postal +pref addressbook en pref +preferred email address to use in distribution lists addressbook en Preferred email address to use in distribution lists +preferred phone addressbook en preferred phone +preferred type of email address to add for distribution lists addressbook en preferred type of email address to add for distribution lists +prefix addressbook en Prefix +public key addressbook en Public Key +publish into groups: addressbook en Publish into groups: +read a list / search for entries. addressbook en Read a list / search for entries. +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. +read only addressbook en read only +record access addressbook en Record Access +record owner addressbook en Record owner +remove selected contacts from distribution list addressbook en Remove selected contacts from distribution list +removed from distribution list addressbook en removed from distribution list +repetition addressbook en Repetition +replacements for inserting contacts into documents addressbook en Replacements for inserting contacts into documents +required fields * addressbook en required fields * +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 a view addressbook en Select a view +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 migration type admin en Select migration type +select multiple contacts for a further action addressbook en Select multiple contacts for a further action +select phone number as prefered way of contact addressbook en select phone number as prefered way of contact +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 / retrieve contacts admin en Select where you want to store / retrieve contacts +selected contacts addressbook en selected contacts +should the columns photo and home address always be displayed, even if they are empty. addressbook en Should the columns photo and home address always be displayed, even if they are empty. +show addressbook en Show +show birthday reminders on main screen addressbook en Show birthday reminders on main screen +show infolog entries for this organisation addressbook en Show InfoLog entries for this organisation +show the contacts of this organisation addressbook en Show the contacts of this organisation +size of popup (wxh, eg.400x300, if a popup should be used) admin en Size of popup (WxH, eg.400x300, if a popup should be used) +start admin en Start +startrecord addressbook en Startrecord +state common en State +street common en Street +subject for email addressbook en Subject for email +successfully imported %1 records into your addressbook. addressbook en Successfully imported %1 record(s) into your addressbook. +suffix addressbook en Suffix +tel home addressbook en tel home +telephony integration admin en Telephony integration +test import (show importable records only in browser) addressbook en Test Import (show importable records only in browser) +thank you for contacting us. addressbook en Thank you for contacting us. +that field name has been used already ! addressbook en That field name has been used already ! +the anonymous user has probably no add rights for this addressbook. addressbook en The anonymous user has probably no add rights for this addressbook. +the anonymous user needs add rights for it! addressbook en The anonymous user needs add rights for it! +the anonymous user needs read it! addressbook en The anonymous user needs read it! +the document can contain placeholder like $$n_fn$$, to be replaced with the contact data (%1full list of placeholder names%2). addressbook en The document can contain placeholder like $$n_fn$$, to be replaced with the contact data (%1full list of placeholder names%2). +there was an error saving your data :-( addressbook en There was an error saving your data :-( +this module displays a contactform, that stores direct into the addressbook. addressbook en This module displays a contactform, that stores direct into the addressbook. +this module displays block from a adddressbook group. addressbook en This module displays Block from a Adddressbook Group. +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 +type addressbook en Type +update a single entry by passing the fields. addressbook en Update a single entry by passing the fields. +update fields by edited organisations? admin en Update Fields by edited organisations? +updated addressbook en Updated +upload or delete the photo addressbook en Upload or delete the photo +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin en URL to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) +use an extra category tab? addressbook en Use an extra category tab? +use an extra tab for private custom fields? admin en Use an extra tab for private custom fields? +use country list addressbook en Use Country List +use setup for a full account-migration admin en use setup for a full account-migration +used for links and for the own sorting of the list addressbook en used for links and for the own sorting of the 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. +verification addressbook en Verification +view linked infolog entries addressbook en View linked InfoLog entries +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! +warning: template "%1" not found, using default template instead. addressbook en WARNING: Template "%1" not found, using default template instead. +weekday addressbook en Weekday +what should links to the addressbook display in other applications. empty values will be left out. you need to log in anew, if you change this setting! addressbook en What should links to the addressbook display in other applications. Empty values will be left out. You need to log in anew, if you change this setting! +where to add the email address addressbook en where to add the email address +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook en Which address format should the addressbook use for countries it does not know the address format. If the address format of a country is known, it uses it independent of this setting. +which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook en Which addressbook should be selected when adding a contact AND you have no add rights to the current addressbook. +which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook en Which charset should be used for the CSV export. The system default is the charset of this eGroupWare installation. +which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook en Which fields should be exported. All means every field stored in the addressbook incl. the custom fields. The business or home address only contains name, company and the selected address. +whole query addressbook en whole query +work email if given, else home email addressbook en Work email if given, else home email +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. +wrong - try again ... addressbook en Wrong - try again ... +yes, for the next three days addressbook en Yes, for the next three days +yes, for the next two weeks addressbook en Yes, for the next two weeks +yes, for the next week addressbook en Yes, for the next week +yes, for today and tomorrow addressbook en Yes, for today and tomorrow +you are not permitted to delete contact %1 addressbook en You are not permitted to delete contact %1 +you are not permittet to delete this contact addressbook en You are not permittet to delete this contact +you are not permittet to edit this contact addressbook en You are not permittet to edit this contact +you are not permittet to view this contact addressbook en you are not permittet to view this contact +you can only use ldap as contact repository if the accounts are stored in ldap too! admin en You can only use LDAP as contact repository if the accounts are stored in LDAP too! +you can respond by visiting: addressbook en To view it visit: +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 a distribution list addressbook en You need to select a distribution list +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
Note: The file may be a zip file collection of .csv, .vcf, or .ldif files. However, do not mix file types per import.
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_es-es.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_es-es.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_es-es.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_es-es.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,410 @@
+%1 added addressbook es-es %1 añadidos
+%1 contact(s) %2 addressbook es-es %1 contactos %2
+%1 contact(s) %2, %3 failed because of insufficent rights !!! addressbook es-es %1 contactos %2, %3 fallaron debido a privilegios insuficientes.
+%1 fields in %2 other organisation member(s) changed addressbook es-es %1 campos en %2 miembros de otra organización cambiados
+%1 records imported addressbook es-es Se han importado %1 registros
+%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook es-es Se han leído %1 registros (no importados todavía, puede volver %2atrás%3 y desmarcar la prueba de importación)
+%1 starts with '%2' addressbook es-es %1 empieza por '%2'
+%s please calculate the result addressbook es-es %s por favor, calcule el resultado
+(e.g. 1969) addressbook es-es (p. ej. 1969)
+(empty = use global limit, no = no export at all) admin es-es (vacío = usar limite global; no = no exportar nada)
+no conversion type <none> could be located. please choose a conversion type from the list addressbook es-es No se encontró el tipo de conversión
O, en Outlook, seleccione su carpeta de contactos, luego, en el menúFichero, Importar y Exportar para guardarlos en un fichero separado por comas (CSV).
O, en Palm Desktop 4.0 o superior, visite la libreta de direcciones y seleccione Exportar desde el menú Archivo. El fichero exportado estará en formato VCard. +imports contacts into your addressbook from a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. addressbook es-es Importa los contactos en la libreta de direcciones desde un fichero CSV. CSV significa 'Valores separados por comas'. Sin embargo, en la pestaña de opciones, también se pueden elegir otros separadores. +in %1 days (%2) is %3's birthday. addressbook es-es En %1 días (%2) es el cumpleaños de %3. +income addressbook es-es Ingresos +insert in document addressbook es-es Insertar en el documento +insufficent rights to delete this list! addressbook es-es No tiene privilegios suficientes para borrar esta lista +international addressbook es-es Internacional +label addressbook es-es Etiqueta +last date addressbook es-es Última fecha +last modified addressbook es-es última modificación +last modified by addressbook es-es última modificación por +ldap context for contacts admin es-es Contexto LDAP para contactos +ldap host for contacts admin es-es Servidor LDAP para contactos +ldap settings for contacts admin es-es Configuración LDAP para contactos +ldif addressbook es-es LDIF +line 2 addressbook es-es Línea 2 +link title for contacts show addressbook es-es Título del enlace para mostrar contactos +links addressbook es-es Enlaces +list all categories addressbook es-es Lista de todas las categorías +list all customfields addressbook es-es Lista de todos los campos personalizados +list already exists! addressbook es-es ¡La lista ya existe! +list created addressbook es-es Se ha creado la lista +list creation failed, no rights! addressbook es-es Falló la creación de lista. No tiene privilegios suficientes. +load sample file addressbook es-es Cargar el fichero de ejemplo +load vcard addressbook es-es Cargar VCard +location addressbook es-es Ubicación +locations addressbook es-es ubicaciones +manage mapping addressbook es-es Administrar los mapeos +mark records as private addressbook es-es Marcar registros como privados +merge into first or account, deletes all other! addressbook es-es ¡Mezclar en el primero o cuenta, borra todos los demás! +merged addressbook es-es Mezclado +message after submitting the form addressbook es-es Mensaje de después de enviar el formulario +message phone addressbook es-es Teléfono de mensajes +middle name addressbook es-es Segundo nombre +migration finished addressbook es-es Migración finalizada +migration to ldap admin es-es Migración a LDAP +mobile addressbook es-es Móvil +mobile phone addressbook es-es Teléfono móvil +modem phone addressbook es-es Teléfono módem +more ... addressbook es-es Más... +move to addressbook: addressbook es-es Mover a la libreta de direcciones: +moved addressbook es-es movido +multiple vcard addressbook es-es VCard múltiple +name for the distribution list addressbook es-es Nombre para la lista de distribución +name of current user, all other contact fields are valid too addressbook es-es Nombre del usuario actual. Todos los demás campos del contacto también son válidos. +name, address addressbook es-es Nombre, Dirección +new contact submitted by %1 at %2 addressbook es-es Nuevo contacto enviado por %1 en %2 +new window opened to edit infolog for your selection addressbook es-es Se ha abierto una ventana nueva para editar la nota para su selección +next date addressbook es-es Fecha siguiente +no categories selected addressbook es-es no se seleccionaron categorías +no vcard addressbook es-es Sin VCard +number addressbook es-es Número +number of records to read (%1) addressbook es-es Número de registros a leer (%1) +options for type admin es-es Opciones para el tipo +organisation addressbook es-es organización +organisations addressbook es-es Organizaciones +organisations by departments addressbook es-es Organizaciones por departamentos +organisations by location addressbook es-es Organizaciones por ubicación +other number addressbook es-es Otro número +other phone addressbook es-es Otro teléfono +own sorting addressbook es-es orden propio +pager common es-es Buscapersonas +parcel addressbook es-es Paquete +participants addressbook es-es Participantes +permission denied !!! addressbook es-es ¡Permiso denegado! +phone number common es-es Número de teléfono +phone numbers common es-es Números de teléfono +photo addressbook es-es Fotografía +please enter a name for that field ! addressbook es-es Por favor, introduzca un nombre para ese campo +please select only one category addressbook es-es Por favor, seleccione sólo una categoría +please update the templatename in your customfields section! addressbook es-es ¡Por favor, actualice el nombre de la plantilla en la sección de campos personalizados! +postal common es-es Postal +pref addressbook es-es pref +preferred email address to use in distribution lists addressbook es-es Dirección de correo electrónica preferida para usar en las listas de distribución +preferred phone addressbook es-es teléfono preferido +preferred type of email address to add for distribution lists addressbook es-es Tipo preferido de dirección de correo electrónico para añadir a las listas de distribución +prefix addressbook es-es Prefijo +public key addressbook es-es Clave pública +publish into groups: addressbook es-es Publicar en los grupos: +read a list / search for entries. addressbook es-es Leer una lista / buscar entradas +read a list of entries. addressbook es-es Leer una lista de entradas +read a single entry by passing the id and fieldlist. addressbook es-es Leer una sola entrada pasando el identificador y la lista de campos +read only addressbook es-es sólo lectura +record access addressbook es-es Acceso al registro +record owner addressbook es-es Propietario del registro +remove selected contacts from distribution list addressbook es-es Eliminar los contactos seleccionados de la lista de distribución +removed from distribution list addressbook es-es eliminados de la lista de distribución +repetition addressbook es-es Repetición +replacements for inserting contacts into documents addressbook es-es Sustituciones para insertar contactos en los documetos +required fields * addressbook es-es Campos requeridos * +role addressbook es-es Rol +room addressbook es-es Habitación +search for '%1' addressbook es-es Buscar '%1' +select a portrait format jpeg photo. it will be resized to 60 pixel width. addressbook es-es Seleccione una foto jpeg en formato vertical. Se redimensionará a un ancho de 60 pixels. +select a view addressbook es-es Seleccionar una vista +select addressbook type addressbook es-es Seleccionar el tipo de libreta de direcciones +select all addressbook es-es Seleccionar todo +select an action or addressbook to move to addressbook es-es Seleccionar una acción o libreta de direcciones a la que mover +select migration type admin es-es Seleccionar el tipo de migración +select multiple contacts for a further action addressbook es-es Seleccionar múltiples contactos para una acción posterior +select phone number as prefered way of contact addressbook es-es Seleccionar el número de teléfono como forma preferida de contacto +select the type of conversion addressbook es-es Seleccione el tipo de conversión +select the type of conversion: addressbook es-es Seleccione el tipo de conversión: +select where you want to store / retrieve contacts admin es-es Seleccione dónde desea almacenar o recuperar contactos +selected contacts addressbook es-es Contactos seleccionados +should the columns photo and home address always be displayed, even if they are empty. addressbook es-es ¿Mostrar las columnas de foto y domicilio particular, incluso si están vacías? +show addressbook es-es Mostrar +show birthday reminders on main screen addressbook es-es Mostrar recordatorios de cumpleaños en la pantalla principal +show infolog entries for this organisation addressbook es-es Mostrar las entradas del Registro de notas y tareas para esta organización +show the contacts of this organisation addressbook es-es Mostrar los contactos de esta organización +size of popup (wxh, eg.400x300, if a popup should be used) admin es-es Tamaño de la ventana (ancho x alto, p.ej. 400x300, si se usa una ventana emergente) +start admin es-es Empezar +startrecord addressbook es-es Registro inicial +state common es-es Provincia +street common es-es Calle +subject for email addressbook es-es Asunto para el correo electrónico +successfully imported %1 records into your addressbook. addressbook es-es Se han importado correctamnte %1 registros en la libreta de direcciones. +suffix addressbook es-es Sufijo +tel home addressbook es-es teléfono particular +telephony integration admin es-es Integración con telefonía +test import (show importable records only in browser) addressbook es-es Test de Importación (mostrar los registros que se pueden importar sólo en el navegador) +thank you for contacting us. addressbook es-es Gracias por ponerse en contacto con nosotros. +that field name has been used already ! addressbook es-es El nombre del campo ya ha sido usado +the anonymous user has probably no add rights for this addressbook. addressbook es-es El usuario anónimo probablemente no tiene derechos de añadir para esta libreta de direcciones. +the anonymous user needs add rights for it! addressbook es-es ¡El usuario anónimo necesita derechos de añadir para esto! +the anonymous user needs read it! addressbook es-es ¡El usuario anónimo necesita leerlo! +the document can contain placeholder like $$n_fn$$, to be replaced with the contact data (%1full list of placeholder names%2). addressbook es-es El documento puede tener un contenedor como $$n_fn$$, para ser sustituido con los datos del contacto (%1lista completa de nombres del contenedor%2). +there was an error saving your data :-( addressbook es-es Ocurrió un error al guardar los datos +this module displays a contactform, that stores direct into the addressbook. addressbook es-es Este módulo muestra un formulario de contacto que se guarda directamente en la libreta de direcciones. +this module displays block from a adddressbook group. addressbook es-es Este módulo muestra el bloque de un grupo de libreta de direcciones +this person's first name was not in the address book. addressbook es-es El primer nombre de esta persona no estaba en la libreta de direcciones. +this person's last name was not in the address book. addressbook es-es El apellido de esta persona no estaba en la libreta de direcciones. +timezone addressbook es-es Zona horaria +to many might exceed your execution-time-limit addressbook es-es a cuánto puede exceder el tiempo límite de ejecución +today is %1's birthday! common es-es ¡Hoy es el cumpleaños de %1! +tomorrow is %1's birthday. common es-es ¡Mañana es el cumpleaños de %1! +translation addressbook es-es Traducción +type addressbook es-es Tipo +update a single entry by passing the fields. addressbook es-es Actualizar una única entrada pasando los campos +update fields by edited organisations? admin es-es ¿Actualizar los campos por organizaciones editadas? +updated addressbook es-es Actualizado +upload or delete the photo addressbook es-es Copiar al servidor o borrar la foto +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin es-es URL a la que enlazar los números de teléfono (use %1 = número para llamar, %u = nombre de la cuenta, %t = teléfono de la cuenta) +use an extra category tab? addressbook es-es ¿Usar una pestaña extra para categorías? +use an extra tab for private custom fields? admin es-es ¿Usar una pestaña extra para campos personalizados privados? +use country list addressbook es-es Utilizar lista de países +use setup for a full account-migration admin es-es Use la instalación para una migración completa de las cuentas +used for links and for the own sorting of the list addressbook es-es utilizado para los enlaces y para el orden propio de la lista +vcard common es-es Tarjeta de visita +vcards require a first name entry. addressbook es-es Las tarjetas de visita requieren el primer nombre. +vcards require a last name entry. addressbook es-es Las tarjetas de visita requieren el apellido. +verification addressbook es-es Verificación +view linked infolog entries addressbook es-es Ver las entradas del Registro que estén vinculadas +warning!! ldap is valid only if you are not using contacts for accounts storage! admin es-es ¡Atención! ¡LDAP es valido sólo si no está usando contactos para almacenar las cuentas! +warning: all contacts found will be deleted! addressbook es-es ATENCIÓN: ¡Se borrarán todos los contactos encontrados! +warning: template "%1" not found, using default template instead. addressbook es-es AVISO: No se encontró la plantilla "%1". Se usa la plantilla predeterminada en su lugar. +weekday addressbook es-es Día semanal +what should links to the addressbook display in other applications. empty values will be left out. you need to log in anew, if you change this setting! addressbook es-es Qué deben mostrar los enlaces a la libreta de direcciones en otras aplicaciones. Los valores vacíos se ignorarán. Es necesario volver a iniciar la sesión si se cambia esta opción. +where to add the email address addressbook es-es dónde añadir la dirección de correo electrónico +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook es-es Qué formato de dirección debe usar la libreta de direcciones para países de los que no conoce el formato de las direcciones. Si se conoce el formato de las direcciones, se usa independientemente de lo indicado en esta opción +which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook es-es Qué libreta de direcciones debe seleccionarse al añadir un contacto Y cuando no haya permiso de añadir en la libreta de direcciones actual. +which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook es-es Juego de caracteres a usar para exportar a CSV. El predeterminado del sistema es el juego de caracteres de esta instalación de eGroupWare. +which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook es-es Qué campos deben exportarse. Indicar todos significa que cada campo almacenado en la libreta de direcciones, incluyendo los personalizados. La dirección del trabajo o particular sólo contiene el nombre, la empresa y la dirección seleccionada. +whole query addressbook es-es la consulta completa +work email if given, else home email addressbook es-es Correo del trabajo si se indica. Si no, correo particular +work phone addressbook es-es Teléfono del trabajo +write (update or add) a single entry by passing the fields. addressbook es-es Escribir (actualizar o añadir) una única entrada pasando los campos. +wrong - try again ... addressbook es-es Incorrecto. Vuelva a intentarlo... +yes, for the next three days addressbook es-es Sí, para los tres próximos días +yes, for the next two weeks addressbook es-es Sí, para las dos semanas siguientes +yes, for the next week addressbook es-es Sí, para la semana siguiente +yes, for today and tomorrow addressbook es-es Sí, para hoy y mañana +you are not permitted to delete contact %1 addressbook es-es No tiene permiso para borrar el contacto %1 +you are not permittet to delete this contact addressbook es-es No tiene permiso para borrar este contacto +you are not permittet to edit this contact addressbook es-es No tiene permiso para editar este contacto +you are not permittet to view this contact addressbook es-es No tiene permiso para ver este contacto +you can only use ldap as contact repository if the accounts are stored in ldap too! admin es-es ¡Sólo puede usar LDAP como repositorio de contactos si las cuentas también están almacenadas en LDAP! +you can respond by visiting: addressbook es-es Para verlo, visite: +you must select a vcard. (*.vcf) addressbook es-es Debe seleccionar una tarjeta (*.vcf) +you must select at least 1 column to display addressbook es-es Debe seleccionar al menos una columna para mostrar +you need to select a distribution list addressbook es-es Necesita seleccionar una lista de distribución +you need to select some contacts first addressbook es-es Necesita seleccionar antes algunos contactos +zip code common es-es Código postal +zip_note addressbook es-es
Nota: El fichero puede ser un fichero zip conteniendo ficheros .csv, .vcf o .ldif. Sin embargo, no mezcle los tipos cada vez que importe.
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_et.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_et.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_et.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_et.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,28 @@
+%1 added addressbook et %1 lisatud
+accounts addressbook et Kontod
+add %1 addressbook et Lisa %1
+add a new contact addressbook et Lisa uus kontakt
+always addressbook et alati
+birthday common et Sünnipäev
+birthdays common et Sünnipäevad
+cell phone addressbook et Mobiil telefon
+city common et Linn
+contains addressbook et sisaldab
+country common et Riik
+create new links addressbook et Tee uued lingid
+created addressbook et Tehtud
+default filter addressbook et Vaikimisi Filter
+delete this contact addressbook et Kustuta see kontakt
+deleted addressbook et kustutatud
+duration addressbook et Kestvus
+email & internet addressbook et Email & Internet
+empty for all addressbook et tühi kõigijaoks
+end addressbook et Lõpp
+existing links addressbook et Eksisteerivad lingid
+links addressbook et Lingid
+photo addressbook et Foto
+select all addressbook et Märgi kõik
+state common et Maakond
+street common et Tänav
+weekday addressbook et Nädalati
+wrong - try again ... addressbook et Vale - proovi uuesti ...
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_eu.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_eu.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_eu.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_eu.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,225 @@
+%1 contact(s) %2 addressbook eu %1 kontaktu %2
+%1 records imported addressbook eu %1 erregistro inportatuak
+%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook eu %1 erregistro irakurriak (oraindik inportatu gabe, atzera itzuli eta "Inportazio Testa" kontrol laukia hautatu gabe utzi)
+%1 starts with '%2' addressbook eu %1 '%2'tik hasten da
+(e.g. 1969) addressbook eu (adib. 1969)
+no conversion type <none> could be located. please choose a conversion type from the list addressbook eu Ez da aurkitu
Edo, Microsoft outlookarekin, hautatu zure kontaktu karpeta eta ondoren hautatu Inportatu eta Exportatu, Fitxategia menutik eta exportatu kontaktuak komas separaturiko testu fitxategi batetara (CVS).
Edo, Palm Desktop 4.0 edo berriagoan, helbide liburura sartu eta hautatu Exportatu, Fitxategia menuan. Exportaturiko fitxategia VCard formatuan egongo da. +in %1 days (%2) is %3's birthday. addressbook eu %1 egunetan (%2) %3ren urtebetzea izango da +income addressbook eu Sarrerak +international addressbook eu Internazionala +label addressbook eu Etiketa +last modified addressbook eu azken aldaketa +last modified by addressbook eu azken aldaketa nork egin du: +ldap context for contacts admin eu LDAP kontextua kontaktuentzat +ldap host for contacts admin eu LDAP zerbitzaria kontaktuentzat +ldif addressbook eu LDIF +line 2 addressbook eu 2. Errenkada +links addressbook eu Loturak +list all categories addressbook eu Kategoria guztien zerrenda +list all customfields addressbook eu Eremu pertsonalizatu guztien zerrenda +load vcard addressbook eu VCard-a kargatu +locations addressbook eu kokalekuak +mark records as private addressbook eu Errenkara pribatu moduan jarri +message phone addressbook eu Mezuen telefonoa +middle name addressbook eu Erdiko izena +mobile addressbook eu Mugikorra +mobile phone addressbook eu Mugikorra +modem phone addressbook eu Modem telefonoa +more ... addressbook eu Gehiago... +moved addressbook eu mugitua +multiple vcard addressbook eu VCard anitzak +no vcard addressbook eu Ez VCard-ik +number addressbook eu Zenbakia +number of records to read (%1) addressbook eu Irakurri beharreko errenkaden kopurua (%1) +only if there is content addressbook eu bakarrik edukia badu +options for type admin eu Motarentzeko aukerak +organisation addressbook eu antolaketa +organisations addressbook eu Antolakuntzak +organisations by departments addressbook eu departamentukako antolaketa +organisations by location addressbook eu Kokalekuaren araberako antolaketa +other number addressbook eu Beste Zebaki bat +other phone addressbook eu Beste telefono bat +own sorting addressbook eu ordena propioa +pager common eu Bilagailua +parcel addressbook eu Partzela +phone number common eu Telefono zenbakia +phone numbers common eu Telefono zenbakiak +photo addressbook eu Argazkia +please enter a name for that field ! addressbook eu Mesedez sartu izen bat eremu horretarako! +please select only one category addressbook eu Mesedez, kategoria bakarra aukeratu ezazu +postal common eu Posta Kutxatilla +pref addressbook eu hobestua +preferred phone addressbook eu hobestutako telefonoa +prefix addressbook eu Aurrizkia +public key addressbook eu Giltza publikoa +publish into groups: addressbook eu Taldeetan publikatu: +read a list of entries. addressbook eu Sarrea zerrenda bat irakurri +read a single entry by passing the id and fieldlist. addressbook eu Sarrera bakarra irakurri "ID"-a eta "eremu zerrenda" pasatuaz. +read only addressbook eu Soilik irakurri +record access addressbook eu Erregistrora sarrera +record owner addressbook eu Erregistroaren jabea +select all addressbook eu Guztiak hautatu +select the type of conversion addressbook eu Hautatu bihurketa mota +select the type of conversion: addressbook eu Hautatu bihurketa mota: +show birthday reminders on main screen addressbook eu Erakutsi urtebetetze abisuak orri nagusian +startrecord addressbook eu Erregistro hasera +state common eu Estatua +street common eu Kalea +successfully imported %1 records into your addressbook. addressbook eu %1 erregistro arrakastaz inportatuak helbide-liburura. +suffix addressbook eu Atzizki +test import (show importable records only in browser) addressbook eu Inportazio proba (erakutsi inportatu daitezkeen errenkadak bakarrik nabigatzailean) +that field name has been used already ! addressbook eu Eremu izen hori dagoeneko erabilia izan da! +this person's first name was not in the address book. addressbook eu Pertsona honen lehen izena ez zegoen helbide-liburuan. +this person's last name was not in the address book. addressbook eu Pertsona honen abizena ez zegoen helbide-liburuan. +to many might exceed your execution-time-limit addressbook eu gehiegi, exekuzio denbora gainditu lezake. +today is %1's birthday! common eu Gaur %1_ren urtebetetzea da! +tomorrow is %1's birthday. common eu Bihar %1 _ren urtebetetzea da. +translation addressbook eu Itzulpena +update a single entry by passing the fields. addressbook eu Eguneratu sarrera bakarra eremua emanez. +use country list addressbook eu Erabili Herrialde zerrenda +vcard common eu VCard +vcards require a first name entry. addressbook eu VCard-ek "izena" sarrera behar du +vcards require a last name entry. addressbook eu VCard-ek "abizena" sarrera behar du +warning!! ldap is valid only if you are not using contacts for accounts storage! admin eu KONTUZ!! LDAP balioduna da soilik kontaktuak kontu korronteko datuak gordetzeko ez badituzu erabiltzen! +work phone addressbook eu Laneko telefonoa +you must select a vcard. (*.vcf) addressbook eu VCard bat hautatu beharra daukazu. (*.vcf) +you must select at least 1 column to display addressbook eu Gutxienez erakusteko zutabe bat hautatu beharra daukazu +zip code common eu ZIP kodea +zip_note addressbook eu
Oharra: fitxategia zip formatuan egon liteke, zebait .cvs, .vcf edo .ldif edukiaz. Dena dela, ez nahastu fitxategi motak inportatzerakoan.
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_fa.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_fa.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_fa.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_fa.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,206 @@
+%1 records imported addressbook fa %1 رکورد وارد شد
+%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook fa تعداد %1 رکورد خوانده شد.(هنوز وارد نشده، شما می توانید بر گردید و آزمایش ورود را غیر فعال کنید)
+(e.g. 1969) addressbook fa (مثلا: 1969)
+actions addressbook fa اعمال
+add a single entry by passing the fields. addressbook fa افزودن ورودی با ارسال فیلدها
+add custom field addressbook fa افزودن فیلد سفارشی
+address book common fa اطلاعات اشخاص
+address book - vcard in addressbook fa مخاطبین - VCard در
+address book - view addressbook fa اطلاعات اشخاص - نمایش
+address line 2 addressbook fa آدرس خط دوم
+address line 3 addressbook fa آدرس خط سوم
+address type addressbook fa نوع آدرس
+addressbook common fa اطلاعات اشخاص
+addressbook preferences addressbook fa پیشفرض اطلاعات اشخاص
+addressbook-fieldname addressbook fa اطلاعات اشخاص - نام فیلد
+addvcard addressbook fa افزودن کارت ویزیت
+advanced search addressbook fa جستجوی پیشرفته
+alt. csv import addressbook fa وارد کردن CSV دیگر
+and addressbook fa و
+are you shure you want to delete this contact? addressbook fa آیا برای حذف این مخاطب مطمئنید؟
+are you sure you want to delete this field? addressbook fa آیا برای حذف این فیلد مطمئنید؟
+attach addressbook fa پیوست شود
+attach file addressbook fa پیوست پرونده
+bbs phone addressbook fa تلفن BBS
+birthday common fa تاریخ تولد
+birthdays common fa تاریخ تولد
+blank addressbook fa خالی
+business common fa کاری
+business address type addressbook fa نوع نشانی کاری
+business city addressbook fa شهر کاری
+business country addressbook fa کشور کاری
+business email addressbook fa رایانامه کاری
+business email type addressbook fa نوع رایانامه کاری
+business fax addressbook fa دورنگار کاری
+business phone addressbook fa تلفن کاری
+business state addressbook fa استان کاری
+business street addressbook fa خیابان کاری
+business zip code addressbook fa کدپستی کاری
+car phone addressbook fa تلفن خودرو
+cell phone addressbook fa تلفن همراه
+charset of file addressbook fa UTF-8
+checkbox addressbook fa جعبه بررسی
+choose an icon for this contact type addressbook fa یک نمایه برای این نوع مخاطب انتخاب کنید
+chosse an etemplate for this contact type addressbook fa یک قالب الکترونیکی برای این نوع مخاطب انتخاب کنید
+city common fa شهر
+company common fa شرکت/سازمان
+company name common fa نام شرکت/سازمان
+configuration common fa پیکربندی
+contact common fa مخاطب
+contact application admin fa برنامه مخاطب
+contact saved addressbook fa مخاطب ضبط شد
+contact settings admin fa تنظیمات مخاطب
+contains addressbook fa شامل است
+copied by %1, from record #%2. addressbook fa بوسیله %1 از رکورد #%2 نسخه برداری شد
+country common fa کشور
+create new links addressbook fa ایجاد پیوندهای جدید
+credit addressbook fa اعتبار
+csv-fieldname addressbook fa نام فیلد-csv
+csv-filename addressbook fa نام پرونده - csv
+custom addressbook fa سفارشی
+custom fields addressbook fa فیلدهای سفارشی
+debug output in browser addressbook fa نمایش خروجی اشکالزدائی در مرورگر
+default filter addressbook fa صافی پیش فرض
+delete a single entry by passing the id. addressbook fa حذف یک ورودی با ارسال شناسه
+department common fa قسمت
+do your really want to delete this contact? addressbook fa آیا واقعا شما می خواهید این مخاطب را حذف کنید؟
+doesn't matter addressbook fa مهم نیست
+domestic addressbook fa خانگی
+download addressbook fa دریافت
+download export file (uncheck to debug output in browser) addressbook fa دریافت پرونده صدور(غیر فعال کنید تا خروجی در مرورگر اشکالزدائی شود)
+download this contact as vcard file addressbook fa این مخاطب را بعنوان پرونده کارت ویزیت دریافت کن
+edit custom field addressbook fa ویرایش فیلد سفارشی
+edit custom fields admin fa ویرایش فیلدهای سفارشی
+edit phonenumbers - addressbook fa ویرایش شماره تلفن
+email & internet addressbook fa اینترنت و رایانامه
+empty for all addressbook fa خالی برای همه
+enter the path to the exported file here addressbook fa مسیر را برای صدور پرونده در اینجا وارد کنید
+existing links addressbook fa پیوندهای موجود
+export addressbook fa صدور
+export contacts addressbook fa صدور مخاطب
+export file name addressbook fa نام پرونده صدور
+export from addressbook addressbook fa صدور از دفتر نشانی
+extra addressbook fa اضافی
+fax addressbook fa فکس
+fax number common fa شماره فکس
+field %1 has been added ! addressbook fa فیلد %1 اضافه شد
+field %1 has been updated ! addressbook fa فیلد %1 بهنگام شد
+field name addressbook fa نام فیلد
+fields to show in address list addressbook fa فیلدها برای نمایش در لیست نشانی
+fieldseparator addressbook fa جدا کننده فیلد
+full name addressbook fa نام کامل
+geo addressbook fa نشانی جغرافیائی
+global categories addressbook fa دسته های عمومی
+grant addressbook access common fa اعطاء دسترسی دفتر نشانی
+haghighi addressbook fa حقیقی
+hoghooghi addressbook fa حقوقی
+home address type addressbook fa نوع نشانی منزل
+home city addressbook fa شهر منزل
+home country addressbook fa کشور منزل
+home email addressbook fa رایانامه منزل
+home email type addressbook fa نوع رایانامه منزل
+home phone addressbook fa تلفن منزل
+home state addressbook fa استان منزل
+home street addressbook fa خیابان منزل
+home zip code addressbook fa کد پستی منزل
+icon addressbook fa نمایه
+import addressbook fa وارد کردن
+import contacts addressbook fa وارد کردن مخاطب
+import csv-file into addressbook addressbook fa وارد کردن پرونده CSV در دفتر نشانی
+import file addressbook fa وارد کردن پرونده
+import from addressbook fa وارد کردن از
+import from ldif, csv, or vcard addressbook fa وارد کردن از LDIF, CSV, یا VCard
+import from outlook addressbook fa وارد کردن از Outlook
+import multiple vcard addressbook fa وارد کردن چند VCard
+import next set addressbook fa وارد کردن سری بعدی
+import_instructions addressbook fa مراحل وارد کردن
+income addressbook fa ورودی
+international addressbook fa بین المللی
+isdn phone addressbook fa تلفن ISDN
+label addressbook fa برچسب
+last modified addressbook fa آخرین تغییرات
+line 2 addressbook fa خط ۲
+links addressbook fa پیوندها
+list all categories addressbook fa فهرست همه دسته ها
+list all customfields addressbook fa فهرست همه فیلدهای سفارشی
+load vcard addressbook fa بارگذاری VCARD
+mark records as private addressbook fa علامت زدن رکوردها بعنوان خصوصی
+message phone addressbook fa تلفن پیام
+middle name addressbook fa نام وسط
+mobile addressbook fa همراه
+mobile phone addressbook fa تلفن همراه
+modem phone addressbook fa تلفن مودم
+more ... addressbook fa بیشتر...
+multiple vcard addressbook fa چندتا Vcard
+no vcard addressbook fa بدون VCard
+number addressbook fa شماره
+number of records to read (%1) addressbook fa تعداد رکوردها برای خواندن (%1)
+operator addressbook fa عملگر
+options addressbook fa گزینه ها
+options for type addressbook fa گزینه های نوع
+or addressbook fa یا
+organisation addressbook fa سازمان
+other number addressbook fa شماره دیگر
+other phone addressbook fa تلفن دیگر
+pager common fa پیجر
+parcel addressbook fa جعبه پستی
+persontype addressbook fa نوع شخص
+phone number common fa شماره تلفن
+phone numbers common fa شماره تلفنها
+please enter a name for that field ! addressbook fa لطفا یک نام برای فیلد انتخاب کنید!
+please select only one category addressbook fa لطفا فقط یک دسته را انتخاب کنید
+postal common fa پستی
+pref addressbook fa پیش
+prefix addressbook fa پیش شماره
+public key addressbook fa کلید عمومی
+publish into groups: addressbook fa انتشار در گروه:
+radiobutton addressbook fa کلیدرادیوئی
+read a list / search for entries. addressbook fa خواندن فهرست/جستجو برای ورودی
+read a list of entries. addressbook fa خواندن یک فهرست از ورودیها
+read a single entry by passing the id and fieldlist. addressbook fa خواندن یک ورودی با وارد کردن شناسه و فهرست فیلد ها
+record access addressbook fa دسترسی رکورد
+record owner addressbook fa مالک رکورد
+retrieve contacts admin fa بازیابی مخاطب
+select all addressbook fa انتخاب همه
+select the type of conversion addressbook fa نوع تبدیل را انتخاب کنید
+select the type of conversion: addressbook fa نوع تبدیل را انتخاب کنید:
+select where you want to store admin fa مکان ضبط را انتخاب کنید
+show addressbook fa نمایش
+show birthday reminders on main screen addressbook fa نمایش یادآور روز تولد در صفحه اصلی
+something went wrong by deleting %1 addressbook fa در حذف %1 یک مورد اشتباهی وجود دارد
+something went wrong by deleting this contact addressbook fa در حذف این مخاطب یک مورد اشتباهی وجود دارد
+something went wrong by reading this contact addressbook fa در خواندن این مخاطب یک مورد اشتباهی وجود دارد
+something went wrong by saving this contact. errorcode %1 addressbook fa در ضبط کردن این مخاطب یک مورد اشتباهی وجود دارد: خطای شماره %1
+startrecord addressbook fa رکورد شروع
+state common fa استان
+street common fa خیابان
+successfully imported %1 records into your addressbook. addressbook fa تعداد %1 رکورد با موفقیت به مخاطبین شما وارد شد.
+suffix addressbook fa پسوند
+tel home addressbook fa شماره منزل
+test import (show importable records only in browser) addressbook fa آزمایش ورود.( فقط نمایش رکوردهای قابل وارد کردن در مرورگر)
+text addressbook fa متنی
+that field name has been used already ! addressbook fa این نام فیلد قبلا استفاده شده است
+this person's first name was not in the address book. addressbook fa نام این شخص در مخاطبین نبود.
+this person's last name was not in the address book. addressbook fa نام خانوادگی این شخص در مخاطبین نبود.
+to many might exceed your execution-time-limit addressbook fa ممکن است به حد زمانی اجرا برسید
+today is %1's birthday! common fa امروز تولد %1 است
+tomorrow is %1's birthday. common fa فردا تولد %1 است
+translation addressbook fa ترجمه
+update a single entry by passing the fields. addressbook fa بهنگام سازی یک ورودی با ارسال یک فیلد
+url addressbook fa وب سایت
+use country list addressbook fa استفاده ار فهرست کشورها
+vcard common fa VCard
+vcards require a first name entry. addressbook fa عناصر VCard یک نام برای ورودی لازم دارند
+vcards require a last name entry. addressbook fa عناصر VCard یک نام خانوادگی برای ورودی لازم دارن
+video phone addressbook fa تلفن تصویری
+voice phone addressbook fa تلفن صوتی
+warning: all contacts found will be deleted! addressbook fa هشدار! تمامی مخاطبین حذف خواهند شد!
+work phone addressbook fa شماره محل کار
+write (update or add) a single entry by passing the fields. addressbook fa نوشتن(افزودن یا بهنگام سازی) یک ورودی با ارسال فیلدها
+you are not permitted to delete contact %1 addressbook fa شما مجاز به حذف مخاطب « %1 » نیستید.
+you are not permittet to delete this contact addressbook fa شما مجاز به حذف این مخاطب نیستید
+you are not permittet to edit this contact addressbook fa شما مجاز به ویرایش این مخاطب نیستید
+you are not permittet to view this contact addressbook fa شما مجاز به
+you must select a vcard. (*.vcf) addressbook fa شما باید یک vcard انتخاب کنید
+you must select at least 1 column to display addressbook fa شما باید حد اقل یک ستون برای نمایش انتخاب کنید
+zip code common fa کد پستی
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_fi.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_fi.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_fi.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_fi.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,322 @@
+%1 added addressbook fi %1 lisätty
+%1 contact(s) %2 addressbook fi %1 yhteystieto(a) %2
+%1 contact(s) %2, %3 failed because of insufficent rights !!! addressbook fi %1 yhteystieto(a) %2, %3 epäonnistui puutteellisien oikeuksien takia !!!
+%1 fields in %2 other organisation member(s) changed addressbook fi %1 kenttiä %2:ssa muun organisaation jäsen(iä) on muutettu
+%1 records imported addressbook fi %1 tietuetta tuotu
+%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook fi %1 tietuetta luettu (ei vielä tuotu, voit %2palata%3 takaisin ja poistaa valinnan Testaa tuontia)
+%1 starts with '%2' addressbook fi %1 alkaa %2
+(e.g. 1969) addressbook fi (esim. 1969)
+no conversion type <none> could be located. please choose a conversion type from the list addressbook fi Muunnostyyppiä
Syntyvä tiedosto on LDIF -muodossa.
Outlookissa: valitse Yhteystiedot -kansio, valitse Tiedosto -valikosta +in %1 days (%2) is %3's birthday. addressbook fi %1 päivää (%2) on %3:n syntymäpäivä +income addressbook fi Tulossa +insufficent rights to delete this list! addressbook fi Puuttelliset oikeudet listan poistamiseksi! +international addressbook fi Kansainvälinen +label addressbook fi Nimikenttä +last modified addressbook fi Viimeksi muokattu +last modified by addressbook fi viimeksi muokannut +ldap context for contacts admin fi LDAP-konteksti +ldap host for contacts admin fi LDAP-palvelin +ldap settings for contacts admin fi Yhteystietojen LDAP asetukset +ldif addressbook fi LDIF +line 2 addressbook fi Rivi 2 +link title for contacts show addressbook fi Linkitä otsikko näyttämää yhteystieto +links addressbook fi Linkit +list all categories addressbook fi Näytä kaikki kategoriat +list all customfields addressbook fi Näytä kaikki omat kentät +list already exists! addressbook fi Lista on jo olemassa +list created addressbook fi Lista luotu +list creation failed, no rights! addressbook fi Listan luonti epäonnistu, ei riittävästi oikeuksia! +load vcard addressbook fi Lataa VCard +locations addressbook fi sijainnit +mark records as private addressbook fi Mark records as private +message phone addressbook fi Vastaajapalvelu +middle name addressbook fi Toimen nimi +migration finished addressbook fi Sulauttaminen valmis +migration to ldap admin fi Sulauta LDAP:iin +mobile addressbook fi GSM +mobile phone addressbook fi Matkapuhelin +modem phone addressbook fi Modem Phone +more ... addressbook fi Lisää ... +move to addressbook: addressbook fi Siirrä osoitekirjaan +moved addressbook fi siirretty +multiple vcard addressbook fi Monta VCardia +name for the distribution list addressbook fi Nimeä jakelulista +name, address addressbook fi Nimi, osoite +no vcard addressbook fi Ei VCard +number addressbook fi Numero +number of records to read (%1) addressbook fi Luettavien tietueiden määrä (%1) +options for type admin fi Option muoto +organisation addressbook fi Organisaatio +organisations addressbook fi Organisaatiot +organisations by departments addressbook fi Organisaatiot osastoittain +organisations by location addressbook fi Organisaatiot sijainneittain +other number addressbook fi Muu numero +other phone addressbook fi Muu puhelin +own sorting addressbook fi oma lajittelu +pager common fi Hakulaite +parcel addressbook fi Paketti +permission denied !!! addressbook fi Pääsy estetty !!! +phone number common fi Puhelinnumero +phone numbers common fi Puhelinnumerot +photo addressbook fi Kuva +please enter a name for that field ! addressbook fi Anna kentän nimi! +please select only one category addressbook fi Valitse kategoria +postal common fi Postal +pref addressbook fi etuliite +preferred phone addressbook fi ensisijainen puhelin +prefix addressbook fi Etuliite +public key addressbook fi Julkinen avain +publish into groups: addressbook fi Julkaise ryhmissä +read a list / search for entries. addressbook fi Lue luettelo / hae tietueita +read a list of entries. addressbook fi Lue tietueiden luettelo +read a single entry by passing the id and fieldlist. addressbook fi Lue yksittäinen tietue antamalla tunniste ja kenttäluettelo. +read only addressbook fi Vain luku +record access addressbook fi Lukuoikeus +record owner addressbook fi Omistaja +remove selected contacts from distribution list addressbook fi Poista valitut yhteystiedot jakelulistalta +removed from distribution list addressbook fi poistettu jakelulistalta +role addressbook fi Rooli +room addressbook fi Tila +search for '%1' addressbook fi haku '%1' +select a portrait format jpeg photo. it will be resized to 60 pixel width. addressbook fi Valitse jpeg muodossa oleva kuva. Se muokataan 60 pikseliä korkeaksi kuvaksi. +select a view addressbook fi Valitse näkymä +select addressbook type addressbook fi Valitse osoitekirjan muoto +select all addressbook fi Valitse kaikki +select an action or addressbook to move to addressbook fi Valitse toiminto tai osoitekirja siirrettäväksi +select migration type admin fi Valitse sulautus tapa +select multiple contacts for a further action addressbook fi Suorita valituille yhteystiedoille seuraava toiminto +select phone number as prefered way of contact addressbook fi valitse puhelinnumero ensisijaiseksi yhteydenotto tavaksi yhteystiedolle +select the type of conversion addressbook fi Valitse muunnoksen tyyppi +select the type of conversion: addressbook fi Valitse muunnoksen tyyppi: +select where you want to store / retrieve contacts admin fi Valitse minne varastoit / mistä palautat yhteystiedot +selected contacts addressbook fi valitse yhteystiedot +should the columns photo and home address always be displayed, even if they are empty. addressbook fi Näytetäänkö kuva ja kotiosoite sarake aina, vaikka ne olisivat tyhjiä. +show addressbook fi Näytä +show birthday reminders on main screen addressbook fi Näytä syntymäpäivämuistutukset päänäytöllä +show infolog entries for this organisation addressbook fi Näytä InfoLogin merkinnät tästä organisaatiosta +show the contacts of this organisation addressbook fi Näytä tämän organisaation yhteystiedot +size of popup (wxh, eg.400x300, if a popup should be used) admin fi Popup ikkunan koko (K x L, esim 400 x 300, jos popup ikkunat ovat käytössä) +start admin fi Aloita +startrecord addressbook fi Aloitustietue +state common fi Osavaltio +street common fi Katuosoite +successfully imported %1 records into your addressbook. addressbook fi Tuotiin %1 tietuetta osoitekirjaan. +suffix addressbook fi Jälkiliite +tel home addressbook fi Kotipuhelin +telephony integration admin fi Puhelinintegrointi +test import (show importable records only in browser) addressbook fi Testaa tuontia (näytä tuotavat tietueet vain selaimessa) +that field name has been used already ! addressbook fi Kentän nimi on jo käytössä! +this person's first name was not in the address book. addressbook fi Etunimeä ei ole osoitekirjassa. +this person's last name was not in the address book. addressbook fi Sukunimeä ei ole osoitekirjassa. +timezone addressbook fi Aikavyöhyke +to many might exceed your execution-time-limit addressbook fi liian moni saattaa ylittää suoritusajan +today is %1's birthday! common fi Tänään syntymäpäiväänsä viettää %1! +tomorrow is %1's birthday. common fi Huomenna syntymäpäiväänsä viettää %1. +translation addressbook fi Käännös +type addressbook fi Muoto +update a single entry by passing the fields. addressbook fi Päivitä yksittäistä tietuetta antamalla kentät. +upload or delete the photo addressbook fi Lataa tai poista kuva +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin fi URL linkki puhelinnumeroon (käytä %1 = soitettava numero, %u = käyttäjän nimi, %t = käyttäjän puhelin) +use an extra category tab? addressbook fi Käytä ylimääräistä kategoria välilehteä +use country list addressbook fi Käytä maaluetteloa +used for links and for the own sorting of the list addressbook fi käytä linkeissä ja omassa lajittelu listassa +vcard common fi VCard +vcards require a first name entry. addressbook fi VCard vaatii etunimen. +vcards require a last name entry. addressbook fi VCard vaatii sukunimen. +view linked infolog entries addressbook fi Näytä linkitetyt Infologin merkinnät +warning!! ldap is valid only if you are not using contacts for accounts storage! admin fi VAROITUS!! LDAP soveltuu vain jos sitä ei käytetä käyttäjätunnusten tallentamiseen! +warning: all contacts found will be deleted! addressbook fi VAROITUS: Kaikki löytyneet osoitteet poistetaan! +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook fi Mitä osoitteen muotoa osoitekirja käyttää maista joiden osoitemuoto on tuntematon. Jos maan osoitemuoto on tiedossa, se käyttää sitä riippumatta asetuksesta. +which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook fi Mikä osoitekirja on valittuna kun lisätään yhteystietoja JA sinulla ei ole oikeuksia lisätä merkintöjä nykyiseen kalenteriin. +which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook fi Mitä merkistökoodausta käytetään CSV viennissä. Järjestelmän oletus on merkistökoodaus joka määriteltiin asennuksen yhteydessä. +which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook fi Mitkä kentät voidaan viedä. Kaikki tarkoittaa jokaista kenttää jotka osoitekirjasta löytyy, sisältäen asiakastiedot. Liiketoiminta tai kotiosoite sisältävät vain nimen, yrityksen ja valitut osoitekentät. +whole query addressbook fi koko kysely +work phone addressbook fi Työpuhelin +yes, for the next three days addressbook fi Kyllä, seuraavan 3 päivän ajalta +yes, for the next two weeks addressbook fi Kyllä, seuraavan 2 viikon ajalta +yes, for the next week addressbook fi Kyllä, seuraavan viikon ajalta +yes, for today and tomorrow addressbook fi Kyllä, tämänpäivän ja huomisen ajalta +you are not permitted to delete contact %1 addressbook fi Sinulla ei ole oikeutta poistaa kontaktia %1 +you are not permittet to delete this contact addressbook fi Sinulla ei ole oikeutta poistaa tätä kontaktia +you are not permittet to edit this contact addressbook fi Sinulla ei ole oikeutta muokata tätä kontaktia +you are not permittet to view this contact addressbook fi Sinulla ei ole oikeutta nähdä tätä kontaktia +you must select a vcard. (*.vcf) addressbook fi Valitse vcard -tiedosto. (*.vcf) +you must select at least 1 column to display addressbook fi Valitse ainakin yksi näytettävä sarake +you need to select a distribution list addressbook fi Valitse ensin jakelulista +you need to select some contacts first addressbook fi Valitse ensin joku yhteystieto +zip code common fi Postinumero +zip_note addressbook fi
Huom: Tiedosto voi olla usean .csv-, .vcf- tai .ldif- tiedoston zip-paketti. Älä kuitenkaan tuo useampaa tiedostotyyppiä kerralla.
diff -Nru /tmp/IEcAucsswJ/egroupware-1.4.004-2.dfsg/addressbook/setup/egw_fr.lang /tmp/zYV1ViGWhF/egroupware-1.6.001+dfsg/addressbook/setup/egw_fr.lang
--- egroupware-1.4.004-2.dfsg/addressbook/setup/egw_fr.lang 1970-01-01 01:00:00.000000000 +0100
+++ egroupware-1.6.001+dfsg/addressbook/setup/egw_fr.lang 2008-11-24 11:43:08.000000000 +0000
@@ -0,0 +1,767 @@
+%1 - %2 of %3 user accounts admin fr %1 - %2 de %3 comptes utilisateurs
+%1 - %2 of %3 user groups admin fr %1 - %2 de %3 groupes utilisateurs
+%1 acl records of not (longer) existing accounts deleted. admin fr %1 droits d'accès de comptes inexistants supprimés.
+%1 added addressbook fr %1 ajouté
+%1 contact(s) %2 addressbook fr %1 contact(s) %2
+%1 contact(s) %2, %3 failed because of insufficent rights !!! addressbook fr %1 contact(s) %2, %3 en erreur (droits d'accès insuffisants).
+%1 fields in %2 other organisation member(s) changed addressbook fr Le champ %1 dans %2 d'autre membre de l'organisation a changé.
+%1 not found or not executable !!! admin fr %1 introuvable ou pas exécutable !!!
+%1 records imported addressbook fr %1 enregistrements importés
+%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook fr %1 enregistrements lus (non encore importé, vous devriez retourner en arrière %2back%3 et décocher le test de límportation)
+%1 starts with '%2' addressbook fr %1 débute avec '%2'
+%s please calculate the result addressbook fr %s calculez s'il vous plait le résultat
+(default no, leave it off if you dont use it) admin fr (Non par défaut, ne pas modifier si vous ne l'utilisez pas)
+(e.g. 1969) addressbook fr (e.g. 1969)
+(stored password will not be shown here) admin fr (Le mot de passe enregistré ne sera pas montré ici)
+(to install new applications use
setup [manage applications] !!!) admin fr (Pour installer de nouvelles applications utilisez
Setup [Gérer Les Applications] !!!)
+- type admin fr - type
+no conversion type <none> could be located. please choose a conversion type from the list addressbook fr Aucun type de conversion
(0-6, 0=sun) admin fr Jour de la semaine
(0-6, 0=Dim)
+db backup and restore admin fr Sauvegarde et restauration de la BDD
+debug output in browser addressbook fr Deboguer la sortie dans le navigateur
+default addressbook fr Défaut
+default addressbook for adding contacts addressbook fr Carnet d'adresses par défaut pour l'ajout de contacts
+default file system space per user admin fr Espace disque par utilisateur (par défaut)
+default file system space per user/group ? admin fr Espace disque par utilisateur/groupe (par défaut) ?
+default filter addressbook fr Filtre par défaut
+deinstall crontab admin fr Désinstaller le crontab
+delete a single entry by passing the id. addressbook fr Effacer une seule entrée en passant l'ID.
+delete account admin fr Supprimer le compte
+delete all records admin fr Supprimer tous les enregistrements
+delete application admin fr Supprimer l'application
+delete category admin fr Supprimer catégorie
+delete group admin fr Supprimer groupe
+delete peer server admin fr Supprimer serveur Pair
+delete selected distribution list! addressbook fr Effacer la liste de distribution sélectionnée!
+delete the category admin fr Supprimer la catégorie
+delete the group admin fr Supprimer le groupe
+delete this category admin fr Supprimer cette catégorie
+delete this contact addressbook fr Supprimer ce contact
+delete this group admin fr Supprimer ce groupe
+delete this organisation including all its contacts addressbook fr Détruire cette organisation et tous ses contacts
+delete this user admin fr Supprimer cet utilisateur
+deleted addressbook fr supprimé
+deletes the photo addressbook fr Supprime la photo
+deletes this field admin fr Supprimer ce champ
+deliver extern admin fr Envoi externe
+deny access to access log admin fr Refuser l'accès au log d'accès
+deny access to application registery admin fr Refuser l'accès à l'enregistrement d'applications
+deny access to applications admin fr Refuser l'accès aux applications
+deny access to asynchronous timed services admin fr Refuser l'accès aux services asynchrones
+deny access to current sessions admin fr Refuser l'accès aux sessions en cours
+deny access to db backup and restore admin fr Refuser l'accès à Sauvegarde et restauration de la BDD
+deny access to error log admin fr Refuser l'accès à la log d'erreurs
+deny access to global categories admin fr Refuser l'accès aux catégories globales
+deny access to groups admin fr Refuser l'accès aux groupes
+deny access to mainscreen message admin fr Refuser l'accès au message de la page principale
+deny access to peer servers admin fr Refuser l'accès aux serveurs pairs
+deny access to phpinfo admin fr Refuser l'accès à phpinfo
+deny access to site configuration admin fr Refuser l'accès à la configuration du site
+deny access to user accounts admin fr Refuser l'accès aux comptes utilisateurs
+deny all users access to grant other users access to their entries ? admin fr Les utilisateurs ne peuvent permettre aux autres l'accès à leurs données ?
+department common fr Département
+departments addressbook fr départements
+description can not exceed 255 characters in length ! admin fr La description ne peut dépasser 255 caractères de long !
+determines the order the fields are displayed admin fr Détermine l'ordre d'afficahge des champs
+disable "auto completion" of the login form admin fr Désactiver "remplissage auto" dans le formulaire de login
+disable wysiwyg-editor admin fr désactiver l'éditeur WYSIWYG
+disabled (not recomended) admin fr désactivé (pas recommandé)
+display admin fr Afficher
+displays a remider for birthdays on the startpage (page you get when you enter egroupware or click on the homepage icon). addressbook fr Affiche un rappel pour les anniversaires sur la page d'accueil (page qui s'affiche quand vous entrez dans eGroupWare ou quand vous cliquez sur l'icône Accueil)
+distribution list deleted addressbook fr La liste de distribution est supprimée
+distribution lists addressbook fr Listes de distribution
+do not delete the category and return back to the list admin fr Ne PAS supprimer la catégorie et retourner à la liste
+do you also want to delete all global subcategories ? admin fr Voulez-vous aussi supprimer toutes les sous-catégories globales ?
+do you want a private addressbook, which can not be viewed by users, you grant access to your personal addressbook? addressbook fr Voulez vous un carnet d'adresse privé qui ne pourra être vu par les autres utilisateurs sauf si vous modifiez les autorisations ?
+do you want to delete all global subcategories ? admin fr Voulez-vous supprimer toutes les sous-catégories globales ?
+do you want to move all global subcategories one level down ? admin fr Voulez-vous déplacer toutes les sous-catégories globales un niveau plus bas ?
+do your really want to delete this contact? addressbook fr Voulez vous vraiment supprimer ce contact?
+doesn't matter addressbook fr sans importance
+domestic addressbook fr Domestique
+don't hide empty columns addressbook fr Ne pas cacher les colonnes vides
+download addressbook fr Télécharger
+download export file (uncheck to debug output in browser) addressbook fr Télécharger le fichier d'exportation (Décocher pour deboguer la sortie dans le navigateur)
+download this contact as vcard file addressbook fr Téléchargez ce contact comme un fichier vCard
+each value is a line like