mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-02-02 11:29:23 +01:00
* Update to 1.8.004: REQUIRES TO VISIT SETUP for schema updates
- backport of security features from Trunk: support for sha512_crypt password and session-list without access to session-directory - backport of numerous CalDAV/CardDAV features and fixes from Trunk: multiple addressbooks and calendars, support of resources, request logging
This commit is contained in:
commit
41fd3575c9
@ -7,7 +7,7 @@
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @package addressbook
|
||||
* @copyright (c) 2005-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
@ -36,6 +36,9 @@ class addressbook_bo extends addressbook_so
|
||||
'org_name: n_family, n_prefix',
|
||||
'org_name: n_given n_family',
|
||||
'org_name: n_fn',
|
||||
'org_name, org_unit: n_family, n_given',
|
||||
'org_name, adr_one_locality: n_family, n_given',
|
||||
'org_name, org_unit, adr_one_locality: n_family, n_given',
|
||||
'n_family, n_given: org_name',
|
||||
'n_family, n_given (org_name)',
|
||||
'n_family, n_prefix: org_name',
|
||||
@ -63,6 +66,7 @@ class addressbook_bo extends addressbook_so
|
||||
'adr_one_region',
|
||||
'adr_one_postalcode',
|
||||
'adr_one_countryname',
|
||||
'adr_one_countrycode',
|
||||
'label',
|
||||
'tel_work',
|
||||
'tel_fax',
|
||||
@ -121,6 +125,12 @@ class addressbook_bo extends addressbook_so
|
||||
* @var boolean
|
||||
*/
|
||||
var $default_private;
|
||||
/**
|
||||
* Use a separate private addressbook (former private flag), for contacts not shareable via regular read acl
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $private_addressbook = false;
|
||||
/**
|
||||
* Categories object
|
||||
*
|
||||
@ -128,9 +138,31 @@ class addressbook_bo extends addressbook_so
|
||||
*/
|
||||
var $categories;
|
||||
|
||||
function __construct($contact_app='addressbook')
|
||||
/**
|
||||
* Tracking changes
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $tracking;
|
||||
|
||||
/**
|
||||
* Keep deleted addresses, or really delete them
|
||||
* Set in Admin -> Addressbook -> Site Configuration
|
||||
* ''=really delete, 'history'=keep, only admins delete, 'userpurge'=keep, users delete
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $delete_history = '';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $contact_app='addressbook' used for acl->get_grants()
|
||||
* @param egw_db $db=null
|
||||
*/
|
||||
function __construct($contact_app='addressbook',egw_db $db=null)
|
||||
{
|
||||
parent::__construct($contact_app);
|
||||
parent::__construct($contact_app,$db);
|
||||
if ($this->log)
|
||||
{
|
||||
$this->logfile = $GLOBALS['egw_info']['server']['temp_dir'].'/log-addressbook_bo';
|
||||
@ -151,6 +183,7 @@ class addressbook_bo extends addressbook_so
|
||||
{
|
||||
$this->default_addressbook = $this->user; // admin set a default or forced pref for personal addressbook
|
||||
}
|
||||
$this->private_addressbook = $this->contact_repository == 'sql' && $this->prefs['private_addressbook'];
|
||||
|
||||
$this->contact_fields = array(
|
||||
'id' => lang('Contact ID'),
|
||||
@ -178,6 +211,7 @@ class addressbook_bo extends addressbook_so
|
||||
'adr_one_region' => lang('state').' ('.lang('business').')',
|
||||
'adr_one_postalcode' => lang('zip code').' ('.lang('business').')',
|
||||
'adr_one_countryname' => lang('country').' ('.lang('business').')',
|
||||
'adr_one_countrycode' => lang('country code').' ('.lang('business').')',
|
||||
'label' => lang('label'),
|
||||
'adr_two_street' => lang('street').' ('.lang('private').')',
|
||||
'adr_two_street2' => lang('address line 2').' ('.lang('private').')',
|
||||
@ -185,6 +219,7 @@ class addressbook_bo extends addressbook_so
|
||||
'adr_two_region' => lang('state').' ('.lang('private').')',
|
||||
'adr_two_postalcode' => lang('zip code').' ('.lang('private').')',
|
||||
'adr_two_countryname' => lang('country').' ('.lang('private').')',
|
||||
'adr_two_countrycode' => lang('country code').' ('.lang('private').')',
|
||||
'tel_work' => lang('work phone'),
|
||||
'tel_cell' => lang('mobile phone'),
|
||||
'tel_fax' => lang('fax').' ('.lang('business').')',
|
||||
@ -257,8 +292,24 @@ class addressbook_bo extends addressbook_so
|
||||
if ($GLOBALS['egw_info']['server']['org_fileds_to_update'])
|
||||
{
|
||||
$this->org_fields = unserialize($GLOBALS['egw_info']['server']['org_fileds_to_update']);
|
||||
|
||||
// Set country code if country name is selected
|
||||
$supported_fields = $this->get_fields('supported',null,0);
|
||||
if(in_array('adr_one_countrycode', $supported_fields) && in_array('adr_one_countryname',$this->org_fields))
|
||||
{
|
||||
$this->org_fields[] = 'adr_one_countrycode';
|
||||
}
|
||||
if(in_array('adr_two_countrycode', $supported_fields) && in_array('adr_two_countryname',$this->org_fields))
|
||||
{
|
||||
$this->org_fields[] = 'adr_two_countrycode';
|
||||
}
|
||||
}
|
||||
$this->categories = new categories($this->user,'addressbook');
|
||||
|
||||
$this->tracking = new addressbook_tracking($this);
|
||||
|
||||
$config = config::read('phpgwapi');
|
||||
$this->delete_history = $config['history'];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -323,15 +374,31 @@ class addressbook_bo extends addressbook_so
|
||||
*
|
||||
* @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
|
||||
* @param boolean $update=false If true, reads the old record for any not set fields
|
||||
* @return string
|
||||
*/
|
||||
function fileas($contact,$type=null)
|
||||
function fileas($contact,$type=null, $isUpdate=false)
|
||||
{
|
||||
if (is_null($type)) $type = $contact['fileas_type'];
|
||||
if (!$type) $type = $this->prefs['fileas_default'] ? $this->prefs['fileas_default'] : $this->fileas_types[0];
|
||||
|
||||
if (strpos($type,'n_fn') !== false) $contact['n_fn'] = $this->fullname($contact);
|
||||
|
||||
if($isUpdate)
|
||||
{
|
||||
$fileas_fields = array('n_prefix','n_given','n_middle','n_family','n_suffix','n_fn','org_name','org_unit','adr_one_locality');
|
||||
$old = null;
|
||||
foreach($fileas_fields as $field)
|
||||
{
|
||||
if(!isset($contact[$field]))
|
||||
{
|
||||
if(is_null($old)) $old = $this->read($contact['id']);
|
||||
$contact[$field] = $old[$field];
|
||||
}
|
||||
}
|
||||
unset($old);
|
||||
}
|
||||
|
||||
$fileas = str_replace(array('n_prefix','n_given','n_middle','n_family','n_suffix','n_fn','org_name','org_unit','adr_one_locality'),
|
||||
array($contact['n_prefix'],$contact['n_given'],$contact['n_middle'],$contact['n_family'],$contact['n_suffix'],
|
||||
$contact['n_fn'],$contact['org_name'],$contact['org_unit'],$contact['adr_one_locality']),$type);
|
||||
@ -480,8 +547,8 @@ class addressbook_bo extends addressbook_so
|
||||
|
||||
// fields that must not be touched
|
||||
$fields_exclude = array(
|
||||
'id' => true,
|
||||
'tid' => true,
|
||||
'id' => true,
|
||||
'tid' => true,
|
||||
'owner' => true,
|
||||
'private' => true,
|
||||
'created' => true,
|
||||
@ -490,9 +557,9 @@ class addressbook_bo extends addressbook_so
|
||||
'modifier' => true,
|
||||
'account_id' => true,
|
||||
'etag' => true,
|
||||
'uid' => true,
|
||||
'uid' => true,
|
||||
'freebusy_uri' => true,
|
||||
'calendar_uri' => true,
|
||||
'calendar_uri' => true,
|
||||
'photo' => true,
|
||||
);
|
||||
|
||||
@ -589,6 +656,8 @@ class addressbook_bo extends addressbook_so
|
||||
*/
|
||||
function db2data($data, $date_format='ts')
|
||||
{
|
||||
static $fb_url = false;
|
||||
|
||||
// convert timestamps from server-time in the db to user-time
|
||||
foreach ($this->timestamps as $name)
|
||||
{
|
||||
@ -602,10 +671,12 @@ class addressbook_bo extends addressbook_so
|
||||
// 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 = calendar_bo::freebusy_url('');
|
||||
if ($fb_url) $data['freebusy_uri'] = $fb_url.urlencode(
|
||||
isset($data['account_lid']) ? $data['account_lid'] : $GLOBALS['egw']->accounts->id2name($data['account_id']));
|
||||
if ($fb_url || @is_dir(EGW_SERVER_ROOT.'/calendar/inc'))
|
||||
{
|
||||
$fb_url = true;
|
||||
$user = isset($data['account_lid']) ? $data['account_lid'] : $GLOBALS['egw']->accounts->id2name($data['account_id']);
|
||||
$data['freebusy_uri'] = calendar_bo::freebusy_url($user);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
@ -672,17 +743,38 @@ class addressbook_bo extends addressbook_so
|
||||
$id = is_array($c) ? $c['id'] : $c;
|
||||
|
||||
$ok = false;
|
||||
if ($this->check_perms(EGW_ACL_DELETE,$c,$deny_account_delete) && ($ok = parent::delete($id,$check_etag)))
|
||||
if ($this->check_perms(EGW_ACL_DELETE,$c,$deny_account_delete))
|
||||
{
|
||||
egw_link::unlink(0,'addressbook',$id);
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $id, 'delete', time());
|
||||
if (!($old = $this->read($id))) return false;
|
||||
// check if we only mark contacts as deleted, or really delete them
|
||||
// already marked as deleted item and accounts are always really deleted
|
||||
// we cant mark accounts as deleted, as no such thing exists for accounts!
|
||||
if ($old['owner'] && $this->delete_history != '' && $old['tid'] != addressbook_so::DELETED_TYPE)
|
||||
{
|
||||
$delete = $old;
|
||||
$delete['tid'] = addressbook_so::DELETED_TYPE;
|
||||
$ok = $this->save($delete);
|
||||
egw_link::unlink(0,'addressbook',$id,'','','',true);
|
||||
}
|
||||
elseif (($ok = parent::delete($id,$check_etag)))
|
||||
{
|
||||
egw_link::unlink(0,'addressbook',$id);
|
||||
}
|
||||
|
||||
// Don't notify of final purge
|
||||
if ($ok && $old['tid'] != addressbook_so::DELETED_TYPE)
|
||||
{
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $id, 'delete', time());
|
||||
$this->tracking->track(array('id' => $id), array('id' => $id), null, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $ok;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
//error_log(__METHOD__.'('.array2string($contact).', deny_account_delete='.array2string($deny_account_delete).', check_etag='.array2string($check_etag).' returning '.array2string($ok));
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -747,6 +839,27 @@ class addressbook_bo extends addressbook_so
|
||||
{
|
||||
$contact['cat_id'] = implode(',',$contact['cat_id']);
|
||||
}
|
||||
|
||||
// Update country codes
|
||||
foreach(array('adr_one_', 'adr_two_') as $c_prefix) {
|
||||
if($contact[$c_prefix.'countryname'] && !$contact[$c_prefix.'countrycode'] &&
|
||||
$code = $GLOBALS['egw']->country->country_code($contact[$c_prefix.'countryname']))
|
||||
{
|
||||
if(strlen($code) == 2)
|
||||
{
|
||||
$contact[$c_prefix.'countrycode'] = $code;
|
||||
}
|
||||
else
|
||||
{
|
||||
$contact[$c_prefix.'countrycode'] = null;
|
||||
}
|
||||
}
|
||||
if($contact[$c_prefix.'countrycode'] != null)
|
||||
{
|
||||
$contact[$c_prefix.'countryname'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// last modified
|
||||
$contact['modifier'] = $this->user;
|
||||
$contact['modified'] = $this->now_su;
|
||||
@ -754,8 +867,9 @@ class addressbook_bo extends addressbook_so
|
||||
if (!isset($contact['n_fn']))
|
||||
{
|
||||
$contact['n_fn'] = $this->fullname($contact);
|
||||
if (isset($contact['org_name'])) $contact['n_fileas'] = $this->fileas($contact);
|
||||
}
|
||||
if (isset($contact['org_name'])) $contact['n_fileas'] = $this->fileas($contact, null, false);
|
||||
|
||||
$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))
|
||||
@ -768,6 +882,22 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get old record for tracking changes
|
||||
if (!isset($old) && $isUpdate)
|
||||
{
|
||||
$old = $this->read($contact['id']);
|
||||
}
|
||||
// IF THE OLD ENTRY IS A ACCOUNT, dont allow to change the owner/location
|
||||
// maybe we need that for id and account_id as well.
|
||||
if (is_array($old) && (!isset($old['owner']) || empty($old['owner'])))
|
||||
{
|
||||
if (isset($to_write['owner']) && !empty($to_write['owner']))
|
||||
{
|
||||
error_log(__METHOD__.__LINE__." Trying to change account to owner:". $to_write['owner'].' Account affected:'.array2string($old).' Data send:'.array2string($to_write));
|
||||
unset($to_write['owner']);
|
||||
}
|
||||
}
|
||||
// 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))
|
||||
{
|
||||
@ -788,6 +918,18 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
// Notify linked apps about changes in the contact data
|
||||
egw_link::notify_update('addressbook', $contact['id'], $contact);
|
||||
|
||||
// Check for restore of deleted contact, restore held links
|
||||
if($old && $old['tid'] == addressbook_so::DELETED_TYPE && $contact['tid'] != addressbook_so::DELETED_TYPE)
|
||||
{
|
||||
egw_link::restore('addressbook', $contact['id']);
|
||||
}
|
||||
|
||||
// Record change history for sql - doesn't work for LDAP accounts
|
||||
if(!$contact['account_id'] || $contact['account_id'] && $this->account_repository == 'sql') {
|
||||
$deleted = ($old['tid'] == addressbook_so::DELETED_TYPE || $contact['tid'] == addressbook_so::DELETED_TYPE);
|
||||
$this->tracking->track($to_write, $old ? $old : null, null, $deleted);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->error ? false : $contact['id'];
|
||||
@ -848,31 +990,55 @@ class addressbook_bo extends addressbook_so
|
||||
{
|
||||
if (!($data = parent::read($contact_id)))
|
||||
{
|
||||
return null; // not found
|
||||
$data = null; // not found
|
||||
}
|
||||
if (!$this->check_perms(EGW_ACL_READ,$data))
|
||||
elseif (!$this->check_perms(EGW_ACL_READ,$data))
|
||||
{
|
||||
return false; // no view perms
|
||||
$data = false; // no view perms
|
||||
}
|
||||
// determine the file-as type
|
||||
$data['fileas_type'] = $this->fileas_type($data);
|
||||
else
|
||||
{
|
||||
// determine the file-as type
|
||||
$data['fileas_type'] = $this->fileas_type($data);
|
||||
|
||||
// Update country name from code
|
||||
if($data['adr_one_countrycode'] != null) {
|
||||
$data['adr_one_countryname'] = $GLOBALS['egw']->country->get_full_name($data['adr_one_countrycode'], true);
|
||||
}
|
||||
if($data['adr_two_countrycode'] != null) {
|
||||
$data['adr_two_countryname'] = $GLOBALS['egw']->country->get_full_name($data['adr_two_countrycode'], true);
|
||||
}
|
||||
}
|
||||
//error_log(__METHOD__.'('.array2string($contact_id).') returning '.array2string($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)
|
||||
* 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
|
||||
* @param int $user=null for which user to check, default current user
|
||||
* @return boolean true permission granted, false for permission denied, null for contact does not exist
|
||||
*/
|
||||
function check_perms($needed,$contact,$deny_account_delete=false,$user=null)
|
||||
{
|
||||
if (!$user) $user = $this->user;
|
||||
if ($user == $this->user)
|
||||
{
|
||||
$grants = $this->grants;
|
||||
$memberships = $this->memberships;
|
||||
}
|
||||
else
|
||||
{
|
||||
$grants = $this->get_grants($user);
|
||||
$memberships = $GLOBALS['egw']->accounts->memberships($user,true);
|
||||
}
|
||||
|
||||
if ((!is_array($contact) || !isset($contact['owner'])) &&
|
||||
!($contact = parent::read(is_array($contact) ? $contact['id'] : $contact)))
|
||||
{
|
||||
@ -881,25 +1047,43 @@ class addressbook_bo extends addressbook_so
|
||||
$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)
|
||||
if (!$owner && $needed == EGW_ACL_EDIT && $contact['account_id'] == $user && $this->own_account_acl)
|
||||
{
|
||||
return true;
|
||||
$access = 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))
|
||||
elseif (!$owner && $needed == EGW_ACL_DELETE && ($deny_account_delete || $contact['account_id'] == $user))
|
||||
{
|
||||
return false;
|
||||
$access = false;
|
||||
}
|
||||
// for reading accounts (owner == 0) and account_selection == groupmembers, check if current user and contact are groupmembers
|
||||
if ($owner == 0 && $needed == EGW_ACL_READ &&
|
||||
elseif ($owner == 0 && $needed == EGW_ACL_READ &&
|
||||
$GLOBALS['egw_info']['user']['preferences']['common']['account_selection'] == 'groupmembers' &&
|
||||
!isset($GLOBALS['egw_info']['user']['apps']['admin']))
|
||||
{
|
||||
return !!array_intersect($GLOBALS['egw']->accounts->memberships($this->user,true),
|
||||
$GLOBALS['egw']->accounts->memberships($contact['account_id'],true));
|
||||
$access = !!array_intersect($memberships,$GLOBALS['egw']->accounts->memberships($contact['account_id'],true));
|
||||
}
|
||||
return ($this->grants[$owner] & $needed) &&
|
||||
(!$contact['private'] || ($this->grants[$owner] & EGW_ACL_PRIVATE) || in_array($owner,$this->memberships));
|
||||
else
|
||||
{
|
||||
$access = ($grants[$owner] & $needed) &&
|
||||
(!$contact['private'] || ($grants[$owner] & EGW_ACL_PRIVATE) || in_array($owner,$memberships));
|
||||
}
|
||||
//error_log(__METHOD__."($needed,$contact[id],$deny_account_delete,$user) returning ".array2string($access));
|
||||
return $access;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access to the file store
|
||||
*
|
||||
* @param int|array $id id of entry or entry array
|
||||
* @param int $check EGW_ACL_READ for read and EGW_ACL_EDIT for write or delete access
|
||||
* @param string $rel_path=null currently not used in InfoLog
|
||||
* @param int $user=null for which user to check, default current user
|
||||
* @return boolean true if access is granted or false otherwise
|
||||
*/
|
||||
function file_access($id,$check,$rel_path=null,$user=null)
|
||||
{
|
||||
return $this->check_perms($check,$id,false,$user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1186,23 +1370,29 @@ class addressbook_bo extends addressbook_so
|
||||
* Is called as hook to participate in the linking
|
||||
*
|
||||
* @param string|array $pattern pattern to search, or an array with a 'search' key
|
||||
* @param array $options Array of options for the search
|
||||
* @return array with id - title pairs of the matching entries
|
||||
*/
|
||||
function link_query($pattern)
|
||||
function link_query($pattern, Array &$options = array())
|
||||
{
|
||||
$result = $criteria = array();
|
||||
$filter = $result = $criteria = array();
|
||||
$limit = false;
|
||||
if ($pattern)
|
||||
{
|
||||
foreach($this->columns_to_search as $col)
|
||||
{
|
||||
$criteria[$col] = is_array($pattern) ? $pattern['search'] : $pattern;
|
||||
}
|
||||
$criteria = is_array($pattern) ? $pattern['search'] : $pattern;
|
||||
}
|
||||
if (($contacts = parent::search($criteria,false,'org_name,n_family,n_given,cat_id','','%',false,'OR')))
|
||||
if($options['start'] || $options['num_rows'])
|
||||
{
|
||||
$limit = array($options['start'], $options['num_rows']);
|
||||
}
|
||||
$filter = (array)$options['filter'];
|
||||
if ($GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) $filter['account_id'] = null;
|
||||
if (($contacts =& parent::search($criteria,false,'org_name,n_family,n_given,cat_id,contact_email','','%',false,'OR', $limit, $filter)))
|
||||
{
|
||||
foreach($contacts as $contact)
|
||||
{
|
||||
$result[$contact['id']] = $this->link_title($contact);
|
||||
$result[$contact['id']] = $this->link_title($contact).
|
||||
($options['type'] === 'email' ? ' <'.$contact['email'].'>' : '');
|
||||
// show category color
|
||||
if ($contact['cat_id'] && ($color = etemplate::cats2color($contact['cat_id'])))
|
||||
{
|
||||
@ -1213,19 +1403,30 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
}
|
||||
}
|
||||
$options['total'] = $this->total;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access to the projects file store
|
||||
* Query for subtype email (returns only contacts with email address set)
|
||||
*
|
||||
* @param int $id id of entry
|
||||
* @param int $check EGW_ACL_READ for read and EGW_ACL_EDIT for write or delete access
|
||||
* @return boolean true if access is granted or false otherwise
|
||||
* @param string|array $pattern
|
||||
* @param array $options
|
||||
* @return Ambigous <multitype:, string, multitype:Ambigous <multitype:, string> string >
|
||||
*/
|
||||
function file_access($id,$check,$rel_path)
|
||||
function link_query_email($pattern, Array &$options = array())
|
||||
{
|
||||
return $this->check_perms($check,$id);
|
||||
if (isset($options['filter']) && !is_array($options['filter']))
|
||||
{
|
||||
$options['filter'] = (array)$options['filter'];
|
||||
}
|
||||
// return only contacts with email set
|
||||
$options['filter'][] = "contact_email LIKE '%@%'";
|
||||
|
||||
// let link query know, to append email to list
|
||||
$options['type'] = 'email';
|
||||
|
||||
return $this->link_query($pattern,$options);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1301,6 +1502,9 @@ class addressbook_bo extends addressbook_so
|
||||
'id' => $event['id'],
|
||||
'app' => 'calendar',
|
||||
'title' => $bocal->link_title($event),
|
||||
'extra_args' => array(
|
||||
'date' => date('Ymd',$event['start']),
|
||||
),
|
||||
);
|
||||
if ($extra_title)
|
||||
{
|
||||
@ -1319,6 +1523,9 @@ class addressbook_bo extends addressbook_so
|
||||
'id' => $event['id'],
|
||||
'app' => 'calendar',
|
||||
'title' => $bocal->link_title($event),
|
||||
'extra_args' => array(
|
||||
'date' => date('Ymd',$event['start']),
|
||||
),
|
||||
);
|
||||
if ($extra_title)
|
||||
{
|
||||
@ -1330,7 +1537,6 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
}
|
||||
}
|
||||
//_debug_array($calendars);
|
||||
return $calendars;
|
||||
}
|
||||
|
||||
@ -1404,6 +1610,7 @@ class addressbook_bo extends addressbook_so
|
||||
function merge($ids)
|
||||
{
|
||||
$this->error = false;
|
||||
$account = null;
|
||||
$custom_fields = config::get_customfields('addressbook', true);
|
||||
$custom_field_list = $this->read_customfields($ids);
|
||||
foreach(parent::search(array('id'=>$ids),false) as $contact) // $this->search calls the extended search from ui!
|
||||
@ -1419,9 +1626,7 @@ class addressbook_bo extends addressbook_so
|
||||
continue;
|
||||
}
|
||||
// Add in custom fields
|
||||
foreach($custom_field_list[$contact['id']] as $field => $value) {
|
||||
$contact['#'.$field] = $value;
|
||||
}
|
||||
if (is_array($custom_field_list[$contact['id']])) $contact = array_merge($contact, $custom_field_list[$contact['id']]);
|
||||
|
||||
$pos = array_search($contact['id'],$ids);
|
||||
$contacts[$pos] = $contact;
|
||||
@ -1490,10 +1695,10 @@ class addressbook_bo extends addressbook_so
|
||||
// info_from and info_link_id (main link)
|
||||
$newlinkID = egw_link::link('addressbook',$target['id'],$data['app'],$data['id'],$data['remark'],$target['owner']);
|
||||
//_debug_array(array('newLinkID'=>$newlinkID));
|
||||
if ($newlinkID)
|
||||
if ($newlinkID)
|
||||
{
|
||||
// update egw_infolog set info_link_id=$newlinkID where info_id=$data['id'] and info_link_id=$data['link_id']
|
||||
if ($data['app']=='infolog')
|
||||
if ($data['app']=='infolog')
|
||||
{
|
||||
$this->db->update('egw_infolog',array(
|
||||
'info_link_id' => $newlinkID
|
||||
@ -1524,42 +1729,45 @@ class addressbook_bo extends addressbook_so
|
||||
{
|
||||
$owner = $list_data['list_owner'];
|
||||
}
|
||||
//error_log(__METHOD__."($list, $required, $owner) grants[$owner]=".$this->grants[$owner]." returning ".array2string(!!($this->grants[$owner] & $required)));
|
||||
return !!($this->grants[$owner] & $required);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a distribution list
|
||||
* Adds / updates a distribution list
|
||||
*
|
||||
* @param string $name list-name
|
||||
* @param string|array $keys list-name or array with column-name => value pairs to specify the list
|
||||
* @param int $owner user- or group-id
|
||||
* @param array $contacts=array() contacts to add
|
||||
* @return list_id or false on error
|
||||
* @param array $contacts=array() contacts to add (only for not yet existing lists!)
|
||||
* @param array &$data=array() values for keys 'list_uid', 'list_carddav_name', 'list_name'
|
||||
* @return int|boolean integer list_id or false on error
|
||||
*/
|
||||
function add_list($name,$owner,$contacts=array())
|
||||
function add_list($keys,$owner,$contacts=array(),array &$data=array())
|
||||
{
|
||||
if (!$this->check_list(null,EGW_ACL_ADD,$owner)) return false;
|
||||
if (!$this->check_list(null,EGW_ACL_ADD|EGW_ACL_EDIT,$owner)) return false;
|
||||
|
||||
return parent::add_list($name,$owner,$contacts);
|
||||
return parent::add_list($keys,$owner,$contacts,$data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one contact to a distribution list
|
||||
* Adds contacts to a distribution list
|
||||
*
|
||||
* @param int $contact contact_id
|
||||
* @param int|array $contact contact_id(s)
|
||||
* @param int $list list-id
|
||||
* @param array $existing=null array of existing contact-id(s) of list, to not reread it, eg. array()
|
||||
* @return false on error
|
||||
*/
|
||||
function add2list($contact,$list)
|
||||
function add2list($contact,$list,array $existing=null)
|
||||
{
|
||||
if (!$this->check_list($list,EGW_ACL_EDIT)) return false;
|
||||
|
||||
return parent::add2list($contact,$list);
|
||||
return parent::add2list($contact,$list,$existing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes one contact from distribution list(s)
|
||||
*
|
||||
* @param int $contact contact_id
|
||||
* @param int|array $contact contact_id(s)
|
||||
* @param int $list list-id
|
||||
* @return false on error
|
||||
*/
|
||||
@ -1680,17 +1888,16 @@ class addressbook_bo extends addressbook_so
|
||||
*/
|
||||
function find_or_add_categories($catname_list, $contact_id=null)
|
||||
{
|
||||
if($contact_id && $contact_id > 0)
|
||||
if ($contact_id && $contact_id > 0 && ($old_contact = $this->read($contact_id)))
|
||||
{
|
||||
// preserve categories without users read access
|
||||
$old_contact = $this->read($contact_id);
|
||||
$old_categories = explode(',',$old_contact['cat_id']);
|
||||
$old_cats_preserve = array();
|
||||
if(is_array($old_categories) && count($old_categories) > 0)
|
||||
if (is_array($old_categories) && count($old_categories) > 0)
|
||||
{
|
||||
foreach($old_categories as $cat_id)
|
||||
foreach ($old_categories as $cat_id)
|
||||
{
|
||||
if(!$this->categories->check_perms(EGW_ACL_READ, $cat_id))
|
||||
if (!$this->categories->check_perms(EGW_ACL_READ, $cat_id))
|
||||
{
|
||||
$old_cats_preserve[] = $cat_id;
|
||||
}
|
||||
@ -1699,11 +1906,10 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
|
||||
$cat_id_list = array();
|
||||
foreach($catname_list as $cat_name)
|
||||
foreach ((array)$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
|
||||
@ -1720,7 +1926,7 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
}
|
||||
|
||||
if(is_array($old_cats_preserve) && count($old_cats_preserve) > 0)
|
||||
if (is_array($old_cats_preserve) && count($old_cats_preserve) > 0)
|
||||
{
|
||||
$cat_id_list = array_merge($cat_id_list, $old_cats_preserve);
|
||||
}
|
||||
@ -1731,6 +1937,7 @@ class addressbook_bo extends addressbook_so
|
||||
sort($cat_id_list, SORT_NUMERIC);
|
||||
}
|
||||
|
||||
//error_log(__METHOD__."(".array2string($catname_list).", $contact_id) returning ".array2string($cat_id_list));
|
||||
return $cat_id_list;
|
||||
}
|
||||
|
||||
@ -2003,4 +2210,40 @@ class addressbook_bo extends addressbook_so
|
||||
}
|
||||
return $matchingContacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a ctag (collection tag) for one addressbook or all addressbooks readable by a user
|
||||
*
|
||||
* Currently implemented as maximum modification date (1 seconde granularity!)
|
||||
*
|
||||
* We have to include deleted entries, as otherwise the ctag will not change if an entry gets deleted!
|
||||
* (Only works if tracking of deleted entries / history is switched on!)
|
||||
*
|
||||
* @param int|array $owner=null 0=accounts, null=all addressbooks or integer account_id of user or group
|
||||
* @return string
|
||||
*/
|
||||
public function get_ctag($owner=null)
|
||||
{
|
||||
$filter = array('tid' => null); // tid=null --> use all entries incl. deleted (tid='D')
|
||||
// show addressbook of a single user?
|
||||
if (!is_null($owner)) $filter['owner'] = $owner;
|
||||
|
||||
// should we hide the accounts addressbook
|
||||
if (!$owner && $GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'])
|
||||
{
|
||||
$filter['account_id'] = null;
|
||||
}
|
||||
$result = $this->search(array(),'contact_modified','contact_modified DESC','','',false,'AND',array(0,1),$filter);
|
||||
|
||||
if (!$result || !isset($result[0]['modified']))
|
||||
{
|
||||
$ctag = 'empty'; // ctag for empty addressbook
|
||||
}
|
||||
else
|
||||
{
|
||||
$ctag = $result[0]['modified'];
|
||||
}
|
||||
//error_log(__METHOD__.'('.array2string($owner).') returning '.array2string($ctag));
|
||||
return $ctag;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* @package addressbook
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
@ -16,6 +16,11 @@
|
||||
*
|
||||
* Propfind now uses a groupdav_propfind_iterator with a callback to query huge addressbooks in chunk,
|
||||
* without getting into problems with memory_limit.
|
||||
*
|
||||
* Permanent error_log() calls should use $this->groupdav->log($str) instead, to be send to PHP error_log()
|
||||
* and our request-log (prefixed with "### " after request and response, like exceptions).
|
||||
*
|
||||
* @todo check/fix contacts in LDAP (no carddav_name column!)
|
||||
*/
|
||||
class addressbook_groupdav extends groupdav_handler
|
||||
{
|
||||
@ -31,6 +36,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
//'NICKNAME',
|
||||
'EMAIL' => 'email',
|
||||
'FN' => 'n_fn',
|
||||
'ORG' => 'org_name',
|
||||
);
|
||||
|
||||
/**
|
||||
@ -41,34 +47,54 @@ class addressbook_groupdav extends groupdav_handler
|
||||
var $charset = 'utf-8';
|
||||
|
||||
/**
|
||||
* What attribute is used to construct the path, default id, can be uid too
|
||||
* 'addressbook_home_set' preference already exploded as array
|
||||
*
|
||||
* A = all available addressbooks
|
||||
* G = primary group
|
||||
* D = distribution lists as groups
|
||||
* O = sync all in one (/<username>/addressbook/)
|
||||
* or nummerical account_id, but not user itself
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
const PATH_ATTRIBUTE = 'id';
|
||||
var $home_set_pref;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $app 'calendar', 'addressbook' or 'infolog'
|
||||
* @param int $debug=null debug-level to set
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @param string $principalURL=null pricipal url of handler
|
||||
* @param groupdav $groupdav calling class
|
||||
*/
|
||||
function __construct($app,$debug=null,$base_uri=null,$principalURL=null)
|
||||
function __construct($app, groupdav $groupdav)
|
||||
{
|
||||
parent::__construct($app,$debug,$base_uri,$principalURL);
|
||||
parent::__construct($app, $groupdav);
|
||||
|
||||
$this->bo = new addressbook_bo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the path for a contact
|
||||
*
|
||||
* @param array $contact
|
||||
* @return string
|
||||
*/
|
||||
static function get_path($contact)
|
||||
{
|
||||
return $contact[self::PATH_ATTRIBUTE].'.vcf';
|
||||
// since 1.9.007 we allow clients to specify the URL when creating a new contact, as specified by CardDAV
|
||||
// LDAP does NOT have a carddav_name attribute --> stick with id mapped to LDAP attribute uid
|
||||
if (version_compare($GLOBALS['egw_info']['apps']['phpgwapi']['version'], '1.9.007', '<') ||
|
||||
$this->bo->contact_repository == 'ldap' ||
|
||||
$this->bo->account_repository == 'ldap' && strpos($_SERVER['REQUEST_URI'].'/','/addressbook-accounts/') !== false)
|
||||
{
|
||||
groupdav_handler::$path_extension = '.vcf';
|
||||
}
|
||||
else
|
||||
{
|
||||
groupdav_handler::$path_attr = 'carddav_name';
|
||||
groupdav_handler::$path_extension = '';
|
||||
}
|
||||
if ($this->debug) error_log(__METHOD__."() contact_repository={$this->bo->contact_repository}, account_repository={$this->bo->account_repository}, REQUEST_URI=$_SERVER[REQUEST_URI] --> path_attr=".self::$path_attr.", path_extension=".self::$path_extension);
|
||||
|
||||
$this->home_set_pref = $GLOBALS['egw_info']['user']['preferences']['groupdav']['addressbook-home-set'];
|
||||
$this->home_set_pref = $this->home_set_pref ? explode(',',$this->home_set_pref) : array();
|
||||
|
||||
// silently switch "Sync all into one" preference on for OS X addressbook, as it only supports one AB
|
||||
// this restores behavior before Lion (10.7), where AB synced all ABs contained in addressbook-home-set
|
||||
if (substr(self::get_agent(),0,9) == 'cfnetwork' && !in_array('O',$this->home_set_pref))
|
||||
{
|
||||
$this->home_set_pref[] = 'O';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,16 +110,27 @@ class addressbook_groupdav extends groupdav_handler
|
||||
function propfind($path,$options,&$files,$user,$id='')
|
||||
{
|
||||
$filter = array();
|
||||
// If "Sync selected addressbooks into one" is set
|
||||
if ($user && $user == $GLOBALS['egw_info']['user']['account_id'] && in_array('O',$this->home_set_pref))
|
||||
{
|
||||
$filter['owner'] = array_keys($this->get_shared(true)); // true: ignore all-in-one pref
|
||||
$filter['owner'][] = $user;
|
||||
}
|
||||
// show addressbook of a single user?
|
||||
if ($user && $path != '/addressbook/') $filter['contact_owner'] = $user;
|
||||
elseif ($user && $path != '/addressbook/' || $user === 0)
|
||||
{
|
||||
$filter['owner'] = $user;
|
||||
}
|
||||
// should we hide the accounts addressbook
|
||||
if ($GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) $filter['account_id'] = null;
|
||||
|
||||
// process REPORT filters or multiget href's
|
||||
if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$filter,$id))
|
||||
if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$filter,$id, $nresults))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ($id) $path = dirname($path).'/'; // carddav_name get's added anyway in the callback
|
||||
|
||||
if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user,$id) filter=".array2string($filter));
|
||||
|
||||
// check if we have to return the full contact data or just the etag's
|
||||
@ -109,8 +146,15 @@ class addressbook_groupdav extends groupdav_handler
|
||||
}
|
||||
}
|
||||
}
|
||||
// return iterator, calling ourself to return result in chunks
|
||||
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
|
||||
if (isset($nresults))
|
||||
{
|
||||
$files['files'] = $this->propfind_callback($path, $filter, array(0, (int)$nresults));
|
||||
}
|
||||
else
|
||||
{
|
||||
// return iterator, calling ourself to return result in chunks
|
||||
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -131,32 +175,74 @@ class addressbook_groupdav extends groupdav_handler
|
||||
$handler = self::_get_handler();
|
||||
}
|
||||
unset($filter['address_data']);
|
||||
|
||||
if (isset($filter['order']))
|
||||
{
|
||||
$order = $filter['order'];
|
||||
unset($filter['order']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$order = 'egw_addressbook.contact_id';
|
||||
}
|
||||
$files = array();
|
||||
// we query etag and modified, as LDAP does not have the strong sql etag
|
||||
if (($contacts =& $this->bo->search(array(),array('id','uid','etag','modified'),'contact_id','','',False,'AND',$start,$filter)))
|
||||
$cols = array('id','uid','etag','modified','n_fn');
|
||||
if (!in_array(self::$path_attr,$cols)) $cols[] = self::$path_attr;
|
||||
if (($contacts =& $this->bo->search(array(),$cols,$order,'','',False,'AND',$start,$filter)))
|
||||
{
|
||||
foreach($contacts as &$contact)
|
||||
{
|
||||
$props = array(
|
||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($contact)),
|
||||
HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'),
|
||||
// getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set
|
||||
HTTP_WebDAV_Server::mkprop('getlastmodified', $contact['modified']),
|
||||
'getcontenttype' => HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'),
|
||||
'getlastmodified' => $contact['modified'],
|
||||
'displayname' => $contact['n_fn'],
|
||||
);
|
||||
if ($address_data)
|
||||
{
|
||||
$content = $handler->getVCard($contact['id'],$this->charset,false);
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content));
|
||||
$props['getcontentlength'] = bytes($content);
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
|
||||
}
|
||||
else
|
||||
$files[] = $this->add_resource($path, $contact, $props);
|
||||
}
|
||||
}
|
||||
// add groups after contacts, but only if enabled and NOT for '/addressbook/' (!isset($filter['owner'])
|
||||
if (in_array('D',$this->home_set_pref) && (!$start || count($contacts) < $start[1]) && isset($filter['owner']))
|
||||
{
|
||||
$where = array(
|
||||
'list_owner' => isset($filter['owner'])?$filter['owner']:array_keys($this->bo->grants)
|
||||
);
|
||||
if (isset($filter[self::$path_attr])) // multiget report?
|
||||
{
|
||||
$where['list_'.self::$path_attr] = $filter[self::$path_attr];
|
||||
}
|
||||
//error_log(__METHOD__."() filter=".array2string($filter).", do_groups=".in_array('D',$this->home_set_pref).", where=".array2string($where));
|
||||
if (($lists = $this->bo->read_lists($where,'contact_uid',$where['list_owner']))) // limit to contacts in same AB!
|
||||
{
|
||||
foreach($lists as $list)
|
||||
{
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
|
||||
$list['carddav_name'] = $list['list_carddav_name'];
|
||||
$etag = $list['list_id'].':'.$list['list_etag'];
|
||||
// for all-in-one addressbook, add selected ABs to etag
|
||||
if (isset($filter['owner']) && is_array($filter['owner']))
|
||||
{
|
||||
$etag .= ':'.implode('-',$filter['owner']);
|
||||
}
|
||||
$props = array(
|
||||
'getcontenttype' => HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'),
|
||||
'getlastmodified' => egw_time::to($list['list_modified'],'ts'),
|
||||
'displayname' => $list['list_name'],
|
||||
'getetag' => '"'.$etag.'"',
|
||||
);
|
||||
if ($address_data)
|
||||
{
|
||||
$content = $handler->getGroupVCard($list);
|
||||
$props['getcontentlength'] = bytes($content);
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
|
||||
}
|
||||
$files[] = $this->add_resource($path, $list, $props);
|
||||
}
|
||||
$files[] = array(
|
||||
'path' => $path.self::get_path($contact),
|
||||
'props' => $props,
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($this->debug) error_log(__METHOD__."($path,".array2string($filter).','.array2string($start).") took ".(microtime(true) - $starttime).' to return '.count($files).' items');
|
||||
@ -169,49 +255,138 @@ class addressbook_groupdav extends groupdav_handler
|
||||
* @param array $options
|
||||
* @param array &$cal_filters
|
||||
* @param string $id
|
||||
* @return boolean true if filter could be processed, false for requesting not here supported VTODO items
|
||||
* @param int &$nresult on return limit for number or results or unchanged/null
|
||||
* @return boolean true if filter could be processed
|
||||
*/
|
||||
function _report_filters($options,&$filters,$id)
|
||||
function _report_filters($options,&$filters,$id, &$nresults)
|
||||
{
|
||||
if ($options['filters'])
|
||||
{
|
||||
foreach($options['filters'] as $filter)
|
||||
/* Example of a complex filter used by Mac Addressbook
|
||||
<B:filter test="anyof">
|
||||
<B:prop-filter name="FN" test="allof">
|
||||
<B:text-match collation="i;unicode-casemap" match-type="contains">becker</B:text-match>
|
||||
<B:text-match collation="i;unicode-casemap" match-type="contains">ralf</B:text-match>
|
||||
</B:prop-filter>
|
||||
<B:prop-filter name="EMAIL" test="allof">
|
||||
<B:text-match collation="i;unicode-casemap" match-type="contains">becker</B:text-match>
|
||||
<B:text-match collation="i;unicode-casemap" match-type="contains">ralf</B:text-match>
|
||||
</B:prop-filter>
|
||||
<B:prop-filter name="NICKNAME" test="allof">
|
||||
<B:text-match collation="i;unicode-casemap" match-type="contains">becker</B:text-match>
|
||||
<B:text-match collation="i;unicode-casemap" match-type="contains">ralf</B:text-match>
|
||||
</B:prop-filter>
|
||||
</B:filter>
|
||||
*/
|
||||
$filter_test = isset($options['filters']['attrs']) && isset($options['filters']['attrs']['test']) ?
|
||||
$options['filters']['attrs']['test'] : 'anyof';
|
||||
$prop_filters = array();
|
||||
|
||||
foreach($options['filters'] as $n => $filter)
|
||||
{
|
||||
switch($filter['name'])
|
||||
if (!is_int($n)) continue; // eg. attributes of filter xml element
|
||||
|
||||
switch((string)$filter['name'])
|
||||
{
|
||||
case 'prop-filter':
|
||||
if ($this->debug > 1) error_log(__METHOD__."($path,...) prop-filter='{$filter['attrs']['name']}'");
|
||||
$prop_filter = $filter['attrs']['name'];
|
||||
case 'param-filter':
|
||||
$this->groupdav->log(__METHOD__."(...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!");
|
||||
break;
|
||||
case 'text-match':
|
||||
if ($this->debug > 1) error_log(__METHOD__."($path,...) text-match: $prop_filter='{$filter['data']}'");
|
||||
if (!isset($this->filter_prop2cal[strtoupper($prop_filter)]))
|
||||
case 'prop-filter': // can be multiple prop-filter, see example
|
||||
if ($matches) $prop_filters[] = implode($prop_test=='allof'?' AND ':' OR ',$matches);
|
||||
$matches = array();
|
||||
$prop_filter = strtoupper($filter['attrs']['name']);
|
||||
$prop_test = isset($filter['attrs']['test']) ? $filter['attrs']['test'] : 'anyof';
|
||||
if ($this->debug > 1) error_log(__METHOD__."(...) prop-filter='$prop_filter', test='$prop_test'");
|
||||
break;
|
||||
case 'is-not-defined':
|
||||
$matches[] = '('.$column."='' OR ".$column.' IS NULL)';
|
||||
break;
|
||||
case 'text-match': // prop-filter can have multiple text-match, see example
|
||||
if (!isset($this->filter_prop2cal[$prop_filter])) // eg. not existing NICKNAME in EGroupware
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."($path,".str_replace(array("\n",' '),'',print_r($options,true)).",,$user) unknown property '$prop_filter' --> ignored");
|
||||
if ($this->debug || $prop_filter != 'NICKNAME') error_log(__METHOD__."(...) text-match: $prop_filter {$filter['attrs']['match-type']} '{$filter['data']}' unknown property '$prop_filter' --> ignored");
|
||||
$column = false; // to ignore following data too
|
||||
}
|
||||
else
|
||||
{
|
||||
switch($filter['attrs']['match-type'])
|
||||
switch($filter['attrs']['collation']) // todo: which other collations allowed, we are allways unicode
|
||||
{
|
||||
case 'i;unicode-casemap':
|
||||
default:
|
||||
case 'equals':
|
||||
$filters[$this->filter_prop2cal[strtoupper($prop_filter)]] = $filter['data'];
|
||||
break;
|
||||
case 'substr': // ToDo: check RFC4790
|
||||
$filters[] = $this->filter_prop2cal[strtoupper($prop_filter)].' LIKE '.$GLOBALS['egw']->db->quote($filter['data']);
|
||||
$comp = ' '.$GLOBALS['egw']->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE].' ';
|
||||
break;
|
||||
}
|
||||
$column = $this->filter_prop2cal[strtoupper($prop_filter)];
|
||||
if (strpos($column, '_') === false) $column = 'contact_'.$column;
|
||||
if (!isset($filters['order'])) $filters['order'] = $column;
|
||||
$match_type = $filter['attrs']['match-type'];
|
||||
$negate_condition = isset($filter['attrs']['negate-condition']) && $filter['attrs']['negate-condition'] == 'yes';
|
||||
}
|
||||
unset($prop_filter);
|
||||
break;
|
||||
case 'param-filter':
|
||||
if ($this->debug) error_log(__METHOD__."($path,...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!");
|
||||
break;
|
||||
case '': // data of text-match element
|
||||
if (isset($filter['data']) && isset($column))
|
||||
{
|
||||
if ($column) // false for properties not known to EGroupware
|
||||
{
|
||||
$value = str_replace(array('%', '_'), array('\\%', '\\_'), $filter['data']);
|
||||
switch($match_type)
|
||||
{
|
||||
case 'equals':
|
||||
$sql_filter = $column . $comp . $GLOBALS['egw']->db->quote($value);
|
||||
break;
|
||||
default:
|
||||
case 'contains':
|
||||
$sql_filter = $column . $comp . $GLOBALS['egw']->db->quote('%'.$value.'%');
|
||||
break;
|
||||
case 'starts-with':
|
||||
$sql_filter = $column . $comp . $GLOBALS['egw']->db->quote($value.'%');
|
||||
break;
|
||||
case 'ends-with':
|
||||
$sql_filter = $column . $comp . $GLOBALS['egw']->db->quote('%'.$value);
|
||||
break;
|
||||
}
|
||||
$matches[] = ($negate_condition ? 'NOT ' : '').$sql_filter;
|
||||
|
||||
if ($this->debug > 1) error_log(__METHOD__."(...) text-match: $prop_filter $match_type' '{$filter['data']}'");
|
||||
}
|
||||
unset($column);
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user) unknown filter --> ignored");
|
||||
$this->groupdav->log(__METHOD__."(".array2string($options).",,$id) unknown filter=".array2string($filter).' --> ignored');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($matches) $prop_filters[] = implode($prop_test=='allof'?' AND ':' OR ',$matches);
|
||||
if ($prop_filters)
|
||||
{
|
||||
$filters[] = $filter = '(('.implode($filter_test=='allof'?') AND (':') OR (', $prop_filters).'))';
|
||||
if ($this->debug) error_log(__METHOD__."($path,...) sql-filter: $filter");
|
||||
}
|
||||
}
|
||||
// parse limit from $options['other']
|
||||
/* Example limit
|
||||
<B:limit>
|
||||
<B:nresults>10</B:nresults>
|
||||
</B:limit>
|
||||
*/
|
||||
foreach((array)$options['other'] as $option)
|
||||
{
|
||||
switch($option['name'])
|
||||
{
|
||||
case 'nresults':
|
||||
$nresults = (int)$option['data'];
|
||||
//error_log(__METHOD__."(...) options[other]=".array2string($options['other'])." --> nresults=$nresults");
|
||||
break;
|
||||
case 'limit':
|
||||
break;
|
||||
case 'href':
|
||||
break; // from addressbook-multiget, handled below
|
||||
default:
|
||||
$this->groupdav->log(__METHOD__."(...) unknown xml: options[other]=".array2string($options['other']));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// multiget --> fetch the url's
|
||||
if ($options['root']['name'] == 'addressbook-multiget')
|
||||
@ -222,15 +397,18 @@ class addressbook_groupdav extends groupdav_handler
|
||||
if ($option['name'] == 'href')
|
||||
{
|
||||
$parts = explode('/',$option['data']);
|
||||
if (($id = array_pop($parts))) $ids[] = basename($id,'.vcf');
|
||||
if (($id = array_pop($parts)))
|
||||
{
|
||||
$ids[] = groupdav_handler::$path_extension ? basename($id,groupdav_handler::$path_extension) : $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($ids) $filters[self::PATH_ATTRIBUTE] = $ids;
|
||||
if ($this->debug) error_log(__METHOD__."($path,,,$user) addressbook-multiget: ids=".implode(',',$ids));
|
||||
if ($ids) $filters[self::$path_attr] = $ids;
|
||||
if ($this->debug) error_log(__METHOD__."(...) addressbook-multiget: ids=".implode(',',$ids));
|
||||
}
|
||||
elseif ($id)
|
||||
{
|
||||
$filters[self::PATH_ATTRIBUTE] = basename($id,'.vcf');
|
||||
$filters[self::$path_attr] = groupdav_handler::$path_extension ? basename($id,groupdav_handler::$path_extension) : $id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -250,16 +428,17 @@ class addressbook_groupdav extends groupdav_handler
|
||||
return $contact;
|
||||
}
|
||||
$handler = self::_get_handler();
|
||||
$options['data'] = $handler->getVCard($contact['id'],$this->charset,false);
|
||||
$options['data'] = $contact['list_id'] ? $handler->getGroupVCard($contact) :
|
||||
$handler->getVCard($contact['id'],$this->charset,false);
|
||||
// e.g. Evolution does not understand 'text/vcard'
|
||||
$options['mimetype'] = 'text/x-vcard; charset='.$this->charset;
|
||||
header('Content-Encoding: identity');
|
||||
header('ETag: '.$this->get_etag($contact));
|
||||
header('ETag: "'.$this->get_etag($contact).'"');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle put request for an event
|
||||
* Handle put request for a contact
|
||||
*
|
||||
* @param array &$options
|
||||
* @param int $id
|
||||
@ -274,6 +453,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
$oldContact = $this->_common_get_put_delete('PUT',$options,$id);
|
||||
if (!is_null($oldContact) && !is_array($oldContact))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(,'$id', $user, '$prefix') returning ".array2string($oldContact));
|
||||
return $oldContact;
|
||||
}
|
||||
|
||||
@ -301,39 +481,26 @@ class addressbook_groupdav extends groupdav_handler
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($oldContact))
|
||||
$contact = $handler->vcardtoegw($vCard, $charset);
|
||||
|
||||
if (is_array($oldContact) || ($oldContact = $this->bo->read(array('contact_uid' => $contact['uid']))))
|
||||
{
|
||||
$contactId = $oldContact['id'];
|
||||
$retval = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// new entry?
|
||||
if (($foundContacts = $handler->search($vCard, null, false, $charset)))
|
||||
{
|
||||
if (($contactId = array_shift($foundContacts)) &&
|
||||
($oldContact = $this->bo->read($contactId)))
|
||||
{
|
||||
$retval = '301 Moved Permanently';
|
||||
}
|
||||
else
|
||||
{
|
||||
// to be safe
|
||||
$contactId = -1;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// new entry
|
||||
$contactId = -1;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
// new entry
|
||||
$contactId = -1;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
$is_group = $contact['##X-ADDRESSBOOKSERVER-KIND'] == 'group';
|
||||
if ($oldContact && $is_group !== isset($oldContact['list_id']))
|
||||
{
|
||||
throw new egw_exception_assertion_failed(__METHOD__."(,'$id',$user,'$prefix') can contact into group or visa-versa!");
|
||||
}
|
||||
|
||||
$contact = $handler->vcardtoegw($vCard, $charset);
|
||||
|
||||
if (is_array($contact['cat_id']))
|
||||
if (!$is_group && is_array($contact['cat_id']))
|
||||
{
|
||||
$contact['cat_id'] = implode(',',$this->bo->find_or_add_categories($contact['cat_id'], $contactId));
|
||||
}
|
||||
@ -348,22 +515,41 @@ class addressbook_groupdav extends groupdav_handler
|
||||
$contact['uid'] = $oldContact['uid'];
|
||||
$contact['owner'] = $oldContact['owner'];
|
||||
$contact['private'] = $oldContact['private'];
|
||||
$contact['carddav_name'] = $oldContact['carddav_name'];
|
||||
$contact['tid'] = $oldContact['tid'];
|
||||
$contact['creator'] = $oldContact['creator'];
|
||||
$contact['account_id'] = $oldContact['account_id'];
|
||||
}
|
||||
// only set owner, if user is explicitly specified in URL (check via prefix, NOT for /addressbook/ !)
|
||||
if ($prefix)
|
||||
else
|
||||
{
|
||||
// check for modified owners, if user has an add right for the new addressbook and
|
||||
// delete rights for the old addressbook (_common_get_put_delete checks for PUT only EGW_ACL_EDIT)
|
||||
if ($oldContact && $user != $oldContact['owner'] && !($this->bo->grants[$user] & EGW_ACL_ADD) &&
|
||||
(!$this->bo->grants[$oldContact['owner']] & EGW_ACL_DELETE))
|
||||
$contact['carddav_name'] = $id;
|
||||
|
||||
// only set owner, if user is explicitly specified in URL (check via prefix, NOT for /addressbook/) or sync-all-in-one!)
|
||||
if ($prefix && !in_array('O',$this->home_set_pref))
|
||||
{
|
||||
$contact['owner'] = $user;
|
||||
}
|
||||
// check if default addressbook is synced, if not use (always synced) personal addressbook
|
||||
elseif($this->bo->default_addressbook && !in_array($this->bo->default_addressbook,$this->home_set_pref))
|
||||
{
|
||||
$contact['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$contact['owner'] = $this->bo->default_addressbook;
|
||||
$contact['private'] = $this->bo->default_private;
|
||||
}
|
||||
// check if user has add rights for addressbook
|
||||
// done here again, as _common_get_put_delete knows nothing about default addressbooks...
|
||||
if (!($this->bo->grants[$contact['owner']] & EGW_ACL_ADD))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(,'$id', $user, '$prefix') returning '403 Forbidden'");
|
||||
return '403 Forbidden';
|
||||
}
|
||||
$contact['owner'] = $user;
|
||||
}
|
||||
if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match);
|
||||
|
||||
if (!($save_ok = $this->bo->save($contact)))
|
||||
if (!($save_ok = $is_group ? $this->save_group($contact, $oldContact) : $this->bo->save($contact)))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(,$id) save(".array2string($contact).") failed, Ok=$save_ok");
|
||||
if ($save_ok === 0)
|
||||
@ -375,73 +561,112 @@ class addressbook_groupdav extends groupdav_handler
|
||||
|
||||
if (!isset($contact['etag']))
|
||||
{
|
||||
$contact = $this->read($save_ok);
|
||||
$contact = $this->read($save_ok,$options['path']);
|
||||
}
|
||||
|
||||
header('ETag: '.$this->get_etag($contact));
|
||||
if ($retval !== true)
|
||||
// send evtl. necessary respose headers: Location, etag, ...
|
||||
// epl-11.1 needs && !$is_group, as we dont store carddav_name for lists!
|
||||
$this->put_response_headers($contact, $options['path'], $retval, self::$path_attr != 'id' && !$is_group);
|
||||
|
||||
if ($this->debug > 1) error_log(__METHOD__."(,'$id', $user, '$prefix') returning ".array2string($retval));
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save distribition-list / group
|
||||
*
|
||||
* @param array $contact
|
||||
* @param array|false $oldContact
|
||||
* @param int|boolean $list_id or false on error
|
||||
*/
|
||||
function save_group(array &$contact, $oldContact=null)
|
||||
{
|
||||
$data = array('list_name' => $contact['n_fn']);
|
||||
if (!isset($contact['owner'])) $contact['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
||||
foreach(array('id','carddav_name','uid','owner') as $name)
|
||||
{
|
||||
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
|
||||
header($h='Location: '.$this->base_uri.$path.self::get_path($contact));
|
||||
if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): $retval");
|
||||
return $retval;
|
||||
if ($name != self::$path_attr) $data['list_'.$name] = $contact[$name];
|
||||
}
|
||||
return true;
|
||||
//error_log(__METHOD__.'('.array2string($contact).', '.array2string($oldContact).') data='.array2string($data));
|
||||
if (($list_id=$this->bo->add_list(array('list_'.self::$path_attr => $contact[self::$path_attr]),
|
||||
$contact['owner'], null, $data)))
|
||||
{
|
||||
// update members given in $contact['##X-ADDRESSBOOKSERVER-MEMBER']
|
||||
$new_members = $contact['##X-ADDRESSBOOKSERVER-MEMBER'];
|
||||
if ($new_members[1] == ':' && ($n = unserialize($new_members)))
|
||||
{
|
||||
$new_members = $n['values'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$new_members = array($new_members);
|
||||
}
|
||||
foreach($new_members as &$uid) $uid = substr($uid,9); // cut off "urn:uuid:" prefix
|
||||
|
||||
if ($oldContact)
|
||||
{
|
||||
$to_add = array_diff($new_members,$oldContact['members']);
|
||||
$to_delete = array_diff($oldContact['members'],$new_members);
|
||||
}
|
||||
else
|
||||
{
|
||||
$to_add = $new_members;
|
||||
}
|
||||
//error_log('to_add='.array2string($to_add).', to_delete='.array2string($to_delete));
|
||||
if ($to_add || $to_delete)
|
||||
{
|
||||
$to_add_ids = $to_delete_ids = array();
|
||||
$filter = array('uid' => $to_delete ? array_merge($to_add, $to_delete) : $to_add);
|
||||
if (($contacts =& $this->bo->search(array(),'id,uid','','','',False,'AND',false,$filter)))
|
||||
{
|
||||
foreach($contacts as $c)
|
||||
{
|
||||
if ($to_delete && in_array($c['uid'], $to_delete))
|
||||
{
|
||||
$to_delete_ids[] = $c['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$to_add_ids[] = $c['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
//error_log('to_add_ids='.array2string($to_add_ids).', to_delete_ids='.array2string($to_delete_ids));
|
||||
if ($to_add_ids) $this->bo->add2list($to_add_ids, $list_id, array());
|
||||
if ($to_delete_ids) $this->bo->remove_from_list($to_delete_ids, $list_id);
|
||||
}
|
||||
$list_id = $data['list_carddav_name'];
|
||||
}
|
||||
if ($this->debug > 1) error_log(__METHOD__.'('.array2string($contact).', '.array2string($oldContact).') on return contact='.array2string($data).' returning '.array2string($list_id));
|
||||
$contact = $data;
|
||||
return $list_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query ctag for addressbook
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $user
|
||||
* @return string
|
||||
*/
|
||||
public function getctag($path,$user)
|
||||
{
|
||||
$filter = array();
|
||||
// show addressbook of a single user?
|
||||
if ($user && $path != '/addressbook/') $filter['contact_owner'] = $user;
|
||||
// should we hide the accounts addressbook
|
||||
if ($GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) $filter['account_id'] = null;
|
||||
// not showing addressbook of a single user?
|
||||
if (is_null($user) || $user === '' || $path == '/addressbook/') $user = null;
|
||||
|
||||
$result = $this->bo->search(array(),'MAX(contact_modified) AS contact_modified','','','',false,'AND',false,$filter);
|
||||
|
||||
if (empty($result))
|
||||
// If "Sync selected addressbooks into one" is set --> ctag need to take selected AB's into account too
|
||||
if ($user && $user == $GLOBALS['egw_info']['user']['account_id'] && in_array('O',$this->home_set_pref))
|
||||
{
|
||||
$ctag = 0;
|
||||
$user = array_merge((array)$user,array_keys($this->get_shared(true))); // true: ignore all-in-one pref
|
||||
}
|
||||
else
|
||||
$ctag = $this->bo->get_ctag($user);
|
||||
// include lists-ctag, if enabled and NOT in /addressbook/ (we dont sync distribution-lists/groups there)
|
||||
if (in_array('D',$this->home_set_pref) && $path != '/addressbook/')
|
||||
{
|
||||
$ctag = $result[0]['modified'];
|
||||
$lists_ctag = $this->bo->lists_ctag($user);
|
||||
}
|
||||
return 'EGw-'.$ctag.'-wGE';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the privileges of the current user
|
||||
*
|
||||
* @param array $props=array() regular props by the groupdav handler
|
||||
* @return array
|
||||
*/
|
||||
static function current_user_privilege_set(array $props=array())
|
||||
{
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::DAV,'current-user-privilege-set',
|
||||
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'privilege',
|
||||
array(
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'read-free-busy',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read-current-user-privilege-set',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'bind',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'unbind',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver-vevent',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-properties',''),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-content',''),
|
||||
))));
|
||||
return $props;
|
||||
//error_log(__METHOD__."('$path', ".array2string($user).") ctag=$ctag=".date('Y-m-d H:i:s',$ctag).", lists_ctag=".($lists_ctag ? $lists_ctag.'='.date('Y-m-d H:i:s',$lists_ctag) : '').' returning '.max($ctag,$lists_ctag));
|
||||
return max($ctag,$lists_ctag);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -465,16 +690,21 @@ class addressbook_groupdav extends groupdav_handler
|
||||
* @param array $props=array() regular props by the groupdav handler
|
||||
* @param string $displayname
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @param int $user=null account_id of owner of collection
|
||||
* @return array
|
||||
*/
|
||||
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
|
||||
public function extra_properties(array $props=array(), $displayname, $base_uri=null, $user=null)
|
||||
{
|
||||
// addressbook description
|
||||
$displayname = translation::convert(lang('Addressbook of') . ' ' .
|
||||
$displayname,translation::charset(),'utf-8');
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-description',$displayname);
|
||||
if (!isset($props['addressbook-description']))
|
||||
{
|
||||
// default addressbook description: can be overwritten via PROPPATCH, in which case it's already set
|
||||
$props['addressbook-description'] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-description',$props['displayname']);
|
||||
}
|
||||
// setting an max image size, so iOS scales the images before transmitting them
|
||||
$props['max-image-size'] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'max-image-size',4096);
|
||||
|
||||
// supported reports (required property for CardDAV)
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
|
||||
$props['supported-report-set'] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('supported-report',array(
|
||||
HTTP_WebDAV_Server::mkprop('report',array(
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-query',''))))),
|
||||
@ -482,7 +712,6 @@ class addressbook_groupdav extends groupdav_handler
|
||||
HTTP_WebDAV_Server::mkprop('report',array(
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-multiget',''))))),
|
||||
));
|
||||
//$props = self::current_user_privilege_set($props);
|
||||
return $props;
|
||||
}
|
||||
|
||||
@ -495,12 +724,9 @@ class addressbook_groupdav extends groupdav_handler
|
||||
{
|
||||
$handler = new addressbook_vcal('addressbook','text/vcard');
|
||||
// Apple iOS or OS X addressbook
|
||||
if ($this->agent = 'cfnetwork' || $this->agent == 'dataaccess')
|
||||
if ($this->agent == 'cfnetwork' || $this->agent == 'dataaccess')
|
||||
{
|
||||
$supportedFields = $handler->supportedFields;
|
||||
// Apple Addressbook don't support CLASS
|
||||
unset($supportedFields['CLASS']);
|
||||
unset($supportedFields['CATEGORIES']);
|
||||
// use just CELL and IPHONE, CELL;WORK and CELL;HOME are NOT understood
|
||||
//'TEL;CELL;WORK' => array('tel_cell'),
|
||||
//'TEL;CELL;HOME' => array('tel_cell_private'),
|
||||
@ -508,6 +734,19 @@ class addressbook_groupdav extends groupdav_handler
|
||||
unset($supportedFields['TEL;CELL;WORK']);
|
||||
$supportedFields['TEL;IPHONE'] = array('tel_cell_private');
|
||||
unset($supportedFields['TEL;CELL;HOME']);
|
||||
$supportedFields['X-ABSHOWAS'] = array('fileas_type'); // Horde vCard class uses uppercase prop-names!
|
||||
// Apple Addressbook pre Lion (OS X 10.7) messes up CLASS and CATEGORIES (Lion cant set them but leaves them alone)
|
||||
if (preg_match('|CFNetwork/([0-9]+)|i', $_SERVER['HTTP_USER_AGENT'],$matches) && $matches[1] < 520)
|
||||
{
|
||||
unset($supportedFields['CLASS']);
|
||||
unset($supportedFields['CATEGORIES']);
|
||||
// gd cant parse or resize images stored from snow leopard addressbook: gd-jpeg:
|
||||
// - JPEG library reports unrecoverable error
|
||||
// - Passed data is not in 'JPEG' format
|
||||
// - Couldn't create GD Image Stream out of Data
|
||||
// FF (10), Safari (5.1.3) and Chrome (17) cant display it either --> ignore images
|
||||
unset($supportedFields['PHOTO']);
|
||||
}
|
||||
}
|
||||
$handler->setSupportedFields('GroupDAV',$this->agent, isset($supportedFields) ?
|
||||
$supportedFields : $handler->supportedFields);
|
||||
@ -528,33 +767,176 @@ class addressbook_groupdav extends groupdav_handler
|
||||
{
|
||||
return $contact;
|
||||
}
|
||||
if (($Ok = $this->bo->delete($contact['id'],self::etag2value($this->http_if_match))) === 0)
|
||||
if (($Ok = isset($contact['list_id']) ? $this->bo->delete_list($contact['list_id']) !== false :
|
||||
$this->bo->delete($contact['id'],self::etag2value($this->http_if_match))) === 0)
|
||||
{
|
||||
return '412 Precondition Failed';
|
||||
}
|
||||
//return $ok;
|
||||
return $Ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a contact
|
||||
*
|
||||
* @param string/id $id
|
||||
* @return array/boolean array with entry, false if no read rights, null if $id does not exist
|
||||
* We have to make sure to not return or even consider in read deleted contacts, as the might have
|
||||
* the same UID and/or carddav_name as not deleted contacts and would block access to valid entries
|
||||
*
|
||||
* @param string|int $id
|
||||
* @param string $path=null
|
||||
* @return array|boolean array with entry, false if no read rights, null if $id does not exist
|
||||
*/
|
||||
function read($id)
|
||||
function read($id, $path=null)
|
||||
{
|
||||
return $this->bo->read(self::PATH_ATTRIBUTE == 'id' ? $id : array(self::PATH_ATTRIBUTE => $id));
|
||||
static $non_deleted_tids;
|
||||
if (is_null($non_deleted_tids))
|
||||
{
|
||||
$non_deleted_tids = $this->bo->content_types;
|
||||
unset($non_deleted_tids[addressbook_so::DELETED_TYPE]);
|
||||
$non_deleted_tids = array_keys($non_deleted_tids);
|
||||
}
|
||||
$contact = $this->bo->read(array(self::$path_attr => $id, 'tid' => $non_deleted_tids));
|
||||
|
||||
// see if we have a distribution-list / group with that id
|
||||
// bo->read_list(..., true) limits returned uid to same owner's addressbook, as iOS and OS X addressbooks
|
||||
// only understands/shows that and if return more, save_lists would delete the others ones on update!
|
||||
$limit_in_ab = true;
|
||||
list(,$account_lid,$app) = explode('/',$path); // eg. /<username>/addressbook/<id>
|
||||
// /<username>/addressbook/ with home_set_prefs containing 'O'=all-in-one contains selected ab's
|
||||
if($account_lid == $GLOBALS['egw_info']['user']['account_lid'] && $app == 'addressbook' && in_array('O',$this->home_set_pref))
|
||||
{
|
||||
$limit_in_ab = array_keys($this->get_shared(true));
|
||||
$limit_in_ab[] = $GLOBALS['egw_info']['user']['account_id'];
|
||||
}
|
||||
/* we are currently not syncing distribution-lists/groups to /addressbook/ as
|
||||
* Apple clients use that only as directory gateway
|
||||
elseif ($account_lid == 'addressbook') // /addressbook/ contains all readably contacts
|
||||
{
|
||||
$limit_in_ab = array_keys($this->bo->grants);
|
||||
}*/
|
||||
if (!$contact && ($contact = $this->bo->read_lists(array('list_'.self::$path_attr => $id),'contact_uid',$limit_in_ab)))
|
||||
{
|
||||
$contact = array_shift($contact);
|
||||
$contact['n_fn'] = $contact['n_family'] = $contact['list_name'];
|
||||
foreach(array('owner','id','carddav_name','modified','modifier','created','creator','etag','uid') as $name)
|
||||
{
|
||||
$contact[$name] = $contact['list_'.$name];
|
||||
}
|
||||
// if NOT limited to containing AB ($limit_in_ab === true), add that limit to etag
|
||||
if ($limit_in_ab !== true)
|
||||
{
|
||||
$contact['etag'] .= ':'.implode('-',$limit_in_ab);
|
||||
}
|
||||
}
|
||||
elseif($contact === array()) // not found from read_lists()
|
||||
{
|
||||
$contact = null;
|
||||
}
|
||||
|
||||
if ($contact && $contact['tid'] == addressbook_so::DELETED_TYPE)
|
||||
{
|
||||
$contact = null; // handle deleted events, as not existing (404 Not Found)
|
||||
}
|
||||
if ($this->debug > 1) error_log(__METHOD__."('$id') returning ".array2string($contact));
|
||||
return $contact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has the neccessary rights on a contact
|
||||
*
|
||||
* @param int $acl EGW_ACL_READ, EGW_ACL_EDIT or EGW_ACL_DELETE
|
||||
* @param array/int $contact contact-array or id
|
||||
* @param array|int $contact contact-array or id
|
||||
* @return boolean null if entry does not exist, false if no access, true if access permitted
|
||||
*/
|
||||
function check_access($acl,$contact)
|
||||
{
|
||||
return $this->bo->check_perms($acl,$contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return calendars/addressbooks shared from other users with the current one
|
||||
*
|
||||
* @param boolean $ignore_all_in_one=false if true, return selected addressbooks and not array() for all-in-one
|
||||
* @return array account_id => account_lid pairs
|
||||
*/
|
||||
function get_shared($ignore_all_in_one=false)
|
||||
{
|
||||
$shared = array();
|
||||
|
||||
// if "Sync all selected addressbook into one" is set --> no (additional) shared addressbooks
|
||||
if (!$ignore_all_in_one && in_array('O',$this->home_set_pref)) return array();
|
||||
|
||||
// replace symbolic id's with real nummeric id's
|
||||
foreach(array(
|
||||
'G' => $GLOBALS['egw_info']['user']['account_primary_group'],
|
||||
'U' => '0',
|
||||
) as $sym => $id)
|
||||
{
|
||||
if (($key = array_search($sym, $this->home_set_pref)) !== false)
|
||||
{
|
||||
$this->home_set_pref[$key] = $id;
|
||||
}
|
||||
}
|
||||
foreach($this->bo->get_addressbooks(EGW_ACL_READ) as $id => $label)
|
||||
{
|
||||
if (($id || !$GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts']) &&
|
||||
$GLOBALS['egw_info']['user']['account_id'] != $id && // no current user and no accounts, if disabled in ab prefs
|
||||
(in_array('A',$this->home_set_pref) || in_array((string)$id,$this->home_set_pref)) &&
|
||||
is_numeric($id) && ($owner = $id ? $this->accounts->id2name($id) : 'accounts'))
|
||||
{
|
||||
$shared[$id] = $owner;
|
||||
}
|
||||
}
|
||||
return $shared;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return appliction specific settings
|
||||
*
|
||||
* @param array $hook_data
|
||||
* @return array of array with settings
|
||||
*/
|
||||
static function get_settings($hook_data)
|
||||
{
|
||||
$addressbooks = array();
|
||||
if (!isset($hook_data['setup']))
|
||||
{
|
||||
$user = $GLOBALS['egw_info']['user']['account_id'];
|
||||
$addressbook_bo = new addressbook_bo();
|
||||
$addressbooks = $addressbook_bo->get_addressbooks(EGW_ACL_READ);
|
||||
unset($addressbooks[$user]); // allways synced
|
||||
unset($addressbooks[$user.'p']);// ignore (optional) private addressbook for now
|
||||
}
|
||||
$addressbooks = array(
|
||||
'A' => lang('All'),
|
||||
'G' => lang('Primary Group'),
|
||||
'U' => lang('Accounts'),
|
||||
'O' => lang('Sync all selected into one'),
|
||||
'D' => lang('Distribution lists as groups')
|
||||
) + $addressbooks;
|
||||
|
||||
// rewriting owner=0 to 'U', as 0 get's always selected by prefs
|
||||
if (!isset($addressbooks[0]))
|
||||
{
|
||||
unset($addressbooks['U']);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($addressbooks[0]);
|
||||
}
|
||||
|
||||
$settings = array();
|
||||
$settings['addressbook-home-set'] = array(
|
||||
'type' => 'multiselect',
|
||||
'label' => 'Addressbooks to sync in addition to personal addressbook',
|
||||
'name' => 'addressbook-home-set',
|
||||
'help' => lang('Only supported by a few fully conformant clients (eg. from Apple). If you have to enter a URL, it will most likly not be suppored!').
|
||||
'<br/>'.lang('They will be sub-folders in users home (%1 attribute).','CardDAV "addressbook-home-set"').
|
||||
'<br/>'.lang('Select "%1", if your client does not support multiple addressbooks.',lang('Sync all selected into one')).
|
||||
'<br/>'.lang('Select "%1", if your client support groups, eg. OS X or iOS addressbook.',lang('Distribution lists as groups')),
|
||||
'values' => $addressbooks,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
);
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ class addressbook_ldap
|
||||
'n_fileas' => 'displayname',
|
||||
'label' => 'postaladdress',
|
||||
'pubkey' => 'usersmimecertificate',
|
||||
'uid' => 'entryuuid',
|
||||
),
|
||||
|
||||
#displayName
|
||||
@ -123,19 +124,21 @@ class addressbook_ldap
|
||||
'mozillaabpersonalpha' => array(
|
||||
'adr_one_street2' => 'mozillaworkstreet2',
|
||||
'adr_one_countryname' => 'c', // 2 letter country code
|
||||
'adr_one_countrycode' => 'c', // 2 letter country code
|
||||
'adr_two_street' => 'mozillahomestreet',
|
||||
'adr_two_street2' => 'mozillahomestreet2',
|
||||
'adr_two_locality' => 'mozillahomelocalityname',
|
||||
'adr_two_region' => 'mozillahomestate',
|
||||
'adr_two_postalcode' => 'mozillahomepostalcode',
|
||||
'adr_two_countryname' => 'mozillahomecountryname',
|
||||
'adr_two_countrycode' => 'mozillahomecountryname',
|
||||
'email_home' => 'mozillasecondemail',
|
||||
'url_home' => 'mozillahomeurl',
|
||||
),
|
||||
// similar to the newer mozillaAbPerson, but uses mozillaPostalAddress2 instead of mozillaStreet2
|
||||
'mozillaorgperson' => array(
|
||||
'adr_one_street2' => 'mozillapostaladdress2',
|
||||
'adr_one_countryname' => 'c', // 2 letter country code
|
||||
'adr_one_countrycode' => 'c', // 2 letter country code
|
||||
'adr_one_countryname' => 'co', // human readable country name, must be after 'c' to take precedence on read!
|
||||
'adr_two_street' => 'mozillahomestreet',
|
||||
'adr_two_street2' => 'mozillahomepostaladdress2',
|
||||
@ -284,7 +287,8 @@ class addressbook_ldap
|
||||
*/
|
||||
function read($contact_id)
|
||||
{
|
||||
if (is_array($contact_id) && isset($contact_id['account_id']) || substr($contact_id,0,8) == 'account:')
|
||||
if (is_array($contact_id) && isset($contact_id['account_id']) ||
|
||||
!is_array($contact_id) && substr($contact_id,0,8) == 'account:')
|
||||
{
|
||||
$filter = 'uidNumber='.(int)(is_array($contact_id) ? $contact_id['account_id'] : substr($contact_id,8));
|
||||
}
|
||||
@ -434,6 +438,7 @@ class addressbook_ldap
|
||||
$needRecreation = false;
|
||||
// never allow to change the uidNumber (account_id) on update, as it could be misused by eg. xmlrpc or syncml
|
||||
unset($ldapContact['uidnumber']);
|
||||
unset($ldapContact['entryuuid']); // not allowed to modify that, no need either
|
||||
|
||||
// add missing objectclasses
|
||||
if($ldapContact['objectClass'] && array_diff($ldapContact['objectClass'],$oldObjectclasses))
|
||||
@ -663,6 +668,7 @@ class addressbook_ldap
|
||||
$sort = 'ASC';
|
||||
foreach(explode(',',$order_by) as $o)
|
||||
{
|
||||
if (substr($o,0,8) == 'contact_') $o = substr($o,8);
|
||||
if (substr($o,-4) == ' ASC')
|
||||
{
|
||||
$sort = 'ASC';
|
||||
@ -1113,9 +1119,17 @@ class addressbook_ldap
|
||||
*/
|
||||
function _egw2mozillaabpersonalpha(&$ldapContact,$data,$isUpdate)
|
||||
{
|
||||
if ($data['adr_one_countryname'])
|
||||
if ($data['adr_one_countrycode'])
|
||||
{
|
||||
$ldapContact['c'] = $data['adr_one_countrycode'];
|
||||
}
|
||||
elseif ($data['adr_one_countryname'])
|
||||
{
|
||||
$ldapContact['c'] = ExecMethod('phpgwapi.country.country_code',$data['adr_one_countryname']);
|
||||
if ($ldapContact['c'] && strlen($ldapContact['c']) > 2) // Bad countryname when "custom" selected!
|
||||
{
|
||||
$ldapContact['c'] = array(); // should return error...
|
||||
}
|
||||
}
|
||||
elseif ($isUpdate)
|
||||
{
|
||||
@ -1134,10 +1148,7 @@ class addressbook_ldap
|
||||
*/
|
||||
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]);
|
||||
}
|
||||
// no special handling necessary, as it supports two distinct attributes: c, cn
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1152,14 +1163,24 @@ class addressbook_ldap
|
||||
*/
|
||||
function _egw2mozillaorgperson(&$ldapContact,$data,$isUpdate)
|
||||
{
|
||||
if ($data['adr_one_countryname'])
|
||||
if ($data['adr_one_countrycode'])
|
||||
{
|
||||
$ldapContact['c'] = $data['adr_one_countrycode'];
|
||||
if ($isUpdate) $ldapContact['co'] = array();
|
||||
}
|
||||
elseif ($data['adr_one_countryname'])
|
||||
{
|
||||
$ldapContact['c'] = ExecMethod('phpgwapi.country.country_code',$data['adr_one_countryname']);
|
||||
if ($ldapContact['c'] && strlen($ldapContact['c']) > 2) // Bad countryname when "custom" selected!
|
||||
{
|
||||
$ldapContact['c'] = array(); // should return error...
|
||||
}
|
||||
}
|
||||
elseif ($isUpdate)
|
||||
{
|
||||
$ldapContact['c'] = array();
|
||||
$ldapContact['c'] = $ldapContact['co'] = array();
|
||||
}
|
||||
//error_log(__METHOD__."() adr_one_countrycode='{$data['adr_one_countrycode']}', adr_one_countryname='{$data['adr_one_countryname']}' --> c=".array2string($ldapContact['c']).', co='.array2string($ldapContact['co']));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,7 +6,7 @@
|
||||
* @author Cornelius Weiss <egw-AT-von-und-zu-weiss.de>
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package addressbook
|
||||
* @copyright (c) 2005-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
@ -128,7 +128,7 @@ class addressbook_so
|
||||
* In SQL we can search all columns, though a view make on real sense
|
||||
*/
|
||||
var $sql_cols_not_to_search = array(
|
||||
'jpegphoto','owner','tid','private','id','cat_id','etag',
|
||||
'jpegphoto','owner','tid','private','cat_id','etag',
|
||||
'modified','modifier','creator','created','tz','account_id',
|
||||
'uid',
|
||||
);
|
||||
@ -164,6 +164,13 @@ class addressbook_so
|
||||
*/
|
||||
var $content_types = array();
|
||||
|
||||
/**
|
||||
* Special content type to indicate a deleted addressbook
|
||||
*
|
||||
* @var String;
|
||||
*/
|
||||
const DELETED_TYPE = 'D';
|
||||
|
||||
/**
|
||||
* total number of matches of last search
|
||||
*
|
||||
@ -172,9 +179,9 @@ class addressbook_so
|
||||
var $total;
|
||||
|
||||
/**
|
||||
* storage object: sql (socontacts_sql) or ldap (so_ldap) backend class
|
||||
* storage object: sql (addressbook_sql) or ldap (addressbook_ldap) backend class
|
||||
*
|
||||
* @var socontacts_sql
|
||||
* @var addressbook_sql
|
||||
*/
|
||||
var $somain;
|
||||
/**
|
||||
@ -192,15 +199,21 @@ class addressbook_so
|
||||
/**
|
||||
* custom fields backend
|
||||
*
|
||||
* @var so_sql
|
||||
* @var addressbook_sql
|
||||
*/
|
||||
var $soextra;
|
||||
var $sodistrib_list;
|
||||
var $backend;
|
||||
|
||||
function __construct($contact_app='addressbook')
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $contact_app='addressbook' used for acl->get_grants()
|
||||
* @param egw_db $db=null
|
||||
*/
|
||||
function __construct($contact_app='addressbook',egw_db $db=null)
|
||||
{
|
||||
$this->db = $GLOBALS['egw']->db;
|
||||
$this->db = is_null($db) ? $GLOBALS['egw']->db : $db;
|
||||
|
||||
$this->user = $GLOBALS['egw_info']['user']['account_id'];
|
||||
$this->memberships = $GLOBALS['egw']->accounts->memberships($this->user,true);
|
||||
@ -220,15 +233,6 @@ class addressbook_so
|
||||
$this->contact_repository = 'ldap';
|
||||
$this->somain = new addressbook_ldap();
|
||||
|
||||
if ($this->user) // not set eg. in setup
|
||||
{
|
||||
// static grants from ldap: all rights for the own personal addressbook and the group ones of the meberships
|
||||
$this->grants = array($this->user => ~0);
|
||||
foreach($this->memberships as $gid)
|
||||
{
|
||||
$this->grants[$gid] = ~0;
|
||||
}
|
||||
}
|
||||
$this->columns_to_search = $this->ldap_search_attributes;
|
||||
}
|
||||
else // sql or sql->ldap
|
||||
@ -237,17 +241,15 @@ class addressbook_so
|
||||
{
|
||||
$this->contact_repository = 'sql-ldap';
|
||||
}
|
||||
$this->somain = new addressbook_sql();
|
||||
$this->somain = new addressbook_sql($db);
|
||||
|
||||
if ($this->user) // not set eg. in setup
|
||||
{
|
||||
// group grants are now grants for the group addressbook and NOT grants for all its members,
|
||||
// therefor the param false!
|
||||
$this->grants = $GLOBALS['egw']->acl->get_grants($contact_app,false);
|
||||
}
|
||||
// remove some columns, absolutly not necessary to search in sql
|
||||
$this->columns_to_search = array_diff(array_values($this->somain->db_cols),$this->sql_cols_not_to_search);
|
||||
}
|
||||
if ($this->user)
|
||||
{
|
||||
$this->grants = $this->get_grants($this->user,$contact_app);
|
||||
}
|
||||
if ($this->account_repository == 'ldap' && $this->contact_repository == 'sql')
|
||||
{
|
||||
if ($this->account_repository != $this->contact_repository)
|
||||
@ -290,7 +292,14 @@ class addressbook_so
|
||||
// ToDo: it should be the other way arround, the backend should set the grants it uses
|
||||
$this->somain->grants =& $this->grants;
|
||||
|
||||
$this->soextra = new so_sql('phpgwapi',$this->extra_table);
|
||||
if($this->somain instanceof addressbook_sql)
|
||||
{
|
||||
$this->soextra =& $this->somain;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->soextra = new addressbook_sql($db);
|
||||
}
|
||||
|
||||
$this->customfields = config::get_customfields('addressbook');
|
||||
$this->content_types = config::get_content_types('addressbook');
|
||||
@ -303,6 +312,54 @@ class addressbook_so
|
||||
'icon' => 'navbar.png'
|
||||
)));
|
||||
}
|
||||
|
||||
// Add in deleted type, if holding deleted contacts
|
||||
$config = config::read('phpgwapi');
|
||||
if($config['history'])
|
||||
{
|
||||
$this->content_types[self::DELETED_TYPE] = array(
|
||||
'name' => lang('Deleted'),
|
||||
'options' => array(
|
||||
'template' => 'addressbook.edit',
|
||||
'icon' => 'deleted.png'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get grants for a given user, taking into account static LDAP ACL
|
||||
*
|
||||
* @param int $user
|
||||
* @param string $contact_app='addressbook'
|
||||
* @return array
|
||||
*/
|
||||
function get_grants($user,$contact_app='addressbook')
|
||||
{
|
||||
if ($user)
|
||||
{
|
||||
// contacts backend (contacts in LDAP require accounts in LDAP!)
|
||||
if($GLOBALS['egw_info']['server']['contact_repository'] == 'ldap' && $this->account_repository == 'ldap')
|
||||
{
|
||||
// static grants from ldap: all rights for the own personal addressbook and the group ones of the meberships
|
||||
$grants = array($user => ~0);
|
||||
foreach($GLOBALS['egw']->accounts->memberships($user,true) as $gid)
|
||||
{
|
||||
$grants[$gid] = ~0;
|
||||
}
|
||||
}
|
||||
else // sql or sql->ldap
|
||||
{
|
||||
// group grants are now grants for the group addressbook and NOT grants for all its members,
|
||||
// therefor the param false!
|
||||
$grants = $GLOBALS['egw']->acl->get_grants($contact_app,false,$user);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$grants = array();
|
||||
}
|
||||
return $grants;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -321,42 +378,19 @@ class addressbook_so
|
||||
/**
|
||||
* Read all customfields of the given id's
|
||||
*
|
||||
* @param int/array $ids
|
||||
* @param int|array $ids
|
||||
* @param array $field_names=null custom fields to read, default all
|
||||
* @return array id => name => value
|
||||
*/
|
||||
function read_customfields($ids,$field_names=null)
|
||||
{
|
||||
if ($this->contact_repository == 'ldap')
|
||||
{
|
||||
return array(); // ldap does not support custom-fields (non-nummeric uid)
|
||||
}
|
||||
if (is_null($field_names)) $field_names = array_keys($this->customfields);
|
||||
|
||||
if(!is_array($ids) && is_numeric($ids)) {
|
||||
$ids = array((int)$ids);
|
||||
}
|
||||
foreach($ids as $key => $id)
|
||||
{
|
||||
if (!(int)$id) unset($ids[$key]);
|
||||
}
|
||||
if (!$ids || !$field_names) return array(); // nothing to do, eg. all these contacts are in ldap
|
||||
|
||||
$fields = array();
|
||||
foreach((array)$this->soextra->search(array(
|
||||
$this->extra_id => $ids,
|
||||
$this->extra_key => $field_names,
|
||||
),false) as $data)
|
||||
{
|
||||
if ($data) $fields[$data[$this->extra_id]][$data[$this->extra_key]] = $data[$this->extra_value];
|
||||
}
|
||||
return $fields;
|
||||
return $this->soextra->read_customfields($ids,$field_names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all distributionlists of the given id's
|
||||
*
|
||||
* @param int/array $ids
|
||||
* @param int|array $ids
|
||||
* @return array id => name => value
|
||||
*/
|
||||
function read_distributionlist($ids, $dl_allowed=array())
|
||||
@ -430,7 +464,10 @@ class addressbook_so
|
||||
if ($this->somain->delete($where))
|
||||
{
|
||||
// delete customfields, can return 0 if there are no customfields
|
||||
$this->soextra->delete(array($this->extra_id => $contact));
|
||||
if(!($this->somain instanceof addressbook_sql))
|
||||
{
|
||||
$this->soextra->delete_customfields(array($this->extra_id => $contact));
|
||||
}
|
||||
|
||||
// delete from distribution list(s)
|
||||
$this->remove_from_list($contact);
|
||||
@ -499,35 +536,14 @@ class addressbook_so
|
||||
}
|
||||
if($error_nr) return $error_nr;
|
||||
|
||||
// save customfields
|
||||
foreach ((array)$this->customfields as $field => $options)
|
||||
{
|
||||
if (!isset($contact['#'.$field])) continue;
|
||||
|
||||
$data = array(
|
||||
$this->extra_id => $contact['id'],
|
||||
$this->extra_owner => $contact['owner'],
|
||||
$this->extra_key => $field,
|
||||
);
|
||||
if((string) $contact['#'.$field] === '') // dont write empty values
|
||||
{
|
||||
$this->soextra->delete($data); // just delete them, in case they were previously set
|
||||
continue;
|
||||
}
|
||||
$data[$this->extra_value] = $contact['#'.$field];
|
||||
if (($error_nr = $this->soextra->save($data)))
|
||||
{
|
||||
return $error_nr;
|
||||
}
|
||||
}
|
||||
return false; // no error
|
||||
}
|
||||
|
||||
/**
|
||||
* reads contact data including custom fields
|
||||
*
|
||||
* @param int/string $contact_id contact_id or 'a'.account_id
|
||||
* @return array/boolean data if row could be retrived else False
|
||||
* @param int|string $contact_id contact_id or 'a'.account_id
|
||||
* @return array|boolean data if row could be retrived else False
|
||||
*/
|
||||
function read($contact_id)
|
||||
{
|
||||
@ -541,18 +557,6 @@ class addressbook_so
|
||||
{
|
||||
return $contact;
|
||||
}
|
||||
// try reading customfields only if we have some (none for LDAP!)
|
||||
if ($this->customfields && $this->contact_repository != 'ldap')
|
||||
{
|
||||
$customfields = $this->soextra->search(array(
|
||||
$this->extra_id => $contact['id'],
|
||||
$this->extra_key => array_keys($this->customfields),
|
||||
),false);
|
||||
foreach ((array)$customfields as $field)
|
||||
{
|
||||
$contact['#'.$field[$this->extra_key]] = $field[$this->extra_value];
|
||||
}
|
||||
}
|
||||
$dl_list=$this->read_distributionlist(array($contact['id']));
|
||||
if (count($dl_list)) $contact['distrib_lists']=implode("\n",$dl_list[$contact['id']]);
|
||||
return $this->db2data($contact);
|
||||
@ -563,10 +567,10 @@ class addressbook_so
|
||||
*
|
||||
* '*' and '?' are replaced with sql-wildcards '%' and '_'
|
||||
*
|
||||
* @param array/string $criteria array of key and data cols, OR string to search over all standard search fields
|
||||
* @param boolean/string $only_keys=true True returns only keys, False returns all cols. comma seperated list of keys to return
|
||||
* @param array|string $criteria array of key and data cols, OR string to search over all standard search fields
|
||||
* @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|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
|
||||
@ -577,14 +581,35 @@ class addressbook_so
|
||||
*/
|
||||
function &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='')
|
||||
{
|
||||
//echo "<p>socontacts::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')</p>\n";
|
||||
//error_log("socontacts::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')");
|
||||
//echo '<p>'.__METHOD__.'('.array2string($criteria,true).','.array2string($only_keys).",'$order_by','$extra_cols','$wildcard','$empty','$op',$start,".array2string($filter,true).",'$join')</p>\n";
|
||||
//error_log(__METHOD__.'('.array2string($criteria,true).','.array2string($only_keys).",'$order_by','$extra_cols','$wildcard','$empty','$op',$start,".array2string($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)
|
||||
// Handle 'None' country option
|
||||
if(is_array($filter) && $filter['adr_one_countrycode'] == '-custom-')
|
||||
{
|
||||
$filter['adr_one_countryname'] = $GLOBALS['egw']->country->get_full_name($filter['adr_one_countryname']);
|
||||
$filter[] = 'adr_one_countrycode IS NULL';
|
||||
unset($filter['adr_one_countrycode']);
|
||||
}
|
||||
// Hide deleted items unless type is specifically deleted
|
||||
if(!is_array($filter)) $filter = $filter ? (array) $filter : array();
|
||||
|
||||
// if no tid set or tid==='' do NOT return deleted entries ($tid === null returns all entries incl. deleted)
|
||||
if(!array_key_exists('tid', $filter) || $filter['tid'] === '')
|
||||
{
|
||||
if ($join && strpos($join,'RIGHT JOIN') !== false) // used eg. to search for groups
|
||||
{
|
||||
$filter[] = '(contact_tid != \'' . self::DELETED_TYPE . '\' OR contact_tid IS NULL)';
|
||||
}
|
||||
else
|
||||
{
|
||||
$filter[] = 'contact_tid != \'' . self::DELETED_TYPE . '\'';
|
||||
}
|
||||
}
|
||||
elseif(is_null($filter['tid']))
|
||||
{
|
||||
unset($filter['tid']); // return all entries incl. deleted
|
||||
}
|
||||
|
||||
$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))
|
||||
@ -602,14 +627,32 @@ class addressbook_so
|
||||
{
|
||||
$cols = $this->account_cols_to_search;
|
||||
}
|
||||
// search the customfields only if some exist, but only for sql!
|
||||
if (get_class($backend) == 'addressbook_sql' && $this->customfields)
|
||||
if($backend instanceof addressbook_sql)
|
||||
{
|
||||
$cols[] = $this->extra_value;
|
||||
// Keep a string, let the parent handle it
|
||||
$criteria = $search;
|
||||
|
||||
foreach($cols as $key => &$col)
|
||||
{
|
||||
if(!array_key_exists($col, $backend->db_cols))
|
||||
{
|
||||
if(!($col = array_search($col, $backend->db_cols)))
|
||||
{
|
||||
// Can't search this column, it will error if we try
|
||||
unset($cols[$key]);
|
||||
}
|
||||
}
|
||||
if ($col=='contact_id') $col='egw_addressbook.contact_id';
|
||||
}
|
||||
|
||||
$backend->columns_to_search = $cols;
|
||||
}
|
||||
foreach($cols as $col)
|
||||
else
|
||||
{
|
||||
$criteria[$col] = $search;
|
||||
foreach($cols as $col)
|
||||
{
|
||||
$criteria[$col] = $search;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_array($criteria) && count($criteria))
|
||||
@ -662,9 +705,17 @@ class addressbook_so
|
||||
{
|
||||
$search = $param['search'];
|
||||
$param['search'] = array();
|
||||
foreach($this->columns_to_search as $col)
|
||||
if($this->somain instanceof addressbook_sql)
|
||||
{
|
||||
if ($col != 'contact_value') $param['search'][$col] = $search; // we dont search the customfields
|
||||
// Keep the string, let the parent deal with it
|
||||
$param['search'] = $search;
|
||||
}
|
||||
else
|
||||
{
|
||||
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']))
|
||||
@ -730,7 +781,10 @@ class addressbook_so
|
||||
if (!$new_owner)
|
||||
{
|
||||
$this->somain->delete(array('owner' => $account_id));
|
||||
$this->soextra->delete(array($this->extra_owner => $account_id));
|
||||
if(!($this->somain instanceof addressbook_sql))
|
||||
{
|
||||
$this->soextra->delete_customfields(array($this->extra_owner => $account_id));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -746,16 +800,19 @@ class addressbook_so
|
||||
/**
|
||||
* return the backend, to be used for the given $contact_id
|
||||
*
|
||||
* @param mixed $contact_id=null
|
||||
* @param array|string|int $keys=null
|
||||
* @param int $owner=null account_id of owner or 0 for accounts
|
||||
* @return object
|
||||
*/
|
||||
function get_backend($contact_id=null,$owner=null)
|
||||
function get_backend($keys=null,$owner=null)
|
||||
{
|
||||
if ($owner === '') $owner = null;
|
||||
|
||||
$contact_id = !is_array($keys) ? $keys :
|
||||
(isset($keys['id']) ? $keys['id'] : $keys['contact_id']);
|
||||
|
||||
if ($this->contact_repository != $this->account_repository && is_object($this->so_accounts) &&
|
||||
(!is_null($owner) && !$owner || is_array($contact_id) && $contact_id['account_id'] || !is_null($contact_id) &&
|
||||
(!is_null($owner) && !$owner || is_array($keys) && $keys['account_id'] || !is_null($contact_id) &&
|
||||
($this->contact_repository == 'sql' && (!is_numeric($contact_id) && !is_array($contact_id) )||
|
||||
$this->contact_repository == 'ldap' && is_numeric($contact_id))))
|
||||
{
|
||||
@ -907,38 +964,55 @@ class addressbook_so
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a distribution list
|
||||
* Get the availible distribution lists for givens users and groups
|
||||
*
|
||||
* @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
|
||||
* @param array $keys column-name => value(s) pairs, eg. array('list_uid'=>$uid)
|
||||
* @param string $member_attr='contact_uid' null: no members, 'contact_uid', 'contact_id', 'caldav_name' return members as that attribute
|
||||
* @param boolean $limit_in_ab=false if true only return members from the same owners addressbook
|
||||
* @return array with list_id => array(list_id,list_name,list_owner,...) pairs
|
||||
*/
|
||||
function add_list($name,$owner,$contacts=array())
|
||||
function read_lists($keys,$member_attr=null,$limit_in_ab=false)
|
||||
{
|
||||
if (!method_exists($this->somain,'add_list')) return false;
|
||||
if (!method_exists($this->somain,'get_lists')) return false;
|
||||
|
||||
return $this->somain->add_list($name,$owner,$contacts);
|
||||
return $this->somain->get_lists($keys,null,$member_attr,$limit_in_ab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one contact to a distribution list
|
||||
* Adds / updates a distribution list
|
||||
*
|
||||
* @param int $contact contact_id
|
||||
* @param string|array $keys list-name or array with column-name => value pairs to specify the list
|
||||
* @param int $owner user- or group-id
|
||||
* @param array $contacts=array() contacts to add (only for not yet existing lists!)
|
||||
* @param array &$data=array() values for keys 'list_uid', 'list_carddav_name', 'list_name'
|
||||
* @return int|boolean integer list_id or false on error
|
||||
*/
|
||||
function add_list($keys,$owner,$contacts=array(),array &$data=array())
|
||||
{
|
||||
if (!method_exists($this->somain,'add_list')) return false;
|
||||
|
||||
return $this->somain->add_list($keys,$owner,$contacts,$data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds contact(s) to a distribution list
|
||||
*
|
||||
* @param int|array $contact contact_id(s)
|
||||
* @param int $list list-id
|
||||
* @param array $existing=null array of existing contact-id(s) of list, to not reread it, eg. array()
|
||||
* @return false on error
|
||||
*/
|
||||
function add2list($contact,$list)
|
||||
function add2list($contact,$list,array $existing=null)
|
||||
{
|
||||
if (!method_exists($this->somain,'add2list')) return false;
|
||||
|
||||
return $this->somain->add2list($contact,$list);
|
||||
return $this->somain->add2list($contact,$list,$existing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes one contact from distribution list(s)
|
||||
*
|
||||
* @param int $contact contact_id
|
||||
* @param int|array $contact contact_id(s)
|
||||
* @param int $list=null list-id or null to remove from all lists
|
||||
* @return false on error
|
||||
*/
|
||||
@ -952,7 +1026,7 @@ class addressbook_so
|
||||
/**
|
||||
* Deletes a distribution list (incl. it's members)
|
||||
*
|
||||
* @param int/array $list list_id(s)
|
||||
* @param int|array $list list_id(s)
|
||||
* @return number of members deleted or false if list does not exist
|
||||
*/
|
||||
function delete_list($list)
|
||||
@ -978,7 +1052,7 @@ class addressbook_so
|
||||
/**
|
||||
* 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)
|
||||
* @param int|string $owner='' addressbook (eg. 0 = accounts), default '' = "all" addressbook (uses the main backend)
|
||||
* @return boolean
|
||||
*/
|
||||
function lists_available($owner='')
|
||||
@ -987,4 +1061,17 @@ class addressbook_so
|
||||
|
||||
return method_exists($backend,'read_list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ctag (max list_modified as timestamp) for lists
|
||||
*
|
||||
* @param int|array $owner=null null for all lists user has access too
|
||||
* @return int
|
||||
*/
|
||||
function lists_ctag($owner=null)
|
||||
{
|
||||
if (!method_exists($this->somain,'lists_ctag')) return 0;
|
||||
|
||||
return $this->somain->lists_ctag($owner);
|
||||
}
|
||||
}
|
||||
|
@ -5,27 +5,21 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package addressbook
|
||||
* @copyright (c) 2006-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2006-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php');
|
||||
|
||||
/**
|
||||
* SQL storage object of the adressbook
|
||||
*/
|
||||
class addressbook_sql extends so_sql
|
||||
class addressbook_sql extends so_sql_cf
|
||||
{
|
||||
/**
|
||||
* name of customefields table
|
||||
* name of custom fields table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $extra_table = 'egw_addressbook_extra';
|
||||
var $extra_join = ' LEFT JOIN egw_addressbook_extra ON egw_addressbook.contact_id=egw_addressbook_extra.contact_id';
|
||||
var $extra_join_order = ' LEFT JOIN egw_addressbook_extra extra_order ON egw_addressbook.contact_id=extra_order.contact_id';
|
||||
var $extra_join_filter = ' JOIN egw_addressbook_extra extra_filter ON egw_addressbook.contact_id=extra_filter.contact_id';
|
||||
var $account_repository = 'sql';
|
||||
var $contact_repository = 'sql';
|
||||
var $grants;
|
||||
@ -33,7 +27,7 @@ class addressbook_sql extends so_sql
|
||||
/**
|
||||
* join to show only active account (and not already expired ones)
|
||||
*/
|
||||
const ACOUNT_ACTIVE_JOIN = ' LEFT JOIN egw_accounts ON egw_addressbook.account_id=egw_accounts.account_id';
|
||||
const ACCOUNT_ACTIVE_JOIN = ' LEFT JOIN egw_accounts ON egw_addressbook.account_id=egw_accounts.account_id';
|
||||
/**
|
||||
* filter to show only active account (and not already expired ones)
|
||||
* UNIX_TIMESTAMP(NOW()) gets replaced with value of time() in the code!
|
||||
@ -60,9 +54,18 @@ class addressbook_sql extends so_sql
|
||||
*/
|
||||
var $ab2list_table = 'egw_addressbook2list';
|
||||
|
||||
function __construct()
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param egw_db $db=null
|
||||
*/
|
||||
function __construct(egw_db $db=null)
|
||||
{
|
||||
$this->so_sql('phpgwapi','egw_addressbook',null,'contact_',true); // true = using the global db object, no clone!
|
||||
parent::__construct('phpgwapi','egw_addressbook','egw_addressbook_extra','contact_',
|
||||
$extra_key='_name',$extra_value='_value',$extra_id='_id',$db);
|
||||
|
||||
// Get custom fields from addressbook instead of phpgwapi
|
||||
$this->customfields = config::get_customfields('addressbook');
|
||||
|
||||
if ($GLOBALS['egw_info']['server']['account_repository'])
|
||||
{
|
||||
@ -105,7 +108,7 @@ class addressbook_sql extends so_sql
|
||||
if (isset($param['advanced_search']) && !empty($param['advanced_search'])) $advanced_search = true;
|
||||
$wildcard ='%';
|
||||
if ($advanced_search || (isset($param['wildcard']) && !empty($param['wildcard']))) $wildcard = ($param['wildcard']?$param['wildcard']:'');
|
||||
|
||||
|
||||
// fix cat_id filter to search in comma-separated multiple cats and return subcats
|
||||
if ((int)$filter['cat_id'])
|
||||
{
|
||||
@ -133,8 +136,8 @@ class addressbook_sql extends so_sql
|
||||
{
|
||||
$filter[] = $this->table_name.'.contact_owner != 0'; // in case there have been accounts in sql previously
|
||||
}
|
||||
$filter[] = "(contact_owner=".(int)$GLOBALS['egw_info']['user']['account_id'].
|
||||
" OR contact_private=0 AND contact_owner IN (".
|
||||
$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))."))";
|
||||
}
|
||||
}
|
||||
@ -254,10 +257,17 @@ class addressbook_sql extends so_sql
|
||||
*/
|
||||
function &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false)
|
||||
{
|
||||
if ((int) $this->debug >= 4) echo '<p>'.__METHOD__.'('.array2string($criteria).','.array2string($only_keys).",'$order_by','$extra_cols','$wildcard','$empty','$op','$start',".array2string($filter).",'$join')</p>\n";
|
||||
if ((int) $this->debug >= 4) echo '<p>'.__METHOD__.'('.array2string($criteria,true).','.array2string($only_keys).",'$order_by','$extra_cols','$wildcard','$empty','$op',$start,".array2string($filter,true).",'$join')</p>\n";
|
||||
//error_log(__METHOD__.'('.array2string($criteria,true).','.array2string($only_keys).",'$order_by','$extra_cols','$wildcard','$empty','$op',$start,".array2string($filter,true).",'$join')");
|
||||
|
||||
$owner = isset($filter['owner']) ? $filter['owner'] : (isset($criteria['owner']) ? $criteria['owner'] : null);
|
||||
|
||||
// fix cat_id criteria to search in comma-separated multiple cats and return subcats
|
||||
if (is_array($criteria) && ($cats = $criteria['cat_id']))
|
||||
{
|
||||
$criteria = array_merge($criteria, $this->_cat_search($criteria['cat_id']));
|
||||
unset($criteria['cat_id']);
|
||||
}
|
||||
// fix cat_id filter to search in comma-separated multiple cats and return subcats
|
||||
if (($cats = $filter['cat_id']))
|
||||
{
|
||||
@ -323,122 +333,28 @@ class addressbook_sql extends so_sql
|
||||
implode(',',array_keys($this->grants)).") $groupmember_sql 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]);
|
||||
}
|
||||
switch((string)$name)
|
||||
{
|
||||
case 'owner':
|
||||
case 'contact_owner':
|
||||
$filter[] = $this->db->expression($this->table_name,$this->table_name.'.',array(
|
||||
'contact_owner' => $val,
|
||||
));
|
||||
unset($filter[$name]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
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)
|
||||
// add join to show only active accounts (only if accounts are shown and in sql and we not already join the accounts table, eg. used by admin)
|
||||
if (!$owner && substr($this->account_repository,0,3) == 'sql' &&
|
||||
strpos($join,$GLOBALS['egw']->accounts->backend->table) === false && !array_key_exists('account_id',$filter))
|
||||
{
|
||||
$join .= self::ACCOUNT_ACTIVE_JOIN;
|
||||
$filter[] = str_replace('UNIX_TIMESTAMP(NOW())',time(),self::ACOUNT_ACTIVE_FILTER);
|
||||
}
|
||||
if ($join || $criteria && is_string($criteria)) // search also adds a join for custom fields!
|
||||
{
|
||||
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' : '*');
|
||||
// Correctly handled by parent class
|
||||
break;
|
||||
case 'string':
|
||||
$only_keys = explode(',',$only_keys);
|
||||
// fall through
|
||||
case 'array':
|
||||
foreach($only_keys as $key => $val)
|
||||
{
|
||||
switch($val)
|
||||
{
|
||||
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;
|
||||
}
|
||||
// postgres requires that expressions in order by appear in the columns of a distinct select
|
||||
if ($this->db->Type != 'mysql' && preg_match_all("/([a-zA-Z_.]+) *(<> *''|IS NULL|IS NOT NULL)? *(ASC|DESC)?(,|$)/ui",$order_by,$all_matches,PREG_SET_ORDER))
|
||||
@ -471,13 +387,6 @@ class addressbook_sql extends so_sql
|
||||
//_debug_array($order_by); _debug_array($extra_cols);
|
||||
}
|
||||
}
|
||||
// add join to show only active accounts (only if accounts are shown and in sql and we not already join the accounts table, eg. used by admin)
|
||||
if (!$owner && substr($this->account_repository,0,3) == 'sql' &&
|
||||
strpos($join,$GLOBALS['egw']->accounts->backend->table) === false && !array_key_exists('account_id',$filter))
|
||||
{
|
||||
$join .= self::ACOUNT_ACTIVE_JOIN;
|
||||
$filter[] = str_replace('UNIX_TIMESTAMP(NOW())',time(),self::ACOUNT_ACTIVE_FILTER);
|
||||
}
|
||||
$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!
|
||||
@ -549,101 +458,200 @@ class addressbook_sql extends so_sql
|
||||
/**
|
||||
* Get the availible distribution lists for givens users and groups
|
||||
*
|
||||
* @param array $uids user or group id's
|
||||
* @param array $uids array of user or group id's for $uid_column='list_owners', or values for $uid_column,
|
||||
* or whole where array: column-name => value(s) pairs
|
||||
* @param string $uid_column='list_owner' column-name or null to use $uids as where array
|
||||
* @param string $member_attr=null null: no members, 'contact_uid', 'contact_id', 'caldav_name' return members as that attribute
|
||||
* @param boolean|int|array $limit_in_ab=false if true only return members from the same owners addressbook,
|
||||
* if int|array only return members from the given owners addressbook(s)
|
||||
* @return array with list_id => array(list_id,list_name,list_owner,...) pairs
|
||||
*/
|
||||
function get_lists($uids)
|
||||
function get_lists($uids,$uid_column='list_owner',$member_attr=null,$limit_in_ab=false)
|
||||
{
|
||||
$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)
|
||||
if (is_array($uids) && isset($uids['list_carddav_name']))
|
||||
{
|
||||
$ids = array();
|
||||
foreach((array)$uids['list_carddav_name'] as $carddav_name)
|
||||
{
|
||||
if (preg_match('/addressbook-lists-([0-9]+)-/',$carddav_name, $matches))
|
||||
{
|
||||
$ids[] = $matches[1];
|
||||
}
|
||||
}
|
||||
unset($uids['list_carddav_name']);
|
||||
if (!$ids) return array();
|
||||
$uids[] = $this->db->expression($this->lists_table, $this->lists_table.'.',array('list_id' => $ids));
|
||||
}
|
||||
$lists = array();
|
||||
$table_def = $this->db->get_table_definitions('phpgwapi',$this->lists_table);
|
||||
$group_by = 'GROUP BY '.$this->lists_table.'.'.implode(','.$this->lists_table.'.',array_keys($table_def['fd']));
|
||||
foreach($this->db->select($this->lists_table,$this->lists_table.'.*,MAX(list_added) AS list_modified',$uid_column?array($uid_column=>$uids):$uids,__LINE__,__FILE__,
|
||||
false,$group_by.' ORDER BY list_owner<>'.(int)$GLOBALS['egw_info']['user']['account_id'].',list_name',false,0,
|
||||
"LEFT JOIN $this->ab2list_table ON $this->ab2list_table.list_id=$this->lists_table.list_id") as $row)
|
||||
{
|
||||
if (!$row['list_id']) continue; // because of join, no lists at all still return one row of NULL
|
||||
if ($member_attr) $row['members'] = array();
|
||||
// generate UID and carddav_name for list_id
|
||||
$row['list_uid'] = common::generate_uid('addressbook-lists', $row['list_id']);
|
||||
$row['list_carddav_name'] = $row['list_uid'].'.vcf';
|
||||
// set list_modified (=MAX(list_added)) as etag
|
||||
if (!$row['list_modified']) $row['list_modified'] = $row['list_created'];
|
||||
$row['list_etag'] = $row['list_modified'];
|
||||
$lists[$row['list_id']] = $row;
|
||||
}
|
||||
//echo "<p>socontacts_sql::get_lists(".print_r($uids,true).")</p>\n"; _debug_array($lists);
|
||||
if ($lists && $member_attr && in_array($member_attr,array('contact_id','contact_uid','caldav_name')))
|
||||
{
|
||||
if ($limit_in_ab)
|
||||
{
|
||||
$in_ab_join = " JOIN $this->lists_table ON $this->lists_table.list_id=$this->ab2list_table.list_id AND $this->lists_table.";
|
||||
if (!is_bool($limit_in_ab))
|
||||
{
|
||||
$in_ab_join .= $this->db->expression($this->lists_table, array('list_owner'=>$limit_in_ab));
|
||||
}
|
||||
else
|
||||
{
|
||||
$in_ab_join .= "list_owner=$this->table_name.contact_owner";
|
||||
}
|
||||
}
|
||||
foreach($this->db->select($this->ab2list_table,"$this->ab2list_table.list_id,$this->table_name.$member_attr",
|
||||
$this->db->expression($this->ab2list_table, $this->ab2list_table.'.', array('list_id'=>array_keys($lists))),
|
||||
__LINE__,__FILE__,false,$member_attr=='contact_id' ? '' :
|
||||
'',false,0,"JOIN $this->table_name ON $this->ab2list_table.contact_id=$this->table_name.contact_id".$in_ab_join) as $row)
|
||||
{
|
||||
$lists[$row['list_id']]['members'][] = $row[$member_attr];
|
||||
}
|
||||
}
|
||||
//error_log(__METHOD__.'('.array2string($uids).", '$uid_column', '$member_attr') returning ".array2string($lists));
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a distribution list
|
||||
* Adds / updates a distribution list
|
||||
*
|
||||
* @param string $name list-name
|
||||
* @param string|array $keys list-name or array with column-name => value pairs to specify the list
|
||||
* @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
|
||||
* @param array $contacts=array() contacts to add (only for not yet existing lists!)
|
||||
* @param array &$data=array() values for keys 'list_uid', 'list_carddav_name', 'list_name'
|
||||
* @return int|boolean integer list_id or false on error
|
||||
*/
|
||||
function add_list($name,$owner,$contacts=array())
|
||||
function add_list($keys,$owner,$contacts=array(),array &$data=array())
|
||||
{
|
||||
if (!$name || !(int)$owner) return false;
|
||||
//error_log(__METHOD__.'('.array2string($keys).", $owner, ".array2string($contacts).', '.array2string($data).') '.function_backtrace());
|
||||
if (!$keys && !$data || !(int)$owner) return false;
|
||||
|
||||
if ($this->db->select($this->lists_table,'list_id',array(
|
||||
'list_name' => $name,
|
||||
'list_owner' => $owner,
|
||||
),__LINE__,__FILE__)->fetchColumn())
|
||||
if ($keys && !is_array($keys)) $keys = array('list_name' => $keys);
|
||||
if ($keys)
|
||||
{
|
||||
return true; // return existing list-id
|
||||
$keys['list_owner'] = $owner;
|
||||
}
|
||||
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)
|
||||
else
|
||||
{
|
||||
foreach($contacts as $contact)
|
||||
$data['list_owner'] = $owner;
|
||||
}
|
||||
if (isset($keys['list_carddav_name']))
|
||||
{
|
||||
if (isset($data['list_id'])) // use id if given
|
||||
{
|
||||
$this->add2list($list_id,$contact);
|
||||
$keys = array(
|
||||
'list_id' => $data['list_id'],
|
||||
);
|
||||
unset($data['list_id']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$keys = false; // cant PUT a name in 11.1
|
||||
}
|
||||
}
|
||||
if (!$keys || !($list_id = $this->db->select($this->lists_table,'list_id',$keys,__LINE__,__FILE__)->fetchColumn()))
|
||||
{
|
||||
$data['list_created'] = time();
|
||||
$data['list_creator'] = $GLOBALS['egw_info']['user']['account_id'];
|
||||
}
|
||||
$data['list_modified'] = $data['list_etag'] = time();
|
||||
$data['list_modifier'] = $GLOBALS['egw_info']['user']['account_id'];
|
||||
if (!$data['list_id']) unset($data['list_id']);
|
||||
|
||||
if (!$this->db->insert($this->lists_table,$data,$keys,__LINE__,__FILE__)) return false;
|
||||
|
||||
if (!$list_id && ($list_id = $this->db->get_last_insert_id($this->lists_table,'list_id')))
|
||||
{
|
||||
$this->add2list($list_id,$contacts,array());
|
||||
}
|
||||
// generate UID and carddav_name for list_id, as we dont store them in 11.1
|
||||
$data['list_uid'] = common::generate_uid('addressbook-lists', $list_id);
|
||||
$data['list_carddav_name'] = $data['list_uid'].'.vcf';
|
||||
|
||||
if ($keys) $data += $keys;
|
||||
//error_log(__METHOD__.'('.array2string($keys).", $owner, ...) data=".array2string($data).' returning '.array2string($list_id));
|
||||
return $list_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one contact to a distribution list
|
||||
* Adds contact(s) to a distribution list
|
||||
*
|
||||
* @param int $contact contact_id
|
||||
* @param int|array $contact contact_id(s)
|
||||
* @param int $list list-id
|
||||
* @param array $existing=null array of existing contact-id(s) of list, to not reread it, eg. array()
|
||||
* @return false on error
|
||||
*/
|
||||
function add2list($contact,$list)
|
||||
function add2list($contact,$list,array $existing=null)
|
||||
{
|
||||
if (!(int)$list || !(int)$contact) return false;
|
||||
if (!(int)$list || !is_array($contact) && !(int)$contact) return false;
|
||||
|
||||
if ($this->db->select($this->ab2list_table,'list_id',array(
|
||||
'contact_id' => $contact,
|
||||
'list_id' => $list,
|
||||
),__LINE__,__FILE__)->fetchColumn())
|
||||
if (!is_array($existing))
|
||||
{
|
||||
$existing = array();
|
||||
foreach($this->db->select($this->ab2list_table,'contact_id',array('list_id'=>$list),__LINE__,__FILE__) as $row)
|
||||
{
|
||||
$existing[] = $row['contact_id'];
|
||||
}
|
||||
}
|
||||
if (!($to_add = array_diff((array)$contact,$existing)))
|
||||
{
|
||||
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__);
|
||||
foreach($to_add as $contact)
|
||||
{
|
||||
$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|array $contact contact_id(s)
|
||||
* @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;
|
||||
if (!(int)$list && !is_null($list) || !is_array($contact) && !(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__);
|
||||
if (!is_null($list))
|
||||
{
|
||||
$where['list_id'] = $list;
|
||||
}
|
||||
else
|
||||
{
|
||||
$list = array();
|
||||
foreach($this->db->select($this->ab2list_table,'list_id',$where,__LINE__,__FILE__) as $row)
|
||||
{
|
||||
$list[] = $row['list_id'];
|
||||
}
|
||||
}
|
||||
if (!$this->db->delete($this->ab2list_table,$where,__LINE__,__FILE__))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -661,6 +669,31 @@ class addressbook_sql extends so_sql
|
||||
return $this->db->affected_rows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ctag (max list_modified as timestamp) for lists
|
||||
*
|
||||
* @param int|array $owner=null null for all lists user has access too
|
||||
* @return int
|
||||
*/
|
||||
function lists_ctag($owner=null)
|
||||
{
|
||||
if (is_null($owner)) $owner = array_keys($this->grants);
|
||||
|
||||
if (!($modified = $this->db->select($this->lists_table,'MAX(list_added)',array('list_owner'=>$owner),
|
||||
__LINE__,__FILE__,false,'',false,0,
|
||||
"JOIN $this->ab2list_table ON $this->ab2list_table.list_id=$this->lists_table.list_id")->fetchColumn()))
|
||||
{
|
||||
$modified = 0;
|
||||
}
|
||||
if (!($created = $this->db->select($this->lists_table,'MAX(list_created)',array('list_owner'=>$owner),
|
||||
__LINE__,__FILE__)->fetchColumn()))
|
||||
{
|
||||
$created = 0;
|
||||
}
|
||||
//error_log(__METHOD__.'('.array2string($owner).") MAX(list_added)=$modified, MAX(list_created)=$created returning ".array2string(max($modified,$created)));
|
||||
return max($modified,$created);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a contact, reimplemented to use the uid, if a non-numeric key is given
|
||||
*
|
||||
@ -682,6 +715,14 @@ class addressbook_sql extends so_sql
|
||||
$keys = array('contact_uid' => $keys);
|
||||
}
|
||||
$contact = parent::read($keys,$extra_cols,$join);
|
||||
|
||||
// Change autoinc_id to match $this->db_cols
|
||||
$this->autoinc_id = $this->db_cols[$this->autoinc_id];
|
||||
if(($id = (int)$this->data[$this->autoinc_id]) && $cfs = $this->read_customfields($keys)) {
|
||||
if (is_array($cfs[$id])) $contact = array_merge($contact,$cfs[$id]);
|
||||
}
|
||||
$this->autoinc_id = array_search($this->autoinc_id, $this->db_cols);
|
||||
|
||||
// enforce a minium uid strength
|
||||
if (is_array($contact) && (!isset($contact['uid'])
|
||||
|| strlen($contact['uid']) < $minimum_uid_length)) {
|
||||
@ -730,12 +771,23 @@ class addressbook_sql extends so_sql
|
||||
$this->data['etag'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$update = array();
|
||||
// enforce a minium uid strength
|
||||
if (!$err && (!isset($this->data['uid'])
|
||||
|| strlen($this->data['uid']) < $minimum_uid_length)) {
|
||||
parent::update(array('uid' => common::generate_uid('addressbook',$this->data['id'])));
|
||||
if (!isset($this->data['uid']) || strlen($this->data['uid']) < $minimum_uid_length)
|
||||
{
|
||||
$update['uid'] = common::generate_uid('addressbook',$this->data['id']);
|
||||
//echo "<p>set uid={$this->data['uid']}, etag={$this->data['etag']}</p>";
|
||||
}
|
||||
// set carddav_name, if not given by caller
|
||||
if (empty($this->data['carddav_name']))
|
||||
{
|
||||
$update['carddav_name'] = $this->data['id'].'.vcf';
|
||||
}
|
||||
if (!$err && $update)
|
||||
{
|
||||
parent::update($update);
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
|
||||
@ -752,4 +804,49 @@ class addressbook_sql extends so_sql
|
||||
|
||||
return $this->db->select($this->lists_table,'*',array('list_id'=>$list),__LINE__,__FILE__)->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* saves custom field data
|
||||
* Re-implemented to deal with extra contact_owner column
|
||||
*
|
||||
* @param array $data data to save (cf's have to be prefixed with self::CF_PREFIX = #)
|
||||
* @return bool false on success, errornumber on failure
|
||||
*/
|
||||
function save_customfields($data)
|
||||
{
|
||||
foreach ((array)$this->customfields as $name => $options)
|
||||
{
|
||||
if (!isset($data[$field = $this->get_cf_field($name)])) continue;
|
||||
|
||||
$where = array(
|
||||
$this->extra_id => $data['id'],
|
||||
$this->extra_key => $name,
|
||||
);
|
||||
$is_multiple = $this->is_multiple($name);
|
||||
|
||||
// we explicitly need to delete fields, if value is empty or field allows multiple values or we have no unique index
|
||||
if(empty($data[$field]) || $is_multiple || !$this->extra_has_unique_index)
|
||||
{
|
||||
$this->db->delete($this->extra_table,$where,__LINE__,__FILE__,$this->app);
|
||||
if (empty($data[$field])) continue; // nothing else to do for empty values
|
||||
}
|
||||
foreach($is_multiple && !is_array($data[$field]) ? explode(',',$data[$field]) : (array)$data[$field] as $value)
|
||||
{
|
||||
if (!$this->db->insert($this->extra_table,array($this->extra_value => $value, 'contact_owner' => $data['owner']),$where,__LINE__,__FILE__,$this->app))
|
||||
{
|
||||
return $this->db->Errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false; // no error
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes custom field data
|
||||
* Implemented to deal with LDAP backend, which saves CFs in SQL, but the account record is in LDAP
|
||||
*/
|
||||
function delete_customfields($data)
|
||||
{
|
||||
$this->db->delete($this->extra_table,$data,__LINE__,__FILE__);
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class addressbook_ui extends addressbook_bo
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $private_addressbook = false;
|
||||
public $private_addressbook = false;
|
||||
protected $org_views;
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,9 @@ class addressbook_vcal extends addressbook_bo
|
||||
'X-ASSISTANT' => array('assistent'),
|
||||
'X-ASSISTANT-TEL' => array('tel_assistent'),
|
||||
'UID' => array('uid'),
|
||||
);
|
||||
'REV' => array('modified'),
|
||||
//set for Apple: 'X-ABSHOWAS' => array('fileas_type'), // Horde vCard class uses uppercase prop-names!
|
||||
);
|
||||
|
||||
/**
|
||||
* VCard version
|
||||
@ -175,23 +177,6 @@ class addressbook_vcal extends addressbook_bo
|
||||
{
|
||||
$contact['cat_id'] = implode(',',$this->find_or_add_categories($contact['cat_id'], -1));
|
||||
}
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['filter_addressbook']))
|
||||
{
|
||||
$owner = $GLOBALS['egw_info']['user']['preferences']['syncml']['filter_addressbook'];
|
||||
switch ($owner)
|
||||
{
|
||||
case 'G':
|
||||
$contact['owner'] = $GLOBALS['egw_info']['user']['account_primary_group'];
|
||||
break;
|
||||
case 'P':
|
||||
case 'N':
|
||||
case 0:
|
||||
$contact['owner'] = $this->user;
|
||||
break;
|
||||
default:
|
||||
$contact['owner'] = (int)$owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($contact['owner']) && $contact['owner'] != $this->user)
|
||||
{
|
||||
@ -220,8 +205,10 @@ class addressbook_vcal extends addressbook_bo
|
||||
#Horde::logMessage("vCalAddressbook clientProperties:\n" . print_r($this->clientProperties, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$vCard = new Horde_iCalendar_vcard($this->version);
|
||||
$vCard->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Addressbook '.$GLOBALS['egw_info']['apps']['phpgwapi']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
|
||||
$sysCharSet = $GLOBALS['egw']->translation->charset();
|
||||
$sysCharSet = translation::charset();
|
||||
|
||||
// KAddressbook and Funambol4BlackBerry always requires non-ascii chars to be qprint encoded.
|
||||
if ($this->productName == 'kde' ||
|
||||
@ -295,6 +282,11 @@ class addressbook_vcal extends addressbook_bo
|
||||
|
||||
switch ($databaseField)
|
||||
{
|
||||
case 'modified':
|
||||
$value = gmdate("Y-m-d\TH:i:s\Z",egw_time::user2server($value));
|
||||
$hasdata++;
|
||||
break;
|
||||
|
||||
case 'private':
|
||||
$value = $value ? 'PRIVATE' : 'PUBLIC';
|
||||
$hasdata++;
|
||||
@ -339,9 +331,9 @@ class addressbook_vcal extends addressbook_bo
|
||||
break;
|
||||
|
||||
case 'cat_id':
|
||||
if (!empty($value) && ($values = $this->get_categories($value)))
|
||||
if (!empty($value) && ($values = /*str_replace(',','\\,',*/$this->get_categories($value)))//)
|
||||
{
|
||||
$values = (array) $GLOBALS['egw']->translation->convert($values, $sysCharSet, $_charset);
|
||||
$values = (array) translation::convert($values, $sysCharSet, $_charset);
|
||||
$value = implode(',', $values); // just for the CHARSET recognition
|
||||
if (($size > 0) && strlen($value) > $size)
|
||||
{
|
||||
@ -388,6 +380,18 @@ class addressbook_vcal extends addressbook_bo
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n_fn':
|
||||
case 'fileas_type':
|
||||
// mark entries with fileas_type == 'org_name' as X-ABSHOWAS:COMPANY (Apple AB specific)
|
||||
if (isset($this->supportedFields['X-ABSHOWAS']) &&
|
||||
$entry['org_name'] == $entry['n_fileas'] && $entry['fileas_type'] == 'org_name')
|
||||
{
|
||||
if ($vcardField == 'X-ABSHOWAS') $value = 'COMPANY';
|
||||
if ($databaseField == 'n_fn') $value = $entry['org_name'];
|
||||
}
|
||||
//error_log("vcardField='$vcardField', databaseField='$databaseField', this->supportedFields['X-ABSHOWAS']=".array2string($this->supportedFields['X-ABSHOWAS'])." --> value='$value'");
|
||||
// fall-through
|
||||
|
||||
default:
|
||||
if (($size > 0) && strlen(implode(',', $values) . $value) > $size)
|
||||
{
|
||||
@ -425,7 +429,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
|| in_array($vcardField,array('FN','ORG','N'))
|
||||
|| ($size >= 0 && !$noTruncate))
|
||||
{
|
||||
$value = $GLOBALS['egw']->translation->convert(trim($value), $sysCharSet, $_charset);
|
||||
$value = translation::convert(trim($value), $sysCharSet, $_charset);
|
||||
$values[] = $value;
|
||||
if (preg_match('/[^\x20-\x7F]/', $value))
|
||||
{
|
||||
@ -478,7 +482,6 @@ class addressbook_vcal extends addressbook_bo
|
||||
}
|
||||
|
||||
$vCard->setAttribute($vcardField, $value, $options, true, $values);
|
||||
//$vCard->setParameter($vcardField, $options);
|
||||
}
|
||||
|
||||
$result = $vCard->exportvCalendar($_charset);
|
||||
@ -535,43 +538,6 @@ class addressbook_vcal extends addressbook_bo
|
||||
// the horde class does the charset conversion. DO NOT CONVERT HERE.
|
||||
// be as flexible as possible
|
||||
|
||||
$databaseFields = array(
|
||||
'ADR;WORK' => array('','adr_one_street2','adr_one_street','adr_one_locality','adr_one_region',
|
||||
'adr_one_postalcode','adr_one_countryname'),
|
||||
'ADR;HOME' => array('','adr_two_street2','adr_two_street','adr_two_locality','adr_two_region',
|
||||
'adr_two_postalcode','adr_two_countryname'),
|
||||
'BDAY' => array('bday'),
|
||||
'X-CLASS' => array('private'),
|
||||
'CLASS' => array('private'),
|
||||
'CATEGORIES' => array('cat_id'),
|
||||
'EMAIL;WORK' => array('email'),
|
||||
'EMAIL;HOME' => array('email_home'),
|
||||
'N' => array('n_family','n_given','n_middle',
|
||||
'n_prefix','n_suffix'),
|
||||
'FN' => array('n_fn'),
|
||||
'NOTE' => array('note'),
|
||||
'ORG' => array('org_name','org_unit','room'),
|
||||
'TEL;CELL;WORK' => array('tel_cell'),
|
||||
'TEL;CELL;HOME' => array('tel_cell_private'),
|
||||
'TEL;CAR' => array('tel_car'),
|
||||
'TEL;OTHER' => array('tel_other'),
|
||||
'TEL;VOICE;WORK' => array('tel_work'),
|
||||
'TEL;FAX;WORK' => array('tel_fax'),
|
||||
'TEL;HOME;VOICE' => array('tel_home'),
|
||||
'TEL;FAX;HOME' => array('tel_fax_home'),
|
||||
'TEL;PAGER' => array('tel_pager'),
|
||||
'TITLE' => array('title'),
|
||||
'URL;WORK' => array('url'),
|
||||
'URL;HOME' => array('url_home'),
|
||||
'ROLE' => array('role'),
|
||||
'NICKNAME' => array('label'),
|
||||
'FBURL' => array('freebusy_uri'),
|
||||
'PHOTO' => array('jpegphoto'),
|
||||
'X-ASSISTANT' => array('assistent'),
|
||||
'X-ASSISTANT-TEL' => array('tel_assistent'),
|
||||
'UID' => array('uid'),
|
||||
);
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
|
||||
@ -589,7 +555,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
}
|
||||
$vcardValues = $vCard->getAllAttributes();
|
||||
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
if (!empty($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
|
||||
}
|
||||
@ -609,6 +575,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
$url = 1;
|
||||
$pref_tel = false;
|
||||
|
||||
$rowNames = array();
|
||||
foreach($vcardValues as $key => $vcardRow)
|
||||
{
|
||||
$rowName = strtoupper($vcardRow['name']);
|
||||
@ -686,7 +653,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
switch ($pname)
|
||||
{
|
||||
case 'PREF':
|
||||
if ($rowName == 'TEL' && !$pref_tel)
|
||||
if (substr($rowName,0,3) == 'TEL' && !$pref_tel)
|
||||
{
|
||||
$pref_tel = $key;
|
||||
}
|
||||
@ -746,6 +713,12 @@ class addressbook_vcal extends addressbook_bo
|
||||
$rowName = 'URL;X-egw-Ref' . $url++;
|
||||
}
|
||||
|
||||
// current algorithm cant cope with multiple attributes of same name
|
||||
// --> cumulate them in values, so they can be used later (works only for values, not for parameters!)
|
||||
if (($k = array_search($rowName, $rowNames)) != false)
|
||||
{
|
||||
$vcardValues[$k]['values'] = array_merge($vcardValues[$k]['values'],$vcardValues[$key]['values']);
|
||||
}
|
||||
$rowNames[$key] = $rowName;
|
||||
}
|
||||
|
||||
@ -812,7 +785,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
{
|
||||
$finalRowNames['TEL;OTHER'] = $vcardKey;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 'TEL;PAGER;WORK':
|
||||
case 'TEL;PAGER;HOME':
|
||||
if (!in_array('TEL;PAGER', $rowNames)
|
||||
@ -820,7 +793,7 @@ class addressbook_vcal extends addressbook_bo
|
||||
{
|
||||
$finalRowNames['TEL;PAGER'] = $vcardKey;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 'TEL;CAR;VOICE':
|
||||
case 'TEL;CAR;CELL':
|
||||
case 'TEL;CAR;CELL;VOICE':
|
||||
@ -930,9 +903,9 @@ class addressbook_vcal extends addressbook_bo
|
||||
|
||||
foreach ($finalRowNames as $key => $vcardKey)
|
||||
{
|
||||
if (isset($databaseFields[$key]))
|
||||
if (isset($this->supportedFields[$key]))
|
||||
{
|
||||
$fieldNames = $databaseFields[$key];
|
||||
$fieldNames = $this->supportedFields[$key];
|
||||
foreach ($fieldNames as $fieldKey => $fieldName)
|
||||
{
|
||||
if (!empty($fieldName))
|
||||
@ -968,6 +941,14 @@ class addressbook_vcal extends addressbook_bo
|
||||
$contact[$fieldName] = str_replace("\r\n", "\n", $vcardValues[$vcardKey]['value']);
|
||||
break;
|
||||
|
||||
case 'fileas_type':
|
||||
// store Apple's X-ABSHOWAS:COMPANY as fileas_type == 'org_name'
|
||||
if ($vcardValues[$vcardKey]['value'] == 'COMPANY')
|
||||
{
|
||||
$contact[$fieldName] = 'org_name';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'uid':
|
||||
if (strlen($value) < $minimum_uid_length) {
|
||||
// we don't use it
|
||||
@ -980,10 +961,24 @@ class addressbook_vcal extends addressbook_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
// add unsupported attributes as with '##' prefix
|
||||
elseif(($attribute = $vcardValues[$vcardKey]) && !in_array($attribute['name'],array('PRODID','REV')))
|
||||
{
|
||||
// for attributes with multiple values in multiple lines, merge the values
|
||||
if (isset($contact['##'.$attribute['name']]))
|
||||
{
|
||||
error_log(__METHOD__."() contact['##$attribute[name]'] = ".array2string($contact['##'.$attribute['name']]));
|
||||
$attribute['values'] = array_merge(
|
||||
is_array($contact['##'.$attribute['name']]) ? $contact['##'.$attribute['name']]['values'] : (array)$contact['##'.$attribute['name']],
|
||||
$attribute['values']);
|
||||
}
|
||||
$contact['##'.$attribute['name']] = $attribute['params'] || count($attribute['values']) > 1 ?
|
||||
serialize($attribute) : $attribute['value'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->fixup_contact($contact);
|
||||
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ .
|
||||
@ -1026,8 +1021,37 @@ class addressbook_vcal extends addressbook_bo
|
||||
|
||||
if (!$file)
|
||||
{
|
||||
$GLOBALS['egw']->common->egw_exit();
|
||||
common::egw_exit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a groupVCard
|
||||
*
|
||||
* @param array $list values for 'list_uid', 'list_name', 'list_modified', 'members'
|
||||
* @param string $version='3.0' vcard version
|
||||
* @return string containing the vcard
|
||||
*/
|
||||
function getGroupVCard(array $list,$version='3.0')
|
||||
{
|
||||
require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar/vcard.php');
|
||||
|
||||
$vCard = new Horde_iCalendar_vcard($version);
|
||||
$vCard->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Addressbook '.$GLOBALS['egw_info']['apps']['phpgwapi']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
|
||||
$vCard->setAttribute('N',$list['list_name'],array(),true,array($list['list_name'],'','','',''));
|
||||
$vCard->setAttribute('FN',$list['list_name']);
|
||||
|
||||
$vCard->setAttribute('X-ADDRESSBOOKSERVER-KIND','group');
|
||||
foreach($list['members'] as $uid)
|
||||
{
|
||||
$vCard->setAttribute('X-ADDRESSBOOKSERVER-MEMBER','urn:uuid:'.$uid);
|
||||
}
|
||||
$vCard->setAttribute('REV',egw_time::to($list['list_modified'],'Y-m-d\TH:i:s\Z'));
|
||||
$vCard->setAttribute('UID',$list['list_uid']);
|
||||
|
||||
return $vCard->exportvCalendar();
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -13,7 +13,7 @@
|
||||
</hbox>
|
||||
<styles>.rightPadAdd { width: 30px; }</styles>
|
||||
</template>
|
||||
<template id="addressbook.index.rows" template="" lang="" group="0" version="1.7.004">
|
||||
<template id="addressbook.index.rows" template="" lang="" group="0" version="1.8.004">
|
||||
<grid width="100%">
|
||||
<columns>
|
||||
<column/>
|
||||
@ -71,7 +71,7 @@
|
||||
<nextmatch-header id="bday" label="Birthday"/>
|
||||
<vbox options="0,0">
|
||||
<nextmatch-header label="Business address" id="business"/>
|
||||
<nextmatch-customfilter id="adr_one_countryname" options="select-country,Country,1" class="countrySelect"/>
|
||||
<nextmatch-customfilter id="adr_one_countrycode" options="select-country,Country,1" class="countrySelect"/>
|
||||
<nextmatch-sortheader id="adr_one_postalcode" label="zip code"/>
|
||||
</vbox>
|
||||
<nextmatch-header label="Home address" id="home"/>
|
||||
|
246
admin/inc/class.admin_accesslog.inc.php
Normal file
246
admin/inc/class.admin_accesslog.inc.php
Normal file
@ -0,0 +1,246 @@
|
||||
<?php
|
||||
/**
|
||||
* EGgroupware admin - access- and session-log
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package admin
|
||||
* @copyright (c) 2009-11 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* Show EGroupware access- and session-log
|
||||
*/
|
||||
class admin_accesslog
|
||||
{
|
||||
/**
|
||||
* Which methods of this class can be called as menuation
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $public_functions = array(
|
||||
'index' => true,
|
||||
'sessions' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Our storage object
|
||||
*
|
||||
* @var so_sql
|
||||
*/
|
||||
protected $so;
|
||||
|
||||
/**
|
||||
* Name of our table
|
||||
*/
|
||||
const TABLE = 'egw_access_log';
|
||||
/**
|
||||
* Name of app the table is registered
|
||||
*/
|
||||
const APP = 'phpgwapi';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
$this->so = new so_sql(self::APP,self::TABLE,null,'',true);
|
||||
}
|
||||
|
||||
/**
|
||||
* query rows for the nextmatch widget
|
||||
*
|
||||
* @param array $query with keys 'start', 'search', 'order', 'sort', 'col_filter'
|
||||
* @param array &$rows returned rows/competitions
|
||||
* @param array &$readonlys eg. to disable buttons based on acl, not use here, maybe in a derived class
|
||||
* @return int total number of rows
|
||||
*/
|
||||
function get_rows($query,&$rows,&$readonlys)
|
||||
{
|
||||
$heartbeat_limit = egw_session::heartbeat_limit();
|
||||
|
||||
if ($query['session_list']) // filter active sessions
|
||||
{
|
||||
$query['col_filter']['lo'] = null; // not logged out
|
||||
$query['col_filter'][0] = 'session_dla > '.(int)(time() - $GLOBALS['egw_info']['server']['sessions_timeout']);
|
||||
$query['col_filter'][1] = "(notification_heartbeat IS NULL OR notification_heartbeat > $heartbeat_limit)";
|
||||
}
|
||||
$total = $this->so->get_rows($query,$rows,$readonlys);
|
||||
|
||||
$no_kill = !$GLOBALS['egw']->acl->check('current_sessions_access',8,'admin') && !$query['session_list'];
|
||||
|
||||
foreach($rows as &$row)
|
||||
{
|
||||
$row['sessionstatus'] = lang('success');
|
||||
if ($row['notification_heartbeat'] > $heartbeat_limit)
|
||||
{
|
||||
$row['sessionstatus'] = lang('active');
|
||||
}
|
||||
if (stripos($row['session_php'],'blocked') !== false ||
|
||||
stripos($row['session_php'],'bad login') !== false ||
|
||||
strpos($row['sessioin_php'],' ') !== false)
|
||||
{
|
||||
$row['sessionstatus'] = $row['session_php'];
|
||||
}
|
||||
if ($row['lo']) {
|
||||
$row['total'] = ($row['lo'] - $row['li']) / 60;
|
||||
$row['sessionstatus'] = lang('logged out');
|
||||
}
|
||||
// eg. for bad login or password
|
||||
if (!$row['account_id']) $row['alt_loginid'] = $row['loginid'];
|
||||
|
||||
$readonlys['kill['.$row['sessionid'].']'] = $no_kill;
|
||||
$readonlys['delete['.$row['sessionid'].']'] = $query['session_list'];
|
||||
|
||||
// do not allow to kill or select own session
|
||||
if ($GLOBALS['egw']->session->sessionid_access_log == $row['sessionid'] && $query['session_list'])
|
||||
{
|
||||
$readonlys['kill['.$row['sessionid'].']'] = $readonlys['selected['.$row['sessionid'].']'] = true;
|
||||
}
|
||||
// do not allow to delete access log off active sessions
|
||||
if (!$row['lo'] && $row['session_dla'] > time()-$GLOBALS['egw_info']['server']['sessions_timeout'] && !$query['session_list'])
|
||||
{
|
||||
$readonlys['delete['.$row['sessionid'].']'] = $readonlys['selected['.$row['sessionid'].']'] = true;
|
||||
}
|
||||
unset($row['session_php']); // for security reasons, do NOT give real PHP sessionid to UI
|
||||
}
|
||||
if ($query['session_list'])
|
||||
{
|
||||
$rows['no_total'] = $rows['no_lo'] = true;
|
||||
}
|
||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('Admin').' - '.
|
||||
($query['session_list'] ? lang('View sessions') : lang('View Access Log')).
|
||||
($query['col_filter']['account_id'] ? ': '.common::grab_owner_name($query['col_filter']['account_id']) : '');
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the access log or session list
|
||||
*
|
||||
* @param array $content=null
|
||||
* @param string $msg=''
|
||||
* @param boolean $sessions_list=false
|
||||
*/
|
||||
function index(array $content=null, $msg='', $sessions_list=false)
|
||||
{
|
||||
//_debug_array($content);
|
||||
if (is_array($content)) $sessions_list = $content['nm']['session_list'];
|
||||
|
||||
// check if user has access to requested functionality
|
||||
if ($GLOBALS['egw']->acl->check($sessions_list ? 'current_sessions_access' : 'access_log_access',1,'admin'))
|
||||
{
|
||||
$GLOBALS['egw']->redirect_link('/index.php');
|
||||
}
|
||||
|
||||
if(!isset($content))
|
||||
{
|
||||
$content['nm'] = array(
|
||||
'get_rows' => 'admin.admin_accesslog.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows'
|
||||
'no_filter' => True, // I disable the 1. filter
|
||||
'no_filter2' => True, // I disable the 2. filter (params are the same as for filter)
|
||||
'no_cat' => True, // I disable the cat-selectbox
|
||||
'header_left' => false, // I template to show left of the range-value, left-aligned (optional)
|
||||
'header_right' => false, // I template to show right of the range-value, right-aligned (optional)
|
||||
'never_hide' => True, // I never hide the nextmatch-line if less then maxmatch entries
|
||||
'lettersearch' => false, // I show a lettersearch
|
||||
'start' => 0, // IO position in list
|
||||
'order' => 'li', // IO name of the column to sort after (optional for the sortheaders)
|
||||
'sort' => 'DESC', // IO direction of the sort: 'ASC' or 'DESC'
|
||||
//'default_cols' => // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns
|
||||
'csv_fields' => false, // I false=disable csv export, true or unset=enable it with auto-detected fieldnames,
|
||||
//or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type)
|
||||
);
|
||||
if ((int)$_GET['account_id'])
|
||||
{
|
||||
$content['nm']['col_filter']['account_id'] = (int)$_GET['account_id'];
|
||||
}
|
||||
if ($sessions_list)
|
||||
{
|
||||
$content['nm']['order'] = 'session_dla';
|
||||
$content['nm']['options-selectcols'] = array(
|
||||
'lo' => false,
|
||||
'total' => false,
|
||||
);
|
||||
}
|
||||
$content['nm']['session_list'] = $sessions_list;
|
||||
}
|
||||
elseif(isset($content['nm']['rows']['delete']) || isset($content['delete']))
|
||||
{
|
||||
if (isset($content['nm']['rows']['delete']))
|
||||
{
|
||||
list($sessionid) = each($content['nm']['rows']['delete']);
|
||||
unset($content['nm']['rows']['delete']);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($content['delete']);
|
||||
$sessionid = $content['nm']['rows']['selected'];
|
||||
}
|
||||
if ($sessionid && $this->so->delete(array('sessionid' => $sessionid)))
|
||||
{
|
||||
$msg = lang('%1 log entries deleted.',1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$msg = lang('Error deleting log entry!');
|
||||
}
|
||||
}
|
||||
elseif(isset($content['nm']['rows']['kill']) || isset($content['kill']))
|
||||
{
|
||||
if (isset($content['nm']['rows']['kill']))
|
||||
{
|
||||
list($sessionid) = each($content['nm']['rows']['kill']);
|
||||
$sessionid = array($sessionid);
|
||||
unset($content['nm']['rows']['kill']);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($content['kill']);
|
||||
$sessionid = $content['nm']['rows']['selected'];
|
||||
}
|
||||
if (($key = array_search($GLOBALS['egw']->session->sessionid_access_log, $sessionid)))
|
||||
{
|
||||
unset($sessionid[$key]); // dont allow to kill own sessions
|
||||
}
|
||||
if ($GLOBALS['egw']->acl->check('current_sessions_access',8,'admin'))
|
||||
{
|
||||
$msg = lang('Permission denied!');
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach((array)$sessionid as $id)
|
||||
{
|
||||
$GLOBALS['egw']->session->destroy($id);
|
||||
}
|
||||
$msg = lang('%1 sessions killed',count($sessionid));
|
||||
}
|
||||
}
|
||||
$readonlys['kill'] = !$sessions_list;
|
||||
$readonlys['delete'] = $sessions_list;
|
||||
|
||||
$content['msg'] = $msg;
|
||||
$content['percent'] = 100.0 * $GLOBALS['egw']->db->query(
|
||||
'SELECT ((SELECT COUNT(*) FROM '.self::TABLE.' WHERE lo != 0) / COUNT(*)) FROM '.self::TABLE,
|
||||
__LINE__,__FILE__)->fetchColumn();
|
||||
|
||||
$tmpl = new etemplate('admin.accesslog');
|
||||
$tmpl->exec('admin.admin_accesslog.index',$content,$sel_options,$readonlys,array(
|
||||
'nm' => $content['nm'],
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display session list
|
||||
*
|
||||
* @param array $content=null
|
||||
* @param string $msg=''
|
||||
*/
|
||||
function sessions(array $content=null, $msg='')
|
||||
{
|
||||
return $this->index(null,$msg,true);
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@ class admin_prefs_sidebox_hooks
|
||||
|
||||
if (! $GLOBALS['egw']->acl->check('current_sessions_access',1,'admin'))
|
||||
{
|
||||
$file['View Sessions'] = egw::link('/index.php','menuaction=admin.uicurrentsessions.list_sessions');
|
||||
$file['View Sessions'] = egw::link('/index.php','menuaction=admin.admin_accesslog.sessions');
|
||||
}
|
||||
|
||||
if (! $GLOBALS['egw']->acl->check('access_log_access',1,'admin'))
|
||||
|
@ -1,71 +0,0 @@
|
||||
<?php
|
||||
/**************************************************************************\
|
||||
* eGroupWare - Administration *
|
||||
* http://www.egroupware.org *
|
||||
* This file written by Joseph Engo <jengo@phpgroupware.org> *
|
||||
* -------------------------------------------- *
|
||||
* This program is free software; you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU General Public License as published by the *
|
||||
* Free Software Foundation; either version 2 of the License, or (at your *
|
||||
* option) any later version. *
|
||||
\**************************************************************************/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
class bocurrentsessions
|
||||
{
|
||||
var $ui;
|
||||
var $so;
|
||||
var $public_functions = array(
|
||||
'kill' => True
|
||||
);
|
||||
|
||||
function total()
|
||||
{
|
||||
return $GLOBALS['egw']->session->session_count();
|
||||
}
|
||||
|
||||
function list_sessions($start,$order,$sort)
|
||||
{
|
||||
$values = $GLOBALS['egw']->session->session_list($start,$sort,$order);
|
||||
|
||||
while (list(,$value) = @each($values))
|
||||
{
|
||||
if (strpos($value['session_lid'],'@') !== false)
|
||||
{
|
||||
$t = explode('@',$value['session_lid']);
|
||||
$session_lid = $t[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
$session_lid = $value['session_lid'];
|
||||
}
|
||||
$tmp = time() - $value['session_dla'];
|
||||
$secs = $tmp % 60;
|
||||
$mins = (($tmp - $secs) % 3600) / 60;
|
||||
$hours = ($tmp - ($mins * 60) - $secs) / 3600;
|
||||
$_values[] = array(
|
||||
'session_id' => $value['session_id'],
|
||||
'session_lid' => $session_lid,
|
||||
'session_ip' => $value['session_ip'],
|
||||
'session_logintime' => $GLOBALS['egw']->common->show_date($value['session_logintime']),
|
||||
'session_action' => $value['session_action'],
|
||||
'session_dla' => $value['session_dla'],
|
||||
'session_idle' => str_pad($hours, 2, '0', STR_PAD_LEFT) . ':' . str_pad($mins, 2, '0', STR_PAD_LEFT) . ':' . str_pad($secs, 2, '0', STR_PAD_LEFT)
|
||||
);
|
||||
}
|
||||
return $_values;
|
||||
}
|
||||
|
||||
function kill()
|
||||
{
|
||||
if ($_GET['ksession'] &&
|
||||
($GLOBALS['sessionid'] != $_GET['ksession']) &&
|
||||
! $GLOBALS['egw']->acl->check('current_sessions_access',8,'admin'))
|
||||
{
|
||||
$GLOBALS['egw']->session->destroy($_GET['ksession'],0);
|
||||
}
|
||||
$this->ui =& CreateObject('admin.uicurrentsessions');
|
||||
$this->ui->list_sessions();
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
%1 log entries deleted. admin de %1 Protokolleinträge gelöscht.
|
||||
%1 not found or not executable !!! admin de %1 nicht gefunden oder nicht ausführbar !!!
|
||||
%1 rights for %2 and applications %3 admin de %1 Rechte für %2 und Anwendung(en) %3
|
||||
%1 sessions killed admin de %1 Sitzungen beendet
|
||||
%1 user %2 admin de %1 Benutzer %2
|
||||
(default no, leave it off if you dont use it) admin de (Vorgabe Nein, ausgeschaltet lassen, wenn nicht benutzt)
|
||||
(stored password will not be shown here) admin de (Gespeichertes Passwort wird hier nicht angezeigt)
|
||||
@ -25,8 +26,8 @@ account preferences admin de Einstellungen der Benutzerkonten
|
||||
account-id's have to be integers! admin de Konten-ID`s müssen vom Typ Integer (Zahl) sein!
|
||||
acl manager admin de ACL-Manager
|
||||
acl rights common de ACL-Rechte
|
||||
action admin de Aktion
|
||||
actions admin de Aktionen
|
||||
action admin de Befehl
|
||||
actions admin de Befehle
|
||||
activate wysiwyg-editor admin de WYSIWYG Editor (formatierter Text) aktivieren
|
||||
add a category admin de Eine Kategorie hinzufügen
|
||||
add a group admin de Eine Gruppe hinzufügen
|
||||
@ -147,6 +148,7 @@ delete peer server admin de Server von Serververbund löschen
|
||||
delete selected entries admin de Ausgewählte Einträge löschen
|
||||
delete the category admin de Kategorie löschen
|
||||
delete the group admin de Gruppe löschen
|
||||
delete the selected entries admin de Die ausgewählten Einträge löschen
|
||||
delete this category admin de Kategorie löschen
|
||||
delete this group admin de Gruppe löschen
|
||||
delete this log entry admin de Diesen Protokolleintrag löschen
|
||||
@ -305,6 +307,7 @@ kill admin de Beenden
|
||||
kill session admin de Sitzung beenden
|
||||
last %1 logins admin de Letze %1 Logins
|
||||
last %1 logins for %2 admin de Letze %1 Logins für %2
|
||||
last action admin de Letzte Aktion
|
||||
last login admin de Letzter Login
|
||||
last login from admin de Letzer Login von
|
||||
last submission: admin de Letzte Absendung:
|
||||
|
@ -7,6 +7,7 @@
|
||||
%1 log entries deleted. admin en %1 log entries deleted.
|
||||
%1 not found or not executable !!! admin en %1 not found or not executable !!!
|
||||
%1 rights for %2 and applications %3 admin en %1 rights for %2 and applications %3
|
||||
%1 sessions killed admin en %1 sessions killed
|
||||
%1 user %2 admin en %1 user %2
|
||||
(default no, leave it off if you dont use it) admin en (default No, leave it off if you dont use it)
|
||||
(stored password will not be shown here) admin en (Stored password will not be shown here)
|
||||
@ -149,6 +150,7 @@ delete peer server admin en Delete peer server
|
||||
delete selected entries admin en Delete selected entries
|
||||
delete the category admin en delete the category
|
||||
delete the group admin en delete the group
|
||||
delete the selected entries admin en Delete the selected entries
|
||||
delete this category admin en delete this category
|
||||
delete this group admin en delete this group
|
||||
delete this log entry admin en Delete this log entry
|
||||
@ -310,6 +312,7 @@ kill admin en Kill
|
||||
kill session admin en Kill session
|
||||
last %1 logins admin en Last %1 logins
|
||||
last %1 logins for %2 admin en Last %1 logins for %2
|
||||
last action admin en Last action
|
||||
last login admin en last login
|
||||
last login from admin en last login from
|
||||
last submission: admin en Last submission:
|
||||
|
75
admin/setup/etemplates.inc.php
Normal file
75
admin/setup/etemplates.inc.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - eTemplates for Application admin
|
||||
* http://www.egroupware.org
|
||||
* generated by soetemplate::dump4setup() 2011-04-13 15:34
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package admin
|
||||
* @subpackage setup
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
$templ_version=1;
|
||||
|
||||
$templ_data[] = array('name' => 'admin.accesslog','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:1:{s:2:"h1";s:6:",!@msg";}i:1;a:2:{s:1:"A";a:4:{s:4:"span";s:13:"all,redItalic";s:5:"align";s:6:"center";s:4:"name";s:3:"msg";s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:4:{s:4:"span";s:3:"all";s:4:"name";s:2:"nm";s:4:"size";s:20:"admin.accesslog.rows";s:4:"type";s:9:"nextmatch";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:3;a:2:{s:1:"A";a:4:{s:4:"size";s:6:"2,,0,0";s:4:"type";s:4:"hbox";i:1;a:3:{s:8:"readonly";s:4:"true";s:4:"type";s:5:"label";s:5:"label";s:32:"Percent of users that logged out";}i:2;a:6:{s:4:"type";s:5:"float";s:9:"precision";s:1:"1";s:5:"label";s:6:": %s %";s:8:"readonly";s:4:"true";s:4:"name";s:7:"percent";s:4:"size";s:1:",";}}s:1:"B";a:6:{s:5:"align";s:5:"right";s:4:"type";s:4:"hbox";i:1;a:6:{s:5:"label";s:6:"Delete";s:7:"onclick";s:46:"return confirm(\'Delete the selected entries\');";s:4:"name";s:6:"delete";s:4:"type";s:6:"button";s:4:"size";s:6:"delete";s:4:"help";s:23:"Delete selected entries";}i:2;a:5:{s:4:"type";s:6:"button";s:4:"size";s:5:"close";s:5:"label";s:4:"Kill";s:4:"name";s:4:"kill";s:7:"onclick";s:63:"return confirm(\'Are you sure you want to kill this session ?\');";}s:4:"size";s:1:"3";i:3;a:4:{s:4:"type";s:10:"buttononly";s:4:"size";s:9:"arrow_ltr";s:5:"label";s:10:"Select all";s:7:"onclick";s:61:"toggle_all(this.form,form::name(\'selected[]\')); return false;";}}}}s:4:"cols";i:2;s:4:"rows";i:3;s:4:"size";s:4:"100%";}}','size' => '100%','style' => '.selectAllArrow { padding-right: 12px; }','modified' => '1302686599',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.accesslog.get_rows','template' => '','lang' => '','group' => '0','version' => '1.3.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:2:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";}i:1;a:4:{s:1:"A";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:7:"LoginID";s:4:"name";s:7:"loginid";}s:1:"B";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:2:"IP";s:4:"name";s:2:"ip";}s:1:"C";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:9:"Logintime";s:4:"name";s:2:"li";}s:1:"D";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:9:"Logoutime";s:4:"name";s:2:"lo";}}i:2;a:4:{s:1:"A";a:3:{s:4:"type";s:14:"select-account";s:4:"name";s:15:"${row}[loginid]";s:8:"readonly";s:1:"1";}s:1:"B";a:3:{s:4:"type";s:5:"label";s:4:"name";s:10:"${row}[ip]";s:7:"no_lang";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[li]";s:8:"readonly";s:1:"1";}s:1:"D";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[lo]";s:8:"readonly";s:1:"1";}}}s:4:"rows";i:2;s:4:"cols";i:4;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1164479930',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.accesslog.rows','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:6:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";s:1:"G";s:10:",@no_total";s:1:"F";s:7:",@no_lo";s:1:"B";s:18:",@no_sessionstatus";s:1:"J";s:2:"1%";}i:1;a:10:{s:1:"A";a:3:{s:4:"type";s:23:"nextmatch-accountfilter";s:4:"size";s:7:"LoginID";s:4:"name";s:10:"account_id";}s:1:"B";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:12:"Login-Status";s:4:"name";s:13:"sessionstatus";}s:1:"C";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:7:"Loginid";s:4:"name";s:7:"loginid";}s:1:"D";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:2:"IP";s:4:"name";s:2:"ip";}s:1:"E";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:5:"Login";s:4:"name";s:2:"li";}s:1:"F";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:6:"Logout";s:4:"name";s:2:"lo";}s:1:"G";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:5:"Total";s:4:"name";s:5:"total";}s:1:"H";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:4:"Idle";s:4:"name";s:11:"session_dla";}s:1:"I";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:11:"Last action";s:4:"name";s:14:"session_action";}s:1:"J";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Actions";s:5:"align";s:6:"center";}i:2;a:4:{s:4:"type";s:10:"buttononly";s:4:"size";s:5:"check";s:5:"label";s:10:"Select all";s:7:"onclick";s:61:"toggle_all(this.form,form::name(\'selected[]\')); return false;";}}}i:2;a:10:{s:1:"A";a:4:{s:4:"type";s:14:"select-account";s:4:"name";s:18:"${row}[account_id]";s:8:"readonly";s:1:"1";s:5:"label";s:22:"$row_cont[alt_loginid]";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:4:"name";s:21:"${row}[sessionstatus]";}s:1:"C";a:2:{s:4:"type";s:5:"label";s:4:"name";s:15:"${row}[loginid]";}s:1:"D";a:2:{s:4:"type";s:5:"label";s:4:"name";s:10:"${row}[ip]";}s:1:"E";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[li]";s:8:"readonly";s:1:"1";}s:1:"F";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[lo]";s:8:"readonly";s:1:"1";}s:1:"G";a:4:{s:4:"type";s:13:"date-duration";s:4:"name";s:13:"${row}[total]";s:8:"readonly";s:1:"1";s:4:"size";s:6:",hm,24";}s:1:"H";a:3:{s:4:"type";s:10:"date-since";s:4:"name";s:19:"${row}[session_dla]";s:8:"readonly";s:1:"1";}s:1:"I";a:2:{s:4:"type";s:5:"label";s:4:"name";s:22:"${row}[session_action]";}s:1:"J";a:6:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"3,,0,0";i:1;a:6:{s:4:"type";s:6:"button";s:4:"size";s:6:"delete";s:5:"label";s:6:"Delete";s:4:"name";s:28:"delete[$row_cont[sessionid]]";s:4:"help";s:21:"Delete this log entry";s:7:"onclick";s:40:"return confirm(\'Delete this log entry\');";}i:2;a:5:{s:4:"type";s:6:"button";s:4:"size";s:5:"close";s:5:"label";s:4:"Kill";s:4:"name";s:26:"kill[$row_cont[sessionid]]";s:7:"onclick";s:63:"return confirm(\'Are you sure you want to kill this session ?\');";}s:5:"align";s:6:"center";i:3;a:4:{s:4:"type";s:8:"checkbox";s:4:"size";s:20:"$row_cont[sessionid]";s:4:"name";s:10:"selected[]";s:5:"align";s:5:"right";}}}}s:4:"rows";i:2;s:4:"cols";i:10;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1254816462',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.applications','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:4:{s:4:"type";s:9:"nextmatch";s:4:"size";s:4:"rows";s:4:"span";s:3:"all";s:4:"name";s:2:"nm";}}i:2;a:1:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:28:"Number applications serially";s:4:"name";s:6:"number";}i:2;a:2:{s:4:"type";s:5:"label";s:5:"label";s:157:"Number the applications serially. If they are not numbered serially, sorting the applications could work wrong. This will not change the application\'s order.";}}}}s:4:"rows";i:2;s:4:"cols";i:1;s:4:"size";s:7:"100%,,0";s:7:"options";a:2:{i:0;s:4:"100%";i:2;s:1:"0";}}}','size' => '100%,,0','style' => '','modified' => '1276610727',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.applications.rows','template' => '','lang' => '','group' => '0','version' => '1.7.002','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:7:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";s:1:"A";s:5:"1px,1";s:1:"E";s:4:"80px";s:1:"D";s:5:"120px";s:1:"F";s:2:"80";s:1:"B";s:5:"120px";}i:1;a:6:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"align";s:6:"center";}s:1:"C";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:4:"Name";s:4:"name";s:4:"name";}s:1:"D";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:7:"Version";s:4:"name";s:7:"version";}s:1:"E";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:5:"Order";s:4:"name";s:5:"order";}s:1:"F";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:7:"Actions";s:4:"name";s:7:"actions";}}i:2;a:6:{s:1:"A";a:3:{s:4:"type";s:5:"image";s:5:"align";s:6:"center";s:4:"name";s:14:"${row}[app_id]";}s:1:"B";a:3:{s:4:"type";s:5:"image";s:4:"name";s:13:"${row}[image]";s:5:"align";s:6:"center";}s:1:"C";a:2:{s:4:"type";s:5:"label";s:4:"name";s:16:"${row}[app_name]";}s:1:"D";a:3:{s:4:"type";s:5:"label";s:4:"name";s:19:"${row}[app_version]";s:8:"readonly";s:1:"1";}s:1:"E";a:4:{s:4:"type";s:5:"label";s:4:"name";s:17:"${row}[app_order]";s:7:"no_lang";s:1:"1";s:8:"readonly";s:1:"1";}s:1:"F";a:5:{s:4:"type";s:4:"hbox";s:8:"readonly";s:1:"1";s:4:"size";s:1:"2";i:1;a:4:{s:4:"type";s:6:"button";s:4:"size";s:3:"up2";s:5:"label";s:2:"up";s:4:"name";s:21:"up[$row_cont[app_id]]";}i:2;a:4:{s:4:"type";s:6:"button";s:4:"size";s:5:"down2";s:5:"label";s:4:"down";s:4:"name";s:23:"down[$row_cont[app_id]]";}}}}s:4:"rows";i:2;s:4:"cols";i:6;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1275405742',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.categories.delete','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:2:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:5:{s:4:"type";s:8:"groupbox";s:4:"size";s:1:"1";s:5:"label";s:20:"Delete this category";i:1;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:3:{s:2:"h3";s:2:"40";s:2:"h1";s:2:"30";s:2:"c2";s:11:"confirmSubs";}i:1;a:2:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:47:"Are you sure you want to delete this category ?";s:5:"align";s:6:"center";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:5:{s:4:"type";s:8:"checkbox";s:5:"label";s:53:"Do you also want to delete all global subcategories ?";s:4:"name";s:12:"delete[subs]";s:4:"span";s:3:"all";s:5:"align";s:6:"center";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:3;a:2:{s:1:"A";a:4:{s:4:"type";s:6:"button";s:5:"label";s:6:"Delete";s:4:"name";s:14:"delete[delete]";s:5:"align";s:6:"center";}s:1:"B";a:5:{s:4:"type";s:10:"buttononly";s:5:"label";s:6:"Cancel";s:4:"name";s:14:"delete[cancel]";s:5:"align";s:6:"center";s:7:"onclick";s:64:"set_style_by_class(\'fieldset\',\'confirmDelete\',\'display\',\'none\');";}}}s:4:"rows";i:3;s:4:"cols";i:2;s:7:"options";a:0:{}}s:4:"span";s:14:",confirmDelete";}}}s:4:"rows";i:1;s:4:"cols";i:1;}i:1;a:3:{s:4:"type";s:4:"text";s:4:"name";s:14:"delete[cat_id]";s:4:"span";s:12:",hiddenCatid";}}','size' => '','style' => '.confirmDelete {
|
||||
position: absolute;
|
||||
left: 120px;
|
||||
top: 80px;
|
||||
background-color: white;
|
||||
display: none;
|
||||
border: 2px solid black;
|
||||
}
|
||||
.hiddenCatid {
|
||||
display: none;
|
||||
}
|
||||
.confirmSubs
|
||||
{
|
||||
}','modified' => '1264754384',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.categories.edit','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:2:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:11:{i:0;a:12:{s:2:"c2";s:2:"th";s:2:"c3";s:3:"row";s:2:"c4";s:7:"row,top";s:2:"c5";s:3:"row";s:2:"c7";s:3:"row";s:2:"c6";s:3:"row";s:2:"h7";s:15:",@appname=phpgw";s:2:"h2";s:2:"25";s:2:"h1";s:6:",!@msg";s:2:"c9";s:3:"row";s:2:"c8";s:3:"row";s:2:"h9";s:11:",!@last_mod";}i:1;a:2:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:4:"span";s:13:"all,redItalic";s:5:"align";s:6:"center";s:4:"name";s:3:"msg";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:9:",,,parent";s:5:"label";s:15:"Parent category";}s:1:"B";a:3:{s:4:"type";s:10:"select-cat";s:4:"size";s:25:"None,,,$cont[appname],,-1";s:4:"name";s:6:"parent";}}i:3;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:7:",,,name";s:5:"label";s:4:"Name";}s:1:"B";a:3:{s:4:"type";s:4:"text";s:4:"size";s:6:"50,150";s:4:"name";s:4:"name";}}i:4;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:14:",,,description";s:5:"label";s:11:"Description";}s:1:"B";a:3:{s:4:"type";s:8:"textarea";s:4:"size";s:4:"5,50";s:4:"name";s:11:"description";}}i:5;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:18:",,,cat_data[color]";s:5:"label";s:5:"Color";}s:1:"B";a:2:{s:4:"type";s:11:"colorpicker";s:4:"name";s:11:"data[color]";}}i:6;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:13:",,,data[icon]";s:5:"label";s:4:"Icon";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:4:{s:4:"type";s:6:"select";s:4:"name";s:10:"data[icon]";s:4:"size";s:4:"None";s:8:"onchange";s:73:"document.getElementById(\'icon_url\').src = \'$cont[base_url]\' + this.value;";}i:2;a:3:{s:4:"type";s:5:"image";s:4:"name";s:8:"icon_url";s:4:"span";s:9:",leftPad5";}}}i:7;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:11:"Application";}s:1:"B";a:4:{s:4:"type";s:10:"select-app";s:4:"name";s:7:"appname";s:8:"readonly";s:1:"1";s:4:"size";s:16:"All applications";}}i:8;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:8:",,,owner";s:5:"label";s:19:"Limit to members of";}s:1:"B";a:4:{s:4:"type";s:14:"select-account";s:4:"size";s:16:"All users,groups";s:4:"name";s:5:"owner";s:4:"help";s:51:"Limit global category to members of a certain group";}}i:9;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:8:"Modified";}s:1:"B";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:8:"last_mod";s:8:"readonly";s:1:"1";}}i:10;a:2:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:4:"Save";s:4:"name";s:12:"button[save]";}i:2;a:3:{s:4:"type";s:6:"button";s:5:"label";s:5:"Apply";s:4:"name";s:13:"button[apply]";}}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:4:{s:4:"type";s:10:"buttononly";s:4:"name";s:14:"button[cancel]";s:5:"label";s:6:"Cancel";s:7:"onclick";s:15:"window.close();";}i:2;a:6:{s:4:"type";s:10:"buttononly";s:5:"label";s:6:"Delete";s:5:"align";s:5:"right";s:4:"name";s:14:"button[delete]";s:4:"help";s:20:"Delete this category";s:7:"onclick";s:157:"set_style_by_class(\'tr\',\'confirmSubs\',\'visibility\',\'$cont[children]\'?\'visible\':\'collapse\'); set_style_by_class(\'fieldset\',\'confirmDelete\',\'display\',\'block\');";}}}}s:4:"rows";i:10;s:4:"cols";i:2;}i:1;a:2:{s:4:"type";s:8:"template";s:4:"name";s:23:"admin.categories.delete";}}','size' => '','style' => '','modified' => '1264740967',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.categories.index','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:2:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:1:{s:2:"h1";s:6:",!@msg";}i:1;a:1:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:4:"name";s:3:"msg";s:5:"align";s:6:"center";s:4:"span";s:13:"all,redItalic";}}i:2;a:1:{s:1:"A";a:3:{s:4:"type";s:9:"nextmatch";s:4:"size";s:4:"rows";s:4:"name";s:2:"nm";}}i:3;a:1:{s:1:"A";a:4:{s:4:"type";s:10:"buttononly";s:5:"label";s:3:"Add";s:4:"name";s:3:"add";s:7:"onclick";s:193:"window.open(egw::link(\'/index.php\',\'menuaction=admin.admin_categories.edit&appname={$cont[nm][appname]}\'),\'_blank\',\'dependent=yes,width=600,height=300,scrollbars=yes,status=yes\'); return false;";}}}s:4:"rows";i:3;s:4:"cols";i:1;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}i:1;a:2:{s:4:"type";s:8:"template";s:4:"name";s:23:"admin.categories.delete";}}','size' => '100%','style' => '.level0 { font-weight: bold; }','modified' => '1264657515',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.categories.index.rows','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:6:{s:2:"c1";s:2:"th";s:2:"c2";s:13:"$row_cont[id]";s:1:"E";s:2:"40";s:1:"H";s:2:"30";s:1:"I";s:2:"1%";s:1:"F";s:2:"80";}i:1;a:9:{s:1:"A";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:4:"Name";s:4:"name";s:4:"name";}s:1:"B";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:11:"Description";s:4:"name";s:11:"description";}s:1:"C";a:3:{s:4:"type";s:16:"nextmatch-header";s:4:"name";s:3:"app";s:5:"label";s:11:"Application";}s:1:"D";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:19:"Limit to members of";s:4:"name";s:5:"owner";}s:1:"E";a:4:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:4:"Icon";s:4:"name";s:4:"icon";s:5:"align";s:6:"center";}s:1:"F";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:5:"Color";s:4:"name";s:5:"color";}s:1:"G";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:8:"Modified";s:4:"name";s:8:"last_mod";}s:1:"H";a:4:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:8:"Children";s:4:"name";s:4:"subs";s:5:"align";s:6:"center";}s:1:"I";a:2:{s:4:"type";s:5:"label";s:5:"label";s:7:"Actions";}}i:2;a:9:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:2:{s:4:"type";s:4:"html";s:4:"name";s:20:"${row}[level_spacer]";}i:2;a:3:{s:4:"type";s:5:"label";s:4:"name";s:12:"${row}[name]";s:4:"span";s:17:",$row_cont[class]";}}s:1:"B";a:2:{s:4:"type";s:5:"label";s:4:"name";s:19:"${row}[description]";}s:1:"C";a:3:{s:4:"type";s:10:"select-app";s:4:"name";s:15:"${row}[appname]";s:8:"readonly";s:1:"1";}s:1:"D";a:4:{s:4:"type";s:14:"select-account";s:4:"name";s:13:"${row}[owner]";s:8:"readonly";s:1:"1";s:4:"size";s:16:"All users,groups";}s:1:"E";a:4:{s:4:"type";s:5:"image";s:4:"name";s:16:"${row}[icon_url]";s:5:"label";s:23:"{$row_cont[data][icon]}";s:5:"align";s:6:"center";}s:1:"F";a:2:{s:4:"type";s:5:"label";s:4:"name";s:19:"${row}[data][color]";}s:1:"G";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:16:"${row}[last_mod]";s:8:"readonly";s:1:"1";}s:1:"H";a:3:{s:4:"type";s:5:"label";s:4:"name";s:12:"${row}[subs]";s:5:"align";s:6:"center";}s:1:"I";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"3,,0,0";i:1;a:5:{s:4:"type";s:10:"buttononly";s:4:"size";s:4:"edit";s:5:"label";s:4:"Edit";s:4:"name";s:19:"edit[$row_cont[id]]";s:7:"onclick";s:185:"window.open(egw::link(\'/index.php\',\'menuaction=admin.admin_categories.edit&cat_id=$row_cont[id]\'),\'_blank\',\'dependent=yes,width=600,height=380,scrollbars=yes,status=yes\'); return false;";}i:2;a:5:{s:4:"type";s:10:"buttononly";s:4:"size";s:3:"new";s:5:"label";s:7:"Add sub";s:4:"name";s:18:"add[$row_cont[id]]";s:7:"onclick";s:208:"window.open(egw::link(\'/index.php\',\'menuaction=admin.admin_categories.edit&parent=$row_cont[id]&appname=$cont[appname]\'),\'_blank\',\'dependent=yes,width=600,height=380,scrollbars=yes,status=yes\'); return false;";}i:3;a:7:{s:4:"type";s:10:"buttononly";s:4:"size";s:6:"delete";s:5:"label";s:6:"Delete";s:4:"name";s:21:"delete[$row_cont[id]]";s:4:"help";s:20:"Delete this category";s:7:"onclick";s:246:"document.getElementById(\'exec[delete][cat_id]\').value=\'$row_cont[id]\'; set_style_by_class(\'tr\',\'confirmSubs\',\'visibility\',\'$row_cont[children]\'?\'visible\':\'collapse\'); set_style_by_class(\'fieldset\',\'confirmDelete\',\'display\',\'block\'); return false;";s:4:"span";s:9:",leftPad5";}}}}s:4:"rows";i:2;s:4:"cols";i:9;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1264657599',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.cmds','template' => '','lang' => '','group' => '0','version' => '1.5.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:9:"nextmatch";s:4:"size";s:15:"admin.cmds.rows";s:4:"name";s:2:"nm";}}}s:4:"rows";i:1;s:4:"cols";i:1;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1195518120',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.cmds.rows','template' => '','lang' => '','group' => '0','version' => '1.5.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:3:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";s:2:"h2";s:4:",!@1";}i:1;a:10:{s:1:"A";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:5:"Title";s:4:"name";s:5:"title";}s:1:"B";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:9:"Requested";s:4:"name";s:9:"requested";}s:1:"C";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:9:"Scheduled";s:4:"name";s:13:"cmd_scheduled";}s:1:"D";a:3:{s:4:"type";s:22:"nextmatch-filterheader";s:4:"size";s:6:"Remote";s:4:"name";s:9:"remote_id";}s:1:"E";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:7:"Created";s:4:"name";s:11:"cmd_created";}s:1:"F";a:3:{s:4:"type";s:23:"nextmatch-accountfilter";s:4:"name";s:7:"creator";s:4:"size";s:7:"Creator";}s:1:"G";a:3:{s:4:"type";s:22:"nextmatch-filterheader";s:4:"name";s:6:"status";s:4:"size";s:6:"Status";}s:1:"H";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:8:"Modified";s:4:"name";s:12:"cmd_modified";}s:1:"I";a:3:{s:4:"type";s:23:"nextmatch-accountfilter";s:4:"size";s:8:"Modifier";s:4:"name";s:8:"modifier";}s:1:"J";a:1:{s:4:"type";s:5:"label";}}i:2;a:10:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:4:"name";s:13:"${row}[title]";}s:1:"B";a:4:{s:4:"type";s:9:"url-email";s:4:"name";s:17:"${row}[requested]";s:4:"size";s:29:",,,$row_cont[requested_email]";s:8:"readonly";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:17:"${row}[scheduled]";s:8:"readonly";s:1:"1";}s:1:"D";a:3:{s:4:"type";s:6:"select";s:4:"name";s:17:"${row}[remote_id]";s:8:"readonly";s:1:"1";}s:1:"E";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:15:"${row}[created]";s:8:"readonly";s:1:"1";}s:1:"F";a:4:{s:4:"type";s:9:"url-email";s:4:"name";s:15:"${row}[creator]";s:4:"size";s:27:",,,$row_cont[creator_email]";s:8:"readonly";s:1:"1";}s:1:"G";a:4:{s:4:"type";s:4:"vbox";s:4:"size";s:6:"2,,0,0";i:1;a:3:{s:4:"type";s:6:"select";s:4:"name";s:14:"${row}[status]";s:8:"readonly";s:1:"1";}i:2;a:3:{s:4:"type";s:5:"label";s:4:"name";s:13:"${row}[error]";s:4:"span";s:10:",redItalic";}}s:1:"H";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:16:"${row}[modified]";s:8:"readonly";s:1:"1";}s:1:"I";a:4:{s:4:"type";s:9:"url-email";s:4:"name";s:16:"${row}[modifier]";s:8:"readonly";s:1:"1";s:4:"size";s:28:",,,$row_cont[modifier_email]";}s:1:"J";a:6:{s:4:"type";s:6:"button";s:4:"size";s:6:"delete";s:5:"label";s:6:"Cancel";s:4:"name";s:21:"delete[$row_cont[id]]";s:4:"help";s:29:"Cancel this scheduled command";s:7:"onclick";s:48:"return confirm(\'Cancel this scheduled command\');";}}}s:4:"rows";i:2;s:4:"cols";i:10;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1195518170',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.customfields','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:6:{i:0;a:1:{s:1:"G";s:3:"80%";}i:1;a:7:{s:1:"A";a:5:{s:4:"type";s:5:"label";s:4:"span";s:13:"all,redItalic";s:4:"name";s:9:"error_msg";s:5:"align";s:6:"center";s:7:"no_lang";s:1:"1";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}s:1:"E";a:1:{s:4:"type";s:5:"label";}s:1:"F";a:1:{s:4:"type";s:5:"label";}s:1:"G";a:2:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";}}i:2;a:7:{s:1:"A";a:4:{s:4:"type";s:8:"template";s:4:"size";s:13:"content_types";s:4:"span";s:3:"all";s:4:"name";s:24:"admin.customfields.types";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}s:1:"E";a:1:{s:4:"type";s:5:"label";}s:1:"F";a:1:{s:4:"type";s:5:"label";}s:1:"G";a:1:{s:4:"type";s:5:"label";}}i:3;a:7:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}s:1:"E";a:1:{s:4:"type";s:5:"label";}s:1:"F";a:1:{s:4:"type";s:5:"label";}s:1:"G";a:1:{s:4:"type";s:5:"label";}}i:4;a:7:{s:1:"A";a:4:{s:4:"type";s:8:"template";s:4:"size";s:6:"fields";s:4:"span";s:3:"all";s:4:"name";s:25:"admin.customfields.fields";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}s:1:"E";a:1:{s:4:"type";s:5:"label";}s:1:"F";a:1:{s:4:"type";s:5:"label";}s:1:"G";a:1:{s:4:"type";s:5:"label";}}i:5;a:7:{s:1:"A";a:6:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";s:4:"span";s:3:"all";i:1;a:4:{s:4:"type";s:6:"button";s:5:"label";s:4:"Save";s:4:"name";s:12:"button[save]";s:4:"help";s:33:"saves the changes made and leaves";}i:2;a:4:{s:4:"type";s:6:"button";s:5:"label";s:5:"Apply";s:4:"name";s:13:"button[apply]";s:4:"help";s:19:"applies the changes";}i:3;a:4:{s:4:"type";s:6:"button";s:5:"label";s:6:"Cancel";s:4:"name";s:14:"button[cancel]";s:4:"help";s:22:"leaves without saveing";}}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}s:1:"E";a:1:{s:4:"type";s:5:"label";}s:1:"F";a:1:{s:4:"type";s:5:"label";}s:1:"G";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:5;s:4:"cols";i:7;}}','size' => '','style' => '.redItalic { color: red; font-style: italics; }','modified' => '1295986974',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.customfields.fields','template' => '','lang' => '','group' => '0','version' => '1.5.001','data' => 'a:1:{i:0;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:4:{s:2:"c1";s:2:"th";s:2:"c2";s:7:"row,top";s:1:"C";s:8:",!@type2";s:1:"E";s:14:",!@use_private";}i:1;a:9:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:4:"Name";s:4:"help";s:83:"the name used internaly (<= 20 chars), changeing it makes existing data unavailible";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Label";}s:1:"C";a:2:{s:4:"type";s:5:"label";s:5:"label";s:7:"Subtype";}s:1:"D";a:2:{s:4:"type";s:5:"label";s:5:"label";s:4:"Type";}s:1:"E";a:2:{s:4:"type";s:5:"label";s:5:"label";s:7:"Private";}s:1:"F";a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Options";s:4:"help";s:40:"each value is a line like <id>[=<label>]";}s:1:"G";a:2:{s:4:"type";s:5:"label";s:5:"label";s:14:"Length<br>Rows";}s:1:"H";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Order";}s:1:"I";a:4:{s:4:"type";s:5:"label";s:5:"label";s:6:"Action";s:5:"align";s:6:"center";s:4:"help";s:18:"deletes this field";}}i:2;a:9:{s:1:"A";a:4:{s:4:"type";s:4:"text";s:4:"size";s:5:"20,32";s:4:"name";s:12:"${row}[name]";s:4:"help";s:83:"the name used internaly (<= 20 chars), changeing it makes existing data unavailible";}s:1:"B";a:4:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";i:1;a:4:{s:4:"type";s:4:"text";s:4:"size";s:4:",255";s:4:"name";s:13:"${row}[label]";s:4:"help";s:30:"the text displayed to the user";}i:2;a:2:{s:4:"type";s:5:"label";s:4:"name";s:13:"${row}[label]";}}s:1:"C";a:4:{s:4:"type";s:6:"select";s:4:"size";s:3:"All";s:4:"name";s:13:"${row}[type2]";s:7:"no_lang";s:1:"1";}s:1:"D";a:3:{s:4:"type";s:18:"customfields-types";s:4:"name";s:12:"{$row}[type]";s:4:"help";s:19:"Type of customfield";}s:1:"E";a:5:{s:4:"type";s:14:"select-account";s:4:"name";s:15:"${row}[private]";s:4:"help";s:60:"Select accounts for which the custom field should be visible";s:5:"align";s:6:"center";s:4:"size";s:6:"3,both";}s:1:"F";a:4:{s:4:"type";s:8:"textarea";s:4:"size";s:4:"2,30";s:4:"name";s:14:"${row}[values]";s:4:"help";s:36:"each value is a line like id[=label]";}s:1:"G";a:4:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";i:1;a:4:{s:4:"type";s:4:"text";s:4:"size";s:1:"5";s:4:"name";s:11:"${row}[len]";s:4:"help";s:63:"max length of the input [, length of the inputfield (optional)]";}i:2;a:5:{s:4:"type";s:3:"int";s:4:"size";s:6:"0,10,2";s:4:"name";s:12:"${row}[rows]";s:4:"help";s:70:"number of row for a multiline inputfield or line of a multi-select-box";s:4:"blur";s:1:"1";}}s:1:"H";a:4:{s:4:"type";s:3:"int";s:4:"size";s:4:"1,,3";s:4:"name";s:13:"${row}[order]";s:4:"help";s:45:"determines the order the fields are displayed";}s:1:"I";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:4:{s:4:"type";s:6:"button";s:5:"label";s:6:"Delete";s:4:"name";s:23:"delete[$row_cont[name]]";s:4:"help";s:18:"deletes this field";}i:2;a:4:{s:4:"type";s:6:"button";s:5:"label";s:6:"Create";s:4:"name";s:21:"create$row_cont[name]";s:4:"help";s:19:"creates a new field";}}}}s:4:"rows";i:2;s:4:"cols";i:9;s:7:"options";a:0:{}}}','size' => '','style' => '','modified' => '1131454776',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.customfields.types','template' => '','lang' => '','group' => '0','version' => '1.2','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:4:{s:1:"D";s:15:",@non_deletable";s:1:"E";s:8:",@no_add";s:1:"F";s:8:",@no_add";s:2:"h1";s:15:",@no_edit_types";}i:1;a:6:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:4:"name";s:8:"app-name";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:7:"- type";}s:1:"C";a:4:{s:4:"type";s:6:"select";s:4:"name";s:5:"types";s:8:"onchange";s:1:"1";s:7:"no_lang";s:1:"1";}s:1:"D";a:4:{s:4:"type";s:6:"button";s:5:"label";s:6:"Delete";s:4:"name";s:6:"delete";s:7:"onclick";s:110:"return confirm(\'WARNING: You are about to delete this type. Entries of this type won\\\'t be accessable then.\');";}s:1:"E";a:3:{s:4:"type";s:4:"text";s:4:"name";s:4:"name";s:4:"blur";s:8:"new name";}s:1:"F";a:3:{s:4:"type";s:6:"button";s:5:"label";s:6:"Create";s:4:"name";s:6:"create";}}}s:4:"rows";i:1;s:4:"cols";i:6;}}','size' => '','style' => '','modified' => '1139823458',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.export_users_csv_selectors','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:4:{s:4:"type";s:14:"select-account";s:4:"size";s:10:"All,groups";s:5:"label";s:5:"Group";s:4:"name";s:8:"group_id";}}}s:4:"rows";i:1;s:4:"cols";i:1;s:4:"name";s:9:"selection";s:7:"options";a:0:{}}}','size' => '','style' => '','modified' => '1302620448',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.passwordreset','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:7:{i:0;a:2:{s:2:"h1";s:6:",!@msg";s:2:"c5";s:4:",top";}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:13:"all,redItalic";s:4:"name";s:3:"msg";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:12:"Select users";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:3;a:2:{s:1:"A";a:3:{s:4:"type";s:14:"select-account";s:4:"size";s:2:"15";s:4:"name";s:5:"users";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:4;a:2:{s:1:"A";a:8:{s:4:"type";s:8:"groupbox";s:4:"size";s:1:"5";s:5:"label";s:7:"Actions";i:1;a:3:{s:4:"type";s:8:"checkbox";s:5:"label";s:21:"Set a random password";s:4:"name";s:9:"random_pw";}i:2;a:5:{s:4:"type";s:11:"select-bool";s:4:"size";s:15:"Leave unchanged";s:5:"label";s:36:"Must change password upon next login";s:4:"name";s:18:"mustchangepassword";s:8:"onchange";s:85:"if (this.value==\'1\') document.getElementById(form::name(\'changepassword\')).value=\'1\';";}i:3;a:5:{s:4:"type";s:11:"select-bool";s:4:"size";s:15:"Leave unchanged";s:5:"label";s:19:"Can change password";s:4:"name";s:14:"changepassword";s:8:"onchange";s:136:"var mustchange=document.getElementById(form::name(\'mustchangepassword\')); if (this.value==\'0\' && mustchange.value) mustchange.value=\'0\';";}i:4;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:4:{s:4:"type";s:6:"select";s:4:"size";s:15:"Leave unchanged";s:4:"name";s:4:"hash";s:5:"label";s:23:"Change password hash to";}i:2;a:5:{s:4:"type";s:4:"text";s:5:"label";s:12:"Current hash";s:4:"name";s:12:"current_hash";s:4:"span";s:14:",leftPad5 gray";s:8:"readonly";s:1:"1";}}i:5;a:3:{s:4:"type";s:8:"checkbox";s:5:"label";s:20:"Notify user by email";s:4:"name";s:6:"notify";}}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:5;a:2:{s:1:"A";a:5:{s:4:"type";s:8:"groupbox";s:4:"size";s:1:"2";s:5:"label";s:17:"Notification mail";i:1;a:4:{s:4:"type";s:4:"text";s:4:"size";s:2:"64";s:4:"name";s:7:"subject";s:4:"blur";s:7:"Subject";}i:2;a:3:{s:4:"type";s:8:"textarea";s:4:"size";s:5:"15,64";s:4:"name";s:4:"body";}}s:1:"B";a:4:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:5:"label";s:4:"span";s:5:",gray";s:5:"label";s:22:"Available placeholders";}i:2;a:6:{s:4:"type";s:4:"grid";s:4:"span";s:5:",gray";s:4:"name";s:12:"replacements";s:4:"data";a:2:{i:0;a:0:{}i:1;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:4:"name";s:12:"${row}[name]";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:4:"name";s:13:"${row}[label]";}}}s:4:"rows";i:1;s:4:"cols";i:2;}}}i:6;a:2:{s:1:"A";a:3:{s:4:"type";s:6:"button";s:5:"label";s:5:"Start";s:4:"name";s:5:"start";}s:1:"B";a:3:{s:4:"type";s:6:"button";s:5:"label";s:12:"Download CSV";s:4:"name";s:12:"download_csv";}}}s:4:"rows";i:6;s:4:"cols";i:2;}}','size' => '','style' => '','modified' => '1301655701',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.remotes','template' => '','lang' => '','group' => '0','version' => '1.5.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:5:{i:0;a:3:{s:2:"h2";s:9:",!@remote";s:2:"h1";s:6:",!@msg";s:2:"h3";s:2:",1";}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:13:"all,redItalic";s:4:"name";s:3:"msg";}}i:2;a:1:{s:1:"A";a:4:{s:4:"type";s:8:"template";s:4:"size";s:6:"remote";s:4:"span";s:10:"all,border";s:4:"name";s:18:"admin.remotes.edit";}}i:3;a:1:{s:1:"A";a:3:{s:4:"type";s:8:"template";s:5:"align";s:5:"right";s:4:"name";s:26:"admin.remotes.header_right";}}i:4;a:1:{s:1:"A";a:3:{s:4:"type";s:9:"nextmatch";s:4:"name";s:2:"nm";s:4:"size";s:18:"admin.remotes.rows";}}}s:4:"rows";i:4;s:4:"cols";i:1;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '.border { border: black solid 2px; }','modified' => '1195926693',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.remotes.edit','template' => '','lang' => '','group' => '0','version' => '1.5.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:9:{i:0;a:8:{s:2:"c2";s:2:"th";s:2:"c3";s:3:"row";s:2:"c5";s:3:"row";s:2:"c6";s:3:"row";s:2:"c4";s:3:"row";s:2:"c7";s:3:"row";s:2:"h5";s:14:",!@remote_hash";s:2:"h1";s:11:",@remote_id";}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:13:"all,redItalic";s:5:"label";s:97:"Remote administration need to be enabled in the remote instance under Admin > Site configuration!";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:4:"size";s:14:",,,remote_name";s:5:"label";s:4:"Name";s:6:"needed";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:4:"size";s:5:"64,64";s:4:"name";s:11:"remote_name";s:6:"needed";s:1:"1";}}i:3;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:13:",,,install_id";s:5:"label";s:10:"Install ID";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:4:"size";s:24:"40,32,/^[a-f0-9]{0,32}$/";s:4:"name";s:10:"install_id";s:4:"help";s:75:"The install ID of an instance can be found under Admin > Site configuration";}}i:4;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:16:",,,config_passwd";s:5:"label";s:8:"Password";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:4:"size";s:5:"40,32";s:4:"name";s:13:"config_passwd";s:4:"help";s:51:"Config password or md5 hash from the header.inc.php";}}i:5;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:4:"Hash";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:4:"name";s:11:"remote_hash";}}i:6;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:13:",,,remote_url";s:5:"label";s:3:"URL";}s:1:"B";a:5:{s:4:"type";s:4:"text";s:4:"size";s:62:"64,128,/^https?:\\/\\/[a-z0-9._-]+(\\:[0-9]+)?(\\/[a-z0-9._-]+)*$/";s:4:"name";s:10:"remote_url";s:6:"needed";s:1:"1";s:4:"help";s:68:"URL of the eGroupWare installation, eg. http://domain.com/egroupware";}}i:7;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:16:",,,remote_domain";s:5:"label";s:8:"Instance";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:4:"size";s:5:"64,64";s:4:"name";s:13:"remote_domain";s:4:"help";s:44:"Name of the eGroupWare instance, eg. default";}}i:8;a:2:{s:1:"A";a:6:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";i:1;a:4:{s:4:"type";s:6:"button";s:5:"label";s:4:"Save";s:4:"name";s:12:"button[save]";s:4:"help";s:16:"Saves this entry";}s:4:"span";s:3:"all";i:2;a:4:{s:4:"type";s:6:"button";s:4:"name";s:13:"button[apply]";s:5:"label";s:5:"Apply";s:4:"help";s:17:"Apply the changes";}i:3;a:4:{s:4:"type";s:6:"button";s:5:"label";s:6:"Cancel";s:4:"name";s:14:"button[cancel]";s:4:"help";s:31:"leave without saveing the entry";}}s:1:"B";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:8;s:4:"cols";i:2;}}','size' => '','style' => '','modified' => '1195927476',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.remotes.header_right','template' => '','lang' => '','group' => '0','version' => '1.5.001','data' => 'a:1:{i:0;a:7:{s:4:"type";s:6:"button";s:4:"data";a:2:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:1;s:4:"cols";i:1;s:4:"name";s:3:"add";s:5:"label";s:3:"Add";s:4:"help";s:25:"Add a new remote instance";}}','size' => '','style' => '','modified' => '1195931282',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.remotes.rows','template' => '','lang' => '','group' => '0','version' => '1.5.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:2:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";}i:1;a:4:{s:1:"A";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:4:"Name";s:4:"name";s:11:"remote_name";}s:1:"B";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:3:"URL";s:4:"name";s:10:"remote_url";}s:1:"C";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:8:"Instance";s:4:"name";s:13:"remote_domain";}s:1:"D";a:2:{s:4:"type";s:5:"label";s:5:"label";s:7:"Actions";}}i:2;a:4:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:4:"name";s:19:"${row}[remote_name]";}s:1:"B";a:3:{s:4:"type";s:5:"label";s:4:"size";s:64:",$row_cont[remote_url]/?domain=$row_cont[remote_domain],,,_blank";s:4:"name";s:18:"${row}[remote_url]";}s:1:"C";a:3:{s:4:"type";s:5:"label";s:4:"name";s:21:"${row}[remote_domain]";s:7:"no_lang";s:1:"1";}s:1:"D";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"1";i:1;a:5:{s:4:"type";s:6:"button";s:4:"size";s:4:"edit";s:5:"label";s:4:"Edit";s:4:"name";s:26:"edit[$row_cont[remote_id]]";i:1;a:1:{s:4:"type";s:4:"hbox";}}s:5:"align";s:6:"center";}}}s:4:"rows";i:2;s:4:"cols";i:4;}}','size' => '','style' => '','modified' => '1195925625',);
|
||||
|
||||
$templ_data[] = array('name' => 'admin.statistics','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:2:{i:0;a:9:{s:4:"type";s:8:"groupbox";s:4:"size";s:1:"5";s:4:"span";s:10:"all,bigger";s:5:"label";s:35:"Official EGroupware usage statistic";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:131:"We ask for the data to improve our profile in the press and to get a better understanding of EGroupware\'s user base and it\'s needs.";}i:2;a:4:{s:4:"type";s:4:"html";s:5:"label";s:63:"The cumulated and anonymised data will be publically available:";i:1;a:2:{s:4:"type";s:4:"vbox";s:5:"label";s:44:"The statistics will be publically available:";}s:4:"name";s:13:"statistic_url";}i:3;a:3:{s:4:"type";s:5:"label";s:5:"label";s:91:"We hope you understand the importance for this voluntary statistic and not deny it lightly.";s:4:"span";s:5:",bold";}i:4;a:3:{s:4:"type";s:5:"label";s:5:"label";s:61:"Only below displayed information is directly submitted to %s.";s:4:"name";s:11:"submit_host";}i:5;a:4:{s:4:"type";s:4:"text";s:5:"label";s:104:"To allow us to track the growth of your individual installation use this submit ID, otherwise delete it:";s:4:"name";s:9:"submit_id";s:4:"size";s:5:"40,40";}}i:1;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:14:{i:0;a:4:{s:1:"A";s:3:"140";s:3:"c10";s:4:",top";s:3:"h11";s:17:",!@last_submitted";s:3:"h12";s:6:",!@msg";}i:1;a:2:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:10:",,,country";s:5:"label";s:7:"Country";}s:1:"B";a:3:{s:4:"type";s:14:"select-country";s:4:"name";s:7:"country";s:4:"size";s:17:"International use";}}i:3;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:5:"Usage";s:4:"size";s:13:",,,usage_type";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:10:"usage_type";}}i:4;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:15:"Number of users";s:4:"size";s:8:",,,users";}s:1:"B";a:5:{s:4:"type";s:4:"text";s:4:"name";s:5:"users";s:4:"help";s:22:"number of active users";s:4:"size";s:2:"-8";s:8:"readonly";s:1:"1";}}i:5;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:11:",,,sessions";s:5:"label";s:21:"Sessions last 30 days";}s:1:"B";a:5:{s:4:"type";s:4:"text";s:4:"name";s:8:"sessions";s:4:"help";s:58:"Number of sessions / EGroupware logins in the last 30 days";s:4:"size";s:2:"-8";s:8:"readonly";s:1:"1";}}i:6;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:18:"EGroupware Version";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:4:"name";s:7:"version";s:4:"size";s:2:"-8";s:8:"readonly";s:1:"1";}}i:7;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:16:"Operating System";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:4:"name";s:2:"os";s:4:"size";s:3:"-40";s:8:"readonly";s:1:"1";}}i:8;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:6:",,,php";s:5:"label";s:11:"PHP Version";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:4:"name";s:3:"php";s:4:"size";s:3:"-20";s:8:"readonly";s:1:"1";}}i:9;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Installation Type";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:12:"install_type";}}i:10;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:12:"Applications";}s:1:"B";a:4:{s:4:"type";s:8:"textarea";s:4:"size";s:5:"10,40";s:4:"name";s:4:"apps";s:4:"help";s:80:"Installed applications, percentage of allowed users and total number of entries.";}}i:11;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:16:"Last submission:";}s:1:"B";a:3:{s:4:"type";s:9:"date-time";s:8:"readonly";s:1:"1";s:4:"name";s:14:"last_submitted";}}i:12;a:2:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:4:"span";s:13:"all,redItalic";s:5:"align";s:6:"center";s:4:"name";s:3:"msg";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:13;a:2:{s:1:"A";a:5:{s:4:"type";s:6:"button";s:5:"label";s:6:"Submit";s:4:"help";s:24:"Submit to egroupware.org";s:7:"onclick";s:14:"$cont[onclick]";s:4:"name";s:6:"submit";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:4:{s:4:"type";s:6:"select";s:4:"name";s:8:"postpone";s:4:"size";s:12:"Postpone for";s:8:"onchange";i:1;}i:2;a:5:{s:4:"type";s:6:"button";s:4:"name";s:6:"cancel";s:5:"label";s:6:"Cancel";s:4:"help";s:84:"Go directly to admin menu, returning here the next time you click on administration.";s:5:"align";s:5:"right";}}}}s:4:"rows";i:13;s:4:"cols";i:2;}}','size' => '','style' => '.bold { font-weight: bold; }
|
||||
fieldset.bigger legend {
|
||||
font-weight: bold;
|
||||
font-size: 125%;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}','modified' => '1257091720',);
|
||||
|
86
admin/templates/default/accesslog.xet
Normal file
86
admin/templates/default/accesslog.xet
Normal file
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- $Id$ -->
|
||||
<overlay>
|
||||
<template id="admin.accesslog.rows" template="" lang="" group="0" version="1.9.001">
|
||||
<grid width="100%">
|
||||
<columns>
|
||||
<column/>
|
||||
<column disabled="@no_sessionstatus"/>
|
||||
<column/>
|
||||
<column/>
|
||||
<column/>
|
||||
<column disabled="@no_lo"/>
|
||||
<column disabled="@no_total"/>
|
||||
<column/>
|
||||
<column/>
|
||||
<column width="1%"/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row class="th">
|
||||
<nextmatch-accountfilter options="LoginID" id="account_id"/>
|
||||
<nextmatch-header label="Login-Status" id="sessionstatus"/>
|
||||
<nextmatch-header label="Loginid" id="loginid"/>
|
||||
<nextmatch-header label="IP" id="ip"/>
|
||||
<nextmatch-sortheader label="Login" id="li"/>
|
||||
<nextmatch-sortheader label="Logout" id="lo"/>
|
||||
<nextmatch-header label="Total" id="total"/>
|
||||
<nextmatch-sortheader label="Idle" id="session_dla"/>
|
||||
<nextmatch-header label="Last action" id="session_action"/>
|
||||
<hbox>
|
||||
<description value="Actions" align="center"/>
|
||||
<buttononly options="check" label="Select all" onclick="toggle_all(this.form,form::name('selected[]')); return false;"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row class="row">
|
||||
<menulist>
|
||||
<menupopup type="select-account" id="${row}[account_id]" readonly="true" label="$row_cont[alt_loginid]"/>
|
||||
</menulist>
|
||||
<description id="${row}[sessionstatus]"/>
|
||||
<description id="${row}[loginid]"/>
|
||||
<description id="${row}[ip]"/>
|
||||
<date-time id="${row}[li]" readonly="true"/>
|
||||
<date-time id="${row}[lo]" readonly="true"/>
|
||||
<date-duration id="${row}[total]" readonly="true" options=",hm,24"/>
|
||||
<date-since id="${row}[session_dla]" readonly="true"/>
|
||||
<description id="${row}[session_action]"/>
|
||||
<hbox options="0,0" align="center">
|
||||
<button image="delete" label="Delete" id="delete[$row_cont[sessionid]]" statustext="Delete this log entry" onclick="return confirm('Delete this log entry');"/>
|
||||
<button image="close" label="Kill" id="kill[$row_cont[sessionid]]" onclick="return confirm('Are you sure you want to kill this session ?');"/>
|
||||
<checkbox options="$row_cont[sessionid]" id="selected[]" align="right"/>
|
||||
</hbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</template>
|
||||
<template id="admin.accesslog" template="" lang="" group="0" version="1.9.001">
|
||||
<grid width="100%">
|
||||
<columns>
|
||||
<column/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row disabled="!@msg">
|
||||
<description span="all" class="redItalic" align="center" id="msg"/>
|
||||
<description/>
|
||||
</row>
|
||||
<row>
|
||||
<nextmatch span="all" id="nm" options="admin.accesslog.rows"/>
|
||||
</row>
|
||||
<row>
|
||||
<hbox options="0,0">
|
||||
<description readonly="true" value="Percent of users that logged out"/>
|
||||
<textbox type="float" precision="1" label=": %s %" readonly="true" id="percent"/>
|
||||
</hbox>
|
||||
<hbox align="right">
|
||||
<button label="Delete" onclick="return confirm('Delete the selected entries');" id="delete" image="delete" statustext="Delete selected entries"/>
|
||||
<button image="close" label="Kill" id="kill" onclick="return confirm('Are you sure you want to kill this session ?');"/>
|
||||
<buttononly options="arrow_ltr" label="Select all" onclick="toggle_all(this.form,form::name('selected[]')); return false;"/>
|
||||
</hbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<styles>
|
||||
.selectAllArrow { padding-right: 12px; }
|
||||
</styles>
|
||||
</template>
|
||||
</overlay>
|
@ -1,12 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Calendar's buisness-object - access only
|
||||
* EGroupware - Calendar's buisness-object - access only
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) 2004-9 by RalfBecker-At-outdoor-training.de
|
||||
* @copyright (c) 2004-11 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -67,7 +67,7 @@ class calendar_bo
|
||||
var $debug=false;
|
||||
|
||||
/**
|
||||
* @var int $now servertime
|
||||
* @var int $now timestamp in server-time
|
||||
*/
|
||||
var $now;
|
||||
|
||||
@ -142,7 +142,7 @@ class calendar_bo
|
||||
'NON-PARTICIPANT' => 'None',
|
||||
);
|
||||
/**
|
||||
* @var array $resources registered scheduling resources of the calendar (gets chached in the session for performance reasons)
|
||||
* @var array $resources registered scheduling resources of the calendar (gets cached in the session for performance reasons)
|
||||
*/
|
||||
var $resources;
|
||||
/**
|
||||
@ -155,6 +155,10 @@ class calendar_bo
|
||||
* @var array $cached_holidays holidays plus birthdays (gets cached in the session for performance reasons)
|
||||
*/
|
||||
var $cached_holidays;
|
||||
/**
|
||||
* @var boholiday
|
||||
*/
|
||||
var $holidays;
|
||||
/**
|
||||
* Instance of the socal class
|
||||
*
|
||||
@ -181,12 +185,25 @@ class calendar_bo
|
||||
*/
|
||||
public $require_acl_invite = false;
|
||||
|
||||
/**
|
||||
* if the number of selected users for a view exeeds this number a view is consolidated (5 is set as default)
|
||||
* @var int
|
||||
*/
|
||||
public $calview_no_consolidate = 5;
|
||||
|
||||
/**
|
||||
* Warnings to show in regular UI
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $warnings = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
if ($this->debug > 0) $this->debug_message('bocal::bocal() started',True,$param);
|
||||
if ($this->debug > 0) $this->debug_message('calendar_bo::bocal() started',True,$param);
|
||||
|
||||
$this->so = new calendar_so();
|
||||
$this->datetime = $GLOBALS['egw']->datetime;
|
||||
@ -195,7 +212,7 @@ class calendar_bo
|
||||
$this->cal_prefs =& $GLOBALS['egw_info']['user']['preferences']['calendar'];
|
||||
|
||||
$this->now = time();
|
||||
$this->now_su = egw_time::to('now','ts');
|
||||
$this->now_su = egw_time::server2user($this->now,'ts');
|
||||
|
||||
$this->user = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
@ -220,12 +237,16 @@ class calendar_bo
|
||||
'info' => __CLASS__.'::email_info',
|
||||
'app' => 'email',
|
||||
);
|
||||
$this->resources[''] = array(
|
||||
'type' => '',
|
||||
'app' => 'home-accounts',
|
||||
);
|
||||
$GLOBALS['egw']->session->appsession('resources','calendar',$this->resources);
|
||||
}
|
||||
//echo "registered resources="; _debug_array($this->resources);
|
||||
|
||||
$this->config = config::read('calendar'); // only used for horizont, regular calendar config is under phpgwapi
|
||||
|
||||
$this->calview_no_consolidate = ($GLOBALS['egw_info']['server']['calview_no_consolidate']?$GLOBALS['egw_info']['server']['calview_no_consolidate']:5);
|
||||
$this->require_acl_invite = $GLOBALS['egw_info']['server']['require_acl_invite'];
|
||||
|
||||
$this->categories = new categories($this->user,'calendar');
|
||||
@ -242,7 +263,7 @@ class calendar_bo
|
||||
if (!$ids) return null;
|
||||
|
||||
$data = array();
|
||||
foreach(!is_array($ids) ? array($ids) : $ids as $id)
|
||||
foreach((array)$ids as $id)
|
||||
{
|
||||
$email = $id;
|
||||
$name = '';
|
||||
@ -258,7 +279,7 @@ class calendar_bo
|
||||
'name' => $name,
|
||||
);
|
||||
}
|
||||
//echo "<p>email_info(".print_r($ids,true).")="; _debug_array($data);
|
||||
//error_log(__METHOD__.'('.array2string($ids).')='.array2string($data).' '.function_backtrace());
|
||||
return $data;
|
||||
}
|
||||
|
||||
@ -386,6 +407,7 @@ class calendar_bo
|
||||
* cols string|array columns to select, if set an iterator will be returned
|
||||
* append string to append to the query, eg. GROUP BY
|
||||
* cfs array if set, query given custom fields or all for empty array, none are returned, if not set (default)
|
||||
* master_only boolean default false, true only take into account participants/status from master (for AS)
|
||||
* @param string $sql_filter=null sql to be and'ed into query (fully quoted), default none
|
||||
* @return iterator|array|boolean array of events or array with YYYYMMDD strings / array of events pairs (depending on $daywise param)
|
||||
* or false if there are no read-grants from _any_ of the requested users or iterator/recordset if cols are given
|
||||
@ -444,18 +466,25 @@ class calendar_bo
|
||||
$this->check_move_horizont($end);
|
||||
}
|
||||
$daywise = !isset($params['daywise']) ? False : !!$params['daywise'];
|
||||
$enum_recuring = $daywise || !isset($params['enum_recuring']) || !!$params['enum_recuring'];
|
||||
$params['enum_recuring'] = $enum_recuring = $daywise || !isset($params['enum_recuring']) || !!$params['enum_recuring'];
|
||||
$cat_id = isset($params['cat_id']) ? $params['cat_id'] : 0;
|
||||
$filter = isset($params['filter']) ? $params['filter'] : 'all';
|
||||
$offset = isset($params['offset']) && $params['offset'] !== false ? (int) $params['offset'] : false;
|
||||
// socal::search() returns rejected group-invitations, as only the user not also the group is rejected
|
||||
// as we cant remove them efficiantly in SQL, we kick them out here, but only if just one user is displayed
|
||||
$users_in = (array)$params_in['users'];
|
||||
$remove_rejected_by_user = !in_array($filter,array('all','rejected')) &&
|
||||
count($users_in) == 1 && $users_in[0] > 0 ? $users_in[0] : null;
|
||||
//error_log(__METHOD__.'('.array2string($params_in).", $sql_filter) params[users]=".array2string($params['users']).' --> remove_rejected_by_user='.array2string($remove_rejected_by_user));
|
||||
|
||||
if ($this->debug && ($this->debug > 1 || $this->debug == 'search'))
|
||||
{
|
||||
$this->debug_message('bocal::search(%1) start=%2, end=%3, daywise=%4, cat_id=%5, filter=%6, query=%7, offset=%8, num_rows=%9, order=%10, sql_filter=%11)',
|
||||
$this->debug_message('calendar_bo::search(%1) start=%2, end=%3, daywise=%4, cat_id=%5, filter=%6, query=%7, offset=%8, num_rows=%9, order=%10, sql_filter=%11)',
|
||||
True,$params,$start,$end,$daywise,$cat_id,$filter,$params['query'],$offset,(int)$params['num_rows'],$params['order'],$params['sql_filter']);
|
||||
}
|
||||
// date2ts(,true) converts to server time, db2data converts again to user-time
|
||||
$events =& $this->so->search(isset($start) ? $this->date2ts($start,true) : null,isset($end) ? $this->date2ts($end,true) : null,
|
||||
$users,$cat_id,$filter,$params['query'],$offset,(int)$params['num_rows'],$params['order'],$params['sql_filter'],$params['cols'],$params['append'],$params['cfs']);
|
||||
$users,$cat_id,$filter,$offset,(int)$params['num_rows'],$params,$remove_rejected_by_user);
|
||||
|
||||
if (isset($params['cols']))
|
||||
{
|
||||
@ -464,29 +493,22 @@ class calendar_bo
|
||||
$this->total = $this->so->total;
|
||||
$this->db2data($events,isset($params['date_format']) ? $params['date_format'] : 'ts');
|
||||
|
||||
// socal::search() returns rejected group-invitations, as only the user not also the group is rejected
|
||||
// as we cant remove them efficiantly in SQL, we kick them out here, but only if just one user is displayed
|
||||
$remove_rejected_by_user = !in_array($filter,array('all','rejected','owner')) && count($params['users']) == 1 ? $params['users'][0] : false;
|
||||
//echo "<p align=right>remove_rejected_by_user=$remove_rejected_by_user, filter=$filter, params[users]=".print_r($param['users'])."</p>\n";
|
||||
foreach($events as $id => $event)
|
||||
{
|
||||
if (isset($start) && $event['end'] < $start)
|
||||
{
|
||||
unset($events[$id]); // remove former events (e.g. whole day)
|
||||
$this->total--;
|
||||
continue;
|
||||
}
|
||||
if ($remove_rejected_by_user && $event['participants'][$remove_rejected_by_user] == 'R')
|
||||
{
|
||||
unset($events[$id]); // remove the rejected event
|
||||
$this->total--;
|
||||
continue;
|
||||
}
|
||||
if ($params['enum_groups'] && $this->enum_groups($event))
|
||||
{
|
||||
$events[$id] = $event;
|
||||
}
|
||||
if (!$this->check_perms(EGW_ACL_READ,$event) || (!$event['public'] && $filter == 'hideprivate'))
|
||||
if (!(int)$event['id'] && preg_match('/^([a-z_]+)([0-9]+)$/',$event['id'],$matches))
|
||||
{
|
||||
$is_private = self::integration_get_private($matches[1],$matches[2],$event);
|
||||
}
|
||||
else
|
||||
{
|
||||
$is_private = !$this->check_perms(EGW_ACL_READ,$event);
|
||||
}
|
||||
if ($is_private || (!$event['public'] && $filter == 'hideprivate'))
|
||||
{
|
||||
$this->clear_private_infos($events[$id],$users);
|
||||
}
|
||||
@ -529,29 +551,11 @@ class calendar_bo
|
||||
$this->debug_message('socalendar::search daywise events=%1',False,$events);
|
||||
}
|
||||
}
|
||||
elseif(!$enum_recuring)
|
||||
{
|
||||
$recur_ids = array();
|
||||
foreach($events as $k => $event)
|
||||
{
|
||||
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
if (!in_array($event['id'],$recur_ids))
|
||||
{
|
||||
$recur_ids[] = $event['id'];
|
||||
}
|
||||
unset($events[$k]);
|
||||
}
|
||||
}
|
||||
if (count($recur_ids))
|
||||
{
|
||||
$events = array_merge($this->read($recur_ids,null,false,$params['date_format']),$events);
|
||||
}
|
||||
}
|
||||
if ($this->debug && ($this->debug > 0 || $this->debug == 'search'))
|
||||
{
|
||||
$this->debug_message('bocal::search(%1)=%2',True,$params,$events);
|
||||
$this->debug_message('calendar_bo::search(%1)=%2',True,$params,$events);
|
||||
}
|
||||
//error_log(__METHOD__."() returning ".count($events)." entries, total=$this->total ".function_backtrace());
|
||||
return $events;
|
||||
}
|
||||
|
||||
@ -618,6 +622,8 @@ class calendar_bo
|
||||
*/
|
||||
function clear_private_infos(&$event,$allowed_participants = array())
|
||||
{
|
||||
if (!is_array($event['participants'])) error_log(__METHOD__.'('.array2string($event).', '.array2string($allowed_participants).') NO PARTICIPANTS '.function_backtrace());
|
||||
|
||||
$event = array(
|
||||
'id' => $event['id'],
|
||||
'start' => $event['start'],
|
||||
@ -646,18 +652,24 @@ class calendar_bo
|
||||
{
|
||||
if ((int) $this->debug >= 2 || $this->debug == 'check_move_horizont')
|
||||
{
|
||||
$this->debug_message('bocal::check_move_horizont(%1) horizont=%2',true,$new_horizont,$this->config['horizont']);
|
||||
$this->debug_message('calendar_bo::check_move_horizont(%1) horizont=%2',true,$new_horizont,(int)$this->config['horizont']);
|
||||
}
|
||||
$new_horizont = $this->date2ts($new_horizont,true); // now we are in server-time, where this function operates
|
||||
|
||||
if ($new_horizont > time()+1000*DAY_s) // some user tries to "look" more then 1000 days in the future
|
||||
{
|
||||
if ($this->debug == 'check_move_horizont') $this->debug_message('bocal::check_move_horizont(%1) horizont=%2 new horizont more then 1000 days from now --> ignoring it',true,$new_horizont,$this->config['horizont']);
|
||||
return;
|
||||
}
|
||||
if ($new_horizont <= $this->config['horizont']) // no move necessary
|
||||
{
|
||||
if ($this->debug == 'check_move_horizont') $this->debug_message('bocal::check_move_horizont(%1) horizont=%2 is bigger ==> nothing to do',true,$new_horizont,$this->config['horizont']);
|
||||
if ($this->debug == 'check_move_horizont') $this->debug_message('calendar_bo::check_move_horizont(%1) horizont=%2 is bigger ==> nothing to do',true,$new_horizont,(int)$this->config['horizont']);
|
||||
return;
|
||||
}
|
||||
if (!empty($GLOBALS['egw_info']['server']['calendar_horizont']))
|
||||
{
|
||||
$maxdays = abs($GLOBALS['egw_info']['server']['calendar_horizont']);
|
||||
}
|
||||
if (empty($maxdays)) $maxdays = 1000; // old default
|
||||
if ($new_horizont > time()+$maxdays*DAY_s) // some user tries to "look" more then the maximum number of days in the future
|
||||
{
|
||||
if ($this->debug == 'check_move_horizont') $this->debug_message('calendar_bo::check_move_horizont(%1) horizont=%2 new horizont more then %3 days from now --> ignoring it',true,$new_horizont,(int)$this->config['horizont'],$maxdays);
|
||||
$this->warnings['horizont'] = lang('Requested date %1 outside allowed range of %2 days: recurring events obmitted!', egw_time::to($new_horizont,true), $maxdays);
|
||||
return;
|
||||
}
|
||||
if ($new_horizont < time()+31*DAY_s)
|
||||
@ -670,21 +682,21 @@ class calendar_bo
|
||||
// create further recurrences for all recurring and not yet (at the old horizont) ended events
|
||||
if (($recuring = $this->so->unfinished_recuring($old_horizont)))
|
||||
{
|
||||
@set_time_limit(0); // disable time-limit, in case it takes longer to calculate the recurrences
|
||||
foreach($this->read(array_keys($recuring)) as $cal_id => $event)
|
||||
{
|
||||
if ($this->debug == 'check_move_horizont')
|
||||
{
|
||||
$this->debug_message('bocal::check_move_horizont(%1): calling set_recurrences(%2,%3)',true,$new_horizont,$event,$old_horizont);
|
||||
$this->debug_message('calendar_bo::check_move_horizont(%1): calling set_recurrences(%2,%3)',true,$new_horizont,$event,$old_horizont);
|
||||
}
|
||||
// insert everything behind max(cal_start), which can be less then $old_horizont because of bugs in the past
|
||||
$this->set_recurrences($event,egw_time::server2user($recuring[$cal_id]+1)); // set_recurences operates in user-time!
|
||||
}
|
||||
}
|
||||
// update the horizont
|
||||
$config = CreateObject('phpgwapi.config','calendar');
|
||||
$config->save_value('horizont',$this->config['horizont'],'calendar');
|
||||
config::save_value('horizont',$this->config['horizont'],'calendar');
|
||||
|
||||
if ($this->debug == 'check_move_horizont') $this->debug_message('bocal::check_move_horizont(%1) new horizont=%2, exiting',true,$new_horizont,$this->config['horizont']);
|
||||
if ($this->debug == 'check_move_horizont') $this->debug_message('calendar_bo::check_move_horizont(%1) new horizont=%2, exiting',true,$new_horizont,(int)$this->config['horizont']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -699,7 +711,7 @@ class calendar_bo
|
||||
{
|
||||
if ($this->debug && ((int) $this->debug >= 2 || $this->debug == 'set_recurrences' || $this->debug == 'check_move_horizont'))
|
||||
{
|
||||
$this->debug_message('bocal::set_recurrences(%1,%2)',true,$event,$start);
|
||||
$this->debug_message('calendar_bo::set_recurrences(%1,%2)',true,$event,$start);
|
||||
}
|
||||
// check if the caller gave us enough information and if not read it from the DB
|
||||
if (!isset($event['participants']) || !isset($event['start']) || !isset($event['end']))
|
||||
@ -725,13 +737,24 @@ class calendar_bo
|
||||
//error_log('set_recurrences: days=' . array2string($days) );
|
||||
foreach($events as $event)
|
||||
{
|
||||
$start_servertime = $this->date2ts($event['start'],true);
|
||||
if (in_array($start_servertime, (array)$days))
|
||||
$start = $this->date2ts($event['start'],true);
|
||||
if (in_array($start, (array)$days))
|
||||
{
|
||||
// we don't change the stati of recurrence exceptions
|
||||
$event['participants'] = array();
|
||||
}
|
||||
$this->so->recurrence($event['id'],$start_servertime,$this->date2ts($event['end'],true),$event['participants']);
|
||||
if ($event['whole_day'])
|
||||
{
|
||||
$time = new egw_time($event['end'], egw_time::$user_timezone);
|
||||
$time =& $this->so->startOfDay($time);
|
||||
$time->setTime(23, 59, 59);
|
||||
$end = $this->date2ts($time,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$end = $this->date2ts($event['end'],true);
|
||||
}
|
||||
$this->so->recurrence($event['id'],$start,$end,$event['participants']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -746,11 +769,11 @@ class calendar_bo
|
||||
*/
|
||||
function db2data(&$events,$date_format='ts')
|
||||
{
|
||||
if (!is_array($events)) echo "<p>bocal::db2data(\$events,$date_format) \$events is no array<br />\n".function_backtrace()."</p>\n";
|
||||
if (!is_array($events)) echo "<p>calendar_bo::db2data(\$events,$date_format) \$events is no array<br />\n".function_backtrace()."</p>\n";
|
||||
foreach ($events as &$event)
|
||||
{
|
||||
// convert timezone id of event to tzid (iCal id like 'Europe/Berlin')
|
||||
if (!$event['tz_id'] || !($event['tzid'] = calendar_timezones::id2tz($event['tz_id'])))
|
||||
if (empty($event['tzid']) && (!$event['tz_id'] || !($event['tzid'] = calendar_timezones::id2tz($event['tz_id']))))
|
||||
{
|
||||
$event['tzid'] = egw_time::$server_timezone->getName();
|
||||
}
|
||||
@ -759,7 +782,7 @@ class calendar_bo
|
||||
// (this will fail on 32bit systems for times > 2038!)
|
||||
$event['start'] = (int)$event['start']; // this is for isWholeDay(), which also calls egw_time
|
||||
$event['end'] = (int)$event['end'];
|
||||
$event['whole_day'] = $this->isWholeDay($event);
|
||||
$event['whole_day'] = self::isWholeDay($event);
|
||||
if ($event['whole_day'] && $date_format != 'server')
|
||||
{
|
||||
// Adjust dates to user TZ
|
||||
@ -783,11 +806,11 @@ class calendar_bo
|
||||
$time->setTime(23, 59, 59);
|
||||
$event['recur_enddate'] = egw_time::to($time, $date_format);
|
||||
}
|
||||
$timestamps = array('modified','created');
|
||||
$timestamps = array('modified','created','max_user_modified');
|
||||
}
|
||||
else
|
||||
{
|
||||
$timestamps = array('start','end','modified','created','recur_enddate','recurrence');
|
||||
$timestamps = array('start','end','modified','created','recur_enddate','recurrence','max_user_modified');
|
||||
}
|
||||
// we convert here from the server-time timestamps to user-time and (optional) to a different date-format!
|
||||
foreach ($timestamps as $ts)
|
||||
@ -847,15 +870,20 @@ class calendar_bo
|
||||
* @param mixed $date=null date to specify a single event of a series
|
||||
* @param boolean $ignore_acl should we ignore the acl, default False for a single id, true for multiple id's
|
||||
* @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in servertime, 'array'=array, or string with date-format
|
||||
* @param array|int $clear_privat_infos_users=null if not null, return events with EGW_ACL_FREEBUSY too,
|
||||
* but call clear_private_infos() with the given users
|
||||
* @return boolean|array event or array of id => event pairs, false if the acl-check went wrong, null if $ids not found
|
||||
*/
|
||||
function read($ids,$date=null,$ignore_acl=False,$date_format='ts')
|
||||
function read($ids,$date=null,$ignore_acl=False,$date_format='ts',$clear_private_infos_users=null)
|
||||
{
|
||||
if (!$ids) return false;
|
||||
|
||||
if ($date) $date = $this->date2ts($date);
|
||||
|
||||
$return = null;
|
||||
|
||||
if ($ignore_acl || is_array($ids) || ($return = $this->check_perms(EGW_ACL_READ,$ids,0,$date_format,$date)))
|
||||
$check = $clear_private_infos_users ? EGW_ACL_FREEBUSY : EGW_ACL_READ;
|
||||
if ($ignore_acl || is_array($ids) || ($return = $this->check_perms($check,$ids,0,$date_format,$date)))
|
||||
{
|
||||
if (is_array($ids) || !isset(self::$cached_event['id']) || self::$cached_event['id'] != $ids ||
|
||||
self::$cached_event_date_format != $date_format ||
|
||||
@ -876,7 +904,7 @@ class calendar_bo
|
||||
self::$cached_event = array_shift($events);
|
||||
self::$cached_event_date_format = $date_format;
|
||||
self::$cached_event_date = $date;
|
||||
$return =& self::$cached_event;
|
||||
$return = self::$cached_event;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -885,9 +913,13 @@ class calendar_bo
|
||||
$return = self::$cached_event;
|
||||
}
|
||||
}
|
||||
if ($clear_private_infos_users && !is_array($ids) && !$this->check_perms(EGW_ACL_READ,$return))
|
||||
{
|
||||
$this->clear_private_infos($return, (array)$clear_private_infos_users);
|
||||
}
|
||||
if ($this->debug && ($this->debug > 1 || $this->debug == 'read'))
|
||||
{
|
||||
$this->debug_message('bocal::read(%1,%2,%3,%4)=%5',True,$ids,$date,$ignore_acl,$date_format,$return);
|
||||
$this->debug_message('calendar_bo::read(%1,%2,%3,%4,%5)=%6',True,$ids,$date,$ignore_acl,$date_format,$clear_private_infos_users,$return);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
@ -921,10 +953,11 @@ class calendar_bo
|
||||
if (!$event['recur_enddate'] || $this->date2ts($event['recur_enddate']) > $this->date2ts($end))
|
||||
{
|
||||
//echo "<p>recur_enddate={$event['recur_enddate']}=".egw_time::to($event['recur_enddate'])." > end=$end=".egw_time::to($end)." --> using end instead of recur_enddate</p>\n";
|
||||
$event['recur_enddate'] = $end;
|
||||
// insert at least the event itself, if it's behind the horizont
|
||||
$event['recur_enddate'] = $this->date2ts($end) < $this->date2ts($event['end']) ? $event['end'] : $end;
|
||||
}
|
||||
// loop over all recurrences and insert them, if they are after $start
|
||||
$rrule = calendar_rrule::event2rrule($event,true); // true = we operate in usertime, like the rest of calendar_bo
|
||||
$rrule = calendar_rrule::event2rrule($event, true); // true = we operate in usertime, like the rest of calendar_bo
|
||||
foreach($rrule as $time)
|
||||
{
|
||||
$time->setUser(); // $time is in timezone of event, convert it to usertime used here
|
||||
@ -993,7 +1026,7 @@ class calendar_bo
|
||||
|
||||
if ($this->debug && ($this->debug > 2 || $this->debug == 'add_adjust_event'))
|
||||
{
|
||||
$this->debug_message('bocal::add_adjust_event(,%1,%2) as %3',True,$event_in,$date_ymd,$event);
|
||||
$this->debug_message('calendar_bo::add_adjust_event(,%1,%2) as %3',True,$event_in,$date_ymd,$event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1009,6 +1042,8 @@ class calendar_bo
|
||||
{
|
||||
static $res_info_cache = array();
|
||||
|
||||
if (!is_scalar($uid)) throw new egw_exception_wrong_parameter(__METHOD__.'('.array2string($uid).') parameter must be scalar');
|
||||
|
||||
if (!isset($res_info_cache[$uid]))
|
||||
{
|
||||
if (is_numeric($uid))
|
||||
@ -1019,6 +1054,7 @@ class calendar_bo
|
||||
'name' => trim($GLOBALS['egw']->accounts->id2name($uid,'account_firstname'). ' ' .
|
||||
$GLOBALS['egw']->accounts->id2name($uid,'account_lastname')),
|
||||
'type' => $GLOBALS['egw']->accounts->get_type($uid),
|
||||
'app' => 'accounts',
|
||||
);
|
||||
}
|
||||
else
|
||||
@ -1031,13 +1067,14 @@ class calendar_bo
|
||||
{
|
||||
$info['email'] = $GLOBALS['egw']->accounts->id2name($info['responsible'],'account_email');
|
||||
}
|
||||
$info['app'] = $this->resources[$uid[0]]['app'];
|
||||
}
|
||||
}
|
||||
$res_info_cache[$uid] = $info;
|
||||
}
|
||||
if ($this->debug && ($this->debug > 2 || $this->debug == 'resource_info'))
|
||||
{
|
||||
$this->debug_message('bocal::resource_info(%1) = %2',True,$uid,$res_info_cache[$uid]);
|
||||
$this->debug_message('calendar_bo::resource_info(%1) = %2',True,$uid,$res_info_cache[$uid]);
|
||||
}
|
||||
return $res_info_cache[$uid];
|
||||
}
|
||||
@ -1055,10 +1092,21 @@ class calendar_bo
|
||||
* @param int $other uid to check (if event==0) or 0 to check against $this->user
|
||||
* @param string $date_format='ts' date-format used for reading: 'ts'=timestamp, 'array'=array, 'string'=iso8601 string for xmlrpc
|
||||
* @param mixed $date_to_read=null date used for reading, internal param for the caching
|
||||
* @param int $user=null for which user to check, default current user
|
||||
* @return boolean true permission granted, false for permission denied or null if event not found
|
||||
*/
|
||||
function check_perms($needed,$event=0,$other=0,$date_format='ts',$date_to_read=null)
|
||||
function check_perms($needed,$event=0,$other=0,$date_format='ts',$date_to_read=null,$user=null)
|
||||
{
|
||||
if (!$user) $user = $this->user;
|
||||
if ($user == $this->user)
|
||||
{
|
||||
$grants = $this->grants;
|
||||
}
|
||||
else
|
||||
{
|
||||
$grants = $GLOBALS['egw']->acl->get_grants('calendar',true,$user);
|
||||
}
|
||||
|
||||
$event_in = $event;
|
||||
if ($other && !is_numeric($other))
|
||||
{
|
||||
@ -1067,7 +1115,7 @@ class calendar_bo
|
||||
}
|
||||
if (is_int($event) && $event == 0)
|
||||
{
|
||||
$owner = $other ? $other : $this->user;
|
||||
$owner = $other ? $other : $user;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1086,10 +1134,10 @@ class calendar_bo
|
||||
$owner = $event['owner'];
|
||||
$private = !$event['public'];
|
||||
}
|
||||
$grants = $this->grants[$owner];
|
||||
$grant = $grants[$owner];
|
||||
|
||||
// now any ACL rights (but invite rights!) implicate FREEBUSY rights (at least READ has to include FREEBUSY)
|
||||
if ($grants & ~EGW_ACL_INVITE) $grants |= EGW_ACL_FREEBUSY;
|
||||
if ($grant & ~EGW_ACL_INVITE) $grant |= EGW_ACL_FREEBUSY;
|
||||
|
||||
if (is_array($event) && ($needed == EGW_ACL_READ || $needed == EGW_ACL_FREEBUSY))
|
||||
{
|
||||
@ -1100,25 +1148,25 @@ class calendar_bo
|
||||
{
|
||||
foreach($event['participants'] as $uid => $accept)
|
||||
{
|
||||
if ($uid == $this->user || $uid < 0 && in_array($this->user,$GLOBALS['egw']->accounts->members($uid,true)))
|
||||
if ($uid == $user || $uid < 0 && in_array($user,$GLOBALS['egw']->accounts->members($uid,true)))
|
||||
{
|
||||
// if we are a participant, we have an implicite FREEBUSY, READ and PRIVAT grant
|
||||
$grants |= EGW_ACL_FREEBUSY | EGW_ACL_READ | EGW_ACL_PRIVATE;
|
||||
$grant |= EGW_ACL_FREEBUSY | EGW_ACL_READ | EGW_ACL_PRIVATE;
|
||||
break;
|
||||
}
|
||||
elseif ($this->grants[$uid] & EGW_ACL_READ)
|
||||
elseif ($grants[$uid] & EGW_ACL_READ)
|
||||
{
|
||||
// if we have a READ grant from a participant, we dont give an implicit privat grant too
|
||||
$grants |= EGW_ACL_READ;
|
||||
$grant |= EGW_ACL_READ;
|
||||
// we cant break here, as we might be a participant too, and would miss the privat grant
|
||||
}
|
||||
elseif (!is_numeric($uid))
|
||||
{
|
||||
// if the owner only grants EGW_ACL_BUSY we are not interested in the recources explicit rights
|
||||
if ($grants == EGW_ACL_FREEBUSY) break;
|
||||
// if the owner only grants EGW_ACL_FREEBUSY we are not interested in the recources explicit rights
|
||||
if ($grant == EGW_ACL_FREEBUSY) break;
|
||||
// if we have a resource as participant
|
||||
$resource = $this->resource_info($uid);
|
||||
$grants |= $resource['rights'];
|
||||
$grant |= $resource['rights'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1129,14 +1177,21 @@ class calendar_bo
|
||||
}
|
||||
else
|
||||
{
|
||||
$access = $this->user == $owner || $grants & $needed
|
||||
&& ($needed == EGW_ACL_FREEBUSY || !$private || $grants & EGW_ACL_PRIVATE);
|
||||
$access = $user == $owner || $grant & $needed
|
||||
&& ($needed == EGW_ACL_FREEBUSY || !$private || $grant & EGW_ACL_PRIVATE);
|
||||
}
|
||||
// do NOT allow users to purge deleted events, if we dont have 'user_purge' enabled
|
||||
if ($access && $needed == EGW_ACL_DELETE && $event['deleted'] &&
|
||||
!$GLOBALS['egw_info']['user']['apps']['admin'] && $user != $this->user &&
|
||||
$GLOBALS['egw_info']['server']['calendar_delete_history'] != 'user_purge')
|
||||
{
|
||||
$access = false;
|
||||
}
|
||||
if ($this->debug && ($this->debug > 2 || $this->debug == 'check_perms'))
|
||||
{
|
||||
$this->debug_message('bocal::check_perms(%1,%2,%3)=%4',True,ACL_TYPE_IDENTIFER.$needed,$event,$other,$access);
|
||||
$this->debug_message('calendar_bo::check_perms(%1,%2,other=%3,%4,%5,user=%6)=%7',True,ACL_TYPE_IDENTIFER.$needed,$event,$other,$date_format,$date_to_read,$user,$access);
|
||||
}
|
||||
//error_log(__METHOD__."($needed,".array2string($event).",$other) returning ".array2string($access));
|
||||
//error_log(__METHOD__."($needed,".array2string($event).",$other,...,$user) returning ".array2string($access));
|
||||
return $access;
|
||||
}
|
||||
|
||||
@ -1266,7 +1321,9 @@ class calendar_bo
|
||||
}
|
||||
$msg = str_replace('%'.($i-1),$param,$msg);
|
||||
}
|
||||
echo '<p>'.$msg."<br>\n".($backtrace ? 'Backtrace: '.function_backtrace(1)."</p>\n" : '').str_repeat(' ',4096);
|
||||
//echo '<p>'.$msg."<br>\n".($backtrace ? 'Backtrace: '.function_backtrace(1)."</p>\n" : '').str_repeat(' ',4096);
|
||||
error_log($msg);
|
||||
if ($backtrace) error_log(function_backtrace(1));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1377,11 +1434,11 @@ class calendar_bo
|
||||
if ($end_m == 24*60-1) ++$duration;
|
||||
$duration = floor($duration/60).lang('h').($duration%60 ? $duration%60 : '');
|
||||
|
||||
$timespan = $t = $GLOBALS['egw']->common->formattime(sprintf('%02d',$start_m/60),sprintf('%02d',$start_m%60));
|
||||
$timespan = $t = common::formattime(sprintf('%02d',$start_m/60),sprintf('%02d',$start_m%60));
|
||||
|
||||
if ($both) // end-time too
|
||||
{
|
||||
$timespan .= ' - '.$GLOBALS['egw']->common->formattime(sprintf('%02d',$end_m/60),sprintf('%02d',$end_m%60));
|
||||
$timespan .= ' - '.common::formattime(sprintf('%02d',$end_m/60),sprintf('%02d',$end_m%60));
|
||||
// dont double am/pm if they are the same in both times
|
||||
if ($this->common_prefs['timeformat'] == 12 && substr($timespan,-2) == substr($t,-2))
|
||||
{
|
||||
@ -1396,12 +1453,14 @@ class calendar_bo
|
||||
* Converts a participant into a (readable) user- or resource-name
|
||||
*
|
||||
* @param string|int $id id of user or resource
|
||||
* @param string|boolean type-letter or false
|
||||
* @param string|boolean $use_type=false type-letter or false
|
||||
* @param boolean $append_email=false append email (Name <email>)
|
||||
* @return string with name
|
||||
*/
|
||||
function participant_name($id,$use_type=false)
|
||||
function participant_name($id,$use_type=false, $append_email=false)
|
||||
{
|
||||
static $id2lid = array();
|
||||
static $id2email = array();
|
||||
|
||||
if ($use_type && $use_type != 'u') $id = $use_type.$id;
|
||||
|
||||
@ -1413,14 +1472,16 @@ class calendar_bo
|
||||
if (($info = $this->resource_info($id)))
|
||||
{
|
||||
$id2lid[$id] = $info['name'] ? $info['name'] : $info['email'];
|
||||
if ($info['name']) $id2email[$id] = $info['email'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$id2lid[$id] = common::grab_owner_name($id);
|
||||
$id2email[$id] = $GLOBALS['egw']->accounts->id2name($id,'account_email');
|
||||
}
|
||||
}
|
||||
return $id2lid[$id];
|
||||
return $id2lid[$id].($append_email && $id2email[$id] ? ' <'.$id2email[$id].'>' : '');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1435,7 +1496,7 @@ class calendar_bo
|
||||
{
|
||||
//_debug_array($event);
|
||||
$names = array();
|
||||
foreach($event['participants'] as $id => $status)
|
||||
foreach((array)$event['participants'] as $id => $status)
|
||||
{
|
||||
calendar_so::split_status($status,$quantity,$role);
|
||||
|
||||
@ -1531,8 +1592,11 @@ class calendar_bo
|
||||
*/
|
||||
function _list_cals_add($id,&$users,&$groups)
|
||||
{
|
||||
$name = $GLOBALS['egw']->common->grab_owner_name($id);
|
||||
$egw_name = $GLOBALS['egw']->accounts->id2name($id);
|
||||
$name = common::grab_owner_name($id);
|
||||
if (!($egw_name = $GLOBALS['egw']->accounts->id2name($id)))
|
||||
{
|
||||
return; // do not return no longer existing accounts which eg. still mentioned in acl
|
||||
}
|
||||
if (($type = $GLOBALS['egw']->accounts->get_type($id)) == 'g')
|
||||
{
|
||||
$arr = &$groups;
|
||||
@ -1541,7 +1605,7 @@ class calendar_bo
|
||||
{
|
||||
$arr = &$users;
|
||||
}
|
||||
$arr[$name] = Array(
|
||||
$arr[$id] = array(
|
||||
'grantor' => $id,
|
||||
'value' => ($type == 'g' ? 'g_' : '') . $id,
|
||||
'name' => $name,
|
||||
@ -1552,7 +1616,7 @@ class calendar_bo
|
||||
/**
|
||||
* generate list of user- / group-calendars for the selectbox in the header
|
||||
*
|
||||
* @return array alphabeticaly sorted array with groups first and then users: $name => array('grantor'=>$id,'value'=>['g_'.]$id,'name'=>$name)
|
||||
* @return array alphabeticaly sorted array with users first and then groups: array('grantor'=>$id,'value'=>['g_'.]$id,'name'=>$name)
|
||||
*/
|
||||
function list_cals()
|
||||
{
|
||||
@ -1561,7 +1625,7 @@ class calendar_bo
|
||||
{
|
||||
$this->_list_cals_add($id,$users,$groups);
|
||||
}
|
||||
if ($memberships = $GLOBALS['egw']->accounts->membership($GLOBALS['egw_info']['user']['account_id']))
|
||||
if (($memberships = $GLOBALS['egw']->accounts->membership($GLOBALS['egw_info']['user']['account_id'])))
|
||||
{
|
||||
foreach($memberships as $group_info)
|
||||
{
|
||||
@ -1576,17 +1640,22 @@ class calendar_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($groups as $name => $group)
|
||||
{
|
||||
foreach ($users as $user)
|
||||
{
|
||||
if ($user['sname'] == $group['sname']) unset($groups[$name]);
|
||||
}
|
||||
}
|
||||
uksort($users,'strnatcasecmp');
|
||||
uksort($groups,'strnatcasecmp');
|
||||
usort($users,array($this,'name_cmp'));
|
||||
usort($groups,array($this,'name_cmp'));
|
||||
|
||||
return $users + $groups; // users first and then groups, both alphabeticaly
|
||||
return array_merge($users, $groups); // users first and then groups, both alphabeticaly
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare function for sort by value of key 'name'
|
||||
*
|
||||
* @param array $a
|
||||
* @param array $b
|
||||
* @return int
|
||||
*/
|
||||
function name_cmp(array $a, array $b)
|
||||
{
|
||||
return strnatcasecmp($a['name'], $b['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1643,12 +1712,12 @@ class calendar_bo
|
||||
'bday' => "!''",
|
||||
);
|
||||
$bdays =& $contacts->search('',array('id','n_family','n_given','n_prefix','n_middle','bday'),
|
||||
'contact_bday ASC',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter);
|
||||
'bday ASC',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter);
|
||||
// search accounts too, if not stored in contacts repository
|
||||
$extra_accounts_search = $contacts->account_repository == 'ldap' && !is_null($contacts->so_accounts) &&
|
||||
!$GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'];
|
||||
if ($extra_accounts_search && ($bdays2 =& $contacts->search('',array('id','n_family','n_given','n_prefix','n_middle','bday'),
|
||||
'contact_bday ASC',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter+array('owner' => 0))))
|
||||
'bday ASC',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter+array('owner' => 0))))
|
||||
{
|
||||
$bdays = !$bdays ? $bdays2 : array_merge($bdays,$bdays2);
|
||||
}
|
||||
@ -1681,7 +1750,7 @@ class calendar_bo
|
||||
}
|
||||
if ((int) $this->debug >= 2 || $this->debug == 'read_holidays')
|
||||
{
|
||||
$this->debug_message('bocal::read_holidays(%1)=%2',true,$year,$this->cached_holidays[$year]);
|
||||
$this->debug_message('calendar_bo::read_holidays(%1)=%2',true,$year,$this->cached_holidays[$year]);
|
||||
}
|
||||
return $this->cached_holidays[$year];
|
||||
}
|
||||
@ -1696,7 +1765,12 @@ class calendar_bo
|
||||
*/
|
||||
function link_title($event)
|
||||
{
|
||||
if (!is_array($event) && (int) $event > 0)
|
||||
if (!is_array($event) && strpos($event, '-') !== false)
|
||||
{
|
||||
list($id, $recur) = explode('-', $event, 2);
|
||||
$event = $this->read($id, $recur);
|
||||
}
|
||||
else if (!is_array($event) && (int) $event > 0)
|
||||
{
|
||||
$event = $this->read($event);
|
||||
}
|
||||
@ -1715,26 +1789,36 @@ class calendar_bo
|
||||
* @param string $pattern pattern to search
|
||||
* @return array with cal_id - title pairs of the matching entries
|
||||
*/
|
||||
function link_query($pattern)
|
||||
function link_query($pattern, Array &$options = array())
|
||||
{
|
||||
$result = array();
|
||||
foreach((array) $this->search(array('query' => $pattern)) as $event)
|
||||
$query = array(
|
||||
'query' => $pattern,
|
||||
'offset' => $options['start'],
|
||||
);
|
||||
if($options['num_rows']) {
|
||||
$query['num_rows'] = $options['num_rows'];
|
||||
}
|
||||
foreach((array) $this->search($query) as $event)
|
||||
{
|
||||
$result[$event['id']] = $this->link_title($event);
|
||||
}
|
||||
$options['total'] = $this->total;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access to the projects file store
|
||||
* Check access to the file store
|
||||
*
|
||||
* @param int $id id of entry
|
||||
* @param int $check EGW_ACL_READ for read and EGW_ACL_EDIT for write or delete access
|
||||
* @param string $rel_path=null currently not used in calendar
|
||||
* @param int $user=null for which user to check, default current user
|
||||
* @return boolean true if access is granted or false otherwise
|
||||
*/
|
||||
function file_access($id,$check,$rel_path)
|
||||
function file_access($id,$check,$rel_path,$user=null)
|
||||
{
|
||||
return $this->check_perms($check,$id);
|
||||
return $this->check_perms($check,$id,0,'ts',null,$user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1794,14 +1878,25 @@ class calendar_bo
|
||||
* @param int|string $user account_id or account_lid
|
||||
* @param string $pw=null password
|
||||
*/
|
||||
static function freebusy_url($user,$pw=null)
|
||||
static function freebusy_url($user='',$pw=null)
|
||||
{
|
||||
if (is_numeric($user)) $user = $GLOBALS['egw']->accounts->id2name($user);
|
||||
|
||||
$credentials = '';
|
||||
|
||||
if ($pw)
|
||||
{
|
||||
$credentials = '&password='.urlencode($pw);
|
||||
}
|
||||
elseif ($GLOBALS['egw_info']['user']['preferences']['calendar']['freebusy'] == 2)
|
||||
{
|
||||
$credentials = $GLOBALS['egw_info']['user']['account_lid']
|
||||
. ':' . $GLOBALS['egw_info']['user']['passwd'];
|
||||
$credentials = '&cred=' . base64_encode($credentials);
|
||||
}
|
||||
return (!$GLOBALS['egw_info']['server']['webserver_url'] || $GLOBALS['egw_info']['server']['webserver_url'][0] == '/' ?
|
||||
($_SERVER['HTTPS'] ? 'https://' : 'http://').$_SERVER['HTTP_HOST'] : '').
|
||||
$GLOBALS['egw_info']['server']['webserver_url'].'/calendar/freebusy.php?user='.urlencode($user).
|
||||
($pw ? '&password='.urlencode($pw) : '');
|
||||
$GLOBALS['egw_info']['server']['webserver_url'].'/calendar/freebusy.php/?user='.urlencode($user).$credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1810,11 +1905,11 @@ class calendar_bo
|
||||
* @param array $event event
|
||||
* @return boolean true if whole day event, false othwerwise
|
||||
*/
|
||||
function isWholeDay($event)
|
||||
public static function isWholeDay($event)
|
||||
{
|
||||
// check if the event is the whole day
|
||||
$start = $this->date2array($event['start']);
|
||||
$end = $this->date2array($event['end']);
|
||||
$start = self::date2array($event['start']);
|
||||
$end = self::date2array($event['end']);
|
||||
|
||||
return !$start['hour'] && !$start['minute'] && $end['hour'] == 23 && $end['minute'] == 59;
|
||||
}
|
||||
@ -1823,10 +1918,13 @@ class calendar_bo
|
||||
* Get the etag for an entry
|
||||
*
|
||||
* @param array|int|string $event array with event or cal_id, or cal_id:recur_date for virtual exceptions
|
||||
* @param string &$schedule_tag=null on return schedule-tag (egw_cal.cal_id:egw_cal.cal_etag, no participant modifications!)
|
||||
* @param boolean $client_share_uid_excpetions Does client understand exceptions to be included in VCALENDAR component of series master sharing its UID
|
||||
* @param boolean $master_only=false only take into account recurrance masters
|
||||
* (for ActiveSync which does not support different participants/status on recurrences/exceptions!)
|
||||
* @return string|boolean string with etag or false
|
||||
*/
|
||||
function get_etag($entry,$client_share_uid_excpetions=true)
|
||||
function get_etag($entry, &$schedule_tag=null, $client_share_uid_excpetions=true,$master_only=false)
|
||||
{
|
||||
if (!is_array($entry))
|
||||
{
|
||||
@ -1834,7 +1932,7 @@ class calendar_bo
|
||||
if (!$this->check_perms(EGW_ACL_FREEBUSY, $entry, 0, 'server')) return false;
|
||||
$entry = $this->read($entry, $recur_date, true, 'server');
|
||||
}
|
||||
$etag = $entry['id'].':'.$entry['etag'];
|
||||
$etag = $schedule_tag = $entry['id'].':'.$entry['etag'];
|
||||
|
||||
// use new MAX(modification date) of egw_cal_user table (deals with virtual exceptions too)
|
||||
if (isset($entry['max_user_modified']))
|
||||
@ -1843,7 +1941,7 @@ class calendar_bo
|
||||
}
|
||||
else
|
||||
{
|
||||
$modified = max($this->so->max_user_modified($entry['id']), $entry['modified']);
|
||||
$modified = max($this->so->max_user_modified($entry['id'],false,$master_only), $entry['modified']);
|
||||
}
|
||||
$etag .= ':' . $modified;
|
||||
// include exception etags into our own etag, if exceptions are included
|
||||
@ -1863,9 +1961,17 @@ class calendar_bo
|
||||
{
|
||||
if ($recurrence['reference'] && $recurrence['id'] != $entry['id']) // ignore series master
|
||||
{
|
||||
$etag .= ':'.$this->get_etag($recurrence);
|
||||
$exception_etag = $this->get_etag($recurrence, $nul);
|
||||
// if $master_only, only add cal_etag, not max. user modification date
|
||||
if ($master_only) list(,$exception_etag) = explode(':',$exception_etag);
|
||||
|
||||
$exception_etags .= ':'.$this->get_etag($recurrence, $nul);
|
||||
}
|
||||
}
|
||||
if ($exception_etags)
|
||||
{
|
||||
$etag .= ':'.md5($exception_etags); // limit size, as there can be many exceptions
|
||||
}
|
||||
}
|
||||
//error_log(__METHOD__ . "($entry[id],$client_share_uid_excpetions) entry=".array2string($entry)." --> etag=$etag");
|
||||
return $etag;
|
||||
@ -1875,19 +1981,45 @@ class calendar_bo
|
||||
* Query ctag for calendar
|
||||
*
|
||||
* @param int|array $user integer user-id or array of user-id's to use, defaults to the current user
|
||||
* @param $filter='owner'
|
||||
* @return string $filter='owner' all (not rejected), accepted, unknown, tentative, rejected or hideprivate
|
||||
* @todo use MAX(modified) to query everything in one sql query, currently we do one query per event (more then the search)
|
||||
* @param string $filter='owner' all (not rejected), accepted, unknown, tentative, rejected or hideprivate
|
||||
* @param boolean $master_only=false only check recurance master (egw_cal_user.recur_date=0)
|
||||
* @return integer
|
||||
*/
|
||||
public function get_ctag($user,$filter='owner')
|
||||
public function get_ctag($user, $filter='owner', $master_only=false)
|
||||
{
|
||||
if ($this->debug > 1) $startime = microtime(true);
|
||||
|
||||
// resolve users to add memberships for users and members for groups
|
||||
$users = $this->resolve_users($user);
|
||||
$ctag = $users ? $this->so->get_ctag($users, $filter == 'owner') : 0; // no rights, return 0 as ctag (otherwise we get SQL error!)
|
||||
$ctag = $users ? $this->so->get_ctag($users, $filter == 'owner', $master_only) : 0; // no rights, return 0 as ctag (otherwise we get SQL error!)
|
||||
|
||||
if ($this->debug > 1) error_log(__METHOD__. "($user, '$filter') = $ctag = ".date('Y-m-d H:i:s',$ctag)." took ".(microtime(true)-$startime)." secs");
|
||||
return $ctag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for timesheet to set some extra data and links
|
||||
*
|
||||
* @param array $data
|
||||
* @param int $data[id] cal_id:recurrence
|
||||
* @return array with key => value pairs to set in new timesheet and link_app/link_id arrays
|
||||
*/
|
||||
function timesheet_set($data)
|
||||
{
|
||||
$set = array();
|
||||
list($id,$recurrence) = explode(':',$data['id']);
|
||||
if ((int)$id && ($event = $this->read($id,$recurrence)))
|
||||
{
|
||||
$set['ts_start'] = $event['start'];
|
||||
$set['ts_title'] = $this->link_title($event);
|
||||
$set['start_time'] = egw_time::to($event['start'],'H:i');
|
||||
$set['ts_description'] = $event['description'];
|
||||
if ($this->isWholeDay($event)) $event['end']++; // whole day events are 1sec short
|
||||
$set['ts_duration'] = ($event['end'] - $event['start']) / 60;
|
||||
$set['ts_quantity'] = ($event['end'] - $event['start']) / 3600;
|
||||
$set['end_time'] = null; // unset end-time
|
||||
$set['cat_id'] = (int)$event['category'];
|
||||
}
|
||||
return $set;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Calendar's buisness-object - access + update
|
||||
* EGroupware - Calendar's buisness-object - access + update
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) 2005-9 by RalfBecker-At-outdoor-training.de
|
||||
* @copyright (c) 2005-11 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -111,7 +111,7 @@ class calendar_boupdate extends calendar_bo
|
||||
* + + + C + which is clearly wrong for everything with a maximum quantity > 1
|
||||
* ++++++++ ++++++++
|
||||
*/
|
||||
function update(&$event,$ignore_conflicts=false,$touch_modified=true,$ignore_acl=false,$updateTS=true,&$messages=null)
|
||||
function update(&$event,$ignore_conflicts=false,$touch_modified=true,$ignore_acl=false,$updateTS=true,&$messages=null, $skip_notification=false)
|
||||
{
|
||||
//error_log(__METHOD__."(".array2string($event).",$ignore_conflicts,$touch_modified,$ignore_acl)");
|
||||
|
||||
@ -130,6 +130,8 @@ class calendar_boupdate extends calendar_bo
|
||||
return false;
|
||||
}
|
||||
|
||||
$status_reset_to_unknown = false;
|
||||
|
||||
if (($new_event = !$event['id'])) // some defaults for new entries
|
||||
{
|
||||
// if no owner given, set user to owner
|
||||
@ -356,19 +358,28 @@ class calendar_boupdate extends calendar_bo
|
||||
$event = $this->read($cal_id); // we re-read the event, in case only partial information was update and we need the full info for the notifies
|
||||
//echo "new $cal_id="; _debug_array($event);
|
||||
|
||||
if($old_event['deleted'] && $event['deleted'] == null)
|
||||
{
|
||||
// Restored, bring back links
|
||||
egw_link::restore('calendar', $cal_id);
|
||||
}
|
||||
if ($this->log_file)
|
||||
{
|
||||
$this->log2file($event2save,$event,$old_event);
|
||||
}
|
||||
// send notifications
|
||||
if ($new_event)
|
||||
if(!$skip_notification)
|
||||
{
|
||||
$this->send_update(MSG_ADDED,$event['participants'],'',$event);
|
||||
}
|
||||
else // update existing event
|
||||
{
|
||||
$this->check4update($event,$old_event);
|
||||
if ($new_event)
|
||||
{
|
||||
$this->send_update(MSG_ADDED,$event['participants'],'',$event);
|
||||
}
|
||||
else // update existing event
|
||||
{
|
||||
$this->check4update($event,$old_event);
|
||||
}
|
||||
}
|
||||
|
||||
// notify the link-class about the update, as other apps may be subscribt to it
|
||||
egw_link::notify_update('calendar',$cal_id,$event);
|
||||
|
||||
@ -393,7 +404,7 @@ class calendar_boupdate extends calendar_bo
|
||||
$old_event = $this->read($event['id']);
|
||||
}
|
||||
$removed = array();
|
||||
foreach($event['participants'] as $uid => $status)
|
||||
foreach((array)$event['participants'] as $uid => $status)
|
||||
{
|
||||
if ((is_null($old_event) || !isset($old_event['participants'][$uid])) && !$this->check_acl_invite($uid))
|
||||
{
|
||||
@ -492,9 +503,10 @@ class calendar_boupdate extends calendar_bo
|
||||
* @param int $msg_type type of the notification: MSG_ADDED, MSG_MODIFIED, MSG_ACCEPTED, ...
|
||||
* @param array $old_event Event before the change
|
||||
* @param array $new_event Event after the change
|
||||
* @return boolean true = update requested, flase otherwise
|
||||
* @param string $role we treat CHAIR like event owners
|
||||
* @return boolean true = update requested, false otherwise
|
||||
*/
|
||||
function update_requested($userid,$part_prefs,$msg_type,$old_event,$new_event)
|
||||
function update_requested($userid,$part_prefs,$msg_type,$old_event,$new_event,$role)
|
||||
{
|
||||
if ($msg_type == MSG_ALARM)
|
||||
{
|
||||
@ -517,6 +529,7 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
case 'time_change_4h':
|
||||
case 'time_change':
|
||||
default:
|
||||
$diff = max(abs($this->date2ts($old_event['start'])-$this->date2ts($new_event['start'])),
|
||||
abs($this->date2ts($old_event['end'])-$this->date2ts($new_event['end'])));
|
||||
$check = $ru == 'time_change_4h' ? 4 * 60 * 60 - 1 : 0;
|
||||
@ -525,13 +538,17 @@ class calendar_boupdate extends calendar_bo
|
||||
++$want_update;
|
||||
}
|
||||
case 'add_cancel':
|
||||
if ($old_event['owner'] == $userid && $msg_is_response ||
|
||||
if ($msg_is_response && ($old_event['owner'] == $userid || $role == 'CHAIR') ||
|
||||
$msg_type == MSG_DELETED || $msg_type == MSG_ADDED || $msg_type == MSG_DISINVITE)
|
||||
{
|
||||
++$want_update;
|
||||
}
|
||||
break;
|
||||
case 'no':
|
||||
if ($msg_is_response && $role == 'CHAIR') // always notify chairs!
|
||||
{
|
||||
++$want_update;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//error_log(__METHOD__."(userid=$userid,,msg_type=$msg_type,...) msg_is_response=$msg_is_response, want_update=$want_update");
|
||||
@ -672,12 +689,31 @@ class calendar_boupdate extends calendar_bo
|
||||
if ($old_event != False) $olddate = new egw_time($old_event['start']);
|
||||
foreach($to_notify as $userid => $statusid)
|
||||
{
|
||||
if ($this->debug > 0) error_log(__METHOD__." trying to notify $userid, with $statusid");
|
||||
unset($res_info);
|
||||
calendar_so::split_status($statusid, $quantity, $role);
|
||||
if ($this->debug > 0) error_log(__METHOD__." trying to notify $userid, with $statusid ($role)");
|
||||
|
||||
if (!is_numeric($userid))
|
||||
{
|
||||
$res_info = $this->resource_info($userid);
|
||||
$userid = $res_info['responsible'];
|
||||
if (!isset($userid)) continue;
|
||||
if (!isset($userid))
|
||||
{
|
||||
if (empty($res_info['email'])) continue; // no way to notify
|
||||
// check if event-owner wants non-EGroupware users notified
|
||||
if (is_null($owner_prefs))
|
||||
{
|
||||
$preferences = new preferences($old_event['owner']);
|
||||
$owner_prefs = $preferences->read_repository();
|
||||
}
|
||||
if ($role != 'CHAIR' && // always notify externals CHAIRs
|
||||
(empty($owner_prefs['calendar']['notify_externals']) ||
|
||||
$owner_prefs['calendar']['notify_externals'] == 'no'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$userid = $res_info['email'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($statusid == 'R' || $GLOBALS['egw']->accounts->get_type($userid) == 'g')
|
||||
@ -690,16 +726,30 @@ class calendar_boupdate extends calendar_bo
|
||||
$user_prefs['calendar']['receive_own_updates']==1) ||
|
||||
$msg_type == MSG_ALARM)
|
||||
{
|
||||
$preferences = CreateObject('phpgwapi.preferences',$userid);
|
||||
$part_prefs = $preferences->read_repository();
|
||||
if (is_numeric($userid))
|
||||
{
|
||||
$preferences = new preferences($userid);
|
||||
$part_prefs = $preferences->read_repository();
|
||||
|
||||
if (!$this->update_requested($userid,$part_prefs,$msg_type,$old_event,$new_event))
|
||||
$GLOBALS['egw']->accounts->get_account_name($userid,$lid,$details['to-firstname'],$details['to-lastname']);
|
||||
$details['to-fullname'] = common::display_fullname('',$details['to-firstname'],$details['to-lastname']);
|
||||
}
|
||||
else // external email address: use preferences of event-owner, plus some hardcoded settings (eg. ical notification)
|
||||
{
|
||||
if (is_null($owner_prefs))
|
||||
{
|
||||
$preferences = new preferences($old_event['owner']);
|
||||
$owner_prefs = $preferences->read_repository();
|
||||
}
|
||||
$part_prefs = $owner_prefs;
|
||||
$part_prefs['calendar']['receive_updates'] = $owner_prefs['calendar']['notify_externals'];
|
||||
$part_prefs['calendar']['update_format'] = 'ical'; // use ical format
|
||||
$details['to-fullname'] = $res_info && !empty($res_info['name']) ? $res_info['name'] : $userid;
|
||||
}
|
||||
if (!$this->update_requested($userid,$part_prefs,$msg_type,$old_event,$new_event,$role))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$GLOBALS['egw']->accounts->get_account_name($userid,$lid,$details['to-firstname'],$details['to-lastname']);
|
||||
$details['to-fullname'] = $GLOBALS['egw']->common->display_fullname('',$details['to-firstname'],$details['to-lastname']);
|
||||
|
||||
// event is in user-time of current user, now we need to calculate the tz-difference to the notified user and take it into account
|
||||
if (!isset($part_prefs['common']['tz'])) $part_prefs['common']['tz'] = $GLOBALS['egw_info']['server']['server_timezone'];
|
||||
$timezone = new DateTimeZone($part_prefs['common']['tz']);
|
||||
@ -735,27 +785,28 @@ class calendar_boupdate extends calendar_bo
|
||||
switch($part_prefs['calendar']['update_format'])
|
||||
{
|
||||
case 'ical':
|
||||
if ($method == 'REQUEST')
|
||||
if (is_null($ics))
|
||||
{
|
||||
if (is_null($ics))
|
||||
{
|
||||
$calendar_ical = new calendar_ical();
|
||||
$calendar_ical->setSupportedFields('full'); // full iCal fields+event TZ
|
||||
$ics = $calendar_ical->exportVCal($event['id'],'2.0',$method);
|
||||
unset($calendar_ical);
|
||||
}
|
||||
$attachment = array( 'string' => $ics,
|
||||
'filename' => 'cal.ics',
|
||||
'encoding' => '8bit',
|
||||
'type' => 'text/calendar; method='.$method,
|
||||
);
|
||||
$calendar_ical = new calendar_ical();
|
||||
$calendar_ical->setSupportedFields('full'); // full iCal fields+event TZ
|
||||
// we need to pass $event[id] so iCal class reads event again,
|
||||
// as event is in user TZ, but iCal class expects server TZ!
|
||||
$ics = $calendar_ical->exportVCal(array($event['id']),'2.0',$method);
|
||||
unset($calendar_ical);
|
||||
}
|
||||
$attachment = array(
|
||||
'string' => $ics,
|
||||
'filename' => 'cal.ics',
|
||||
'encoding' => '8bit',
|
||||
'type' => 'text/calendar; method='.$method,
|
||||
);
|
||||
// fall through
|
||||
case 'extended':
|
||||
$body .= "\n\n".lang('Event Details follow').":\n";
|
||||
foreach($event_arr as $key => $val)
|
||||
{
|
||||
if(strlen($details[$key])) {
|
||||
if(!empty($details[$key]))
|
||||
{
|
||||
switch($key){
|
||||
case 'access':
|
||||
case 'priority':
|
||||
@ -770,7 +821,8 @@ class calendar_boupdate extends calendar_bo
|
||||
break;
|
||||
}
|
||||
// send via notification_app
|
||||
if($GLOBALS['egw_info']['apps']['notifications']['enabled']) {
|
||||
if($GLOBALS['egw_info']['apps']['notifications']['enabled'])
|
||||
{
|
||||
try {
|
||||
$notification = new notifications();
|
||||
$notification->set_receivers(array($userid));
|
||||
@ -785,7 +837,9 @@ class calendar_boupdate extends calendar_bo
|
||||
error_log(__METHOD__.' error while notifying user '.$userid.':'.$exception->getMessage());
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log(__METHOD__.' cannot send any notifications because notifications is not installed');
|
||||
}
|
||||
}
|
||||
@ -872,12 +926,59 @@ class calendar_boupdate extends calendar_bo
|
||||
return false;
|
||||
}
|
||||
|
||||
// invalidate the read-cache if it contains the event we store now
|
||||
if ($event['id'] && $event['id'] == self::$cached_event['id']) self::$cached_event = array();
|
||||
if ($event['id'])
|
||||
{
|
||||
// invalidate the read-cache if it contains the event we store now
|
||||
if ($event['id'] == self::$cached_event['id']) self::$cached_event = array();
|
||||
$old_event = $this->read($event['id'], $event['recurrence'], false, 'server');
|
||||
}
|
||||
else
|
||||
{
|
||||
$old_event = null;
|
||||
}
|
||||
|
||||
if (!isset($event['whole_day'])) $event['whole_day'] = $this->isWholeDay($event);
|
||||
$save_event = $event;
|
||||
if ($event['whole_day'])
|
||||
{
|
||||
if (!empty($event['start']))
|
||||
{
|
||||
$time = new egw_time($event['start'], egw_time::$user_timezone);
|
||||
$time =& $this->so->startOfDay($time);
|
||||
$event['start'] = egw_time::to($time, 'ts');
|
||||
$save_event['start'] = $time;
|
||||
}
|
||||
if (!empty($event['end']))
|
||||
{
|
||||
$time = new egw_time($event['end'], egw_time::$user_timezone);
|
||||
$time =& $this->so->startOfDay($time);
|
||||
$time->setTime(23, 59, 59);
|
||||
$event['end'] = egw_time::to($time, 'ts');
|
||||
}
|
||||
if (!empty($event['recurrence']))
|
||||
{
|
||||
$time = new egw_time($event['recurrence'], egw_time::$user_timezone);
|
||||
$time =& $this->so->startOfDay($time);
|
||||
$event['recurrence'] = egw_time::to($time, 'ts');
|
||||
}
|
||||
if (!empty($event['recur_enddate']))
|
||||
{
|
||||
$time = new egw_time($event['recur_enddate'], egw_time::$user_timezone);
|
||||
$time =& $this->so->startOfDay($time);
|
||||
$event['recur_enddate'] = egw_time::to($time, 'ts');
|
||||
$time->setUser();
|
||||
$save_event['recur_enddate'] = egw_time::to($time, 'ts');
|
||||
}
|
||||
$timestamps = array('modified','created');
|
||||
// all-day events are handled in server time
|
||||
$event['tzid'] = $save_event['tzid'] = egw_time::$server_timezone->getName();
|
||||
}
|
||||
else
|
||||
{
|
||||
$timestamps = array('start','end','modified','created','recur_enddate','recurrence');
|
||||
}
|
||||
// we run all dates through date2ts, to adjust to server-time and the possible date-formats
|
||||
foreach(array('start','end','modified','created','recur_enddate','recurrence') as $ts)
|
||||
foreach($timestamps as $ts)
|
||||
{
|
||||
// we convert here from user-time to timestamps in server-time!
|
||||
if (isset($event[$ts])) $event[$ts] = $event[$ts] ? $this->date2ts($event[$ts],true) : 0;
|
||||
@ -892,7 +993,16 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
foreach($event['recur_exception'] as $n => $date)
|
||||
{
|
||||
$event['recur_exception'][$n] = $this->date2ts($date,true);
|
||||
if ($event['whole_day'])
|
||||
{
|
||||
$time = new egw_time($date, egw_time::$user_timezone);
|
||||
$time =& $this->so->startOfDay($time);
|
||||
$date = egw_time::to($time, 'ts');
|
||||
}
|
||||
else
|
||||
{
|
||||
$event['recur_exception'][$n] = $this->date2ts($date,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// same with the alarms
|
||||
@ -935,7 +1045,12 @@ class calendar_boupdate extends calendar_bo
|
||||
unset($save_event['participants']);
|
||||
$this->set_recurrences($save_event, $set_recurrences_start);
|
||||
}
|
||||
if ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,$event['id'] ? 'modify' : 'add',time());
|
||||
if ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', $cal_id, $event['id'] ? 'modify' : 'add', $this->now);
|
||||
|
||||
// Update history
|
||||
$tracking = new calendar_tracking($this);
|
||||
if (empty($event['id']) && !empty($cal_id)) $event['id']=$cal_id;
|
||||
$tracking->track($event, $old_event);
|
||||
|
||||
return $cal_id;
|
||||
}
|
||||
@ -1119,7 +1234,7 @@ class calendar_boupdate extends calendar_bo
|
||||
* @param boolean $updateTS=true update the content history of the event
|
||||
* @return int number of changed recurrences
|
||||
*/
|
||||
function set_status($event,$uid,$status,$recur_date=0,$ignore_acl=false,$updateTS=true)
|
||||
function set_status($event,$uid,$status,$recur_date=0,$ignore_acl=false,$updateTS=true,$skip_notification=false)
|
||||
{
|
||||
$cal_id = is_array($event) ? $event['id'] : $event;
|
||||
//echo "<p>calendar_boupdate::set_status($cal_id,$uid,$status,$recur_date)</p>\n";
|
||||
@ -1133,11 +1248,15 @@ class calendar_boupdate extends calendar_bo
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
"($cal_id, $uid, $status, $recur_date)\n",3,$this->logfile);
|
||||
}
|
||||
$old_event = $this->read($cal_id, $recur_date, false, 'server');
|
||||
if (($Ok = $this->so->set_status($cal_id,is_numeric($uid)?'u':$uid[0],
|
||||
is_numeric($uid)?$uid:substr($uid,1),$status,
|
||||
$recur_date?$this->date2ts($recur_date,true):0,$role)))
|
||||
{
|
||||
if ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time());
|
||||
if ($updateTS)
|
||||
{
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', $cal_id, 'modify', $this->now);
|
||||
}
|
||||
|
||||
static $status2msg = array(
|
||||
'R' => MSG_REJECTED,
|
||||
@ -1145,13 +1264,18 @@ class calendar_boupdate extends calendar_bo
|
||||
'A' => MSG_ACCEPTED,
|
||||
'D' => MSG_DELEGATED,
|
||||
);
|
||||
if (isset($status2msg[$status]))
|
||||
if (isset($status2msg[$status]) && !$skip_notification)
|
||||
{
|
||||
if (!is_array($event)) $event = $this->read($cal_id);
|
||||
if (isset($recur_date)) $event = $this->read($event['id'],$recur_date); //re-read the actually edited recurring event
|
||||
$this->send_update($status2msg[$status],$event['participants'],$event);
|
||||
}
|
||||
|
||||
// Update history
|
||||
$event = $this->read($cal_id, $recur_date, false, 'server');
|
||||
$tracking = new calendar_tracking($this);
|
||||
$tracking->track($event, $old_event);
|
||||
|
||||
}
|
||||
return $Ok;
|
||||
}
|
||||
@ -1195,22 +1319,47 @@ class calendar_boupdate extends calendar_bo
|
||||
* @param boolean $ignore_acl=false true for no ACL check, default do ACL check
|
||||
* @return boolean true on success, false on error (usually permission denied)
|
||||
*/
|
||||
function delete($cal_id,$recur_date=0,$ignore_acl=false)
|
||||
function delete($cal_id,$recur_date=0,$ignore_acl=false,$skip_notification=false)
|
||||
{
|
||||
if (!($event = $this->read($cal_id,$recur_date)) ||
|
||||
!$ignore_acl && !$this->check_perms(EGW_ACL_DELETE,$event))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$this->send_update(MSG_DELETED,$event['participants'],$event);
|
||||
|
||||
// Don't send notification if the event has already been deleted
|
||||
if(!$event['deleted'] && !$skip_notification)
|
||||
{
|
||||
$this->send_update(MSG_DELETED,$event['participants'],$event);
|
||||
}
|
||||
|
||||
if (!$recur_date || $event['recur_type'] == MCAL_RECUR_NONE)
|
||||
{
|
||||
$this->so->delete($cal_id);
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'delete',time());
|
||||
$config = config::read('phpgwapi');
|
||||
if(!$config['calendar_delete_history'] || $event['deleted'])
|
||||
{
|
||||
$this->so->delete($cal_id);
|
||||
|
||||
// delete all links to the event
|
||||
egw_link::unlink(0,'calendar',$cal_id);
|
||||
// delete all links to the event
|
||||
egw_link::unlink(0,'calendar',$cal_id);
|
||||
}
|
||||
elseif ($config['calendar_delete_history'])
|
||||
{
|
||||
// mark all links to the event as deleted, but keep them
|
||||
egw_link::unlink(0,'calendar',$cal_id,'','','',true);
|
||||
|
||||
$event['deleted'] = $this->now;
|
||||
$this->save($event, $ignore_acl);
|
||||
// Actually delete alarms
|
||||
if (isset($event['alarm']) && is_array($event['alarm']))
|
||||
{
|
||||
foreach($event['alarm'] as $id => $alarm)
|
||||
{
|
||||
$this->delete_alarm($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', $cal_id, 'delete', $this->now);
|
||||
}
|
||||
else // delete an exception
|
||||
{
|
||||
@ -1384,7 +1533,7 @@ class calendar_boupdate extends calendar_bo
|
||||
echo "<p>error opening '$this->log_file' !!!</p>\n";
|
||||
return false;
|
||||
}
|
||||
fwrite($f,$type.': '.$GLOBALS['egw']->common->grab_owner_name($this->user).': '.date('r')."\n");
|
||||
fwrite($f,$type.': '.common::grab_owner_name($this->user).': '.date('r')."\n");
|
||||
fwrite($f,"Time: time to save / saved time read back / old time before save\n");
|
||||
foreach(array('start','end') as $name)
|
||||
{
|
||||
@ -1418,9 +1567,9 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
$alarm['time'] = $this->date2ts($alarm['time'],true); // user to server-time
|
||||
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id, 'modify', time());
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', $cal_id, 'modify', $this->now);
|
||||
|
||||
return $this->so->save_alarm($cal_id,$alarm, $this->now_su);
|
||||
return $this->so->save_alarm($cal_id,$alarm, $this->now);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1438,9 +1587,9 @@ class calendar_boupdate extends calendar_bo
|
||||
return false; // no rights to delete the alarm
|
||||
}
|
||||
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id, 'modify', time());
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', $cal_id, 'modify', $this->now);
|
||||
|
||||
return $this->so->delete_alarm($id, $this->now_su);
|
||||
return $this->so->delete_alarm($id, $this->now);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1448,16 +1597,16 @@ class calendar_boupdate extends calendar_bo
|
||||
* currently used for ical/sif import
|
||||
*
|
||||
* @param array $catname_list names of the categories which should be found or added
|
||||
* @param int $cal_id=-1 match against existing event and expand the returned category ids
|
||||
* @param int|array $old_event=null match against existing event and expand the returned category ids
|
||||
* by the ones the user normally does not see due to category permissions - used to preserve categories
|
||||
* @return array category ids (found, added and preserved categories)
|
||||
*/
|
||||
function find_or_add_categories($catname_list, $cal_id=-1)
|
||||
function find_or_add_categories($catname_list, $old_event=null)
|
||||
{
|
||||
if ($cal_id && $cal_id > 0)
|
||||
if (is_array($old_event) || $old_event > 0)
|
||||
{
|
||||
// preserve categories without users read access
|
||||
$old_event = $this->read($cal_id);
|
||||
if (!is_array($old_event)) $old_event = $this->read($old_event);
|
||||
$old_categories = explode(',',$old_event['category']);
|
||||
$old_cats_preserve = array();
|
||||
if (is_array($old_categories) && count($old_categories) > 0)
|
||||
@ -1548,13 +1697,25 @@ class calendar_boupdate extends calendar_bo
|
||||
"($filter)[EVENT]:" . array2string($event)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
if (!isset($event['recurrence'])) $event['recurrence'] = 0;
|
||||
|
||||
if ($filter == 'master')
|
||||
{
|
||||
$query[] = 'recur_type!='. MCAL_RECUR_NONE;
|
||||
$query['cal_recurrence'] = 0;
|
||||
}
|
||||
|
||||
if (!isset($event['recurrence'])) $event['recurrence'] = 0;
|
||||
elseif ($filter == 'exact')
|
||||
{
|
||||
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
$query[] = 'recur_type='.$event['recur_type'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$query[] = 'recur_type IS NULL';
|
||||
}
|
||||
$query['cal_recurrence'] = $event['recurrence'];
|
||||
}
|
||||
|
||||
if ($event['id'])
|
||||
{
|
||||
@ -1679,7 +1840,6 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
elseif (isset($event['start']))
|
||||
{
|
||||
|
||||
if ($filter == 'relax')
|
||||
{
|
||||
$query[] = ('cal_start>' . ($event['start'] - 3600));
|
||||
@ -1700,7 +1860,6 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
$matchFields = array('priority', 'public');
|
||||
}
|
||||
$matchFields[] = 'recurrence';
|
||||
foreach ($matchFields as $key)
|
||||
{
|
||||
if (isset($event[$key])) $query['cal_'.$key] = $event[$key];
|
||||
@ -1723,7 +1882,7 @@ class calendar_boupdate extends calendar_bo
|
||||
'[QUERY]: ' . array2string($query)."\n",3,$this->logfile);
|
||||
}
|
||||
if (!count($users) || !($foundEvents =
|
||||
$this->so->search(null, null, $users, 0, 'owner', $query)))
|
||||
$this->so->search(null, null, $users, 0, 'owner', false, 0, array('query' => $query))))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
@ -1821,7 +1980,7 @@ class calendar_boupdate extends calendar_bo
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check times
|
||||
if ($filter != 'relax')
|
||||
{
|
||||
@ -1925,8 +2084,15 @@ class calendar_boupdate extends calendar_bo
|
||||
unset($egwEvent['participants'][$attendee]);
|
||||
}
|
||||
}
|
||||
// ORGANIZER is maybe missing
|
||||
// ORGANIZER and Groups may be missing
|
||||
unset($egwEvent['participants'][$egwEvent['owner']]);
|
||||
foreach ($egwEvent['participants'] as $attendee => $status)
|
||||
{
|
||||
if (is_numeric($attendee) && $attendee < 0)
|
||||
{
|
||||
unset($egwEvent['participants'][$attendee]);
|
||||
}
|
||||
}
|
||||
if (!empty($egwEvent['participants']))
|
||||
{
|
||||
if ($this->log)
|
||||
@ -1978,7 +2144,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
'() missing event[recur_exception]: ' .
|
||||
array2string($event['recur_exception']));
|
||||
array2string($event['recur_exception'])."\n",3,$this->logfile);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -2002,12 +2168,10 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
$matchingEvents[] = $egwEvent['id']; // exact match
|
||||
}
|
||||
if (!empty($event['uid']) &&
|
||||
count($matchingEvents) > 1 || $filter != 'master' &&
|
||||
$egwEvent['recur_type'] != MCAL_RECUR_NONE &&
|
||||
empty($event['recur_type']))
|
||||
|
||||
if ($filter == 'exact' && !empty($event['uid']) && count($matchingEvents) > 1
|
||||
|| $filter != 'master' && !empty($egwEvent['recur_type']) && empty($event['recur_type']))
|
||||
{
|
||||
|
||||
// Unknown exception for existing series
|
||||
if ($this->log)
|
||||
{
|
||||
@ -2170,7 +2334,7 @@ class calendar_boupdate extends calendar_bo
|
||||
// check for changed data
|
||||
foreach (array('start','end','uid','title','location','description',
|
||||
'priority','public','special','non_blocking') as $key)
|
||||
{
|
||||
{
|
||||
if (!empty($event[$key]) && $recurrence_event[$key] != $event[$key])
|
||||
{
|
||||
if ($wasPseudo)
|
||||
@ -2190,7 +2354,7 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// the event id here is always the id of the master event
|
||||
// unset it to prevent confusion of stored event and master event
|
||||
unset($event['id']);
|
||||
@ -2252,4 +2416,15 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Delete events that are more than $age years old
|
||||
*
|
||||
* Purges old events from the database
|
||||
*
|
||||
* @param int|float $age How many years old the event must be before it is deleted
|
||||
*/
|
||||
function purge($age)
|
||||
{
|
||||
$this->so->purge(time() - 365*24*3600*(float)$age);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* iCal import and export via Horde iCalendar classes
|
||||
* EGroupware - Calendar iCal import and export via Horde iCalendar classes
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke <lkneschke@egroupware.org>
|
||||
@ -228,10 +228,10 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal->setAttribute('PRODID','-//eGroupWare//NONSGML eGroupWare Calendar '.$GLOBALS['egw_info']['apps']['calendar']['version'].'//'.
|
||||
$vcal->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Calendar '.$GLOBALS['egw_info']['apps']['calendar']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
$vcal->setAttribute('VERSION', $version);
|
||||
$vcal->setAttribute('METHOD', $method);
|
||||
if ($method) $vcal->setAttribute('METHOD', $method);
|
||||
$events_exported = false;
|
||||
|
||||
if (!is_array($events)) $events = array($events);
|
||||
@ -354,42 +354,15 @@ class calendar_ical extends calendar_boupdate
|
||||
if ($tzid && $tzid != 'UTC' && !in_array($tzid,$vtimezones_added))
|
||||
{
|
||||
// check if we have vtimezone component data for tzid of event, if not default to user timezone (default to server tz)
|
||||
if (!($vtimezone = calendar_timezones::tz2id($tzid,'component')))
|
||||
if (calendar_timezones::add_vtimezone($vcal, $tzid) ||
|
||||
!in_array($tzid = egw_time::$user_timezone->getName(), $vtimezones_added) &&
|
||||
calendar_timezones::add_vtimezone($vcal, $tzid))
|
||||
{
|
||||
error_log(__METHOD__."() unknown TZID='$tzid', defaulting to user timezone '".egw_time::$user_timezone->getName()."'!");
|
||||
$vtimezone = calendar_timezones::tz2id($tzid=egw_time::$user_timezone->getName(),'component');
|
||||
$tzid = null;
|
||||
}
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
{
|
||||
self::$tz_cache[$tzid] = calendar_timezones::DateTimeZone($tzid);
|
||||
}
|
||||
//error_log("in_array('$tzid',\$vtimezones_added)=".array2string(in_array($tzid,$vtimezones_added)).", component=$vtimezone");;
|
||||
if (!in_array($tzid,$vtimezones_added))
|
||||
{
|
||||
// $vtimezone is a string with a single VTIMEZONE component, afaik Horde_iCalendar can not add it directly
|
||||
// --> we have to parse it and let Horde_iCalendar add it again
|
||||
$horde_vtimezone = Horde_iCalendar::newComponent('VTIMEZONE',$container=false);
|
||||
$horde_vtimezone->parsevCalendar($vtimezone,'VTIMEZONE');
|
||||
// DTSTART must be in local time!
|
||||
$standard = $horde_vtimezone->findComponent('STANDARD');
|
||||
if (is_a($standard, 'Horde_iCalendar'))
|
||||
{
|
||||
$dtstart = $standard->getAttribute('DTSTART');
|
||||
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
|
||||
$dtstart->setTimezone(self::$tz_cache[$tzid]);
|
||||
$standard->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
|
||||
}
|
||||
$daylight = $horde_vtimezone->findComponent('DAYLIGHT');
|
||||
if (is_a($daylight, 'Horde_iCalendar'))
|
||||
{
|
||||
$dtstart = $daylight->getAttribute('DTSTART');
|
||||
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
|
||||
$dtstart->setTimezone(self::$tz_cache[$tzid]);
|
||||
$daylight->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
|
||||
}
|
||||
$vcal->addComponent($horde_vtimezone);
|
||||
$vtimezones_added[] = $tzid;
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
{
|
||||
self::$tz_cache[$tzid] = calendar_timezones::DateTimeZone($tzid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->productManufacturer != 'file' && $this->uidExtension)
|
||||
@ -434,7 +407,6 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
$event['recur_exception'] = $exceptions;
|
||||
}
|
||||
|
||||
foreach ($egwSupportedFields as $icalFieldName => $egwFieldName)
|
||||
{
|
||||
if (!isset($this->supportedFields[$egwFieldName]))
|
||||
@ -451,13 +423,14 @@ class calendar_ical extends calendar_boupdate
|
||||
switch ($icalFieldName)
|
||||
{
|
||||
case 'ATTENDEE':
|
||||
$attendees = count($event['participants']);
|
||||
foreach ((array)$event['participants'] as $uid => $status)
|
||||
{
|
||||
calendar_so::split_status($status, $quantity, $role);
|
||||
if ($attendees == 1 &&
|
||||
$uid == $this->user && $status == 'A') continue;
|
||||
// do not include event owner/ORGANIZER as participant in his own calendar, if he is only participant
|
||||
if (count($event['participants']) == 1 && $event['owner'] == $uid) continue;
|
||||
|
||||
if (!($info = $this->resource_info($uid))) continue;
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ .
|
||||
@ -491,11 +464,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
case 'g':
|
||||
$cutype = 'GROUP';
|
||||
if ($this->productManufacturer == 'groupdav')
|
||||
{
|
||||
$participantURL = 'invalid:nomail';
|
||||
$cutype = 'INDIVIDUAL';
|
||||
}
|
||||
$participantURL = 'urn:uuid:'.common::generate_uid('accounts', $uid);
|
||||
$members = $GLOBALS['egw']->accounts->members($uid, true);
|
||||
if (!isset($event['participants'][$this->user]) && in_array($this->user, $members))
|
||||
{
|
||||
@ -508,13 +477,16 @@ class calendar_ical extends calendar_boupdate
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'RSVP' => 'TRUE',
|
||||
'X-EGROUPWARE-UID' => $this->user,
|
||||
'EMAIL' => $user['email'],
|
||||
);
|
||||
);
|
||||
$event['participants'][$this->user] = true;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
$cutype = 'RESOURCE';
|
||||
$participantURL = 'urn:uuid:'.common::generate_uid('resources', substr($uid, 1));
|
||||
$cutype = groupdav_principals::resource_is_location(substr($uid, 1)) ? 'ROOM' : 'RESOURCE';
|
||||
// unset resource email (email of responsible user) as iCal at least has problems,
|
||||
// if resonpsible is also pariticipant or organizer
|
||||
unset($info['email']);
|
||||
break;
|
||||
case 'u': // account
|
||||
case 'c': // contact
|
||||
@ -524,7 +496,12 @@ class calendar_ical extends calendar_boupdate
|
||||
default:
|
||||
$cutype = 'UNKNOWN';
|
||||
break;
|
||||
};
|
||||
}
|
||||
// generate urn:uuid, if we have no other participant URL
|
||||
if (empty($participantURL) && $info && $info['app'])
|
||||
{
|
||||
$participantURL = 'urn:uuid:'.common::generate_uid($info['app'], substr($uid, 1));
|
||||
}
|
||||
// ROLE={CHAIR|REQ-PARTICIPANT|OPT-PARTICIPANT|NON-PARTICIPANT|X-*}
|
||||
$options = array();
|
||||
if (!empty($participantCN)) $options['CN'] = $participantCN;
|
||||
@ -532,20 +509,24 @@ class calendar_ical extends calendar_boupdate
|
||||
if (!empty($status)) $options['PARTSTAT'] = $status;
|
||||
if (!empty($cutype)) $options['CUTYPE'] = $cutype;
|
||||
if (!empty($rsvp)) $options['RSVP'] = $rsvp;
|
||||
if (!empty($info['email'])) $options['EMAIL'] = $info['email'];
|
||||
if (!empty($info['email']) && $participantURL != 'MAILTO:'.$info['email'])
|
||||
{
|
||||
$options['EMAIL'] = $info['email']; // only add EMAIL attribute, if not already URL, as eg. Akonadi is reported to have problems with it
|
||||
}
|
||||
if ($info['type'] != 'e') $options['X-EGROUPWARE-UID'] = $uid;
|
||||
if ($quantity > 1) $options['X-EGROUPWARE-QUANTITY'] = $quantity;
|
||||
$attributes['ATTENDEE'][] = $participantURL;
|
||||
$attributes['ATTENDEE'][] = $participantURL;
|
||||
$parameters['ATTENDEE'][] = $options;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'CLASS':
|
||||
$attributes['CLASS'] = $event['public'] ? 'PUBLIC' : 'PRIVATE';
|
||||
// Apple iCal on OS X uses X-CALENDARSERVER-ACCESS: CONFIDENTIAL on VCALANDAR (not VEVENT!)
|
||||
if (!$event['public']) $vcal->setAttribute('X-CALENDARSERVER-ACCESS', 'CONFIDENTIAL');
|
||||
break;
|
||||
|
||||
case 'ORGANIZER':
|
||||
// according to iCalendar standard, ORGANIZER not used for events in the own calendar
|
||||
if (!$organizerCN)
|
||||
{
|
||||
$organizerCN = '"' . trim($GLOBALS['egw']->accounts->id2name($event['owner'],'account_firstname')
|
||||
@ -575,7 +556,8 @@ class calendar_ical extends calendar_boupdate
|
||||
$parameters['ATTENDEE'][] = $options;
|
||||
}
|
||||
}
|
||||
if ($this->productManufacturer != 'groupdav' || !$this->check_perms(EGW_ACL_EDIT,$event))
|
||||
// do NOT use ORGANIZER for events without further participants or a different organizer
|
||||
if (count($event['participants']) > 1 || !isset($event['participants'][$event['owner']]))
|
||||
{
|
||||
$attributes['ORGANIZER'] = $organizerURL;
|
||||
$parameters['ORGANIZER']['CN'] = $organizerCN;
|
||||
@ -873,7 +855,11 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$attributes['CREATED'] = $event['created'] ? $event['created'] : $event['modified'];
|
||||
}
|
||||
if ($event['modified'])
|
||||
if ($event['max_user_modified'])
|
||||
{
|
||||
$attributes['LAST-MODIFIED'] = max($event['modified'], $event['max_user_modified']);
|
||||
}
|
||||
elseif ($event['modified'])
|
||||
{
|
||||
$attributes['LAST-MODIFIED'] = $event['modified'];
|
||||
}
|
||||
@ -968,12 +954,12 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
foreach (is_array($value) && $parameters[$key]['VALUE']!='DATE' ? $value : array($value) as $valueID => $valueData)
|
||||
{
|
||||
$valueData = $GLOBALS['egw']->translation->convert($valueData,$GLOBALS['egw']->translation->charset(),$charset);
|
||||
$paramData = (array) $GLOBALS['egw']->translation->convert(is_array($value) ?
|
||||
$valueData = translation::convert($valueData,translation::charset(),$charset);
|
||||
$paramData = (array) translation::convert(is_array($value) ?
|
||||
$parameters[$key][$valueID] : $parameters[$key],
|
||||
$GLOBALS['egw']->translation->charset(),$charset);
|
||||
$valuesData = (array) $GLOBALS['egw']->translation->convert($values[$key],
|
||||
$GLOBALS['egw']->translation->charset(),$charset);
|
||||
translation::charset(),$charset);
|
||||
$valuesData = (array) translation::convert($values[$key],
|
||||
translation::charset(),$charset);
|
||||
$content = $valueData . implode(';', $valuesData);
|
||||
|
||||
if (preg_match('/[^\x20-\x7F]/', $content) ||
|
||||
@ -1080,10 +1066,12 @@ class calendar_ical extends calendar_boupdate
|
||||
* @param int $user=null account_id of owner, default null
|
||||
* @param string $charset The encoding charset for $text. Defaults to
|
||||
* utf-8 for new format, iso-8859-1 for old format.
|
||||
* @param string $caldav_name=null name from CalDAV client or null (to use default)
|
||||
* @return int|boolean cal_id > 0 on success, false on failure or 0 for a failed etag|permission denied
|
||||
*/
|
||||
function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='', $user=null, $charset=null)
|
||||
function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='', $user=null, $charset=null, $caldav_name=null)
|
||||
{
|
||||
//error_log(__METHOD__."(, $cal_id, $etag, $merge, $recur_date, $principalURL, $user, $charset, $caldav_name)");
|
||||
$this->events_imported = 0;
|
||||
$replace = $delete_exceptions= false;
|
||||
|
||||
@ -1286,7 +1274,9 @@ class calendar_ical extends calendar_boupdate
|
||||
// participants OR the event no longer contains participants, add them back
|
||||
unset($event['participants']);
|
||||
}
|
||||
else
|
||||
// since we export now all participants in CalDAV as urn:uuid, if they have no email,
|
||||
// we dont need and dont want that special treatment anymore, as it keeps client from changing resources
|
||||
elseif ($this->productManufacturer != 'groupdav')
|
||||
{
|
||||
foreach ($event_info['stored_event']['participants'] as $uid => $status)
|
||||
{
|
||||
@ -1304,15 +1294,20 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($event['whole_day']) && $event['tzid'] != $event_info['stored_event']['tzid'])
|
||||
/* Modifying an existing event with timezone different from default timezone of user
|
||||
* to a whole-day event (no timezone allowed according to iCal rfc)
|
||||
* --> code to modify start- and end-time here creates a one day longer event!
|
||||
* Skipping that code, creates the event correct in default timezone of user
|
||||
if (!empty($event['whole_day']) && $event['tzid'] != $event_info['stored_event']['tzid'])
|
||||
{
|
||||
// Adjust dates to original TZ
|
||||
$time = new egw_time($event['start'],egw_time::$server_timezone);
|
||||
$time =& $this->so->startOfDay($time, $event_info['stored_event']['tzid']);
|
||||
$event['start'] = egw_time::to($time,'server');
|
||||
$time = new egw_time($event['end'],egw_time::$server_timezone);
|
||||
$time =& $this->so->startOfDay($time, $event_info['stored_event']['tzid']);
|
||||
$time->setTime(23, 59, 59);
|
||||
//$time = new egw_time($event['end'],egw_time::$server_timezone);
|
||||
//$time =& $this->so->startOfDay($time, $event_info['stored_event']['tzid']);
|
||||
//$time->setTime(23, 59, 59);
|
||||
$time->modify('+'.round(($event['end']-$event['start'])/DAY_s).' day');
|
||||
$event['end'] = egw_time::to($time,'server');
|
||||
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
@ -1329,7 +1324,8 @@ class calendar_ical extends calendar_boupdate
|
||||
$time =& $this->so->startOfDay($time, $event_info['stored_event']['tzid']);
|
||||
$event['recurrence'] = egw_time::to($time,'server');
|
||||
}
|
||||
}
|
||||
error_log(__METHOD__."() TZ adjusted {$event_info['stored_event']['tzid']} --> {$event['tzid']} event=".array2string($event));
|
||||
}*/
|
||||
|
||||
calendar_rrule::rrule2tz($event, $event_info['stored_event']['start'],
|
||||
$event_info['stored_event']['tzid']);
|
||||
@ -1338,10 +1334,19 @@ class calendar_ical extends calendar_boupdate
|
||||
// avoid that iCal changes the organizer, which is not allowed
|
||||
$event['owner'] = $event_info['stored_event']['owner'];
|
||||
}
|
||||
$event['caldav_name'] = $event_info['stored_event']['caldav_name'];
|
||||
|
||||
// as we no longer export event owner/ORGANIZER as only participant, we have to re-add owner as participant
|
||||
// to not loose him, as EGroupware knows events without owner/ORGANIZER as participant
|
||||
if (isset($event_info['stored_event']['participants'][$event['owner']]) && !isset($event['participants'][$event['owner']]))
|
||||
{
|
||||
$event['participant'][$event['owner']] = $event_info['stored_event']['participants'][$event['owner']];
|
||||
}
|
||||
}
|
||||
else // common adjustments for new events
|
||||
{
|
||||
unset($event['id']);
|
||||
if ($caldav_name) $event['caldav_name'] = $caldav_name;
|
||||
// set non blocking all day depending on the user setting
|
||||
if (!empty($event['whole_day']) && $this->nonBlockingAllday)
|
||||
{
|
||||
@ -1380,11 +1385,15 @@ class calendar_ical extends calendar_boupdate
|
||||
|
||||
if (!$event['participants']
|
||||
|| !is_array($event['participants'])
|
||||
|| !count($event['participants']))
|
||||
|| !count($event['participants'])
|
||||
// for new events, allways add owner as participant. Users expect to participate too, if they invite further participants.
|
||||
// They can now only remove themselfs, if that is desired, after storing the event first.
|
||||
|| !isset($event['participants'][$event['owner']]))
|
||||
{
|
||||
$status = $event['owner'] == $this->user ? 'A' : 'U';
|
||||
$status = calendar_so::combine_status($status, 1, 'CHAIR');
|
||||
$event['participants'] = array($event['owner'] => $status);
|
||||
if (!is_array($event['participants'])) $event['participants'] = array();
|
||||
$event['participants'][$event['owner']] = $status;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1730,7 +1739,8 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
}
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
return $return_id;
|
||||
|
||||
return $updated_id === 0 ? 0 : $return_id;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2165,7 +2175,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
if (($event = $this->_ical2egw_callback($component,$this->tzid,$principalURL)))
|
||||
{
|
||||
$events[] = $event;
|
||||
$events[] = $event;
|
||||
}
|
||||
}
|
||||
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
@ -2191,7 +2201,7 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
|
||||
if (!is_a($component, 'Horde_iCalendar_vevent') ||
|
||||
!($event = $this->vevent2egw($component, $component->getAttribute('VERSION'), $this->supportedFields, $principalURL)))
|
||||
!($event = $this->vevent2egw($component, $component->_container->getAttribute('VERSION'), $this->supportedFields, $principalURL)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -2230,13 +2240,14 @@ class calendar_ical extends calendar_boupdate
|
||||
* @param array $component VEVENT
|
||||
* @param string $version vCal version (1.0/2.0)
|
||||
* @param array $supportedFields supported fields of the device
|
||||
* @param string $principalURL='' Used for CalDAV imports
|
||||
* @param string $principalURL='' Used for CalDAV imports, no longer used in favor of groupdav_principals::url2uid()
|
||||
* @param string $check_component='Horde_iCalendar_vevent'
|
||||
*
|
||||
* @return array|boolean event on success, false on failure
|
||||
*/
|
||||
function vevent2egw(&$component, $version, $supportedFields, $principalURL='')
|
||||
function vevent2egw(&$component, $version, $supportedFields, $principalURL='', $check_component='Horde_iCalendar_vevent')
|
||||
{
|
||||
if (!is_a($component, 'Horde_iCalendar_vevent'))
|
||||
if ($check_component && !is_a($component, $check_component))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
@ -2352,6 +2363,16 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
switch ($attributes['name'])
|
||||
{
|
||||
case 'DURATION': // clients can use DTSTART+DURATION, instead of DTSTART+DTEND
|
||||
if (!isset($vcardData['end']))
|
||||
{
|
||||
$vcardData['end'] = $vcardData['start'] + $attributes['value'];
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log(__METHOD__."() find DTEND AND DURATION --> ignoring DURATION");
|
||||
}
|
||||
break;
|
||||
case 'X-MICROSOFT-CDO-ALLDAYEVENT':
|
||||
$event['whole_day'] = true;
|
||||
break;
|
||||
@ -2671,8 +2692,18 @@ class calendar_ical extends calendar_boupdate
|
||||
$vcardData['category'] = array();
|
||||
}
|
||||
break;
|
||||
case 'ATTENDEE':
|
||||
case 'ORGANIZER':
|
||||
$event['organizer'] = $attributes['value']; // no egw field, but needed in AS
|
||||
if (strtoupper(substr($event['organizer'],0,7)) == 'MAILTO:')
|
||||
{
|
||||
$event['organizer'] = substr($event['organizer'],7);
|
||||
}
|
||||
if (!empty($attributes['params']['CN']))
|
||||
{
|
||||
$event['organizer'] = $attributes['params']['CN'].' <'.$event['organizer'].'>';
|
||||
}
|
||||
// fall throught
|
||||
case 'ATTENDEE':
|
||||
if (isset($attributes['params']['PARTSTAT']))
|
||||
{
|
||||
$attributes['params']['STATUS'] = $attributes['params']['PARTSTAT'];
|
||||
@ -2693,29 +2724,6 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$role = $attributes['params']['ROLE'];
|
||||
}
|
||||
// try pricipal url from CalDAV
|
||||
if (strpos($attributes['value'], 'http') === 0)
|
||||
{
|
||||
if (!empty($principalURL) && strstr($attributes['value'], $principalURL) !== false)
|
||||
{
|
||||
$uid = $this->user;
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. "(): Found myself: '$uid'\n",3,$this->logfile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
||||
. '(): Unknown URI: ' . $attributes['value']
|
||||
. "\n",3,$this->logfile);
|
||||
}
|
||||
$attributes['value'] = '';
|
||||
}
|
||||
}
|
||||
// parse email and cn from attendee
|
||||
if (preg_match('/MAILTO:([@.a-z0-9_-]+)|MAILTO:"?([.a-z0-9_ -]*)"?[ ]*<([@.a-z0-9_-]*)>/i',
|
||||
$attributes['value'],$matches))
|
||||
@ -2755,6 +2763,9 @@ class calendar_ical extends calendar_boupdate
|
||||
// we use the current user
|
||||
$uid = $this->user;
|
||||
}
|
||||
// check principal url from CalDAV here after X-EGROUPWARE-UID and to get optional X-EGROUPWARE-QUANTITY
|
||||
if (!$uid) $uid = groupdav_principals::url2uid($attributes['value']);
|
||||
|
||||
// try to find an email address
|
||||
if (!$uid && $email && ($uid = $GLOBALS['egw']->accounts->name2id($email, 'account_email')))
|
||||
{
|
||||
@ -2990,6 +3001,14 @@ class calendar_ical extends calendar_boupdate
|
||||
$event['recur_enddate'] = egw_time::to($last, 'server');
|
||||
}
|
||||
|
||||
// Apple iCal on OS X uses X-CALENDARSERVER-ACCESS: CONFIDENTIAL on VCALANDAR (not VEVENT!)
|
||||
if (($x_calendarserver_access = $component->_container->getAttribute('X-CALENDARSERVER-ACCESS')) &&
|
||||
!is_a($x_calendarserver_access, 'PEAR_Error'))
|
||||
{
|
||||
$event['public'] = (int)(strtoupper($x_calendarserver_access) == 'PUBLIC');
|
||||
}
|
||||
//error_log(__METHOD__."() X-CALENDARSERVER-ACCESS=".array2string($x_calendarserver_access).' --> public='.array2string($event['public']));
|
||||
|
||||
// if no end is given in iCal we use the default lenght from user prefs
|
||||
// whole day events get one day in calendar_boupdate::save()
|
||||
if (!isset($event['end']))
|
||||
@ -3044,52 +3063,47 @@ class calendar_ical extends calendar_boupdate
|
||||
* @param mixed $end=null end-date, default now+1 month
|
||||
* @param boolean $utc=true if false, use severtime for dates
|
||||
* @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8
|
||||
* @return string
|
||||
* @param mixed $start=null default now
|
||||
* @param string $method='PUBLISH' or eg. 'REPLY'
|
||||
* @param array $extra=null extra attributes to add
|
||||
* X-CALENDARSERVER-MASK-UID can be used to not include an event specified by this uid as busy
|
||||
*/
|
||||
function freebusy($user,$end=null,$utc=true, $charset='UTF-8')
|
||||
function freebusy($user,$end=null,$utc=true, $charset='UTF-8', $start=null, $method='PUBLISH', array $extra=null)
|
||||
{
|
||||
if (!$end) $end = $this->now_su + 100*DAY_s; // default next 100 days
|
||||
if (!$start) $start = time(); // default now
|
||||
if (!$end) $end = time() + 100*DAY_s; // default next 100 days
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal->setAttribute('PRODID','-//eGroupWare//NONSGML eGroupWare Calendar '.$GLOBALS['egw_info']['apps']['calendar']['version'].'//'.
|
||||
$vcal->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Calendar '.$GLOBALS['egw_info']['apps']['calendar']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
$vcal->setAttribute('VERSION','2.0');
|
||||
$vcal->setAttribute('METHOD',$method);
|
||||
|
||||
$vfreebusy = Horde_iCalendar::newComponent('VFREEBUSY',$vcal);
|
||||
$parameters = array(
|
||||
'ORGANIZER' => $GLOBALS['egw']->translation->convert(
|
||||
$GLOBALS['egw']->accounts->id2name($user,'account_firstname').' '.
|
||||
$GLOBALS['egw']->accounts->id2name($user,'account_lastname'),
|
||||
$GLOBALS['egw']->translation->charset(),$charset),
|
||||
if ($uid) $vfreebusy->setAttribute('UID', $uid);
|
||||
|
||||
$attributes = array(
|
||||
'DTSTAMP' => time(),
|
||||
'DTSTART' => $this->date2ts($start,true), // true = server-time
|
||||
'DTEND' => $this->date2ts($end,true), // true = server-time
|
||||
);
|
||||
if ($utc)
|
||||
if (!$utc)
|
||||
{
|
||||
foreach (array(
|
||||
'URL' => $this->freebusy_url($user),
|
||||
'DTSTART' => $this->date2ts($this->now_su,true), // true = server-time
|
||||
'DTEND' => $this->date2ts($end,true), // true = server-time
|
||||
'ORGANIZER' => $GLOBALS['egw']->accounts->id2name($user,'account_email'),
|
||||
'DTSTAMP' => time(),
|
||||
) as $attr => $value)
|
||||
foreach ($attributes as $attr => $value)
|
||||
{
|
||||
$vfreebusy->setAttribute($attr, $value);
|
||||
$attributes[$attr] = date('Ymd\THis', $value);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (is_null($extra)) $extra = array(
|
||||
'URL' => $this->freebusy_url($user),
|
||||
'ORGANIZER' => 'mailto:'.$GLOBALS['egw']->accounts->id2name($user,'account_email'),
|
||||
);
|
||||
foreach($attributes+$extra as $attr => $value)
|
||||
{
|
||||
foreach (array(
|
||||
'URL' => $this->freebusy_url($user),
|
||||
'DTSTART' => date('Ymd\THis',$this->date2ts($this->now_su,true)), // true = server-time
|
||||
'DTEND' => date('Ymd\THis',$this->date2ts($end,true)), // true = server-time
|
||||
'ORGANIZER' => $GLOBALS['egw']->accounts->id2name($user,'account_email'),
|
||||
'DTSTAMP' => date('Ymd\THis',time()),
|
||||
) as $attr => $value)
|
||||
{
|
||||
$vfreebusy->setAttribute($attr, $value);
|
||||
}
|
||||
$vfreebusy->setAttribute($attr, $value);
|
||||
}
|
||||
$fbdata = parent::search(array(
|
||||
'start' => $this->now_su,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'users' => $user,
|
||||
'date_format' => 'server',
|
||||
@ -3100,20 +3114,23 @@ class calendar_ical extends calendar_boupdate
|
||||
foreach ($fbdata as $event)
|
||||
{
|
||||
if ($event['non_blocking']) continue;
|
||||
if ($event['uid'] === $extra['X-CALENDARSERVER-MASK-UID']) continue;
|
||||
|
||||
$fbtype = $event['participants'][$user] == 'T' ? 'BUSY-TENTATIVE' : 'BUSY';
|
||||
|
||||
if ($utc)
|
||||
{
|
||||
$vfreebusy->setAttribute('FREEBUSY',array(array(
|
||||
'start' => $event['start'],
|
||||
'end' => $event['end'],
|
||||
)));
|
||||
)), array('FBTYPE' => $fbtype));
|
||||
}
|
||||
else
|
||||
{
|
||||
$vfreebusy->setAttribute('FREEBUSY',array(array(
|
||||
'start' => date('Ymd\THis',$event['start']),
|
||||
'end' => date('Ymd\THis',$event['end']),
|
||||
)));
|
||||
)), array('FBTYPE' => $fbtype));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
794
calendar/inc/class.calendar_rrule.inc.php
Normal file
794
calendar/inc/class.calendar_rrule.inc.php
Normal file
@ -0,0 +1,794 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Calendar recurrence rules
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) 2009 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* Recurrence rule iterator
|
||||
*
|
||||
* The constructor accepts times only as DateTime (or decendents like egw_date) to work timezone-correct.
|
||||
* The timezone of the event is determined by timezone of the startime, other times get converted to that timezone.
|
||||
*
|
||||
* There's a static factory method calendar_rrule::event2rrule(array $event,$usertime=true), which converts an
|
||||
* event read by calendar_bo::read() or calendar_bo::search() to a rrule iterator.
|
||||
*
|
||||
* The rrule iterator object can be casted to string, to get a human readable description of the rrule.
|
||||
*
|
||||
* There's an interactive test-form, if the class get's called directly: http://localhost/egroupware/calendar/inc/class.calendar_rrule.inc.php
|
||||
*
|
||||
* @todo Integrate iCal import and export, so all recurrence code resides just in this class
|
||||
* @todo Implement COUNT, can be stored in enddate assuming counts are far smaller then timestamps (eg. < 1000 is a count)
|
||||
* @todo Implement WKST (week start day), currently WKST=SU is used (this is not stored in current DB schema, it's a user preference)
|
||||
*/
|
||||
class calendar_rrule implements Iterator
|
||||
{
|
||||
/**
|
||||
* No recurrence
|
||||
*/
|
||||
const NONE = 0;
|
||||
/**
|
||||
* Daily recurrence
|
||||
*/
|
||||
const DAILY = 1;
|
||||
/**
|
||||
* Weekly recurrance on day(s) specified by bitfield in $data
|
||||
*/
|
||||
const WEEKLY = 2;
|
||||
/**
|
||||
* Monthly recurrance iCal: monthly_bymonthday
|
||||
*/
|
||||
const MONTHLY_MDAY = 3;
|
||||
/**
|
||||
* Monthly recurrance iCal: BYDAY (by weekday, eg. 1st Friday of month)
|
||||
*/
|
||||
const MONTHLY_WDAY = 4;
|
||||
/**
|
||||
* Yearly recurrance
|
||||
*/
|
||||
const YEARLY = 5;
|
||||
/**
|
||||
* Translate recure types to labels
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static public $types = Array(
|
||||
self::NONE => 'None',
|
||||
self::DAILY => 'Daily',
|
||||
self::WEEKLY => 'Weekly',
|
||||
self::MONTHLY_WDAY => 'Monthly (by day)',
|
||||
self::MONTHLY_MDAY => 'Monthly (by date)',
|
||||
self::YEARLY => 'Yearly'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array $recur_egw2ical_2_0 converstaion of egw recur-type => ical FREQ
|
||||
*/
|
||||
static private $recur_egw2ical_2_0 = array(
|
||||
self::DAILY => 'DAILY',
|
||||
self::WEEKLY => 'WEEKLY',
|
||||
self::MONTHLY_WDAY => 'MONTHLY', // BYDAY={1..7, -1}{MO..SO, last workday}
|
||||
self::MONTHLY_MDAY => 'MONTHLY', // BYMONHTDAY={1..31, -1 for last day of month}
|
||||
self::YEARLY => 'YEARLY',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array $recur_egw2ical_1_0 converstaion of egw recur-type => ical FREQ
|
||||
*/
|
||||
static private $recur_egw2ical_1_0 = array(
|
||||
self::DAILY => 'D',
|
||||
self::WEEKLY => 'W',
|
||||
self::MONTHLY_WDAY => 'MP', // BYDAY={1..7,-1}{MO..SO, last workday}
|
||||
self::MONTHLY_MDAY => 'MD', // BYMONHTDAY={1..31,-1}
|
||||
self::YEARLY => 'YM',
|
||||
);
|
||||
|
||||
/**
|
||||
* RRule type: NONE, DAILY, WEEKLY, MONTHLY_MDAY, MONTHLY_WDAY, YEARLY
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $type = self::NONE;
|
||||
|
||||
/**
|
||||
* Interval
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $interval = 1;
|
||||
|
||||
/**
|
||||
* Number for monthly byday: 1, ..., 5, -1=last weekday of month
|
||||
*
|
||||
* EGroupware Calendar does NOT explicitly store it, it's only implicitly defined by series start date
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $monthly_byday_num;
|
||||
|
||||
/**
|
||||
* Number for monthly bymonthday: 1, ..., 31, -1=last day of month
|
||||
*
|
||||
* EGroupware Calendar does NOT explicitly store it, it's only implicitly defined by series start date
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $monthly_bymonthday;
|
||||
|
||||
/**
|
||||
* Enddate of recurring event or null, if not ending
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $enddate;
|
||||
/**
|
||||
* Enddate of recurring event, as Ymd integer (eg. 20091111)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $enddate_ymd;
|
||||
|
||||
const SUNDAY = 1;
|
||||
const MONDAY = 2;
|
||||
const TUESDAY = 4;
|
||||
const WEDNESDAY = 8;
|
||||
const THURSDAY = 16;
|
||||
const FRIDAY = 32;
|
||||
const SATURDAY = 64;
|
||||
const WORKDAYS = 62; // Mo, ..., Fr
|
||||
const ALLDAYS = 127;
|
||||
/**
|
||||
* Translate weekday bitmasks to labels
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static public $days = array(
|
||||
self::MONDAY => 'Monday',
|
||||
self::TUESDAY => 'Tuesday',
|
||||
self::WEDNESDAY => 'Wednesday',
|
||||
self::THURSDAY => 'Thursday',
|
||||
self::FRIDAY => 'Friday',
|
||||
self::SATURDAY => 'Saturday',
|
||||
self::SUNDAY => 'Sunday',
|
||||
);
|
||||
/**
|
||||
* Bitmask of valid weekdays for weekly repeating events: self::SUNDAY|...|self::SATURDAY
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $weekdays;
|
||||
|
||||
/**
|
||||
* Array of exception dates (Ymd strings)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $exceptions=array();
|
||||
|
||||
/**
|
||||
* Array of exceptions as DateTime/egw_time objects
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $exceptions_objs=array();
|
||||
|
||||
/**
|
||||
* Starttime of series
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $time;
|
||||
|
||||
/**
|
||||
* Current "position" / time
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $current;
|
||||
|
||||
/**
|
||||
* Last day of the week according to user preferences
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $lastdayofweek;
|
||||
|
||||
/**
|
||||
* Cached timezone data
|
||||
*
|
||||
* @var array id => data
|
||||
*/
|
||||
protected static $tz_cache = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* The constructor accepts on DateTime (or decendents like egw_date) for all times, to work timezone-correct.
|
||||
* The timezone of the event is determined by timezone of $time, other times get converted to that timezone.
|
||||
*
|
||||
* @param DateTime $time start of event in it's own timezone
|
||||
* @param int $type self::NONE, self::DAILY, ..., self::YEARLY
|
||||
* @param int $interval=1 1, 2, ...
|
||||
* @param DateTime $enddate=null enddate or null for no enddate (in which case we user '+5 year' on $time)
|
||||
* @param int $weekdays=0 self::SUNDAY=1|self::MONDAY=2|...|self::SATURDAY=64
|
||||
* @param array $exceptions=null DateTime objects with exceptions
|
||||
*/
|
||||
public function __construct(DateTime $time,$type,$interval=1,DateTime $enddate=null,$weekdays=0,array $exceptions=null)
|
||||
{
|
||||
switch($GLOBALS['egw_info']['user']['preferences']['calendar']['weekdaystarts'])
|
||||
{
|
||||
case 'Sunday':
|
||||
$this->lastdayofweek = self::SATURDAY;
|
||||
break;
|
||||
case 'Saturday':
|
||||
$this->lastdayofweek = self::FRIDAY;
|
||||
break;
|
||||
default: // Monday
|
||||
$this->lastdayofweek = self::SUNDAY;
|
||||
}
|
||||
|
||||
$this->time = $time;
|
||||
|
||||
if (!in_array($type,array(self::NONE, self::DAILY, self::WEEKLY, self::MONTHLY_MDAY, self::MONTHLY_WDAY, self::YEARLY)))
|
||||
{
|
||||
throw new egw_exception_wrong_parameter(__METHOD__."($time,$type,$interval,$enddate,$data,...) type $type is NOT valid!");
|
||||
}
|
||||
$this->type = $type;
|
||||
|
||||
// determine only implicit defined rules for RRULE=MONTHLY,BYDAY={-1, 1, ..., 5}{MO,..,SU}
|
||||
if ($type == self::MONTHLY_WDAY)
|
||||
{
|
||||
// check for last week of month
|
||||
if (($day = $this->time->format('d')) >= 21 && $day > self::daysInMonth($this->time)-7)
|
||||
{
|
||||
$this->monthly_byday_num = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->monthly_byday_num = 1 + floor(($this->time->format('d')-1) / 7);
|
||||
}
|
||||
}
|
||||
elseif($type == self::MONTHLY_MDAY)
|
||||
{
|
||||
$this->monthly_bymonthday = (int)$this->time->format('d');
|
||||
// check for last day of month
|
||||
if ($this->monthly_bymonthday >= 28)
|
||||
{
|
||||
$test = clone $this->time;
|
||||
$test->modify('1 day');
|
||||
if ($test->format('m') != $this->time->format('m'))
|
||||
{
|
||||
$this->monthly_bymonthday = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)$interval < 1)
|
||||
{
|
||||
$interval = 1; // calendar stores no (extra) interval as null, so using default 1 here
|
||||
}
|
||||
$this->interval = (int)$interval;
|
||||
|
||||
$this->enddate = $enddate;
|
||||
// no recurrence --> current date is enddate
|
||||
if ($type == self::NONE)
|
||||
{
|
||||
$enddate = clone $this->time;
|
||||
}
|
||||
// set a maximum of 5 years if no enddate given
|
||||
elseif (is_null($enddate))
|
||||
{
|
||||
$enddate = clone $this->time;
|
||||
$enddate->modify('5 year');
|
||||
}
|
||||
// convert enddate to timezone of time, if necessary
|
||||
else
|
||||
{
|
||||
$enddate->setTimezone($this->time->getTimezone());
|
||||
}
|
||||
$this->enddate_ymd = (int)$enddate->format('Ymd');
|
||||
|
||||
// if no valid weekdays are given for weekly repeating, we use just the current weekday
|
||||
if (!($this->weekdays = (int)$weekdays) && ($type == self::WEEKLY || $type == self::MONTHLY_WDAY))
|
||||
{
|
||||
$this->weekdays = self::getWeekday($this->time);
|
||||
}
|
||||
if ($exceptions)
|
||||
{
|
||||
foreach($exceptions as $exception)
|
||||
{
|
||||
$exception->setTimezone($this->time->getTimezone());
|
||||
$this->exceptions[] = $exception->format('Ymd');
|
||||
}
|
||||
$this->exceptions_objs = $exceptions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of days in month of given date
|
||||
*
|
||||
* @param DateTime $time
|
||||
* @return int
|
||||
*/
|
||||
private static function daysInMonth(DateTime $time)
|
||||
{
|
||||
list($year,$month) = explode('-',$time->format('Y-m'));
|
||||
$last_day = new egw_time();
|
||||
$last_day->setDate($year,$month+1,0);
|
||||
|
||||
return (int)$last_day->format('d');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current element
|
||||
*
|
||||
* @return DateTime
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return clone $this->current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key of the current element, we use a Ymd integer as key
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return (int)$this->current->format('Ymd');
|
||||
}
|
||||
|
||||
/**
|
||||
* Move forward to next recurence, not caring for exceptions
|
||||
*/
|
||||
public function next_no_exception()
|
||||
{
|
||||
switch($this->type)
|
||||
{
|
||||
case self::NONE: // need to add at least one day, to end "series", as enddate == current date
|
||||
case self::DAILY:
|
||||
$this->current->modify($this->interval.' day');
|
||||
break;
|
||||
|
||||
case self::WEEKLY:
|
||||
// advance to next valid weekday
|
||||
do
|
||||
{
|
||||
// interval in weekly means event runs on valid days eg. each 2. week
|
||||
// --> on the last day of the week we have to additionally advance interval-1 weeks
|
||||
if ($this->interval > 1 && self::getWeekday($this->current) == $this->lastdayofweek)
|
||||
{
|
||||
$this->current->modify(($this->interval-1).' week');
|
||||
}
|
||||
$this->current->modify('1 day');
|
||||
//echo __METHOD__.'() '.$this->current->format('l').', '.$this->current.": $this->weekdays & ".self::getWeekday($this->current)."<br />\n";
|
||||
}
|
||||
while(!($this->weekdays & self::getWeekday($this->current)));
|
||||
break;
|
||||
|
||||
case self::MONTHLY_WDAY: // iCal: BYDAY={1, ..., 5, -1}{MO..SO}
|
||||
// advance to start of next month
|
||||
list($year,$month) = explode('-',$this->current->format('Y-m'));
|
||||
$month += $this->interval+($this->monthly_byday_num < 0 ? 1 : 0);
|
||||
$this->current->setDate($year,$month,$this->monthly_byday_num < 0 ? 0 : 1);
|
||||
//echo __METHOD__."() $this->monthly_byday_num".substr(self::$days[$this->monthly_byday_wday],0,2).": setDate($year,$month,1): ".$this->current->format('l').', '.$this->current."<br />\n";
|
||||
// now advance to n-th week
|
||||
if ($this->monthly_byday_num > 1)
|
||||
{
|
||||
$this->current->modify(($this->monthly_byday_num-1).' week');
|
||||
//echo __METHOD__."() $this->monthly_byday_num".substr(self::$days[$this->monthly_byday_wday],0,2).': modify('.($this->monthly_byday_num-1).' week): '.$this->current->format('l').', '.$this->current."<br />\n";
|
||||
}
|
||||
// advance to given weekday
|
||||
while(!($this->weekdays & self::getWeekday($this->current)))
|
||||
{
|
||||
$this->current->modify(($this->monthly_byday_num < 0 ? -1 : 1).' day');
|
||||
//echo __METHOD__."() $this->monthly_byday_num".substr(self::$days[$this->monthly_byday_wday],0,2).': modify(1 day): '.$this->current->format('l').', '.$this->current."<br />\n";
|
||||
}
|
||||
break;
|
||||
|
||||
case self::MONTHLY_MDAY: // iCal: monthly_bymonthday={1, ..., 31, -1}
|
||||
list($year,$month) = explode('-',$this->current->format('Y-m'));
|
||||
$day = $this->monthly_bymonthday+($this->monthly_bymonthday < 0 ? 1 : 0);
|
||||
$month += $this->interval+($this->monthly_bymonthday < 0 ? 1 : 0);
|
||||
$this->current->setDate($year,$month,$day);
|
||||
//echo __METHOD__."() setDate($year,$month,$day): ".$this->current->format('l').', '.$this->current."<br />\n";
|
||||
break;
|
||||
|
||||
case self::YEARLY:
|
||||
$this->current->modify($this->interval.' year');
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new egw_exception_assertion_failed(__METHOD__."() invalid type #$this->type !");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move forward to next recurence, taking into account exceptions
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
do
|
||||
{
|
||||
$this->next_no_exception();
|
||||
}
|
||||
while($this->exceptions && in_array($this->current->format('Ymd'),$this->exceptions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get weekday of $time as self::SUNDAY=1, ..., self::SATURDAY=64 integer mask
|
||||
*
|
||||
* @param DateTime $time
|
||||
* @return int self::SUNDAY=1, ..., self::SATURDAY=64
|
||||
*/
|
||||
static protected function getWeekday(DateTime $time)
|
||||
{
|
||||
//echo __METHOD__.'('.$time->format('l').' '.$time.') 1 << '.$time->format('w').' = '.(1 << (int)$time->format('w'))."<br />\n";
|
||||
return 1 << (int)$time->format('w');
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind the Iterator to the first element (called at beginning of foreach loop)
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->current = clone $this->time;
|
||||
while ($this->valid() &&
|
||||
$this->exceptions &&
|
||||
in_array($this->current->format('Ymd'),$this->exceptions))
|
||||
{
|
||||
$this->next_no_exception();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current position is valid
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function valid ()
|
||||
{
|
||||
return $this->current->format('Ymd') <= $this->enddate_ymd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string represenation of RRule
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function __toString( )
|
||||
{
|
||||
$str = '';
|
||||
// Repeated Events
|
||||
if($this->type != self::NONE)
|
||||
{
|
||||
list($str) = explode(' (',lang(self::$types[$this->type])); // remove (by day/date) from Monthly
|
||||
|
||||
$str_extra = array();
|
||||
switch ($this->type)
|
||||
{
|
||||
case self::MONTHLY_MDAY:
|
||||
$str_extra[] = ($this->monthly_bymonthday == -1 ? lang('last') : $this->monthly_bymonthday.'.').' '.lang('day');
|
||||
break;
|
||||
|
||||
case self::WEEKLY:
|
||||
case self::MONTHLY_WDAY:
|
||||
$repeat_days = array();
|
||||
if ($this->weekdays == self::ALLDAYS)
|
||||
{
|
||||
$repeat_days[] = $this->type == self::WEEKLY ? lang('all') : lang('day');
|
||||
}
|
||||
elseif($this->weekdays == self::WORKDAYS)
|
||||
{
|
||||
$repeat_days[] = $this->type == self::WEEKLY ? lang('workdays') : lang('workday');
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (self::$days as $mask => $label)
|
||||
{
|
||||
if ($this->weekdays & $mask)
|
||||
{
|
||||
$repeat_days[] = lang($label);
|
||||
}
|
||||
}
|
||||
}
|
||||
if($this->type == self::WEEKLY && count($repeat_days))
|
||||
{
|
||||
$str_extra[] = lang('days repeated').': '.implode(', ',$repeat_days);
|
||||
}
|
||||
elseif($this->type == self::MONTHLY_WDAY)
|
||||
{
|
||||
$str_extra[] = ($this->monthly_byday_num == -1 ? lang('last') : $this->monthly_byday_num.'.').' '.implode(', ',$repeat_days);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
if($this->interval > 1)
|
||||
{
|
||||
$str_extra[] = lang('Interval').': '.$this->interval;
|
||||
}
|
||||
if ($this->enddate)
|
||||
{
|
||||
if ($this->enddate->getTimezone()->getName() != egw_time::$user_timezone->getName())
|
||||
{
|
||||
$this->enddate->setTimezone(egw_time::$user_timezone);
|
||||
}
|
||||
$str_extra[] = lang('ends').': '.lang($this->enddate->format('l')).', '.$this->enddate->format(egw_time::$user_dateformat);
|
||||
}
|
||||
if ($this->time->getTimezone()->getName() != egw_time::$user_timezone->getName())
|
||||
{
|
||||
$str_extra[] = $this->time->getTimezone()->getName();
|
||||
}
|
||||
if(count($str_extra))
|
||||
{
|
||||
$str .= ' ('.implode(', ',$str_extra).')';
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a VEVENT RRULE
|
||||
* @param string $version='1.0' could be '2.0', too
|
||||
*
|
||||
* $return array vCalendar RRULE
|
||||
*/
|
||||
public function generate_rrule($version='1.0')
|
||||
{
|
||||
$repeat_days = array();
|
||||
$rrule = array();
|
||||
|
||||
if ($this->type == self::NONE) return false; // no recuring event
|
||||
|
||||
if ($version == '1.0')
|
||||
{
|
||||
$rrule['FREQ'] = self::$recur_egw2ical_1_0[$this->type] . $this->interval;
|
||||
switch ($this->type)
|
||||
{
|
||||
case self::WEEKLY:
|
||||
foreach (self::$days as $mask => $label)
|
||||
{
|
||||
if ($this->weekdays & $mask)
|
||||
{
|
||||
$repeat_days[] = strtoupper(substr($label,0,2));
|
||||
}
|
||||
}
|
||||
$rrule['BYDAY'] = implode(' ', $repeat_days);
|
||||
$rrule['FREQ'] = $rrule['FREQ'].' '.$rrule['BYDAY'];
|
||||
break;
|
||||
|
||||
case self::MONTHLY_MDAY: // date of the month: BYMONTDAY={1..31}
|
||||
break;
|
||||
|
||||
case self::MONTHLY_WDAY: // weekday of the month: BDAY={1..5}+ {MO..SO}
|
||||
$rrule['BYDAY'] = abs($this->monthly_byday_num);
|
||||
$rrule['BYDAY'] .= ($this->monthly_byday_num < 0) ? '- ' : '+ ';
|
||||
$rrule['BYDAY'] .= strtoupper(substr($this->time->format('l'),0,2));
|
||||
$rrule['FREQ'] = $rrule['FREQ'].' '.$rrule['BYDAY'];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$this->enddate)
|
||||
{
|
||||
$rrule['UNTIL'] = '#0';
|
||||
}
|
||||
}
|
||||
else // $version == '2.0'
|
||||
{
|
||||
$rrule['FREQ'] = self::$recur_egw2ical_2_0[$this->type];
|
||||
switch ($this->type)
|
||||
{
|
||||
case self::WEEKLY:
|
||||
foreach (self::$days as $mask => $label)
|
||||
{
|
||||
if ($this->weekdays & $mask)
|
||||
{
|
||||
$repeat_days[] = strtoupper(substr($label,0,2));
|
||||
}
|
||||
}
|
||||
$rrule['BYDAY'] = implode(',', $repeat_days);
|
||||
break;
|
||||
|
||||
case self::MONTHLY_MDAY: // date of the month: BYMONTDAY={1..31}
|
||||
$rrule['BYMONTHDAY'] = $this->monthly_bymonthday;
|
||||
break;
|
||||
|
||||
case MCAL_RECUR_MONTHLY_WDAY: // weekday of the month: BDAY={1..5}{MO..SO}
|
||||
$rrule['BYDAY'] = $this->monthly_byday_num .
|
||||
strtoupper(substr($this->time->format('l'),0,2));
|
||||
break;
|
||||
}
|
||||
if ($this->interval > 1)
|
||||
{
|
||||
$rrule['INTERVAL'] = $this->interval;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->enddate)
|
||||
{
|
||||
$this->rewind();
|
||||
$enddate = $this->current();
|
||||
do
|
||||
{
|
||||
$this->next_no_exception();
|
||||
$occurrence = $this->current();
|
||||
}
|
||||
while ($this->valid() && ($enddate = $occurrence));
|
||||
$rrule['UNTIL'] = $enddate;
|
||||
}
|
||||
|
||||
return $rrule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get instance for a given event array
|
||||
*
|
||||
* @param array $event
|
||||
* @param boolean $usertime=true true: event timestamps are usertime (default for calendar_bo::(read|search), false: servertime
|
||||
* @param string $to_tz timezone for exports (null for event's timezone)
|
||||
*
|
||||
* @return calendar_rrule false on error
|
||||
*/
|
||||
public static function event2rrule(array $event,$usertime=true,$to_tz=null)
|
||||
{
|
||||
if (!is_array($event) || !isset($event['tzid'])) return false;
|
||||
if (!$to_tz) $to_tz = $event['tzid'];
|
||||
$timestamp_tz = $usertime ? egw_time::$user_timezone : egw_time::$server_timezone;
|
||||
$time = is_a($event['start'],'DateTime') ? $event['start'] : new egw_time($event['start'],$timestamp_tz);
|
||||
|
||||
if (!isset(self::$tz_cache[$to_tz]))
|
||||
{
|
||||
self::$tz_cache[$to_tz] = calendar_timezones::DateTimeZone($to_tz);
|
||||
}
|
||||
|
||||
self::rrule2tz($event, $time, $to_tz);
|
||||
|
||||
$time->setTimezone(self::$tz_cache[$to_tz]);
|
||||
|
||||
if ($event['recur_enddate'])
|
||||
{
|
||||
$enddate = is_a($event['recur_enddate'],'DateTime') ? $event['recur_enddate'] : new egw_time($event['recur_enddate'],$timestamp_tz);
|
||||
}
|
||||
if (is_array($event['recur_exception']))
|
||||
{
|
||||
foreach($event['recur_exception'] as $exception)
|
||||
{
|
||||
$exceptions[] = is_a($exception,'DateTime') ? $exception : new egw_time($exception,$timestamp_tz);
|
||||
}
|
||||
}
|
||||
return new calendar_rrule($time,$event['recur_type'],$event['recur_interval'],$enddate,$event['recur_data'],$exceptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recurrence data (keys 'recur_*') to merge into an event
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rrule2event()
|
||||
{
|
||||
return array(
|
||||
'recur_type' => $this->type,
|
||||
'recur_interval' => $this->interval,
|
||||
'recur_enddate' => $this->enddate ? $this->enddate->format('ts') : null,
|
||||
'recur_data' => $this->weekdays,
|
||||
'recur_exception' => $this->exceptions,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift a recurrence rule to a new timezone
|
||||
*
|
||||
* @param array $event recurring event
|
||||
* @param DateTime/string starttime of the event (in servertime)
|
||||
* @param string $to_tz new timezone
|
||||
*/
|
||||
public static function rrule2tz(array &$event,$starttime,$to_tz)
|
||||
{
|
||||
// We assume that the difference between timezones can result
|
||||
// in a maximum of one day
|
||||
|
||||
if (!is_array($event) ||
|
||||
!isset($event['recur_type']) ||
|
||||
$event['recur_type'] == MCAL_RECUR_NONE ||
|
||||
empty($event['recur_data']) || $event['recur_data'] == ALLDAYS ||
|
||||
empty($event['tzid']) || empty($to_tz) ||
|
||||
$event['tzid'] == $to_tz) return;
|
||||
|
||||
if (!isset(self::$tz_cache[$event['tzid']]))
|
||||
{
|
||||
self::$tz_cache[$event['tzid']] = calendar_timezones::DateTimeZone($event['tzid']);
|
||||
}
|
||||
if (!isset(self::$tz_cache[$to_tz]))
|
||||
{
|
||||
self::$tz_cache[$to_tz] = calendar_timezones::DateTimeZone($to_tz);
|
||||
}
|
||||
|
||||
$time = is_a($starttime,'DateTime') ?
|
||||
$starttime : new egw_time($starttime, egw_time::$server_timezone);
|
||||
$time->setTimezone(self::$tz_cache[$event['tzid']]);
|
||||
$remote = clone $time;
|
||||
$remote->setTimezone(self::$tz_cache[$to_tz]);
|
||||
$delta = (int)$remote->format('w') - (int)$time->format('w');
|
||||
if ($delta)
|
||||
{
|
||||
// We have to generate a shifted rrule
|
||||
switch ($event['recur_type'])
|
||||
{
|
||||
case self::MONTHLY_WDAY:
|
||||
case self::WEEKLY:
|
||||
$mask = (int)$event['recur_data'];
|
||||
|
||||
if ($delta == 1 || $delta == -6)
|
||||
{
|
||||
$mask = $mask << 1;
|
||||
if ($mask & 128) $mask = $mask - 127; // overflow
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($mask & 1) $mask = $mask + 128; // underflow
|
||||
$mask = $mask >> 1;
|
||||
}
|
||||
$event['recur_data'] = $mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__) // some tests
|
||||
{
|
||||
ini_set('display_errors',1);
|
||||
error_reporting(E_ALL & ~E_NOTICE);
|
||||
function lang($str) { return $str; }
|
||||
$GLOBALS['egw_info']['user']['preferences']['common']['tz'] = $_REQUEST['user-tz'] ? $_REQUEST['user-tz'] : 'Europe/Berlin';
|
||||
require_once('../../phpgwapi/inc/class.egw_time.inc.php');
|
||||
require_once('../../phpgwapi/inc/class.html.inc.php');
|
||||
require_once('../../phpgwapi/inc/class.egw_exception.inc.php');
|
||||
|
||||
if (!isset($_REQUEST['time']))
|
||||
{
|
||||
$now = new egw_time('now',new DateTimeZone($_REQUEST['tz'] = 'UTC'));
|
||||
$_REQUEST['time'] = $now->format();
|
||||
$_REQUEST['type'] = calendar_rrule::WEEKLY;
|
||||
$_REQUEST['interval'] = 2;
|
||||
$now->modify('2 month');
|
||||
$_REQUEST['enddate'] = $now->format('Y-m-d');
|
||||
$_REQUEST['user-tz'] = 'Europe/Berlin';
|
||||
}
|
||||
echo "<html>\n<head>\n\t<title>Test calendar_rrule class</title>\n</head>\n<body>\n<form method='GET'>\n";
|
||||
echo "<p>Date+Time: ".html::input('time',$_REQUEST['time']).
|
||||
html::select('tz',$_REQUEST['tz'],egw_time::getTimezones())."</p>\n";
|
||||
echo "<p>Type: ".html::select('type',$_REQUEST['type'],calendar_rrule::$types)."\n".
|
||||
"Interval: ".html::input('interval',$_REQUEST['interval'])."</p>\n";
|
||||
echo "<table><tr><td>\n";
|
||||
echo "Weekdays:<br />".html::checkbox_multiselect('weekdays',$_REQUEST['weekdays'],calendar_rrule::$days,false,'','7',false,'height: 150px;')."\n";
|
||||
echo "</td><td>\n";
|
||||
echo "<p>Exceptions:<br />".html::textarea('exceptions',$_REQUEST['exceptions'],'style="height: 150px;"')."\n";
|
||||
echo "</td></tr></table>\n";
|
||||
echo "<p>Enddate: ".html::input('enddate',$_REQUEST['enddate'])."</p>\n";
|
||||
echo "<p>Display recurances in ".html::select('user-tz',$_REQUEST['user-tz'],egw_time::getTimezones())."</p>\n";
|
||||
echo "<p>".html::submit_button('calc','Calculate')."</p>\n";
|
||||
echo "</form>\n";
|
||||
|
||||
$tz = new DateTimeZone($_REQUEST['tz']);
|
||||
$time = new egw_time($_REQUEST['time'],$tz);
|
||||
if ($_REQUEST['enddate']) $enddate = new egw_time($_REQUEST['enddate'],$tz);
|
||||
$weekdays = 0; foreach((array)$_REQUEST['weekdays'] as $mask) $weekdays |= $mask;
|
||||
if ($_REQUEST['exceptions']) foreach(preg_split("/[,\r\n]+ ?/",$_REQUEST['exceptions']) as $exception) $exceptions[] = new egw_time($exception);
|
||||
|
||||
$rrule = new calendar_rrule($time,$_REQUEST['type'],$_REQUEST['interval'],$enddate,$weekdays,$exceptions);
|
||||
echo "<h3>".$time->format('l').', '.$time.' ('.$tz->getName().') '.$rrule."</h3>\n";
|
||||
foreach($rrule as $rtime)
|
||||
{
|
||||
$rtime->setTimezone(egw_time::$user_timezone);
|
||||
echo ++$n.': '.$rtime->format('l').', '.$rtime."<br />\n";
|
||||
}
|
||||
echo "</body>\n</html>\n";
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Calendar's storage-object
|
||||
* EGroupware - Calendar's storage-object
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
@ -64,6 +64,9 @@ define('WEEK_s',7*DAY_s);
|
||||
* UI only operates in user-time, so there have to be no conversation at all !!!
|
||||
* BO's functions take and return user-time only (!), they convert internaly everything to servertime, because
|
||||
* SO operates only on server-time
|
||||
*
|
||||
* DB-model uses egw_cal_user.cal_status='X' for participants who got deleted. They never get returned by
|
||||
* read or search methods, but influence the ctag of the deleted users calendar!
|
||||
*/
|
||||
class calendar_so
|
||||
{
|
||||
@ -98,7 +101,6 @@ class calendar_so
|
||||
*/
|
||||
protected static $tz_cache = array();
|
||||
|
||||
|
||||
/**
|
||||
* Constructor of the socal class
|
||||
*/
|
||||
@ -122,7 +124,7 @@ class calendar_so
|
||||
*
|
||||
* @param int|array|string $ids id or array of id's of the entries to read, or string with a single uid
|
||||
* @param int $recur_date=0 if set read the next recurrence at or after the timestamp, default 0 = read the initital one
|
||||
* @return array|boolean array with id => data pairs or false if entry not found
|
||||
* @return array|boolean array with cal_id => event array pairs or false if entry not found
|
||||
*/
|
||||
function read($ids,$recur_date=0)
|
||||
{
|
||||
@ -143,23 +145,29 @@ class calendar_so
|
||||
$group_by_cols .= ','.$this->repeats_table.'.'.implode(','.$this->repeats_table.'.',array_keys($table_def['fd']));
|
||||
|
||||
$where = array();
|
||||
if (is_array($ids))
|
||||
{
|
||||
array_walk($ids,create_function('&$val,$key','$val = (int) $val;'));
|
||||
|
||||
$where[] = $this->cal_table.'.cal_id IN ('.implode(',',$ids).')';
|
||||
}
|
||||
elseif (is_numeric($ids))
|
||||
{
|
||||
$where[] = $this->cal_table.'.cal_id = '.(int) $ids;
|
||||
}
|
||||
else
|
||||
if (is_scalar($ids) && !is_numeric($ids)) // a single uid
|
||||
{
|
||||
// We want only the parents to match
|
||||
$where['cal_uid'] = $ids;
|
||||
$where['cal_reference'] = 0;
|
||||
$where['cal_recurrence'] = 0;
|
||||
}
|
||||
elseif(is_array($ids) && isset($ids[count($ids)-1]) || is_scalar($ids)) // one or more cal_id's
|
||||
{
|
||||
$where['cal_id'] = $ids;
|
||||
}
|
||||
else // array with column => value pairs
|
||||
{
|
||||
$where = $ids;
|
||||
unset($ids); // otherwise users get not read!
|
||||
}
|
||||
if (isset($where['cal_id'])) // prevent non-unique column-name cal_id
|
||||
{
|
||||
$where[] = $this->db->expression($this->cal_table, $this->cal_table.'.',array(
|
||||
'cal_id' => $where['cal_id'],
|
||||
));
|
||||
unset($where['cal_id']);
|
||||
}
|
||||
if ((int) $recur_date)
|
||||
{
|
||||
$where[] = 'cal_start >= '.(int)$recur_date;
|
||||
@ -196,11 +204,17 @@ class calendar_so
|
||||
sort($event['recur_exception']);
|
||||
if ($event['recur_exception'][0] < $event['start'])
|
||||
{
|
||||
// leading exceptions => move start and end
|
||||
$event['end'] -= $event['start'] - $event['recur_exception'][0];
|
||||
$event['start'] = $event['recur_exception'][0];
|
||||
/* Do NOT move start- and end-date, to the earliest exception, as they will NOT be found in CalDAV or ActiveSync, because
|
||||
* we only recognice recuring events which start before or in the current timerange and end in or after it or have no end-date.
|
||||
* --> give an error message, as it is a debuging/support nightmare, if this get's silently fixed when reading events.
|
||||
* No idea how this situation (exceptions before startdate) can be created anyway.
|
||||
*
|
||||
* $event['end'] -= $event['start'] - $event['recur_exception'][0];
|
||||
* $event['start'] = $event['recur_exception'][0];
|
||||
*/
|
||||
error_log(__METHOD__."() recuring event #$event[id]: $event[title] has exceptions before it's startdate ".date('Y-m-d H:i:s',$event['start']));
|
||||
}
|
||||
}
|
||||
}//*/
|
||||
}
|
||||
|
||||
// check if we have a real recurance, if not set $recur_date=0
|
||||
@ -217,11 +231,13 @@ class calendar_so
|
||||
}
|
||||
}
|
||||
|
||||
$need_max_user_modified = array();
|
||||
// participants, if a recur_date give, we read that recurance, plus the one users from the default entry with recur_date=0
|
||||
// sorting by cal_recur_date ASC makes sure recurence status always overwrites series status
|
||||
foreach($this->db->select($this->user_table,'*',array(
|
||||
'cal_id' => $ids,
|
||||
'cal_recur_date' => $recur_date,
|
||||
"cal_status != 'X'",
|
||||
),__LINE__,__FILE__,false,'ORDER BY cal_user_type DESC,cal_recur_date ASC,'.self::STATUS_SORT,'calendar') as $row) // DESC puts users before resources and contacts
|
||||
{
|
||||
// combine all participant data in uid and status values
|
||||
@ -230,6 +246,23 @@ class calendar_so
|
||||
|
||||
$events[$row['cal_id']]['participants'][$uid] = $status;
|
||||
$events[$row['cal_id']]['participant_types'][$row['cal_user_type']][$row['cal_user_id']] = $status;
|
||||
|
||||
if ($events[$row['cal_id']]['recur_type'])
|
||||
{
|
||||
$need_max_user_modified[$row['cal_id']] = $row['cal_id'];
|
||||
}
|
||||
elseif (($modified = $this->db->from_timestamp($row['cal_user_modified'])) > $events[$row['cal_id']]['max_user_modified'])
|
||||
{
|
||||
$events[$row['cal_id']]['max_user_modified'] = $modified;
|
||||
}
|
||||
}
|
||||
// max_user_modified for recurring events has to include all recurrences, above code only querys $recur_date!
|
||||
if ($need_max_user_modified)
|
||||
{
|
||||
foreach($this->max_user_modified($need_max_user_modified) as $id => $modified)
|
||||
{
|
||||
$events[$id]['max_user_modified'] = $modified;
|
||||
}
|
||||
}
|
||||
|
||||
// custom fields
|
||||
@ -260,18 +293,21 @@ class calendar_so
|
||||
* This includes ALL recurences of an event series
|
||||
*
|
||||
* @param int|array $ids one or multiple cal_id's
|
||||
* @param booelan $return_maximum=false if true return only the maximum, even for multiple ids
|
||||
* @param boolean $return_maximum=false if true return only the maximum, even for multiple ids
|
||||
* @param boolean $master_only=false only check recurance master (egw_cal_user.recur_date=0)
|
||||
* @return int|array (array of) modification timestamp(s)
|
||||
*/
|
||||
function max_user_modified($ids, $return_maximum=false)
|
||||
function max_user_modified($ids, $return_maximum=false, $master_only=false)
|
||||
{
|
||||
if (!is_array($ids) || count($ids) == 1) $return_maximum = true;
|
||||
if (!is_array($ids)) $return_maximum = true;
|
||||
|
||||
$where = array('cal_id' => $ids);
|
||||
if ($master_only) $where['cal_recur_date'] = 0;
|
||||
|
||||
if ($return_maximum)
|
||||
{
|
||||
if (($etags = $this->db->select($this->user_table,'MAX(cal_user_modified)',array(
|
||||
'cal_id' => $ids,
|
||||
),__LINE__,__FILE__,false,'','calendar')->fetchColumn()))
|
||||
if (($etags = $this->db->select($this->user_table,'MAX(cal_user_modified)',$where,
|
||||
__LINE__,__FILE__,false,'','calendar')->fetchColumn()))
|
||||
{
|
||||
$etags = $this->db->from_timestamp($etags);
|
||||
}
|
||||
@ -279,15 +315,13 @@ class calendar_so
|
||||
else
|
||||
{
|
||||
$etags = array();
|
||||
foreach($this->db->select($this->user_table,'cal_id,MAX(cal_user_modified) AS user_etag',array(
|
||||
'cal_id' => $ids,
|
||||
),__LINE__,__FILE__,false,'GROUP BY cal_id','calendar') as $row)
|
||||
foreach($this->db->select($this->user_table,'cal_id,MAX(cal_user_modified) AS user_etag',$where,
|
||||
__LINE__,__FILE__,false,'GROUP BY cal_id','calendar') as $row)
|
||||
{
|
||||
$etags[$row['cal_id']] = $this->db->from_timestamp($row['user_etag']);
|
||||
}
|
||||
}
|
||||
//echo "<p>".__METHOD__.'('.array2string($ids).','.array($return_maximum).') = '.array2string($etags)."</p>\n";
|
||||
//error_log(__METHOD__.'('.array2string($ids).','.array2string($return_maximum).') = '.array2string($etags));
|
||||
//error_log(__METHOD__.'('.array2string($ids).', '.array2string($return_maximum).', '.array2string($master_only).') = '.array2string($etags).' '.function_backtrace());
|
||||
return $etags;
|
||||
}
|
||||
|
||||
@ -298,14 +332,19 @@ class calendar_so
|
||||
*
|
||||
* @param int|array $users one or mulitple calendar users
|
||||
* @param booelan $owner_too=false if true return also events owned by given users
|
||||
* @param boolean $master_only=false only check recurance master (egw_cal_user.recur_date=0)
|
||||
* @return int maximum modification timestamp
|
||||
*/
|
||||
function get_ctag($users, $owner_too=false)
|
||||
function get_ctag($users, $owner_too=false,$master_only=false)
|
||||
{
|
||||
$where = array(
|
||||
'cal_user_type' => 'u',
|
||||
'cal_user_id' => $users,
|
||||
);
|
||||
if ($master_only)
|
||||
{
|
||||
$where['cal_recur_date'] = 0;
|
||||
}
|
||||
if ($owner_too)
|
||||
{
|
||||
// owner can only by users, no groups
|
||||
@ -341,7 +380,7 @@ class calendar_so
|
||||
{
|
||||
$cats = $GLOBALS['egw']->categories->return_all_children($cat_id);
|
||||
array_walk($cats,create_function('&$val,$key','$val = (int) $val;'));
|
||||
|
||||
if (is_array($cat_id) && count($cat_id)==1) $cat_id = $cat_id[0];
|
||||
$sql = '(cal_category'.(count($cats) > 1 ? " IN ('".implode("','",$cats)."')" : '='.$this->db->quote((int)$cat_id));
|
||||
foreach($cats as $cat)
|
||||
{
|
||||
@ -360,36 +399,43 @@ class calendar_so
|
||||
* @param int|array $users user-id or array of user-id's, !$users means all entries regardless of users
|
||||
* @param int|array $cat_id=0 mixed category-id or array of cat-id's (incl. all sub-categories), default 0 = all
|
||||
* @param string $filter='all' string filter-name: all (not rejected), accepted, unknown, tentative, rejected or hideprivate (handled elsewhere!)
|
||||
* @param string $query='' pattern so search for, if unset or empty all matching entries are returned (no search)
|
||||
* Please Note: a search never returns repeating events more then once AND does not honor start+end date !!!
|
||||
* @param int|boolean $offset=False offset for a limited query or False (default)
|
||||
* @param int $num_rows=0 number of rows to return if offset set, default 0 = use default in user prefs
|
||||
* @param string $order='cal_start' column-names plus optional DESC|ASC separted by comma
|
||||
* @param string $sql_filter='' sql to be and'ed into query (fully quoted)
|
||||
* @param string|array $_cols=null what to select, default "$this->repeats_table.*,$this->cal_table.*,cal_start,cal_end,cal_recur_date",
|
||||
* @param array $params=array()
|
||||
* @param string|array $params['query'] string: pattern so search for, if unset or empty all matching entries are returned (no search)
|
||||
* Please Note: a search never returns repeating events more then once AND does not honor start+end date !!!
|
||||
* array: everything is directly used as $where
|
||||
* @param string $params['order']='cal_start' column-names plus optional DESC|ASC separted by comma
|
||||
* @param string $params['sql_filter'] sql to be and'ed into query (fully quoted)
|
||||
* @param string|array $params['cols'] what to select, default "$this->repeats_table.*,$this->cal_table.*,cal_start,cal_end,cal_recur_date",
|
||||
* if specified and not false an iterator for the rows is returned
|
||||
* @param string $append='' SQL to append to the query before $order, eg. for a GROUP BY clause
|
||||
* @param array $cfs=null custom fields to query, null = none, array() = all, or array with cfs names
|
||||
* @param string $params['append'] SQL to append to the query before $order, eg. for a GROUP BY clause
|
||||
* @param array $params['cfs'] custom fields to query, null = none, array() = all, or array with cfs names
|
||||
* @param array $params['users'] raw parameter as passed to calendar_bo::search() no memberships resolved!
|
||||
* @param boolean $params['master_only']=false, true only take into account participants/status from master (for AS)
|
||||
* @param int $remove_rejected_by_user=null add join to remove entry, if given user has rejected it
|
||||
* @return array of cal_ids, or false if error in the parameters
|
||||
*
|
||||
* ToDo: search custom-fields too
|
||||
*/
|
||||
function &search($start,$end,$users,$cat_id=0,$filter='all',$query='',$offset=False,$num_rows=0,$order='cal_start',$sql_filter='',$_cols=null,$append='',$cfs=null)
|
||||
function &search($start,$end,$users,$cat_id=0,$filter='all',$offset=False,$num_rows=0,array $params=array(),$remove_rejected_by_user=null)
|
||||
{
|
||||
//echo '<p>'.__METHOD__.'('.($start ? date('Y-m-d H:i',$start) : '').','.($end ? date('Y-m-d H:i',$end) : '').','.array2string($users).','.array2string($cat_id).",'$filter',".array2string($query).",$offset,$num_rows,$order,$show_rejected,".array2string($_cols).",$append,".array2string($cfs).")</p>\n";
|
||||
//error_log(__METHOD__.'('.($start ? date('Y-m-d H:i',$start) : '').','.($end ? date('Y-m-d H:i',$end) : '').','.array2string($users).','.array2string($cat_id).",'$filter',".array2string($offset).",$num_rows,".array2string($params).') '.function_backtrace());
|
||||
|
||||
$cols = !is_null($_cols) ? $_cols : "$this->repeats_table.*,$this->cal_table.*,cal_start,cal_end,cal_recur_date";
|
||||
$cols = self::get_columns('calendar', $this->cal_table);
|
||||
$cols[0] = $this->db->to_varchar($this->cal_table.'.cal_id');
|
||||
$cols = isset($params['cols']) ? $params['cols'] : "$this->repeats_table.recur_type,$this->repeats_table.recur_enddate,$this->repeats_table.recur_interval,$this->repeats_table.recur_data,$this->repeats_table.recur_exception,".implode(',',$cols).",cal_start,cal_end,$this->user_table.cal_recur_date";
|
||||
|
||||
$where = array();
|
||||
if (is_array($query))
|
||||
if (is_array($params['query']))
|
||||
{
|
||||
$where = $query;
|
||||
$where = $params['query'];
|
||||
}
|
||||
elseif ($query)
|
||||
elseif ($params['query'])
|
||||
{
|
||||
foreach(array('cal_title','cal_description','cal_location') as $col)
|
||||
{
|
||||
$to_or[] = $col.' '.$this->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote('%'.$query.'%');
|
||||
$to_or[] = $col.' '.$this->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote('%'.$params['query'].'%');
|
||||
}
|
||||
$where[] = '('.implode(' OR ',$to_or).')';
|
||||
|
||||
@ -402,9 +448,9 @@ class calendar_so
|
||||
$private_filter = '(cal_public=1 OR cal_public=0 AND '.$this->db->expression($this->cal_table, array('cal_owner' => $params['private_grants'])) . ')';
|
||||
$where[] = $private_filter;
|
||||
}
|
||||
if (!empty($sql_filter) && is_string($sql_filter))
|
||||
if (!empty($params['sql_filter']) && is_string($params['sql_filter']))
|
||||
{
|
||||
$where[] = $sql_filter;
|
||||
$where[] = $params['sql_filter'];
|
||||
}
|
||||
if ($users)
|
||||
{
|
||||
@ -420,7 +466,8 @@ class calendar_so
|
||||
$users_by_type[$user[0]][] = (int) substr($user,1);
|
||||
}
|
||||
}
|
||||
$to_or = $user_or = $owner_or = array();
|
||||
$to_or = $user_or = array();
|
||||
$owner_or = null;
|
||||
$useUnionQuery = $this->db->capabilities['distinct_on_text'] && $this->db->capabilities['union'];
|
||||
$table_def = $this->db->get_table_definitions('calendar',$this->user_table);
|
||||
foreach($users_by_type as $type => $ids)
|
||||
@ -428,20 +475,22 @@ class calendar_so
|
||||
// when we are able to use Union Querys, we do not OR our query, we save the needed parts for later construction of the union
|
||||
if ($useUnionQuery)
|
||||
{
|
||||
$user_or[] = $this->db->expression($table_def,array(
|
||||
$user_or[] = $this->db->expression($table_def,$this->user_table.'.',array(
|
||||
'cal_user_type' => $type,
|
||||
),' AND '.$this->user_table.'.',array(
|
||||
'cal_user_id' => $ids,
|
||||
));
|
||||
if ($type == 'u' && ($filter == 'owner'))
|
||||
if ($type == 'u' && $filter == 'owner')
|
||||
{
|
||||
$cal_table_def = $this->db->get_table_definitions('calendar',$this->cal_table);
|
||||
$owner_or[] = $this->db->expression($cal_table_def,array('cal_owner' => $ids));
|
||||
$owner_or = $this->db->expression($cal_table_def,array('cal_owner' => $ids));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$to_or[] = $this->db->expression($table_def,array(
|
||||
$to_or[] = $this->db->expression($table_def,$this->user_table.'.',array(
|
||||
'cal_user_type' => $type,
|
||||
),' AND '.$this->user_table.'.',array(
|
||||
'cal_user_id' => $ids,
|
||||
));
|
||||
if ($type == 'u' && ($filter == 'owner'))
|
||||
@ -454,27 +503,35 @@ class calendar_so
|
||||
// this is only used, when we cannot use UNIONS
|
||||
if (!$useUnionQuery) $where[] = '('.implode(' OR ',$to_or).')';
|
||||
|
||||
if($filter != 'deleted')
|
||||
{
|
||||
$where[] = 'cal_deleted IS NULL';
|
||||
}
|
||||
switch($filter)
|
||||
{
|
||||
case 'showonlypublic':
|
||||
$where[] = "cal_public=1";
|
||||
$where[] = "cal_status != 'R'"; break;
|
||||
$where['cal_public'] = 1;
|
||||
$where[] = "$this->user_table.cal_status NOT IN ('R','X')"; break;
|
||||
case 'deleted':
|
||||
$where[] = 'cal_deleted IS NOT NULL'; break;
|
||||
case 'unknown':
|
||||
$where[] = "cal_status='U'"; break;
|
||||
$where[] = "$this->user_table.cal_status='U'"; break;
|
||||
case 'not-unknown':
|
||||
$where[] = "$this->user_table.cal_status NOT IN ('U','X')"; break;
|
||||
case 'accepted':
|
||||
$where[] = "cal_status='A'"; break;
|
||||
$where[] = "$this->user_table.cal_status='A'"; break;
|
||||
case 'tentative':
|
||||
$where[] = "cal_status='T'"; break;
|
||||
$where[] = "$this->user_table.cal_status='T'"; break;
|
||||
case 'rejected':
|
||||
$where[] = "cal_status='R'"; break;
|
||||
$where[] = "$this->user_table.cal_status='R'"; break;
|
||||
case 'delegated':
|
||||
$where[] = "cal_status='D'"; break;
|
||||
$where[] = "$this->user_table.cal_status='D'"; break;
|
||||
case 'all':
|
||||
case 'owner':
|
||||
$where[] = "$this->user_table.cal_status!='X'"; break;
|
||||
break;
|
||||
default:
|
||||
//if (!$show_rejected) // not longer used
|
||||
$where[] = "cal_status != 'R'";
|
||||
$where[] = "$this->user_table.cal_status NOT IN ('R','X')";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -482,105 +539,126 @@ class calendar_so
|
||||
{
|
||||
$where[] = $this->cat_filter($cat_id);
|
||||
}
|
||||
if ($start) $where[] = (int)$start.' < cal_end';
|
||||
if ($start)
|
||||
{
|
||||
if ($params['enum_recuring'])
|
||||
{
|
||||
$where[] = (int)$start.' < cal_end';
|
||||
}
|
||||
else
|
||||
{
|
||||
// we check recur_endate!=0, because it can be NULL, 0 or !=0 !!!
|
||||
$where[] = (int)$start.' < (CASE WHEN recur_type IS NULL THEN cal_end ELSE (CASE WHEN recur_enddate!=0 THEN recur_enddate ELSE 9999999999 END) END)';
|
||||
}
|
||||
}
|
||||
// if not enum recuring events, we have to use minimum start- AND end-dates, otherwise we get more then one event per cal_id!
|
||||
if (!$params['enum_recuring'])
|
||||
{
|
||||
$where[] = "$this->user_table.cal_recur_date=0";
|
||||
$group_by = 'GROUP BY '.str_replace(array('cal_start,','cal_end,'),'',implode(', ',(array)$cols));
|
||||
$cols = str_replace(array('cal_start','cal_end'),array('MIN(cal_start) AS cal_start','MIN(cal_end) AS cal_end'),$cols);
|
||||
}
|
||||
if ($end) $where[] = 'cal_start < '.(int)$end;
|
||||
|
||||
if (!preg_match('/^[a-z_ ,]+$/i',$order)) $order = 'cal_start'; // gard against SQL injection
|
||||
if (!preg_match('/^[a-z_ ,c]+$/i',$params['order'])) $params['order'] = 'cal_start'; // gard against SQL injection
|
||||
|
||||
if ($remove_rejected_by_user)
|
||||
{
|
||||
$rejected_by_user_join = "LEFT JOIN $this->user_table rejected_by_user".
|
||||
" ON $this->cal_table.cal_id=rejected_by_user.cal_id".
|
||||
" AND rejected_by_user.cal_user_type='u'".
|
||||
" AND rejected_by_user.cal_user_id=".$this->db->quote($remove_rejected_by_user).
|
||||
" AND (recur_type IS NULL AND rejected_by_user.cal_recur_date=0 OR cal_start=rejected_by_user.cal_recur_date)";
|
||||
$or_required = array(
|
||||
'rejected_by_user.cal_status IS NULL',
|
||||
"rejected_by_user.cal_status NOT IN ('R','X')",
|
||||
);
|
||||
if ($filter == 'owner') $or_required[] = 'cal_owner='.(int)$remove_rejected_by_user;
|
||||
$where[] = '('.implode(' OR ',$or_required).')';
|
||||
}
|
||||
//$starttime = microtime(true);
|
||||
if ($useUnionQuery)
|
||||
{
|
||||
// allow apps to supply participants and/or icons
|
||||
if (!isset($params['cols'])) $cols .= ',NULL AS participants,NULL AS icons';
|
||||
|
||||
// changed the original OR in the query into a union, to speed up the query execution under MySQL 5
|
||||
$select = array(
|
||||
'table' => $this->cal_table,
|
||||
'join' => "JOIN $this->dates_table ON $this->cal_table.cal_id=$this->dates_table.cal_id JOIN $this->user_table ON $this->cal_table.cal_id=$this->user_table.cal_id LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id",
|
||||
'join' => "JOIN $this->dates_table ON $this->cal_table.cal_id=$this->dates_table.cal_id JOIN $this->user_table ON $this->cal_table.cal_id=$this->user_table.cal_id LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id $rejected_by_user_join",
|
||||
'cols' => $cols,
|
||||
'where' => $where,
|
||||
'app' => 'calendar',
|
||||
'append'=> $append,
|
||||
'append'=> $params['append'].' '.$group_by,
|
||||
);
|
||||
$selects = array();
|
||||
// we check if there are parts to use for the construction of our UNION query,
|
||||
// as replace the OR by construction of a suitable UNION for performance reasons
|
||||
if (!empty($owner_or)||!empty($user_or))
|
||||
if ($owner_or || $user_or)
|
||||
{
|
||||
if (!empty($owner_or) && !empty($user_or))
|
||||
foreach($user_or as $user_sql)
|
||||
{
|
||||
// if the query is to be filtered by owner OR user we need 4 selects for the union
|
||||
//_debug_array($owner_or);
|
||||
$selects = array();
|
||||
foreach(array_keys($user_or) as $key)
|
||||
$selects[] = $select;
|
||||
$selects[count($selects)-1]['where'][] = $user_sql;
|
||||
if ($params['enum_recuring'])
|
||||
{
|
||||
$selects[count($selects)-1]['where'][] = "recur_type IS NULL AND $this->user_table.cal_recur_date=0";
|
||||
$selects[] = $select;
|
||||
$selects[count($selects)-1]['where'][] = $user_or[$key];
|
||||
$selects[count($selects)-1]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
|
||||
$selects[] = $select;
|
||||
$selects[count($selects)-1]['where'][] = $user_or[$key];
|
||||
$selects[count($selects)-1]['where'][] = 'cal_recur_date=cal_start';
|
||||
$selects[count($selects)-1]['where'][] = $user_sql;
|
||||
$selects[count($selects)-1]['where'][] = "$this->user_table.cal_recur_date=cal_start";
|
||||
}
|
||||
$selects[] = $select;
|
||||
$selects[count($selects)-1]['where'][] = $owner_or;
|
||||
$selects[count($selects)-1]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
|
||||
$selects[] = $select;
|
||||
$selects[count($selects)-1]['where'][] = $owner_or;
|
||||
$selects[count($selects)-1]['where'][] = 'cal_recur_date=cal_start';
|
||||
}
|
||||
else
|
||||
// if the query is to be filtered by owner we need to add more selects for the union
|
||||
if ($owner_or)
|
||||
{
|
||||
// if the query is to be filtered only by user we need 2 selects for the union
|
||||
$selects = array();
|
||||
foreach(array_keys($user_or) as $key)
|
||||
$selects[] = $select;
|
||||
$selects[count($selects)-1]['where'][] = $owner_or;
|
||||
if ($params['enum_recuring'])
|
||||
{
|
||||
$selects[count($selects)-1]['where'][] = "recur_type IS NULL AND $this->user_table.cal_recur_date=0";
|
||||
$selects[] = $select;
|
||||
$selects[count($selects)-1]['where'][] = $user_or[$key];
|
||||
$selects[count($selects)-1]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
|
||||
$selects[] = $select;
|
||||
$selects[count($selects)-1]['where'][] = $user_or[$key];
|
||||
$selects[count($selects)-1]['where'][] = 'cal_recur_date=cal_start';
|
||||
$selects[count($selects)-1]['where'][] = $owner_or;
|
||||
$selects[count($selects)-1]['where'][] = "$this->user_table.cal_recur_date=cal_start";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the query is to be filtered by neither by user nor owner (should not happen?) we need 2 selects for the union
|
||||
$selects = array($select,$select);
|
||||
$selects[0]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
|
||||
$selects[1]['where'][] = 'cal_recur_date=cal_start';
|
||||
$selects[] = $select;
|
||||
if ($params['enum_recuring'])
|
||||
{
|
||||
$selects[count($selects)-1]['where'][] = "recur_type IS NULL AND $this->user_table.cal_recur_date=0";
|
||||
$selects[] = $select;
|
||||
$selects[count($selects)-1]['where'][] = "$this->user_table.cal_recur_date=cal_start";
|
||||
}
|
||||
}
|
||||
if (is_numeric($offset)) // get the total too
|
||||
if (is_numeric($offset) && !$params['no_total']) // get the total too
|
||||
{
|
||||
$save_selects = $selects;
|
||||
// we only select cal_table.cal_id (and not cal_table.*) to be able to use DISTINCT (eg. MsSQL does not allow it for text-columns)
|
||||
$countSelects = count($selects);
|
||||
foreach(array_keys($selects) as $key)
|
||||
{
|
||||
$selects[$key]['cols'] = "DISTINCT $this->repeats_table.*,$this->cal_table.cal_id,cal_start,cal_end,cal_recur_date";
|
||||
//$selects[0]['cols'] = $selects[1]['cols'] = "DISTINCT $this->repeats_table.*,$this->cal_table.cal_id,cal_start,cal_end,cal_recur_date";
|
||||
$selects[$key]['cols'] = "DISTINCT $this->repeats_table.recur_type,$this->repeats_table.recur_enddate,$this->repeats_table.recur_interval,$this->repeats_table.recur_data,$this->repeats_table.recur_exception,".$this->db->to_varchar($this->cal_table.'.cal_id').",cal_start,cal_end,$this->user_table.cal_recur_date";
|
||||
if (!$params['enum_recuring'])
|
||||
{
|
||||
$selects[$key]['cols'] = str_replace('cal_start','MIN(cal_start) AS cal_start',$selects[$key]['cols']);
|
||||
}
|
||||
}
|
||||
if (!isset($param['cols'])) self::get_union_selects($selects,$start,$end,$users,$cat_id,$filter,$params['query'],$params['users']);
|
||||
|
||||
$this->total = $this->db->union($selects,__LINE__,__FILE__)->NumRows();
|
||||
$i = 0;
|
||||
foreach(array_keys($selects) as $key)
|
||||
{
|
||||
if ($i >= $countSelects) continue;
|
||||
$i++;
|
||||
$selects[$key]['cols'] = $select['cols']; // restore the original cols
|
||||
//$selects[0]['cols'] = $selects[1]['cols'] = $select['cols']; // restore the original cols
|
||||
}
|
||||
$i = 0;
|
||||
$selections = array();
|
||||
foreach(array_keys($selects) as $key)
|
||||
{
|
||||
if ($i >= $countSelects) continue;
|
||||
$i++;
|
||||
$selections[] = $selects[$key];
|
||||
}
|
||||
|
||||
$selects = $selections;
|
||||
// restore original cols / selects
|
||||
$selects = $save_selects; unset($save_selects);
|
||||
}
|
||||
// error_log("calendar_so_search:\n" . print_r($selects, true));
|
||||
$rs = $this->db->union($selects,__LINE__,__FILE__,$order,$offset,$num_rows);
|
||||
if (!isset($param['cols'])) self::get_union_selects($selects,$start,$end,$users,$cat_id,$filter,$params['query'],$params['users']);
|
||||
|
||||
$rs = $this->db->union($selects,__LINE__,__FILE__,$params['order'],$offset,$num_rows);
|
||||
}
|
||||
else // MsSQL oder MySQL 3.23
|
||||
{
|
||||
$where[] = '(recur_type IS NULL AND cal_recur_date=0 OR cal_recur_date=cal_start)';
|
||||
$where[] = "(recur_type IS NULL AND $this->user_table.cal_recur_date=0 OR $this->user_table.cal_recur_date=cal_start)";
|
||||
|
||||
//_debug_array($where);
|
||||
if (is_numeric($offset)) // get the total too
|
||||
@ -588,13 +666,14 @@ class calendar_so
|
||||
// we only select cal_table.cal_id (and not cal_table.*) to be able to use DISTINCT (eg. MsSQL does not allow it for text-columns)
|
||||
$this->total = $this->db->select($this->cal_table,"DISTINCT $this->repeats_table.*,$this->cal_table.cal_id,cal_start,cal_end,cal_recur_date",
|
||||
$where,__LINE__,__FILE__,false,'','calendar',0,
|
||||
"JOIN $this->dates_table ON $this->cal_table.cal_id=$this->dates_table.cal_id JOIN $this->user_table ON $this->cal_table.cal_id=$this->user_table.cal_id LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id")->NumRows();
|
||||
"JOIN $this->dates_table ON $this->cal_table.cal_id=$this->dates_table.cal_id JOIN $this->user_table ON $this->cal_table.cal_id=$this->user_table.cal_id $rejected_by_user_join LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id")->NumRows();
|
||||
}
|
||||
$rs = $this->db->select($this->cal_table,($this->db->capabilities['distinct_on_text'] ? 'DISTINCT ' : '').$cols,
|
||||
$where,__LINE__,__FILE__,$offset,$append.' ORDER BY '.$order,'calendar',$num_rows,
|
||||
"JOIN $this->dates_table ON $this->cal_table.cal_id=$this->dates_table.cal_id JOIN $this->user_table ON $this->cal_table.cal_id=$this->user_table.cal_id LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id");
|
||||
$where,__LINE__,__FILE__,$offset,$params['append'].' ORDER BY '.$params['order'],'calendar',$num_rows,
|
||||
"JOIN $this->dates_table ON $this->cal_table.cal_id=$this->dates_table.cal_id JOIN $this->user_table ON $this->cal_table.cal_id=$this->user_table.cal_id $rejected_by_user_join LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id");
|
||||
}
|
||||
if (!is_null($_cols))
|
||||
//error_log(__METHOD__."() useUnionQuery=$useUnionQuery --> query took ".(microtime(true)-$starttime));
|
||||
if (isset($params['cols']))
|
||||
{
|
||||
return $rs; // if colums are specified we return the recordset / iterator
|
||||
}
|
||||
@ -630,15 +709,18 @@ class calendar_so
|
||||
//_debug_array($events);
|
||||
if (count($ids))
|
||||
{
|
||||
$ids = array_unique($ids);
|
||||
|
||||
$need_max_user_modified = array();
|
||||
// now ready all users with the given cal_id AND (cal_recur_date=0 or the fitting recur-date)
|
||||
// This will always read the first entry of each recuring event too, we eliminate it later
|
||||
$recur_dates[] = 0;
|
||||
$utcal_id_view = " (SELECT * FROM ".$this->user_table." WHERE cal_id IN (".implode(',',array_unique($ids)).")) utcalid ";
|
||||
$utcal_id_view = " (SELECT * FROM ".$this->user_table." WHERE cal_id IN (".implode(',',$ids).") AND cal_status!='X') utcalid ";
|
||||
//$utrecurdate_view = " (select * from ".$this->user_table." where cal_recur_date in (".implode(',',array_unique($recur_dates)).")) utrecurdates ";
|
||||
foreach($this->db->select($utcal_id_view,'*',array(
|
||||
//'cal_id' => array_unique($ids),
|
||||
'cal_recur_date' => $recur_dates,
|
||||
),__LINE__,__FILE__,false,'ORDER BY cal_id,cal_user_type DESC,'.self::STATUS_SORT,'calendar',$num_rows=0,$join='',
|
||||
),__LINE__,__FILE__,false,'ORDER BY cal_id,cal_user_type DESC,'.self::STATUS_SORT,'calendar',$num_rows,$join='',
|
||||
$this->db->get_table_definitions('calendar',$this->user_table)) as $row) // DESC puts users before resources and contacts
|
||||
{
|
||||
$id = $row['cal_id'];
|
||||
@ -662,12 +744,30 @@ class calendar_so
|
||||
|
||||
// set data, if recurrence is requested
|
||||
if (isset($events[$id])) $events[$id]['participants'][$uid] = $status;
|
||||
|
||||
// fill max_user_modified:
|
||||
if (!$params['master_only'] && $events[$id]['recur_type'])
|
||||
{
|
||||
$need_max_user_modified[$id] = $id;
|
||||
}
|
||||
elseif (isset($events[$id]) && ($modified = $this->db->from_timestamp($row['cal_user_modified'])) > $events[$id]['max_user_modified'])
|
||||
{
|
||||
$events[$id]['max_user_modified'] = $modified;
|
||||
}
|
||||
}
|
||||
// max_user_modified for recurring events has to include all recurrences, above code only querys $recur_date!
|
||||
if (!$params['enum_recuring'] && $need_max_user_modified)
|
||||
{
|
||||
foreach($this->max_user_modified($need_max_user_modified) as $id => $modified)
|
||||
{
|
||||
$events[$id]['max_user_modified'] = $modified;
|
||||
}
|
||||
}
|
||||
//custom fields are not shown in the regular views, so we only query them, if explicitly required
|
||||
if (!is_null($cfs))
|
||||
if (!is_null($params['cfs']))
|
||||
{
|
||||
$where = array('cal_id' => $ids);
|
||||
if ($cfs) $where['cal_extra_name'] = $cfs;
|
||||
if ($params['cfs']) $where['cal_extra_name'] = $params['cfs'];
|
||||
foreach($this->db->select($this->extra_table,'*',$where,
|
||||
__LINE__,__FILE__,false,'','calendar') as $row)
|
||||
{
|
||||
@ -702,9 +802,140 @@ class calendar_so
|
||||
}
|
||||
}
|
||||
//echo "<p>socal::search\n"; _debug_array($events);
|
||||
//error_log(__METHOD__."(,filter=".array2string($params['query']).",offset=$offset, num_rows=$num_rows) returning ".count($events)." entries".($offset!==false?" total=$this->total":'').' '.function_backtrace());
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data returned by calendar_search_union hook
|
||||
*/
|
||||
private static $integration_data;
|
||||
|
||||
/**
|
||||
* Ask other apps if they want to participate in calendar search / display
|
||||
*
|
||||
* @param &$selects parts of union query
|
||||
* @param $start see search()
|
||||
* @param $end
|
||||
* @param $users as used in calendar_so ($users_raw plus all members and memberships added by calendar_bo)
|
||||
* @param $cat_id
|
||||
* @param $filter
|
||||
* @param $query
|
||||
* @param $users_raw as passed to calendar_bo::search (no members and memberships added)
|
||||
*/
|
||||
private static function get_union_selects(array &$selects,$start,$end,$users,$cat_id,$filter,$query,$users_raw)
|
||||
{
|
||||
if (in_array(basename($_SERVER['SCRIPT_FILENAME']),array('groupdav.php','rpc.php','xmlrpc.php','/activesync/index.php')) ||
|
||||
!in_array($GLOBALS['egw_info']['flags']['currentapp'],array('calendar','home')))
|
||||
{
|
||||
return; // disable integration for GroupDAV, SyncML, ...
|
||||
}
|
||||
self::$integration_data = $GLOBALS['egw']->hooks->process(array(
|
||||
'location' => 'calendar_search_union',
|
||||
'cols' => $selects[0]['cols'], // cols to return
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'users' => $users,
|
||||
'users_raw' => $users_raw,
|
||||
'cat_id'=> $cat_id,
|
||||
'filter'=> $filter,
|
||||
'query' => $query,
|
||||
));
|
||||
foreach(self::$integration_data as $app => $data)
|
||||
{
|
||||
if (is_array($data['selects']))
|
||||
{
|
||||
//echo $app; _debug_array($data);
|
||||
$selects = array_merge($selects,$data['selects']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data from last 'calendar_search_union' hook call
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_integration_data()
|
||||
{
|
||||
return self::$integration_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return union cols constructed from application cols and required cols
|
||||
*
|
||||
* Every col not supplied in $app_cols get returned as NULL.
|
||||
*
|
||||
* @param array $app_cols required name => own name pairs
|
||||
* @param string|array $required array or comma separated column names or table.*
|
||||
* @param string $required_app='calendar'
|
||||
* @return string cols for union query to match ones supplied in $required
|
||||
*/
|
||||
public static function union_cols(array $app_cols,$required,$required_app='calendar')
|
||||
{
|
||||
// remove evtl. used DISTINCT, we currently dont need it
|
||||
if (($distinct = substr($required,0,9) == 'DISTINCT '))
|
||||
{
|
||||
$required = substr($required,9);
|
||||
}
|
||||
$return_cols = array();
|
||||
foreach(is_array($required) ? $required : explode(',',$required) as $cols)
|
||||
{
|
||||
if (substr($cols,-2) == '.*')
|
||||
{
|
||||
$cols = self::get_columns($required_app,substr($cols,0,-2));
|
||||
}
|
||||
elseif (strpos($cols,' AS ') !== false)
|
||||
{
|
||||
list(,$cols) = explode(' AS ',$cols);
|
||||
}
|
||||
foreach((array)$cols as $col)
|
||||
{
|
||||
if (substr($col,0,7) == 'egw_cal') // remove table name
|
||||
{
|
||||
$col = preg_replace('/^egw_cal[a-z_]*\./','',$col);
|
||||
}
|
||||
if (isset($app_cols[$col]))
|
||||
{
|
||||
$return_cols[] = $app_cols[$col];
|
||||
}
|
||||
else
|
||||
{
|
||||
$return_cols[] = 'NULL';
|
||||
}
|
||||
}
|
||||
}
|
||||
return implode(',',$return_cols);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get columns of given table, taking into account historically different column order of egw_cal table
|
||||
*
|
||||
* @param string $app
|
||||
* @param string $table
|
||||
* @return array of column names
|
||||
*/
|
||||
static private function get_columns($app,$table)
|
||||
{
|
||||
if ($table != 'egw_cal')
|
||||
{
|
||||
$table_def = $GLOBALS['egw']->db->get_table_definitions($app,$table);
|
||||
$cols = array_keys($table_def['fd']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// special handling for egw_cal, as old databases have a different column order!!!
|
||||
$cols =& egw_cache::getSession(__CLASS__,$table);
|
||||
|
||||
if (is_null($cols))
|
||||
{
|
||||
$meta = $GLOBALS['egw']->db->metadata($table,true);
|
||||
$cols = array_keys($meta['meta']);
|
||||
}
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for conflicts
|
||||
*/
|
||||
@ -756,6 +987,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
|
||||
if (empty($minimum_uid_length) || $minimum_uid_length<=1) $minimum_uid_length = 8; // we just do not accept no uid, or uid way to short!
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -779,7 +1011,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
// add colum prefix 'cal_' if there's not already a 'recur_' prefix
|
||||
foreach($event as $col => $val)
|
||||
{
|
||||
if ($col[0] != '#' && substr($col,0,6) != 'recur_' && $col != 'alarm' && $col != 'tz_id')
|
||||
if ($col[0] != '#' && substr($col,0,6) != 'recur_' && $col != 'alarm' && $col != 'tz_id' && $col != 'caldav_name')
|
||||
{
|
||||
$event['cal_'.$col] = $val;
|
||||
unset($event[$col]);
|
||||
@ -834,15 +1066,38 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
$etag = 0;
|
||||
}
|
||||
$update = array();
|
||||
// event without uid or not strong enough uid
|
||||
if (!isset($event['cal_uid']) || strlen($event['cal_uid']) < $minimum_uid_length)
|
||||
{
|
||||
// event (without uid), not strong enough uid
|
||||
$event['cal_uid'] = $GLOBALS['egw']->common->generate_uid('calendar',$cal_id);
|
||||
$this->db->update($this->cal_table, array('cal_uid' => $event['cal_uid']),
|
||||
array('cal_id' => $event['cal_id']),__LINE__,__FILE__,'calendar');
|
||||
$update['cal_uid'] = $event['cal_uid'] = $GLOBALS['egw']->common->generate_uid('calendar',$cal_id);
|
||||
}
|
||||
// write information about recuring event, if recur_type is present in the array
|
||||
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
||||
// set caldav_name, if not given by caller
|
||||
if (empty($event['caldav_name']) && version_compare($GLOBALS['egw_info']['apps']['calendar']['version'], '1.9.003', '>='))
|
||||
{
|
||||
$update['caldav_name'] = $event['caldav_name'] = $cal_id.'.ics';
|
||||
}
|
||||
if ($update)
|
||||
{
|
||||
$this->db->update($this->cal_table, $update, array('cal_id' => $cal_id),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
|
||||
if ($event['recur_type'] == MCAL_RECUR_NONE)
|
||||
{
|
||||
$this->db->delete($this->dates_table,array(
|
||||
'cal_id' => $cal_id),
|
||||
__LINE__,__FILE__,'calendar');
|
||||
|
||||
// delete all user-records, with recur-date != 0
|
||||
$this->db->delete($this->user_table,array(
|
||||
'cal_id' => $cal_id, 'cal_recur_date != 0'),
|
||||
__LINE__,__FILE__,'calendar');
|
||||
|
||||
$this->db->delete($this->repeats_table,array(
|
||||
'cal_id' => $cal_id),
|
||||
__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
else // write information about recuring event, if recur_type is present in the array
|
||||
{
|
||||
// fetch information about the currently saved (old) event
|
||||
$old_min = (int) $this->db->select($this->dates_table,'MIN(cal_start)',array('cal_id'=>$cal_id),__LINE__,__FILE__,false,'','calendar')->fetchColumn();
|
||||
@ -951,14 +1206,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
// write the repeats table
|
||||
$event['recur_exception'] = empty($event['recur_exception']) ? null : implode(',',$event['recur_exception']);
|
||||
unset($event[0]); // unset the 'etag=etag+1', as it's not in the repeats table
|
||||
if($event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
$this->db->insert($this->repeats_table,$event,array('cal_id' => $cal_id),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->db->delete($this->repeats_table,array('cal_id' => $cal_id),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
$this->db->insert($this->repeats_table,$event,array('cal_id' => $cal_id),__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
// update start- and endtime if present in the event-array, evtl. we need to move all recurrences
|
||||
if (isset($event['cal_start']) && isset($event['cal_end']))
|
||||
@ -975,6 +1223,12 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
{
|
||||
if ($name[0] == '#')
|
||||
{
|
||||
if (is_array($value) && array_key_exists('id',$value))
|
||||
{
|
||||
//error_log(__METHOD__.__LINE__."$name => ".array2string($value).function_backtrace());
|
||||
$value = $value['id'];
|
||||
//error_log(__METHOD__.__LINE__."$name => ".array2string($value));
|
||||
}
|
||||
if ($value)
|
||||
{
|
||||
$this->db->insert($this->extra_table,array(
|
||||
@ -993,13 +1247,12 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
}
|
||||
}
|
||||
// updating or saving the alarms, new alarms have a temporary numeric id!
|
||||
// ToDo: recuring events !!!
|
||||
// updating or saving the alarms; new alarms have a temporary numeric id!
|
||||
if (is_array($event['alarm']))
|
||||
{
|
||||
foreach ($event['alarm'] as $id => $alarm)
|
||||
{
|
||||
if (is_numeric($id)) unset($alarm['id']); // unset the temporary id, to add the alarm
|
||||
if (is_numeric($id)) unset($alarm['id']); // unset the temporary id to add the alarm
|
||||
|
||||
if(!isset($alarm['offset']))
|
||||
{
|
||||
@ -1268,7 +1521,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
));
|
||||
}
|
||||
$where[1] = '('.implode(' OR ',$to_or).')';
|
||||
$this->db->delete($this->user_table,$where,__LINE__,__FILE__,'calendar');
|
||||
$this->db->update($this->user_table,array('cal_status'=>'X'),$where,__LINE__,__FILE__,'calendar');
|
||||
unset($where[1]);
|
||||
}
|
||||
}
|
||||
@ -1376,6 +1629,10 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
'cal_start' => $start,
|
||||
),__LINE__,__FILE__,'calendar');
|
||||
|
||||
if (!is_array($participants))
|
||||
{
|
||||
error_log(__METHOD__."($cal_id, $start, $end, ".array2string($participants).") participants is NO array! ".function_backtrace());
|
||||
}
|
||||
foreach($participants as $uid => $status)
|
||||
{
|
||||
if ($status == 'G') continue; // dont save group-invitations
|
||||
@ -1433,6 +1690,50 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all events that were before the given date.
|
||||
*
|
||||
* Recurring events that finished before the date will be deleted.
|
||||
* Recurring events that span the date will be ignored. Non-recurring
|
||||
* events before the date will be deleted.
|
||||
*
|
||||
* @param int $date
|
||||
*/
|
||||
function purge($date)
|
||||
{
|
||||
// Start with egw_cal, it's the easiest
|
||||
$sql = "(SELECT egw_cal.cal_id FROM egw_cal
|
||||
LEFT JOIN egw_cal_repeats ON
|
||||
egw_cal_repeats.cal_id = egw_cal.cal_id
|
||||
JOIN egw_cal_dates ON
|
||||
egw_cal.cal_id = egw_cal_dates.cal_id
|
||||
WHERE cal_end < $date AND (egw_cal_repeats.cal_id IS NULL OR (recur_enddate < $date AND recur_enddate != 0))) AS TOPROCESS";
|
||||
|
||||
// Get what we want to delete for all tables and links
|
||||
foreach($this->db->select(
|
||||
$sql,
|
||||
array('cal_id'),
|
||||
null,
|
||||
__LINE__, __FILE__, false
|
||||
) as $row)
|
||||
{
|
||||
//echo __METHOD__." About to delete".$row['cal_id']."\r\n";
|
||||
foreach($this->all_tables as $table)
|
||||
{
|
||||
$this->db->delete($table, array('cal_id'=>$row['cal_id']), __LINE__, __FILE__, 'calendar');
|
||||
}
|
||||
// handle sync
|
||||
$this->db->update('egw_api_content_history',array(
|
||||
'sync_deleted' => time(),
|
||||
),array(
|
||||
'sync_appname' => 'calendar',
|
||||
'sync_contentid' => $row['cal_id'], // sync_contentid is varchar(60)!
|
||||
), __LINE__, __FILE__);
|
||||
// handle links
|
||||
egw_link::unlink('', 'calendar', $row['cal_id']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read the alarms of a calendar-event specified by $cal_id
|
||||
*
|
||||
@ -1485,12 +1786,13 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
*
|
||||
* @param int $cal_id Id of the calendar-entry
|
||||
* @param array $alarm array with fields: text, owner, enabled, ..
|
||||
* @param timestamp $now_su=0 timestamp for modification of related event
|
||||
* @param timestamp $now=0 timestamp for modification of related event
|
||||
* @return string id of the alarm
|
||||
*/
|
||||
function save_alarm($cal_id, $alarm, $now_su = 0)
|
||||
function save_alarm($cal_id, $alarm, $now=0)
|
||||
{
|
||||
//echo "<p>save_alarm(cal_id=$cal_id, alarm="; print_r($alarm); echo ")</p>\n";
|
||||
//error_log(__METHOD__."(.$cal_id,$now,".array2string($alarm).')');
|
||||
if (!($id = $alarm['id']))
|
||||
{
|
||||
$alarms = $this->read_alarms($cal_id); // find a free alarm#
|
||||
@ -1515,8 +1817,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
|
||||
// update the modification information of the related event
|
||||
$datetime = $GLOBALS['egw']->datetime;
|
||||
$now = ($now_su ? $now_su : time() + $datetime->this->tz_offset);
|
||||
if (!$now) $now = time();
|
||||
$modifier = $GLOBALS['egw_info']['user']['account_id'];
|
||||
$this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier),
|
||||
array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar');
|
||||
@ -1545,17 +1846,16 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
* delete one alarms identified by its id
|
||||
*
|
||||
* @param string $id alarm-id is a string of 'cal:'.$cal_id.':'.$alarm_nr, it is used as the job-id too
|
||||
* @param timestamp $now_su=0 timestamp for modification of related event
|
||||
* @param timestamp $now=0 timestamp for modification of related event
|
||||
* @return int number of alarms deleted
|
||||
*/
|
||||
function delete_alarm($id, $now_su = 0)
|
||||
function delete_alarm($id, $now=0)
|
||||
{
|
||||
// update the modification information of the related event
|
||||
list(,$cal_id) = explode(':',$id);
|
||||
if ($cal_id)
|
||||
{
|
||||
$datetime = $GLOBALS['egw']->datetime;
|
||||
$now = ($now_su ? $now_su : time() + $datetime->this->tz_offset);
|
||||
if (!$now) $now = time();
|
||||
$modifier = $GLOBALS['egw_info']['user']['account_id'];
|
||||
$this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier),
|
||||
array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar');
|
||||
@ -2062,7 +2362,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
*
|
||||
* @return DateTime
|
||||
*/
|
||||
function &startOfDay(egw_time $time, $tz_id)
|
||||
function &startOfDay(egw_time $time, $tz_id=null)
|
||||
{
|
||||
if (empty($tz_id))
|
||||
{
|
||||
@ -2078,4 +2378,19 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
}
|
||||
return new egw_time($time->format('Y-m-d 00:00:00'), $timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Udates the modification timestamp
|
||||
*
|
||||
* @param id event id
|
||||
* @param time new timestamp
|
||||
* @param modifier uid of the modifier
|
||||
*
|
||||
*/
|
||||
function updateModified($id, $time, $modifier)
|
||||
{
|
||||
$this->db->update($this->cal_table,
|
||||
array('cal_modified' => $time, 'cal_modifier' => $modifier),
|
||||
array('cal_id' => $id), __LINE__,__FILE__, 'calendar');
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Calendar's timezone information
|
||||
* EGroupware - Calendar's timezone information
|
||||
*
|
||||
* Timezone information get imported from SQLite database, "borrowed" of Lighting TB extension.
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2009 by RalfBecker-At-outdoor-training.de
|
||||
* @copyright (c) 2009-11 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -67,7 +67,7 @@ class calendar_timezones
|
||||
* @return DateTimeZone
|
||||
* @throws Exception if called with an unknown TZID
|
||||
*/
|
||||
public function DateTimeZone($tzid)
|
||||
public static function DateTimeZone($tzid)
|
||||
{
|
||||
if (($id = self::tz2id($tzid,'alias')))
|
||||
{
|
||||
@ -321,6 +321,94 @@ class calendar_timezones
|
||||
'<h3>'.self::import_tz_aliases()."</h3>\n",
|
||||
lang('Update timezones'),true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add VTIMEZONE component to VCALENDAR
|
||||
*
|
||||
* @param Horde_iCalendar $vcal
|
||||
* @param string $tzid
|
||||
* @return boolean false if no vtimezone component available, true on success
|
||||
*/
|
||||
public static function add_vtimezone($vcal, $tzid)
|
||||
{
|
||||
include_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
// checking type of $val, now we included the object definition (no need to always include it!)
|
||||
if (!$vcal instanceof Horde_iCalendar)
|
||||
{
|
||||
throw new egw_exception_wrong_parameter(__METHOD__.'('.array2string($val).", '$tzid') no Horde_iCalendar!");
|
||||
}
|
||||
// check if we have vtimezone component data for $tzid
|
||||
if (!($vtimezone = calendar_timezones::tz2id($tzid, 'component')))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// $vtimezone is a string with a single VTIMEZONE component, afaik Horde_iCalendar can not add it directly
|
||||
// --> we have to parse it and let Horde_iCalendar add it again
|
||||
$horde_vtimezone = Horde_iCalendar::newComponent('VTIMEZONE',$container=false);
|
||||
$horde_vtimezone->parsevCalendar($vtimezone,'VTIMEZONE');
|
||||
// DTSTART is in UTC time, Horde_iCalendar parses it in server timezone, which we need to set again for printing
|
||||
$standard = $horde_vtimezone->findComponent('STANDARD');
|
||||
if (is_a($standard, 'Horde_iCalendar'))
|
||||
{
|
||||
$dtstart = $standard->getAttribute('DTSTART');
|
||||
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
|
||||
$dtstart->setTimezone(egw_time::$server_timezone);
|
||||
$standard->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
|
||||
}
|
||||
$daylight = $horde_vtimezone->findComponent('DAYLIGHT');
|
||||
if (is_a($daylight, 'Horde_iCalendar'))
|
||||
{
|
||||
$dtstart = $daylight->getAttribute('DTSTART');
|
||||
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
|
||||
$dtstart->setTimezone(egw_time::$server_timezone);
|
||||
$daylight->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
|
||||
}
|
||||
//error_log($vtimezone); error_log($horde_vtimezone->_exportvData('VTIMEZONE'));
|
||||
$vcal->addComponent($horde_vtimezone);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query timezone of a given user, returns 'tzid' or VTIMEZONE 'component'
|
||||
*
|
||||
* @param int $user=null
|
||||
* @param string $type='vcalendar' 'tzid' or everything tz2id supports, default 'vcalendar' = full vcalendar component
|
||||
* @return string
|
||||
*/
|
||||
public static function user_timezone($user=null, $type='vcalendar')
|
||||
{
|
||||
if (!$user || $user == $GLOBALS['egw_info']['user']['account_id'])
|
||||
{
|
||||
$tzid = $GLOBALS['egw_info']['user']['preferences']['common']['tz'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$prefs_obj = new preferences($user);
|
||||
$prefs = $prefs_obj->read();
|
||||
$tzid = $prefs['common']['tz'];
|
||||
}
|
||||
if (!$tzid) $tzid = egw_time::$server_timezone->getName();
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case 'vcalendar':
|
||||
include_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
// checking type of $val, now we included the object definition (no need to always include it!)
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Calendar '.$GLOBALS['egw_info']['apps']['calendar']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
self::add_vtimezone($vcal, $tzid);
|
||||
$tzid = $vcal->exportvCalendar('utf-8');
|
||||
break;
|
||||
case 'tzid':
|
||||
break;
|
||||
default:
|
||||
$tzid = self::tz2id($tzid,$type == 'vcalendar' ? 'component' : $type);
|
||||
break;
|
||||
}
|
||||
return $tzid;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__) // some tests
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
$setup_info['calendar']['name'] = 'calendar';
|
||||
$setup_info['calendar']['version'] = '1.8';
|
||||
$setup_info['calendar']['version'] = '1.9.004';
|
||||
$setup_info['calendar']['app_order'] = 3;
|
||||
$setup_info['calendar']['enable'] = 1;
|
||||
$setup_info['calendar']['index'] = 'calendar.calendar_uiviews.index';
|
||||
@ -41,6 +41,9 @@ $setup_info['calendar']['hooks']['preferences'] = 'calendar_hooks::preferences';
|
||||
$setup_info['calendar']['hooks']['settings'] = 'calendar_hooks::settings';
|
||||
$setup_info['calendar']['hooks']['sidebox_menu'] = 'calendar.calendar_ui.sidebox_menu';
|
||||
$setup_info['calendar']['hooks']['search_link'] = 'calendar_hooks::search_link';
|
||||
$setup_info['calendar']['hooks']['config_validate'] = 'calendar_hooks::config_validate';
|
||||
$setup_info['calendar']['hooks']['timesheet_set'] = 'calendar.calendar_bo.timesheet_set';
|
||||
$setup_info['calendar']['hooks']['export_limit'] = 'calendar_hooks::getAppExportLimit';
|
||||
|
||||
/* Dependencies for this app to work */
|
||||
$setup_info['calendar']['depends'][] = array(
|
||||
@ -65,3 +68,5 @@ $setup_info['calendar']['check_install'] = array(
|
||||
'from' => 'Calendar',
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
|
124
calendar/setup/tables_current.inc.php
Normal file
124
calendar/setup/tables_current.inc.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Calendar setup
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
$phpgw_baseline = array(
|
||||
'egw_cal' => array(
|
||||
'fd' => array(
|
||||
'cal_id' => array('type' => 'auto','nullable' => False),
|
||||
'cal_uid' => array('type' => 'varchar','precision' => '255','nullable' => False,'comment' => 'unique id of event(-series)'),
|
||||
'cal_owner' => array('type' => 'int','precision' => '4','nullable' => False,'comment' => 'event owner / calendar'),
|
||||
'cal_category' => array('type' => 'varchar','precision' => '30','comment' => 'category id'),
|
||||
'cal_modified' => array('type' => 'int','precision' => '8','comment' => 'ts of last modification'),
|
||||
'cal_priority' => array('type' => 'int','precision' => '2','nullable' => False,'default' => '2'),
|
||||
'cal_public' => array('type' => 'int','precision' => '2','nullable' => False,'default' => '1','comment' => '1=public, 0=private event'),
|
||||
'cal_title' => array('type' => 'varchar','precision' => '255','nullable' => False,'default' => '1'),
|
||||
'cal_description' => array('type' => 'text'),
|
||||
'cal_location' => array('type' => 'varchar','precision' => '255'),
|
||||
'cal_reference' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0','comment' => 'cal_id of series for exception'),
|
||||
'cal_modifier' => array('type' => 'int','precision' => '4','comment' => 'user who last modified event'),
|
||||
'cal_non_blocking' => array('type' => 'int','precision' => '2','default' => '0','comment' => '1 for non-blocking events'),
|
||||
'cal_special' => array('type' => 'int','precision' => '2','default' => '0'),
|
||||
'cal_etag' => array('type' => 'int','precision' => '4','default' => '0','comment' => 'etag for optimistic locking'),
|
||||
'cal_creator' => array('type' => 'int','precision' => '4','nullable' => False,'comment' => 'creating user'),
|
||||
'cal_created' => array('type' => 'int','precision' => '8','nullable' => False,'comment' => 'creation time of event'),
|
||||
'cal_recurrence' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0','comment' => 'cal_start of original recurrence for exception'),
|
||||
'tz_id' => array('type' => 'int','precision' => '4','comment' => 'key into egw_cal_timezones'),
|
||||
'cal_deleted' => array('type' => 'int','precision' => '8','comment' => 'ts when event was deleted'),
|
||||
'caldav_name' => array('type' => 'varchar','precision' => '64','comment' => 'name part of CalDAV URL, if specified by client')
|
||||
),
|
||||
'pk' => array('cal_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('cal_uid','cal_owner','cal_modified','cal_deleted','caldav_name'),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_cal_holidays' => array(
|
||||
'fd' => array(
|
||||
'hol_id' => array('type' => 'auto','nullable' => False),
|
||||
'hol_locale' => array('type' => 'char','precision' => '2','nullable' => False),
|
||||
'hol_name' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'hol_mday' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0'),
|
||||
'hol_month_num' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0'),
|
||||
'hol_occurence' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0'),
|
||||
'hol_dow' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0'),
|
||||
'hol_observance_rule' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0')
|
||||
),
|
||||
'pk' => array('hol_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('hol_locale'),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_cal_repeats' => array(
|
||||
'fd' => array(
|
||||
'cal_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'recur_type' => array('type' => 'int','precision' => '2','nullable' => False),
|
||||
'recur_enddate' => array('type' => 'int','precision' => '8'),
|
||||
'recur_interval' => array('type' => 'int','precision' => '2','default' => '1'),
|
||||
'recur_data' => array('type' => 'int','precision' => '2','default' => '1'),
|
||||
'recur_exception' => array('type' => 'text','comment' => 'comma-separated start timestamps of exceptions')
|
||||
),
|
||||
'pk' => array('cal_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_cal_user' => array(
|
||||
'fd' => array(
|
||||
'cal_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'cal_recur_date' => array('type' => 'int','precision' => '8','default' => '0'),
|
||||
'cal_user_type' => array('type' => 'varchar','precision' => '1','nullable' => False,'default' => 'u','comment' => 'u=user, g=group, c=contact, r=resource, e=email'),
|
||||
'cal_user_id' => array('type' => 'varchar','precision' => '128','nullable' => False,'comment' => 'id or email-address for type=e'),
|
||||
'cal_status' => array('type' => 'char','precision' => '1','default' => 'A','comment' => 'U=unknown, A=accepted, R=rejected, T=tentative'),
|
||||
'cal_quantity' => array('type' => 'int','precision' => '4','default' => '1','comment' => 'only for certain types (eg. resources)'),
|
||||
'cal_role' => array('type' => 'varchar','precision' => '64','default' => 'REQ-PARTICIPANT','comment' => 'CHAIR, REQ-PARTICIPANT, OPT-PARTICIPANT, NON-PARTICIPANT, X-CAT-$cat_id'),
|
||||
'cal_user_modified' => array('type' => 'timestamp','default' => 'current_timestamp','comment' => 'automatic timestamp of last update')
|
||||
),
|
||||
'pk' => array('cal_id','cal_recur_date','cal_user_type','cal_user_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('cal_user_modified',array('cal_user_type','cal_user_id')),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_cal_extra' => array(
|
||||
'fd' => array(
|
||||
'cal_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'cal_extra_name' => array('type' => 'varchar','precision' => '40','nullable' => False),
|
||||
'cal_extra_value' => array('type' => 'varchar','precision' => '255','nullable' => False,'default' => '')
|
||||
),
|
||||
'pk' => array('cal_id','cal_extra_name'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_cal_dates' => array(
|
||||
'fd' => array(
|
||||
'cal_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'cal_start' => array('type' => 'int','precision' => '8','nullable' => False,'comment' => 'starttime in server time'),
|
||||
'cal_end' => array('type' => 'int','precision' => '8','nullable' => False,'comment' => 'endtime in server time')
|
||||
),
|
||||
'pk' => array('cal_id','cal_start'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_cal_timezones' => array(
|
||||
'fd' => array(
|
||||
'tz_id' => array('type' => 'auto','nullable' => False),
|
||||
'tz_tzid' => array('type' => 'varchar','precision' => '128','nullable' => False),
|
||||
'tz_alias' => array('type' => 'int','precision' => '4','comment' => 'tz_id for data'),
|
||||
'tz_latitude' => array('type' => 'int','precision' => '4'),
|
||||
'tz_longitude' => array('type' => 'int','precision' => '4'),
|
||||
'tz_component' => array('type' => 'text','comment' => 'iCal VTIMEZONE component')
|
||||
),
|
||||
'pk' => array('tz_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('tz_alias'),
|
||||
'uc' => array('tz_tzid')
|
||||
)
|
||||
);
|
@ -1630,6 +1630,7 @@ function calendar_upgrade1_5_002()
|
||||
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.6';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adjust UIDs of series exceptions to RFC standard
|
||||
* Propagate cal_reference field to temporarily contain RECURRENCE-ID
|
||||
@ -1968,24 +1969,50 @@ function calendar_upgrade1_7_009()
|
||||
|
||||
function calendar_upgrade1_7_010()
|
||||
{
|
||||
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.8';
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_cal','cal_deleted',array(
|
||||
'type' => 'bool',
|
||||
'nullable' => False,
|
||||
'default' => '0',
|
||||
'comment' => '1 if the event has been deleted, but you want to keep it around'
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.001'; // was 1.7.011
|
||||
}
|
||||
|
||||
function calendar_upgrade1_7_011()
|
||||
{
|
||||
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.001';
|
||||
}
|
||||
|
||||
function calendar_upgrade1_8()
|
||||
{
|
||||
calendar_upgrade1_7_010();
|
||||
|
||||
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.001';
|
||||
}
|
||||
|
||||
/**
|
||||
* Downgrade from Trunk / EPL 10.1 to 1.8: droping cal_deleted
|
||||
*
|
||||
* Convert bool column cal_deleted with egw_api_content_history table to a unix timestamp
|
||||
*
|
||||
* Using cal_modified as deleted-timestamp, as querying it from SyncML tables creates too many problems (refresh table stops before copying all rows!)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function calendar_upgrade1_7_011()
|
||||
function calendar_upgrade1_9_001()
|
||||
{
|
||||
$deleted = 'cal_deleted=1 OR cal_deleted IS NOT NULL AND cal_deleted != 0';
|
||||
foreach(array('egw_cal_dates','egw_cal_extra','egw_cal_repeats','egw_cal_user') as $table)
|
||||
{
|
||||
$GLOBALS['egw_setup']->db->delete($table,"cal_id IN (SELECT cal_id FROM egw_cal WHERE $deleted)",__LINE__,__FILE__,'calendar');
|
||||
}
|
||||
$GLOBALS['egw_setup']->db->delete('egw_cal',$deleted,__LINE__,__FILE__);
|
||||
|
||||
$GLOBALS['egw_setup']->oProc->DropColumn('egw_cal',array(
|
||||
// delete in the past wrongly created entries for a single recurrence, which mess up the update, beside being wrong anyway
|
||||
$GLOBALS['egw_setup']->db->delete('egw_api_content_history',array(
|
||||
'sync_appname' => 'calendar',
|
||||
"sync_contentid LIKE '%:%'",
|
||||
), __LINE__, __FILE__);
|
||||
|
||||
/* done by RefreshTable() anyway
|
||||
$GLOBALS['egw_setup']->oProc->AlterColumn('egw_cal','cal_deleted',array(
|
||||
'type' => 'int',
|
||||
'precision' => '8',
|
||||
'comment' => 'ts when event was deleted'
|
||||
));*/
|
||||
$GLOBALS['egw_setup']->oProc->RefreshTable('egw_cal',array(
|
||||
'fd' => array(
|
||||
'cal_id' => array('type' => 'auto','nullable' => False),
|
||||
'cal_uid' => array('type' => 'varchar','precision' => '255','nullable' => False,'comment' => 'unique id of event(-series)'),
|
||||
@ -2012,15 +2039,42 @@ function calendar_upgrade1_7_011()
|
||||
'fk' => array(),
|
||||
'ix' => array('cal_uid','cal_owner','cal_deleted'),
|
||||
'uc' => array()
|
||||
),'cal_deleted');
|
||||
),array(
|
||||
// for deleted rows use cal_modified as deleted date, NULL for not deleted ones
|
||||
'cal_deleted' => 'CASE cal_deleted WHEN '.$GLOBALS['egw_setup']->db->quote(true,'bool').' THEN cal_modified ELSE NULL END',
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.8';
|
||||
}
|
||||
function calendar_upgrade1_9_001()
|
||||
{
|
||||
return calendar_upgrade1_7_011();
|
||||
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.002';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add column to store CalDAV name given by client
|
||||
*/
|
||||
function calendar_upgrade1_9_002()
|
||||
{
|
||||
return calendar_upgrade1_7_011();
|
||||
}
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_cal','caldav_name',array(
|
||||
'type' => 'varchar',
|
||||
'precision' => '64',
|
||||
'comment' => 'name part of CalDAV URL, if specified by client'
|
||||
));
|
||||
$GLOBALS['egw_setup']->db->query($sql='UPDATE egw_cal SET caldav_name='.
|
||||
$GLOBALS['egw_setup']->db->concat(
|
||||
$GLOBALS['egw_setup']->db->to_varchar('cal_id'),"'.ics'"),__LINE__,__FILE__);
|
||||
|
||||
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_cal','caldav_name');
|
||||
|
||||
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.003';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add index for cal_modified and cal_user_modified to improve ctag and etag generation on big installtions
|
||||
*/
|
||||
function calendar_upgrade1_9_003()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_cal','cal_modified');
|
||||
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_cal_user','cal_user_modified');
|
||||
|
||||
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.004';
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ $tz_aliases = array(
|
||||
'Arabic Standard Time' => 'Asia/Baghdad',
|
||||
'Argentina Standard Time' => 'America/Argentina/Buenos_Aires', // was 'America/Buenos_Aires',
|
||||
'Armenian Standard Time' => 'Asia/Yerevan',
|
||||
'Asia/Katmandu' => 'Asia/Kathmandu',
|
||||
'Asia/Calcutta' => 'Asia/Kolkata',
|
||||
'Atlantic Standard Time' => 'America/Halifax',
|
||||
'Azerbaijan Standard Time' => 'Asia/Baku',
|
||||
'Azores Standard Time' => 'Atlantic/Azores',
|
||||
@ -50,7 +52,7 @@ $tz_aliases = array(
|
||||
'Greenland Standard Time' => 'America/Godthab',
|
||||
'Greenwich Standard Time' => 'Atlantic/Reykjavik', // was 'Africa/Reykjavik',
|
||||
'Hawaiian Standard Time' => 'Pacific/Honolulu',
|
||||
'India Standard Time' => 'Asia/Calcutta',
|
||||
'India Standard Time' => 'Asia/Kolkata',
|
||||
'Iran Standard Time' => 'Asia/Tehran',
|
||||
'Israel Standard Time' => 'Asia/Jerusalem',
|
||||
'Jordan Standard Time' => 'Asia/Amman',
|
||||
@ -67,7 +69,7 @@ $tz_aliases = array(
|
||||
'Myanmar Standard Time' => 'Asia/Rangoon',
|
||||
'N. Central Asia Standard Time' => 'Asia/Novosibirsk',
|
||||
'Namibia Standard Time' => 'Africa/Windhoek',
|
||||
'Nepal Standard Time' => 'Asia/Katmandu',
|
||||
'Nepal Standard Time' => 'Asia/Kathmandu',
|
||||
'New Zealand Standard Time' => 'Pacific/Auckland',
|
||||
'Newfoundland Standard Time' => 'America/St_Johns',
|
||||
'North Asia East Standard Time' => 'Asia/Irkutsk',
|
||||
@ -100,4 +102,4 @@ $tz_aliases = array(
|
||||
'West Asia Standard Time' => 'Asia/Tashkent',
|
||||
'West Pacific Standard Time' => 'Pacific/Port_Moresby',
|
||||
'Yakutsk Standard Time' => 'Asia/Yakutsk',
|
||||
);
|
||||
);
|
||||
|
@ -1,24 +1,38 @@
|
||||
<?php
|
||||
//
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP Version 4 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1997-2003 The PHP Group |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | This source file is subject to version 2.02 of the PHP license, |
|
||||
// | that is bundled with this package in the file LICENSE, and is |
|
||||
// | available at through the world-wide-web at |
|
||||
// | http://www.php.net/license/2_02.txt. |
|
||||
// | If you did not receive a copy of the PHP license and are unable to |
|
||||
// | obtain it through the world-wide-web, please send a note to |
|
||||
// | license@php.net so we can mail you a copy immediately. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Hartmut Holzgraefe <hholzgra@php.net> |
|
||||
// | Christian Stocker <chregu@bitflux.ch> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: Server.php,v 1.56 2006/10/10 11:53:16 hholzgra Exp $
|
||||
//
|
||||
<?php // $Id$
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2002-2007 Christian Stocker, Hartmut Holzgraefe |
|
||||
| All rights reserved |
|
||||
| |
|
||||
| Redistribution and use in source and binary forms, with or without |
|
||||
| modification, are permitted provided that the following conditions |
|
||||
| are met: |
|
||||
| |
|
||||
| 1. Redistributions of source code must retain the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer. |
|
||||
| 2. Redistributions in binary form must reproduce the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer in |
|
||||
| the documentation and/or other materials provided with the |
|
||||
| distribution. |
|
||||
| 3. The names of the authors may not be used to endorse or promote |
|
||||
| products derived from this software without specific prior |
|
||||
| written permission. |
|
||||
| |
|
||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
||||
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
||||
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
||||
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
||||
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
||||
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
||||
| POSSIBILITY OF SUCH DAMAGE. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once "HTTP/WebDAV/Tools/_parse_propfind.php";
|
||||
require_once "HTTP/WebDAV/Tools/_parse_proppatch.php";
|
||||
require_once "HTTP/WebDAV/Tools/_parse_lockinfo.php";
|
||||
@ -169,23 +183,23 @@ class HTTP_WebDAV_Server
|
||||
// default uri is the complete request uri
|
||||
$uri = (@$this->_SERVER["HTTPS"] === "on" ? "https:" : "http:") . '//'.$this->_SERVER['HTTP_HOST'];
|
||||
}
|
||||
// support for PHP running as (F)CGI
|
||||
if (!isset($this->_SERVER['PATH_INFO']) && isset($this->_SERVER['ORIG_PATH_INFO']))
|
||||
{
|
||||
$this->_SERVER['PATH_INFO'] = $this->_SERVER['ORIG_PATH_INFO'];
|
||||
}
|
||||
// we cant use SCRIPT_NAME, because it fails, if there's any url rewriting
|
||||
//error_log("pathinfo:\n". $this->_urldecode($this->_SERVER['REQUEST_URI']).":\n".$this->_SERVER['PATH_INFO']);
|
||||
$uri .= $this->_urldecode($this->_SERVER['REQUEST_URI']);
|
||||
if (!empty($this->_SERVER["PATH_INFO"]))
|
||||
{
|
||||
$uri = substr($uri,0,-strlen($this->_SERVER["PATH_INFO"]));
|
||||
$uri .= $this->_SERVER["SCRIPT_NAME"];
|
||||
|
||||
// WebDAV has no concept of a query string and clients (including cadaver)
|
||||
// seem to pass '?' unencoded, so we need to extract the path info out
|
||||
// of the request URI ourselves
|
||||
$path_info = substr($this->_SERVER["REQUEST_URI"], strlen($this->_SERVER["SCRIPT_NAME"]));
|
||||
|
||||
// just in case the path came in empty ...
|
||||
if (empty($path_info)) {
|
||||
$path_info = "/";
|
||||
}
|
||||
|
||||
$path_info = empty($this->_SERVER["PATH_INFO"]) ? "/" : $this->_SERVER["PATH_INFO"];
|
||||
$path_info = $this->_urldecode($path_info);
|
||||
|
||||
$this->base_uri = $uri;
|
||||
$this->uri = $uri . $path_info;
|
||||
|
||||
// set path
|
||||
// $_SERVER['PATH_INFO'] is already urldecoded
|
||||
//$this->path = $this->_urldecode($path_info);
|
||||
@ -546,7 +560,7 @@ class HTTP_WebDAV_Server
|
||||
* OPTIONS method handler
|
||||
*
|
||||
* The OPTIONS method handler creates a valid OPTIONS reply
|
||||
* including Dav: and Allowed: heaers
|
||||
* including Dav: and Allowed: headers
|
||||
* based on the implemented methods found in the actual instance
|
||||
*
|
||||
* @param void
|
||||
@ -824,8 +838,10 @@ class HTTP_WebDAV_Server
|
||||
/* TODO right now the user implementation has to make sure
|
||||
collections end in a slash, this should be done in here
|
||||
by checking the resource attribute */
|
||||
// path needs to be urlencoded (only basic version of this class!)
|
||||
$href = $this->_urlencode($this->_mergePathes($this->base_uri, $path));
|
||||
$href = $this->_mergePaths($this->base_uri, $path);
|
||||
|
||||
/* minimal urlencoding is needed for the resource path */
|
||||
$href = $this->_urlencode($href);
|
||||
|
||||
if ($this->crrnd)
|
||||
{
|
||||
@ -876,6 +892,17 @@ class HTTP_WebDAV_Server
|
||||
echo $prop["val"];
|
||||
echo ' </'.($this->crrnd?'':'D:')."lockdiscovery>\n";
|
||||
break;
|
||||
// the following are non-standard Microsoft extensions to the DAV namespace
|
||||
case "lastaccessed":
|
||||
echo ' <'.($this->crrnd?'':'D:')."lastaccessed ns0:dt=\"dateTime.rfc1123\">"
|
||||
. gmdate("D, d M Y H:i:s ", $prop['val'])
|
||||
. 'GMT</'.($this->crrnd?'':'D:')."lastaccessed>\n";
|
||||
break;
|
||||
case "ishidden":
|
||||
echo ' <'.($this->crrnd?'':'D:')."ishidden>"
|
||||
. is_string($prop['val']) ? $prop['val'] : ($prop['val'] ? 'true' : 'false')
|
||||
. '</'.($this->crrnd?'':'D:')."</D:ishidden>\n";
|
||||
break;
|
||||
default:
|
||||
$ns_defs = '';
|
||||
if (is_array($prop['val']))
|
||||
@ -885,7 +912,7 @@ class HTTP_WebDAV_Server
|
||||
} elseif (isset($prop['raw'])) {
|
||||
$val = $this->_prop_encode('<![CDATA['.$prop['val'].']]>');
|
||||
} else {
|
||||
$val = $this->_prop_encode(htmlspecialchars($prop['val']));
|
||||
$val = $this->_prop_encode(htmlspecialchars($prop['val'], ENT_NOQUOTES, 'utf-8'));
|
||||
}
|
||||
echo ' <'.($this->crrnd?'':'D:')."$prop[name]$ns_defs>$val".
|
||||
'</'.($this->crrnd?'':'D:')."$prop[name]>\n";
|
||||
@ -919,13 +946,22 @@ class HTTP_WebDAV_Server
|
||||
$ns_name = '';
|
||||
}
|
||||
$vals .= "<$ns_name$subprop[name]";
|
||||
if (is_array($subprop['val'])) // val contains only attributes, no value
|
||||
if (is_array($subprop['val']))
|
||||
{
|
||||
foreach($subprop['val'] as $attr => $val)
|
||||
{
|
||||
$vals .= ' '.$attr.'="'.htmlspecialchars($val).'"';
|
||||
}
|
||||
$vals .= '/>';
|
||||
if (isset($subprop['val'][0]))
|
||||
{
|
||||
$vals .= '>';
|
||||
$vals .= $this->_hierarchical_prop_encode($subprop['val'], $subprop['ns'], $ns_defs, $ns_hash);
|
||||
$vals .= "</$ns_name$subprop[name]>";
|
||||
}
|
||||
else // val contains only attributes, no value
|
||||
{
|
||||
foreach($subprop['val'] as $attr => $val)
|
||||
{
|
||||
$vals .= ' '.$attr.'="'.htmlspecialchars($val, ENT_NOQUOTES, 'utf-8').'"';
|
||||
}
|
||||
$vals .= '/>';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -933,7 +969,7 @@ class HTTP_WebDAV_Server
|
||||
if (isset($subprop['raw'])) {
|
||||
$vals .= '<![CDATA['.$subprop['val'].']]>';
|
||||
} else {
|
||||
$vals .= htmlspecialchars($subprop['val']);
|
||||
$vals .= htmlspecialchars($subprop['val'], ENT_NOQUOTES, 'utf-8');
|
||||
}
|
||||
$vals .= "</$ns_name$subprop[name]>";
|
||||
}
|
||||
@ -944,7 +980,7 @@ class HTTP_WebDAV_Server
|
||||
{
|
||||
$val = '<![CDATA['.$prop['val'].']]>';
|
||||
} else {
|
||||
$val = htmlspecialchars($prop['val']);
|
||||
$val = htmlspecialchars($prop['val'], ENT_NOQUOTES, 'utf-8');
|
||||
}
|
||||
$val = $this->_prop_encode($val);
|
||||
// properties from namespaces != "DAV:" or without any namespace
|
||||
@ -1049,7 +1085,7 @@ class HTTP_WebDAV_Server
|
||||
|
||||
echo "<D:multistatus xmlns:D=\"DAV:\">\n";
|
||||
echo ' <'.($this->crrnd?'':'D:')."response>\n";
|
||||
echo ' <'.($this->crrnd?'':'D:')."href>".$this->_urlencode($this->_mergePathes($this->_SERVER["SCRIPT_NAME"], $this->path)).'</'.($this->crrnd?'':'D:')."href>\n";
|
||||
echo ' <'.($this->crrnd?'':'D:')."href>".$this->_urlencode($this->_mergePaths($this->_SERVER["SCRIPT_NAME"], $this->path)).'</'.($this->crrnd?'':'D:')."href>\n";
|
||||
|
||||
foreach ($options["props"] as $prop) {
|
||||
echo ' <'.($this->crrnd?'':'D:')."propstat>\n";
|
||||
@ -1060,7 +1096,7 @@ class HTTP_WebDAV_Server
|
||||
|
||||
if ($responsedescr) {
|
||||
echo ' <'.($this->crrnd?'':'D:')."responsedescription>".
|
||||
$this->_prop_encode(htmlspecialchars($responsedescr)).
|
||||
$this->_prop_encode(htmlspecialchars($responsedescr, ENT_NOQUOTES, 'utf-8')).
|
||||
'</'.($this->crrnd?'':'D:')."responsedescription>\n";
|
||||
}
|
||||
|
||||
@ -1225,7 +1261,7 @@ class HTTP_WebDAV_Server
|
||||
if (false === $status) {
|
||||
$this->http_status("404 not found");
|
||||
} else {
|
||||
// TODO: check setting of headers in various code pathes above
|
||||
// TODO: check setting of headers in various code paths above
|
||||
$this->http_status("$status");
|
||||
}
|
||||
}
|
||||
@ -1363,8 +1399,6 @@ class HTTP_WebDAV_Server
|
||||
$options = Array();
|
||||
$options['path'] = $this->path;
|
||||
|
||||
error_log('WebDAV POST: ' . $this->path);
|
||||
|
||||
if (isset($this->_SERVER['CONTENT_LENGTH']))
|
||||
{
|
||||
$options['content_length'] = $this->_SERVER['CONTENT_LENGTH'];
|
||||
@ -1488,8 +1522,6 @@ class HTTP_WebDAV_Server
|
||||
}
|
||||
}
|
||||
|
||||
$options['stream'] = fopen('php://input', 'r');
|
||||
|
||||
if (method_exists($this, 'POST')) {
|
||||
$status = $this->POST($options);
|
||||
|
||||
@ -1557,7 +1589,7 @@ class HTTP_WebDAV_Server
|
||||
// for now we do not support any sort of multipart requests
|
||||
if (!strncmp($this->_SERVER["CONTENT_TYPE"], "multipart/", 10)) {
|
||||
$this->http_status("501 not implemented");
|
||||
echo "The service does not support mulipart PUT requests";
|
||||
echo "The service does not support multipart PUT requests";
|
||||
return;
|
||||
}
|
||||
$options["content_type"] = $this->_SERVER["CONTENT_TYPE"];
|
||||
@ -1636,11 +1668,16 @@ class HTTP_WebDAV_Server
|
||||
return;
|
||||
}
|
||||
|
||||
$range = array("start"=>$matches[1], "end"=>$matches[2]);
|
||||
$range = array("start" => $matches[1], "end" => $matches[2]);
|
||||
if (is_numeric($matches[3])) {
|
||||
$range["total_length"] = $matches[3];
|
||||
}
|
||||
$option["ranges"][] = $range;
|
||||
|
||||
if (!isset($options['ranges'])) {
|
||||
$options['ranges'] = array();
|
||||
}
|
||||
|
||||
$options["ranges"][] = $range;
|
||||
|
||||
// TODO make sure the implementation supports partial PUT
|
||||
// this has to be done in advance to avoid data being overwritten
|
||||
@ -1665,8 +1702,6 @@ class HTTP_WebDAV_Server
|
||||
}
|
||||
}
|
||||
|
||||
$options["stream"] = fopen("php://input", "r");
|
||||
|
||||
$stat = $this->PUT($options);
|
||||
|
||||
if ($stat === false) {
|
||||
@ -1678,17 +1713,36 @@ class HTTP_WebDAV_Server
|
||||
|
||||
if (!empty($options["ranges"])) {
|
||||
// TODO multipart support is missing (see also above)
|
||||
if (0 == fseek($stream, $range[0]["start"], SEEK_SET)) {
|
||||
$length = $range[0]["end"]-$range[0]["start"]+1;
|
||||
if (!fwrite($stream, fread($options["stream"], $length))) {
|
||||
$stat = "403 Forbidden";
|
||||
if (0 == fseek($stream, $options['ranges'][0]["start"], SEEK_SET)) {
|
||||
$length = $options['ranges'][0]["end"] - $options['ranges'][0]["start"]+1;
|
||||
|
||||
while (!feof($options['stream'])) {
|
||||
if ($length <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($length <= 8192) {
|
||||
$data = fread($options['stream'], $length);
|
||||
} else {
|
||||
$data = fread($options['stream'], 8192);
|
||||
}
|
||||
|
||||
if ($data === false) {
|
||||
$stat = "400 Bad request";
|
||||
} elseif (strlen($data)) {
|
||||
if (false === fwrite($stream, $data)) {
|
||||
$stat = "403 Forbidden";
|
||||
break;
|
||||
}
|
||||
$length -= strlen($data);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$stat = "403 Forbidden";
|
||||
}
|
||||
} else {
|
||||
while (!feof($options["stream"])) {
|
||||
if (false === fwrite($stream, fread($options["stream"], 4096))) {
|
||||
if (false === fwrite($stream, fread($options["stream"], 8192))) {
|
||||
$stat = "403 Forbidden";
|
||||
break;
|
||||
}
|
||||
@ -1854,26 +1908,32 @@ class HTTP_WebDAV_Server
|
||||
if (is_bool($stat)) {
|
||||
$http_stat = $stat ? "200 OK" : "423 Locked";
|
||||
} else {
|
||||
$http_stat = $stat;
|
||||
$http_stat = (string)$stat;
|
||||
}
|
||||
$this->http_status($http_stat);
|
||||
|
||||
if ($http_stat{0} == 2) { // 2xx states are ok
|
||||
if ($options["timeout"]) {
|
||||
if (is_numeric($options["timeout"]))
|
||||
{
|
||||
// more than a million is considered an absolute timestamp
|
||||
// less is more likely a relative value
|
||||
if ($options["timeout"]>1000000) {
|
||||
$timeout = "Second-".($options['timeout']-time());
|
||||
} else {
|
||||
$timeout = "Second-$options[timeout]";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$timeout = $options[timeout];
|
||||
}
|
||||
// if multiple timeout values were given we take the first only
|
||||
if (is_array($options["timeout"])) {
|
||||
reset($options["timeout"]);
|
||||
$options["timeout"] = current($options["timeout"]);
|
||||
}
|
||||
// if the timeout is numeric only we need to reformat it
|
||||
if (is_numeric($options["timeout"])) {
|
||||
// more than a million is considered an absolute timestamp
|
||||
// less is more likely a relative value
|
||||
if ($options["timeout"]>1000000) {
|
||||
$timeout = "Second-".($options['timeout']-time());
|
||||
} else {
|
||||
$timeout = "Second-$options[timeout]";
|
||||
}
|
||||
} else {
|
||||
// non-numeric values are passed on verbatim,
|
||||
// no error checking is performed here in this case
|
||||
// TODO: send "Infinite" on invalid timeout strings?
|
||||
$timeout = $options["timeout"];
|
||||
}
|
||||
} else {
|
||||
$timeout = "Infinite";
|
||||
}
|
||||
@ -1987,14 +2047,21 @@ class HTTP_WebDAV_Server
|
||||
$options["depth"] = "infinity";
|
||||
}
|
||||
|
||||
extract(parse_url($this->_SERVER["HTTP_DESTINATION"]));
|
||||
$path = urldecode($path);
|
||||
$http_host = $host;
|
||||
if (isset($port) && $port != 80)
|
||||
$http_host.= ":$port";
|
||||
|
||||
$http_header_host = preg_replace("/:80$/", "", $this->_SERVER["HTTP_HOST"]);
|
||||
|
||||
$url = parse_url($this->_SERVER["HTTP_DESTINATION"]);
|
||||
$path = urldecode($url["path"]);
|
||||
|
||||
if (isset($url["host"])) {
|
||||
// TODO check url scheme, too
|
||||
$http_host = $url["host"];
|
||||
if (isset($url["port"]) && $url["port"] != 80)
|
||||
$http_host.= ":".$url["port"];
|
||||
} else {
|
||||
// only path given, set host to self
|
||||
$http_host == $http_header_host;
|
||||
}
|
||||
|
||||
if ($http_host == $http_header_host &&
|
||||
!strncmp($this->_SERVER["SCRIPT_NAME"], $path,
|
||||
strlen($this->_SERVER["SCRIPT_NAME"]))) {
|
||||
@ -2491,7 +2558,7 @@ class HTTP_WebDAV_Server
|
||||
/**
|
||||
* private minimalistic version of PHP urlencode()
|
||||
*
|
||||
* only blanks and XML special chars must be encoded here
|
||||
* only blanks, percent and XML special chars must be encoded here
|
||||
* full urlencode() encoding confuses some clients ...
|
||||
*
|
||||
* @param string URL to encode
|
||||
@ -2511,6 +2578,7 @@ class HTTP_WebDAV_Server
|
||||
}
|
||||
//error_log( __METHOD__."\n" .print_r($url,true));
|
||||
return strtr($url, array(' ' => '%20',
|
||||
'%' => '%25',
|
||||
'&' => '%26',
|
||||
'<' => '%3C',
|
||||
'>' => '%3E',
|
||||
@ -2528,7 +2596,7 @@ class HTTP_WebDAV_Server
|
||||
*/
|
||||
function _urldecode($path)
|
||||
{
|
||||
return urldecode($path);
|
||||
return rawurldecode($path);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2584,7 +2652,7 @@ class HTTP_WebDAV_Server
|
||||
|
||||
foreach($subprop as $attr => $val)
|
||||
{
|
||||
$vals .= ' '.$attr.'="'.htmlspecialchars($val).'"';
|
||||
$vals .= ' '.$attr.'="'.htmlspecialchars($val, ENT_NOQUOTES, 'utf-8').'"';
|
||||
}
|
||||
|
||||
$ret .= '<'.($prop['ns'] == $ns ? ($this->cnrnd ? $ns_hash[$ns].':' : '') : $ns_hash[$prop['ns']].':').$prop['name'].
|
||||
@ -2603,8 +2671,14 @@ class HTTP_WebDAV_Server
|
||||
{
|
||||
$val = $this->_prop_encode('<![CDATA['.$prop['val'].']]>');
|
||||
} else {
|
||||
$val = $this->_prop_encode(htmlspecialchars($prop['val']));
|
||||
} }
|
||||
$val = $this->_prop_encode(htmlspecialchars($prop['val'], ENT_NOQUOTES, 'utf-8'));
|
||||
// for href properties we need (minimalistic) urlencoding, eg. space
|
||||
if ($prop['name'] == 'href')
|
||||
{
|
||||
$val = $this->_urlencode($val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ret .= '<'.($prop['ns'] == $ns ? ($this->cnrnd ? $ns_hash[$ns].':' : '') : $ns_hash[$prop['ns']].':').$prop['name'].
|
||||
(empty($prop['val']) ? ' />' : '>'.$val.'</'.($prop['ns'] == $ns ? ($this->cnrnd ? $ns_hash[$ns].':' : '') : ($this->crrnd ? '' : $ns_hash[$prop['ns']].':')).$prop['name'].'>');
|
||||
@ -2672,17 +2746,17 @@ class HTTP_WebDAV_Server
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two pathes, make sure there is exactly one slash between them
|
||||
* Merge two paths, make sure there is exactly one slash between them
|
||||
*
|
||||
* @param string parent path
|
||||
* @param string child path
|
||||
* @return string merged path
|
||||
*/
|
||||
function _mergePathes($parent, $child)
|
||||
function _mergePaths($parent, $child)
|
||||
{
|
||||
//error_log("merge called :\n$parent \n$child\n" . function_backtrace());
|
||||
//error_log("merge :\n".print_r($this->_mergePathes($this->_SERVER["SCRIPT_NAME"], $this->path)true));
|
||||
if ($child{0} == '/') {
|
||||
//error_log("merge called :\n$parent \n$child\n" . function_backtrace());
|
||||
//error_log("merge :\n".print_r($this->_mergePaths($this->_SERVER["SCRIPT_NAME"], $this->path)true));
|
||||
if ($child{0} == '/') {
|
||||
return $this->_unslashify($parent).$child;
|
||||
} else {
|
||||
return $this->_slashify($parent).$child;
|
||||
|
@ -1,4 +1,37 @@
|
||||
<?php
|
||||
<?php // $Id: Filesystem.php 312282 2011-06-19 13:39:05Z clockwerx $
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2002-2007 Christian Stocker, Hartmut Holzgraefe |
|
||||
| All rights reserved |
|
||||
| |
|
||||
| Redistribution and use in source and binary forms, with or without |
|
||||
| modification, are permitted provided that the following conditions |
|
||||
| are met: |
|
||||
| |
|
||||
| 1. Redistributions of source code must retain the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer. |
|
||||
| 2. Redistributions in binary form must reproduce the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer in |
|
||||
| the documentation and/or other materials provided with the |
|
||||
| distribution. |
|
||||
| 3. The names of the authors may not be used to endorse or promote |
|
||||
| products derived from this software without specific prior |
|
||||
| written permission. |
|
||||
| |
|
||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
||||
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
||||
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
||||
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
||||
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
||||
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
||||
| POSSIBILITY OF SUCH DAMAGE. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once "HTTP/WebDAV/Server.php";
|
||||
require_once "System.php";
|
||||
@ -73,11 +106,9 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
// special treatment for litmus compliance test
|
||||
// reply on its identifier header
|
||||
// not needed for the test itself but eases debugging
|
||||
foreach (apache_request_headers() as $key => $value) {
|
||||
if (stristr($key, "litmus")) {
|
||||
error_log("Litmus test $value");
|
||||
header("X-Litmus-reply: ".$value);
|
||||
}
|
||||
if (isset($this->_SERVER['HTTP_X_LITMUS'])) {
|
||||
error_log("Litmus test ".$this->_SERVER['HTTP_X_LITMUS']);
|
||||
header("X-Litmus-reply: ".$this->_SERVER['HTTP_X_LITMUS']);
|
||||
}
|
||||
|
||||
// set root directory, defaults to webserver document root if not set
|
||||
@ -135,13 +166,13 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
$files["files"][] = $this->fileinfo($options["path"]);
|
||||
|
||||
// information for contained resources requested?
|
||||
if (!empty($options["depth"])) { // TODO check for is_dir() first?
|
||||
if (!empty($options["depth"]) && is_dir($fspath) && $this->_is_readable($fspath)) {
|
||||
|
||||
// make sure path ends with '/'
|
||||
$options["path"] = $this->_slashify($options["path"]);
|
||||
|
||||
// try to open directory
|
||||
$handle = @opendir($fspath);
|
||||
$handle = opendir($fspath);
|
||||
|
||||
if ($handle) {
|
||||
// ok, now get all its contents
|
||||
@ -183,15 +214,19 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
$info["props"][] = $this->mkprop("creationdate", filectime($fspath));
|
||||
$info["props"][] = $this->mkprop("getlastmodified", filemtime($fspath));
|
||||
|
||||
// Microsoft extensions: last access time and 'hidden' status
|
||||
$info["props"][] = $this->mkprop("lastaccessed", fileatime($fspath));
|
||||
$info["props"][] = $this->mkprop("ishidden", ('.' === substr(basename($fspath), 0, 1)));
|
||||
|
||||
// type and size (caller already made sure that path exists)
|
||||
if (is_dir($fspath)) {
|
||||
// directory (WebDAV collection)
|
||||
$info["props"][] = $this->mkprop("resourcetype", array($this->mkprop('collection', '')));
|
||||
$info["props"][] = $this->mkprop("resourcetype", "collection");
|
||||
$info["props"][] = $this->mkprop("getcontenttype", "httpd/unix-directory");
|
||||
} else {
|
||||
// plain file (WebDAV resource)
|
||||
$info["props"][] = $this->mkprop("resourcetype", "");
|
||||
if (is_readable($fspath)) {
|
||||
if ($this->_is_readable($fspath)) {
|
||||
$info["props"][] = $this->mkprop("getcontenttype", $this->_mimetype($fspath));
|
||||
} else {
|
||||
$info["props"][] = $this->mkprop("getcontenttype", "application/x-non-readable");
|
||||
@ -255,6 +290,31 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if path is readable by current user
|
||||
*
|
||||
* Allow extending classes to overwrite it
|
||||
*
|
||||
* @param string $fspath
|
||||
* @return boolean
|
||||
*/
|
||||
function _is_readable($fspath)
|
||||
{
|
||||
return is_readable($fspath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if path is writable by current user
|
||||
*
|
||||
* Allow extending classes to overwrite it
|
||||
*
|
||||
* @param string $fspath
|
||||
* @return boolean
|
||||
*/
|
||||
function _is_writable($fspath)
|
||||
{
|
||||
return is_writable($fspath);
|
||||
}
|
||||
|
||||
/**
|
||||
* try to detect the mime type of a file
|
||||
@ -264,7 +324,7 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
*/
|
||||
function _mimetype($fspath)
|
||||
{
|
||||
if (@is_dir($fspath)) {
|
||||
if (is_dir($fspath)) {
|
||||
// directories are easy
|
||||
return "httpd/unix-directory";
|
||||
} else if (function_exists("mime_content_type")) {
|
||||
@ -325,12 +385,12 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
}
|
||||
|
||||
/**
|
||||
* GET method handler
|
||||
* HEAD method handler
|
||||
*
|
||||
* @param array parameter passing array
|
||||
* @return bool true on success
|
||||
*/
|
||||
function GET(&$options)
|
||||
function HEAD(&$options)
|
||||
{
|
||||
// get absolute fs path to requested resource
|
||||
$fspath = $this->base . $options["path"];
|
||||
@ -338,11 +398,6 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
// sanity check
|
||||
if (!file_exists($fspath)) return false;
|
||||
|
||||
// is this a collection?
|
||||
if (is_dir($fspath)) {
|
||||
return $this->GetDir($fspath, $options);
|
||||
}
|
||||
|
||||
// detect resource type
|
||||
$options['mimetype'] = $this->_mimetype($fspath);
|
||||
|
||||
@ -355,11 +410,33 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
// detect resource size
|
||||
$options['size'] = filesize($fspath);
|
||||
|
||||
// no need to check result here, it is handled by the base class
|
||||
if (!($options['stream'] = fopen($fspath, "r")))
|
||||
{
|
||||
return '403 Forbidden';
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* GET method handler
|
||||
*
|
||||
* @param array parameter passing array
|
||||
* @return bool true on success
|
||||
*/
|
||||
function GET(&$options)
|
||||
{
|
||||
// get absolute fs path to requested resource
|
||||
$fspath = $this->base . $options["path"];
|
||||
|
||||
// is this a collection?
|
||||
if (is_dir($fspath)) {
|
||||
return $this->GetDir($fspath, $options);
|
||||
}
|
||||
|
||||
// the header output is the same as for HEAD
|
||||
if (!$this->HEAD($options)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// no need to check result here, it is handled by the base class
|
||||
$options['stream'] = fopen($fspath, "r");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -383,12 +460,16 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
// fixed width directory column format
|
||||
$format = "%15s %-19s %-s\n";
|
||||
|
||||
$handle = @opendir($fspath);
|
||||
if (!$this->_is_readable($fspath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$handle = opendir($fspath);
|
||||
if (!$handle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
echo "<html><head><title>Index of ".htmlspecialchars($options['path'])."</title></head>\n";
|
||||
echo "<html><head><title>Index of ".htmlspecialchars(urldecode($options['path']))."</title></head>\n";
|
||||
|
||||
echo "<h1>Index of ".htmlspecialchars($options['path'])."</h1>\n";
|
||||
|
||||
@ -403,7 +484,7 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
printf($format,
|
||||
number_format(filesize($fullpath)),
|
||||
strftime("%Y-%m-%d %H:%M:%S", filemtime($fullpath)),
|
||||
'<a href="'.$name.'">'.$name.'</a>');
|
||||
'<a href="'.$name.'">'.urldecode($name).'</a>');
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,12 +507,23 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
{
|
||||
$fspath = $this->base . $options["path"];
|
||||
|
||||
if (!@is_dir(dirname($fspath))) {
|
||||
return "409 Conflict";
|
||||
$dir = dirname($fspath);
|
||||
if (!file_exists($dir) || !is_dir($dir)) {
|
||||
return "409 Conflict"; // TODO right status code for both?
|
||||
}
|
||||
|
||||
$options["new"] = ! file_exists($fspath);
|
||||
|
||||
if ($options["new"] && !$this->_is_writable($dir)) {
|
||||
return "403 Forbidden";
|
||||
}
|
||||
if (!$options["new"] && !$this->_is_writable($fspath)) {
|
||||
return "403 Forbidden";
|
||||
}
|
||||
if (!$options["new"] && is_dir($fspath)) {
|
||||
return "403 Forbidden";
|
||||
}
|
||||
|
||||
$fp = fopen($fspath, "w");
|
||||
|
||||
return $fp;
|
||||
@ -493,7 +585,7 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
$query = "DELETE FROM {$this->db_prefix}properties
|
||||
WHERE path LIKE '".$this->_slashify($options["path"])."%'";
|
||||
mysql_query($query);
|
||||
System::rm("-rf $path");
|
||||
System::rm(array("-rf", $path));
|
||||
} else {
|
||||
unlink($path);
|
||||
}
|
||||
@ -535,10 +627,34 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
return "502 bad gateway";
|
||||
}
|
||||
|
||||
$source = $this->base .$options["path"];
|
||||
if (!file_exists($source)) return "404 Not found";
|
||||
$source = $this->base . $options["path"];
|
||||
if (!file_exists($source)) {
|
||||
return "404 Not found";
|
||||
}
|
||||
|
||||
if (is_dir($source)) { // resource is a collection
|
||||
switch ($options["depth"]) {
|
||||
case "infinity": // valid
|
||||
break;
|
||||
case "0": // valid for COPY only
|
||||
if ($del) { // MOVE?
|
||||
return "400 Bad request";
|
||||
}
|
||||
break;
|
||||
case "1": // invalid for both COPY and MOVE
|
||||
default:
|
||||
return "400 Bad request";
|
||||
}
|
||||
}
|
||||
|
||||
$dest = $this->base . $options["dest"];
|
||||
$destdir = dirname($dest);
|
||||
|
||||
if (!file_exists($destdir) || !is_dir($destdir)) {
|
||||
return "409 Conflict";
|
||||
}
|
||||
|
||||
|
||||
$new = !file_exists($dest);
|
||||
$existing_col = false;
|
||||
|
||||
@ -568,11 +684,6 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dir($source) && ($options["depth"] != "infinity")) {
|
||||
// RFC 2518 Section 9.2, last paragraph
|
||||
return "400 Bad request";
|
||||
}
|
||||
|
||||
if ($del) {
|
||||
if (!rename($source, $dest)) {
|
||||
return "500 Internal server error";
|
||||
@ -590,7 +701,7 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
WHERE path = '".$options["path"]."'";
|
||||
mysql_query($query);
|
||||
} else {
|
||||
if (is_dir($source)) {
|
||||
if (is_dir($source) && $options["depth"] == "infinity") { // no find for depth="0"
|
||||
$files = System::find($source);
|
||||
$files = array_reverse($files);
|
||||
} else {
|
||||
@ -610,14 +721,19 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
$destfile = str_replace($source, $dest, $file);
|
||||
|
||||
if (is_dir($file)) {
|
||||
if (!is_dir($destfile)) {
|
||||
// TODO "mkdir -p" here? (only natively supported by PHP 5)
|
||||
if (!@mkdir($destfile)) {
|
||||
if (!file_exists($destfile)) {
|
||||
if (!$this->_is_writable(dirname($destfile))) {
|
||||
return "403 Forbidden";
|
||||
}
|
||||
if (!mkdir($destfile)) {
|
||||
return "409 Conflict";
|
||||
}
|
||||
} else if (!is_dir($destfile)) {
|
||||
return "409 Conflict";
|
||||
}
|
||||
} else {
|
||||
if (!@copy($file, $destfile)) {
|
||||
|
||||
if (!copy($file, $destfile)) {
|
||||
return "409 Conflict";
|
||||
}
|
||||
}
|
||||
@ -683,6 +799,7 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
|
||||
$fspath = $this->base . $options["path"];
|
||||
|
||||
// TODO recursive locks on directories not supported yet
|
||||
// makes litmus test "32. lock_collection" fail
|
||||
if (is_dir($fspath) && !empty($options["depth"])) {
|
||||
return "409 Conflict";
|
||||
}
|
||||
|
251
egw-pear/HTTP/WebDAV/Tools/_parse_lockinfo.php
Normal file
251
egw-pear/HTTP/WebDAV/Tools/_parse_lockinfo.php
Normal file
@ -0,0 +1,251 @@
|
||||
<?php // $Id: _parse_lockinfo.php 246152 2007-11-14 10:49:27Z hholzgra $
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2002-2007 Christian Stocker, Hartmut Holzgraefe |
|
||||
| All rights reserved |
|
||||
| |
|
||||
| Redistribution and use in source and binary forms, with or without |
|
||||
| modification, are permitted provided that the following conditions |
|
||||
| are met: |
|
||||
| |
|
||||
| 1. Redistributions of source code must retain the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer. |
|
||||
| 2. Redistributions in binary form must reproduce the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer in |
|
||||
| the documentation and/or other materials provided with the |
|
||||
| distribution. |
|
||||
| 3. The names of the authors may not be used to endorse or promote |
|
||||
| products derived from this software without specific prior |
|
||||
| written permission. |
|
||||
| |
|
||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
||||
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
||||
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
||||
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
||||
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
||||
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
||||
| POSSIBILITY OF SUCH DAMAGE. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* helper class for parsing LOCK request bodies
|
||||
*
|
||||
* @package HTTP_WebDAV_Server
|
||||
* @author Hartmut Holzgraefe <hholzgra@php.net>
|
||||
* @version @package-version@
|
||||
*/
|
||||
class _parse_lockinfo
|
||||
{
|
||||
/**
|
||||
* success state flag
|
||||
*
|
||||
* @var bool
|
||||
* @access public
|
||||
*/
|
||||
var $success = false;
|
||||
|
||||
/**
|
||||
* lock type, currently only "write"
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $locktype = "";
|
||||
|
||||
/**
|
||||
* lock scope, "shared" or "exclusive"
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $lockscope = "";
|
||||
|
||||
/**
|
||||
* lock owner information
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $owner = "";
|
||||
|
||||
/**
|
||||
* flag that is set during lock owner read
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $collect_owner = false;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param string path of stream to read
|
||||
* @access public
|
||||
*/
|
||||
function _parse_lockinfo($path)
|
||||
{
|
||||
// we assume success unless problems occur
|
||||
$this->success = true;
|
||||
|
||||
// remember if any input was parsed
|
||||
$had_input = false;
|
||||
|
||||
// open stream
|
||||
$f_in = fopen($path, "r");
|
||||
if (!$f_in) {
|
||||
$this->success = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// create namespace aware parser
|
||||
$xml_parser = xml_parser_create_ns("UTF-8", " ");
|
||||
|
||||
// set tag and data handlers
|
||||
xml_set_element_handler($xml_parser,
|
||||
array(&$this, "_startElement"),
|
||||
array(&$this, "_endElement"));
|
||||
xml_set_character_data_handler($xml_parser,
|
||||
array(&$this, "_data"));
|
||||
|
||||
// we want a case sensitive parser
|
||||
xml_parser_set_option($xml_parser,
|
||||
XML_OPTION_CASE_FOLDING, false);
|
||||
|
||||
// parse input
|
||||
while ($this->success && !feof($f_in)) {
|
||||
$line = fgets($f_in);
|
||||
if (is_string($line)) {
|
||||
$had_input = true;
|
||||
$this->success &= xml_parse($xml_parser, $line, false);
|
||||
}
|
||||
}
|
||||
|
||||
// finish parsing
|
||||
if ($had_input) {
|
||||
$this->success &= xml_parse($xml_parser, "", true);
|
||||
}
|
||||
|
||||
// check if required tags where found
|
||||
$this->success &= !empty($this->locktype);
|
||||
$this->success &= !empty($this->lockscope);
|
||||
|
||||
// free parser resource
|
||||
xml_parser_free($xml_parser);
|
||||
|
||||
// close input stream
|
||||
fclose($f_in);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tag start handler
|
||||
*
|
||||
* @param resource parser
|
||||
* @param string tag name
|
||||
* @param array tag attributes
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function _startElement($parser, $name, $attrs)
|
||||
{
|
||||
// namespace handling
|
||||
if (strstr($name, " ")) {
|
||||
list($ns, $tag) = explode(" ", $name);
|
||||
} else {
|
||||
$ns = "";
|
||||
$tag = $name;
|
||||
}
|
||||
|
||||
|
||||
if ($this->collect_owner) {
|
||||
// everything within the <owner> tag needs to be collected
|
||||
$ns_short = "";
|
||||
$ns_attr = "";
|
||||
if ($ns) {
|
||||
if ($ns == "DAV:") {
|
||||
$ns_short = "D:";
|
||||
} else {
|
||||
$ns_attr = " xmlns='$ns'";
|
||||
}
|
||||
}
|
||||
$this->owner .= "<$ns_short$tag$ns_attr>";
|
||||
} else if ($ns == "DAV:") {
|
||||
// parse only the essential tags
|
||||
switch ($tag) {
|
||||
case "write":
|
||||
$this->locktype = $tag;
|
||||
break;
|
||||
case "exclusive":
|
||||
case "shared":
|
||||
$this->lockscope = $tag;
|
||||
break;
|
||||
case "owner":
|
||||
$this->collect_owner = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* data handler
|
||||
*
|
||||
* @param resource parser
|
||||
* @param string data
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function _data($parser, $data)
|
||||
{
|
||||
// only the <owner> tag has data content
|
||||
if ($this->collect_owner) {
|
||||
$this->owner .= $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tag end handler
|
||||
*
|
||||
* @param resource parser
|
||||
* @param string tag name
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function _endElement($parser, $name)
|
||||
{
|
||||
// namespace handling
|
||||
if (strstr($name, " ")) {
|
||||
list($ns, $tag) = explode(" ", $name);
|
||||
} else {
|
||||
$ns = "";
|
||||
$tag = $name;
|
||||
}
|
||||
|
||||
// <owner> finished?
|
||||
if (($ns == "DAV:") && ($tag == "owner")) {
|
||||
$this->collect_owner = false;
|
||||
}
|
||||
|
||||
// within <owner> we have to collect everything
|
||||
if ($this->collect_owner) {
|
||||
$ns_short = "";
|
||||
$ns_attr = "";
|
||||
if ($ns) {
|
||||
if ($ns == "DAV:") {
|
||||
$ns_short = "D:";
|
||||
} else {
|
||||
$ns_attr = " xmlns='$ns'";
|
||||
}
|
||||
}
|
||||
$this->owner .= "</$ns_short$tag$ns_attr>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -1,24 +1,37 @@
|
||||
<?php
|
||||
//
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP Version 4 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1997-2003 The PHP Group |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | This source file is subject to version 2.02 of the PHP license, |
|
||||
// | that is bundled with this package in the file LICENSE, and is |
|
||||
// | available at through the world-wide-web at |
|
||||
// | http://www.php.net/license/2_02.txt. |
|
||||
// | If you did not receive a copy of the PHP license and are unable to |
|
||||
// | obtain it through the world-wide-web, please send a note to |
|
||||
// | license@php.net so we can mail you a copy immediately. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Hartmut Holzgraefe <hholzgra@php.net> |
|
||||
// | Christian Stocker <chregu@bitflux.ch> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: _parse_propfind.php,v 1.4 2006/10/10 11:53:17 hholzgra Exp $
|
||||
//
|
||||
<?php // $Id: _parse_propfind.php 246152 2007-11-14 10:49:27Z hholzgra $
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2002-2007 Christian Stocker, Hartmut Holzgraefe |
|
||||
| All rights reserved |
|
||||
| |
|
||||
| Redistribution and use in source and binary forms, with or without |
|
||||
| modification, are permitted provided that the following conditions |
|
||||
| are met: |
|
||||
| |
|
||||
| 1. Redistributions of source code must retain the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer. |
|
||||
| 2. Redistributions in binary form must reproduce the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer in |
|
||||
| the documentation and/or other materials provided with the |
|
||||
| distribution. |
|
||||
| 3. The names of the authors may not be used to endorse or promote |
|
||||
| products derived from this software without specific prior |
|
||||
| written permission. |
|
||||
| |
|
||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
||||
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
||||
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
||||
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
||||
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
||||
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
||||
| POSSIBILITY OF SUCH DAMAGE. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* helper class for parsing PROPFIND request bodies
|
||||
@ -183,9 +196,8 @@ class _parse_propfind
|
||||
|
||||
// record root tag
|
||||
if ($this->depth == 0) {
|
||||
$this->root = array('name' => $tag, 'xmlns' => $ns);
|
||||
$this->root = array('name' => $tag, 'xmlns' => $ns, 'attrs' => $attrs);
|
||||
}
|
||||
|
||||
// special tags at level 1: <allprop> and <propname>
|
||||
if ($this->depth == 1) {
|
||||
$this->use = 'props';
|
||||
@ -201,27 +213,41 @@ class _parse_propfind
|
||||
break;
|
||||
case 'filter':
|
||||
$this->use = 'filters';
|
||||
$this->filters['attrs'] = $attrs; // need attrs eg. <filters test="(anyof|alloff)">
|
||||
break;
|
||||
default:
|
||||
$this->use = 'other';
|
||||
break;
|
||||
}
|
||||
}
|
||||
//echo "$this->depth: use=$this->use $ns:$tag attrs=".array2string($attrs)."\n";
|
||||
|
||||
// requested properties are found at level 2
|
||||
// CalDAV filters can be at deeper levels too and we need the attrs, same for other tags (eg. multiget href's)
|
||||
if ($this->depth == 2 || $this->use == 'filters' && $this->depth >= 2 || $this->use == 'other') {
|
||||
if ($this->depth == 2 || $this->use == 'filters' && $this->depth >= 2 || $this->use == 'other' ||
|
||||
$this->use == 'props' && $this->depth >= 2) {
|
||||
$prop = array("name" => $tag);
|
||||
if ($ns)
|
||||
$prop["xmlns"] = $ns;
|
||||
if ($this->use != 'props') {
|
||||
if ($this->use != 'props' || $this->depth > 2) {
|
||||
$prop['attrs'] = $attrs;
|
||||
$prop['depth'] = $this->depth;
|
||||
}
|
||||
// this can happen if we have allprop and prop in one propfind:
|
||||
// <allprop /><prop><blah /></prop>, eg. blah is not automatic returned by allprop
|
||||
if (!is_array($this->{$this->use}) && $this->{$this->use}) $this->{$this->use} = array($this->{$this->use});
|
||||
$this->{$this->use}[] = $prop;
|
||||
// collect sub-elements of props in the original props children attribute
|
||||
// eg. required for CalDAV <calendar-data><expand start="..." end="..."/></calendar-data>
|
||||
if ($this->use == 'props' && $this->depth > 2)
|
||||
{
|
||||
$this->last_prop['children'][$tag] = $prop;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this can happen if we have allprop and prop in one propfind:
|
||||
// <allprop /><prop><blah /></prop>, eg. blah is not automatic returned by allprop
|
||||
if (!is_array($this->{$this->use}) && $this->{$this->use}) $this->{$this->use} = array($this->{$this->use});
|
||||
$this->{$this->use}[] =& $prop;
|
||||
$this->last_prop =& $prop;
|
||||
unset($prop);
|
||||
}
|
||||
}
|
||||
|
||||
// increment depth count
|
||||
|
@ -1,24 +1,38 @@
|
||||
<?php
|
||||
//
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP Version 4 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1997-2003 The PHP Group |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | This source file is subject to version 2.02 of the PHP license, |
|
||||
// | that is bundled with this package in the file LICENSE, and is |
|
||||
// | available at through the world-wide-web at |
|
||||
// | http://www.php.net/license/2_02.txt. |
|
||||
// | If you did not receive a copy of the PHP license and are unable to |
|
||||
// | obtain it through the world-wide-web, please send a note to |
|
||||
// | license@php.net so we can mail you a copy immediately. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Hartmut Holzgraefe <hholzgra@php.net> |
|
||||
// | Christian Stocker <chregu@bitflux.ch> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: _parse_proppatch.php,v 1.6 2006/10/10 11:53:17 hholzgra Exp $
|
||||
//
|
||||
<?php // $Id: _parse_proppatch.php 246152 2007-11-14 10:49:27Z hholzgra $
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2002-2007 Christian Stocker, Hartmut Holzgraefe |
|
||||
| All rights reserved |
|
||||
| |
|
||||
| Redistribution and use in source and binary forms, with or without |
|
||||
| modification, are permitted provided that the following conditions |
|
||||
| are met: |
|
||||
| |
|
||||
| 1. Redistributions of source code must retain the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer. |
|
||||
| 2. Redistributions in binary form must reproduce the above copyright |
|
||||
| notice, this list of conditions and the following disclaimer in |
|
||||
| the documentation and/or other materials provided with the |
|
||||
| distribution. |
|
||||
| 3. The names of the authors may not be used to endorse or promote |
|
||||
| products derived from this software without specific prior |
|
||||
| written permission. |
|
||||
| |
|
||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
||||
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
||||
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
||||
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
||||
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
||||
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
||||
| POSSIBILITY OF SUCH DAMAGE. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* helper class for parsing PROPPATCH request bodies
|
||||
|
1617
etemplate/inc/class.so_sql.inc.php
Normal file
1617
etemplate/inc/class.so_sql.inc.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -187,6 +187,7 @@ class so_sql_cf extends so_sql
|
||||
),__LINE__,__FILE__,false,'',$this->app) as $row)
|
||||
{
|
||||
$entry =& $entries[$row[$this->extra_id]];
|
||||
if (!is_array($entry)) $entry = array();
|
||||
$field = $this->get_cf_field($row[$this->extra_key]);
|
||||
|
||||
if ($this->allow_multiple_values && $this->is_multiple($row[$this->extra_key]))
|
||||
@ -417,10 +418,12 @@ class so_sql_cf extends so_sql
|
||||
// if string given as criteria --> search in all (or $this->columns_to_search) columns including custom fields
|
||||
if ($criteria && is_string($criteria))
|
||||
{
|
||||
$criteria = $this->search2criteria($criteria,$wildcard,$op,$this->extra_value);
|
||||
$criteria = $this->search2criteria($criteria,$wildcard,$op);
|
||||
}
|
||||
if ($criteria && is_array($criteria))
|
||||
{
|
||||
$join .= $this->extra_join;
|
||||
|
||||
// check if we search in the custom fields
|
||||
if (isset($criteria[$this->extra_value]))
|
||||
{
|
||||
@ -432,7 +435,6 @@ class so_sql_cf extends so_sql
|
||||
$this->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE]. ' ' .
|
||||
$this->db->quote($wildcard.$criteria[$this->extra_value].$wildcard);
|
||||
unset($criteria[$this->extra_value]);
|
||||
$join .= $this->extra_join;
|
||||
}
|
||||
// replace ambiguous auto-id with (an exact match of) table_name.autoid
|
||||
if (isset($criteria[$this->autoinc_id]))
|
||||
@ -444,15 +446,76 @@ class so_sql_cf extends so_sql
|
||||
}
|
||||
unset($criteria[$this->autoinc_id]);
|
||||
}
|
||||
// replace ambiguous column with (an exact match of) table_name.column
|
||||
foreach($criteria as $name => $val)
|
||||
{
|
||||
$extra_columns = $this->db->get_table_definitions($app, $this->extra_table);
|
||||
if(is_string($name) && $extra_columns['fd'][array_search($name, $this->db_cols)])
|
||||
{
|
||||
$criteria[] = $this->db->expression($this->table_name,$this->table_name.'.',array(
|
||||
array_search($name, $this->db_cols) => $val,
|
||||
));
|
||||
unset($criteria[$name]);
|
||||
}
|
||||
elseif (is_string($name) && $this->is_cf($name))
|
||||
{
|
||||
if ($op != 'AND')
|
||||
{
|
||||
$name = substr($name, 1);
|
||||
if (($negate = $criteria[$name][0] === '!'))
|
||||
{
|
||||
$val = substr($val,1);
|
||||
}
|
||||
$cfcriteria[] = '(' . $this->extra_table.'.'.$this->extra_value . ' ' .($negate ? 'NOT ' : '').
|
||||
$this->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE]. ' ' .
|
||||
$this->db->quote($wildcard.$val.$wildcard) . ' AND ' .
|
||||
$this->extra_table.'.'.$this->extra_key . ' = ' . $this->db->quote($name) .
|
||||
')';
|
||||
unset($criteria[self::CF_PREFIX.$name]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// criteria operator is AND we remap the criteria to be transformed to filters
|
||||
$filter[$name] = $val;
|
||||
unset($criteria[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($cfcriteria && $op =='OR') $criteria[] = implode(' OR ',$cfcriteria);
|
||||
}
|
||||
if($only_keys === true) {
|
||||
// Expand to keys here, so table_name can be prepended below
|
||||
$only_keys = array_values($this->db_key_cols);
|
||||
}
|
||||
// replace ambiguous column with (an exact match of) table_name.column
|
||||
if(is_array($only_keys))
|
||||
{
|
||||
foreach($only_keys as $key => &$col)
|
||||
{
|
||||
if(is_numeric($key) && in_array($col, $this->db_cols))
|
||||
{
|
||||
$col = $this->table_name .'.'.array_search($col, $this->db_cols).' AS '.$col;
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if we order by a custom field --> join cf table for given cf and order by it's value
|
||||
if (strpos($order_by,self::CF_PREFIX) !== false &&
|
||||
preg_match('/'.self::CF_PREFIX.'([^ ]+) (asc|desc)/i',$order_by,$matches))
|
||||
if (strpos($order_by,self::CF_PREFIX) !== false)
|
||||
{
|
||||
$order_by = str_replace($matches[0],'extra_order.'.$this->extra_value.' IS NULL,extra_order.'.$this->extra_value.' '.$matches[2],$order_by);
|
||||
$join .= $this->extra_join_order.' AND extra_order.'.$this->extra_key.'='.$this->db->quote($matches[1]);
|
||||
// fields to order by, as cutomfields may have names with spaces, we examine each order by criteria
|
||||
$fields2order = explode(',',$order_by);
|
||||
foreach($fields2order as $k => $v)
|
||||
{
|
||||
if (strpos($v,self::CF_PREFIX) !== false)
|
||||
{
|
||||
// we found a customfield, so we split that part by space char in order to get Sorting Direction and Fieldname
|
||||
$buff = explode(' ',trim($v));
|
||||
$orderDir = array_pop($buff);
|
||||
$key = trim(implode(' ',$buff));
|
||||
$order_by = str_replace($v,'extra_order.'.$this->extra_value.' IS NULL,extra_order.'.$this->extra_value.' '.$orderDir,$order_by);
|
||||
$join .= $this->extra_join_order.' AND extra_order.'.$this->extra_key.'='.$this->db->quote(substr($key,1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if we filter by a custom field
|
||||
if (is_array($filter))
|
||||
{
|
||||
@ -470,6 +533,17 @@ class so_sql_cf extends so_sql
|
||||
}
|
||||
unset($filter[$this->autoinc_id]);
|
||||
}
|
||||
// replace ambiguous column with (an exact match of) table_name.column
|
||||
elseif (is_string($name) && $val!=null && in_array($name, $this->db_cols))
|
||||
{
|
||||
$extra_columns = $this->db->get_table_definitions($app, $this->extra_table);
|
||||
if($extra_columns['fd'][array_search($name, $this->db_cols)]) {
|
||||
$filter[] = $this->db->expression($this->table_name,$this->table_name.'.',array(
|
||||
array_search($name, $this->db_cols) => $val,
|
||||
));
|
||||
unset($filter[$name]);
|
||||
}
|
||||
}
|
||||
elseif (is_string($name) && $this->is_cf($name))
|
||||
{
|
||||
if (!empty($val)) // empty -> dont filter
|
||||
@ -480,13 +554,21 @@ class so_sql_cf extends so_sql
|
||||
}
|
||||
else // using egw_db::expression to allow to use array() with possible values or NULL
|
||||
{
|
||||
if($this->customfields[$this->get_cf_name($name)]['type'] == 'select' &&
|
||||
if($this->customfields[$this->get_cf_name($name)]['type'] == 'select' &&
|
||||
$this->customfields[$this->get_cf_name($name)]['rows'] > 1)
|
||||
{
|
||||
// Multi-select - any entry with the filter value selected matches
|
||||
$sql_filter = str_replace($this->extra_value,'extra_filter.'.
|
||||
$this->extra_value,$this->db->expression($this->extra_table,array(
|
||||
"CONCAT(',',{$this->extra_value},',') LIKE '%,$val,%'"
|
||||
$this->db->concat("','",$this->extra_value,"','").' '.$this->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote('%,'.$val.',%')
|
||||
))
|
||||
);
|
||||
}
|
||||
elseif ($this->customfields[$this->get_cf_name($name)]['type'] == 'text')
|
||||
{
|
||||
$sql_filter = str_replace($this->extra_value,'extra_filter.'.$this->extra_value,
|
||||
$this->db->expression($this->extra_table,array(
|
||||
$this->extra_value.' '.$this->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote($wildcard.$val.$wildcard)
|
||||
))
|
||||
);
|
||||
}
|
||||
@ -495,7 +577,6 @@ class so_sql_cf extends so_sql
|
||||
$sql_filter = str_replace($this->extra_value,'extra_filter.'.
|
||||
$this->extra_value,$this->db->expression($this->extra_table,array($this->extra_value => $val)));
|
||||
}
|
||||
|
||||
}
|
||||
// need to use a LEFT JOIN for negative search or to allow NULL values
|
||||
$need_left_join = $val[0] === '!' || strpos($sql_filter,'IS NULL') !== false ? ' LEFT ' : '';
|
||||
@ -534,6 +615,45 @@ class so_sql_cf extends so_sql
|
||||
return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return criteria array for a given search pattern
|
||||
* Reimplemented to search custom fields
|
||||
*
|
||||
* @param string $pattern search pattern incl. * or ? as wildcard, if no wildcards used we append and prepend one!
|
||||
* @param string &$wildcard='' on return wildcard char to use, if pattern does not already contain wildcards!
|
||||
* @param string &$op='AND' on return boolean operation to use, if pattern does not start with ! we use OR else AND
|
||||
* @param string $extra_col=null extra column to search
|
||||
* @param array $search_cols=array() List of columns to search. If not provided, all columns in $this->db_cols will be considered
|
||||
* @return array or column => value pairs
|
||||
*/
|
||||
public function search2criteria($pattern,&$wildcard='',&$op='AND',$extra_col=null, $search_cols = array())
|
||||
{
|
||||
// This function can get called multiple times. Make sure it doesn't re-process.
|
||||
if (empty($pattern) || is_array($pattern)) return $pattern;
|
||||
if(strpos($pattern, 'CAST(COALESCE(') !== false)
|
||||
{
|
||||
return $pattern;
|
||||
}
|
||||
|
||||
$pattern = trim($pattern);
|
||||
$filter = array();
|
||||
if(!$search_cols)
|
||||
{
|
||||
$search_cols = $this->get_default_search_columns();
|
||||
}
|
||||
|
||||
// Add in custom field column, if it is not already there
|
||||
if(!in_array($this->extra_table.'.'.$this->extra_value, $search_cols))
|
||||
{
|
||||
$search_cols[] = $this->extra_table.'.'.$this->extra_value;
|
||||
}
|
||||
|
||||
// Let parent deal with the normal stuff
|
||||
$criteria = parent::search2criteria($pattern, $wildcard, $op, $extra_col, $search_cols);
|
||||
|
||||
return $criteria;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to test if $field is a custom field: check for the prefix
|
||||
*
|
||||
|
15
groupdav.php
15
groupdav.php
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - GroupDAV access
|
||||
* EGroupware - CalDAV/CardDAV/GroupDAV server
|
||||
*
|
||||
* Using the PEAR HTTP/WebDAV/Server class (which need to be installed!)
|
||||
*
|
||||
@ -9,10 +9,19 @@
|
||||
* @package api
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-11 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
// switching off output compression for Lighttpd and HTTPS, as it makes problems with TB Lightning
|
||||
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' &&
|
||||
strpos($_SERVER['SERVER_SOFTWARE'],'lighttpd/1.4') === 0 &&
|
||||
strpos($_SERVER['HTTP_USER_AGENT'],'Lightning') !== false)
|
||||
{
|
||||
ini_set('zlib.output_compression',0);
|
||||
}
|
||||
//error_log("HTTPS='$_SERVER[HTTPS]', SERVER_SOFTWARE='$_SERVER[SERVER_SOFTWARE]', HTTP_USER_AGENT='$_SERVER[HTTP_USER_AGENT]', REQUEST_METHOD='$_SERVER[REQUEST_METHOD]' --> zlib.output_compression=".ini_get('zlib.output_compression'));
|
||||
|
||||
$starttime = microtime(true);
|
||||
|
||||
$GLOBALS['egw_info'] = array(
|
||||
@ -35,4 +44,4 @@ $headertime = microtime(true);
|
||||
|
||||
$groupdav = new groupdav();
|
||||
$groupdav->ServeRequest();
|
||||
//error_log(sprintf("GroupDAV %s request took %5.3f s (header include took %5.3f s)",$_SERVER['REQUEST_METHOD'],microtime(true)-$starttime,$headertime-$starttime));
|
||||
//error_log(sprintf('GroupDAV %s: status "%s", took %5.3f s'.($headertime?' (header include took %5.3f s)':''),$_SERVER['REQUEST_METHOD'].($_SERVER['REQUEST_METHOD']=='REPORT'?' '.$groupdav->propfind_options['root']['name']:'').' '.$_SERVER['PATH_INFO'],$groupdav->_http_status,microtime(true)-$starttime,$headertime-$starttime));
|
||||
|
@ -1,12 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* InfoLog - Business object
|
||||
* EGroupware - InfoLog - Business object
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @package infolog
|
||||
* @copyright (c) 2003-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2003-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -28,8 +28,6 @@ class infolog_bo
|
||||
var $so;
|
||||
var $vfs;
|
||||
var $vfs_basedir='/infolog';
|
||||
var $link_pathes = array();
|
||||
var $send_file_ips = array();
|
||||
/**
|
||||
* Set Logging
|
||||
*
|
||||
@ -54,13 +52,19 @@ class infolog_bo
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $timestamps = array('info_startdate','info_enddate','info_datemodified','info_datecompleted');
|
||||
var $timestamps = array('info_startdate','info_enddate','info_datemodified','info_datecompleted','info_created');
|
||||
/**
|
||||
* fields the responsible user can change
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $responsible_edit=array('info_status','info_percent','info_datecompleted');
|
||||
/**
|
||||
* fields a user may exclude from copy, if an entry is copied, the ones below are excluded by default.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $copy_excludefields = array('info_id', 'info_uid', 'info_etag', 'caldav_name', 'info_created', 'info_creator', 'info_datemodified', 'info_modifier');
|
||||
/**
|
||||
* implicit ACL rights of the responsible user: read or edit
|
||||
*
|
||||
@ -117,17 +121,21 @@ class infolog_bo
|
||||
'responsible-open-today' => 'responsible open',
|
||||
'responsible-open-overdue' => 'responsible overdue',
|
||||
'responsible-upcoming' => 'responsible upcoming',
|
||||
'responsible-open-upcoming'=> 'responsible open and upcoming',
|
||||
'delegated' => 'delegated',
|
||||
'delegated-open-today' => 'delegated open',
|
||||
'delegated-open-overdue' => 'delegated overdue',
|
||||
'delegated-upcoming' => 'delegated upcomming',
|
||||
'delegated-open-upcoming' => 'delegated open and upcoming',
|
||||
'own' => 'own',
|
||||
'own-open-today' => 'own open',
|
||||
'own-open-overdue' => 'own overdue',
|
||||
'own-upcoming' => 'own upcoming',
|
||||
'open-today' => 'open',
|
||||
'own-open-upcoming' => 'own open and upcoming',
|
||||
'open-today' => 'open(status)',
|
||||
'open-overdue' => 'overdue',
|
||||
'upcoming' => 'upcoming',
|
||||
'open-upcoming' => 'open and upcoming',
|
||||
'bydate' => 'startdate',
|
||||
);
|
||||
|
||||
@ -180,9 +188,6 @@ class infolog_bo
|
||||
);
|
||||
if (($config_data = config::read('infolog')))
|
||||
{
|
||||
$this->link_pathes = $config_data['link_pathes'];
|
||||
$this->send_file_ips = $config_data['send_file_ips'];
|
||||
|
||||
if (isset($config_data['status']) && is_array($config_data['status']))
|
||||
{
|
||||
foreach($config_data['status'] as $key => $data)
|
||||
@ -227,6 +232,10 @@ class infolog_bo
|
||||
{
|
||||
$this->responsible_edit = array_merge($this->responsible_edit,$config_data['responsible_edit']);
|
||||
}
|
||||
if (is_array($config_data['copy_excludefields']))
|
||||
{
|
||||
$this->copy_excludefields = array_merge($this->copy_excludefields,$config_data['copy_excludefields']);
|
||||
}
|
||||
if ($config_data['implicit_rights'] == 'edit')
|
||||
{
|
||||
$this->implicit_rights = 'edit';
|
||||
@ -286,53 +295,73 @@ class infolog_bo
|
||||
* @param int|array $info data or info_id of infolog entry to check
|
||||
* @param int $required_rights EGW_ACL_{READ|EDIT|ADD|DELETE}
|
||||
* @param int $other uid to check (if info==0) or 0 to check against $this->user
|
||||
* @param int $user=null user whos rights to check, default current user
|
||||
* @return boolean
|
||||
*/
|
||||
function check_access($info,$required_rights,$other=0)
|
||||
function check_access($info,$required_rights,$other=0,$user=null)
|
||||
{
|
||||
static $cache = array();
|
||||
|
||||
if (!$info)
|
||||
{
|
||||
$owner = $other ? $other : $this->user;
|
||||
$grants = $this->grants[$owner];
|
||||
return $grants & $required_rights;
|
||||
}
|
||||
|
||||
$info_id = is_array($info) ? $info['info_id'] : $info;
|
||||
|
||||
if (isset($cache[$info_id][$required_rights]))
|
||||
if (!$user) $user = $this->user;
|
||||
if ($user == $this->user)
|
||||
{
|
||||
return $cache[$info_id][$required_rights];
|
||||
$grants = $this->grants;
|
||||
if ($info_id) $access =& $cache[$info_id][$required_rights]; // we only cache the current user!
|
||||
}
|
||||
// handle delete for the various history modes
|
||||
if ($this->history)
|
||||
else
|
||||
{
|
||||
if (!is_array($info) && !($info = $this->so->read($info_id))) return false;
|
||||
$grants = $GLOBALS['egw']->acl->get_grants('infolog',$this->group_owners ? $this->group_owners : true,$user);
|
||||
}
|
||||
if (!$info)
|
||||
{
|
||||
$owner = $other ? $other : $user;
|
||||
$grant = $grants[$owner];
|
||||
return $grant & $required_rights;
|
||||
}
|
||||
|
||||
if ($info['info_status'] == 'deleted' &&
|
||||
($required_rights == EGW_ACL_EDIT || // no edit rights for deleted entries
|
||||
$required_rights == EGW_ACL_ADD || // no add rights for deleted entries
|
||||
$required_rights == EGW_ACL_DELETE && ($this->history == 'history_no_delete' || // no delete at all!
|
||||
$this->history == 'history_admin_delete' && !isset($GLOBALS['egw_info']['user']['apps']['admin'])))) // delete only for admins
|
||||
{
|
||||
return $cache[$info_id][$required_rights] = false;
|
||||
}
|
||||
if ($required_rights == EGW_ACL_UNDELETE)
|
||||
{
|
||||
if ($info['info_status'] != 'deleted')
|
||||
{
|
||||
return $cache[$info_id][$required_rights] = false; // can only undelete deleted items
|
||||
}
|
||||
// undelete requires edit rights
|
||||
return $cache[$info_id][$required_rights] = $this->so->check_access( $info,EGW_ACL_EDIT,$this->implicit_rights == 'edit' );
|
||||
}
|
||||
}
|
||||
elseif ($required_rights == EGW_ACL_UNDELETE)
|
||||
|
||||
if (!isset($access))
|
||||
{
|
||||
return $cache[$info_id][$required_rights] = false;
|
||||
// handle delete for the various history modes
|
||||
if ($this->history)
|
||||
{
|
||||
if (!is_array($info) && !($info = $this->so->read(array('info_id' => $info_id)))) return false;
|
||||
|
||||
if ($info['info_status'] == 'deleted' &&
|
||||
($required_rights == EGW_ACL_EDIT || // no edit rights for deleted entries
|
||||
$required_rights == EGW_ACL_ADD || // no add rights for deleted entries
|
||||
$required_rights == EGW_ACL_DELETE && ($this->history == 'history_no_delete' || // no delete at all!
|
||||
$this->history == 'history_admin_delete' && (!isset($GLOBALS['egw_info']['user']['apps']['admin']) || $user!=$this->user)))) // delete only for admins
|
||||
{
|
||||
$access = false;
|
||||
}
|
||||
elseif ($required_rights == EGW_ACL_UNDELETE)
|
||||
{
|
||||
if ($info['info_status'] != 'deleted')
|
||||
{
|
||||
$access = false; // can only undelete deleted items
|
||||
}
|
||||
else
|
||||
{
|
||||
// undelete requires edit rights
|
||||
$access = $this->so->check_access( $info,EGW_ACL_EDIT,$this->implicit_rights == 'edit',$grants,$user );
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($required_rights == EGW_ACL_UNDELETE)
|
||||
{
|
||||
$access = false;
|
||||
}
|
||||
if (!isset($access))
|
||||
{
|
||||
$access = $this->so->check_access( $info,$required_rights,$this->implicit_rights == 'edit',$grants,$user );
|
||||
}
|
||||
}
|
||||
return $cache[$info_id][$required_rights] = $this->so->check_access( $info,$required_rights,$this->implicit_rights == 'edit' );
|
||||
// else $cached = ' (from cache)';
|
||||
// error_log(__METHOD__."($info_id,$required_rights,$other,$user) returning$cached ".array2string($access));
|
||||
return $access;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -517,7 +546,7 @@ class infolog_bo
|
||||
/**
|
||||
* Read an infolog entry specified by $info_id
|
||||
*
|
||||
* @param int|array $info_id integer id or array with key 'info_id' of the entry to read
|
||||
* @param int|array $info_id integer id or array with id's or array with column=>value pairs of the entry to read
|
||||
* @param boolean $run_link_id2from=true should link_id2from run, default yes,
|
||||
* need to be set to false if called from link-title to prevent an infinit recursion
|
||||
* @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time,
|
||||
@ -527,9 +556,17 @@ class infolog_bo
|
||||
*/
|
||||
function &read($info_id,$run_link_id2from=true,$date_format='ts')
|
||||
{
|
||||
if (is_array($info_id))
|
||||
//error_log(__METHOD__.'('.array2string($info_id).', '.array2string($run_link_id2from).", '$date_format') ".function_backtrace());
|
||||
if (is_scalar($info_id) || isset($info_id[count($info_id)-1]))
|
||||
{
|
||||
$info_id = isset($info_id['info_id']) ? $info_id['info_id'] : $info_id[0];
|
||||
if (is_scalar($info_id) && !is_numeric($info_id))
|
||||
{
|
||||
$info_id = array('info_uid' => $info_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
$info_id = array('info_id' => $info_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (($data = $this->so->read($info_id)) === False)
|
||||
@ -574,19 +611,20 @@ class infolog_bo
|
||||
* @param int|array $info_id int id
|
||||
* @param boolean $delete_children should the children be deleted
|
||||
* @param int|boolean $new_parent parent to use for not deleted children if > 0
|
||||
* @param boolean $skip_notification Do not send notification of delete
|
||||
* @return boolean True if delete was successful, False otherwise ($info_id does not exist or no rights)
|
||||
*/
|
||||
function delete($info_id,$delete_children=False,$new_parent=False)
|
||||
function delete($info_id,$delete_children=False,$new_parent=False, $skip_notification=False)
|
||||
{
|
||||
if (is_array($info_id))
|
||||
{
|
||||
$info_id = (int)(isset($info_id[0]) ? $info_id[0] : (isset($info_id['info_id']) ? $info_id['info_id'] : $info_id['info_id']));
|
||||
}
|
||||
if ($this->so->read($info_id) === False)
|
||||
if (($info = $this->so->read(array('info_id' => $info_id), true, 'server')) === False)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
if (!$this->check_access($info_id,EGW_ACL_DELETE))
|
||||
if (!$this->check_access($info,EGW_ACL_DELETE))
|
||||
{
|
||||
return False;
|
||||
}
|
||||
@ -597,7 +635,7 @@ class infolog_bo
|
||||
{
|
||||
if ($delete_children && $this->so->grants[$owner] & EGW_ACL_DELETE)
|
||||
{
|
||||
$this->delete($id,$delete_children,$new_parent); // call ourself recursive to delete the child
|
||||
$this->delete($id,$delete_children,$new_parent,$skip_notification); // call ourself recursive to delete the child
|
||||
}
|
||||
else // dont delete or no rights to delete the child --> re-parent it
|
||||
{
|
||||
@ -608,8 +646,6 @@ class infolog_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!($info = $this->read($info_id, true, 'server'))) return false; // should not happen
|
||||
|
||||
$deleted = $info;
|
||||
$deleted['info_status'] = 'deleted';
|
||||
$deleted['info_datemodified'] = time();
|
||||
@ -622,7 +658,7 @@ class infolog_bo
|
||||
|
||||
$this->so->write($deleted);
|
||||
|
||||
egw_link::unlink(0,'infolog',$info_id,'','!file'); // keep the file attachments, only delete the rest
|
||||
egw_link::unlink(0,'infolog',$info_id,'','!file','',true); // keep the file attachments, hide the rest
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -635,11 +671,14 @@ class infolog_bo
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('infolog_'.$info['info_type'], $info_id, 'delete', time());
|
||||
|
||||
// send email notifications and do the history logging
|
||||
if (!is_object($this->tracking))
|
||||
if(!$skip_notification)
|
||||
{
|
||||
$this->tracking = new infolog_tracking($this);
|
||||
if (!is_object($this->tracking))
|
||||
{
|
||||
$this->tracking = new infolog_tracking($this);
|
||||
}
|
||||
$this->tracking->track($deleted,$info,$this->user,true);
|
||||
}
|
||||
$this->tracking->track($deleted,$info,$this->user,true);
|
||||
}
|
||||
return True;
|
||||
}
|
||||
@ -654,27 +693,35 @@ class infolog_bo
|
||||
* @param boolean $touch_modified=true touch the modification data and sets the modiefier's user-id
|
||||
* @param boolean $user2server=true conversion between user- and server-time necessary
|
||||
* @param boolean $skip_notification=false true = do NOT send notification, false (default) = send notifications
|
||||
* @param boolean $throw_exception=false Throw an exception (if required fields are not set)
|
||||
* @param string $purge_cfs=null null=dont, 'ical'=only iCal X-properties (cfs name starting with "#"), 'all'=all cfs
|
||||
*
|
||||
* @return int/boolean info_id on a successfull write or false
|
||||
* @return int|boolean info_id on a successfull write or false
|
||||
*/
|
||||
function write(&$values, $check_defaults=true, $touch_modified=true, $user2server=true, $skip_notification=false)
|
||||
function write(&$values_in, $check_defaults=true, $touch_modified=true, $user2server=true,
|
||||
$skip_notification=false, $throw_exception=false, $purge_cfs=null)
|
||||
{
|
||||
$values = $values_in;
|
||||
//echo "boinfolog::write()values="; _debug_array($values);
|
||||
if (!$values['info_id'] && !$this->check_access(0,EGW_ACL_EDIT,$values['info_owner']) &&
|
||||
!$this->check_access(0,EGW_ACL_ADD,$values['info_owner']))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// we need to get the old values to update the links in customfields and for the tracking
|
||||
if ($values['info_id'])
|
||||
{
|
||||
$old = $this->read($values['info_id'], false, 'server');
|
||||
}
|
||||
if (($status_only = $values['info_id'] && !$this->check_access($values['info_id'],EGW_ACL_EDIT)))
|
||||
{
|
||||
if (!isset($values['info_responsible']))
|
||||
{
|
||||
if (!($values_read = $this->read($values['info_id']))) return false;
|
||||
$responsible =& $values_read['info_responsible'];
|
||||
$responsible = $old['info_responsible'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$responsible =& $values['info_responsible'];
|
||||
$responsible = $values['info_responsible'];
|
||||
}
|
||||
if (!($status_only = in_array($this->user, (array)$responsible))) // responsible has implicit right to change status
|
||||
{
|
||||
@ -695,14 +742,12 @@ class infolog_bo
|
||||
$set_completed = !$values['info_datecompleted'] && // set date completed of finished job, only if its not already set
|
||||
(in_array($values['info_status'],array('done','billed','cancelled')) || (int)$values['info_percent'] == 100);
|
||||
|
||||
$backup_values = $values; // to return the full values
|
||||
$values = array(
|
||||
'info_id' => $values['info_id'],
|
||||
'info_datemodified' => $values['info_datemodified'],
|
||||
);
|
||||
$values = $old;
|
||||
// only overwrite explicitly allowed fields
|
||||
$values['info_datemodified'] = $values_in['info_datemodified'];
|
||||
foreach ($this->responsible_edit as $name)
|
||||
{
|
||||
if (isset($backup_values[$name])) $values[$name] = $backup_values[$name];
|
||||
if (isset($values_in[$name])) $values[$name] = $values_in[$name];
|
||||
}
|
||||
if ($set_completed)
|
||||
{
|
||||
@ -746,7 +791,7 @@ class infolog_bo
|
||||
$status = 'done';
|
||||
if (isset($values['info_type'])) {
|
||||
if (isset($this->status[$values['info_type']]['done'])) {
|
||||
$status = 'done';
|
||||
$status = 'done';
|
||||
} elseif (isset($this->status[$values['info_type']]['billed'])) {
|
||||
$status = 'billed';
|
||||
} elseif (isset($this->status[$values['info_type']]['cancelled'])) {
|
||||
@ -766,13 +811,35 @@ class infolog_bo
|
||||
{
|
||||
$values['info_subject'] = $this->subject_from_des($values['info_des']);
|
||||
}
|
||||
|
||||
// Check required custom fields
|
||||
if($throw_exception) {
|
||||
$custom = config::get_customfields('infolog');
|
||||
foreach($custom as $c_name => $c_field)
|
||||
{
|
||||
if($c_field['type2']) $type2 = explode(',',$c_field['type2']);
|
||||
if($c_field['needed'] && (!$c_field['type2'] || $c_field['type2'] && in_array($values['info_type'],$type2)))
|
||||
{
|
||||
// Required custom field
|
||||
if(!$values['#'.$c_name])
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('For infolog type %1, %2 is required',lang($values['info_type']),$c_field['label']));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($this->group_owners[$values['info_type']]))
|
||||
{
|
||||
$values['info_owner'] = $this->group_owners[$values['info_type']];
|
||||
if (!($this->grants[$this->group_owners[$values['info_type']]] & EGW_ACL_EDIT))
|
||||
{
|
||||
if (!$this->check_access($values['info_id'],EGW_ACL_EDIT)) return false; // no edit rights from the group-owner and no implicit rights (delegated and sufficient rights)
|
||||
if (!$this->check_access($values['info_id'],EGW_ACL_EDIT) ||
|
||||
!$values['info_id'] && !$this->check_access($values,EGW_ACL_ADD)
|
||||
)
|
||||
{
|
||||
return false; // no edit rights from the group-owner and no implicit rights (delegated and sufficient rights)
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!$values['info_id'] && !$values['info_owner'] || $GLOBALS['egw']->accounts->get_type($values['info_owner']) == 'g')
|
||||
@ -785,8 +852,6 @@ class infolog_bo
|
||||
$values['info_from'] = $this->link_id2from($values);
|
||||
}
|
||||
|
||||
if ($status_only && !$undelete) $values = array_merge($backup_values,$values);
|
||||
|
||||
$to_write = $values;
|
||||
if ($user2server)
|
||||
{
|
||||
@ -826,20 +891,22 @@ class infolog_bo
|
||||
}
|
||||
if ($touch_modified || !$values['info_modifier'])
|
||||
{
|
||||
$values['info_modifier'] = $this->so->user;
|
||||
$to_write['info_modifier'] = $this->so->user;
|
||||
$values['info_modifier'] = $to_write['info_modifier'] = $this->so->user;
|
||||
}
|
||||
|
||||
// set created and creator for new entries
|
||||
if (!$values['info_id'])
|
||||
{
|
||||
$values['info_created'] = $this->user_time_now;
|
||||
$to_write['info_created'] = $this->now;
|
||||
$values['info_creator'] = $to_write['info_creator'] = $this->so->user;
|
||||
}
|
||||
//_debug_array($values);
|
||||
// error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n".array2string($values)."\n",3,'/tmp/infolog');
|
||||
|
||||
// we need to get the old values to update the links in customfields and for the tracking
|
||||
if ($values['info_id'])
|
||||
if (($info_id = $this->so->write($to_write, $check_modified, $purge_cfs)))
|
||||
{
|
||||
$old = $this->read($values['info_id'], false, 'server');
|
||||
}
|
||||
if (($info_id = $this->so->write($to_write,$check_modified)))
|
||||
{
|
||||
if (!isset($values['info_type']) || $status_only)
|
||||
if (!isset($values['info_type']) || $status_only || empty($values['caldav_url']))
|
||||
{
|
||||
$values = $this->read($info_id, true, 'server');
|
||||
}
|
||||
@ -871,6 +938,12 @@ class infolog_bo
|
||||
// create (and remove) links in custom fields
|
||||
customfields_widget::update_customfield_links('infolog',$values,$old,'info_id');
|
||||
|
||||
// Check for restore of deleted entry, restore held links
|
||||
if($old['info_status'] == 'deleted' && $values['info_status'] != 'deleted')
|
||||
{
|
||||
egw_link::restore('infolog', $info_id);
|
||||
}
|
||||
|
||||
// notify the link-class about the update, as other apps may be subscribt to it
|
||||
egw_link::notify_update('infolog',$info_id,$values);
|
||||
|
||||
@ -888,15 +961,23 @@ class infolog_bo
|
||||
$values = array_merge($values,$missing_fields);
|
||||
}
|
||||
// Add keys missing in the $to_write array
|
||||
if ($missing_fields = array_diff_key($values,$to_write))
|
||||
if (($missing_fields = array_diff_key($values,$to_write)))
|
||||
{
|
||||
$to_write = array_merge($to_write,$missing_fields);
|
||||
}
|
||||
$this->tracking->track($to_write,$old,$this->user,$values['info_status'] == 'deleted' || $old['info_status'] == 'deleted',
|
||||
null,$skip_notification);
|
||||
}
|
||||
if ($info_from_set) $values['info_from'] = '';
|
||||
|
||||
if ($info_from_set) $values['info_from'] = '';
|
||||
|
||||
// Change new values back to user time before sending them back
|
||||
if($user2server)
|
||||
{
|
||||
$this->time2time($values);
|
||||
}
|
||||
// merge changes (keeping extra values from the UI)
|
||||
$values_in = array_merge($values_in,$values);
|
||||
}
|
||||
return $info_id;
|
||||
}
|
||||
|
||||
@ -926,7 +1007,13 @@ class infolog_bo
|
||||
*/
|
||||
function &search(&$query)
|
||||
{
|
||||
//echo "<p>boinfolog::search(".print_r($query,True).")</p>\n";
|
||||
//error_log(__METHOD__.'('.array2string($query).')');
|
||||
|
||||
if($query['filter'] == 'bydate')
|
||||
{
|
||||
if (is_int($query['startdate'])) $query['col_filter'][] = 'info_startdate >= '.$GLOBALS['egw']->db->quote($query['startdate']);
|
||||
if (is_int($query['enddate'])) $query['col_filter'][] = 'info_startdate <= '.$GLOBALS['egw']->db->quote($query['enddate']+(60*60*24)-1);
|
||||
}
|
||||
if (!isset($query['date_format']) || $query['date_format'] != 'server')
|
||||
{
|
||||
if (isset($query['col_filter']))
|
||||
@ -983,6 +1070,31 @@ class infolog_bo
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query ctag for infolog
|
||||
*
|
||||
* @param array $filter=array('filter'=>'own','info_type'=>'task')
|
||||
* @return string
|
||||
*/
|
||||
public function getctag(array $filter=array('filter'=>'own','info_type'=>'task'))
|
||||
{
|
||||
$filter += array(
|
||||
'order' => 'info_datemodified',
|
||||
'sort' => 'DESC',
|
||||
'date_format' => 'server',
|
||||
'start' => 0,
|
||||
'num_rows' => 1,
|
||||
);
|
||||
|
||||
$result =& $this->search($filter);
|
||||
|
||||
if (empty($result)) return 'EGw-empty-wGE';
|
||||
|
||||
$entry = array_shift($result);
|
||||
|
||||
return $entry['info_datemodified'];
|
||||
}
|
||||
|
||||
/**
|
||||
* imports a mail identified by uid as infolog
|
||||
*
|
||||
@ -1017,7 +1129,7 @@ class infolog_bo
|
||||
'info_addr' => implode(', ',$email),
|
||||
'info_subject' => $_subject,
|
||||
'info_des' => $_message,
|
||||
'info_startdate' => $_date,
|
||||
'info_startdate' => egw_time::server2user($_date),
|
||||
'info_status' => $status,
|
||||
'info_priority' => 1,
|
||||
'info_percent' => $status == 'done' ? 100 : 0,
|
||||
@ -1146,15 +1258,17 @@ class infolog_bo
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access to the projects file store
|
||||
* Check access to the file store
|
||||
*
|
||||
* @param int|array $id id of entry or entry array
|
||||
* @param int $check EGW_ACL_READ for read and EGW_ACL_EDIT for write or delete access
|
||||
* @param string $rel_path=null currently not used in InfoLog
|
||||
* @param int $user=null for which user to check, default current user
|
||||
* @return boolean true if access is granted or false otherwise
|
||||
*/
|
||||
function file_access($id,$check,$rel_path=null)
|
||||
function file_access($id,$check,$rel_path=null,$user=null)
|
||||
{
|
||||
return $this->check_access($id,$check);
|
||||
return $this->check_access($id,$check,0,$user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1222,6 +1336,8 @@ class infolog_bo
|
||||
$title = ($do_events?common::formattime($start->format('H'),$start->format('i')).' ':'').
|
||||
$info['info_subject'];
|
||||
$view = egw_link::view('infolog',$info['info_id']);
|
||||
$edit = egw_link::edit('infolog',$info['info_id'], $size);
|
||||
$edit['size'] = $size;
|
||||
$content=array();
|
||||
foreach ($icons = array(
|
||||
$info['info_type'] => 'infolog',
|
||||
@ -1238,6 +1354,7 @@ class infolog_bo
|
||||
'endtime' => ($info['info_enddate'] ? $info['info_enddate'] : $info['info_startdate']),
|
||||
'title' => $title,
|
||||
'view' => $view,
|
||||
'edit' => $edit,
|
||||
'icons' => $icons,
|
||||
'content' => $content
|
||||
);
|
||||
@ -1424,24 +1541,27 @@ class infolog_bo
|
||||
|
||||
if (is_null($this->tracking) || $this->tracking->user != $user)
|
||||
{
|
||||
require_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.infolog_tracking.inc.php');
|
||||
$this->tracking = new infolog_tracking($this);
|
||||
}
|
||||
switch($pref)
|
||||
{
|
||||
case 'notify_due_responsible':
|
||||
$info['prefix'] = lang('Due %1',$this->enums['type'][$info['info_type']]);
|
||||
$info['message'] = lang('%1 you are responsible for is due at %2',$this->enums['type'][$info['info_type']],
|
||||
$this->tracking->datetime($info['info_enddate'],false));
|
||||
break;
|
||||
case 'notify_due_delegated':
|
||||
$info['prefix'] = lang('Due %1',$this->enums['type'][$info['info_type']]);
|
||||
$info['message'] = lang('%1 you delegated is due at %2',$this->enums['type'][$info['info_type']],
|
||||
$this->tracking->datetime($info['info_enddate'],false));
|
||||
break;
|
||||
case 'notify_start_responsible':
|
||||
$info['prefix'] = lang('Starting %1',$this->enums['type'][$info['info_type']]);
|
||||
$info['message'] = lang('%1 you are responsible for is starting at %2',$this->enums['type'][$info['info_type']],
|
||||
$this->tracking->datetime($info['info_startdate'],null));
|
||||
break;
|
||||
case 'notify_start_delegated':
|
||||
$info['prefix'] = lang('Starting %1',$this->enums['type'][$info['info_type']]);
|
||||
$info['message'] = lang('%1 you delegated is starting at %2',$this->enums['type'][$info['info_type']],
|
||||
$this->tracking->datetime($info['info_startdate'],null));
|
||||
break;
|
||||
|
214
infolog/inc/class.infolog_datasource.inc.php
Normal file
214
infolog/inc/class.infolog_datasource.inc.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
/**
|
||||
* InfoLog - Datasource for ProjektManager
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package infolog
|
||||
* @subpackage projectmanager
|
||||
* @copyright (c) 2005-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
include_once(EGW_INCLUDE_ROOT.'/projectmanager/inc/class.datasource.inc.php');
|
||||
|
||||
/**
|
||||
* DataSource for InfoLog
|
||||
*
|
||||
* The InfoLog datasource set's only real start- and endtimes, plus planned and used time and
|
||||
* the responsible user as resources (not always the owner too!).
|
||||
* The read method of the extended datasource class sets the planned start- and endtime:
|
||||
* - planned start from the end of a start constrain
|
||||
* - planned end from the planned time and a start-time
|
||||
* - planned start and end from the "real" values
|
||||
*/
|
||||
class infolog_datasource extends datasource
|
||||
{
|
||||
/**
|
||||
* Reference to infolog_bo
|
||||
*
|
||||
* @var infolog_bo
|
||||
*/
|
||||
var $infolog_bo;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct('infolog');
|
||||
|
||||
$this->valid = PM_COMPLETION|PM_PLANNED_START|PM_PLANNED_END|PM_REAL_END|PM_PLANNED_TIME|PM_REPLANNED_TIME|PM_USED_TIME|PM_RESOURCES;
|
||||
|
||||
// we use $GLOBALS['infolog_bo'] as an already running instance might be availible there
|
||||
if (!is_object($GLOBALS['infolog_bo']))
|
||||
{
|
||||
$GLOBALS['infolog_bo'] = new infolog_bo();
|
||||
}
|
||||
$this->infolog_bo =& $GLOBALS['infolog_bo'];
|
||||
}
|
||||
|
||||
/**
|
||||
* get an entry from the underlaying app (if not given) and convert it into a datasource array
|
||||
*
|
||||
* @param mixed $data_id id as used in the link-class for that app, or complete entry as array
|
||||
* @return array/boolean array with the data supported by that source or false on error (eg. not found, not availible)
|
||||
*/
|
||||
function get($data_id)
|
||||
{
|
||||
if (!is_array($data_id))
|
||||
{
|
||||
$data =& $this->infolog_bo->read((int) $data_id);
|
||||
|
||||
if (!is_array($data)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$data =& $data_id;
|
||||
}
|
||||
return array(
|
||||
'pe_title' => $this->infolog_bo->link_title($data),
|
||||
'pe_completion' => $data['info_percent'],
|
||||
'pe_planned_start'=> $data['info_startdate'] ? $data['info_startdate'] : null,
|
||||
'pe_planned_end' => $data['info_enddate'] ? $data['info_enddate'] : null,
|
||||
'pe_real_end' => $data['info_datecompleted'] ? $data['info_datecompleted'] : null,
|
||||
'pe_planned_time' => $data['info_planned_time'],
|
||||
'pe_replanned_time' => $data['info_replanned_time'],
|
||||
'pe_used_time' => $data['info_used_time'],
|
||||
'pe_resources' => count($data['info_responsible']) ? $data['info_responsible'] : array($data['info_owner']),
|
||||
'pe_details' => $data['info_des'] ? nl2br($data['info_des']) : '',
|
||||
'pl_id' => $data['pl_id'],
|
||||
'pe_unitprice' => $data['info_price'],
|
||||
'pe_planned_quantity' => $data['info_planned_time'] / 60,
|
||||
'pe_planned_budget' => $data['info_planned_time'] / 60 * $data['info_price'],
|
||||
'pe_used_quantity' => $data['info_used_time'] / 60,
|
||||
'pe_used_budget' => $data['info_used_time'] / 60 * $data['info_price'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the datasource of a projectelement (InfoLog entry) and re-link it with project $target
|
||||
*
|
||||
* @param array $element source project element representing an InfoLog entry, $element['pe_app_id'] = info_id
|
||||
* @param int $target target project id
|
||||
* @param array $target_data=null data of target-project, atm not used by the infolog datasource
|
||||
* @return array/boolean array(info_id,link_id) on success, false otherwise
|
||||
*/
|
||||
function copy($element,$target,$extra=null)
|
||||
{
|
||||
$info =& $this->infolog_bo->read((int) $element['pe_app_id']);
|
||||
|
||||
if (!is_array($info)) return false;
|
||||
|
||||
// unsetting info_link_id and evtl. info_from
|
||||
if ($info['info_link_id'])
|
||||
{
|
||||
$this->infolog_bo->link_id2from($info); // unsets info_from and sets info_link_target
|
||||
unset($info['info_link_id']);
|
||||
}
|
||||
// we need to unset a view fields, to get a new entry
|
||||
foreach(array('info_id','info_owner','info_modified','info_modifierer') as $key)
|
||||
{
|
||||
unset($info[$key]);
|
||||
}
|
||||
if(!($info['info_id'] = $this->infolog_bo->write($info))) return false;
|
||||
|
||||
// link the new infolog against the project and setting info_link_id and evtl. info_from
|
||||
$info['info_link_id'] = egw_link::link('projectmanager',$target,'infolog',$info['info_id'],$element['pe_remark'],0,0,1);
|
||||
if (!$info['info_from'])
|
||||
{
|
||||
$info['info_from'] = egw_link::title('projectmanager',$target);
|
||||
}
|
||||
if ($info['info_status'] == 'template')
|
||||
{
|
||||
$info['info_status'] = $this->infolog_bo->activate($info);
|
||||
}
|
||||
$this->infolog_bo->write($info);
|
||||
|
||||
// creating again all links, beside the one to the source-project
|
||||
foreach(egw_link::get_links('infolog',$element['pe_app_id']) as $link)
|
||||
{
|
||||
if ($link['app'] == 'projectmanager' && $link['id'] == $element['pm_id'] || // ignoring the source project
|
||||
$link['app'] == egw_link::VFS_APPNAME) // ignoring files attachments for now
|
||||
{
|
||||
continue;
|
||||
}
|
||||
egw_link::link('infolog',$info['info_id'],$link['app'],$link['id'],$link['remark']);
|
||||
}
|
||||
$ret = array($info['info_id'],$info['info_link_id']);
|
||||
|
||||
// if we have a parent set, return our callback to modify the parent id, after all entries are copied
|
||||
if ($info['info_id_parent'])
|
||||
{
|
||||
$ret[] = array($this,'copy_callback'); // callback
|
||||
$ret[] = array($info['info_id'],$info['info_id_parent']); // $param
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called after copying of all datasource, used to:
|
||||
* - fix parent id's
|
||||
*
|
||||
* @param array $param array($info_id,$info_id_parent)
|
||||
* @param array $apps_copied array('infolog' => array($old_info_id => $new_info_id))
|
||||
*/
|
||||
public function copy_callback(array $param, array $apps_copied)
|
||||
{
|
||||
//error_log(__METHOD__."(".array2string($param).', '.array2string($apps_copied).')');
|
||||
list($info_id,$parent_id) = $param;
|
||||
if (isset($apps_copied['infolog'][$parent_id]) && ($info = $this->infolog_bo->read($info_id)))
|
||||
{
|
||||
$info['info_id_parent'] = $apps_copied['infolog'][$parent_id];
|
||||
$this->infolog_bo->write($info,false,true,true,true); // no default and no notification
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the datasource of a project element
|
||||
*
|
||||
* @param int $id
|
||||
* @return boolean true on success, false on error
|
||||
*/
|
||||
function delete($id)
|
||||
{
|
||||
if (!is_object($GLOBALS['infolog_bo']))
|
||||
{
|
||||
include_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.infolog_bo.inc.php');
|
||||
$GLOBALS['infolog_bo'] = new infolog_bo();
|
||||
}
|
||||
// dont delete infolog, which are linked to other elements, but their project
|
||||
if (count(egw_link::get_links('infolog',$id)) > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return $this->infolog_bo->delete($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the status of an infolog entry according to the project status
|
||||
*
|
||||
* @param int $id
|
||||
* @param string $status
|
||||
* @return boolean true if status changed, false otherwise
|
||||
*/
|
||||
function change_status($id,$status)
|
||||
{
|
||||
//error_log("datasource_infolog::change_status($id,$status)");
|
||||
if (($info = $this->infolog_bo->read($id)) && $this->infolog_bo->check_access($info,EGW_ACL_EDIT))
|
||||
{
|
||||
if ($status == 'active' && in_array($info['info_status'],array('template','nonactive','archive')))
|
||||
{
|
||||
$status = $this->infolog_bo->activate($info);
|
||||
}
|
||||
if($info['info_status'] != $status && isset($this->infolog_bo->status[$info['info_type']][$status]))
|
||||
{
|
||||
//error_log("datasource_infolog::change_status($id,$status) setting status from ".$info['info_status']);
|
||||
$info['info_status'] = $status;
|
||||
return $this->infolog_bo->write($info) !== false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
157
infolog/inc/class.infolog_egw_record.inc.php
Normal file
157
infolog/inc/class.infolog_egw_record.inc.php
Normal file
@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Infolog - importexport
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package infolog
|
||||
* @subpackage importexport
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @copyright Nathan Gray
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* class infolog_egw_record
|
||||
*
|
||||
* compability layer for iface_egw_record needet for importexport
|
||||
*/
|
||||
class infolog_egw_record implements importexport_iface_egw_record
|
||||
{
|
||||
private $identifier = '';
|
||||
private $record = array();
|
||||
private $bo;
|
||||
|
||||
// Used in conversions
|
||||
static $types = array(
|
||||
'select-account' => array('info_owner','info_responsible','modifier'),
|
||||
'date-time' => array('info_datecompleted', 'info_datemodified','created','last_event','next_event'),
|
||||
'date' => array('info_startdate', 'info_enddate'),
|
||||
'select-cat' => array('info_cat', 'cat_id'),
|
||||
'links' => array('info_link_id'),
|
||||
);
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* reads record from backend if identifier is given.
|
||||
*
|
||||
* @param string $_identifier
|
||||
*/
|
||||
public function __construct( $_identifier='' ){
|
||||
$this->identifier = $_identifier;
|
||||
$this->bo = new infolog_bo();
|
||||
if($_identifier) {
|
||||
$this->record = $this->bo->read($this->identifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* magic method to set attributes of record
|
||||
*
|
||||
* @param string $_attribute_name
|
||||
*/
|
||||
public function __get($_attribute_name) {
|
||||
return $this->record[$_attribute_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* magig method to set attributes of record
|
||||
*
|
||||
* @param string $_attribute_name
|
||||
* @param data $data
|
||||
*/
|
||||
public function __set($_attribute_name, $data) {
|
||||
$this->record[$_attribute_name] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts this object to array.
|
||||
* @abstract We need such a function cause PHP5
|
||||
* dosn't allow objects do define it's own casts :-(
|
||||
* once PHP can deal with object casts we will change to them!
|
||||
*
|
||||
* @return array complete record as associative array
|
||||
*/
|
||||
public function get_record_array() {
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets title of record
|
||||
*
|
||||
*@return string tiltle
|
||||
*/
|
||||
public function get_title() {
|
||||
if (empty($this->record)) {
|
||||
$this->get_record();
|
||||
}
|
||||
return $this->record['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
* sets complete record from associative array
|
||||
*
|
||||
* @todo add some checks
|
||||
* @return void
|
||||
*/
|
||||
public function set_record(array $_record){
|
||||
$this->record = $_record;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets identifier of this record
|
||||
*
|
||||
* @return string identifier of current record
|
||||
*/
|
||||
public function get_identifier() {
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* saves record into backend
|
||||
*
|
||||
* @return string identifier
|
||||
*/
|
||||
public function save ( $_dst_identifier ) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* copys current record to record identified by $_dst_identifier
|
||||
*
|
||||
* @param string $_dst_identifier
|
||||
* @return string dst_identifier
|
||||
*/
|
||||
public function copy ( $_dst_identifier ) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* moves current record to record identified by $_dst_identifier
|
||||
* $this will become moved record
|
||||
*
|
||||
* @param string $_dst_identifier
|
||||
* @return string dst_identifier
|
||||
*/
|
||||
public function move ( $_dst_identifier ) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* delets current record from backend
|
||||
*
|
||||
*/
|
||||
public function delete () {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* destructor
|
||||
*
|
||||
*/
|
||||
public function __destruct() {
|
||||
unset ($this->bo);
|
||||
}
|
||||
|
||||
} // end of egw_addressbook_record
|
||||
?>
|
133
infolog/inc/class.infolog_export_csv.inc.php
Normal file
133
infolog/inc/class.infolog_export_csv.inc.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package infolog
|
||||
* @subpackage importexport
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @copyright Nathan Gray
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* export plugin of infolog
|
||||
*/
|
||||
class infolog_export_csv implements importexport_iface_export_plugin {
|
||||
|
||||
|
||||
/**
|
||||
* Exports records as defined in $_definition
|
||||
*
|
||||
* @param egw_record $_definition
|
||||
*/
|
||||
public function export( $_stream, importexport_definition $_definition) {
|
||||
$options = $_definition->plugin_options;
|
||||
|
||||
$bo = new infolog_bo();
|
||||
$selection = array();
|
||||
$query = array();
|
||||
|
||||
$export_object = new importexport_export_csv($_stream, (array)$options);
|
||||
$export_object->set_mapping($options['mapping']);
|
||||
|
||||
// do we need to query the cf's
|
||||
foreach($options['mapping'] as $field => $map) {
|
||||
if($field[0] == '#') $query['custom_fields'][] = $field;
|
||||
}
|
||||
|
||||
if ($options['selection'] == 'search') {
|
||||
$query = array_merge($GLOBALS['egw']->session->appsession('session_data','infolog'), $query);
|
||||
$query['num_rows'] = -1; // all
|
||||
$selection = $bo->search($query);
|
||||
}
|
||||
elseif ( $options['selection'] == 'all' ) {
|
||||
$query['num_rows'] = -1;
|
||||
$selection = $bo->search($query);
|
||||
} else {
|
||||
$selection = explode(',',$options['selection']);
|
||||
}
|
||||
|
||||
foreach ($selection as $_identifier) {
|
||||
if(!is_array($_identifier)) {
|
||||
$record = new infolog_egw_record($_identifier);
|
||||
} else {
|
||||
$record = new infolog_egw_record();
|
||||
$record->set_record($_identifier);
|
||||
}
|
||||
// Some conversion
|
||||
if($options['convert']) {
|
||||
importexport_export_csv::convert($record, infolog_egw_record::$types, 'infolog');
|
||||
$this->convert($record);
|
||||
} else {
|
||||
// Implode arrays, so they don't say 'Array'
|
||||
foreach($record->get_record_array() as $key => $value) {
|
||||
if(is_array($value)) $record->$key = implode(',', $value);
|
||||
}
|
||||
}
|
||||
$export_object->export_record($record);
|
||||
unset($record);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns translated name of plugin
|
||||
*
|
||||
* @return string name
|
||||
*/
|
||||
public static function get_name() {
|
||||
return lang('Infolog CSV export');
|
||||
}
|
||||
|
||||
/**
|
||||
* returns translated (user) description of plugin
|
||||
*
|
||||
* @return string descriprion
|
||||
*/
|
||||
public static function get_description() {
|
||||
return lang("Exports Infolog entries into a CSV File.");
|
||||
}
|
||||
|
||||
/**
|
||||
* retruns file suffix for exported file
|
||||
*
|
||||
* @return string suffix
|
||||
*/
|
||||
public static function get_filesuffix() {
|
||||
return 'csv';
|
||||
}
|
||||
|
||||
public static function get_mimetype() {
|
||||
return 'text/csv';
|
||||
}
|
||||
|
||||
/**
|
||||
* return html for options.
|
||||
* this way the plugin has all opertunities for options tab
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function get_options_etpl() {
|
||||
}
|
||||
|
||||
/**
|
||||
* returns slectors of this plugin via xajax
|
||||
*
|
||||
*/
|
||||
public function get_selectors_etpl() {
|
||||
return array(
|
||||
'name' => 'infolog.export_csv_selectors',
|
||||
'content' => 'search'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert some internal data to something with more meaning
|
||||
*
|
||||
* This is for something specific to Infolog, in addition to the normal conversions.
|
||||
*/
|
||||
public static function convert(infolog_egw_record &$record) {
|
||||
// Stub, for now
|
||||
}
|
||||
}
|
@ -1,20 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare: GroupDAV access: infolog handler
|
||||
* EGroupware: GroupDAV access: infolog handler
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package infolog
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
|
||||
/**
|
||||
* eGroupWare: GroupDAV access: infolog handler
|
||||
* EGroupware: GroupDAV access: infolog handler
|
||||
*
|
||||
* Permanent error_log() calls should use $this->groupdav->log($str) instead, to be send to PHP error_log()
|
||||
* and our request-log (prefixed with "### " after request and response, like exceptions).
|
||||
*/
|
||||
class infolog_groupdav extends groupdav_handler
|
||||
{
|
||||
@ -42,24 +45,36 @@ class infolog_groupdav extends groupdav_handler
|
||||
'PRIORITY' => 'info_priority',
|
||||
'LOCATION' => 'info_location',
|
||||
'COMPLETED' => 'info_datecompleted',
|
||||
'CREATED' => 'info_created',
|
||||
);
|
||||
|
||||
/**
|
||||
* Are we using info_id, info_uid or caldav_name for the path/url
|
||||
*
|
||||
* Get's set in constructor to 'caldav_name' and groupdav_handler::$path_extension = ''!
|
||||
*/
|
||||
static $path_attr = 'info_id';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $app 'calendar', 'addressbook' or 'infolog'
|
||||
* @param int $debug=null debug-level to set
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @param string $principalURL=null pricipal url of handler
|
||||
* @param groupdav $groupdav calling class
|
||||
*/
|
||||
function __construct($app,$debug=null,$base_uri=null,$principalURL=null)
|
||||
function __construct($app, groupdav $groupdav)
|
||||
{
|
||||
parent::__construct($app,$debug,$base_uri,$principalURL);
|
||||
parent::__construct($app, $groupdav);
|
||||
|
||||
$this->bo = new infolog_bo();
|
||||
$this->vCalendar = new Horde_iCalendar;
|
||||
}
|
||||
|
||||
const PATH_ATTRIBUTE = 'info_id';
|
||||
// since 1.9.002 we allow clients to specify the URL when creating a new event, as specified by CalDAV
|
||||
if (version_compare($GLOBALS['egw_info']['apps']['calendar']['version'], '1.9.002', '>='))
|
||||
{
|
||||
self::$path_attr = 'caldav_name';
|
||||
groupdav_handler::$path_extension = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the path for an event
|
||||
@ -67,18 +82,55 @@ class infolog_groupdav extends groupdav_handler
|
||||
* @param array|int $info
|
||||
* @return string
|
||||
*/
|
||||
static function get_path($info)
|
||||
function get_path($info)
|
||||
{
|
||||
if (is_numeric($info) && self::PATH_ATTRIBUTE == 'info_id')
|
||||
if (is_numeric($info) && self::$path_attr == 'info_id')
|
||||
{
|
||||
$name = $info;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_array($info)) $info = $this->bo->read($info);
|
||||
$name = $info[self::PATH_ATTRIBUTE];
|
||||
$name = $info[self::$path_attr];
|
||||
}
|
||||
return $name.'.ics';
|
||||
return $name.groupdav_handler::$path_extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filter-array for infolog_bo::search used by getctag and propfind
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $user account_id
|
||||
* @return array
|
||||
*/
|
||||
private function get_infolog_filter($path, $user)
|
||||
{
|
||||
if (!($infolog_types = $GLOBALS['egw_info']['user']['preferences']['groupdav']['infolog-types']))
|
||||
{
|
||||
$infolog_types = 'task';
|
||||
}
|
||||
if ($path == '/infolog/')
|
||||
{
|
||||
$task_filter= 'own';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($user == $GLOBALS['egw_info']['user']['account_id'])
|
||||
{
|
||||
$task_filter = 'own';
|
||||
}
|
||||
else
|
||||
{
|
||||
$task_filter = 'user' . $user;
|
||||
}
|
||||
}
|
||||
|
||||
$ret = array(
|
||||
'filter' => $task_filter,
|
||||
'info_type' => explode(',', $infolog_types),
|
||||
);
|
||||
//error_log(__METHOD__."('$path', $user) returning ".array2string($ret));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,29 +144,8 @@ class infolog_groupdav extends groupdav_handler
|
||||
*/
|
||||
function propfind($path,$options,&$files,$user,$id='')
|
||||
{
|
||||
$myself = ($user == $GLOBALS['egw_info']['user']['account_id']);
|
||||
|
||||
if ($path == '/infolog/')
|
||||
{
|
||||
$task_filter= 'own';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($myself)
|
||||
{
|
||||
$task_filter = 'open';
|
||||
}
|
||||
else
|
||||
{
|
||||
$task_filter = 'open-user' . $user;
|
||||
}
|
||||
}
|
||||
|
||||
// todo add a filter to limit how far back entries from the past get synced
|
||||
$filter = array(
|
||||
'info_type' => 'task',
|
||||
'filter' => $task_filter,
|
||||
);
|
||||
$filter = $this->get_infolog_filter($path, $user);
|
||||
|
||||
// process REPORT filters or multiget href's
|
||||
if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$filter,$id))
|
||||
@ -123,6 +154,11 @@ class infolog_groupdav extends groupdav_handler
|
||||
// when trying to request not supported components, eg. VTODO on a calendar collection
|
||||
return true;
|
||||
}
|
||||
// enable time-range filter for tests via propfind / autoindex
|
||||
//$filter[] = $sql = $this->_time_range_filter(array('end' => '20001231T000000Z'));
|
||||
|
||||
if ($id) $path = dirname($path).'/'; // caldav_name get's added anyway in the callback
|
||||
|
||||
if ($this->debug > 1)
|
||||
{
|
||||
error_log(__METHOD__."($path,,,$user,$id) filter=".
|
||||
@ -175,11 +211,12 @@ class infolog_groupdav extends groupdav_handler
|
||||
'filter' => $task_filter,
|
||||
'date_format' => 'server',
|
||||
'col_filter' => $filter,
|
||||
'custom_fields' => true, // otherwise custom fields get NOT loaded!
|
||||
);
|
||||
|
||||
if (!$calendar_data)
|
||||
{
|
||||
$query['cols'] = array('info_id', 'info_datemodified');
|
||||
$query['cols'] = array('info_id', 'info_datemodified', 'info_uid', 'caldav_name', 'info_subject');
|
||||
}
|
||||
|
||||
if (is_array($start))
|
||||
@ -200,28 +237,17 @@ class infolog_groupdav extends groupdav_handler
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
$props = array(
|
||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($task)),
|
||||
HTTP_WebDAV_Server::mkprop('getcontenttype',$this->agent != 'kde' ?
|
||||
'text/calendar; charset=utf-8; component=VTODO' : 'text/calendar'), // Konqueror (3.5) dont understand it otherwise
|
||||
// getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set
|
||||
HTTP_WebDAV_Server::mkprop('getlastmodified', $task['info_datemodified']),
|
||||
HTTP_WebDAV_Server::mkprop('resourcetype',''), // DAVKit requires that attribute!
|
||||
HTTP_WebDAV_Server::mkprop('getcontentlength',''),
|
||||
'getcontenttype' => $this->agent != 'kde' ? 'text/calendar; charset=utf-8; component=VTODO' : 'text/calendar', // Konqueror (3.5) dont understand it otherwise
|
||||
'getlastmodified' => $task['info_datemodified'],
|
||||
'displayname' => $task['info_subject'],
|
||||
);
|
||||
if ($calendar_data)
|
||||
{
|
||||
$content = $handler->exportVTODO($task,'2.0','PUBLISH');
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content));
|
||||
$content = $handler->exportVTODO($task, '2.0', null); // no METHOD:PUBLISH for CalDAV
|
||||
$props['getcontentlength'] = bytes($content);
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data',$content);
|
||||
}
|
||||
else
|
||||
{
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
|
||||
}
|
||||
$files[] = array(
|
||||
'path' => $path.self::get_path($task),
|
||||
'props' => $props,
|
||||
);
|
||||
$files[] = $this->add_resource($path, $task, $props);
|
||||
}
|
||||
}
|
||||
if ($this->debug) error_log(__METHOD__."($path) took ".(microtime(true) - $starttime).' to return '.count($files).' items');
|
||||
@ -240,6 +266,8 @@ class infolog_groupdav extends groupdav_handler
|
||||
{
|
||||
if ($options['filters'])
|
||||
{
|
||||
$cal_filters_in = $cal_filters; // remember filter, to be able to reset standard open-filter, if client sets own filters
|
||||
|
||||
foreach($options['filters'] as $filter)
|
||||
{
|
||||
switch($filter['name'])
|
||||
@ -276,21 +304,19 @@ class infolog_groupdav extends groupdav_handler
|
||||
if ($this->debug) error_log(__METHOD__."($options[path],...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!");
|
||||
break;
|
||||
case 'time-range':
|
||||
if ($this->debug > 1) error_log(__FILE__ . __METHOD__."($options[path],...) time-range={$filter['attrs']['start']}-{$filter['attrs']['end']}");
|
||||
if (!empty($filter['attrs']['start']))
|
||||
{
|
||||
$cal_filters[] = 'info_startdate >= ' . (int)$this->vCalendar->_parseDateTime($filter['attrs']['start']);
|
||||
}
|
||||
if (!empty($filter['attrs']['end']))
|
||||
{
|
||||
$cal_filters[] = 'info_startdate <= ' . (int)$this->vCalendar->_parseDateTime($filter['attrs']['end']);
|
||||
}
|
||||
$cal_filters[] = $this->_time_range_filter($filter['attrs']);
|
||||
break;
|
||||
default:
|
||||
if ($this->debug) error_log(__METHOD__."($options[path],".array2string($options).",...) unknown filter --> ignored");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if client set an own filter, reset the open-standard filter
|
||||
/* not longer necessary, as we use now own and user anyway
|
||||
if ($cal_filters != $cal_filters_in)
|
||||
{
|
||||
$cal_filters['filter'] = str_replace(array('open', 'open-user'), array('own', 'user'), $cal_filters['filter']);
|
||||
}*/
|
||||
}
|
||||
// multiget or propfind on a given id
|
||||
//error_log(__FILE__ . __METHOD__ . "multiget of propfind:");
|
||||
@ -299,14 +325,8 @@ class infolog_groupdav extends groupdav_handler
|
||||
$ids = array();
|
||||
if ($id)
|
||||
{
|
||||
if (is_numeric($id))
|
||||
{
|
||||
$cal_filters['info_id'] = $id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$cal_filters['info_uid'] = basename($id,'.ics');
|
||||
}
|
||||
$cal_filters[self::$path_attr] = groupdav_handler::$path_extension ?
|
||||
basename($id,groupdav_handler::$path_extension) : $id;
|
||||
}
|
||||
else // fetch all given url's
|
||||
{
|
||||
@ -315,19 +335,78 @@ class infolog_groupdav extends groupdav_handler
|
||||
if ($option['name'] == 'href')
|
||||
{
|
||||
$parts = explode('/',$option['data']);
|
||||
if (is_numeric($id = basename(array_pop($parts),'.ics'))) $ids[] = $id;
|
||||
if (($id = basename(array_pop($parts))))
|
||||
{
|
||||
$cal_filters[self::$path_attr][] = groupdav_handler::$path_extension ?
|
||||
basename($id,groupdav_handler::$path_extension) : $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($ids)
|
||||
{
|
||||
$cal_filters[] = 'info_id IN ('.implode(',',array_map(create_function('$n','return (int)$n;'),$ids)).')';
|
||||
}
|
||||
}
|
||||
if ($this->debug > 1) error_log(__METHOD__ ."($options[path],...,$id) calendar-multiget: ids=".implode(',',$ids));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SQL filter from time-range filter attributes
|
||||
*
|
||||
* CalDAV time-range for VTODO checks DTSTART, DTEND, DUE, CREATED and allways includes tasks if none given
|
||||
* @see http://tools.ietf.org/html/rfc4791#section-9.9
|
||||
*
|
||||
* @param array $attrs values for keys 'start' and/or 'end', at least one is required by CalDAV rfc!
|
||||
* @return string with sql
|
||||
*/
|
||||
private function _time_range_filter(array $attrs)
|
||||
{
|
||||
$to_or = $to_and = array();
|
||||
if (!empty($attrs['start']))
|
||||
{
|
||||
$start = (int)$this->vCalendar->_parseDateTime($attrs['start']);
|
||||
}
|
||||
if (!empty($attrs['end']))
|
||||
{
|
||||
$end = (int)$this->vCalendar->_parseDateTime($attrs['end']);
|
||||
}
|
||||
elseif (empty($attrs['start']))
|
||||
{
|
||||
$this->groupdav->log(__METHOD__.'('.array2string($attrs).') minimum one of start or end is required!');
|
||||
return '1'; // to not give sql error, but simply not filter out anything
|
||||
}
|
||||
// we dont need to care for DURATION line in rfc4791#section-9.9, as we always put that in DUE/info_enddate
|
||||
|
||||
// we have start- and/or enddate
|
||||
if (isset($start))
|
||||
{
|
||||
$to_and[] = "($start < info_enddate OR $start <= info_startdate)";
|
||||
}
|
||||
if (isset($end))
|
||||
{
|
||||
$to_and[] = "(info_startdate < $end OR info_enddate <= $end)";
|
||||
}
|
||||
$to_or[] = '('.implode(' AND ', $to_and).')';
|
||||
|
||||
/* either start or enddate is already included in the above, because of OR!
|
||||
// only a startdate, no enddate
|
||||
$to_or[] = "NOT info_enddate > 0".($start ? " AND $start <= info_startdate" : '').
|
||||
($end ? " AND info_startdate < $end" : '');
|
||||
|
||||
// only an enddate, no startdate
|
||||
$to_or[] = "NOT info_startdate > 0".($start ? " AND $start < info_enddate" : '').
|
||||
($end ? " AND info_enddate <= $end" : '');*/
|
||||
|
||||
// no startdate AND no enddate (2. half of rfc4791#section-9.9) --> use created and due dates instead
|
||||
$to_or[] = 'NOT info_startdate > 0 AND NOT info_enddate > 0 AND ('.
|
||||
// we have a completed date
|
||||
"info_datecompleted > 0".(isset($start) ? " AND ($start <= info_datecompleted OR $start <= info_created)" : '').
|
||||
(isset($end) ? " AND (info_datecompleted <= $end OR info_created <= $end)" : '').' OR '.
|
||||
// we have no completed date, but always a created date
|
||||
"NOT info_datecompleted > 0". (isset($end) ? " AND info_created < $end" : '').
|
||||
')';
|
||||
$sql = '('.implode(' OR ', $to_or).')';
|
||||
if ($this->debug > 1) error_log(__FILE__ . __METHOD__.'('.array2string($attrs).") time-range={$filter['attrs']['start']}-{$filter['attrs']['end']} --> $sql");
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle get request for a task / infolog entry
|
||||
@ -344,10 +423,10 @@ class infolog_groupdav extends groupdav_handler
|
||||
return $task;
|
||||
}
|
||||
$handler = $this->_get_handler();
|
||||
$options['data'] = $handler->exportVTODO($id,'2.0','PUBLISH');
|
||||
$options['data'] = $handler->exportVTODO($task, '2.0', null); // no METHOD:PUBLISH for CalDAV
|
||||
$options['mimetype'] = 'text/calendar; charset=utf-8';
|
||||
header('Content-Encoding: identity');
|
||||
header('ETag: '.$this->get_etag($task));
|
||||
header('ETag: "'.$this->get_etag($task).'"');
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -378,104 +457,31 @@ class infolog_groupdav extends groupdav_handler
|
||||
$taskId = $oldTask['info_id'];
|
||||
$retval = true;
|
||||
}
|
||||
else
|
||||
else // new entry
|
||||
{
|
||||
// new entry?
|
||||
if (($foundTasks = $handler->searchVTODO($vTodo)))
|
||||
{
|
||||
if (($taskId = array_shift($foundTasks)) &&
|
||||
($oldTask = $this->bo->read($taskId)))
|
||||
{
|
||||
$retval = '301 Moved Permanently';
|
||||
}
|
||||
else
|
||||
{
|
||||
// to be safe
|
||||
$taskId = 0;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// new entry
|
||||
$taskId = 0;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
$taskId = 0;
|
||||
$retval = '201 Created';
|
||||
}
|
||||
if ($user)
|
||||
{
|
||||
if (!$prefix) // for everything in /infolog/
|
||||
{
|
||||
$user = null; // do NOT set current user (infolog_bo->write() set it for new entries anyway)
|
||||
}
|
||||
elseif($oldTask) // existing entries
|
||||
{
|
||||
if ($oldTask['info_owner'] != $user)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(,$id,$user,$prefix) changing owner of existing entries is forbidden!");
|
||||
return '403 Forbidden'; // changing owner of existing entries is generally forbidden
|
||||
}
|
||||
$user = null;
|
||||
}
|
||||
else // new entries in /$user/infolog
|
||||
{
|
||||
// ACL is checked in infolog_bo->write() called by infolog_ical->importVTODO().
|
||||
// Not sure if it's a good idea to set a different owner, as GUI does NOT allow that,
|
||||
// thought there's an ACL for it and backend (infolog_bo) checks it.
|
||||
// More like the GUI would be to add it for current user and delegate it to $user.
|
||||
}
|
||||
}
|
||||
if (!($infoId = $handler->importVTODO($vTodo, $taskId, false, $user)))
|
||||
if (!($infoId = $handler->importVTODO($vTodo, $taskId, false, $user, null, $id)))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(,$id) import_vtodo($options[content]) returned false");
|
||||
return '403 Forbidden';
|
||||
}
|
||||
|
||||
/*
|
||||
if (strstr($option['path'], '/infolog/') === 0)
|
||||
{
|
||||
$task_filter= 'own';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($myself)
|
||||
{
|
||||
$task_filter = 'open';
|
||||
}
|
||||
else
|
||||
{
|
||||
$task_filter = 'user' . $user. '-open';
|
||||
}
|
||||
}
|
||||
|
||||
$query = array(
|
||||
'order' => 'info_datemodified',
|
||||
'sort' => 'DESC',
|
||||
'filter' => $task_filter,
|
||||
'date_format' => 'server',
|
||||
'col_filter' => array('info_id' => $infoId),
|
||||
);
|
||||
|
||||
if (!$this->bo->search($query))
|
||||
{
|
||||
$retval = '410 Gone';
|
||||
}
|
||||
else
|
||||
*/
|
||||
if ($infoId != $taskId)
|
||||
{
|
||||
$retval = '201 Created';
|
||||
|
||||
}
|
||||
|
||||
header('ETag: '.$this->get_etag($infoId));
|
||||
if ($retval !== true)
|
||||
// send evtl. necessary respose headers: Location, etag, ...
|
||||
// but only for new entries, as X-INFOLOG-STATUS get's not updated on client, if we confirm with an etag
|
||||
if ($retval !== true && (!$path_attr_is_name ||
|
||||
// POST with add-member query parameter
|
||||
$_SERVER['REQUEST_METHOD'] == 'POST' && isset($_GET['add-member'])))
|
||||
{
|
||||
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
|
||||
header('Location: '.$this->base_uri.$path.self::get_path($infoId));
|
||||
return $retval;
|
||||
$this->put_response_headers($infoId, $options['path'], $retval, self::$path_attr == 'caldav_name');
|
||||
}
|
||||
return true;
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -491,32 +497,42 @@ class infolog_groupdav extends groupdav_handler
|
||||
{
|
||||
return $task;
|
||||
}
|
||||
return $this->bo->delete($id);
|
||||
return $this->bo->delete($task['info_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an entry
|
||||
*
|
||||
* @param string/id $id
|
||||
* @return array/boolean array with entry, false if no read rights, null if $id does not exist
|
||||
* We have to make sure to not return or even consider in read deleted infologs, as the might have
|
||||
* the same UID and/or caldav_name as not deleted ones and would block access to valid entries
|
||||
*
|
||||
* @param string|id $id
|
||||
* @return array|boolean array with entry, false if no read rights, null if $id does not exist
|
||||
*/
|
||||
function read($id)
|
||||
{
|
||||
if (is_numeric($id)) return $this->bo->read($id,false,'server');
|
||||
return null;
|
||||
return $this->bo->read(array(self::$path_attr => $id, "info_status!='deleted'"),false,'server');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has the neccessary rights on a task / infolog entry
|
||||
*
|
||||
* @param int $acl EGW_ACL_READ, EGW_ACL_EDIT or EGW_ACL_DELETE
|
||||
* @param array/int $task task-array or id
|
||||
* @param array|int $task task-array or id
|
||||
* @return boolean null if entry does not exist, false if no access, true if access permitted
|
||||
*/
|
||||
function check_access($acl,$task)
|
||||
{
|
||||
if (is_null($task)) return true;
|
||||
return $this->bo->check_access($task,$acl);
|
||||
|
||||
$access = $this->bo->check_access($task,$acl);
|
||||
|
||||
if (!$access && $acl == EGW_ACL_EDIT && $this->bo->is_responsible($task))
|
||||
{
|
||||
$access = true; // access limited to $this->bo->responsible_edit fields (handled in infolog_bo::write())
|
||||
}
|
||||
if ($this->debug > 1) error_log(__METHOD__."($acl, ".array2string($task).') returning '.array2string($access));
|
||||
return $access;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -526,48 +542,16 @@ class infolog_groupdav extends groupdav_handler
|
||||
*/
|
||||
public function getctag($path,$user)
|
||||
{
|
||||
$myself = ($user == $GLOBALS['egw_info']['user']['account_id']);
|
||||
|
||||
if ($path == '/infolog/')
|
||||
{
|
||||
$task_filter= 'own';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($myself)
|
||||
{
|
||||
$task_filter = 'open';
|
||||
}
|
||||
else
|
||||
{
|
||||
$task_filter = 'open-user' . $user;
|
||||
}
|
||||
}
|
||||
|
||||
$query = array(
|
||||
'order' => 'info_datemodified',
|
||||
'sort' => 'DESC',
|
||||
'filter' => $task_filter,
|
||||
'date_format' => 'server',
|
||||
'col_filter' => array('info_type' => 'task'),
|
||||
'start' => 0,
|
||||
'num_rows' => 1,
|
||||
);
|
||||
|
||||
$result =& $this->bo->search($query);
|
||||
|
||||
if (empty($result)) return 'EGw-0-wGE';
|
||||
|
||||
$entry = array_shift($result);
|
||||
|
||||
return $this->get_etag($entry);
|
||||
return $this->bo->getctag($this->get_infolog_filter($path, $user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the etag for an infolog entry
|
||||
*
|
||||
* @param array/int $info array with infolog entry or info_id
|
||||
* @return string/boolean string with etag or false
|
||||
* etag currently uses the modifcation time (info_modified), 1.9.002 adds etag column, but it's not yet used!
|
||||
*
|
||||
* @param array|int $info array with infolog entry or info_id
|
||||
* @return string|boolean string with etag or false
|
||||
*/
|
||||
function get_etag($info)
|
||||
{
|
||||
@ -579,7 +563,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return 'EGw-'.$info['info_id'].':'.$info['info_datemodified'].'-wGE';
|
||||
return $info['info_id'].':'.$info['info_datemodified'];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -588,30 +572,33 @@ class infolog_groupdav extends groupdav_handler
|
||||
* @param array $props=array() regular props by the groupdav handler
|
||||
* @param string $displayname
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @param int $user=null account_id of owner of collection
|
||||
* @return array
|
||||
*/
|
||||
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
|
||||
public function extra_properties(array $props=array(), $displayname, $base_uri=null,$user=null)
|
||||
{
|
||||
// calendar description
|
||||
$displayname = translation::convert(lang('Tasks of') . ' ' .
|
||||
$displayname,translation::charset(),'utf-8');
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname);
|
||||
// email of the current user, see caldav-sheduling draft
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email'])));
|
||||
$displayname = translation::convert(lang('Tasks of'),translation::charset(),'utf-8').' '.$displayname;
|
||||
$props['calendar-description'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname);
|
||||
// supported components, currently only VEVENT
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array(
|
||||
// HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VEVENT')),
|
||||
$props['supported-calendar-component-set'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array(
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VCALENDAR')),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTIMEZONE')),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')),
|
||||
));
|
||||
|
||||
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
|
||||
// supported reports
|
||||
$props['supported-report-set'] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
|
||||
HTTP_WebDAV_Server::mkprop('supported-report',array(
|
||||
HTTP_WebDAV_Server::mkprop('report',array(
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-query',''))),
|
||||
HTTP_WebDAV_Server::mkprop('report',array(
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget','')))))));
|
||||
|
||||
// get timezone of calendar
|
||||
if ($this->groupdav->prop_requested('calendar-timezone'))
|
||||
{
|
||||
$props['calendar-timezone'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-timezone',
|
||||
calendar_timezones::user_timezone($user));
|
||||
}
|
||||
return $props;
|
||||
}
|
||||
|
||||
@ -628,4 +615,38 @@ class infolog_groupdav extends groupdav_handler
|
||||
|
||||
return $handler;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return appliction specific settings
|
||||
*
|
||||
* @param array $hook_data
|
||||
* @return array of array with settings
|
||||
*/
|
||||
static function get_settings($hook_data)
|
||||
{
|
||||
if (!isset($hook_data['setup']))
|
||||
{
|
||||
translation::add_app('infolog');
|
||||
$infolog = new infolog_bo();
|
||||
$types = $infolog->enums['type'];
|
||||
}
|
||||
if (!isset($types))
|
||||
{
|
||||
$types = array(
|
||||
'task' => 'Tasks',
|
||||
);
|
||||
}
|
||||
$settings = array();
|
||||
$settings['infolog-types'] = array(
|
||||
'type' => 'multiselect',
|
||||
'label' => 'InfoLog types to sync',
|
||||
'name' => 'infolog-types',
|
||||
'help' => 'Which InfoLog types should be synced with the device, default only tasks.',
|
||||
'values' => $types,
|
||||
'default' => 'task',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
);
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
496
infolog/inc/class.infolog_hooks.inc.php
Normal file
496
infolog/inc/class.infolog_hooks.inc.php
Normal file
@ -0,0 +1,496 @@
|
||||
<?php
|
||||
/**
|
||||
* InfoLog - Admin-, Preferences- and SideboxMenu-Hooks
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package infolog
|
||||
* @copyright (c) 2003-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class containing admin, preferences and sidebox-menus (used as hooks)
|
||||
*/
|
||||
class infolog_hooks
|
||||
{
|
||||
/**
|
||||
* For which groups should no group acl be used: infolog group owners
|
||||
*
|
||||
* @param string|array $data
|
||||
* @return boolean|array true, false or array with group-account_id's
|
||||
*/
|
||||
static function not_enum_group_acls($data)
|
||||
{
|
||||
$config = config::read('infolog');
|
||||
|
||||
return $config['group_owners'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called by link-class to include infolog 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)
|
||||
{
|
||||
// register our not_enum_group_acls hook, if not already registered
|
||||
// can be removed after next infolog version update after 1.6
|
||||
if ($GLOBALS['egw']->hooks->single('not_enum_group_acls',$acl_app) === false)
|
||||
{
|
||||
include(EGW_INCLUDE_ROOT.'/infolog/setup/setup.inc.php');
|
||||
$GLOBALS['egw']->hooks->register_hooks('infolog',$setup_info['infolog']['hooks']);
|
||||
unset($setup_info);
|
||||
}
|
||||
|
||||
return array(
|
||||
'query' => 'infolog.infolog_bo.link_query',
|
||||
'title' => 'infolog.infolog_bo.link_title',
|
||||
'titles' => 'infolog.infolog_bo.link_titles',
|
||||
'view' => array(
|
||||
'menuaction' => 'infolog.infolog_ui.index',
|
||||
'action' => 'sp'
|
||||
),
|
||||
'view_id' => 'action_id',
|
||||
'view_list' => 'infolog.infolog_ui.index',
|
||||
'add' => array(
|
||||
'menuaction' => 'infolog.infolog_ui.edit',
|
||||
'type' => 'task'
|
||||
),
|
||||
'add_app' => 'action',
|
||||
'add_id' => 'action_id',
|
||||
'add_popup' => '750x550',
|
||||
'file_access'=> 'infolog.infolog_bo.file_access',
|
||||
'edit' => array(
|
||||
'menuaction' => 'infolog.infolog_ui.edit',
|
||||
),
|
||||
'edit_id' => 'info_id',
|
||||
'edit_popup' => '750x580',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* hooks to build sidebox-menu plus the admin and preferences sections
|
||||
*
|
||||
* @param string/array $args hook args
|
||||
*/
|
||||
static function all_hooks($args)
|
||||
{
|
||||
$appname = 'infolog';
|
||||
$location = is_array($args) ? $args['location'] : $args;
|
||||
//echo "<p>admin_prefs_sidebox_hooks::all_hooks(".print_r($args,True).") appname='$appname', location='$location'</p>\n";
|
||||
|
||||
if ($location == 'sidebox_menu')
|
||||
{
|
||||
$file = array(
|
||||
'infolog list' => egw::link('/index.php',array(
|
||||
'menuaction' => 'infolog.infolog_ui.index' )),
|
||||
'Add' => "javascript:egw_openWindowCentered2('".egw::link('/index.php',array(
|
||||
'menuaction' => 'infolog.infolog_ui.edit',
|
||||
),false)."','_blank',750,410,'yes');",
|
||||
);
|
||||
display_sidebox($appname,$GLOBALS['egw_info']['apps']['infolog']['title'].' '.lang('Menu'),$file);
|
||||
}
|
||||
|
||||
if ($GLOBALS['egw_info']['user']['apps']['preferences'] && $location != 'admin')
|
||||
{
|
||||
$file = array(
|
||||
'Preferences' => egw::link('/index.php','menuaction=preferences.uisettings.index&appname='.$appname),
|
||||
'Grant Access' => egw::link('/index.php','menuaction=preferences.uiaclprefs.index&acl_app='.$appname),
|
||||
'Edit Categories' => egw::link('/index.php','menuaction=preferences.uicategories.index&cats_app=' . $appname . '&cats_level=True&global_cats=True')
|
||||
);
|
||||
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' => egw::link('/index.php',array(
|
||||
'menuaction' => 'infolog.infolog_ui.admin' )),
|
||||
'Global Categories' => egw::link('/index.php',array(
|
||||
'menuaction' => 'admin.uicategories.index',
|
||||
'appname' => $appname,
|
||||
'global_cats'=> True)),
|
||||
'Custom fields, typ and status' => egw::link('/index.php',array(
|
||||
'menuaction' => 'infolog.infolog_customfields.edit')),
|
||||
'CSV-Import' => egw::link('/infolog/csv_import.php'),
|
||||
);
|
||||
if ($location == 'admin')
|
||||
{
|
||||
display_section($appname,$file);
|
||||
}
|
||||
else
|
||||
{
|
||||
display_sidebox($appname,lang('Admin'),$file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* populates $settings for the preferences
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function settings()
|
||||
{
|
||||
/* Setup some values to fill the array of this app's settings below */
|
||||
$info = new infolog_bo(); // need some labels from
|
||||
$filters = $show_home = array();
|
||||
$show_home[] = lang("DON'T show InfoLog");
|
||||
foreach($info->filters as $key => $label)
|
||||
{
|
||||
$show_home[$key] = $filters[$key] = lang($label);
|
||||
}
|
||||
|
||||
// migrage old filter-pref 1,2 to the filter one 'own-open-today'
|
||||
if (isset($GLOBALS['type']) && in_array($GLOBALS['egw']->preferences->{$GLOBALS['type']}['homeShowEvents'],array('1','2')))
|
||||
{
|
||||
$GLOBALS['egw']->preferences->add('infolog','homeShowEvents','own-open-today',$GLOBALS['type']);
|
||||
$GLOBALS['egw']->preferences->save_repository();
|
||||
}
|
||||
$show_links = array(
|
||||
'all' => lang('all links and attachments'),
|
||||
'links' => lang('only the links'),
|
||||
'attach' => lang('only the attachments'),
|
||||
'none' => lang('no links or attachments'),
|
||||
'no_describtion' => lang('no describtion, links or attachments'),
|
||||
);
|
||||
$show_details = array(
|
||||
0 => lang('No'),
|
||||
1 => lang('Yes'),
|
||||
2 => lang('Only for details'),
|
||||
);
|
||||
|
||||
/* Settings array for this app */
|
||||
$settings = array(
|
||||
'defaultFilter' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Default Filter for InfoLog',
|
||||
'name' => 'defaultFilter',
|
||||
'values' => $filters,
|
||||
'help' => 'This is the filter InfoLog uses when you enter the application. Filters limit the entries to show in the actual view. There are filters to show only finished, still open or futures entries of yourself or all users.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> 'none',
|
||||
),
|
||||
'homeShowEvents' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'InfoLog filter for the main screen',
|
||||
'name' => 'homeShowEvents',
|
||||
'values' => $show_home,
|
||||
'help' => 'Should InfoLog show up on the main screen and with which filter. Works only if you dont selected an application for the main screen (in your preferences).',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> 'responsible-open-today',
|
||||
),
|
||||
'listNoSubs' => array(
|
||||
'type' => 'check',
|
||||
'label' => 'List no Subs/Childs',
|
||||
'name' => 'listNoSubs',
|
||||
'help' => 'Should InfoLog show Subtasks, -calls or -notes in the normal view or not. You can always view the Subs via there parent.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> '0', // No = List subs
|
||||
),
|
||||
'show_links' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Show in the InfoLog list',
|
||||
'name' => 'show_links',
|
||||
'values' => $show_links,
|
||||
'help' => 'Should InfoLog show the links to other applications and/or the file-attachments in the InfoLog list (normal view when you enter InfoLog).',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> 'all',
|
||||
),
|
||||
'never_hide' => array(
|
||||
'type' => 'check',
|
||||
'label' => 'Never hide search and filters',
|
||||
'name' => 'never_hide',
|
||||
'help' => 'If not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences).',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> '1',
|
||||
),
|
||||
'show_percent' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Show status and percent done separate',
|
||||
'name' => 'show_percent',
|
||||
'values' => $show_details,
|
||||
'help' => 'Should the Infolog list show the percent done only for status ongoing or two separate icons.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> 1, // Yes
|
||||
),
|
||||
'show_id' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Show ticket Id',
|
||||
'name' => 'show_id',
|
||||
'values' => $show_details,
|
||||
'help' => 'Should the Infolog list show a unique numerical Id, which can be used eg. as ticket Id.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> '1', // Yes
|
||||
),
|
||||
'limit_des_lines' => array(
|
||||
'type' => 'input',
|
||||
'size' => 5,
|
||||
'label' => 'Limit number of description lines (default 5, 0 for no limit)',
|
||||
'name' => 'limit_des_lines',
|
||||
'help' => 'How many describtion lines should be directly visible. Further lines are available via a scrollbar.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> 5,
|
||||
),
|
||||
'limit_des_width' => array(
|
||||
'type' => 'input',
|
||||
'size' => 5,
|
||||
'label' => 'Limit width of description column ((effective only if lines limit is set), 0 for no limit)',
|
||||
'name' => 'limit_des_width',
|
||||
'help' => 'How wide should the description area be. This value is numeric and interpreted as em; 60 works reasonably well.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
),
|
||||
'set_start' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Startdate for new entries',
|
||||
'name' => 'set_start',
|
||||
'values' => array(
|
||||
'date' => lang('todays date'),
|
||||
'datetime' => lang('actual date and time'),
|
||||
'empty' => lang('leave it empty'),
|
||||
),
|
||||
'help' => 'To what should the startdate of new entries be set.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> 'date',
|
||||
),
|
||||
'cal_show' => array(
|
||||
'type' => 'multiselect',
|
||||
'label' => 'Which types should the calendar show',
|
||||
'name' => 'cal_show',
|
||||
'values' => $info->enums['type'],
|
||||
'help' => 'Can be used to show further InfoLog types in the calendar or limit it to show eg. only tasks.',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> 'tasks,phone',
|
||||
),
|
||||
'cat_add_default' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'Default category for new Infolog entries',
|
||||
'name' => 'cat_add_default',
|
||||
'values' => self::all_cats(),
|
||||
'help' => 'You can choose a categorie to be preselected, when you create a new Infolog entry',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
// notification preferences
|
||||
$settings['notify_creator'] = array(
|
||||
'type' => 'check',
|
||||
'label' => 'Receive notifications about own items',
|
||||
'name' => 'notify_creator',
|
||||
'help' => 'Do you want a notification, if items you created get updated?',
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> '1', // Yes
|
||||
);
|
||||
$settings['notify_assigned'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about items assigned to you',
|
||||
'name' => 'notify_assigned',
|
||||
'help' => 'Do you want a notification, if items get assigned to you or assigned items get updated?',
|
||||
'values' => array(
|
||||
'0' => lang('No'),
|
||||
'1' => lang('Yes'),
|
||||
'assignment' => lang('Only if I get assigned or removed'),
|
||||
),
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> '1', // Yes
|
||||
);
|
||||
|
||||
// to add options for more then 3 days back or in advance, you need to update soinfolog::users_with_open_entries()!
|
||||
$options = array(
|
||||
'0' => lang('No'),
|
||||
'-1d' => lang('one day after'),
|
||||
'0d' => lang('same day'),
|
||||
'1d' => lang('one day in advance'),
|
||||
'2d' => lang('%1 days in advance',2),
|
||||
'3d' => lang('%1 days in advance',3),
|
||||
);
|
||||
$settings['notify_due_delegated'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about due entries you delegated',
|
||||
'name' => 'notify_due_delegated',
|
||||
'help' => 'Do you want a notification, if items you delegated are due?',
|
||||
'values' => $options,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> '0', // No
|
||||
);
|
||||
$settings['notify_due_responsible'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about due entries you are responsible for',
|
||||
'name' => 'notify_due_responsible',
|
||||
'help' => 'Do you want a notification, if items you are responsible for are due?',
|
||||
'values' => $options,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> '0d', // Same day
|
||||
);
|
||||
$settings['notify_start_delegated'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about starting entries you delegated',
|
||||
'name' => 'notify_start_delegated',
|
||||
'help' => 'Do you want a notification, if items you delegated are about to start?',
|
||||
'values' => $options,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> '0', // No
|
||||
);
|
||||
$settings['notify_start_responsible'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Receive notifications about starting entries you are responsible for',
|
||||
'name' => 'notify_start_responsible',
|
||||
'help' => 'Do you want a notification, if items you are responsible for are about to start?',
|
||||
'values' => $options,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> '0d', // Same day
|
||||
);
|
||||
|
||||
// Merge print
|
||||
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
|
||||
{
|
||||
$link = egw::link('/index.php','menuaction=infolog.infolog_merge.show_replacements');
|
||||
|
||||
$settings['default_document'] = array(
|
||||
'type' => 'input',
|
||||
'size' => 60,
|
||||
'label' => 'Default document to insert entries',
|
||||
'name' => 'default_document',
|
||||
'help' => lang('If you specify a document (full vfs path) here, infolog displays an extra document icon for each entry. That icon allows to download the specified document with the contact data inserted.').' '.
|
||||
lang('The document can contain placeholder like {{info_subject}}, to be replaced with the contact data (%1full list of placeholder names%2).','<a href="'.$link.'" target="_blank">','</a>').' '.
|
||||
lang('At the moment the following document-types are supported:').'*.rtf, *.txt',
|
||||
'run_lang' => false,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
);
|
||||
$settings['document_dir'] = array(
|
||||
'type' => 'input',
|
||||
'size' => 60,
|
||||
'label' => 'Directory with documents to insert entries',
|
||||
'name' => 'document_dir',
|
||||
'help' => lang('If you specify a directory (full vfs path) here, infolog displays an action for each document. That action allows to download the specified document with the infolog data inserted.').' '.
|
||||
lang('The document can contain placeholder like {{info_subject}}, to be replaced with the contact data (%1full list of placeholder names%2).','<a href="'.$link.'" target="_blank">','</a>').' '.
|
||||
lang('At the moment the following document-types are supported:').'*.rtf, *.txt',
|
||||
'run_lang' => false,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
);
|
||||
}
|
||||
|
||||
// Import / Export for nextmatch
|
||||
if ($GLOBALS['egw_info']['user']['apps']['importexport'])
|
||||
{
|
||||
$definitions = new importexport_definitions_bo(array(
|
||||
'type' => 'export',
|
||||
'application' => 'infolog'
|
||||
));
|
||||
$options = array();
|
||||
foreach ((array)$definitions->get_definitions() as $identifier)
|
||||
{
|
||||
try
|
||||
{
|
||||
$definition = new importexport_definition($identifier);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// permission error
|
||||
continue;
|
||||
}
|
||||
if ($title = $definition->get_title())
|
||||
{
|
||||
$options[$title] = $title;
|
||||
}
|
||||
unset($definition);
|
||||
}
|
||||
$default_def = 'export-infolog';
|
||||
$settings['nextmatch-export-definition'] = array(
|
||||
'type' => 'select',
|
||||
'values' => $options,
|
||||
'label' => 'Export definitition to use for nextmatch export',
|
||||
'name' => 'nextmatch-export-definition',
|
||||
'help' => lang('If you specify an export definition, it will be used when you export'),
|
||||
'run_lang' => false,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default'=> isset($options[$default_def]) ? $default_def : false,
|
||||
);
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return InoLog Categories (used for setting )
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function all_cats()
|
||||
{
|
||||
$categories = new categories('','infolog');
|
||||
$accountId = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
foreach((array)$categories->return_sorted_array(0,False,'','','',true) as $cat)
|
||||
{
|
||||
$s = str_repeat(' ',$cat['level']) . stripslashes($cat['name']);
|
||||
|
||||
if ($cat['app_name'] == 'phpgw' || $cat['owner'] == '-1')
|
||||
{
|
||||
$s .= ' ♦';
|
||||
}
|
||||
elseif ($cat['owner'] != $accountId)
|
||||
{
|
||||
$s .= '<' . $GLOBALS['egw']->accounts->id2name($cat['owner'], 'account_fullname') . '>';
|
||||
}
|
||||
elseif ($cat['access'] == 'private')
|
||||
{
|
||||
$s .= ' ♥';
|
||||
}
|
||||
$sel_options[$cat['id']] = $s; // 0.9.14 only
|
||||
}
|
||||
return $sel_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verification hook called if settings / preferences get stored
|
||||
*
|
||||
* Installs a task to send async infolog notifications at 2h everyday
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
static function verify_settings($data)
|
||||
{
|
||||
if ($data['prefs']['notify_due_delegated'] || $data['prefs']['notify_due_responsible'] ||
|
||||
$data['prefs']['notify_start_delegated'] || $data['prefs']['notify_start_responsible'])
|
||||
{
|
||||
$async = new asyncservice();
|
||||
|
||||
if (!$async->read('infolog-async-notification'))
|
||||
{
|
||||
$async->set_timer(array('hour' => 2),'infolog-async-notification','infolog.infolog_bo.async_notification',null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* InfoLog - iCalendar Parser
|
||||
* EGroupware - InfoLog - iCalendar Parser
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke <lkneschke@egroupware.org>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @author Ralf Becker <RalfBecker@outdoor-training.de>
|
||||
* @package infolog
|
||||
* @subpackage syncml
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
@ -15,7 +16,6 @@ require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
||||
|
||||
/**
|
||||
* InfoLog: Create and parse iCal's
|
||||
*
|
||||
*/
|
||||
class infolog_ical extends infolog_bo
|
||||
{
|
||||
@ -157,8 +157,8 @@ class infolog_ical extends infolog_bo
|
||||
$taskData['info_cat'] = $cats[0];
|
||||
}
|
||||
|
||||
$taskData = $GLOBALS['egw']->translation->convert($taskData,
|
||||
$GLOBALS['egw']->translation->charset(), $charset);
|
||||
$taskData = translation::convert($taskData,
|
||||
translation::charset(), $charset);
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
@ -167,39 +167,25 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
|
||||
$vcal = new Horde_iCalendar;
|
||||
$vcal->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware InfoLog '.$GLOBALS['egw_info']['apps']['infolog']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
$vcal->setAttribute('VERSION',$_version);
|
||||
$vcal->setAttribute('METHOD',$_method);
|
||||
if ($_method) $vcal->setAttribute('METHOD',$_method);
|
||||
|
||||
$tzid = $this->tzid;
|
||||
if ($tzid && $tzid != 'UTC')
|
||||
{
|
||||
// check if we have vtimezone component data for tzid of event, if not default to user timezone (default to server tz)
|
||||
if (!($vtimezone = calendar_timezones::tz2id($tzid,'component')))
|
||||
if (!calendar_timezones::add_vtimezone($vcal, $tzid))
|
||||
{
|
||||
error_log(__METHOD__."() unknown TZID='$tzid', defaulting to user timezone '".egw_time::$user_timezone->getName()."'!");
|
||||
$vtimezone = calendar_timezones::tz2id($tzid=egw_time::$user_timezone->getName(),'component');
|
||||
calendar_timezones::add_vtimezone($vcal, $tzid=egw_time::$user_timezone->getName());
|
||||
$tzid = null;
|
||||
}
|
||||
if (!isset(self::$tz_cache[$tzid]))
|
||||
{
|
||||
self::$tz_cache[$tzid] = calendar_timezones::DateTimeZone($tzid);
|
||||
}
|
||||
// $vtimezone is a string with a single VTIMEZONE component, afaik Horde_iCalendar can not add it directly
|
||||
// --> we have to parse it and let Horde_iCalendar add it again
|
||||
$horde_vtimezone = Horde_iCalendar::newComponent('VTIMEZONE',$container=false);
|
||||
$horde_vtimezone->parsevCalendar($vtimezone,'VTIMEZONE');
|
||||
// DTSTART must be in local time!
|
||||
$standard = $horde_vtimezone->findComponent('STANDARD');
|
||||
$dtstart = $standard->getAttribute('DTSTART');
|
||||
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
|
||||
$dtstart->setTimezone(self::$tz_cache[$tzid]);
|
||||
$standard->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
|
||||
$daylight = $horde_vtimezone->findComponent('DAYLIGHT');
|
||||
$dtstart = $daylight->getAttribute('DTSTART');
|
||||
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
|
||||
$dtstart->setTimezone(self::$tz_cache[$tzid]);
|
||||
$daylight->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
|
||||
$vcal->addComponent($horde_vtimezone);
|
||||
}
|
||||
|
||||
$vevent = Horde_iCalendar::newComponent('VTODO',$vcal);
|
||||
@ -212,13 +198,13 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
// set fields that may contain non-ascii chars and encode them if necessary
|
||||
foreach (array(
|
||||
'SUMMARY' => $taskData['info_subject'],
|
||||
'DESCRIPTION' => $taskData['info_des'],
|
||||
'LOCATION' => $taskData['info_location'],
|
||||
'RELATED-TO' => $taskData['info_id_parent'],
|
||||
'UID' => $taskData['info_uid'],
|
||||
'CATEGORIES' => $taskData['info_cat'],
|
||||
) as $field => $value)
|
||||
'SUMMARY' => $taskData['info_subject'],
|
||||
'DESCRIPTION' => $taskData['info_des'],
|
||||
'LOCATION' => $taskData['info_location'],
|
||||
'RELATED-TO' => $taskData['info_id_parent'],
|
||||
'UID' => $taskData['info_uid'],
|
||||
'CATEGORIES' => $taskData['info_cat'],
|
||||
) as $field => $value)
|
||||
{
|
||||
if (isset($this->clientProperties[$field]['Size']))
|
||||
{
|
||||
@ -319,7 +305,8 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
|
||||
$vevent->setAttribute('DTSTAMP',time());
|
||||
$vevent->setAttribute('CREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$taskData['info_id'],'add'));
|
||||
$vevent->setAttribute('CREATED', $taskData['info_created'] ? $taskData['info_created'] :
|
||||
$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$taskData['info_id'],'add'));
|
||||
$vevent->setAttribute('LAST-MODIFIED', $taskData['info_datemodified'] ? $taskData['info_datemodified'] :
|
||||
$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$taskData['info_id'],'modify'));
|
||||
$vevent->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE');
|
||||
@ -339,6 +326,34 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
$vevent->setAttribute('PRIORITY', $priority);
|
||||
|
||||
// for CalDAV add all X-Properties previously parsed
|
||||
if ($this->productManufacturer == 'groupdav')
|
||||
{
|
||||
foreach($taskData as $name => $value)
|
||||
{
|
||||
if (substr($name, 0, 2) == '##')
|
||||
{
|
||||
if ($name[2] == ':')
|
||||
{
|
||||
if ($value[1] == ':' && ($v = unserialize($value)) !== false) $value = $v;
|
||||
foreach((array)$value as $compvData)
|
||||
{
|
||||
$comp = Horde_iCalendar::newComponent(substr($name,3), $vevent);
|
||||
$comp->parsevCalendar($compvData,substr($name,3),'utf-8');
|
||||
$vevent->addComponent($comp);
|
||||
}
|
||||
}
|
||||
elseif ($value[1] == ':' && ($attr = unserialize($value)) !== false)
|
||||
{
|
||||
$vevent->setAttribute(substr($name, 2), $attr['value'], $attr['params'], true, $attr['values']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$vevent->setAttribute(substr($name, 2), $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$vcal->addComponent($vevent);
|
||||
|
||||
$retval = $vcal->exportvCalendar();
|
||||
@ -426,12 +441,12 @@ class infolog_ical extends infolog_bo
|
||||
* @param int $_taskID=-1 info_id, default -1 = new entry
|
||||
* @param boolean $merge=false merge data with existing entry
|
||||
* @param int $user=null delegate new task to this account_id, default null
|
||||
* @param string $charset The encoding charset for $text. Defaults to
|
||||
* @param string $charset=null The encoding charset for $text. Defaults to
|
||||
* utf-8 for new format, iso-8859-1 for old format.
|
||||
*
|
||||
* @param string $caldav_name=null CalDAV URL name-part for new entries
|
||||
* @return int|boolean integer info_id or false on error
|
||||
*/
|
||||
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false, $user=null, $charset=null)
|
||||
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false, $user=null, $charset=null, $caldav_name=null)
|
||||
{
|
||||
|
||||
if ($this->tzid)
|
||||
@ -449,20 +464,21 @@ class infolog_ical extends infolog_bo
|
||||
// keep the dates
|
||||
$this->time2time($taskData, $this->tzid, false);
|
||||
|
||||
// we suppose that a not set status in a vtodo means that the task did not started yet
|
||||
if (empty($taskData['info_status']))
|
||||
{
|
||||
$taskData['info_status'] = 'not-started';
|
||||
}
|
||||
|
||||
if (empty($taskData['info_datecompleted']))
|
||||
{
|
||||
$taskData['info_datecompleted'] = 0;
|
||||
}
|
||||
|
||||
if (!is_null($user))
|
||||
if (!is_null($user) && $_taskID)
|
||||
{
|
||||
$taskData['info_owner'] = $user;
|
||||
if ($this->check_access($taskData, EGW_ACL_ADD))
|
||||
{
|
||||
$taskData['info_owner'] = $user;
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData['info_responsible'][] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->log)
|
||||
@ -471,7 +487,11 @@ class infolog_ical extends infolog_bo
|
||||
array2string($taskData)."\n",3,$this->logfile);
|
||||
}
|
||||
|
||||
return $this->write($taskData, true, true, false);
|
||||
if ($caldav_name)
|
||||
{
|
||||
$taskData['caldav_name'] = $caldav_name;
|
||||
}
|
||||
return $this->write($taskData, true, true, false, false, false, 'ical');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -564,13 +584,39 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
|
||||
$taskData = array();
|
||||
$taskData['info_type'] = 'task';
|
||||
|
||||
if ($_taskID > 0)
|
||||
{
|
||||
$taskData['info_id'] = $_taskID;
|
||||
}
|
||||
foreach ($component->_attributes as $attribute)
|
||||
// iOS reminder app only sets COMPLETED, but never STATUS nor PERCENT-COMPLETED
|
||||
// if we have no STATUS, set STATUS by existence of COMPLETED and/or PERCENT-COMPLETE and X-INFOLOG-STATUS
|
||||
// if we have no PERCENT-COMPLETE set it from STATUS: 0=NEEDS-ACTION, 10=IN-PROCESS, 100=COMPLETED
|
||||
if (!($status = $component->getAttribute('STATUS')) || !is_scalar($status))
|
||||
{
|
||||
$completed = $component->getAttribute('COMPLETED');
|
||||
$x_infolog_status = $component->getAttribute('X-INFOLOG-STATUS');
|
||||
// check if we have a X-INFOLOG-STATUS and it's completed state is different from given COMPLETED attr
|
||||
if (is_scalar($x_infolog_status) &&
|
||||
($this->_status2vtodo[$x_infolog_status] === 'COMPLETED') != is_scalar($completed))
|
||||
{
|
||||
$percent_completed = $component->getAttribute('PERCENT-COMPLETE');
|
||||
$status = $completed && is_scalar($completed) ? 'COMPLETED' :
|
||||
($percent_completed && is_scalar($percent_completed) && $percent_completed > 0 ? 'IN-PROCESS' : 'NEEDS-ACTION');
|
||||
$component->setAttribute('STATUS', $status);
|
||||
if (!is_scalar($percent_completed))
|
||||
{
|
||||
$component->setAttribute('PERCENT-COMPLETE', $percent_completed = $status == 'COMPLETED' ?
|
||||
100 : ($status == 'NEEDS-ACTION' ? 0 : 10));
|
||||
}
|
||||
if ($this->log) error_log(__METHOD__."() setting STATUS='$status' and PERCENT-COMPLETE=$percent_completed from COMPLETED and X-INFOLOG-STATUS='$x_infolog_status'\n",3,$this->logfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->log) error_log(__METHOD__."() no STATUS, X-INFOLOG-STATUS='$x_infolog_status', COMPLETED".(is_scalar($completed)?'='.$completed:' not set')." --> leaving status and percent unchanged",3,$this->logfile);
|
||||
}
|
||||
}
|
||||
foreach ($component->getAllAttributes() as $attribute)
|
||||
{
|
||||
//$attribute['value'] = trim($attribute['value']);
|
||||
if (!strlen($attribute['value'])) continue;
|
||||
@ -608,11 +654,18 @@ class infolog_ical extends infolog_bo
|
||||
$taskData['info_location'] = str_replace("\r\n", "\n", $attribute['value']);
|
||||
break;
|
||||
|
||||
case 'DURATION':
|
||||
if (!isset($taskData['info_startdate']))
|
||||
{
|
||||
$taskData['info_startdate'] = $component->getAttribute('DTSTART');
|
||||
}
|
||||
$attribute['value'] += $taskData['info_startdate'];
|
||||
$taskData['##DURATION'] = $attribute['value'];
|
||||
// fall throught
|
||||
case 'DUE':
|
||||
// eGroupWare uses date only
|
||||
$parts = @getdate($attribute['value']);
|
||||
$value = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
||||
$taskData['info_enddate'] = $value;
|
||||
// even as EGroupware only displays the date, we can still store the full value
|
||||
// unless infolog get's stored, it does NOT truncate the time
|
||||
$taskData['info_enddate'] = $attribute['value'];
|
||||
break;
|
||||
|
||||
case 'COMPLETED':
|
||||
@ -643,14 +696,12 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
break;
|
||||
|
||||
case 'X-INFOLOG-STATUS':
|
||||
break;
|
||||
case 'STATUS':
|
||||
// check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user)
|
||||
foreach ($component->_attributes as $attr)
|
||||
{
|
||||
if ($attr['name'] == 'X-INFOLOG-STATUS') break;
|
||||
}
|
||||
$taskData['info_status'] = $this->vtodo2status($attribute['value'],
|
||||
$attr['name'] == 'X-INFOLOG-STATUS' ? $attr['value'] : null);
|
||||
($attr=$component->getAttribute('X-INFOLOG-STATUS')) && is_scalar($attr) ? $attr : null);
|
||||
break;
|
||||
|
||||
case 'SUMMARY':
|
||||
@ -679,10 +730,47 @@ class infolog_ical extends infolog_bo
|
||||
case 'PERCENT-COMPLETE':
|
||||
$taskData['info_percent'] = (int) $attribute['value'];
|
||||
break;
|
||||
|
||||
// ignore all PROPS, we dont want to store like X-properties or unsupported props
|
||||
case 'DTSTAMP':
|
||||
case 'SEQUENCE':
|
||||
case 'CREATED':
|
||||
case 'LAST-MODIFIED':
|
||||
//case 'ATTENDEE': // todo: add real support for it
|
||||
break;
|
||||
|
||||
default: // X- attribute or other by EGroupware unsupported property
|
||||
//error_log(__METHOD__."() $attribute[name] = ".array2string($attribute));
|
||||
// for attributes with multiple values in multiple lines, merge the values
|
||||
if (isset($taskData['##'.$attribute['name']]))
|
||||
{
|
||||
//error_log(__METHOD__."() taskData['##$attribute[name]'] = ".array2string($taskData['##'.$attribute['name']]));
|
||||
$attribute['values'] = array_merge(
|
||||
is_array($taskData['##'.$attribute['name']]) ? $taskData['##'.$attribute['name']]['values'] : (array)$taskData['##'.$attribute['name']],
|
||||
$attribute['values']);
|
||||
}
|
||||
$taskData['##'.$attribute['name']] = $attribute['params'] || count($attribute['values']) > 1 ?
|
||||
serialize($attribute) : $attribute['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// store included, but unsupported components like valarm as x-properties
|
||||
foreach($component->getComponents() as $comp)
|
||||
{
|
||||
$name = '##:'.strtoupper($comp->getType());
|
||||
$compvData = $comp->exportvCalendar($comp,'utf-8');
|
||||
if (isset($taskData[$name]))
|
||||
{
|
||||
$taskData[$name] = array($taskData[$name]);
|
||||
$taskData[$name][] = $compvData;
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData[$name] = $compvData;
|
||||
}
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_taskID)\n" .
|
||||
@ -704,8 +792,8 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
if(!($note = $this->read($_noteID, true, 'server'))) return false;
|
||||
|
||||
$note = $GLOBALS['egw']->translation->convert($note,
|
||||
$GLOBALS['egw']->translation->charset(), $charset);
|
||||
$note = translation::convert($note,
|
||||
translation::charset(), $charset);
|
||||
|
||||
switch ($_type)
|
||||
{
|
||||
@ -717,11 +805,13 @@ class infolog_ical extends infolog_bo
|
||||
if (!empty($note['info_cat']))
|
||||
{
|
||||
$cats = $this->get_categories(array($note['info_cat']));
|
||||
$note['info_cat'] = $GLOBALS['egw']->translation->convert($cats[0],
|
||||
$GLOBALS['egw']->translation->charset(), $charset);
|
||||
$note['info_cat'] = translation::convert($cats[0],
|
||||
translation::charset(), $charset);
|
||||
}
|
||||
$vnote = new Horde_iCalendar_vnote();
|
||||
$vNote->setAttribute('VERSION', '1.1');
|
||||
$vnote->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware InfoLog '.$GLOBALS['egw_info']['apps']['infolog']['version'].'//'.
|
||||
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
|
||||
$vnote->setAttribute('VERSION', '1.1');
|
||||
foreach (array( 'SUMMARY' => $note['info_subject'],
|
||||
'BODY' => $note['info_des'],
|
||||
'CATEGORIES' => $note['info_cat'],
|
||||
@ -863,7 +953,7 @@ class infolog_ical extends infolog_bo
|
||||
case 'text/plain':
|
||||
$note = array();
|
||||
$note['info_type'] = 'note';
|
||||
$txt = $GLOBALS['egw']->translation->convert($_data, $charset);
|
||||
$txt = translation::convert($_data, $charset);
|
||||
$txt = str_replace("\r\n", "\n", $txt);
|
||||
|
||||
if (preg_match('/([^\n]+)\n\n(.*)/ms', $txt, $match))
|
||||
|
455
infolog/inc/class.infolog_import_infologs_csv.inc.php
Normal file
455
infolog/inc/class.infolog_import_infologs_csv.inc.php
Normal file
@ -0,0 +1,455 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package importexport
|
||||
* @link http://www.egroupware.org
|
||||
* @author Cornelius Weiss <nelius@cwtech.de>
|
||||
* @copyright Cornelius Weiss <nelius@cwtech.de>
|
||||
* @version $Id: $
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* class import_csv for infolog
|
||||
*/
|
||||
class infolog_import_infologs_csv implements importexport_iface_import_plugin {
|
||||
|
||||
private static $plugin_options = array(
|
||||
'fieldsep', // char
|
||||
'charset', // string
|
||||
'contact_owner', // int
|
||||
'update_cats', // string {override|add} overides record
|
||||
// with cat(s) from csv OR add the cat from
|
||||
// csv file to exeisting cat(s) of record
|
||||
'num_header_lines', // int number of header lines
|
||||
'field_conversion', // array( $csv_col_num => conversion)
|
||||
'field_mapping', // array( $csv_col_num => adb_filed)
|
||||
'conditions', /* => array containing condition arrays:
|
||||
'type' => exists, // exists
|
||||
'string' => '#kundennummer',
|
||||
'true' => array(
|
||||
'action' => update,
|
||||
'last' => true,
|
||||
),
|
||||
'false' => array(
|
||||
'action' => insert,
|
||||
'last' => true,
|
||||
),*/
|
||||
|
||||
);
|
||||
|
||||
public static $special_fields = array(
|
||||
'projectmanager' => 'Link to Projectmanager, use Project-ID, Title or @project_id(id_or_title)',
|
||||
'addressbook' => 'Link to Addressbook, use nlast,nfirst[,org] or contact_id from addressbook',
|
||||
'link_1' => '1. link: appname:appid the entry should be linked to, eg.: addressbook:123',
|
||||
'link_2' => '2. link: appname:appid the entry should be linked to, eg.: addressbook:123',
|
||||
'link_3' => '3. link: appname:appid the entry should be linked to, eg.: addressbook:123',
|
||||
);
|
||||
|
||||
/**
|
||||
* actions wich could be done to data entries
|
||||
*/
|
||||
protected static $actions = array( 'none', 'update', 'insert', 'delete', );
|
||||
|
||||
/**
|
||||
* conditions for actions
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $conditions = array( 'exists' );
|
||||
|
||||
/**
|
||||
* @var definition
|
||||
*/
|
||||
private $definition;
|
||||
|
||||
/**
|
||||
* @var business object
|
||||
*/
|
||||
private $boinfolog;
|
||||
|
||||
/**
|
||||
* For figuring out if a record has changed
|
||||
*/
|
||||
protected $tracking;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $dry_run = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $user = null;
|
||||
|
||||
/**
|
||||
* List of import errors
|
||||
*/
|
||||
protected $errors = array();
|
||||
|
||||
/**
|
||||
* List of actions, and how many times that action was taken
|
||||
*/
|
||||
protected $results = array();
|
||||
|
||||
/**
|
||||
* imports entries according to given definition object.
|
||||
* @param resource $_stream
|
||||
* @param string $_charset
|
||||
* @param definition $_definition
|
||||
*/
|
||||
public function import( $_stream, importexport_definition $_definition ) {
|
||||
$import_csv = new importexport_import_csv( $_stream, array(
|
||||
'fieldsep' => $_definition->plugin_options['fieldsep'],
|
||||
'charset' => $_definition->plugin_options['charset'],
|
||||
));
|
||||
|
||||
$this->definition = $_definition;
|
||||
|
||||
$this->user = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
// dry run?
|
||||
$this->dry_run = isset( $_definition->plugin_options['dry_run'] ) ? $_definition->plugin_options['dry_run'] : false;
|
||||
|
||||
// fetch the infolog bo
|
||||
$this->boinfolog = new infolog_bo();
|
||||
|
||||
// Get the tracker for changes
|
||||
$this->tracking = new infolog_tracking($this->boinfolog);
|
||||
|
||||
// set FieldMapping.
|
||||
$import_csv->mapping = $_definition->plugin_options['field_mapping'];
|
||||
|
||||
// set FieldConversion
|
||||
$import_csv->conversion = $_definition->plugin_options['field_conversion'];
|
||||
|
||||
// Add extra conversions
|
||||
$import_csv->conversion_class = $this;
|
||||
|
||||
//check if file has a header lines
|
||||
if ( isset( $_definition->plugin_options['num_header_lines'] ) && $_definition->plugin_options['num_header_lines'] > 0) {
|
||||
$import_csv->skip_records($_definition->plugin_options['num_header_lines']);
|
||||
} elseif(isset($_definition->plugin_options['has_header_line']) && $_definition->plugin_options['has_header_line']) {
|
||||
// First method is preferred
|
||||
$import_csv->skip_records(1);
|
||||
}
|
||||
|
||||
// set Owner
|
||||
$_definition->plugin_options['record_owner'] = $_definition->plugin_options['record_owner'] ?
|
||||
$_definition->plugin_options['record_owner'] : $this->user;
|
||||
$_definition->plugin_options['record_owner'] = $this->user;
|
||||
|
||||
$_lookups = array(
|
||||
'info_type' => $this->boinfolog->enums['types'],
|
||||
'info_status' => $this->boinfolog->status['task']
|
||||
);
|
||||
|
||||
// Start counting successes
|
||||
$count = 0;
|
||||
$this->results = array();
|
||||
|
||||
// Failures
|
||||
$this->errors = array();
|
||||
|
||||
while ( $record = $import_csv->get_record() ) {
|
||||
$success = false;
|
||||
|
||||
// don't import empty records
|
||||
if( count( array_unique( $record ) ) < 2 ) continue;
|
||||
|
||||
$lookups = $_lookups;
|
||||
if($record['info_type'] && $this->boinfolog->status[$record['info_type']]) {
|
||||
$lookups['info_status'] = $this->boinfolog->status[$record['info_type']];
|
||||
}
|
||||
|
||||
importexport_import_csv::convert($record, infolog_egw_record::$types, 'infolog', $lookups);
|
||||
|
||||
// Set owner, unless it's supposed to come from CSV file
|
||||
if($_definition->plugin_options['owner_from_csv']) {
|
||||
if(!is_numeric($record['info_owner'])) {
|
||||
$this->errors[$import_csv->get_current_position()] = lang(
|
||||
'Invalid owner ID: %1. Might be a bad field translation. Used %2 instead.',
|
||||
$record['info_owner'],
|
||||
$_definition->plugin_options['record_owner']
|
||||
);
|
||||
$record['info_owner'] = $_definition->plugin_options['record_owner'];
|
||||
}
|
||||
} else {
|
||||
$record['info_owner'] = $_definition->plugin_options['record_owner'];
|
||||
}
|
||||
|
||||
// Special values
|
||||
if ($record['addressbook'] && !is_numeric($record['addressbook']))
|
||||
{
|
||||
list($lastname,$firstname,$org_name) = explode(',',$record['addressbook']);
|
||||
$record['addressbook'] = self::addr_id($lastname,$firstname,$org_name);
|
||||
}
|
||||
if ($record['projectmanager'] && !is_numeric($record['projectmanager']))
|
||||
{
|
||||
$record['projectmanager'] = self::project_id($record['projectmanager']);
|
||||
}
|
||||
|
||||
if ( $_definition->plugin_options['conditions'] ) {
|
||||
foreach ( $_definition->plugin_options['conditions'] as $condition ) {
|
||||
$results = array();
|
||||
switch ( $condition['type'] ) {
|
||||
// exists
|
||||
case 'exists' :
|
||||
if($record[$condition['string']]) {
|
||||
$query['col_filter'] = array( $condition['string'] => $record[$condition['string']],);
|
||||
$results = $this->boinfolog->search($query);
|
||||
}
|
||||
|
||||
if ( is_array( $results ) && count( array_keys( $results )) >= 1) {
|
||||
// apply action to all records matching this exists condition
|
||||
$action = $condition['true'];
|
||||
foreach ( (array)$results as $contact ) {
|
||||
$record['id'] = $contact['id'];
|
||||
if ( $_definition->plugin_options['update_cats'] == 'add' ) {
|
||||
if ( !is_array( $contact['cat_id'] ) ) $contact['cat_id'] = explode( ',', $contact['cat_id'] );
|
||||
if ( !is_array( $record['cat_id'] ) ) $record['cat_id'] = explode( ',', $record['cat_id'] );
|
||||
$record['cat_id'] = implode( ',', array_unique( array_merge( $record['cat_id'], $contact['cat_id'] ) ) );
|
||||
}
|
||||
$success = $this->action( $action['action'], $record, $import_csv->get_current_position() );
|
||||
}
|
||||
} else {
|
||||
$action = $condition['false'];
|
||||
$success = ($this->action( $action['action'], $record, $import_csv->get_current_position() ));
|
||||
}
|
||||
break;
|
||||
|
||||
// not supported action
|
||||
default :
|
||||
die('condition / action not supported!!!');
|
||||
break;
|
||||
}
|
||||
if ($action['last']) break;
|
||||
}
|
||||
} else {
|
||||
// unconditional insert
|
||||
$success = $this->action( 'insert', $record, $import_csv->get_current_position() );
|
||||
}
|
||||
if($success) $count++;
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* perform the required action
|
||||
*
|
||||
* @param int $_action one of $this->actions
|
||||
* @param array $_data contact data for the action
|
||||
* @return bool success or not
|
||||
*/
|
||||
private function action ( $_action, $_data, $record_num = 0 ) {
|
||||
$result = true;
|
||||
switch ($_action) {
|
||||
case 'none' :
|
||||
return true;
|
||||
case 'update' :
|
||||
// Only update if there are changes
|
||||
$old = $this->boinfolog->read($_data['info_id']);
|
||||
|
||||
if(!$this->definition->plugin_options['change_owner']) {
|
||||
// Don't change addressbook of an existing contact
|
||||
unset($_data['owner']);
|
||||
}
|
||||
|
||||
// Merge to deal with fields not in import record
|
||||
$_data = array_merge($old, $_data);
|
||||
$changed = $this->tracking->changed_fields($_data, $old);
|
||||
if(count($changed) == 0 && !$this->definition->plugin_options['update_timestamp']) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Fall through
|
||||
case 'insert' :
|
||||
if ( $this->dry_run ) {
|
||||
//print_r($_data);
|
||||
$this->results[$_action]++;
|
||||
break;
|
||||
} else {
|
||||
$result = $this->boinfolog->write( $_data, true, true);
|
||||
if(!$result) {
|
||||
$this->errors[$record_num] = lang('Permissions error - %1 could not %2',
|
||||
$GLOBALS['egw']->accounts->id2name($_data['info_owner']),
|
||||
lang($_action)
|
||||
);
|
||||
} else {
|
||||
$this->results[$_action]++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new egw_exception('Unsupported action');
|
||||
}
|
||||
|
||||
// Process some additional fields
|
||||
if(!is_numeric($result)) {
|
||||
return $result;
|
||||
}
|
||||
$info_link_id = false;
|
||||
foreach(self::$special_fields as $field => $desc) {
|
||||
if(!$_data[$field]) continue;
|
||||
if(strpos('link', $field) === 0) {
|
||||
list($app, $id) = explode(':', $_data[$field]);
|
||||
} else {
|
||||
$app = $field;
|
||||
$id = $_data[$field];
|
||||
}
|
||||
if ($app && $app_id) {
|
||||
//echo "<p>linking infolog:$id with $app:$app_id</p>\n";
|
||||
$link_id = egw_link::link('infolog',$id,$app,$app_id);
|
||||
if ($link_id && !$info_link_id)
|
||||
{
|
||||
$to_write = array(
|
||||
'info_id' => $id,
|
||||
'info_link_id' => $link_id,
|
||||
);
|
||||
$infolog_bo->write($to_write);
|
||||
$info_link_id = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns translated name of plugin
|
||||
*
|
||||
* @return string name
|
||||
*/
|
||||
public static function get_name() {
|
||||
return lang('Infolog CSV import');
|
||||
}
|
||||
|
||||
/**
|
||||
* returns translated (user) description of plugin
|
||||
*
|
||||
* @return string descriprion
|
||||
*/
|
||||
public static function get_description() {
|
||||
return lang("Imports entries into the infolog from a CSV File. CSV means 'Comma Seperated Values'. However in the options Tab you can also choose other seperators.");
|
||||
}
|
||||
|
||||
/**
|
||||
* retruns file suffix(s) plugin can handle (e.g. csv)
|
||||
*
|
||||
* @return string suffix (comma seperated)
|
||||
*/
|
||||
public static function get_filesuffix() {
|
||||
return 'csv';
|
||||
}
|
||||
|
||||
/**
|
||||
* return etemplate components for options.
|
||||
* @abstract We can't deal with etemplate objects here, as an uietemplate
|
||||
* objects itself are scipt orientated and not "dialog objects"
|
||||
*
|
||||
* @return array (
|
||||
* name => string,
|
||||
* content => array,
|
||||
* sel_options => array,
|
||||
* preserv => array,
|
||||
* )
|
||||
*/
|
||||
public function get_options_etpl() {
|
||||
// lets do it!
|
||||
}
|
||||
|
||||
/**
|
||||
* returns etemplate name for slectors of this plugin
|
||||
*
|
||||
* @return string etemplate name
|
||||
*/
|
||||
public function get_selectors_etpl() {
|
||||
// lets do it!
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns errors that were encountered during importing
|
||||
* Maximum of one error message per record, but you can append if you need to
|
||||
*
|
||||
* @return Array (
|
||||
* record_# => error message
|
||||
* )
|
||||
*/
|
||||
public function get_errors() {
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of actions taken, and the number of records for that action.
|
||||
* Actions are things like 'insert', 'update', 'delete', and may be different for each plugin.
|
||||
*
|
||||
* @return Array (
|
||||
* action => record count
|
||||
* )
|
||||
*/
|
||||
public function get_results() {
|
||||
return $this->results;
|
||||
}
|
||||
// end of iface_export_plugin
|
||||
|
||||
// Extra conversion functions - must be static
|
||||
public static function addr_id( $n_family,$n_given=null,$org_name=null ) {
|
||||
|
||||
// find in Addressbook, at least n_family AND (n_given OR org_name) have to match
|
||||
static $contacts;
|
||||
if (is_null($n_given) && is_null($org_name))
|
||||
{
|
||||
// Maybe all in one
|
||||
list($n_family, $n_given, $org_name) = explode(',', $n_family);
|
||||
}
|
||||
$n_family = trim($n_family);
|
||||
if(!is_null($n_given)) $n_given = trim($n_given);
|
||||
if (!is_object($contacts))
|
||||
{
|
||||
$contacts =& CreateObject('phpgwapi.contacts');
|
||||
}
|
||||
if (!is_null($org_name)) // org_name given?
|
||||
{
|
||||
$org_name = trim($org_name);
|
||||
$addrs = $contacts->read( 0,0,array('id'),'',"n_family=$n_family,n_given=$n_given,org_name=$org_name" );
|
||||
if (!count($addrs))
|
||||
{
|
||||
$addrs = $contacts->read( 0,0,array('id'),'',"n_family=$n_family,org_name=$org_name",'','n_family,org_name');
|
||||
}
|
||||
}
|
||||
if (!is_null($n_given) && (is_null($org_name) || !count($addrs))) // first name given and no result so far
|
||||
{
|
||||
$addrs = $contacts->search(array('n_family' => $n_family, 'n_given' => $n_given));
|
||||
}
|
||||
if (is_null($n_given) && is_null($org_name)) // just one name given, check against fn (= full name)
|
||||
{
|
||||
$addrs = $contacts->read( 0,0,array('id'),'',"n_fn=$n_family",'','n_fn' );
|
||||
}
|
||||
if (count($addrs))
|
||||
{
|
||||
return $addrs[0]['id'];
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
public static function project_id($num_or_title)
|
||||
{
|
||||
static $boprojects;
|
||||
|
||||
if (!$num_or_title) return false;
|
||||
|
||||
if (!is_object($boprojects))
|
||||
{
|
||||
$boprojects =& CreateObject('projectmanager.boprojectmanager');
|
||||
}
|
||||
if (($projects = $boprojects->search(array('pm_number' => $num_or_title))) ||
|
||||
($projects = $boprojects->search(array('pm_title' => $num_or_title))))
|
||||
{
|
||||
return $projects[0]['pm_id'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
?>
|
192
infolog/inc/class.infolog_merge.inc.php
Normal file
192
infolog/inc/class.infolog_merge.inc.php
Normal file
@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/**
|
||||
* Infolog - document merge
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Nathan Gray
|
||||
* @package infolog
|
||||
* @copyright (c) 2007-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright 2011 Nathan Gray
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* Infolog - document merge object
|
||||
*/
|
||||
class infolog_merge extends bo_merge
|
||||
{
|
||||
/**
|
||||
* Functions that can be called via menuaction
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $public_functions = array(
|
||||
'show_replacements' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Business object to pull records from
|
||||
*/
|
||||
protected $bo = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->bo = new infolog_bo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get infolog replacements
|
||||
*
|
||||
* @param int $id id of entry
|
||||
* @param string &$content=null content to create some replacements only if they are use
|
||||
* @return array|boolean
|
||||
*/
|
||||
protected function get_replacements($id,&$content=null)
|
||||
{
|
||||
if (!($replacements = $this->infolog_replacements($id)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!(strpos($content,'$$info_contact/') === false))
|
||||
{
|
||||
// Check to see if it's actually a contact, then load
|
||||
if(is_array($replacements['$$info_link$$']) && $replacements['$$info_link$$']['app'] == 'addressbook')
|
||||
{
|
||||
$replacements += $this->contact_replacements($replacements['$$info_link$$']['id'],'info_contact');
|
||||
}
|
||||
if(is_array($replacements['$$info_link$$'])) unset($replacements['$$info_link$$']);
|
||||
}
|
||||
return $replacements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get infolog replacements
|
||||
*
|
||||
* @param int $id id of entry
|
||||
* @param string $prefix='' prefix like eg. 'erole'
|
||||
* @return array|boolean
|
||||
*/
|
||||
public function infolog_replacements($id,$prefix='')
|
||||
{
|
||||
$record = new infolog_egw_record($id);
|
||||
$info = array();
|
||||
|
||||
// Convert to human friendly values
|
||||
$types = infolog_egw_record::$types;
|
||||
$_selects = $this->bo->enums + array('status' => $this->bo->status[$record->info_type]);
|
||||
foreach($_selects as $name => $value)
|
||||
{
|
||||
$selects['info_'.$name] = $value;
|
||||
$types['select'][] = 'info_'.$name;
|
||||
}
|
||||
importexport_export_csv::convert($record, $types, 'infolog', $selects);
|
||||
if($record->info_contact)
|
||||
{
|
||||
$array['info_contact'] = $array['info_link']['title'];
|
||||
}
|
||||
// Set any missing custom fields, or the marker will stay
|
||||
$array = $record->get_record_array();
|
||||
foreach($this->bo->customfields as $name => $field)
|
||||
{
|
||||
if(!$array['#'.$name]) $array['#'.$name] = '';
|
||||
}
|
||||
|
||||
// Add markers
|
||||
foreach($array as $key => &$value)
|
||||
{
|
||||
if(!$value) $value = '';
|
||||
$info['$$'.($prefix ? $prefix.'/':'').$key.'$$'] = $value;
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate table with replacements for the preferences
|
||||
*
|
||||
*/
|
||||
public function show_replacements()
|
||||
{
|
||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('infolog').' - '.lang('Replacements for inserting entries into documents');
|
||||
$GLOBALS['egw_info']['flags']['nonavbar'] = false;
|
||||
common::egw_header();
|
||||
|
||||
echo "<table width='90%' align='center'>\n";
|
||||
echo '<tr><td colspan="4"><h3>'.lang('Infolog fields:')."</h3></td></tr>";
|
||||
|
||||
$n = 0;
|
||||
$tracking = new infolog_tracking($this->bo);
|
||||
$fields = array('info_id' => lang('Infolog ID')) + $tracking->field2label;
|
||||
foreach($fields as $name => $label)
|
||||
{
|
||||
if (in_array($name,array('custom'))) continue; // dont show them
|
||||
|
||||
if (in_array($name,array('info_subject', 'info_des')) && $n&1) // main values, which should be in the first column
|
||||
{
|
||||
echo "</tr>\n";
|
||||
$n++;
|
||||
}
|
||||
if (!($n&1)) echo '<tr>';
|
||||
echo '<td>{{'.$name.'}}</td><td>'.$label.'</td>';
|
||||
if ($n&1) echo "</tr>\n";
|
||||
$n++;
|
||||
}
|
||||
|
||||
echo '<tr><td colspan="4"><h3>'.lang('Custom fields').":</h3></td></tr>";
|
||||
foreach($this->bo->customfields as $name => $field)
|
||||
{
|
||||
echo '<tr><td>{{#'.$name.'}}</td><td colspan="3">'.$field['label']."</td></tr>\n";
|
||||
}
|
||||
|
||||
echo '<tr><td colspan="4"><h3>'.lang('Contact fields').':</h3></td></tr>';
|
||||
$n = 0;
|
||||
foreach($this->contacts->contact_fields as $name => $label)
|
||||
{
|
||||
if (in_array($name,array('tid','label','geo'))) continue; // dont show them, as they are not used in the UI atm.
|
||||
|
||||
if (in_array($name,array('email','org_name','tel_work','url')) && $n&1) // main values, which should be in the first column
|
||||
{
|
||||
echo "</tr>\n";
|
||||
$n++;
|
||||
}
|
||||
if (!($n&1)) echo '<tr>';
|
||||
echo '<td>{{info_contact/'.$name.'}}</td><td>'.$label.'</td>';
|
||||
if ($n&1) echo "</tr>\n";
|
||||
$n++;
|
||||
}
|
||||
|
||||
echo '<tr><td colspan="4"><h3>'.lang('Custom fields').":</h3></td></tr>";
|
||||
foreach($this->contacts->customfields as $name => $field)
|
||||
{
|
||||
echo '<tr><td>{{info_contact/#'.$name.'}}</td><td colspan="3">'.$field['label']."</td></tr>\n";
|
||||
}
|
||||
|
||||
echo '<tr><td colspan="4"><h3>'.lang('General fields:')."</h3></td></tr>";
|
||||
foreach(array(
|
||||
'date' => lang('Date'),
|
||||
'user/n_fn' => lang('Name of current user, all other contact fields are valid too'),
|
||||
'user/account_lid' => lang('Username'),
|
||||
'pagerepeat' => lang('For serial letter use this tag. Put the content, you want to repeat between two Tags.'),
|
||||
'label' => lang('Use this tag for addresslabels. Put the content, you want to repeat, between two tags.'),
|
||||
'labelplacement' => lang('Tag to mark positions for address labels'),
|
||||
'IF fieldname' => lang('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.'),
|
||||
'NELF' => lang('Example {{NELF role}} - if field role is not empty, you will get a new line with the value of field role'),
|
||||
'NENVLF' => lang('Example {{NELFNV role}} - if field role is not empty, set a LF without any value of the field'),
|
||||
'LETTERPREFIX' => lang('Example {{LETTERPREFIX}} - Gives a letter prefix without double spaces, if the title is emty for example'),
|
||||
'LETTERPREFIXCUSTOM' => lang('Example {{LETTERPREFIXCUSTOM n_prefix title n_family}} - Example: Mr Dr. James Miller'),
|
||||
) as $name => $label)
|
||||
{
|
||||
echo '<tr><td>{{'.$name.'}}</td><td colspan="3">'.$label."</td></tr>\n";
|
||||
}
|
||||
|
||||
echo "</table>\n";
|
||||
|
||||
common::egw_footer();
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* InfoLog - Storage object
|
||||
* EGroupare - InfoLog - Storage object
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package infolog
|
||||
* @copyright (c) 2003-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2003-11 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -83,13 +83,16 @@ class infolog_so
|
||||
* @param array $info infolog entry as array
|
||||
* @return boolean
|
||||
*/
|
||||
function is_responsible($info)
|
||||
function is_responsible($info,$user=null)
|
||||
{
|
||||
static $user_and_memberships;
|
||||
if (is_null($user_and_memberships))
|
||||
if (!$user) $user = $this->user;
|
||||
|
||||
static $um_cache = array();
|
||||
if ($user == $this->user) $user_and_memberships =& $um_cache[$user];
|
||||
if (!isset($user_and_memberships))
|
||||
{
|
||||
$user_and_memberships = $GLOBALS['egw']->accounts->memberships($this->user,true);
|
||||
$user_and_memberships[] = $this->user;
|
||||
$user_and_memberships = $GLOBALS['egw']->accounts->memberships($user,true);
|
||||
$user_and_memberships[] = $user;
|
||||
}
|
||||
return $info['info_responsible'] && array_intersect((array)$info['info_responsible'],$user_and_memberships);
|
||||
}
|
||||
@ -100,10 +103,15 @@ class infolog_so
|
||||
* @param array|int $info data or info_id of InfoLog entry
|
||||
* @param int $required_rights EGW_ACL_xyz anded together
|
||||
* @param boolean $implicit_edit=false responsible has only implicit read and add rigths, unless this is set to true
|
||||
* @param array $grants=null grants to use, default (null) $this->grants
|
||||
* @param int $user=null user to check, default (null) $this->user
|
||||
* @return boolean True if access is granted else False
|
||||
*/
|
||||
function check_access( $info,$required_rights,$implicit_edit=false )
|
||||
function check_access( $info,$required_rights,$implicit_edit=false,array $grants=null,$user=null )
|
||||
{
|
||||
if (is_null($grants)) $grants = $this->grants;
|
||||
if (!$user) $user = $this->user;
|
||||
|
||||
if (is_array($info))
|
||||
{
|
||||
|
||||
@ -112,7 +120,7 @@ class infolog_so
|
||||
{
|
||||
// dont change our own internal data,
|
||||
$backup_data = $this->data;
|
||||
$info = $this->read($info);
|
||||
$info = $this->read(array('info_id'=>$info));
|
||||
$this->data = $backup_data;
|
||||
}
|
||||
else
|
||||
@ -124,15 +132,14 @@ class infolog_so
|
||||
return False;
|
||||
}
|
||||
$owner = $info['info_owner'];
|
||||
|
||||
$access_ok = $owner == $this->user || // user has all rights
|
||||
$access_ok = $owner == $user || // user has all rights
|
||||
// ACL only on public entrys || $owner granted _PRIVATE
|
||||
(!!($this->grants[$owner] & $required_rights) ||
|
||||
$this->is_responsible($info) && // implicite rights for responsible user(s) and his memberships
|
||||
(!!($grants[$owner] & $required_rights) ||
|
||||
$this->is_responsible($info,$user) && // implicite rights for responsible user(s) and his memberships
|
||||
($required_rights == EGW_ACL_READ || $required_rights == EGW_ACL_ADD || $implicit_edit && $required_rights == EGW_ACL_EDIT)) &&
|
||||
($info['info_access'] == 'public' || !!($this->grants[$this->user] & EGW_ACL_PRIVATE));
|
||||
($info['info_access'] == 'public' || !!($this->grants[$user] & EGW_ACL_PRIVATE));
|
||||
|
||||
//echo "<p align=right>check_access(info_id=$info_id,requited=$required_rights,implicit_edit=$implicit_edit) owner=$owner, responsible=(".implode(',',$info['info_responsible'])."): access".($access_ok?"Ok":"Denied")."</p>\n";
|
||||
// error_log(__METHOD__."($info[info_id],$required_rights,$implicit_edit,".array2string($grants).",$user) returning ".array2string($access_ok));
|
||||
return $access_ok;
|
||||
}
|
||||
|
||||
@ -255,7 +262,7 @@ class infolog_so
|
||||
)," AND info_responsible='0' OR ",$this->responsible_filter($f_user),')');
|
||||
}
|
||||
}
|
||||
//echo "<p>aclFilter(filter='$filter_was',user='$user') = '$filtermethod', privat_user_list=".print_r($privat_user_list,True).", public_user_list=".print_r($public_user_list,True)."</p>\n";
|
||||
//echo "<p>aclFilter(filter='$filter_was',user='$f_user') = '$filtermethod', privat_user_list=".print_r($privat_user_list,True).", public_user_list=".print_r($public_user_list,True)."</p>\n";
|
||||
return $this->acl_filter[$filter.$f_user] = $filtermethod; // cache the filter
|
||||
}
|
||||
|
||||
@ -295,7 +302,7 @@ class infolog_so
|
||||
*/
|
||||
function dateFilter($filter = '')
|
||||
{
|
||||
preg_match('/(upcoming|today|overdue|date|enddate)([-\\/.0-9]*)/',$filter,$vars);
|
||||
preg_match('/(open-upcoming|upcoming|today|overdue|date|enddate)([-\\/.0-9]*)/',$filter,$vars);
|
||||
$filter = $vars[1];
|
||||
|
||||
if (isset($vars[2]) && !empty($vars[2]) && ($date = preg_split('/[-\\/.]/',$vars[2])))
|
||||
@ -310,6 +317,8 @@ class infolog_so
|
||||
}
|
||||
switch ($filter)
|
||||
{
|
||||
case 'open-upcoming':
|
||||
return "AND (info_startdate >= $tomorrow OR NOT (info_status IN ('done','billed','cancelled','deleted','template','nonactive','archive')))";
|
||||
case 'upcoming':
|
||||
return " AND info_startdate >= $tomorrow";
|
||||
case 'today':
|
||||
@ -353,11 +362,12 @@ class infolog_so
|
||||
*
|
||||
* some cacheing is done to prevent multiple reads of the same entry
|
||||
*
|
||||
* @param int|string $info_id id or uid of entry
|
||||
* @param array $where where clause for entry to read
|
||||
* @return array|boolean the entry as array or False on error (eg. entry not found)
|
||||
*/
|
||||
function read($info_id) // did _not_ ensure ACL
|
||||
function read(array $where) // did _not_ ensure ACL
|
||||
{
|
||||
//error_log(__METHOD__.'('.array2string($where).')');
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
|
||||
@ -367,18 +377,16 @@ class infolog_so
|
||||
$minimum_uid_length = 8;
|
||||
}
|
||||
|
||||
//echo "<p>read($info_id) ".function_backtrace()."</p>\n";
|
||||
if (!$info_id || !$this->db->select($this->info_table,'*',
|
||||
$this->db->expression($this->info_table,array('info_id'=>$info_id),' OR ',array('info_uid'=>$info_id)),__LINE__,__FILE__) ||
|
||||
!(($this->data = $this->db->row(true))))
|
||||
if (!$where || !($this->data = $this->db->select($this->info_table,'*',$where,__LINE__,__FILE__)->fetch()))
|
||||
{
|
||||
$this->init( );
|
||||
//error_log(__METHOD__.'('.array2string($where).') returning FALSE');
|
||||
return False;
|
||||
}
|
||||
if (!$this->data['info_uid'] || strlen($this->data['info_uid']) < $minimum_uid_length) {
|
||||
// entry without uid --> create one based on our info_id and save it
|
||||
|
||||
$this->data['info_uid'] = $GLOBALS['egw']->common->generate_uid('infolog', $info_id);
|
||||
if (!$this->data['info_uid'] || strlen($this->data['info_uid']) < $minimum_uid_length)
|
||||
{
|
||||
$this->data['info_uid'] = common::generate_uid('infolog', $this->data['info_id']);
|
||||
$this->db->update($this->info_table,
|
||||
array('info_uid' => $this->data['info_uid']),
|
||||
array('info_id' => $this->data['info_id']), __LINE__,__FILE__);
|
||||
@ -387,11 +395,11 @@ class infolog_so
|
||||
{
|
||||
$this->data['info_responsible'] = $this->data['info_responsible'] ? explode(',',$this->data['info_responsible']) : array();
|
||||
}
|
||||
$this->db->select($this->extra_table,'info_extra_name,info_extra_value',array('info_id'=>$this->data['info_id']),__LINE__,__FILE__);
|
||||
while ($this->db->next_record())
|
||||
foreach($this->db->select($this->extra_table,'info_extra_name,info_extra_value',array('info_id'=>$this->data['info_id']),__LINE__,__FILE__) as $row)
|
||||
{
|
||||
$this->data['#'.$this->db->f(0)] = $this->db->f(1);
|
||||
$this->data['#'.$row['info_extra_name']] = $row['info_extra_value'];
|
||||
}
|
||||
//error_log(__METHOD__.'('.array2string($where).') returning '.array2string($this->data));
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
@ -403,8 +411,7 @@ class infolog_so
|
||||
*/
|
||||
function get_status($ids)
|
||||
{
|
||||
$this->db->select($this->info_table,'info_id,info_type,info_status,info_percent',array('info_id'=>$ids),__LINE__,__FILE__);
|
||||
while (($info = $this->db->row(true)))
|
||||
foreach($this->db->select($this->info_table,'info_id,info_type,info_status,info_percent',array('info_id'=>$ids),__LINE__,__FILE__) as $info)
|
||||
{
|
||||
switch ($info['info_type'].'-'.$info['info_status'])
|
||||
{
|
||||
@ -522,9 +529,10 @@ class infolog_so
|
||||
*
|
||||
* @param array $values with the data of the log-entry
|
||||
* @param int $check_modified=0 old modification date to check before update (include in WHERE)
|
||||
* @param string $purge_cfs=null null=dont, 'ical'=only iCal X-properties (cfs name starting with "#"), 'all'=all cfs
|
||||
* @return int|boolean info_id, false on error or 0 if the entry has been updated in the meantime
|
||||
*/
|
||||
function write($values,$check_modified=0) // did _not_ ensure ACL
|
||||
function write($values, $check_modified=0, $purge_cfs=null) // did _not_ ensure ACL
|
||||
{
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
@ -575,21 +583,34 @@ class infolog_so
|
||||
|
||||
$this->db->insert($this->info_table,$to_write,false,__LINE__,__FILE__);
|
||||
$info_id = $this->data['info_id'] = $this->db->get_last_insert_id($this->info_table,'info_id');
|
||||
|
||||
}
|
||||
|
||||
if (!$this->data['info_uid'] || strlen($this->data['info_uid']) < $minimum_uid_length) {
|
||||
// entry without uid --> create one based on our info_id and save it
|
||||
|
||||
$this->data['info_uid'] = $GLOBALS['egw']->common->generate_uid('infolog', $info_id);
|
||||
$this->db->update($this->info_table,
|
||||
array('info_uid' => $this->data['info_uid']),
|
||||
$update = array();
|
||||
// entry without (reasonable) uid --> create one based on our info_id and save it
|
||||
if (!$this->data['info_uid'] || strlen($this->data['info_uid']) < $minimum_uid_length)
|
||||
{
|
||||
$update['info_uid'] = $this->data['info_uid'] = common::generate_uid('infolog', $info_id);
|
||||
}
|
||||
// entry without caldav_name --> generate one based on info_id plus '.ics' extension
|
||||
if (empty($this->data['caldav_name']))
|
||||
{
|
||||
$update['caldav_name'] = $this->data['caldav_name'] = $info_id.'.ics';
|
||||
}
|
||||
if ($update)
|
||||
{
|
||||
$this->db->update($this->info_table,$update,
|
||||
array('info_id' => $info_id), __LINE__,__FILE__);
|
||||
}
|
||||
|
||||
//echo "<p>soinfolog.write values= "; _debug_array($values);
|
||||
|
||||
// write customfields now
|
||||
if ($purge_cfs)
|
||||
{
|
||||
$where = array('info_id' => $info_id);
|
||||
if ($purge_cfs == 'ical') $where[] = "info_extra_name LIKE '#%'";
|
||||
$this->db->delete($this->extra_table,$where,__LINE__,__FILE__);
|
||||
}
|
||||
$to_delete = array();
|
||||
foreach($values as $key => $val)
|
||||
{
|
||||
@ -613,7 +634,7 @@ class infolog_so
|
||||
$to_delete[] = substr($key,1);
|
||||
}
|
||||
}
|
||||
if ($to_delete)
|
||||
if ($to_delete && !$purge_cfs)
|
||||
{
|
||||
$this->db->delete($this->extra_table,array(
|
||||
'info_id' => $info_id,
|
||||
@ -624,8 +645,8 @@ class infolog_so
|
||||
//error_log("### soinfolog::write(".print_r($to_write,true).") where=".print_r($where,true)." returning id=".$this->data['info_id']);
|
||||
|
||||
// update the index
|
||||
egw_index::save('infolog',$this->data['info_id'],$this->data['info_owner'],$this->data,$this->data['info_cat'],
|
||||
array('info_uid','info_type','info_status','info_confirm','info_access'));
|
||||
//egw_index::save('infolog',$this->data['info_id'],$this->data['info_owner'],$this->data,$this->data['info_cat'],
|
||||
// array('info_uid','info_type','info_status','info_confirm','info_access'));
|
||||
|
||||
return $this->data['info_id'];
|
||||
}
|
||||
@ -645,7 +666,10 @@ class infolog_so
|
||||
if ((int)$info_id <= 0) return 0;
|
||||
}
|
||||
$counts = array();
|
||||
foreach($this->db->select($this->info_table,'info_id_parent,COUNT(*) AS info_anz_subs',array('info_id_parent' => $info_id),__LINE__,__FILE__,
|
||||
foreach($this->db->select($this->info_table,'info_id_parent,COUNT(*) AS info_anz_subs',array(
|
||||
'info_id_parent' => $info_id,
|
||||
"info_status != 'deleted'", // dont count deleted subs as subs, as they are not shown by default
|
||||
),__LINE__,__FILE__,
|
||||
false,'GROUP BY info_id_parent','infolog') as $row)
|
||||
{
|
||||
$counts[$row['info_id_parent']] = (int)$row['info_anz_subs'];
|
||||
@ -673,7 +697,7 @@ class infolog_so
|
||||
*/
|
||||
function search(&$query)
|
||||
{
|
||||
//echo "<p>soinfolog.search(".print_r($query,True).")</p>\n";
|
||||
//error_log(__METHOD__.'('.array2string($query).')');
|
||||
$action2app = array(
|
||||
'addr' => 'addressbook',
|
||||
'proj' => 'projects',
|
||||
@ -682,7 +706,9 @@ class infolog_so
|
||||
$action = isset($action2app[$query['action']]) ? $action2app[$query['action']] : $query['action'];
|
||||
if ($action != '')
|
||||
{
|
||||
$links = solink::get_links($action=='sp'?'infolog':$action,explode(',',$query['action_id']),'infolog');
|
||||
$links = solink::get_links($action=='sp'?'infolog':$action,
|
||||
is_array($query['action_id']) ? $query['action_id'] : explode(',',$query['action_id']),'infolog');
|
||||
|
||||
if (count($links))
|
||||
{
|
||||
$links = call_user_func_array('array_merge',$links); // flatten the array
|
||||
@ -735,7 +761,7 @@ class infolog_so
|
||||
$filtermethod .= ' AND '.$data;
|
||||
continue;
|
||||
}
|
||||
if (substr($col,0,5) != 'info_' && substr($col,0,1)!='#') $col = 'info_'.$col;
|
||||
if ($col[0] != '#' && substr($col,0,5) != 'info_' && isset($table_def['fd']['info_'.$col])) $col = 'info_'.$col;
|
||||
if (!empty($data) && preg_match('/^[a-z_0-9]+$/i',$col))
|
||||
{
|
||||
switch ($col)
|
||||
@ -768,17 +794,16 @@ class infolog_so
|
||||
// Multi-select - any entry with the filter value selected matches
|
||||
$filtermethod .= $this->db->expression($this->extra_table, array(
|
||||
'info_extra_name' => substr($col,1),
|
||||
"CONCAT(',',info_extra_value,',') LIKE '%,$data,%'"
|
||||
$this->db->concat("','",'info_extra_value',"','").' '.$this->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote('%,'.$data.',%'),
|
||||
)).')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$filtermethod .= $this->db->expression($this->extra_table,array(
|
||||
'info_extra_name' => substr($col,1),
|
||||
'info_extra_value' => $data,
|
||||
)).')';
|
||||
'info_extra_name' => substr($col,1),
|
||||
'info_extra_value' => $data,
|
||||
)).')';
|
||||
}
|
||||
|
||||
$cfcolfilter++;
|
||||
}
|
||||
}
|
||||
@ -818,14 +843,15 @@ class infolog_so
|
||||
// at the moment MaxDB 7.5 cant cast nor search text columns, it's suppost to change in 7.6
|
||||
if ($this->db->capabilities['like_on_text']) $columns[] = 'info_des';
|
||||
|
||||
$search = so_sql::search2criteria($query['search'], $wildcard, $op, null, $columns);
|
||||
$sql_query = 'AND ('.(is_numeric($query['search']) ? 'main.info_id='.(int)$query['search'].' OR ' : '').
|
||||
implode($pattern.' OR ',$columns).$pattern.') ';
|
||||
implode($op, $search) .')';
|
||||
|
||||
$join = ($cfcolfilter>0 ? '':'LEFT')." JOIN $this->extra_table ON main.info_id=$this->extra_table.info_id ";
|
||||
// mssql and others cant use DISTICT if text columns (info_des) are involved
|
||||
$distinct = $this->db->capabilities['distinct_on_text'] ? 'DISTINCT' : '';
|
||||
}
|
||||
$pid = 'AND info_id_parent='.($action == 'sp' ? $query['action_id'] : 0);
|
||||
$pid = 'AND ' . $this->db->expression($this->info_table,array('info_id_parent' => ($action == 'sp' ?$query['action_id'] : 0)));
|
||||
|
||||
if (!$GLOBALS['egw_info']['user']['preferences']['infolog']['listNoSubs'] &&
|
||||
$action != 'sp' || isset($query['subs']) && $query['subs'])
|
||||
@ -883,11 +909,19 @@ class infolog_so
|
||||
|
||||
$ids[$info['info_id']] = $info;
|
||||
}
|
||||
static $index_load_cfs;
|
||||
if (is_null($index_load_cfs) && $query['col_filter']['info_type'])
|
||||
{
|
||||
$config_data = config::read('infolog');
|
||||
$index_load_cfs = (array)$config_data['index_load_cfs'];
|
||||
}
|
||||
// if no specific custom field is selected, show/query all custom fields
|
||||
if ($ids && ($query['custom_fields'] || $query['csv_export']))
|
||||
if ($ids && ($query['custom_fields'] || $query['csv_export'] ||
|
||||
$index_load_cfs && $query['col_filter']['info_type'] && in_array($query['col_filter']['info_type'],$index_load_cfs)))
|
||||
{
|
||||
$where = array('info_id' => array_keys($ids));
|
||||
if (!($query['csv_export'] || strchr($query['selectcols'],'#') === false))
|
||||
if (!($query['csv_export'] || strchr($query['selectcols'],'#') === false ||
|
||||
$index_load_cfs && $query['col_filter']['info_type'] && in_array($query['col_filter']['info_type'],$index_load_cfs)))
|
||||
{
|
||||
$where['info_extra_name'] = array();
|
||||
foreach(explode(',',$query['selectcols']) as $col)
|
||||
|
@ -56,11 +56,11 @@ class infolog_tracking extends bo_tracking
|
||||
'info_status' => 'St',
|
||||
'info_percent' => 'Pe',
|
||||
'info_datecompleted' => 'Co',
|
||||
'info_datemodified' => 'Mo',
|
||||
'info_location' => 'Lo',
|
||||
'info_startdate' => 'st',
|
||||
'info_enddate' => 'En',
|
||||
'info_responsible' => 'Re',
|
||||
'info_cc' => 'cc',
|
||||
'info_subject' => 'Su',
|
||||
'info_des' => 'De',
|
||||
'info_location' => 'Lo',
|
||||
@ -75,11 +75,14 @@ class infolog_tracking extends bo_tracking
|
||||
/**
|
||||
* Translate field-names to labels
|
||||
*
|
||||
* @note The order of these fields is used to determine the order for CSV export
|
||||
* @var array
|
||||
*/
|
||||
var $field2label = array(
|
||||
'info_type' => 'Type',
|
||||
'info_from' => 'Contact',
|
||||
'info_subject' => 'Subject',
|
||||
'info_des' => 'Description',
|
||||
'info_addr' => 'Phone/Email',
|
||||
'info_link_id' => 'primary link',
|
||||
'info_cat' => 'Category',
|
||||
@ -94,8 +97,7 @@ class infolog_tracking extends bo_tracking
|
||||
'info_startdate' => 'Startdate',
|
||||
'info_enddate' => 'Enddate',
|
||||
'info_responsible' => 'Responsible',
|
||||
'info_subject' => 'Subject',
|
||||
'info_des' => 'Description',
|
||||
'info_cc' => 'Cc',
|
||||
// PM fields
|
||||
'info_planned_time' => 'planned time',
|
||||
'info_used_time' => 'used time',
|
||||
@ -136,7 +138,11 @@ class infolog_tracking extends bo_tracking
|
||||
*/
|
||||
function get_subject($data,$old)
|
||||
{
|
||||
if (!$old || $old['info_status'] == 'deleted')
|
||||
if ($data['prefix'])
|
||||
{
|
||||
$prefix = $data['prefix']; // async notification
|
||||
}
|
||||
elseif (!$old || $old['info_status'] == 'deleted')
|
||||
{
|
||||
$prefix = lang('New %1',lang($this->infolog->enums['type'][$data['info_type']]));
|
||||
}
|
||||
@ -245,7 +251,7 @@ class infolog_tracking extends bo_tracking
|
||||
}
|
||||
$details['#'.$name] = array(
|
||||
'label' => $field['label'],
|
||||
'value' => $data['#'.$name],
|
||||
'value' => (is_array($field['values']) && !empty($field['values']) && array_key_exists($data['#'.$name],$field['values']))?$field['values'][$data['#'.$name]] : $data['#'.$name],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -254,7 +260,7 @@ class infolog_tracking extends bo_tracking
|
||||
|
||||
/**
|
||||
* Track changes
|
||||
*
|
||||
*
|
||||
* Overrides parent to log the modified date in the history, but not to send a notification
|
||||
*
|
||||
* @param array $data current entry
|
||||
@ -317,4 +323,31 @@ class infolog_tracking extends bo_tracking
|
||||
|
||||
return parent::save_history($data,$old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a notification-config value
|
||||
*
|
||||
* @param string $what
|
||||
* - 'copy' array of email addresses notifications should be copied too, can depend on $data
|
||||
* - 'lang' string lang code for copy mail
|
||||
* - 'sender' string send email address
|
||||
* @param array $data current entry
|
||||
* @param array $old=null old/last state of the entry or null for a new entry
|
||||
* @return mixed
|
||||
*/
|
||||
function get_config($name,$data,$old=null)
|
||||
{
|
||||
$config = array();
|
||||
switch($name)
|
||||
{
|
||||
case 'copy': // include the info_cc addresses
|
||||
if ($data['info_access'] == 'private') return array(); // no copies for private entries
|
||||
if ($data['info_cc'])
|
||||
{
|
||||
$config = array_merge($config,preg_split('/, ?/',$data['info_cc']));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package infolog
|
||||
* @copyright (c) 2003-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2003-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -1055,6 +1055,7 @@ class infolog_ui
|
||||
$parent = $this->bo->so->data;
|
||||
$content['info_id'] = $info_id = 0;
|
||||
$content['info_uid'] = ''; // ensure that we have our own UID
|
||||
$content['caldav_name'] = ''; // ensure that we have our own caldav_name
|
||||
$content['info_owner'] = $this->user;
|
||||
$content['info_id_parent'] = $parent['info_id'];
|
||||
/*
|
||||
@ -1220,13 +1221,17 @@ class infolog_ui
|
||||
}
|
||||
}
|
||||
$preserv = $content;
|
||||
// for implizit edit of responsible user make all fields readonly, but status and percent
|
||||
if ($info_id && !$this->bo->check_access($info_id,EGW_ACL_EDIT) && $this->bo->is_responsible($content) && !$undelete)
|
||||
// for no edit rights or implizit edit of responsible user make all fields readonly, but status and percent
|
||||
if ($info_id && !$this->bo->check_access($info_id,EGW_ACL_EDIT) && !$undelete)
|
||||
{
|
||||
$content['status_only'] = !in_array('link_to',$this->bo->responsible_edit);
|
||||
foreach(array_diff(array_merge(array_keys($content),array('pm_id')),$this->bo->responsible_edit) as $name)
|
||||
{
|
||||
$readonlys[$name] = true;
|
||||
foreach($this->bo->responsible_edit as $name)
|
||||
{
|
||||
$readonlys[$name] = false;
|
||||
}
|
||||
$readonlys['button[edit]'] = $readonlys['button[save]'] = $readonlys['button[apply]'] = $readonlys['no_notifications'] = false;
|
||||
}
|
||||
unset($readonlys[$tabs]);
|
||||
// need to set all customfields extra, as they are not set if empty
|
||||
|
29
infolog/inc/class.infolog_wizard_export_csv.inc.php
Normal file
29
infolog/inc/class.infolog_wizard_export_csv.inc.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Wizard for Infolog CSV export
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package infolog
|
||||
* @subpackage importexport
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
class infolog_wizard_export_csv extends importexport_wizard_basic_export_csv
|
||||
{
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
// Field mapping
|
||||
$bo = new infolog_tracking();
|
||||
$this->export_fields = array('info_id' => 'Infolog ID') + $bo->field2label;
|
||||
|
||||
// Custom fields
|
||||
unset($this->export_fields['custom']); // Heading, not a real field
|
||||
$custom = config::get_customfields('infolog', true);
|
||||
foreach($custom as $name => $data) {
|
||||
$this->export_fields['#'.$name] = $data['label'];
|
||||
}
|
||||
}
|
||||
}
|
120
infolog/inc/class.infolog_wizard_import_infologs_csv.inc.php
Normal file
120
infolog/inc/class.infolog_wizard_import_infologs_csv.inc.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Wizard for Infolog CSV import
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package addressbook
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @version $Id: $
|
||||
*/
|
||||
|
||||
class infolog_wizard_import_infologs_csv extends importexport_wizard_basic_import_csv
|
||||
{
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->steps += array(
|
||||
'wizard_step50' => lang('Manage mapping'),
|
||||
# This doesn't work with infolog very well
|
||||
#'wizard_step60' => lang('Choose owner of imported data'),
|
||||
);
|
||||
|
||||
// Field mapping
|
||||
$tracking = new infolog_tracking();
|
||||
$this->mapping_fields = array('info_id' => 'Infolog ID') + $tracking->field2label + infolog_import_infologs_csv::$special_fields;
|
||||
// List each custom field
|
||||
unset($this->mapping_fields['custom']);
|
||||
$custom = config::get_customfields('infolog');
|
||||
foreach($custom as $name => $data) {
|
||||
$this->mapping_fields['#'.$name] = $data['label'];
|
||||
}
|
||||
|
||||
// Actions
|
||||
$this->actions = array(
|
||||
'none' => lang('none'),
|
||||
'update' => lang('update'),
|
||||
'insert' => lang('insert'),
|
||||
'delete' => lang('delete'),
|
||||
);
|
||||
|
||||
// Conditions
|
||||
$this->conditions = array(
|
||||
'exists' => lang('exists'),
|
||||
);
|
||||
}
|
||||
|
||||
function wizard_step50(&$content, &$sel_options, &$readonlys, &$preserv)
|
||||
{
|
||||
$result = parent::wizard_step50($content, $sel_options, $readonlys, $preserv);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
# Skipped for now (or forever)
|
||||
function wizard_step60(&$content, &$sel_options, &$readonlys, &$preserv)
|
||||
{
|
||||
if($this->debug) error_log(__METHOD__.'->$content '.print_r($content,true));
|
||||
unset($content['no_owner_map']);
|
||||
// Check that record owner has access
|
||||
$access = true;
|
||||
if($content['record_owner'])
|
||||
{
|
||||
$bo = new infolog_bo();
|
||||
$access = $bo->check_access(0,EGW_ACL_EDIT, $content['record_owner']);
|
||||
}
|
||||
|
||||
// return from step60
|
||||
if ($content['step'] == 'wizard_step60')
|
||||
{
|
||||
if(!$access) {
|
||||
$step = $content['step'];
|
||||
unset($content['step']);
|
||||
return $step;
|
||||
}
|
||||
switch (array_search('pressed', $content['button']))
|
||||
{
|
||||
case 'next':
|
||||
return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],1);
|
||||
case 'previous' :
|
||||
return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],-1);
|
||||
case 'finish':
|
||||
return 'wizard_finish';
|
||||
default :
|
||||
return $this->wizard_step60($content,$sel_options,$readonlys,$preserv);
|
||||
}
|
||||
}
|
||||
// init step60
|
||||
else
|
||||
{
|
||||
$content['msg'] = $this->steps['wizard_step60'];
|
||||
if(!$access) {
|
||||
$content['msg'] .= "\n* " . lang('Owner does not have edit rights');
|
||||
}
|
||||
$content['step'] = 'wizard_step60';
|
||||
if(!array_key_exists($content['record_owner']) && $content['plugin_options']) {
|
||||
$content['record_owner'] = $content['plugin_options']['record_owner'];
|
||||
}
|
||||
if(!array_key_exists($content['owner_from_csv']) && $content['plugin_options']) {
|
||||
$content['owner_from_csv'] = $content['plugin_options']['owner_from_csv'];
|
||||
}
|
||||
if(!array_key_exists($content['change_owner']) && $content['plugin_options']) {
|
||||
$content['change_owner'] = $content['plugin_options']['change_owner'];
|
||||
}
|
||||
|
||||
if(!in_array('info_owner', $content['field_mapping'])) {
|
||||
$content['no_owner_map'] = true;
|
||||
}
|
||||
|
||||
$preserv = $content;
|
||||
unset ($preserv['button']);
|
||||
return 'infolog.importexport_wizard_chooseowner';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
28
infolog/js/edit.js
Normal file
28
infolog/js/edit.js
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Javascript used on the infolog edit popup
|
||||
*/
|
||||
|
||||
function add_email_from_ab(ab_id,info_cc)
|
||||
{
|
||||
var ab = document.getElementById(ab_id);
|
||||
|
||||
if (!ab || !ab.value)
|
||||
{
|
||||
set_style_by_class('tr','hiddenRow','display','block');
|
||||
}
|
||||
else
|
||||
{
|
||||
var cc = document.getElementById(info_cc);
|
||||
|
||||
for(var i=0; i < ab.options.length && ab.options[i].value != ab.value; ++i) ;
|
||||
|
||||
if (i < ab.options.length)
|
||||
{
|
||||
cc.value += (cc.value?', ':'')+ab.options[i].text.replace(/^.* <(.*)>$/,'$1');
|
||||
ab.value = '';
|
||||
ab.onchange();
|
||||
set_style_by_class('tr','hiddenRow','display','none');
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
30
infolog/js/index.js
Normal file
30
infolog/js/index.js
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Javascript used on the infolog index page
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Javascript handling for multiple entry actions
|
||||
*/
|
||||
function do_infolog_action(selbox) {
|
||||
if(selbox.value == "") return;
|
||||
var prefix = selbox.id.substring(0,selbox.id.indexOf('['));
|
||||
var popup = document.getElementById(prefix + '[' + selbox.value + '_popup]');
|
||||
if(popup) {
|
||||
popup.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
selbox.form.submit();
|
||||
selbox.value = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide popup and clear values
|
||||
*/
|
||||
function hide_popup(element, div_id) {
|
||||
var prefix = element.id.substring(0,element.id.indexOf('['));
|
||||
var popup = document.getElementById(prefix+'['+div_id+']');
|
||||
if(popup) {
|
||||
popup.style.display = 'none';
|
||||
}
|
||||
}
|
363
infolog/lang/egw_bg.lang
Normal file
363
infolog/lang/egw_bg.lang
Normal file
@ -0,0 +1,363 @@
|
||||
%1 days in advance infolog bg %1 дена предварително
|
||||
%1 deleted infolog bg %1 е изтрит
|
||||
%1 deleted by %2 at %3 infolog bg %1 е изтрит от %2 в %3
|
||||
%1 modified infolog bg %1 е променен
|
||||
%1 modified by %2 at %3 infolog bg %1 е променен от %2 в %3
|
||||
%1 records imported infolog bg %1 записа са импортирани
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog bg %1 записа прочетени (все още не импортирани, може да се върнете %2обратно%3 и да махнете отметката Тестов Импорт)
|
||||
%1 you are responsible for is due at %2 infolog bg %1, за което отговаряте, приключва на %2
|
||||
%1 you are responsible for is starting at %2 infolog bg %1, за което отговаряте, започва на %2
|
||||
%1 you delegated is due at %2 infolog bg %1, делегирано от Вас приключва на %2
|
||||
%1 you delegated is starting at %2 infolog bg %1, делегирано от Вас започва на %2
|
||||
- subprojects from infolog bg - Подпроекти от
|
||||
0% infolog bg 0%
|
||||
10% infolog bg 10%
|
||||
100% infolog bg 100%
|
||||
20% infolog bg 20%
|
||||
30% infolog bg 30%
|
||||
40% infolog bg 40%
|
||||
50% infolog bg 50%
|
||||
60% infolog bg 60%
|
||||
70% infolog bg 70%
|
||||
80% infolog bg 80%
|
||||
90% infolog bg 90%
|
||||
a short subject for the entry infolog bg тема на записа накратко
|
||||
abort without deleting infolog bg Отказ без изтриване
|
||||
accept infolog bg приемане
|
||||
action infolog bg Действие
|
||||
actual date and time infolog bg действителни дата и час
|
||||
add infolog bg Добавяне
|
||||
add a file infolog bg Добави файл
|
||||
add a new entry infolog bg Добави нов запис
|
||||
add a new note infolog bg Добави нова бележка
|
||||
add a new phonecall infolog bg Добави ново телефонно обаждане
|
||||
add a new sub-task, -note, -call to this entry infolog bg Добави нова под-задача, -бележка, -обаждане към този запис
|
||||
add a new todo infolog bg Добави Предстоящо
|
||||
add file infolog bg Добави файл
|
||||
add sub infolog bg Добави Под-
|
||||
add timesheet entry infolog bg Добави запис в Графика
|
||||
add: infolog bg Добавяне:
|
||||
all infolog bg Всички
|
||||
all links and attachments infolog bg всички връзки и приложения
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog bg позволява установяване статуса на запис, напр. Предстоящо като Изпълнено, ако е приключило (стойностите зависят от типа на записа)
|
||||
apply the changes infolog bg Приложи промените
|
||||
archive infolog bg архив
|
||||
are you shure you want to delete this entry ? infolog bg Желаете ли да изтриете този запис ?
|
||||
attach a file infolog bg Прилагане на файл
|
||||
attach file infolog bg Приложи файл
|
||||
attention: no contact with address %1 found. infolog bg Внимание! Не е намерен контакт с адрес %1.
|
||||
back to main list infolog bg Обратно към основния списък
|
||||
billed infolog bg таксуван
|
||||
both infolog bg и двете
|
||||
call infolog bg обаждане
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog bg Може да се използва за нови типове елементи в Дневника и Календара, или за филтър, напр. само Задачи
|
||||
cancel infolog bg Отмени
|
||||
cancelled infolog bg отменен
|
||||
categories infolog bg Категории
|
||||
category infolog bg Категория
|
||||
change the status of an entry, eg. close it infolog bg Променя статуса на запис, напр. приключва го
|
||||
charset of file infolog bg Символен набор (Charset) на файла
|
||||
check to set startday infolog bg отбележете за начална дата
|
||||
check to specify custom contact infolog bg отбележете за използване на контакт по избор
|
||||
click here to create the link infolog bg кликнете тук за създаване на връзката
|
||||
click here to start the search infolog bg кликнете тук за начало на търсенето
|
||||
close infolog bg Затвори
|
||||
comment infolog bg Коментар
|
||||
completed infolog bg Приключен
|
||||
configuration infolog bg Конфигурация
|
||||
confirm infolog bg Потвърди
|
||||
contact infolog bg Контакт
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog bg Копирайте промените в клипборда, %1презаредете записа%2 и ги съберете.
|
||||
create new links infolog bg Създаване на нови връзки
|
||||
creates a new field infolog bg създава ново поле
|
||||
creates a new status with the given values infolog bg създава нов статус съз зададените стойности
|
||||
creates a new typ with the given name infolog bg създава нов тип със зададеното име
|
||||
creation infolog bg Създаване
|
||||
csv-fieldname infolog bg Име на полето в CSV
|
||||
csv-filename infolog bg Име на CSV файла
|
||||
csv-import common bg Импорт на CSV
|
||||
custom infolog bg По избор
|
||||
custom contact-address, leave empty to use information from most recent link infolog bg Адрес на контакт по избор, ако не се попълни използва последната връзка
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog bg Информация за контакт по избор, ако не се попълни използва последната връзка
|
||||
custom fields infolog bg Полета по избор
|
||||
custom fields, typ and status common bg По избор - полета, тип и статус
|
||||
custom from infolog bg Форма по избор
|
||||
custom regarding infolog bg По избор - относно
|
||||
custom status for typ infolog bg По избор - статус за тип
|
||||
customfields infolog bg Полета по избор
|
||||
date completed infolog bg Дата на завършване
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog bg Дата на завършване (непопълнена се установява автоматично при статус Изпълнен или Таксуван)
|
||||
datecreated infolog bg дата на създаване
|
||||
dates, status, access infolog bg Дати, Статус, Достъп
|
||||
days infolog bg дни
|
||||
default category for new infolog entries infolog bg Категория по подразбиране за нови записи в Дневника
|
||||
default filter for infolog infolog bg Филтър по подразбиране в Дневника
|
||||
default status for a new log entry infolog bg Сатус по подразбиране на новите записи
|
||||
delegated infolog bg делегиран
|
||||
delegated open infolog bg делегиран - отворен
|
||||
delegated overdue infolog bg делегиран - просрочен
|
||||
delegated upcomming infolog bg делегиран - предстоящ
|
||||
delegation infolog bg Делегиране
|
||||
delete infolog bg Изтриване
|
||||
delete one record by passing its id. infolog bg Изтриване на един запис чрез предаване на ИД №
|
||||
delete the entry infolog bg Изтриване записа
|
||||
delete this entry infolog bg изтриване на този запис
|
||||
delete this entry and all listed sub-entries infolog bg Изтриване на този запис и всички показани под-записи
|
||||
deleted infolog bg изтрит
|
||||
deletes the selected typ infolog bg изтрива избрания тип
|
||||
deletes this field infolog bg изтрива това поле
|
||||
deletes this status infolog bg изтрива този статус
|
||||
description infolog bg Описание
|
||||
determines the order the fields are displayed infolog bg определя реда за показване на полетата
|
||||
disables a status without deleting it infolog bg забранява даден статус, без да го изтрива
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog bg Изисква потвърждение от отговорния при: приемане на задачата, приключването й или и двете
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog bg Желаете ли известие при назначаване задачи или при актуализация на вече назначените?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog bg Желаете ли известие преди началото на задачи, за които отговаряте?
|
||||
do you want a notification, if items you are responsible for are due? infolog bg Желаете ли известие при достигане на крайния срок за задачи, за които отговаряте?
|
||||
do you want a notification, if items you created get updated? infolog bg Желаете ли известие при актуализация на създадени от вас записи?
|
||||
do you want a notification, if items you delegated are about to start? infolog bg Желаете ли известие преди началото на задачи, които сте делефирали?
|
||||
do you want a notification, if items you delegated are due? infolog bg Желаете ли известие при достигане на крайния срок за задачи, които сте делегирали?
|
||||
do you want to receive notifications as html-mails or plain text? infolog bg Известията да бъдат във вид на HTML или текстови съобщения?
|
||||
don't show infolog infolog bg НЕ показвай Дневника
|
||||
done infolog bg приключен
|
||||
download infolog bg Изтегляне
|
||||
duration infolog bg Продължителност
|
||||
each value is a line like <id>[=<label>] infolog bg всяка стойност е ред във формат <id>[=<label>]
|
||||
edit infolog bg Редактиране
|
||||
edit or create categories for ingolog infolog bg Редактиране или създаване на категории за Дневника
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog bg право за редакция (пълна редакция включва и промяна на отговорника!)
|
||||
edit status infolog bg Редактиране на статуса
|
||||
edit the entry infolog bg Редактиране на записа
|
||||
edit this entry infolog bg Редактиране на записа
|
||||
empty for all infolog bg непопълнен за всички
|
||||
enddate infolog bg Краен срок
|
||||
enddate can not be before startdate infolog bg Крайния срок не може да бъде преди началната дата
|
||||
enter a custom contact, leave empty if linked entry should be used infolog bg Въведете контакт по избор, или ще се използва контакт от връзка
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog bg Въведете телефон/E-Mail, или ще се използват от връзка
|
||||
enter a textual description of the log-entry infolog bg въведете текстово описание за Log-записа
|
||||
enter the query pattern infolog bg Въведете низ за запитване
|
||||
entry and all files infolog bg Записа и всички файлове
|
||||
error: saving the entry infolog bg Грешка при запис
|
||||
error: the entry has been updated since you opened it for editing! infolog bg Грешка: записът е бил обновен, след като сте го отворили за редакция!
|
||||
existing links infolog bg Съществуващи връзки
|
||||
fax infolog bg Факс
|
||||
field must not be empty !!! infolog bg Полето не може да бъде празно !!!
|
||||
fieldseparator infolog bg Разделител на полетата
|
||||
finish infolog bg край
|
||||
for which types should this field be used infolog bg за кои типове да се използва полето
|
||||
from infolog bg От
|
||||
general infolog bg Общи
|
||||
group owner for infolog bg Група-собственик на
|
||||
high infolog bg висок
|
||||
history logging infolog bg Запис на история
|
||||
history logging and deleting of items infolog bg Запис на история и изтриване на елементи
|
||||
id infolog bg No.
|
||||
id# infolog bg No.
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog bg Ако за даден тип собственика е група, всички записи от този тип ще бъдат собственост на групата, НЕ на потребителя, който ги е създал!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog bg Ако не е зададен, редът за търсене и филтър е скрит за брой елементи, по-малък от "Максимален брой резултати на страница", дефиниран в настройките
|
||||
import infolog bg Импорт
|
||||
import next set infolog bg импорт на следващ набор
|
||||
info log common bg Дневник
|
||||
infolog common bg Дневник
|
||||
infolog - delete infolog bg Дневник - Изтриване
|
||||
infolog - edit infolog bg Дневник - Редактиране
|
||||
infolog - import csv-file infolog bg Дневник - Импорт на CSV-файл
|
||||
infolog - new infolog bg Дневник - Нов
|
||||
infolog - new subproject infolog bg Дневник - Нов подпроект
|
||||
infolog - subprojects from infolog bg Дневник - Подпроект от
|
||||
infolog entry deleted infolog bg Записът е изтрит от Дневника
|
||||
infolog entry saved infolog bg Записът е запазен в Дневника
|
||||
infolog filter for the main screen infolog bg Филтър за главния екран на Дневника
|
||||
infolog list infolog bg Дневник - списък
|
||||
infolog preferences common bg Дневник - настройки
|
||||
infolog-fieldname infolog bg Дневник - име на поле
|
||||
invalid filename infolog bg Невалидно име на файл
|
||||
label<br>helptext infolog bg Етикет<br>Помощен текст
|
||||
last changed infolog bg Последна промяна
|
||||
last modified infolog bg Последно изменение
|
||||
leave it empty infolog bg оставете непопълнено
|
||||
leave without saveing the entry infolog bg изход без запис
|
||||
leaves without saveing infolog bg изход без запис
|
||||
length<br>rows infolog bg Дължина<br>Редове
|
||||
link infolog bg Връзка
|
||||
links infolog bg Връзки
|
||||
links of this entry infolog bg Връзки на записа
|
||||
list all categories infolog bg Покажи всички категории
|
||||
list no subs/childs infolog bg Покажи без Под-
|
||||
location infolog bg Местонахождение
|
||||
longer textual description infolog bg по-дълго текстово описание
|
||||
low infolog bg нисък
|
||||
max length of the input [, length of the inputfield (optional)] infolog bg макс. дължина на входа[, дължнина на вх.поле (опция)]
|
||||
name must not be empty !!! infolog bg Името трябва да бъде попълнено!!!
|
||||
name of new type to create infolog bg име на новия тип
|
||||
never hide search and filters infolog bg Не скривай търсенето и филтрите
|
||||
new %1 infolog bg Нов %1
|
||||
new %1 created by %2 at %3 infolog bg Нов %1, създаден от %2 в %3
|
||||
new name infolog bg ново име
|
||||
new search infolog bg Ново търсене
|
||||
no - cancel infolog bg Не - Отменя
|
||||
no describtion, links or attachments infolog bg няма описание, връзки или приложения
|
||||
no details infolog bg без детайли
|
||||
no entries found, try again ... infolog bg няма намерени записи, опитайте отново
|
||||
no filter infolog bg няма филтър
|
||||
no links or attachments infolog bg няма връзки или приложения
|
||||
nonactive infolog bg неактивен
|
||||
none infolog bg Няма
|
||||
normal infolog bg нормален
|
||||
not infolog bg не е
|
||||
not assigned infolog bg не назначен
|
||||
not-started infolog bg не започнат
|
||||
note infolog bg Бележка
|
||||
number of records to read (%1) infolog bg Брой записи за четене (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog bg Брой редове за многоредово текстово поле или множествен избор
|
||||
offer infolog bg оферта
|
||||
one day after infolog bg един ден по-късно
|
||||
one day in advance infolog bg един ден предварително
|
||||
ongoing infolog bg състоящ се
|
||||
only for details infolog bg Само за детайлите
|
||||
only if i get assigned or removed infolog bg Само ако бъда включен или изключен
|
||||
only the attachments infolog bg само приложенията
|
||||
only the links infolog bg само връзките
|
||||
open infolog bg отвори
|
||||
optional note to the link infolog bg бележка към връзката
|
||||
order infolog bg Ред
|
||||
overdue infolog bg просрочен
|
||||
own infolog bg собствен
|
||||
own open infolog bg отворен от собственика
|
||||
own overdue infolog bg просрочен от собственика
|
||||
own upcoming infolog bg предстоящ за собственика
|
||||
parent infolog bg Родителски
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog bg път от страна на (web-)сървъра<br>напр. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog bg Пътят до файловете на потребителите и групите ТРЯБВА ДА БЪДЕ ИЗВЪН document-root на WEB сървъра!!!
|
||||
pattern for search in addressbook infolog bg низ за търсене в Адр. указател
|
||||
pattern for search in projects infolog bg низ за търсене в Проектите
|
||||
percent completed infolog bg Степен на изпълнение
|
||||
permission denied infolog bg Достъпът отказан
|
||||
phone infolog bg Телефонен разговор
|
||||
phone/email infolog bg Телефон/E-Mail
|
||||
phonecall infolog bg Телефонен разговор
|
||||
planned infolog bg планиран
|
||||
planned time infolog bg планирано време
|
||||
price infolog bg Цена
|
||||
pricelist infolog bg Ценова листа
|
||||
primary link infolog bg основна връзка
|
||||
priority infolog bg Приоритет
|
||||
private infolog bg Личен
|
||||
project infolog bg Проект
|
||||
project settings: price, times infolog bg Параметри на проекта: цена, срокове
|
||||
re: infolog bg Отг:
|
||||
read one record by passing its id. infolog bg Прочита един запис чрез предаване на ИД №
|
||||
read rights (default) infolog bg право за четене (по подразбиране)
|
||||
receive notifications about due entries you are responsible for infolog bg Известяване за срока на задачи, за които сте отговорни
|
||||
receive notifications about due entries you delegated infolog bg Известяване за срока на задачи, които сте делегирали
|
||||
receive notifications about items assigned to you infolog bg Известяване за срока на задачи, назначени на Вас
|
||||
receive notifications about own items infolog bg Известяване за срока на собствени задачи
|
||||
receive notifications about starting entries you are responsible for infolog bg Известяване за началото на задачи, за които сте отговорни
|
||||
receive notifications about starting entries you delegated infolog bg Известяване за началото на задачи, които сте делегирали
|
||||
receive notifications as html-mails infolog bg Получаване на известия във вид на HTML E-mail-и
|
||||
remark infolog bg Забележка
|
||||
remove this link (not the entry itself) infolog bg Премахване на връзката (не и на записа)
|
||||
responsible infolog bg отговорен
|
||||
responsible open infolog bg отворен от отговорника
|
||||
responsible overdue infolog bg просрочен от отговорника
|
||||
responsible upcoming infolog bg предстоящ за отговорника
|
||||
responsible user, priority infolog bg отговорен потребител, приоритет
|
||||
returns a list / search for records. infolog bg Връща списък / търси записи.
|
||||
rights for the responsible infolog bg Права на отговорника
|
||||
same day infolog bg същия ден
|
||||
save infolog bg запис
|
||||
saves the changes made and leaves infolog bg запазва направените промени и излиза
|
||||
saves this entry infolog bg Запазва записа
|
||||
search infolog bg Търсене
|
||||
search for: infolog bg Търсене за:
|
||||
select infolog bg Избор
|
||||
select a category for this entry infolog bg избор на категория за този запис
|
||||
select a price infolog bg Избор на цена
|
||||
select a priority for this task infolog bg приоритет на задачата
|
||||
select a project infolog bg Изберете проект
|
||||
select a responsible user: a person you want to delegate this task infolog bg избор на отговорник: потребител, на който да делегирате тази задача
|
||||
select a typ to edit it's status-values or delete it infolog bg изберете тип за да редактирате статуса или да го изтриете
|
||||
select an app to search in infolog bg Изберете приложение, в което да се търси
|
||||
select an entry to link with infolog bg Изберете запис, с който да се свърже
|
||||
select to filter by owner infolog bg филтър по собственик
|
||||
select to filter by responsible infolog bg филтър по отговорни
|
||||
sets the status of this entry and its subs to done infolog bg Маркира записа заедно с под-зап. като Изпълнени
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog bg Дневникът да показва ли Под-задачите, -обажданията -бележките в стандартния изглед или не. Тези елементи винаги могат да бъдат показани чрез "родителите" им.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog bg Дневникът да показва ли връзките към други приложения и/или приложените файлове в "Дневник-списък" (стандартния изглед при влизане в Дневник)?
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog bg Да се показва ли Дневникът на главния екран и с какъв филтър. Работи само, ако не сте избрали приложение за главния екран (в настройките)?
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog bg Да се използват ли пълните имена (име, презиме и фамилия) или само потребителските имена?
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog bg В списъка на Дневника да се показва ли уникалния цифров идентификатор, който може да се използва примерно като No. на етикет?
|
||||
should the infolog list show the column "last modified". infolog bg Да се показва ли в списъка на Дневника колоната "последно изменен"?
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog bg Да показва ли в списъка на Дневника степента на изпълнение само за състоящите се в момента, или две отделни икони?
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog bg да бъде ли този запис видим само за Вас и хората, на които сте дали достъп до Лични чрез ACL-списъка (за контрол на достъпа)
|
||||
show a column for used and planned times in the list. infolog bg Показва колона за използваното и планираното време в списъка.
|
||||
show full usernames infolog bg Показва пълните имена на потребители
|
||||
show in the infolog list infolog bg Показва списък на Дневника
|
||||
show last modified infolog bg Последно променени
|
||||
show status and percent done separate infolog bg Статус и степен на изпълнение отделно
|
||||
show ticket id infolog bg Показва No. на етикет
|
||||
show times infolog bg Показва времената
|
||||
small view infolog bg умален изглед
|
||||
start a new search, cancel this link infolog bg Започва ново търсене, отказва тази връзка
|
||||
startdate infolog bg Начална дата
|
||||
startdate enddate infolog bg Начална дата дата за прикл.
|
||||
startdate for new entries infolog bg Начална дата за новите записи
|
||||
startrecord infolog bg Начален запис
|
||||
status infolog bg Статус
|
||||
status ... infolog bg Статус...
|
||||
sub infolog bg Под-
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog bg Под-записите са такива за "родителските" или главните записи, ако няма "родителски"
|
||||
subject infolog bg Тема
|
||||
task infolog bg Предстоящо
|
||||
template infolog bg Шаблон
|
||||
test import (show importable records <u>only</u> in browser) infolog bg Тестов импорт (показва импортируемите записи <u>само</u> в браузъра)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog bg името, използвано в системата (до 10 символа) Промяната му прави съществуващите данни недостъпни
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog bg името, използвано в системата (до 20 символа) Промяната му прави съществуващите данни недостъпни
|
||||
the text displayed to the user infolog bg текстът, показван на потребителя
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog bg Филтърът, който Дневникът използва, когато влезете в него. Филтрите ограничават записите, които се показват. Има филтри за показване само на приключените, неприключените или предстоящи елементи за Вас или всички потребители.
|
||||
til when should the todo or phonecall be finished infolog bg до кога да приключи Предстоящо или Тел. обаждане
|
||||
times infolog bg Времена
|
||||
to many might exceed your execution-time-limit infolog bg твърде много могат да надвишат максималното време за изпълнение
|
||||
to what should the startdate of new entries be set. infolog bg Каква да бъде началната дата за новите записи.
|
||||
today infolog bg Днес
|
||||
todays date infolog bg днешна дата
|
||||
todo infolog bg Предстоящо
|
||||
translation infolog bg Превод
|
||||
typ infolog bg Тип
|
||||
typ '%1' already exists !!! infolog bg Тип '%1' вече съществува !!!
|
||||
type infolog bg Тип
|
||||
type ... infolog bg Тип ...
|
||||
type of customfield infolog bg Тип на полето по избор
|
||||
type of the log-entry: note, phonecall or todo infolog bg Тип на записа: Бележка, Тел.обаждане или Предстоящо
|
||||
unlink infolog bg Премахва връзка
|
||||
upcoming infolog bg предстоящ
|
||||
urgency infolog bg спешност
|
||||
urgent infolog bg спешно
|
||||
used time infolog bg използвано време
|
||||
valid path on clientside<br>eg. \servershare or e: infolog bg валиден път от страна на клиента<br>напр. \\Server\Share или e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog bg валиден път от страна на клиента<br>напр. \\Server\Share или e:\
|
||||
values for selectbox infolog bg Стойности за избор
|
||||
view all subs of this entry infolog bg Показва всички под- на записа
|
||||
view other subs infolog bg показва другите Под-
|
||||
view parent infolog bg Показва "Родителя"
|
||||
view subs infolog bg показва Под-
|
||||
view the parent of this entry and all his subs infolog bg Показва Родителя на записа и всичките му под-
|
||||
view this linked entry in its application infolog bg показва свързания запис в съотв. приложение
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog bg Кои допълнителни полета да бъдат достъпни за редакция от отговорника, без да има съответните права?<br />Статус, степен на изпълнение и датата на приключване винаги са достъпни.
|
||||
which implicit acl rights should the responsible get? infolog bg Какви права от Списъка за контрол на достъпа (ACL) да получава отговорника при назначаването си?
|
||||
which types should the calendar show infolog bg Кои типове да се показват в Календара
|
||||
whole query infolog bg всички резултати
|
||||
will-call infolog bg ще телефонира
|
||||
write (add or update) a record by passing its fields. infolog bg Запис (добавяне или актуализация) на запис чрез подаване на полетата му
|
||||
yes - delete infolog bg Да - Изтриване
|
||||
yes - delete including sub-entries infolog bg Да - Изтриване с под-записите
|
||||
yes, noone can purge deleted items infolog bg Да, никой не може да заличава изтрити записи
|
||||
yes, only admins can purge deleted items infolog bg Да, само администраторите могат да заличават изтрити записи
|
||||
yes, with larger fontsize infolog bg Да, с по-голям размер на шрифта
|
||||
yes, with purging of deleted items possible infolog bg Да, с възможност за заличаване на изтрити записи
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog bg Може да настроите предварителен избор на категория при създаване на нов запис
|
||||
you have entered an invalid ending date infolog bg Въвели сте невалидна дата на приключване
|
||||
you have entered an invalid starting date infolog bg Въвели сте невалидна начална дата
|
||||
you have to enter a name, to create a new typ!!! infolog bg За създаване на нов тип е необходимо да въведете име!!!
|
||||
you must enter a subject or a description infolog bg Необходимо е да въведете тема или описание
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog bg Базата данни не е обновена (%1 вм. %2). Моля, използвайте %3setup%4 за обновяване.
|
325
infolog/lang/egw_ca.lang
Normal file
325
infolog/lang/egw_ca.lang
Normal file
@ -0,0 +1,325 @@
|
||||
%1 modified by %2 at %3 infolog ca %1 modificat per %2 a %3
|
||||
%1 records imported infolog ca %1 registres importats
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog ca %1 registres llegits (encara sense importar, podeu %2tornar%3 i desmarcar Provar d'Importació)
|
||||
- subprojects from infolog ca - Subprojectes de
|
||||
0% infolog ca 0%
|
||||
10% infolog ca 10%
|
||||
100% infolog ca 100%
|
||||
20% infolog ca 20%
|
||||
30% infolog ca 30%
|
||||
40% infolog ca 40%
|
||||
50% infolog ca 50%
|
||||
60% infolog ca 60%
|
||||
70% infolog ca 70%
|
||||
80% infolog ca 80%
|
||||
90% infolog ca 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog ca <b>fitxers adjunts via enllaços simbòlics</b> en lloc d'enviaments i recuperacions via fitxer:/ruta per clients de la xarxa local
|
||||
a short subject for the entry infolog ca descripció curta per l'entrada
|
||||
abort without deleting infolog ca Cancel·lar sense esborrar
|
||||
accept infolog ca acceptar
|
||||
action infolog ca Acció
|
||||
actual date and time infolog ca Data i hora actual
|
||||
add infolog ca Afegir
|
||||
add a file infolog ca Afegir arxiu
|
||||
add a new entry infolog ca Afegir una nova entrada
|
||||
add a new note infolog ca Afegir una nova nota
|
||||
add a new phonecall infolog ca Afegir una nova trucada
|
||||
add a new sub-task, -note, -call to this entry infolog ca Afegir nova subtasca, -nota-, -trucada a aquesta entrada
|
||||
add a new todo infolog ca Afegir nova tasca pendent
|
||||
add file infolog ca Afegir arxiu
|
||||
add sub infolog ca afegir Sub
|
||||
add timesheet entry infolog ca Afegeix entrada d'horari
|
||||
add: infolog ca Afegir:
|
||||
all infolog ca Tots
|
||||
all links and attachments infolog ca tots els enllaços i arxius adjunts
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog ca permet establir l'estat d'una entrada, p.e. posar una tasca pendent com a finalitzada si està acabada (els valors depenen del tipus d'entrada)
|
||||
apply the changes infolog ca Aplica els canvis
|
||||
are you shure you want to delete this entry ? infolog ca Esteu segurs d'esborrar aquesta entrada?
|
||||
attach a file infolog ca Adjunta un arxiu
|
||||
attach file infolog ca Adjunta arxiu
|
||||
attension: no contact with address %1 found. infolog ca Atenció: No s'ha trobat el contacte amb l'adreça %1
|
||||
attention: no contact with address %1 found. infolog ca Atenció: No s'ha trobat el contacte amb l'adreça %1
|
||||
back to main list infolog ca Tornar a la llista principal
|
||||
billed infolog ca facturat
|
||||
both infolog ca ambdós
|
||||
call infolog ca truca
|
||||
cancel infolog ca Cancel·la
|
||||
cancelled infolog ca cancel·lat
|
||||
categories infolog ca Categories
|
||||
category infolog ca Categoria
|
||||
change the status of an entry, eg. close it infolog ca Canviar l'estat d'una entrada, ex. tancar-la
|
||||
charset of file infolog ca Joc de caràcters de l'arxiu
|
||||
check to set startday infolog ca marca per establir data d'inici
|
||||
check to specify custom contact infolog ca Comproveu per especificat el contacte personalitzat
|
||||
click here to create the link infolog ca premeu aquí per crear un enllaç
|
||||
click here to start the search infolog ca premeu aquí per començar la recerca
|
||||
close infolog ca Tancar
|
||||
comment infolog ca Comentari
|
||||
completed infolog ca Complet
|
||||
configuration infolog ca Configuració
|
||||
confirm infolog ca confirmar
|
||||
contact infolog ca Contacte
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog ca Copia els teus canvis al portapapers, %1recarrega l'entrada%2 i ajunta-ho.
|
||||
create new links infolog ca Crear nous enllaços
|
||||
creates a new field infolog ca crea un camp nou
|
||||
creates a new status with the given values infolog ca crea un nou estat amb els valors donats
|
||||
creates a new typ with the given name infolog ca crea un nou tipus amb el nom donat
|
||||
creation infolog ca Creació
|
||||
csv-fieldname infolog ca CSV-Nom de Camp
|
||||
csv-filename infolog ca CSV-Nom d'Arxiu
|
||||
csv-import common ca CSV-Importar
|
||||
custom infolog ca Personalitzat
|
||||
custom contact-address, leave empty to use information from most recent link infolog ca Adreça de contacte personalitzada. Deixar en blanc per usar la informació de l'enllaç més recent
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog ca Informació de contacte personalitzada. Deixar en blanc per usar la informació de l'enllaç més recent
|
||||
custom fields infolog ca Camps personalitzats
|
||||
custom fields, typ and status common ca Camps personalitzats, tipus i estat
|
||||
custom regarding infolog ca Records personals
|
||||
custom status for typ infolog ca Estat personalitzat per al tipus
|
||||
customfields infolog ca Camps personalitzats
|
||||
date completed infolog ca Data complerta
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog ca Data complerta (deixeu-la buida per
|
||||
datecreated infolog ca data de creació
|
||||
dates, status, access infolog ca Dates, Estat, Accés
|
||||
days infolog ca dies
|
||||
default filter for infolog infolog ca Filtre predeterminat per Tasques
|
||||
default status for a new log entry infolog ca Estat predeterminat per a una nova entrada de registre
|
||||
delegation infolog ca Delegació
|
||||
delete infolog ca Esborrar
|
||||
delete one record by passing its id. infolog ca Suprimeix un registre indicant el seu ID.
|
||||
delete the entry infolog ca Esborrar l'entrada
|
||||
delete this entry infolog ca esborrar aquesta entrada
|
||||
delete this entry and all listed sub-entries infolog ca Esborra aquesta entrada i totes les subentrades llistades
|
||||
deletes the selected typ infolog ca esborra el tipus seleccionat
|
||||
deletes this field infolog ca esborra aquest camp
|
||||
deletes this status infolog ca esborra aquest estat
|
||||
description infolog ca Descripció
|
||||
determines the order the fields are displayed infolog ca determina l'ordre en que es mostren els camps
|
||||
disables a status without deleting it infolog ca desactiva un estat sense esborrar-lo
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog ca Voleu una confirmació del responsable en acceptar, finalitzar la tasca, o ambdues coses?
|
||||
do you want a notification mail, if items you created get updated? infolog ca Voleu un e-mail de notificació si els elements que heu creat són actualitzats?
|
||||
do you want a notification mails, if items get assigned to you or assigned items get updated? infolog ca Voleu un e-mail de notificació si us assignen elements o si els elements assignats són actualitzats?
|
||||
do you want to receive notifications as html-mails or plain text? infolog ca Voleu rebre notificacions com e-mails html o text simple?
|
||||
do you want to see custom infolog types in the calendar? infolog ca Voleu veure tipus personalitzats de Tasques i Notes al calendari?
|
||||
don't show infolog infolog ca NO mostris Tasques i Notes
|
||||
done infolog ca fet
|
||||
download infolog ca Descarregar
|
||||
duration infolog ca Duració
|
||||
each value is a line like <id>[=<label>] infolog ca cada valor és una línia com <id>[=<etiqueta>]
|
||||
edit infolog ca Editar
|
||||
edit or create categories for ingolog infolog ca Editar o crear categories per les Tasques
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog ca drets d'edició (drets totals d'edició inclouen fer algú responsable)
|
||||
edit status infolog ca Editar Estat
|
||||
edit the entry infolog ca Editar l'entrada
|
||||
edit this entry infolog ca Editar aquesta entrada
|
||||
empty for all infolog ca buidar tot
|
||||
enddate infolog ca Data de finalització
|
||||
enddate can not be before startdate infolog ca La data de finalització no pot ser anterior a la d'inici
|
||||
enter a custom contact, leave empty if linked entry should be used infolog ca entreu un contacte personalitzat, o deixeu-lo buit si preferiu usar un enllaç
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog ca entreu un telèfon o correu electrònic personalitzat, o deixeu-lo buit si preferiu usar un enllaç
|
||||
enter a textual description of the log-entry infolog ca entreu un text descriptiu de l'entrada
|
||||
enter the query pattern infolog ca entreu el patró de recerca
|
||||
entry and all files infolog ca Entrada i tots els arxius
|
||||
error: saving the entry infolog ca Error guardant l'entrada
|
||||
error: the entry has been updated since you opened it for editing! infolog ca Error: l'entrada ha estat actualitzada des de que l'has obert per editar-la!
|
||||
existing links infolog ca Enllaços existents
|
||||
fax infolog ca Fax
|
||||
field must not be empty !!! infolog ca El camp no ha d'estar buit !!!
|
||||
fieldseparator infolog ca Separador de camps
|
||||
finish infolog ca finalitzar
|
||||
for which types should this field be used infolog ca per quins tipus s'utilitza aquest camp
|
||||
from infolog ca De
|
||||
general infolog ca General
|
||||
group owner for infolog ca Propietari de grup per
|
||||
high infolog ca alta
|
||||
id infolog ca id
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog ca Si un tipus té un propietari de grup, totes les entrades del tipus seran del grup donat i no de l'usuari que l'ha creat!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog ca Si no se posa, la línia amb cerca i filtres s'amaga per menys entrades de "max coincidències per pàgina" (definit a les teves preferències comuns).
|
||||
import infolog ca Importar
|
||||
import next set infolog ca importar grup següent
|
||||
info log common ca Tasques i Notes
|
||||
infolog common ca Tasques i Notes
|
||||
infolog - delete infolog ca Tasques i Notes - Esborrar
|
||||
infolog - edit infolog ca Tasques i Notes - Editar
|
||||
infolog - import csv-file infolog ca Tasques i Notes - Importar arxiu CSV
|
||||
infolog - new infolog ca Tasques i Notes - Nou
|
||||
infolog - new subproject infolog ca Tasques i Notes - Nou Subprojecte
|
||||
infolog - subprojects from infolog ca Tasques i Notes- Subprojectes de
|
||||
infolog entry deleted infolog ca Entrada de Tasques i Notes esborrada
|
||||
infolog entry saved infolog ca Entrada de Tasques i notes desada
|
||||
infolog filter for the main screen infolog ca Filtre de Tasques i Notes per la pàgina d'inici
|
||||
infolog list infolog ca Llista de Tasques i Notes
|
||||
infolog preferences common ca Preferències de Tasques i Notes
|
||||
infolog-fieldname infolog ca Tasques i Notes - Nom de Camp
|
||||
invalid filename infolog ca El nom d'arxiu no és vàlid
|
||||
label<br>helptext infolog ca Marca<br>Text d'ajuda
|
||||
last changed infolog ca Darrer canvi
|
||||
last modified infolog ca Darrera modificació
|
||||
leave it empty infolog ca deixa-ho buit
|
||||
leave without saveing the entry infolog ca Sortir sense desar l'entrada
|
||||
leaves without saveing infolog ca Sortir sense desar
|
||||
length<br>rows infolog ca Longitud<br>Files
|
||||
link infolog ca Enllaç
|
||||
links infolog ca Enllaços
|
||||
links of this entry infolog ca Enllaços de l'entrada
|
||||
list all categories infolog ca Llista totes les categories
|
||||
list no subs/childs infolog ca No llistar Subs/Fills
|
||||
location infolog ca Ubicació
|
||||
longer textual description infolog ca descripció llarga de l'entrada
|
||||
low infolog ca baix
|
||||
max length of the input [, length of the inputfield (optional)] infolog ca longitud màxima de l'entrada [, longitud del camp d'entrada (opcional)]
|
||||
name must not be empty !!! infolog ca El nom no pot estar buit !!!
|
||||
name of new type to create infolog ca Nom del nou tipus a crear
|
||||
never hide search and filters infolog ca Mai amaga cerca i filtres
|
||||
new %1 created by %2 at %3 infolog ca Nou %1 creat per %2 a %3
|
||||
new name infolog ca nou nom
|
||||
new search infolog ca Nova recerca
|
||||
no - cancel infolog ca No - Cancel·lar
|
||||
no describtion, links or attachments infolog ca sense descripció, links o adjunts
|
||||
no details infolog ca sense detalls
|
||||
no entries found, try again ... infolog ca no s'han trobat registres, intenteu de nou ...
|
||||
no filter infolog ca sense filtre
|
||||
no links or attachments infolog ca sense enllaços o adjunts
|
||||
none infolog ca Cap
|
||||
normal infolog ca normal
|
||||
not infolog ca no
|
||||
not assigned infolog ca sense assignar
|
||||
not-started infolog ca sense començar
|
||||
note infolog ca Nota
|
||||
number of records to read (%1) infolog ca Nombre de registres a llegir (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog ca Número de fila per a un quadre de text multilínia o llista desplegable multiselecció
|
||||
offer infolog ca suggerit
|
||||
ongoing infolog ca en curs
|
||||
only for details infolog ca Només per detalls
|
||||
only the attachments infolog ca només adjunts
|
||||
only the links infolog ca només enllaços
|
||||
open infolog ca obert
|
||||
optional note to the link infolog ca nota opcional per a l'enllaç
|
||||
order infolog ca Ordre
|
||||
overdue infolog ca vençut
|
||||
own infolog ca propi
|
||||
own open infolog ca propi obert
|
||||
own overdue infolog ca propi vençut
|
||||
own upcoming infolog ca propi en camí
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog ca Ruta al servidor (web) <br>ex. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog ca La ruta als arxius d'usuari i grups HA D'ESTAR FORA de l'estructura de directoris del servidor web!!
|
||||
pattern for search in addressbook infolog ca patró a cercar a la Llibreta d'Adreces
|
||||
pattern for search in projects infolog ca patró a cercar dins Projectes
|
||||
percent completed infolog ca Percentatge completat
|
||||
permission denied infolog ca Permís denegat
|
||||
phone infolog ca Trucada Telefònica
|
||||
phone/email infolog ca Telèfon/Correu electrònic
|
||||
phonecall infolog ca Trucada Telefònica
|
||||
planned infolog ca panificat
|
||||
planned time infolog ca temps planificat
|
||||
price infolog ca Preu
|
||||
priority infolog ca Prioritat
|
||||
private infolog ca Privat
|
||||
project infolog ca Projecte
|
||||
project settings: price, times infolog ca Configuració del projecte: preu, horaris
|
||||
re: infolog ca Re:
|
||||
read one record by passing its id. infolog ca Llegeix un registre introduïnt el seu ID.
|
||||
read rights (default) infolog ca llegiu els drets (per defecte)
|
||||
receive notifications about items assigned to you infolog ca Rebeu notificacions sobre els vostres elements assignats
|
||||
receive notifications about own items infolog ca Rebeu notificacions sobre els vostres propis elements
|
||||
receive notifications as html-mails infolog ca Rebeu notificacions com a e-mails html
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog ca expressió regular per IPs locals <br>ex. ^192\.168\.1\.
|
||||
remark infolog ca Comentari
|
||||
remove this link (not the entry itself) infolog ca Eliminar aquest enllaç (no l'entrada)
|
||||
responsible infolog ca Responsable
|
||||
responsible open infolog ca responsable obrir
|
||||
responsible overdue infolog ca responsable restràs
|
||||
responsible upcoming infolog ca responsable pròxim
|
||||
responsible user, priority infolog ca usuari responsable, prioritat
|
||||
returns a list / search for records. infolog ca Retorna una llista / cerca registres.
|
||||
rights for the responsible infolog ca Drets del responsable
|
||||
save infolog ca Desar
|
||||
saves the changes made and leaves infolog ca Desar els canvis fets i sortir
|
||||
saves this entry infolog ca Desar aquesta entrada
|
||||
search infolog ca Cercar
|
||||
search for: infolog ca Cercar per:
|
||||
select infolog ca Seleccionar
|
||||
select a category for this entry infolog ca seleccionar una categoria per aquesta entrada
|
||||
select a price infolog ca Selecciona un preu
|
||||
select a priority for this task infolog ca seleccionar una prioritat per aquesta tasca
|
||||
select a project infolog ca Selecciona un projecte
|
||||
select a responsible user: a person you want to delegate this task infolog ca seleccionar un responsable: una persona en la que es vol delegar la tasca
|
||||
select a typ to edit it's status-values or delete it infolog ca seleccionar un tipus per editar els seus valors d'estat o esborrar-lo
|
||||
select an app to search in infolog ca Seleccionar una aplicació on cercar
|
||||
select an entry to link with infolog ca Seleccionar una entrada per enllaçar
|
||||
select to filter by owner infolog ca selecciona filtrar per propietari
|
||||
select to filter by responsible infolog ca selecciona filtrar per responsable
|
||||
sets the status of this entry and its subs to done infolog ca Estableix l'estat d'aquesta entrada i les seves subtasques com a fetes.
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog ca S'han de mostrar les Subtasques, (subtrucades o subnotes) a la visualització normal? Podeu veure sempre els subtipus a través del seu tipus pare.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog ca Tasques i Notes hauria de mostrar els enllaços a altres aplicacions i/o els fitxers adjunts dins la llista de Tasques i Notes (vista normal quan entres a Tasques i Notes).
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog ca Tasques i Notes hauria de mostrar-se a la pàgina d'inici i amb quin filtre. Funciona només si no seleccioneu una aplicació per la pantalla d'inici (en les vostres preferències).
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog ca Fem servir noms complets (cognom i nom de pila), o només els noms d'usuari de l'aplicació?
|
||||
should the calendar show custom types too infolog ca El calendari ha de mostrar tipus personalitzats també
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog ca La llista de Tasques i Notes ha de mostrar un únic Id numèric, que pot ser utilitzat p.e. com ticket Id.
|
||||
should the infolog list show the column "last modified". infolog ca La llista de Tasques i Notes ha de mostrar la columna "darrera modificació".
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog ca La llista de Tasques i Notes ha de mostrar el percentatge fet només per estat iniciat o per dues icones separades.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog ca Aquesta entrada ha de ser visible només per vos i a qui atorgueu accés privat mitjançant la llista LCA?
|
||||
show a column for used and planned times in the list. infolog ca Mostra una columna per a horaris utilitzats i planificats de la llista.
|
||||
show full usernames infolog ca Mostrar noms d'usuari complets
|
||||
show in the infolog list infolog ca Mostrar la llista de Tasques i Notes
|
||||
show last modified infolog ca Mostra la darrera modificació
|
||||
show status and percent done separate infolog ca Mostra per separat l'estat i el percentatge completat
|
||||
show ticket id infolog ca Mostra ticket Id
|
||||
show times infolog ca Mostra horaris
|
||||
small view infolog ca vista reduïda
|
||||
start a new search, cancel this link infolog ca iniciar nova recerca, cancel·lar aquest enllaç
|
||||
startdate infolog ca Data d'inici
|
||||
startdate enddate infolog ca Dates d'inici i fi
|
||||
startdate for new entries infolog ca Data d'inici per a noves entrades
|
||||
startrecord infolog ca Començar gravació de registre
|
||||
status infolog ca Estat
|
||||
status ... infolog ca Estat...
|
||||
sub infolog ca Sub
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog ca Les subentrades se converteixen en filles de l'entrada pare o de l'entrada principal si no té pare.
|
||||
subject infolog ca Assumpte
|
||||
task infolog ca Tasca
|
||||
test import (show importable records <u>only</u> in browser) infolog ca Prova d'Importació (mostrar registres importables <u>només</u> al navegador)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog ca nom utilitzat internament (<= 10 caràcters). Si es canvia algunes dades seran inaccessibles
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog ca nom utilitzat internament (<= 20 caràcters). Si es canvia algunes dades seran inaccessibles
|
||||
the text displayed to the user infolog ca el text mostrat a l'usuari
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog ca Aquest és el filtre que Tasques i Notes usa quan entreu a l'aplicació. Els filtres limiten les entrades que es mostren a la vista actual. Hi ha filtres per mostrar només les acabades, encara obertes o entrades futures vostres o de tots els usuaris.
|
||||
til when should the todo or phonecall be finished infolog ca Quan s'ha de finalitzar la tasca o trucada telefònica?
|
||||
times infolog ca Hores
|
||||
to many might exceed your execution-time-limit infolog ca Quant es pot excedir el límit de temps d'execució?
|
||||
to what should the startdate of new entries be set. infolog ca En relació a què s'ha d'establir la data d'inici de les noves entrades.
|
||||
today infolog ca Avui
|
||||
todays date infolog ca data d'avui
|
||||
todo infolog ca Tasques Pendents
|
||||
translation infolog ca Traducció
|
||||
typ infolog ca Tipus
|
||||
typ '%1' already exists !!! infolog ca El tipus '%1' ja existeix!
|
||||
type infolog ca Tipus
|
||||
type ... infolog ca Tipus...
|
||||
type of customfield infolog ca Tipus de camp personalitzat
|
||||
type of the log-entry: note, phonecall or todo infolog ca Tipus d'entrada: Nota, Trucada Telefònica o Tasca Pendent
|
||||
unlink infolog ca Desenllaçar
|
||||
upcoming infolog ca propera
|
||||
urgency infolog ca Urgència
|
||||
urgent infolog ca urgent
|
||||
used time infolog ca temps usat
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog ca Ruta vàlida en el client<br>ex. \\servidor\recurs o e:\
|
||||
values for selectbox infolog ca Valors per a llista desplegable
|
||||
view all subs of this entry infolog ca Veure tots els subs d'aquesta entrada
|
||||
view other subs infolog ca veure altres subs
|
||||
view parent infolog ca Veure pare
|
||||
view subs infolog ca Veure subs
|
||||
view the parent of this entry and all his subs infolog ca Veure el pare d'aquesta entrada i tots els seus subs
|
||||
view this linked entry in its application infolog ca Veure aquesta entrada vinculada a la seva aplicació
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog ca Quan s'han d'iniciar les Tasques Pendents o les Trucades Telefòniques. Es mostra a la data del filtre o en obrir manualment a la plana d'inici
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog ca Quins camps adicionals pot editar el responsable sense tenir drets per editar?<br />,Estat, percentatge i data complerta sempre estan permesos.
|
||||
which implicit acl rights should the responsible get? infolog ca Quins drets ACL implícits ha de tenir el responsable?
|
||||
whole query infolog ca consulta sencera
|
||||
will-call infolog ca trucarà
|
||||
write (add or update) a record by passing its fields. infolog ca Escriu (afegeix o actualitza) un registre, introduïnt els seus camps.
|
||||
yes - delete infolog ca Sí - Esborrar
|
||||
yes - delete including sub-entries infolog ca Sí - Esborrar incloent subentrades
|
||||
you can't delete one of the stock types !!! infolog ca No podeu esborrar un dels tipus de cotitzacions !!
|
||||
you have entered an invalid ending date infolog ca Heu entrat una data incorrecta de finalització
|
||||
you have entered an invalid starting date infolog ca Heu entrat una data incorrecta d'inici
|
||||
you have to enter a name, to create a new typ!!! infolog ca Heu d'entrar un nom per crear un tipus nou!!!
|
||||
you must enter a subject or a description infolog ca Heu d'entrar un assumpte o descripció
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog ca La teva base de dades NO està al dia (%1 vs. %2), per favor, executa %3setup%4 per actualitzar la teva base de dades.
|
@ -75,7 +75,7 @@ completed infolog cs Ukončeno
|
||||
configuration infolog cs Konfigurace
|
||||
confirm infolog cs Potvrdit
|
||||
contact infolog cs Kontakt
|
||||
copy of: infolog cs Kopie (čeho):
|
||||
copy of: infolog cs Kopie z:
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog cs Zkopírujte Vaše úpravy do clipboardu, %1načtěte znovu záznam%2 a slučte je.
|
||||
create new links infolog cs Vytvořit nové odkazy
|
||||
creates a new field infolog cs vytvoří novou položku
|
||||
@ -104,6 +104,7 @@ default filter for infolog infolog cs Výchozí filtr pro InfoLog
|
||||
default status for a new log entry infolog cs výchozí stav pro nový záznam
|
||||
delegated infolog cs delegované
|
||||
delegated open infolog cs delegované otevřené
|
||||
delegated open and upcoming infolog cs delegované otevřené a nadcházející
|
||||
delegated overdue infolog cs delegované po termínu
|
||||
delegated upcomming infolog cs delegované nadcházející
|
||||
delegation infolog cs Pověření
|
||||
@ -130,6 +131,7 @@ do you want to receive notifications as html-mails or plain text? infolog cs Chc
|
||||
don't show infolog infolog cs NEzobrazovat InfoLog
|
||||
done infolog cs hotovo
|
||||
download infolog cs Stáhnout
|
||||
due %1 infolog cs Do %1
|
||||
duration infolog cs Trvání
|
||||
e-mail: infolog cs E-mail:
|
||||
each value is a line like <id>[=<label>] infolog cs každá hodnota je řádkem jako <id>[=<label>]
|
||||
@ -179,7 +181,7 @@ infolog - import csv-file infolog cs InfoLog - Importovat CSV soubor
|
||||
infolog - new infolog cs InfoLog - Nový
|
||||
infolog - new subproject infolog cs InfoLog - Nový podprojekt
|
||||
infolog - subprojects from infolog cs InfoLog - Podprojekty (čeho)
|
||||
infolog copied - the copy can now be edited infolog cs InfoLog zkopírován - kopii lze nyní editovat
|
||||
infolog copied - the copy can now be edited infolog cs Infolog byl zkopírován a kopii lze nyní editovat
|
||||
infolog entry deleted infolog cs Záznam InfoLogu smazán
|
||||
infolog entry saved infolog cs Záznam InfoLogu uložen
|
||||
infolog filter for the main screen infolog cs Filtr InfoLogu pro hlavní obrazovku
|
||||
@ -205,7 +207,6 @@ location infolog cs Umístění
|
||||
longer textual description infolog cs delší textový popis
|
||||
low infolog cs Nízká
|
||||
max length of the input [, length of the inputfield (optional)] infolog cs maximální délka vstupu (volitelné)
|
||||
modifierer infolog cs Modifikátor
|
||||
name must not be empty !!! infolog cs Název nemůže být prázdný !!!
|
||||
name of new type to create infolog cs název nově vytvářeného typu
|
||||
never hide search and filters infolog cs Nikdy neskrývat hledání a filtry
|
||||
@ -238,12 +239,14 @@ only if i get assigned or removed infolog cs Jen pokud budu přidělen nebo odeb
|
||||
only the attachments infolog cs jen přílohy
|
||||
only the links infolog cs jen odkazy
|
||||
open infolog cs otevřít
|
||||
open and upcoming infolog cs otevřené a nadcházející
|
||||
optional note to the link infolog cs volitelná poznámka k odkazu
|
||||
order infolog cs Pořadí
|
||||
organization infolog cs Organizace
|
||||
overdue infolog cs po termínu
|
||||
own infolog cs vlastní
|
||||
own open infolog cs vlastní otevřené
|
||||
own open and upcoming infolog cs vlastní otevřené a nadcházející
|
||||
own overdue infolog cs vlastní po termínu
|
||||
own upcoming infolog cs vlastní nadcházející
|
||||
parent infolog cs Nadřazený
|
||||
@ -258,7 +261,7 @@ phone infolog cs Telefonní hovor
|
||||
phone/email infolog cs Telefon/E-mail
|
||||
phonecall infolog cs Telefonní hovor
|
||||
planned infolog cs plánované
|
||||
planned time infolog cs plánovaný čas
|
||||
planned time infolog cs Plánovaný čas
|
||||
price infolog cs Cena
|
||||
pricelist infolog cs Ceník
|
||||
primary link infolog cs hlavní odkaz
|
||||
@ -284,6 +287,7 @@ remark infolog cs Poznámka
|
||||
remove this link (not the entry itself) infolog cs Odstranit tento odkaz (ne celý záznam)
|
||||
responsible infolog cs odpovědný
|
||||
responsible open infolog cs odpovědný - otevřené
|
||||
responsible open and upcoming infolog cs odpovědný - otevřené a nadcházející
|
||||
responsible overdue infolog cs odpovědný - po termínu
|
||||
responsible upcoming infolog cs odpovědný - nastávající
|
||||
responsible user, priority infolog cs odpovědný uživatel, priorita
|
||||
@ -307,8 +311,8 @@ select an entry to link with infolog cs Vybrat záznam, na který se má odkazov
|
||||
select to filter by owner infolog cs vybrat pro filtrování dle vlastníka
|
||||
select to filter by responsible infolog cs vybrat pro filtrování dle odpovědné osoby
|
||||
sender infolog cs Odesílatel
|
||||
set status to done infolog cs Změnit stav na hotovo
|
||||
set status to done for all entries infolog cs Změnit stav na hotovo u všech záznamů
|
||||
set status to done infolog cs Nastavit stav na hotovo
|
||||
set status to done for all entries infolog cs Nastavit stav na hotovo pro všechny záznamy
|
||||
sets the status of this entry and its subs to done infolog cs Nastavit stav záznamu a jeho podpoložek na hotový
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog cs Má InfoLog zobrazovat Pod-úkoly, -hovory nebo -poznámky v normálním zobrazení nebo ne? Podpoložky můžete vždy zobrazit přes jejich rodiče.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog cs Má InfoLog zobrazovat odkazy na ostatní aplikace nebo připojené soubory v seznamu InfoLogu nebo ne (normální zobrazení při vstupu do InfoLogu)?
|
||||
@ -330,6 +334,7 @@ start a new search, cancel this link infolog cs začít nové hledání, zrušit
|
||||
startdate infolog cs Počáteční datum
|
||||
startdate enddate infolog cs Počáteční datum Datum dokončení
|
||||
startdate for new entries infolog cs Počáteční datum pro nové záznamy
|
||||
starting %1 infolog cs Začíná %1
|
||||
startrecord infolog cs První záznam
|
||||
status infolog cs Stav
|
||||
status ... infolog cs Stav ...
|
||||
@ -338,6 +343,7 @@ sub-entries become subs of the parent or main entries, if there's no parent info
|
||||
subject infolog cs Předmět
|
||||
sum infolog cs Celkem
|
||||
task infolog cs Úkol
|
||||
tasks of infolog cs Úkoly
|
||||
template infolog cs Šablona
|
||||
test import (show importable records <u>only</u> in browser) infolog cs Testovat import (zobrazit importovatelné záznamy <u>jen</u> v prohlížeči)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog cs název používaný interně (<= 10 znaků), jeho změna způsobí nedostupnost stávajících dat
|
||||
@ -376,6 +382,7 @@ when should the todo or phonecall be started, it shows up from that date in the
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog cs Které dodatečné položky má mít odpovědná osoba možnost editovat bez toho, že by měla práva k editaci?<br>Stav, procento a datum dokončení může vždy.
|
||||
which implicit acl rights should the responsible get? infolog cs Jaká implicitní ACL práva má odpovědná osoba dostat?
|
||||
which types should the calendar show infolog cs Které typy má kalendář zobrazovat
|
||||
whole query infolog cs celý dotaz
|
||||
will-call infolog cs zavolá
|
||||
write (add or update) a record by passing its fields. infolog cs Zapsat (přidat nebo smazat) záznam zadáním jeho položek.
|
||||
yes - close infolog cs Ano - uzavřít
|
||||
|
488
infolog/lang/egw_de.lang
Normal file
488
infolog/lang/egw_de.lang
Normal file
@ -0,0 +1,488 @@
|
||||
%1 days in advance infolog de %1 Tage im Voraus
|
||||
%1 deleted infolog de %1 gelöscht
|
||||
%1 deleted by %2 at %3 infolog de %1 wurde von %2 am %3 gelöscht
|
||||
%1 entries %2 infolog de %1 Einträge %2
|
||||
%1 entries %2, %3 failed because of insufficent rights !!! infolog de %1 Einträge %2, %3 wegen fehlender Rechte!!!
|
||||
%1 modified infolog de %1 geändert
|
||||
%1 modified by %2 at %3 infolog de %1 wurde von %2 am %3 geändert
|
||||
%1 records imported infolog de %1 Datensätze importiert
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog de %1 Datensätze gelesen (noch nicht importiert, sie können %2zurück%3 gehen und Test Import ausschalten)
|
||||
%1 you are responsible for is due at %2 infolog de %1 für die Sie verantwortlich sind ist am %2 fällig
|
||||
%1 you are responsible for is starting at %2 infolog de %1 für die Sie verantwortlich sind startet am %2
|
||||
%1 you delegated is due at %2 infolog de %1 die Sie delegierten ist am %2 fällig
|
||||
%1 you delegated is starting at %2 infolog de %1 die Sie delegierten startet am %2
|
||||
- subprojects from infolog de - Untereinträge von
|
||||
0% infolog de 0%
|
||||
10% infolog de 10%
|
||||
100% infolog de 100%
|
||||
20% infolog de 20%
|
||||
30% infolog de 30%
|
||||
40% infolog de 40%
|
||||
50% infolog de 50%
|
||||
60% infolog de 60%
|
||||
70% infolog de 70%
|
||||
80% infolog de 80%
|
||||
90% infolog de 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog de <b>Dateianhänge über Symlinks</b> anstatt sie hochzuladen und Zugriff mit file:/pfad für lokale Benutzer
|
||||
a short subject for the entry infolog de einen kurzen Titel für diesen Eintrag
|
||||
abort without deleting infolog de Abbruch ohne zu Löschen
|
||||
accept infolog de bei Annahme
|
||||
action infolog de Befehle
|
||||
actions... infolog de Befehle...
|
||||
actual date and time infolog de aktuelles Datum und Uhrzeit
|
||||
add infolog de Hinzufügen
|
||||
add / remove link infolog de Hinzufügen / Entfernen von Verknüpfungen
|
||||
add a file infolog de Datei anhängen
|
||||
add a new entry infolog de einen neuen Eintrag anlegen
|
||||
add a new note infolog de eine neue Notiz anlegen
|
||||
add a new phonecall infolog de einen neuen Telefonanruf anlegen
|
||||
add a new sub-task, -note, -call to this entry infolog de einen neuen Unterauftrag, -notiz, -anruf zu diesem Eintrag anlegen
|
||||
add a new todo infolog de einen neuen Auftrag anlegen
|
||||
add file infolog de Datei hinzufügen
|
||||
add or delete links infolog de Verknüpfungen hinzufügen oder löschen
|
||||
add sub infolog de neuen Untereintrag anlegen
|
||||
add timesheet entry infolog de Stundenzettel Eintrag hinzufügen
|
||||
add: infolog de Hinzufügen:
|
||||
added infolog de Hinzugefügt
|
||||
all infolog de alle
|
||||
all links and attachments infolog de alle Verknüpfungen und Anhänge
|
||||
all projects infolog de Alle Projekte
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog de erlaubt den Status eines Eintrags zu setzen, zB. eine Aufgabe auf erledigt wenn sie beendet ist (Werte hängen vom Type des Eintrags ab)
|
||||
alternatives infolog de Alternativen
|
||||
apply the action on the whole query, not only the shown entries!!! infolog de Wendet den Befehl auf die gesamte Abfrage an, NICHT nur auf die angezeigten Datensätze !!
|
||||
apply the changes infolog de Übernimmt die Änderungen
|
||||
archive infolog de Archiviert
|
||||
are you shure you want to close this entry ? infolog de Wollen Sie wirklich den Infolog schliessen?
|
||||
are you shure you want to delete this entry ? infolog de Sind Sie sicher, dass Sie diesen Eintrag löschen wollen?
|
||||
at the moment the following document-types are supported: infolog de Zur Zeit werden die folgenden Dokument Typen unterstützt:
|
||||
attach a file infolog de Datei anhängen
|
||||
attach file infolog de Datei anhängen
|
||||
attention: no contact with address %1 found. infolog de Achtung: Kein Kontakt mit der Adresse %1 gefunden!
|
||||
back to main list infolog de Zurück zur Gesamtliste
|
||||
billed infolog de abgerechnet
|
||||
both infolog de Annahme+erledigt
|
||||
call infolog de anrufen
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog de Kann dazu benutzt werden um weitere InfoLog Typen im Kalender anzuzeigen oder zu begrenzen dass z.B. nur noch Aufgaben angezeigt werden.
|
||||
cancel infolog de Abbruch
|
||||
cancelled infolog de abgesagt
|
||||
categories infolog de Kategorien
|
||||
category infolog de Kategorie
|
||||
change category infolog de Kategorie ändern
|
||||
change completed infolog de Änderungen duchgeführt
|
||||
change completion infolog de Bearbeitungsstatus ändern
|
||||
change history infolog de Änderungsverlauf
|
||||
change owner when updating infolog de Ändert den Benutzer bei bei diesem Änderungsvorgang
|
||||
change responsible infolog de Zuständigkeit ändern
|
||||
change status: infolog de Status ändern
|
||||
change the status of an entry, eg. close it infolog de Status eines Eintrags ändern, z.B. Ihn als erledigt markieren
|
||||
change type: infolog de Infolog Typ ändern
|
||||
changed category to %1 infolog de Kategorie geändert zu %1
|
||||
changed completion to %1% infolog de Bearbeitungsstatus geändert zu %1
|
||||
changed responsible infolog de Zuständigkeit ändern
|
||||
changed status to %1 infolog de Typ geändert zu %1
|
||||
changed type infolog de Typ ändern
|
||||
charset of file infolog de Zeichensatz der Datei
|
||||
check all infolog de Alle marktieren
|
||||
check to set startday infolog de ankreuzen um Startdatum zu setzen
|
||||
check to specify custom contact infolog de Ankreuzen um einen eigenen Kontakt anzugeben
|
||||
choose owner of imported data infolog de Wählen Sie den Eigentümer der Importierten Daten
|
||||
click here to create the link infolog de hier klicken um die Verknüpfung zu erzeugen
|
||||
click here to start the search infolog de hier klicken um die Suche zu starten
|
||||
close infolog de Schließen
|
||||
close all infolog de Alle schließen
|
||||
close this entry and all listed sub-entries infolog de Diesen Eintrag und alle Untereinträge schliessen
|
||||
closed infolog de geschlossen
|
||||
colon (:) separated list of field names to use if value is empty or to sum up infolog de Spalte (:) Liste von Feldnamen, die für eine Summierung verwendet werden können
|
||||
comment infolog de Kommentar
|
||||
compare infolog de vergleichen
|
||||
completed infolog de Erledigt
|
||||
configuration infolog de Konfiguration
|
||||
confirm infolog de Bestätigung
|
||||
contact infolog de Kontakt
|
||||
contact cf infolog de Kontakt CF
|
||||
contact fields infolog de Kontaktfelder
|
||||
contactfield infolog de Kontaktfelder
|
||||
copy of: infolog de Kopie von:
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog de Kopieren Sie ihre Änderungen in die Zwischenablage, %1laden den Eintrag neu%2 und fügen diese wieder ein.
|
||||
create new links infolog de Neue Verknüpfung erzeugen
|
||||
creates a new field infolog de erstellt ein neues Feld
|
||||
creates a new status with the given values infolog de erstellt einen neuen Status mit den angegebenen Werten
|
||||
creates a new typ with the given name infolog de erstellt einen neuen Typ mit dem eingegebenen Namen
|
||||
creation infolog de Erstellung
|
||||
csv-fieldname infolog de CSV-Feldname
|
||||
csv-filename infolog de CSV-Dateiname
|
||||
csv-import common de CSV-Import
|
||||
custom infolog de Benutzerdefiniert
|
||||
custom contact-address, leave empty to use information from most recent link infolog de benutzerdefinierte Kontaktadresse, leer lassen um die Daten der Verknüpfung zu verwenden
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog de benutzerdefinierte Kontaktinformationen, leer lassen um die Daten der Verknüpfung zu verwenden
|
||||
custom fields infolog de Benutzerdefinierte Felder
|
||||
custom fields, typ and status common de Benutzerdefinierte Felder, Typen und Status
|
||||
custom from infolog de Benutzerdefinierter Kontakt
|
||||
custom regarding infolog de Benutzerdefinierter Bezug
|
||||
custom status for typ infolog de Benutzerdefinierter Status für Typ
|
||||
customfields infolog de Benutzerdefinierte Felder
|
||||
date completed infolog de Erledigt am
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog de Fertigstellungsdatum (leer lassen um es automatisch zu setzen wenn der Status erledigt oder abgerechnet ist)
|
||||
datecreated infolog de Erstellt am
|
||||
dates, status, access infolog de Daten, Status, Zugriff
|
||||
days infolog de Tage
|
||||
default category for new infolog entries infolog de Vorgabe Kategorie für neue InfoLog Einträge
|
||||
default document to insert entries infolog de Standarddokument zum Einfügen von Infologs
|
||||
default filter for infolog infolog de Standard-Filter für InfoLog
|
||||
default status for a new log entry infolog de Vorgabe für den Status eines neuen Eintrags
|
||||
delegated infolog de delegiert
|
||||
delegated open infolog de delegiert offen
|
||||
delegated open and upcoming infolog de delegiert offene und zukünftige
|
||||
delegated overdue infolog de delegiert überfällig
|
||||
delegated upcomming infolog de delegiert zukünftig
|
||||
delegation infolog de Delegation
|
||||
delete infolog de Löschen
|
||||
delete one record by passing its id. infolog de Einen Datensatz spezifiziert durch seine id löschen.
|
||||
delete selected entries? infolog de Sollen die ausgewählen Datensätze gelöscht werden?
|
||||
delete the entry infolog de Eintrag löschen
|
||||
delete this entry infolog de diesen Eintrag löschen
|
||||
delete this entry and all listed sub-entries infolog de Diesen Eintrag und all aufgelisteten Untereinträge löschen
|
||||
deleted infolog de gelöscht
|
||||
deletes the selected typ infolog de löscht den ausgewählten Typ
|
||||
deletes this field infolog de löscht dieses Feld
|
||||
deletes this status infolog de löscht diesen Status
|
||||
description infolog de Beschreibung
|
||||
determines the order the fields are displayed infolog de legt die Reihenfolge fest in der die Felder angezeigt werden
|
||||
directory with documents to insert entries infolog de Verzeichnis mit Dokumenten zum Einfügen von Infologs
|
||||
disables a status without deleting it infolog de deaktiviert einen Status ohne ihn zu löschen
|
||||
do not notify of these changes infolog de Keine Benachrichtigung senden
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog de Wollen Sie eine Bestätigung des Verantwortlichen bei: Annahme, Beendigung der Aufgabe oder bei beidem
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog de Wollen Sie eine Benachrichtigung, wenn Einträge Ihnen zugewiesen werden oder zugewiesene Einträge geändert werden?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog de Wollen Sie eine Benachrichtigung, wenn Einträge für die Sie verantwortlich sind beginnen sollen?
|
||||
do you want a notification, if items you are responsible for are due? infolog de Wollen Sie eine Benachrichtigung, wenn Einträge für die Sie verantwortlich sind fällig werden?
|
||||
do you want a notification, if items you created get updated? infolog de Wollen Sie eine Benachrichtigung, wenn Einträge die Sie angelegt haben aktualisiert werden?
|
||||
do you want a notification, if items you delegated are about to start? infolog de Wollen Sie eine Benachrichtigung, wenn Einträge die Sie delegiert haben beginnen sollen?
|
||||
do you want a notification, if items you delegated are due? infolog de Wollen Sie eine Benachrichtigung, wenn Einträge die Sie delegiert haben fällig werden?
|
||||
do you want to receive notifications as html-mails or plain text? infolog de Wollen Sie die Benachrichtigungen als HTML Mail oder reinen Text empfangen?
|
||||
document '%1' does not exist or is not readable for you! infolog de Dokument '%1' existiert nicht, oder ist nicht lesbar für Sie!
|
||||
don't show infolog infolog de InfoLog NICHT anzeigen
|
||||
done common de erledigt
|
||||
download infolog de Datei laden
|
||||
due %1 infolog de %1 fällig
|
||||
duration infolog de Dauer
|
||||
e-mail: infolog de E-Mail
|
||||
each value is a line like <id>[=<label>] infolog de jeder Wert ist eine Zeile im Format id=[angezeigter Wert]
|
||||
edit infolog de Bearbeiten
|
||||
edit or create categories for ingolog infolog de Kategorien für InfoLog bearbeiten oder neu anlegen
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog de Bearbeitungsrechte (komplettes Bearbeiten einschl. jemand anderen dafür verantwortlich machen!)
|
||||
edit status infolog de Status ändern
|
||||
edit the entry infolog de Eintrag bearbeiten
|
||||
edit this entry infolog de diesen Eintrag bearbeiten
|
||||
empty for all infolog de leer für alle
|
||||
end infolog de Ende
|
||||
enddate infolog de Fällig am
|
||||
enddate can not be before startdate infolog de Das Fälligkeitsdatum kann nicht vor dem Startdatum liegen
|
||||
enter a custom contact, leave empty if linked entry should be used infolog de benutzerdefinierter Kontakt, leer lassen um die Daten der Verknüpfung zu verwenden
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog de benutzerdefinierte Telefonnumer/E-Mail-Adresse, leer lassen um die Daten der Verknüpfung zu verwenden
|
||||
enter a textual description of the log-entry infolog de geben Sie eine textliche Beschreibung des Eintrags ein
|
||||
enter the query pattern infolog de geben Sie ein Suchmuster ein
|
||||
entry and all files infolog de Eintrag und alle Dateien
|
||||
error: saving the entry infolog de Fehler: beim Speichern des Eintrags
|
||||
error: the entry has been updated since you opened it for editing! infolog de Fehler: der Eintrag wurde geändert seit Sie ihn zum Bearbeiten geöffnet haben!
|
||||
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. infolog de Beispiel: "{{IF n_prefix~Herr~Sehr geehrter~Sehr geehrte}}" - suche in dem Feld "n_prefix" nach "Herr", wenn gefunden, schreibe "Sehr geehrter", wenn nicht gefunden schreibe "Sehr geehrte". Es ist auch möglich anstatt fixer Werte, den Wert eines andren Feldes zu übernehmen. Beispiel (Land wird nur dann angezeigt, denn es nicht DEUTSCHLAND ist: }
|
||||
example {{letterprefixcustom n_prefix title n_family}} - example: mr dr. james miller infolog de Beispiel für {{LETTERPREFIXCUSTOM n_prefix title n_family}} - Beispiel: Herr Dr. James Miller
|
||||
example {{nelf role}} - if field role is not empty, you will get a new line with the value of field role infolog de Beispiel {{NELF role}} - Erzeugt einen Zeilenumbruch, wenn das Feld role nicht leer ist. Der Wert des Feldes role (Funktion) wird nach dem Zeilenumbruch ausgegeben.
|
||||
example {{nelfnv role}} - if field role is not empty, set a lf without any value of the field infolog de Beispiel {{NELFNV role}} -Erzeugt einen Zeilenumbruch, wenn das Feld role (Funktion) einen Wert besitzt. Der Wert role (Funktion) wird auch bei Vorhandensein des Feldes role nicht ausgegeben.
|
||||
execute a further action for this entry infolog de Eine weitere Aktion für diesen Eintrag ausführen
|
||||
existing links infolog de Bestehende Verknüpfungen
|
||||
exists infolog de Besteht
|
||||
export definitition to use for nextmatch export infolog de Export Profil der Listenansicht (Disketten Symbol)
|
||||
exports infolog entries into a csv file. infolog de Exportiert Infolog Einträge in einen CSV Datei.
|
||||
fax infolog de Fax
|
||||
field must not be empty !!! infolog de Feld darf nicht leer sein !!!
|
||||
fieldseparator infolog de Feldbegrenzer
|
||||
finish infolog de wenn erledigt
|
||||
first argument for preg_replace infolog de Ersten Argument für pre_replace
|
||||
for serial letter use this tag. put the content, you want to repeat between two tags. infolog de Für Serienbriefe benutzen Sie folgenden Platzhalter. Fügen die den Inhalt zwischen diese beiden Platzhalter ein.
|
||||
for which types should this field be used infolog de für welche Typen soll dieses Feld benutzt werden
|
||||
from infolog de Von
|
||||
general infolog de Allgemein
|
||||
general fields: infolog de Allgemeine Felder
|
||||
global categories infolog de Globale Kategorien
|
||||
group owner for infolog de Gruppeneigentümer für
|
||||
high infolog de hoch
|
||||
history infolog de Historie
|
||||
history logging infolog de Protokollierung der Historie
|
||||
history logging and deleting of items infolog de Protokollierung der Historie und löschen von Einträgen
|
||||
how many describtion lines should be directly visible. further lines are available via a scrollbar. infolog de Wie viele Zeilen der Beschreibung sollen direkt sichtbar sein. Zusätzliche Zeilen können über einen Rollbalken (scrollbar) erreicht werden.
|
||||
how wide should the description area be. this value is numeric and interpreted as em; 60 works reasonably well. infolog de Wie breit darf das Beschreibungsfeld sein. Sie können hier einen nummerischen Wert eintragen.
|
||||
id infolog de Id
|
||||
id# infolog de Id#
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog de Wenn ein Typ einen Gruppeneigentümer hat, gehören alle Einträge dieses Typs der angegebenen Gruppe und NICHT dem Benutzer der sie angelegt hat!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog de Falls nicht gesetzt, wird die Suche und die Filter ausgeblendet für weniger Einträge als "maximale Treffer pro Seite" (in ihren allgemeinen Einstellungen definiert).
|
||||
if you specify a directory (full vfs path) here, infolog displays an action for each document. that action allows to download the specified document with the infolog data inserted. infolog de Wenn Sie hier ein Verzeichnis angeben (kompletter Pfad des VFS), erstellt das Infolog eine Aktion zum Einfügen der Infolog Daten für jeden Dokument.
|
||||
if you specify a document (full vfs path) here, infolog displays an extra document icon for each entry. that icon allows to download the specified document with the contact data inserted. infolog de Wenn Sie hier ein Verzeichnis angeben (kompletter Pfad des VFS), erstellt das Infolog eine Aktion zum Einfügen der Infolog Daten für jeden Dokument.
|
||||
if you specify an export definition, it will be used when you export infolog de Wählen Sie eine Export Definition für den Export.
|
||||
import infolog de Import
|
||||
import next set infolog de Nächsten Satz importieren
|
||||
importance infolog de Wichtigkeit
|
||||
imports entries into the infolog from a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. infolog de Importiert Einträge in das Infolog Modul aus einer CSV Datei (Komma getrennte Werte).
|
||||
info log common de InfoLog
|
||||
infolog common de InfoLog
|
||||
infolog - delete infolog de InfoLog - Löschen
|
||||
infolog - edit infolog de InfoLog - Bearbeiten
|
||||
infolog - import csv-file infolog de InfoLog - Import CSV-Datei
|
||||
infolog - new infolog de InfoLog - Anlegen
|
||||
infolog - new subproject infolog de InfoLog - Anlegen Teilprojekt
|
||||
infolog - subprojects from infolog de InfoLog - Teilprojekte von
|
||||
infolog copied - the copy can now be edited infolog de Infolog Kopie - Diese Kopie kann jetzt bearbeitet werden
|
||||
infolog csv export infolog de Infolog CSV Export
|
||||
infolog csv import infolog de Infolog CSV Import
|
||||
infolog entry deleted infolog de InfoLog Eintrag gelöscht
|
||||
infolog entry saved infolog de InfoLog Eintrag gespeichert
|
||||
infolog fields: infolog de Infolog Felder
|
||||
infolog filter for the main screen infolog de InfoLog Filter für Startseite
|
||||
infolog id infolog de Infolog ID
|
||||
infolog list infolog de InfoLog Liste
|
||||
infolog preferences common de InfoLog Einstellungen
|
||||
infolog-fieldname infolog de InfoLog-Feldname
|
||||
insert infolog de einfügen
|
||||
insert in document infolog de In ein Dokument einfügen
|
||||
invalid filename infolog de Ungültiger Dateiname
|
||||
invalid owner id: %1. might be a bad field translation. used %2 instead. infolog de Ungültige Eigentümer ID: %1. Ist möglicher Weise eine falsche Feld Übersetzung. Es wird %2 anstatt dem ursprünglichen Wert verwendet.
|
||||
invalid status for entry type %1. infolog de Ungültiger Status für den eingegebenen Typ %1
|
||||
label<br>helptext infolog de Beschriftung<br>Hilfetext
|
||||
last changed infolog de letzte Änderung
|
||||
last modified infolog de zuletzt geändert
|
||||
leave blank to get the used time calculated by timesheet entries infolog de Leer lassen um die Zeit nach den Stundenzetteln zu bekommen
|
||||
leave it empty infolog de leer lassen
|
||||
leave it empty for a full week infolog de leer lassen, für eine gesamte Woche
|
||||
leave without saveing the entry infolog de Abbruch ohne den Eintrag zu speichern
|
||||
leaves without saveing infolog de Abbruch ohne speichern
|
||||
length<br>rows infolog de Länge<br />Zeilen
|
||||
limit number of description lines (default 5, 0 for no limit) infolog de Begrenze Anzahl Beschreibungszeilen (Vorgabe 5, 0 für keine Grenze)
|
||||
limit width of description column ((effective only if lines limit is set), 0 for no limit) infolog de Beschränkt die Breite der Spalte Beschreibung. Setzten Sie den Wert 0, für kein Limit.
|
||||
link infolog de Verknüpfung
|
||||
linked to %1 infolog de Verknüpft mit %1
|
||||
links infolog de Verknüpfungen
|
||||
links of this entry infolog de Verknüpfungen dieses Eintrags
|
||||
list all categories infolog de Alle Kategorien anzeigen
|
||||
list no subs/childs infolog de Untereinträge nicht anzeigen
|
||||
location infolog de Ort
|
||||
longer textual description infolog de längere textliche Beschreibung
|
||||
low infolog de niedrig
|
||||
manage mapping infolog de Verwaltung der Zuordnung
|
||||
max length of the input [, length of the inputfield (optional)] infolog de max. Länge der Eingabe [, Länge des Eingabefeldes (optional)]
|
||||
modifier infolog de Geändert von
|
||||
modifierer infolog de Geändert von
|
||||
name must not be empty !!! infolog de Name darf nicht leer sein !!!
|
||||
name of current user, all other contact fields are valid too infolog de Name des aktiven Benutzers, all anderen Kontakt Felder sind weiterhin gültig
|
||||
name of new type to create infolog de Name des neu anzulegenden Typs
|
||||
never hide search and filters infolog de Suche und Filter niemals ausblenden
|
||||
new %1 infolog de Neue %1
|
||||
new %1 created by %2 at %3 infolog de Neue %1 wurde von %2 am %3 angelegt
|
||||
new name infolog de neuer Name
|
||||
new search infolog de Neue Suche
|
||||
no - cancel infolog de Nein - Abbruch
|
||||
no describtion, links or attachments infolog de Keine Beschreibung, Verknüpfungen oder Anhänge
|
||||
no details infolog de Keine Details
|
||||
no entries found, try again ... infolog de Kein Einträge gefunden, nochmal versuchen ...
|
||||
no filter infolog de kein Filter
|
||||
no links or attachments infolog de keine Verknüpfungen oder Anhänge
|
||||
no project infolog de Kein Projekt
|
||||
nonactive infolog de Nicht aktiv
|
||||
none infolog de keine
|
||||
normal infolog de normal
|
||||
not infolog de nicht
|
||||
not assigned infolog de nicht zugewiesen
|
||||
not-started infolog de nicht gestartet
|
||||
note infolog de Notiz
|
||||
number of records to read (%1) infolog de Anzahl Datensätze lesen (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog de Anzahl Zeilen für ein mehrzeiliges Eingabefeld oder eines mehrfachen Auswahlfeldes
|
||||
offer infolog de Angebot
|
||||
one day after infolog de am nächsten Tag
|
||||
one day in advance infolog de am Vortag
|
||||
ongoing infolog de in Arbeit
|
||||
only for details infolog de Nur bei Details
|
||||
only if i get assigned or removed infolog de Nur wenn ich zugewiesen oder entfernt werde
|
||||
only the attachments infolog de nur die Anhänge
|
||||
only the links infolog de nur die Verknüpfungen
|
||||
open infolog de offen
|
||||
open and upcoming infolog de zukünftige und offene
|
||||
optional note to the link infolog de zusätzliche Notiz zur Verknüpfung
|
||||
order infolog de Reihenfolge
|
||||
organization infolog de Organisation
|
||||
overdue infolog de überfällig
|
||||
own infolog de eigene
|
||||
own open infolog de eigene offen
|
||||
own open and upcoming infolog de eigene offene und zukünftige
|
||||
own overdue infolog de eigene überfällig
|
||||
own upcoming infolog de eigene zukünftig
|
||||
owner does not have edit rights infolog de Der Besitzer dieses Datensatzes benötigt Bearbeitungsrechte
|
||||
parent infolog de Elterneintrag
|
||||
parent infolog infolog de Übergeordneter Infolog
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog de Pfad auf (Web-)Server<br>zB. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog de Pfad zu Benutzer- und Gruppen-Dateien MUSS AUSSERHALB des Wurzelverzeichnisses des Webservers (document-root) liegen!!!
|
||||
pattern for search in addressbook infolog de Muster für Suche im Adressbuch
|
||||
pattern for search in projects infolog de Muster für Suche des Projekts
|
||||
percent completed infolog de Prozent erledigt
|
||||
permission denied infolog de Zugriff verweigert
|
||||
permissions error - %1 could not %2 infolog de Fehler in den Zugriffsberechtigungen - %1 could not %2
|
||||
phone infolog de Anruf
|
||||
phone/email infolog de Telefon/E-Mail
|
||||
phonecall infolog de Telefonanruf
|
||||
planned infolog de geplant
|
||||
planned time infolog de geplante Zeit
|
||||
price infolog de Preis
|
||||
pricelist infolog de Preisliste
|
||||
primary link infolog de Primäre Verknüpfung
|
||||
priority infolog de Priorität
|
||||
private infolog de Privat
|
||||
project infolog de Projekt
|
||||
project settings: price, times infolog de Einstellungen zum Projekt: Preis, Zeiten
|
||||
projectmanager infolog de Projektmanager
|
||||
re-planned infolog de Umgeplant
|
||||
re-planned time infolog de Umgeplante Zeit
|
||||
re: infolog de Re:
|
||||
read one record by passing its id. infolog de Einen Datensatz spezifiziert durch seine id lesen.
|
||||
read rights (default) infolog de Leserechte (Vorgabe)
|
||||
receive notifications about due entries you are responsible for infolog de Benachrichtigungen über fällige Einträge für die Sie verantwortlich sind
|
||||
receive notifications about due entries you delegated infolog de Benachrichtigungen über fällige Einträge die Sie delegiert haben
|
||||
receive notifications about items assigned to you infolog de Benachrichtigungen über Einträge für die Sie verantwortlich sind
|
||||
receive notifications about own items infolog de Benachrichtigungen über eigene Einträge
|
||||
receive notifications about starting entries you are responsible for infolog de Benachrichtigungen über zu startende Einträge für die Sie verantwortlich sind
|
||||
receive notifications about starting entries you delegated infolog de Benachrichtigungen über zu startende Einträge die Sie delegiert haben
|
||||
receive notifications as html-mails infolog de Benachrichtigungen als HTML Mails
|
||||
regular expression infolog de Reguläre Ausdrücke
|
||||
remark infolog de Bemerkung
|
||||
remove this link (not the entry itself) infolog de Diese Verknüpfung lösen (nicht den Eintrag selbst)
|
||||
removed infolog de Entfernt
|
||||
replacement infolog de Platzhalter
|
||||
replacements for inserting entries into documents infolog de Platzhalter für das Einfügen in Dokumente
|
||||
responsible infolog de verantwortlich
|
||||
responsible open infolog de verantwortlich offen
|
||||
responsible open and upcoming infolog de verantwortlich offene und zukünftige
|
||||
responsible overdue infolog de verantwortlich überfällig
|
||||
responsible upcoming infolog de verantwortlich zukünftig
|
||||
responsible user, priority infolog de Verantwortlicher, Priorität
|
||||
returns a list / search for records. infolog de Liefert eine Liste von / sucht nach Datensätzen.
|
||||
rights for the responsible infolog de Rechte für den Verantwortlichen
|
||||
same day infolog de gleichen Tag
|
||||
save infolog de Speichern
|
||||
saves the changes made and leaves infolog de speichert die Änderungen und beendet
|
||||
saves this entry infolog de diesen Eintrag speichern
|
||||
search infolog de Suchen
|
||||
search for: infolog de Suchen nach:
|
||||
second parameter for preg_replace infolog de 2. Paramter für preg_replace
|
||||
select infolog de Auswählen
|
||||
select a category for this entry infolog de eine Kategorie für diesen Eintrag auswählen
|
||||
select a price infolog de Preis auswählen
|
||||
select a priority for this task infolog de eine Priorität für diesen Eintrag auswählen
|
||||
select a project infolog de Projekt auswählen
|
||||
select a responsible user: a person you want to delegate this task infolog de Verantwortlichen auswählen: Person(en) der Sie diese Aufgabe delegieren wollen
|
||||
select a typ to edit it's status-values or delete it infolog de einen Type auswählen um seine Statuswerte zu ändern oder ihn zu löschen
|
||||
select an action infolog de Befehl oder Aktion auswählen
|
||||
select an action... infolog de Befehl oder Aktion auswählen...
|
||||
select an app to search in infolog de eine Anwendung zum Durchsuchen auswählen
|
||||
select an entry to link with infolog de einen Eintrag zum Verknüpfen auswählen
|
||||
select multiple contacts for a further action infolog de Wählen Sie mehrere Konatkte für eine weitere Aktion aus.
|
||||
select new category infolog de Wählen Sie eine Kategory
|
||||
select to filter by owner infolog de Besitzer zum Filtern auswählen
|
||||
select to filter by responsible infolog de Verantwortlichen zum Filtern auswählen
|
||||
select users or groups infolog de Wählen Sie Benutzer oder Gruppen aus
|
||||
selection cf infolog de Auswahl für CF
|
||||
sender infolog de Absender
|
||||
set status to done infolog de Status auf erledigt setzen
|
||||
set status to done for all entries infolog de Status für alle Einträge auf erledigt setzen
|
||||
sets the status of this entry and its subs to done infolog de Setzt den Status dieses Eintrags und seiner Untereinträge auf erledigt
|
||||
sets the status of this entry to done infolog de Setzt den Status für diesen Infolog auf erledigt
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog de Soll InfoLog Untereinträge in der normalen Ansicht anzeigen oder nicht. Sie können die Untereinträge immer über deren Haupteintrag anzeigen.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog de Soll InfoLog die Verknüpfungen zu anderen Anwendungen und/oder die Datei-Anhänge in der InfoLog Liste (normale Ansicht wenn InfoLog aufgerufen wird) anzeigen.
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog de Soll InfoLog auf der Startseite angezeigt werden und mit welchem Filter. Funktioniert nur, wenn Sie keine (einzelne) Anwendung für die Startseite ausgewählt haben (in Ihren Einstellungen).
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog de Soll InfoLog den vollen Namen (Vor- und Familienname) oder nur die Benutzerkennung verwenden.
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog de Soll die InfoLog Liste eine eindeutige Nummer anzeigen, die zB. als Ticketnummer verwendet werden kann.
|
||||
should the infolog list show the column "last modified". infolog de Soll die InfoLog Liste die Spalte "Zuletzt geändert" anzeigen.
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog de Soll die InfoLog Liste Prozent erledigt nur für den Status "in Arbeit" anzeigen oder zwei separate Icons.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog de soll dieser Eintrag nur sichtbar sein für Sie und Personen denen Sie privaten Zugriff über die ACL erlaubt haben
|
||||
show a column for used and planned times in the list. infolog de Zeige eine Spalte für benutzte und geplante Zeiten in der List.
|
||||
show a x if content equals this compare value, otherwise show nothing infolog de zeigt ein X an, wenn der Inhalt mit dem Vergleichswert übereinstimmt, ansonsten erfolgt keine Anzeige.
|
||||
show full usernames infolog de Kompletten Benutzernamen anzeigen
|
||||
show in the infolog list infolog de In der InfoLog Liste anzeigen
|
||||
show last modified infolog de Zuletzt geändert anzeigen
|
||||
show status and percent done separate infolog de Status und Prozent erledigt separat anzeigen
|
||||
show ticket id infolog de Ticketnummer anzeigen
|
||||
show times infolog de Zeiten anzeigen
|
||||
small view infolog de schmale Ansicht
|
||||
start infolog de Start
|
||||
start a new search, cancel this link infolog de eine neue Suche starten, diese Verknüpfung abbrechen
|
||||
startdate infolog de Startdatum
|
||||
startdate enddate infolog de Startdatum Fälligkeitsdatum
|
||||
startdate for new entries infolog de Startdatum für neue Einträge
|
||||
starting %1 infolog de %1 startet
|
||||
startrecord infolog de Startdatensatz
|
||||
status infolog de Status
|
||||
status ... infolog de Status ...
|
||||
sub infolog de Unter-<br />einträge
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog de Untereinträge gehören dann zum übergeordneten Eintrag oder werden Haupteinträge wenn es keinen übergeordneten gibt.
|
||||
sub-entries will not be closed infolog de Untereinträge werden nicht geschlossen
|
||||
subject infolog de Titel
|
||||
sum infolog de Summe
|
||||
tag to mark positions for address labels infolog de Platzhalter, um die Position der Adresslabels festzulegen
|
||||
task infolog de Aufgabe
|
||||
tasks of infolog de Aufgaben von
|
||||
template infolog de Vorlage
|
||||
test import (show importable records <u>only</u> in browser) infolog de Test Import (zeige importierbare Datensätze <u>nur</u> im Browser)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog de der Name wird intern benutzt (<= 10 Zeichen), wenn er geändert wird, werden existierende Daten unzugänglich
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog de der Name wird intern benutzt (<= 20 Zeichen), wenn er geändert wird, werden existierende Daten unzugänglich
|
||||
the text displayed to the user infolog de der Text der dem Benutzer angezeigt wird
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog de Das ist der Filter, den InfoLog benutzt wenn es das erste mal aufgerufen wird. Filter beschränken die aktuelle Anzeige. Es gibt Filter um nur beendete, offene oder zukünftige Einträge von Ihnen oder allen Benutzern anzuzeigen.
|
||||
til when should the todo or phonecall be finished infolog de bis wann soll der Auftrag oder Anruf erledigt sein
|
||||
times infolog de Zeiten
|
||||
to many might exceed your execution-time-limit infolog de zu viel können Ihre Laufzeitbeschränkung überschreiten
|
||||
to what should the startdate of new entries be set. infolog de Auf was soll das Startdatum von neuen Einträgen gesetzt werden.
|
||||
today infolog de Heute
|
||||
todays date infolog de heutiges Datum
|
||||
todo infolog de Aufgabe
|
||||
translation infolog de Translation
|
||||
typ infolog de Typ
|
||||
typ '%1' already exists !!! infolog de Typ '%1' existiert bereits !!!
|
||||
type infolog de Typ
|
||||
type ... infolog de Typ ...
|
||||
type of customfield infolog de Typ des benutzerdefinierten Feldes
|
||||
type of the log-entry: note, phonecall or todo infolog de Typ des Eintrags: Notiz, Anruf oder Auftrag
|
||||
unlink infolog de Verknüpfung lösen
|
||||
unlinked from %1 infolog de Verknüpfung entfernt von %1
|
||||
upcoming infolog de zukünftig
|
||||
urgency infolog de Priorität
|
||||
urgent infolog de Dringend
|
||||
use all infolog de Alle Einträge
|
||||
use field from csv if possible infolog de Verwendet die Felder vom CSV, wenn möglich
|
||||
use search results infolog de Verwendet die Sucherbegnisse
|
||||
use this tag for addresslabels. put the content, you want to repeat, between two tags. infolog de Benutzern Sie diesen Platzhalter für Adressetiketten. Fügen Sie den Inhalt, den Sie wiederholen möchten zwischen zwei Platzhalter ein.
|
||||
used time infolog de benötigte Zeit
|
||||
values for selectbox infolog de Werte für die Auswahlbox
|
||||
view all subs of this entry infolog de alle Untereinträge dieses Eintrag anzeigen
|
||||
view other subs infolog de andere Untereinträge anzeigen
|
||||
view parent infolog de übergeordneter Eintrag anzeigen
|
||||
view subs infolog de Untereinträge anzeigen
|
||||
view the parent of this entry and all his subs infolog de übergeordneter Eintrag mit allen seinen Untereinträgen anzeigen
|
||||
view this linked entry in its application infolog de diesen verknüpfen Eintrag in seiner Anwendung anzeigen
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog de wann soll mit dem Auftrag oder Anruf begonnen werden, ab diesem Datum wird er beim Filter offen oder eigene offen angezeigt (Startseite)
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog de Welche zusätzlichen Felder soll der Verantwortliche bearbeiten können ohne Bearbeitungsrechte zu haben?<br />Status, Prozent und Datum erledigt sind immer erlaubt.
|
||||
which implicit acl rights should the responsible get? infolog de Welche impliziten Zugriffsrechte soll der Verantwortliche bekommen?
|
||||
which types should the calendar show infolog de Welche Typen soll der Kalender anzeigen
|
||||
whole query infolog de gesamte Abfrage
|
||||
will-call infolog de ruft zurück
|
||||
write (add or update) a record by passing its fields. infolog de Schreiben (zufügen oder aktualisieren) eines Datensatzes durch Angabe seiner Felder.
|
||||
yes - close infolog de Ja schließen
|
||||
yes - close including sub-entries infolog de Ja- schließen inklusive Untereinträge
|
||||
yes - delete infolog de Ja - Löschen
|
||||
yes - delete including sub-entries infolog de Ja - Löschen einschließlich Untereinträge
|
||||
yes, noone can purge deleted items infolog de Ja, niemand darf gelöschte Einträge bereinigen
|
||||
yes, only admins can purge deleted items infolog de Ja, nur Admins dürfen gelöschte Einträge bereinigen
|
||||
yes, with larger fontsize infolog de Ja, mit einer größeren Schrift
|
||||
yes, with purging of deleted items possible infolog de Ja, jeder darf gelöschte Einträge bereinigen
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog de Sie können eine Kategorie festlegen die vorausgewählt wird, wenn Sie neue InfoLog Einträge anlegen.
|
||||
you can't delete one of the stock types !!! infolog de Sie können keinen der Standardtypen löschen!!!
|
||||
you have entered an invalid ending date infolog de Sie haben ein ungültiges Fälligkeitsdatum eingegeben
|
||||
you have entered an invalid starting date infolog de Sie haben ein ungültiges Startdatum eingegeben
|
||||
you have to enter a name, to create a new typ!!! infolog de Sie müssen einen Namen angeben, um einen neuen Typ zu erzeugen!!!
|
||||
you must enter a subject or a description infolog de Sie müssen einen Titel oder eine Beschreibung eingeben
|
||||
you need to select an entry for linking. infolog de Sie müssen einen Datensatz auswählen, um eine Verknüpfung zu erstellen.
|
||||
you need to select some entries first infolog de Bitte wählen Sie zuerst die Datensätze aus, die Sie bearbeiten wollen.
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog de Ihre Datenbank ist NICHT aktuell (%1 gegenüber %2), bitte rufen Sie %3setup%4 auf um ihre Datenbank zu aktualisieren.
|
348
infolog/lang/egw_el.lang
Normal file
348
infolog/lang/egw_el.lang
Normal file
@ -0,0 +1,348 @@
|
||||
%1 days in advance infolog el %1 ημέρες πριν
|
||||
%1 deleted infolog el %1 διαγράφηκαν
|
||||
%1 deleted by %2 at %3 infolog el %1 διαγράφηκαν από %2 στις %3
|
||||
%1 modified infolog el %1 επεξεργάστηκαν
|
||||
%1 modified by %2 at %3 infolog el %1 επεξεργάστηκαν από %2 στις %3
|
||||
%1 records imported infolog el %1 εγγραφές εισήχθησαν
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog el Έχουν διαβαστεί %1 εγγραφές (δεν έχουν εισαχθεί ακόμη, μπορείτε να πάτε %2 πίσω %3 και να ξετσεκάρετε το Τεστ Εισαγωγής)
|
||||
- subprojects from infolog el - Υποκατηγορίες σχεδίων από
|
||||
0% infolog el 0%
|
||||
10% infolog el 10%
|
||||
100% infolog el 100%
|
||||
20% infolog el 20%
|
||||
30% infolog el 30%
|
||||
40% infolog el 40%
|
||||
50% infolog el 50%
|
||||
60% infolog el 60%
|
||||
70% infolog el 70%
|
||||
80% infolog el 80%
|
||||
90% infolog el 90%
|
||||
a short subject for the entry infolog el ένα μικρό θέμα για την καταχώρηση
|
||||
abort without deleting infolog el Έξοδος χωρίς διαγραφή
|
||||
accept infolog el αποδοχή
|
||||
action infolog el Ενέργεια
|
||||
actual date and time infolog el πραγματική ημερομηνία και ώρα
|
||||
add infolog el Προσθήκη
|
||||
add a file infolog el Προσθήκη αρχείου
|
||||
add a new entry infolog el Προσθήκη νέας καταχώρησης
|
||||
add a new note infolog el Προσθήκη νέας σημείωσης
|
||||
add a new phonecall infolog el Προσθήκη νέας τηλεφωνικής κλήσης
|
||||
add a new sub-task, -note, -call to this entry infolog el Προσθήκη νεόυ υπο-καθήκοντος,-σημείωσης,-κλήσης σε αυτή την καταχώρηση
|
||||
add a new todo infolog el Προσθήκη νέας εκκρεμότητας
|
||||
add file infolog el Προσθήκη αρχείου
|
||||
add sub infolog el προσθήκη υπό
|
||||
add: infolog el Προσθήκη:
|
||||
all infolog el Όλα
|
||||
all links and attachments infolog el όλοι οι σύνδεσμοι και οι επισυνάψεις
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog el επιτρέπει τον καθορισμό της κατάστασης μιας καταχώρησης,π.χ. καθορισμός μιας εκκρεμότητας σε ολοκληρωμένη εάν τελείωσε (αξίες εξαρτώνται από τον τύπο της καταχώρησης)
|
||||
apply the changes infolog el Εφαρμογή των αλλαγών
|
||||
are you shure you want to delete this entry ? infolog el Είστε σίγουρος ότι θέλετε να διαγράψετε αυτή την καταχώρηση;
|
||||
attach a file infolog el Επισύναψη αρχείου
|
||||
attach file infolog el Επισύναψη αρχείου
|
||||
attention: no contact with address %1 found. infolog el Προσοχή: Καμία Επαφή με τη διεύθυνση %1 δεν βρέθηκε.
|
||||
back to main list infolog el Πίσω στη βασική λίστα
|
||||
billed infolog el χρεώθηκε
|
||||
both infolog el και οι δύο
|
||||
call infolog el κλήση
|
||||
cancel infolog el Ακύρωση
|
||||
cancelled infolog el ακυρώθηκε
|
||||
categories infolog el Κατηγορίες
|
||||
category infolog el Κατηγορία
|
||||
change the status of an entry, eg. close it infolog el Αλλαγή της κατάστασης μιας καταχώρησης, π.χ. κλείσιμο
|
||||
charset of file infolog el Κωδικοσελίδα αρχείου
|
||||
check to set startday infolog el Έλεγχος για ορισμό ημέρας έναρξης
|
||||
check to specify custom contact infolog el Έλεγχος για καθορισμό επαφής πελάτη
|
||||
click here to create the link infolog el κάντε κλικ εδώ για τη δημιουργία συνδέσμου
|
||||
click here to start the search infolog el κάντε κλικ εδώ για να αρχίσετε την αναζήτηση
|
||||
close infolog el Κλείσιμο
|
||||
comment infolog el Σχόλιο
|
||||
completed infolog el Ολοκληρώθηκε
|
||||
configuration infolog el Τροποποίηση
|
||||
confirm infolog el Επιβεβαίωση
|
||||
contact infolog el Επαφή
|
||||
create new links infolog el Δημιουργία νέων συνδέσμων
|
||||
creates a new field infolog el δημιουργεί νέο πεδίο
|
||||
creates a new status with the given values infolog el δημιουργεί μια νέα κατάσταση με τις δοσμένες αξίες
|
||||
creates a new typ with the given name infolog el δημιουργεί ένα νέο τύπο με το δοσμένο όνομα
|
||||
creation infolog el Δημιουργία
|
||||
csv-fieldname infolog el CSV-Όνομα πεδίου
|
||||
csv-filename infolog el CSV-Όνομα αρχείου
|
||||
csv-import common el CSV-Εισαγωγή
|
||||
custom infolog el Προσαρμογή
|
||||
custom contact-address, leave empty to use information from most recent link infolog el Προσαρμοσμένη διεύθυνση επαφής, να μένει κενό για τη χρησιμοποίηση των πιο πρόσφατων συνδέσμων
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog el Προσαρμοσμένες πληροφορίες επαφής, να μένει κενό για τη χρησιμοποίηση των πιο πρόσφατων συνδέσμων
|
||||
custom fields infolog el Προσαρμοσμένα πεδία
|
||||
custom fields, typ and status common el Προσαρμοσμένα πεδία,τύπος και κατάσταση
|
||||
custom regarding infolog el Προσαρμοσμένη αναφορά
|
||||
custom status for typ infolog el Προσαρμοσμένη κατάσταση για τον τύπο
|
||||
customfields infolog el Προσαρμοσμένα πεδία
|
||||
date completed infolog el Ημερομηνία και ώρα ολοκλήρωσης
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog el Συνάντηση ολοκληρώθηκε(να μείνει κενό για να οριστεί αυτόματα αν η κατάσταση εχει τελειώσει ή χρεωθεί
|
||||
datecreated infolog el ορίστηκε συνάντηση
|
||||
dates, status, access infolog el Συναντήσεις, Κατάσταση,Είσοδος
|
||||
days infolog el ημέρες
|
||||
default category for new infolog entries infolog el Προκαθορισμένη κατηγορία για νέες καταχωρήσεις στο InfoLog
|
||||
default filter for infolog infolog el Προκαθορισμένο Φίλτρο για το InfoLog
|
||||
default status for a new log entry infolog el προκαθορισμένη κατάσταση για νέες καταχωρήσεις
|
||||
delegated infolog el εξουσιοδοτήθηκε
|
||||
delegated open infolog el εξουσιοδοτημένα ανοικτά
|
||||
delegated overdue infolog el εξουσιοδοτημένα καθυστερημένα
|
||||
delegated upcomming infolog el εξουσιοδοτημένα επερχόμενα
|
||||
delegation infolog el Εξουσιοδότηση
|
||||
delete infolog el Διαγραφή
|
||||
delete one record by passing its id. infolog el Διαγραφή μιας εγγραφής διαβαίνοντας απο το id της.
|
||||
delete the entry infolog el Διαγραφή αυτής της καταχώρησης
|
||||
delete this entry infolog el δαγραφή αυτής της καταχώρησης
|
||||
delete this entry and all listed sub-entries infolog el Διαγραφή αυτής της καταχώρησης και όλων των υπο-καταχωρήσεων στη λίστα
|
||||
deleted infolog el διαγράφηκαν
|
||||
deletes the selected typ infolog el διαγραφή του επιλεγμένου τύπου
|
||||
deletes this field infolog el διαγραφή αυτού του πεδίου
|
||||
deletes this status infolog el διαγραφή αυτής της κατάστασης
|
||||
description infolog el Περιγραφή
|
||||
determines the order the fields are displayed infolog el καθορίζει τη σειρά με την οποία εμφανίζονται τα πεδία
|
||||
disables a status without deleting it infolog el ακυρώνει μια κατάσταση χωρίς να τη διαγράφει
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog el επιθυμείτε επιβεβαίωση του υπεύθυνου για:αποδοχή,ολοκλήρωση του έργου ή και τα δύο
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog el Επιθυμείτε ειδοποίηση, αν αντικείμενα ανατίθενται σε εσάς ή αντικείμενα τα οποία έχουν ανατεθεί ενημερώνονται;
|
||||
do you want a notification, if items you are responsible for are about to start? infolog el Επιθυμείτε ειδοποίηση, αν αντικείμενα για τα οποία είστε υπεύθυνος πρόκειται να ξεκινήσουν;
|
||||
do you want a notification, if items you are responsible for are due? infolog el Επιθυμείτε ειδοποίηση, αν αντικείμενα για τα οποία είστε υπεύθυνος έχουν καθυστερήσει;
|
||||
do you want a notification, if items you created get updated? infolog el Επιθυμείτε ειδοποίηση, αν αντικείμενα που έχετε δημιουργήσει ενημερώνονται;
|
||||
do you want a notification, if items you delegated are about to start? infolog el Επιθυμείτε ειδοποίηση, αν αντικείμενα για τα οποία είστε εξουσιοδοτημένος πρόκειται να ξεκινήσουν;
|
||||
do you want a notification, if items you delegated are due? infolog el Επιθυμείτε ειδοποίηση, αν αντικείμενα για τα οποία είστε εξουσιοδοτημένος έχουν καθυστερήσει;
|
||||
do you want to receive notifications as html-mails or plain text? infolog el Επιθυμείτε να λαμβάνετε ειδοποιήσεις ως html-mails ή απλό κείμενο;
|
||||
don't show infolog infolog el ΜΗΝ εμφανίζετε το InfoLog
|
||||
done infolog el ολοκληρώθηκε
|
||||
download infolog el Download
|
||||
duration infolog el Διάρκεια
|
||||
each value is a line like <id>[=<label>] infolog el κάθε αξία είναι μία γραμμή όπως <id>[=<label>]
|
||||
edit infolog el Προσαρμογή
|
||||
edit or create categories for ingolog infolog el Επιμέλεια ή δημιουργία κατηγοριών για το InfoLog
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog el προσαρμογή δικαιωμάτων(ολοκληρωμένη προσαρμογή δικαιωμάτων συμπεριλαμβανομένου τον καθορισμό κάποιου άλλου ως υπεύθυνο!)
|
||||
edit status infolog el Επιμέλεια κατάστασης
|
||||
edit the entry infolog el Επιμέλεια της καταχώρησης
|
||||
edit this entry infolog el Επιμέλεια αυτής της καταχώρησης
|
||||
empty for all infolog el κενό για όλα
|
||||
enddate infolog el Προθεσμία λήξης
|
||||
enddate can not be before startdate infolog el Η προθεσμία λήξης δεν μπορεί να είναι προηγούμενη της ημερομηνίας έναρξης
|
||||
enter a custom contact, leave empty if linked entry should be used infolog el είσοδος σε μία προσαρμοσμένη επαφή, να μείνει κενή αν πρέπει να χρησιμοποιηθεί συνδεδεμένη καταχώρηση
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog el είσοδος σε ένα προσαρμοσμένο τηλέφωνο/email, να μένει κενό αν πρέπει να χρησιμοποιηθεί συνδεδεμένη καταχώρηση
|
||||
enter a textual description of the log-entry infolog el Πληκτρολογήστε μία περιγραφή κειμένου για την καταχώρηση
|
||||
enter the query pattern infolog el Enter the query pattern
|
||||
error: saving the entry infolog el Σφάλμα: κατά την αποθήκευση της καταχώρησης
|
||||
error: the entry has been updated since you opened it for editing! infolog el Σφάλμα:η καταχώρηση έχει ενημερωθεί από όταν την ανοίξατε για προσαρμογή!
|
||||
existing links infolog el Υπάρχοντες σύνδεσμοι
|
||||
fax infolog el Fax
|
||||
field must not be empty !!! infolog el Το πεδίο δεν πρέπει να μείνει κενό !!!
|
||||
fieldseparator infolog el Διαχωριστής πεδίων
|
||||
finish infolog el τέλος
|
||||
for which types should this field be used infolog el για ποιους τύπους να χρησιμοποιηθεί αυτό το πεδίο
|
||||
from infolog el Από
|
||||
general infolog el Γενικά
|
||||
high infolog el υψηλή
|
||||
history logging infolog el Ιστορικό εισόδων
|
||||
history logging and deleting of items infolog el Ιστορικό εισόδων και διαγραφών αντικειμένων
|
||||
id infolog el Id
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog el Αν ο τύπος έχει έναν ιδιοκτήτη ομάδας, όλες οι καταχωρήσεις αυτού του τύπου θα ανήκουν στη συγκεριμένη ομάδα και ΟΧΙ στο χρήστη που το δημιούργησε!
|
||||
import infolog el Εισαγωγή
|
||||
import next set infolog el εισαγωγή επόμενου σετ
|
||||
info log common el Infolog
|
||||
infolog common el Infolog
|
||||
infolog - delete infolog el Infolog - Διαγραφή
|
||||
infolog - edit infolog el Infolog - Επιμέλεια
|
||||
infolog - import csv-file infolog el Infolog - Εισαγωγή CSV αρχείου
|
||||
infolog - new infolog el Infolog - Νέο
|
||||
infolog - new subproject infolog el Infolog - Νέα υποκατηγορία σχεδίων
|
||||
infolog - subprojects from infolog el Infolog - Υποκατηγορίες σχεδίων από
|
||||
infolog entry deleted infolog el Infolog καταχώρηση διεγράφη
|
||||
infolog entry saved infolog el Infolog καταχώρηση αποθηκεύτηκε
|
||||
infolog filter for the main screen infolog el Infolog φίλτρο για τη βασική οθόνη
|
||||
infolog list infolog el Infolog λίστα
|
||||
infolog preferences common el Infolog προτιμήσεις
|
||||
infolog-fieldname infolog el Infolog - Όνομα πεδίου
|
||||
invalid filename infolog el Άκυρο όνομα αρχείου
|
||||
label<br>helptext infolog el Ετικέτα<br>Κείμενο βοήθειας
|
||||
last changed infolog el Τελευταία αλλαγή
|
||||
last modified infolog el Τελευταία προσαρμογή
|
||||
leave it empty infolog el να μείνει κενό
|
||||
leave without saveing the entry infolog el αποχώρηση χωρίς αποθήκευση της καταχώρησης
|
||||
leaves without saveing infolog el αποχωρεί χωρίς αποθήκευση
|
||||
length<br>rows infolog el Μήκος<br>Γραμμών
|
||||
link infolog el Σύνδεσμος
|
||||
links infolog el Σύνδεσμοι
|
||||
links of this entry infolog el Σύνδεσμοι αυτής της καταχώρησης
|
||||
list all categories infolog el Να μπουν σε λίστα όλες οι κατηγορίες
|
||||
list no subs/childs infolog el Να μην εμφανίζονται οι υπο- καταχωρήσεις
|
||||
location infolog el Τοποθεσία
|
||||
longer textual description infolog el εκτενέστερη περιγραφή κειμένου
|
||||
low infolog el χαμηλή
|
||||
max length of the input [, length of the inputfield (optional)] infolog el μέγιστο μήκος εισροής [μήκος πεδίου εισροών (κατ'επιλογή)]
|
||||
name must not be empty !!! infolog el Το όνομα δεν πρέπει να μένει κενό
|
||||
name of new type to create infolog el όνομα νέου τύπου προς δημιουργία
|
||||
never hide search and filters infolog el Να μην αποκρύπτεται ποτέ η αναζήτηση και τα φίλτρα
|
||||
new %1 infolog el Νέο %1
|
||||
new %1 created by %2 at %3 infolog el Νέο %1 δημιουργήθηκε από %2 στις %3
|
||||
new name infolog el νέο όνομα
|
||||
new search infolog el Νέα αναζήτηση
|
||||
no - cancel infolog el Όχι-Άκυρο
|
||||
no describtion, links or attachments infolog el καμία περιγραφή, σύνδεσμος ή επισύναψη
|
||||
no details infolog el συνοπτικά
|
||||
no entries found, try again ... infolog el δεν βρέθηκαν καταχωρήσεις, προσπαθήστε ξανά
|
||||
no filter infolog el κανένα Φίλτρο
|
||||
no links or attachments infolog el κανένα φίλτρο ή επισυνάψεις
|
||||
nonactive infolog el ανενεργό
|
||||
none infolog el Κανένα
|
||||
normal infolog el κανονικό
|
||||
not infolog el δεν
|
||||
not assigned infolog el δεν έχει ανατεθεί
|
||||
not-started infolog el δεν έχει αρχίσει
|
||||
note infolog el Σημείωση
|
||||
number of records to read (%1) infolog el Αριθμός εγγραφών προς ανάγνωση (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog el αριθμός σειράς για ένα πολυγραμμικό πεδίο εισροών ή γραμμή ενός κουτιού πολλών επιλογών
|
||||
offer infolog el προσφορά
|
||||
one day after infolog el μία μέρα μετά
|
||||
one day in advance infolog el Μία μέρα νωρίτερα
|
||||
ongoing infolog el τρέχων
|
||||
only for details infolog el Μόνο για λεπτομέρειες
|
||||
only if i get assigned or removed infolog el Μόνο εάν μου ανατεθεί ή αφαιρεθεί
|
||||
only the attachments infolog el μόνο οι επισυνάψεις
|
||||
only the links infolog el μόνο οι σύνδεσμοι
|
||||
open infolog el ανοικτά
|
||||
optional note to the link infolog el προαιρετική σημείωση στο σύνδεσμο
|
||||
order infolog el Παραγγελία
|
||||
overdue infolog el καθυστερημένα
|
||||
own infolog el δικά μου
|
||||
own open infolog el δικά μου ανοικτά
|
||||
own overdue infolog el δικά μου καθυστερημένα
|
||||
own upcoming infolog el δικά μου επερχόμενα
|
||||
parent infolog el Μητρική
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog el Το μονοπάτι προς τα αρχεία του χρήστη και των ομάδων ΠΡΕΠΕΙ ΝΑ ΕΙΝΑΙ ΕΚΤΟΣ της πορείας των εγγράφων των webservers!!!
|
||||
pattern for search in addressbook infolog el πρότυπο αναζήτησης στο βιβλίο διευθύνσεων
|
||||
pattern for search in projects infolog el πρότυπο αναζήτησης στα σχέδια
|
||||
percent completed infolog el ποσοστό που έχει ολοκληρωθεί
|
||||
permission denied infolog el Άδεια απορρίπτεται
|
||||
phone infolog el Κλήση τηλεφώνου
|
||||
phone/email infolog el Τηλέφωνο/Email
|
||||
phonecall infolog el Κλήση τηλεφώνου
|
||||
planned infolog el προγραμματίστηκε
|
||||
planned time infolog el ώρα σχεδίου
|
||||
price infolog el Τιμή
|
||||
pricelist infolog el Τιμοκατάλογος
|
||||
primary link infolog el κύριος σύνδεσμος
|
||||
priority infolog el Προτεραιότητα
|
||||
private infolog el Προσωπικό
|
||||
project infolog el Σχέδιο
|
||||
project settings: price, times infolog el Ρυθμίσεις σχεδίων:τιμή, ώρες
|
||||
re: infolog el Αφορά:
|
||||
read one record by passing its id. infolog el Διαβάστε μία εγγραφή διαβαίνοντας από το ID της
|
||||
read rights (default) infolog el ανάγνωση δικαιωμάτων (προκαθορισμένη)
|
||||
receive notifications about due entries you are responsible for infolog el Λήψη ειδοποιήσεων για καταχωρήσεις των οποίων είστε υπεύθυνος και που έχουν καθυστερήσει
|
||||
receive notifications about due entries you delegated infolog el Λήψη ειδοποιήσεων για καταχωρήσεις των οποίων είστε εξουσιοδοτημένος και που έχουν καθυστερήσει
|
||||
receive notifications about items assigned to you infolog el Λήψη ειδοποιήσεων για αντικείμενα τα οποία σας έχουν ανατεθεί
|
||||
receive notifications about own items infolog el Λήψη ειδοποιήσεων για τα δικά σας αντικείμενα
|
||||
receive notifications about starting entries you are responsible for infolog el Λήψη ειδοποιήσεων για καταχωρήσεις που ξεκινούν και για τις οποίες είστε υπεύθυνος
|
||||
receive notifications about starting entries you delegated infolog el Λήψη ειδοποιήσεων για καταχωρήσεις που ξεκινούν και για τις οποίες είστε εξουσιοδοτημένος
|
||||
receive notifications as html-mails infolog el Λήψη ειδοποιήσεων ως html-mails
|
||||
remark infolog el Ξαναμαρκάρετε
|
||||
remove this link (not the entry itself) infolog el Αφαιρέστε το σύνδεσμο (όχι την ίδια την καταχώρηση)
|
||||
responsible infolog el υπεύθυνος
|
||||
responsible open infolog el υπεύθυνος ανοικτά
|
||||
responsible overdue infolog el υπεύθυνος καθυστερημένα
|
||||
responsible upcoming infolog el υπεύθυνος επερχόμενα
|
||||
responsible user, priority infolog el υπεύθυνος χρήστης, προτεραιότητα
|
||||
returns a list / search for records. infolog el Επιστρέφει μια λίστα/αναζήτηση για εγγραφές
|
||||
rights for the responsible infolog el Δικαιώματα για τον υπεύθυνο
|
||||
same day infolog el ίδια ημέρα
|
||||
save infolog el Αποθήκευση
|
||||
saves the changes made and leaves infolog el αποθηκεύει τις αλλαγές που έγιναν και αποχωρεί
|
||||
saves this entry infolog el Αποθηκεύει την καταχώρηση
|
||||
search infolog el Αναζήτηση
|
||||
search for: infolog el Αναζήτηση για:
|
||||
select infolog el Επιλέξτε
|
||||
select a category for this entry infolog el επιλέξτε μια κατηγορία για αυτήν την καταχώρηση
|
||||
select a price infolog el Επιλέξτε μια τιμή
|
||||
select a priority for this task infolog el επιλέξτε προτεραιότητα για αυτό το έργο
|
||||
select a project infolog el Επιλέξτε ένα έργο
|
||||
select a responsible user: a person you want to delegate this task infolog el Επιλέξτε τον υπεύθυνο χρήστη: ένα άτομο στο οποίο θέλετε να αναθέσετε αυτό το έργο
|
||||
select a typ to edit it's status-values or delete it infolog el επιλέξτε έναν τύπο για να επιμεληθείτε την κατάστασή του
|
||||
select an app to search in infolog el Επελέξτε μία εφαρμογή στην οποία θα γίνει αναζήτηση
|
||||
select an entry to link with infolog el Επελέξτε μία καταχώρηση προς σύνδεση
|
||||
select to filter by owner infolog el Επιλογή φίλτρου σύμφωνα με τον ιδιοκτήτη
|
||||
select to filter by responsible infolog el Επιλογή φίλτρου σύμφωνα με τον υπεύθυνο
|
||||
sets the status of this entry and its subs to done infolog el Ορίζει την κατάσταση αυτής της καταχώρησης και των υποκατηγοριών της σε ολοκληρωμένη
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog el Θα έπρεπε το InfoLog να εμφανίζει τις υπο-εργασίες, -κλήσεις ή -σημειώσεις στην κανονική εμφάνιση ή όχι. Μπορείτε πάντα να βλέπετε τις υποκατηγορίες μέσω των μητρικών τους.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog el Θα έπρεπε το InfoLog να εμφανίζει τους συνδέσμους με άλλες εφαρμογές και/ή τις προσκολλήσεις αρχείου στην InfoLog λίστα (κανονική εμφάνιση όταν εισέρχεστε στο InfoLog).
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog el Θα έπρεπε το InfoLog να εμφανίζεται στη βασική οθόνη και με ποιο φίλτρο.Λειτουργεί μόνο αν δεν επιλέξατε μία εφαρμογή για την βασική οθόνη (στις προτιμήσεις σας).
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog el Θα έπρεπε το InfoLog να χρησιμοποιεί ολόκληρα ονόματα (επώνυμα και οικογενειακά ονόματα) ή μόνο τα ονόματα εισόδου.
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog el Θα έπρεπε η InfoLog λίστα να εμφανίζει ένα μοναδικό νούμερο Id, το οποίο να μπορεί να χρησιμοποιείται π.χ. ως Id εισιτηρίου.
|
||||
should the infolog list show the column "last modified". infolog el Θα έπρεπε η InfoLog λίστα να εμφανίζει τη στήλη "τελευταία τροποποίηση".
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog el Θα έπρεπε η InfoLog λίστα να εμφανίζει το ποσοστό ολοκλήρωσης μόνο για την κατάσταση τρέχων ή δύο ξεχωριστά εικονίδια.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog el θέλετε αυτή η καταχώρηση να είναι ορατή σε εσάς και στα άτομα που δίνεται προσωπική άδεια μέσω του ACL
|
||||
show a column for used and planned times in the list. infolog el Παρουσιάστε μία στήλη για χρησιμοποιημένες και προγραμματισμένες ώρες στη λίστα
|
||||
show full usernames infolog el Παρουσίαση ολόκληρων των ονομάτων χρήστη
|
||||
show in the infolog list infolog el Εμφάνιση στην InfoLog λίστα
|
||||
show last modified infolog el Εμφάνιση τελευταίας μετατροπής
|
||||
show status and percent done separate infolog el Παρουσίαση της κατάστασης και του ποσοστού ολοκλήρωσης ξεχωριστά
|
||||
show ticket id infolog el Εμφάνιση Id εισιτηρίου
|
||||
show times infolog el Εμφάνιση των ωρών
|
||||
small view infolog el μικρή εμφάνιση
|
||||
start a new search, cancel this link infolog el έναρξη νέας αναζήτησης, ακύρωση αυτού του συνδέσμου
|
||||
startdate infolog el Ημερομηνία έναρξης
|
||||
startdate enddate infolog el Ημερομηνία έναρξης ημερομηνία εξόφλησης
|
||||
startdate for new entries infolog el Ημερομηνία έναρξης για νέες καταχωρήσεις
|
||||
startrecord infolog el Έναρξη εγγραφής
|
||||
status infolog el Κατάσταση
|
||||
status ... infolog el Κατάσταση
|
||||
sub infolog el Υπό
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog el Υπό-καταχωρήσεις γίνονται υποκατηγορίες των μητρικών ή βασικών καταχωρήσεων, αν δεν υπάρχει μητρική
|
||||
subject infolog el Θέμα
|
||||
sum infolog el Σύνολο
|
||||
task infolog el Εργασίες
|
||||
template infolog el Πρότυπο
|
||||
test import (show importable records <u>only</u> in browser) infolog el Έλεγχος Εισαγωγής (εμφάνιση εισαγώγιμων εγγραφών <u>only</> στο browser)
|
||||
the text displayed to the user infolog el το κείμενο εμφανίζεται στο χρήστη
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog el Αυτές είναι οι χρήσεις του InfoLog φίλτρου όταν εισέρχεστε στην εφαρμογή.Τα φίλτρα περιορίζουν τις καταχωρήσεις να εμφανίζονται στην πραγματική παρουσίαση.Υπάρχουν φίλτρα που παρουσιάζουν μόνο τα ολοκληρωμένα, τα τρέχοντα ή τις δικές σας μελλοντικές καταχωρήσεις ή και όλων των χρηστών.
|
||||
til when should the todo or phonecall be finished infolog el μέχρι πότε πρέπει το θέμα προς διεκπαιρέωση ή η τηλεφωνική κλήση να έχει τελείωσει
|
||||
times infolog el Ώρες
|
||||
to many might exceed your execution-time-limit infolog el Πάρα πολλοί. Ενδεχόμενο υπέρβασης ορίου χρόνου εκτέλεσης
|
||||
to what should the startdate of new entries be set. infolog el Σε τι πρέπει η ημερομηνία έναρξης νέων καταχωρήσεων να οριστεί.
|
||||
today infolog el Σήμερα
|
||||
todays date infolog el σημερινή ημερομηνία
|
||||
todo infolog el Εργασίες
|
||||
translation infolog el Μετάφραση
|
||||
typ infolog el Τύπος
|
||||
typ '%1' already exists !!! infolog el Ο τύπος '%1' υπάρχει ήδη
|
||||
type infolog el Τύπος
|
||||
type ... infolog el Τύπος ...
|
||||
type of customfield infolog el Τύπος προσαρμοσμένου πεδίου
|
||||
type of the log-entry: note, phonecall or todo infolog el Τύπος της ειδόδου-καταχώρησης: Σημείωση, Κλήση τηλεφώνου ή Εργασίες
|
||||
unlink infolog el Αποσύνδεση
|
||||
upcoming infolog el επερχόμενο
|
||||
urgency infolog el επείγον
|
||||
urgent infolog el επείγον
|
||||
used time infolog el χρησιμοποιημένος χρόνος
|
||||
valid path on clientside<br>eg. \servershare or e: infolog el έγκυρο μονοπάτι προς την πλευρά του πελάτη<br>π.χ. \\Server\Share ή e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog el έγκυρο μονοπάτι προς την πλευρά του πελάτη<br>π.χ. \\Server\Share ή e:\
|
||||
values for selectbox infolog el Αξίες του επιλεγμένου κουτιού
|
||||
view all subs of this entry infolog el Εμφάνιση όλων των υποκατηγοριών αυτής της καταχώρησης
|
||||
view other subs infolog el εμφάνιση άλλων υποκατηγοριών
|
||||
view parent infolog el Εμφάνιση μητρικής
|
||||
view subs infolog el εμφάνιση υποκατηγοριών
|
||||
view the parent of this entry and all his subs infolog el Εμφάνιση της μητρικής αυτής της καταχώρησης και όλων των υποκατηγοριών της
|
||||
view this linked entry in its application infolog el εμφάνιση αυτής της συνδεδεμένης καταχώρησης στην αίτησή της
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog el πότε θα έπρεπε οι Εργασίες ή Κλήση τηλεφώνου να αρχίζουν,εμφανίζεται από εκείνη την ημερομηνία στο άνοιγμα φίλτρου ή δικά μου άνοιγμα (αρχική σελίδα)
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog el Ποια επιπλέον πεδία πρέπει ο υπεύθυνος να έχει άδεια να επιμεληθεί χωρίς να έχει δικαιώματα επιμέλειας;<br/>Κατάσταση, ποσοστό και ημερομηνία ολοκλήρωσης είναι πάντοτε επιτρεπτά.
|
||||
which implicit acl rights should the responsible get? infolog el Ποια αυτονόητα ACL δικαιώματα πρέπει ο υπεύθυνος να έχει;
|
||||
whole query infolog el ολόκληρη απορία
|
||||
will-call infolog el θα τηλεφωνήσει
|
||||
write (add or update) a record by passing its fields. infolog el Καταγραφή (προσθήκη ή ενημέρωση) μιας εγγραφής διαβαίνοντας από τα πεδία της.
|
||||
yes - delete infolog el Ναι- Διαγραφή
|
||||
yes - delete including sub-entries infolog el Ναι-Διαγραφή συμπεριλαμβανομένων και των υπο-καταχωρήσεων
|
||||
yes, noone can purge deleted items infolog el Νια, κανείς δεν μπορεί να καθαρίσει τα αντικείμενα που έχουν διαγραφεί
|
||||
yes, only admins can purge deleted items infolog el Ναι, μόνο ο διαχειριστής μπορεί να καθαρίσει τα αντικείμενα που έχουν διαγραφεί
|
||||
yes, with larger fontsize infolog el Ναι, με μεγαλύτερο μέγεθος φόντου
|
||||
yes, with purging of deleted items possible infolog el Ναι, με τον καθαρισμό των διαγραμένων αντικειμένων να είναι δυνατός
|
||||
you can't delete one of the stock types !!! infolog el Δεν μπορείτε να διαγράψετε έναν από τους προκαθορισμένους τύπους !!!
|
||||
you have entered an invalid ending date infolog el Έχετε πληκτρολογήσει μια άκυρη ημερομηνία οφειλής
|
||||
you have entered an invalid starting date infolog el Έχετε πληκτρολογήσει μια άκυρη ημερομηνία έναρξης
|
||||
you have to enter a name, to create a new typ!!! infolog el Πρέπει να πληκτρολογήσετε ένα όνομα, για τη δημιουργία νέου τύπου!!!
|
||||
you must enter a subject or a description infolog el Πρέπει να πληκτρολογήσετε ένα θέμα ή μια περιγραφή
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog el Το ηλεκτρονικό σας αρχείο ΔΕΝ είναι ενημερωμένο (%1 vs. %2), παρακαλώ τρέξτε %3setup%4 για να ενημερώσετε το ηλεκτρονικό σας αρχείο.
|
490
infolog/lang/egw_en.lang
Normal file
490
infolog/lang/egw_en.lang
Normal file
@ -0,0 +1,490 @@
|
||||
%1 days in advance infolog en %1 days in advance
|
||||
%1 deleted infolog en %1 deleted
|
||||
%1 deleted by %2 at %3 infolog en %1 deleted by %2 at %3
|
||||
%1 entries %2 infolog en %1 entries %2
|
||||
%1 entries %2, %3 failed because of insufficent rights !!! infolog en %1 entries %2, %3 failed because of insufficent rights !!!
|
||||
%1 modified infolog en %1 modified
|
||||
%1 modified by %2 at %3 infolog en %1 modified by %2 at %3
|
||||
%1 records imported infolog en %1 records imported
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog en %1 records read (not yet imported, you may go %2back%3 and uncheck Test Import)
|
||||
%1 you are responsible for is due at %2 infolog en %1 you are responsible for is due at %2
|
||||
%1 you are responsible for is starting at %2 infolog en %1 you are responsible for is starting at %2
|
||||
%1 you delegated is due at %2 infolog en %1 you delegated is due at %2
|
||||
%1 you delegated is starting at %2 infolog en %1 you delegated is starting at %2
|
||||
- subprojects from infolog en - Subprojects from
|
||||
0% infolog en 0%
|
||||
10% infolog en 10%
|
||||
100% infolog en 100%
|
||||
20% infolog en 20%
|
||||
30% infolog en 30%
|
||||
40% infolog en 40%
|
||||
50% infolog en 50%
|
||||
60% infolog en 60%
|
||||
70% infolog en 70%
|
||||
80% infolog en 80%
|
||||
90% infolog en 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog en <b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients
|
||||
a short subject for the entry infolog en a short subject for the entry
|
||||
abort without deleting infolog en Abort without deleting
|
||||
accept infolog en accept
|
||||
action infolog en Action
|
||||
actions... infolog en Actions...
|
||||
actual date and time infolog en actual date and time
|
||||
add infolog en Add
|
||||
add / remove link infolog en Add / Remove link
|
||||
add a file infolog en Add a file
|
||||
add a new entry infolog en Add a new Entry
|
||||
add a new note infolog en Add a new Note
|
||||
add a new phonecall infolog en Add a new Phone Call
|
||||
add a new sub-task, -note, -call to this entry infolog en Add a new sub-task, -note, -call to this entry
|
||||
add a new todo infolog en Add a new ToDo
|
||||
add file infolog en Add file
|
||||
add or delete links infolog en Add or delete links
|
||||
add sub infolog en add Sub
|
||||
add timesheet entry infolog en Add timesheet entry
|
||||
add: infolog en Add:
|
||||
added infolog en added
|
||||
all infolog en All
|
||||
all links and attachments infolog en all links and attachments
|
||||
all projects infolog en All projects
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog en Allows to set the status of an entry, eg. set a ToDo to done if it's finished (values depend on entry-type)
|
||||
alternatives infolog en Alternatives
|
||||
apply the action on the whole query, not only the shown entries!!! infolog en Apply the action on the whole query, NOT only the shown entries!!!
|
||||
apply the changes infolog en Apply the changes
|
||||
archive infolog en archive
|
||||
are you shure you want to close this entry ? infolog en Are you shure you want to close this entry ?
|
||||
are you shure you want to delete this entry ? infolog en Are you sure you want to delete this entry ?
|
||||
at the moment the following document-types are supported: infolog en At the moment the following document-types are supported:
|
||||
attach a file infolog en Attach a file
|
||||
attach file infolog en Attach file
|
||||
attention: no contact with address %1 found. infolog en Attention: No Contact with address %1 found.
|
||||
back to main list infolog en Back to main list
|
||||
billed infolog en billed
|
||||
both infolog en both
|
||||
call infolog en call
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog en Can be used to show further InfoLog types in the calendar or limit it to show e.g. only tasks.
|
||||
cancel infolog en Cancel
|
||||
cancelled infolog en cancelled
|
||||
categories infolog en Categories
|
||||
category infolog en Category
|
||||
change category infolog en Change category
|
||||
change completed infolog en Change completed
|
||||
change completion infolog en Change completion
|
||||
change history infolog en Change history
|
||||
change owner when updating infolog en Change owner when updating
|
||||
change responsible infolog en Change responsible
|
||||
change status: infolog en Change status:
|
||||
change the status of an entry, eg. close it infolog en Change the status of an entry, eg. close it
|
||||
change type: infolog en Change type:
|
||||
changed category to %1 infolog en changed category to %1
|
||||
changed completion to %1% infolog en changed completion to %1%
|
||||
changed responsible infolog en changed responsible
|
||||
changed status to %1 infolog en changed status to %1
|
||||
changed type infolog en changed type
|
||||
charset of file infolog en Charset of file
|
||||
check all infolog en Check all
|
||||
check to set startday infolog en check to set startday
|
||||
check to specify custom contact infolog en Check to specify custom contact
|
||||
choose owner of imported data infolog en Choose owner of imported data
|
||||
click here to create the link infolog en click here to create the Link
|
||||
click here to start the search infolog en click here to start the search
|
||||
close infolog en Close
|
||||
close all infolog en Close all
|
||||
close this entry and all listed sub-entries infolog en Close this entry and all listed sub-entries
|
||||
closed infolog en closed
|
||||
colon (:) separated list of field names to use if value is empty or to sum up infolog en colon (:) separated list of field names to use if value is empty or to sum up
|
||||
comment infolog en Comment
|
||||
compare infolog en Compare
|
||||
completed infolog en Completed
|
||||
configuration infolog en Configuration
|
||||
confirm infolog en Confirm
|
||||
contact infolog en Contact
|
||||
contact cf infolog en contact CF
|
||||
contact fields infolog en Contact fields
|
||||
contactfield infolog en Contactfield
|
||||
copy of: infolog en Copy of:
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog en Copy your changes to the clipboard, %1reload the entry%2 and merge them.
|
||||
create new links infolog en Create new links
|
||||
creates a new field infolog en creates a new field
|
||||
creates a new status with the given values infolog en creates a new status with the given values
|
||||
creates a new typ with the given name infolog en creates a new type with the given name
|
||||
creation infolog en Creation
|
||||
csv-fieldname infolog en CSV-Fieldname
|
||||
csv-filename infolog en CSV-Filename
|
||||
csv-import common en CSV-Import
|
||||
custom infolog en Custom
|
||||
custom contact-address, leave empty to use information from most recent link infolog en Custom contact-address, leave empty to use information from most recent link
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog en Custom contact-information, leave empty to use information from most recent link
|
||||
custom fields infolog en Custom Fields
|
||||
custom fields, typ and status common en Custom fields, type and status
|
||||
custom from infolog en Custom from
|
||||
custom regarding infolog en Custom regarding
|
||||
custom status for typ infolog en Custom status for type
|
||||
customfields infolog en Customfields
|
||||
date completed infolog en Date completed
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog en Date completed (leave it empty to have it automatically set if status is done or billed)
|
||||
datecreated infolog en date created
|
||||
dates, status, access infolog en Dates, Status, Access
|
||||
days infolog en days
|
||||
default category for new infolog entries infolog en Default category for new Infolog entries
|
||||
default document to insert entries infolog en Default document to insert entries
|
||||
default filter for infolog infolog en Default Filter for InfoLog
|
||||
default status for a new log entry infolog en default status for a new log entry
|
||||
delegated infolog en delegated
|
||||
delegated open infolog en delegated open
|
||||
delegated open and upcoming infolog en delegated open and upcoming
|
||||
delegated overdue infolog en delegated overdue
|
||||
delegated upcomming infolog en delegated upcomming
|
||||
delegation infolog en Delegation
|
||||
delete infolog en Delete
|
||||
delete one record by passing its id. infolog en Delete one record by passing its id.
|
||||
delete selected entries? infolog en Delete selected entries?
|
||||
delete the entry infolog en Delete the entry
|
||||
delete this entry infolog en delete this entry
|
||||
delete this entry and all listed sub-entries infolog en Delete this entry and all listed sub-entries
|
||||
deleted infolog en deleted
|
||||
deletes the selected typ infolog en deletes the selected type
|
||||
deletes this field infolog en deletes this field
|
||||
deletes this status infolog en deletes this status
|
||||
description infolog en Description
|
||||
determines the order the fields are displayed infolog en determines the order the fields are displayed
|
||||
directory with documents to insert entries infolog en Directory with documents to insert entries
|
||||
disables a status without deleting it infolog en disables a status without deleting it
|
||||
do not notify of these changes infolog en Do not notify of these changes
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog en Do you want a confirmation of the responsible on: accepting, finishing the task or both
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog en Do you want a notification, if items get assigned to you or assigned items get updated?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog en Do you want a notification, if items you are responsible for are about to start?
|
||||
do you want a notification, if items you are responsible for are due? infolog en Do you want a notification, if items you are responsible for are due?
|
||||
do you want a notification, if items you created get updated? infolog en Do you want a notification, if items you created get updated?
|
||||
do you want a notification, if items you delegated are about to start? infolog en Do you want a notification, if items you delegated are about to start?
|
||||
do you want a notification, if items you delegated are due? infolog en Do you want a notification, if items you delegated are due?
|
||||
do you want to receive notifications as html-mails or plain text? infolog en Do you want to receive notifications as html-mails or plain text?
|
||||
document '%1' does not exist or is not readable for you! infolog en Document '%1' does not exist or is not readable for you!
|
||||
don't show infolog infolog en DON'T show InfoLog
|
||||
done common en done
|
||||
download infolog en Download
|
||||
due %1 infolog en Due %1
|
||||
duration infolog en Duration
|
||||
e-mail: infolog en E-mail:
|
||||
each value is a line like <id>[=<label>] infolog en Each value is a line like <id>[=<label>]
|
||||
edit infolog en Edit
|
||||
edit or create categories for ingolog infolog en Edit or create categories for IngoLog
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog en Edit rights (full edit rights incl. making someone else responsible!)
|
||||
edit status infolog en Edit status
|
||||
edit the entry infolog en Edit the entry
|
||||
edit this entry infolog en Edit this entry
|
||||
empty for all infolog en empty for all
|
||||
end infolog en End
|
||||
enddate infolog en Due date
|
||||
enddate can not be before startdate infolog en Due date can not be before start date
|
||||
enter a custom contact, leave empty if linked entry should be used infolog en Enter a custom contact, leave empty if linked entry should be used
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog en Enter a custom phone/email, leave empty if linked entry should be used
|
||||
enter a textual description of the log-entry infolog en enter a textual description of the log-entry
|
||||
enter the query pattern infolog en Enter the query pattern
|
||||
entry and all files infolog en Entry and all files
|
||||
error: saving the entry infolog en Error: saving the entry
|
||||
error: the entry has been updated since you opened it for editing! infolog 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. infolog 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.
|
||||
example {{letterprefixcustom n_prefix title n_family}} - example: mr dr. james miller infolog en Example {{LETTERPREFIXCUSTOM n_prefix title n_family}} - Example: Mr Dr. James Miller
|
||||
example {{nelf role}} - if field role is not empty, you will get a new line with the value of field role infolog en Example {{NELF role}} - if field role is not empty, you will get a new line with the value of field role
|
||||
example {{nelfnv role}} - if field role is not empty, set a lf without any value of the field infolog en Example {{NELFNV role}} - if field role is not empty, set a LF without any value of the field
|
||||
execute a further action for this entry infolog en Execute a further action for this entry
|
||||
existing links infolog en Existing links
|
||||
exists infolog en exists
|
||||
export definitition to use for nextmatch export infolog en Export definitition to use for nextmatch export
|
||||
exports infolog entries into a csv file. infolog en Exports Infolog entries into a CSV File.
|
||||
fax infolog en Fax
|
||||
field must not be empty !!! infolog en Field must not be empty !!!
|
||||
fieldseparator infolog en Fieldseparator
|
||||
finish infolog en finish
|
||||
first argument for preg_replace infolog en first argument for preg_replace
|
||||
for serial letter use this tag. put the content, you want to repeat between two tags. infolog en For serial letter use this tag. Put the content, you want to repeat between two Tags.
|
||||
for which types should this field be used infolog en for which types should this field be used
|
||||
from infolog en From
|
||||
general infolog en General
|
||||
general fields: infolog en General fields:
|
||||
global categories infolog en Global Categories
|
||||
group owner for infolog en Group owner for
|
||||
high infolog en high
|
||||
history infolog en History
|
||||
history logging infolog en History logging
|
||||
history logging and deleting of items infolog en History logging and deleting of items
|
||||
how many describtion lines should be directly visible. further lines are available via a scrollbar. infolog en How many description lines should be directly visible. Further lines are available via a scroll bar.
|
||||
how wide should the description area be. this value is numeric and interpreted as em; 60 works reasonably well. infolog en How wide should the description area be. This value is numeric and interpreted as em; 60 works reasonably well.
|
||||
id infolog en Id
|
||||
id# infolog en Id#
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog en If a type has a group owner, all entries of that type will be owned by the given group and NOT the user who created it!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog en If not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences).
|
||||
if you specify a directory (full vfs path) here, infolog displays an action for each document. that action allows to download the specified document with the infolog data inserted. infolog en If you specify a directory (full vfs path) here, infolog displays an action for each document. That action allows to download the specified document with the infolog data inserted.
|
||||
if you specify a document (full vfs path) here, infolog displays an extra document icon for each entry. that icon allows to download the specified document with the contact data inserted. infolog en If you specify a document (full vfs path) here, infolog displays an extra document icon for each entry. That icon allows to download the specified document with the contact data inserted.
|
||||
if you specify an export definition, it will be used when you export infolog en If you specify an export definition, it will be used when you export
|
||||
import infolog en Import
|
||||
import next set infolog en import next set
|
||||
importance infolog en Importance
|
||||
imports entries into the infolog from a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. infolog en Imports entries into the infolog from a CSV File. CSV means 'Comma Seperated Values'. However in the options Tab you can also choose other seperators.
|
||||
info log common en InfoLog
|
||||
infolog common en InfoLog
|
||||
infolog - delete infolog en Info Log - Delete
|
||||
infolog - edit infolog en InfoLog - Edit
|
||||
infolog - import csv-file infolog en InfoLog - Import CSV-File
|
||||
infolog - new infolog en InfoLog - New
|
||||
infolog - new subproject infolog en InfoLog - New Subproject
|
||||
infolog - subprojects from infolog en InfoLog - Subprojects from
|
||||
infolog copied - the copy can now be edited infolog en Infolog copied - the copy can now be edited
|
||||
infolog csv export infolog en Infolog CSV export
|
||||
infolog csv import infolog en Infolog CSV import
|
||||
infolog entry deleted infolog en InfoLog entry deleted
|
||||
infolog entry saved infolog en InfoLog entry saved
|
||||
infolog fields: infolog en Infolog fields:
|
||||
infolog filter for the main screen infolog en InfoLog filter for the main screen
|
||||
infolog id infolog en Infolog ID
|
||||
infolog list infolog en InfoLog list
|
||||
infolog preferences common en InfoLog preferences
|
||||
infolog-fieldname infolog en Info Log-Fieldname
|
||||
insert infolog en insert
|
||||
insert in document infolog en Insert in document
|
||||
invalid filename infolog en Invalid filename
|
||||
invalid owner id: %1. might be a bad field translation. used %2 instead. infolog en Invalid owner ID: %1. Might be a bad field translation. Used %2 instead.
|
||||
invalid status for entry type %1. infolog en Invalid status for entry type %1.
|
||||
label<br>helptext infolog en Label<br>Helptext
|
||||
last changed infolog en Last changed
|
||||
last modified infolog en Last modified
|
||||
leave blank to get the used time calculated by timesheet entries infolog en Leave blank to get the used time calculated by time sheet entries
|
||||
leave it empty infolog en leave it empty
|
||||
leave it empty for a full week infolog en Leave it empty for a full week
|
||||
leave without saveing the entry infolog en leave without saveing the entry
|
||||
leaves without saveing infolog en leaves without saveing
|
||||
length<br>rows infolog en Length<br>Rows
|
||||
limit number of description lines (default 5, 0 for no limit) infolog en Limit number of description lines (default 5, 0 for no limit)
|
||||
limit width of description column ((effective only if lines limit is set), 0 for no limit) infolog en Limit width of description column ((effective only if lines limit is set), 0 for no limit)
|
||||
link infolog en Link
|
||||
linked to %1 infolog en linked to %1
|
||||
links infolog en Links
|
||||
links of this entry infolog en Links of this entry
|
||||
list all categories infolog en List all categories
|
||||
list no subs/childs infolog en List no Subs/Childs
|
||||
location infolog en Location
|
||||
longer textual description infolog en longer textual description
|
||||
low infolog en low
|
||||
manage mapping infolog en Manage mapping
|
||||
max length of the input [, length of the inputfield (optional)] infolog en max length of the input [, length of the input field (optional)]
|
||||
modifier infolog en Modifier
|
||||
modifierer infolog en Modifierer
|
||||
name must not be empty !!! infolog en Name must not be empty !!!
|
||||
name of current user, all other contact fields are valid too infolog en Name of current user, all other contact fields are valid too
|
||||
name of new type to create infolog en name of new type to create
|
||||
never hide search and filters infolog en Never hide search and filters
|
||||
new %1 infolog en New %1
|
||||
new %1 created by %2 at %3 infolog en New %1 created by %2 at %3
|
||||
new name infolog en new name
|
||||
new search infolog en New search
|
||||
no - cancel infolog en No - Cancel
|
||||
no describtion, links or attachments infolog en no describtion, links or attachments
|
||||
no details infolog en no details
|
||||
no entries found, try again ... infolog en no entries found, try again ...
|
||||
no filter infolog en no Filter
|
||||
no links or attachments infolog en no links or attachments
|
||||
no project infolog en No project
|
||||
nonactive infolog en nonactive
|
||||
none infolog en None
|
||||
normal infolog en normal
|
||||
not infolog en not
|
||||
not assigned infolog en not assigned
|
||||
not-started infolog en not started
|
||||
note infolog en Note
|
||||
number of records to read (%1) infolog en Number of records to read (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog en number of row for a multi-line input field or line of a multi-select-box
|
||||
offer infolog en offer
|
||||
one day after infolog en one day after
|
||||
one day in advance infolog en one day in advance
|
||||
ongoing infolog en ongoing
|
||||
only for details infolog en Only for details
|
||||
only if i get assigned or removed infolog en Only if I get assigned or removed
|
||||
only the attachments infolog en only the attachments
|
||||
only the links infolog en only the links
|
||||
open infolog en open
|
||||
open and upcoming infolog en open and upcoming
|
||||
optional note to the link infolog en optional note to the Link
|
||||
order infolog en Order
|
||||
organization infolog en Organization
|
||||
overdue infolog en overdue
|
||||
own infolog en own
|
||||
own open infolog en own open
|
||||
own open and upcoming infolog en own open and upcoming
|
||||
own overdue infolog en own overdue
|
||||
own upcoming infolog en own upcoming
|
||||
owner does not have edit rights infolog en Owner does not have edit rights
|
||||
parent infolog en Parent
|
||||
parent infolog infolog en Parent Infolog
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog en path on (web-)serverside<br>eg. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog en Path to user and group files HAS TO BE OUTSIDE of the webservers document-root!!!
|
||||
pattern for search in addressbook infolog en pattern for search in Addressbook
|
||||
pattern for search in projects infolog en pattern for search in Projects
|
||||
percent completed infolog en Percent completed
|
||||
permission denied infolog en Permission denied
|
||||
permissions error - %1 could not %2 infolog en Permissions error - %1 could not %2
|
||||
phone infolog en Phone Call
|
||||
phone/email infolog en Phone/Email
|
||||
phonecall infolog en Phone Call
|
||||
planned infolog en planned
|
||||
planned time infolog en planned time
|
||||
price infolog en Price
|
||||
pricelist infolog en Pricelist
|
||||
primary link infolog en primary link
|
||||
priority infolog en Priority
|
||||
private infolog en Private
|
||||
project infolog en Project
|
||||
project settings: price, times infolog en Project settings: price, times
|
||||
projectmanager infolog en Projectmanager
|
||||
re-planned infolog en Re-planned
|
||||
re-planned time infolog en Re-planned time
|
||||
re: infolog en Re:
|
||||
read one record by passing its id. infolog en Read one record by passing its id.
|
||||
read rights (default) infolog en read rights (default)
|
||||
receive notifications about due entries you are responsible for infolog en Receive notifications about due entries you are responsible for
|
||||
receive notifications about due entries you delegated infolog en Receive notifications about due entries you delegated
|
||||
receive notifications about items assigned to you infolog en Receive notifications about items assigned to you
|
||||
receive notifications about own items infolog en Receive notifications about own items
|
||||
receive notifications about starting entries you are responsible for infolog en Receive notifications about starting entries you are responsible for
|
||||
receive notifications about starting entries you delegated infolog en Receive notifications about starting entries you delegated
|
||||
receive notifications as html-mails infolog en Receive notifications as html-mails
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog en reg. expr. for local IP's<br>eg. ^192\.168\.1\.
|
||||
regular expression infolog en Regular expression
|
||||
remark infolog en Remark
|
||||
remove this link (not the entry itself) infolog en Remove this link (not the entry itself)
|
||||
removed infolog en removed
|
||||
replacement infolog en Replacement
|
||||
replacements for inserting entries into documents infolog en Replacements for inserting entries into documents
|
||||
responsible infolog en responsible
|
||||
responsible open infolog en responsible open
|
||||
responsible open and upcoming infolog en responsible open and upcoming
|
||||
responsible overdue infolog en responsible overdue
|
||||
responsible upcoming infolog en responsible upcoming
|
||||
responsible user, priority infolog en responsible user, priority
|
||||
returns a list / search for records. infolog en Returns a list / search for records.
|
||||
rights for the responsible infolog en Rights for the responsible
|
||||
same day infolog en same day
|
||||
save infolog en Save
|
||||
saves the changes made and leaves infolog en saves the changes made and leaves
|
||||
saves this entry infolog en Saves this entry
|
||||
search infolog en Search
|
||||
search for: infolog en Search for:
|
||||
second parameter for preg_replace infolog en second parameter for preg_replace
|
||||
select infolog en Select
|
||||
select a category for this entry infolog en select a category for this entry
|
||||
select a price infolog en Select a price
|
||||
select a priority for this task infolog en select a priority for this task
|
||||
select a project infolog en Select a project
|
||||
select a responsible user: a person you want to delegate this task infolog en Select a responsible user: a person you want to delegate this task
|
||||
select a typ to edit it's status-values or delete it infolog en Select a type to edit it's status-values or delete it
|
||||
select an action infolog en Select an action
|
||||
select an action... infolog en Select an action...
|
||||
select an app to search in infolog en Select an App to search in
|
||||
select an entry to link with infolog en Select an entry to link with
|
||||
select multiple contacts for a further action infolog en Select multiple contacts for a further action
|
||||
select new category infolog en Select new category
|
||||
select to filter by owner infolog en select to filter by owner
|
||||
select to filter by responsible infolog en select to filter by responsible
|
||||
select users or groups infolog en Select users or groups
|
||||
selection cf infolog en Selection CF
|
||||
sender infolog en Sender
|
||||
set status to done infolog en Set status to done
|
||||
set status to done for all entries infolog en Set status to done for all entries
|
||||
sets the status of this entry and its subs to done infolog en Sets the status of this entry and its subs to done
|
||||
sets the status of this entry to done infolog en Sets the status of this entry to done
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog en Should InfoLog show Subtasks, -calls or -notes in the normal view or not. You can always view the subs via their parent.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog en Should InfoLog show the links to other applications and/or the file-attachments in the InfoLog list (normal view when you enter InfoLog).
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog en Should InfoLog show up on the main screen and with which filter. Works only if you didn't select an application for the main screen (in your preferences).
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog en Should InfoLog use full names (sure name and family name) or just the login names.
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog en Should the InfoLog list show a unique numerical Id, which can be used eg. as ticket Id.
|
||||
should the infolog list show the column "last modified". infolog en Should the InfoLog list show the column "last modified".
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog en Should the InfoLog list show the percent done only for status ongoing or two separate icons.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog en should this entry only be visible to you and people you grant private access via the ACL
|
||||
show a column for used and planned times in the list. infolog en Show a column for used and planned times in the list.
|
||||
show a x if content equals this compare value, otherwise show nothing infolog en show a X if content equals this compare value, otherwise show nothing
|
||||
show full usernames infolog en Show full usernames
|
||||
show in the infolog list infolog en Show in the InfoLog list
|
||||
show last modified infolog en Show last modified
|
||||
show status and percent done separate infolog en Show status and percent done separate
|
||||
show ticket id infolog en Show ticket Id
|
||||
show times infolog en Show times
|
||||
small view infolog en small view
|
||||
start infolog en Start
|
||||
start a new search, cancel this link infolog en start a new search, cancel this link
|
||||
startdate infolog en Start Date
|
||||
startdate enddate infolog en Start Date Due Date
|
||||
startdate for new entries infolog en Startdate for new entries
|
||||
starting %1 infolog en Starting %1
|
||||
startrecord infolog en Startrecord
|
||||
status infolog en Status
|
||||
status ... infolog en Status ...
|
||||
sub infolog en Sub
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog en Sub-entries become subs of the parent or main entries, if there's no parent
|
||||
sub-entries will not be closed infolog en Sub-entries will not be closed
|
||||
subject infolog en Subject
|
||||
sum infolog en Sum
|
||||
tag to mark positions for address labels infolog en Tag to mark positions for address labels
|
||||
task infolog en ToDo
|
||||
tasks of infolog en Tasks of
|
||||
template infolog en Template
|
||||
test import (show importable records <u>only</u> in browser) infolog en Test Import (show importable records <u>only</u> in browser)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog en the name used internally (<= 10 chars), changing it makes existing data unavailable
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog en the name used internally (<= 20 chars), changing it makes existing data unavailable
|
||||
the text displayed to the user infolog en the text displayed to the user
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog en This is the filter InfoLog uses when you enter the application. Filters limit the entries to show in the actual view. There are filters to show only finished, still open or futures entries of yourself or all users.
|
||||
til when should the todo or phonecall be finished infolog en til when should the ToDo or Phone call be finished
|
||||
times infolog en Times
|
||||
to many might exceed your execution-time-limit infolog en to many might exceed your execution-time-limit
|
||||
to what should the startdate of new entries be set. infolog en To what should the start date of new entries be set.
|
||||
today infolog en Today
|
||||
todays date infolog en todays date
|
||||
todo infolog en ToDo
|
||||
translation infolog en Translation
|
||||
typ infolog en Type
|
||||
typ '%1' already exists !!! infolog en Type '%1' already exists !!!
|
||||
type infolog en Type
|
||||
type ... infolog en Type ...
|
||||
type of customfield infolog en Type of customfield
|
||||
type of the log-entry: note, phonecall or todo infolog en Type of the log-entry: Note, Phone call or ToDo
|
||||
unlink infolog en Unlink
|
||||
unlinked from %1 infolog en unlinked from %1
|
||||
upcoming infolog en upcoming
|
||||
urgency infolog en urgency
|
||||
urgent infolog en urgent
|
||||
use all infolog en Use all
|
||||
use field from csv if possible infolog en Use field from CSV if possible
|
||||
use search results infolog en Use search results
|
||||
use this tag for addresslabels. put the content, you want to repeat, between two tags. infolog en Use this tag for addresslabels. Put the content, you want to repeat, between two tags.
|
||||
used time infolog en used time
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog en valid path on clientside<br>eg. \\Server\Share or e:\
|
||||
values for selectbox infolog en Values for selectbox
|
||||
view all subs of this entry infolog en View all subs of this entry
|
||||
view other subs infolog en view other Subs
|
||||
view parent infolog en View parent
|
||||
view subs infolog en view Subs
|
||||
view the parent of this entry and all his subs infolog en View the parent of this entry and all his subs
|
||||
view this linked entry in its application infolog en view this linked entry in its application
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog en when should the ToDo or Phone call be started, it shows up from that date in the filter open or own open (start page)
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog en Which additional fields should the responsible be allowed to edit without having edit rights?<br />Status, percent and date completed are always allowed.
|
||||
which implicit acl rights should the responsible get? infolog en Which implicit ACL rights should the responsible get?
|
||||
which types should the calendar show infolog en Which types should the calendar show
|
||||
whole query infolog en whole query
|
||||
will-call infolog en will call
|
||||
write (add or update) a record by passing its fields. infolog en Write (add or update) a record by passing its fields.
|
||||
yes - close infolog en Yes - Close
|
||||
yes - close including sub-entries infolog en Yes - Close including sub-entries
|
||||
yes - delete infolog en Yes - Delete
|
||||
yes - delete including sub-entries infolog en Yes - Delete including sub-entries
|
||||
yes, noone can purge deleted items infolog en Yes, noone can purge deleted items
|
||||
yes, only admins can purge deleted items infolog en Yes, only admins can purge deleted items
|
||||
yes, with larger fontsize infolog en Yes, with larger fontsize
|
||||
yes, with purging of deleted items possible infolog en Yes, with purging of deleted items possible
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog en You can choose a category to be preselected, when you create a new InfoLog entry
|
||||
you can't delete one of the stock types !!! infolog en You can't delete one of the stock types !!!
|
||||
you have entered an invalid ending date infolog en You have entered an invalid due date
|
||||
you have entered an invalid starting date infolog en You have entered an invalid starting date
|
||||
you have to enter a name, to create a new typ!!! infolog en You have to enter a name, to create a new type!!!
|
||||
you must enter a subject or a description infolog en You must enter a subject or a description
|
||||
you need to select an entry for linking. infolog en You need to select an entry for linking.
|
||||
you need to select some entries first infolog en You need to select some entries first
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog en Your database is NOT up to date (%1 vs. %2), please run %3setup%4 to update your database.
|
@ -26,7 +26,6 @@ a short subject for the entry infolog es-es descripción corta para la entrada
|
||||
abort without deleting infolog es-es Cancelar sin eliminar
|
||||
accept infolog es-es aceptar
|
||||
action infolog es-es Acción
|
||||
actions... infolog es-es Acciones...
|
||||
actual date and time infolog es-es Fecha y hora actuales
|
||||
add infolog es-es Añadir
|
||||
add a file infolog es-es Añadir archivo
|
||||
@ -75,7 +74,6 @@ completed infolog es-es Completado
|
||||
configuration infolog es-es Configuración
|
||||
confirm infolog es-es Confirmar
|
||||
contact infolog es-es Contacto
|
||||
copy of: infolog es-es Copia de:
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog es-es Copiar los cambios al portapapeles, %1recargar la entrada%2 e incluirlos.
|
||||
create new links infolog es-es Crear nuevos enlaces
|
||||
creates a new field infolog es-es crea un campo nuevo
|
||||
@ -179,7 +177,6 @@ infolog - import csv-file infolog es-es Registro - Importar archivo CSV
|
||||
infolog - new infolog es-es Registro - Nuevo
|
||||
infolog - new subproject infolog es-es Registro - Nuevo subproyecto
|
||||
infolog - subprojects from infolog es-es Registro - Subproyectos de
|
||||
infolog copied - the copy can now be edited infolog es-es Registro copiado - ahora la copia se puede editar
|
||||
infolog entry deleted infolog es-es Se ha borrado la entrada del registro
|
||||
infolog entry saved infolog es-es Se ha guardado la entrada en el registro
|
||||
infolog filter for the main screen infolog es-es Filtro para el registro en la pantalla principal
|
||||
@ -279,7 +276,6 @@ receive notifications about own items infolog es-es Recibir notificaciones acerc
|
||||
receive notifications about starting entries you are responsible for infolog es-es Recibir notificaciones acerca de las entradas que comienzan de las que usted es responsable
|
||||
receive notifications about starting entries you delegated infolog es-es Recibir notificaciones acerca de las entradas que comienzan que usted ha delegado
|
||||
receive notifications as html-mails infolog es-es Recibir notificaciones como correo html
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog es-es expresión regular para IPs locales<br>ej. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog es-es expresión regular para IPs locales<br>ej. ^192\.168\.1\.
|
||||
remark infolog es-es Comentario
|
||||
remove this link (not the entry itself) infolog es-es Eliminar este enlace (no la entrada en sí)
|
||||
@ -308,8 +304,6 @@ select an entry to link with infolog es-es Seleccionar una entrada a la que apun
|
||||
select to filter by owner infolog es-es seleccionar para filtrar por propietario
|
||||
select to filter by responsible infolog es-es seleccionar para filtrar por responsable
|
||||
sender infolog es-es Remitente
|
||||
set status to done infolog es-es Establecer estado a terminado
|
||||
set status to done for all entries infolog es-es Establecer el estado a terminado para todas las entradas
|
||||
sets the status of this entry and its subs to done infolog es-es Pone el estado de esta entrada y las inferiores a Hecho
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog es-es ¿Mostrar las Subtareas (llamadas o notas) en la vista normal? Siempre puede ver estos subtipos a través de su tipo superior.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog es-es ¿Deben mostrarse los enlaces a otras aplicaciones y/o los ficheros adjuntos en la lista del registro (la vista normal al entrar en el registro)?
|
||||
@ -365,7 +359,6 @@ urgency infolog es-es Urgencia
|
||||
urgent infolog es-es urgente
|
||||
used time infolog es-es tiempo utilizado
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog es-es ruta válida en el cliente<br>p.ej. \\servidor\recurso o e:
|
||||
valid path on clientside<br>eg. \servershare or e: infolog es-es ruta válida en el cliente<br>p.ej. \\servidor\recurso o e:
|
||||
values for selectbox infolog es-es Valores para lista desplegable
|
||||
view all subs of this entry infolog es-es Ver todos los subs de esta entrada
|
||||
view other subs infolog es-es ver otros subs
|
||||
@ -377,6 +370,7 @@ when should the todo or phonecall be started, it shows up from that date in the
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog es-es ¿Qué campos adicionales puede editar el responsable sin tener derechos de edición?<br />El estado, porcentaje y fecha de finalización se permiten siempre.
|
||||
which implicit acl rights should the responsible get? infolog es-es ¿Qué derechos implícitos de ACL debe tener el responsable?
|
||||
which types should the calendar show infolog es-es Qué tipos debe mostrar el calendario
|
||||
whole query infolog es-es la consulta completa
|
||||
will-call infolog es-es va a llamar
|
||||
write (add or update) a record by passing its fields. infolog es-es Escribir (añadir o actualizar) un registro pasando sus campos.
|
||||
yes - close infolog es-es Sí, cerrar
|
||||
|
398
infolog/lang/egw_fi.lang
Normal file
398
infolog/lang/egw_fi.lang
Normal file
@ -0,0 +1,398 @@
|
||||
%1 days in advance infolog fi %1 päivää etukäteen
|
||||
%1 deleted infolog fi %1 poistettu
|
||||
%1 deleted by %2 at %3 infolog fi %1 poistanut: %2, klo %3
|
||||
%1 modified infolog fi %1 muokattu
|
||||
%1 modified by %2 at %3 infolog fi %1 muokannut: %2, klo %3
|
||||
%1 records imported infolog fi %1 tietue(tta) tuotu
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog fi %1 tietue(tta) luettu (Ei vielä tuotu, mene %2takaisin%3 ja poista valinta Testi Tuonti)
|
||||
%1 you are responsible for is due at %2 infolog fi %1, jossa olet vastuuhenkilönä, erääntyy
|
||||
%1 you are responsible for is starting at %2 infolog fi %1, jossa olet vastuuhenkilönä, alkaa
|
||||
%1 you delegated is due at %2 infolog fi %1, jonka delegoit, erääntyy
|
||||
%1 you delegated is starting at %2 infolog fi %1, jonka delegoit, alkaa
|
||||
- subprojects from infolog fi - Aliprojektit
|
||||
0% infolog fi 0%
|
||||
10% infolog fi 10%
|
||||
100% infolog fi 100%
|
||||
20% infolog fi 20%
|
||||
30% infolog fi 30%
|
||||
40% infolog fi 40%
|
||||
50% infolog fi 50%
|
||||
60% infolog fi 60%
|
||||
70% infolog fi 70%
|
||||
80% infolog fi 80%
|
||||
90% infolog fi 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog fi <b>Liitetiedostot symbolisina linkkeinä</b>Sen sijaan että lataisit ja etsisit tiedostoja: /polku suoraan lähiverkon koneille
|
||||
a short subject for the entry infolog fi Lyhyt aihe merkinnälle
|
||||
abort without deleting infolog fi Keskeytä ilman poistamista
|
||||
accept infolog fi Hyväksy
|
||||
action infolog fi Toiminnot
|
||||
actions... infolog fi Toiminnot...
|
||||
actual date and time infolog fi Tämänhetkinen päivä ja aika
|
||||
add infolog fi Lisää
|
||||
add a file infolog fi Lisää tiedosto
|
||||
add a new entry infolog fi Lisää uusi merkintä
|
||||
add a new note infolog fi Lisää uusi muistiinpano
|
||||
add a new phonecall infolog fi Lisää uusi puhelinsoitto
|
||||
add a new sub-task, -note, -call to this entry infolog fi Lisää uusi ali-tehtävä, -huomautus, -soitto merkinnälle
|
||||
add a new todo infolog fi Lisää uusi tehtävä
|
||||
add file infolog fi Lisää tiedosto
|
||||
add sub infolog fi Lisää Sub
|
||||
add timesheet entry infolog fi Lisää ajanseurannan merkintä
|
||||
add: infolog fi Lisää:
|
||||
all infolog fi Kaikki
|
||||
all links and attachments infolog fi Kaikki linkit ja liitteet
|
||||
all projects infolog fi Kaikki projektit
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog fi Salli tilan muokkaaminen, esim. tehtävän tehdyksi asettaminen, jos se on päättynyt (arvot riippuvat sisällön muodosta).
|
||||
alternatives infolog fi Vaihtoehdot
|
||||
apply the changes infolog fi Hyväksy muutokset
|
||||
archive infolog fi Arkisto
|
||||
are you shure you want to close this entry ? infolog fi Haluatko varmasti sulkea tämän ikkunan?
|
||||
are you shure you want to delete this entry ? infolog fi Halutako varmasti poistaa tämän merkinnän?
|
||||
attach a file infolog fi Liitä tiedosto
|
||||
attach file infolog fi Liitä tiedosto
|
||||
attention: no contact with address %1 found. infolog fi Huomio: Yhteytietoja/Kontaktia %1 ei löytynyt
|
||||
back to main list infolog fi Takaisin päälistaan
|
||||
billed infolog fi Laskutettu
|
||||
both infolog fi Molemmat
|
||||
call infolog fi Puhelinsoitto
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog fi Valitse InfoLog tyypit joiden haluat näkyvän kalenterissa. Voit myös rajoittaa kalenterissa näkyvien IngoLogien määrän vain esim. Tehtäviin.
|
||||
cancel infolog fi Peruuta
|
||||
cancelled infolog fi Peruutettu
|
||||
categories infolog fi Kategoriat
|
||||
category infolog fi Kategoria
|
||||
change history infolog fi Muuta historiaa
|
||||
change the status of an entry, eg. close it infolog fi Vaihda merkinnän tilaa, esim. "Valmis"
|
||||
charset of file infolog fi Tiedoston merkistö
|
||||
check to set startday infolog fi Tarkista aloituspäivä
|
||||
check to specify custom contact infolog fi Valitse tietty yhteystieto
|
||||
click here to create the link infolog fi Luo linkki
|
||||
click here to start the search infolog fi Aloita haku
|
||||
close infolog fi Sulje
|
||||
close all infolog fi Sulje kaikki
|
||||
close this entry and all listed sub-entries infolog fi Sulje tämä merkintä ja kaikki sen alimerkinnät
|
||||
comment infolog fi Kommentti
|
||||
completed infolog fi Valmis
|
||||
configuration infolog fi Asetukset
|
||||
confirm infolog fi Vahvista
|
||||
contact infolog fi Yhteystieto
|
||||
copy of: infolog fi Kopio:
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog fi Kopioi tekemäsi muutokset leikepöydälle, %1 lataa merkintä %2 ja sulauta ne.
|
||||
create new links infolog fi Luo uusi linkki
|
||||
creates a new field infolog fi Luo uusi kenttä
|
||||
creates a new status with the given values infolog fi Luo uusi tila annetuilla arvoilla
|
||||
creates a new typ with the given name infolog fi Luo uusi tyyppi annetuilla nimillä
|
||||
creation infolog fi Luo uusi
|
||||
csv-fieldname infolog fi CSV -kentän nimi
|
||||
csv-filename infolog fi CSV -tiedoston nimi
|
||||
csv-import common fi CSV -Tuonti
|
||||
custom infolog fi Muokkaa
|
||||
custom fields infolog fi Lisäkentät
|
||||
custom fields, typ and status common fi Lisäkentät, tyyppi ja tila
|
||||
custom status for typ infolog fi Muokattava tila InfoLog-tyypille
|
||||
customfields infolog fi Lisäkentät
|
||||
date completed infolog fi Valmistumispäivä
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog fi Valmistumispäivä (jätä tyhjäksi automaattista asetusta varten, jos tilana on "Valmis" tai "Laskutettu")
|
||||
datecreated infolog fi Luotu
|
||||
dates, status, access infolog fi Päivämäärä, tila, ACL-oikeudet
|
||||
days infolog fi päivää
|
||||
default category for new infolog entries infolog fi Oletuskategoria uusille InfoLog -merkinnöille
|
||||
default filter for infolog infolog fi InfoLogin oletussuodatin
|
||||
default status for a new log entry infolog fi Uuden merkinnän oletustila
|
||||
delegated infolog fi Delegoidut
|
||||
delegated open infolog fi Delegoidut avoimet
|
||||
delegated open and upcoming infolog fi Delegoidut avoimet ja tulevat
|
||||
delegated overdue infolog fi Delegoidut myöhästyneet
|
||||
delegated upcomming infolog fi Delegoidut tulevat
|
||||
delegation infolog fi Delegointi
|
||||
delete infolog fi Poista
|
||||
delete one record by passing its id. infolog fi Poista yksi tietue ohittaen sen id.
|
||||
delete the entry infolog fi Poista merkintä
|
||||
delete this entry infolog fi Poista tämä merkintä
|
||||
delete this entry and all listed sub-entries infolog fi Poista tämä merkintä ja kaikki sen alimerkinnät
|
||||
deleted infolog fi Poistettu
|
||||
deletes the selected typ infolog fi Poista valittu tyyppi
|
||||
deletes this field infolog fi Poista tämä kenttä
|
||||
deletes this status infolog fi Poista tämä tila
|
||||
description infolog fi Kuvaus
|
||||
determines the order the fields are displayed infolog fi Määrittelee näkyvissä olevien kenttien järjestyksen
|
||||
disables a status without deleting it infolog fi Ota tila pois käytöstä poistamatta sitä
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog fi Haluatko vahvistuksen vastuuhenkilöltä: tehtävän hyväksymisestä, tehtävän valmistumisesta vai molemmista?
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog fi Haluatko muistutusviestin, jos sinulle delegoidaan tai delegoimaasi merkintää/tehtävää päivitetään?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog fi Haluatko muistutusviestin, kun merkinnän/tehtävän alkamispäivä lähestyy, jos olet vastuuhenkilönä?
|
||||
do you want a notification, if items you are responsible for are due? infolog fi Haluatko muistutusviestin, kun merkinnän/tehtävän eräpäivä lähestyy, jos olet vastuuhenkilönä?
|
||||
do you want a notification, if items you created get updated? infolog fi Haluatko muistutusviestin, jos luomiasi merkintöjä/tehtäviä päivitetään?
|
||||
do you want a notification, if items you delegated are about to start? infolog fi Haluatko muistutusviestin, kun delegoimasi merkinnän/tehtävän alkamispäivä lähestyy?
|
||||
do you want a notification, if items you delegated are due? infolog fi Haluatko muistutusviestin, kun delegoimasi merkinnän/tehtävän eräpäivä lähestyy?
|
||||
do you want to receive notifications as html-mails or plain text? infolog fi Haluatko muistutusviestiesi olevan HTML vai pelkkänä tekstinä?
|
||||
don't show infolog infolog fi Älä näytä InfoLogia
|
||||
done infolog fi Valmis
|
||||
download infolog fi Lataa
|
||||
due %1 infolog fi Erääntyy %1
|
||||
duration infolog fi Kesto
|
||||
e-mail: infolog fi Sähköposti:
|
||||
each value is a line like <id>[=<label>] infolog fi Jokainen arvo on rivillä kuten <id>[=<label>]
|
||||
edit infolog fi Muokkaa
|
||||
edit or create categories for ingolog infolog fi Muokkaa tai luo kategoria InfoLogiin
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog fi Muokkausoikeudet (täydet muokkausoikeudet, mukaanlukien delegointi!)
|
||||
edit status infolog fi Muokkaa tilaa
|
||||
edit the entry infolog fi Muokkaa merkintää
|
||||
edit this entry infolog fi Muokkaa tätä merkintää
|
||||
empty for all infolog fi Tyhjä kaikille
|
||||
enddate infolog fi Erääntymispäivä
|
||||
enddate can not be before startdate infolog fi Erääntymispäivä ei voi olla ennen alkamispäivää
|
||||
enter a custom contact, leave empty if linked entry should be used infolog fi Syötä kontakti, jätä tyhjäsi jos linkitettyä kontaktia käytetään
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog fi Syötä puhelinnumero/sähköposti, jätä tyhjäsi jos linkitettyä yhteystietoa käytetään
|
||||
enter a textual description of the log-entry infolog fi Syötä tekstimuotoinen kuvaus merkintään
|
||||
enter the query pattern infolog fi Anna tiedustelun malli
|
||||
entry and all files infolog fi Merkintä ja kaikki tiedostot
|
||||
error: saving the entry infolog fi Virhe tallentaessa merkintää
|
||||
error: the entry has been updated since you opened it for editing! infolog fi Virhe: Merkintää on päivitetty sen jälkeen kun avasit sen muokattavaksi!
|
||||
existing links infolog fi Olemassa olevat linkit
|
||||
fax infolog fi Faksi
|
||||
field must not be empty !!! infolog fi Kenttää ei voi jättää tyhjäksi!!
|
||||
fieldseparator infolog fi Kenttäerotin
|
||||
finish infolog fi Lopeta
|
||||
for which types should this field be used infolog fi Mitkä Infolog-tyypit käyttävät tätä kenttää?
|
||||
from infolog fi Lähettäjä:
|
||||
general infolog fi Yleinen
|
||||
global categories infolog fi Yleiset kategoriat
|
||||
group owner for infolog fi Ryhmän omistaja
|
||||
high infolog fi Korkea
|
||||
history infolog fi Historia
|
||||
history logging infolog fi Merkintöjen historia
|
||||
history logging and deleting of items infolog fi Historia ja poistettujen merkintöjen lopullinen poistaminen. Kenellä on oikeus tarkastella ja poistaa lopullisesti (deletoituja) merkintöjä?
|
||||
how many describtion lines should be directly visible. further lines are available via a scrollbar. infolog fi Kuinka monta riviä kuvaustekstiä on näkyvillä. Loput rivit ovat näkyvillä scroll barissa.
|
||||
id infolog fi Id
|
||||
id# infolog fi Id#
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog fi Jos tyypin omistaa ryhmä, kaikki tapahtumat/merkinnät omistaa ryhmä, EI käyttäjä joka loi sen!
|
||||
import infolog fi Tuonti
|
||||
import next set infolog fi Tuo seuraava osa
|
||||
importance infolog fi Tärkeys
|
||||
info log common fi InfoLog
|
||||
infolog common fi InfoLog
|
||||
infolog - delete infolog fi InfoLog - Poista
|
||||
infolog - edit infolog fi InfoLog - Muokkaa
|
||||
infolog - import csv-file infolog fi InfoLog - Tuo CSV-tiedosto
|
||||
infolog - new infolog fi InfoLog - Uusi
|
||||
infolog - new subproject infolog fi InfoLog - Uusi aliprojekti
|
||||
infolog - subprojects from infolog fi InfoLog - Aliprojektit kohteesta
|
||||
infolog copied - the copy can now be edited infolog fi InfoLog kopioitu - kopiota voidaan nyt muokata
|
||||
infolog entry deleted infolog fi InfoLog merkintä poistettu
|
||||
infolog entry saved infolog fi InfoLog merkintä tallennettu
|
||||
infolog filter for the main screen infolog fi InfoLog suodatin etusivulla
|
||||
infolog list infolog fi InfoLog lista
|
||||
infolog preferences common fi InfoLog asetukset
|
||||
infolog-fieldname infolog fi InfoLog kentän nimi
|
||||
invalid filename infolog fi Tiedostonimi ei kelpaa
|
||||
label<br>helptext infolog fi Otsikko<br>Vihjeteksti
|
||||
last changed infolog fi Viimeksi muutettu
|
||||
last modified infolog fi Viimeksi muokattu
|
||||
leave blank to get the used time calculated by timesheet entries infolog fi Jätä tyhjäksi, jos haluat (kulutetun ajan) summan tulevan Ajanhallinnan merkinnöistä.
|
||||
leave it empty infolog fi Jätä tyhjäksi
|
||||
leave without saveing the entry infolog fi Poistu tallentamatta merkintää
|
||||
leaves without saveing infolog fi Poistu tallentamatta
|
||||
length<br>rows infolog fi Pituus<br>Rivit
|
||||
limit number of description lines (default 5, 0 for no limit) infolog fi Rajoita kuvauskentän rivien määrää (Oletus on 5, merkitse 0, jos et halua rajoitusta).
|
||||
link infolog fi Linkki
|
||||
links infolog fi Linkit
|
||||
links of this entry infolog fi Tämän merkinnän linkit
|
||||
list all categories infolog fi Listaa kaikki kategoriat
|
||||
list no subs/childs infolog fi Älä listaa alimerkintöjä
|
||||
location infolog fi Sijainti
|
||||
longer textual description infolog fi Pitempi tekstikuvaus
|
||||
low infolog fi Matala
|
||||
max length of the input [, length of the inputfield (optional)] infolog fi Kentän tekstin maksimipituus [, kentän maksimi pituus(vaihtoehtoinen)]
|
||||
name must not be empty !!! infolog fi Nimikenttä ei saa olla tyhjä !!!
|
||||
name of new type to create infolog fi Luotavan tyypin nimi
|
||||
never hide search and filters infolog fi Hakua ja suodattimia ei piiloiteta koskaan
|
||||
new %1 infolog fi Uusi %1
|
||||
new %1 created by %2 at %3 infolog fi Uusi %1, luonut %1, %3
|
||||
new name infolog fi Uusi nimi
|
||||
new search infolog fi Uusi haku
|
||||
no - cancel infolog fi Ei - Peruuta
|
||||
no describtion, links or attachments infolog fi Ei kuvausta, linkkejä tai liitetiedostoja
|
||||
no details infolog fi Ei lisätietoja
|
||||
no entries found, try again ... infolog fi Merkintöjä ei löytynyt, yritä uudelleen ...
|
||||
no filter infolog fi Ei suodatinta
|
||||
no links or attachments infolog fi Ei linkkejä tai liitteitä
|
||||
no project infolog fi Ei projektia
|
||||
nonactive infolog fi Aktivoimaton
|
||||
none infolog fi Ei mitään
|
||||
normal infolog fi Normaali
|
||||
not infolog fi ei
|
||||
not assigned infolog fi Kohdistamattomat
|
||||
not-started infolog fi Aloittamatta olevat
|
||||
note infolog fi Muistiinpano
|
||||
number of records to read (%1) infolog fi (%1) tietuetta luettu
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog fi Rivien määrä monenrivisessä tekstikentässä tai monivalinta-laatikosta
|
||||
offer infolog fi Tarjous
|
||||
one day after infolog fi Päivää myöhemmin
|
||||
one day in advance infolog fi Päivä etukäteen
|
||||
ongoing infolog fi Meneillään oleva
|
||||
only for details infolog fi Vain lisätiedot
|
||||
only if i get assigned or removed infolog fi Vain jos minulle delegoidaan tai minut poistetaan vastuusta
|
||||
only the attachments infolog fi Vain liitteet
|
||||
only the links infolog fi Vain linkit
|
||||
open infolog fi Avoimet
|
||||
open and upcoming infolog fi Avoimet ja tulevat
|
||||
optional note to the link infolog fi Vapaaehtoinen muistiinpano linkkiin
|
||||
order infolog fi Järjestä
|
||||
organization infolog fi Organisaatio
|
||||
overdue infolog fi Myöhästynyt
|
||||
own infolog fi Omat
|
||||
own open infolog fi Omat avoimet
|
||||
own open and upcoming infolog fi Omat avoimet ja tulevat
|
||||
own overdue infolog fi Omat myöhästyneet
|
||||
own upcoming infolog fi Omat tulevat
|
||||
parent infolog fi Päämerkintä
|
||||
parent infolog infolog fi Päämerkintä
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog fi Polku (web-)palvelimella<br>esim. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog fi Polku käyttäjän ja ryhmän tiedostoihin pitää olla palvelimen tiedostojuuren ULKOPUOLELLA!!!
|
||||
pattern for search in addressbook infolog fi Merkkijonohaku Yhteystiedoista
|
||||
pattern for search in projects infolog fi Merkkijonohaku Projekteista
|
||||
percent completed infolog fi Prosenttia valmistunut
|
||||
permission denied infolog fi Pääsy estetty
|
||||
phone infolog fi Puhelinsoitto
|
||||
phone/email infolog fi Puhelin/E-mail
|
||||
phonecall infolog fi Puhelinsoitto
|
||||
planned infolog fi Suunniteltu
|
||||
planned time infolog fi Suunniteltu aikataulu
|
||||
price infolog fi Hinta
|
||||
pricelist infolog fi Hinnasto
|
||||
primary link infolog fi Ensisijainen linkki
|
||||
priority infolog fi Tärkeys
|
||||
private infolog fi Yksityinen
|
||||
project infolog fi Projekti
|
||||
project settings: price, times infolog fi Projektin asetukset: hinta, aika
|
||||
projectmanager infolog fi Projektinhallinta
|
||||
re-planned infolog fi Uudelleen suunniteltu
|
||||
re-planned time infolog fi Uudelleen suunniteltu aikataulu
|
||||
re: infolog fi Re:
|
||||
read one record by passing its id. infolog fi Lue yksi tietue ohittaen sen id.
|
||||
read rights (default) infolog fi Lukuoikeudet (oletus)
|
||||
receive notifications about due entries you are responsible for infolog fi Vastaanota muistutusviestejä eräpäivää lähestyvistä merkinnöistä/tehtävistä, joissa olet vastuuhenkilönä.
|
||||
receive notifications about due entries you delegated infolog fi Vastaanota muistutusviestejä delegoimistasi eräpäivää lähestyvistä merkinnöistä/tehtävistä.
|
||||
receive notifications about items assigned to you infolog fi Vastaanota muistutusviestejä sinulle delegoiduista merkinnöistä/tehtävistä.
|
||||
receive notifications about own items infolog fi Vastaanota muistutusviestejä omista merkinnöistä/tehtävistä.
|
||||
receive notifications about starting entries you are responsible for infolog fi Vastaanota muistutusviestejä alkamassa olevista merkinnöistä/tehtävistä, joissa olet vastuuhenkilönä.
|
||||
receive notifications about starting entries you delegated infolog fi Vastaanota muistutusviestejä delegoimistasi alkamassa olevista merkinnöistä/tehtävistä.
|
||||
receive notifications as html-mails infolog fi Vastaanota muistutusviestit HTMLnä
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog fi reg. expr. paikallisille IP-osoitteille<br>esim. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog fi reg. expr. paikallisille IP-osoitteille<br>esim. ^192\.168\.1\.
|
||||
remark infolog fi Merkitse uudelleen
|
||||
remove this link (not the entry itself) infolog fi Poista tämä linkki (ei poista itse merkintää)
|
||||
responsible infolog fi Vastuuhenkilö
|
||||
responsible open infolog fi Vastuuhenkilö, avoimet
|
||||
responsible open and upcoming infolog fi Vastuuhenkilö, avoimet ja tulevat
|
||||
responsible overdue infolog fi Vastuuhenkilö, myöhästyneet
|
||||
responsible upcoming infolog fi Vastuuhenkilö, tulevat
|
||||
responsible user, priority infolog fi Vastuuhenkilö, tärkeysaste
|
||||
returns a list / search for records. infolog fi Palauttaa listan / haun arvoista
|
||||
rights for the responsible infolog fi Vastuuhenkilön oikeudet
|
||||
same day infolog fi Samana päivänä
|
||||
save infolog fi Tallenna
|
||||
saves the changes made and leaves infolog fi Tallenna muutokset ja poistu
|
||||
saves this entry infolog fi Tallenna tämä merkintä
|
||||
search infolog fi Etsi
|
||||
search for: infolog fi Etsi:
|
||||
select infolog fi Valitse
|
||||
select a category for this entry infolog fi Valitse kategoria merkinnälle
|
||||
select a price infolog fi Valitse hinta
|
||||
select a priority for this task infolog fi Valitse tehtävän tärkeys
|
||||
select a project infolog fi Valitse projekti
|
||||
select a responsible user: a person you want to delegate this task infolog fi Valitse vastuuhenkilö, jolle haluat siirtää tehtävän
|
||||
select a typ to edit it's status-values or delete it infolog fi Valitse tyyppi muokataksesi sen tilan arvoa tai poistaaksesi sen.
|
||||
select an app to search in infolog fi Valitse haettava sovellus
|
||||
select an entry to link with infolog fi Valitse merkintä linkitettäväksi
|
||||
select to filter by owner infolog fi Suodata omistajan mukaan
|
||||
select to filter by responsible infolog fi Suodata vastuuhenkilön mukaan
|
||||
sender infolog fi Lähettäjä
|
||||
set status to done infolog fi Aseta tilaksi "Valmis"
|
||||
set status to done for all entries infolog fi Aseta kaikkien merkintöjen tilaksi "Valmis"
|
||||
sets the status of this entry and its subs to done infolog fi Aseta tälle merkinnälle ja sen alimerkinnöille tilaksi "Valmis".
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog fi Näyttääkö InfoLog alitehtävät, -soitot tai -muistiot normaalinäkymässä? Voit aina nähdä alimerkinnät päämerkinnän alta?
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog fi Näyttääkö InfoLog linkkejä muihin sovelluksiin ja / tai liitetiedostoihin InfoLog listalla (normaalinäkymässä kun avaat InfoLogin).
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog fi Näyttetääkö InfoLog näkymä etusivulla ja millä suotimilla. Toimii vain jos et ole valinnut mitään sovellusta etusivulle omissa (henkilökohtaisissa) asetuksissasi?
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog fi Käyttääkö InfoLog koko nimeä (etunimi, sukunimi) vai ainoastaan kirjautumisnimeä.
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog fi Näyttääkö InfoLog lista yksilöllisen numerotunnisteen, jota voidaan käyttää esimerkiksi merkinnän tunnisteena?
|
||||
should the infolog list show the column "last modified". infolog fi Näyttääkö InfoLog listaussarakkeen "viimeksi muokattu?
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog fi Näyttääkö InfoLog listauksessa montako prosenttia tehtävästä on tehty vai näytetäänkö kaksi erillistä kuvaketta?
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog fi pitäisikö tämän merkinnän näkyä vain sinulle ja niille joille olet antanut oikeudet ACL:ssä?
|
||||
show a column for used and planned times in the list. infolog fi Näytä listalla sarakkeet käytetystä ja suunnitellusta ajankäytöstä.
|
||||
show full usernames infolog fi Näytä koko käyttäjänimet
|
||||
show in the infolog list infolog fi Näytä InfoLogin listassa
|
||||
show last modified infolog fi Näytä viimeksi muokattu
|
||||
show status and percent done separate infolog fi Näytä tila ja prosenttia tehty, erillisinä kohtina.
|
||||
show ticket id infolog fi Näytä merkinnän id
|
||||
show times infolog fi Näytä ajat
|
||||
small view infolog fi Pieni näkymä
|
||||
start a new search, cancel this link infolog fi Aloita uusi haku
|
||||
startdate infolog fi Aloituspäivä
|
||||
startdate enddate infolog fi Aloituspäivä, Erääntymispäivä
|
||||
startdate for new entries infolog fi Aloituspäivä uusille merkinnöille
|
||||
starting %1 infolog fi Alkaa %1
|
||||
startrecord infolog fi Startrecord
|
||||
status infolog fi Tila
|
||||
status ... infolog fi Tila...
|
||||
sub infolog fi Sub
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog fi Alimerkinnät (sub entries) tulevat päämerkinnän (parent) alle tai päämerkinnöiksi, ellei niille aseteta päämerkintää.
|
||||
subject infolog fi Aihe
|
||||
sum infolog fi Summa
|
||||
task infolog fi Tehtävä
|
||||
tasks of infolog fi Tehtävät:
|
||||
template infolog fi Mallipohja
|
||||
test import (show importable records <u>only</u> in browser) infolog fi Testi Tuonti (näytä tuotavat tietueet <u>vain</u> selaimessa)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog fi Nimi on sisäisessä käytössä (<= 10 merkkiä), sen muuttaminen aiheuttaa nykyisen tiedon menettämisen.
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog fi Nimi on sisäisessä käytössä (<= 10 merkkiä), sen muuttaminen aiheuttaa nykyisen tiedon menettämisen.
|
||||
the text displayed to the user infolog fi Käyttäjälle näytettävä teksti
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog fi Käytä valitsemaasi suodatinta kun kirjaudut InfoLogiin. Suodatin rajoittaa kerralla näkyvien merkintöjen määrää. (Suodata avoimet, tulevat tai myöhästyneet, jne... merkinnät ensinäkymäksi)
|
||||
til when should the todo or phonecall be finished infolog fi Milloin tehtävä tai puhelinsoitto on valmistunut
|
||||
times infolog fi Ajat
|
||||
to many might exceed your execution-time-limit infolog fi Liian moni saattaa ylittää suoritusajan ylärajan.
|
||||
to what should the startdate of new entries be set. infolog fi Mikä alkamispäivä uusille merkinnöille asetetaan.
|
||||
today infolog fi Tänään
|
||||
todays date infolog fi Päivämäärä
|
||||
todo infolog fi Tehtävä
|
||||
translation infolog fi Käännös
|
||||
typ infolog fi Tyyppi
|
||||
typ '%1' already exists !!! infolog fi Tyyppi %1 on jo olemassa
|
||||
type infolog fi Tyyppi
|
||||
type ... infolog fi Tyyppi...
|
||||
type of customfield infolog fi Lisäkentän tyyppi
|
||||
type of the log-entry: note, phonecall or todo infolog fi InfoLog -merkinnän tyyppi: Muistio, Soitto, Tehtävä
|
||||
unlink infolog fi Poista linkki
|
||||
upcoming infolog fi Tuleva
|
||||
urgency infolog fi Tärkeys
|
||||
urgent infolog fi Tärkeä
|
||||
used time infolog fi Käytetty aika
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog fi polku asiakkaan puolella<br>eg. \\Server\Share tai e:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog fi polku asiakkaan puolella<br>eg. \\Server\Share tai e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog fi polku asiakkaan puolella<br>eg. \\Server\Share tai e:\
|
||||
values for selectbox infolog fi Valintalaatikon arvot
|
||||
view all subs of this entry infolog fi Näytä kaikki tämän merkinnän alimerkinnät
|
||||
view other subs infolog fi Näytä muut alimerkinnät
|
||||
view parent infolog fi Näytä isäntä
|
||||
view subs infolog fi Näytä alimerkinnät
|
||||
view the parent of this entry and all his subs infolog fi Näytä tämän merkinnän päämerkintä ja kaikki sen alimerkinnät
|
||||
view this linked entry in its application infolog fi Näytä tämä linkitetty merkintä sovelluksessa
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog fi Millon tehtävän tai puhelinsoiton pitäisi alkaa, se näkyy sinä päivä avoimissa tai omissa avoimissa tehtävissä (aloitussivulla)?
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog fi Mitä muita kenttiä vastuuhenkilö saa muokata, ilman että hänellä on muokkas oikeuksia? <br/>Tila, prosentit, valmistumispäivä ovat aina sallittuja.
|
||||
which implicit acl rights should the responsible get? infolog fi Mitä ACL -oikeuksia vastuuhenkilö saa?
|
||||
which types should the calendar show infolog fi Mitkä InfoLog tyypit kalenterin tulisi näyttää
|
||||
whole query infolog fi Koko kysely
|
||||
will-call infolog fi soittaa
|
||||
yes - close infolog fi Kyllä - Sulje
|
||||
yes - close including sub-entries infolog fi Kyllä - Sulje myös alimerkinnät
|
||||
yes - delete infolog fi Kyllä - Poista
|
||||
yes - delete including sub-entries infolog fi Kyllä - Poista myös alimerkinnät
|
||||
yes, noone can purge deleted items infolog fi Kyllä, kukaan ei voi lopullisesti poistaa poistettuja merkintöjä
|
||||
yes, only admins can purge deleted items infolog fi Kyllä, ainoastaan ylläpitäjät voivat lopullisesti poistaa poistettuja merkintöjä
|
||||
yes, with larger fontsize infolog fi Kyllä, Isompi fonttikoko
|
||||
yes, with purging of deleted items possible infolog fi Kyllä, Poistettujen merkintöjen lopullinen poistaminen on mahdollista
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog fi Minkä kategorian pitäisi olla oletuksena, kun luot uutta InfoLog merkintää?
|
||||
you can't delete one of the stock types !!! infolog fi Et voi poistaa mitään tyyppien ryhmästä !!!
|
||||
you have entered an invalid ending date infolog fi Virheellinen erääntymispäivä
|
||||
you have entered an invalid starting date infolog fi Virheellinen alkamispäivä
|
||||
you have to enter a name, to create a new typ!!! infolog fi Kirjoita nimi luodaksesi uuden tyypin !!!
|
||||
you must enter a subject or a description infolog fi Anna aihe tai kuvaus
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog fi Tietokantasi EI ole ajantasalla (%1 vs. %2), suorita %3asetukset%4 päivittääksesi tietokantasi.
|
318
infolog/lang/egw_fr.lang
Normal file
318
infolog/lang/egw_fr.lang
Normal file
@ -0,0 +1,318 @@
|
||||
%1 records imported infolog fr %1 enregistrements importés
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog fr %1 enregistrements lus (pas encore importés, vous pourriez %2revenir%3 et désélectionner Test d'Importation)
|
||||
- subprojects from infolog fr - Sous-projets de
|
||||
0% infolog fr 0%
|
||||
10% infolog fr 10%
|
||||
100% infolog fr 100%
|
||||
20% infolog fr 20%
|
||||
30% infolog fr 30%
|
||||
40% infolog fr 40%
|
||||
50% infolog fr 50%
|
||||
60% infolog fr 60%
|
||||
70% infolog fr 70%
|
||||
80% infolog fr 80%
|
||||
90% infolog fr 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog fr <b>Attachement de fichiers via des liens symboliques</b> à la place du dépôt de fichiers et récupération via fichier:/chemin pour les clients avec accès réseau direct
|
||||
a short subject for the entry infolog fr Un court sujet pour l'entrée
|
||||
abort without deleting infolog fr Annuler sans supprimer
|
||||
accept infolog fr Accepte
|
||||
action infolog fr Action
|
||||
actual date and time infolog fr date et heure actuelles
|
||||
add infolog fr Ajouter
|
||||
add a file infolog fr Ajouter un fichier
|
||||
add a new entry infolog fr Ajouter uen nouvelle entrée
|
||||
add a new note infolog fr Ajouter une nouvelle Note
|
||||
add a new phonecall infolog fr Ajouter un nouvel appel téléphonique
|
||||
add a new sub-task, -note, -call to this entry infolog fr Ajouter un(e) nouvelle sous-tâche, -note, -appel à cette entrée
|
||||
add a new todo infolog fr Ajouter un nouveau A-faire
|
||||
add file infolog fr Ajouter un fichier
|
||||
add sub infolog fr Ajouter enfant
|
||||
add timesheet entry infolog fr Ajouter une entrée feuille de temps
|
||||
add: infolog fr Ajouter:
|
||||
all infolog fr Tous
|
||||
all links and attachments infolog fr Tous les liens et attachements
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog fr permet de changer le statut d´une entrée, c'est-à-dire de spécifier un A-Faire à fait s'il est terminé (les valeurs dépendent du type d´entrée).
|
||||
apply the changes infolog fr Appliquer les changements
|
||||
are you shure you want to delete this entry ? infolog fr Etes-vous sûr de vouloir supprimer cette entrée ?
|
||||
attach a file infolog fr Attacher un fichier
|
||||
attach file infolog fr Attacher un fichier
|
||||
attension: no contact with address %1 found. infolog fr Attention: Aucun contact avec adresse %1 trouvé.
|
||||
back to main list infolog fr Retour à la liste principale
|
||||
billed infolog fr Facturé
|
||||
both infolog fr Les deux
|
||||
call infolog fr Appel
|
||||
cancel infolog fr Annuler
|
||||
cancelled infolog fr Annulé
|
||||
categories infolog fr Catégories
|
||||
category infolog fr Catégorie
|
||||
change the status of an entry, eg. close it infolog fr Change le statut d´une entrée, c'est-à-dire la ferme
|
||||
charset of file infolog fr Jeu de caractères du fichier
|
||||
check to set startday infolog fr Vérifier pour mettre le jour de départ
|
||||
check to specify custom contact infolog fr Vérifiez pour spécifier un contact personnalisé
|
||||
click here to create the link infolog fr Cliquer ici pour créer le lien
|
||||
click here to start the search infolog fr Cliquer ici pour démarrer la recherche
|
||||
close infolog fr Fermer
|
||||
comment infolog fr Commentaire
|
||||
completed infolog fr Terminé
|
||||
configuration infolog fr Configuration
|
||||
confirm infolog fr Confirmer
|
||||
contact infolog fr Contact
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog fr Copie vos changements vers le presse-papiers, %1recharger l'entrée%2 et les fusionne.
|
||||
create new links infolog fr Créer de nouveaux liens
|
||||
creates a new field infolog fr crée un nouveau champ
|
||||
creates a new status with the given values infolog fr crée un nouveau statut avec la valeur spécifiée
|
||||
creates a new typ with the given name infolog fr créée un nouveau type avec le nom spécifié
|
||||
creation infolog fr Création
|
||||
csv-fieldname infolog fr CSV-Nomdechamp
|
||||
csv-filename infolog fr CSV-Nomdefichier
|
||||
csv-import common fr CSV-Importer
|
||||
custom infolog fr Personnalisé
|
||||
custom contact-address, leave empty to use information from most recent link infolog fr Adresse de contact personnalisée, laissez vide pour utiliser l'information du lien le plus récent
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog fr Information de contact personnalisée, laissez vide pour utiliser l'information du lien le plus récent
|
||||
custom fields infolog fr Champs personnalisés
|
||||
custom fields, typ and status common fr Champs, types et statuts personnalisés
|
||||
custom regarding infolog fr Personnalisé concernant
|
||||
custom status for typ infolog fr Statuts personnalisés pour le type
|
||||
customfields infolog fr Champs personnalisés
|
||||
date completed infolog fr Date de clôture
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog fr Date de clôture (laisser vide pour que ce soit rempli automatiquement si le statut est Fait ou Rempli)
|
||||
datecreated infolog fr Date de création
|
||||
dates, status, access infolog fr Dates, Statut, Accès
|
||||
days infolog fr Jours
|
||||
default filter for infolog infolog fr Filtre par défaut pour InfoLog
|
||||
default status for a new log entry infolog fr statut par défaut pour une nouvelle entrée de log
|
||||
delegation infolog fr Délégation
|
||||
delete infolog fr Supprimer
|
||||
delete one record by passing its id. infolog fr Effacer un enregistrement en passant son id.
|
||||
delete the entry infolog fr supprimer l´entrée
|
||||
delete this entry infolog fr supprimer cette entrée
|
||||
delete this entry and all listed sub-entries infolog fr Détruire cette entrée et toutes les sous-entrées listées
|
||||
deletes the selected typ infolog fr supprime le type sélectionné
|
||||
deletes this field infolog fr supprime ce champ
|
||||
deletes this status infolog fr supprime ce statut
|
||||
description infolog fr Description
|
||||
determines the order the fields are displayed infolog fr détermine l´ordre d´affichage des champs
|
||||
disables a status without deleting it infolog fr désactive un statut sans le supprimer
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog fr Voulez-vous une confirmation du responsable sur: accepter, finir la tâche, ou les deux
|
||||
do you want to see custom infolog types in the calendar? infolog fr Voulez-vous voir les types d'InfoLog personnalisé dans le calendrier?
|
||||
don't show infolog infolog fr NE PAS afficher InfoLog
|
||||
done infolog fr Fait
|
||||
download infolog fr Télécharger
|
||||
duration infolog fr Durée
|
||||
each value is a line like <id>[=<label>] infolog fr chaque valeur est une ligne telle que <id>[=<label>]
|
||||
edit infolog fr Modifier
|
||||
edit or create categories for ingolog infolog fr Modifier ou créer des catégories pour InfoLog
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog fr modifier les droits (édition complète des droits, pouvant rendre quelqu'un d'autre responsable!)
|
||||
edit status infolog fr Modifier Statut
|
||||
edit the entry infolog fr Modifier l'entrée
|
||||
edit this entry infolog fr Modifier cette entrée
|
||||
empty for all infolog fr vide pour tous
|
||||
enddate infolog fr Date de fin
|
||||
enddate can not be before startdate infolog fr La date de fin ne peut pas être avant la date de début
|
||||
enter a custom contact, leave empty if linked entry should be used infolog fr Entrez un contact personnalisé, laissez vide si l'entrée liée devrait être utilisée
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog fr Entrez un EMail/numéro de téléphone personnalisé, laissez vide si l'entrée liée devait être utilisée
|
||||
enter a textual description of the log-entry infolog fr Entrez une description textuelle de l'entrée de Log
|
||||
enter the query pattern infolog fr Entrez le champ de requête
|
||||
entry and all files infolog fr Entrée et tous les fichiers
|
||||
error: saving the entry infolog fr Erreur: lors de l'enregistrement de l'entrée
|
||||
error: the entry has been updated since you opened it for editing! infolog fr Erreur: cette entrée a été mise à jour pendant que vous l'aviez ouverte pour la modifier!
|
||||
existing links infolog fr Liens existants
|
||||
fax infolog fr Fax
|
||||
fieldseparator infolog fr Séparateur de champ
|
||||
finish infolog fr Terminer
|
||||
for which types should this field be used infolog fr pour quels types ce champ devrait être utilisé
|
||||
from infolog fr De
|
||||
general infolog fr Général
|
||||
group owner for infolog fr Propriétaire de Groupe pour
|
||||
high infolog fr Haut
|
||||
id infolog fr Id
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog fr Si un type a un propriétaire de groupe, toutes les entrées de ce type appartiendront à ce groupe, et NON à l'utilisateur qui l'a créé!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog fr Si non renseigné, la ligne contenant la recherche et les filtres est cachée lorsqu'il y a plus d'entrées que le "Nombre max d'occurences correspondantes par page" (défini dans les préférences).
|
||||
import infolog fr Importer
|
||||
import next set infolog fr importer l´élément suivant
|
||||
info log common fr InfoLog
|
||||
infolog common fr InfoLog
|
||||
infolog - delete infolog fr InfoLog - Supprimer
|
||||
infolog - edit infolog fr InfoLog - Modifier
|
||||
infolog - import csv-file infolog fr InfoLog - Importer fichier CSV
|
||||
infolog - new infolog fr InfoLog - Nouveau
|
||||
infolog - new subproject infolog fr InfoLog - Nouveau sous-projet
|
||||
infolog - subprojects from infolog fr InfoLog - Sous-projets de
|
||||
infolog entry deleted infolog fr InfoLog entrée supprimée
|
||||
infolog entry saved infolog fr InfoLog entrée enregistrée
|
||||
infolog filter for the main screen infolog fr InfoLog filtre pour l'écran principal
|
||||
infolog list infolog fr Liste InfoLog
|
||||
infolog preferences common fr Préférences InfoLog
|
||||
infolog-fieldname infolog fr InfoLog - Nom du champ
|
||||
invalid filename infolog fr Nom de fichier invalide
|
||||
label<br>helptext infolog fr Label<br>Texte d´aide
|
||||
last changed infolog fr Dernière modification
|
||||
last modified infolog fr Dernière modification
|
||||
leave it empty infolog fr laisser vide
|
||||
leave without saveing the entry infolog fr quitter sans enregistrer l'entrée
|
||||
leaves without saveing infolog fr quitte sans enregistrer
|
||||
length<br>rows infolog fr Longueur<br>Lignes
|
||||
link infolog fr Lien
|
||||
links infolog fr Liens
|
||||
links of this entry infolog fr Liens de cette entrée
|
||||
list all categories infolog fr Liste toutes les catégories
|
||||
list no subs/childs infolog fr Ne pas lister les Sous/Enfants
|
||||
location infolog fr Emplacement
|
||||
longer textual description infolog fr Description textuelle plus longue
|
||||
low infolog fr Bas
|
||||
max length of the input [, length of the inputfield (optional)] infolog fr taille max de l´entrée [, taille du champ d´entrée (optionnel)]
|
||||
name must not be empty !!! infolog fr Le nom ne peut pas être vide !!!
|
||||
name of new type to create infolog fr nom du nouveau type à créer
|
||||
never hide search and filters infolog fr Ne jamais cacher la recherche et les filtres
|
||||
new name infolog fr nouveau nom
|
||||
new search infolog fr Nouvelle recherche
|
||||
no - cancel infolog fr Non - Abandonner
|
||||
no describtion, links or attachments infolog fr Pas de description, de liens ou d'attachements
|
||||
no details infolog fr Pas de détails
|
||||
no entries found, try again ... infolog fr Aucune occurrence trouvée, essayez à nouveau ...
|
||||
no filter infolog fr Aucun filtre
|
||||
no links or attachments infolog fr Aucun lien ou attachement
|
||||
none infolog fr Aucun
|
||||
normal infolog fr Normal
|
||||
not infolog fr pas
|
||||
not assigned infolog fr Pas attribué
|
||||
not-started infolog fr Non démarré
|
||||
note infolog fr Note
|
||||
number of records to read (%1) infolog fr Nombre d'enregistrements à lire (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog fr nombre de lignes pour un champ d´entrées multilignes ou pour une boîte de sélection multiple
|
||||
offer infolog fr Offre
|
||||
ongoing infolog fr Entrant
|
||||
only for details infolog fr Seulement pour les détails
|
||||
only the attachments infolog fr Seulement les attachements
|
||||
only the links infolog fr Seulement les liens
|
||||
open infolog fr Ouvrir
|
||||
optional note to the link infolog fr note optionnelle vers le lien
|
||||
order infolog fr Tri
|
||||
overdue infolog fr Tardif
|
||||
own infolog fr Propre
|
||||
own open infolog fr Propre ouvert
|
||||
own overdue infolog fr Propre tardif
|
||||
own upcoming infolog fr Propre arrivant
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog fr Chemin côté (web)server<br>p.ex. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog fr Le chemin vers les fichiers utilisateurs et groupes DOIT FIGURER EN DEHORS du répertoire racine des serveurs Web!!!
|
||||
pattern for search in addressbook infolog fr Chaîne de caractères à rechercher dans le carnet d'adresses
|
||||
pattern for search in projects infolog fr Chaîne de caractères à rechercher dans les projets
|
||||
percent completed infolog fr Pourcentage complété
|
||||
permission denied infolog fr Permission refusée
|
||||
phone infolog fr Appel téléphonique
|
||||
phone/email infolog fr Téléphone/EMail
|
||||
phonecall infolog fr Appel téléphonique
|
||||
planned infolog fr planifié
|
||||
planned time infolog fr Temps prévu
|
||||
price infolog fr Prix
|
||||
priority infolog fr Priorité
|
||||
private infolog fr Privé
|
||||
project infolog fr Projet
|
||||
project settings: price, times infolog fr Réglages projet: prix, heures
|
||||
re: infolog fr Re:
|
||||
read one record by passing its id. infolog fr Lire un enregistrement en passant son id.
|
||||
read rights (default) infolog fr droits de lecture (défaut)
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog fr Expr. reg. pour les IPs locales<br>p.e. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog fr Expr. reg. pour les IPs locales<br>p.e. ^192\.168\.1\.
|
||||
remark infolog fr Remarque
|
||||
remove this link (not the entry itself) infolog fr Enlever ce lien (pas l'entrée elle-même)
|
||||
responsible infolog fr Responsable
|
||||
responsible open infolog fr Responsable ouverture
|
||||
responsible overdue infolog fr Responsable tardif
|
||||
responsible upcoming infolog fr Responsable à venir
|
||||
responsible user, priority infolog fr Responsable utilisateur, priorité
|
||||
returns a list / search for records. infolog fr Retourne une liste / Recherche d´enregistrements.
|
||||
rights for the responsible infolog fr Droits pour le responsable
|
||||
save infolog fr Enregistrer
|
||||
saves the changes made and leaves infolog fr enregistre les modifications et quitte
|
||||
saves this entry infolog fr Enregistre cette entrée
|
||||
search infolog fr Rechercher
|
||||
search for: infolog fr Rechercher ceci:
|
||||
select infolog fr Choisir
|
||||
select a category for this entry infolog fr Choisissez une catégorie pour cette entrée
|
||||
select a price infolog fr Sélectionnez un prix
|
||||
select a priority for this task infolog fr Choisissez une priorité pour cette tâche
|
||||
select a project infolog fr Sélectionnez un projet
|
||||
select a responsible user: a person you want to delegate this task infolog fr Choisissez un utilisateur responsable: une personne à qui déléguer cette tâche
|
||||
select a typ to edit it's status-values or delete it infolog fr sélectionnez un type dont la valeur est à éditer ou effacez-le
|
||||
select an app to search in infolog fr Choisissez une App dans laquelle rechercher
|
||||
select an entry to link with infolog fr Choisissez une entrée à lier
|
||||
select to filter by owner infolog fr Filtrer par propriétaire
|
||||
select to filter by responsible infolog fr Filtrer par responsable
|
||||
sets the status of this entry and its subs to done infolog fr Fixer le statut de cette entrée et ses sous-entrées à Fait
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog fr InfoLog doit-il afficher les sous-tâches, -appels ou -notes dans la vue normale ou pas. Vous pouvez toujours voir les sous- via leurs parents.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog fr InfoLog doit-il afficher les liens vers d'autres applications et/ou les attachements de fichiers dans la liste InfoLog (vue normale quand vous entrez dans InfoLog)
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog fr InfoLog doit-il s'afficher sur l'écran principal et avec quel filtre. Ne fonctionne que si vous n'avez pas sélectionné une application pour l'écran principal (dans vos préférences)
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog fr InfoLog doit-il utiliser les noms complets (surnom et nom de famille) ou juste les noms de connexion.
|
||||
should the calendar show custom types too infolog fr Le calendrier doit-il afficher aussi les types personnalisés
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog fr InfoLog doit-il afficher un Id numérique unique qui peut être utilisé p.ex. comme Id de ticket.
|
||||
should the infolog list show the column "last modified". infolog fr La liste InfoLog doit-elle afficher la colonne "dernière modification".
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog fr La liste InfoLog doit-elle afficher le pourcentage de réalisation seulement pour le statut en cours ou deux icônes séparées.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog fr Cette entrée ne doit-elle être visible que par vous et les personnes à qui vous avez donné l'accès privé via ACL
|
||||
show a column for used and planned times in the list. infolog fr Afficher une colonne dans la liste pour les temps utilisés et planifiés.
|
||||
show full usernames infolog fr Montrer les noms complets d'utilisateurs
|
||||
show in the infolog list infolog fr Montrer dans la liste InfoLog
|
||||
show last modified infolog fr Montrer les derniers modifiés
|
||||
show status and percent done separate infolog fr Montrer les statuts et pourcentage réalisés séparément
|
||||
show ticket id infolog fr Montrer l'Id de ticket
|
||||
show times infolog fr Montrer les heures
|
||||
small view infolog fr vue réduite
|
||||
start a new search, cancel this link infolog fr Démarre une nouvelle recherche, annule ce lien
|
||||
startdate infolog fr Date de départ
|
||||
startdate enddate infolog fr Date de départ date de fin
|
||||
startdate for new entries infolog fr Date de début pour les nouvelles entrées
|
||||
startrecord infolog fr Enregistrement de départ
|
||||
status infolog fr Statut
|
||||
status ... infolog fr Statut ...
|
||||
sub infolog fr Enfant
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog fr Les sous-entrées deviennent les enfants des parents des entrées principales s'il n'y a pas de parent
|
||||
subject infolog fr Sujet
|
||||
task infolog fr Tâche
|
||||
test import (show importable records <u>only</u> in browser) infolog fr Tester l'importation (montrer les enregistrements importables <u>seulement</u> dans le navigateur)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog fr le nom utilisé en interne (<= 10 caractères), le modifier rend les données indisponible
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog fr le nom est utilisé en interne (<= 20 caractères), si vous le modifiez vous rendez les données indisponibles
|
||||
the text displayed to the user infolog fr le texte affiché pour l´utilisateur
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog fr Ceci est le filtre qu'InfoLog utilise quand vous entrez dans l'application. Les filtres limitent les entrées à montrer dans la vue actuelle. Il y a des filtres pour montrer seulement ceux temrminés, encore ouverts ou les futures entrées de vous-même ou de tous les utilisateurs.
|
||||
til when should the todo or phonecall be finished infolog fr jusqu'à quand le A-faire ou l'appel téléphonique devrait être terminé
|
||||
times infolog fr Heures
|
||||
to many might exceed your execution-time-limit infolog fr trop peut excéder votre temps limite d´exécution.
|
||||
to what should the startdate of new entries be set. infolog fr A quoi devrait être fixée la date de départ de la nouvelle entrée.
|
||||
today infolog fr Aujourd'hui
|
||||
todays date infolog fr date du jour
|
||||
todo infolog fr A-faire
|
||||
translation infolog fr Traduction
|
||||
typ infolog fr Type
|
||||
typ '%1' already exists !!! infolog fr Type '%1' existe déjà !!!
|
||||
type infolog fr Type
|
||||
type ... infolog fr Type ...
|
||||
type of customfield infolog fr Type de champ personnalisé
|
||||
type of the log-entry: note, phonecall or todo infolog fr Type de l'entrée Log: Note, Appel téléphonique ou A-faire
|
||||
unlink infolog fr Délier
|
||||
upcoming infolog fr Arrivant
|
||||
urgency infolog fr Priorité
|
||||
urgent infolog fr Urgent
|
||||
used time infolog fr Temps utilisé
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog fr Chemin valide côté client<br>p.e. \\Partage\Serveur ou e:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog fr Chemin valide côté client<br>p.e. \\Partage\Serveur ou e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog fr Chemin valide côté client<br>p.e. \\Partage\Serveur ou e:\
|
||||
values for selectbox infolog fr Valeurs des boîtes de sélection
|
||||
view all subs of this entry infolog fr Voir tous les Enfants de cette entrée
|
||||
view other subs infolog fr Voir les autres Enfants
|
||||
view parent infolog fr Voir le parent
|
||||
view subs infolog fr Voir les Enfants
|
||||
view the parent of this entry and all his subs infolog fr Voir le parent de cette entrée et tous ses Enfants
|
||||
view this linked entry in its application infolog fr Voir cette entrée liée dans son application
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog fr Quand le A-faire ou l'appel téléphonique devrait être démarré, il s'affiche depuis cette date dans le filtre ouvert ou propre ouvert (page de démarrage)
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog fr Quels champs supplémentaires le responsable devrait être autorisé à modifier sans avoir à modifier les droits d'édition??<br />Statuts, pourcentage et date de fin sont toujours permis.
|
||||
which implicit acl rights should the responsible get? infolog fr Quels droits ACL implicites le responsable devrait obtenir?
|
||||
whole query infolog fr requête entière
|
||||
will-call infolog fr Va appeler
|
||||
write (add or update) a record by passing its fields. infolog fr Ecrit (ajoute ou met à jour) un enregistrement en passant ses champs.
|
||||
yes - delete infolog fr Oui - Supprimer
|
||||
yes - delete including sub-entries infolog fr Oui - Supprimer y-compris les sous-entrées
|
||||
you can't delete one of the stock types !!! infolog fr Vous ne pouvez pas effacer un des types de stock !!!
|
||||
you have entered an invalid ending date infolog fr Vous avez entré une date de fin invalide
|
||||
you have entered an invalid starting date infolog fr Vous avez entré une date de début invalide
|
||||
you have to enter a name, to create a new typ!!! infolog fr Vous devez entrer un nom pour créer un nouveau type!!!
|
||||
you must enter a subject or a description infolog fr Vous devez entrer un sujet ou une description
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog fr Votre base de données n'est PAS à jour (%1 au lieu de %2), veuillez exécuter %3setup%4 pour la mettre à jour.
|
393
infolog/lang/egw_hu.lang
Normal file
393
infolog/lang/egw_hu.lang
Normal file
@ -0,0 +1,393 @@
|
||||
%1 days in advance infolog hu %1 napot előre
|
||||
%1 deleted infolog hu %1 törölve
|
||||
%1 deleted by %2 at %3 infolog hu %1 törölve %2 által, ekkor: %3
|
||||
%1 modified infolog hu %1 módosítva
|
||||
%1 modified by %2 at %3 infolog hu %1 módosítva %2 által, ekkor: %3
|
||||
%1 records imported infolog hu %1 bejegyzés importálva
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog hu %1 bejegyzés beolvasva (importálás nem történt, %2visszatérés%3 után a Test Import kapcsolót ki kell kapcsolni a tényleges beolvasáshoz)
|
||||
%1 you are responsible for is due at %2 infolog hu %1 felelőseként a határidő %2
|
||||
%1 you are responsible for is starting at %2 infolog hu %1 felelőseként a kezdés ideje %2
|
||||
%1 you delegated is due at %2 infolog hu %1 megbízottjaként a határidő %2
|
||||
%1 you delegated is starting at %2 infolog hu %1 megbízottjaként a kezdés ideje %2
|
||||
- subprojects from infolog hu - Alprojektek innen
|
||||
0% infolog hu 0%
|
||||
10% infolog hu 10%
|
||||
100% infolog hu 100%
|
||||
20% infolog hu 20%
|
||||
30% infolog hu 30%
|
||||
40% infolog hu 40%
|
||||
50% infolog hu 50%
|
||||
60% infolog hu 60%
|
||||
70% infolog hu 70%
|
||||
80% infolog hu 80%
|
||||
90% infolog hu 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog hu <b>állomány csatolás szimbolikus link használatával</b> állományok feltöltése és letöltése helyett file:/útvonal megadásával közvetlen helyi hálózati kliensek esetében
|
||||
a short subject for the entry infolog hu egy rövid tárgy a bejegyzésnek
|
||||
abort without deleting infolog hu Megszakítás törlés nélkül
|
||||
accept infolog hu elfogad
|
||||
action infolog hu Művelet
|
||||
actual date and time infolog hu aktuális dátum és idő
|
||||
add infolog hu Hozzáad
|
||||
add a file infolog hu Állomány hozzáadása
|
||||
add a new entry infolog hu Új bejegyzés hozzáadása
|
||||
add a new note infolog hu Új megjegyzés hozzáadása
|
||||
add a new phonecall infolog hu Új telefonhívás hozzáadása
|
||||
add a new sub-task, -note, -call to this entry infolog hu Új alfeladat, -jegyzet, -hívás hozzáadása a bejegyzéshez
|
||||
add a new todo infolog hu Új tennivaló hozzáadása
|
||||
add file infolog hu Állomány hozzáadása
|
||||
add sub infolog hu Albejegyzés hozzáadása
|
||||
add timesheet entry infolog hu Regiszter bejegyzés hozzáadása
|
||||
add: infolog hu Hozzáadás:
|
||||
all infolog hu Összes
|
||||
all links and attachments infolog hu Minden hivatkozás és melléklet
|
||||
all projects infolog hu Minden projekt
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog hu engedélyezi a bejegyzés állapotának állíthatóságát; pl. egy ToDo-nál a Kész állapotot kell beállítani, ha megvalósult a feladat (az értékek bejegyzéstípusonként eltérhetnek)
|
||||
alternatives infolog hu Alternatívák
|
||||
apply the changes infolog hu Változások végrehajtása
|
||||
archive infolog hu archív
|
||||
are you shure you want to close this entry ? infolog hu Valóban le akarod zárni ezt a bejegyzést?
|
||||
are you shure you want to delete this entry ? infolog hu Valóban törölni kívánod ezt a bejegyzést?
|
||||
attach a file infolog hu Állomány csatolása
|
||||
attach file infolog hu Állomány csatolása
|
||||
attention: no contact with address %1 found. infolog hu Figyelem: %1 címmel Kapcsolat nem található.
|
||||
back to main list infolog hu Vissza a fő listára
|
||||
billed infolog hu számlázva
|
||||
both infolog hu mindkettő
|
||||
call infolog hu hívás
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog hu Alkalmazható további InfoLog típusok megjelenítésére a naptárban vagy korlátozható pl. csak a teendők megjelenítésére.
|
||||
cancel infolog hu Mégsem
|
||||
cancelled infolog hu megszakítva
|
||||
categories infolog hu Kategóriák
|
||||
category infolog hu Kategória
|
||||
change history infolog hu Történet módosítása
|
||||
change the status of an entry, eg. close it infolog hu Bejegyzés státusza megváltozott, pl. lezárták
|
||||
charset of file infolog hu Állomány karakterkészlete
|
||||
check to set startday infolog hu Kezdőnap beállításhoz ikszelje be
|
||||
check to specify custom contact infolog hu Kapcsolja be az egyéni kapcsolat megadásához
|
||||
click here to create the link infolog hu hivatkozás létrehozásához kattintson ide
|
||||
click here to start the search infolog hu keresés elindításához kattintson ide
|
||||
close infolog hu Lezár
|
||||
close all infolog hu Mindet lezár
|
||||
close this entry and all listed sub-entries infolog hu Bejegyzés lezárása minden el bejegyzéssel együtt
|
||||
comment infolog hu Megjegyzés
|
||||
completed infolog hu Teljesítve
|
||||
configuration infolog hu Konfiguráció
|
||||
confirm infolog hu Megerősít
|
||||
contact infolog hu Kapcsolat
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog hu A változásokat másolja a Vágóasztalra, %1újra olvassa be a bejegyzést%2 és fűzze össze őket
|
||||
create new links infolog hu Új hivatkozás létrehozása
|
||||
creates a new field infolog hu Új mező létrehozása
|
||||
creates a new status with the given values infolog hu Új állapot létrehozása az adott értékkel
|
||||
creates a new typ with the given name infolog hu Új típus létrehozása az adott néven
|
||||
creation infolog hu Létrehozás
|
||||
csv-fieldname infolog hu CSV-Mezőnév
|
||||
csv-filename infolog hu CSV-Fájlnév
|
||||
csv-import common hu CSV-Import
|
||||
custom infolog hu Egyedi
|
||||
custom contact-address, leave empty to use information from most recent link infolog hu Egyedi kapcsolat cím, hagyja üresen annak az információnak a használatához ami a legújabb hivatkozásban található
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog hu Egyedi kapcsolat információ, hagyja üresen annak az információnak a használatához ami a legújabb hivatkozásban található
|
||||
custom fields infolog hu Egyedi mezők
|
||||
custom fields, typ and status common hu Egyedi mezők, típus és státusz
|
||||
custom from infolog hu Egyedi innen
|
||||
custom regarding infolog hu Egyedi vonatkozás
|
||||
custom status for typ infolog hu Típus egyedi státusza
|
||||
customfields infolog hu Egyedi mezők
|
||||
date completed infolog hu Teljesítés dátuma
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog hu Teljesítés dátuma (ha üresen hagyja, akkor készrejelentés vagy számlázás esetén az a dátum kerül beállításra)
|
||||
datecreated infolog hu létrehozás dátuma
|
||||
dates, status, access infolog hu Dátumok, Státusz, Elérés
|
||||
days infolog hu napok
|
||||
default category for new infolog entries infolog hu Alapértelmezett kategória új Infolog bejegyzéshez
|
||||
default filter for infolog infolog hu Infolog alapértelmezett szűrője
|
||||
default status for a new log entry infolog hu Alapértelmezett státusz egy új napló bejegyzésnek
|
||||
delegated infolog hu megbízva
|
||||
delegated open infolog hu nyitott megbízatás
|
||||
delegated overdue infolog hu lejárt megbízatás
|
||||
delegated upcomming infolog hu közelgő megbízatás
|
||||
delegation infolog hu Feladat delegálás
|
||||
delete infolog hu Töröl
|
||||
delete one record by passing its id. infolog hu Egy rekord törlése az azonosítója alapján
|
||||
delete the entry infolog hu Bejegyzés törlése
|
||||
delete this entry infolog hu Aktuális bejegyzés törlése
|
||||
delete this entry and all listed sub-entries infolog hu Aktuális és az összes listázott albejegyzés törlése
|
||||
deleted infolog hu törölve
|
||||
deletes the selected typ infolog hu kiválasztott típus törlése
|
||||
deletes this field infolog hu Aktuális mező törlése
|
||||
deletes this status infolog hu Aktuális státusz törlése
|
||||
description infolog hu Leírás
|
||||
determines the order the fields are displayed infolog hu megjelenített mezők rendezésének meghatározása
|
||||
disables a status without deleting it infolog hu státusz tiltása annak törlése nélkül
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog hu A felelős jóváhagyása szükséges a feladat elfogadásához / befejezéséhez vagy mindkettőhöz.
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog hu Kér értesítést, ha egy bejegyzést önhöz rendeltek, vagy egy megbízatást frissítettek?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog hu Kér értesítést, ha egy saját feladatát rövidesen el kell kezdenie?
|
||||
do you want a notification, if items you are responsible for are due? infolog hu Kér értesítést, ha egy saját feladatának a határideje rövidesen lejár?
|
||||
do you want a notification, if items you created get updated? infolog hu Kér értesítést, ha egy ön által létrehozott bejegyzést frissítettek?
|
||||
do you want a notification, if items you delegated are about to start? infolog hu Kér értesítést, ha egy megbízásos feladatot rövidesen el kell kezdenie?
|
||||
do you want a notification, if items you delegated are due? infolog hu Kér értesítést, ha egy megbízásos feladatának határideje rövidesen elérkezik?
|
||||
do you want to receive notifications as html-mails or plain text? infolog hu Az értesítést html vagy normál szöveges formában kéri?
|
||||
don't show infolog infolog hu Infolog bejegyzés elrejtése
|
||||
done infolog hu kész
|
||||
download infolog hu Letölt
|
||||
duration infolog hu Időtartam
|
||||
e-mail: infolog hu E-mail:
|
||||
each value is a line like <id>[=<label>] infolog hu minden érték egy sorban, formája: <id>[=<label>]
|
||||
edit infolog hu Szerkeszt
|
||||
edit or create categories for ingolog infolog hu Szerkesztés vagy kategória létrehozása az Infolognak
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog hu jogok szerkesztése (teljes mértékű szerkesztés, beleértve másvalakit felelőssé megtenni!)
|
||||
edit status infolog hu Állapot szerkesztése
|
||||
edit the entry infolog hu Bejegyzés szerkesztése
|
||||
edit this entry infolog hu Aktuális bejegyzés szerkesztése
|
||||
empty for all infolog hu összes törlése
|
||||
enddate infolog hu Lejárat napja
|
||||
enddate can not be before startdate infolog hu A lejárat dátuma nem lehet korábbi mint a kezdés dátuma
|
||||
enter a custom contact, leave empty if linked entry should be used infolog hu egyedi kapcsolat megadása, üresen hagyva a hivatkozott bejegyzést használja
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog hu egyedi telefon/email, üresen hagyva a hivatkozott bejegyzést használja
|
||||
enter a textual description of the log-entry infolog hu bejegyzés szöveges leírásának megadása
|
||||
enter the query pattern infolog hu Lekérdező minta megadása
|
||||
entry and all files infolog hu Bejegyzés és minden állomány
|
||||
error: saving the entry infolog hu Hiba a bejegyzés mentésekor
|
||||
error: the entry has been updated since you opened it for editing! infolog hu Hiba: a bejegyzés megváltozott azóta, hogy megnyitotta szerkesztésre! Másvalaki frissítette.
|
||||
existing links infolog hu Létező hivatkozások
|
||||
fax infolog hu Fax
|
||||
field must not be empty !!! infolog hu A mezőt ki kell tölteni!!!
|
||||
fieldseparator infolog hu Mező elválasztó
|
||||
finish infolog hu befejez
|
||||
for which types should this field be used infolog hu használható típusok a mezőben
|
||||
from infolog hu Feladó
|
||||
general infolog hu Általános
|
||||
global categories infolog hu Globális kategóriák
|
||||
group owner for infolog hu Csoport tulajdonos
|
||||
high infolog hu magas
|
||||
history infolog hu Történet
|
||||
history logging infolog hu Történet követése (log)
|
||||
history logging and deleting of items infolog hu Történet követése (log) és bejegyzések törlése
|
||||
how many describtion lines should be directly visible. further lines are available via a scrollbar. infolog hu Mennyi leírás sor legyen látható? További sorokat a csúszka használatával lehet megtekinteni.
|
||||
id infolog hu Azonosító
|
||||
id# infolog hu Azonosító#
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog hu Ha egy típusnak van csoport tulajdonosa, akkor az ezzel a típussal létrehozott bejegyzések tulajdonosa a megadott CSOPORT és nem az a felhasználó, aki létrehozta!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog hu Ha nincs beállítva, a kereső és szűrő sor rejtve marad abban az esetben, ha a "maximális egyezés egy lapon" limittől kevesebb találat volt (ahogy az Általános beállítások alatt be van állítva)
|
||||
import infolog hu Importál
|
||||
import next set infolog hu Következő széria importálása
|
||||
importance infolog hu Fontosság
|
||||
info log common hu InfoLog
|
||||
infolog common hu InfoLog
|
||||
infolog - delete infolog hu InfoLog - Törlés
|
||||
infolog - edit infolog hu InfoLog - Szerkesztés
|
||||
infolog - import csv-file infolog hu InfoLog - CSV-állomány import
|
||||
infolog - new infolog hu InfoLog - Új
|
||||
infolog - new subproject infolog hu InfoLog - Új alprojekt
|
||||
infolog - subprojects from infolog hu InfoLog - Alprojekt innen
|
||||
infolog entry deleted infolog hu InfoLog bejegyzés törölve
|
||||
infolog entry saved infolog hu InfoLog bejegyzés elmentve
|
||||
infolog filter for the main screen infolog hu InfoLog szűrő a fő képernyőn
|
||||
infolog list infolog hu InfoLog lista
|
||||
infolog preferences common hu InfoLog tulajdonságok
|
||||
infolog-fieldname infolog hu InfoLog - Mezőnév
|
||||
invalid filename infolog hu Érvénytelen állománynév
|
||||
label<br>helptext infolog hu Címke<br>Segítség szöveg
|
||||
last changed infolog hu Utolsó változás
|
||||
last modified infolog hu Utolsó módosítás
|
||||
leave blank to get the used time calculated by timesheet entries infolog hu Hagyd üresen, hogy a kalkulált időt az időtábla bejegyzéseiből lehessen kalkulálni.
|
||||
leave it empty infolog hu hagyja üresen
|
||||
leave without saveing the entry infolog hu kilépés mentés nélkül
|
||||
leaves without saveing infolog hu kilépés mentés nélkül
|
||||
length<br>rows infolog hu Sorok<br>Hossza
|
||||
limit number of description lines (default 5, 0 for no limit) infolog hu A leírás sorainak felső határa (5 alapértelmezésben, 0 korlátlan számú sorhoz)
|
||||
link infolog hu Hivatkozás
|
||||
links infolog hu Hivatkozások
|
||||
links of this entry infolog hu Aktuális bejegyzés hivatkozásai
|
||||
list all categories infolog hu Összes kategória listázása
|
||||
list no subs/childs infolog hu Albejegyzések elrejtése
|
||||
location infolog hu Hely
|
||||
longer textual description infolog hu hosszabb szöveges leírás
|
||||
low infolog hu alacsony
|
||||
max length of the input [, length of the inputfield (optional)] infolog hu beviteli mező maximális mérete (opcionális)
|
||||
modifierer infolog hu Módosította
|
||||
name must not be empty !!! infolog hu Név nem lehet üres!!!
|
||||
name of new type to create infolog hu új típusnév létrehozása
|
||||
never hide search and filters infolog hu Soha ne rejtse el a keresést és szűrést
|
||||
new %1 infolog hu Új %1
|
||||
new %1 created by %2 at %3 infolog hu %1 új létrehozva %2 által, ekkor: %3
|
||||
new name infolog hu új név
|
||||
new search infolog hu Új keresés
|
||||
no - cancel infolog hu Nem - Mégsem
|
||||
no describtion, links or attachments infolog hu nincsenek leírások, hivatkozások, mellékletek
|
||||
no details infolog hu Részletek nélkül
|
||||
no entries found, try again ... infolog hu nem találtam bejegyzést, próbálja újra ...
|
||||
no filter infolog hu Szűrő nélkül
|
||||
no links or attachments infolog hu nincs hivatkozás vagy melléklet
|
||||
no project infolog hu Nincs projekt
|
||||
nonactive infolog hu nem aktív
|
||||
none infolog hu Semmi
|
||||
normal infolog hu Normál
|
||||
not infolog hu nem
|
||||
not assigned infolog hu Nincs hozzárendelve senkihez
|
||||
not-started infolog hu Még nem indult el
|
||||
note infolog hu Feljegyzés
|
||||
number of records to read (%1) infolog hu Bejegyzések száma olvasáshoz (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog hu többsoros beviteli mező vagy többszörös kiválasztó doboz sorainak száma
|
||||
offer infolog hu ajánlat
|
||||
one day after infolog hu egy nappal ezután
|
||||
one day in advance infolog hu egy nappal előre
|
||||
ongoing infolog hu folyamatban levő
|
||||
only for details infolog hu Csak a részletekhez
|
||||
only if i get assigned or removed infolog hu Csak ha hozzám rendelték vagy törölték
|
||||
only the attachments infolog hu csupán a mellékletek
|
||||
only the links infolog hu csupán a hivatkozások
|
||||
open infolog hu nyitott
|
||||
optional note to the link infolog hu tetszőleges megjegyzés a hivatkozáshoz
|
||||
order infolog hu Rendezés
|
||||
organization infolog hu Szervezet
|
||||
overdue infolog hu lejárt
|
||||
own infolog hu saját
|
||||
own open infolog hu saját nyitott
|
||||
own overdue infolog hu saját lejárt
|
||||
own upcoming infolog hu saját közelgő
|
||||
parent infolog hu Szülő
|
||||
parent infolog infolog hu Szülő Infolog bejegyzés
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog hu út a (web-)szerveroldalon<br>pl. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog hu A felhasználók/csoportok állományainak útvonala KÍVÜL KELL ESSEN a webszerver dokumentum könyvtárán!!!
|
||||
pattern for search in addressbook infolog hu keresési minta a címjegyzékben
|
||||
pattern for search in projects infolog hu keresési minta a projektekben
|
||||
percent completed infolog hu Teljesítés százalékban
|
||||
permission denied infolog hu Hozzáférés megtagadva
|
||||
phone infolog hu Telefonhívás
|
||||
phone/email infolog hu Telefon/Email
|
||||
phonecall infolog hu Telefonhívás
|
||||
planned infolog hu tervezett
|
||||
planned time infolog hu tervezett idő
|
||||
price infolog hu Ár
|
||||
pricelist infolog hu Árlista
|
||||
primary link infolog hu elsődleges kapcsolat
|
||||
priority infolog hu Prioritás
|
||||
private infolog hu Magán
|
||||
project infolog hu Projekt
|
||||
project settings: price, times infolog hu Projekt beállítások: ár, idő
|
||||
projectmanager infolog hu Projektmanager
|
||||
re-planned infolog hu újratervezett
|
||||
re-planned time infolog hu újratervezés ideje
|
||||
re: infolog hu Válasz:
|
||||
read one record by passing its id. infolog hu Egy bejegyzés olvasása az azonosítója alapján.
|
||||
read rights (default) infolog hu olvasási jogok (alapbeállítás)
|
||||
receive notifications about due entries you are responsible for infolog hu Értesítés a felelősségembe tartozó bejegyzés határidejének lejártáról
|
||||
receive notifications about due entries you delegated infolog hu Értesítés a hozzám rendelt bejegyzés határidejének lejártáról
|
||||
receive notifications about items assigned to you infolog hu Értesítés bejegyzés hozzám rendeléséről
|
||||
receive notifications about own items infolog hu Értesítés saját bejegyzésekről
|
||||
receive notifications about starting entries you are responsible for infolog hu Értesítés a felelősségembe tartozó bejegyzés kezdéséről
|
||||
receive notifications about starting entries you delegated infolog hu Értesítés a hozzám rendelt bejegyzés kezdéséről
|
||||
receive notifications as html-mails infolog hu Értesítés mint html email
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog hu reguláris kifejezés a helyi IP címhez <b>pl. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog hu reguláris kifejezés a helyi IP címhez <b>pl. ^192\.168\.1\.
|
||||
remark infolog hu Megjegyzés
|
||||
remove this link (not the entry itself) infolog hu Hivatkozás eltávolítása (nem a bejegyzést magát)
|
||||
responsible infolog hu Felelős
|
||||
responsible open infolog hu Felelős nyitott
|
||||
responsible overdue infolog hu Felelős lejárt
|
||||
responsible upcoming infolog hu Felelős közelgő
|
||||
responsible user, priority infolog hu Felelős felhasználó, prioritás
|
||||
returns a list / search for records. infolog hu Lista visszaadása / bejegyzés keresése
|
||||
rights for the responsible infolog hu Felelős jogai
|
||||
same day infolog hu azonos napon
|
||||
save infolog hu Mentés
|
||||
saves the changes made and leaves infolog hu Változás mentése és kilépés
|
||||
saves this entry infolog hu Bejegyzés mentése
|
||||
search infolog hu Keresés
|
||||
search for: infolog hu Keresés:
|
||||
select infolog hu Kiválaszt
|
||||
select a category for this entry infolog hu Kategória választása a bejegyzés számára
|
||||
select a price infolog hu Ár kiválasztása
|
||||
select a priority for this task infolog hu Feladat prioritásának kiválasztása
|
||||
select a project infolog hu Projekt kiválasztása
|
||||
select a responsible user: a person you want to delegate this task infolog hu Felelős kiválasztása: az a személy akit megbíz a feladattal
|
||||
select a typ to edit it's status-values or delete it infolog hu válassz egy tipust szerkeszteni annak a státusz értékét vagy törölni azt
|
||||
select an app to search in infolog hu Alkalmazásban keresés
|
||||
select an entry to link with infolog hu Bejegyzés választása hivatkozás készítéshez
|
||||
select to filter by owner infolog hu szűrés tulajdonosra
|
||||
select to filter by responsible infolog hu szűrés felelősre
|
||||
sender infolog hu Feladó
|
||||
sets the status of this entry and its subs to done infolog hu Bejegyzés és hozzátartozó albejegyzések állapotának megváltoztatása készre
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog hu InfoLog megjelenítse-e az alfeladatokat, -hívásokat vagy -feljegyzéseket a normál nézetben. Az albejegyzéseket mindig el lehet érni a szülőn keresztül.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog hu Infolog megjelenítse-e a hivatkozásokat más alkalmazáskhoz és/vagy állomány mellékleteket a normál nézetben.
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog hu Az InfoLog megjelenik a Kezdőlapon egy szűrő alkalmazásával, listázva a feladatait stb. Akkor működik, ha nem választott ki egy alkalmazást Főképernyőnek (a beállításai között). Ha nem tudja, ez miről szól, akkor valószínűleg nem állította át és működni fog.
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog hu Az InfoLog használja-e a teljes nevet (családi és keresztnév), vagy csak a bejelentkező nevet.
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog hu Az InfoLog lista megjelenítse-e az egyedi azonosítót, ami egy szám. Ez a szám alkalmas például jegy azonosító használatára (egyértelműbb, mint a megnevezés, tehát van értelme).
|
||||
should the infolog list show the column "last modified". infolog hu Az InfoLog lista megjelenítse-e az "utolsó módosítás" oszlopot is.
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog hu Az InfoLog lista megjelenítse-e a %-os készültséget a folyamatban lévő feladatokra, vagy használjon két külön ikont? Javaslat: két ikon.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog hu A bejegyzés csak saját magának látható és azoknak a felhasználóknak, akiknek hozzáférést biztosít az ACL-en keresztül.
|
||||
show a column for used and planned times in the list. infolog hu Tervezett és felhasznált idők megjelenítése a listában. Erősen javasolt!!! E nélkül ugyanis nem lehet Regiszter bejegyzést hozzáadni az InfoLog bejegyzéshez.
|
||||
show full usernames infolog hu Teljes felhasználónév mutatása
|
||||
show in the infolog list infolog hu InfoLog listában mutassa a következőket
|
||||
show last modified infolog hu Mutassa az utolsónak módosítottat
|
||||
show status and percent done separate infolog hu Mutassa a státuszt és százalékos készültséged külön-külön
|
||||
show ticket id infolog hu Mutassa a jegy azonosítóját
|
||||
show times infolog hu Időtartamok megjelenítése
|
||||
small view infolog hu kis nézet
|
||||
start a new search, cancel this link infolog hu új keresés indítása, hivatkozás elhagyása
|
||||
startdate infolog hu Kezdés dátuma
|
||||
startdate enddate infolog hu Kezdés dátuma Befejezés dátuma
|
||||
startdate for new entries infolog hu Új bejegyzés kezdési időpontja
|
||||
startrecord infolog hu Kezdő bejegyzés
|
||||
status infolog hu Állapot
|
||||
status ... infolog hu Állapot ...
|
||||
sub infolog hu Albejegyzés
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog hu Az albejegyzések a struktúrában felettük álló kategóriának lesznek gyermekei, ha nincs szülő.
|
||||
subject infolog hu Tárgy
|
||||
sum infolog hu Összesen
|
||||
task infolog hu Tennivaló
|
||||
template infolog hu Sablon
|
||||
test import (show importable records <u>only</u> in browser) infolog hu Test Import (<u>csupán</u> az importálható bejegyzések mutatása a böngészöben)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog hu Belső használatú név (<= 10 karakter), megváltoztatása esetén a meglévő adatok elérhetetlenek lesznek!!
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog hu Belső használatú név (<= 20 karakter), megváltoztatása esetén a meglévő adatok elérhetetlenek lesznek!!
|
||||
the text displayed to the user infolog hu a szöveg megjelenítve a felhasználónak
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog hu Az InfoLog alkalmazásba belépéskor ezt a szűrőt használja az alkalmazás. A szűrők korlátozzák a megjelenített bejegyzéseket az aktuális nézetben. Léteznek szűrők a csak befejezett, nyitott, vagy jövőbeli bejegyzésekhez saját magunk, vagy az összes felhasználó számára is.
|
||||
til when should the todo or phonecall be finished infolog hu amíg a Tennivalók vagy Telefonhívások befejeződnek
|
||||
times infolog hu Időigény
|
||||
to many might exceed your execution-time-limit infolog hu Futtatási időkorlát túllépés
|
||||
to what should the startdate of new entries be set. infolog hu Új bejegyzés esetén az alapértelmezett kezdési időpont.
|
||||
today infolog hu Ma
|
||||
todays date infolog hu Mai dátum
|
||||
todo infolog hu Tennivalók
|
||||
translation infolog hu Fordítás
|
||||
typ infolog hu Típus
|
||||
typ '%1' already exists !!! infolog hu '%1' típus már létezik!!!
|
||||
type infolog hu Típus
|
||||
type ... infolog hu Típus ...
|
||||
type of customfield infolog hu Egyedi mező típusa
|
||||
type of the log-entry: note, phonecall or todo infolog hu Napló bejegyzés típusa: Jegyzet, Telefon hívás vagy Tennivaló
|
||||
unlink infolog hu Hivatkozás törlése
|
||||
upcoming infolog hu közelgő
|
||||
urgency infolog hu Sürgősség
|
||||
urgent infolog hu sürgős
|
||||
used time infolog hu felhasznált idő
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog hu Kliensoldali érvényes útvonal<br>pl. \\Server\Share vagy e:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog hu Kliensoldali érvényes útvonal<br>pl. \\Server\Share vagy e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog hu Kliensoldali érvényes útvonal<br>pl. \\Server\Share vagy e:\
|
||||
values for selectbox infolog hu Éktékek a kiválasztódoboznak
|
||||
view all subs of this entry infolog hu Bejegyzés összes albejegyzésének a megtekintése
|
||||
view other subs infolog hu egyéb albejegyzések megtekintése
|
||||
view parent infolog hu Szülő megtekintése
|
||||
view subs infolog hu Albejegyzések megtekintése
|
||||
view the parent of this entry and all his subs infolog hu Szülő bejegyzés és összes albejegyzésének megtekintése
|
||||
view this linked entry in its application infolog hu hivatkozott bejegyzés megtekintése a hozzá tartozó alkalmazással
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog hu Ha egy tennivaló vagy telefonhívás elindult, a nyitott (vagy saját nyitott) szűrőbe bekerül a dátuma (ezt is ki kell találni, hogy hol szerepel)
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog hu A bejegyzés felelőse mely mezőket szerkesztheti anélkül, hogy egyébként szerkesztési jogosultságai lennének?<br/>A Státusz, százalékos készültség és dátum mindig szerkeszthető!<br/>(például ha az alapértelmezett csoportjogosultság nem tenné lehetővé, hogy a leírást módosítsa a felelős).
|
||||
which implicit acl rights should the responsible get? infolog hu Mely értelemszerűen felmerülő ACL jogosultságokat kapjon a felelős?
|
||||
which types should the calendar show infolog hu Mely típust mutasson a naptár
|
||||
whole query infolog hu teljes lekérdezés
|
||||
will-call infolog hu hívni fog
|
||||
write (add or update) a record by passing its fields. infolog hu Kiír (hozzáad vagy módosít) egy bejegyzést a mezők átadásával.
|
||||
yes - close infolog hu Igen - lezárni
|
||||
yes - close including sub-entries infolog hu Igen - lezárni az albejegyzésekkel együtt
|
||||
yes - delete infolog hu Igen - Töröl
|
||||
yes - delete including sub-entries infolog hu Igen - Törlés az összes albejegyzéssel együtt
|
||||
yes, noone can purge deleted items infolog hu Igen, senki nem távolíthatja el a törölt elemeket
|
||||
yes, only admins can purge deleted items infolog hu Igen, csak az adminisztrátorok távolíthatják el a törölt elemeket
|
||||
yes, with larger fontsize infolog hu Igen, nagyobb karaktermérettel
|
||||
yes, with purging of deleted items possible infolog hu Igen, az összes törölt elem eltávolítható
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog hu Választhatsz alapértelmezett kategóriát új InfoLog bejegyzések létrehozásához.
|
||||
you can't delete one of the stock types !!! infolog hu Gyári típust nem lehet törölni !!!
|
||||
you have entered an invalid ending date infolog hu Helytelen befejezési dátum
|
||||
you have entered an invalid starting date infolog hu Helytelen kezdési dátum
|
||||
you have to enter a name, to create a new typ!!! infolog hu Új típus létrehozásához meg kell adni egy nevet!
|
||||
you must enter a subject or a description infolog hu Meg kell adni a tárgyat vagy a leírást
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog hu Az adatbázis frissítésre szorul (%1 <-> %2), kérem futtassa a %3beállításokat%4 az adatbázis frissítéséhez.
|
267
infolog/lang/egw_id.lang
Normal file
267
infolog/lang/egw_id.lang
Normal file
@ -0,0 +1,267 @@
|
||||
%1 days in advance infolog id %1 hari dimuka
|
||||
%1 deleted infolog id %1 dihapus
|
||||
%1 deleted by %2 at %3 infolog id %1 dihapus oleh %2 pada %3
|
||||
%1 modified infolog id %1 diubah
|
||||
%1 modified by %2 at %3 infolog id %1 diubah oleh %2 pada %3
|
||||
%1 records imported infolog id %1 rekaman diimpor
|
||||
%1 you are responsible for is due at %2 infolog id %1 dimana anda bertanggungjawab akan berakhir pada %2
|
||||
%1 you are responsible for is starting at %2 infolog id %1 dimana anda bertanggungjawab akan mulai pada %2
|
||||
%1 you delegated is due at %2 infolog id %1 dimana anda didelegasikan akan berakhir pada %2
|
||||
%1 you delegated is starting at %2 infolog id %1 dimana anda didelegasikan akan mulai pada %2
|
||||
- subprojects from infolog id - Sub-proyek dari
|
||||
0% infolog id 0%
|
||||
10% infolog id 10%
|
||||
100% infolog id 100%
|
||||
20% infolog id 20%
|
||||
30% infolog id 30%
|
||||
40% infolog id 40%
|
||||
50% infolog id 50%
|
||||
60% infolog id 60%
|
||||
70% infolog id 70%
|
||||
80% infolog id 80%
|
||||
90% infolog id 90%
|
||||
abort without deleting infolog id Batal tanpa menghapus
|
||||
accept infolog id diterima
|
||||
action infolog id Tindakan
|
||||
actions... infolog id Tindakan...
|
||||
actual date and time infolog id Tanggal dan waktu sesungguhnya
|
||||
add infolog id Tambah
|
||||
add a file infolog id Tambah berkas
|
||||
add a new entry infolog id Tambah Entri baru
|
||||
add a new note infolog id Tambah Catatan baru
|
||||
add a new phonecall infolog id Tambah Panggilan telepon baru
|
||||
add a new sub-task, -note, -call to this entry infolog id Tambah sub-task, -catatan, -panggilan ke entri ini
|
||||
add a new todo infolog id Tambah ToDo baru
|
||||
add file infolog id Tambah berkas
|
||||
add sub infolog id tambah Sub
|
||||
add timesheet entry infolog id Tamba entri lembarwaktu
|
||||
add: infolog id Tambah:
|
||||
all infolog id Semua
|
||||
all links and attachments infolog id semua tautan dan lampiran
|
||||
all projects infolog id Semua Proyek
|
||||
alternatives infolog id Pengganti
|
||||
apply the changes infolog id Terapkan perubahan
|
||||
archive infolog id arsip
|
||||
are you shure you want to close this entry ? infolog id Apakah anda yakin hendak menutup entri ini?
|
||||
are you shure you want to delete this entry ? infolog id Apakah anda yakin hendak menghapus entri ini?
|
||||
attach a file infolog id Lampirkan berkas
|
||||
attach file infolog id Lampirkan berkas
|
||||
attention: no contact with address %1 found. infolog id Perhatian: Tidak ditemukan Kontak dengan alamat %1.
|
||||
back to main list infolog id Kembali ke daftar utama
|
||||
billed infolog id ditagihkan
|
||||
both infolog id both
|
||||
call infolog id panggilan
|
||||
cancel infolog id Batal
|
||||
cancelled infolog id dibatalkan
|
||||
categories infolog id Kategori
|
||||
category infolog id Kategori
|
||||
change history infolog id Riwayat pengubahan
|
||||
click here to create the link infolog id klik disini untuk membuat tautan
|
||||
click here to start the search infolog id Klik disini untuk memulai pencarian
|
||||
close infolog id Tutup
|
||||
close all infolog id Tutup semua
|
||||
close this entry and all listed sub-entries infolog id Tutup entri ini dan semua sub-entri yang tercantum
|
||||
comment infolog id Komentar
|
||||
completed infolog id Lengkap
|
||||
configuration infolog id Konfigurasi
|
||||
confirm infolog id konfirmasi
|
||||
contact infolog id Kontak
|
||||
copy of: infolog id Salinan dari:
|
||||
create new links infolog id Bikin tautan baru
|
||||
creates a new field infolog id bikin field baru
|
||||
creation infolog id Creation
|
||||
csv-fieldname infolog id CSV-Fieldname
|
||||
csv-filename infolog id CSV-Filename
|
||||
csv-import common id CSV-Import
|
||||
custom infolog id Custom
|
||||
custom fields infolog id Custom Fields
|
||||
custom fields, typ and status common id Custom fields, tipe dan status
|
||||
custom from infolog id Custom from
|
||||
custom regarding infolog id Custom regarding
|
||||
customfields infolog id Customfields
|
||||
date completed infolog id Tanggal selesai
|
||||
datecreated infolog id tanggal dibuat
|
||||
dates, status, access infolog id Tanggal, Status, Akses
|
||||
days infolog id hari
|
||||
default category for new infolog entries infolog id Kategori bawaan untuk entri baru InfoLog
|
||||
default filter for infolog infolog id Saringan bawaan untuk InfoLog
|
||||
default status for a new log entry infolog id Status bawaan untuk entri baru InfoLog
|
||||
delegated infolog id didelegasikan
|
||||
delegated open infolog id delegated open
|
||||
delegated overdue infolog id delegated overdue
|
||||
delegated upcomming infolog id delegated upcomming
|
||||
delegation infolog id Delegasi
|
||||
delete infolog id Hapus
|
||||
delete the entry infolog id Hapus entri
|
||||
delete this entry infolog id Hapus entri ini
|
||||
delete this entry and all listed sub-entries infolog id Hapus entri ini dan semua sub-entri tercamtum
|
||||
deleted infolog id terhapus
|
||||
deletes this field infolog id hapus field ini
|
||||
deletes this status infolog id hapus status ini
|
||||
description infolog id Uraian
|
||||
don't show infolog infolog id JANGAN tampilkan InfoLog
|
||||
done infolog id selesai
|
||||
download infolog id Unduh
|
||||
due %1 infolog id Berakhir %1
|
||||
duration infolog id Durasi
|
||||
e-mail: infolog id E-mail:
|
||||
edit infolog id Edit
|
||||
edit or create categories for ingolog infolog id Edit atau bikin kategori untuk InfoLog
|
||||
edit status infolog id Edit status
|
||||
edit the entry infolog id Edit entri
|
||||
edit this entry infolog id Edit entri ini
|
||||
enddate infolog id Tanggal jatuh-tempo
|
||||
enddate can not be before startdate infolog id Tanggal jatuh-tempo tidak dapat sebelum tanggal memulai
|
||||
existing links infolog id Tautan yang ada
|
||||
fax infolog id Fax
|
||||
fieldseparator infolog id Pemisah field
|
||||
finish infolog id rampung
|
||||
from infolog id Dari
|
||||
general infolog id Umum
|
||||
global categories infolog id Kategori Global
|
||||
high infolog id tinggi
|
||||
history infolog id Riwayat
|
||||
history logging infolog id Catatan riwayat
|
||||
history logging and deleting of items infolog id Riwayat catatan dan penghapusan item
|
||||
id infolog id ID
|
||||
id# infolog id ID#
|
||||
import infolog id Impor
|
||||
import next set infolog id Impor kelompok berikutnya
|
||||
importance infolog id Importance
|
||||
info log common id InfoLog
|
||||
infolog common id InfoLog
|
||||
infolog - delete infolog id InfoLog - Hapus
|
||||
infolog - edit infolog id InfoLog - Edit
|
||||
infolog - import csv-file infolog id InfoLog - Impor berkas-CSV
|
||||
infolog - new infolog id InfoLog - Baru
|
||||
infolog - new subproject infolog id InfoLog - Subproyek Baru
|
||||
infolog - subprojects from infolog id InfoLog - Subproyek dari
|
||||
infolog list infolog id Daftar InfoLog
|
||||
infolog preferences common id Kesukaan InfoLog
|
||||
infolog-fieldname infolog id Nama field-InfoLog
|
||||
invalid filename infolog id Nama berkas keliru
|
||||
label<br>helptext infolog id Label<br>Helptext
|
||||
last changed infolog id Pengubahan terakhir
|
||||
last modified infolog id Pengubahan terakhir
|
||||
leave it empty infolog id biarkan kosong
|
||||
length<br>rows infolog id Length<br>Rows
|
||||
link infolog id Tautan
|
||||
links infolog id Tautan
|
||||
list all categories infolog id Daftar semua kategori
|
||||
location infolog id Lokasi
|
||||
low infolog id rendah
|
||||
new %1 infolog id Baru %1
|
||||
new %1 created by %2 at %3 infolog id Baru %1 dibikin oleh %2 pada %3
|
||||
new name infolog id nama baru
|
||||
new search infolog id Pencarian baru
|
||||
no - cancel infolog id Tidak - Batal
|
||||
no describtion, links or attachments infolog id tiada uraian, tautan atau lampiran
|
||||
no details infolog id tiada kejelasan
|
||||
no entries found, try again ... infolog id tiada entri ditemukan, coba lagi ...
|
||||
no filter infolog id tiada Saringan
|
||||
no links or attachments infolog id tiada tautan dan lampiran
|
||||
no project infolog id Tiada proyek
|
||||
nonactive infolog id tidak aktif
|
||||
none infolog id Tiada
|
||||
normal infolog id normal
|
||||
not infolog id not
|
||||
not assigned infolog id not assigned
|
||||
not-started infolog id belum dimulai
|
||||
note infolog id Catatan
|
||||
offer infolog id penawaran
|
||||
one day after infolog id sehari setelah
|
||||
one day in advance infolog id sehari dimuka
|
||||
ongoing infolog id berlangsung
|
||||
open infolog id buka
|
||||
order infolog id Urutan
|
||||
organization infolog id Organisasi
|
||||
overdue infolog id lewat waktu
|
||||
own infolog id own
|
||||
own open infolog id own open
|
||||
own overdue infolog id own overdue
|
||||
own upcoming infolog id own upcoming
|
||||
parent infolog id Leluhur
|
||||
parent infolog infolog id InfoLog Leluhur
|
||||
pattern for search in addressbook infolog id pola pencarian pada Buku Alamat
|
||||
pattern for search in projects infolog id pola pencarian pada Proyek
|
||||
percent completed infolog id Persentasi rampung
|
||||
permission denied infolog id Ijin Ditolak
|
||||
phone infolog id Panggilan Telepon
|
||||
phone/email infolog id Telepon/Email
|
||||
phonecall infolog id Panggilan Telepon
|
||||
planned infolog id direncanakan
|
||||
planned time infolog id waktu yang direncanakan
|
||||
price infolog id Harga
|
||||
pricelist infolog id Daftar harga
|
||||
primary link infolog id tautan utama
|
||||
priority infolog id Prioritas
|
||||
private infolog id Privat
|
||||
project infolog id Proyek
|
||||
project settings: price, times infolog id Pengaturan Proyek: harga, waktu
|
||||
projectmanager infolog id Manajer Proyek
|
||||
re-planned infolog id Perencanaan ulang
|
||||
re-planned time infolog id Waktu Perencanaan ulang
|
||||
re: infolog id Re:
|
||||
remark infolog id Remark
|
||||
responsible infolog id penanggungjawab
|
||||
responsible open infolog id responsible open
|
||||
responsible overdue infolog id responsible overdue
|
||||
responsible upcoming infolog id responsible upcoming
|
||||
same day infolog id hari yang sama
|
||||
save infolog id Simpan
|
||||
saves the changes made and leaves infolog id simpan perubahan dan tinggalkan
|
||||
saves this entry infolog id Simpan entri ini
|
||||
search infolog id Cari
|
||||
search for: infolog id Mencari:
|
||||
select infolog id Pilih
|
||||
select a category for this entry infolog id pilih kategori untuk entri ini
|
||||
select a price infolog id Pilih harga
|
||||
select a priority for this task infolog id pilih prioritas untuk tugas ini
|
||||
select a project infolog id Pilih proyek
|
||||
sender infolog id Pengirim
|
||||
set status to done infolog id Tetapkan status menjadi selesai
|
||||
set status to done for all entries infolog id Tetapkan status menjadi selesai untuk semua entri
|
||||
sets the status of this entry and its subs to done infolog id Tetapkan status entri ini dan sub-entrinya menjadi selesai
|
||||
show full usernames infolog id Tampilkan Nama lengkap pengguna
|
||||
show in the infolog list infolog id Tampilkan pada daftar InfoLog
|
||||
show last modified infolog id Tampilkan pengubahan terakhir
|
||||
show status and percent done separate infolog id Tampilkan terpisah status dan persentasi selesai
|
||||
show ticket id infolog id Tampilkan ID Tiket
|
||||
show times infolog id Tampilkan waktu
|
||||
small view infolog id tampilan kecil
|
||||
start a new search, cancel this link infolog id memulai pencarian baru, batalkan tautan ini
|
||||
startdate infolog id Tanggal memulai
|
||||
startdate enddate infolog id Tanggal memulai Tanggal berakhir
|
||||
startdate for new entries infolog id Tanggal memulai untuk entri baru
|
||||
starting %1 infolog id Memulai %1
|
||||
startrecord infolog id Rekaman awal
|
||||
status infolog id Status
|
||||
status ... infolog id Status ...
|
||||
sub infolog id Sub
|
||||
subject infolog id Subyek
|
||||
sum infolog id Jml
|
||||
task infolog id ToDo
|
||||
template infolog id Templat
|
||||
times infolog id Waktu
|
||||
today infolog id Hari ini
|
||||
todays date infolog id Tanggal sekarang
|
||||
todo infolog id ToDo
|
||||
translation infolog id Terjemahan
|
||||
typ infolog id Tipe
|
||||
typ '%1' already exists !!! infolog id Tipe '%1' telah ada !!!
|
||||
type infolog id Tipe
|
||||
type ... infolog id Tipe ...
|
||||
type of the log-entry: note, phonecall or todo infolog id Tipe entri log: Catatan, Panggilan telepon atau ToDo
|
||||
unlink infolog id Batalkan tautan
|
||||
upcoming infolog id mendatang
|
||||
urgency infolog id urgency
|
||||
urgent infolog id mendesak
|
||||
used time infolog id waktu yang dihabiskan
|
||||
view parent infolog id Lihat leluhur
|
||||
view subs infolog id view Subs
|
||||
whole query infolog id seluruh query
|
||||
will-call infolog id will call
|
||||
yes - close infolog id Ya - Tutup
|
||||
yes - close including sub-entries infolog id Ya - Tutup berikut sub-entrinya
|
||||
yes - delete infolog id Ya - Hapus
|
||||
yes - delete including sub-entries infolog id Ya - Hapus berikut sub-entrinya
|
377
infolog/lang/egw_nl.lang
Normal file
377
infolog/lang/egw_nl.lang
Normal file
@ -0,0 +1,377 @@
|
||||
%1 days in advance infolog nl %1 dagen tevoren
|
||||
%1 deleted infolog nl %1 verwijderd
|
||||
%1 deleted by %2 at %3 infolog nl %1 verwijderd door %2 op %3
|
||||
%1 modified infolog nl %1 gewijzigd
|
||||
%1 modified by %2 at %3 infolog nl %1 gewijzigd door %2 op %3
|
||||
%1 records imported infolog nl %1 records geïmporteerd
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog nl %1 records gelezen (nog niet geïmporteerd, u kunt terug gaan naar %2back%3 en 'Test Import' uitvinken)
|
||||
%1 you are responsible for is due at %2 infolog nl %1 waar jij verantwoordelijk voor bent vervalt op %2
|
||||
%1 you are responsible for is starting at %2 infolog nl %1 waar jij verantwoordelijk voor bent start op %2
|
||||
%1 you delegated is due at %2 infolog nl %1 die jij gedelegeerd hebt vervalt op %2
|
||||
%1 you delegated is starting at %2 infolog nl %1 die jij gedelegeerd hebt start op %2
|
||||
- subprojects from infolog nl - Subprojecten van
|
||||
0% infolog nl 0%
|
||||
10% infolog nl 10%
|
||||
100% infolog nl 100%
|
||||
20% infolog nl 20%
|
||||
30% infolog nl 30%
|
||||
40% infolog nl 40%
|
||||
50% infolog nl 50%
|
||||
60% infolog nl 60%
|
||||
70% infolog nl 70%
|
||||
80% infolog nl 80%
|
||||
90% infolog nl 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog nl <b>bestandsbijlagen via symbolische links</b> in plaats van uploads en ontvangen via file:/pad voor directe LAN-clients
|
||||
a short subject for the entry infolog nl een kort onderwerp voor een nieuw infolog
|
||||
abort without deleting infolog nl Afbreken zonder te verwijderen
|
||||
accept infolog nl Accepteren
|
||||
action infolog nl Actie
|
||||
actual date and time infolog nl werkelijke datum en tijd
|
||||
add infolog nl Toevoegen
|
||||
add a file infolog nl Een bestand toevoegen
|
||||
add a new entry infolog nl Een nieuw infolog toevoegen
|
||||
add a new note infolog nl Een nieuwe notitie toevoegen
|
||||
add a new phonecall infolog nl Een nieuw telefoongesprek toevoegen
|
||||
add a new sub-task, -note, -call to this entry infolog nl Een nieuwe subtaak, subnotitie, subtelefoongesprek aan dit infolog toevoegen
|
||||
add a new todo infolog nl Een nieuwe taak toevoegen
|
||||
add file infolog nl Bestand toevoegen
|
||||
add sub infolog nl Sub toevoegen
|
||||
add timesheet entry infolog nl Urenregistratie toevoegen
|
||||
add: infolog nl Toevoegen:
|
||||
all infolog nl Alles
|
||||
all links and attachments infolog nl alle links en bijlagen
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog nl Toestaan de status van een infolog te wijzigen, bijv. een taak op status klaar zetten (waarden zijn onafhankelijk van infolog-type)
|
||||
applies the changes infolog nl wijzigingen doorvoeren
|
||||
apply the changes infolog nl De wijzigingen doorvoeren
|
||||
archive infolog nl archief
|
||||
are you shure you want to delete this entry ? infolog nl Weet u zeker dat deze infolog wilt verwijderen
|
||||
attach a file infolog nl Een bestand toevoegen
|
||||
attach file infolog nl Een bestand toevoegen
|
||||
attention: no contact with address %1 found. infolog nl Attentie: Geen contact met adres %1 gevonden.
|
||||
back to main list infolog nl Terug naar hoofdlijst
|
||||
billed infolog nl gefactureerd
|
||||
both infolog nl beiden
|
||||
call infolog nl bellen
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog nl Kan gebruikt worden om meer InfoLog types in de kalender te tonen of de weergave te beperken door bijvoorbeeld alleen maar taken te tonen.
|
||||
cancel infolog nl Annuleren
|
||||
cancelled infolog nl geannuleerd
|
||||
categories infolog nl Categorieën
|
||||
category infolog nl Categorie
|
||||
change history infolog nl Historie van wijzigingen
|
||||
change the status of an entry, eg. close it infolog nl Wijzig de status van een item, bijvoorbeeld afsluiten
|
||||
charset of file infolog nl Karakterset van bestand
|
||||
check to set startday infolog nl Markeer om startdag aan te geven
|
||||
check to specify custom contact infolog nl Markeer om aangepaste contact aan te geven
|
||||
click here to create the link infolog nl klik hier om een link aan te maken
|
||||
click here to start the search infolog nl klik hier om te starten met zoeken
|
||||
close infolog nl Sluiten
|
||||
comment infolog nl Opmerking
|
||||
completed infolog nl Voltooid
|
||||
configuration infolog nl Configuratie
|
||||
confirm infolog nl Bevestigen
|
||||
contact infolog nl Contact
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog nl Kopieer uw wijzigingen naar het klembord, %1laad het record opnieuw%2 voeg de wijziging ermee samen.
|
||||
create new links infolog nl Nieuwe links aanmaken
|
||||
creates a new field infolog nl Maakt nieuw veld aan
|
||||
creates a new status with the given values infolog nl Maakt nieuwe status aan met de ingevoerde waarden
|
||||
creates a new typ with the given name infolog nl Maakt nieuw type aan met de ingevoerde naam
|
||||
creation infolog nl Aanmaak
|
||||
csv-fieldname infolog nl CSV-Veldnaam
|
||||
csv-filename infolog nl CSV-Bestandsnaam
|
||||
csv-import common nl CSV-Import
|
||||
custom infolog nl Aangepast
|
||||
custom contact-address, leave empty to use information from most recent link infolog nl Aangepast contactadres, laat dit leeg om de informatie te gebruiken van de meest recente link
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog nl Aangepaste contactinformatie, laat dit leeg om de informatie te gebruiken van de meest recente link
|
||||
custom fields infolog nl Aangepast velden
|
||||
custom fields, typ and status common nl Aangepaste velden, type en status
|
||||
custom from infolog nl Aangepast van
|
||||
custom regarding infolog nl Aangepast m.b.t.
|
||||
custom status for typ infolog nl Aangepaste status voor type
|
||||
customfields infolog nl Aanpaste velden
|
||||
date completed infolog nl Datum voltooid
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog nl Datum voltooid (leeg laten als je het automatisch wilt laten vullen indien de status op gedaan of gefactureerd wordt gezet)
|
||||
datecreated infolog nl datum aangemaakt
|
||||
dates, status, access infolog nl Data, Status, Toegang
|
||||
days infolog nl dagen
|
||||
default category for new infolog entries infolog nl Standaard categorie voor nieuwe InfoLog invoer
|
||||
default filter for infolog infolog nl Standaard filter voor InfoLog
|
||||
default status for a new log entry infolog nl Standaard status voor een nieuwe infolog
|
||||
delegated infolog nl gedelegeerd
|
||||
delegated open infolog nl gedelegeerd openstaand
|
||||
delegated overdue infolog nl gedelegeerd over tijd
|
||||
delegated upcomming infolog nl gedelegeerd toekomstig
|
||||
delegation infolog nl Delegatie
|
||||
delete infolog nl Verwijderen
|
||||
delete one record by passing its id. infolog nl Verwijder één record door het id mee te geven.
|
||||
delete the entry infolog nl Infolog verwijderen
|
||||
delete this entry infolog nl dit infolog verwijderen
|
||||
delete this entry and all listed sub-entries infolog nl Deze infolog en alle getoonde onderliggende infologs verwijderen
|
||||
deleted infolog nl verwijderd
|
||||
deletes the selected typ infolog nl verwijderd het geselecteerde type
|
||||
deletes this field infolog nl verwijderd dit veld
|
||||
deletes this status infolog nl verwijderd deze status
|
||||
description infolog nl Beschrijving
|
||||
determines the order the fields are displayed infolog nl bepaald hoe de volgorde van de velden wordt weergegeven
|
||||
disables a status without deleting it infolog nl deactiveerd een status zonder het te verwijderen
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog nl Wilt een een bevestiging van de verantwoordelijke voor accepteren, voor beëindigen, of voor beide
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog nl Wilt u een notificatie ontvangen indien items aan u toegewezen worden of toegewezen items gewijzigd worden?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog nl Wilt u een notificatie ontvangen indien items waarvoor u verantwoordelijk bent op het punt staat te starten?
|
||||
do you want a notification, if items you are responsible for are due? infolog nl Wilt u een notificatie ontvangen indien item, waarvoor u verantwoordelijk bent, op het punt staan te vervallen?
|
||||
do you want a notification, if items you created get updated? infolog nl Wilt u een notificatie ontvangen indien items, die u heeft aangemaakt, bijgewerkt worden?
|
||||
do you want a notification, if items you delegated are about to start? infolog nl Wilt u een notificatie ontvangen indien items, die u heeft gedelegeerd, op het punt staan te starten?
|
||||
do you want a notification, if items you delegated are due? infolog nl Wilt u een notificatie ontvangen indien items, die u heeft gedelegeerd, op het punt staan te vervallen?
|
||||
do you want to receive notifications as html-mails or plain text? infolog nl Wilt u notificaties ontvangen als html-emails of als platte tekst?
|
||||
don't show infolog infolog nl InfoLog NIET weergeven
|
||||
done infolog nl gereed
|
||||
download infolog nl Downloaden
|
||||
duration infolog nl Duur
|
||||
each value is a line like <id>[=<label>] infolog nl elke waarde is een regel zoals <id>[=<label>]
|
||||
edit infolog nl Wijzigen
|
||||
edit or create categories for ingolog infolog nl Categorieën voor InfoLog aanmaken of wijzigen
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog nl bewerk rechten (volledige rechten voor bewerking, inclusief anderen hiervoor verantwoordelijk maken!)
|
||||
edit status infolog nl Wijzig status
|
||||
edit the entry infolog nl Wijzig de infolog
|
||||
edit this entry infolog nl Wijzig dit infolog
|
||||
empty for all infolog nl leeg voor alle
|
||||
enddate infolog nl Einddatum
|
||||
enddate can not be before startdate infolog nl Einddatum kan vroeger zijn dan begindatum
|
||||
enter a custom contact, leave empty if linked entry should be used infolog nl Voer een nieuw contact in, laat dit leeg als u de gelinkte wilt gebruiken
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog nl voer een aangepaste telefoon/email in, laat dit leeg als u de gelinkte wilt gebruiken
|
||||
enter a textual description of the log-entry infolog nl Voer een textuele beschrijving in van de infolog
|
||||
enter the query pattern infolog nl Geef een zoek patroon
|
||||
entry and all files infolog nl Infolog en alle bestanden
|
||||
error: saving the entry infolog nl Fout: bij opslaan van de infolog
|
||||
error: the entry has been updated since you opened it for editing! infolog nl Fout: de infolog is gewijzigd sinds dat u het opende voor bewerking!
|
||||
existing links infolog nl Bestaande links
|
||||
fax infolog nl Fax
|
||||
field must not be empty !!! infolog nl Veld mag niet leeg zijn !!!
|
||||
fieldseparator infolog nl Veldonderbreker
|
||||
finish infolog nl Einde
|
||||
for which types should this field be used infolog nl Voor welke type wordt dit veld gebruikt
|
||||
from infolog nl Van
|
||||
general infolog nl Algemeen
|
||||
group owner for infolog nl Groepseigenaar
|
||||
high infolog nl hoog
|
||||
history infolog nl Historie
|
||||
history logging infolog nl Historie vastleggen
|
||||
history logging and deleting of items infolog nl Historie vastleggen en verwijdering van items
|
||||
id infolog nl ID
|
||||
id# infolog nl ID#
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog nl Indien een type een groepseigenaar heeft wordt alle invoer van dat type eigendom van de betreffende groep en NIET de gebruiker die ze heeft aangemaakt!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog nl Indien niet ingesteld wordt de regel met zoeken en filters verborgen in het geval van minder entries dan "maximum aantal matches per pagina" (zoals bepaald in uw algemene voorkeuren).
|
||||
import infolog nl Importeren
|
||||
import next set infolog nl Volgende set imporeten
|
||||
info log common nl InfoLog
|
||||
infolog common nl InfoLog
|
||||
infolog - delete infolog nl InfoLog - Verwijderen
|
||||
infolog - edit infolog nl InfoLog - Wijzigen
|
||||
infolog - import csv-file infolog nl InfoLog - Importeer CSV-bestand
|
||||
infolog - new infolog nl InfoLog - Nieuw
|
||||
infolog - new subproject infolog nl InfoLog - Nieuw subproject
|
||||
infolog - subprojects from infolog nl InfoLog - Subprojecten van
|
||||
infolog entry deleted infolog nl InfoLog verwijderd
|
||||
infolog entry saved infolog nl InfoLog opgeslagen
|
||||
infolog filter for the main screen infolog nl InfoLog filter tbv de voorpagina
|
||||
infolog list infolog nl InfoLog lijst
|
||||
infolog preferences common nl InfoLog voorkeuren
|
||||
infolog-fieldname infolog nl InfoLog-veldnaam
|
||||
invalid filename infolog nl Ongeldige bestandsnaam
|
||||
label<br>helptext infolog nl Label<br/>Helptekst
|
||||
last changed infolog nl Laatst gewijzigd
|
||||
last modified infolog nl Laatst gewijzigd
|
||||
leave blank to get the used time calculated by timesheet entries infolog nl Laat het leeg om de gebruikte tijd uit de urenregistratie te verkrijgen
|
||||
leave it empty infolog nl leeg laten
|
||||
leave without saveing the entry infolog nl weggaan zonder op te slaan
|
||||
leaves without saveing infolog nl weggaan zonder op te slaan
|
||||
length<br>rows infolog nl Lengte<br/>Regels
|
||||
link infolog nl Link
|
||||
links infolog nl Links
|
||||
links of this entry infolog nl Links van deze infolog
|
||||
list all categories infolog nl Toon alle categorieën
|
||||
list no subs/childs infolog nl Sub's niet weergeven
|
||||
location infolog nl Locatie
|
||||
longer textual description infolog nl langere tekstuele beschrijving
|
||||
low infolog nl laag
|
||||
max length of the input [, length of the inputfield (optional)] infolog nl maximale lengte van de invoer [lengte van het invoerveld (optioneel)]
|
||||
modifierer infolog nl Gewijzigd door
|
||||
name must not be empty !!! infolog nl Naam mag niet leeg zijn !!!
|
||||
name of new type to create infolog nl Naam van het nieuw te creëren type
|
||||
never hide search and filters infolog nl Zoeken en filters niet verbergen
|
||||
new %1 infolog nl Nieuw %1
|
||||
new %1 created by %2 at %3 infolog nl Nieuw %1 aangemaakt door %2 op %3
|
||||
new name infolog nl nieuwe naam
|
||||
new search infolog nl Nieuwe zoekopdracht
|
||||
no - cancel infolog nl Nee - Annuleren
|
||||
no describtion, links or attachments infolog nl geen beschrijving, links of bijlagen
|
||||
no details infolog nl geen details
|
||||
no entries found, try again ... infolog nl Geen items gevonden, probeer het nogmaals ...
|
||||
no filter infolog nl Geen filter
|
||||
no links or attachments infolog nl geen links of bijlagen
|
||||
nonactive infolog nl inactief
|
||||
none infolog nl Geen
|
||||
normal infolog nl normaal
|
||||
not infolog nl niet
|
||||
not assigned infolog nl Niet toegewezen
|
||||
not-started infolog nl niet gestart
|
||||
note infolog nl Notitie
|
||||
number of records to read (%1) infolog nl Aantal records om te importen (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog nl Aantal regels voor een een invoertekstvak of van een menu-box
|
||||
offer infolog nl offerte
|
||||
one day after infolog nl één dag na
|
||||
one day in advance infolog nl één dag voor
|
||||
ongoing infolog nl lopende
|
||||
only for details infolog nl Alleen voor details
|
||||
only if i get assigned or removed infolog nl Alleen indien ik wordt toegewezen of verwijderd
|
||||
only the attachments infolog nl alleen de bijlagen
|
||||
only the links infolog nl alleen de links
|
||||
open infolog nl open
|
||||
optional note to the link infolog nl optionele notitie bij de link
|
||||
order infolog nl Order
|
||||
overdue infolog nl te laat
|
||||
own infolog nl eigen
|
||||
own open infolog nl eigen - openstaande
|
||||
own overdue infolog nl eigen - te laat
|
||||
own upcoming infolog nl eigen - toekomstige
|
||||
parent infolog nl Ouder
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog nl pad aan de serverkant <br/> bijv. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog nl Pad naar gebruiker- en groepsbestanden MOETEN BUITEN de documentendirectory zijn van de webserver's
|
||||
pattern for search in addressbook infolog nl Patroon voor zoekopdracht in Adressenboek
|
||||
pattern for search in projects infolog nl Patroon voor zoekopdracht in Projecten
|
||||
percent completed infolog nl Percentage voltooid
|
||||
permission denied infolog nl Toestemming geweigerd
|
||||
phone infolog nl Telefoongesprek
|
||||
phone/email infolog nl Telefoon/Email
|
||||
phonecall infolog nl Telefoongesprek
|
||||
planned infolog nl gepland
|
||||
planned time infolog nl geplande tijd
|
||||
price infolog nl Prijs
|
||||
pricelist infolog nl Prijslijst
|
||||
primary link infolog nl primaire link
|
||||
priority infolog nl Prioriteit
|
||||
private infolog nl Privé
|
||||
project infolog nl Project
|
||||
project settings: price, times infolog nl Project instellingen: prijs, tijden
|
||||
projectmanager infolog nl Projectmanager
|
||||
re-planned infolog nl Hergepland
|
||||
re-planned time infolog nl Hergeplande tijd
|
||||
re: infolog nl Re:
|
||||
read one record by passing its id. infolog nl Lees één record door het id mee te geven.
|
||||
read rights (default) infolog nl leesrechten (standaard)
|
||||
receive notifications about due entries you are responsible for infolog nl Ontvang notificaties over vervallende items waarvoor u verantwoordelijk bent
|
||||
receive notifications about due entries you delegated infolog nl Ontvang notificaties over vervallende items waaraan u bent toegewezen
|
||||
receive notifications about items assigned to you infolog nl Ontvang notificaties over items die aan u zijn toegewezen
|
||||
receive notifications about own items infolog nl Ontvang notificaties over uw eigen items
|
||||
receive notifications about starting entries you are responsible for infolog nl Ontvang notificaties over startende items waarvoor u verantwoordelijk bent
|
||||
receive notifications about starting entries you delegated infolog nl Ontvang notificaties over startende items die aan u zijn toegewezen
|
||||
receive notifications as html-mails infolog nl Ontvang notificaties als html-emails
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog nl reg. expr. for local IP's<br>eg. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog nl reg. expr. for local IP's<br>eg. ^192\.168\.1\.
|
||||
remark infolog nl aandachtspunt
|
||||
remove this link (not the entry itself) infolog nl Verwijder deze link (niet het record zeld)
|
||||
responsible infolog nl verantwoordelijk
|
||||
responsible open infolog nl verantwoordelijk open
|
||||
responsible overdue infolog nl verantwoordelijk te laat
|
||||
responsible upcoming infolog nl verantwoordelijk toekomstige
|
||||
responsible user, priority infolog nl verantwoordelijke gebruiker, prioriteit
|
||||
returns a list / search for records. infolog nl Toont een lijst / zoek records
|
||||
rights for the responsible infolog nl Rechten voor de verantwoordelijke
|
||||
same day infolog nl dezelfde dag
|
||||
save infolog nl Opslaan
|
||||
saves the changes made and leaves infolog nl Slaat wijzigingen op en verlaat het scherm
|
||||
saves this entry infolog nl Slaat deze infolog op
|
||||
search infolog nl Zoeken
|
||||
search for: infolog nl Zoeken naar:
|
||||
select infolog nl Selecteren
|
||||
select a category for this entry infolog nl Selecteer een categorie voor deze infolog
|
||||
select a price infolog nl Selecteer een prijs
|
||||
select a priority for this task infolog nl Selecteer een prioriteit voor deze taak
|
||||
select a project infolog nl Selecteer een project
|
||||
select a responsible user: a person you want to delegate this task infolog nl Selecteer een verantwoordelijke gebruiker: een persoon aan wie u deze taak wilt delegeren
|
||||
select a typ to edit it's status-values or delete it infolog nl Selecteer een type waarvan uw de statuswaarden wilt wijzigen of om te verwijderen
|
||||
select an app to search in infolog nl Selecteer een applicatie om in te zoeken
|
||||
select an entry to link with infolog nl Selecteer een infolog om mee te linken
|
||||
select to filter by owner infolog nl selecteer om te filteren op eigenaar
|
||||
select to filter by responsible infolog nl selecteer om te filteren bij verantwoordelijke
|
||||
sets the status of this entry and its subs to done infolog nl Zet de status van dit item en de onderliggende op gedaan
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog nl Moet InfoLog subtaken, -telefoongesprekken of -notities standaard weergeven, ja of nee. U kunt altijd sub's weergeven via de bovenliggende infolog ?
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog nl Moet InfoLog de links naar andere toepassingen en/of bestanden in de InfoLog lijst (normale weergave als u InfoLog start).
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog nl Moet InfoLog op de voorpagina getoond worden en met welk filter. Werkt alleen indien u geen toepassing voor de voorpagina heeft gekozen (in uw voorkeuren).
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog nl Moet InfoLog volledige namen (voor- en achternaam) gebruiken of alleen gebruikersnamen?
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog nl Moet de InfoLog lijst een uniek nummer tonen dat bijvoorbeeld als ticket ID gebruik kan worden?
|
||||
should the infolog list show the column "last modified". infolog nl Moet de InfoLog lijst de kolom "laatst gewijzigd" tonen?
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog nl Moet de InfoLog lijst uitsluitend het percentage voltooid tonen bij status in behandeling of moet het twee separate ikonen tonen.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog nl Moet deze infolog alleen zochtbaar zijn voor u en de personen die toegang hebben tot uw persoonlijke informatie d.m.v. het ingestelde toegangsbeheer
|
||||
show a column for used and planned times in the list. infolog nl Toont een kolom voor gebruikte en geplande tijden in de lijst.
|
||||
show full usernames infolog nl Volledige gebruikersnamen weergeven
|
||||
show in the infolog list infolog nl In de InfoLoglijst weergeven
|
||||
show last modified infolog nl Laatst gewijzigd weergeven
|
||||
show status and percent done separate infolog nl Status en percentage voltooid separaat weergeven
|
||||
show ticket id infolog nl Ticket ID weergeven
|
||||
show times infolog nl Toon tijden
|
||||
small view infolog nl kleine weergave
|
||||
start a new search, cancel this link infolog nl Start een nieuwe zoekopdracht, deze link annuleren
|
||||
startdate infolog nl Startdatum
|
||||
startdate enddate infolog nl Startdatum Einddatum
|
||||
startdate for new entries infolog nl Startdatum voor nieuwe items
|
||||
startrecord infolog nl Startregel
|
||||
status infolog nl Status
|
||||
status ... infolog nl Status ...
|
||||
sub infolog nl Onderliggende
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog nl Sub infologs worden subs van de bovenliggende of hoofd infologs als er geen boven liggende infolog is
|
||||
subject infolog nl Onderwerp
|
||||
sum infolog nl Som
|
||||
task infolog nl Taak
|
||||
template infolog nl Template
|
||||
test import (show importable records <u>only</u> in browser) infolog nl Test Import (te importeren record weergeven in uw browser)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog nl de naam die intern gebruikt wordt (<= 10 tekens), als je dit wijzigt worden de huidige gegevens onbereikbaar
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog nl de naam die intern gebruikt wordt (<= 20 tekens), als je dit wijzigt worden de huidige gegevens onbereikbaar
|
||||
the text displayed to the user infolog nl De tekst die wordt weergegeven aan de gebruiker
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog nl Dit is het filter dat InfoLog standaard gebruikt wanneer u InfoLog opent. Filters geven een selectie weer van het totale aantal infologs. Er zijn filters voor AFGEWERKTE, OPENSTAANDE of TOEKOMSTIGE infologs voor U of ALLE gebruikers.
|
||||
til when should the todo or phonecall be finished infolog nl Wanneer moet de taak of het telefoongesprek afgehandeld zijn?
|
||||
times infolog nl Tijden
|
||||
to many might exceed your execution-time-limit infolog nl Te veel kan mogelijk de uitvoertijd van dit programme overschrijden.
|
||||
to what should the startdate of new entries be set. infolog nl Waarop moet de startdatum van nieuwe items ingesteld worden.
|
||||
today infolog nl Vandaag
|
||||
todays date infolog nl datum van vandaag
|
||||
todo infolog nl taak
|
||||
translation infolog nl Vertaling
|
||||
typ infolog nl Type
|
||||
typ '%1' already exists !!! infolog nl Type '%1' bestaat al !!!
|
||||
type infolog nl Type
|
||||
type ... infolog nl Type ...
|
||||
type of customfield infolog nl Type van aangepaste veld
|
||||
type of the log-entry: note, phonecall or todo infolog nl Infologtype: Taak, Telefoongesprek of Notitie
|
||||
unlink infolog nl Maak link ongedaan
|
||||
upcoming infolog nl aankomende
|
||||
urgency infolog nl Prioriteit
|
||||
urgent infolog nl dringend
|
||||
used time infolog nl gebruikte tijd
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog nl geldig pad op de computer van de cliënt<br/>. Bijv. \\Server\Share of D:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog nl geldig pad op de computer van de cliënt<br/>. Bijv. \\Server\Share of D:\
|
||||
values for selectbox infolog nl Waarden voor selectbox
|
||||
view all subs of this entry infolog nl Alle sub's van deze infolog weergeven
|
||||
view other subs infolog nl overige sub's weergeven
|
||||
view parent infolog nl bovenliggende weergeven
|
||||
view subs infolog nl Sub's weergeven
|
||||
view the parent of this entry and all his subs infolog nl Van deze infolog de bovenliggende en alle bijbehorende zijn sub's weergeven
|
||||
view this linked entry in its application infolog nl Gelinkt record in bijbehorende applicatie bekijken
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog nl Wanneer moet de Taak of het Telefoongesprek worden gestart? If zal vanaf die datum worden weergeven in het filter OPEN of EIGEN OPENSTAANDE
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog nl Welke additionele velden moet de verantwoordelijke kunnen bewerken zonder daarvoor speciale bewerk rechten te moeten krijgen?<br />Status, percentage en datum voltooid zijn altijd toegestaan.
|
||||
which implicit acl rights should the responsible get? infolog nl Welke impliciete ACL rechten moet de verantwoordelijke krijgen?
|
||||
which types should the calendar show infolog nl Welke types moet de kalender weergeven
|
||||
whole query infolog nl gehele query
|
||||
will-call infolog nl zal bellen
|
||||
write (add or update) a record by passing its fields. infolog nl Schrijf (toevoegen of bijwerken) een record door de velden mee te geven.
|
||||
yes - delete infolog nl Ja - Verwijderen
|
||||
yes - delete including sub-entries infolog nl Ja - Verwijderen inclusief de onderliggende infologs
|
||||
yes, noone can purge deleted items infolog nl Ja, niemand kan gewiste items definitief verwijderen
|
||||
yes, only admins can purge deleted items infolog nl Ja, alleen beheerders kunnen gewiste items definitief verwijderen
|
||||
yes, with larger fontsize infolog nl Ja, met groter lettertype
|
||||
yes, with purging of deleted items possible infolog nl Ja, met definitieve verwijdering van gewiste items als mogelijk
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog nl U kunt een categorie kiezen als voorgeselecteerd voor het geval u een nieuw InfoLog item aanmaakt
|
||||
you can't delete one of the stock types !!! infolog nl U kunt de standaard types niet verwijderen
|
||||
you have entered an invalid ending date infolog nl U heeft een ongeldige einddatum ingevoerd
|
||||
you have entered an invalid starting date infolog nl U heeft een ongeldige startdatum ingevoerd
|
||||
you have to enter a name, to create a new typ!!! infolog nl U moet een naam invoeren om een nieuw type aan te maken!
|
||||
you must enter a subject or a description infolog nl U moet een onderwerp of een beschrijving invoeren
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog nl Uw database is NIET actueel (%1 vs. %2), voer s.v.p. %3setup%4 uit om uw database te actualiseren.
|
@ -1,14 +1,5 @@
|
||||
%1 days in advance infolog pl %1 dni w przód
|
||||
%1 deleted infolog pl %1 usunięto
|
||||
%1 deleted by %2 at %3 infolog pl %1 usunięto przez %2 , %3
|
||||
%1 modified infolog pl %1 zmodyfikowano
|
||||
%1 modified by %2 at %3 infolog pl %1 zmodyfikowano przez %2, %3
|
||||
%1 records imported infolog pl Zaimportowano %1 rekordów
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog pl %1 rekordów wczytano (jeszcze nie zaimportowano, możesz %2wrócić%3 i odznaczyć Test Import)
|
||||
%1 you are responsible for is due at %2 infolog pl %1 za które jesteś odpowiedzialny ma termin zakończenia %2
|
||||
%1 you are responsible for is starting at %2 infolog pl %1 za które jesteś odpowiedzialny zaczynia się %2
|
||||
%1 you delegated is due at %2 infolog pl %1 które oddelegowałeś ma termin zakończenia %2
|
||||
%1 you delegated is starting at %2 infolog pl %1 które oddelegowałeś zaczyna się %2
|
||||
- subprojects from infolog pl - Projekty podrzędne od
|
||||
0% infolog pl 0%
|
||||
10% infolog pl 10%
|
||||
@ -26,7 +17,6 @@ a short subject for the entry infolog pl krótki temat tego wpisu
|
||||
abort without deleting infolog pl Anuluj bez kasowania
|
||||
accept infolog pl Akceptuj
|
||||
action infolog pl Czynność
|
||||
actions... infolog pl Czynności...
|
||||
actual date and time infolog pl aktualna data i czas
|
||||
add infolog pl Dodaj
|
||||
add a file infolog pl Dodaj plik
|
||||
@ -41,26 +31,20 @@ add timesheet entry infolog pl Dodaj wpis czasu pracy
|
||||
add: infolog pl Dodaj:
|
||||
all infolog pl Wszystko
|
||||
all links and attachments infolog pl wszystkie linki i załączniki
|
||||
all projects infolog pl Wszystkie projekty
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog pl pozwala zmienić status wpisu, np. z Do Zrobienia na Wykonane (wartości zależą od typu wpisu)
|
||||
alternatives infolog pl Alternatywy
|
||||
apply the changes infolog pl Zastosuj zmiany
|
||||
archive infolog pl archiwum
|
||||
are you shure you want to close this entry ? infolog pl Czy na pewno zamknąć ten wpis?
|
||||
are you shure you want to delete this entry ? infolog pl Na pewno usunąć ten wpis?
|
||||
attach a file infolog pl Dołącz plik
|
||||
attach file infolog pl Dołącz plik
|
||||
attention: no contact with address %1 found. infolog pl Uwaga: Brak kontaktu z adresem %1.
|
||||
attension: no contact with address %1 found. infolog pl Uwaga: nie znaleziono kontaktu z adresem %1.
|
||||
back to main list infolog pl Wróć do głównej listy
|
||||
billed infolog pl rozliczony
|
||||
both infolog pl Oba
|
||||
call infolog pl rozmowa
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog pl Może być użyte w celu wyświetlenia większej ilość typów wpisów Dzennika CRM w kalendarzu lub ograniczyć ich wyświetlanie np tylko do zadań.
|
||||
cancel infolog pl Anuluj
|
||||
cancelled infolog pl anulowany
|
||||
categories infolog pl Kategorie
|
||||
category infolog pl Kategoria
|
||||
change history infolog pl Zmień historię
|
||||
change the status of an entry, eg. close it infolog pl Zmień status wpisu, np. zakończ go
|
||||
charset of file infolog pl Kodowanie pliku (charset)
|
||||
check to set startday infolog pl check to set startday
|
||||
@ -68,14 +52,11 @@ check to specify custom contact infolog pl Zaznacz, aby określić niestandardow
|
||||
click here to create the link infolog pl kliknij tutaj aby stworzyć odnośnik
|
||||
click here to start the search infolog pl kliknij tutaj aby rozpocząć szukanie
|
||||
close infolog pl Zamknij
|
||||
close all infolog pl Zamknij wszystko
|
||||
close this entry and all listed sub-entries infolog pl Zamknij ten wpis i wszystkie wpisy podrzędne
|
||||
comment infolog pl Komentarz
|
||||
completed infolog pl Wykonany
|
||||
configuration infolog pl Konfiguracja
|
||||
confirm infolog pl Potwierdzenie
|
||||
contact infolog pl Kontakt
|
||||
copy of: infolog pl Kopia z:
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog pl Kopiuje Twoje zmiany do schowka, %1odświeża zawartość wpisu%2 i łączy je ze sobą.
|
||||
create new links infolog pl Tworzy nowe linki
|
||||
creates a new field infolog pl stwórz nowe pole
|
||||
@ -90,7 +71,6 @@ custom contact-address, leave empty to use information from most recent link inf
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog pl Własna informacja dla kontaktu, zostaw puste aby użyć informacji z dodawanego linku
|
||||
custom fields infolog pl Pola własne
|
||||
custom fields, typ and status common pl Typ i status pola własnego
|
||||
custom from infolog pl Władny formularz
|
||||
custom regarding infolog pl Custom regarding
|
||||
custom status for typ infolog pl Własny status dla typu
|
||||
customfields infolog pl Polawłasne
|
||||
@ -99,20 +79,14 @@ date completed (leave it empty to have it automatic set if status is done or bil
|
||||
datecreated infolog pl Data utworzenia
|
||||
dates, status, access infolog pl daty, statusy i dostęp
|
||||
days infolog pl dni
|
||||
default category for new infolog entries infolog pl Domyślna kategoria dla nowych wpisów Dziennika CRM
|
||||
default filter for infolog infolog pl Domyślny filtr dziennika
|
||||
default status for a new log entry infolog pl domyślny status dla nowego wpisu do logu
|
||||
delegated infolog pl oddelegowane
|
||||
delegated open infolog pl oddelegowane otwarte
|
||||
delegated overdue infolog pl oddelegowane przeterminowane
|
||||
delegated upcomming infolog pl oddelegowane nadchodzące
|
||||
delegation infolog pl Delegacja
|
||||
delete infolog pl Kasuj
|
||||
delete one record by passing its id. infolog pl Skasuj jeden rekord przekazując jego id.
|
||||
delete the entry infolog pl Kasuj wpis
|
||||
delete this entry infolog pl skasuj ten wpis
|
||||
delete this entry and all listed sub-entries infolog pl Skasuj ten wpis oraz wszystkie podane podwpisy
|
||||
deleted infolog pl usunięte
|
||||
deletes the selected typ infolog pl kasuje wybrany typ
|
||||
deletes this field infolog pl kasuje to pole
|
||||
deletes this status infolog pl kasuje ten status
|
||||
@ -120,18 +94,11 @@ description infolog pl Opis
|
||||
determines the order the fields are displayed infolog pl określa kolejność wyświetlania pól
|
||||
disables a status without deleting it infolog pl wyłącza status bez kasowania go
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog pl czy chcesz potwierdzenia osoby odpowiedzialnej do: akceptacji, zakończenia zadania lub obydwu?
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog pl Czy chcesz powiadomienia jeśli zostaną przypisane ci nowe zadania albo jeśli istniejące zostaną zaktualizowane?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog pl Czy chcesz powiadomienia, jeśli zadania za które jesteś odpowiedzialny niedługo się zaczynają?
|
||||
do you want a notification, if items you are responsible for are due? infolog pl Czy chcesz powiadomienia jeśli nadszedł termin wykonania zadań za które jesteś odpowiedzialny?
|
||||
do you want a notification, if items you created get updated? infolog pl Czy chcesz powiadomienia, jeśli zadania które utworzyłeś zostaną zaktualizowane?
|
||||
do you want a notification, if items you delegated are about to start? infolog pl Czy chcesz powiadomienia, jeśli zadania które oddelegowałeś niedługo się zaczynają?
|
||||
do you want a notification, if items you delegated are due? infolog pl Czy chcesz powiadomienia, jeśli dobiegł termin wykonania oddelegowanych przez ciebie zadań?
|
||||
do you want to receive notifications as html-mails or plain text? infolog pl Czy chcesz otrzymywać powiadomienia jako HTML czy zwykły tekst?
|
||||
do you want to see custom infolog types in the calendar? infolog pl Czy chcesz oglądać niestandardowe wpisy CRM Dziennik w kalendarzu?
|
||||
don't show infolog infolog pl NIE pokazuj InfoLog
|
||||
done infolog pl wykonano
|
||||
download infolog pl Pobierz
|
||||
duration infolog pl Czas trwania
|
||||
e-mail: infolog pl E-Mail:
|
||||
each value is a line like <id>[=<label>] infolog pl każda wartość jest linią, jak <id>[=<nazwa>]
|
||||
edit infolog pl Edycja
|
||||
edit or create categories for ingolog infolog pl Edytuj lub twórzy kategorie dla CRM Dziennik
|
||||
@ -151,26 +118,18 @@ error: saving the entry infolog pl Błąd przy zapisywaniu zadania
|
||||
error: the entry has been updated since you opened it for editing! infolog pl Błąd: zadanie zostało zaktualizowane odkąd otworzyłeś je do edycji!
|
||||
existing links infolog pl Istniejące linki
|
||||
fax infolog pl Fax
|
||||
field must not be empty !!! infolog pl Pole nie może być puste !
|
||||
fieldseparator infolog pl Separator pól
|
||||
finish infolog pl Koniec
|
||||
for which types should this field be used infolog pl dla jakich typów to pole będzie uzywane
|
||||
from infolog pl Od
|
||||
general infolog pl Ogólnie
|
||||
global categories infolog pl Kategorie Globalne
|
||||
group owner for infolog pl Właściciel grupowy dla
|
||||
high infolog pl wysoki
|
||||
history infolog pl Historia
|
||||
history logging infolog pl Zapis historii
|
||||
history logging and deleting of items infolog pl Zapis historii i usuwanie wpisów
|
||||
how many describtion lines should be directly visible. further lines are available via a scrollbar. infolog pl Ile linii opisu ma być widocznych bezpośrednio. Pozostałe linie są dostępne przez skrolowanie.
|
||||
id infolog pl id
|
||||
id# infolog pl Id #
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog pl Jeżeli typ ma właściciela grupowego, wszystkie zadania tego typu będą własnością określonej grupy ZAMIAST użytkownika, który je utworzył!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog pl Jeżeli nie zaznaczone, wiersz z opcjami wyszukiwania oraz filtrami jest ukrywany dla mniejszej liczby zadań niż "po ile wyświetlać na stronie" (zgodnie z wartością ze wspólnych ustawień aplikacji).
|
||||
import infolog pl Import
|
||||
import next set infolog pl importuj nastepny zestaw
|
||||
importance infolog pl Ważność
|
||||
info log common pl CRM Dziennik
|
||||
infolog common pl CRM Dziennik
|
||||
infolog - delete infolog pl CRM Dziennik - Usuwanie
|
||||
@ -179,9 +138,8 @@ infolog - import csv-file infolog pl CRM Dziennik - Import pliku CSV
|
||||
infolog - new infolog pl CRM Dziennik - Nowy
|
||||
infolog - new subproject infolog pl CRM Dziennik - Nowy podprojekt
|
||||
infolog - subprojects from infolog pl CRM Dziennik - Podprojekt z
|
||||
infolog copied - the copy can now be edited infolog pl Dziennik skopiowany - można teraz edytować kopię
|
||||
infolog entry deleted infolog pl Wpis Dziennika skasowany
|
||||
infolog entry saved infolog pl Wpis Dziennika zapisany
|
||||
infolog entry deleted infolog pl Wpis nfoLog skasowany
|
||||
infolog entry saved infolog pl Wpis InfoLog zapisany
|
||||
infolog filter for the main screen infolog pl Filtr dziennika na stronę główną
|
||||
infolog list infolog pl CRM Dziennik lista
|
||||
infolog preferences common pl CRM Dziennik preferencje
|
||||
@ -190,12 +148,10 @@ invalid filename infolog pl Niepoprawna nazwa pliku
|
||||
label<br>helptext infolog pl Etykieta<br>Tekst pomocy
|
||||
last changed infolog pl Ostatnia zmiana
|
||||
last modified infolog pl Ostatnio modyfikowany
|
||||
leave blank to get the used time calculated by timesheet entries infolog pl Pozostaw puste jeśli chcesz aby zużyty czas został obliczony na podstawie wpisów Czasu Pracy
|
||||
leave it empty infolog pl zostaw puste
|
||||
leave without saveing the entry infolog pl cofnij bez zapisywania wpisu
|
||||
leaves without saveing infolog pl cofnij bez zapisywania
|
||||
length<br>rows infolog pl Długość<br>Linie
|
||||
limit number of description lines (default 5, 0 for no limit) infolog pl Ogranicz liczbę linii opisu (domyślnie 5, 0 - bez limitu)
|
||||
link infolog pl Podłącz
|
||||
links infolog pl Linki
|
||||
links of this entry infolog pl Linki do tego wpisu
|
||||
@ -205,12 +161,9 @@ location infolog pl Lokalizacja
|
||||
longer textual description infolog pl dłuższy opis tekstowy
|
||||
low infolog pl niski
|
||||
max length of the input [, length of the inputfield (optional)] infolog pl maksymalna długość wprowadzanego tekstu [, długość pola (opcjonalnie)]
|
||||
modifierer infolog pl Modyfikator
|
||||
name must not be empty !!! infolog pl Nazwa nie może być pusta!!!
|
||||
name of new type to create infolog pl nazwa nowego tworzonego typu
|
||||
never hide search and filters infolog pl Nigdy nie ukrywaj pól wyszukiwania i filtrów
|
||||
new %1 infolog pl Nowy %1
|
||||
new %1 created by %2 at %3 infolog pl Nowy %1 utworzony przez %2 , %3
|
||||
new name infolog pl nowa nazwa
|
||||
new search infolog pl Nowe wyszukiwanie
|
||||
no - cancel infolog pl Nie - Anuluj
|
||||
@ -219,8 +172,6 @@ no details infolog pl bez szczegółów
|
||||
no entries found, try again ... infolog pl nie znaleziono wpisów, spróbuj jeszcze raz
|
||||
no filter infolog pl Bez filtra
|
||||
no links or attachments infolog pl brak linków lub załączników
|
||||
no project infolog pl Brak projektu
|
||||
nonactive infolog pl niekaktywny
|
||||
none infolog pl Brak
|
||||
normal infolog pl normalny
|
||||
not infolog pl Nie
|
||||
@ -230,24 +181,18 @@ note infolog pl Notatka
|
||||
number of records to read (%1) infolog pl Liczba rekordów do wczytania (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog pl ilość wierszy dla pól składających się z wielu linijek lub zespołu boksów wielokrotnego wyboru
|
||||
offer infolog pl oferta
|
||||
one day after infolog pl jeden dzień po
|
||||
one day in advance infolog pl jeden dzień przed
|
||||
ongoing infolog pl W toku
|
||||
only for details infolog pl Tylko dla szczegółów
|
||||
only if i get assigned or removed infolog pl Tylko jeśli zostanę przypisany lub usunięty
|
||||
only the attachments infolog pl tylko załączniki
|
||||
only the links infolog pl tylko linki
|
||||
open infolog pl otwarte
|
||||
optional note to the link infolog pl opcjonalna notatka do linku
|
||||
order infolog pl Kolejność
|
||||
organization infolog pl Organizacja
|
||||
overdue infolog pl zaległe
|
||||
own infolog pl stworzone przez Ciebie - wszystkie
|
||||
own open infolog pl stworzone przez Ciebie - otwarte
|
||||
own overdue infolog pl stworzone przez Ciebie - zaległe
|
||||
own upcoming infolog pl stworzone przez Ciebie - nadchodzące
|
||||
parent infolog pl Nadrzędny
|
||||
parent infolog infolog pl Nadrzędny Dziennik
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog pl ścieżka na (web-)serwerze<br>np. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog pl Ścieżka do użytkownika i grupy MUSI BYĆ POZA rootem dokumentów www (document-root)!!!
|
||||
pattern for search in addressbook infolog pl wzorzec poszukiwania w książce adresowej
|
||||
@ -260,25 +205,13 @@ phonecall infolog pl Telefon
|
||||
planned infolog pl zaplanowany
|
||||
planned time infolog pl zaplanowany termin
|
||||
price infolog pl Cena
|
||||
pricelist infolog pl Lista cen
|
||||
primary link infolog pl główny link
|
||||
priority infolog pl Priorytet
|
||||
private infolog pl Prywatne
|
||||
project infolog pl Projekt
|
||||
project settings: price, times infolog pl Ustawienia projektu: cena, terminy
|
||||
projectmanager infolog pl Manger projektu
|
||||
re-planned infolog pl Re-planowany
|
||||
re-planned time infolog pl Re-planowany czas
|
||||
re: infolog pl Odp:
|
||||
read one record by passing its id. infolog pl Odczytaj jeden rekord przekazując jego id.
|
||||
read rights (default) infolog pl prawda odczytu (domyślne)
|
||||
receive notifications about due entries you are responsible for infolog pl Otrzymuj powiadomienia o zaległych zadaniach za które jesteś odpowiedzialny
|
||||
receive notifications about due entries you delegated infolog pl Otrzymuj powiadomienia o zaległych zadaniach które oddelegowałeś
|
||||
receive notifications about items assigned to you infolog pl Otrzymuj powiadomienia o zadaniach ci przydzielonych
|
||||
receive notifications about own items infolog pl Otrzymuj powiadomienia o własnych zadaniach
|
||||
receive notifications about starting entries you are responsible for infolog pl Otrzymuj powiadomienia o rozpoczęciu zadań za które jesteś odpowiedzialny
|
||||
receive notifications about starting entries you delegated infolog pl Otrzymuj powiadomienia o rozpoczęciu zadań które oddelegowałeś
|
||||
receive notifications as html-mails infolog pl Otrzymuj powiadomienia jako wiadomości HTML
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog pl wyrażenie regularne dla lokalnych IP<br>np. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog pl wyrażenie regularne dla lokalnych IP<br>np. ^192\.168\.1\.
|
||||
remark infolog pl Przypomnienie
|
||||
@ -290,7 +223,6 @@ responsible upcoming infolog pl oddelegowane na Ciebie - nadchodzące
|
||||
responsible user, priority infolog pl osoba odpowiedzialna, priorytet
|
||||
returns a list / search for records. infolog pl Pokazuje listę wyszukanych rekordów
|
||||
rights for the responsible infolog pl Uprawnienia do osoby odpowiedzialnej
|
||||
same day infolog pl ten sam dzień
|
||||
save infolog pl Zapisz
|
||||
saves the changes made and leaves infolog pl zapisuje zmiany i wychodzi
|
||||
saves this entry infolog pl Zapisuję ten wpis
|
||||
@ -307,14 +239,12 @@ select an app to search in infolog pl Wybierz Aplikację aby w niej szukać
|
||||
select an entry to link with infolog pl Wybierz wpis z którym połączysz
|
||||
select to filter by owner infolog pl wybierz aby sortować po właścicielu
|
||||
select to filter by responsible infolog pl wybierz aby sortować po osobie odpowiedzialnej
|
||||
sender infolog pl Nadawca
|
||||
set status to done infolog pl Ustaw status na wykonany
|
||||
set status to done for all entries infolog pl Ustaw status na wykonany dla wszystkich wpisów
|
||||
sets the status of this entry and its subs to done infolog pl Ustaw stan wpisu i jego wpisów podrzędnych na "gotowy".
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog pl Czy Dziennik CRM ma w domyślnym widoku wyświetlać wszystkie Zadania, Rozmowy i Notatki podrzędne? Możesz zawsze dotrzeć do nich poprzez ich <i>rodzica</i>.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog pl Czy Dziennik CRM powinien pokazywać odnośniki do innych aplikacji oraz/lub załączone pliki na liście zadań (domyślny widok gdy uruchamiany jest Dziennik CRM)?
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog pl Czy Dziennik CRM powinien pokazywać zadania na głównym ekranie a jeżeli tak, to z jakim filtrem. Działa tylko, jeżeli nie wybrano aplikacji na główny ekran (we wspólnych ustawieniach).
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog pl Czy CRM - Dziennik ma używać pełnych danych osobowych (imię, nazwisko), czy tylko loginów.
|
||||
should the calendar show custom types too infolog pl Czy pokazywać osobiste typy w kalendarzu
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog pl Czy na liście zadań Dziennika CRM pokazywać unikalny identyfikator numeryczny, który może być używany np. jako numer kolejny zadania?
|
||||
should the infolog list show the column "last modified". infolog pl Czy na liście zadań Dziennika CRM pokazywać kolumnę "ostatnio zmodyfikowany"?
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog pl Czy na liście zadań Dziennika CRM pokazywać stopień zaawansowania tylko dla zadań "w toku", czy zawsze dwie osobne ikony?
|
||||
@ -337,9 +267,7 @@ status ... infolog pl Status ...
|
||||
sub infolog pl Podrz.
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog pl Zadani są podrzędne wobec zadań, z których je utworzono lub głównych zadań, jeżeli zadania z których je utworzono nie istnieją.
|
||||
subject infolog pl Temat
|
||||
sum infolog pl Suma
|
||||
task infolog pl Zadanie
|
||||
template infolog pl Szablon
|
||||
test import (show importable records <u>only</u> in browser) infolog pl Import testowy (pokazuje importowane rekordy <u>tylko</u> w przeglądarce!)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog pl nazwa użyta wewnętrznie (<= 10 znaków), zmiana spowoduje niedostępność istniejących danych
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog pl nazwa użyta wewnętrznie (<= 20 znaków), zmiana spowoduje niedostępność istniejących danych
|
||||
@ -377,18 +305,11 @@ view this linked entry in its application infolog pl zoabcz podlinkowany wpis w
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog pl kiedy zadanie lub telefon powinno wystartować, to pokazuje z tej daty w filtrze otwartym lub jego otwartym (strona startowa)
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog pl Które dodatkowe pola powinna móc edytować osoba odpowiedzialna nie posiadając praw edycji? <br />Status, stopień zaawansowania oraz data wykonania są zawsze możliwe do edycji.
|
||||
which implicit acl rights should the responsible get? infolog pl Które prawa ACL powinna otrzymać niejawnie osoba odpowiedzialna?
|
||||
which types should the calendar show infolog pl Jakie typy powinien pokazywać kalendarz
|
||||
whole query infolog pl Całe zapytanie
|
||||
will-call infolog pl zadzwoni
|
||||
write (add or update) a record by passing its fields. infolog pl Zapisz (dodaj lub uaktualnij) zapis przez przechodzenie po jego polach
|
||||
yes - close infolog pl Tak - Zamknij
|
||||
yes - close including sub-entries infolog pl Tak - Zamknij z wpisami podrzędnymi
|
||||
yes - delete infolog pl Tak - Usuń
|
||||
yes - delete including sub-entries infolog pl Tak - Usuń wraz z podrzędnymi
|
||||
yes, noone can purge deleted items infolog pl Tak, nikt nie może wymazać usuniętych wpisów
|
||||
yes, only admins can purge deleted items infolog pl Tak, tylko admin może wymazać usunięte wpisy
|
||||
yes, with larger fontsize infolog pl Tak, z większą czcionką
|
||||
yes, with purging of deleted items possible infolog pl Tak, z możliwością wymazywania istniejących wpisów
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog pl Możesz wybrać kategorię automatycznie wybieraną przy tworzeniu nowego wpisu Dziennika
|
||||
you can't delete one of the stock types !!! infolog pl Nie możesz usunąć jesdnego z typów!!!
|
||||
you have entered an invalid ending date infolog pl Podałeś niepoprawną datę zakończenia
|
||||
you have entered an invalid starting date infolog pl Podałeś niepoprawną datę rozpoczęcia
|
||||
|
371
infolog/lang/egw_pt-br.lang
Normal file
371
infolog/lang/egw_pt-br.lang
Normal file
@ -0,0 +1,371 @@
|
||||
%1 days in advance infolog pt-br %1 dias para frente
|
||||
%1 deleted infolog pt-br %1 removido
|
||||
%1 deleted by %2 at %3 infolog pt-br %1 removido por %2 em %3
|
||||
%1 modified infolog pt-br %1 modificado
|
||||
%1 modified by %2 at %3 infolog pt-br %1 modificado por %2 em %3
|
||||
%1 records imported infolog pt-br %1 registros importados
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog pt-br %1 arquivos lidos (não foi importado, você pode %2voltar%3 e efetuar o Teste de importação)
|
||||
%1 you are responsible for is due at %2 infolog pt-br %1, você é o responsável. Excede o prazo em %2
|
||||
%1 you are responsible for is starting at %2 infolog pt-br %1, você é o responsável. Inicia em %2
|
||||
%1 you delegated is due at %2 infolog pt-br %1, você designou. Excede o prazo em %2
|
||||
%1 you delegated is starting at %2 infolog pt-br %1, você designou. Inicia em %2
|
||||
- subprojects from infolog pt-br - Subprojetos de
|
||||
0% infolog pt-br 0%
|
||||
10% infolog pt-br 10%
|
||||
100% infolog pt-br 100%
|
||||
20% infolog pt-br 20%
|
||||
30% infolog pt-br 30%
|
||||
40% infolog pt-br 40%
|
||||
50% infolog pt-br 50%
|
||||
60% infolog pt-br 60%
|
||||
70% infolog pt-br 70%
|
||||
80% infolog pt-br 80%
|
||||
90% infolog pt-br 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog pt-br <b>Arquivos anexados</b> através do sistema de envio:/caminho para clientes de sua própria rede
|
||||
a short subject for the entry infolog pt-br um nome curto para este registro
|
||||
abort without deleting infolog pt-br Cancelar sem apagar
|
||||
accept infolog pt-br aceitar
|
||||
action infolog pt-br Ação
|
||||
actual date and time infolog pt-br Data e Hora atuais
|
||||
add infolog pt-br Adicionar
|
||||
add a file infolog pt-br Adicionar um arquivo
|
||||
add a new entry infolog pt-br Adicionar um novo registro
|
||||
add a new note infolog pt-br Adicionar uma nota
|
||||
add a new phonecall infolog pt-br Adicionar uma nova ligação
|
||||
add a new sub-task, -note, -call to this entry infolog pt-br Adicionar um sub-tarefa, -nota, -ligação para este registro
|
||||
add a new todo infolog pt-br Adicionar um Apontamento
|
||||
add file infolog pt-br Adicionar um arquivo
|
||||
add sub infolog pt-br adicionar uma Sub
|
||||
add timesheet entry infolog pt-br Adicionar registro à planilha de tempo
|
||||
add: infolog pt-br Adicionar:
|
||||
all infolog pt-br Todos
|
||||
all links and attachments infolog pt-br todos links e arquivos anexados
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog pt-br permite configurar o status de um registro. Ex. marque um Apontamento com o Status finalizado quando esta estiver terminada. (Os valores dependem do tipo de registro)
|
||||
apply the changes infolog pt-br Aplicar as alterações
|
||||
archive infolog pt-br arquivar
|
||||
are you shure you want to delete this entry ? infolog pt-br Você tem certeza que deseja apagar este registro?
|
||||
attach a file infolog pt-br Anexar um arquivo
|
||||
attach file infolog pt-br Anexar arquivo
|
||||
attention: no contact with address %1 found. infolog pt-br Atenção: nenhum contato com endereço %1 encontrado.
|
||||
back to main list infolog pt-br Retornar a lista principal
|
||||
billed infolog pt-br cobrado
|
||||
both infolog pt-br ambos
|
||||
call infolog pt-br ligar
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog pt-br Pode ser usado para exibir tipos de Tarefas na Agenda or limitar sua exibição, por exemplo: somente tarefas.
|
||||
cancel infolog pt-br Cancelar
|
||||
cancelled infolog pt-br Cancelada
|
||||
categories infolog pt-br Categorias
|
||||
category infolog pt-br Categoria
|
||||
change the status of an entry, eg. close it infolog pt-br Alterar o status de um registro (ex. fechado)
|
||||
charset of file infolog pt-br Conjunto de carácteres do arquivo
|
||||
check to set startday infolog pt-br Selecione para determinar a data de início
|
||||
check to specify custom contact infolog pt-br Marque para especificar contato personalizado
|
||||
click here to create the link infolog pt-br clique aqui para inserir um hyperlink
|
||||
click here to start the search infolog pt-br clique aqui para iniciar uma pesquisa
|
||||
close infolog pt-br Fechar
|
||||
comment infolog pt-br Comentário
|
||||
completed infolog pt-br Completada
|
||||
configuration infolog pt-br Configuração
|
||||
confirm infolog pt-br Confirme
|
||||
contact infolog pt-br Contato
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog pt-br Copiar suas alterações para a área de transferência, %1recarregar o registro%2 e mesclá-los.
|
||||
create new links infolog pt-br Criar um novo hyperlink
|
||||
creates a new field infolog pt-br criar um novo campo
|
||||
creates a new status with the given values infolog pt-br criar um status novo com os valores antigos
|
||||
creates a new typ with the given name infolog pt-br criar um novo tipo com nomes antigos
|
||||
creation infolog pt-br Criação
|
||||
csv-fieldname infolog pt-br CSV-Nome do Campo
|
||||
csv-filename infolog pt-br CSV-Nome do Arquivo
|
||||
csv-import common pt-br CSV-Importar
|
||||
custom infolog pt-br Personalizado
|
||||
custom contact-address, leave empty to use information from most recent link infolog pt-br Personalizar endereço de contato, deixe vazio para usar a informação do link mais recente.
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog pt-br Personalizar informações de contato, deixe vazio para utilizar a informação do link mais recente.
|
||||
custom fields infolog pt-br Campos Personalizáveis
|
||||
custom fields, typ and status common pt-br Campos Personalizáveis, tipo e status
|
||||
custom from infolog pt-br Personalizar de
|
||||
custom regarding infolog pt-br Personalizar Atenção
|
||||
custom status for typ infolog pt-br Personalizar status por tipo
|
||||
customfields infolog pt-br Campos Perssonalizáveis
|
||||
date completed infolog pt-br Data de Finalização
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog pt-br Data de finalização (deixe em branco para ser automaticamente informada, quando o status for alterado para Completada ou Cobrada)
|
||||
datecreated infolog pt-br data da criação
|
||||
dates, status, access infolog pt-br Datas, Status, Acessos
|
||||
days infolog pt-br dias
|
||||
default category for new infolog entries infolog pt-br Categoria padrão para novos registros Tarefas
|
||||
default filter for infolog infolog pt-br Filtro padrao
|
||||
default status for a new log entry infolog pt-br status padrão para um novo registro
|
||||
delegated infolog pt-br designado
|
||||
delegated open infolog pt-br designado e aberto
|
||||
delegated overdue infolog pt-br designado e prazo excedido
|
||||
delegated upcomming infolog pt-br designado e prazo excedendo
|
||||
delegation infolog pt-br Atribuição
|
||||
delete infolog pt-br Apagar
|
||||
delete one record by passing its id. infolog pt-br Apagar um registro contornando seu id.
|
||||
delete the entry infolog pt-br Apagar o registro
|
||||
delete this entry infolog pt-br Apagar este registro
|
||||
delete this entry and all listed sub-entries infolog pt-br Apagar este registro e todos os sub-registros listados
|
||||
deleted infolog pt-br removido
|
||||
deletes the selected typ infolog pt-br Apagar os tipos selecionados
|
||||
deletes this field infolog pt-br Apagar este campo
|
||||
deletes this status infolog pt-br Apagar este status
|
||||
description infolog pt-br Descrição
|
||||
determines the order the fields are displayed infolog pt-br determine a ordem em que os campos aparecerão
|
||||
disables a status without deleting it infolog pt-br desabilitar o status após a remoção
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog pt-br você quer uma confirmação do responsável quanto à: aceitação, encerramento ou ambos
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog pt-br Você quer receber uma notificação, caso itens forem designados a você ou caso itens designados a você forem atualizados?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog pt-br Você quer receber uma notificação, caso algum item esteja prestes a iniciar e você seja o responsável?
|
||||
do you want a notification, if items you are responsible for are due? infolog pt-br Você quer receber uma notificação, caso itens excedam o prazo e você seja o responsável?
|
||||
do you want a notification, if items you created get updated? infolog pt-br Você quer receber uma notificação, se itens que você criou forem atualizados?
|
||||
do you want a notification, if items you delegated are about to start? infolog pt-br Você quer receber uma notificação, se itens que você designou estiverem prestes a iniciar?
|
||||
do you want a notification, if items you delegated are due? infolog pt-br Você quer receber uma notificação, se itens que você designou excederem o prazo?
|
||||
do you want to receive notifications as html-mails or plain text? infolog pt-br Você quer receber notificações em HTML ou texto puro?
|
||||
don't show infolog infolog pt-br Não exibir Tarefas
|
||||
done infolog pt-br Encerrado
|
||||
download infolog pt-br Baixar
|
||||
duration infolog pt-br Duração
|
||||
each value is a line like <id>[=<label>] infolog pt-br cada valor por linha <id>[=<label>]
|
||||
edit infolog pt-br Editar
|
||||
edit or create categories for ingolog infolog pt-br Editar ou criar categorias para o Módulo Tarefas
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog pt-br Permissões de edição (edição total inclui fazer outra pessoa responsável)
|
||||
edit status infolog pt-br Editar o Status
|
||||
edit the entry infolog pt-br Editar o registro
|
||||
edit this entry infolog pt-br Editar este registro
|
||||
empty for all infolog pt-br esvaziar tudo
|
||||
enddate infolog pt-br Data Final
|
||||
enddate can not be before startdate infolog pt-br A data final não pode ser anterior a data inicial
|
||||
enter a custom contact, leave empty if linked entry should be used infolog pt-br Digitar um contato personalizado, deixe vazio para utilizar o que já existe
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog pt-br Digitar um fone/e-mail personalizado, deixe vazio para utilizar o que já existe
|
||||
enter a textual description of the log-entry infolog pt-br Digitar uma descrição para este novo registro
|
||||
enter the query pattern infolog pt-br Digite o argumento da consulta
|
||||
entry and all files infolog pt-br Este e todos os arquivos
|
||||
error: saving the entry infolog pt-br Erro salvando o registro
|
||||
error: the entry has been updated since you opened it for editing! infolog pt-br Erro: o registro foi atualizado desde sua abertura, por você, para edição!
|
||||
existing links infolog pt-br Links existentes
|
||||
fax infolog pt-br Fax
|
||||
field must not be empty !!! infolog pt-br O campo não pode estar vazio!!!
|
||||
fieldseparator infolog pt-br Separador de Campos
|
||||
finish infolog pt-br finalizar
|
||||
for which types should this field be used infolog pt-br para quais tipos este campo deve ser utilizado
|
||||
from infolog pt-br De
|
||||
general infolog pt-br Geral
|
||||
group owner for infolog pt-br Grupo-proprietário para
|
||||
high infolog pt-br alta
|
||||
history logging infolog pt-br Registro de histórico
|
||||
history logging and deleting of items infolog pt-br Registro de histórico e remoção de itens
|
||||
id infolog pt-br Id
|
||||
id# infolog pt-br Id#
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog pt-br Se um tipo tem um grupo-proprietário, todas as entradas deste tipo terão como dono o grupo informado e não o usuário que as criou.
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog pt-br Se não informado, a linha com Pesquisa e Filtros ficará oculta para menos registros que "número máximo de registro por página" (definido em suas preferências).
|
||||
import infolog pt-br Importar
|
||||
import next set infolog pt-br importar o próximo conjunto
|
||||
info log common pt-br Tarefas
|
||||
infolog common pt-br Tarefas
|
||||
infolog - delete infolog pt-br Apagar - Tarefas
|
||||
infolog - edit infolog pt-br Editar - Tarefas
|
||||
infolog - import csv-file infolog pt-br Importar arquivo CVS - Tarefas
|
||||
infolog - new infolog pt-br Nova - Tarefas
|
||||
infolog - new subproject infolog pt-br Novo Subprojeto - Tarefas
|
||||
infolog - subprojects from infolog pt-br Novo Subprojeto de - Tarefas
|
||||
infolog entry deleted infolog pt-br Tarefa removida
|
||||
infolog entry saved infolog pt-br Tarefa salva
|
||||
infolog filter for the main screen infolog pt-br Filtro para Tarefas na Página Inicial
|
||||
infolog list infolog pt-br Lista de Tarefas
|
||||
infolog preferences common pt-br Preferências - Tarefas
|
||||
infolog-fieldname infolog pt-br Nome do campo - Tarefas
|
||||
invalid filename infolog pt-br Nome de arquivo inválido
|
||||
label<br>helptext infolog pt-br Etiqueta<br>Texto para ajuda
|
||||
last changed infolog pt-br Última alteração
|
||||
last modified infolog pt-br Última modificação
|
||||
leave it empty infolog pt-br Deixe em branco
|
||||
leave without saveing the entry infolog pt-br Sair sem salvar o registro
|
||||
leaves without saveing infolog pt-br Sair sem salvar
|
||||
length<br>rows infolog pt-br Largura<br>Colunas
|
||||
link infolog pt-br Link
|
||||
links infolog pt-br Links
|
||||
links of this entry infolog pt-br Links para este registro
|
||||
list all categories infolog pt-br Listar todas as categorias
|
||||
list no subs/childs infolog pt-br não listar subs/filhos
|
||||
location infolog pt-br Local
|
||||
longer textual description infolog pt-br descrição detalhada
|
||||
low infolog pt-br baixo
|
||||
max length of the input [, length of the inputfield (optional)] infolog pt-br tamanho máximo para inclusão [, tamanho para o campo (opcional)]
|
||||
modifierer infolog pt-br Modificador
|
||||
name must not be empty !!! infolog pt-br O campo nome não pode estar vazio!!!
|
||||
name of new type to create infolog pt-br nome para o novo tipo
|
||||
never hide search and filters infolog pt-br Nunca ocultar Pesquisa e Filtros
|
||||
new %1 infolog pt-br Novo %1
|
||||
new %1 created by %2 at %3 infolog pt-br Novo %1 criado por %2 em %3
|
||||
new name infolog pt-br novo nome
|
||||
new search infolog pt-br Nova pesquisa
|
||||
no - cancel infolog pt-br Não - Cancelar
|
||||
no describtion, links or attachments infolog pt-br Sem descrição, links ou anexos
|
||||
no details infolog pt-br Sem detalhes
|
||||
no entries found, try again ... infolog pt-br nenhum registro encontrado, tente novamente ...
|
||||
no filter infolog pt-br sem filtro
|
||||
no links or attachments infolog pt-br sem links ou anexos
|
||||
nonactive infolog pt-br não ativo
|
||||
none infolog pt-br Nenhum
|
||||
normal infolog pt-br normal
|
||||
not infolog pt-br não
|
||||
not assigned infolog pt-br não atribuido
|
||||
not-started infolog pt-br Não iniciada
|
||||
note infolog pt-br Nota
|
||||
number of records to read (%1) infolog pt-br Número de registros para ler (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog pt-br Número de linha para campos ou caixas de entrada multilinhas
|
||||
offer infolog pt-br Livre
|
||||
one day after infolog pt-br um dia depois
|
||||
one day in advance infolog pt-br um dia adiantado
|
||||
ongoing infolog pt-br Aberto
|
||||
only for details infolog pt-br Somente para detalhes
|
||||
only if i get assigned or removed infolog pt-br Somente se eu for designado ou removido
|
||||
only the attachments infolog pt-br apenas arquivos anexos
|
||||
only the links infolog pt-br apenas links
|
||||
open infolog pt-br abrir
|
||||
optional note to the link infolog pt-br Nota opcional para o Link
|
||||
order infolog pt-br Ordem
|
||||
overdue infolog pt-br atrasado
|
||||
own infolog pt-br Suas tarefas
|
||||
own open infolog pt-br Suas tarefas abertas
|
||||
own overdue infolog pt-br Suas tarefas em Atraso
|
||||
own upcoming infolog pt-br Suas tarefas futuras
|
||||
parent infolog pt-br Pai
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog pt-br caminho (web-)serverside<br>ex. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog pt-br O diretório para os arquivos de usuário ou grupo DEVE ESTAR FORA da raiz de documentos do servidor web!!!
|
||||
pattern for search in addressbook infolog pt-br argumento de pesquisa em catálogo de endereços
|
||||
pattern for search in projects infolog pt-br argumento de pesquisa nos Projetos
|
||||
percent completed infolog pt-br Percentagem completada
|
||||
permission denied infolog pt-br Permissão negada
|
||||
phone infolog pt-br Chamadas Telefônicas
|
||||
phone/email infolog pt-br Telefone/E-mail
|
||||
phonecall infolog pt-br Chamadas Telefônicas
|
||||
planned infolog pt-br Planejada
|
||||
planned time infolog pt-br Horas planejadas
|
||||
price infolog pt-br Preço
|
||||
pricelist infolog pt-br Lista de preços
|
||||
primary link infolog pt-br Link primário
|
||||
priority infolog pt-br Prioridade
|
||||
private infolog pt-br Particular
|
||||
project infolog pt-br Projeto
|
||||
project settings: price, times infolog pt-br Configurações do projeto: preço, tempo
|
||||
re: infolog pt-br Re:
|
||||
read one record by passing its id. infolog pt-br Ler um registro contornando seu id.
|
||||
read rights (default) infolog pt-br Permissões de leitura (padrão)
|
||||
receive notifications about due entries you are responsible for infolog pt-br Receber notificações sobre registros com prazos excedidos, cujo responsável seja você.
|
||||
receive notifications about due entries you delegated infolog pt-br Receber notificações sobre registros com prazos excedidos que você tenha designado
|
||||
receive notifications about items assigned to you infolog pt-br Receber notificações sobre registros designados a você
|
||||
receive notifications about own items infolog pt-br Receber notificações sobre seus próprios registros
|
||||
receive notifications about starting entries you are responsible for infolog pt-br Receber notificações sobre registros prestes a se iniciar, cujo responsável seja você.
|
||||
receive notifications about starting entries you delegated infolog pt-br Receber notificações sobre registros prestes a se iniciar que você tenha designado.
|
||||
receive notifications as html-mails infolog pt-br Receber notificações em formato HTML
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog pt-br reg. expr. for local IP's<br>eg. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog pt-br reg. expr. for local IP's<br>eg. ^192\.168\.1\.
|
||||
remark infolog pt-br Destaque
|
||||
remove this link (not the entry itself) infolog pt-br Remover este link (não o registro)
|
||||
responsible infolog pt-br Responsável
|
||||
responsible open infolog pt-br Responsável pela abertura
|
||||
responsible overdue infolog pt-br Responsável pela realização
|
||||
responsible upcoming infolog pt-br Responsável futuro
|
||||
responsible user, priority infolog pt-br Usuário responsável, prioridade
|
||||
returns a list / search for records. infolog pt-br Retornar uma lista / pesquisar por registros
|
||||
rights for the responsible infolog pt-br Permissões para o responsável
|
||||
same day infolog pt-br mesmo dia
|
||||
save infolog pt-br Salvar
|
||||
saves the changes made and leaves infolog pt-br salvar as alterações realizadas e sair.
|
||||
saves this entry infolog pt-br Salvar este registro
|
||||
search infolog pt-br Pesquisar
|
||||
search for: infolog pt-br Pesquizar por:
|
||||
select infolog pt-br Selecionar
|
||||
select a category for this entry infolog pt-br selecione uma categoria para este registro
|
||||
select a price infolog pt-br Selecione um preço
|
||||
select a priority for this task infolog pt-br selecione uma prioridade para esta tarefa
|
||||
select a project infolog pt-br Selecione um projeto
|
||||
select a responsible user: a person you want to delegate this task infolog pt-br selecione um responsável: a pessoa a quem você delegará essa tarefa
|
||||
select a typ to edit it's status-values or delete it infolog pt-br selecione um tipo para editar o valor do status ou apague-o
|
||||
select an app to search in infolog pt-br Selecione em que aplicativo a pesquisa será feita
|
||||
select an entry to link with infolog pt-br Selecione um registro para link
|
||||
select to filter by owner infolog pt-br Selecione para filtrar por proprietário
|
||||
select to filter by responsible infolog pt-br Selecione para filtrar por responsável
|
||||
sets the status of this entry and its subs to done infolog pt-br Configura o status deste registros e seus sub-registros como Completada
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog pt-br As sub tarefas de chamadas, notas, devem ser mostradas ou não . Você pode sempre pode visualizar as sub tarefas à partir da principal.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog pt-br Links para outros aplicativos ou anexos deverão ser exibidos na lista de Tarefas (quando você abrir Tarefas em modo normal de visualização).
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog pt-br O aplicativo Tarefas deverá ser exibido na Página Inicial ? Com qual filtro? Funciona somente se você não selecionou um aplicativo para sua Página Inicial (em suas preferências).
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog pt-br O aplicativo Tarefas deve usar o nome completo (nome e sobrenome) ou apenas o login de acesso.
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog pt-br A lista do aplicativo Tarefas deverá exibir um identificador número único, que poderá ser usado, por exemplo, como identificador de Ticket.
|
||||
should the infolog list show the column "last modified". infolog pt-br A lista do aplicativo Tarefas deverá exibir a coluna "Última alteração".
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog pt-br A lista do aplicativo Tarefas deverá exibir a percentagem já realizada somente para o status ou dois ícones separados.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog pt-br Este registro deve ser visível apenas para você e para usuários que você determine atráves das regras de controle de acesso, ou deve ser público?
|
||||
show a column for used and planned times in the list. infolog pt-br Exibir uma coluna para tempo planejado e usado na lista.
|
||||
show full usernames infolog pt-br Mostrar nomes completos
|
||||
show in the infolog list infolog pt-br Mostrar na lista de tarefas
|
||||
show last modified infolog pt-br Exibir última alteração
|
||||
show status and percent done separate infolog pt-br Exibir status e percentagem já realizada separados
|
||||
show ticket id infolog pt-br Exibir identificador do Ticket
|
||||
show times infolog pt-br Exibir horários
|
||||
small view infolog pt-br visão compacta
|
||||
start a new search, cancel this link infolog pt-br iniciar um nova pesquisa, cancelar este link
|
||||
startdate infolog pt-br Data Inicial
|
||||
startdate enddate infolog pt-br Data inicial / Data Final
|
||||
startdate for new entries infolog pt-br Data inicial para novas tarefas
|
||||
startrecord infolog pt-br Iniciar registro
|
||||
status infolog pt-br Status
|
||||
status ... infolog pt-br Status ...
|
||||
sub infolog pt-br Sub
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog pt-br Sub-entradas tornam-se "filhas" da "entrada-pai" ou, se não houver "entrada-pai", da entrada principal
|
||||
subject infolog pt-br Assunto
|
||||
sum infolog pt-br Soma
|
||||
task infolog pt-br Pendências
|
||||
template infolog pt-br Modelo
|
||||
test import (show importable records <u>only</u> in browser) infolog pt-br Teste de Importação (mostrará arquivos importados <u>apenas</u> no navegador)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog pt-br o nome usado internamente (<= 10 caracteres), alterando-o fará dados existentes inacessíveis
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog pt-br o nome usado internamente (<= 20 caracteres), alterando-o fará dados existentes inacessíveis
|
||||
the text displayed to the user infolog pt-br o texto mostrado ao usuário
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog pt-br Estes são os filtros padrões do Módulo de Tarefas. Os filtros ajudam a limitar a visão atual. Existem filtros para mostrar tarefas encerradas, ou abertas, ou até todas as tarefas disponíveis a todos os usuários.
|
||||
til when should the todo or phonecall be finished infolog pt-br até quando uma pendência ou chamada esteja encerrada.
|
||||
times infolog pt-br Horários
|
||||
to many might exceed your execution-time-limit infolog pt-br mostrar muitos registros pode provocar a violação do tempo limite do servidor
|
||||
to what should the startdate of new entries be set. infolog pt-br Para que data inicial novas tarefas deverão ser configuradas.
|
||||
today infolog pt-br Para Hoje
|
||||
todays date infolog pt-br Data de hoje
|
||||
todo infolog pt-br Pendências
|
||||
translation infolog pt-br Tradução
|
||||
typ infolog pt-br Tipo
|
||||
typ '%1' already exists !!! infolog pt-br O tipo '%1' já existe!!!
|
||||
type infolog pt-br Tipo
|
||||
type ... infolog pt-br Tipo ...
|
||||
type of customfield infolog pt-br Tipo de campo personalizado
|
||||
type of the log-entry: note, phonecall or todo infolog pt-br Tipo de registro: Nota, Recado ou Pendência
|
||||
unlink infolog pt-br Remover link
|
||||
upcoming infolog pt-br futuras
|
||||
urgency infolog pt-br urgência
|
||||
urgent infolog pt-br urgente
|
||||
used time infolog pt-br Horas utilizadas
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog pt-br valid path on clientside<br>eg. \\Server\Share or e:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog pt-br valid path on clientside<br>eg. \\Server\Share or e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog pt-br valid path on clientside<br>eg. \\Server\Share or e:\
|
||||
values for selectbox infolog pt-br Valores para a caixa de seleção
|
||||
view all subs of this entry infolog pt-br Ver todas as subs para este registro
|
||||
view other subs infolog pt-br ver outras subs
|
||||
view parent infolog pt-br Ver superiores
|
||||
view subs infolog pt-br ver inferiores
|
||||
view the parent of this entry and all his subs infolog pt-br Ver o registro superior e todos os inferiores
|
||||
view this linked entry in its application infolog pt-br Ver esse link no aplicativo correspondente
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog pt-br Quando uma pendência ou chamada for iniciada ela deverá ser mostrada primeiro no filtro que esteja aberto ou na sua página inicial
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog pt-br Que registros adicionais o responsável estará autorizado a editar sem ter acesso à edição?<br/>Status, percentagem e data de finalização são sempre autorizados.
|
||||
which implicit acl rights should the responsible get? infolog pt-br Que direitos implícitos o responsável deverá receber ?
|
||||
which types should the calendar show infolog pt-br Quais tipos deverão ser exibidos pela Agenda
|
||||
whole query infolog pt-br toda a consulta
|
||||
will-call infolog pt-br a chamar
|
||||
write (add or update) a record by passing its fields. infolog pt-br Escrever (adicionar ou atualizar) um registro contornando seus campos.
|
||||
yes - delete infolog pt-br Sim - Apagar
|
||||
yes - delete including sub-entries infolog pt-br Sim - Apagar inclusive sub-registros
|
||||
yes, noone can purge deleted items infolog pt-br Sim, ninguém pode limpar registros removidos
|
||||
yes, only admins can purge deleted items infolog pt-br Sim, somente administradores podem limpar registros removidos
|
||||
yes, with larger fontsize infolog pt-br Sim, com fontes grandes
|
||||
yes, with purging of deleted items possible infolog pt-br Sim, com possibilidade de limpeza de registros removidos
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog pt-br Você pode selecionar uma categoria para ser pré-selecionada, quando você criar um novo registro.
|
||||
you can't delete one of the stock types !!! infolog pt-br Você não pode apagar um destes tipos!!!
|
||||
you have entered an invalid ending date infolog pt-br Você informou uma data final inválida
|
||||
you have entered an invalid starting date infolog pt-br Você informou uma data inícial inválida
|
||||
you have to enter a name, to create a new typ!!! infolog pt-br Você deve digitar um nome para criar um novo tipo!!!
|
||||
you must enter a subject or a description infolog pt-br Você deve digitar um assunto ou uma descrição
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog pt-br Sua base de dados NÃO está atualizada (%1 x %2), por favor execute %3setup%4 para atualizá-la.
|
371
infolog/lang/egw_ru.lang
Normal file
371
infolog/lang/egw_ru.lang
Normal file
@ -0,0 +1,371 @@
|
||||
%1 days in advance infolog ru %1 дней(я) до
|
||||
%1 deleted infolog ru %1 удален
|
||||
%1 deleted by %2 at %3 infolog ru %1 удален %2 в %3
|
||||
%1 modified infolog ru %1 изменен
|
||||
%1 modified by %2 at %3 infolog ru %1 изменен %2 в %3
|
||||
%1 records imported infolog ru %1 записей импортировано
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog ru %1 записей прочтено (но не импортировано, вы можете вернуться %2назад%3 и снять флаг с Тестировать Импорт)
|
||||
%1 you are responsible for is due at %2 infolog ru %1 за который вы отвечаете должен быть завершен в %2
|
||||
%1 you are responsible for is starting at %2 infolog ru %1 за который вы отвечаете должен начаться в %2
|
||||
%1 you delegated is due at %2 infolog ru %1 который вы назначили должен быть завершен в %2
|
||||
%1 you delegated is starting at %2 infolog ru %1 который вы назначили должен начаться в %2
|
||||
- subprojects from infolog ru - Подпроект из
|
||||
0% infolog ru 0%
|
||||
10% infolog ru 10%
|
||||
100% infolog ru 100%
|
||||
20% infolog ru 20%
|
||||
30% infolog ru 30%
|
||||
40% infolog ru 40%
|
||||
50% infolog ru 50%
|
||||
60% infolog ru 60%
|
||||
70% infolog ru 70%
|
||||
80% infolog ru 80%
|
||||
90% infolog ru 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog ru <b>вложение файлов через символические ссылки</b> вместо публикации и получение через file:/путь для подключенных непосредственно к локальной сети клиентов
|
||||
a short subject for the entry infolog ru короткая тема для записи
|
||||
abort without deleting infolog ru Прервать без удаления
|
||||
accept infolog ru принять
|
||||
action infolog ru Действие
|
||||
actual date and time infolog ru актуальные дата и время
|
||||
add infolog ru Добавить
|
||||
add a file infolog ru Добавить файл
|
||||
add a new entry infolog ru Добавить новую Запись
|
||||
add a new note infolog ru Добавить новую Заметку
|
||||
add a new phonecall infolog ru Добавить новый Телефонный Звонок
|
||||
add a new sub-task, -note, -call to this entry infolog ru Добавить новую подзадачу, -заметку, -звонок к этой записи
|
||||
add a new todo infolog ru Добавить новое Задание
|
||||
add file infolog ru Добавить файл
|
||||
add sub infolog ru Добавить Под...
|
||||
add timesheet entry infolog ru Добавить запись табеля учета времени
|
||||
add: infolog ru Добавить:
|
||||
all infolog ru Все
|
||||
all links and attachments infolog ru все ссылки и вложения
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog ru позволяет установить состояние записи, напр. установить Задание в состояние "выполнено" если оно окончено (значение зависит от типа записи)
|
||||
apply the changes infolog ru Применить изменения
|
||||
archive infolog ru Архив
|
||||
are you shure you want to delete this entry ? infolog ru Вы уверены, что хотите удалить эту запись ?
|
||||
attach a file infolog ru Прикрепить файл
|
||||
attach file infolog ru Прикрепить файл
|
||||
attention: no contact with address %1 found. infolog ru Внимание: Контакт с адресом %1 не найден
|
||||
back to main list infolog ru Назад к основному списку
|
||||
billed infolog ru оплачно
|
||||
both infolog ru оба
|
||||
call infolog ru звонок
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog ru Может быть использовано для показа будущих типов ИнфоЖурнала или для ограничения показываемого например только задачами.
|
||||
cancel infolog ru Отмена
|
||||
cancelled infolog ru отменено
|
||||
categories infolog ru Категории
|
||||
category infolog ru Категория
|
||||
change the status of an entry, eg. close it infolog ru Изменить состояние записи, например - закрыть ее.
|
||||
charset of file infolog ru Кодировка файла.
|
||||
check to set startday infolog ru отметить, чтобы установить дату начала
|
||||
check to specify custom contact infolog ru Отметить для указания пользовательского контакта
|
||||
click here to create the link infolog ru Нажмите здесь для создания Ссылки
|
||||
click here to start the search infolog ru Нажмите здесь для начала поиска
|
||||
close infolog ru Закрыть
|
||||
comment infolog ru Комментарий
|
||||
completed infolog ru Завершено
|
||||
configuration infolog ru Конфигурация
|
||||
confirm infolog ru Подтвердить
|
||||
contact infolog ru Контакт
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog ru Скопируйте изменения в буфер обмена, %1перезагрузите запись%2 и объедините их.
|
||||
create new links infolog ru Создать новые ссылки
|
||||
creates a new field infolog ru Создать новое поле
|
||||
creates a new status with the given values infolog ru создает новое состояние с данными значениями
|
||||
creates a new typ with the given name infolog ru создает новый тип с данным именем
|
||||
creation infolog ru Создание
|
||||
csv-fieldname infolog ru Имя поля CSV
|
||||
csv-filename infolog ru Имя файла CSV
|
||||
csv-import common ru Импорт CSV
|
||||
custom infolog ru Пользовательский
|
||||
custom contact-address, leave empty to use information from most recent link infolog ru Пользовательский адрес для контакта, оставьте незаполненным для использования информации из наиболее свежей ссылки
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog ru Пользовательская информация для контакта, оставьте незаполненным для использования информации из наиболее свежей ссылки
|
||||
custom fields infolog ru Пользовательские Поля
|
||||
custom fields, typ and status common ru Пользовательские поля, тип и состояние
|
||||
custom from infolog ru Пользовательский из (?)
|
||||
custom regarding infolog ru Пользовательский относительно (?)
|
||||
custom status for typ infolog ru Пользовательское состояние для типа
|
||||
customfields infolog ru Пользовательские поля
|
||||
date completed infolog ru Дата завершения
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog ru Дата завершения (оставьте незаполненным, если хотите чтобы она автоматически установилась если состояние будет "сделано" или "оплачено")
|
||||
datecreated infolog ru дата создания
|
||||
dates, status, access infolog ru Даты, Состояние, Доступ
|
||||
days infolog ru дни
|
||||
default category for new infolog entries infolog ru Категория по умолчанию для новых записей ИнфоЖурнала
|
||||
default filter for infolog infolog ru Фильтр по Умолчанию для ИнфоЖурнала
|
||||
default status for a new log entry infolog ru статус по умолчанию для новой записи журнала
|
||||
delegated infolog ru назначеные
|
||||
delegated open infolog ru открытые назначенные
|
||||
delegated overdue infolog ru просроченные назначенные
|
||||
delegated upcomming infolog ru назначенные приближающиеся
|
||||
delegation infolog ru Назначение
|
||||
delete infolog ru Удалить
|
||||
delete one record by passing its id. infolog ru Удалить одну запись по ее идентификатору
|
||||
delete the entry infolog ru Удалить запись
|
||||
delete this entry infolog ru Удалить эту запись
|
||||
delete this entry and all listed sub-entries infolog ru Удалить эту запись и все перечисленные под-записи
|
||||
deleted infolog ru удален
|
||||
deletes the selected typ infolog ru удаляет выбранный тип
|
||||
deletes this field infolog ru удаляет это поле
|
||||
deletes this status infolog ru удаляет это состояние
|
||||
description infolog ru Описание
|
||||
determines the order the fields are displayed infolog ru оперделяет порядок, в котором отображаются поля
|
||||
disables a status without deleting it infolog ru отключает состояние без удаления его
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog ru хотите ли Вы подтверждения принятия под ответственность на: принятие, завершение задания или на оба.
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog ru Вы желаете получать напоминания, при назначении вам заданий(записей) или при их изменении?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog ru Вы желаете получать напоминания при запуске задач(записей) за которые вы отвечаете?
|
||||
do you want a notification, if items you are responsible for are due? infolog ru Вы желаете получать напоминания, если задачи за которые вы отвечаете должны быть уже завершены?
|
||||
do you want a notification, if items you created get updated? infolog ru Вы желаете получать напоминания при изменении записей созданных вами?
|
||||
do you want a notification, if items you delegated are about to start? infolog ru Вы желаете получать напоминания при запуске задач(записей) которые вам назначены?
|
||||
do you want a notification, if items you delegated are due? infolog ru Вы желаете получать напоминания, если задачи которые вы назначили должны быть уже завершены?
|
||||
do you want to receive notifications as html-mails or plain text? infolog ru Вы желаете получать напоминания в виде HTML или обычного текста?
|
||||
don't show infolog infolog ru НЕ показывать ИнфоЖурнал
|
||||
done infolog ru сделано
|
||||
download infolog ru Получить
|
||||
duration infolog ru Продолжительность
|
||||
each value is a line like <id>[=<label>] infolog ru каждое значение - это строка вида <идентификатор>[=<метка>]
|
||||
edit infolog ru Редактировать
|
||||
edit or create categories for ingolog infolog ru Редактировать или созадть категории для ИнфоЖурнала
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog ru редактировать права (полное редактирование прав, вкл. назначение кого-то еще ответственным!)
|
||||
edit status infolog ru Редактировать состояние
|
||||
edit the entry infolog ru Редактировать запись
|
||||
edit this entry infolog ru Редактировать эту запись
|
||||
empty for all infolog ru пусто для всех
|
||||
enddate infolog ru До даты
|
||||
enddate can not be before startdate infolog ru До даты не может быть раньше даты начала
|
||||
enter a custom contact, leave empty if linked entry should be used infolog ru введите пользовательский контакт, оставьте незаполненным, если должна использоваться связанная запись
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog ru введите пользовательский телефон/электронный адрес, оставьте незаполненным, если должна использоваться связанная запись
|
||||
enter a textual description of the log-entry infolog ru введите текстовое описание для записи журнала
|
||||
enter the query pattern infolog ru Введите шаблон вопроса
|
||||
entry and all files infolog ru Запись и все файлы
|
||||
error: saving the entry infolog ru Ошибка: сохраниние записи
|
||||
error: the entry has been updated since you opened it for editing! infolog ru Ошибака: запись была обновлена с тех пор, как Вы открыли её для редактирования!
|
||||
existing links infolog ru Существующие ссылки
|
||||
fax infolog ru Факс
|
||||
field must not be empty !!! infolog ru Поле должно быть заполнено !!!
|
||||
fieldseparator infolog ru Разделитель полей
|
||||
finish infolog ru окончание
|
||||
for which types should this field be used infolog ru для каких типов это поле должно быть использовано
|
||||
from infolog ru Из
|
||||
general infolog ru Общий
|
||||
group owner for infolog ru Группа-владелец для
|
||||
high infolog ru высокий
|
||||
history logging infolog ru Запись истории
|
||||
history logging and deleting of items infolog ru Журналирование истории и удаление записей
|
||||
id infolog ru Ид
|
||||
id# infolog ru Ид№
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog ru Если тип имеет группу-владельца, все записи этого типа будут иметь владельцем данную группу, а НЕ пользователя, который их создал!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog ru Если не установлено, строка с поиском и фильтрами скрыта для количества записей меньшего, чем "макс. совпадений на страницу" (как определено в ваших общих настройках)
|
||||
import infolog ru Импорт
|
||||
import next set infolog ru Импортировать следующий набор
|
||||
info log common ru ИнфоЖурнал
|
||||
infolog common ru ИнфоЖурнал
|
||||
infolog - delete infolog ru ИнфоЖурнал - Удаление
|
||||
infolog - edit infolog ru ИнфоЖурнал - Редактирование
|
||||
infolog - import csv-file infolog ru ИнфоЖурнал - импорт файла CSV
|
||||
infolog - new infolog ru ИнфоЖурнал - Новый
|
||||
infolog - new subproject infolog ru ИнфоЖурнал - Новый Подпроект
|
||||
infolog - subprojects from infolog ru ИнфоЖурнал - Подпроект из
|
||||
infolog entry deleted infolog ru Запись ИнфоЖурнала удалена
|
||||
infolog entry saved infolog ru Запись ИнфоЖурнала сохранена
|
||||
infolog filter for the main screen infolog ru Фильтр ИнфоЖурнала для основного экрана
|
||||
infolog list infolog ru Список ИнфоЖурнала
|
||||
infolog preferences common ru Настройки ИнфоЖурнала
|
||||
infolog-fieldname infolog ru Название поля ИнфоЖурнала
|
||||
invalid filename infolog ru Неправильное имя файла
|
||||
label<br>helptext infolog ru Метка<br>Текст помощи
|
||||
last changed infolog ru Последние изменения
|
||||
last modified infolog ru Последние изменения
|
||||
leave it empty infolog ru оставьте это незаполненным
|
||||
leave without saveing the entry infolog ru выйти без сохранения записи
|
||||
leaves without saveing infolog ru выйти без сохранения
|
||||
length<br>rows infolog ru Длина<br>Строк
|
||||
link infolog ru Ссылка
|
||||
links infolog ru Ссылки
|
||||
links of this entry infolog ru Ссылки этой записи
|
||||
list all categories infolog ru Список всех категорий
|
||||
list no subs/childs infolog ru Не пролистывать Подчиненные/Порожденные
|
||||
location infolog ru Местоположение
|
||||
longer textual description infolog ru более полное текстовое описание
|
||||
low infolog ru низкий
|
||||
max length of the input [, length of the inputfield (optional)] infolog ru максимальная длина ввода [, длина поля ввода (необязательно)]
|
||||
modifierer infolog ru Кто изменил
|
||||
name must not be empty !!! infolog ru Имя не должно быть пустым !!!
|
||||
name of new type to create infolog ru имя вновь создаваемого типа
|
||||
never hide search and filters infolog ru никогда не скрывать поиск и фильтры
|
||||
new %1 infolog ru Новый %1
|
||||
new %1 created by %2 at %3 infolog ru Новый %1 содан %2 в %3
|
||||
new name infolog ru новое имя
|
||||
new search infolog ru Новый поиск
|
||||
no - cancel infolog ru Нет - Отменить
|
||||
no describtion, links or attachments infolog ru без описания, ссылок или вложений
|
||||
no details infolog ru без подробностей
|
||||
no entries found, try again ... infolog ru не найдены записи, попробуйте снова
|
||||
no filter infolog ru без Фильтра
|
||||
no links or attachments infolog ru без ссылок или приложений
|
||||
nonactive infolog ru неактивен
|
||||
none infolog ru Ничего
|
||||
normal infolog ru нормальный
|
||||
not infolog ru нет
|
||||
not assigned infolog ru не назначено
|
||||
not-started infolog ru не начато
|
||||
note infolog ru Заметка
|
||||
number of records to read (%1) infolog ru количество записей к чтению (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog ru количество строк в многострочном поле ввода или списке с множественным выбором
|
||||
offer infolog ru предложено
|
||||
one day after infolog ru через один день
|
||||
one day in advance infolog ru за один день до
|
||||
ongoing infolog ru в работе
|
||||
only for details infolog ru Только для подробностей
|
||||
only if i get assigned or removed infolog ru Только если Я присоединен или отсоединен
|
||||
only the attachments infolog ru только вложения
|
||||
only the links infolog ru только ссылки
|
||||
open infolog ru открытые
|
||||
optional note to the link infolog ru необязательная заметка к Ссылке
|
||||
order infolog ru Порядок
|
||||
overdue infolog ru просроченные
|
||||
own infolog ru свои
|
||||
own open infolog ru свои открытые
|
||||
own overdue infolog ru свои просроченные
|
||||
own upcoming infolog ru свои ожидаемые
|
||||
parent infolog ru Родитель
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog ru путь на (веб-)сервере<br>напр. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog ru Путь к файлам пользователя или группы должен быть ВНЕ корневого каталога для документов веб-сервера!!!
|
||||
pattern for search in addressbook infolog ru шаблон поиска в Адресной книге
|
||||
pattern for search in projects infolog ru шаблон для поиска в Проектах
|
||||
percent completed infolog ru Завершено процентов
|
||||
permission denied infolog ru Доступ запрещен
|
||||
phone infolog ru Телефонный Звонок
|
||||
phone/email infolog ru Телефон/E-mail
|
||||
phonecall infolog ru Телефонный Звонок
|
||||
planned infolog ru запланировано
|
||||
planned time infolog ru запланированное время
|
||||
price infolog ru Цена
|
||||
pricelist infolog ru Прайслист
|
||||
primary link infolog ru первичная ссылка
|
||||
priority infolog ru Приоритет
|
||||
private infolog ru Личный
|
||||
project infolog ru Проект
|
||||
project settings: price, times infolog ru Установки проекта: цена, времена
|
||||
re: infolog ru Re:
|
||||
read one record by passing its id. infolog ru Прочитать одну запись указанием её идентификатора
|
||||
read rights (default) infolog ru права на чтение (по умолчанию)
|
||||
receive notifications about due entries you are responsible for infolog ru Получать напоминания о необходимости завершения работ за которые вы отвечаете
|
||||
receive notifications about due entries you delegated infolog ru Получать напоминания о необходимости завершения работ которые вы назначили
|
||||
receive notifications about items assigned to you infolog ru Получать сообщения о записях соединенных с вами
|
||||
receive notifications about own items infolog ru Получать сообщения о своих записях
|
||||
receive notifications about starting entries you are responsible for infolog ru Получать сообщения о запуске записей за которые вы отвечаете
|
||||
receive notifications about starting entries you delegated infolog ru Получать сообщения о запуске записей которые вам назначены
|
||||
receive notifications as html-mails infolog ru Получать сообщения в виде HTML-писем
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog ru рег. выр. для локальных IP<br>напр. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog ru рег. выр. для локальных IP<br>напр. ^192\.168\.1\.
|
||||
remark infolog ru Примечание
|
||||
remove this link (not the entry itself) infolog ru Удалить эту ссылку (не саму запись)
|
||||
responsible infolog ru Ответственный
|
||||
responsible open infolog ru ответственного открытые
|
||||
responsible overdue infolog ru ответственного просроченные
|
||||
responsible upcoming infolog ru ответственного ожидаемые
|
||||
responsible user, priority infolog ru ответственный пользователь, приоритет
|
||||
returns a list / search for records. infolog ru Возврщает список / поиск для записей.
|
||||
rights for the responsible infolog ru Права для ответственного
|
||||
same day infolog ru этот же день
|
||||
save infolog ru Сохранить
|
||||
saves the changes made and leaves infolog ru сохраняет сделанные изменения и выходит
|
||||
saves this entry infolog ru Сохраняет эту запись
|
||||
search infolog ru Поиск
|
||||
search for: infolog ru Искать:
|
||||
select infolog ru Выбрать
|
||||
select a category for this entry infolog ru выбрать категорию для этой записи
|
||||
select a price infolog ru Выбрать цену
|
||||
select a priority for this task infolog ru выбрать приоритет для этой задачи
|
||||
select a project infolog ru Выбрать проект
|
||||
select a responsible user: a person you want to delegate this task infolog ru выбрать ответственного пользователя: человека, которому вы хотите поручить эту задачу
|
||||
select a typ to edit it's status-values or delete it infolog ru выбрать тип для редактирования значения статуса или удалить
|
||||
select an app to search in infolog ru Выбрать Приложение, в котором надо искать
|
||||
select an entry to link with infolog ru Выбрать запись, с которой нужна связь
|
||||
select to filter by owner infolog ru выбрать для фильтрации по владельцу
|
||||
select to filter by responsible infolog ru выбрать для фильтрации по ответственному
|
||||
sets the status of this entry and its subs to done infolog ru Устанавливает состояние этой записи и ей подчиненных в "сделано"
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog ru Должен ли ИнфоЖурнал показывает подзадания, -звонки или -заметки в нормальном виде или нет. Вы всегда можете посмотреть подэлементы через их родителей.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog ru Должен ли ИнфоЖурнал показывать ссылки на другие приложения и/или прикрепленные файлы в списке ИнфоЖурнала (нормальный вид при входе в ИнфоЖурнал)
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog ru Должен ли ИнфоЖурнал отображаться на основной странице и с каким фильтром. Работает только если Вы не выбрали приложение для основной страницы (в Ваших настройках).
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog ru Должен ли ИнфоЖурнал использовать полные имена (имя и фамилия) или только имена для входа
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog ru Должен ли список ИнфоЖурнала показывать уникальные числовые идентификаторы, которые могут быть использованы, например, как идентификаторы талонов
|
||||
should the infolog list show the column "last modified". infolog ru Должен ли список ИнфоЖурнала показывать колонку "последнее изменение"
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog ru Должен ли список ИнфоЖурнала показывать процент выполнения только статуса в работе или две разных пиктограммы.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog ru должна ли эта запись быть видима только для вас и тех, кому вы дали личный доступ через ACL
|
||||
show a column for used and planned times in the list. infolog ru Показывать колонку для использованного и запланированого времени в списке.
|
||||
show full usernames infolog ru Показывать полные имена пользователей
|
||||
show in the infolog list infolog ru Показывать в списке ИнфоЖурнала
|
||||
show last modified infolog ru Показывать последнее изменение
|
||||
show status and percent done separate infolog ru Показывать состояние и процент выполнения отдельно
|
||||
show ticket id infolog ru Показывать идентификатор талона
|
||||
show times infolog ru Показывать количество раз (времена?)
|
||||
small view infolog ru мелкий вид
|
||||
start a new search, cancel this link infolog ru начать новый поиск, отменить эту ссылку
|
||||
startdate infolog ru Дата Начала
|
||||
startdate enddate infolog ru Дата Начала До Даты
|
||||
startdate for new entries infolog ru Дата начала для новых записей
|
||||
startrecord infolog ru Начальная запись
|
||||
status infolog ru Состояние
|
||||
status ... infolog ru Состояние ...
|
||||
sub infolog ru Под
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog ru Под-записи становятся подзаписями родительских или главных записей если нет родителей
|
||||
subject infolog ru Предмет
|
||||
sum infolog ru Сумма
|
||||
task infolog ru Задание
|
||||
template infolog ru Шаблон
|
||||
test import (show importable records <u>only</u> in browser) infolog ru Тест Импорта (показывает импортируемые записи <u>только</u> в браузере)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog ru имя, используется внутри (<=10 символов), его изменение делает существующие данные недоступными
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog ru имя, используется внутри (<=20 символов), его изменение делает существующие данные недоступными
|
||||
the text displayed to the user infolog ru текст, показываемый пользователю
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog ru Это фильтр, который ИнфоЖурнал использует, когда вы входите в приложение. Фильтры ограничивают записи, которые надо показать, в текущем режиме показа. Есть фильтры для показа только завершенных, открытых или будущих записей - ваших или всех пользователей.
|
||||
til when should the todo or phonecall be finished infolog ru до того как Задание или Звонок будет завершено
|
||||
times infolog ru Количество раз (времена?)
|
||||
to many might exceed your execution-time-limit infolog ru слишком много превысит ваше ограничение на время исполнения
|
||||
to what should the startdate of new entries be set. infolog ru Как должна устанавливаться дата начала новой записи.
|
||||
today infolog ru Сегодня
|
||||
todays date infolog ru сегодняшняя дата
|
||||
todo infolog ru Задание
|
||||
translation infolog ru Перевод
|
||||
typ infolog ru Тип
|
||||
typ '%1' already exists !!! infolog ru Тип '%1' уже существует !!!
|
||||
type infolog ru Тип
|
||||
type ... infolog ru Тип ...
|
||||
type of customfield infolog ru Тип пользовательского поля
|
||||
type of the log-entry: note, phonecall or todo infolog ru Тип записи: Заметка, Телефонный звонок или Задание
|
||||
unlink infolog ru Расцепить ссылку
|
||||
upcoming infolog ru приход
|
||||
urgency infolog ru срочность
|
||||
urgent infolog ru срочное
|
||||
used time infolog ru использованное время
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog ru действительный путь на стороне клиента.<br>напр. \\Server\Share или e:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog ru действительный путь на стороне клиента.<br>напр. \\Server\Share или e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog ru действительный путь на стороне клиента.<br>напр. \\Server\Share или e:\
|
||||
values for selectbox infolog ru Значения для списка выбора
|
||||
view all subs of this entry infolog ru Смотреть все подзаписи этой записи
|
||||
view other subs infolog ru смотреть другие подзаписи
|
||||
view parent infolog ru смотреть родительскую запись
|
||||
view subs infolog ru смотреть Подзаписи
|
||||
view the parent of this entry and all his subs infolog ru Показать родительскую запись данной записи и всех подзаписей
|
||||
view this linked entry in its application infolog ru показать данную запись в ее приложении
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog ru когда Задание или Телефонный Звонок должны начаться, они показываются с этой даты при открытии фильтра или просто открытии (стартовая страница) (?..)
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog ru Какие дополнительные поля должен мочь редактировать ответственный, не имея прав на редактирование?<br/>Состояние, процент и дата завершения уже разрешены.
|
||||
which implicit acl rights should the responsible get? infolog ru Какие подразумеваемые права ACL должен получить ответственный?
|
||||
which types should the calendar show infolog ru Какие типы календарь должен показывать
|
||||
whole query infolog ru весь запрос
|
||||
will-call infolog ru позвонит
|
||||
write (add or update) a record by passing its fields. infolog ru Запишите (добавьте или обновите) запись прохождением её полей.
|
||||
yes - delete infolog ru Да - Удалить
|
||||
yes - delete including sub-entries infolog ru Да - Удалить включая подзаписи
|
||||
yes, noone can purge deleted items infolog ru Да, никто не может уничтожить удаленые записи
|
||||
yes, only admins can purge deleted items infolog ru Да, только администраторы могут уничтожить удаленые записи
|
||||
yes, with larger fontsize infolog ru Да, с бо`льшим размером шрифта
|
||||
yes, with purging of deleted items possible infolog ru Да, с возможностью уничтожения удаленых записей
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog ru Вы можете выбратькатегорию, которая будет выбрана заранее при создании новой записи ИнфоЖурнала
|
||||
you can't delete one of the stock types !!! infolog ru Вы не можете удалить один из основных типов!!!
|
||||
you have entered an invalid ending date infolog ru Вы ввели неверную дату окончания
|
||||
you have entered an invalid starting date infolog ru Вы ввели неверную дату начала
|
||||
you have to enter a name, to create a new typ!!! infolog ru Вы должны ввести имя, чтобы создать новый тип!!!
|
||||
you must enter a subject or a description infolog ru Вы должны ввести тему или описание
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog ru Ваша база данных устарела (%1 вместо %2),запустите %3установка%4 для обновления вашей базы данныхх.
|
404
infolog/lang/egw_sk.lang
Normal file
404
infolog/lang/egw_sk.lang
Normal file
@ -0,0 +1,404 @@
|
||||
%1 days in advance infolog sk %1 dní v predstihu
|
||||
%1 deleted infolog sk %1 - odstránená
|
||||
%1 deleted by %2 at %3 infolog sk %1 - odstránil/a: %2 %3
|
||||
%1 modified infolog sk %1 - zmena
|
||||
%1 modified by %2 at %3 infolog sk %1 - zmenu vykonal/a: %2 %3
|
||||
%1 records imported infolog sk Naimportovaných bolo %1 záznamov
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog sk Načítaných bolo %1 záznamov (zatiaľ nenaimportované, môžete ísť %2späť%3 a odznačiť Test importu)
|
||||
%1 you are responsible for is due at %2 infolog sk %1 - ste zodpovední, termín je %2
|
||||
%1 you are responsible for is starting at %2 infolog sk %1 - ste zodpovední, začína sa %2
|
||||
%1 you delegated is due at %2 infolog sk %1 - delegovali ste, termín je %2
|
||||
%1 you delegated is starting at %2 infolog sk %1 - delegovali ste, začína sa %2
|
||||
- subprojects from infolog sk - Podprojekty od (z)
|
||||
0% infolog sk 0%
|
||||
10% infolog sk 10%
|
||||
100% infolog sk 100%
|
||||
20% infolog sk 20%
|
||||
30% infolog sk 30%
|
||||
40% infolog sk 40%
|
||||
50% infolog sk 50%
|
||||
60% infolog sk 60%
|
||||
70% infolog sk 70%
|
||||
80% infolog sk 80%
|
||||
90% infolog sk 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog sk <b>súborové prílohy pomocou symbolických odkazov</b> namiesto nahrávania a sťahovania pomocou file:/cesta pre priamych klientov LAN
|
||||
a short subject for the entry infolog sk Krátky predmet záznamu
|
||||
abort without deleting infolog sk Zrušiť bez odstránenia
|
||||
accept infolog sk Prijať
|
||||
action infolog sk Akcia
|
||||
actions... infolog sk Akcie...
|
||||
actual date and time infolog sk Aktuálny dátum a čas
|
||||
add infolog sk Pridať
|
||||
add a file infolog sk Pridať súbor
|
||||
add a new entry infolog sk Pridať nový Záznam
|
||||
add a new note infolog sk Pridať novú Poznámku
|
||||
add a new phonecall infolog sk Pridať nový Telefonát
|
||||
add a new sub-task, -note, -call to this entry infolog sk Pridať novú pod-úlohu, -poznámku, -hovor k tomuto záznamu
|
||||
add a new todo infolog sk Pridať novú Úlohu
|
||||
add file infolog sk Pridať súbor
|
||||
add sub infolog sk Pridať Podradený záznam
|
||||
add timesheet entry infolog sk Pridať záznam do Harmonogramu
|
||||
add: infolog sk Pridať:
|
||||
all infolog sk Všetko
|
||||
all links and attachments infolog sk Všetky odkazy a prílohy
|
||||
all projects infolog sk Všetky projekty
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog sk umožňuje nastaviť stav záznamu, napr. nastaviť Úlohu ktorá sa má vykonať po ukončení (hodnoty závisia na type záznamu)
|
||||
alternatives infolog sk Alternatívy
|
||||
apply the changes infolog sk Uplatniť zmeny
|
||||
archive infolog sk Archív
|
||||
are you shure you want to close this entry ? infolog sk Naozaj chcete uzavrieť tento záznam?
|
||||
are you shure you want to delete this entry ? infolog sk Naozaj chcete odstrániť tento záznam?
|
||||
attach a file infolog sk Priložiť súbor
|
||||
attach file infolog sk Priložiť súbor
|
||||
attention: no contact with address %1 found. infolog sk Upozornenie: Kontakt s adresou %1 sa nenašiel.
|
||||
back to main list infolog sk Naspäť na hlavný zoznam
|
||||
billed infolog sk Vyúčtované
|
||||
both infolog sk Obidvoje
|
||||
call infolog sk Volať
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog sk Dá sa použiť na zobrazenie ďalších typov Záznamníka v Kalendári, alebo obmedziť zobrazovanie napr. len na úlohy.
|
||||
cancel infolog sk Zrušiť
|
||||
cancelled infolog sk Zrušené
|
||||
categories infolog sk Kategórie
|
||||
category infolog sk Kategória
|
||||
change history infolog sk Zmeniť históriu
|
||||
change the status of an entry, eg. close it infolog sk Zmeniť stav záznamu, napr. uzavrieť ho
|
||||
charset of file infolog sk Znaková sada súboru
|
||||
check to set startday infolog sk Ak chcete zadať dátum začiatku, označte to
|
||||
check to specify custom contact infolog sk Ak chcete uviesť používateľsky definovaný kontakt, označte to
|
||||
click here to create the link infolog sk Ak chcete vytvoriť odkaz, kliknite sem
|
||||
click here to start the search infolog sk Ak chcete začať hľadanie, kliknite sem
|
||||
close infolog sk Zavrieť
|
||||
close all infolog sk Zavrieť všetko
|
||||
close this entry and all listed sub-entries infolog sk Zavrieť tento záznam a všetky uvedené podzáznamy
|
||||
comment infolog sk Poznámka
|
||||
completed infolog sk Stav vybavenia
|
||||
configuration infolog sk Konfigurácia
|
||||
confirm infolog sk Potvrdiť
|
||||
contact infolog sk Kontakt
|
||||
copy of: infolog sk Kópia z:
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog sk Skopírujte zmeny do schránky, %1znovunačítajte záznam%2 a zlúčte ich.
|
||||
create new links infolog sk Vytvoriť nové odkazy
|
||||
creates a new field infolog sk vytvorí nové pole
|
||||
creates a new status with the given values infolog sk Vytvorí nový stav so zadanými hodnotami
|
||||
creates a new typ with the given name infolog sk Vytvorí nový typ podľa zadaného mena
|
||||
creation infolog sk Poradové číslo
|
||||
csv-fieldname infolog sk CSV-názov položky
|
||||
csv-filename infolog sk CSV-názov súboru
|
||||
csv-import common sk CSV-Import
|
||||
custom infolog sk Používateľom definované
|
||||
custom contact-address, leave empty to use information from most recent link infolog sk Používateľom definovaná kontaktná adresa - ak necháte prázdne, použije sa údaj z najčerstvejšieho odkazu
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog sk Používateľom definované kontaktné informácie - ak necháte prázdne, použije sa údaj z najčerstvejšieho odkazu
|
||||
custom fields infolog sk Používateľské polia
|
||||
custom fields, typ and status common sk Používateľské polia, typ a stav
|
||||
custom from infolog sk Používateľom definované od
|
||||
custom regarding infolog sk Používateľom definované ohľadom
|
||||
custom status for typ infolog sk Používateľom definovaný stav pre typ
|
||||
customfields infolog sk Používateľské polia
|
||||
date completed infolog sk Dátum dokončenia
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog sk Dátum dokončenia (ak ponecháte prázdne, vyplní sa automaticky podľa toho, kedy bol nastavený stav "hotovo", alebo kedy prebehlo vyúčtovanie).
|
||||
datecreated infolog sk Dátum vytvorenia
|
||||
dates, status, access infolog sk Dátum, Stav, Prístup
|
||||
days infolog sk dní
|
||||
default category for new infolog entries infolog sk Predvolená kategória pre nové záznamy Záznamníka
|
||||
default filter for infolog infolog sk Predvolený filter pre Záznamník
|
||||
default status for a new log entry infolog sk Predvolený stav pre nový záznam
|
||||
delegated infolog sk Delegované
|
||||
delegated open infolog sk Delegované - otvorené
|
||||
delegated open and upcoming infolog sk Delegované - otvorené a blížiace sa
|
||||
delegated overdue infolog sk Delegované - meškajúce
|
||||
delegated upcomming infolog sk Delegované - blížiace sa
|
||||
delegation infolog sk Delegovať
|
||||
delete infolog sk Odstrániť
|
||||
delete one record by passing its id. infolog sk Odstrániť konkrétny záznam podľa zadaného ID.
|
||||
delete the entry infolog sk Odstrániť záznam
|
||||
delete this entry infolog sk Odstrániť tento záznam
|
||||
delete this entry and all listed sub-entries infolog sk Odstrániť tento záznam a všetky zobrazené podzáznamy
|
||||
deleted infolog sk Odstránené
|
||||
deletes the selected typ infolog sk Odstráni vybraný typ
|
||||
deletes this field infolog sk odstráni toto pole
|
||||
deletes this status infolog sk odstráni tento stav
|
||||
description infolog sk Popis
|
||||
determines the order the fields are displayed infolog sk Určuje poradie, v akom sa polia zobrazujú
|
||||
disables a status without deleting it infolog sk Zablokuje stav bez toho, aby sa odstránil
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog sk Budete vyžadovať potvrdenie zodpovedného k týmto akciám?: prijatiu, ukončeniu úlohy, alebo obidvom
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog sk Chcete dostať pripomienku, keď nastanú zmeny v položkách, ktoré sú vám priradené?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog sk Chcete dostať pripomienku, keď sa majú začať položky, za ktoré ste zodpovední?
|
||||
do you want a notification, if items you are responsible for are due? infolog sk Chcete dostať pripomienku, keď nastane termín splnenia tých položiek, za ktoré ste zodpovední?
|
||||
do you want a notification, if items you created get updated? infolog sk Chcete dostať pripomienku, keď nastanú zmeny v položkách, ktoré ste vytvorili?
|
||||
do you want a notification, if items you delegated are about to start? infolog sk Chcete dostať pripomienku, keď sa majú začať položky, ktoré ste delegovali?
|
||||
do you want a notification, if items you delegated are due? infolog sk Chcete dostať pripomienku, keď nastane termín splnenia tých položiek, ktoré ste delegovali?
|
||||
do you want to receive notifications as html-mails or plain text? infolog sk E-mailové pripomienky chcete dostávať ako HTML, alebo ako čistý text?
|
||||
don't show infolog infolog sk NEzobrazovať Záznamník
|
||||
done infolog sk Hotovo
|
||||
download infolog sk Stiahnuť
|
||||
due %1 infolog sk Termín %1
|
||||
duration infolog sk Trvanie
|
||||
e-mail: infolog sk E-mail:
|
||||
each value is a line like <id>[=<label>] infolog sk každá hodnota je riadok v tvare <id>[=<label>]
|
||||
edit infolog sk Upraviť
|
||||
edit or create categories for ingolog infolog sk Upraviť alebo vytvoriť kategórie pre Záznamník
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog sk Plné práva úprav (vrátane nastavenia niekoho iného za zodpovednú osobu!)
|
||||
edit status infolog sk Upraviť stav
|
||||
edit the entry infolog sk Upraviť záznam
|
||||
edit this entry infolog sk Uprav tento záznam
|
||||
empty for all infolog sk Prázdne znamená všetko
|
||||
enddate infolog sk Termín splnenia
|
||||
enddate can not be before startdate infolog sk Termín splnenia nemôže byť pred dátumom začatia
|
||||
enter a custom contact, leave empty if linked entry should be used infolog sk Zadajte používateľsky definovaný kontakt, alebo ponechajte prázdne ak sa má použiť záznam pripojený odkazom
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog sk zadajte používateľsky definovaný telefón/E-mail, alebo ponechajte prázdne ak sa má použiť záznam pripojený odkazom
|
||||
enter a textual description of the log-entry infolog sk Zadajte text popisujúci tento záznam
|
||||
enter the query pattern infolog sk Zadajte výraz pre vyhľadávanie
|
||||
entry and all files infolog sk Záznam a všetky súbory
|
||||
error: saving the entry infolog sk Chyba pri ukladaní záznamu
|
||||
error: the entry has been updated since you opened it for editing! infolog sk Chyba: odkedy ste záznam otvorili pre úpravy, bol medzitým aktualizovaný!
|
||||
existing links infolog sk Existujúce odkazy
|
||||
fax infolog sk Fax
|
||||
field must not be empty !!! infolog sk Pole nesmie byť prázdne!!!
|
||||
fieldseparator infolog sk Oddeľovač polí
|
||||
finish infolog sk Koniec
|
||||
for which types should this field be used infolog sk Pre ktoré typy sa má použiť toto pole
|
||||
from infolog sk Od
|
||||
general infolog sk Hlavné
|
||||
global categories infolog sk Globálne kategórie
|
||||
group owner for infolog sk Skupinový vlastník pre
|
||||
high infolog sk Vysoká
|
||||
history infolog sk História
|
||||
history logging infolog sk Zaznamenávanie histórie
|
||||
history logging and deleting of items infolog sk Zaznamenávať históriu a odstránené položky?
|
||||
how many describtion lines should be directly visible. further lines are available via a scrollbar. infolog sk Koľko riadkov z popisu má byť priamo viditeľných? Ďalšie riadky budú dostupné cez posuvník.
|
||||
id infolog sk ID
|
||||
id# infolog sk ID#
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog sk Ak tento typ MÁ skupinového vlastníka, všetky záznamy tohto typu bude vlastniť zadaná skupina a NIE používateľ, ktorý záznam vytvoril!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog sk Ak nie je nastavené, riadok vyhľadávania a filtrov je skrytý pre menej záznamov než "maximálny počet záznamov zobrazených na stránke" (ako je definované v bežných nastaveniach).
|
||||
import infolog sk Import
|
||||
import next set infolog sk Importovať ďalšiu sadu
|
||||
importance infolog sk Dôležitosť
|
||||
info log common sk Záznamník
|
||||
infolog common sk Záznamník
|
||||
infolog - delete infolog sk Záznamník - Odstrániť
|
||||
infolog - edit infolog sk Záznamník - Upraviť
|
||||
infolog - import csv-file infolog sk Záznamník - Importovať súbor CSV
|
||||
infolog - new infolog sk Záznamník - Nové
|
||||
infolog - new subproject infolog sk Záznamník - Nový podprojekt
|
||||
infolog - subprojects from infolog sk Záznamník - Podprojekty od
|
||||
infolog copied - the copy can now be edited infolog sk Záznamník skopírovaný - kópia sa už môže upravovať
|
||||
infolog entry deleted infolog sk Záznam bol odstránený
|
||||
infolog entry saved infolog sk Záznam bol uložený
|
||||
infolog filter for the main screen infolog sk Filter Záznamníka pre hlavnú stránku
|
||||
infolog list infolog sk Záznamník - Zoznam
|
||||
infolog preferences common sk Predvoľby Záznamníka
|
||||
infolog-fieldname infolog sk Záznamník - Názov poľa
|
||||
invalid filename infolog sk Chybný názov súboru
|
||||
label<br>helptext infolog sk Označenie<br>Pomocný text
|
||||
last changed infolog sk Naposledy zmenené
|
||||
last modified infolog sk Naposledy upravil
|
||||
leave blank to get the used time calculated by timesheet entries infolog sk Ak chcete, aby bol čas spočítaný na základe záznamov Harmonogramu, tak ponechajte prázdne.
|
||||
leave it empty infolog sk Ponechať prázdne
|
||||
leave without saveing the entry infolog sk Odísť bez uloženia záznamu
|
||||
leaves without saveing infolog sk Odísť bez uloženia
|
||||
length<br>rows infolog sk Dĺžka<br>Riadky
|
||||
limit number of description lines (default 5, 0 for no limit) infolog sk Obmedziť počet riadkov opisu (0 znamená bez limitu; predvolené: 5)
|
||||
link infolog sk Odkaz
|
||||
links infolog sk Odkazy
|
||||
links of this entry infolog sk Odkazy pre tento záznam
|
||||
list all categories infolog sk Zobraziť všetky kategórie
|
||||
list no subs/childs infolog sk Neukazuj Podradené / Dcérske
|
||||
location infolog sk Umiestnenie
|
||||
longer textual description infolog sk Dlhší opisný text
|
||||
low infolog sk Nízka
|
||||
max length of the input [, length of the inputfield (optional)] infolog sk maximálna dĺžka vstupu [, dĺžka vstupného poľa (voliteľné)]
|
||||
name must not be empty !!! infolog sk Názov nemôže byť prázdny!
|
||||
name of new type to create infolog sk Názov novovytvoreného typu
|
||||
never hide search and filters infolog sk Neschovávať hľadanie a filtre
|
||||
new %1 infolog sk Nové: %1
|
||||
new %1 created by %2 at %3 infolog sk Nové: %1, vytvoril %2 %3
|
||||
new name infolog sk Nový názov
|
||||
new search infolog sk Nové hľadanie
|
||||
no - cancel infolog sk Nie - Zrušiť
|
||||
no describtion, links or attachments infolog sk Žiadny popis, odkaz ani príloha
|
||||
no details infolog sk Žiadne podrobnosti
|
||||
no entries found, try again ... infolog sk Nenašiel som také záznamy, skúste znovu...
|
||||
no filter infolog sk Žiadny filter
|
||||
no links or attachments infolog sk Žiadne odkazy alebo prílohy
|
||||
no project infolog sk Žiadny projekt
|
||||
nonactive infolog sk Neaktívne
|
||||
none infolog sk Žiadne
|
||||
normal infolog sk Normálna
|
||||
not infolog sk Nie
|
||||
not assigned infolog sk Nepridelené
|
||||
not-started infolog sk Ešte nezačaté
|
||||
note infolog sk Poznámka
|
||||
number of records to read (%1) infolog sk Počet záznamov, ktoré sa majú načítať (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog sk číslo riadku pre viacriadkové vstupné pole alebo riadok vo výberovom okne
|
||||
offer infolog sk Ponuka
|
||||
one day after infolog sk Deň po
|
||||
one day in advance infolog sk 1 deň v predstihu
|
||||
ongoing infolog sk Prebiehajúce
|
||||
only for details infolog sk Len pre podrobnosti
|
||||
only if i get assigned or removed infolog sk Iba ak mi je to priradené alebo odobraté
|
||||
only the attachments infolog sk Iba prílohy
|
||||
only the links infolog sk Iba odkazy
|
||||
open infolog sk Otvorené
|
||||
open and upcoming infolog sk Otvorené a blížiace sa
|
||||
optional note to the link infolog sk Voliteľná poznámka k odkazu
|
||||
order infolog sk Triedenie
|
||||
organization infolog sk Organizácia
|
||||
overdue infolog sk Meškajúce
|
||||
own infolog sk Vlastné
|
||||
own open infolog sk Vlastné - otvorené
|
||||
own open and upcoming infolog sk Vlastné - otvorené a blížiace sa
|
||||
own overdue infolog sk Vlastné - meškajúce
|
||||
own upcoming infolog sk Vlastné - blížiace sa
|
||||
parent infolog sk Rodič
|
||||
parent infolog infolog sk Rodičovský Záznamník
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog sk cesta na strane (web-)servera <br>napr. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog sk Cesta k súborom používateľa a skupiny MUSÍ BYŤ MIMO document-root webservera!
|
||||
pattern for search in addressbook infolog sk Výraz pre hľadanie v Adresári
|
||||
pattern for search in projects infolog sk Výraz pre hľadanie v Projektoch
|
||||
percent completed infolog sk Na koľko percent vyriešené
|
||||
permission denied infolog sk Prístup bol odmietnutý
|
||||
phone infolog sk Telefonát
|
||||
phone/email infolog sk Telefón / E-mail
|
||||
phonecall infolog sk Telefonát
|
||||
planned infolog sk Plánované
|
||||
planned time infolog sk Plánovaný čas
|
||||
price infolog sk Cena
|
||||
pricelist infolog sk Cenník
|
||||
primary link infolog sk Primárny odkaz
|
||||
priority infolog sk Priorita
|
||||
private infolog sk Súkromné
|
||||
project infolog sk Projekt
|
||||
project settings: price, times infolog sk Nastavenia Projektu: cena, časy
|
||||
projectmanager infolog sk Projektovník
|
||||
re-planned infolog sk Pre-plánované
|
||||
re-planned time infolog sk Pre-plánovaný čas
|
||||
re: infolog sk Re:
|
||||
read one record by passing its id. infolog sk Načítaj jednotlivý záznam zadaním id.
|
||||
read rights (default) infolog sk Právo na čítanie (predvolené)
|
||||
receive notifications about due entries you are responsible for infolog sk Dostávať pripomienky o záznamoch, ktorým nastáva termín splnenia a ste za ne zodpovední
|
||||
receive notifications about due entries you delegated infolog sk Dostávať pripomienky o záznamoch, ktoré ste delegovali
|
||||
receive notifications about items assigned to you infolog sk Dostávať pripomienky o položkách, ktoré Vám boli priradené
|
||||
receive notifications about own items infolog sk Dostávať pripomienky o vlastných položkách
|
||||
receive notifications about starting entries you are responsible for infolog sk Dostávať pripomienky o začínajúcich položkách, za ktoré ste zodpovední
|
||||
receive notifications about starting entries you delegated infolog sk Dostávať pripomienky o začínajúcich položkách, ktoré ste delegovali
|
||||
receive notifications as html-mails infolog sk Dostávať pripomienky ako HTML E-maily
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog sk reg. výraz pre lokálne IP adresy<br>napr. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog sk reg. výraz pre lokálne IP adresy<br>napr. ^192\.168\.1\.
|
||||
remark infolog sk Poznámka
|
||||
remove this link (not the entry itself) infolog sk Odstrániť tento odkaz (nie záznam samotný)
|
||||
responsible infolog sk Zodpovednosť
|
||||
responsible open infolog sk Zodpovednosť - otvorené
|
||||
responsible open and upcoming infolog sk Zodpovednosť - otvorené a blížiace sa
|
||||
responsible overdue infolog sk Zodpovednosť - meškajúce
|
||||
responsible upcoming infolog sk Zodpovednosť - blížiace sa
|
||||
responsible user, priority infolog sk Zodpovedný používateľ, priorita
|
||||
returns a list / search for records. infolog sk Vráti zoznam / hľadanie záznamov.
|
||||
rights for the responsible infolog sk Práva pre zodpovednú osobu
|
||||
same day infolog sk V ten deň
|
||||
save infolog sk Uložiť
|
||||
saves the changes made and leaves infolog sk Uloží vykonané zmeny a odíde
|
||||
saves this entry infolog sk Uloží tento záznam
|
||||
search infolog sk Hľadať
|
||||
search for: infolog sk Hľadať (čo):
|
||||
select infolog sk Vybrať
|
||||
select a category for this entry infolog sk vyberte kategóriu pre tento záznam
|
||||
select a price infolog sk Vyberte cenu
|
||||
select a priority for this task infolog sk Vyberte prioritu pre túto úlohu
|
||||
select a project infolog sk Vyberte projekt
|
||||
select a responsible user: a person you want to delegate this task infolog sk vyberte zodpovedného používateľa: toho, na ktorého chcete delegovať túto úlohu
|
||||
select a typ to edit it's status-values or delete it infolog sk vyberte typ pre úpravu hodnôt stavov, alebo ho odstráňte
|
||||
select an app to search in infolog sk Vyberte, v ktorej aplikácii chcete hľadať
|
||||
select an entry to link with infolog sk Vyberte záznam na ktorý chcete vytvoriť odkaz
|
||||
select to filter by owner infolog sk Filtrovanie podľa vlastníka
|
||||
select to filter by responsible infolog sk Filtrovanie podľa zodpovedného
|
||||
sender infolog sk Odosielateľ
|
||||
set status to done infolog sk Nastaviť stav na hotovo
|
||||
set status to done for all entries infolog sk Nastaviť stav na hotovo pre všetky položky
|
||||
sets the status of this entry and its subs to done infolog sk Nastaví stav záznamu a jeho podzáznamov na Hotovo
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog sk Má Záznamník zobrazovať Podúlohy, Podhovory alebo Podpoznámky v normálnom zobrazení alebo nie? Vždy ešte môžete zobraziť Podradené záznamy cez ich rodičovský záznam.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog sk Má Záznamník zobrazovať v zozname odkazy na iné aplikácie a/alebo súbory v prílohe (v normálnom pohľade, keď otvoríte Záznamník)?
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog sk Zobrazovať Záznamník na hlavnej stránke? Ak áno, s akým filtrom? Táto voľba funguje len v prípade, ak ste už nevybrali konkrétnu aplikáciu pre hlavnú stránku (vo vašich predvoľbách).
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog sk Má Záznamník používať plné mená (meno, priezvisko) alebo iba používateľské mená?
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog sk Má sa v zozname Záznamníka zobrazovať jedinečné číselné ID, ktoré môže byť použité napr. ako ID problému?
|
||||
should the infolog list show the column "last modified". infolog sk Zobrazovať v zozname Záznamníka aj stĺpec "Naposledy zmenené"?
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog sk Zobrazovať v zozname Záznamníka percentuálny stav vybavenia len pre stav "prebiehajúci", alebo ako dve samostatné ikony?
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog sk Má byť tento záznam viditeľný IBA pre vás a pre ľudí, ktorým pridelíte súkromný prístup cez ACL?
|
||||
show a column for used and planned times in the list. infolog sk V zozname zobraziť stĺpec pre použité a plánované časy.
|
||||
show full usernames infolog sk Zobraziť plné používateľské mená
|
||||
show in the infolog list infolog sk Zobraziť v zozname Záznamníka
|
||||
show last modified infolog sk Zobraziť čas poslednej úpravy
|
||||
show status and percent done separate infolog sk Zobraziť samostatne stav záznamu a percentuálny stav vybavenia
|
||||
show ticket id infolog sk Zobraziť ID problému
|
||||
show times infolog sk Zobraziť časy
|
||||
small view infolog sk Zmenšený pohľad
|
||||
start a new search, cancel this link infolog sk Spustiť nové vyhľadávanie, zrušiť tento odkaz
|
||||
startdate infolog sk Dátum začatia
|
||||
startdate enddate infolog sk Dátum začatia Termín splnenia
|
||||
startdate for new entries infolog sk Dátum začatia pre nové záznamy
|
||||
starting %1 infolog sk Začiatok %1
|
||||
startrecord infolog sk Prvý záznam
|
||||
status infolog sk Stav
|
||||
status ... infolog sk Stav...
|
||||
sub infolog sk Podradené
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog sk Podzáznamy sa dostanú pod rodičovské alebo hlavné záznamy, ak nie je k dispozícii rodičovský.
|
||||
subject infolog sk Predmet
|
||||
sum infolog sk Suma
|
||||
task infolog sk Úloha
|
||||
tasks of infolog sk Úlohy pre
|
||||
template infolog sk Šablóna
|
||||
test import (show importable records <u>only</u> in browser) infolog sk Test importu (zobraz importovateľné záznamy <u>iba</u> v prehliadači)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog sk vnútorne používané meno (<= 10 znakov), jeho zmena zneprístupní existujúce údaje
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog sk vnútorne používané meno (<= 20 znakov), jeho zmena zneprístupní existujúce údaje
|
||||
the text displayed to the user infolog sk Text zobrazený používateľovi
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog sk Toto je filter, ktorý Záznamník používa keď otvoríte aplikáciu. Filtre obmedzujú, ktoré záznamy sú zobrazené vo vybranom pohľade. Sú tu filtre na zobrazenie iba dokončených záznamov, alebo naopak -ešte otvorených, alebo budúcich záznamov, a to buď Vaších, alebo všetkých používateľov.
|
||||
til when should the todo or phonecall be finished infolog sk Dokiaľ sa nedokončí Úloha alebo Telefonát
|
||||
times infolog sk Časy
|
||||
to many might exceed your execution-time-limit infolog sk Ak priveľa, môže dôjsť k prekročeniu Vašich obmedzení ohľadom povoleného času behu aplikácie
|
||||
to what should the startdate of new entries be set. infolog sk Ako má byť nastavený dátum začatia u nových záznamov?
|
||||
today infolog sk Dnes
|
||||
todays date infolog sk Dnešný dátum
|
||||
todo infolog sk Úloha
|
||||
translation infolog sk Preklad
|
||||
typ infolog sk Typ
|
||||
typ '%1' already exists !!! infolog sk Typ '%1' už existuje !!!
|
||||
type infolog sk Typ
|
||||
type ... infolog sk Typ ...
|
||||
type of customfield infolog sk Typ používateľského poľa
|
||||
type of the log-entry: note, phonecall or todo infolog sk Typ záznamu: Poznámka, Telefonát alebo Úloha
|
||||
unlink infolog sk Zruš odkaz
|
||||
upcoming infolog sk Blížiace sa
|
||||
urgency infolog sk Súrnosť
|
||||
urgent infolog sk Súrna
|
||||
used time infolog sk Použitý čas
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog sk platná cesta na strane klienta<br>napr. \\Server\Share alebo e:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog sk platná cesta na strane klienta<br>napr. \\Server\Share alebo e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog sk platná cesta na strane klienta<br>napr. \\Server\Share alebo e:\
|
||||
values for selectbox infolog sk Hodnoty pre výberovú ponuku
|
||||
view all subs of this entry infolog sk Zobraziť všetky podradené záznamy
|
||||
view other subs infolog sk Zobraziť ostatné Podradené záznamy
|
||||
view parent infolog sk Zobraziť Rodičovský záznam
|
||||
view subs infolog sk Zobraziť Podradené záznamy
|
||||
view the parent of this entry and all his subs infolog sk Zobraziť Rodičovský záznam a všetky jeho podradené
|
||||
view this linked entry in its application infolog sk Zobraziť tento odkaz v jeho aplikácii
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog sk keď má byť začatá Úloha alebo Telefonát, ukáže sa akoby od tohto dátumu vo filtri "otvorené" alebo "moje otvorené" (úvodná stránka)
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog sk Ktoré prídavné položky majú byť zodpovednej osobe prístupné pre úpravy, a to aj bez pridelených práv na úpravy?<br />Stav, percentuálny stav vybavenia a dátum dokončenia sú prístupné vždy.
|
||||
which implicit acl rights should the responsible get? infolog sk Ktoré implicitné ACL oprávnenia má zodpovedná osoba obdržať automaticky?
|
||||
which types should the calendar show infolog sk Aké typy má kalendár ukazovať
|
||||
whole query infolog sk Celý dopyt
|
||||
will-call infolog sk Zavolá
|
||||
write (add or update) a record by passing its fields. infolog sk Zapísať (pridať alebo upraviť) záznam použitím príslušných položiek.
|
||||
yes - close infolog sk Áno - Zavrieť
|
||||
yes - close including sub-entries infolog sk Áno - Zavrieť vrátane podzáznamov
|
||||
yes - delete infolog sk Áno - Odstrániť
|
||||
yes - delete including sub-entries infolog sk Áno - Odstrániť vrátane podzáznamov
|
||||
yes, noone can purge deleted items infolog sk Áno, nikto nemôže vyčistiť odstránené položky
|
||||
yes, only admins can purge deleted items infolog sk Áno, iba správcovia môžu vyčistiť odstránené položky
|
||||
yes, with larger fontsize infolog sk Áno, s väčším písmom
|
||||
yes, with purging of deleted items possible infolog sk Áno, s možnosťou vyčistenia odstránených položiek
|
||||
you can choose a categorie to be preselected, when you create a new infolog entry infolog sk Môžete si vybrať, ktorá kategória bude predvybraná, keď budete vytvárať nový záznam Záznamníka.
|
||||
you can't delete one of the stock types !!! infolog sk Nemôžete odstrániť východiskový typ!!
|
||||
you have entered an invalid ending date infolog sk Zadali ste chybný termín ukončenia
|
||||
you have entered an invalid starting date infolog sk Zadali ste chybný dátum začatia
|
||||
you have to enter a name, to create a new typ!!! infolog sk Ak chcete vytvoriť nový typ, musíte zadať jeho názov!!
|
||||
you must enter a subject or a description infolog sk Musíte zadať predmet alebo opis
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog sk Vaša databáza je neaktuálna (%1 oproti %2), prosím spustite %3setup%4 aby sa zaktualizovala.
|
361
infolog/lang/egw_sl.lang
Normal file
361
infolog/lang/egw_sl.lang
Normal file
@ -0,0 +1,361 @@
|
||||
%1 days in advance infolog sl %1 dni vnaprej
|
||||
%1 deleted infolog sl %1 izbrisan
|
||||
%1 deleted by %2 at %3 infolog sl %1 izbrisal %2 dne %3
|
||||
%1 modified infolog sl %1 spremenjen
|
||||
%1 modified by %2 at %3 infolog sl %1 spremenil %2 dne %3
|
||||
%1 records imported infolog sl %1 zapisov uvoženih
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog sl %1 zapisov prebranih (niso še uvoženi, zato lahko greste %2nazaj%3 in jih odznačite za prenos)
|
||||
%1 you are responsible for is due at %2 infolog sl %1, za katerega ste odgovorni, poteče %2
|
||||
%1 you are responsible for is starting at %2 infolog sl %1, za katerega ste odgovorni, se začne %2
|
||||
%1 you delegated is due at %2 infolog sl %1, katerega ste dodelili, poteče %2
|
||||
%1 you delegated is starting at %2 infolog sl %1, katerega ste dodelili, se začne %2
|
||||
- subprojects from infolog sl - Podprojekt iz
|
||||
0% infolog sl 0%
|
||||
10% infolog sl 10%
|
||||
100% infolog sl 100%
|
||||
20% infolog sl 20%
|
||||
30% infolog sl 30%
|
||||
40% infolog sl 40%
|
||||
50% infolog sl 50%
|
||||
60% infolog sl 60%
|
||||
70% infolog sl 70%
|
||||
80% infolog sl 80%
|
||||
90% infolog sl 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog sl <b>priponke s simbolično povezavo</b> namesto prenosa na način file://path za neposredne LAN kliente
|
||||
a short subject for the entry infolog sl Kratek predmet za vnos
|
||||
abort without deleting infolog sl Prekliči brez brisanja
|
||||
accept infolog sl Sprejmi
|
||||
action infolog sl Dejanje
|
||||
actual date and time infolog sl Dejanski datum in čas
|
||||
add infolog sl Dodaj
|
||||
add a file infolog sl Dodaj datoteko
|
||||
add a new entry infolog sl Dodaj nov zapis
|
||||
add a new note infolog sl Dodaj novo opombo
|
||||
add a new phonecall infolog sl Dodaj nov telefonski klic
|
||||
add a new sub-task, -note, -call to this entry infolog sl Dodaj novo podnalogo, opombo, klic za ta zapis
|
||||
add a new todo infolog sl Dodaj novo opravilo
|
||||
add file infolog sl Dodaj datoteko
|
||||
add sub infolog sl Dodaj namestnika
|
||||
add timesheet entry infolog sl Dodaj vnos timeheet
|
||||
add: infolog sl Dodaj:
|
||||
all infolog sl Vse
|
||||
all links and attachments infolog sl Vse povezave in priponke
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog sl Dovoli spreminjanje statusov zapisov, npr. določi Opravilo kot končano, če se konča (vrednost je odvisna od tipa vhoda)
|
||||
apply the changes infolog sl Uveljavi spremembe
|
||||
archive infolog sl Arhiv
|
||||
are you shure you want to delete this entry ? infolog sl Ali ste prepričani, da želite izbrisati ta zapis?
|
||||
attach a file infolog sl Pripni datoteko
|
||||
attach file infolog sl Pripni datoteko
|
||||
attention: no contact with address %1 found. infolog sl Pozor: Stik z naslovom %1 ni bil najden.
|
||||
back to main list infolog sl Nazaj na glavni seznam
|
||||
billed infolog sl Obračunan
|
||||
both infolog sl Oba
|
||||
call infolog sl Klic
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog sl Lahko se uporabi za prikaz nadaljnjih vrst Infodnevnika v koledarju ali za omejitev prikaza npr. samp opravil.
|
||||
cancel infolog sl Prekliči
|
||||
cancelled infolog sl Preklicano
|
||||
categories infolog sl Kategorije
|
||||
category infolog sl Kategorija
|
||||
change the status of an entry, eg. close it infolog sl Sprememba statusa vnosa, npr. zapiranje
|
||||
charset of file infolog sl Nabor znakov datoteke
|
||||
check to set startday infolog sl Označite za postavitev začetnega dneva
|
||||
check to specify custom contact infolog sl Potrdite za določitev kontakta po meri
|
||||
click here to create the link infolog sl Kliknite tukaj da ustvarite povezavo
|
||||
click here to start the search infolog sl Kliknite tukaj za začetek iskanja
|
||||
close infolog sl Zapri
|
||||
comment infolog sl Opomba
|
||||
completed infolog sl Končano
|
||||
configuration infolog sl Konfiguracija
|
||||
confirm infolog sl Potrdi
|
||||
contact infolog sl Kontakt
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog sl Kopira spremembe v odložišče, %1 ponovno naloži vnos %2 in jih zlije.
|
||||
create new links infolog sl Ustvari nove povezave
|
||||
creates a new field infolog sl Ustvari novo polje
|
||||
creates a new status with the given values infolog sl Ustvari nov status s podanimi vrednostmi
|
||||
creates a new typ with the given name infolog sl Ustvari nov tip s podanim imenom
|
||||
creation infolog sl Datum ustvarjenja
|
||||
csv-fieldname infolog sl CSV-Ime polja
|
||||
csv-filename infolog sl CSV-Ime datoteke
|
||||
csv-import common sl CSV-Uvoz
|
||||
custom infolog sl Lasten
|
||||
custom contact-address, leave empty to use information from most recent link infolog sl Lastni kontaktni naslov (pustite prazno za uporabo informacije iz najnovejše povezave)
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog sl Lastne kontaktne informacije (pustite prazno za uporabo informacije iz najnovejše povezave)
|
||||
custom fields infolog sl Lastna polja
|
||||
custom fields, typ and status common sl Lastna polja, tip in status
|
||||
custom regarding infolog sl Lastno glede na
|
||||
custom status for typ infolog sl Lastni satus za tip
|
||||
customfields infolog sl Lastna polja
|
||||
date completed infolog sl Datum zaključka
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog sl Datum zaključka (pustite prazno, da se nastavi samodejno, če je status nastavljen na Končano ali Obračunano)
|
||||
datecreated infolog sl Datum ustvarjanja
|
||||
dates, status, access infolog sl Datumi, status, dostop
|
||||
days infolog sl Dnevi
|
||||
default filter for infolog infolog sl Napačen filter za InfoDnevnik
|
||||
default status for a new log entry infolog sl Privzeti status za nov zapis v dnevnik
|
||||
delegated infolog sl Dodeljeni
|
||||
delegated open infolog sl Dodeljeni odprti
|
||||
delegated overdue infolog sl Dodeljeni pretečeni
|
||||
delegated upcomming infolog sl Dodeljeni prihajajoči
|
||||
delegation infolog sl Pooblastitev
|
||||
delete infolog sl Izbriši
|
||||
delete one record by passing its id. infolog sl Izbriši zapis s podano šifro.
|
||||
delete the entry infolog sl Izbriši vnos
|
||||
delete this entry infolog sl Izbriši ta vnos
|
||||
delete this entry and all listed sub-entries infolog sl Izbriši ta vnos in podrejene vnose
|
||||
deleted infolog sl Izbrisano
|
||||
deletes the selected typ infolog sl Izbriše izbrani tip
|
||||
deletes this field infolog sl Izbriše to polje
|
||||
deletes this status infolog sl Izbriše ta status
|
||||
description infolog sl Opis
|
||||
determines the order the fields are displayed infolog sl ugotovi vrstni red polj, ki so prikazana
|
||||
disables a status without deleting it infolog sl Onemogoči status brez brisanja
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog sl Ali želite potrdilo odgovornosti za: sprejemanje, končanje naloge ali oboje?
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog sl Želite prejeti obvestilo, če je element dodeljen vam ali se dodeljeni elemeni posodobijo?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog sl Želite prejeti obvestilo, če se bodo elementi, za katere ste odgovorni kmalu začnejo?
|
||||
do you want a notification, if items you are responsible for are due? infolog sl Želite prejeti obvestilo, če so elementi, za keter ste odgovorni pretečeni?
|
||||
do you want a notification, if items you created get updated? infolog sl Želite prejeti obvestilo, če so elementi, ki ste jih ustvarili posodobljeni?
|
||||
do you want a notification, if items you delegated are about to start? infolog sl Želite prejeti obvestilo, če se bodo elementi, za katere ste odgovorni kmalu začnejo?
|
||||
do you want a notification, if items you delegated are due? infolog sl Želite prejeti obvestilo, če so elementi, za katere ste odgovorni pretečeni?
|
||||
do you want to receive notifications as html-mails or plain text? infolog sl Želite prejemati obvestila v obliki HTML ali kot navadno besedilo?
|
||||
don't show infolog infolog sl Ne prikaži InfoDnevnika
|
||||
done infolog sl Končano
|
||||
download infolog sl Prenos
|
||||
duration infolog sl Trajanje
|
||||
each value is a line like <id>[=<label>] infolog sl vsaka vrednost je vrstice kot <šifra>[=<oznaka>]
|
||||
edit infolog sl Uredi
|
||||
edit or create categories for ingolog infolog sl Uredi ali ustvari kategorije za InfoDnevnik
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog sl Uredi pravice (vse pravice, vključno z vnosom namestnika!)
|
||||
edit status infolog sl Uredi status
|
||||
edit the entry infolog sl Uredi vnos
|
||||
edit this entry infolog sl Uredi ta vnos
|
||||
empty for all infolog sl Prazno za vse
|
||||
enddate infolog sl Končni datum
|
||||
enddate can not be before startdate infolog sl Končni datum ne more biti pred datumom začetka
|
||||
enter a custom contact, leave empty if linked entry should be used infolog sl Vnesite lastni kontakt (pustite prazno, če naj bo uporabljen zapis povezave)
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog sl Vpišite telefon/e-naslov (pustite prazno, če naj bo uporabljen zapis povezave)
|
||||
enter a textual description of the log-entry infolog sl Vpišite opis vnosa v dnevnik
|
||||
enter the query pattern infolog sl Vnesite vzorec poizvedbe
|
||||
entry and all files infolog sl Zapis in vse datoteke
|
||||
error: saving the entry infolog sl Napaka pri shranjevanju vnosa
|
||||
error: the entry has been updated since you opened it for editing! infolog sl Napaka: vnos je bil spremenjen odkar ste ga odprli za urejanje!
|
||||
existing links infolog sl Obstoječe povezave
|
||||
fax infolog sl Faks
|
||||
fieldseparator infolog sl Ločilo polj
|
||||
finish infolog sl Konec
|
||||
for which types should this field be used infolog sl Za ketere tipe naj bo to polje uporabljeno
|
||||
from infolog sl Od
|
||||
general infolog sl Splošno
|
||||
group owner for infolog sl Skupinski lastnik za
|
||||
high infolog sl Visoko
|
||||
history logging infolog sl Beleenje zgodovine
|
||||
history logging and deleting of items infolog sl Beleenje zgodovine in brisanje elementov
|
||||
id infolog sl Šifra
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog sl Če ima vrsta skupinskega lastnika, bo lastnik vseh vnosov te vrste dana skupina in NE uporabnik, ki jo je ustvaril!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog sl Če ni nastavljen, je vrstica za iskanje in filtriranje skrita za manj vnosov kakor "maksimalno število zadetkov na stran" (kakor je definirano v vaših nastavitvah.
|
||||
import infolog sl Uvoz
|
||||
import next set infolog sl Uvozi naslednji niz
|
||||
info log common sl InfoDnevnik
|
||||
infolog common sl InfoDnevnik
|
||||
infolog - delete infolog sl InfoDnevnik - Izbriši
|
||||
infolog - edit infolog sl InfoDnevnik - Uredi
|
||||
infolog - import csv-file infolog sl InfoDnevnik - Uvoz CSV-Datoteke
|
||||
infolog - new infolog sl InfoDnevnik - Nov
|
||||
infolog - new subproject infolog sl InfoDnevnik - Nov podprojekt
|
||||
infolog - subprojects from infolog sl InfoDnevnik - Podprojekt od
|
||||
infolog entry deleted infolog sl Vnos InfoDnevnika je bil izbrisan
|
||||
infolog entry saved infolog sl Vnos InfoDnevnika je bil shranjen
|
||||
infolog filter for the main screen infolog sl Filter InfoDnevnika za uvodni zaslon
|
||||
infolog list infolog sl Seznam InfoDnevnika
|
||||
infolog preferences common sl Nastavitve InfoDnevnika
|
||||
infolog-fieldname infolog sl Info Log - ime polja
|
||||
invalid filename infolog sl Napačno ime datoteke
|
||||
label<br>helptext infolog sl Oznaka<br>Pomoč
|
||||
last changed infolog sl Zadnjič spremenjeno
|
||||
last modified infolog sl Zadnjič prilagojeno
|
||||
leave it empty infolog sl Pusti prazno
|
||||
leave without saveing the entry infolog sl Zapusti brez shranjevanja zapisa
|
||||
leaves without saveing infolog sl Zapusti brez shranjevanja
|
||||
length<br>rows infolog sl Dolžina<br>Vrstice
|
||||
link infolog sl Povezava
|
||||
links infolog sl Povezave
|
||||
links of this entry infolog sl Povezave tega zapisa
|
||||
list all categories infolog sl Seznam vseh kategorij.
|
||||
list no subs/childs infolog sl Seznam nima podrejenih seznamov
|
||||
location infolog sl Lokacija
|
||||
longer textual description infolog sl Daljši opis
|
||||
low infolog sl Nizko
|
||||
max length of the input [, length of the inputfield (optional)] infolog sl Največja dolžina vhoda [dolžina vhodnega polja (neobvezno)]
|
||||
name must not be empty !!! infolog sl Ime ne sme biti prazno!!!
|
||||
name of new type to create infolog sl Ime novega tipa, ki ga ustvarjate
|
||||
never hide search and filters infolog sl Nikoli skriti iskanja in filtrov
|
||||
new %1 infolog sl Nov %1
|
||||
new %1 created by %2 at %3 infolog sl Nov %1 ustvaril %2 dne %3
|
||||
new name infolog sl Novo ime
|
||||
new search infolog sl Novo iskanje
|
||||
no - cancel infolog sl Ne - Prekliči
|
||||
no describtion, links or attachments infolog sl Brez opisa, povezav ali priponk
|
||||
no details infolog sl Brez podrobnosti
|
||||
no entries found, try again ... infolog sl Noben zapis ni bil najden, poskusite znova ...
|
||||
no filter infolog sl Brez filtra
|
||||
no links or attachments infolog sl Brez povezav ali prilog
|
||||
nonactive infolog sl Neaktivno
|
||||
none infolog sl Noben
|
||||
normal infolog sl Običajno
|
||||
not infolog sl Ne
|
||||
not assigned infolog sl Nedodeljen
|
||||
not-started infolog sl Ne začet
|
||||
note infolog sl Opomba
|
||||
number of records to read (%1) infolog sl Število zapisov za branje (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog sl Število vrstic vnosnega polja ali vrstica izbirnega polja
|
||||
offer infolog sl Ponudba
|
||||
one day after infolog sl En dan po
|
||||
one day in advance infolog sl En dan vnaprej
|
||||
ongoing infolog sl Nadaljevalni
|
||||
only for details infolog sl Samo za podrobnosti
|
||||
only if i get assigned or removed infolog sl Samo če sem dodeljen ali odstranjen
|
||||
only the attachments infolog sl Samo priloge
|
||||
only the links infolog sl Samo povezave
|
||||
open infolog sl Odprt
|
||||
optional note to the link infolog sl Neobvezna opomba za povezavo
|
||||
order infolog sl Vrstni red
|
||||
overdue infolog sl Zapadel
|
||||
own infolog sl Lastni
|
||||
own open infolog sl Lastni odprt
|
||||
own overdue infolog sl Lastni zapadel
|
||||
own upcoming infolog sl Lastni prihajajoč
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog sl Pot na (web-)stran strežnika<br>npr. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog sl Pot do uporabnikov in skupine datotek MORA BITI ZUNAJ glavnega direktorija spletnega strežnika!
|
||||
pattern for search in addressbook infolog sl Vzorec za iskanje po adresarju
|
||||
pattern for search in projects infolog sl Vzorec za iskanje po Projektih
|
||||
percent completed infolog sl Odstotek končanega
|
||||
permission denied infolog sl Dostop zavrnjen
|
||||
phone infolog sl Telefonski klic
|
||||
phone/email infolog sl Telefon/E-naslov
|
||||
phonecall infolog sl Telefonski klic
|
||||
planned infolog sl Planirano
|
||||
planned time infolog sl Planirani čas
|
||||
price infolog sl Cena
|
||||
priority infolog sl Prioriteta
|
||||
private infolog sl Zasebno
|
||||
project infolog sl Projekt
|
||||
project settings: price, times infolog sl Nastavitve projekta: cena, časi
|
||||
re: infolog sl Odg:
|
||||
read one record by passing its id. infolog sl Preberi zapis s podano šifro.
|
||||
read rights (default) infolog sl Pravice branja (privzeto)
|
||||
receive notifications about due entries you are responsible for infolog sl Prejem obvestila o pretečenih vnosih, za ketere ste odgovorni
|
||||
receive notifications about due entries you delegated infolog sl Prejem obvestila o pretečenih vnosih, ketere ste dodelili
|
||||
receive notifications about items assigned to you infolog sl Prejem obvestila o elementih, dodeljenih vam
|
||||
receive notifications about own items infolog sl Prejem obvestila o lastnih elementih
|
||||
receive notifications about starting entries you are responsible for infolog sl Prejem obvestila o začetku vnosov, za ketere ste odgovorni
|
||||
receive notifications about starting entries you delegated infolog sl Prejem obvestila o začetku vnosov, ki ste jih dodelili
|
||||
receive notifications as html-mails infolog sl Prejem obvestila kot sporočilo HTML
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog sl Regularni izraz za lokalne IP-je<br>npr. ^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog sl Regularni izraz za lokalne IP-je<br>npr. ^192\.168\.1\.
|
||||
remark infolog sl Opazka
|
||||
remove this link (not the entry itself) infolog sl Odstrani povezavo (ne pa tudi zapisa)
|
||||
responsible infolog sl Odgovoren
|
||||
responsible open infolog sl Odgovoren odprt
|
||||
responsible overdue infolog sl Odgovoren pretekel
|
||||
responsible upcoming infolog sl Odgovoren prihajajoč
|
||||
responsible user, priority infolog sl Odgovoren uporabnik, prioriteta
|
||||
returns a list / search for records. infolog sl Vrne seznam / iskanje zapisov.
|
||||
rights for the responsible infolog sl Pravice odgovornega
|
||||
same day infolog sl Isti dan
|
||||
save infolog sl Shrani
|
||||
saves the changes made and leaves infolog sl Shrani spremembe in zapusti
|
||||
saves this entry infolog sl Shrani ta zapis
|
||||
search infolog sl Poišči
|
||||
search for: infolog sl Išči:
|
||||
select infolog sl Izberi
|
||||
select a category for this entry infolog sl Izberite kategorijo za ta zapis
|
||||
select a price infolog sl Izberite ceno
|
||||
select a priority for this task infolog sl Izberite prioriteto za to nalogo
|
||||
select a project infolog sl Izberite projekt
|
||||
select a responsible user: a person you want to delegate this task infolog sl Izberite odgovornega uporabnika: osebo, ki bo lahko urejala to nalogo
|
||||
select a typ to edit it's status-values or delete it infolog sl Izberite tip za urejanje vrednosti statusa ali brisanje
|
||||
select an app to search in infolog sl Izberite aplikacijo za iskanje
|
||||
select an entry to link with infolog sl Izberite zapis s katerim želite povezati
|
||||
select to filter by owner infolog sl Izberite za filtriranje po lastniku
|
||||
select to filter by responsible infolog sl Izberite za filtriranje po odgovornosti
|
||||
sets the status of this entry and its subs to done infolog sl Nastavi status tega vnosa in podrejenih vnosov na končano
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog sl Ali naj InfoDnevnik prikaže podrejena opravila - klice ali opombe - v splošnem oknu? Podrejena opravila lahko vedno vidite preko njihovih nadrejenih opravil?
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog sl Ali naj InfoDnevnik prikaže povezave do drugih aplikacij in/ali datotečne povezave v seznamu InfoDnevnik (splošni pogled, ko vstopite v InfoDnevnik)?
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog sl Ali naj se InfoDnevnik prikaže v uvodnem zaslonu in s katerim filtrom. Deluje samo, če v nastavitveh za uvodni zaslon ne izberete aplikacije.
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog sl Ali naj InfoDnevnik uporabi polna imena (ime in priimek) ali samo uporabniška imena?
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog sl Ali naj se InfoDnevnik prikaže številčno šifro, ki se lahko uporabi kot šifra opravila?
|
||||
should the infolog list show the column "last modified". infolog sl Ali naj se InfoDnevnik prikaže stolpec "Zadnjič spremenjeno"?
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog sl Ali naj se InfoDnevnik prikaže odstotek opravljenega samo za status nadaljevalnega ali dve ločeni ikoni?
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog sl Naj bo ta zapis viden samo vam in ljudem, ki jim dodelite pravice preko ACL-jev?
|
||||
show a column for used and planned times in the list. infolog sl V seznamu prikaže stolpec za uporabljene in planirane čase.
|
||||
show full usernames infolog sl Prikaži polna uporabniška imena
|
||||
show in the infolog list infolog sl Prikaži v seznamu InfoDnevnika
|
||||
show last modified infolog sl Prikaži zadnjič spremenjeno
|
||||
show status and percent done separate infolog sl Prikaži status in odstotek opravljenega ločeno
|
||||
show ticket id infolog sl Prikaži šifro opravila
|
||||
show times infolog sl Prikaži čase
|
||||
small view infolog sl Skrčen pogled
|
||||
start a new search, cancel this link infolog sl Zaženi novo iskanje, prekini to povezavo
|
||||
startdate infolog sl Začetni datum
|
||||
startdate enddate infolog sl Začetni datum Končni datum
|
||||
startdate for new entries infolog sl Začetni datum za nove vnose
|
||||
startrecord infolog sl Začetni zapis
|
||||
status infolog sl Status
|
||||
status ... infolog sl Status ...
|
||||
sub infolog sl Podrejeni
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog sl Podrejeni vnosi postanejo podrejeni staršu ali glavnemu vnosu, če ni starša
|
||||
subject infolog sl Predmet
|
||||
task infolog sl Opravila
|
||||
template infolog sl Predloga
|
||||
test import (show importable records <u>only</u> in browser) infolog sl Test uvoza (pokaži pomemebmne zapise <u>samo</u> v brskalniku)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog sl Ime, ki se uporablja interno (manj kot 10 znakov). Sprememba tega bo povzročila, da obstoječ podatek ne bo na voljo.
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog sl Ime, ki se uporablja interno (manj kot 20 znakov). Sprememba tega bo povzročila, da obstoječ podatek ne bo na voljo.
|
||||
the text displayed to the user infolog sl besedilo, ki se prikaže uporabniku
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog sl To je filter, ki ga InfoDnevnik uporablja, ko vstopite v aplikacijo. Filter omejuje število prikazanih zapisov v trenutnem pogledu. Obstajajo filtri, ki prikazujejo samo dokončane, še odprte ali zapise v prihodnosti, vaše ali tuje zapise.
|
||||
til when should the todo or phonecall be finished infolog sl Do kdaj naj bo opravilo ali telefonski klic opravljen
|
||||
times infolog sl Časi
|
||||
to many might exceed your execution-time-limit infolog sl Preveč lahko preseže čas izvajanja
|
||||
to what should the startdate of new entries be set. infolog sl Na kaj naj bo nastavljen začetni datum novega vnosa?
|
||||
today infolog sl Danes
|
||||
todays date infolog sl Današnji datum
|
||||
todo infolog sl Opravila
|
||||
translation infolog sl Prevod
|
||||
typ infolog sl Tip
|
||||
typ '%1' already exists !!! infolog sl Tip '%1' že obstaja!
|
||||
type infolog sl Tip
|
||||
type ... infolog sl Tip ...
|
||||
type of customfield infolog sl Vrsta polja po meri
|
||||
type of the log-entry: note, phonecall or todo infolog sl Tip log zapisa: opomba, telefonski klic ali Opravilo
|
||||
unlink infolog sl Odstrani povezavo
|
||||
upcoming infolog sl Prihajajoč
|
||||
urgency infolog sl Nujnost
|
||||
urgent infolog sl Nujno
|
||||
used time infolog sl Porabljen čas
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog sl Veljavna pot na strani odjemalca<br>npr. \\Strežnik\Skupno ali e:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog sl Veljavna pot na strani odjemalca<br>npr. \\Strežnik\Skupno ali e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog sl Veljavna pot na strani odjemalca<br>npr. \\Strežnik\Skupno ali e:\
|
||||
values for selectbox infolog sl Vrednosti za izbirno polje
|
||||
view all subs of this entry infolog sl Poglej vse podrejene zapise
|
||||
view other subs infolog sl Poglej ostale podrejene zapise
|
||||
view parent infolog sl Poglej nadrejenega
|
||||
view subs infolog sl Pogled podrejenih zapisov
|
||||
view the parent of this entry and all his subs infolog sl Poglej nadrejenega in vse njegove podrejene zapise
|
||||
view this linked entry in its application infolog sl Poglej ta povezani vnos v njegovi aplikaciji
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog sl Kdaj naj se Opravila ali Telefonski klic zaženejo?
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog sl Katera dodatna polja lahko odgovorni ureja brez pravic za urejanje?<br />Status, odstotek in datum opravljenega so vedno dovoljeni.
|
||||
which implicit acl rights should the responsible get? infolog sl Katere pravice ACL naj dobi odgovorni?
|
||||
which types should the calendar show infolog sl Katere vrste naj koledar prikaže
|
||||
whole query infolog sl Celotno povpraševanje
|
||||
will-call infolog sl Bodo klicani
|
||||
write (add or update) a record by passing its fields. infolog sl Zapišite (dodajte ali posodobite) zapis s podanimi vrednostmi.
|
||||
yes - delete infolog sl Da - Izbriši
|
||||
yes - delete including sub-entries infolog sl Da - Izbriši, vključno s podrejenimi vnosi
|
||||
yes, noone can purge deleted items infolog sl Da, nihče ne sme odstraniti izbrisanih elementov
|
||||
yes, only admins can purge deleted items infolog sl Da, samo administratorji lahko odstranijo izbrisana elemente
|
||||
yes, with larger fontsize infolog sl Da, z večjo pisavo
|
||||
yes, with purging of deleted items possible infolog sl Da, z odstranitvijo vseh možnih elementov
|
||||
you can't delete one of the stock types !!! infolog sl Ne morete izbrisati glavnega tipa!
|
||||
you have entered an invalid ending date infolog sl Vnesli ste napačen končni datum
|
||||
you have entered an invalid starting date infolog sl Vnesli ste napačen začetni datum
|
||||
you have to enter a name, to create a new typ!!! infolog sl Vpisati morate ime za imenovanje novega tipa
|
||||
you must enter a subject or a description infolog sl Vpisati morate predmet ali opis
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog sl Vaša podatkovna baza NI obnovljena (%1 vs. %2), prosimo poženite %3 nastavitev%4 za prenovo vaše podatkovne baze.
|
316
infolog/lang/egw_sv.lang
Normal file
316
infolog/lang/egw_sv.lang
Normal file
@ -0,0 +1,316 @@
|
||||
%1 records imported infolog sv %1 poster importerade
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog sv %1 poster lästa (ännu inte importerade, gå %2tillbaka%3 och avmarkera Testimport)
|
||||
- subprojects from infolog sv - Underprojekt till
|
||||
0% infolog sv 0%
|
||||
10% infolog sv 10%
|
||||
100% infolog sv 100%
|
||||
20% infolog sv 20%
|
||||
30% infolog sv 30%
|
||||
40% infolog sv 40%
|
||||
50% infolog sv 50%
|
||||
60% infolog sv 60%
|
||||
70% infolog sv 70%
|
||||
80% infolog sv 80%
|
||||
90% infolog sv 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog sv <b>Filbilagor via symlänk eller genväg</b> istället för uppladdning och hämtning via file:/sökväg för lokala användare
|
||||
a short subject for the entry infolog sv Ett kort ämne för post
|
||||
abort without deleting infolog sv Avbryt utan att radera
|
||||
accept infolog sv Acceptera
|
||||
action infolog sv Åtgärd
|
||||
actual date and time infolog sv Faktiskt datum och tid
|
||||
add infolog sv Lägg till
|
||||
add a file infolog sv Lägg till fil
|
||||
add a new entry infolog sv Lägg till Post
|
||||
add a new note infolog sv Lägg till Anteckning
|
||||
add a new phonecall infolog sv Lägg till Samtal
|
||||
add a new sub-task, -note, -call to this entry infolog sv Lägg till ny Under- Uppgift, Anteckning eller Samtal till post
|
||||
add a new todo infolog sv Lägg till Uppgift
|
||||
add file infolog sv Lägg till fil
|
||||
add sub infolog sv Lägg till under
|
||||
add timesheet entry infolog sv Lägg till tidredovisnings post
|
||||
add: infolog sv Lägg till:
|
||||
all infolog sv Alla
|
||||
all links and attachments infolog sv Alla länkar och bilagor
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog sv Tillåter statusändring på post, ex. Sätt uppgift till färdig när klar.
|
||||
apply the changes infolog sv Spara ändringar
|
||||
are you shure you want to delete this entry ? infolog sv Vill du verkligen radera posten?
|
||||
attach a file infolog sv Bifoga fil
|
||||
attach file infolog sv Bifoga fil
|
||||
attension: no contact with address %1 found. infolog sv Ingen kontakt med adressen %1 hittades
|
||||
back to main list infolog sv Tillbaks till huvudlistan
|
||||
billed infolog sv Fakturerad
|
||||
both infolog sv Båda
|
||||
call infolog sv Samtal
|
||||
cancel infolog sv Avbryt
|
||||
cancelled infolog sv Avbruten
|
||||
categories infolog sv Kategorier
|
||||
category infolog sv Kategori
|
||||
change the status of an entry, eg. close it infolog sv Ändra status på post, t.ex. stäng den
|
||||
charset of file infolog sv Filens teckenuppsättning
|
||||
check to set startday infolog sv Markera för att sätta startdag
|
||||
check to specify custom contact infolog sv Markera för att ange annan kontakt
|
||||
click here to create the link infolog sv Klicka för att skapa länk
|
||||
click here to start the search infolog sv Klicka för att starta sökning
|
||||
close infolog sv Stäng
|
||||
comment infolog sv Kommentar
|
||||
completed infolog sv Färdig
|
||||
configuration infolog sv Alternativ
|
||||
confirm infolog sv Bekräfta
|
||||
contact infolog sv Kontakt
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog sv Kopiera dina ändringar till urklipp, %1 ladda om posten och migrera.
|
||||
create new links infolog sv Skapa länkar
|
||||
creates a new field infolog sv Skapar fält
|
||||
creates a new status with the given values infolog sv Skapar ett status med givet värde
|
||||
creates a new typ with the given name infolog sv Skapar en typ med namnet
|
||||
creation infolog sv Skapad
|
||||
csv-fieldname infolog sv CSV fältnamn
|
||||
csv-filename infolog sv CSV filnamn
|
||||
csv-import common sv CSV import
|
||||
custom infolog sv Anpassad
|
||||
custom contact-address, leave empty to use information from most recent link infolog sv Anpassade kontaktadresser, lämna tom för att använda info från senaste länk
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog sv Anpassade kontaktadresser, lämna tom för att använda info från senaste länk
|
||||
custom fields infolog sv Anpassade fält
|
||||
custom fields, typ and status common sv Anpassade fält, typ och status
|
||||
custom regarding infolog sv Anpassa beträffande
|
||||
custom status for typ infolog sv Anpassad status för typ
|
||||
customfields infolog sv Anpassat fält
|
||||
date completed infolog sv Datum färdigt
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog sv Datum färdigt (lämnas tomt för att automatiskt fyllas i vid färdigställande eller fakturering).
|
||||
datecreated infolog sv Skapad datum
|
||||
dates, status, access infolog sv Datum, status, åtkomst
|
||||
days infolog sv Dagar
|
||||
default filter for infolog infolog sv Standard filter för InfoLogg
|
||||
default status for a new log entry infolog sv Standard status för nya loggar
|
||||
delegation infolog sv Delegering
|
||||
delete infolog sv Radera
|
||||
delete one record by passing its id. infolog sv Ange ID för att radera post
|
||||
delete the entry infolog sv Radera post
|
||||
delete this entry infolog sv Radera posten
|
||||
delete this entry and all listed sub-entries infolog sv Radera posten och alla under
|
||||
deletes the selected typ infolog sv Raderar valda typer
|
||||
deletes this field infolog sv Raderar fältet
|
||||
deletes this status infolog sv Raderar denna status
|
||||
description infolog sv Beskrivning
|
||||
determines the order the fields are displayed infolog sv Bestämmer i vilken ordning fält ska visas
|
||||
disables a status without deleting it infolog sv Inaktivera status utan att radera
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog sv Vill du få bekräftelse från ansvarig angående acceptering, avslut eller båda?
|
||||
do you want to see custom infolog types in the calendar? infolog sv Vill du se anpassade InfoLogg typer i kalendern?
|
||||
don't show infolog infolog sv Visa INTE InfoLogg
|
||||
done infolog sv Färdig
|
||||
download infolog sv Ladda ner
|
||||
duration infolog sv Varaktighet
|
||||
each value is a line like <id>[=<label>] infolog sv Varje värde är en rad med formatet <id>[=<namn>]
|
||||
edit infolog sv Ändra
|
||||
edit or create categories for ingolog infolog sv Ändra eller skapa kategori för InfoLogg
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog sv Skrivrättigheter (fulla ändringsrättingheter inkl. delegering)
|
||||
edit status infolog sv Ändra status
|
||||
edit the entry infolog sv Ändra post
|
||||
edit this entry infolog sv Ändra posten
|
||||
empty for all infolog sv Tom för alla
|
||||
enddate infolog sv Slutdatum
|
||||
enddate can not be before startdate infolog sv Slutdatum kan inte vara före startdatum
|
||||
enter a custom contact, leave empty if linked entry should be used infolog sv Ange alternativ kontakt eller lämna tomt för att använda den länkade
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog sv Ange alternativ telefon/e-post eller lämna tomt för att använda den länkade
|
||||
enter a textual description of the log-entry infolog sv Skriv beskrivning av uppgiften
|
||||
enter the query pattern infolog sv Söksträng
|
||||
entry and all files infolog sv Post och alla filer
|
||||
error: saving the entry infolog sv Kunde inte spara posten
|
||||
error: the entry has been updated since you opened it for editing! infolog sv Posten har ändrats sedan du öppnade den för skrivning!
|
||||
existing links infolog sv Befintliga länkar
|
||||
fax infolog sv Fax
|
||||
fieldseparator infolog sv Fältavskiljare
|
||||
finish infolog sv Avsluta
|
||||
for which types should this field be used infolog sv För vilka typer ska fältet användas?
|
||||
from infolog sv Från
|
||||
general infolog sv Allmänt
|
||||
high infolog sv Hög
|
||||
id infolog sv ID
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog sv Om inte satt, kommer raden med sökning och filter vara gömd för färre poster än "max träffar per sida" (som du anav under allmäna alternativ).
|
||||
import infolog sv Importera
|
||||
import next set infolog sv Importera nästa
|
||||
info log common sv InfoLogg
|
||||
infolog common sv InfoLogg
|
||||
infolog - delete infolog sv InfoLogg - Radera
|
||||
infolog - edit infolog sv InfoLogg - Ändra
|
||||
infolog - import csv-file infolog sv InfoLogg - importera CSV fil
|
||||
infolog - new infolog sv InfoLogg - Ny
|
||||
infolog - new subproject infolog sv InfoLogg - Nytt underprojekt
|
||||
infolog - subprojects from infolog sv InfoLogg - Underprojekt till
|
||||
infolog entry deleted infolog sv InfoLogg post raderad
|
||||
infolog entry saved infolog sv InfoLogg post sparad
|
||||
infolog filter for the main screen infolog sv InfoLogg filter för Hemsidan
|
||||
infolog list infolog sv InfoLogg lista
|
||||
infolog preferences common sv InfoLogg alternativ
|
||||
infolog-fieldname infolog sv InfoLogg fältnamn
|
||||
invalid filename infolog sv Ogiltigt filnamn
|
||||
label<br>helptext infolog sv Etikett<br>Hjälptext
|
||||
last changed infolog sv Senaste ändring
|
||||
last modified infolog sv Senast ändrad
|
||||
leave it empty infolog sv Lämnas tomt
|
||||
leave without saveing the entry infolog sv Lämna utan att spara post
|
||||
leaves without saveing infolog sv Lämnar utan att spara
|
||||
length<br>rows infolog sv Längd<br>Rader
|
||||
link infolog sv Länk
|
||||
links infolog sv Länkar
|
||||
links of this entry infolog sv Postens länkar
|
||||
list all categories infolog sv Lista alla kategorier
|
||||
list no subs/childs infolog sv Lista inte underobjekt
|
||||
location infolog sv Placering
|
||||
longer textual description infolog sv Längre beskrivning
|
||||
low infolog sv Låg
|
||||
max length of the input [, length of the inputfield (optional)] infolog sv Max längd på indatafältet
|
||||
name must not be empty !!! infolog sv Namnet får inte vara tomt!
|
||||
name of new type to create infolog sv Skapa typ med namnet
|
||||
never hide search and filters infolog sv Göm aldrig sök eller filter
|
||||
new name infolog sv Nytt namn
|
||||
new search infolog sv Ny sökning
|
||||
no - cancel infolog sv Nej - Avbryt
|
||||
no describtion, links or attachments infolog sv Ingen beskrivning, länk eller bilaga
|
||||
no details infolog sv Inga detaljer
|
||||
no entries found, try again ... infolog sv Inga poster hittade, försök igen
|
||||
no filter infolog sv Inga filter
|
||||
no links or attachments infolog sv Inga länkar eller bilagor
|
||||
none infolog sv Ingen
|
||||
normal infolog sv Normal
|
||||
not infolog sv Inte
|
||||
not assigned infolog sv Inte tilldelad
|
||||
not-started infolog sv Inte påbörjad
|
||||
note infolog sv Anteckning
|
||||
number of records to read (%1) infolog sv Antal poster att läsa (%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog sv Antal rader för flera raders indata eller rad i flervals ruta
|
||||
offer infolog sv Erbjudande
|
||||
ongoing infolog sv Pågående
|
||||
only for details infolog sv Endast detaljer
|
||||
only the attachments infolog sv Endast bilagor
|
||||
only the links infolog sv Endast länkar
|
||||
open infolog sv Öppen
|
||||
optional note to the link infolog sv Frivillig anteckning till länken
|
||||
order infolog sv Sortering
|
||||
overdue infolog sv Förfallen
|
||||
own infolog sv Mina
|
||||
own open infolog sv Mina öppna
|
||||
own overdue infolog sv Mina förfallna
|
||||
own upcoming infolog sv Mina kommande
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog sv Sökväg på servern<br>ex. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog sv Sökväg till användar och grupp filer MÅSTE VARA UTANFÖR webbserverns dokument root!
|
||||
pattern for search in addressbook infolog sv Sökmönster i Adressboken
|
||||
pattern for search in projects infolog sv Sökmönster i Projekt
|
||||
percent completed infolog sv Procent färdig
|
||||
permission denied infolog sv Åtkomst nekas
|
||||
phone infolog sv Samtal
|
||||
phone/email infolog sv Telefon/E-post
|
||||
phonecall infolog sv Telefonsamtal
|
||||
planned infolog sv Planerad
|
||||
planned time infolog sv Planerad tid
|
||||
price infolog sv Pris
|
||||
priority infolog sv Prioritet
|
||||
private infolog sv Privat
|
||||
project infolog sv Projekt
|
||||
project settings: price, times infolog sv Projekt inställningar: Pris, antal
|
||||
re: infolog sv Sv:
|
||||
read one record by passing its id. infolog sv Ange ID för att läsa post
|
||||
read rights (default) infolog sv Läsrättighet (standard)
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog sv Giltigt uttryck för lokala IP-adresser.<br>dvs 192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog sv Giltigt uttryck för lokala IP-adresser.<br>dvs 192\.168\.1\.
|
||||
remark infolog sv Anmärkning
|
||||
remove this link (not the entry itself) infolog sv Radera länk (inte posten)
|
||||
responsible infolog sv Ansvarig
|
||||
responsible open infolog sv Ansvarig öppna
|
||||
responsible overdue infolog sv Ansvarig förfallna
|
||||
responsible upcoming infolog sv Ansvarig kommande
|
||||
responsible user, priority infolog sv Ansvarig användare, prioritet
|
||||
returns a list / search for records. infolog sv Returnerar lista / sök poster
|
||||
rights for the responsible infolog sv Rättigheter åt den ansvarige
|
||||
save infolog sv Spara
|
||||
saves the changes made and leaves infolog sv Spara ändringar och avsluta
|
||||
saves this entry infolog sv Spara post
|
||||
search infolog sv Sök
|
||||
search for: infolog sv Sök:
|
||||
select infolog sv Välj
|
||||
select a category for this entry infolog sv Välj kategori för posten
|
||||
select a price infolog sv Välj pris
|
||||
select a priority for this task infolog sv Välj prioritet för posten
|
||||
select a project infolog sv Välj projekt
|
||||
select a responsible user: a person you want to delegate this task infolog sv Välj ansvarig person, någon du delegerar ärendet till
|
||||
select a typ to edit it's status-values or delete it infolog sv Välj typ att ändra eller radera
|
||||
select an app to search in infolog sv Välj applikation att söka i
|
||||
select an entry to link with infolog sv Välj post att länka med
|
||||
select to filter by owner infolog sv Välj för att sortera enl ägare
|
||||
select to filter by responsible infolog sv Välj för att sortera enl ansvarig
|
||||
sets the status of this entry and its subs to done infolog sv Anger status för posten och alla under till färdig
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog sv Ska InfoLogg visa under- Uppgift, Samtal eller Anteckning i normala vyn eller inte? Du kan alltid visa dessa via topobjektet
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog sv Ska InfoLogg visa länkar till andra applikationer och/eller bilaga i InfoLogg vyn (normal vy när du öppnar InfoLogg)
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog sv Ska InfoLogg visas på Startsidan och med vilket filter. Fungerar bara om du inte valt en annan applikation till STartsidan (under alternativ)
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog sv Ska InfoLogg visa fullständiga namn (förnamn och efternamn) eller bara inloggningsnamnet?
|
||||
should the calendar show custom types too infolog sv Ska kalendern visa anpassade fält också
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog sv Ska InfoLogg visa unika numeriska ID som även kan användas som t.ex. ärende ID
|
||||
should the infolog list show the column "last modified". infolog sv Ska InfoLogg visa kolumnen "Senast ändrad"
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog sv Ska InfoLogg visa procent färdig enbart för status pågående eller två separata ikoner
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog sv Ska denna post enbart visas för dig och de du givit tillgång till via ACL?
|
||||
show a column for used and planned times in the list. infolog sv Visa kolumn för förbrukade och planerat antal i vyn
|
||||
show full usernames infolog sv Visa fullständigt användarnamn
|
||||
show in the infolog list infolog sv Visa i InfoLogg lista
|
||||
show last modified infolog sv Visa senast ändrad
|
||||
show status and percent done separate infolog sv Visa status och procent färdig separat
|
||||
show ticket id infolog sv Visa ärende ID
|
||||
show times infolog sv Visa antal
|
||||
small view infolog sv Liten vy
|
||||
start a new search, cancel this link infolog sv Gör ny sökning och avbryt denna länk
|
||||
startdate infolog sv Startdatum
|
||||
startdate enddate infolog sv Start- Slutdatum
|
||||
startdate for new entries infolog sv Startdatum för nya poster
|
||||
startrecord infolog sv Startposition
|
||||
status infolog sv Status
|
||||
status ... infolog sv Status ...
|
||||
sub infolog sv Under
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog sv Underposter blir underordnade huvudposten om det inte finns någon förälder
|
||||
subject infolog sv Ämne
|
||||
task infolog sv Uppgift
|
||||
test import (show importable records <u>only</u> in browser) infolog sv Testimport (visa importerara poster <u>bara</u> i browser)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog sv internt namn (<= 10 tecken), ändring gör existerande data otillgängligt
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog sv internt namn (<= 20 tecken), ändring gör existerande data otillgängligt
|
||||
the text displayed to the user infolog sv Texten som visas för användare
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog sv Detta filter använder InfoLogg när du öppnar applikationen. Filtren kan visa bara avslutade, öppna eller framtida objekt som tillhör dig eller alla.
|
||||
til when should the todo or phonecall be finished infolog sv Tills när ska Uppgift och Samtal vara utförda
|
||||
times infolog sv Antal
|
||||
to many might exceed your execution-time-limit infolog sv För många kan gå över exekverings tidgränsen
|
||||
to what should the startdate of new entries be set. infolog sv Till vilket startdatum ska nya poster sättas?
|
||||
today infolog sv Idag
|
||||
todays date infolog sv Dagens datum
|
||||
todo infolog sv Uppgift
|
||||
translation infolog sv Översättning
|
||||
typ infolog sv Typ
|
||||
typ '%1' already exists !!! infolog sv Typ '%1' finns redan
|
||||
type infolog sv Typ
|
||||
type ... infolog sv Typ ...
|
||||
type of customfield infolog sv Typ av anpassat fält
|
||||
type of the log-entry: note, phonecall or todo infolog sv Typ av InfoLogg: Anteckning, Samtal eller Uppgift
|
||||
unlink infolog sv Radera länk
|
||||
upcoming infolog sv Kommande
|
||||
urgency infolog sv Prioritet
|
||||
urgent infolog sv Brådskande
|
||||
used time infolog sv Förbrukad tid
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog sv Giltid sökväg för klient<br>t ex \\server\share eller e:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog sv Giltid sökväg för klient<br>t ex \\server\share eller e:\
|
||||
valid path on clientside<br>eg. servershare or e: infolog sv Giltid sökväg för klient<br>t ex \\server\share eller e:\
|
||||
values for selectbox infolog sv Värde för valrutan
|
||||
view all subs of this entry infolog sv Visa alla under denna post
|
||||
view other subs infolog sv Visa andra under
|
||||
view parent infolog sv Visa rot
|
||||
view subs infolog sv Visa under
|
||||
view the parent of this entry and all his subs infolog sv Visa rot till denna post och dess underkategorier
|
||||
view this linked entry in its application infolog sv Visa den länkade posten i dess applikation
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog sv När Uppgift och Samtal ska påbörjas visas de från aktuellt datum i Mina eller Mina öppna (Startsidan)
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog sv Vilka övriga fält ska ansvariga kunna ändra utan ändringsrättigheter?<br />Status, procent och datum är alltid tillåtna.
|
||||
which implicit acl rights should the responsible get? infolog sv Vilka ACL rättigheter ska den ansvarigefå?
|
||||
whole query infolog sv Hela frågan
|
||||
will-call infolog sv Ska ringa
|
||||
write (add or update) a record by passing its fields. infolog sv Fyll i fälten för att skapa eller uppdatera post
|
||||
yes - delete infolog sv Ja - Radera
|
||||
yes - delete including sub-entries infolog sv Ja - Radera inklusive under
|
||||
you can't delete one of the stock types !!! infolog sv Du kan inte radera inbyggda typer
|
||||
you have entered an invalid ending date infolog sv Ogiltigt Slutdatum
|
||||
you have entered an invalid starting date infolog sv Ogiltigt Startdatum
|
||||
you have to enter a name, to create a new typ!!! infolog sv Ange namn för att skapa typ
|
||||
you must enter a subject or a description infolog sv Ange ämne eller beskrivning
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog sv Din databas är inte uppdaterad (%1 vs. %2), var god och kör %3installationen%4 för att uppdatera.
|
360
infolog/lang/egw_zh-tw.lang
Normal file
360
infolog/lang/egw_zh-tw.lang
Normal file
@ -0,0 +1,360 @@
|
||||
%1 days in advance infolog zh-tw %1 天提出
|
||||
%1 deleted infolog zh-tw %1 刪除了
|
||||
%1 deleted by %2 at %3 infolog zh-tw %1 由 %2 在 %3 刪除了
|
||||
%1 modified infolog zh-tw %1 更新了
|
||||
%1 modified by %2 at %3 infolog zh-tw %1 由 %2 在 %3 更新了
|
||||
%1 records imported infolog zh-tw %1 筆資料匯入
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog zh-tw 讀取 %1 筆資料(尚未匯入,您可以回到 %2上一頁%3 並且取消匯入測試)
|
||||
%1 you are responsible for is due at %2 infolog zh-tw 您負責的 %1 到期日為 %2
|
||||
%1 you are responsible for is starting at %2 infolog zh-tw 您負責的 %1 開始日期為 %2
|
||||
%1 you delegated is due at %2 infolog zh-tw 您委派的 %1 到期日為 %2
|
||||
%1 you delegated is starting at %2 infolog zh-tw 您委派的 %1 開始日期為 %2
|
||||
- subprojects from infolog zh-tw - 附加專案來自
|
||||
0% infolog zh-tw 0%
|
||||
10% infolog zh-tw 10%
|
||||
100% infolog zh-tw 100%
|
||||
20% infolog zh-tw 20%
|
||||
30% infolog zh-tw 30%
|
||||
40% infolog zh-tw 40%
|
||||
50% infolog zh-tw 50%
|
||||
60% infolog zh-tw 60%
|
||||
70% infolog zh-tw 70%
|
||||
80% infolog zh-tw 80%
|
||||
90% infolog zh-tw 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog zh-tw <b>透過符號連結來附加檔案</b>取代原本上傳檔案的方式
|
||||
a short subject for the entry infolog zh-tw 一個簡短的主題
|
||||
abort without deleting infolog zh-tw 取消刪除
|
||||
accept infolog zh-tw 確定
|
||||
action infolog zh-tw 動作
|
||||
actual date and time infolog zh-tw 實際日期與時間
|
||||
add infolog zh-tw 新增
|
||||
add a file infolog zh-tw 新增檔案
|
||||
add a new entry infolog zh-tw 新增個事件
|
||||
add a new note infolog zh-tw 新增記事
|
||||
add a new phonecall infolog zh-tw 新增電話聯絡清單
|
||||
add a new sub-task, -note, -call to this entry infolog zh-tw 新增一個附屬工作、記事與連絡清單到這個事件
|
||||
add a new todo infolog zh-tw 新增待辦事項
|
||||
add file infolog zh-tw 新增檔案
|
||||
add sub infolog zh-tw 新增子分類
|
||||
add timesheet entry infolog zh-tw 新增時間表資料
|
||||
add: infolog zh-tw 新增:
|
||||
all infolog zh-tw 全部
|
||||
all links and attachments infolog zh-tw 所有的連結與附加檔案
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog zh-tw 允許設定事件的狀態,例如這個事件如果結束就將指定的待辦事項設定為完成(附屬在事件下的)
|
||||
apply the changes infolog zh-tw 儲存異動
|
||||
archive infolog zh-tw 歸檔
|
||||
are you shure you want to delete this entry ? infolog zh-tw 您確定要刪除這個事件?
|
||||
attach a file infolog zh-tw 附加一個檔案
|
||||
attach file infolog zh-tw 附加檔案
|
||||
attention: no contact with address %1 found. infolog zh-tw 注意:找不到住址為 %1 的聯絡人。
|
||||
back to main list infolog zh-tw 回到主要清單
|
||||
billed infolog zh-tw 已付款
|
||||
both infolog zh-tw 皆
|
||||
call infolog zh-tw 呼叫
|
||||
can be used to show further infolog types in the calendar or limit it to show eg. only tasks. infolog zh-tw 可以用來在行事曆顯示未來的記事類型或是限制顯示,例如任務
|
||||
cancel infolog zh-tw 取消
|
||||
cancelled infolog zh-tw 取消了
|
||||
categories infolog zh-tw 分類
|
||||
category infolog zh-tw 類別
|
||||
change the status of an entry, eg. close it infolog zh-tw 修改資料狀態,例如:關閉
|
||||
charset of file infolog zh-tw 檔案字元編碼
|
||||
check to set startday infolog zh-tw 設定開始日期
|
||||
check to specify custom contact infolog zh-tw 勾選這個項目來指定自訂聯絡人
|
||||
click here to create the link infolog zh-tw 點選這裡來建立連結
|
||||
click here to start the search infolog zh-tw 點選這裡來開始搜尋
|
||||
close infolog zh-tw 關閉
|
||||
comment infolog zh-tw 備註
|
||||
completed infolog zh-tw 完成了
|
||||
configuration infolog zh-tw 設定
|
||||
confirm infolog zh-tw 確認
|
||||
contact infolog zh-tw 聯絡
|
||||
copy your changes to the clipboard, %1reload the entry%2 and merge them. infolog zh-tw 複製異動資料到剪貼簿, %1重新讀取資料%2並且將他們合併。
|
||||
create new links infolog zh-tw 建立新的連結
|
||||
creates a new field infolog zh-tw 建立新的區域
|
||||
creates a new status with the given values infolog zh-tw 使用輸入的值來建立新的狀態
|
||||
creates a new typ with the given name infolog zh-tw 使用輸入的名稱來建立新的格式
|
||||
creation infolog zh-tw 建立
|
||||
csv-fieldname infolog zh-tw CSV-欄位名稱
|
||||
csv-filename infolog zh-tw CSV-檔案名稱
|
||||
csv-import common zh-tw CSV-匯入
|
||||
custom infolog zh-tw 自訂
|
||||
custom contact-address, leave empty to use information from most recent link infolog zh-tw 自訂聯絡住址,如果空白就會使用最近連結資訊
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog zh-tw 自訂聯絡資訊,如果空白就會使用最近連結資訊
|
||||
custom fields infolog zh-tw 自訂欄位
|
||||
custom fields, typ and status common zh-tw 自訂欄位、格式與狀態
|
||||
custom regarding infolog zh-tw 自訂關於
|
||||
custom status for typ infolog zh-tw 自訂格式的狀態
|
||||
customfields infolog zh-tw 自定欄位
|
||||
date completed infolog zh-tw 完成日期
|
||||
date completed (leave it empty to have it automatic set if status is done or billed) infolog zh-tw 完成日期(保留空白會自動使用狀態改為完成或已付款的時間)
|
||||
datecreated infolog zh-tw 建立日期
|
||||
dates, status, access infolog zh-tw 日期、狀態、存取
|
||||
days infolog zh-tw 日
|
||||
default filter for infolog infolog zh-tw 記事本的預設過濾方式
|
||||
default status for a new log entry infolog zh-tw 事件紀錄的預設狀態
|
||||
delegated infolog zh-tw 委派
|
||||
delegated open infolog zh-tw 進行中的委派
|
||||
delegated overdue infolog zh-tw 過期的委派
|
||||
delegated upcomming infolog zh-tw 即將開始的委派
|
||||
delegation infolog zh-tw 授權
|
||||
delete infolog zh-tw 刪除
|
||||
delete one record by passing its id. infolog zh-tw 透過傳遞ID來刪除記錄
|
||||
delete the entry infolog zh-tw 刪除這個事件
|
||||
delete this entry infolog zh-tw 刪除這個事件
|
||||
delete this entry and all listed sub-entries infolog zh-tw 刪除這筆資料與所有附屬的項目
|
||||
deleted infolog zh-tw 刪除了
|
||||
deletes the selected typ infolog zh-tw 刪除這個格式
|
||||
deletes this field infolog zh-tw 刪除這個欄位
|
||||
deletes this status infolog zh-tw 刪除這個狀態
|
||||
description infolog zh-tw 描述
|
||||
determines the order the fields are displayed infolog zh-tw 決定顯示的順序與欄位
|
||||
disables a status without deleting it infolog zh-tw 停用一個狀態而不是刪除
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog zh-tw 您希望做再次的確認在:同意,工作完成或是兩者都要
|
||||
do you want a notification, if items get assigned to you or assigned items get updated? infolog zh-tw 項目指派給您或是指派的項目有更新時,您是否想要收到提醒?
|
||||
do you want a notification, if items you are responsible for are about to start? infolog zh-tw 您負責的項目快要開始時,您是否想要收到提醒?
|
||||
do you want a notification, if items you are responsible for are due? infolog zh-tw 您負責的項目過期時,您是否想要收到提醒?
|
||||
do you want a notification, if items you created get updated? infolog zh-tw 您建立的項目更新時,您是否想要收到提醒?
|
||||
do you want a notification, if items you delegated are about to start? infolog zh-tw 您指派的項目快要開始時,您是否想要收到提醒?
|
||||
do you want a notification, if items you delegated are due? infolog zh-tw 您指派的項目過期時,您是否想要收到提醒?
|
||||
do you want to receive notifications as html-mails or plain text? infolog zh-tw 您希望收到的提醒信件格式為 html 或純文字?
|
||||
don't show infolog infolog zh-tw 不要顯示記事本
|
||||
done infolog zh-tw 完成
|
||||
download infolog zh-tw 下載
|
||||
duration infolog zh-tw 進行期間
|
||||
each value is a line like <id>[=<label>] infolog zh-tw 每個值都是這樣的線 <id>[=<label>]
|
||||
edit infolog zh-tw 編輯
|
||||
edit or create categories for ingolog infolog zh-tw 編輯或建立訊息紀錄的類別
|
||||
edit rights (full edit rights incl. making someone else responsible!) infolog zh-tw 編輯權限(完整的編輯權限包括指定負責人!)
|
||||
edit status infolog zh-tw 編輯狀態
|
||||
edit the entry infolog zh-tw 編輯這個事件
|
||||
edit this entry infolog zh-tw 編輯這個事件
|
||||
empty for all infolog zh-tw 全部空白
|
||||
enddate infolog zh-tw 結束日期
|
||||
enddate can not be before startdate infolog zh-tw 結束日期不應該在開始日期之前
|
||||
enter a custom contact, leave empty if linked entry should be used infolog zh-tw 輸入一個自訂的聯絡人,如果連結的事件必須使用就請保持空白
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog zh-tw 輸入一個自訂的電話/email,如果連結的事件必須使用就請保持空白
|
||||
enter a textual description of the log-entry infolog zh-tw 輸入事件紀錄的原始描述
|
||||
enter the query pattern infolog zh-tw 輸入查詢的方式
|
||||
entry and all files infolog zh-tw 事件與所有檔案
|
||||
error: saving the entry infolog zh-tw 錯誤: 儲存資料時
|
||||
error: the entry has been updated since you opened it for editing! infolog zh-tw 錯誤: 在您開始編輯後這個資料已經被其他人更新了!
|
||||
existing links infolog zh-tw 已經存在的連結
|
||||
fax infolog zh-tw 傳真
|
||||
fieldseparator infolog zh-tw 欄位分隔字元
|
||||
finish infolog zh-tw 完成
|
||||
for which types should this field be used infolog zh-tw 這個欄位使用什麼格式
|
||||
from infolog zh-tw 從
|
||||
general infolog zh-tw 一般
|
||||
group owner for infolog zh-tw 群組擁有者
|
||||
high infolog zh-tw 高
|
||||
history logging infolog zh-tw 歷史記錄
|
||||
history logging and deleting of items infolog zh-tw 歷史記錄與刪除項目
|
||||
id infolog zh-tw ID
|
||||
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog zh-tw 如果一個類型有群組擁有者,所有該類型的資料將會屬於指定的群組而非建立的使用者!
|
||||
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog zh-tw 如果沒有設定,在資料數量少於"每頁顯示資料數量上限"(在您的一般設定中)時會隱藏過濾與搜尋功能。
|
||||
import infolog zh-tw 匯入
|
||||
import next set infolog zh-tw 匯入下一組
|
||||
info log common zh-tw 記事本
|
||||
infolog common zh-tw 記事本
|
||||
infolog - delete infolog zh-tw 記事本 - 刪除
|
||||
infolog - edit infolog zh-tw 記事本 - 編輯
|
||||
infolog - import csv-file infolog zh-tw 記事本 - 匯入CSV檔案
|
||||
infolog - new infolog zh-tw 記事本 - 新增
|
||||
infolog - new subproject infolog zh-tw 記事本 - 新增附屬專案
|
||||
infolog - subprojects from infolog zh-tw 記事本 - 附屬專案自
|
||||
infolog entry deleted infolog zh-tw 記事本資料刪除了
|
||||
infolog entry saved infolog zh-tw 記事本資料儲存了
|
||||
infolog filter for the main screen infolog zh-tw 首頁的記事本顯示規則
|
||||
infolog list infolog zh-tw 記事本清單
|
||||
infolog preferences common zh-tw 記事本設定
|
||||
infolog-fieldname infolog zh-tw 記事本 - 欄位名稱
|
||||
invalid filename infolog zh-tw 錯誤的檔案名稱
|
||||
label<br>helptext infolog zh-tw 標籤<br>說明文字
|
||||
last changed infolog zh-tw 最後修改
|
||||
last modified infolog zh-tw 最後修改
|
||||
leave it empty infolog zh-tw 保持空白
|
||||
leave without saveing the entry infolog zh-tw 離開並且不要儲存這個事件
|
||||
leaves without saveing infolog zh-tw 離開並且不要儲存
|
||||
length<br>rows infolog zh-tw 長度<br>列
|
||||
link infolog zh-tw 連結
|
||||
links infolog zh-tw 連結
|
||||
links of this entry infolog zh-tw 這個事件的連結
|
||||
list all categories infolog zh-tw 列出所有類別
|
||||
list no subs/childs infolog zh-tw 不要列出附屬資訊
|
||||
location infolog zh-tw 位置
|
||||
longer textual description infolog zh-tw 較長的原文描述
|
||||
low infolog zh-tw 低
|
||||
max length of the input [, length of the inputfield (optional)] infolog zh-tw 最大輸入長度[, 輸入欄位長度 (選填)]
|
||||
name must not be empty !!! infolog zh-tw 名稱不能空白!
|
||||
name of new type to create infolog zh-tw 建立新的格式名稱
|
||||
never hide search and filters infolog zh-tw 永遠顯示搜尋與過濾功能
|
||||
new %1 infolog zh-tw 新 %1
|
||||
new %1 created by %2 at %3 infolog zh-tw 新 %1 由 %2 在 %3 建立
|
||||
new name infolog zh-tw 新的名稱
|
||||
new search infolog zh-tw 新的搜尋
|
||||
no - cancel infolog zh-tw 否 - 取消
|
||||
no describtion, links or attachments infolog zh-tw 沒有說明、連結或附加檔案
|
||||
no details infolog zh-tw 沒有細節
|
||||
no entries found, try again ... infolog zh-tw 沒有找到任何事件,請重新嘗試...
|
||||
no filter infolog zh-tw 沒有過濾規則
|
||||
no links or attachments infolog zh-tw 沒有連結或附加檔案
|
||||
nonactive infolog zh-tw 停用
|
||||
none infolog zh-tw 無
|
||||
normal infolog zh-tw 一般
|
||||
not infolog zh-tw 否
|
||||
not assigned infolog zh-tw 不指定
|
||||
not-started infolog zh-tw 未開始
|
||||
note infolog zh-tw 記事
|
||||
number of records to read (%1) infolog zh-tw 讀取的資料筆數(%1)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog zh-tw 輸入欄位或是下拉式選單的數量
|
||||
offer infolog zh-tw 提供
|
||||
one day after infolog zh-tw 一天後
|
||||
one day in advance infolog zh-tw 一天前
|
||||
ongoing infolog zh-tw 不間斷的
|
||||
only for details infolog zh-tw 只顯示細節
|
||||
only if i get assigned or removed infolog zh-tw 只在我被指派或移除時
|
||||
only the attachments infolog zh-tw 只有附加檔案
|
||||
only the links infolog zh-tw 只有連結
|
||||
open infolog zh-tw 開啟
|
||||
optional note to the link infolog zh-tw 連結的附加說明
|
||||
order infolog zh-tw 順序
|
||||
overdue infolog zh-tw 過期的
|
||||
own infolog zh-tw 自己的
|
||||
own open infolog zh-tw 開啟自己的
|
||||
own overdue infolog zh-tw 自己的過期
|
||||
own upcoming infolog zh-tw 自己的即將來臨
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog zh-tw 伺服器(網站-)路徑<br>例如/var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog zh-tw 使用者與群組檔案路徑必須在網站伺服器的網頁根目錄之外!
|
||||
pattern for search in addressbook infolog zh-tw 搜尋通訊錄的條件
|
||||
pattern for search in projects infolog zh-tw 搜尋專案的條件
|
||||
percent completed infolog zh-tw 完成比例
|
||||
permission denied infolog zh-tw 拒絕存取
|
||||
phone infolog zh-tw 聯絡清單
|
||||
phone/email infolog zh-tw 電話/Email
|
||||
phonecall infolog zh-tw 聯絡清單
|
||||
planned infolog zh-tw 已規劃
|
||||
planned time infolog zh-tw 已規劃時間
|
||||
price infolog zh-tw 價格
|
||||
priority infolog zh-tw 優先權
|
||||
private infolog zh-tw 私人的
|
||||
project infolog zh-tw 專案
|
||||
project settings: price, times infolog zh-tw 專案設定: 價格、時間
|
||||
re: infolog zh-tw 回覆:
|
||||
read one record by passing its id. infolog zh-tw 透過傳遞ID來讀取記錄
|
||||
read rights (default) infolog zh-tw 閱讀權限(預設)
|
||||
receive notifications about due entries you are responsible for infolog zh-tw 接收您負責項目即將過期的提醒
|
||||
receive notifications about due entries you delegated infolog zh-tw 接收您指派項目即將過期的提醒
|
||||
receive notifications about items assigned to you infolog zh-tw 接收項目指派給您的提醒
|
||||
receive notifications about own items infolog zh-tw 接收自己項目的提醒
|
||||
receive notifications about starting entries you are responsible for infolog zh-tw 接收您負責項目即將開始的提醒
|
||||
receive notifications about starting entries you delegated infolog zh-tw 接收您指派項目即將開始的提醒
|
||||
receive notifications as html-mails infolog zh-tw 提醒信件格式為 html
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog zh-tw 本地端IP的過濾規則<br>例如^192\.168\.1\.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog zh-tw 本地端IP的過濾規則<br>例如^192\.168\.1\.
|
||||
remark infolog zh-tw 標註
|
||||
remove this link (not the entry itself) infolog zh-tw 移除這個連結(不是它的資料)
|
||||
responsible infolog zh-tw 責任
|
||||
responsible open infolog zh-tw 責任開始時間
|
||||
responsible overdue infolog zh-tw 責任期間
|
||||
responsible upcoming infolog zh-tw 即將產生的責任
|
||||
responsible user, priority infolog zh-tw 負責人、順序
|
||||
returns a list / search for records. infolog zh-tw 傳回一個清單 / 搜尋記錄
|
||||
rights for the responsible infolog zh-tw 負責人權限
|
||||
same day infolog zh-tw 同一天
|
||||
save infolog zh-tw 儲存
|
||||
saves the changes made and leaves infolog zh-tw 儲存後離開
|
||||
saves this entry infolog zh-tw 儲存這個事件
|
||||
search infolog zh-tw 搜尋
|
||||
search for: infolog zh-tw 搜尋:
|
||||
select infolog zh-tw 選擇
|
||||
select a category for this entry infolog zh-tw 選擇這個事件的類別
|
||||
select a price infolog zh-tw 選擇價格
|
||||
select a priority for this task infolog zh-tw 選擇這個任務的優先權
|
||||
select a project infolog zh-tw 選擇專案
|
||||
select a responsible user: a person you want to delegate this task infolog zh-tw 選擇負責人:這個任務的代表人
|
||||
select a typ to edit it's status-values or delete it infolog zh-tw 選擇一個格式來編輯它的狀態或是將它刪除
|
||||
select an app to search in infolog zh-tw 選擇要搜尋的應用程式
|
||||
select an entry to link with infolog zh-tw 選擇要連結的事件
|
||||
select to filter by owner infolog zh-tw 依據擁有者過濾
|
||||
select to filter by responsible infolog zh-tw 依據負責人過濾
|
||||
sets the status of this entry and its subs to done infolog zh-tw 設定這筆資料與附屬項目的狀態為完成
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog zh-tw 記事本需要在一般瀏覽中顯示附屬任務,聯絡清單或是記事嗎?您可以在原始事件中看到附屬的資訊。
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when you enter infolog). infolog zh-tw 記事本是否要顯示與其他應用程式的連結與/或附加檔案(通常會在進入記事本時看到)。
|
||||
should infolog show up on the main screen and with which filter. works only if you dont selected an application for the main screen (in your preferences). infolog zh-tw 首頁要依據指定的規則顯示記事本嗎?如果您沒有設定預設的應用程式(偏好中)就會顯示。
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog zh-tw 記事本使用全名或是登入名稱?
|
||||
should the infolog list show a unique numerical id, which can be used eg. as ticket id. infolog zh-tw 記事清單是否要顯示唯一的編號,其他功能可能會需要,例如傳票編號。
|
||||
should the infolog list show the column "last modified". infolog zh-tw 記事本清單要顯示異動日期欄位嗎?
|
||||
should the infolog list show the percent done only for status ongoing or two separate icons. infolog zh-tw 記事清單是否只要顯示進行中狀態完成的比率或是兩個獨立的圖示。
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog zh-tw 這個事件只允許您以及您從ACL取得存取權限的人?
|
||||
show a column for used and planned times in the list. infolog zh-tw 在清單中顯示一個用於已使用與已規劃時間的欄位。
|
||||
show full usernames infolog zh-tw 顯示完整的使用者姓名
|
||||
show in the infolog list infolog zh-tw 在記事本清單中顯示
|
||||
show last modified infolog zh-tw 顯示異動日期
|
||||
show status and percent done separate infolog zh-tw 將狀態與完成度比率分開
|
||||
show ticket id infolog zh-tw 顯示傳票編號
|
||||
show times infolog zh-tw 顯示時間
|
||||
small view infolog zh-tw 縮小
|
||||
start a new search, cancel this link infolog zh-tw 開啟一個新的搜尋並且取消這個連結
|
||||
startdate infolog zh-tw 開始日期
|
||||
startdate enddate infolog zh-tw 開始日期 結束日期
|
||||
startdate for new entries infolog zh-tw 新資料的開始日期
|
||||
startrecord infolog zh-tw 開始紀錄
|
||||
status infolog zh-tw 狀態
|
||||
status ... infolog zh-tw 狀態...
|
||||
sub infolog zh-tw 附屬
|
||||
sub-entries become subs of the parent or main entries, if there's no parent infolog zh-tw 如果沒有父項目的資訊,附屬資料會歸屬到主要資料的父項目
|
||||
subject infolog zh-tw 主題
|
||||
task infolog zh-tw 待辦事項
|
||||
template infolog zh-tw 樣板
|
||||
test import (show importable records <u>only</u> in browser) infolog zh-tw 測試匯入(<u>只在</u>瀏覽器中顯示可以匯入的資料)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog zh-tw 內部名稱(小於10個字元),修改它將造成目前的資料無法瀏覽
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog zh-tw 內部名稱(小於20個字元),修改它將造成目前的資料無法瀏覽
|
||||
the text displayed to the user infolog zh-tw 給使用者的訊息
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog zh-tw 這是記事本在您進入這個應用程式時使用的過濾方式,過濾方式將會限制實際瀏覽的事件。過濾方式可以決定您自己或是所有使用者"已經完成的","進行中"或是"未來的事件"
|
||||
til when should the todo or phonecall be finished infolog zh-tw 待辦事項或是聯絡清單應該完成的時間
|
||||
times infolog zh-tw 時間
|
||||
to many might exceed your execution-time-limit infolog zh-tw 超過了程式執行時間
|
||||
to what should the startdate of new entries be set. infolog zh-tw 新資料的開始日期應該設定為什麼。
|
||||
today infolog zh-tw 今天
|
||||
todays date infolog zh-tw 今天日期
|
||||
todo infolog zh-tw 待辦事項
|
||||
translation infolog zh-tw 翻譯
|
||||
typ infolog zh-tw 格式
|
||||
typ '%1' already exists !!! infolog zh-tw '%1' 格式已經存在!
|
||||
type infolog zh-tw 格式
|
||||
type ... infolog zh-tw 格式 ...
|
||||
type of customfield infolog zh-tw 自訂欄位類型
|
||||
type of the log-entry: note, phonecall or todo infolog zh-tw 紀錄簿的格式:記事、聯絡清單或是待辦事項
|
||||
unlink infolog zh-tw 刪除
|
||||
upcoming infolog zh-tw 即將到來
|
||||
urgency infolog zh-tw 緊急
|
||||
urgent infolog zh-tw 緊急的
|
||||
used time infolog zh-tw 使用的時間
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog zh-tw 用戶端可用的路徑<br>例如\\Server\Share 或是 e:\
|
||||
valid path on clientside<br>eg. \servershare or e: infolog zh-tw 用戶端可用的路徑<br>例如\\Server\Share 或是 e:\
|
||||
values for selectbox infolog zh-tw 選單的值
|
||||
view all subs of this entry infolog zh-tw 顯示這個事件的所有附屬資訊
|
||||
view other subs infolog zh-tw 顯示其他附屬資訊
|
||||
view parent infolog zh-tw 顯示主要的
|
||||
view subs infolog zh-tw 顯示附屬的
|
||||
view the parent of this entry and all his subs infolog zh-tw 顯示這個事件的主要與所有附屬事件
|
||||
view this linked entry in its application infolog zh-tw 在應用程式中顯示這個被連結的事件
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog zh-tw 待辦事項或是聯絡清單應該開始的時間?當過濾條件為"所有未完成"或是"自己未完成"時顯示在開始頁面。
|
||||
which additional fields should the responsible be allowed to edit without having edit rights?<br />status, percent and date completed are always allowed. infolog zh-tw 哪些額外欄位即使負責人沒有編輯權限也能夠編輯?<br />狀態、比率與完成日期預設都會允許。
|
||||
which implicit acl rights should the responsible get? infolog zh-tw 負責人可以取得哪個隱含的權限?
|
||||
which types should the calendar show infolog zh-tw 行事曆要顯示哪些類型
|
||||
whole query infolog zh-tw 整個查詢
|
||||
will-call infolog zh-tw 將連絡
|
||||
write (add or update) a record by passing its fields. infolog zh-tw 透過傳遞它的欄位來寫入(新增或更新)一筆記錄
|
||||
yes - delete infolog zh-tw 確定 - 刪除
|
||||
yes - delete including sub-entries infolog zh-tw 確定 - 刪除(包含附屬資料)
|
||||
yes, noone can purge deleted items infolog zh-tw 是,沒有人可以排除刪除的項目
|
||||
yes, only admins can purge deleted items infolog zh-tw 是,只有管理者可以排除刪除的項目
|
||||
yes, with larger fontsize infolog zh-tw 是,使用較大的字體
|
||||
yes, with purging of deleted items possible infolog zh-tw 是,與可能排除的項目
|
||||
you can't delete one of the stock types !!! infolog zh-tw 您不能刪除股票的種類!
|
||||
you have entered an invalid ending date infolog zh-tw 您輸入了錯誤的結束日期
|
||||
you have entered an invalid starting date infolog zh-tw 您輸入了錯誤的開始日期
|
||||
you have to enter a name, to create a new typ!!! infolog zh-tw 您必須輸入一個名稱來建立一個新的格式!
|
||||
you must enter a subject or a description infolog zh-tw 您必須輸入主題或是描述
|
||||
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. infolog zh-tw 您的資料庫架構需要更新(%1 vs. %2),請執行%3安裝%4來更新資料庫。
|
280
infolog/lang/egw_zh.lang
Normal file
280
infolog/lang/egw_zh.lang
Normal file
@ -0,0 +1,280 @@
|
||||
%1 records imported infolog zh 已导入%1条记录
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog zh 已读取%1条记录(但尚未导入,您可以进入%2,返回%3,并且清除"测试导入"复选框)
|
||||
%1 records read (not yet imported, you may go back and uncheck test import) infolog zh 已读取%1条记录(但尚未导入,您可以进入%2,返回%3,并且清除"测试导入"复选框)
|
||||
- subprojects from infolog zh - 子项目来自
|
||||
0% infolog zh 0%
|
||||
10% infolog zh 10%
|
||||
20% infolog zh 20%
|
||||
30% infolog zh 30%
|
||||
40% infolog zh 40%
|
||||
50% infolog zh 50%
|
||||
60% infolog zh 60%
|
||||
70% infolog zh 70%
|
||||
80% infolog zh 80%
|
||||
90% infolog zh 90%
|
||||
<b>file-attachments via symlinks</b> instead of uploads and retrieval via file:/path for direct lan-clients infolog zh <b>通过符号链接添加文件</b> 而不是通过局域网客户端的file:/path来上传和下载
|
||||
a short subject for the entry infolog zh 请输入该事项的标题
|
||||
abort without deleting infolog zh 放弃,不作任何删除
|
||||
accept infolog zh 接受
|
||||
action infolog zh 操作
|
||||
add infolog zh 新建事项
|
||||
add a file infolog zh 添加文件
|
||||
add a new entry infolog zh 新建事项
|
||||
add a new note infolog zh 新建备注
|
||||
add a new phonecall infolog zh 新建函电
|
||||
add a new sub-task, -note, -call to this entry infolog zh 新建该事项的子任务, 备注, 或函电
|
||||
add a new todo infolog zh 新建任务
|
||||
add file infolog zh 添加文件
|
||||
add sub infolog zh 添加子类别
|
||||
add: infolog zh 添加:
|
||||
all infolog zh 全部
|
||||
all links and attachments infolog zh 所有关联条目及关联文件
|
||||
allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog zh 允许设置条目的状态, 例如, 设置一个任务已完成(设定值取决于条目类型)
|
||||
applies the changes infolog zh 应用更改
|
||||
are you shure you want to delete this entry ? infolog zh 确定要删除该事项吗?
|
||||
are you sure you want to delete this entry infolog zh 确定要删除该事项
|
||||
attach infolog zh 关联
|
||||
attach a file infolog zh 添加文件
|
||||
attach file infolog zh 添加关联文件
|
||||
back to main list infolog zh 返回主列表
|
||||
back to projectlist infolog zh 返回项目列表
|
||||
billed infolog zh 付费
|
||||
both infolog zh 都
|
||||
call infolog zh 已致电
|
||||
cancel infolog zh 取消
|
||||
categories infolog zh 类别
|
||||
category infolog zh 类别
|
||||
change the status of an entry, eg. close it infolog zh 更改该事项的状态.
|
||||
charset of file infolog zh 文件编码
|
||||
check to set startday infolog zh 选中此项设定起始日期
|
||||
click here to attach the file infolog zh 点击此处关联该文件
|
||||
click here to create the link infolog zh 点击此处关联该条目
|
||||
click here to start the search infolog zh 点击此处开始搜索
|
||||
close infolog zh 关闭
|
||||
comment infolog zh 注释
|
||||
configuration infolog zh 全局配置
|
||||
confirm infolog zh 确认
|
||||
contact infolog zh 联系人
|
||||
create new links infolog zh 新建关联
|
||||
creates a new field infolog zh 新建字段
|
||||
creates a new status with the given values infolog zh 新建状态
|
||||
creates a new typ with the given name infolog zh 新建类型
|
||||
csv-fieldname infolog zh CSV - 字段名
|
||||
csv-filename infolog zh CSV文件名
|
||||
csv-import common zh 从CSV文件导入
|
||||
custom infolog zh 自定义
|
||||
custom contact-address, leave empty to use information from most recent link infolog zh 请输入联系方式. 留空将自动设为首要关联
|
||||
custom contact-information, leave emtpy to use information from most recent link infolog zh 请输入联系人信息. 留空将自动设为首要关联
|
||||
custom fields infolog zh 自定义字段
|
||||
custom fields, typ and status common zh 自定义字段, 类型及状态
|
||||
custom regarding infolog zh 自定义关于
|
||||
custom status for typ infolog zh 自定义该类型的可选状态:
|
||||
customfields infolog zh Customfields
|
||||
datecreated infolog zh 日期已创建
|
||||
dates, status, access infolog zh 其他信息
|
||||
days infolog zh 日
|
||||
default infolog zh 默认状态
|
||||
default filter for infolog infolog zh 浏览事项时的默认查看范围
|
||||
default status for a new log entry infolog zh 新建该类型事项的默认状态
|
||||
delegation infolog zh 委派
|
||||
delete infolog zh 删除
|
||||
delete all subs (if not subs will be subs of this enties parent or have no parent) infolog zh Delete all subs (if not subs will be subs of this enties parent or have no parent)
|
||||
delete one record by passing its id. infolog zh 通过事项ID删除事件
|
||||
delete the entry infolog zh 删除该事项
|
||||
delete this entry infolog zh 删除该事项
|
||||
deletes the selected typ infolog zh 删除选定类型
|
||||
deletes this field infolog zh 删除该字段
|
||||
deletes this status infolog zh 删除该状态
|
||||
description infolog zh 内容
|
||||
description can not exceed 8000 characters in length infolog zh 事项内容最多包含8000个字符
|
||||
determines the order the fields are displayed infolog zh 设定字段的显示顺序
|
||||
disables a status without deleting it infolog zh 禁用状态,但不删除
|
||||
do you want a confirmation of the responsible on: accepting, finishing the task or both infolog zh 在接受或结束任务时,是否等待确认
|
||||
done infolog zh 已完成
|
||||
download infolog zh 下载
|
||||
duration infolog zh 持续时间
|
||||
each value is a line like <id>[=<label>] infolog zh 请设定选择框的选项, 格式: <选项名>=<显示名>, 每行代表一个选项.
|
||||
edit infolog zh 编辑
|
||||
edit or create categories for ingolog infolog zh 编辑或创建记事薄的类别
|
||||
edit status infolog zh Edit Status
|
||||
edit the entry infolog zh 编辑该事项
|
||||
edit this entry infolog zh 编辑该事项
|
||||
empty for all infolog zh 全部清空
|
||||
enddate infolog zh 终止日期
|
||||
enddate can not be before startdate infolog zh 终止日期必须在起始日期之后
|
||||
enter a custom contact, leave empty if linked entry should be used infolog zh 输入自定义联系人, 留空则使用链接条目
|
||||
enter a custom phone/email, leave empty if linked entry should be used infolog zh 输入自定义电话号码/EMail地址, 留空则使用链接条目
|
||||
enter a search pattern infolog zh 输入关键字
|
||||
enter a textual description of the log-entry infolog zh 输入该事项的具体内容
|
||||
enter filename to upload and attach, use [browse...] to search for it infolog zh 请输入待关联文件的名称, 或通过点击[浏览]来选定文件
|
||||
enter the query pattern infolog zh 输入查询模式
|
||||
entry and all files infolog zh 条目及所有文件
|
||||
existing links infolog zh 现有关联
|
||||
fax infolog zh 传真
|
||||
fieldseparator infolog zh 字段分隔符
|
||||
file infolog zh 文件
|
||||
finish infolog zh 结束
|
||||
for which types should this field be used infolog zh 请选择字段所属类型, 即字段对哪些类型的事项可见
|
||||
from infolog zh 寄件人
|
||||
global categories infolog zh 全局类别
|
||||
high infolog zh 高
|
||||
id infolog zh 代号
|
||||
import infolog zh 导入
|
||||
import next set infolog zh 导入下一配置
|
||||
info log common zh 记事薄
|
||||
infolog common zh 记事薄
|
||||
infolog index infolog zh 索引
|
||||
infolog - delete infolog zh 记事薄-删除
|
||||
infolog - edit infolog zh 记事薄-编辑
|
||||
infolog - import csv-file infolog zh 记事薄 - 从CSV文件导入
|
||||
infolog - new infolog zh 记事薄-新建
|
||||
infolog - new subproject infolog zh 记事薄 - 新建子项目
|
||||
infolog - subprojects from infolog zh 记事薄 - 子项目来自
|
||||
infolog list infolog zh 浏览事项
|
||||
infolog preferences common zh 记事薄个性化配置
|
||||
infolog-fieldname infolog zh 记事薄 - 字段名
|
||||
invalid filename infolog zh 文件名无效
|
||||
label infolog zh 显示名
|
||||
label<br>helptext infolog zh 标签<br>提示信息
|
||||
last changed infolog zh 最近修改记录
|
||||
last modified infolog zh 最近修改记录
|
||||
leave without saveing the entry infolog zh 取消, 不保存对该事项的操作
|
||||
leaves without saveing infolog zh 取消, 不作保存
|
||||
length<br>rows infolog zh 长度<br>高度
|
||||
link infolog zh 关联
|
||||
links infolog zh 关联
|
||||
links of this entry infolog zh 设定与事项相关的条目或文件
|
||||
list no subs/childs infolog zh 不显示子事项
|
||||
list all categories infolog zh 列出所有类别
|
||||
longer textual description infolog zh 设定事项的具体内容
|
||||
low infolog zh 低
|
||||
max length of the input [, length of the inputfield (optional)] infolog zh 输入文本的最大长度[,文本框的宽度]
|
||||
max number of entries to display on the main screen infolog zh 首页中显示的最大事项数目
|
||||
name must not be empty !!! infolog zh 名称不能为空!!!
|
||||
name of new type to create infolog zh 请输入新建类型的名称
|
||||
new name infolog zh 新名称
|
||||
new search infolog zh 重新搜索
|
||||
no - cancel infolog zh 否
|
||||
no entries found, try again ... infolog zh 未发现条目, 再次尝试 ...
|
||||
no filter infolog zh 所有事项
|
||||
no links or attachments infolog zh 不显示任何关联
|
||||
none infolog zh 无
|
||||
normal infolog zh 普通
|
||||
not infolog zh not
|
||||
not assigned infolog zh 未指定
|
||||
note infolog zh 备注
|
||||
number of records to read (%1) infolog zh 待读取记录数(%1)
|
||||
number of records to read (<=200) infolog zh 读取的记录数(<=200)
|
||||
number of row for a multiline inputfield or line of a multi-select-box infolog zh 文本框或多选框的高度
|
||||
of infolog zh 总共
|
||||
offer infolog zh 等待回应
|
||||
ongoing infolog zh 正在进行
|
||||
only the attachments infolog zh 仅显示关联文件
|
||||
only the links infolog zh 仅显示关联条目
|
||||
only up to this number of entries are displayed on the main screen. infolog zh 首页中最多可显示多少事项?
|
||||
open infolog zh 待决事项
|
||||
optional note about the link infolog zh 该关联的说明
|
||||
optional note to the link infolog zh 该关联的说明
|
||||
order infolog zh 顺序
|
||||
overdue infolog zh 延误事项
|
||||
own infolog zh 个人事项
|
||||
own open infolog zh 待决的个人事项
|
||||
own overdue infolog zh 延误的个人事项
|
||||
own upcoming infolog zh 临近的个人事项
|
||||
owner infolog zh 所有者
|
||||
owner responsible infolog zh 负责人
|
||||
path on (web-)serverside<br>eg. /var/samba/share infolog zh (Web)服务器端的路径<br>例如. /var/samba/Share
|
||||
path to user and group files has to be outside of the webservers document-root!!! infolog zh 存放用户和组文件的路径不能在Web服务器的根目录内!!!
|
||||
pattern for search in addressbook infolog zh 查找通讯录的模式
|
||||
pattern for search in projects infolog zh 查找项目的模式
|
||||
phone infolog zh 函电
|
||||
phone/email infolog zh 电话号码/EMail地址
|
||||
phonecall infolog zh 函电
|
||||
priority infolog zh 优先级
|
||||
private infolog zh 私有事项
|
||||
project infolog zh 项目
|
||||
re: infolog zh 回复:
|
||||
read one record by passing its id. infolog zh 通过事项ID来读取记录
|
||||
reg. expr. for local ip's<br>eg. ^192.168.1. infolog zh 本地IP地址的正则表达式<br>例如. ^192.168.1.
|
||||
reg. expr. for local ip's<br>eg. ^192\.168\.1\. infolog zh 本地IP地址的正则表达式<br>例如.. ^192\.168\.1\.
|
||||
remark infolog zh 注释
|
||||
remove this link (not the entry itself) infolog zh 取消关联
|
||||
responsible infolog zh 委派给
|
||||
responsible user, priority, ... infolog zh 设定事项的委派及优先级
|
||||
returns a list / search for records. infolog zh 返回一个清单 / 搜索记录
|
||||
save infolog zh 确定
|
||||
saves the changes made and leaves infolog zh 保存更改, 返回上一级页面
|
||||
saves this entry infolog zh 保存该条目
|
||||
search infolog zh 搜索
|
||||
search for: infolog zh 查找:
|
||||
select infolog zh 指定
|
||||
select a category for this entry infolog zh 指定该事项的类别
|
||||
select a primary contact, to show in the list infolog zh 指定在浏览事项时显示的首要关联
|
||||
select a priority for this task infolog zh 指定该任务的优先级
|
||||
select a responsible user: a person you want to delegate this task infolog zh 请指定受委派的用户, 将该事项委派给此人.
|
||||
select a typ to edit it's status-values or delete it infolog zh 选定一个类型以编辑其状态值或删除
|
||||
select an app to search in infolog zh 选定要查找的应用程序
|
||||
select an entry to link with infolog zh 选定要链接的条目
|
||||
should infolog display your open entries - not finised tasks, phonecalls or notes - on the main screen. works only if you dont selected an application for the main screen (in your preferences). infolog zh 待决事项指未完成的事项. 该选项仅当未设定首页应用程序时有效.
|
||||
should infolog show subtasks, -calls or -notes in the normal view or not. you can always view the subs via there parent. infolog zh 浏览事项时是否显示子事项? 无论该选项如何设定, 用户总可以经由父事项来查看子事项.
|
||||
should infolog show the links to other applications and/or the file-attachments in the infolog list (normal view when u enter infolog). infolog zh 浏览事项时是否显示各事项的关联条目和关联文件?
|
||||
should infolog use full names (surname and familyname) or just the loginnames. infolog zh 在记事薄中显示姓名还是登录名.
|
||||
should this entry only be visible to you and people you grant privat access via the acl infolog zh 是否仅所有者本人及其授权的用户可以访问该事项?
|
||||
show full usernames infolog zh 显示完整的用户名
|
||||
show in the infolog list infolog zh 浏览事项时是否显示关联?
|
||||
show list of upcoming entries infolog zh 仅显示临近的事项
|
||||
show open entries: tasks/calls/notes on main screen infolog zh 在首页显示待决事项
|
||||
showing infolog zh 当前显示
|
||||
small view infolog zh 小视图查看
|
||||
start a new search, cancel this link infolog zh 不关联该条目, 重新开始搜索
|
||||
startdate infolog zh 起始日期
|
||||
startdate enddate infolog zh 起始日期 终止日期
|
||||
startrecord infolog zh 起始记录
|
||||
status infolog zh 状态
|
||||
status ... infolog zh (状态)
|
||||
sub infolog zh 子类别
|
||||
subject infolog zh 标题
|
||||
task infolog zh 任务
|
||||
test import (show importable records <u>only</u> in browser) infolog zh 测试导入 (在浏览器中仅显示可导入的记录)
|
||||
the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog zh 供系统使用的内部名称(最多10个字符), 更改该名称可能导致已有事项无效
|
||||
the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog zh 供系统使用的内部名称(最多20个字符), 更改该名称可能导致已有事项无效
|
||||
the name used internaly (<= 32 chars), changeing it makes existing data unavailible infolog zh 供系统使用的内部名称(最多32个字符), 更改该名称可能导致已有事项无效
|
||||
the text displayed to the user infolog zh 字段的显示名
|
||||
this is the filter infolog uses when you enter the application. filters limit the entries to show in the actual view. there are filters to show only finished, still open or futures entries of yourself or all users. infolog zh 浏览记事薄中的事项时, 默认查看哪些条目?
|
||||
til when should the todo or phonecall be finished infolog zh 事项的中止日期, 仅对任务和函电有效.
|
||||
to many might exceed your execution-time-limit infolog zh to many might exceed your execution-time-limit
|
||||
today infolog zh 按日查看
|
||||
todo infolog zh 任务
|
||||
translation infolog zh 翻译
|
||||
typ infolog zh 类型
|
||||
typ '%1' already exists !!! infolog zh 类型'%1'已存在!!!
|
||||
type infolog zh 类型
|
||||
type ... infolog zh (类型)
|
||||
type of the log-entry: note, phonecall or todo infolog zh 请选择该事项的类型: 任务, 函电或备注
|
||||
unlink infolog zh 取消关联
|
||||
upcoming infolog zh 临近事项
|
||||
upload infolog zh 提交
|
||||
urgency infolog zh 紧急
|
||||
urgent infolog zh 最高
|
||||
use button to search for address infolog zh 点击该按钮以查找地址
|
||||
use button to search for project infolog zh 点击该按钮以查找项目
|
||||
valid path on clientside<br>eg. \\\\\\\\server\\\\share or e:\\\\ infolog zh 客户端有效路径<br>例如. \\Server\Share 或 e:\
|
||||
valid path on clientside<br>eg. \\\\server\\share or e:\\ infolog zh 客户端有效路径<br>例如. \\Server\Share 或 e:\
|
||||
valid path on clientside<br>eg. \\server\share or e:\ infolog zh 客户端有效路径<br>例如. \\Server\Share 或 e:\
|
||||
values for selectbox infolog zh 预设选项
|
||||
view all subs of this entry infolog zh 查看该条目的所有子任务
|
||||
view other subs infolog zh 查看其他子任务
|
||||
view parent infolog zh 查看父任务
|
||||
view subs infolog zh 查看子任务
|
||||
view the parent of this entry and all his subs infolog zh 查看该条目的父任务及所有子任务
|
||||
view this linked entry in its application infolog zh 查看该关联
|
||||
when should the todo or phonecall be started, it shows up from that date in the filter open or own open (startpage) infolog zh 事项的起始日期, 仅对任务和函电有效.it shows up from that date in the filter open or own open (startpage)
|
||||
whole query infolog zh 完整查询
|
||||
will-call infolog zh 将致电
|
||||
write (add or update) a record by passing its fields. infolog zh 通过事项的字段写入(新增或更新)一个记录
|
||||
yes - delete infolog zh 是
|
||||
you can't delete one of the stock types !!! infolog zh 无法删除stock类型!!!
|
||||
you have entered an invalid ending date infolog zh 输入的终止日期无效
|
||||
you have entered an invalid starting date infolog zh 输入的起始日期无效
|
||||
you have to enter a name, to create a new typ!!! infolog zh 必须输入新建类型的名称!!!
|
||||
you must enter a subject or a description infolog zh 必须输入事项的标题或内容
|
118
infolog/setup/importexport_default.xml
Normal file
118
infolog/setup/importexport_default.xml
Normal file
@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<entry type="array" name="importExportDefinitions">
|
||||
<entry type="array" name="metainfo">
|
||||
<entry type="string" name="type">importexport definitions</entry>
|
||||
<entry type="string" name="charset">utf-8</entry>
|
||||
<entry type="integer" name="entries">2</entry>
|
||||
</entry>
|
||||
<entry type="array" name="definitions">
|
||||
<entry type="array" name="export-infolog">
|
||||
<entry type="string" name="name">export-infolog</entry>
|
||||
<entry type="string" name="application">infolog</entry>
|
||||
<entry type="string" name="plugin">infolog_export_csv</entry>
|
||||
<entry type="string" name="type">export</entry>
|
||||
<entry type="array" name="allowed_users">
|
||||
<entry type="string" name="0">Default</entry>
|
||||
</entry>
|
||||
<entry type="array" name="plugin_options">
|
||||
<entry type="array" name="mapping">
|
||||
<entry type="string" name="info_type">Type</entry>
|
||||
<entry type="string" name="info_from">Contact</entry>
|
||||
<entry type="string" name="info_subject">Subject</entry>
|
||||
<entry type="string" name="info_des">Description</entry>
|
||||
<entry type="string" name="info_addr">Phone/Email</entry>
|
||||
<entry type="string" name="info_link_id">primary link</entry>
|
||||
<entry type="string" name="info_cat">Category</entry>
|
||||
<entry type="string" name="info_priority">Priority</entry>
|
||||
<entry type="string" name="info_owner">Owner</entry>
|
||||
<entry type="string" name="info_access">Access</entry>
|
||||
<entry type="string" name="info_status">Status</entry>
|
||||
<entry type="string" name="info_percent">Completed</entry>
|
||||
<entry type="string" name="info_datecompleted">Date completed</entry>
|
||||
<entry type="string" name="info_datemodified">Last changed</entry>
|
||||
<entry type="string" name="info_location">Location</entry>
|
||||
<entry type="string" name="info_startdate">Startdate</entry>
|
||||
<entry type="string" name="info_enddate">Enddate</entry>
|
||||
<entry type="string" name="info_responsible">Responsible</entry>
|
||||
<entry type="string" name="info_planned_time">planned time</entry>
|
||||
<entry type="string" name="info_used_time">used time</entry>
|
||||
<entry type="string" name="pl_id">pricelist</entry>
|
||||
<entry type="string" name="info_price">price</entry>
|
||||
<entry type="string" name="all_custom_fields">infolog</entry>
|
||||
</entry>
|
||||
<entry type="string" name="delimiter">;</entry>
|
||||
<entry type="string" name="charset">utf-8</entry>
|
||||
<entry type="string" name="begin_with_fieldnames">label</entry>
|
||||
<entry type="string" name="convert">1</entry>
|
||||
</entry>
|
||||
<entry type="string" name="modified">2011-03-02 09:58:16</entry>
|
||||
</entry>
|
||||
<entry type="array" name="import-infolog">
|
||||
<entry type="string" name="name">import-infolog</entry>
|
||||
<entry type="string" name="application">infolog</entry>
|
||||
<entry type="string" name="plugin">infolog_import_infologs_csv</entry>
|
||||
<entry type="string" name="type">import</entry>
|
||||
<entry type="array" name="allowed_users">
|
||||
<entry type="string" name="0">Default</entry>
|
||||
</entry>
|
||||
<entry type="array" name="plugin_options">
|
||||
<entry type="string" name="fieldsep">;</entry>
|
||||
<entry type="string" name="charset">utf-8</entry>
|
||||
<entry type="string" name="num_header_lines">1</entry>
|
||||
<entry type="array" name="csv_fields">
|
||||
<entry type="string" name="0">info_from</entry>
|
||||
<entry type="string" name="1">info_subject</entry>
|
||||
<entry type="string" name="2">info_des</entry>
|
||||
<entry type="string" name="3">info_addr</entry>
|
||||
<entry type="string" name="4">info_link_id</entry>
|
||||
<entry type="string" name="5">info_cat</entry>
|
||||
<entry type="string" name="6">info_priority</entry>
|
||||
<entry type="string" name="7">info_owner</entry>
|
||||
<entry type="string" name="8">info_access</entry>
|
||||
<entry type="string" name="9">info_status</entry>
|
||||
<entry type="string" name="10">info_percent</entry>
|
||||
<entry type="string" name="11">info_datecompleted</entry>
|
||||
<entry type="string" name="12">info_datemodified</entry>
|
||||
<entry type="string" name="13">info_location</entry>
|
||||
<entry type="string" name="14">info_startdate</entry>
|
||||
<entry type="string" name="15">info_enddate</entry>
|
||||
<entry type="string" name="16">info_responsible</entry>
|
||||
<entry type="string" name="17">info_planned_time</entry>
|
||||
<entry type="string" name="18">info_used_time</entry>
|
||||
<entry type="string" name="19">pl_id</entry>
|
||||
<entry type="string" name="20">info_price</entry>
|
||||
<entry type="string" name="21">no_csv_1</entry>
|
||||
<entry type="string" name="22">no_csv_2</entry>
|
||||
<entry type="string" name="23">no_csv_3</entry>
|
||||
</entry>
|
||||
<entry type="array" name="field_mapping">
|
||||
<entry type="string" name="0">info_type</entry>
|
||||
<entry type="string" name="1">info_from</entry>
|
||||
<entry type="string" name="2">info_subject</entry>
|
||||
<entry type="string" name="3">info_des</entry>
|
||||
<entry type="string" name="4">info_addr</entry>
|
||||
<entry type="string" name="5">info_link_id</entry>
|
||||
<entry type="string" name="6">info_cat</entry>
|
||||
<entry type="string" name="7">info_priority</entry>
|
||||
<entry type="string" name="8">info_owner</entry>
|
||||
<entry type="string" name="9">info_access</entry>
|
||||
<entry type="string" name="10">info_status</entry>
|
||||
<entry type="string" name="11">info_percent</entry>
|
||||
<entry type="string" name="12">info_datecompleted</entry>
|
||||
<entry type="string" name="13">info_datemodified</entry>
|
||||
<entry type="string" name="14">info_location</entry>
|
||||
<entry type="string" name="15">info_startdate</entry>
|
||||
<entry type="string" name="16">info_enddate</entry>
|
||||
<entry type="string" name="17">info_responsible</entry>
|
||||
<entry type="string" name="18">info_planned_time</entry>
|
||||
<entry type="string" name="19">info_used_time</entry>
|
||||
<entry type="string" name="20">pl_id</entry>
|
||||
<entry type="string" name="21">info_price</entry>
|
||||
</entry>
|
||||
<entry type="string" name="field_conversion"/>
|
||||
<entry type="string" name="conditions"/>
|
||||
</entry>
|
||||
<entry type="string" name="modified">2011-03-01 18:06:41</entry>
|
||||
</entry>
|
||||
</entry>
|
||||
</entry>
|
@ -6,13 +6,13 @@
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package infolog
|
||||
* @subpackage setup
|
||||
* @copyright (c) 2003-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2003-11 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
$setup_info['infolog']['name'] = 'infolog';
|
||||
$setup_info['infolog']['version'] = '1.8';
|
||||
$setup_info['infolog']['version'] = '1.9.003';
|
||||
$setup_info['infolog']['app_order'] = 5;
|
||||
$setup_info['infolog']['tables'] = array('egw_infolog','egw_infolog_extra');
|
||||
$setup_info['infolog']['enable'] = 1;
|
||||
@ -36,7 +36,7 @@ $setup_info['infolog']['description'] =
|
||||
<p>Other documents / files can be linked to InfoLog entries and are store in the VFS
|
||||
(eGroupWare\'s virtual file system).</p>';
|
||||
$setup_info['infolog']['note'] =
|
||||
'<p>There is a <b>CSV import filter</b> (in the admin-section) to import existing data.
|
||||
'<p>There is a <b>CSV import</b> (in the admin-section) to import existing data.
|
||||
It allows to interactivly assign fields, customize the values with regular
|
||||
expressions and direct calls to php-functions (e.g. to link the phone calls
|
||||
(again) to the addressbook entrys).</p>
|
||||
|
68
infolog/setup/tables_current.inc.php
Normal file
68
infolog/setup/tables_current.inc.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware - InfoLog - Setup
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package infolog
|
||||
* @subpackage setup
|
||||
* @copyright (c) 2003-11 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
$phpgw_baseline = array(
|
||||
'egw_infolog' => array(
|
||||
'fd' => array(
|
||||
'info_id' => array('type' => 'auto','nullable' => False),
|
||||
'info_type' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => 'task'),
|
||||
'info_from' => array('type' => 'varchar','precision' => '255'),
|
||||
'info_addr' => array('type' => 'varchar','precision' => '255'),
|
||||
'info_subject' => array('type' => 'varchar','precision' => '255'),
|
||||
'info_des' => array('type' => 'text'),
|
||||
'info_owner' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'info_responsible' => array('type' => 'varchar','precision' => '255','nullable' => False,'default' => '0'),
|
||||
'info_access' => array('type' => 'varchar','precision' => '10','default' => 'public'),
|
||||
'info_cat' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'info_datemodified' => array('type' => 'int','precision' => '8','nullable' => False),
|
||||
'info_startdate' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0'),
|
||||
'info_enddate' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0'),
|
||||
'info_id_parent' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'info_planned_time' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'info_replanned_time' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'info_used_time' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'info_status' => array('type' => 'varchar','precision' => '40','default' => 'done'),
|
||||
'info_confirm' => array('type' => 'varchar','precision' => '10','default' => 'not'),
|
||||
'info_modifier' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'info_link_id' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'info_priority' => array('type' => 'int','precision' => '2','default' => '1'),
|
||||
'pl_id' => array('type' => 'int','precision' => '4'),
|
||||
'info_price' => array('type' => 'float','precision' => '8'),
|
||||
'info_percent' => array('type' => 'int','precision' => '2','default' => '0'),
|
||||
'info_datecompleted' => array('type' => 'int','precision' => '8'),
|
||||
'info_location' => array('type' => 'varchar','precision' => '255'),
|
||||
'info_custom_from' => array('type' => 'int','precision' => '1'),
|
||||
'info_uid' => array('type' => 'varchar','precision' => '255'),
|
||||
'info_cc' => array('type' => 'varchar','precision' => '255'),
|
||||
'caldav_name' => array('type' => 'varchar','precision' => '64','comment' => 'name part of CalDAV URL, if specified by client'),
|
||||
'info_etag' => array('type' => 'int','precision' => '4','default' => '0','comment' => 'etag, not yet used'),
|
||||
'info_created' => array('type' => 'int','precision' => '8'),
|
||||
'info_creator' => array('type' => 'int','precision' => '4'),
|
||||
),
|
||||
'pk' => array('info_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('caldav_name',array('info_owner','info_responsible','info_status','info_startdate'),array('info_id_parent','info_owner','info_responsible','info_status','info_startdate')),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_infolog_extra' => array(
|
||||
'fd' => array(
|
||||
'info_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'info_extra_name' => array('type' => 'varchar','precision' => '64','nullable' => False),
|
||||
'info_extra_value' => array('type' => 'text','nullable' => False)
|
||||
),
|
||||
'pk' => array('info_id','info_extra_name'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
)
|
||||
);
|
@ -6,7 +6,7 @@
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package infolog
|
||||
* @subpackage setup
|
||||
* @copyright (c) 2003-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2003-11 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -634,3 +634,58 @@ function infolog_upgrade1_6()
|
||||
{
|
||||
return $GLOBALS['setup_info']['infolog']['currentver'] = '1.8';
|
||||
}
|
||||
|
||||
function infolog_upgrade1_8()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_infolog','info_cc',array(
|
||||
'type' => 'varchar',
|
||||
'precision' => '255'
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['infolog']['currentver'] = '1.9.001';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add column to store CalDAV name given by client and etag (not yet used!)
|
||||
*/
|
||||
function infolog_upgrade1_9_001()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_infolog','caldav_name',array(
|
||||
'type' => 'varchar',
|
||||
'precision' => '64',
|
||||
'comment' => 'name part of CalDAV URL, if specified by client'
|
||||
));
|
||||
$GLOBALS['egw_setup']->db->query('UPDATE egw_infolog SET caldav_name='.
|
||||
$GLOBALS['egw_setup']->db->concat(
|
||||
$GLOBALS['egw_setup']->db->to_varchar('info_id'),"'.ics'"),__LINE__,__FILE__);
|
||||
|
||||
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_infolog','caldav_name');
|
||||
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_infolog','info_etag',array(
|
||||
'type' => 'int',
|
||||
'precision' => '4',
|
||||
'default' => '0',
|
||||
'comment' => 'etag, not yet used'
|
||||
));
|
||||
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_infolog','info_created',array(
|
||||
'type' => 'int',
|
||||
'precision' => '8',
|
||||
));
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_infolog','info_creator',array(
|
||||
'type' => 'int',
|
||||
'precision' => '4',
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['infolog']['currentver'] = '1.9.002';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fix caldav_name of subentries is identical with parent: not necessary
|
||||
*/
|
||||
function infolog_upgrade1_9_002()
|
||||
{
|
||||
return $GLOBALS['setup_info']['infolog']['currentver'] = '1.9.003';
|
||||
}
|
274
infolog/templates/default/edit.xet
Normal file
274
infolog/templates/default/edit.xet
Normal file
@ -0,0 +1,274 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- $Id$ -->
|
||||
<overlay>
|
||||
<template id="infolog.edit.description" template="" lang="" group="0" version="1.6.001">
|
||||
<grid width="100%" height="245" border="0">
|
||||
<columns>
|
||||
<column width="100"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row class="th">
|
||||
<description span="all" value="Description" options=",,,info_des"/>
|
||||
</row>
|
||||
<row class="row" valign="top">
|
||||
<description/>
|
||||
<textbox multiline="true" rows="13" no_lang="1" id="info_des" statustext="enter a textual description of the log-entry" class="description"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</template>
|
||||
<template id="infolog.edit.links" template="" lang="" group="0" version="1.3.001">
|
||||
<grid width="100%" height="245" overflow="auto">
|
||||
<columns>
|
||||
<column width="100"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row class="th" disabled="@status_only">
|
||||
<description span="all" value="Create new links"/>
|
||||
</row>
|
||||
<row class="row" disabled="@status_only">
|
||||
<link-to span="all" id="link_to"/>
|
||||
</row>
|
||||
<row>
|
||||
<link-add span="all" id="link_to"/>
|
||||
</row>
|
||||
<row class="th">
|
||||
<description span="all" value="Existing links"/>
|
||||
</row>
|
||||
<row class="row_off" valign="top">
|
||||
<link-list span="all" id="link_to"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</template>
|
||||
<template id="infolog.edit.delegation" template="" lang="" group="0" version="1.3.001">
|
||||
<grid width="100%" height="245">
|
||||
<columns>
|
||||
<column width="100"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row class="th">
|
||||
<description span="all" value="General"/>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description options=",,,info_priority" value="Priority"/>
|
||||
<menulist>
|
||||
<menupopup id="info_priority" statustext="select a priority for this task"/>
|
||||
</menulist>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description options=",,,info_location" value="Location"/>
|
||||
<textbox size="80" maxlength="255" id="info_location"/>
|
||||
</row>
|
||||
<row class="th">
|
||||
<description span="all" value="Delegation"/>
|
||||
</row>
|
||||
<row class="row" valign="top">
|
||||
<description options=",,,info_responsible" value="Responsible"/>
|
||||
<listbox type="select-account" id="info_responsible" rows="10" options="both" statustext="select a responsible user: a person you want to delegate this task"/>
|
||||
</row>
|
||||
<row class="row" disabled="1">
|
||||
<description options=",,,info_confirm" value="Confirm"/>
|
||||
<menulist>
|
||||
<menupopup id="info_confirm" statustext="do you want a confirmation of the responsible on: accepting, finishing the task or both"/>
|
||||
</menulist>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</template>
|
||||
<template id="infolog.edit.project" template="" lang="" group="0" version="1.5.004">
|
||||
<grid width="100%" height="245">
|
||||
<columns>
|
||||
<column width="100"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row class="th">
|
||||
<description span="all" value="Projectmanager"/>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description value="Project"/>
|
||||
<projectmanager-select id="pm_id" onchange="1" options="None"/>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description value="Price"/>
|
||||
<hbox span="all">
|
||||
<projectmanager-pricelist id="pl_id" options="None" onchange="this.form['exec[info_price]'].value=this.options[this.selectedIndex].text.lastIndexOf('(') < 0 ? '' : this.options[this.selectedIndex].text.slice(this.options[this.selectedIndex].text.lastIndexOf('(')+1,-1);"/>
|
||||
<textbox type="float" id="info_price" span="all"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description options=",,,info_planned_time" value="planned time"/>
|
||||
<date-duration id="info_planned_time" options=",$cont[duration_format]"/>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description options=",,,info_replanned_time" value="Re-planned time"/>
|
||||
<date-duration id="info_replanned_time" options=",$cont[duration_format]"/>
|
||||
</row>
|
||||
<row class="row" valign="top" height="60%">
|
||||
<description options=",,,info_used_time" value="used time" statustext="Leave blank to get the used time calculated by timesheet entries"/>
|
||||
<date-duration id="info_used_time"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</template>
|
||||
<template id="infolog.edit.customfields" template="" lang="" group="0" version="1.0.1.001">
|
||||
<grid width="100%" height="245" class="row_on" spacing="0" padding="0" overflow="auto">
|
||||
<columns>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row class="th" height="20">
|
||||
<description value="Custom fields"/>
|
||||
</row>
|
||||
<row height="100%">
|
||||
<customfields options="@info_type"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</template>
|
||||
<template id="infolog.edit.history" template="" lang="" group="0" version="1.3.002">
|
||||
<grid width="100%" height="245" overflow="auto">
|
||||
<columns>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row valign="top">
|
||||
<historylog id="history"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</template>
|
||||
<template id="infolog.edit" template="" lang="" group="0" version="1.9.001">
|
||||
<grid width="100%">
|
||||
<columns>
|
||||
<column width="103"/>
|
||||
<column width="260"/>
|
||||
<column width="140"/>
|
||||
<column width="27%"/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row disabled="!@msg">
|
||||
<html span="all" class="redItalic" align="center" id="msg" no_lang="1"/>
|
||||
<description/>
|
||||
<description/>
|
||||
<description/>
|
||||
</row>
|
||||
<row class="th" height="28">
|
||||
<description value="Type" options=",,,info_type"/>
|
||||
<hbox span="all" options="0,0">
|
||||
<menulist>
|
||||
<menupopup id="info_type" onchange="1" statustext="Type of the log-entry: Note, Phonecall or ToDo" no_lang="1"/>
|
||||
</menulist>
|
||||
<int id="info_number" class="infoId" readonly="true"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description value="Contact" options=",,,info_from"/>
|
||||
<vbox options="0,0">
|
||||
<hbox options="0,0">
|
||||
<link-entry id="info_contact" class="noWrap"/>
|
||||
<checkbox id="info_custom_from" onchange="document.getElementById(form::name('info_from')).style.display=this.checked?'block':'none';" statustext="Check to specify custom contact"/>
|
||||
</hbox>
|
||||
<textbox size="36" maxlength="255" id="info_from" statustext="Custom contact-information, leave emtpy to use information from most recent link" blur="@blur_title" class="$cont[hide_from_css]"/>
|
||||
</vbox>
|
||||
<description options=",,,info_addr" value="Phone/Email"/>
|
||||
<textbox size="30" maxlength="255" id="info_addr" statustext="Custom contact-address, leave empty to use information from most recent link" class="inputFullWidth"/>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description value="Category" options=",,,info_cat"/>
|
||||
<menulist>
|
||||
<menupopup type="select-cat" options="None" id="info_cat" statustext="select a category for this entry"/>
|
||||
</menulist>
|
||||
<hbox span="all">
|
||||
<description value="Parent"/>
|
||||
<link-entry options="infolog" id="info_id_parent" align="right" class="noWrap"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description value="Subject" options=",,,info_subject"/>
|
||||
<textbox size="80" maxlength="255" span="all" id="info_subject" statustext="a short subject for the entry"/>
|
||||
</row>
|
||||
<row valign="top" height="250">
|
||||
<tabbox span="all" id="description|links|delegation|project|customfields|history">
|
||||
<tabs>
|
||||
<tab label="Description" statustext="longer textual description"/>
|
||||
<tab label="Links" statustext="Links of this entry"/>
|
||||
<tab label="Delegation" statustext="responsible user, priority"/>
|
||||
<tab label="Projectmanager" statustext="Project settings: price, times"/>
|
||||
<tab label="Customfields" statustext="Custom fields"/>
|
||||
<tab label="History" statustext="Change history"/>
|
||||
</tabs>
|
||||
<tabpanels>
|
||||
<template id="infolog.edit.description"/>
|
||||
<template id="infolog.edit.links"/>
|
||||
<template id="infolog.edit.delegation"/>
|
||||
<template id="infolog.edit.project"/>
|
||||
<template id="infolog.edit.customfields"/>
|
||||
<template id="infolog.edit.history"/>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
</row>
|
||||
<row class="th" disabled="1">
|
||||
<description span="all" value="Dates, Status, Access"/>
|
||||
</row>
|
||||
<row class="row_on">
|
||||
<description value="Startdate" options=",,,info_startdate"/>
|
||||
<date-time options=",2" id="info_startdate" statustext="when should the ToDo or Phonecall be started, it shows up from that date in the filter open or own open (startpage)"/>
|
||||
<description value="Enddate" options=",,,info_enddate"/>
|
||||
<date id="info_enddate" statustext="til when should the ToDo or Phonecall be finished"/>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description value="Status" options=",,,info_status"/>
|
||||
<menulist>
|
||||
<menupopup id="info_status" statustext="@status_help" onchange="if (this.value=='done' || this.value=='billed') set_element(this.form,'exec[info_percent]','100'); else if (this.value=='not-started') set_element(this.form,'exec[info_percent]','0');"/>
|
||||
</menulist>
|
||||
<description value="Completed" options=",,,info_percent"/>
|
||||
<menulist>
|
||||
<menupopup type="select-percent" id="info_percent" statustext="Percent completed" onchange="if (this.value==100 && this.form['exec[info_status]'].value != 'done' && this.form['exec[info_status]'].value != 'billed' && this.form['exec[info_status]'].value != 'cancelled') this.form['exec[info_status]'].value='done'; else if (this.value != 100 && this.form['exec[info_status]'].value != 'cancelled') this.form['exec[info_status]'].value=this.value != 0 ? 'ongoing' : 'not-started'; else if (this.value==0 && this.form['exec[info_status]'].value != 'cancelled' && this.form['exec[info_status]'].value != 'offer') this.form['exec[info_status]'].value='not-started'; "/>
|
||||
</menulist>
|
||||
</row>
|
||||
<row class="row">
|
||||
<description options=",,,info_datecompleted" value="Date completed"/>
|
||||
<date-time id="info_datecompleted" statustext="Date completed (leave it empty to have it automatic set if status is done or billed)"/>
|
||||
<description value="Private" options=",,,info_access"/>
|
||||
<checkbox options="private,public" id="info_access" statustext="should this entry only be visible to you and people you grant privat access via the ACL"/>
|
||||
</row>
|
||||
<row class="row" disabled="!@info_owner">
|
||||
<description value="Owner"/>
|
||||
<menulist>
|
||||
<menupopup type="select-account" id="info_owner" readonly="true"/>
|
||||
</menulist>
|
||||
<description value="Last modified"/>
|
||||
<hbox options="0" orient="0">
|
||||
<menulist>
|
||||
<menupopup type="select-account" id="info_modifier" readonly="true"/>
|
||||
</menulist>
|
||||
<date-time class="lpadding5" id="info_datemodified" readonly="true"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row>
|
||||
<hbox span="3">
|
||||
<button label="Save" id="button[save]" statustext="Saves this entry"/>
|
||||
<button id="button[apply]" label="Apply" statustext="Apply the changes"/>
|
||||
<button label="Cancel" id="button[cancel]" statustext="leave without saveing the entry" onclick="window.close();"/>
|
||||
<menulist>
|
||||
<menupopup id="action" statustext="Execute a further action for this entry" options="Actions..." onchange="this.form.submit(); this.value='';"/>
|
||||
</menulist>
|
||||
<checkbox label="Do not notify of these changes" id="no_notifications" span="2"/>
|
||||
<html id="js"/>
|
||||
</hbox>
|
||||
<button label="Delete" align="right" id="button[delete]" statustext="delete this entry" onclick="return $cont[info_anz_subs] || confirm('Delete this entry');"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<styles>
|
||||
.hideFrom input { display: none; }
|
||||
.link_select select { width: 250px; }
|
||||
.description textarea { width: 98%; }
|
||||
</styles>
|
||||
</template>
|
||||
</overlay>
|
@ -14,7 +14,7 @@
|
||||
</hbox>
|
||||
</template>
|
||||
<template id="infolog.index.rows-noheader" template="" lang="" group="0" version="1.7.005">
|
||||
<grid>
|
||||
<grid width="100%" class="my_form">
|
||||
<columns>
|
||||
<column width="2%"/>
|
||||
<column/>
|
||||
@ -146,6 +146,7 @@
|
||||
<description/>
|
||||
<description/>
|
||||
</hbox>
|
||||
<image src="filemanager/navbar" options="/index.php?menuaction=filemanager.filemanager_ui.index&path=/apps/infolog/$row_cont[info_id]" class="image16" label="Filemanager"/>
|
||||
</vbox>
|
||||
</row>
|
||||
</rows>
|
||||
@ -296,6 +297,7 @@
|
||||
<button image="done" label="Set status to done" id="close[$row_cont[info_id]]" statustext="Sets the status of this entry to done"/>
|
||||
<button image="done_all" label="Set status to done for all entries" id="close_all[$row_cont[info_id]]" statustext="Sets the status of this entry and its subs to done"/>
|
||||
</hbox>
|
||||
<image src="filemanager/navbar" options="/index.php?menuaction=filemanager.filemanager_ui.index&path=/apps/infolog/$row_cont[info_id]" class="image16" label="Filemanager"/>
|
||||
</vbox>
|
||||
</row>
|
||||
</rows>
|
||||
|
@ -215,7 +215,8 @@ class accounts
|
||||
* Searches / lists accounts: users and/or groups
|
||||
*
|
||||
* @param array with the following keys:
|
||||
* @param $param['type'] string/int 'accounts', 'groups', 'owngroups' (groups the user is a member of), 'both'
|
||||
* @param $param['type'] string/int 'accounts', 'groups', 'owngroups' (groups the user is a member of), 'both',
|
||||
* 'groupmembers' (members of groups the user is a member of), 'groupmembers+memberships' (incl. memberships too)
|
||||
* or integer group-id for a list of members of that group
|
||||
* @param $param['start'] int first account to return (returns offset or max_matches entries) or all if not set
|
||||
* @param $param['order'] string column to sort after, default account_lid if unset
|
||||
@ -233,7 +234,7 @@ class accounts
|
||||
*/
|
||||
function search($param)
|
||||
{
|
||||
//echo "<p>accounts::search(".print_r($param,True).") start: ".microtime()."</p>\n";
|
||||
//error_log(__METHOD__.'('.array2string($param).')');
|
||||
self::setup_cache();
|
||||
$account_search = &self::$cache['account_search'];
|
||||
$serial = serialize($param);
|
||||
@ -245,7 +246,7 @@ class accounts
|
||||
// no backend understands $param['app'] and sql does not understand group-parameters
|
||||
// --> do an full search first and then filter and limit that search
|
||||
elseif($param['app'] || $this->config['account_repository'] != 'ldap' &&
|
||||
(is_numeric($param['type']) || $param['type'] == 'owngroups'))
|
||||
(is_numeric($param['type']) || in_array($param['type'],array('owngroups','groupmembers','groupmembers+memberships'))))
|
||||
{
|
||||
$app = $param['app'];
|
||||
unset($param['app']);
|
||||
@ -254,14 +255,24 @@ class accounts
|
||||
|
||||
if ($this->config['account_repository'] != 'ldap' && is_numeric($param['type']))
|
||||
{
|
||||
$group = (int) $param['type'];
|
||||
$members = $this->members($param['type'],true);
|
||||
$param['type'] = 'accounts';
|
||||
}
|
||||
elseif ($param['type'] == 'owngroups')
|
||||
{
|
||||
$group = true;
|
||||
$members = $this->memberships($GLOBALS['egw_info']['user']['account_id'],true);
|
||||
$param['type'] = 'groups';
|
||||
}
|
||||
elseif(in_array($param['type'],array('groupmembers','groupmembers+memberships')))
|
||||
{
|
||||
$members = array();
|
||||
foreach($this->memberships($GLOBALS['egw_info']['user']['account_id'],true) as $grp)
|
||||
{
|
||||
$members = array_unique(array_merge($members,$this->members($grp,true)));
|
||||
if ($param['type'] == 'groupmembers+memberships') $members[] = $grp;
|
||||
}
|
||||
$param['type'] = $param['type'] == 'groupmembers+memberships' ? 'both' : 'accounts';
|
||||
}
|
||||
// call ourself recursive to get (evtl. cached) full search
|
||||
$full_search = $this->search($param);
|
||||
|
||||
@ -272,9 +283,9 @@ class accounts
|
||||
// we want the result merged, whatever it takes, as we only care for the ids
|
||||
$valid = $this->split_accounts($app,!in_array($param['type'],array('accounts','groups')) ? 'merge' : $param['type']);
|
||||
}
|
||||
if ($group)
|
||||
if (isset($members))
|
||||
{
|
||||
$members = is_int($group) ? $this->members($group,true) : $this->memberships($GLOBALS['egw_info']['user']['account_id'],true);
|
||||
//error_log(__METHOD__.'() members='.array2string($members));
|
||||
if (!$members) $members = array();
|
||||
$valid = !$app ? $members : array_intersect($valid,$members); // use the intersection
|
||||
}
|
||||
|
@ -82,20 +82,20 @@ class auth
|
||||
}
|
||||
|
||||
/**
|
||||
* return a random string of size $size
|
||||
* return a random string of letters [0-9a-zA-Z] of size $size
|
||||
*
|
||||
* @param $size int-size of random string to return
|
||||
*/
|
||||
static function randomstring($size)
|
||||
{
|
||||
$s = '';
|
||||
$random_char = array(
|
||||
static $random_char = array(
|
||||
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
||||
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
|
||||
'w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L',
|
||||
'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
|
||||
);
|
||||
|
||||
$s = '';
|
||||
for ($i=0; $i<$size; $i++)
|
||||
{
|
||||
$s .= $random_char[mt_rand(1,61)];
|
||||
@ -124,14 +124,17 @@ class auth
|
||||
*
|
||||
* encryption type set in setup and calls the appropriate encryption functions
|
||||
*
|
||||
* @param $cleartext cleartext password
|
||||
* @param $encrypted encrypted password, can have a {hash} prefix, which overrides $type
|
||||
* @param $type type of encryption
|
||||
* @param $username used as optional key of encryption for md5_hmac
|
||||
* @param string $cleartext cleartext password
|
||||
* @param string $encrypted encrypted password, can have a {hash} prefix, which overrides $type
|
||||
* @param string $type_i type of encryption
|
||||
* @param string $username used as optional key of encryption for md5_hmac
|
||||
* @param string &$type=null on return detected type of hash
|
||||
* @return boolean
|
||||
*/
|
||||
static function compare_password($cleartext,$encrypted,$type,$username='')
|
||||
static function compare_password($cleartext, $encrypted, $type_in, $username='', &$type=null)
|
||||
{
|
||||
// allow to specify the hash type to prefix the hash, to easy migrate passwords from ldap
|
||||
$type = $type_in;
|
||||
$saved_enc = $encrypted;
|
||||
if (preg_match('/^\\{([a-z_5]+)\\}(.+)$/i',$encrypted,$matches))
|
||||
{
|
||||
@ -149,34 +152,100 @@ class auth
|
||||
break;
|
||||
default:
|
||||
$encrypted = $saved_enc;
|
||||
// ToDo: the others ...
|
||||
break;
|
||||
}
|
||||
}
|
||||
elseif($encrypted[0] == '$')
|
||||
{
|
||||
$type = 'crypt';
|
||||
}
|
||||
|
||||
switch($type)
|
||||
{
|
||||
case 'plain':
|
||||
if(strcmp($cleartext,$encrypted) == 0)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
$ret = $cleartext === $encrypted;
|
||||
break;
|
||||
case 'smd5':
|
||||
return self::smd5_compare($cleartext,$encrypted);
|
||||
$ret = self::smd5_compare($cleartext,$encrypted);
|
||||
break;
|
||||
case 'sha':
|
||||
return self::sha_compare($cleartext,$encrypted);
|
||||
$ret = self::sha_compare($cleartext,$encrypted);
|
||||
break;
|
||||
case 'ssha':
|
||||
return self::ssha_compare($cleartext,$encrypted);
|
||||
$ret = self::ssha_compare($cleartext,$encrypted);
|
||||
break;
|
||||
case 'crypt':
|
||||
case 'des':
|
||||
case 'md5_crypt':
|
||||
case 'blowish_crypt': // was for some time a typo in setup
|
||||
case 'blowfish_crypt':
|
||||
case 'ext_crypt':
|
||||
return self::crypt_compare($cleartext,$encrypted,$type);
|
||||
case 'sha256_crypt':
|
||||
case 'sha512_crypt':
|
||||
$ret = self::crypt_compare($cleartext, $encrypted, $type);
|
||||
break;
|
||||
case 'md5_hmac':
|
||||
return self::md5_hmac_compare($cleartext,$encrypted,$username);
|
||||
case 'md5':
|
||||
$ret = self::md5_hmac_compare($cleartext,$encrypted,$username);
|
||||
break;
|
||||
default:
|
||||
return strcmp(md5($cleartext),$encrypted) == 0 ? true : false;
|
||||
$type = 'md5';
|
||||
// fall through
|
||||
case 'md5':
|
||||
$ret = md5($cleartext) === $encrypted;
|
||||
break;
|
||||
}
|
||||
//error_log(__METHOD__."('$cleartext', '$encrypted', '$type_in', '$username') type='$type' returning ".array2string($ret));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters used for crypt: const name, salt prefix, len of random salt, postfix
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static $crypt_params = array( //
|
||||
'crypt' => array('CRYPT_STD_DES', '', 2, ''),
|
||||
'ext_crypt' => array('CRYPT_EXT_DES', '_J9..', 4, ''),
|
||||
'md5_crypt' => array('CRYPT_MD5', '$1$', 8, '$'),
|
||||
//'old_blowfish_crypt' => array('CRYPT_BLOWFISH', '$2$', 13, ''), // old blowfish hash not in line with php.net docu, but could be in use
|
||||
'blowfish_crypt' => array('CRYPT_BLOWFISH', '$2a$12$', 22, ''), // $2a$12$ = 2^12 = 4096 rounds
|
||||
'sha256_crypt' => array('CRYPT_SHA256', '$5$', 16, '$'), // no "round=N$" --> default of 5000 rounds
|
||||
'sha512_crypt' => array('CRYPT_SHA512', '$6$', 16, '$'), // no "round=N$" --> default of 5000 rounds
|
||||
);
|
||||
|
||||
/**
|
||||
* compare crypted passwords for authentication whether des,ext_des,md5, or blowfish crypt
|
||||
*
|
||||
* @param string $form_val user input value for comparison
|
||||
* @param string $db_val stored value / hash (from database)
|
||||
* @param string &$type detected crypt type on return
|
||||
* @return boolean True on successful comparison
|
||||
*/
|
||||
static function crypt_compare($form_val, $db_val, &$type)
|
||||
{
|
||||
// detect type of hash by salt part of $db_val
|
||||
list($first, $dollar, $salt, $salt2) = explode('$', $db_val);
|
||||
foreach(self::$crypt_params as $type => $params)
|
||||
{
|
||||
list(,$prefix, $random, $postfix) = $params;
|
||||
list(,$d) = explode('$', $prefix);
|
||||
if ($dollar === $d || !$dollar && ($first[0] === $prefix[0] || $first[0] !== '_' && !$prefix))
|
||||
{
|
||||
$len = !$postfix ? strlen($prefix)+$random : strlen($prefix.$salt.$postfix);
|
||||
// sha(256|512) might contain options, explicit $rounds=N$ prefix in salt
|
||||
if (($type == 'sha256_crypt' || $type == 'sha512_crypt') && substr($salt, 0, 7) === 'rounds=')
|
||||
{
|
||||
$len += strlen($salt2)+1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$salt = substr($db_val, 0, $len);
|
||||
$new_hash = crypt($form_val, $salt);
|
||||
//error_log(__METHOD__."('$form_val', '$db_val') type=$type --> len=$len --> salt='$salt' --> new_hash='$new_hash' returning ".array2string($db_val === $new_hash));
|
||||
|
||||
return $db_val === $new_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,41 +260,30 @@ class auth
|
||||
static function encrypt_ldap($password, $type=null)
|
||||
{
|
||||
if (is_null($type)) $type = $GLOBALS['egw_info']['server']['ldap_encryption_type'];
|
||||
|
||||
$salt = '';
|
||||
switch(strtolower($type))
|
||||
{
|
||||
default: // eg. setup >> config never saved
|
||||
case 'des':
|
||||
$salt = self::randomstring(2);
|
||||
$_password = crypt($password, $salt);
|
||||
$e_password = '{crypt}'.$_password;
|
||||
break;
|
||||
case 'blowish_crypt': // was for some time a typo in setup
|
||||
$type = $type == 'blowish_crypt' ? 'blowfish_crypt' : 'crypt';
|
||||
// fall through
|
||||
case 'crypt':
|
||||
case 'sha256_crypt':
|
||||
case 'sha512_crypt':
|
||||
case 'blowfish_crypt':
|
||||
if(@defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH == 1)
|
||||
{
|
||||
$salt = '$2$' . self::randomstring(13);
|
||||
$e_password = '{crypt}'.crypt($password,$salt);
|
||||
break;
|
||||
}
|
||||
self::$error = 'no blowfish crypt';
|
||||
break;
|
||||
case 'md5_crypt':
|
||||
if(@defined('CRYPT_MD5') && CRYPT_MD5 == 1)
|
||||
{
|
||||
$salt = '$1$' . self::randomstring(9);
|
||||
$e_password = '{crypt}'.crypt($password,$salt);
|
||||
break;
|
||||
}
|
||||
self::$error = 'no md5 crypt';
|
||||
break;
|
||||
case 'ext_crypt':
|
||||
if(@defined('CRYPT_EXT_DES') && CRYPT_EXT_DES == 1)
|
||||
list($const, $prefix, $len, $postfix) = self::$crypt_params[$type];
|
||||
if(defined($const) && constant($const) == 1)
|
||||
{
|
||||
$salt = self::randomstring(9);
|
||||
$e_password = '{crypt}'.crypt($password,$salt);
|
||||
$salt = $prefix.self::randomstring($len).$postfix;
|
||||
$e_password = '{crypt}'.crypt($password, $salt);
|
||||
break;
|
||||
}
|
||||
self::$error = 'no ext crypt';
|
||||
self::$error = 'no '.str_replace('_', ' ', $type);
|
||||
$e_password = false;
|
||||
break;
|
||||
case 'md5':
|
||||
/* New method taken from the openldap-software list as recommended by
|
||||
@ -235,7 +293,7 @@ class auth
|
||||
break;
|
||||
case 'smd5':
|
||||
$salt = self::randomstring(16);
|
||||
$hash = md5($password . $salt,true);
|
||||
$hash = md5($password . $salt, true);
|
||||
$e_password = '{SMD5}' . base64_encode($hash . $salt);
|
||||
break;
|
||||
case 'sha':
|
||||
@ -243,14 +301,15 @@ class auth
|
||||
break;
|
||||
case 'ssha':
|
||||
$salt = self::randomstring(16);
|
||||
$hash = sha1($password . $salt,true);
|
||||
$hash = sha1($password . $salt, true);
|
||||
$e_password = '{SSHA}' . base64_encode($hash . $salt);
|
||||
break;
|
||||
case 'plain':
|
||||
// if plain no type is prepended
|
||||
$e_password =$password;
|
||||
$e_password = $password;
|
||||
break;
|
||||
}
|
||||
//error_log(__METHOD__."('$password', ".array2string($type).") returning ".array2string($e_password).(self::$error ? ' error='.self::$error : ''));
|
||||
return $e_password;
|
||||
}
|
||||
|
||||
@ -263,67 +322,43 @@ class auth
|
||||
static function encrypt_sql($password)
|
||||
{
|
||||
/* Grab configured type, or default to md5() (old method) */
|
||||
$type = @$GLOBALS['egw_info']['server']['sql_encryption_type']
|
||||
? strtolower($GLOBALS['egw_info']['server']['sql_encryption_type'])
|
||||
: 'md5';
|
||||
$type = @$GLOBALS['egw_info']['server']['sql_encryption_type'] ?
|
||||
strtolower($GLOBALS['egw_info']['server']['sql_encryption_type']) : 'md5';
|
||||
|
||||
switch($type)
|
||||
{
|
||||
case 'plain':
|
||||
// since md5 is the default, type plain must be prepended, for eGroupware to understand
|
||||
return '{PLAIN}'.$password;
|
||||
case 'crypt':
|
||||
if(@defined('CRYPT_STD_DES') && CRYPT_STD_DES == 1)
|
||||
{
|
||||
$salt = self::randomstring(2);
|
||||
return crypt($password,$salt);
|
||||
}
|
||||
self::$error = 'no std crypt';
|
||||
$e_password = '{PLAIN}'.$password;
|
||||
break;
|
||||
case 'blowfish_crypt':
|
||||
if(@defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH == 1)
|
||||
{
|
||||
$salt = '$2$' . self::randomstring(13);
|
||||
return crypt($password,$salt);
|
||||
}
|
||||
self::$error = 'no blowfish crypt';
|
||||
break;
|
||||
case 'md5_crypt':
|
||||
if(@defined('CRYPT_MD5') && CRYPT_MD5 == 1)
|
||||
{
|
||||
$salt = '$1$' . self::randomstring(9);
|
||||
return crypt($password,$salt);
|
||||
}
|
||||
self::$error = 'no md5 crypt';
|
||||
break;
|
||||
case 'ext_crypt':
|
||||
if(@defined('CRYPT_EXT_DES') && CRYPT_EXT_DES == 1)
|
||||
{
|
||||
$salt = self::randomstring(9);
|
||||
return crypt($password,$salt);
|
||||
}
|
||||
self::$error = 'no ext crypt';
|
||||
break;
|
||||
case 'smd5':
|
||||
$salt = self::randomstring(16);
|
||||
$hash = md5($password . $salt,true);
|
||||
return '{SMD5}' . base64_encode($hash . $salt);
|
||||
case 'sha':
|
||||
return '{SHA}' . base64_encode(sha1($password,true));
|
||||
case 'ssha':
|
||||
$salt = self::randomstring(16);
|
||||
$hash = sha1($password . $salt,true);
|
||||
return '{SSHA}' . base64_encode($hash . $salt);
|
||||
|
||||
case 'md5':
|
||||
default:
|
||||
/* This is the old standard for password storage in SQL */
|
||||
return md5($password);
|
||||
$e_password = md5($password);
|
||||
break;
|
||||
|
||||
// all other types are identical to ldap, so no need to doublicate the code here
|
||||
case 'des':
|
||||
case 'blowish_crypt': // was for some time a typo in setup
|
||||
case 'crypt':
|
||||
case 'sha256_crypt':
|
||||
case 'sha512_crypt':
|
||||
case 'blowfish_crypt':
|
||||
case 'md5_crypt':
|
||||
case 'ext_crypt':
|
||||
case 'smd5':
|
||||
case 'sha':
|
||||
case 'ssha':
|
||||
$e_password = self::encrypt_ldap($password, $type);
|
||||
break;
|
||||
|
||||
default:
|
||||
self::$error = 'no valid encryption available';
|
||||
$e_password = false;
|
||||
break;
|
||||
}
|
||||
if (!self::$error)
|
||||
{
|
||||
self::$error = 'no valid encryption available';
|
||||
}
|
||||
return False;
|
||||
//error_log(__METHOD__."('$password') using '$type' returning ".array2string($e_password).(self::$error ? ' error='.self::$error : ''));
|
||||
return $e_password;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -423,31 +458,6 @@ class auth
|
||||
return strcmp($orig_hash,$new_hash) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare crypted passwords for authentication whether des,ext_des,md5, or blowfish crypt
|
||||
*
|
||||
* @param string $form_val user input value for comparison
|
||||
* @param string $db_val stored value (from database)
|
||||
* @param string $type crypt() type
|
||||
* @return boolean True on successful comparison
|
||||
*/
|
||||
static function crypt_compare($form_val,$db_val,$type)
|
||||
{
|
||||
$saltlen = array(
|
||||
'blowfish_crypt' => 16,
|
||||
'md5_crypt' => 12,
|
||||
'ext_crypt' => 9,
|
||||
'crypt' => 2
|
||||
);
|
||||
|
||||
// PHP's crypt(): salt + hash
|
||||
// notice: "The encryption type is triggered by the salt argument."
|
||||
$salt = substr($db_val, 0, (int)$saltlen[$type]);
|
||||
$new_hash = crypt($form_val, $salt);
|
||||
|
||||
return strcmp($db_val,$new_hash) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare md5_hmac-encrypted passwords for authentication (see RFC2104)
|
||||
*
|
||||
|
@ -128,8 +128,10 @@ class auth_ldap implements auth_backend
|
||||
// try to query password from ldap server (might fail because of ACL) and check if we need to migrate the hash
|
||||
if (($sri = ldap_search($ldap, $userDN,"(objectclass=*)", array('userPassword'))) &&
|
||||
($values = ldap_get_entries($ldap, $sri)) && isset($values[0]['userpassword'][0]) &&
|
||||
($type = preg_match('/^{(.+)}/',$values[0]['userpassword'][0],$matches) ? $matches[1] : 'plain') &&
|
||||
in_array(strtolower($type),explode(',',strtolower($GLOBALS['egw_info']['server']['pwd_migration_types']))))
|
||||
($type = preg_match('/^{(.+)}/',$values[0]['userpassword'][0],$matches) ? strtolower($matches[1]) : 'plain') &&
|
||||
// for crypt use auth::crypt_compare to detect correct sub-type, strlen("{crypt}")=7
|
||||
($type != 'crypt' || auth::crypt_compare($passwd, substr($values[0]['userpassword'][0], 7), $type)) &&
|
||||
in_array($type, explode(',',strtolower($GLOBALS['egw_info']['server']['pwd_migration_types']))))
|
||||
{
|
||||
$this->change_password($passwd, $passwd, $allValues[0]['uidnumber'][0], false);
|
||||
}
|
||||
|
@ -69,22 +69,27 @@ class auth_sql implements auth_backend
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!($match = auth::compare_password($passwd,$row['account_pwd'],$this->type,strtolower($username))) ||
|
||||
preg_match('/^{(.+)}/',$row['account_pwd'],$matches) && // explicit specified hash, eg. from ldap
|
||||
in_array(strtolower($matches[1]),explode(',',strtolower($GLOBALS['egw_info']['server']['pwd_migration_types']))))
|
||||
if(!($match = auth::compare_password($passwd, $row['account_pwd'], $this->type, strtolower($username), $type)) ||
|
||||
$type != $this->type && in_array($type, explode(',',strtolower($GLOBALS['egw_info']['server']['pwd_migration_types']))))
|
||||
{
|
||||
// do we have to migrate an old password ?
|
||||
if($GLOBALS['egw_info']['server']['pwd_migration_allowed'] && !empty($GLOBALS['egw_info']['server']['pwd_migration_types']))
|
||||
{
|
||||
foreach(explode(',', $GLOBALS['egw_info']['server']['pwd_migration_types']) as $type)
|
||||
if (!$match)
|
||||
{
|
||||
if(($match = auth::compare_password($passwd,$row['account_pwd'],$type,strtolower($username))))
|
||||
foreach(explode(',', $GLOBALS['egw_info']['server']['pwd_migration_types']) as $type)
|
||||
{
|
||||
$encrypted_passwd = auth::encrypt_sql($passwd);
|
||||
$this->_update_passwd($encrypted_passwd,$passwd,$row['account_id'],false,true);
|
||||
break;
|
||||
if(($match = auth::compare_password($passwd,$row['account_pwd'],$type,strtolower($username))))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($match)
|
||||
{
|
||||
$encrypted_passwd = auth::encrypt_sql($passwd);
|
||||
$this->_update_passwd($encrypted_passwd,$passwd,$row['account_id'],false,true);
|
||||
}
|
||||
}
|
||||
if (!$match) return false;
|
||||
}
|
||||
|
@ -222,6 +222,14 @@ class egw_db
|
||||
* DB requires varchar columns to be truncated to the max. size (eg. Postgres)
|
||||
*/
|
||||
const CAPABILITY_REQUIRE_TRUNCATE_VARCHAR = 'require_truncate_varchar';
|
||||
/**
|
||||
* How to cast a column to varchar: CAST(%s AS varchar)
|
||||
*
|
||||
* MySQL requires to use CAST(%s AS char)!
|
||||
*
|
||||
* Use as: $sql = sprintf($GLOBALS['egw']->db->capabilities[egw_db::CAPABILITY_CAST_AS_VARCHAR],$expression);
|
||||
*/
|
||||
const CAPABILITY_CAST_AS_VARCHAR = 'cast_as_varchar';
|
||||
/**
|
||||
* default capabilities will be changed by method set_capabilities($ado_driver,$db_version)
|
||||
*
|
||||
@ -240,6 +248,7 @@ class egw_db
|
||||
self::CAPABILITY_CLIENT_ENCODING => false,
|
||||
self::CAPABILITY_CASE_INSENSITIV_LIKE => 'LIKE',
|
||||
self::CAPABILITY_REQUIRE_TRUNCATE_VARCHAR => true,
|
||||
self::CAPABILITY_CAST_AS_VARCHAR => 'CAST(%s AS varchar)',
|
||||
);
|
||||
|
||||
var $prepared_sql = array(); // sql is the index
|
||||
@ -265,6 +274,7 @@ class egw_db
|
||||
$this->$var = $db_data[$key];
|
||||
}
|
||||
}
|
||||
//if ($GLOBALS['egw_info']['server']['default_domain'] == 'ralfsmacbook.local') $this->query_log = '/tmp/query.log';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -498,6 +508,7 @@ class egw_db
|
||||
$this->capabilities[self::CAPABILITY_UNION] = (float) $db_version >= 4.0;
|
||||
$this->capabilities[self::CAPABILITY_NAME_CASE] = 'preserv';
|
||||
$this->capabilities[self::CAPABILITY_CLIENT_ENCODING] = (float) $db_version >= 4.1;
|
||||
$this->capabilities[self::CAPABILITY_CAST_AS_VARCHAR] = 'CAST(%s AS char)';
|
||||
break;
|
||||
|
||||
case 'postgres':
|
||||
@ -836,7 +847,7 @@ class egw_db
|
||||
if ($id === False) // function not supported
|
||||
{
|
||||
echo "<p>db::get_last_insert_id(table='$table',field='$field') not yet implemented for db-type '$this->Type' OR no insert operation before</p>\n";
|
||||
function_backtrace();
|
||||
echo '<p>'.function_backtrace()."</p>\n";
|
||||
return -1;
|
||||
}
|
||||
return $id;
|
||||
@ -1251,7 +1262,7 @@ class egw_db
|
||||
case 'mssql':
|
||||
return "DATEDIFF(second,'1970-01-01',($expr))";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1313,6 +1324,38 @@ class egw_db
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a column or sql expression to integer, necessary at least for postgreSQL
|
||||
*
|
||||
* @param string $expr
|
||||
* @return string
|
||||
*/
|
||||
function to_int($expr)
|
||||
{
|
||||
switch($this->Type)
|
||||
{
|
||||
case 'pgsql':
|
||||
return $expr.'::integer';
|
||||
}
|
||||
return $expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a column or sql expression to varchar, necessary at least for postgreSQL
|
||||
*
|
||||
* @param string $expr
|
||||
* @return string
|
||||
*/
|
||||
function to_varchar($expr)
|
||||
{
|
||||
switch($this->Type)
|
||||
{
|
||||
case 'pgsql':
|
||||
return 'CAST('.$expr.' AS varchar)';
|
||||
}
|
||||
return $expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correctly Quote Identifiers like table- or colmnnames for use in SQL-statements
|
||||
*
|
||||
|
@ -389,7 +389,7 @@ abstract class egw_framework
|
||||
{
|
||||
if( $GLOBALS['egw_info']['user']['apps']['admin'] && $GLOBALS['egw_info']['user']['preferences']['common']['show_currentusers'])
|
||||
{
|
||||
$current_users = '<a href="' . egw::link('/index.php','menuaction=admin.uicurrentsessions.list_sessions') . '">' .
|
||||
$current_users = '<a href="' . egw::link('/index.php','menuaction=admin.admin_accesslog.sessions') . '">' .
|
||||
lang('Current users') . ': ' . $GLOBALS['egw']->session->session_count() . '</a>';
|
||||
return $current_users;
|
||||
}
|
||||
|
@ -132,6 +132,13 @@ class egw_session
|
||||
*/
|
||||
var $kp3;
|
||||
|
||||
/**
|
||||
* Primary key of egw_access_log row for updates
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
var $sessionid_access_log;
|
||||
|
||||
/**
|
||||
* name of XML-RPC/SOAP method called
|
||||
*
|
||||
@ -579,7 +586,7 @@ class egw_session
|
||||
$this->register_session($this->login,$user_ip,$now,$this->session_flags);
|
||||
if ($this->session_flags != 'A') // dont log anonymous sessions
|
||||
{
|
||||
$this->log_access($this->sessionid,$login,$user_ip,$this->account_id);
|
||||
$this->sessionid_access_log = $this->log_access($this->sessionid,$login,$user_ip,$this->account_id);
|
||||
}
|
||||
self::appsession('account_previous_login','phpgwapi',$GLOBALS['egw']->auth->previous_login);
|
||||
$GLOBALS['egw']->accounts->update_lastlogin($this->account_id,$user_ip);
|
||||
@ -640,10 +647,11 @@ class egw_session
|
||||
/**
|
||||
* Write or update (for logout) the access_log
|
||||
*
|
||||
* @param string $sessionid id of session or 0 for unsuccessful logins
|
||||
* @param string|int $sessionid PHP sessionid or 0 for unsuccessful logins
|
||||
* @param string $login account_lid (evtl. with domain) or '' for settion the logout-time
|
||||
* @param string $user_ip ip to log
|
||||
* @param int $account_id numerical account_id
|
||||
* @return int $sessionid primary key of egw_access_log for login, null otherwise
|
||||
*/
|
||||
private function log_access($sessionid,$login='',$user_ip='',$account_id='')
|
||||
{
|
||||
@ -652,17 +660,24 @@ class egw_session
|
||||
if ($login)
|
||||
{
|
||||
$GLOBALS['egw']->db->insert(self::ACCESS_LOG_TABLE,array(
|
||||
'sessionid' => $sessionid,
|
||||
'session_php' => $sessionid,
|
||||
'loginid' => $login,
|
||||
'ip' => $user_ip,
|
||||
'li' => $now,
|
||||
'lo' => 0,
|
||||
'account_id'=> $account_id,
|
||||
),false,__LINE__,__FILE__);
|
||||
|
||||
$ret = $GLOBALS['egw']->db->get_last_insert_id(self::ACCESS_LOG_TABLE,'sessionid');
|
||||
}
|
||||
else
|
||||
{
|
||||
$GLOBALS['egw']->db->update(self::ACCESS_LOG_TABLE,array('lo' => $now),array('sessionid' => $sessionid),__LINE__,__FILE__);
|
||||
$GLOBALS['egw']->db->update(self::ACCESS_LOG_TABLE,array(
|
||||
'lo' => $now
|
||||
),is_numeric($sessionid) ? array(
|
||||
'sessionid' => $sessionid,
|
||||
) : array(
|
||||
'session_php' => $sessionid,
|
||||
),__LINE__,__FILE__);
|
||||
}
|
||||
if ($GLOBALS['egw_info']['server']['max_access_log_age'])
|
||||
{
|
||||
@ -670,6 +685,8 @@ class egw_session
|
||||
|
||||
$GLOBALS['egw']->db->delete(self::ACCESS_LOG_TABLE,"li < $max_age",__LINE__,__FILE__);
|
||||
}
|
||||
//error_log(__METHOD__."('$sessionid', '$login', '$user_ip', $account_id) returning ".array2string($ret));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -866,6 +883,10 @@ class egw_session
|
||||
{
|
||||
$this->update_dla();
|
||||
}
|
||||
elseif ($GLOBALS['egw_info']['flags']['currentapp'] == 'notifications')
|
||||
{
|
||||
$this->update_notification_heartbeat();
|
||||
}
|
||||
$this->account_id = $GLOBALS['egw']->accounts->name2id($this->account_lid,'account_lid','u');
|
||||
if (!$this->account_id)
|
||||
{
|
||||
@ -964,6 +985,15 @@ class egw_session
|
||||
//echo 'DEBUG: Sessions: account_id is empty!<br>'."\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// query accesslog-id, if not set in session (session is made persistent after login!)
|
||||
if (!$this->sessionid_access_log)
|
||||
{
|
||||
$this->sessionid_access_log = $GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE,'sessionid',array(
|
||||
'session_php' => $this->sessionid,
|
||||
),__LINE__,__FILE__)->fetchColumn();
|
||||
//error_log(__METHOD__."() sessionid=$this->sessionid --> sessionid_access_log=$this->sessionid_access_log");
|
||||
}
|
||||
if (self::ERROR_LOG_DEBUG) error_log("--> session::verify($sessionid) SUCCESS");
|
||||
|
||||
return true;
|
||||
@ -976,16 +1006,23 @@ class egw_session
|
||||
* @param string $kp3
|
||||
* @return boolean true on success, false on error
|
||||
*/
|
||||
function destroy($sessionid, $kp3)
|
||||
function destroy($sessionid, $kp3='')
|
||||
{
|
||||
if (!$sessionid && $kp3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$this->log_access($this->sessionid); // log logout-time
|
||||
$this->log_access($sessionid); // log logout-time
|
||||
|
||||
if (self::ERROR_LOG_DEBUG) error_log(__METHOD__."($sessionid,$kp3) parent::destroy()=$ret");
|
||||
|
||||
if (is_numeric($sessionid)) // do we have a access-log-id --> get PHP session id
|
||||
{
|
||||
$sessionid = $GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE,'session_php',array(
|
||||
'sessionid' => $sessionid,
|
||||
),__LINE__,__FILE__)->fetchColumn();
|
||||
}
|
||||
|
||||
$GLOBALS['egw']->hooks->process(array(
|
||||
'location' => 'session_destroyed',
|
||||
'sessionid' => $sessionid,
|
||||
@ -1011,12 +1048,12 @@ class egw_session
|
||||
}
|
||||
else
|
||||
{
|
||||
$sessions = self::session_list(0,'','',true);
|
||||
$this->commit_session(); // close our own session
|
||||
|
||||
if (isset($sessions[$sessionid]) && session_module_name() == 'files')
|
||||
session_id($sessionid);
|
||||
if (session_start())
|
||||
{
|
||||
//echo '<p>'.__METHOD__."($session_id): unlink('".$sessions[$sessionid]['php_session_file']."')</p>\n";
|
||||
@unlink($sessions[$sessionid]['php_session_file']);
|
||||
session_destroy();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -1320,24 +1357,41 @@ class egw_session
|
||||
}
|
||||
|
||||
/**
|
||||
* Update session_action and session_dla (session last used time),
|
||||
* Update session_action and session_dla (session last used time)
|
||||
*/
|
||||
private function update_dla()
|
||||
{
|
||||
if (isset($_GET['menuaction']))
|
||||
// This way XML-RPC users aren't always listed as xmlrpc.php
|
||||
if ($this->xmlrpc_method_called)
|
||||
{
|
||||
$action = $this->xmlrpc_method_called;
|
||||
}
|
||||
elseif (isset($_GET['menuaction']))
|
||||
{
|
||||
$action = $_GET['menuaction'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$action = $_SERVER['PHP_SELF'];
|
||||
// remove EGroupware path, if not installed in webroot
|
||||
$egw_path = $GLOBALS['egw_info']['server']['webserver_url'];
|
||||
if ($egw_path[0] != '/') $egw_path = parse_url($egw_path,PHP_URL_PATH);
|
||||
if ($egw_path)
|
||||
{
|
||||
list(,$action) = explode($egw_path,$action,2);
|
||||
}
|
||||
}
|
||||
|
||||
// This way XML-RPC users aren't always listed as
|
||||
// xmlrpc.php
|
||||
if ($this->xmlrpc_method_called)
|
||||
// update dla in access-log table, if we have an access-log row (non-anonymous session)
|
||||
if ($this->sessionid_access_log)
|
||||
{
|
||||
$action = $this->xmlrpc_method_called;
|
||||
$GLOBALS['egw']->db->update(self::ACCESS_LOG_TABLE,array(
|
||||
'session_dla' => time(),
|
||||
'session_action' => $action,
|
||||
'lo' => null, // just in case it was (automatic) timed out before
|
||||
),array(
|
||||
'sessionid' => $this->sessionid_access_log,
|
||||
),__LINE__,__FILE__);
|
||||
}
|
||||
|
||||
$_SESSION[self::EGW_SESSION_VAR]['session_dla'] = time();
|
||||
@ -1345,6 +1399,23 @@ class egw_session
|
||||
if (self::ERROR_LOG_DEBUG) error_log(__METHOD__.'() _SESSION['.self::EGW_SESSION_VAR.']='.array2string($_SESSION[self::EGW_SESSION_VAR]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update notification_heartbeat time of session
|
||||
*/
|
||||
private function update_notification_heartbeat()
|
||||
{
|
||||
// update dla in access-log table, if we have an access-log row (non-anonymous session)
|
||||
if ($this->sessionid_access_log)
|
||||
{
|
||||
$GLOBALS['egw']->db->update(self::ACCESS_LOG_TABLE,array(
|
||||
'notification_heartbeat' => time(),
|
||||
),array(
|
||||
'sessionid' => $this->sessionid_access_log,
|
||||
'lo IS NULL',
|
||||
),__LINE__,__FILE__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the diverse repositories / init classes with data from the just loged in user
|
||||
*
|
||||
@ -1473,32 +1544,80 @@ class egw_session
|
||||
* Get a session list (of the current instance)
|
||||
*
|
||||
* @param int $start
|
||||
* @param string $sort='session_dla' session_lid, session_id, session_started, session_logintime, session_action, or (default) session_dla
|
||||
* @param string $order='DESC' ASC or DESC
|
||||
* @param string $sort='DESC' ASC or DESC
|
||||
* @param string $order='session_dla' session_lid, session_id, session_started, session_logintime, session_action, or (default) session_dla
|
||||
* @param boolean $all_no_sort=False skip sorting and limiting to maxmatchs if set to true
|
||||
* @return array with sessions (values for keys as in $sort) or array() if not supported by session-handler
|
||||
* @return array with sessions (values for keys as in $sort)
|
||||
*/
|
||||
public static function session_list($start,$sort='DESC',$order='session_dla',$all_no_sort=False)
|
||||
{
|
||||
if (method_exists(self::$session_handler,'session_list'))
|
||||
$sessions = array();
|
||||
if (!preg_match('/^[a-z0-9_ ,]+$/i',$order_by=$order.' '.$sort))
|
||||
{
|
||||
return call_user_func(array(self::$session_handler,'session_list'),$start,$sort,$order,$all_no_sort);
|
||||
$order_by = 'session_dla DESC';
|
||||
}
|
||||
return array();
|
||||
foreach($GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE, '*', array(
|
||||
'lo' => null,
|
||||
'session_dla > '.(int)(time() - $GLOBALS['egw_info']['server']['sessions_timeout']),
|
||||
'(notification_heartbeat IS NULL OR notification_heartbeat > '.self::heartbeat_limit().')',
|
||||
), __LINE__, __FILE__, $all_no_sort ? false : $start, 'ORDER BY '.$order_by) as $row)
|
||||
{
|
||||
$sessions[$row['sessionid']] = $row;
|
||||
}
|
||||
return $sessions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query number of sessions (not more then once every N secs)
|
||||
*
|
||||
* @return int|boolean integer number of sessions or false if not supported by session-handler
|
||||
* @return int number of active sessions
|
||||
*/
|
||||
public static function session_count()
|
||||
{
|
||||
if (method_exists(self::$session_handler,'session_count'))
|
||||
return $GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE, 'COUNT(*)', array(
|
||||
'lo' => null,
|
||||
'session_dla > '.(int)(time() - $GLOBALS['egw_info']['server']['sessions_timeout']),
|
||||
'(notification_heartbeat IS NULL OR notification_heartbeat > '.self::heartbeat_limit().')',
|
||||
), __LINE__, __FILE__)->fetchColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get limit / latest time of heartbeat for session to be active
|
||||
*
|
||||
* @return int TS in server-time
|
||||
*/
|
||||
public static function heartbeat_limit()
|
||||
{
|
||||
static $limit;
|
||||
|
||||
if (is_null($limit))
|
||||
{
|
||||
return call_user_func(array(self::$session_handler,'session_count'));
|
||||
$config = config::read('notifications');
|
||||
if (!($popup_poll_interval = $config['popup_poll_interval']))
|
||||
{
|
||||
$popup_poll_interval = 60;
|
||||
}
|
||||
$limit = (int)(time() - $popup_poll_interval-10); // 10s grace periode
|
||||
}
|
||||
return false;
|
||||
return $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given user can be reached via notifications
|
||||
*
|
||||
* Checks if notifications callback checked in not more then heartbeat_limit() seconds ago
|
||||
*
|
||||
* @param int $account_id
|
||||
* @param int number of active sessions of given user with notifications running
|
||||
*/
|
||||
public static function notifications_active($account_id)
|
||||
{
|
||||
return $GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE, 'COUNT(*)', array(
|
||||
'lo' => null,
|
||||
'session_dla > '.(int)(time() - $GLOBALS['egw_info']['server']['sessions_timeout']),
|
||||
'account_id' => $account_id,
|
||||
'notifications_heartbeat > '.self::heartbeat_limit(),
|
||||
), __LINE__, __FILE__)->fetchColumn();
|
||||
}
|
||||
|
||||
/*
|
||||
|
264
phpgwapi/inc/class.egw_tail.inc.php
Normal file
264
phpgwapi/inc/class.egw_tail.inc.php
Normal file
@ -0,0 +1,264 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware - Ajax log file viewer (tail -f)
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker@outdoor-training.de>
|
||||
* @copyright 2012 by RalfBecker@outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package etemplate
|
||||
* @subpackage api
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ajax log file viewer (tail -f)
|
||||
*
|
||||
* To not allow to view arbitrary files, allowed filenames are stored in the session.
|
||||
* Class fetches log-file periodically in chunks for 8k.
|
||||
* If fetch returns no new content next request will be in 2s, otherwise in 200ms.
|
||||
* As logfiles can be quiet huge, we display at max the last 32k of it!
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* $error_log = new egw_tail('/var/log/apache2/error_log');
|
||||
* echo $error_log->show();
|
||||
*
|
||||
* Strongly prefered for security reasons is to use a path relative to EGroupware's files_dir,
|
||||
* eg. new egw_tail('groupdav/somelog')!
|
||||
*/
|
||||
class egw_tail
|
||||
{
|
||||
/**
|
||||
* Maximum size of single ajax request
|
||||
*
|
||||
* Currently also maximum size / 4 of displayed logfile content!
|
||||
*/
|
||||
const MAX_CHUNK_SIZE = 8192;
|
||||
|
||||
/**
|
||||
* Contains allowed filenames to display, we can NOT allow to display arbitrary files!
|
||||
*
|
||||
* @param array
|
||||
*/
|
||||
protected $filenames;
|
||||
|
||||
/**
|
||||
* Filename class is instanciated to view, set by constructor
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* Methods allowed to call via menuaction
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $public_functions = array(
|
||||
'download' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $filename=null if not starting with as slash relative to EGw files dir (this is strongly prefered for security reasons)
|
||||
*/
|
||||
public function __construct($filename=null)
|
||||
{
|
||||
$this->filenames =& egw_cache::getSession('phpgwapi', __CLASS__);
|
||||
|
||||
if ($filename)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
|
||||
if (!$this->filenames || !in_array($filename,$this->filenames)) $this->filenames[] = $filename;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback to load next chunk of log-file
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $start=0 last position in log-file
|
||||
* @throws egw_exception_wrong_parameter
|
||||
*/
|
||||
public function ajax_chunk($filename,$start=0)
|
||||
{
|
||||
if (!in_array($filename,$this->filenames))
|
||||
{
|
||||
throw new egw_exception_wrong_parameter("Not allowed to view '$filename'!");
|
||||
}
|
||||
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
|
||||
|
||||
if (file_exists($filename))
|
||||
{
|
||||
$size = filesize($filename);
|
||||
if (!$start || $start < 0 || $start > $size || $size-$start > 4*self::MAX_CHUNK_SIZE)
|
||||
{
|
||||
$start = $size - 4*self::MAX_CHUNK_SIZE;
|
||||
if ($start < 0) $start = 0;
|
||||
}
|
||||
$size = egw_vfs::hsize($size);
|
||||
$content = file_get_contents($filename, false, null, $start, self::MAX_CHUNK_SIZE);
|
||||
$length = bytes($content);
|
||||
$writable = is_writable($filename) || is_writable(dirname($filename));
|
||||
}
|
||||
else
|
||||
{
|
||||
$start = $length = 0;
|
||||
$content = '';
|
||||
$writable = $size = false;
|
||||
}
|
||||
$response = egw_json_response::get();
|
||||
$response->data(array( // send all responses as data
|
||||
'size' => $size,
|
||||
'writable' => $writable,
|
||||
'next' => $start + $length,
|
||||
'length' => $length,
|
||||
'content' => $content,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback to delete log-file
|
||||
*
|
||||
* @param string $filename
|
||||
* @param boolean $truncate=false true: truncate file, false: delete file
|
||||
* @throws egw_exception_wrong_parameter
|
||||
*/
|
||||
public function ajax_delete($filename,$truncate=false)
|
||||
{
|
||||
if (!in_array($filename,$this->filenames))
|
||||
{
|
||||
throw new egw_exception_wrong_parameter("Not allowed to view '$filename'!");
|
||||
}
|
||||
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
|
||||
if ($truncate)
|
||||
{
|
||||
file_put_contents($filename, '');
|
||||
}
|
||||
else
|
||||
{
|
||||
unlink($filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html & javascript for logviewer
|
||||
*
|
||||
* @param string $header=null default $this->filename
|
||||
* @param string $id='log'
|
||||
* @return string
|
||||
* @throws egw_exception_wrong_parameter
|
||||
*/
|
||||
public function show($header=null, $id='log')
|
||||
{
|
||||
if (!isset($this->filename))
|
||||
{
|
||||
throw new egw_exception_wrong_parameter("Must be instanciated with filename!");
|
||||
}
|
||||
if (is_null($header)) $header = $this->filename;
|
||||
|
||||
return '
|
||||
<script type="text/javascript">
|
||||
var '.$id.'_tail_start = 0;
|
||||
function button_'.$id.'(button)
|
||||
{
|
||||
if (button.id != "clear_'.$id.'")
|
||||
{
|
||||
var ajax = new egw_json_request("home.egw_tail.ajax_delete",["'.$this->filename.'",button.id=="empty_'.$id.'"]);
|
||||
ajax.sendRequest(true);
|
||||
}
|
||||
$j("#'.$id.'").text("");
|
||||
}
|
||||
function refresh_'.$id.'()
|
||||
{
|
||||
var ajax = new egw_json_request("home.egw_tail.ajax_chunk",["'.$this->filename.'",'.$id.'_tail_start]);
|
||||
ajax.sendRequest(true,function(_data) {
|
||||
if (_data.length) {
|
||||
'.$id.'_tail_start = _data.next;
|
||||
var log = $j("#'.$id.'").append(_data.content.replace(/</g,"<"));
|
||||
log.animate({ scrollTop: log.attr("scrollHeight") - log.height() + 20 }, 500);
|
||||
}
|
||||
if (_data.size === false)
|
||||
{
|
||||
$j("#download_'.$id.'").hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
$j("#download_'.$id.'").show().attr("title","'.lang('Size').': "+_data.size);
|
||||
}
|
||||
if (_data.writable === false)
|
||||
{
|
||||
$j("#delete_'.$id.'").hide();
|
||||
$j("#empty_'.$id.'").hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
$j("#delete_'.$id.'").show();
|
||||
$j("#empty_'.$id.'").show();
|
||||
}
|
||||
window.setTimeout(refresh_'.$id.',_data.length?200:2000);
|
||||
});
|
||||
}
|
||||
function resize_'.$id.'()
|
||||
{
|
||||
$j("#'.$id.'").width(egw_getWindowInnerWidth()-20).height(egw_getWindowInnerHeight()-33);
|
||||
}
|
||||
$j(document).ready(function()
|
||||
{
|
||||
resize_'.$id.'();
|
||||
refresh_'.$id.'();
|
||||
});
|
||||
$j(window).resize(resize_'.$id.');
|
||||
</script>
|
||||
<p style="float: left; margin: 5px"><b>'.htmlspecialchars($header).'</b></p>
|
||||
<div style="float: right; margin: 2px; margin-right: 5px">
|
||||
'.html::form(
|
||||
html::input('clear_'.$id,lang('Clear window'),'button','id="clear_'.$id.'" onClick="button_'.$id.'(this)"')."\n".
|
||||
html::input('delete_'.$id,lang('Delete file'),'button','id="delete_'.$id.'" onClick="button_'.$id.'(this)"')."\n".
|
||||
html::input('empty_'.$id,lang('Empty file'),'button','id="empty_'.$id.'" onClick="button_'.$id.'(this)"')."\n".
|
||||
html::input('download_'.$id,lang('Download'),'submit','id="download_'.$id.'"'),
|
||||
'','/index.php',array(
|
||||
'menuaction' => 'phpgwapi.egw_tail.download',
|
||||
'filename' => $this->filename,
|
||||
)).'
|
||||
</div>
|
||||
<pre class="tail" id="'.$id.'" style="clear: both; width: 99.5%; border: 2px groove silver; margin-bottom: 0; overflow: auto;"></pre>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a file specified per GET parameter (must be in $this->filesnames!)
|
||||
*
|
||||
* @throws egw_exception_wrong_parameter
|
||||
*/
|
||||
public function download()
|
||||
{
|
||||
$filename = $_GET['filename'];
|
||||
if (!in_array($filename,$this->filenames))
|
||||
{
|
||||
throw new egw_exception_wrong_parameter("Not allowed to download '$filename'!");
|
||||
}
|
||||
html::content_header(basename($filename),'text/plain');
|
||||
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
|
||||
for($n=ob_get_level(); $n > 0; --$n) ob_end_clean(); // stop all output buffering, to NOT run into memory_limit
|
||||
readfile($filename);
|
||||
common::egw_exit();
|
||||
}
|
||||
}
|
||||
|
||||
// some testcode, if this file is called via it's URL (you need to uncomment and adapt filename!)
|
||||
/*if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__)
|
||||
{
|
||||
$GLOBALS['egw_info'] = array(
|
||||
'flags' => array(
|
||||
'currentapp' => 'admin',
|
||||
'nonavbar' => true,
|
||||
),
|
||||
);
|
||||
include_once '../../header.inc.php';
|
||||
|
||||
$error_log = new egw_tail('/opt/local/apache2/logs/error_log');
|
||||
echo $error_log->show();
|
||||
}*/
|
File diff suppressed because it is too large
Load Diff
@ -7,12 +7,15 @@
|
||||
* @package api
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* EGroupware: GroupDAV access: abstract baseclass for groupdav/caldav/carddav handlers
|
||||
*
|
||||
* Permanent error_log() calls should use $this->groupdav->log($str) instead, to be send to PHP error_log()
|
||||
* and our request-log (prefixed with "### " after request and response, like exceptions).
|
||||
*/
|
||||
abstract class groupdav_handler
|
||||
{
|
||||
@ -37,6 +40,12 @@ abstract class groupdav_handler
|
||||
* @var accounts
|
||||
*/
|
||||
var $accounts;
|
||||
/**
|
||||
* Reference to the ACL class
|
||||
*
|
||||
* @var acl
|
||||
*/
|
||||
var $acl;
|
||||
/**
|
||||
* Translates method names into ACL bits
|
||||
*
|
||||
@ -53,18 +62,18 @@ abstract class groupdav_handler
|
||||
* @var string
|
||||
*/
|
||||
var $app;
|
||||
/**
|
||||
* Calling groupdav object
|
||||
*
|
||||
* @var groupdav
|
||||
*/
|
||||
var $groupdav;
|
||||
/**
|
||||
* Base url of handler, need to prefix all pathes not automatic handled by HTTP_WebDAV_Server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $base_uri;
|
||||
/**
|
||||
* principal URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $principalURL;
|
||||
/**
|
||||
* HTTP_IF_MATCH / etag of current request / last call to _common_get_put_delete() method
|
||||
*
|
||||
@ -78,34 +87,39 @@ abstract class groupdav_handler
|
||||
*/
|
||||
var $agent;
|
||||
|
||||
/**
|
||||
* Extension to append to url/path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static $path_extension = '.ics';
|
||||
|
||||
/**
|
||||
* Which attribute to use to contruct name part of url/path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static $path_attr = 'id';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $app 'calendar', 'addressbook' or 'infolog'
|
||||
* @param int $debug=null debug-level to set
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @param string $principalURL=null pricipal url of handler
|
||||
* @param groupdav $groupdav calling class
|
||||
*/
|
||||
function __construct($app,$debug=null,$base_uri=null,$principalURL=null)
|
||||
function __construct($app, groupdav $groupdav)
|
||||
{
|
||||
$this->app = $app;
|
||||
if (!is_null($debug)) $this->debug = $debug;
|
||||
$this->base_uri = is_null($base_uri) ? $base_uri : $_SERVER['SCRIPT_NAME'];
|
||||
if (is_null($principalURL))
|
||||
{
|
||||
$this->principalURL = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:") .
|
||||
'//'.$_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->principalURL = $principalURL.'principals/users/'.
|
||||
$GLOBALS['egw_info']['user']['account_lid'].'/';
|
||||
}
|
||||
if (!is_null($parent->debug)) $this->debug = $groupdav->debug;
|
||||
$this->base_uri = $groupdav->base_uri;
|
||||
$this->groupdav = $groupdav;
|
||||
|
||||
$this->agent = self::get_agent();
|
||||
|
||||
$this->egw_charset = translation::charset();
|
||||
|
||||
$this->accounts = $GLOBALS['egw']->accounts;
|
||||
$this->acl = $GLOBALS['egw']->acl;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,16 +176,17 @@ abstract class groupdav_handler
|
||||
/**
|
||||
* Read an entry
|
||||
*
|
||||
* @param string/int $id
|
||||
* @return array/boolean array with entry, false if no read rights, null if $id does not exist
|
||||
* @param string|int $id
|
||||
* @param string $path=null implementation can use it, used in call from _common_get_put_delete
|
||||
* @return array|boolean array with entry, false if no read rights, null if $id does not exist
|
||||
*/
|
||||
abstract function read($id);
|
||||
abstract function read($id /*,$path=null*/);
|
||||
|
||||
/**
|
||||
* Check if user has the neccessary rights on an entry
|
||||
*
|
||||
* @param int $acl EGW_ACL_READ, EGW_ACL_EDIT or EGW_ACL_DELETE
|
||||
* @param array/int $entry entry-array or id
|
||||
* @param array|int $entry entry-array or id
|
||||
* @return boolean null if entry does not exist, false if no access, true if access permitted
|
||||
*/
|
||||
abstract function check_access($acl,$entry);
|
||||
@ -182,9 +197,10 @@ abstract class groupdav_handler
|
||||
* @param array $props=array() regular props by the groupdav handler
|
||||
* @param string $displayname
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @param int $user=null account_id of owner of collection
|
||||
* @return array
|
||||
*/
|
||||
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
|
||||
public function extra_properties(array $props=array(), $displayname, $base_uri=null, $user=null)
|
||||
{
|
||||
return $props;
|
||||
}
|
||||
@ -192,8 +208,8 @@ abstract class groupdav_handler
|
||||
/**
|
||||
* Get the etag for an entry, can be reimplemented for other algorithm or field names
|
||||
*
|
||||
* @param array/int $event array with event or cal_id
|
||||
* @return string/boolean string with etag or false
|
||||
* @param array|int $event array with event or cal_id
|
||||
* @return string|boolean string with etag or false
|
||||
*/
|
||||
function get_etag($entry)
|
||||
{
|
||||
@ -206,7 +222,7 @@ abstract class groupdav_handler
|
||||
// error_log(__METHOD__."(".array2string($entry).") Cant create etag!");
|
||||
return false;
|
||||
}
|
||||
return 'EGw-'.$entry['id'].':'.(isset($entry['etag']) ? $entry['etag'] : $entry['modified']).'-wGE';
|
||||
return $entry['id'].':'.(isset($entry['etag']) ? $entry['etag'] : $entry['modified']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -217,7 +233,7 @@ abstract class groupdav_handler
|
||||
*/
|
||||
static function etag2value($etag)
|
||||
{
|
||||
list(,$val) = explode(':',substr($etag,4,-4),2);
|
||||
list(,$val) = explode(':',$etag,2);
|
||||
|
||||
return $val;
|
||||
}
|
||||
@ -230,19 +246,22 @@ abstract class groupdav_handler
|
||||
*
|
||||
* @param string $method GET, PUT, DELETE
|
||||
* @param array &$options
|
||||
* @param int $id
|
||||
* @param int|string &$id on return self::$path_extension got removed
|
||||
* @param boolean &$return_no_access=false if set to true on call, instead of '403 Forbidden' the entry is returned and $return_no_access===false
|
||||
* @param boolean $ignore_if_match=false if true, ignore If-Match precondition
|
||||
* @return array|string entry on success, string with http-error-code on failure, null for PUT on an unknown id
|
||||
*/
|
||||
function _common_get_put_delete($method,&$options,$id,&$return_no_access=false)
|
||||
function _common_get_put_delete($method,&$options,&$id,&$return_no_access=false,$ignore_if_match=false)
|
||||
{
|
||||
if (self::$path_extension) $id = basename($id,self::$path_extension);
|
||||
|
||||
if ($this->app != 'principals' && !$GLOBALS['egw_info']['user']['apps'][$this->app])
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."($method,,$id) 403 Forbidden: no app rights for '$this->app'");
|
||||
return '403 Forbidden'; // no app rights
|
||||
}
|
||||
$extra_acl = $this->method2acl[$method];
|
||||
if (!($entry = $this->read($id)) && ($method != 'PUT' || $entry === false) ||
|
||||
if (!($entry = $this->read($id, $options['path'])) && ($method != 'PUT' || $entry === false) ||
|
||||
($extra_acl != EGW_ACL_READ && $this->check_access($extra_acl,$entry) === false))
|
||||
{
|
||||
if ($return_no_access && !is_null($entry))
|
||||
@ -261,29 +280,35 @@ abstract class groupdav_handler
|
||||
$etag = $this->get_etag($entry);
|
||||
// If the clients sends an "If-Match" header ($_SERVER['HTTP_IF_MATCH']) we check with the current etag
|
||||
// of the calendar --> on failure we return 412 Precondition failed, to not overwrite the modifications
|
||||
if (isset($_SERVER['HTTP_IF_MATCH']))
|
||||
if (isset($_SERVER['HTTP_IF_MATCH']) && !$ignore_if_match)
|
||||
{
|
||||
if (strstr($_SERVER['HTTP_IF_MATCH'], $etag) === false)
|
||||
$this->http_if_match = $_SERVER['HTTP_IF_MATCH'];
|
||||
// strip of quotes around etag, if they exist, that way we allow etag with and without quotes
|
||||
if ($this->http_if_match[0] == '"') $this->http_if_match = substr($this->http_if_match, 1, -1);
|
||||
|
||||
if ($this->http_if_match !== $etag)
|
||||
{
|
||||
$this->http_if_match = $_SERVER['HTTP_IF_MATCH'];
|
||||
if ($this->debug) error_log(__METHOD__."($method,,$id) HTTP_IF_MATCH='$_SERVER[HTTP_IF_MATCH]', etag='$etag': 412 Precondition failed");
|
||||
if ($this->debug) error_log(__METHOD__."($method,path=$options[path],$id) HTTP_IF_MATCH='$_SERVER[HTTP_IF_MATCH]', etag='$etag': 412 Precondition failed".array2string($entry));
|
||||
return '412 Precondition Failed';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->http_if_match = $etag;
|
||||
// if an IF_NONE_MATCH is given, check if we need to send a new export, or the current one is still up-to-date
|
||||
if ($method == 'GET' && isset($_SERVER['HTTP_IF_NONE_MATCH']))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."($method,,$id) HTTP_IF_NONE_MATCH='$_SERVER[HTTP_IF_NONE_MATCH]', etag='$etag': 304 Not Modified");
|
||||
return '304 Not Modified';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."($method,,$id) HTTP_IF_NONE_MATCH='$_SERVER[HTTP_IF_NONE_MATCH]', etag='$etag': 412 Precondition failed");
|
||||
return '412 Precondition Failed';
|
||||
$if_none_match = $_SERVER['HTTP_IF_NONE_MATCH'];
|
||||
// strip of quotes around etag, if they exist, that way we allow etag with and without quotes
|
||||
if ($if_none_match[0] == '"') $if_none_match = substr($if_none_match, 1, -1);
|
||||
|
||||
// if an IF_NONE_MATCH is given, check if we need to send a new export, or the current one is still up-to-date
|
||||
if (in_array($method, array('GET','HEAD')) && $etag === $if_none_match)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."($method,,$id) HTTP_IF_NONE_MATCH='$_SERVER[HTTP_IF_NONE_MATCH]', etag='$etag': 304 Not Modified");
|
||||
return '304 Not Modified';
|
||||
}
|
||||
if ($method == 'PUT' && ($if_none_match == '*' || $if_none_match == $etag))
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."($method,,$id) HTTP_IF_NONE_MATCH='$_SERVER[HTTP_IF_NONE_MATCH]', etag='$etag': 412 Precondition failed");
|
||||
return '412 Precondition Failed';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $entry;
|
||||
@ -294,13 +319,10 @@ abstract class groupdav_handler
|
||||
*
|
||||
* @static
|
||||
* @param string $app 'calendar', 'addressbook' or 'infolog'
|
||||
* @param int $user=null owner of the collection, default current user
|
||||
* @param int $debug=null debug-level to set
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @param string $principalURL=null pricipal url of handler
|
||||
* @param groupdav $groupdav calling class
|
||||
* @return groupdav_handler
|
||||
*/
|
||||
static function &app_handler($app,$debug=null,$base_uri=null,$principalURL=null)
|
||||
static function app_handler($app, $groupdav)
|
||||
{
|
||||
static $handler_cache = array();
|
||||
|
||||
@ -309,13 +331,10 @@ abstract class groupdav_handler
|
||||
$class = $app.'_groupdav';
|
||||
if (!class_exists($class) && !class_exists($class = 'groupdav_'.$app)) return null;
|
||||
|
||||
$handler_cache[$app] = new $class($app,$debug,$base_uri,$principalURL);
|
||||
$handler_cache[$app] = new $class($app, $groupdav);
|
||||
}
|
||||
$handler_cache[$app]->$debug = $debug;
|
||||
$handler_cache[$app]->$base_uri = $base_uri;
|
||||
$handler_cache[$app]->$principalURL = $principalURL;
|
||||
|
||||
if ($debug) error_log(__METHOD__."('$app', '$base_uri', '$principalURL')");
|
||||
if ($debug) error_log(__METHOD__."('$app')");
|
||||
|
||||
return $handler_cache[$app];
|
||||
}
|
||||
@ -335,19 +354,23 @@ abstract class groupdav_handler
|
||||
// identify the agent (GroupDAV client) from the HTTP_USER_AGENT header
|
||||
$user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
|
||||
foreach(array(
|
||||
'carddav-sync' => 'carddav-sync', // dmfs.org CardDAV client for Android: CardDAV-Sync (Android) (like iOS/5.0.1 (9A405) dataaccessd/1.0) gzip
|
||||
'iphone' => 'iphone', // Apple iPhone iCal
|
||||
'davkit' => 'davkit', // Apple iCal 10.6
|
||||
'coredav' => 'coredav', // Apple iCal 10.7
|
||||
'calendarstore' => 'calendarstore', // Apple iCal 5.0.1 under OS X 10.7.2
|
||||
'dataaccess' => 'dataaccess', // Apple addressbook iPhone
|
||||
'cfnetwork' => 'cfnetwork', // Apple Addressbook 10.6/7
|
||||
'bionicmessage.net' => 'funambol', // funambol GroupDAV connector from bionicmessage.net
|
||||
'zideone' => 'zideone', // zideone outlook plugin
|
||||
'lightning' => 'lightning', // Lighting (SOGo connector for addressbook)
|
||||
'lightning' => 'lightning', // Lighting (incl. SOGo connector for addressbook)
|
||||
'webkit' => 'webkit', // Webkit Browser (also reports KHTML!)
|
||||
'akonadi' => 'akonadi', // new KDE PIM framework (also reports KHTML!)
|
||||
'khtml' => 'kde', // KDE clients
|
||||
'neon' => 'neon',
|
||||
'ical4ol' => 'ical4ol', // iCal4OL client
|
||||
'evolution' => 'evolution', // Evolution
|
||||
'thunderbird' => 'thunderbird', // SOGo connector for addressbook, no Lightning installed
|
||||
) as $pattern => $name)
|
||||
{
|
||||
if (strpos($user_agent,$pattern) !== false)
|
||||
@ -370,6 +393,15 @@ abstract class groupdav_handler
|
||||
if ((int)$matches[1] < 868) $agent .= '_old';
|
||||
}
|
||||
break;
|
||||
case 'kde':
|
||||
// Akonadi (new KDE Pim framework) unfortunately has same user-agent as old kde
|
||||
// we can only assume KDE 4.7+ uses Akonadi native resource, while below this was not available
|
||||
// Unfortunately the old pre-Akonadi GroupDAV resource can still be used, but we have no way of detecting it
|
||||
if (preg_match('/KHTML\/([0-9.]+)/', $_SERVER['HTTP_USER_AGENT'], $matches) && (float)$matches[1] >= 4.7)
|
||||
{
|
||||
$agent = 'akonadi';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -378,6 +410,147 @@ abstract class groupdav_handler
|
||||
|
||||
return $agent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return priviledges for current user, default is read and read-current-user-privilege-set
|
||||
*
|
||||
* Priviledges are for the collection, not the resources / entries!
|
||||
*
|
||||
* @param string $path path of collection
|
||||
* @param int $user=null owner of the collection, default current user
|
||||
* @return array with privileges
|
||||
*/
|
||||
public function current_user_privileges($path, $user=null)
|
||||
{
|
||||
static $grants;
|
||||
if (is_null($grants))
|
||||
{
|
||||
$grants = $this->acl->get_grants($this->app, $this->app != 'addressbook');
|
||||
}
|
||||
$priviledes = array('read-current-user-privilege-set' => 'read-current-user-privilege-set');
|
||||
|
||||
if (!$user || $grants[$user] & EGW_ACL_READ)
|
||||
{
|
||||
$priviledes['read'] = 'read';
|
||||
// allows on all calendars/addressbooks to write properties, as we store them on a per-user basis
|
||||
// and only allow to modify explicit named properties in CalDAV, CardDAV or Calendarserver name-space
|
||||
$priviledes['write-properties'] = 'write-properties';
|
||||
}
|
||||
if (!$user || $grants[$user] & EGW_ACL_ADD)
|
||||
{
|
||||
$priviledes['bind'] = 'bind'; // PUT for new resources
|
||||
}
|
||||
if (!$user || $grants[$user] & EGW_ACL_EDIT)
|
||||
{
|
||||
$priviledes['write-content'] = 'write-content'; // otherwise iOS calendar does not allow to add events
|
||||
}
|
||||
if (!$user || $grants[$user] & EGW_ACL_DELETE)
|
||||
{
|
||||
$priviledes['unbind'] = 'unbind'; // DELETE
|
||||
}
|
||||
// copy/move of existing resources might require write-properties, thought we do not support an explicit PROPATCH
|
||||
return $priviledes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the path/name for an entry
|
||||
*
|
||||
* @param array $entry
|
||||
* @return string
|
||||
*/
|
||||
function get_path($entry)
|
||||
{
|
||||
return $entry[self::$path_attr].self::$path_extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send response-headers for a PUT (or POST with add-member query parameter)
|
||||
*
|
||||
* @param int|array $entry id or array of new created entry
|
||||
* @param string $path
|
||||
* @param int|string $retval
|
||||
* @param boolean $path_attr_is_name=true true: path_attr is ca(l|rd)dav_name, false: id (GroupDAV needs Location header)
|
||||
*/
|
||||
function put_response_headers($entry, $path, $retval, $path_attr_is_name=true)
|
||||
{
|
||||
// we should not return an etag here, as EGroupware never stores ical/vcard byte-by-byte
|
||||
// as SOGO Connector requires ETag header to recognice as successful PUT, we are sending them again for it
|
||||
// --> as all clients dislike not getting an ETag for a PUT, we sending it again even not storing byte-by-byte
|
||||
//if (get_class($this) == 'addressbook_groupdav' && in_array(self::get_agent(),array('thunderbird','lightning')))
|
||||
{
|
||||
header('ETag: "'.$this->get_etag($entry).'"');
|
||||
}
|
||||
// send Location header only if we dont use caldav_name as path-attribute or
|
||||
if ($retval !== true && (!$path_attr_is_name ||
|
||||
// POST with add-member query parameter
|
||||
$_SERVER['REQUEST_METHOD'] == 'POST' && isset($_GET['add-member'])))
|
||||
{
|
||||
$path = preg_replace('|(.*)/[^/]*|', '\1/', $path);
|
||||
header('Location: '.$this->base_uri.$path.$this->get_path($entry));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return calendars/addressbooks shared from other users with the current one
|
||||
*
|
||||
* return array account_id => account_lid pairs
|
||||
*/
|
||||
function get_shared()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return appliction specific settings
|
||||
*
|
||||
* @param array $hook_data
|
||||
* @return array of array with settings
|
||||
*/
|
||||
static function get_settings($hook_data)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a resource
|
||||
*
|
||||
* @param string $path path of collection, NOT entry!
|
||||
* @param array $entry
|
||||
* @param array $props
|
||||
* @return array with values for keys 'path' and 'props'
|
||||
*/
|
||||
public function add_resource($path, array $entry, array $props)
|
||||
{
|
||||
foreach(array(
|
||||
'getetag' => $this->get_etag($entry),
|
||||
'getcontenttype' => 'text/calendar',
|
||||
'getlastmodified' => $entry['modified'],
|
||||
'displayname' => $entry['title'],
|
||||
) as $name => $value)
|
||||
{
|
||||
if (!isset($props[$name]))
|
||||
{
|
||||
$props[$name] = $value;
|
||||
}
|
||||
}
|
||||
// if requested add privileges
|
||||
$privileges = array('read', 'read-current-user-privilege-set');
|
||||
if ($this->groupdav->prop_requested('current-user-privilege-set') === true && !isset($props['current-user-privilege-set']))
|
||||
{
|
||||
if ($this->check_access(EGW_ACL_EDIT, $entry))
|
||||
{
|
||||
$privileges[] = 'write-content';
|
||||
}
|
||||
}
|
||||
if ($this->groupdav->prop_requested('owner') === true && !isset($props['owner']) &&
|
||||
($account_lid = $this->accounts->name2id($entry['owner'])))
|
||||
{
|
||||
$type = $this->accounts->get_type($entry['owner']) == 'u' ? 'users' : 'groups';
|
||||
$props['owner'] = HTTP_WebDAV_Server::mkprop('href', $this->base_uri.'/principals/'.$type.'/'.$account_lid.'/');
|
||||
}
|
||||
// we urldecode here, as HTTP_WebDAV_Server uses a minimal (#?%) urlencoding for incomming pathes and urlencodes pathes in propfind
|
||||
return $this->groupdav->add_resource($path.urldecode($this->get_path($entry)), $props, $privileges);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -460,16 +633,15 @@ class groupdav_propfind_iterator implements Iterator
|
||||
*
|
||||
* @param groupdav_handler $handler
|
||||
* @param array $filter filter for propfind call
|
||||
* @param array $files=null extra files/responses to return too
|
||||
* @param array $files=array() extra files/responses to return too
|
||||
*/
|
||||
public function __construct(groupdav_handler $handler, $path, array $filter,array &$files=null)
|
||||
public function __construct(groupdav_handler $handler, $path, array $filter,array &$files=array())
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."('$path', ".array2string($filter).",)");
|
||||
$this->path = $path;
|
||||
$this->handler = $handler;
|
||||
$this->filter = $filter;
|
||||
$this->files = $files;
|
||||
$this->common_files = $files;
|
||||
$this->files = $this->common_files = $files;
|
||||
reset($this->files);
|
||||
}
|
||||
|
||||
@ -507,6 +679,12 @@ class groupdav_propfind_iterator implements Iterator
|
||||
if ($this->debug) error_log(__METHOD__."() returning TRUE");
|
||||
return true;
|
||||
}
|
||||
// check if previous query gave less then CHUNK_SIZE entries --> we're done
|
||||
if ($this->start && count($this->files) < self::CHUNK_SIZE)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
|
||||
return false;
|
||||
}
|
||||
// try query further files via propfind callback of handler and store result in $this->files
|
||||
$this->files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
|
||||
if (!is_array($this->files) || !($entries = count($this->files)))
|
||||
@ -514,10 +692,10 @@ class groupdav_propfind_iterator implements Iterator
|
||||
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
|
||||
return false; // no further entries
|
||||
}
|
||||
$this->start += $entries;
|
||||
$this->start += self::CHUNK_SIZE;
|
||||
reset($this->files);
|
||||
|
||||
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files) !== false));
|
||||
if ($this->debug) error_log(__METHOD__."() this->start=$this->start, entries=$entries, count(this->files)=".count($this->files)." returning ".array2string(current($this->files) !== false));
|
||||
|
||||
return current($this->files) !== false;
|
||||
}
|
||||
@ -529,11 +707,9 @@ class groupdav_propfind_iterator implements Iterator
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."()");
|
||||
|
||||
// query first set of files via propfind callback of handler and store result in $this->files
|
||||
$this->start = 0;
|
||||
$files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
|
||||
$this->files = array_merge($this->common_files, $files);
|
||||
$this->start += self::CHUNK_SIZE;
|
||||
$this->files = $this->common_files;
|
||||
if (!$this->files) $this->next(); // otherwise valid will return false and nothing get returned
|
||||
reset($this->files);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
* @package api
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2010 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2010-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
@ -16,6 +16,10 @@
|
||||
*/
|
||||
class groupdav_hooks
|
||||
{
|
||||
public $public_functions = array(
|
||||
'log' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Show GroupDAV preferences link in preferences
|
||||
*
|
||||
@ -54,62 +58,103 @@ class groupdav_hooks
|
||||
|
||||
if ($hook_data['setup'])
|
||||
{
|
||||
$addressbooks = array();
|
||||
$apps = array('addressbook','calendar','infolog');
|
||||
}
|
||||
else
|
||||
{
|
||||
$user = $GLOBALS['egw_info']['user']['account_id'];
|
||||
$addressbook_bo = new addressbook_bo();
|
||||
$addressbooks = $addressbook_bo->get_addressbooks(EGW_ACL_READ);
|
||||
unset($addressbooks[$user]); // Use P for personal addressbook
|
||||
unset($addressbooks[$user.'p']);// ignore (optional) private addressbook for now
|
||||
$apps = array_keys($GLOBALS['egw_info']['user']['apps']);
|
||||
}
|
||||
$addressbooks = array(
|
||||
'P' => lang('Personal'),
|
||||
'G' => lang('Primary Group'),
|
||||
//'U' => lang('Accounts'), // not yet working
|
||||
'O' => lang('All in one'),
|
||||
'A' => lang('All'),
|
||||
) + $addressbooks;
|
||||
|
||||
// rewriting owner=0 to 'U', as 0 get's always selected by prefs
|
||||
if (!isset($addressbooks[0]))
|
||||
foreach($apps as $app)
|
||||
{
|
||||
unset($addressbooks['U']);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($addressbooks[0]);
|
||||
$class_name = $app.'_groupdav';
|
||||
if (class_exists($class_name, true))
|
||||
{
|
||||
$settings += call_user_func(array($class_name,'get_settings'), $hook_data);
|
||||
}
|
||||
}
|
||||
|
||||
$settings['addressbook-home-set'] = array(
|
||||
'type' => 'multiselect',
|
||||
'label' => 'Addressbooks to sync with Apple clients',
|
||||
'name' => 'addressbook-home-set',
|
||||
'help' => 'Addressbooks for CardDAV attribute "addressbook-home-set".',
|
||||
'values' => $addressbooks,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'default' => 'P',
|
||||
$settings[] = array(
|
||||
'type' => 'section',
|
||||
'title' => 'Logging / debuging',
|
||||
);
|
||||
|
||||
$settings['debug_level'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Debug level for Apache/PHP error-log',
|
||||
'label' => 'Enable logging',
|
||||
'name' => 'debug_level',
|
||||
'help' => 'Enables debug-messages to Apache/PHP error-log, allowing to diagnose problems on a per user basis.',
|
||||
'help' => 'Enables logging of CalDAV/CardDAV traffic to diagnose problems with devices.',
|
||||
'values' => array(
|
||||
'0' => 'Off',
|
||||
'r' => 'Requests and truncated responses',
|
||||
'f' => 'Requests and full responses to files directory',
|
||||
'1' => 'Debug 1 - function calls',
|
||||
'2' => 'Debug 2 - more info',
|
||||
'3' => 'Debug 3 - complete $_SERVER array',
|
||||
'0' => lang('Off'),
|
||||
'r' => lang('Requests and truncated responses to Apache error-log'),
|
||||
'f' => lang('Requests and full responses to files directory'),
|
||||
),
|
||||
'xmlrpc' => true,
|
||||
'admin' => false,
|
||||
'default' => '0',
|
||||
);
|
||||
if ($GLOBALS['type'] === 'forced' || $GLOBALS['type'] === 'user' &&
|
||||
$GLOBALS['egw_info']['user']['preferences']['groupdav']['debug-log'] !== 'never')
|
||||
{
|
||||
if ($GLOBALS['type'] === 'user')
|
||||
{
|
||||
$logs = array();
|
||||
if (file_exists($log_dir=$GLOBALS['egw_info']['server']['files_dir'].'/groupdav') && ($files = scandir($log_dir)))
|
||||
{
|
||||
$account_lid_len = strlen($GLOBALS['egw_info']['user']['account_lid']);
|
||||
foreach($files as $log)
|
||||
{
|
||||
if (substr($log,0,$account_lid_len+1) == $GLOBALS['egw_info']['user']['account_lid'].'-' &&
|
||||
substr($log,-4) == '.log')
|
||||
{
|
||||
$logs['groupdav/'.$log] = egw_time::to(filemtime($log_dir.'/'.$log)).': '.
|
||||
str_replace('!','/',substr($log,$account_lid_len+1,-4));
|
||||
}
|
||||
}
|
||||
}
|
||||
$link = egw::link('/index.php',array(
|
||||
'menuaction' => 'groupdav.groupdav_hooks.log',
|
||||
'filename' => '',
|
||||
));
|
||||
$onchange = "egw_openWindowCentered('$link'+encodeURIComponent(this.value), '_blank', 1000, 500); this.value=''";
|
||||
}
|
||||
else // allow to force users to NOT be able to delete their profiles
|
||||
{
|
||||
$logs = array('never' => lang('Never'));
|
||||
}
|
||||
$settings['show-log'] = array(
|
||||
'type' => 'select',
|
||||
'label' => 'Show log of following device',
|
||||
'name' => 'show-log',
|
||||
'help' => lang('You need to set enable logging to "%1" to create/update a log.',
|
||||
lang('Requests and full responses to files directory')),
|
||||
'values' => $logs,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
'onchange' => $onchange,
|
||||
);
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open log window for log-file specified in GET parameter filename (relative to files_dir)
|
||||
*
|
||||
* $_GET['filename'] has to be in groupdav sub-dir of files_dir and start with account_lid of current user
|
||||
*
|
||||
* @throws egw_exception_wrong_parameter
|
||||
*/
|
||||
public function log()
|
||||
{
|
||||
$filename = $_GET['filename'];
|
||||
if (!preg_match('|^groupdav/'.preg_quote($GLOBALS['egw_info']['user']['account_lid'],'|').'-[^/]+\.log$|',$filename))
|
||||
{
|
||||
throw new egw_exception_wrong_parameter("Access denied to file '$filename'!");
|
||||
}
|
||||
$GLOBALS['egw_info']['flags']['css'] = '
|
||||
body { background-color: #e0e0e0; }
|
||||
pre.tail { background-color: white; padding-left: 5px; margin-left: 5px; }
|
||||
';
|
||||
$header = str_replace('!','/',substr($filename,10+strlen($GLOBALS['egw_info']['user']['account_lid']),-4));
|
||||
$tail = new egw_tail($filename);
|
||||
$GLOBALS['egw']->framework->render($tail->show($header),false,false);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -616,7 +616,23 @@ class schema_proc
|
||||
$blob_column_included = $auto_column_included = False;
|
||||
foreach($aTableDef['fd'] as $name => $data)
|
||||
{
|
||||
if ($aDefaults && isset($aDefaults[$name])) // use given default
|
||||
// new auto column with no default or explicit NULL as default (can be an existing column too!)
|
||||
if ($data['type'] == 'auto' &&
|
||||
(!isset($old_table_def['fd'][$name]) && (!$aDefaults || !isset($aDefaults[$name])) ||
|
||||
$aDefaults && strtoupper($aDefaults[$name]) == 'NULL'))
|
||||
{
|
||||
$sequence_name = $sTableName.'_'.$name.'_seq';
|
||||
switch($GLOBALS['egw_setup']->db->Type)
|
||||
{
|
||||
case 'mysql':
|
||||
$value = 'NULL'; break;
|
||||
case 'pgsql':
|
||||
$value = "nextval('$sequence_name'::regclass)"; break;
|
||||
default:
|
||||
$value = "nextval('$sequence_name')"; break;
|
||||
}
|
||||
}
|
||||
elseif ($aDefaults && isset($aDefaults[$name])) // use given default
|
||||
{
|
||||
$value = $aDefaults[$name];
|
||||
}
|
||||
@ -650,6 +666,11 @@ class schema_proc
|
||||
{
|
||||
$value = 'NULL';
|
||||
}
|
||||
// some stuff is NOT to be quoted
|
||||
elseif (in_array(strtoupper($data['default']),array('CURRENT_TIMESTAMP','CURRENT_DATE','NULL','NOW()')))
|
||||
{
|
||||
$value = $data['default'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $this->m_odb->quote(isset($data['default']) ? $data['default'] : '',$data['type']);
|
||||
@ -690,10 +711,11 @@ class schema_proc
|
||||
$Ok = $this->RenameTable($sTableName,$tmp_name);
|
||||
}
|
||||
$Ok = $Ok && $this->CreateTable($sTableName,$aTableDef) &&
|
||||
$this->m_odb->query("$extra INSERT INTO $sTableName (".
|
||||
$this->m_odb->query($sql_copy_data="$extra INSERT INTO $sTableName (".
|
||||
implode(',',array_keys($aTableDef['fd'])).
|
||||
") SELEcT $distinct $select FROM $tmp_name",__LINE__,__FILE__) &&
|
||||
$this->DropTable($tmp_name);
|
||||
//error_log($sql_copy_data);
|
||||
|
||||
if (!$Ok)
|
||||
{
|
||||
|
@ -470,7 +470,8 @@ class Horde_iCalendar {
|
||||
{
|
||||
// Default values.
|
||||
$requiredAttributes['PRODID'] = '-//The Horde Project//Horde_iCalendar Library' . (defined('HORDE_VERSION') ? ', Horde ' . constant('HORDE_VERSION') : '') . '//EN';
|
||||
$requiredAttributes['METHOD'] = 'PUBLISH';
|
||||
// METHOD is only required for iTip, but not for CalDAV, therefore removing it here calendar_ical sets it anyway by default
|
||||
//$requiredAttributes['METHOD'] = 'PUBLISH';
|
||||
|
||||
foreach ($requiredAttributes as $name => $default_value) {
|
||||
if (is_a($this->getattribute($name), 'PEAR_Error')) {
|
||||
@ -821,17 +822,15 @@ class Horde_iCalendar {
|
||||
case 'ORG':
|
||||
$value = trim($value);
|
||||
// As of rfc 2426 2.4.2 semicolon, comma, and colon must
|
||||
// be escaped (comma is unescaped after splitting below).
|
||||
$value = str_replace(array('\\n', '\\N', '\\;', '\\:'),
|
||||
array("\n", "\n", ';', ':'),
|
||||
// be escaped (semicolon is unescaped after splitting below).
|
||||
$value = str_replace(array('\\n', '\\N', '\\,', '\\:'),
|
||||
array("\n", "\n", ',', ':'),
|
||||
$value);
|
||||
|
||||
// Split by unescaped semicolons:
|
||||
$values = preg_split('/(?<!\\\\);/', $value);
|
||||
$value = str_replace('\\;', ';', $value);
|
||||
$values = str_replace('\\;', ';', $values);
|
||||
$value = str_replace('\\,', ',', $value);
|
||||
$values = str_replace('\\,', ',', $values);
|
||||
$this->setAttribute($tag, trim($value), $params, true, $values);
|
||||
break;
|
||||
|
||||
@ -840,15 +839,13 @@ class Horde_iCalendar {
|
||||
case 'CATEGORIES':
|
||||
$value = trim($value);
|
||||
// As of rfc 2426 2.4.2 semicolon, comma, and colon must
|
||||
// be escaped (semicolon is unescaped after splitting below).
|
||||
$value = str_replace(array('\\n', '\\N', '\\,', '\\:'),
|
||||
array("\n", "\n", ',', ':'),
|
||||
// be escaped (comma is unescaped after splitting below).
|
||||
$value = str_replace(array('\\n', '\\N', '\\;', '\\:'),
|
||||
array("\n", "\n", ';', ':'),
|
||||
$value);
|
||||
|
||||
// Split by unescaped commas:
|
||||
$values = preg_split('/(?<!\\\\),/', $value);
|
||||
$value = str_replace('\\;', ';', $value);
|
||||
$values = str_replace('\\;', ';', $values);
|
||||
$value = str_replace('\\,', ',', $value);
|
||||
$values = str_replace('\\,', ',', $values);
|
||||
$this->setAttribute($tag, trim($value), $params, true, $values);
|
||||
@ -860,16 +857,14 @@ class Horde_iCalendar {
|
||||
$value = trim($value);
|
||||
// vCalendar 1.0 and vCard 2.1 only escape semicolons
|
||||
// and use unescaped semicolons to create lists.
|
||||
$value = str_replace(array('\\n', '\\N', '\\;', '\\:'),
|
||||
array("\n", "\n", ';', ':'),
|
||||
$value = str_replace(array('\\n', '\\N', '\\,', '\\:'),
|
||||
array("\n", "\n", ',', ':'),
|
||||
$value);
|
||||
|
||||
// Split by unescaped semicolons:
|
||||
$values = preg_split('/(?<!\\\\);/', $value);
|
||||
$value = str_replace('\\;', ';', $value);
|
||||
$values = str_replace('\\;', ';', $values);
|
||||
$value = str_replace('\\,', ',', $value);
|
||||
$values = str_replace('\\,', ',', $values);
|
||||
$this->setAttribute($tag, trim($value), $params, true, $values);
|
||||
} else {
|
||||
$value = trim($value);
|
||||
|
@ -12,7 +12,7 @@
|
||||
/* Basic information about this app */
|
||||
$setup_info['phpgwapi']['name'] = 'phpgwapi';
|
||||
$setup_info['phpgwapi']['title'] = 'eGroupWare API';
|
||||
$setup_info['phpgwapi']['version'] = '1.8.002';
|
||||
$setup_info['phpgwapi']['version'] = '1.8.004';
|
||||
$setup_info['phpgwapi']['versions']['current_header'] = '1.29';
|
||||
$setup_info['phpgwapi']['enable'] = 3;
|
||||
$setup_info['phpgwapi']['app_order'] = 1;
|
||||
@ -28,8 +28,6 @@ $setup_info['phpgwapi']['tables'][] = 'egw_applications';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_acl';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_accounts';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_preferences';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_sessions';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_app_sessions';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_access_log';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_hooks';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_languages';
|
||||
@ -39,7 +37,6 @@ $setup_info['phpgwapi']['tables'][] = 'egw_categories';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_log';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_log_msg';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_interserv';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_vfs';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_history_log';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_async';
|
||||
$setup_info['phpgwapi']['tables'][] = 'egw_api_content_history';
|
||||
|
475
phpgwapi/setup/tables_current.inc.php
Normal file
475
phpgwapi/setup/tables_current.inc.php
Normal file
@ -0,0 +1,475 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - API Setup
|
||||
*
|
||||
* Current DB schema
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @package api
|
||||
* @subpackage setup
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
$phpgw_baseline = array(
|
||||
'egw_config' => array(
|
||||
'fd' => array(
|
||||
'config_app' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'config_name' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||
'config_value' => array('type' => 'text')
|
||||
),
|
||||
'pk' => array('config_app','config_name'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_applications' => array(
|
||||
'fd' => array(
|
||||
'app_id' => array('type' => 'auto','precision' => '4','nullable' => False),
|
||||
'app_name' => array('type' => 'varchar','precision' => '25','nullable' => False),
|
||||
'app_enabled' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'app_order' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'app_tables' => array('type' => 'text','nullable' => False),
|
||||
'app_version' => array('type' => 'varchar','precision' => '20','nullable' => False,'default' => '0.0'),
|
||||
'app_icon' => array('type' => 'varchar','precision' => '32'),
|
||||
'app_icon_app' => array('type' => 'varchar','precision' => '25'),
|
||||
'app_index' => array('type' => 'varchar','precision' => '64')
|
||||
),
|
||||
'pk' => array('app_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(array('app_enabled','app_order')),
|
||||
'uc' => array('app_name')
|
||||
),
|
||||
'egw_acl' => array(
|
||||
'fd' => array(
|
||||
'acl_appname' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'acl_location' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||
'acl_account' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'acl_rights' => array('type' => 'int','precision' => '4')
|
||||
),
|
||||
'pk' => array('acl_appname','acl_location','acl_account'),
|
||||
'fk' => array(),
|
||||
'ix' => array('acl_account',array('acl_location','acl_account'),array('acl_appname','acl_account')),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_accounts' => array(
|
||||
'fd' => array(
|
||||
'account_id' => array('type' => 'auto','nullable' => False),
|
||||
'account_lid' => array('type' => 'varchar','precision' => '64','nullable' => False),
|
||||
'account_pwd' => array('type' => 'varchar','precision' => '128','nullable' => False),
|
||||
'account_lastlogin' => array('type' => 'int','precision' => '4'),
|
||||
'account_lastloginfrom' => array('type' => 'varchar','precision' => '255'),
|
||||
'account_lastpwd_change' => array('type' => 'int','precision' => '4'),
|
||||
'account_status' => array('type' => 'char','precision' => '1','nullable' => False,'default' => 'A'),
|
||||
'account_expires' => array('type' => 'int','precision' => '4'),
|
||||
'account_type' => array('type' => 'char','precision' => '1'),
|
||||
'account_primary_group' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0')
|
||||
),
|
||||
'pk' => array('account_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array('account_lid')
|
||||
),
|
||||
'egw_preferences' => array(
|
||||
'fd' => array(
|
||||
'preference_owner' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'preference_app' => array('type' => 'varchar','precision' => '25','nullable' => False),
|
||||
'preference_value' => array('type' => 'text','nullable' => False)
|
||||
),
|
||||
'pk' => array('preference_owner','preference_app'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_access_log' => array(
|
||||
'fd' => array(
|
||||
'sessionid' => array('type' => 'auto','nullable' => False,'comment' => 'primary key'),
|
||||
'loginid' => array('type' => 'varchar','precision' => '64','nullable' => False,'comment' => 'username used to login'),
|
||||
'ip' => array('type' => 'varchar','precision' => '40','nullable' => False,'comment' => 'ip of user'),
|
||||
'li' => array('type' => 'int','precision' => '8','nullable' => False,'comment' => 'TS if login'),
|
||||
'lo' => array('type' => 'int','precision' => '8','comment' => 'TD of logout'),
|
||||
'account_id' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0','comment' => 'numerical account id'),
|
||||
'session_dla' => array('type' => 'int','precision' => '8','comment' => 'TS of last user action'),
|
||||
'session_action' => array('type' => 'varchar','precision' => '64','comment' => 'menuaction or path of last user action'),
|
||||
'session_php' => array('type' => 'varchar','precision' => '64','nullable' => False,'comment' => 'php session-id or error-message'),
|
||||
'notification_heartbeat' => array('type' => 'int','precision' => '8','comment' => 'TS of last notification request')
|
||||
),
|
||||
'pk' => array('sessionid'),
|
||||
'fk' => array(),
|
||||
'ix' => array('li','lo','session_dla','notification_heartbeat'),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_hooks' => array(
|
||||
'fd' => array(
|
||||
'hook_id' => array('type' => 'auto','nullable' => False),
|
||||
'hook_appname' => array('type' => 'varchar','precision' => '255'),
|
||||
'hook_location' => array('type' => 'varchar','precision' => '255'),
|
||||
'hook_filename' => array('type' => 'varchar','precision' => '255')
|
||||
),
|
||||
'pk' => array('hook_id'),
|
||||
'ix' => array(),
|
||||
'fk' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_languages' => array(
|
||||
'fd' => array(
|
||||
'lang_id' => array('type' => 'varchar','precision' => '5','nullable' => False),
|
||||
'lang_name' => array('type' => 'varchar','precision' => '50','nullable' => False)
|
||||
),
|
||||
'pk' => array('lang_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_lang' => array(
|
||||
'fd' => array(
|
||||
'lang' => array('type' => 'varchar','precision' => '5','nullable' => False,'default' => ''),
|
||||
'app_name' => array('type' => 'varchar','precision' => '32','nullable' => False,'default' => 'common'),
|
||||
'message_id' => array('type' => 'varchar','precision' => '128','nullable' => False,'default' => ''),
|
||||
'content' => array('type' => 'text')
|
||||
),
|
||||
'pk' => array('lang','app_name','message_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_nextid' => array(
|
||||
'fd' => array(
|
||||
'id' => array('type' => 'int','precision' => '4','nullable' => True),
|
||||
'appname' => array('type' => 'varchar','precision' => '25','nullable' => False)
|
||||
),
|
||||
'pk' => array('appname'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_categories' => array(
|
||||
'fd' => array(
|
||||
'cat_id' => array('type' => 'auto','precision' => '4','nullable' => False),
|
||||
'cat_main' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'cat_parent' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'cat_level' => array('type' => 'int','precision' => '2','nullable' => False,'default' => '0'),
|
||||
'cat_owner' => array('type' => 'varchar','precision' => '255','nullable' => False,'default' => '0'),
|
||||
'cat_access' => array('type' => 'varchar','precision' => '7'),
|
||||
'cat_appname' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'cat_name' => array('type' => 'varchar','precision' => '150','nullable' => False),
|
||||
'cat_description' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||
'cat_data' => array('type' => 'text'),
|
||||
'last_mod' => array('type' => 'int','precision' => '8','nullable' => False)
|
||||
),
|
||||
'pk' => array('cat_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(array('cat_appname','cat_owner','cat_parent','cat_level')),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_log' => array(
|
||||
'fd' => array(
|
||||
'log_id' => array('type' => 'auto','precision' => '4','nullable' => False),
|
||||
'log_date' => array('type' => 'timestamp','nullable' => False),
|
||||
'log_user' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'log_app' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'log_severity' => array('type' => 'char','precision' => '1','nullable' => False)
|
||||
),
|
||||
'pk' => array('log_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_log_msg' => array(
|
||||
'fd' => array(
|
||||
'log_msg_log_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'log_msg_seq_no' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'log_msg_date' => array('type' => 'timestamp','nullable' => False),
|
||||
'log_msg_tx_fid' => array('type' => 'varchar','precision' => '4','nullable' => True),
|
||||
'log_msg_tx_id' => array('type' => 'varchar','precision' => '4','nullable' => True),
|
||||
'log_msg_severity' => array('type' => 'char','precision' => '1','nullable' => False),
|
||||
'log_msg_code' => array('type' => 'varchar','precision' => '30','nullable' => False),
|
||||
'log_msg_msg' => array('type' => 'text','nullable' => False),
|
||||
'log_msg_parms' => array('type' => 'text','nullable' => False),
|
||||
'log_msg_file' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||
'log_msg_line' => array('type' => 'int','precision' => '4','nullable' => False)
|
||||
),
|
||||
'pk' => array('log_msg_log_id','log_msg_seq_no'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_interserv' => array(
|
||||
'fd' => array(
|
||||
'server_id' => array('type' => 'auto','nullable' => False),
|
||||
'server_name' => array('type' => 'varchar','precision' => '64','nullable' => True),
|
||||
'server_host' => array('type' => 'varchar','precision' => '255','nullable' => True),
|
||||
'server_url' => array('type' => 'varchar','precision' => '255','nullable' => True),
|
||||
'trust_level' => array('type' => 'int','precision' => '4'),
|
||||
'trust_rel' => array('type' => 'int','precision' => '4'),
|
||||
'username' => array('type' => 'varchar','precision' => '64','nullable' => True),
|
||||
'password' => array('type' => 'varchar','precision' => '255','nullable' => True),
|
||||
'admin_name' => array('type' => 'varchar','precision' => '255','nullable' => True),
|
||||
'admin_email' => array('type' => 'varchar','precision' => '255','nullable' => True),
|
||||
'server_mode' => array('type' => 'varchar','precision' => '16','nullable' => False,'default' => 'xmlrpc'),
|
||||
'server_security' => array('type' => 'varchar','precision' => '16','nullable' => True)
|
||||
),
|
||||
'pk' => array('server_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_history_log' => array(
|
||||
'fd' => array(
|
||||
'history_id' => array('type' => 'auto','precision' => '4','nullable' => False),
|
||||
'history_record_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'history_appname' => array('type' => 'varchar','precision' => '64','nullable' => False),
|
||||
'history_owner' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'history_status' => array('type' => 'varchar','precision' => '64','nullable' => False),
|
||||
'history_new_value' => array('type' => 'text','nullable' => False),
|
||||
'history_timestamp' => array('type' => 'timestamp','nullable' => False,'default' => 'current_timestamp'),
|
||||
'history_old_value' => array('type' => 'text','nullable' => False)
|
||||
),
|
||||
'pk' => array('history_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(array('history_appname','history_record_id','history_status','history_timestamp')),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_async' => array(
|
||||
'fd' => array(
|
||||
'async_id' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||
'async_next' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'async_times' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||
'async_method' => array('type' => 'varchar','precision' => '80','nullable' => False),
|
||||
'async_data' => array('type' => 'text','nullable' => False),
|
||||
'async_account_id' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0')
|
||||
),
|
||||
'pk' => array('async_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_api_content_history' => array(
|
||||
'fd' => array(
|
||||
'sync_appname' => array('type' => 'varchar','precision' => '60','nullable' => False),
|
||||
'sync_contentid' => array('type' => 'varchar','precision' => '60','nullable' => False),
|
||||
'sync_added' => array('type' => 'timestamp'),
|
||||
'sync_modified' => array('type' => 'timestamp'),
|
||||
'sync_deleted' => array('type' => 'timestamp'),
|
||||
'sync_id' => array('type' => 'auto','nullable' => False),
|
||||
'sync_changedby' => array('type' => 'int','precision' => '4','nullable' => False)
|
||||
),
|
||||
'pk' => array('sync_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('sync_added','sync_modified','sync_deleted','sync_changedby',array('sync_appname','sync_contentid')),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_links' => array(
|
||||
'fd' => array(
|
||||
'link_id' => array('type' => 'auto','nullable' => False),
|
||||
'link_app1' => array('type' => 'varchar','precision' => '25','nullable' => False),
|
||||
'link_id1' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'link_app2' => array('type' => 'varchar','precision' => '25','nullable' => False),
|
||||
'link_id2' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'link_remark' => array('type' => 'varchar','precision' => '100'),
|
||||
'link_lastmod' => array('type' => 'int','precision' => '8','nullable' => False),
|
||||
'link_owner' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'deleted' => array('type' => 'timestamp')
|
||||
),
|
||||
'pk' => array('link_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('deleted',array('link_app1','link_id1','link_lastmod'),array('link_app2','link_id2','link_lastmod')),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_addressbook' => array(
|
||||
'fd' => array(
|
||||
'contact_id' => array('type' => 'auto','nullable' => False),
|
||||
'contact_tid' => array('type' => 'char','precision' => '1','default' => 'n'),
|
||||
'contact_owner' => array('type' => 'int','precision' => '8','nullable' => False),
|
||||
'contact_private' => array('type' => 'int','precision' => '1','default' => '0'),
|
||||
'cat_id' => array('type' => 'varchar','precision' => '255'),
|
||||
'n_family' => array('type' => 'varchar','precision' => '64'),
|
||||
'n_given' => array('type' => 'varchar','precision' => '64'),
|
||||
'n_middle' => array('type' => 'varchar','precision' => '64'),
|
||||
'n_prefix' => array('type' => 'varchar','precision' => '64'),
|
||||
'n_suffix' => array('type' => 'varchar','precision' => '64'),
|
||||
'n_fn' => array('type' => 'varchar','precision' => '128'),
|
||||
'n_fileas' => array('type' => 'varchar','precision' => '255'),
|
||||
'contact_bday' => array('type' => 'varchar','precision' => '12'),
|
||||
'org_name' => array('type' => 'varchar','precision' => '128'),
|
||||
'org_unit' => array('type' => 'varchar','precision' => '64'),
|
||||
'contact_title' => array('type' => 'varchar','precision' => '64'),
|
||||
'contact_role' => array('type' => 'varchar','precision' => '64'),
|
||||
'contact_assistent' => array('type' => 'varchar','precision' => '64'),
|
||||
'contact_room' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_one_street' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_one_street2' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_one_locality' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_one_region' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_one_postalcode' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_one_countryname' => array('type' => 'varchar','precision' => '64'),
|
||||
'contact_label' => array('type' => 'text'),
|
||||
'adr_two_street' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_two_street2' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_two_locality' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_two_region' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_two_postalcode' => array('type' => 'varchar','precision' => '64'),
|
||||
'adr_two_countryname' => array('type' => 'varchar','precision' => '64'),
|
||||
'tel_work' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_cell' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_fax' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_assistent' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_car' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_pager' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_home' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_fax_home' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_cell_private' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_other' => array('type' => 'varchar','precision' => '40'),
|
||||
'tel_prefer' => array('type' => 'varchar','precision' => '32'),
|
||||
'contact_email' => array('type' => 'varchar','precision' => '128'),
|
||||
'contact_email_home' => array('type' => 'varchar','precision' => '128'),
|
||||
'contact_url' => array('type' => 'varchar','precision' => '128'),
|
||||
'contact_url_home' => array('type' => 'varchar','precision' => '128'),
|
||||
'contact_freebusy_uri' => array('type' => 'varchar','precision' => '128'),
|
||||
'contact_calendar_uri' => array('type' => 'varchar','precision' => '128'),
|
||||
'contact_note' => array('type' => 'text'),
|
||||
'contact_tz' => array('type' => 'varchar','precision' => '8'),
|
||||
'contact_geo' => array('type' => 'varchar','precision' => '32'),
|
||||
'contact_pubkey' => array('type' => 'text'),
|
||||
'contact_created' => array('type' => 'int','precision' => '8'),
|
||||
'contact_creator' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'contact_modified' => array('type' => 'int','precision' => '8','nullable' => False),
|
||||
'contact_modifier' => array('type' => 'int','precision' => '4'),
|
||||
'contact_jpegphoto' => array('type' => 'blob'),
|
||||
'account_id' => array('type' => 'int','precision' => '4'),
|
||||
'contact_etag' => array('type' => 'int','precision' => '4','default' => '0'),
|
||||
'contact_uid' => array('type' => 'varchar','precision' => '255'),
|
||||
'adr_one_countrycode' => array('type' => 'varchar','precision' => '2'),
|
||||
'adr_two_countrycode' => array('type' => 'varchar','precision' => '2'),
|
||||
'carddav_name' => array('type' => 'varchar','precision' => '64','comment' => 'name part of CardDAV URL, if specified by client')
|
||||
),
|
||||
'pk' => array('contact_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('contact_owner','cat_id','n_fileas','contact_modified','contact_uid','carddav_name',array('n_family','n_given'),array('n_given','n_family'),array('org_name','n_family','n_given')),
|
||||
'uc' => array('account_id')
|
||||
),
|
||||
'egw_addressbook_extra' => array(
|
||||
'fd' => array(
|
||||
'contact_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'contact_owner' => array('type' => 'int','precision' => '8'),
|
||||
'contact_name' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||
'contact_value' => array('type' => 'text')
|
||||
),
|
||||
'pk' => array('contact_id','contact_name'),
|
||||
'fk' => array(),
|
||||
'ix' => array(array('contact_name','contact_value(32)')),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_addressbook_lists' => array(
|
||||
'fd' => array(
|
||||
'list_id' => array('type' => 'auto','nullable' => False),
|
||||
'list_name' => array('type' => 'varchar','precision' => '80','nullable' => False),
|
||||
'list_owner' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'list_created' => array('type' => 'int','precision' => '8'),
|
||||
'list_creator' => array('type' => 'int','precision' => '4')
|
||||
),
|
||||
'pk' => array('list_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array(array('list_owner','list_name'))
|
||||
),
|
||||
'egw_addressbook2list' => array(
|
||||
'fd' => array(
|
||||
'contact_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'list_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'list_added' => array('type' => 'int','precision' => '8'),
|
||||
'list_added_by' => array('type' => 'int','precision' => '4')
|
||||
),
|
||||
'pk' => array('contact_id','list_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_sqlfs' => array(
|
||||
'fd' => array(
|
||||
'fs_id' => array('type' => 'auto','nullable' => False),
|
||||
'fs_dir' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'fs_name' => array('type' => 'varchar','precision' => '200','nullable' => False),
|
||||
'fs_mode' => array('type' => 'int','precision' => '2','nullable' => False),
|
||||
'fs_uid' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'fs_gid' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'fs_created' => array('type' => 'timestamp','precision' => '8','nullable' => False),
|
||||
'fs_modified' => array('type' => 'timestamp','precision' => '8','nullable' => False),
|
||||
'fs_mime' => array('type' => 'varchar','precision' => '96','nullable' => False),
|
||||
'fs_size' => array('type' => 'int','precision' => '8','nullable' => False),
|
||||
'fs_creator' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'fs_modifier' => array('type' => 'int','precision' => '4'),
|
||||
'fs_active' => array('type' => 'bool','nullable' => False,'default' => 't'),
|
||||
'fs_content' => array('type' => 'blob'),
|
||||
'fs_link' => array('type' => 'varchar','precision' => '255')
|
||||
),
|
||||
'pk' => array('fs_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(array('fs_dir','fs_active','fs_name')),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_index_keywords' => array(
|
||||
'fd' => array(
|
||||
'si_id' => array('type' => 'auto','nullable' => False),
|
||||
'si_keyword' => array('type' => 'varchar','precision' => '64','nullable' => False),
|
||||
'si_ignore' => array('type' => 'bool')
|
||||
),
|
||||
'pk' => array('si_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array('si_keyword')
|
||||
),
|
||||
'egw_index' => array(
|
||||
'fd' => array(
|
||||
'si_app' => array('type' => 'varchar','precision' => '25','nullable' => False),
|
||||
'si_app_id' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'si_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'si_owner' => array('type' => 'int','precision' => '4','nullable' => False)
|
||||
),
|
||||
'pk' => array('si_app','si_app_id','si_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('si_id'),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_cat2entry' => array(
|
||||
'fd' => array(
|
||||
'ce_app' => array('type' => 'varchar','precision' => '25','nullable' => False),
|
||||
'ce_app_id' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'cat_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'ce_owner' => array('type' => 'int','precision' => '4','nullable' => False)
|
||||
),
|
||||
'pk' => array('ce_app','ce_app_id','cat_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('cat_id'),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_locks' => array(
|
||||
'fd' => array(
|
||||
'lock_token' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||
'lock_path' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||
'lock_expires' => array('type' => 'int','precision' => '8','nullable' => False),
|
||||
'lock_owner' => array('type' => 'varchar','precision' => '255'),
|
||||
'lock_recursive' => array('type' => 'bool','nullable' => False,'default' => '0'),
|
||||
'lock_write' => array('type' => 'bool','nullable' => False,'default' => '0'),
|
||||
'lock_exclusive' => array('type' => 'bool','nullable' => False,'default' => '0'),
|
||||
'lock_created' => array('type' => 'int','precision' => '8','default' => '0'),
|
||||
'lock_modified' => array('type' => 'int','precision' => '8','default' => '0')
|
||||
),
|
||||
'pk' => array('lock_token'),
|
||||
'fk' => array(),
|
||||
'ix' => array('lock_path','lock_expires'),
|
||||
'uc' => array()
|
||||
),
|
||||
'egw_sqlfs_props' => array(
|
||||
'fd' => array(
|
||||
'fs_id' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'prop_namespace' => array('type' => 'varchar','precision' => '64','nullable' => False),
|
||||
'prop_name' => array('type' => 'varchar','precision' => '64','nullable' => False),
|
||||
'prop_value' => array('type' => 'text')
|
||||
),
|
||||
'pk' => array('fs_id','prop_namespace','prop_name'),
|
||||
'fk' => array(),
|
||||
'ix' => array(),
|
||||
'uc' => array()
|
||||
)
|
||||
);
|
@ -67,7 +67,7 @@ function phpgwapi_upgrade1_7_003()
|
||||
{
|
||||
// resetting owner for all global (and group) cats to -1
|
||||
$GLOBALS['egw_setup']->db->update('egw_categories',array('cat_owner' => -1),'cat_owner <= 0',__LINE__,__FILE__);
|
||||
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.8.001';
|
||||
}
|
||||
|
||||
@ -80,15 +80,294 @@ function phpgwapi_upgrade1_8_001()
|
||||
}
|
||||
|
||||
/**
|
||||
* Downgrade from trunk
|
||||
*
|
||||
* Reserve 1.8.003 in case we want to create a separte security update
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function phpgwapi_upgrade1_8_002()
|
||||
{
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.8.003';
|
||||
}
|
||||
|
||||
/**
|
||||
* Update methods for 1.8.004 (called below)
|
||||
*/
|
||||
/**
|
||||
* Add index to improve import of contacts using a custom field as primary key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function phpgwapi_upgrade1_9_001()
|
||||
{
|
||||
return phpgwapi_upgrade1_7_003();
|
||||
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_addressbook_extra',
|
||||
array('contact_name','contact_value(32)'));
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.002';
|
||||
}
|
||||
|
||||
function phpgwapi_upgrade1_9_002()
|
||||
{
|
||||
return phpgwapi_upgrade1_7_003();
|
||||
/* done by RefreshTable() anyway
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_links','deleted',array(
|
||||
'type' => 'timestamp'
|
||||
));*/
|
||||
$GLOBALS['egw_setup']->oProc->RefreshTable('egw_links',array(
|
||||
'fd' => array(
|
||||
'link_id' => array('type' => 'auto','nullable' => False),
|
||||
'link_app1' => array('type' => 'varchar','precision' => '25','nullable' => False),
|
||||
'link_id1' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'link_app2' => array('type' => 'varchar','precision' => '25','nullable' => False),
|
||||
'link_id2' => array('type' => 'varchar','precision' => '50','nullable' => False),
|
||||
'link_remark' => array('type' => 'varchar','precision' => '100'),
|
||||
'link_lastmod' => array('type' => 'int','precision' => '8','nullable' => False),
|
||||
'link_owner' => array('type' => 'int','precision' => '4','nullable' => False),
|
||||
'deleted' => array('type' => 'timestamp')
|
||||
),
|
||||
'pk' => array('link_id'),
|
||||
'fk' => array(),
|
||||
'ix' => array('deleted',array('link_app1','link_id1','link_lastmod'),array('link_app2','link_id2','link_lastmod')),
|
||||
'uc' => array()
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.003';
|
||||
}
|
||||
|
||||
|
||||
function phpgwapi_upgrade1_9_003()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_addressbook','adr_one_countrycode',array(
|
||||
'type' => 'varchar',
|
||||
'precision' => '2'
|
||||
));
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_addressbook','adr_two_countrycode',array(
|
||||
'type' => 'varchar',
|
||||
'precision' => '2'
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.004';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update script to populate country codes
|
||||
*
|
||||
* Sets country code for any recognized country in any installed language, then clears the country name
|
||||
* to avoid conflicts / confusion.
|
||||
*/
|
||||
function phpgwapi_upgrade1_9_004()
|
||||
{
|
||||
// Get all installed translations for names
|
||||
$country = new country();
|
||||
$country_query = 'SELECT DISTINCT message_id, content
|
||||
FROM ' . translation::LANG_TABLE . '
|
||||
WHERE message_id IN ("' . implode('","', array_values($country->countries())) . '")
|
||||
ORDER BY message_id';
|
||||
$result = $GLOBALS['egw_setup']->oProc->query($country_query, __LINE__, __FILE__);
|
||||
|
||||
$country_list = array();
|
||||
$current_name = null;
|
||||
$id = null;
|
||||
foreach($result as $row) {
|
||||
if($row['message_id'] != $current_name) {
|
||||
$current_name = $row['message_id'];
|
||||
$id = array_search(strtoupper($current_name), $country->countries());
|
||||
if(!$id) continue;
|
||||
}
|
||||
$country_list[$id][] = $row['content'];
|
||||
}
|
||||
|
||||
// Build conversion
|
||||
$case = 'CASE UPPER(adr_%1$s_countryname)';
|
||||
foreach($country_list as $key => $names) {
|
||||
foreach($names as $name) {
|
||||
$case .= "\n" . "WHEN UPPER(\"$name\") THEN '$key'";
|
||||
}
|
||||
}
|
||||
$case .= ' END';
|
||||
|
||||
$sql = 'UPDATE egw_addressbook SET ';
|
||||
$sql .= "adr_one_countrycode = (" . sprintf($case, 'one') . '),';
|
||||
$sql .= "adr_two_countrycode = (" . sprintf($case, 'two') . ')';
|
||||
|
||||
// Change names
|
||||
$GLOBALS['egw_setup']->oProc->query($sql,__LINE__,__FILE__);
|
||||
|
||||
// Clear text names
|
||||
$GLOBALS['egw_setup']->oProc->query('UPDATE egw_addressbook SET adr_one_countryname = NULL WHERE adr_one_countrycode IS NOT NULL',__LINE__,__FILE__);
|
||||
$GLOBALS['egw_setup']->oProc->query('UPDATE egw_addressbook SET adr_two_countryname = NULL WHERE adr_two_countrycode IS NOT NULL',__LINE__,__FILE__);
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.005';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add index to li (login time) column to speed up maintenance (periodic delete of old rows)
|
||||
*
|
||||
* Delete some obsolete / since a long time not used tables:
|
||||
* - egw_vfs (replaced by egw_sqlfs in 1.6)
|
||||
* - egw_(app_)sessions (not used since 1.4)
|
||||
*/
|
||||
function phpgwapi_upgrade1_9_005()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_access_log','li');
|
||||
|
||||
$GLOBALS['egw_setup']->oProc->DropTable('egw_app_sessions');
|
||||
$GLOBALS['egw_setup']->oProc->DropTable('egw_sessions');
|
||||
$GLOBALS['egw_setup']->oProc->DropTable('egw_vfs');
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.006';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column to store CalDAV name given by client
|
||||
*/
|
||||
function phpgwapi_upgrade1_9_006()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_addressbook','carddav_name',array(
|
||||
'type' => 'varchar',
|
||||
'precision' => '64',
|
||||
'comment' => 'name part of CardDAV URL, if specified by client'
|
||||
));
|
||||
$GLOBALS['egw_setup']->db->query($sql='UPDATE egw_addressbook SET carddav_name='.
|
||||
$GLOBALS['egw_setup']->db->concat(
|
||||
$GLOBALS['egw_setup']->db->to_varchar('contact_id'),"'.vcf'"),__LINE__,__FILE__);
|
||||
|
||||
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_addressbook','carddav_name');
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.007';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns for session list (dla, action), make sessionid primary key and TS 64bit
|
||||
*/
|
||||
function phpgwapi_upgrade1_9_007()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->RefreshTable('egw_access_log',array(
|
||||
'fd' => array(
|
||||
'sessionid' => array('type' => 'auto','nullable' => False,'comment' => 'primary key'),
|
||||
'loginid' => array('type' => 'varchar','precision' => '64','nullable' => False,'comment' => 'username used to login'),
|
||||
'ip' => array('type' => 'varchar','precision' => '40','nullable' => False,'comment' => 'ip of user'),
|
||||
'li' => array('type' => 'int','precision' => '8','nullable' => False,'comment' => 'TS if login'),
|
||||
'lo' => array('type' => 'int','precision' => '8','comment' => 'TD of logout'),
|
||||
'account_id' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0','comment' => 'numerical account id'),
|
||||
'session_dla' => array('type' => 'int','precision' => '8','comment' => 'TS of last user action'),
|
||||
'session_action' => array('type' => 'varchar','precision' => '64','comment' => 'menuaction or path of last user action'),
|
||||
'session_php' => array('type' => 'char','precision' => '64','nullable' => False,'comment' => 'php session-id or error-message'),
|
||||
'notification_heartbeat' => array('type' => 'int','precision' => '8','comment' => 'TS of last notification request')
|
||||
),
|
||||
'pk' => array('sessionid'),
|
||||
'fk' => array(),
|
||||
'ix' => array('li','lo','session_dla','notification_heartbeat'),
|
||||
'uc' => array()
|
||||
),array(
|
||||
'session_php' => 'sessionid',
|
||||
'sessionid' => 'NULL', // to NOT copy old sessionid, but create a new sequence
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.008';
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter column cat_owner to varchar(255) to support multiple owners/groups per cat
|
||||
*/
|
||||
function phpgwapi_upgrade1_9_008()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->AlterColumn('egw_categories','cat_owner',array(
|
||||
'type' => 'varchar',
|
||||
'precision' => '255',
|
||||
'nullable' => False,
|
||||
'default' => '0'
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.009';
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter column account_pwd to varchar(128) to allow to store sha256_crypt hashes
|
||||
*
|
||||
* Enable password migration to new default "securest available", if current hash is the default (sql: md5, ldap: des)
|
||||
* or the 1.9.009 migration to ssha is running
|
||||
*/
|
||||
function phpgwapi_upgrade1_9_009()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->AlterColumn('egw_accounts','account_pwd',array(
|
||||
'type' => 'varchar',
|
||||
'precision' => '128',
|
||||
'nullable' => False
|
||||
));
|
||||
|
||||
// query password hashing from database
|
||||
$config = array(
|
||||
'auth_type' => 'sql',
|
||||
'account_repository' => null, // default is auth_type
|
||||
'sql_encryption_type' => 'md5',
|
||||
'ldap_encryption_type' => 'des',
|
||||
'pwd_migration_allowed' => null, // default off
|
||||
'pwd_migration_types' => null,
|
||||
);
|
||||
foreach($GLOBALS['egw_setup']->db->select('egw_config','config_name,config_value',array(
|
||||
'config_app' => 'phpgwapi',
|
||||
'config_name' => array_keys($config),
|
||||
),__LINE__,__FILE__) as $row)
|
||||
{
|
||||
$config[$row['config_name']] = $row['config_value'];
|
||||
}
|
||||
if (!isset($config['account_repository'])) $config['account_repository'] = $config['auth_type'];
|
||||
|
||||
// changing pw hashing only, if we auth agains our own account repository and no migration already active
|
||||
if ($config['auth_type'] == $config['account_repository'] &&
|
||||
(!$config['pwd_migration_allowed'] || $config['pwd_migration_types'] == 'md5,crypt')) // 1.9.009 migration to ssha
|
||||
{
|
||||
require_once EGW_SERVER_ROOT.'/setup/inc/hook_config.inc.php'; // for sql_passwdhashes to get securest available password hash
|
||||
sql_passwdhashes(array(), true, $securest);
|
||||
// OpenLDAP has no own support for extended crypt like sha512_crypt, but relys the OS crypt implementation,
|
||||
// do NOT automatically migrate to anything above SSHA for OS other then Linux (Darwin can not auth anymore!)
|
||||
if ($config['auth_type'] == 'sql' && in_array($config['sql_encryption_type'], array('md5','ssha')) ||
|
||||
$config['auth_type'] == 'ldap'&& in_array($config['ldap_encryption_type'], array('des','ssha')) &&
|
||||
(PHP_OS == 'Linux' || $securest == 'ssha'))
|
||||
{
|
||||
$config['pwd_migration_types'] = 'md5,crypt'; // des is called crypt in hash
|
||||
if ($config['pwd_migration_allowed'] && $securest != 'ssha') $config['pwd_migration_types'] .= ',ssha';
|
||||
$config['sql_encryption_type'] = $config['ldap_encryption_type'] = $securest;
|
||||
$config['pwd_migration_allowed'] = 'True';
|
||||
echo "<p>Enabling password migration to $securest</p>\n";
|
||||
}
|
||||
foreach($config as $name => $value)
|
||||
{
|
||||
$GLOBALS['egw_setup']->db->insert('egw_config',array(
|
||||
'config_value' => $value,
|
||||
),array(
|
||||
'config_app' => 'phpgwapi',
|
||||
'config_name' => $name,
|
||||
),__LINE__,__FILE__);
|
||||
}
|
||||
}
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.012'; // was 1.9.010, but in case someone updates from an older Trunk
|
||||
}
|
||||
|
||||
/**
|
||||
* Add index for contact_modified to improve performance of ctag generation on big installtions
|
||||
*/
|
||||
function phpgwapi_upgrade1_9_012()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_addressbook','contact_modified');
|
||||
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.8.004';
|
||||
}
|
||||
|
||||
/**
|
||||
* Combiupdate 1.8.004: includes Trunk updates 1.9.001-1.9.010+1.9.013
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function phpgwapi_upgrade1_8_003()
|
||||
{
|
||||
foreach(array('1.9.001','1.9.002','1.9.003','1.9.004','1.9.005','1.9.006','1.9.007','1.9.008','1.9.009','1.9.012') as $version)
|
||||
{
|
||||
$func = 'phpgwapi_upgrade'.str_replace('.', '_', $version);
|
||||
$func();
|
||||
}
|
||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.8.004';
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,7 +108,7 @@ class bo_acl
|
||||
$perm_cats[$cat['id']] = $s;
|
||||
}
|
||||
}
|
||||
return isset($perm_cats)?$perm_cats:array();
|
||||
return $perm_cats;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - resources
|
||||
* EGroupware - resources
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package resources
|
||||
@ -16,7 +16,7 @@
|
||||
*
|
||||
* @package resources
|
||||
*/
|
||||
class bo_resources
|
||||
class resources_bo
|
||||
{
|
||||
const PICTURE_NAME = '.picture.jpg';
|
||||
var $resource_icons = '/resources/templates/default/images/resource_icons/';
|
||||
@ -24,7 +24,7 @@ class bo_resources
|
||||
/**
|
||||
* Instance of resources so object
|
||||
*
|
||||
* @var so_resources
|
||||
* @var resources_so
|
||||
*/
|
||||
var $so;
|
||||
/**
|
||||
@ -38,9 +38,9 @@ class bo_resources
|
||||
*/
|
||||
var $cats;
|
||||
|
||||
function bo_resources()
|
||||
function __construct()
|
||||
{
|
||||
$this->so =& CreateObject('resources.so_resources');
|
||||
$this->so = new resources_so();
|
||||
$this->acl =& CreateObject('resources.bo_acl');
|
||||
$this->cats = $this->acl->egw_cats;
|
||||
|
||||
@ -69,7 +69,6 @@ class bo_resources
|
||||
}
|
||||
}
|
||||
if ($this->debug) _debug_array($query);
|
||||
$criteria = array('name' => $query['search'], 'short_description' => $query['search'], 'inventory_number' => $query['search']);
|
||||
$read_onlys = 'res_id,name,short_description,quantity,useable,bookable,buyable,cat_id,location,storage_info';
|
||||
|
||||
$accessory_of = $query['view_accs_of'] ? $query['view_accs_of'] : -1;
|
||||
@ -91,7 +90,9 @@ class bo_resources
|
||||
$filter['cat_id'] = array_keys($readcats);
|
||||
}
|
||||
// if there is no catfilter -> this means you have no rights, so set the cat filter to null
|
||||
if (!isset($filter['cat_id']) || empty($filter['cat_id'])) $filter['cat_id'] = NUll;
|
||||
if (!isset($filter['cat_id']) || empty($filter['cat_id'])) {
|
||||
$filter['cat_id'] = NUll;
|
||||
}
|
||||
|
||||
if ($query['show_bookable'])
|
||||
{
|
||||
@ -100,7 +101,8 @@ class bo_resources
|
||||
$order_by = $query['order'] ? $query['order'].' '. $query['sort'] : '';
|
||||
$start = (int)$query['start'];
|
||||
|
||||
$rows = $this->so->search($criteria,$read_onlys,$order_by,'','%',$empty=False,$op='OR',$start,$filter,$join='',$need_full_no_count=false);
|
||||
$query['col_filter'] = $filter;
|
||||
$this->so->get_rows($query, $rows, $readonlys);
|
||||
$nr = $this->so->total;
|
||||
|
||||
// we are called to serve bookable resources (e.g. calendar-dialog)
|
||||
@ -157,7 +159,7 @@ class bo_resources
|
||||
}
|
||||
}
|
||||
}
|
||||
$rows[$num]['picture_thumb'] = $this->get_picture($resource['res_id']);
|
||||
$rows[$num]['picture_thumb'] = $this->get_picture($resource);
|
||||
$rows[$num]['admin'] = $this->acl->get_cat_admin($resource['cat_id']);
|
||||
}
|
||||
return $nr;
|
||||
@ -318,7 +320,7 @@ class bo_resources
|
||||
*/
|
||||
function get_calendar_info($res_id)
|
||||
{
|
||||
//echo "<p>bo_resources::get_calendar_info(".print_r($res_id,true).")</p>\n";
|
||||
//echo "<p>resources_bo::get_calendar_info(".print_r($res_id,true).")</p>\n";
|
||||
if(!is_array($res_id) && $res_id < 1) return;
|
||||
|
||||
$data = $this->so->search(array('res_id' => $res_id),self::TITLE_COLS.',useable');
|
||||
@ -366,9 +368,10 @@ class bo_resources
|
||||
* @param string|array $pattern if it's a string it is the string we will search for as a criteria, if it's an array we
|
||||
* will seach for 'search' key in this array to get the string criteria. others keys handled are actually used
|
||||
* for calendar disponibility.
|
||||
* @param array $options Array of options for the search
|
||||
*
|
||||
*/
|
||||
function link_query( $pattern )
|
||||
function link_query( $pattern, Array &$options = array() )
|
||||
{
|
||||
if (is_array($pattern))
|
||||
{
|
||||
@ -385,7 +388,11 @@ class bo_resources
|
||||
'cat_id' => array_flip((array)$this->acl->get_cats(EGW_ACL_READ)),
|
||||
//'accessory_of' => '-1'
|
||||
);
|
||||
$data = $this->so->search($criteria,$only_keys,$order_by='name',$extra_cols='',$wildcard='%',$empty,$op='OR',false,$filter);
|
||||
$limit = false;
|
||||
if($options['start'] || $options['num_rows']) {
|
||||
$limit = array($options['start'], $options['num_rows']);
|
||||
}
|
||||
$data = $this->so->search($criteria,$only_keys,$order_by='',$extra_cols='',$wildcard='%',$empty,$op='OR',$limit,$filter);
|
||||
// maybe we need to check disponibility of the searched resources in the calendar if $pattern ['exec'] contains some extra args
|
||||
$show_conflict=False;
|
||||
if (is_array($pattern) && isset($pattern['exec']) )
|
||||
@ -499,6 +506,7 @@ class bo_resources
|
||||
error_log(__METHOD__." No Data found for Resource with id ".$resource['res_id']);
|
||||
}
|
||||
}
|
||||
$options['total'] = $this->so->total;
|
||||
return $list;
|
||||
}
|
||||
|
||||
@ -613,21 +621,18 @@ class bo_resources
|
||||
/**
|
||||
* get resource picture either from vfs or from symlink
|
||||
* Cornelius Weiss <egw@von-und-zu-weiss.de>
|
||||
* @param int $res_id id of resource
|
||||
* @param int|array $resource res-id or whole resource array
|
||||
* @param bool $fullsize false = thumb, true = full pic
|
||||
* @return string url of picture
|
||||
*/
|
||||
function get_picture($res_id=0,$fullsize=false)
|
||||
function get_picture($resource,$fullsize=false)
|
||||
{
|
||||
if ($res_id > 0)
|
||||
{
|
||||
$src = $this->so->get_value('picture_src',$res_id);
|
||||
}
|
||||
#echo $scr."<br>". $this->pictures_dir."<br>";
|
||||
switch($src)
|
||||
if ($resource && !is_array($resource)) $resource = $this->read($resource);
|
||||
|
||||
switch($resource['picture_src'])
|
||||
{
|
||||
case 'own_src':
|
||||
$picture = egw_link::vfs_path('resources',$res_id,self::PICTURE_NAME,true); // vfs path
|
||||
$picture = egw_link::vfs_path('resources',$resource['res_id'],self::PICTURE_NAME,true); // vfs path
|
||||
if ($fullsize)
|
||||
{
|
||||
$picture = egw::link(egw_vfs::download_url($picture));
|
||||
@ -636,17 +641,17 @@ class bo_resources
|
||||
{
|
||||
$picture = egw::link('/etemplate/thumbnail.php',array('path' => $picture));
|
||||
}
|
||||
//$picture=$GLOBALS['egw_info']['server'].$picture;
|
||||
#echo $picture."<br>";
|
||||
break;
|
||||
|
||||
case 'cat_src':
|
||||
list($picture) = $this->cats->return_single($this->so->get_value('cat_id',$res_id));
|
||||
list($picture) = $this->cats->return_single($resource['cat_id']);
|
||||
$picture = unserialize($picture['data']);
|
||||
if($picture['icon'])
|
||||
{
|
||||
$picture = $GLOBALS['egw_info']['server']['webserver_url'].'/phpgwapi/images/'.$picture['icon'];
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
case 'gen_src':
|
||||
default :
|
||||
$picture = $GLOBALS['egw_info']['server']['webserver_url'].$this->resource_icons;
|
||||
@ -656,7 +661,6 @@ class bo_resources
|
||||
}
|
||||
|
||||
/**
|
||||
* remove_picture
|
||||
* removes picture from vfs
|
||||
*
|
||||
* Cornelius Weiss <egw@von-und-zu-weiss.de>
|
145
resources/inc/class.resources_egw_record.inc.php
Normal file
145
resources/inc/class.resources_egw_record.inc.php
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - Resources - importexport
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package Resources
|
||||
* @subpackage importexport
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @copyright Nathan Gray
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* class resources_egw_record
|
||||
*
|
||||
* compability layer for iface_egw_record needet for importexport
|
||||
*/
|
||||
class resources_egw_record implements importexport_iface_egw_record
|
||||
{
|
||||
private $identifier = '';
|
||||
private $record = array();
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* reads record from backend if identifier is given.
|
||||
*
|
||||
* @param string $_identifier
|
||||
*/
|
||||
public function __construct( $_identifier='' ) {
|
||||
$this->identifier = $_identifier;
|
||||
if($this->identifier) {
|
||||
$this->record = ExecMethod('resources.resources_bo.read', $this->identifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* magic method to set attributes of record
|
||||
*
|
||||
* @param string $_attribute_name
|
||||
*/
|
||||
public function __get($_attribute_name) {
|
||||
return $this->record[$_attribute_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* magig method to set attributes of record
|
||||
*
|
||||
* @param string $_attribute_name
|
||||
* @param data $data
|
||||
*/
|
||||
public function __set($_attribute_name, $data) {
|
||||
$this->record[$_attribute_name] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts this object to array.
|
||||
* @abstract We need such a function cause PHP5
|
||||
* dosn't allow objects do define it's own casts :-(
|
||||
* once PHP can deal with object casts we will change to them!
|
||||
*
|
||||
* @return array complete record as associative array
|
||||
*/
|
||||
public function get_record_array() {
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets title of record
|
||||
*
|
||||
*@return string tiltle
|
||||
*/
|
||||
public function get_title() {
|
||||
if (empty($this->record)) {
|
||||
$this->get_record();
|
||||
}
|
||||
return $this->record['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* sets complete record from associative array
|
||||
*
|
||||
* @todo add some checks
|
||||
* @return void
|
||||
*/
|
||||
public function set_record(array $_record){
|
||||
$this->record = $_record;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets identifier of this record
|
||||
*
|
||||
* @return string identifier of current record
|
||||
*/
|
||||
public function get_identifier() {
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* saves record into backend
|
||||
*
|
||||
* @return string identifier
|
||||
*/
|
||||
public function save ( $_dst_identifier ) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* copys current record to record identified by $_dst_identifier
|
||||
*
|
||||
* @param string $_dst_identifier
|
||||
* @return string dst_identifier
|
||||
*/
|
||||
public function copy ( $_dst_identifier ) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* moves current record to record identified by $_dst_identifier
|
||||
* $this will become moved record
|
||||
*
|
||||
* @param string $_dst_identifier
|
||||
* @return string dst_identifier
|
||||
*/
|
||||
public function move ( $_dst_identifier ) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* delets current record from backend
|
||||
*
|
||||
*/
|
||||
public function delete () {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* destructor
|
||||
*
|
||||
*/
|
||||
public function __destruct() {
|
||||
}
|
||||
|
||||
} // end of egw_addressbook_record
|
||||
?>
|
129
resources/inc/class.resources_export_csv.inc.php
Normal file
129
resources/inc/class.resources_export_csv.inc.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package resources
|
||||
* @subpackage importexport
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @copyright Nathan Gray
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* export resources to CSV
|
||||
*/
|
||||
class resources_export_csv implements importexport_iface_export_plugin {
|
||||
|
||||
/**
|
||||
* Exports records as defined in $_definition
|
||||
*
|
||||
* @param egw_record $_definition
|
||||
*/
|
||||
public function export( $_stream, importexport_definition $_definition) {
|
||||
$options = $_definition->plugin_options;
|
||||
|
||||
$bo = new resources_bo();
|
||||
$selection = array();
|
||||
if ($options['selection'] == 'selected') {
|
||||
// ui selection with checkbox 'selected'
|
||||
$query = egw_cache::getSession('resources', 'get_rows');
|
||||
$query['num_rows'] = -1; // all
|
||||
unset($query['store_state']);
|
||||
$bo->get_rows($query,$selection,$readonlys);
|
||||
}
|
||||
elseif ( $options['selection'] == 'all' ) {
|
||||
$query = array(
|
||||
'num_rows' => -1,
|
||||
); // all
|
||||
$bo->get_rows($query,$selection,$readonlys);
|
||||
} else {
|
||||
$selection = explode(',',$options['selection']);
|
||||
}
|
||||
|
||||
$export_object = new importexport_export_csv($_stream, (array)$options);
|
||||
$export_object->set_mapping($options['mapping']);
|
||||
|
||||
// Check if we need to load the custom fields
|
||||
$need_custom = false;
|
||||
foreach(config::get_customfields('resources') as $field => $settings) {
|
||||
if($options['mapping']['#'.$field]) {
|
||||
$need_custom = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$types = importexport_export_csv::$types;
|
||||
$types['select-bool'] = array('bookable');
|
||||
|
||||
foreach ($selection as $record) {
|
||||
if(!is_array($record) || !$record['res_id']) continue;
|
||||
|
||||
if($need_custom) {
|
||||
$record = $bo->read($record['res_id']);
|
||||
}
|
||||
$resource = new resources_egw_record();
|
||||
$resource->set_record($record);
|
||||
if($options['convert']) {
|
||||
importexport_export_csv::convert($resource, $types, 'resources');
|
||||
} else {
|
||||
// Implode arrays, so they don't say 'Array'
|
||||
foreach($resource->get_record_array() as $key => $value) {
|
||||
if(is_array($value)) $resource->$key = implode(',', $value);
|
||||
}
|
||||
}
|
||||
|
||||
$export_object->export_record($resource);
|
||||
unset($resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns translated name of plugin
|
||||
*
|
||||
* @return string name
|
||||
*/
|
||||
public static function get_name() {
|
||||
return lang('Resources CSV export');
|
||||
}
|
||||
|
||||
/**
|
||||
* returns translated (user) description of plugin
|
||||
*
|
||||
* @return string descriprion
|
||||
*/
|
||||
public static function get_description() {
|
||||
return lang("Exports a list of resources to a CSV File.");
|
||||
}
|
||||
|
||||
/**
|
||||
* retruns file suffix for exported file
|
||||
*
|
||||
* @return string suffix
|
||||
*/
|
||||
public static function get_filesuffix() {
|
||||
return 'csv';
|
||||
}
|
||||
|
||||
public static function get_mimetype() {
|
||||
return 'text/csv';
|
||||
}
|
||||
|
||||
/**
|
||||
* return html for options.
|
||||
* this way the plugin has all opportunities for options tab
|
||||
*
|
||||
*/
|
||||
public function get_options_etpl() {
|
||||
}
|
||||
|
||||
/**
|
||||
* returns selectors information
|
||||
*
|
||||
*/
|
||||
public function get_selectors_etpl() {
|
||||
return array(
|
||||
'name' => 'resources.export_csv_selectors'
|
||||
);
|
||||
}
|
||||
}
|
173
resources/inc/class.resources_hooks.inc.php
Normal file
173
resources/inc/class.resources_hooks.inc.php
Normal file
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare - resources
|
||||
* General hook object for resources
|
||||
* It encapsulats all the diffent hook methods
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package resources
|
||||
* @link http://www.egroupware.org
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* General hook object for resources
|
||||
* It encapsulats all the diffent hook methods
|
||||
* @package resources
|
||||
*/
|
||||
class resources_hooks
|
||||
{
|
||||
function admin_prefs_sidebox($args)
|
||||
{
|
||||
$this->acl =& CreateObject('resources.bo_acl');
|
||||
|
||||
$appname = 'resources';
|
||||
$location = is_array($args) ? $args['location'] : $args;
|
||||
|
||||
if ($location == 'sidebox_menu')
|
||||
{
|
||||
$title = $GLOBALS['egw_info']['apps']['resources']['title'].' '.lang('Menu');
|
||||
$file = array(
|
||||
'Resources list' => egw::link('/index.php',array('menuaction' => 'resources.resources_ui.index' )),
|
||||
);
|
||||
if($this->acl->get_cats(EGW_ACL_ADD))
|
||||
{
|
||||
$file['Add resource'] = "javascript:egw_openWindowCentered2('".egw::link('/index.php',array(
|
||||
'menuaction' => 'resources.resources_ui.edit',
|
||||
),false)."','_blank',800,600,'yes')";
|
||||
}
|
||||
display_sidebox($appname,$title,$file);
|
||||
}
|
||||
|
||||
/* if ($GLOBALS['egw_info']['user']['apps']['preferences'] && $location != 'admin')
|
||||
{
|
||||
$file = array(
|
||||
'Preferences' => egw::link('/preferences/preferences.php','appname='.$appname),
|
||||
'Grant Access' => egw::link('/index.php','menuaction=preferences.uiaclprefs.index&acl_app='.$appname),
|
||||
'Edit Categories' => egw::link('/index.php','menuaction=preferences.uicategories.index&cats_app=' . $appname . '&cats_level=True&global_cats=True')
|
||||
);
|
||||
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(
|
||||
'Global Categories' => egw::link('/index.php',array(
|
||||
'menuaction' => 'admin.uicategories.index',
|
||||
'appname' => $appname,
|
||||
'global_cats'=> true)),
|
||||
'Configure Access Permissions' => egw::link('/index.php',
|
||||
'menuaction=resources.ui_acl.acllist'),
|
||||
'Custom Fields'=>egw::link('/index.php',
|
||||
'menuaction=admin.customfields.edit&appname=resources'),
|
||||
);
|
||||
if ($location == 'admin')
|
||||
{
|
||||
display_section($appname,$file);
|
||||
}
|
||||
else
|
||||
{
|
||||
display_sidebox($appname,lang('Admin'),$file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function search_link($args)
|
||||
{
|
||||
return array(
|
||||
'query' => 'resources.resources_bo.link_query',
|
||||
'title' => 'resources.resources_bo.link_title',
|
||||
'titles' => 'resources.resources_bo.link_titles',
|
||||
'view' => array(
|
||||
'menuaction' => 'resources.resources_ui.show'
|
||||
),
|
||||
'view_id' => 'res_id',
|
||||
'view_popup' => '850x600',
|
||||
'view_list' => 'resources.resources_ui.index',
|
||||
'add' => array(
|
||||
'menuaction' => 'resources.resources_ui.edit',
|
||||
),
|
||||
'add_app' => 'link_app',
|
||||
'add_id' => 'link_id',
|
||||
'add_popup' => '800x600',
|
||||
'find_extra' => array('name_preg' => '/^(?(?=^.picture.jpg$)|.+)$/'), // remove pictures from regular attachment list
|
||||
);
|
||||
}
|
||||
|
||||
function calendar_resources($args)
|
||||
{
|
||||
return array(
|
||||
'widget' => 'resources_select',// widget to use for the selection of resources
|
||||
'info' => 'resources.resources_bo.get_calendar_info',// info method, returns array with id, type & name for a given id
|
||||
'max_quantity' => 'useable',// if set, key for max. quantity in array returned by info method
|
||||
'new_status' => 'resources.resources_bo.get_calendar_new_status',// method returning the status for new items, else 'U' is used
|
||||
'type' => 'r',// one char type-identifiy for this resources
|
||||
'icon' => 'calicon',//icon
|
||||
'participants_header' => lang('resources'), // header of participants from this type
|
||||
'cal_sidebox' => array(
|
||||
'menu_title' => lang('Select resources'),
|
||||
'file' => 'resources.resources_ui.get_calendar_sidebox'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle deleted category
|
||||
*
|
||||
* Resources' ACL _requires_ a category.
|
||||
* Moves all resources to parent, if it exists. If it doesn't, another category is created.
|
||||
*/
|
||||
function delete_category($args)
|
||||
{
|
||||
$cat = categories::read($args['cat_id']);
|
||||
|
||||
if(!$cat) return; // Can't find current cat?
|
||||
|
||||
if($cat['parent'] == 0)
|
||||
{
|
||||
// No parent, try the default cat from setup
|
||||
$categories = new categories('', 'resources');
|
||||
$default = $categories->name2id('General resources');
|
||||
if($default)
|
||||
{
|
||||
$new_cat_id = $default;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default missing, look for 'No category'
|
||||
$new_cat_id = $categories->name2id('No category');
|
||||
if($new_cat_id == 0) {
|
||||
// No category not there, add it
|
||||
$new_cat_id = $categories->add(array(
|
||||
'name' => 'No category',
|
||||
'description' => 'This category has been added to rescue resources whose category was deleted.',
|
||||
'parent' => 0
|
||||
));
|
||||
$admin = -2;
|
||||
ExecMethod2('resources.bo_acl.set_rights', $new_cat_id, array($admin), array($admin), array($admin), array($admin),array($admin));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$new_cat_id = $cat['parent'];
|
||||
}
|
||||
|
||||
// Get any resources affected
|
||||
$query = array('filter' => $args['cat_id']);
|
||||
$bo = new resources_bo();
|
||||
$bo->get_rows($query, $resources, $readonly);
|
||||
foreach($resources as $resource)
|
||||
{
|
||||
$resource['cat_id'] = $new_cat_id;
|
||||
$bo->save($resource);
|
||||
}
|
||||
}
|
||||
}
|
312
resources/inc/class.resources_import_csv.inc.php
Normal file
312
resources/inc/class.resources_import_csv.inc.php
Normal file
@ -0,0 +1,312 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare import CSV plugin to import resources
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package resources
|
||||
* @subpackage importexport
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @copyright Nathan Gray
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* class to import resources from CSV
|
||||
*/
|
||||
class resources_import_csv implements importexport_iface_import_plugin {
|
||||
|
||||
private static $plugin_options = array(
|
||||
'fieldsep', // char
|
||||
'charset', // string
|
||||
'contact_owner', // int
|
||||
'update_cats', // string {override|add} overides record
|
||||
// with cat(s) from csv OR add the cat from
|
||||
// csv file to exeisting cat(s) of record
|
||||
'num_header_lines', // int number of header lines
|
||||
'field_conversion', // array( $csv_col_num => conversion)
|
||||
'field_mapping', // array( $csv_col_num => adb_filed)
|
||||
'conditions', /* => array containing condition arrays:
|
||||
'type' => exists, // exists
|
||||
'string' => '#kundennummer',
|
||||
'true' => array(
|
||||
'action' => update,
|
||||
'last' => true,
|
||||
),
|
||||
'false' => array(
|
||||
'action' => insert,
|
||||
'last' => true,
|
||||
),*/
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
* actions wich could be done to data entries
|
||||
*/
|
||||
protected static $actions = array( 'none', 'update', 'insert', 'delete', );
|
||||
|
||||
/**
|
||||
* conditions for actions
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $conditions = array( 'exists' );
|
||||
|
||||
/**
|
||||
* @var definition
|
||||
*/
|
||||
private $definition;
|
||||
|
||||
/**
|
||||
* @var bo
|
||||
*/
|
||||
private $bo;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $dry_run = false;
|
||||
|
||||
/**
|
||||
* @var bool is current user admin?
|
||||
*/
|
||||
private $is_admin = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $user = null;
|
||||
|
||||
/**
|
||||
* List of import errors
|
||||
*/
|
||||
protected $errors = array();
|
||||
|
||||
/**
|
||||
* List of actions, and how many times that action was taken
|
||||
*/
|
||||
protected $results = array();
|
||||
|
||||
/**
|
||||
* imports entries according to given definition object.
|
||||
* @param resource $_stream
|
||||
* @param string $_charset
|
||||
* @param definition $_definition
|
||||
*/
|
||||
public function import( $_stream, importexport_definition $_definition ) {
|
||||
$import_csv = new importexport_import_csv( $_stream, array(
|
||||
'fieldsep' => $_definition->plugin_options['fieldsep'],
|
||||
'charset' => $_definition->plugin_options['charset'],
|
||||
));
|
||||
|
||||
$this->definition = $_definition;
|
||||
|
||||
// user, is admin ?
|
||||
$this->is_admin = isset( $GLOBALS['egw_info']['user']['apps']['admin'] ) && $GLOBALS['egw_info']['user']['apps']['admin'];
|
||||
$this->user = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
// dry run?
|
||||
$this->dry_run = isset( $_definition->plugin_options['dry_run'] ) ? $_definition->plugin_options['dry_run'] : false;
|
||||
|
||||
// fetch the resource bo
|
||||
$this->bo = new resources_bo();
|
||||
|
||||
// set FieldMapping.
|
||||
$import_csv->mapping = $_definition->plugin_options['field_mapping'];
|
||||
|
||||
// set FieldConversion
|
||||
$import_csv->conversion = $_definition->plugin_options['field_conversion'];
|
||||
|
||||
//check if file has a header lines
|
||||
if ( isset( $_definition->plugin_options['num_header_lines'] ) && $_definition->plugin_options['num_header_lines'] > 0) {
|
||||
$import_csv->skip_records($_definition->plugin_options['num_header_lines']);
|
||||
} elseif(isset($_definition->plugin_options['has_header_line']) && $_definition->plugin_options['has_header_line']) {
|
||||
// First method is preferred
|
||||
$import_csv->skip_records(1);
|
||||
}
|
||||
|
||||
// Start counting successes
|
||||
$count = 0;
|
||||
$this->results = array();
|
||||
|
||||
// Failures
|
||||
$this->errors = array();
|
||||
|
||||
while ( $record = $import_csv->get_record() ) {
|
||||
$success = false;
|
||||
|
||||
// don't import empty records
|
||||
if( count( array_unique( $record ) ) < 2 ) continue;
|
||||
|
||||
// Automatically handle text categories without explicit translation
|
||||
$record['cat_id'] = importexport_helper_functions::cat_name2id($record['cat_id']);
|
||||
|
||||
if ( $_definition->plugin_options['conditions'] ) {
|
||||
foreach ( $_definition->plugin_options['conditions'] as $condition ) {
|
||||
$results = array();
|
||||
switch ( $condition['type'] ) {
|
||||
// exists
|
||||
case 'exists' :
|
||||
if($record[$condition['string']]) {
|
||||
$results = $this->bo->so->search(
|
||||
array( $condition['string'] => $record[$condition['string']]),
|
||||
False
|
||||
);
|
||||
}
|
||||
|
||||
if ( is_array( $results ) && count( array_keys( $results )) >= 1) {
|
||||
// apply action to all contacts matching this exists condition
|
||||
$action = $condition['true'];
|
||||
foreach ( (array)$results as $resource ) {
|
||||
$record['res_id'] = $resource['res_id'];
|
||||
if ( $_definition->plugin_options['update_cats'] == 'add' ) {
|
||||
if ( !is_array( $resource['cat_id'] ) ) $resource['cat_id'] = explode( ',', $resource['cat_id'] );
|
||||
if ( !is_array( $record['cat_id'] ) ) $record['cat_id'] = explode( ',', $record['cat_id'] );
|
||||
$record['cat_id'] = implode( ',', array_unique( array_merge( $record['cat_id'], $resource['cat_id'] ) ) );
|
||||
}
|
||||
$success = $this->action( $action['action'], $record, $import_csv->get_current_position() );
|
||||
}
|
||||
} else {
|
||||
$action = $condition['false'];
|
||||
$success = ($this->action( $action['action'], $record, $import_csv->get_current_position() ));
|
||||
}
|
||||
break;
|
||||
|
||||
// not supported action
|
||||
default :
|
||||
die('condition / action not supported!!!');
|
||||
break;
|
||||
}
|
||||
if ($action['last']) break;
|
||||
}
|
||||
} else {
|
||||
// unconditional insert
|
||||
$success = $this->action( 'insert', $record, $import_csv->get_current_position() );
|
||||
}
|
||||
if($success) $count++;
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* perform the required action
|
||||
*
|
||||
* @param int $_action one of $this->actions
|
||||
* @param array $_data contact data for the action
|
||||
* @return bool success or not
|
||||
*/
|
||||
private function action ( $_action, $_data, $record_num = 0 ) {
|
||||
switch ($_action) {
|
||||
case 'none' :
|
||||
return true;
|
||||
case 'update' :
|
||||
// Only update if there are changes
|
||||
$old = $this->bo->read($_data['res_id']);
|
||||
|
||||
// Merge to deal with fields not in import record
|
||||
$_data = array_merge($old, $_data);
|
||||
|
||||
// Fall through
|
||||
case 'insert' :
|
||||
if($_action == 'insert') {
|
||||
// Backend doesn't like inserting with ID specified, it can overwrite
|
||||
unset($_data['res_id']);
|
||||
}
|
||||
if ( $this->dry_run ) {
|
||||
//print_r($_data);
|
||||
$this->results[$_action]++;
|
||||
return true;
|
||||
} else {
|
||||
$result = $this->bo->save( $_data );
|
||||
if($result) {
|
||||
$this->errors[$record_num] = $result;
|
||||
return false;
|
||||
} else {
|
||||
$this->results[$_action]++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new egw_exception('Unsupported action');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns translated name of plugin
|
||||
*
|
||||
* @return string name
|
||||
*/
|
||||
public static function get_name() {
|
||||
return lang('Resources CSV import');
|
||||
}
|
||||
|
||||
/**
|
||||
* returns translated (user) description of plugin
|
||||
*
|
||||
* @return string descriprion
|
||||
*/
|
||||
public static function get_description() {
|
||||
return lang("Imports a list of resources from a CSV file.");
|
||||
}
|
||||
|
||||
/**
|
||||
* retruns file suffix(s) plugin can handle (e.g. csv)
|
||||
*
|
||||
* @return string suffix (comma seperated)
|
||||
*/
|
||||
public static function get_filesuffix() {
|
||||
return 'csv';
|
||||
}
|
||||
|
||||
/**
|
||||
* return etemplate components for options.
|
||||
* @abstract We can't deal with etemplate objects here, as an uietemplate
|
||||
* objects itself are scipt orientated and not "dialog objects"
|
||||
*
|
||||
* @return array (
|
||||
* name => string,
|
||||
* content => array,
|
||||
* sel_options => array,
|
||||
* preserv => array,
|
||||
* )
|
||||
*/
|
||||
public function get_options_etpl() {
|
||||
// lets do it!
|
||||
}
|
||||
|
||||
/**
|
||||
* returns etemplate name for slectors of this plugin
|
||||
*
|
||||
* @return string etemplate name
|
||||
*/
|
||||
public function get_selectors_etpl() {
|
||||
// lets do it!
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns errors that were encountered during importing
|
||||
* Maximum of one error message per record, but you can append if you need to
|
||||
*
|
||||
* @return Array (
|
||||
* record_# => error message
|
||||
* )
|
||||
*/
|
||||
public function get_errors() {
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of actions taken, and the number of records for that action.
|
||||
* Actions are things like 'insert', 'update', 'delete', and may be different for each plugin.
|
||||
*
|
||||
* @return Array (
|
||||
* action => record count
|
||||
* )
|
||||
*/
|
||||
public function get_results() {
|
||||
return $this->results;
|
||||
}
|
||||
} // end of iface_export_plugin
|
||||
?>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user