From 88d6ccbb9471a36d06f7b6d926743cf35dbc75ef Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 28 May 2007 05:29:23 +0000 Subject: [PATCH 01/30] "typo in translation" --- infolog/setup/phpgw_de.lang | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/infolog/setup/phpgw_de.lang b/infolog/setup/phpgw_de.lang index 94a08214b2..5bf7f1128c 100644 --- a/infolog/setup/phpgw_de.lang +++ b/infolog/setup/phpgw_de.lang @@ -25,7 +25,7 @@ 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 zufόgen +add file infolog de Datei hinzufόgen add sub infolog de neuen Untereintrag anlegen add timesheet entry infolog de Stundenzettel Eintrag hinzfόgen add: infolog de Hinzufόgen: @@ -219,7 +219,7 @@ remove this link (not the entry itself) infolog de Diese Verkn responsible infolog de verantwortlich responsible open infolog de verantwortlich offen responsible overdue infolog de verantwortlich όberfδllig -responsible upcoming infolog de verantwortlich zufόnftig +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 @@ -294,7 +294,6 @@ urgent infolog de Dringend used time infolog de benφtigte Zeit valid path on clientside
eg. \\server\share or e:\ infolog de gόltiger Pfad clientseitig
zB. \\Server\Share oder e:\ valid path on clientside
eg. \servershare or e: infolog de gόltiger Pfad clientseitig
zB. \\Server\Share oder e:\ -valid path on clientside
eg. servershare or e: infolog de gόltiger Pfad clientseitig
zB. \\Server\Share oder e:\ 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 From f6552713ca9d40f471d0a8612490a0a13d2f3f9a Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 28 May 2007 11:46:47 +0000 Subject: [PATCH 02/30] "fix for bug #804: PEAR include failing -> no message, thanks to regis leroy" --- setup/check_install.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/check_install.php b/setup/check_install.php index ca0b422cae..bc58e9089c 100644 --- a/setup/check_install.php +++ b/setup/check_install.php @@ -242,7 +242,7 @@ { $pear_config = '/etc/php5/cli/pear.conf'; } - @require_once 'PEAR/Config.php'; + @include_once 'PEAR/Config.php'; if (!class_exists('PEAR_Config')) return false; From f2fb5fad4b84e77dc050111bf20eb8f04c912761 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 28 May 2007 21:17:15 +0000 Subject: [PATCH 03/30] --- etemplate/inc/class.bo_tracking.inc.php | 621 ++++++++++++++++++ infolog/inc/class.boinfolog.inc.php | 20 +- infolog/inc/class.infolog_tracking.inc.php | 226 +++++++ infolog/inc/hook_settings.inc.php | 264 ++++---- notifications/inc/class.notification.inc.php | 22 + .../inc/class.notification_popup.inc.php | 12 +- 6 files changed, 1038 insertions(+), 127 deletions(-) create mode 100644 etemplate/inc/class.bo_tracking.inc.php create mode 100644 infolog/inc/class.infolog_tracking.inc.php diff --git a/etemplate/inc/class.bo_tracking.inc.php b/etemplate/inc/class.bo_tracking.inc.php new file mode 100644 index 0000000000..ec4f92e2b3 --- /dev/null +++ b/etemplate/inc/class.bo_tracking.inc.php @@ -0,0 +1,621 @@ + + * @package etemplate + * @subpackage api + * @copyright (c) 2007 by Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id$ + */ + +/** + * Abstract base class for trackering: + * - logging all modifications of an entry + * - notifying users about changes in an entry + * + * You need to extend these class in your application: + * 1. set the required class-vars: app, id_field + * 2. optional set class-vars: creator_field, assigned_field, check2prefs + * 3. implement the required methods: get_config, get_details + * 4. optionally re-implement: get_subject, get_body, get_attachments, get_link, get_message + * They are all documented in this file via phpDocumentor comments. + */ +class bo_tracking +{ + /** + * Application we are tracking + * + * @var string + */ + var $app; + /** + * Name of the id-field, used as id in the history log (required!) + * + * @var string + */ + var $id_field; + /** + * Name of the field with the creator id, if the creator of an entry should be notified + * + * @var string + */ + var $creator_field; + /** + * Name of the field with the id(s) of assinged users, if they should be notified + * + * @var string + */ + var $assigned_field; + /** + * Can be used to map the following prefs to different names: + * - notify_creator - user wants to be notified for items he created + * - notify_assigned - user wants to be notified for items assigned to him + * - notify_html - user wants his notifications as html-email + * @var array + */ + var $check2pref; + /** + * Translate field-name to 2-char history status + * + * @var array + */ + var $field2history = array(); + /** + * Should the user (passed to the track method or current user if not passed) be used as sender or get_config('sender') + * + * @var boolean + */ + var $prefer_user_as_sender = true; + + /** + * Array with error-messages if track($data,$old) returns false + * + * @var array + */ + var $errors = array(); + + /** + * instance of the historylog object for the app we are tracking + * + * @access private + * @var historylog + */ + var $historylog; + + /** + * Current user, can be set via bo_tracking::track(,,$user) + * + * @access private + * @var int; + */ + var $user; + /** + * Saved user preferences, if send_notifications need to set an other language + * + * @access private + * @var array + */ + var $save_prefs; + /** + * Datetime format of the currently notified user (send_notificaton) + * + * @var string + */ + var $datetime_format; + /** + * Offset to server-time of the currently notified user (send_notificaton) + * + * @var int + */ + var $tz_offset_s; + + /** + * Get a config value, which can depend on $data and $old + * + * Need to be implemented in your extended tracking class! + * + * @abstract + * @param string $what possible values are: + * - 'copy' array of email addresses notifications should be copied too, can depend on $data + * - 'lang' string lang code for copy mail + * - 'subject' string subject line for the notification of $data,$old, defaults to link-title + * @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) + { + die('You need to extend the bo_tracking class, to be able to use it (abstract base class)!'); + } + + /** + * Tracks the changes in one entry $data, by comparing it with the last version in $old + * + * @param array $data current entry + * @param array $old=null old/last state of the entry or null for a new entry + * @param int $user=null user who made the changes, default to current user + * @return int/boolean false on error, integer number of changes logged or true for new entries ($old == null) + */ + function track($data,$old=null,$user=null) + { + $this->user = !is_null($user) ? $user : $GLOBALS['egw_info']['user']['account_id']; + + $changes = true; + + if ($old) + { + $changes = $this->save_history($data,$old); + } + if (!$this->do_notifications($data,$old)) + { + $changes = false; + } + return $changes; + } + + /** + * Save changes to the history log + * + * @internal use only track($data,$old) + * @param array $data current entry + * @param array $old=null old/last state of the entry or null for a new entry + * @param int number of log-entries made + */ + function save_history($data,$old) + { + $changes = 0; + foreach($this->field2history as $name => $status) + { + if ($old[$name] != $data[$name]) + { + if (!is_object($this->historylog)) + { + require_once(EGW_API_INC.'/class.historylog.inc.php'); + $this->historylog =& new historylog($this->app); + } + $this->historylog->add($status,$data[$this->id_field],$data[$name],$old[$name]); + ++$changes; + } + } + return $changes; + } + + /** + * sending all notifications for the changed entry + * + * @internal use only track($data,$old,$user) + * @param array $data current entry + * @param array $old=null old/last state of the entry or null for a new entry + * @return boolean true on success, false on error (error messages are in $this->errors) + */ + function do_notifications($data,$old) + { + $this->errors = $email_sent = array(); + + // entry creator + if ($this->creator_field && ($email = $GLOBALS['egw']->accounts->id2name($data[$this->creator_field],'account_email')) && + !in_array($email, $email_sent)) + { + $this->send_notification($data,$old,$email,$data[$this->creator_field],'notify_creator'); + $email_sent[] = $email; + } + + // assigned / responsible users + if ($this->assigned_field) + { + $assignees = $old_assignees = array(); + if ($data[$this->assigned_field]) // current assignments + { + $assignees = is_array($data[$this->assigned_field]) ? + $data[$this->assigned_field] : explode(',',$data[$this->assigned_field]); + } + if ($old && $old[$this->assigned_field]) + { + $old_assignees = is_array($old[$this->assigned_field]) ? + $old[$this->assigned_field] : explode(',',$old[$this->assigned_field]); + } + foreach(array_unique(array_merge($assignees,$old_assignees)) as $assignee) + { + if (!$assignee) continue; + + // item assignee is a user + if ($GLOBALS['egw']->accounts->get_type($assignee) == 'u') + { + if (($email = $GLOBALS['egw']->accounts->id2name($assignee,'account_email')) && !in_array($email, $email_sent)) + { + $this->send_notification($old,$email,$data['tr_assigned'],'notify_assigned'); + $email_sent[] = $email; + } + } + else // item assignee is a group + { + foreach($GLOBALS['egw']->accounts->members($assignee,true) as $u) + { + if ($email = $GLOBALS['egw']->accounts->id2name($u,'account_email') && !in_array($email, $email_sent)) + { + $this->send_notification($old,$email,$u,'notify_assigned'); + $email_sent[] = $email; + } + } + } + } + } + + // notification copies + if (($copies = $this->get_config('copy',$data,$old))) + { + $lang = $this->get_config('lang',$data,$old); + foreach($copies as $email) + { + if (strchr($email,'@') !== false && !in_array($email, $email_sent)) + { + $this->send_notification($data,$old,$email,$lang,'notify_copy'); + $email_sent[] = $email; + } + } + } + + // restore the user enviroment + if ($this->save_prefs) $GLOBALS['egw_info']['user'] = $this->save_prefs; unset($this->save_prefs); + if ($GLOBALS['egw_info']['user']['preferences']['common']['lang'] != $GLOBALS['egw']->translation->userlang) + { + $GLOBALS['egw']->translation->init(); + } + return !count($this->errors); + } + + /** + * Send a popup notification via the notification app + * + * @param int $user + * @param string $message + * @return boolean true on success, false on error + */ + function popup_notification($user,$message) + { + static $is_php51; + if (is_null($is_php51)) $is_php51 = version_compare(phpversion(),'5.1.0','>='); + + if (!$is_php51) return false; + + // check if the to notifying user has rights to run the notifcation app + $ids = $GLOBALS['egw']->accounts->memberships($user,true); + $ids[] = $user; + if (!$GLOBALS['egw']->acl->get_specific_rights_for_account($ids,'run','notifications')) return false; + + if (!include_once(EGW_INCLUDE_ROOT. '/notifications/inc/class.notification.inc.php')) return false; + + return is_null(notify(array($user),$message)); // return the exeception on error + } + + /** + * Sending a notification to the given email-address + * + * @internal use only track($data,$old,$user) + * @param array $data current entry + * @param array $old=null old/last state of the entry or null for a new entry + * @param string $email address to send the notification to + * @param string $user_or_lang='en' user-id or 2 char lang-code for a non-system user + * @param string $check=null pref. to check if a notification is wanted + * @return boolean true on success or false on error (error-message is in $this->errors) + */ + function send_notification($data,$old,$email,$user_or_lang,$check=null) + { + if (!$email) return false; + + //echo "

botracker::send_notification(,'$email',$user_or_lang)

\n"; + //echo "old"; _debug_array($old); + //echo "data"; _debug_array($data); + + if (!$this->save_prefs) $this->save_prefs = $GLOBALS['egw_info']['user']; + + if (is_numeric($user_or_lang)) // user --> read everything from his prefs + { + if ($user_or_lang != $this->user) + { + $GLOBALS['egw']->preferences->preferences($user_or_lang); + $GLOBALS['egw_info']['user']['preferences'] = $GLOBALS['egw']->preferences->read_repository(); + } + if ($check && !$GLOBALS['egw_info']['user']['preferences'][$this->app][$this->check2pref ? $this->check2pref[$check] : $check]) + { + return false; // no notification requested + } + // notification via notification app. + $this->popup_notification($user_or_lang,$this->get_subject($data,$old)); + } + else + { + // for the notification copy, we use the default-prefs plus the language from the the tracker config + $GLOBALS['egw_info']['user']['preferences'] = $GLOBALS['egw']->preferences->default; + $GLOBALS['egw_info']['user']['preferences']['common']['lang'] = $user_or_lang; + } + $this->datetime_format = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat'].' '. + ($GLOBALS['egw_info']['user']['preferences']['common']['timeformat'] != 12 ? 'H:i' : 'h:i a'); + $this->tz_offset_s = 3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset']; + + if ($lang != $GLOBALS['egw']->translation->userlang) // load the right language if needed + { + $GLOBALS['egw']->translation->init(); + } + + // PHPMailer aka send-class, seems not to be able to send more then one mail, IF we need to authenticate to the SMTP server + // There for the object is newly created for ever mail, 'til this get fixed in PHPMailer. + //if(!is_object($GLOBALS['egw']->send)) + { + require_once(EGW_API_INC.'/class.send.inc.php'); + $GLOBALS['egw']->send = $send =& new send(); + } + //$send = &$GLOBALS['egw']->send; + $send->ClearAddresses(); + $send->ClearAttachments(); + + // does the user wants html-emails + $html_email = !!$GLOBALS['egw_info']['user']['preferences']['tracker'][$this->check2pref ? $this->check2pref['notify_html'] : 'notify_html']; + $send->IsHTML($html_email); + + if (preg_match('/^(.+) *<(.+)>/',$email,$matches)) // allow to use eg. "Ralf Becker " as address + { + $send->AddAddress($matches[2],$matches[1]); + } + else + { + $send->AddAddress($email,is_numeric($user_or_lang) ? $GLOBALS['egw']->accounts->id2name($user_or_lang,'account_fullname') : ''); + } + $send->AddCustomHeader("X-eGroupWare-type: {$this->app}update"); + + $sender = $this->get_sender($user,$data,$old); + if (preg_match('/^(.+) *<(.+)>/',$sender,$matches)) // allow to use eg. "Ralf Becker " as sender + { + $send->From = $matches[2]; + $send->FromName = $matches[1]; + } + else + { + $send->From = $sender; + $send->FromName = ''; + } + $send->Subject = $this->get_subject($data,$old); + + $send->Body = $this->get_body($html_email,$data,$old); + + foreach($this->get_attachments($data,$old) as $attachment) + { + if (isset($attachment['content'])) + { + $send->AddStringAttachment($attachment['content'],$attachment['filename'],$attachment['encoding'],$attachment['mimetype']); + } + elseif (isset($attachment['path'])) + { + $send->AddAttachment($attachment['path'],$attachment['filename'],$attachment['encoding'],$attachment['$mimetype']); + } + } + + if (!$send->Send()) + { + $this->errors[] = lang('Error while notifying %1: %2',$email,$send->ErrorInfo); + return false; + } + return true; + } + + /** + * Return date+time formatted for the currently notified user (send_notification) + * + * @param int $timestamp + * @return string + */ + function datetime($timestamp) + { + return date($this->datetime_format,$timestamp+$this->tz_offset_s); + } + + /** + * Get sender address + * + * @param array $data + * @param array $old + * @return string + */ + function get_sender($data,$old) + { + if ($this->prefer_user_as_sender && $this->user && ($email = $GLOBALS['egw']->accounts->id2name($this->user,'account_email'))) + { + $name = $GLOBALS['egw']->accounts->id2name($this->user,'account_fullname'); + + return $name ? $name.' <'.$email.'>' : $email; + } + if (($sender = $this->get_config('sender',$data,$old))) + { + return $sender; + } + return 'eGroupWare '.lang($this->app).' link)) + { + require_once(EGW_API_INC.'/class.bolink.inc.php'); + $GLOBALS['egw']->link =& new bolink(); + } + return $GLOBALS['egw']->link->title($this->app,$data[$this->id_field]); + } + + /** + * Get the modified / new message (1. line of mail body) for a given entry, can be reimplemented + * + * Default implementation does nothing + * + * @param array $data + * @param array $old + * @return string + */ + function get_message($data,$old) + { + return ''; + } + + /** + * Get a link to view the entry, can be reimplemented + * + * Default implementation checks get_config('link') (appending the id) or link::view($this->app,$id) + * + * @param array $data + * @param array $old + * @return string + */ + function get_link($data,$old) + { + if (($link = $this->get_config('link',$data,$old))) + { + if (strpos($link,$this->id_field.'=') === false) + { + $link .= '&'.$this->id_field.'='.$data[$this->id_field]; + } + } + elseif (($view = $GLOBALS['egw']->link->view($this->app,$data[$this->id_field]))) + { + $link = preg_replace('/(sessionid|kp3|domain)=[^&]+&?/','',$GLOBALS['egw']->link('/index.php',$view)); + + if ($link{0} == '/') + { + $link = ($_SERVER['HTTPS'] || $GLOBALS['egw_info']['server']['enforce_ssl'] ? 'https://' : 'http://'). + ($GLOBALS['egw_info']['server']['hostname'] ? $GLOBALS['egw_info']['server']['hostname'] : $_SERVER['HTTP_HOST']).$link; + } + if ($GLOBALS['egw']->link->is_popup($this->app,'view')) $link .= '&nopopup=1'; + } + return $link; + } + + /** + * Get the body of the notification message, can be reimplemented + * + * @param boolean $html_email + * @param array $data + * @param array $old + * @return string + */ + function get_body($html_email,$data,$old) + { + $body = ''; + if ($html_email) + { + $body = "\n\n".''."\n"; + } + // new or modified message + if (($message = $this->get_message($data,$old))) + { + $body .= $this->format_line($html_email,'message',false,$message); + } + if (($link = $this->get_link($data,$old))) + { + $body .= $this->format_line($html_email,'link',false,lang('You can respond by visiting:'),$link); + } + foreach($this->get_details($data) as $name => $detail) + { + $modified = $old && $data[$name] != $old[$name]; + if ($modified) error_log("data[$name]='{$data[$name]}', old[$name]='{$old[$name]}' --> modified=".(int)$modified); + if (empty($detail['value']) && !$modified) continue; // skip unchanged, empty values + + $body .= $this->format_line($html_email,$detail['type'],$modified, + ($detail['label'] ? $detail['label'].': ':'').$detail['value']); + } + if ($html_email) + { + $body .= "
\n\n\n"; + } + return $body; + } + + /** + * Format one line to the mail body + * + * @internal + * @param boolean $html_mail + * @param string $type 'link', 'message', 'summary', 'multiline', 'reply' and ''=regular content + * @param boolean $modified mark field as modified + * @param string $line + * @param string $link=null + * @return string + */ + function format_line($html_mail,$type,$modified,$line,$link=null) + { + $content = ''; + + if ($html_mail) + { + $color = $modified ? 'red' : false; + $size = 'small'; + $bold = false; + $background = '#FFFFF1'; + switch($type) + { + case 'message': + $background = '#D3DCE3;'; + $bold = true; + break; + case 'link': + $background = '#F1F1F1'; + break; + case 'summary': + $background = '#F1F1F1'; + $bold = true; + break; + case 'multiline': + $line = nl2br($line); + break; + case 'reply': + $background = '#F1F1F1'; + break; + default: + $size = 'x-small'; + } + $style = ($bold ? 'font-weight:bold;' : '').($size ? 'font-size:'.$size.';' : '').($color?'color:'.$color:''); + + $content = ''; + } + else // text-mail + { + if ($type == 'reply') $content = str_repeat('-',64)."\n"; + if ($modified) $content .= '> '; + } + $content .= $line; + + if ($link) + { + $content .= ' '; + if ($html_mail) $content .= ''; + $content .= $link; + if ($html_mail) $content .= ''; + } + if ($html_mail) $content .= ''; + + $content .= "\n"; + + return $content; + } + + /** + * Get the attachments for a notificaton mail + * + * @param array $data + * @param array $old + * @return array with values for either 'content' or 'path' and optionally 'mimetype', 'filename' and 'encoding' + */ + function get_attachments($data,$old) + { + return array(); + } +} \ No newline at end of file diff --git a/infolog/inc/class.boinfolog.inc.php b/infolog/inc/class.boinfolog.inc.php index 7d4b80162e..2553a58ae9 100644 --- a/infolog/inc/class.boinfolog.inc.php +++ b/infolog/inc/class.boinfolog.inc.php @@ -105,6 +105,12 @@ class boinfolog * @var array */ var $group_owners=array(); + /** + * Current user + * + * @var int + */ + var $user; /** * Constructor Infolog BO @@ -606,10 +612,10 @@ class boinfolog { if ($to_write[$time]) $to_write[$time] -= $this->tz_offset_s; } - // if we have links in customfields, we need to get the old values, to be able to remove changed links - if ($this->has_customfields($values['info_type'],true) && $values['info_id']) + // 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']); + $old = $this->read($values['info_id'],false); } if(($info_id = $this->so->write($to_write,$check_modified))) { @@ -640,6 +646,14 @@ class boinfolog // notify the link-class about the update, as other apps may be subscribt to it $this->link->notify_update('infolog',$info_id,$values); + + // send email notifications and do the history logging + require_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.infolog_tracking.inc.php'); + if (!is_object($this->tracking)) + { + $this->tracking =& new infolog_tracking($this); + } + $this->tracking->track($values,$old,$this->user); } if ($info_from_set) $values['info_from'] = ''; diff --git a/infolog/inc/class.infolog_tracking.inc.php b/infolog/inc/class.infolog_tracking.inc.php new file mode 100644 index 0000000000..f94d3b7bc3 --- /dev/null +++ b/infolog/inc/class.infolog_tracking.inc.php @@ -0,0 +1,226 @@ + + * @package tracker + * @copyright (c) 2007 by Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id$ + */ + +require_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.bo_tracking.inc.php'); + +/** + * Tracker - tracking object for the tracker + */ +class infolog_tracking extends bo_tracking +{ + /** + * Application we are tracking (required!) + * + * @var string + */ + var $app = 'infolog'; + /** + * Name of the id-field, used as id in the history log (required!) + * + * @var string + */ + var $id_field = 'info_id'; + /** + * Name of the field with the creator id, if the creator of an entry should be notified + * + * @var string + */ + var $creator_field = 'info_owner'; + /** + * Name of the field with the id(s) of assinged users, if they should be notified + * + * @var string + */ + var $assigned_field = 'info_responsible'; + /** + * Translate field-names to 2-char history status + * + * @var array + */ + var $field2history = array(); + /** + * Translate field-names to labels + * + * @var array + */ + var $field2label = array( + 'info_type' => 'Type', + 'info_from' => 'Contact', + 'info_addr' => 'Phone/Email', + 'info_cat' => 'Category', + 'info_priority' => 'Priority', + 'info_owner' => 'Owner', + 'info_status' => 'Status', + 'info_percent' => 'Completed', + 'info_datecompleted' => 'Date completed', + 'info_location' => 'Location', + 'info_startdate' => 'Startdate', + 'info_enddate' => 'Enddate', + 'info_responsible' => 'Responsible', + 'info_subject' => 'Subject', + ); + + /** + * Instance of the boinfolog class calling us + * + * @access private + * @var boinfolog + */ + var $infolog; + + /** + * Constructor + * + * @param botracker $botracker + * @return tracker_tracking + */ + function infolog_tracking(&$boinfolog) + { + $this->infolog =& $boinfolog; + } + + /** + * Tracks the changes in one entry $data, by comparing it with the last version in $old + * + * Reimplemented to fix some fields, who otherwise allways show up as modified + * + * @param array $data current entry + * @param array $old=null old/last state of the entry or null for a new entry + * @param int $user=null user who made the changes, default to current user + * @return int/boolean false on error, integer number of changes logged or true for new entries ($old == null) + */ + function track($data,$old=null,$user=null) + { + if ($old) + { + foreach($this->infolog->timestamps as $name) + { + if (!$old[$name]) $old[$name] = ''; + } + } + return parent::track($data,$old,$user); + } + + + /** + * 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) + { + return null; + } + + /** + * Get the modified / new message (1. line of mail body) for a given entry, can be reimplemented + * + * @param array $data + * @param array $old + * @return array/string array(message,user-id,timestamp-in-servertime) or string + */ + function get_message($data,$old) + { + if (!$data['info_datemodified'] || !$old) + { + return lang('New %1 created by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]), + $GLOBALS['egw']->common->grab_owner_name($this->infolog->user),$this->datetime(time())); + } + return lang('%1 modified by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]), + $GLOBALS['egw']->common->grab_owner_name($data['info_modifier']), + $this->datetime($data['info_datemodified']-$this->infolog->tz_offset_s)); + } + + /** + * Get the details of an entry + * + * @param array $data + * @param string $datetime_format of user to notify, eg. 'Y-m-d H:i' + * @param int $tz_offset_s offset in sec to be add to server-time to get the user-time of the user to notify + * @return array of details as array with values for keys 'label','value','type' + */ + function get_details($data) + { + $responsible = array(); + if ($data['info_responsible']) + { + foreach($data['info_responsible'] as $uid) + { + $responsible[] = $GLOBALS['egw']->common->grab_owner_name($uid); + } + } + if ($data['info_cat'] && !is_object($GLOBALS['egw']->categories)) + { + require_once(EGW_API_INC.'/class.categories.inc.php'); + $GLOBALS['egw']->categories =& new categories($this->infolog->user,'infolog'); + } + if ($GLOBALS['egw_info']['user']['preferences']['infolog']['show_id']) + { + $id = ' #'.$data['info_id']; + } + foreach(array( + 'info_type' => lang($this->infolog->enums['type'][$data['info_type']]).$id, + 'info_from' => $data['info_from'], + 'info_addr' => $data['info_addr'], + 'info_cat' => $data['info_cat'] ? $GLOBALS['egw']->categories->id2name($data['info_cat']) : '', + 'info_priority' => lang($this->infolog->enums['priority'][$data['info_priority']]), + 'info_owner' => $GLOBALS['egw']->common->grab_owner_name($data['info_owner']), + 'info_status' => lang($this->infolog->status[$data['info_type']][$data['info_status']]), + 'info_percent' => (int)$data['info_percent'].'%', + 'info_datecompleted' => $data['info_datecomplete'] ? $this->datetime($data['info_datecompleted']-$this->infolog->tz_offset_s) : '', + 'info_location' => $data['info_location'], + 'info_startdate' => $data['info_startdate'] ? $this->datetime($data['info_startdate']-$this->infolog->tz_offset_s) : '', + 'info_enddate' => $data['info_enddate'] ? $this->datetime($data['info_enddate']-$this->infolog->tz_offset_s) : '', + 'info_responsible' => implode(', ',$responsible), + 'info_subject' => $data['info_subject'], + ) as $name => $value) + { + $details[$name] = array( + 'label' => lang($this->field2label[$name]), + 'value' => $value, + ); + if ($name == 'info_subject') $details[$name]['type'] = 'summary'; + } + $details['info_des'] = array( + 'value' => $data['info_des'], + 'type' => 'multiline', + ); + // should be moved to bo_tracking because auf the different custom field types + if ($this->infolog->customfields) + { + foreach($this->infolog->customfields as $name => $field) + { + if ($field['type2'] && $field['type2'] != $data['info_type']) continue; // different type + + if (!$header_done) + { + $details['custom'] = array( + 'value' => lang('Custom fields').':', + 'type' => 'reply', + ); + $header_done = true; + } + $details[$name] = array( + 'label' => $field['label'], + 'value' => $data['#'.$name], + ); + } + } + return $details; + } +} \ No newline at end of file diff --git a/infolog/inc/hook_settings.inc.php b/infolog/inc/hook_settings.inc.php index 2a051c7cee..4313863d29 100644 --- a/infolog/inc/hook_settings.inc.php +++ b/infolog/inc/hook_settings.inc.php @@ -9,124 +9,150 @@ * @version $Id$ */ - /* Setup some values to fill the array of this app's settings below */ - $ui =& CreateObject('infolog.uiinfolog'); // need some labels from - $filters = $show_home = array(); - $show_home[] = lang("DON'T show InfoLog"); - foreach($ui->filters as $key => $label) - { - $show_home[$key] = $filters[$key] = lang($label); - } - $have_custom_fields = count($ui->bo->customfields) > 0; - unset($ui); +/* Setup some values to fill the array of this app's settings below */ +$ui =& CreateObject('infolog.uiinfolog'); // need some labels from +$filters = $show_home = array(); +$show_home[] = lang("DON'T show InfoLog"); +foreach($ui->filters as $key => $label) +{ + $show_home[$key] = $filters[$key] = lang($label); +} +$have_custom_fields = count($ui->bo->customfields) > 0; +unset($ui); - // migrage old filter-pref 1,2 to the filter one 'own-open-today' - if (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'), +// migrage old filter-pref 1,2 to the filter one 'own-open-today' +if (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 */ +$GLOBALS['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 + ), + '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 + ), + '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 + ), + '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 + ), + '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 + ), + '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 + ), + '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 + ), + '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 + ), +); +if ($have_custom_fields) +{ + $GLOBALS['settings']['cal_show_custom'] = array( + 'type' => 'check', + 'label' => 'Should the calendar show custom types too', + 'name' => 'cal_show_custom', + 'help' => 'Do you want to see custom InfoLog types in the calendar?', + 'xmlrpc' => True, + 'admin' => False ); - $show_details = array( - 0 => lang('No'), - 1 => lang('Yes'), - 2 => lang('Only for details'), - ); - /* Settings array for this app */ - $GLOBALS['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 - ), - '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 - ), - '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 - ), - '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 - ), - '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 - ), - '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 - ), - '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 - ), - '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 - ), - ); - if ($have_custom_fields) - { - $GLOBALS['settings']['cal_show_custom'] = array( - 'type' => 'check', - 'label' => 'Should the calendar show custom types too', - 'name' => 'cal_show_custom', - 'help' => 'Do you want to see custom InfoLog types in the calendar?', - 'xmlrpc' => True, - 'admin' => False - ); - } - unset($show_home); - unset($show_details); - unset($filters); - unset($show_links); +} +unset($show_home); +unset($show_details); +unset($filters); +unset($show_links); + +// notification preferences +$GLOBALS['settings']['notify_creator'] = array( + 'type' => 'check', + 'label' => 'Receive notifications about own items', + 'name' => 'notify_creator', + 'help' => 'Do you want a notification mail, if items you created get updated?', + 'xmlrpc' => True, + 'admin' => False, +); +$GLOBALS['settings']['notify_assigned'] = array( + 'type' => 'check', + 'label' => 'Receive notifications about items assigned to you', + 'name' => 'notify_assigned', + 'help' => 'Do you want a notification mails, if items get assigned to you or assigned items get updated?', + 'xmlrpc' => True, + 'admin' => False, +); +$GLOBALS['settings']['notify_html'] = array( + 'type' => 'check', + 'label' => 'Receive notifications as html-mails', + 'name' => 'notify_html', + 'help' => 'Do you want to receive notifications as html-mails or plain text?', + 'xmlrpc' => True, + 'admin' => False, +); diff --git a/notifications/inc/class.notification.inc.php b/notifications/inc/class.notification.inc.php index 1ecda43efc..cdbd063f24 100644 --- a/notifications/inc/class.notification.inc.php +++ b/notifications/inc/class.notification.inc.php @@ -126,3 +126,25 @@ final class notification { } } + +/** + * Small helper function to just send a message + * + * @param array $receivers + * @param string $message + * @return Exception + */ +function notify(array $receivers,$message) +{ + $notification = new notification(); + $notification->set_receivers($receivers); + $notification->set_message($message); + try{ + $notification->send(); + } + catch(Exception $exception) { + error_log("notify(array($user),'$message'".$exception->getMessage()); + return $exception; + } + return null; +} diff --git a/notifications/inc/class.notification_popup.inc.php b/notifications/inc/class.notification_popup.inc.php index 9b458dc585..b7f173e38e 100644 --- a/notifications/inc/class.notification_popup.inc.php +++ b/notifications/inc/class.notification_popup.inc.php @@ -68,10 +68,12 @@ class notification_popup implements iface_notification { // If we are called from class notification account and prefs are objects. // otherwise we have to fetch this objects for current user. if (!is_object($_account)) { - $account_id = $GLOBALS['egw_info']['user']['account_id']; - $this->account = $GLOBALS['egw']->accounts->get_account_data($account_id); - $this->account[$account_id]['id'] = $account_id; - $this->account = (object)$this->account[$account_id]; + $_account = (object) $GLOBALS['egw']->accounts->read($_account); + $_account->id =& $_account->account_id; +// $account_id = $GLOBALS['egw_info']['user']['account_id']; +// $this->account = $GLOBALS['egw']->accounts->get_account_data($account_id); +// $this->account[$account_id]['id'] = $account_id; +// $this->account = (object)$this->account[$account_id]; } else { $this->account = $_account; @@ -94,7 +96,7 @@ class notification_popup implements iface_notification { $user_sessions[] = $session['session_id']; } } - if ( empty($user_sessions) ) throw new Exception("Notice: User $this->account isn't online. Can't send notification via popup"); + if ( empty($user_sessions) ) throw new Exception("Notice: User #{$this->account->id} isn't online. Can't send notification via popup"); $this->save( $_message, $user_sessions ); } From 86ecd44066d1ad5e853a00f2f511fd82e30aff65 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 29 May 2007 05:58:46 +0000 Subject: [PATCH 04/30] "bugfix for xmlrpc (KAdressbook): customfield names (keys) were NOT prefix with a hash" --- addressbook/inc/class.boaddressbook.inc.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addressbook/inc/class.boaddressbook.inc.php b/addressbook/inc/class.boaddressbook.inc.php index ee990cd3c0..6132904e87 100644 --- a/addressbook/inc/class.boaddressbook.inc.php +++ b/addressbook/inc/class.boaddressbook.inc.php @@ -201,7 +201,10 @@ class boaddressbook if ($customfields && isset($customfields[$data['id']])) { - $data += $customfields[$data['id']]; + foreach($customfields[$data['id']] as $name => $value) + { + $data['#'.$name] = $value; + } } // remove empty or null elements, they dont need to be transfered $data = array_diff($data,array('',null)); From 7ed708df75205903c2a9d294e29a595320229d22 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 29 May 2007 08:35:27 +0000 Subject: [PATCH 05/30] NOT FOR 1.4: a very first step to the new vfs structure, it only does a ls via commandline of the old vfs --- filemanager/ls.php | 230 +++++++++ .../inc/class.iface_stream_wrapper.inc.php | 243 ++++++++++ .../inc/class.oldvfs_stream_wrapper.inc.php | 442 ++++++++++++++++++ 3 files changed, 915 insertions(+) create mode 100755 filemanager/ls.php create mode 100644 phpgwapi/inc/class.iface_stream_wrapper.inc.php create mode 100644 phpgwapi/inc/class.oldvfs_stream_wrapper.inc.php diff --git a/filemanager/ls.php b/filemanager/ls.php new file mode 100755 index 0000000000..000506530b --- /dev/null +++ b/filemanager/ls.php @@ -0,0 +1,230 @@ +#!/usr/bin/php -qC + + * @copyright (c) 2006 by Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id$ + */ + +chdir(dirname(__FILE__)); // to enable our relative pathes to work + +if (isset($_SERVER['HTTP_HOST'])) // security precaution: forbit calling admin-cli as web-page +{ + die('

ls.php must NOT be called as web-page --> exiting !!!

'); +} + +/* +// this is kind of a hack, as the autocreate_session_callback can not change the type of the loaded account-class +// so we need to make sure the right one is loaded by setting the domain before the header gets included. +$arg0s = explode(',',@$arguments[0]); +@list(,$_GET['domain']) = explode('@',$arg0s[0]); + +if (is_dir('/tmp')) ini_set('session.save_path','/tmp'); // regular users may have no rights to apache's session dir + +$GLOBALS['egw_info'] = array( + 'flags' => array( + 'currentapp' => 'admin', + 'noheader' => true, + 'autocreate_session_callback' => 'user_pass_from_argv', + ) +); + +include('../header.inc.php'); +*/ + +/** + * callback if the session-check fails, redirects via xajax to login.php + * + * @param array &$account account_info with keys 'login', 'passwd' and optional 'passwd_type' + * @return boolean/string true if we allow the access and account is set, a sessionid or false otherwise + */ +function user_pass_from_argv(&$account) +{ + $account = $GLOBALS['egw_login_data']; + //print_r($account); + if (!($sessionid = $GLOBALS['egw']->session->create($account))) + { + echo "Wrong admin-account or -password !!!\n\n"; + usage('',1); + } + if (!$GLOBALS['egw_info']['user']['apps']['admin']) // will be tested by the header too, but whould give html error-message + { + echo "Permission denied !!!\n\n"; + usage('',2); + } + return $sessionid; +} + +/** + * Give a usage message and exit + * + * @param string $action=null + * @param int $ret=0 exit-code + */ +function usage($action=null,$ret=0) +{ + $cmd = basename($_SERVER['argv'][0]); + echo "Usage: $cmd URL\n\n"; + + exit; +} +$long=false; +array_shift($_SERVER['argv']); +while(($url = array_shift($_SERVER['argv']))) +{ + if ($url == '-l') + { + $long = true; + continue; + } + switch(parse_url($url,PHP_URL_SCHEME)) + { + case 'webdav': + require_once('HTTP/WebDAV/Client.php'); + break; + case 'oldvfs': + if (!isset($GLOBALS['egw_info'])) + { + $_GET['domain'] = parse_url($url,PHP_URL_HOST); + $GLOBALS['egw_login_data'] = array( + 'login' => parse_url($url,PHP_URL_USER), + 'passwd' => parse_url($url,PHP_URL_PASS), + 'passwd_type' => 'text', + ); + + if (is_dir('/tmp')) ini_set('session.save_path','/tmp'); // regular users may have no rights to apache's session dir + + $GLOBALS['egw_info'] = array( + 'flags' => array( + 'currentapp' => 'admin', + 'noheader' => true, + 'autocreate_session_callback' => 'user_pass_from_argv', + ) + ); + + include('../header.inc.php'); + } + require_once(EGW_API_INC.'/class.oldvfs_stream_wrapper.inc.php'); + break; + case '': + case 'ftp': + break; + default: + die("Unknown scheme in $url !!!\n\n"); + } + if (($dir = opendir($url))) + { + if ($_SERVER['argc'] > 2) + { + echo "\n".basename(parse_url($url,PHP_URL_PATH)).":\n"; + } + while(($file = readdir($dir)) !== false) + { + do_stat($url.'/'.$file,$long); + } + closedir($dir); + } + else + { + do_stat($url,$long); + } +/* else + { + echo "File or directory not found !!!\n\n"; + }*/ + if (!$long) echo "\n"; +} + +function do_stat($url,$long=false) +{ + $bname = basename(parse_url($url,PHP_URL_PATH)); + + if ($long) + { + $stat = stat($url); + //print_r($stat); + + $perms = verbosePerms($stat['mode']); + $uid = isset($GLOBALS['egw']) && $stat['uid'] ? $GLOBALS['egw']->accounts->id2name($stat['uid']) : posix_getpwuid($stat['uid']); + if (is_array($uid)) $uid = $uid['name']; + $gid = isset($GLOBALS['egw']) && $stat['gid'] ? $GLOBALS['egw']->accounts->id2name($stat['gid']) : posix_getgrgid($stat['gid']); + if (is_array($gid)) $gid = $gid['name']; + $size = hsize($stat['size']); + $mtime = date('Y-m-d H:i:s',$stat['mtime']); + $nlink = $stat['nlink']; + + echo "$perms $nlink\t$uid\t$gid\t$size\t$mtime\t$bname\n"; + } + else + { + echo "$bname\t"; + } +} + +function hsize($size) +{ + if ($size < 1024) return $size; + if ($size < 1024*1024) return sprintf('%3.1lfk',(float)$size/1024); + return sprintf('%3.1lfM',(float)$size/(1024*1024)); +} + +function verbosePerms( $in_Perms ) +{ + if($in_Perms & 0x1000) // FIFO pipe + { + $sP = 'p'; + } + elseif($in_Perms & 0x2000) // Character special + { + $sP = 'c'; + } + elseif($in_Perms & 0x4000) // Directory + { + $sP = 'd'; + } + elseif($in_Perms & 0x6000) // Block special + { + $sP = 'b'; + } + elseif($in_Perms & 0x8000) // Regular + { + $sP = '-'; + } + elseif($in_Perms & 0xA000) // Symbolic Link + { + $sP = 'l'; + } + elseif($in_Perms & 0xC000) // Socket + { + $sP = 's'; + } + else // UNKNOWN + { + $sP = 'u'; + } + + // owner + $sP .= (($in_Perms & 0x0100) ? 'r' : '-') . + (($in_Perms & 0x0080) ? 'w' : '-') . + (($in_Perms & 0x0040) ? (($in_Perms & 0x0800) ? 's' : 'x' ) : + (($in_Perms & 0x0800) ? 'S' : '-')); + + // group + $sP .= (($in_Perms & 0x0020) ? 'r' : '-') . + (($in_Perms & 0x0010) ? 'w' : '-') . + (($in_Perms & 0x0008) ? (($in_Perms & 0x0400) ? 's' : 'x' ) : + (($in_Perms & 0x0400) ? 'S' : '-')); + + // world + $sP .= (($in_Perms & 0x0004) ? 'r' : '-') . + (($in_Perms & 0x0002) ? 'w' : '-') . + (($in_Perms & 0x0001) ? (($in_Perms & 0x0200) ? 't' : 'x' ) : + (($in_Perms & 0x0200) ? 'T' : '-')); + return $sP; +} + diff --git a/phpgwapi/inc/class.iface_stream_wrapper.inc.php b/phpgwapi/inc/class.iface_stream_wrapper.inc.php new file mode 100644 index 0000000000..efb3f7bd1e --- /dev/null +++ b/phpgwapi/inc/class.iface_stream_wrapper.inc.php @@ -0,0 +1,243 @@ +=') && version_compare(PHP_VERSION,'5.1','<')) + * { + * $eof = !$eof; + * } + * + * @return boolean true if the read/write position is at the end of the stream and no more data availible, false otherwise + */ + function stream_eof ( ); + + /** + * This method is called in response to ftell() calls on the stream. + * + * @return integer current read/write position of the stream + */ + function stream_tell ( ); + + /** + * This method is called in response to fseek() calls on the stream. + * + * You should update the read/write position of the stream according to offset and whence. + * See fseek() for more information about these parameters. + * + * @param integer $offset + * @param integer $whence + * @return boolean TRUE if the position was updated, FALSE otherwise. + */ + function stream_seek ( $offset, $whence ); + + /** + * This method is called in response to fflush() calls on the stream. + * + * If you have cached data in your stream but not yet stored it into the underlying storage, you should do so now. + * + * @return booelan TRUE if the cached data was successfully stored (or if there was no data to store), or FALSE if the data could not be stored. + */ + function stream_flush ( ); + + /** + * This method is called in response to fstat() calls on the stream. + * + * If you plan to use your wrapper in a require_once you need to define stream_stat(). + * If you plan to allow any other tests like is_file()/is_dir(), you have to define url_stat(). + * stream_stat() must define the size of the file, or it will never be included. + * url_stat() must define mode, or is_file()/is_dir()/is_executable(), and any of those functions affected by clearstatcache() simply won't work. + * It's not documented, but directories must be a mode like 040777 (octal), and files a mode like 0100666. + * If you wish the file to be executable, use 7s instead of 6s. + * The last 3 digits are exactly the same thing as what you pass to chmod. + * 040000 defines a directory, and 0100000 defines a file. + * + * @return array containing the same values as appropriate for the stream. + */ + function stream_stat ( ); + + /** + * This method is called in response to unlink() calls on URL paths associated with the wrapper. + * + * It should attempt to delete the item specified by path. + * In order for the appropriate error message to be returned, do not define this method if your wrapper does not support unlinking! + * + * @param string $path + * @return boolean TRUE on success or FALSE on failure + */ + function unlink ( $path ); + + /** + * This method is called in response to rename() calls on URL paths associated with the wrapper. + * + * It should attempt to rename the item specified by path_from to the specification given by path_to. + * In order for the appropriate error message to be returned, do not define this method if your wrapper does not support renaming. + * + * @param string $path_from + * @param string $path_to + * @return boolean TRUE on success or FALSE on failure + */ + function rename ( $path_from, $path_to ); + + /** + * This method is called in response to mkdir() calls on URL paths associated with the wrapper. + * + * It should attempt to create the directory specified by path. + * In order for the appropriate error message to be returned, do not define this method if your wrapper does not support creating directories. + * + * @param string $path + * @param int $mode + * @param int $options Posible values include STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE + * @return boolean TRUE on success or FALSE on failure + */ + function mkdir ( $path, $mode, $options ); + + /** + * This method is called in response to rmdir() calls on URL paths associated with the wrapper. + * + * It should attempt to remove the directory specified by path. + * In order for the appropriate error message to be returned, do not define this method if your wrapper does not support removing directories. + * + * @param string $path + * @param int $options Possible values include STREAM_REPORT_ERRORS. + * @return boolean TRUE on success or FALSE on failure. + */ + function rmdir ( $path, $options ); + + /** + * This method is called immediately when your stream object is created for examining directory contents with opendir(). + * + * @param string $path URL that was passed to opendir() and that this object is expected to explore. + * @return booelan + */ + function dir_opendir ( $path, $options ); + + /** + * This method is called in response to stat() calls on the URL paths associated with the wrapper. + * + * It should return as many elements in common with the system function as possible. + * Unknown or unavailable values should be set to a rational value (usually 0). + * + * If you plan to use your wrapper in a require_once you need to define stream_stat(). + * If you plan to allow any other tests like is_file()/is_dir(), you have to define url_stat(). + * stream_stat() must define the size of the file, or it will never be included. + * url_stat() must define mode, or is_file()/is_dir()/is_executable(), and any of those functions affected by clearstatcache() simply won't work. + * It's not documented, but directories must be a mode like 040777 (octal), and files a mode like 0100666. + * If you wish the file to be executable, use 7s instead of 6s. + * The last 3 digits are exactly the same thing as what you pass to chmod. + * 040000 defines a directory, and 0100000 defines a file. + * + * @param string $path + * @param int $flags holds additional flags set by the streams API. It can hold one or more of the following values OR'd together: + * - STREAM_URL_STAT_LINK For resources with the ability to link to other resource (such as an HTTP Location: forward, + * or a filesystem symlink). This flag specified that only information about the link itself should be returned, + * not the resource pointed to by the link. + * This flag is set in response to calls to lstat(), is_link(), or filetype(). + * - STREAM_URL_STAT_QUIET If this flag is set, your wrapper should not raise any errors. If this flag is not set, + * you are responsible for reporting errors using the trigger_error() function during stating of the path. + * @return array + */ + function url_stat ( $path, $flags ); + + /** + * This method is called in response to readdir(). + * + * It should return a string representing the next filename in the location opened by dir_opendir(). + * + * @return string + */ + function dir_readdir ( ); + + /** + * This method is called in response to rewinddir(). + * + * It should reset the output generated by dir_readdir(). i.e.: + * The next call to dir_readdir() should return the first entry in the location returned by dir_opendir(). + * + * @return boolean + */ + function dir_rewinddir ( ); + + /** + * This method is called in response to closedir(). + * + * You should release any resources which were locked or allocated during the opening and use of the directory stream. + * + * @return boolean + */ + function dir_closedir ( ); +} diff --git a/phpgwapi/inc/class.oldvfs_stream_wrapper.inc.php b/phpgwapi/inc/class.oldvfs_stream_wrapper.inc.php new file mode 100644 index 0000000000..7308ca77a1 --- /dev/null +++ b/phpgwapi/inc/class.oldvfs_stream_wrapper.inc.php @@ -0,0 +1,442 @@ + + * @copyright (c) 2007 by Ralf Becker + * @version $Id$ + */ + +require_once(EGW_API_INC.'/class.vfs_home.inc.php'); +require_once(EGW_API_INC.'/class.iface_stream_wrapper.inc.php'); + +/** + * eGroupWare API: VFS - old (until eGW 1.4 inclusive) VFS stream wrapper + * + * This class uses eGW's vfs_home class to access the vfs. + * + * The interface is according to the docu on php.net + * + * @link http://de.php.net/manual/de/function.stream-wrapper-register.php + */ +class oldvfs_stream_wrapper implements iface_stream_wrapper +{ + /** + * optional context param when opening the stream, null if no context passed + * + * @var mixed + */ + var $context; + + /** + * Instance of the old vfs class + * + * @var vfs_home + */ + static protected $old_vfs; + + /** + * Path off the file opened by stream_open + * + * @var string + */ + protected $opened_path; + /** + * Mode of the file opened by stream_open + * + * @var int + */ + protected $opened_mode; + /** + * Global vfs::ls() cache + * + * @var array + */ + static protected $cache=array(); + /** + * Directory vfs::ls() of path opened with dir_opendir() + * + * @var string + */ + protected $opened_dir; + + /** + * Constructor + * + * @return oldvfs_stream_wrapper + */ + function __construct() + { + error_log('oldvfs_stream_wrapper::__construct()'); + if (!is_object($this->old_vfs)) $this->old_vfs = new vfs_home(); + } + + /** + * This method is called immediately after your stream object is created. + * + * @param string $path URL that was passed to fopen() and that this object is expected to retrieve + * @param string $mode mode used to open the file, as detailed for fopen() + * @param int $options additional flags set by the streams API (or'ed together): + * - STREAM_USE_PATH If path is relative, search for the resource using the include_path. + * - STREAM_REPORT_ERRORS If this flag is set, you are responsible for raising errors using trigger_error() during opening of the stream. + * If this flag is not set, you should not raise any errors. + * @param string $opened_path full path of the file/resource, if the open was successfull and STREAM_USE_PATH was set + * @return boolean true if the ressource was opened successful, otherwise false + */ + function stream_open ( $path, $mode, $options, &$opened_path ) + { + + } + + /** + * This method is called when the stream is closed, using fclose(). + * + * You must release any resources that were locked or allocated by the stream. + */ + function stream_close ( ) + { + + } + + /** + * This method is called in response to fread() and fgets() calls on the stream. + * + * You must return up-to count bytes of data from the current read/write position as a string. + * If there are less than count bytes available, return as many as are available. + * If no more data is available, return either FALSE or an empty string. + * You must also update the read/write position of the stream by the number of bytes that were successfully read. + * + * @param int $count + * @return string/false up to count bytes read or false on EOF + */ + function stream_read ( $count ) + { + + } + + /** + * This method is called in response to fwrite() calls on the stream. + * + * You should store data into the underlying storage used by your stream. + * If there is not enough room, try to store as many bytes as possible. + * You should return the number of bytes that were successfully stored in the stream, or 0 if none could be stored. + * You must also update the read/write position of the stream by the number of bytes that were successfully written. + * + * @param string $data + * @return integer + */ + function stream_write ( $data ) + { + + } + + /** + * This method is called in response to feof() calls on the stream. + * + * Important: PHP 5.0 introduced a bug that wasn't fixed until 5.1: the return value has to be the oposite! + * + * if(version_compare(PHP_VERSION,'5.0','>=') && version_compare(PHP_VERSION,'5.1','<')) + * { + * $eof = !$eof; + * } + * + * @return boolean true if the read/write position is at the end of the stream and no more data availible, false otherwise + */ + function stream_eof ( ) + { + + } + + /** + * This method is called in response to ftell() calls on the stream. + * + * @return integer current read/write position of the stream + */ + function stream_tell ( ) + { + + } + + /** + * This method is called in response to fseek() calls on the stream. + * + * You should update the read/write position of the stream according to offset and whence. + * See fseek() for more information about these parameters. + * + * @param integer $offset + * @param integer $whence + * @return boolean TRUE if the position was updated, FALSE otherwise. + */ + function stream_seek ( $offset, $whence ) + { + + } + + /** + * This method is called in response to fflush() calls on the stream. + * + * If you have cached data in your stream but not yet stored it into the underlying storage, you should do so now. + * + * @return booelan TRUE if the cached data was successfully stored (or if there was no data to store), or FALSE if the data could not be stored. + */ + function stream_flush ( ) + { + + } + + /** + * This method is called in response to fstat() calls on the stream. + * + * If you plan to use your wrapper in a require_once you need to define stream_stat(). + * If you plan to allow any other tests like is_file()/is_dir(), you have to define url_stat(). + * stream_stat() must define the size of the file, or it will never be included. + * url_stat() must define mode, or is_file()/is_dir()/is_executable(), and any of those functions affected by clearstatcache() simply won't work. + * It's not documented, but directories must be a mode like 040777 (octal), and files a mode like 0100666. + * If you wish the file to be executable, use 7s instead of 6s. + * The last 3 digits are exactly the same thing as what you pass to chmod. + * 040000 defines a directory, and 0100000 defines a file. + * + * @return array containing the same values as appropriate for the stream. + */ + function stream_stat ( ) + { + + } + + /** + * This method is called in response to unlink() calls on URL paths associated with the wrapper. + * + * It should attempt to delete the item specified by path. + * In order for the appropriate error message to be returned, do not define this method if your wrapper does not support unlinking! + * + * @param string $path + * @return boolean TRUE on success or FALSE on failure + */ + function unlink ( $path ) + { + + } + + /** + * This method is called in response to rename() calls on URL paths associated with the wrapper. + * + * It should attempt to rename the item specified by path_from to the specification given by path_to. + * In order for the appropriate error message to be returned, do not define this method if your wrapper does not support renaming. + * + * @param string $path_from + * @param string $path_to + * @return boolean TRUE on success or FALSE on failure + */ + function rename ( $path_from, $path_to ) + { + + } + + /** + * This method is called in response to mkdir() calls on URL paths associated with the wrapper. + * + * It should attempt to create the directory specified by path. + * In order for the appropriate error message to be returned, do not define this method if your wrapper does not support creating directories. + * + * @param string $path + * @param int $mode + * @param int $options Posible values include STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE + * @return boolean TRUE on success or FALSE on failure + */ + function mkdir ( $path, $mode, $options ) + { + + } + + /** + * This method is called in response to rmdir() calls on URL paths associated with the wrapper. + * + * It should attempt to remove the directory specified by path. + * In order for the appropriate error message to be returned, do not define this method if your wrapper does not support removing directories. + * + * @param string $path + * @param int $options Possible values include STREAM_REPORT_ERRORS. + * @return boolean TRUE on success or FALSE on failure. + */ + function rmdir ( $path, $options ) + { + + } + + /** + * This method is called immediately when your stream object is created for examining directory contents with opendir(). + * + * @param string $path URL that was passed to opendir() and that this object is expected to explore. + * @return booelan + */ + function dir_opendir ( $url, $options ) + { + error_log("oldvfs_stream_wrapper::dir_opendir('$path',$options)"); + + if (!is_object($GLOBALS['egw']->vfs)) + { + $GLOBALS['egw']->vfs =& new vfs_home(); + } + $path = parse_url($url,PHP_URL_PATH); + + $this->opened_dir = $GLOBALS['egw']->vfs->ls(array( + 'string' => $path, + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + 'checksubdirs' => false, + 'nofiles' => false, + //'orderby' => '', + //'mime_type' => '', + )); + if (!is_array($this->opened_dir)) + { + $this->opened_dir = null; + return false; + } + //print_r($this->opened_dir); + reset($this->opened_dir); + + return true; + } + + /** + * This method is called in response to stat() calls on the URL paths associated with the wrapper. + * + * It should return as many elements in common with the system function as possible. + * Unknown or unavailable values should be set to a rational value (usually 0). + * + * If you plan to use your wrapper in a require_once you need to define stream_stat(). + * If you plan to allow any other tests like is_file()/is_dir(), you have to define url_stat(). + * stream_stat() must define the size of the file, or it will never be included. + * url_stat() must define mode, or is_file()/is_dir()/is_executable(), and any of those functions affected by clearstatcache() simply won't work. + * It's not documented, but directories must be a mode like 040777 (octal), and files a mode like 0100666. + * If you wish the file to be executable, use 7s instead of 6s. + * The last 3 digits are exactly the same thing as what you pass to chmod. + * 040000 defines a directory, and 0100000 defines a file. + * + * @param string $path + * @param int $flags holds additional flags set by the streams API. It can hold one or more of the following values OR'd together: + * - STREAM_URL_STAT_LINK For resources with the ability to link to other resource (such as an HTTP Location: forward, + * or a filesystem symlink). This flag specified that only information about the link itself should be returned, + * not the resource pointed to by the link. + * This flag is set in response to calls to lstat(), is_link(), or filetype(). + * - STREAM_URL_STAT_QUIET If this flag is set, your wrapper should not raise any errors. If this flag is not set, + * you are responsible for reporting errors using the trigger_error() function during stating of the path. + * @return array + */ + function url_stat ( $url, $flags ) + { + error_log("oldvfs_stream_wrapper::url_stat('$url',$flags)"); + + /*return array( + 'mode' => 0100666, + 'name' => basename(parse_url($path,PHP_URL_PATH)), + 'size' => strlen(basename(parse_url($path,PHP_URL_PATH))), + 'nlink' => 1, + 'uid' => 1000, + 'gid' => 100, + 'mtime' => time(), + );*/ + + if (!is_object($GLOBALS['egw']->vfs)) + { + $GLOBALS['egw']->vfs =& new vfs_home(); + } + $path = parse_url($url,PHP_URL_PATH); + + list($info) = $GLOBALS['egw']->vfs->ls(array( + 'string' => $path, + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + 'checksubdirs' => false, + 'nofiles' => true, + //'orderby' => '', + //'mime_type' => '', + )); + //print_r($info); + + return $info ? $this->vfsinfo2stat($info) : false; + } + + /** + * This method is called in response to readdir(). + * + * It should return a string representing the next filename in the location opened by dir_opendir(). + * + * @return string + */ + function dir_readdir ( ) + { + error_log("oldvfs_stream_wrapper::dir_readdir($this->opened_dir_path)"); + + if (!is_array($this->opened_dir)) return false; + + $file = current($this->opened_dir); next($this->opened_dir); + + return $file ? $file['name'] : false; + } + + /** + * This method is called in response to rewinddir(). + * + * It should reset the output generated by dir_readdir(). i.e.: + * The next call to dir_readdir() should return the first entry in the location returned by dir_opendir(). + * + * @return boolean + */ + function dir_rewinddir ( ) + { + error_log("oldvfs_stream_wrapper::dir_rewinddir($this->opened_dir_path)"); + + if (!is_array($this->opened_dir)) return false; + + reset($this->opened_dir); + + return true; + } + + /** + * This method is called in response to closedir(). + * + * You should release any resources which were locked or allocated during the opening and use of the directory stream. + * + * @return boolean + */ + function dir_closedir ( ) + { + error_log("oldvfs_stream_wrapper::dir_closedir($this->opened_dir_path)"); + + if (!is_array($this->opened_dir)) return false; + + $this->opened_dir = $this->opened_dir_path = null; + + return true; + } + + /** + * Convert a vfs-file-info into a stat array + * + * @param array $info + * @return array + */ + function vfsinfo2stat($info) + { + $stat = array( + 'ino' => $info['file_id'], + 'name' => $info['name'], + 'mode' => $info['mime_type'] == 'Directory' ? 040700 : 0100600, + 'size' => $info['size'], + 'uid' => $info['owner_id'] > 0 ? $info['owner_id'] : 0, + 'gid' => $info['owner_id'] < 0 ? $info['owner_id'] : 0, + 'mtime' => strtotime($info['modified'] ? $info['modified'] : $info['created']), + 'ctime' => strtotime($info['created']), + 'nlink' => $info['mime_type'] == 'Directory' ? 2 : 1, + ); + //print_r($stat); + return $stat; + } +} + +stream_register_wrapper('oldvfs','oldvfs_stream_wrapper'); From 688dd5f46fe052ab7e7bdee06f0a480b7bd9d255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Manuel=20G=C3=B3mez=20Senovilla?= Date: Thu, 31 May 2007 14:49:26 +0000 Subject: [PATCH 06/30] Latest lang updates --- addressbook/setup/phpgw_es-es.lang | 5 +- addressbook/setup/phpgw_fi.lang | 16 +- addressbook/setup/phpgw_hi.lang | 5 + addressbook/setup/phpgw_pl.lang | 3 +- addressbook/setup/phpgw_pt-br.lang | 5 +- addressbook/setup/phpgw_sk.lang | 15 +- addressbook/setup/phpgw_zh-tw.lang | 4 +- admin/setup/phpgw_es-es.lang | 7 + admin/setup/phpgw_fi.lang | 44 +++--- admin/setup/phpgw_pl.lang | 14 +- admin/setup/phpgw_pt-br.lang | 7 + admin/setup/phpgw_sk.lang | 95 ++++++------ admin/setup/phpgw_sl.lang | 11 +- admin/setup/phpgw_zh-tw.lang | 7 + calendar/setup/phpgw_fi.lang | 7 +- calendar/setup/phpgw_sk.lang | 22 +-- calendar/setup/phpgw_zh-tw.lang | 4 +- etemplate/setup/phpgw_fi.lang | 25 +++- etemplate/setup/phpgw_pl.lang | 14 ++ filemanager/setup/phpgw_sk.lang | 47 +++--- importexport/setup/phpgw_fi.lang | 8 + importexport/setup/phpgw_fr.lang | 8 + importexport/setup/phpgw_pl.lang | 8 + importexport/setup/phpgw_sk.lang | 8 + infolog/setup/phpgw_fi.lang | 19 ++- infolog/setup/phpgw_pl.lang | 7 +- infolog/setup/phpgw_sk.lang | 154 ++++++++++---------- notifications/setup/phpgw_pl.lang | 3 + notifications/setup/phpgw_sk.lang | 2 +- phpgwapi/setup/phpgw_fi.lang | 1 + phpgwapi/setup/phpgw_pl.lang | 5 +- phpgwapi/setup/phpgw_pt-br.lang | 64 ++------ phpgwapi/setup/phpgw_sk.lang | 20 +-- phpgwapi/setup/phpgw_sl.lang | 26 ++-- phpgwapi/setup/phpgw_zh-tw.lang | 3 +- preferences/setup/phpgw_sk.lang | 34 ++--- resources/setup/phpgw_fi.lang | 5 +- resources/setup/phpgw_sk.lang | 28 ++-- setup/lang/phpgw_pl.lang | 226 +++++++++++++++++++++-------- setup/lang/phpgw_sk.lang | 4 + setup/lang/phpgw_sl.lang | 23 ++- 41 files changed, 629 insertions(+), 384 deletions(-) create mode 100644 addressbook/setup/phpgw_hi.lang create mode 100644 importexport/setup/phpgw_fi.lang create mode 100644 importexport/setup/phpgw_fr.lang create mode 100644 importexport/setup/phpgw_pl.lang create mode 100644 importexport/setup/phpgw_sk.lang create mode 100644 notifications/setup/phpgw_pl.lang diff --git a/addressbook/setup/phpgw_es-es.lang b/addressbook/setup/phpgw_es-es.lang index a14355021f..a4b3846cf5 100644 --- a/addressbook/setup/phpgw_es-es.lang +++ b/addressbook/setup/phpgw_es-es.lang @@ -16,6 +16,7 @@ add a contact to this organisation addressbook es-es A add a new contact addressbook es-es Aρadir un contacto nuevo add a new list addressbook es-es Aρadir una lista nueva add a single entry by passing the fields. addressbook es-es Aρadir una entrada simple pasando los campos +add business email of whole distribution list? addressbook es-es ΏAρadir el correo electrσnico de la empresa de toda la lista de distribuciσn? add custom field addressbook es-es Aρadir campo personalizado add to distribution list: addressbook es-es Aρadir a la lista de distribuciσn: added by synchronisation addressbook es-es Aρadido por sincronizaciσn @@ -167,6 +168,7 @@ home phone addressbook es-es Tel home state addressbook es-es Provincia de residencia home street addressbook es-es Domicilio personal home zip code addressbook es-es Cσdigo postal +how many contacts should non-admins be able to export (empty = no limit) admin es-es ΏCuαntos contactos deben los no administradores ser capaces de exportar (vacνo=sin lνmite)? icon addressbook es-es Icono if accounts are already in ldap admin es-es si las cuentas ya estαn en LDAP import addressbook es-es Importar @@ -195,6 +197,7 @@ link title for contacts show addressbook es-es T links addressbook es-es Enlaces list all categories addressbook es-es Lista de todas las categorνas list all customfields addressbook es-es Lista de todos los campos personalizados +list already exists! addressbook es-es ΅La lista ya existe! list created addressbook es-es Se ha creado la lista list creation failed, no rights! addressbook es-es Fallσ la creaciσn de lista. No tiene privilegios suficientes. load vcard addressbook es-es Cargar VCard @@ -289,7 +292,7 @@ translation addressbook es-es Traducci type addressbook es-es Tipo update a single entry by passing the fields. addressbook es-es Actualizar una ϊnica entrada pasando los campos upload or delete the photo addressbook es-es Copiar al servidor o borrar la foto -url to link telephone numbers to (use %1 for the number) admin es-es URL para vincular nϊmeros de telιfono (use %1 para el nϊmero) +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin es-es URL a la que enlazar los nϊmeros de telιfono (use %1 = nϊmero para llamar, %u = nombre de la cuenta, %t = telιfono de la cuenta) use an extra category tab? addressbook es-es ΏUsar una pestaρa extra para categorνas? use country list addressbook es-es Utilizar lista de paνses use setup for a full account-migration admin es-es Use la instalaciσn para una migraciσn completa de las cuentas diff --git a/addressbook/setup/phpgw_fi.lang b/addressbook/setup/phpgw_fi.lang index ca7100b833..c0f97a656c 100644 --- a/addressbook/setup/phpgw_fi.lang +++ b/addressbook/setup/phpgw_fi.lang @@ -16,6 +16,7 @@ add a contact to this organisation addressbook fi Lis add a new contact addressbook fi Lisδδ uusi yhteystieto add a new list addressbook fi Lisδδ uusi lista add a single entry by passing the fields. addressbook fi Lisδδ yksittδinen tietue antamalla kentδt. +add business email of whole distribution list? addressbook fi Lisδδ tyφsδhkφpostiosoite koko jakelulistalle add custom field addressbook fi Lisδδ oma kenttδ add to distribution list: addressbook fi Lisδδ jakelulista added by synchronisation addressbook fi lisδtty synckronoinnin yhteydessδ @@ -80,6 +81,7 @@ contact id addressbook fi Yhteystiedon ID contact repository admin fi Yhteystietojen varasto contact saved addressbook fi Kontakti tallennettu contact settings admin fi Yhteystiedot - asetukset +contacts and account contact-data to ldap admin fi yhteystiedot ja kδyttδjδtilien yhteystiedot LDAP:sta contacts to ldap admin fi yhteystiedot LDAP:sta contacts to ldap, account contact-data to sql admin fi Yhteystiedot LDAP:ssa, kδyttδjδtilien yhteysttiedot SQL:ssδ contains addressbook fi sisδltδδ @@ -166,6 +168,7 @@ home phone addressbook fi Puhelin home state addressbook fi Lδδni home street addressbook fi Katuosoite home zip code addressbook fi Postinumero +how many contacts should non-admins be able to export (empty = no limit) admin fi Kuinka monta yhteystietoa muut kuin pδδkδyttδjδt voivat viedδ kerralla (jδtδ tyhjδksi jollet halua rajoituksia) icon addressbook fi Kuvake if accounts are already in ldap admin fi jos kδyttδjδtili on jo LDAP:ssa import addressbook fi Tuonti @@ -182,7 +185,7 @@ in %1 days (%2) is %3's birthday. addressbook fi %1 p income addressbook fi Tulossa insufficent rights to delete this list! addressbook fi Puuttelliset oikeudet listan poistamiseksi! international addressbook fi Kansainvδlinen -label addressbook fi Label +label addressbook fi Nimikenttδ last modified addressbook fi Viimeksi muokattu last modified by addressbook fi viimeksi muokannut ldap context for contacts admin fi LDAP-konteksti @@ -194,6 +197,7 @@ link title for contacts show addressbook fi Linkit links addressbook fi Linkit list all categories addressbook fi Nδytδ kaikki kategoriat list all customfields addressbook fi Nδytδ kaikki omat kentδt +list already exists! addressbook fi Lista on jo olemassa list created addressbook fi Lista luotu list creation failed, no rights! addressbook fi Listan luonti epδonnistu, ei riittδvδsti oikeuksia! load vcard addressbook fi Lataa VCard @@ -215,6 +219,7 @@ name, address addressbook fi Nimi, osoite no vcard addressbook fi Ei VCard number addressbook fi Numero number of records to read (%1) addressbook fi Luettavien tietueiden mδδrδ (%1) +options for type admin fi Option muoto organisation addressbook fi Organisaatio organisations addressbook fi Organisaatiot organisations by departments addressbook fi Organisaatiot osastoittain @@ -232,6 +237,7 @@ please enter a name for that field ! addressbook fi Anna kent please select only one category addressbook fi Valitse kategoria postal common fi Postal pref addressbook fi etuliite +preferred phone addressbook fi ensisijainen puhelin prefix addressbook fi Etuliite public key addressbook fi Julkinen avain publish into groups: addressbook fi Julkaise ryhmissδ @@ -253,6 +259,7 @@ select all addressbook fi Valitse kaikki select an action or addressbook to move to addressbook fi Valitse toiminto tai osoitekirja siirrettδvδksi select migration type admin fi Valitse sulautus tapa select multiple contacts for a further action addressbook fi Suorita valituille yhteystiedoille seuraava toiminto +select phone number as prefered way of contact addressbook fi valitse puhelinnumero ensisijaiseksi yhteydenotto tavaksi yhteystiedolle select the type of conversion addressbook fi Valitse muunnoksen tyyppi select the type of conversion: addressbook fi Valitse muunnoksen tyyppi: select where you want to store / retrieve contacts admin fi Valitse minne varastoit / mistδ palautat yhteystiedot @@ -270,6 +277,7 @@ street common fi Katuosoite successfully imported %1 records into your addressbook. addressbook fi Tuotiin %1 tietuetta osoitekirjaan. suffix addressbook fi Jδlkiliite tel home addressbook fi Kotipuhelin +telephony integration admin fi Puhelinintegrointi test import (show importable records only in browser) addressbook fi Testaa tuontia (nδytδ tuotavat tietueet vain selaimessa) that field name has been used already ! addressbook fi Kentδn nimi on jo kδytφssδ! this person's first name was not in the address book. addressbook fi Etunimeδ ei ole osoitekirjassa. @@ -282,14 +290,20 @@ translation addressbook fi K type addressbook fi Muoto update a single entry by passing the fields. addressbook fi Pδivitδ yksittδistδ tietuetta antamalla kentδt. upload or delete the photo addressbook fi Lataa tai poista kuva +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin fi URL linkki puhelinnumeroon (kδytδ %1 = soitettava numero, %u = kδyttδjδn nimi, %t = kδyttδjδn puhelin) use an extra category tab? addressbook fi Kδytδ ylimδδrδistδ kategoria vδlilehteδ use country list addressbook fi Kδytδ maaluetteloa +used for links and for the own sorting of the list addressbook fi kδytδ linkeissδ ja omassa lajittelu listassa vcard common fi VCard vcards require a first name entry. addressbook fi VCard vaatii etunimen. vcards require a last name entry. addressbook fi VCard vaatii sukunimen. view linked infolog entries addressbook fi Nδytδ linkitetyt Infologin merkinnδt warning!! ldap is valid only if you are not using contacts for accounts storage! admin fi VAROITUS!! LDAP soveltuu vain jos sitδ ei kδytetδ kδyttδjδtunnusten tallentamiseen! warning: all contacts found will be deleted! addressbook fi VAROITUS: Kaikki lφytyneet osoitteet poistetaan! +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook fi Mitδ osoitteen muotoa osoitekirja kδyttδδ maista joiden osoitemuoto on tuntematon. Jos maan osoitemuoto on tiedossa, se kδyttδδ sitδ riippumatta asetuksesta. +which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook fi Mikδ osoitekirja on valittuna kun lisδtδδn yhteystietoja JA sinulla ei ole oikeuksia lisδtδ merkintφjδ nykyiseen kalenteriin. +which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook fi Mitδ merkistφkoodausta kδytetδδn CSV viennissδ. Jδrjestelmδn oletus on merkistφkoodaus joka mδδriteltiin asennuksen yhteydessδ. +which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook fi Mitkδ kentδt voidaan viedδ. Kaikki tarkoittaa jokaista kenttδδ jotka osoitekirjasta lφytyy, sisδltδen asiakastiedot. Liiketoiminta tai kotiosoite sisδltδvδt vain nimen, yrityksen ja valitut osoitekentδt. whole query addressbook fi koko kysely work phone addressbook fi Tyφpuhelin yes, for the next three days addressbook fi Kyllδ, seuraavan 3 pδivδn ajalta diff --git a/addressbook/setup/phpgw_hi.lang b/addressbook/setup/phpgw_hi.lang new file mode 100644 index 0000000000..8135bf5b2b --- /dev/null +++ b/addressbook/setup/phpgw_hi.lang @@ -0,0 +1,5 @@ +%1 added addressbook hi %1 ???? ??? +%1 contact(s) %2 addressbook hi %1 ??????? %2 +%1 contact(s) %2, %3 failed because of insufficent rights !!! addressbook hi %1 ??????? %2,%3 ????? ??????? ?? ????? ???? ????? +%1 fields in %2 other organisation member(s) changed addressbook hi %2 ?? %1 ??????? ?? ????? ????????? ?? ???? +%1 records imported addressbook hi %1 ???????? ?? ?????? ?? ??? diff --git a/addressbook/setup/phpgw_pl.lang b/addressbook/setup/phpgw_pl.lang index 799a3abfea..48b7eda1c0 100755 --- a/addressbook/setup/phpgw_pl.lang +++ b/addressbook/setup/phpgw_pl.lang @@ -167,6 +167,7 @@ home phone addressbook pl Telefon domowy home state addressbook pl Wojewdztwo home street addressbook pl Ulica home zip code addressbook pl Kod pocztowy +how many contacts should non-admins be able to export (empty = no limit) admin pl Jak duΏ± paczkκ kontaktσw mog± eksportowaζ nie-administratorzy (puste oznacza brak limitu) icon addressbook pl Ikonka if accounts are already in ldap admin pl je¶li konta s± juΏ w LDAPie import addressbook pl Importuj @@ -289,7 +290,7 @@ translation addressbook pl T type addressbook pl typ update a single entry by passing the fields. addressbook pl Aktualizuj pojedyρczy wpis poprzez podawanie warto¶ci pσl. upload or delete the photo addressbook pl Za³aduj lub usuρ zdjκcie -url to link telephone numbers to (use %1 for the number) admin pl Rodzaj odno¶nika URL dla numerσw telefonσw (uΏyj %1 jako numer) +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin pl Odno¶nik URL do numerσw telefonσw (uΏyj %1 zamiast numeru telefonu, %2 zamiast nazwy konta, %3 zamiast numeru telefonu konta) use an extra category tab? addressbook pl UΏywaζ specjalnej zak³adki kategorii? use country list addressbook pl UΏyj listy krajσw use setup for a full account-migration admin pl uΏyj (/setup) w celu pe³nej migracji kont diff --git a/addressbook/setup/phpgw_pt-br.lang b/addressbook/setup/phpgw_pt-br.lang index fb8058187d..af7e5a43f3 100644 --- a/addressbook/setup/phpgw_pt-br.lang +++ b/addressbook/setup/phpgw_pt-br.lang @@ -16,6 +16,7 @@ add a contact to this organisation addressbook pt-br Adicionar um contato para e add a new contact addressbook pt-br Adicionar um novo contato add a new list addressbook pt-br Adicionar uma nova lista add a single entry by passing the fields. addressbook pt-br Adicionar uma ϊnica entrada informando os campos. +add business email of whole distribution list? addressbook pt-br Adicionar e-mail comercial para uma lista de distribuiηγo inteira ? add custom field addressbook pt-br Adicionar campo personalizado add to distribution list: addressbook pt-br Adicionar a uma lista de distribuiηγo added by synchronisation addressbook pt-br adicionado por sincronizaηγo @@ -167,6 +168,7 @@ home phone addressbook pt-br Telefone residencial home state addressbook pt-br Estado home street addressbook pt-br Rua, Av, Trav., etc. home zip code addressbook pt-br CEP +how many contacts should non-admins be able to export (empty = no limit) admin pt-br Quantos contatos nγo-administradores sγo capazes de exportar (vazio = sem limite) icon addressbook pt-br Νcone if accounts are already in ldap admin pt-br se as contas jα estiverem em LDAP import addressbook pt-br Importar @@ -195,6 +197,7 @@ link title for contacts show addressbook pt-br T links addressbook pt-br Links list all categories addressbook pt-br Listar todas as categorias list all customfields addressbook pt-br Listas todos os campos personalizados +list already exists! addressbook pt-br Lista jα existe! list created addressbook pt-br Lista criada list creation failed, no rights! addressbook pt-br Criaηγo da lista falhou. Sem direitos suficientes! load vcard addressbook pt-br Carregar VCard @@ -289,7 +292,7 @@ translation addressbook pt-br Tradu type addressbook pt-br Tipo update a single entry by passing the fields. addressbook pt-br Atualizar uma ϊnica entrada informando os campos upload or delete the photo addressbook pt-br Carregar ou remover a foto -url to link telephone numbers to (use %1 for the number) admin pt-br URL para linkar nϊmeros de telefones (usar %1 para o nϊmero) +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin pt-br URL para linkar nϊmeros de telefones (use %1 = nϊmero a ser chamado, %u = nome da conta, %t = nϊmero do telefone) use an extra category tab? addressbook pt-br Usar uma tab extra para categoria ? use country list addressbook pt-br Usar lista de paνses use setup for a full account-migration admin pt-br usar setup para uma migraηγo de contas completa diff --git a/addressbook/setup/phpgw_sk.lang b/addressbook/setup/phpgw_sk.lang index 113ca61bf3..2006c57e0c 100644 --- a/addressbook/setup/phpgw_sk.lang +++ b/addressbook/setup/phpgw_sk.lang @@ -16,6 +16,7 @@ add a contact to this organisation addressbook sk Prida add a new contact addressbook sk Prida» novύ kontakt add a new list addressbook sk Prida» novύ zoznam add a single entry by passing the fields. addressbook sk Prida» zαznam pomocou zadania polν. +add business email of whole distribution list? addressbook sk Prida» Zamestnanie - Email celιho distribuθnιho zoznamu add custom field addressbook sk Prida» pouΎνvateµskϊ poloΎku add to distribution list: addressbook sk Prida» do distribuθnιho zoznamu: added by synchronisation addressbook sk Pridanι cez synchronizαciu @@ -32,7 +33,7 @@ addressbook menu addressbook sk Menu Adres addressbook preferences addressbook sk Predvoµby Adresαra addressbook the contact should be saved to addressbook sk Adresαr -tento kontakt uloΎi» do addressbook-fieldname addressbook sk Pole adresαra -addvcard addressbook sk Pridaj vizitku VCard +addvcard addressbook sk Prida» vizitku VCard advanced search addressbook sk Pokroθilι hµadanie all contacts addressbook sk VΉetky kontakty allow users to maintain their own account-data admin sk Povoli» pouΎνvateµom, aby spravovali ϊdaje svojich vlastnύch pouΎνvateµskύch ϊθtov @@ -73,13 +74,13 @@ company common sk Spolo company name addressbook sk Nαzov firmy configuration common sk Konfigurαcia contact common sk Kontakt -contact application admin sk Kontakty +contact application admin sk Aplikαcia kontaktov contact copied addressbook sk Kontakt bol skopνrovanύ contact deleted addressbook sk Kontakt bol odstrαnenύ contact id addressbook sk ID kontaktu contact repository admin sk Zdroj kontaktov contact saved addressbook sk Kontakt bol uloΎenύ -contact settings admin sk Nastavenia Kontaktov +contact settings admin sk Nastavenia kontaktu contacts and account contact-data to ldap admin sk kontakty a kontaktnι ϊdaje ϊθtu do LDAP contacts to ldap admin sk kontakty do LDAP contacts to ldap, account contact-data to sql admin sk kontakty do LDAP, kontaktnι ϊdaje ϊθtu do SQL @@ -131,7 +132,7 @@ existing links addressbook sk Existuj export addressbook sk Export export as csv addressbook sk Exportova» ako CSV export as vcard addressbook sk Exportova» ako vizitku VCard -export contacts addressbook sk Export kontaktov +export contacts addressbook sk Exportova» kontakty export file name addressbook sk Nαzov sϊboru pre export export from addressbook addressbook sk Export z Adresαra export selection addressbook sk Exportova» vύber @@ -167,10 +168,11 @@ home phone addressbook sk Domov - Telef home state addressbook sk Domov - ©tαt home street addressbook sk Domov - Ulica home zip code addressbook sk Domov - PSΘ +how many contacts should non-admins be able to export (empty = no limit) admin sk Koµko kontaktov mτΎe exportova» pouΎνvateµ, ktorύ nie je sprαvcom (prαzdne = bez obmedzenν) icon addressbook sk Ikona if accounts are already in ldap admin sk ak sϊ ϊθty uΎ v LDAP import addressbook sk Import -import contacts addressbook sk Importuj kontakty +import contacts addressbook sk Importova» kontakty import csv-file into addressbook addressbook sk Importovat CSV sϊbor do Adresαra import file addressbook sk Importuj sϊbor import from addressbook sk Import z @@ -195,6 +197,7 @@ link title for contacts show addressbook sk N links addressbook sk Odkazy list all categories addressbook sk Zoznam vΉetkύch kategσriν list all customfields addressbook sk Zobrazi» vΉetky pouΎνvateµskι poloΎky +list already exists! addressbook sk Zoznam uΎ existuje! list created addressbook sk Zoznam bol vytvorenύ list creation failed, no rights! addressbook sk Nepodarilo sa vytvori» zoznam, nemαte prαva! load vcard addressbook sk Nahra» vizitku VCard @@ -289,7 +292,7 @@ translation addressbook sk Preklad type addressbook sk Typ update a single entry by passing the fields. addressbook sk Aktualizova» jednotlivύ zαznam podµa zadanύch polν upload or delete the photo addressbook sk Nahra» alebo vymaza» tϊto fotku -url to link telephone numbers to (use %1 for the number) admin sk URL na vytvorenie odkazu na telefσnne θνsla (pouΎite %1 pre θνslo) +url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin sk URL adresa, na ktorϊ sa majϊ odkαza» telefσnne θνsla (pouΎite %1 = volanι θνslo, %u = nαzov ϊθtu, %t = telefσnne θνslo ϊθtu) use an extra category tab? addressbook sk PouΎi» extra kartu kategσrie? use country list addressbook sk PouΎi» zoznam krajνn use setup for a full account-migration admin sk Pre plnϊ migrαciu ϊθtov pouΎite Setup diff --git a/addressbook/setup/phpgw_zh-tw.lang b/addressbook/setup/phpgw_zh-tw.lang index 9ee6ff07c8..dce1637f56 100644 --- a/addressbook/setup/phpgw_zh-tw.lang +++ b/addressbook/setup/phpgw_zh-tw.lang @@ -95,6 +95,7 @@ csv-filename addressbook zh-tw CSVζ”ε custom addressbook zh-tw θ‡θ¨‚ custom fields addressbook zh-tw θ‡θ¨‚ζ¬„δ½ debug output in browser addressbook zh-tw εΎη€θ¦½ε™¨θΌΈε…¥ι―θ¤θ¨ζ― +default address format addressbook zh-tw ι θ¨­δ½ε€ζ ΌεΌ default addressbook for adding contacts addressbook zh-tw ζ–°εΆθ―絡人時η„ι θ¨­ι€θ¨ι„ default filter addressbook zh-tw ι θ¨­ι濾器 delete a single entry by passing the id. addressbook zh-tw εΎidε除一筆資料。 @@ -166,6 +167,7 @@ home phone addressbook zh-tw ι›»θ©± home state addressbook zh-tw η/εΈ‚ home street addressbook zh-tw ε°ε€ home zip code addressbook zh-tw 郵ιε€θ™ +how many contacts should non-admins be able to export (empty = no limit) admin zh-tw ιη®΅η†ε“΅ε―以ε―ε‡Ίη„θ―絡人數ι‡οΌη©Ίη™½θ΅¨η¤ΊδΈι™ε¶οΌ‰ icon addressbook zh-tw ε–η¤Ί if accounts are already in ldap admin zh-tw 如ζεΈ³θ™ε·²η¶“ε­ε¨ζ–Ό LDAP import addressbook zh-tw ε―ε…¥ @@ -288,7 +290,6 @@ translation addressbook zh-tw θ½‰ζ› type addressbook zh-tw ι΅ε‹ update a single entry by passing the fields. addressbook zh-tw εΎζ¬„δ½ζ›΄ζ–°δΈ€η­†θ³‡ζ–™γ€‚ upload or delete the photo addressbook zh-tw δΈε‚³ζ–ζ―ε除照片 -url to link telephone numbers to (use %1 for the number) admin zh-tw θ¦εΌ•η”¨ι›»θ©±θ™ηΆΌη„網ε€οΌδ½Ώη”¨ %1 來替代θ™ηΆΌοΌ‰ use an extra category tab? addressbook zh-tw 使用附ε ι΅ε¥ζ¨™η±¤οΌ use country list addressbook zh-tw 使用ε‹ε®¶ζΈ…ε–® use setup for a full account-migration admin zh-tw 使用安θ£η¨‹εΌδΎ†ε®ζ•΄θ½‰ζ›εΈ³θ™ @@ -300,6 +301,7 @@ view linked infolog entries addressbook zh-tw ζΆθ¦–ι€£ηµη„θ¨δΊ‹θ³‡ζ–™ warning!! ldap is valid only if you are not using contacts for accounts storage! admin zh-tw 注ζ„οΌοΌεζ‰η•¶ζ‚¨ζ²’ζ‰ε°‡θ―絡人δ½η‚ΊεΈ³θ™ε„²ε­ζ™‚LDAPζ‰ζƒη”ζ•οΌ warning: all contacts found will be deleted! addressbook zh-tw θ­¦ε‘οΌζ‰Ύε°η„所ζ‰θ―絡人都ζƒθΆ«ει™¤οΌ what should links to the addressbook display in other applications. empty values will be left out. you need to log in anew, if you change this setting! addressbook zh-tw ε¨ε…¶δ»–程εΌι€£ηµε°ι€θ¨ι„η„ι΅―η¤Ίζ–‡ε­—οΌη©Ίη™½ζƒθΆ«εΏ½η•¥οΌδ»»δ½•η„δΏ®ζ­£εΏ…ι ε¨ι‡ζ–°η™»ε…¥εΎζ‰ζƒε¥—η”¨οΌ +which address format should the addressbook use for countries it does not know the address format. if the address format of a country is known, it uses it independent of this setting. addressbook zh-tw ι€θ¨ι„ε¨δΈζΈ…ζ¥δ½ε€ζ ΌεΌη„ε‹ε®¶θ¦δ½Ώη”¨η„δ½ε€ζ ΌεΌοΌε¦‚ζ已經η¥ι“οΌε®ƒζƒδ½Ώη”¨η¨η«‹η„θ¨­ε®γ€‚ which addressbook should be selected when adding a contact and you have no add rights to the current addressbook. addressbook zh-tw ζ–°εΆθ―絡人時θ¦ιΈζ“‡ε“個ι€θ¨ι„οΌη›®ε‰η„ι€θ¨ι„您沒ζ‰ζ–°εΆζ¬ι™γ€‚ which charset should be used for the csv export. the system default is the charset of this egroupware installation. addressbook zh-tw CSV ζ ΌεΌζ”ζ΅εΈζ›δ½Ώη”¨η„ε­—ε…ƒη·¨ηΆΌοΌι θ¨­ζƒθ‡ε®‰θ£δΈ€θ‡΄γ€‚ which fields should be exported. all means every field stored in the addressbook incl. the custom fields. the business or home address only contains name, company and the selected address. addressbook zh-tw θ¦ε―ε‡Ίε“些欄δ½οΌε…¨ιƒ¨δ»£θ΅¨ε„²ε­ε¨ι€θ¨ι„η„ζ―一個欄δ½οΌε…ε«θ‡θ¨‚欄δ½οΌ›ε…¬εΈζ–δ½ε®¶δ½ε€εε…ε«ε§“εγ€ε…¬εΈθ‡ιΈζ“‡η„δ½ε€γ€‚ diff --git a/admin/setup/phpgw_es-es.lang b/admin/setup/phpgw_es-es.lang index 69f3baef54..9601184338 100644 --- a/admin/setup/phpgw_es-es.lang +++ b/admin/setup/phpgw_es-es.lang @@ -92,6 +92,8 @@ check ip address of all sessions admin es-es Comprobar la IP de todas las sesio check items to %1 to %2 for %3 admin es-es Comprobar elementos a %1 a %2 para %3 click to select a color admin es-es Pulse para seleccionar un color color admin es-es Color +cookie domain (default empty means use full domain name, for sitemgr eg. ".domain.com" allows to use the same cookie for egw.domain.com and www.domain.com) admin es-es Dominio de la cookie (vacνo significa usar el nombre del dominio completo, para el Administrador de sitios web, p. ej. "dominio.com" permite usar la misma cookie para egw.dominio.com y www.dominio.com) +cookie path (allows multiple egw sessions with different directories, has problemes with sitemgr!) admin es-es Ruta de la cookie (permite mϊltiples sesiones de egw con distintos directorios, pero ΅tiene problemas con el Administrador de sitios web!) country selection admin es-es Selecciσn de paνs create group admin es-es Crear grupo creates a new field admin es-es crea un campo nuevo @@ -144,6 +146,7 @@ do not delete the category and return back to the list admin es-es NO borrar la do you also want to delete all global subcategories ? admin es-es ΏDesea eliminar tambiιn todas las subcategorνas globales? do you want to delete all global subcategories ? admin es-es ΏDesea borrar todas las subcategorνas globales? do you want to move all global subcategories one level down ? admin es-es ΏDesea mover todas las subcategorνas globales un nivel hacia abajo? +document root (default) admin es-es Raνz de los documentos (Document root) (predeterminado) each value is a line like [=