Calendar can now store participants which are no accounts or contacts.

- as required by iCal/CalDAV/GroupDAV/SyncML
- this also fixes problems with LDAP contacts, which have non-numeric
  ids
- iCal code now converts to and from all participant types supported by
  eGroupWare: some types (eg. ressources) require that the clients keeps
  the new X-EGROUPWARE-UID attribute
- calendar UI allows to enter email addresses via the addressbook search
  box (dont type search, but direct add)
This commit is contained in:
Ralf Becker 2008-05-08 15:02:35 +00:00
parent 5d50d41004
commit cb9212e691
9 changed files with 271 additions and 151 deletions

View File

@ -7,7 +7,7 @@
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2004-7 by RalfBecker-At-outdoor-training.de * @copyright (c) 2004-7 by RalfBecker-At-outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
require_once(EGW_INCLUDE_ROOT.'/calendar/inc/class.socal.inc.php'); require_once(EGW_INCLUDE_ROOT.'/calendar/inc/class.socal.inc.php');
@ -128,7 +128,7 @@ class bocal
*/ */
var $resources; var $resources;
/** /**
* @internal * @internal
* @var array $cached_event here we do some caching to read single events only once * @var array $cached_event here we do some caching to read single events only once
*/ */
var $cached_event = array(); var $cached_event = array();
@ -156,7 +156,7 @@ class bocal
function bocal() function bocal()
{ {
if ($this->debug > 0) $this->debug_message('bocal::bocal() started',True,$param); if ($this->debug > 0) $this->debug_message('bocal::bocal() started',True,$param);
$this->so = new socal(); $this->so = new socal();
$this->datetime = $GLOBALS['egw']->datetime; $this->datetime = $GLOBALS['egw']->datetime;
@ -185,13 +185,49 @@ class bocal
$this->resources[$data['type']] = $data + array('app' => $app); $this->resources[$data['type']] = $data + array('app' => $app);
} }
} }
$this->resources['e'] = array(
'type' => 'e',
'info' => 'bocal::email_info',
'app' => 'email',
);
$GLOBALS['egw']->session->appsession('resources','calendar',$this->resources); $GLOBALS['egw']->session->appsession('resources','calendar',$this->resources);
} }
//echo "registered resources="; _debug_array($this->resources); //echo "registered resources="; _debug_array($this->resources);
$this->config = config::read('calendar'); $this->config = config::read('calendar');
} }
/**
* returns info about email addresses as participants
*
* @param int/array $ids single contact-id or array of id's
* @return array
*/
static function email_info($ids)
{
if (!$ids) return null;
$data = array();
foreach(!is_array($ids) ? array($ids) : $ids as $id)
{
$email = $id;
$name = '';
if (preg_match('/^(.*) *<([a-z0-9_.@-]{8,})>$/i',$email,$matches))
{
$name = $matches[1];
$email = $matches[2];
}
$data[] = array(
'res_id' => $id,
'email' => $email,
'rights' => EGW_ACL_READ_FOR_PARTICIPANTS,
'name' => $name,
);
}
//echo "<p>email_info(".print_r($ids,true).")="; _debug_array($data);
return $data;
}
/** /**
* Add group-members as participants with status 'G' * Add group-members as participants with status 'G'
* *
@ -244,14 +280,14 @@ class bocal
* show_rejected if set rejected invitation are shown only when true, otherwise it depends on the cal-pref or a running query * show_rejected if set rejected invitation are shown only when true, otherwise it depends on the cal-pref or a running query
* ignore_acl if set and true no check_perms for a general EGW_ACL_READ grants is performed * ignore_acl if set and true no check_perms for a general EGW_ACL_READ grants is performed
* enum_groups boolean if set and true, group-members will be added as participants with status 'G' * enum_groups boolean if set and true, group-members will be added as participants with status 'G'
* @return array of events or array with YYYYMMDD strings / array of events pairs (depending on $daywise param) * @return array of events or array with YYYYMMDD strings / array of events pairs (depending on $daywise param)
* or false if there are no read-grants from _any_ of the requested users * or false if there are no read-grants from _any_ of the requested users
*/ */
function &search($params) function &search($params)
{ {
$params_in = $params; $params_in = $params;
if (!isset($params['users']) || !$params['users'] || if (!isset($params['users']) || !$params['users'] ||
count($params['users']) == 1 && isset($params['users'][0]) && !$params['users'][0]) // null or '' casted to an array count($params['users']) == 1 && isset($params['users'][0]) && !$params['users'][0]) // null or '' casted to an array
{ {
// for a search use all account you have read grants from // for a search use all account you have read grants from
@ -288,7 +324,7 @@ class bocal
foreach($members as $member) foreach($members as $member)
{ {
// use only members which gave the user a read-grant // use only members which gave the user a read-grant
if (!in_array($member['account_id'],$users) && if (!in_array($member['account_id'],$users) &&
($params['ignore_acl'] || $this->check_perms(EGW_ACL_READ,0,$member['account_id']))) ($params['ignore_acl'] || $this->check_perms(EGW_ACL_READ,0,$member['account_id'])))
{ {
$users[] = $member['account_id']; $users[] = $member['account_id'];
@ -311,7 +347,7 @@ class bocal
} }
} }
} }
// if we have no grants from the given user(s), we directly return no events / an empty array, // if we have no grants from the given user(s), we directly return no events / an empty array,
// as calling the so-layer without users would give the events of all users (!) // as calling the so-layer without users would give the events of all users (!)
if (!count($users)) if (!count($users))
{ {
@ -340,7 +376,7 @@ class bocal
$users,$cat_id,$filter,$params['query'],$offset,(int)$params['num_rows'],$params['order'],$show_rejected); $users,$cat_id,$filter,$params['query'],$offset,(int)$params['num_rows'],$params['order'],$show_rejected);
$this->total = $this->so->total; $this->total = $this->so->total;
$this->db2data($events,isset($params['date_format']) ? $params['date_format'] : 'ts'); $this->db2data($events,isset($params['date_format']) ? $params['date_format'] : 'ts');
// socal::search() returns rejected group-invitations, as only the user not also the group is rejected // socal::search() returns rejected group-invitations, as only the user not also the group is rejected
// as we cant remove them efficiantly in SQL, we kick them out here, but only if just one user is displayed // as we cant remove them efficiantly in SQL, we kick them out here, but only if just one user is displayed
$remove_rejected_by_user = !$show_rejected && count($params['users']) == 1 ? $params['users'][0] : false; $remove_rejected_by_user = !$show_rejected && count($params['users']) == 1 ? $params['users'][0] : false;
@ -397,7 +433,7 @@ class bocal
if ($ymd != ($last = $this->date2string($e_end))) if ($ymd != ($last = $this->date2string($e_end)))
{ {
$daysEvents[$last][] =& $events[$k]; $daysEvents[$last][] =& $events[$k];
} }
} }
$events =& $daysEvents; $events =& $daysEvents;
if ($this->debug && ($this->debug > 2 || $this->debug == 'search')) if ($this->debug && ($this->debug > 2 || $this->debug == 'search'))
@ -430,7 +466,7 @@ class bocal
} }
return $events; return $events;
} }
/** /**
* Clears all non-private info from a privat event * Clears all non-private info from a privat event
* *
@ -452,7 +488,7 @@ class bocal
'non_blocking' => $event['non_blocking'], 'non_blocking' => $event['non_blocking'],
); );
} }
/** /**
* check and evtl. move the horizont (maximum date for unlimited recuring events) to a new date * check and evtl. move the horizont (maximum date for unlimited recuring events) to a new date
* *
@ -466,7 +502,7 @@ class bocal
$this->debug_message('bocal::check_move_horizont(%1) horizont=%2',true,$new_horizont,$this->config['horizont']); $this->debug_message('bocal::check_move_horizont(%1) horizont=%2',true,$new_horizont,$this->config['horizont']);
} }
$new_horizont = $this->date2ts($new_horizont,true); // now we are in server-time, where this function operates $new_horizont = $this->date2ts($new_horizont,true); // now we are in server-time, where this function operates
if ($new_horizont > time()+1000*DAY_s) // some user tries to "look" more then 1000 days in the future if ($new_horizont > time()+1000*DAY_s) // some user tries to "look" more then 1000 days in the future
{ {
if ($this->debug == 'check_move_horizont') $this->debug_message('bocal::check_move_horizont(%1) horizont=%2 new horizont more then 1000 days from now --> ignoring it',true,$new_horizont,$this->config['horizont']); if ($this->debug == 'check_move_horizont') $this->debug_message('bocal::check_move_horizont(%1) horizont=%2 new horizont more then 1000 days from now --> ignoring it',true,$new_horizont,$this->config['horizont']);
@ -500,7 +536,7 @@ class bocal
// update the horizont // update the horizont
$config =& CreateObject('phpgwapi.config','calendar'); $config =& CreateObject('phpgwapi.config','calendar');
$config->save_value('horizont',$this->config['horizont'],'calendar'); $config->save_value('horizont',$this->config['horizont'],'calendar');
if ($this->debug == 'check_move_horizont') $this->debug_message('bocal::check_move_horizont(%1) new horizont=%2, exiting',true,$new_horizont,$this->config['horizont']); if ($this->debug == 'check_move_horizont') $this->debug_message('bocal::check_move_horizont(%1) new horizont=%2, exiting',true,$new_horizont,$this->config['horizont']);
} }
@ -523,7 +559,7 @@ class bocal
$event['participants'] = $event_read['participants']; $event['participants'] = $event_read['participants'];
} }
if (!$start) $start = $event['start']; if (!$start) $start = $event['start'];
$events = array(); $events = array();
$this->insert_all_repetitions($event,$start,$this->date2ts($this->config['horizont'],true),$events,null); $this->insert_all_repetitions($event,$start,$this->date2ts($this->config['horizont'],true),$events,null);
@ -532,7 +568,7 @@ class bocal
$this->so->recurrence($event['id'],$this->date2ts($event['start'],true),$this->date2ts($event['end'],true),$event['participants']); $this->so->recurrence($event['id'],$this->date2ts($event['start'],true),$this->date2ts($event['end'],true),$event['participants']);
} }
} }
/** /**
* convert data read from the db, eg. convert server to user-time * convert data read from the db, eg. convert server to user-time
* *
@ -569,7 +605,7 @@ class bocal
} }
} }
} }
/** /**
* convert a date from server to user-time * convert a date from server to user-time
* *
@ -579,7 +615,7 @@ class bocal
function date2usertime($ts,$date_format='ts') function date2usertime($ts,$date_format='ts')
{ {
if (empty($ts)) return $ts; if (empty($ts)) return $ts;
switch ($date_format) switch ($date_format)
{ {
case 'ts': case 'ts':
@ -612,7 +648,7 @@ class bocal
if ($ignore_acl || is_array($ids) || ($return = $this->check_perms(EGW_ACL_READ,$ids,0,$date_format,$date))) if ($ignore_acl || is_array($ids) || ($return = $this->check_perms(EGW_ACL_READ,$ids,0,$date_format,$date)))
{ {
if (is_array($ids) || !isset($this->cached_event['id']) || $this->cached_event['id'] != $ids || if (is_array($ids) || !isset($this->cached_event['id']) || $this->cached_event['id'] != $ids ||
$this->cached_event_date_format != $date_format || $this->cached_event_date_format != $date_format ||
$this->cached_event['recur_type'] != MCAL_RECUR_NONE && !is_null($date) && (!$date || $this->cached_event['start'] < $date)) $this->cached_event['recur_type'] != MCAL_RECUR_NONE && !is_null($date) && (!$date || $this->cached_event['start'] < $date))
{ {
@ -621,7 +657,7 @@ class bocal
if ($events) if ($events)
{ {
$this->db2data($events,$date_format); $this->db2data($events,$date_format);
if (is_array($ids)) if (is_array($ids))
{ {
$return =& $events; $return =& $events;
@ -672,7 +708,7 @@ class bocal
$this->debug_message('bocal::insert_all_repitions(%1,%2,%3,&$event,%4)',true,$event,$start,$end,$recur_exceptions); $this->debug_message('bocal::insert_all_repitions(%1,%2,%3,&$event,%4)',true,$event,$start,$end,$recur_exceptions);
} }
$start_in = $start; $end_in = $end; $start_in = $start; $end_in = $end;
$start = $this->date2ts($start); $start = $this->date2ts($start);
$end = $this->date2ts($end); $end = $this->date2ts($end);
$event_start_ts = $this->date2ts($event['start']); $event_start_ts = $this->date2ts($event['start']);
@ -684,7 +720,7 @@ class bocal
} }
$id = $event['id']; $id = $event['id'];
$event_start_arr = $this->date2array($event['start']); $event_start_arr = $this->date2array($event['start']);
// to be able to calculate the repetitions as difference to the start-date, // to be able to calculate the repetitions as difference to the start-date,
// both need to be calculated without daylight saving: mktime(,,,,,,0) // both need to be calculated without daylight saving: mktime(,,,,,,0)
$event_start_daybegin_ts = adodb_mktime(0,0,0,$event_start_arr['month'],$event_start_arr['day'],$event_start_arr['year'],0); $event_start_daybegin_ts = adodb_mktime(0,0,0,$event_start_arr['month'],$event_start_arr['day'],$event_start_arr['year'],0);
@ -710,7 +746,7 @@ class bocal
$search_date_ymd = (int)$this->date2string($ts); $search_date_ymd = (int)$this->date2string($ts);
$have_exception = !is_null($recur_exceptions) && isset($recur_exceptions[$search_date_ymd]); $have_exception = !is_null($recur_exceptions) && isset($recur_exceptions[$search_date_ymd]);
if (!$have_exception) // no execption by an edited event => check the deleted ones if (!$have_exception) // no execption by an edited event => check the deleted ones
{ {
foreach((array)$event['recur_exception'] as $exception_ts) foreach((array)$event['recur_exception'] as $exception_ts)
@ -731,7 +767,7 @@ class bocal
$search_date_month = adodb_date('m',$ts); $search_date_month = adodb_date('m',$ts);
$search_date_day = adodb_date('d',$ts); $search_date_day = adodb_date('d',$ts);
$search_date_dow = adodb_date('w',$ts); $search_date_dow = adodb_date('w',$ts);
// to be able to calculate the repetitions as difference to the start-date, // to be able to calculate the repetitions as difference to the start-date,
// both need to be calculated without daylight saving: mktime(,,,,,,0) // both need to be calculated without daylight saving: mktime(,,,,,,0)
$search_beg_day = adodb_mktime(0,0,0,$search_date_month,$search_date_day,$search_date_year,0); $search_beg_day = adodb_mktime(0,0,0,$search_date_month,$search_date_day,$search_date_year,0);
@ -879,10 +915,32 @@ class bocal
function resource_info($uid) function resource_info($uid)
{ {
static $res_info_cache = array(); static $res_info_cache = array();
if (!isset($res_info_cache[$uid])) if (!isset($res_info_cache[$uid]))
{ {
list($res_info_cache[$uid]) = $this->resources[$uid{0}]['info'] ? ExecMethod($this->resources[$uid{0}]['info'],substr($uid,1)) : false; if (is_numeric($uid))
{
$info = array(
'res_id' => $uid,
'email' => $GLOBALS['egw']->accounts->id2name($uid,'account_email'),
'name' => trim($GLOBALS['egw']->accounts->id2name($uid,'account_firstname'). ' ' .
$GLOBALS['egw']->accounts->id2name($uid,'account_lastname')),
'type' => $GLOBALS['egw']->accounts->get_type($uid),
);
}
else
{
list($info) = $this->resources[$uid[0]]['info'] ? ExecMethod($this->resources[$uid[0]]['info'],substr($uid,1)) : false;
if ($info)
{
$info['type'] = $uid[0];
if (!$info['email'] && $info['responsible'])
{
$info['email'] = $GLOBALS['egw']->accounts->id2name($info['responsible'],'account_email');
}
}
}
$res_info_cache[$uid] = $info;
} }
if ($this->debug && ($this->debug > 2 || $this->debug == 'resource_info')) if ($this->debug && ($this->debug > 2 || $this->debug == 'resource_info'))
{ {
@ -938,7 +996,7 @@ class bocal
} }
$user = $GLOBALS['egw_info']['user']['account_id']; $user = $GLOBALS['egw_info']['user']['account_id'];
$grants = $this->grants[$owner]; $grants = $this->grants[$owner];
if (is_array($event) && $needed == EGW_ACL_READ) if (is_array($event) && $needed == EGW_ACL_READ)
{ {
// Check if the $user is one of the participants or has a read-grant from one of them // Check if the $user is one of the participants or has a read-grant from one of them
@ -946,7 +1004,7 @@ class bocal
// //
foreach($event['participants'] as $uid => $accept) foreach($event['participants'] as $uid => $accept)
{ {
if ($uid == $user || $uid < 0 && in_array($user,$GLOBALS['egw']->accounts->members($uid,true))) if ($uid == $user || $uid < 0 && in_array($user,$GLOBALS['egw']->accounts->members($uid,true)))
{ {
// if we are a participant, we have an implicite READ and PRIVAT grant // if we are a participant, we have an implicite READ and PRIVAT grant
$grants |= EGW_ACL_READ | EGW_ACL_PRIVATE; $grants |= EGW_ACL_READ | EGW_ACL_PRIVATE;
@ -956,14 +1014,14 @@ class bocal
{ {
// if we have a READ grant from a participant, we dont give an implicit privat grant too // if we have a READ grant from a participant, we dont give an implicit privat grant too
$grants |= EGW_ACL_READ; $grants |= EGW_ACL_READ;
// we cant break here, as we might be a participant too, and would miss the privat grant // we cant break here, as we might be a participant too, and would miss the privat grant
} }
elseif (!is_numeric($uid)) elseif (!is_numeric($uid))
{ {
// if we have a resource as participant // if we have a resource as participant
$resource = $this->resource_info($uid); $resource = $this->resource_info($uid);
$grants |= $resource['rights']; $grants |= $resource['rights'];
} }
} }
} }
@ -1105,10 +1163,10 @@ class bocal
else else
{ {
$date = $this->date2ts($date,False); $date = $this->date2ts($date,False);
// if timezone is requested, we dont need to convert to user-time // if timezone is requested, we dont need to convert to user-time
if (($tz_used = substr($format,-1)) == 'O' || $tz_used == 'Z') $server2user = false; if (($tz_used = substr($format,-1)) == 'O' || $tz_used == 'Z') $server2user = false;
if ($server2user && substr($format,-1) ) if ($server2user && substr($format,-1) )
{ {
$date += $this->tz_offset_s; $date += $this->tz_offset_s;
@ -1249,7 +1307,7 @@ class bocal
if ($display_day) if ($display_day)
{ {
$range = lang(adodb_date('l',$first['raw'])).($this->common_prefs['dateformat']{0} != 'd' ? ' ' : ', '); $range = lang(adodb_date('l',$first['raw'])).($this->common_prefs['dateformat'][0] != 'd' ? ' ' : ', ');
} }
for ($i = 0; $i < 5; $i += 2) for ($i = 0; $i < 5; $i += 2)
{ {
@ -1319,7 +1377,7 @@ class bocal
} }
return $range; return $range;
} }
/** /**
* Displays a timespan, eg. $both ? "10:00 - 13:00: 3h" (10:00 am - 1 pm: 3h) : "10:00 3h" (10:00 am 3h) * Displays a timespan, eg. $both ? "10:00 - 13:00: 3h" (10:00 am - 1 pm: 3h) : "10:00 3h" (10:00 am 3h)
* *
@ -1334,7 +1392,7 @@ class bocal
$duration = floor($duration/60).lang('h').($duration%60 ? $duration%60 : ''); $duration = floor($duration/60).lang('h').($duration%60 ? $duration%60 : '');
$timespan = $t = $GLOBALS['egw']->common->formattime(sprintf('%02d',$start_m/60),sprintf('%02d',$start_m%60)); $timespan = $t = $GLOBALS['egw']->common->formattime(sprintf('%02d',$start_m/60),sprintf('%02d',$start_m%60));
if ($both) // end-time too if ($both) // end-time too
{ {
$timespan .= ' - '.$GLOBALS['egw']->common->formattime(sprintf('%02d',$end_m/60),sprintf('%02d',$end_m%60)); $timespan .= ' - '.$GLOBALS['egw']->common->formattime(sprintf('%02d',$end_m/60),sprintf('%02d',$end_m%60));
@ -1357,14 +1415,18 @@ class bocal
function participant_name($id,$use_type=false) function participant_name($id,$use_type=false)
{ {
static $id2lid = array(); static $id2lid = array();
if ($use_type && $use_type != 'u') $id = $use_type.$id; if ($use_type && $use_type != 'u') $id = $use_type.$id;
if (!isset($id2lid[$id])) if (!isset($id2lid[$id]))
{ {
if (!is_numeric($id)) if (!is_numeric($id))
{ {
$id2lid[$id] = egw_link::title($this->resources[$id{0}]['app'],substr($id,1)); $id2lid[$id] = '#'.$id;
if (($info = $this->resource_info($id)))
{
$id2lid[$id] = $info['name'] ? $info['name'] : $info['email'];
}
} }
else else
{ {
@ -1507,12 +1569,12 @@ class bocal
return $users + $groups; // users first and then groups, both alphabeticaly return $users + $groups; // users first and then groups, both alphabeticaly
} }
/** /**
* Convert the recure-information of an event, into a human readable string * Convert the recure-information of an event, into a human readable string
* *
* @param array $event * @param array $event
* @return string * @return string
*/ */
function recure2string($event) function recure2string($event)
{ {
@ -1588,7 +1650,7 @@ class bocal
} }
$this->holidays->prepare_read_holidays($year); $this->holidays->prepare_read_holidays($year);
$this->cached_holidays[$year] = $this->holidays->read_holiday(); $this->cached_holidays[$year] = $this->holidays->read_holiday();
// search for birthdays // search for birthdays
if ($GLOBALS['egw_info']['server']['hide_birthdays'] != 'yes') if ($GLOBALS['egw_info']['server']['hide_birthdays'] != 'yes')
{ {
@ -1613,7 +1675,7 @@ class bocal
} }
} }
} }
// store holidays and birthdays in the session // store holidays and birthdays in the session
$this->cached_holidays = $GLOBALS['egw']->session->appsession('holidays','calendar',$this->cached_holidays); $this->cached_holidays = $GLOBALS['egw']->session->appsession('holidays','calendar',$this->cached_holidays);
} }
if ((int) $this->debug >= 2 || $this->debug == 'read_holidays') if ((int) $this->debug >= 2 || $this->debug == 'read_holidays')
@ -1622,10 +1684,10 @@ class bocal
} }
return $this->cached_holidays[$year]; return $this->cached_holidays[$year];
} }
/** /**
* get title for an event identified by $event * get title for an event identified by $event
* *
* Is called as hook to participate in the linking * Is called as hook to participate in the linking
* *
* @param int/array $entry int cal_id or array with event * @param int/array $entry int cal_id or array with event
@ -1661,7 +1723,7 @@ class bocal
} }
return $result; return $result;
} }
/** /**
* Hook called by link-class to include calendar in the appregistry of the linkage * Hook called by link-class to include calendar in the appregistry of the linkage
* *
@ -1682,7 +1744,7 @@ class bocal
'menuaction' => 'calendar.uiforms.edit', 'menuaction' => 'calendar.uiforms.edit',
), ),
'add_app' => 'link_app', 'add_app' => 'link_app',
'add_id' => 'link_id', 'add_id' => 'link_id',
'add_popup' => '750x400', 'add_popup' => '750x400',
); );
} }
@ -1744,7 +1806,7 @@ class bocal
$GLOBALS['egw']->preferences->save_repository(False,'default'); $GLOBALS['egw']->preferences->save_repository(False,'default');
} }
} }
/** /**
* Get the freebusy URL of a user * Get the freebusy URL of a user
* *
@ -1755,7 +1817,7 @@ class bocal
{ {
if (is_numeric($user)) $user = $GLOBALS['egw']->accounts->id2name($user); if (is_numeric($user)) $user = $GLOBALS['egw']->accounts->id2name($user);
return (!$GLOBALS['egw_info']['server']['webserver_url'] || $GLOBALS['egw_info']['server']['webserver_url']{0} == '/' ? return (!$GLOBALS['egw_info']['server']['webserver_url'] || $GLOBALS['egw_info']['server']['webserver_url'][0] == '/' ?
($_SERVER['HTTPS'] ? 'https://' : 'http://').$_SERVER['HTTP_HOST'] : ''). ($_SERVER['HTTPS'] ? 'https://' : 'http://').$_SERVER['HTTP_HOST'] : '').
$GLOBALS['egw_info']['server']['webserver_url'].'/calendar/freebusy.php?user='.urlencode($user). $GLOBALS['egw_info']['server']['webserver_url'].'/calendar/freebusy.php?user='.urlencode($user).
($pw ? '&password='.urlencode($pw) : ''); ($pw ? '&password='.urlencode($pw) : '');

View File

@ -155,7 +155,7 @@ class bocalupdate extends bocal
$users = array_unique($users); $users = array_unique($users);
} }
$users[] = $uid; $users[] = $uid;
if (in_array($uid{0},$types_with_quantity)) if (in_array($uid[0],$types_with_quantity))
{ {
$quantity[$uid] = max(1,(int) substr($status,2)); $quantity[$uid] = max(1,(int) substr($status,2));
} }
@ -188,19 +188,19 @@ class bocalupdate extends bocal
$common_parts = array_intersect($users,array_keys($overlap['participants'])); $common_parts = array_intersect($users,array_keys($overlap['participants']));
foreach($common_parts as $n => $uid) foreach($common_parts as $n => $uid)
{ {
if ($overlap['participants'][$uid]{0} == 'R') if ($overlap['participants'][$uid][0] == 'R')
{ {
unset($common_parts[$uid]); unset($common_parts[$uid]);
continue; continue;
} }
if (is_numeric($uid) || !in_array($uid{0},$types_with_quantity)) if (is_numeric($uid) || !in_array($uid[0],$types_with_quantity))
{ {
continue; // no quantity check: quantity allways 1 ==> conflict continue; // no quantity check: quantity allways 1 ==> conflict
} }
if (!isset($max_quantity[$uid])) if (!isset($max_quantity[$uid]))
{ {
$res_info = $this->resource_info($uid); $res_info = $this->resource_info($uid);
$max_quantity[$uid] = $res_info[$this->resources[$uid{0}]['max_quantity']]; $max_quantity[$uid] = $res_info[$this->resources[$uid[0]]['max_quantity']];
} }
$quantity[$uid] += max(1,(int) substr($overlap['participants'][$uid],2)); $quantity[$uid] += max(1,(int) substr($overlap['participants'][$uid],2));
if ($quantity[$uid] <= $max_quantity[$uid]) if ($quantity[$uid] <= $max_quantity[$uid])
@ -741,7 +741,7 @@ class bocalupdate extends bocal
*/ */
function check_status_perms($uid,$event) function check_status_perms($uid,$event)
{ {
if ($uid{0} == 'c') // for contact we use the owner of the event if ($uid[0] == 'c' || $uid['0'] == 'e') // for contact we use the owner of the event
{ {
if (!is_array($event) && !($event = $this->read($event))) return false; if (!is_array($event) && !($event = $this->read($event))) return false;
@ -774,7 +774,7 @@ class bocalupdate extends bocal
{ {
return false; return false;
} }
if (($Ok = $this->so->set_status($cal_id,is_numeric($uid)?'u':$uid{0},is_numeric($uid)?$uid:substr($uid,1),$status,$recur_date ? $this->date2ts($recur_date,true) : 0))) if (($Ok = $this->so->set_status($cal_id,is_numeric($uid)?'u':$uid[0],is_numeric($uid)?$uid:substr($uid,1),$status,$recur_date ? $this->date2ts($recur_date,true) : 0)))
{ {
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time()); $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time());
@ -850,7 +850,7 @@ class bocalupdate extends bocal
$eventStart_arr = $this->date2array($event['start']); // give this as 'date' to the link to pick the right recurrence for the participants state $eventStart_arr = $this->date2array($event['start']); // give this as 'date' to the link to pick the right recurrence for the participants state
$link = $GLOBALS['egw_info']['server']['webserver_url'].'/index.php?menuaction=calendar.uiforms.edit&cal_id='.$event['id'].'&date='.$eventStart_arr['full'].'&no_popup=1'; $link = $GLOBALS['egw_info']['server']['webserver_url'].'/index.php?menuaction=calendar.uiforms.edit&cal_id='.$event['id'].'&date='.$eventStart_arr['full'].'&no_popup=1';
// if url is only a path, try guessing the rest ;-) // if url is only a path, try guessing the rest ;-)
if ($link{0} == '/') if ($link[0] == '/')
{ {
$link = ($GLOBALS['egw_info']['server']['enforce_ssl'] || $_SERVER['HTTPS'] ? 'https://' : 'http://'). $link = ($GLOBALS['egw_info']['server']['enforce_ssl'] || $_SERVER['HTTPS'] ? 'https://' : 'http://').
($GLOBALS['egw_info']['server']['hostname'] ? $GLOBALS['egw_info']['server']['hostname'] : $_SERVER['HTTP_HOST']). ($GLOBALS['egw_info']['server']['hostname'] ? $GLOBALS['egw_info']['server']['hostname'] : $_SERVER['HTTP_HOST']).

View File

@ -191,14 +191,9 @@
case 'ATTENDEE': case 'ATTENDEE':
foreach((array)$event['participants'] as $uid => $status) foreach((array)$event['participants'] as $uid => $status)
{ {
// ToDo, this needs to deal with resources too!!! if (!($info = $this->resource_info($uid))) continue;
if (!is_numeric($uid)) continue;
$mailto = $GLOBALS['egw']->accounts->id2name($uid,'account_email');
$cn = trim($GLOBALS['egw']->accounts->id2name($uid,'account_firstname'). ' ' .
$GLOBALS['egw']->accounts->id2name($uid,'account_lastname'));
// RB: MAILTO href contains only the email-address, NO cn! // RB: MAILTO href contains only the email-address, NO cn!
$attributes['ATTENDEE'][] = $mailto ? 'MAILTO:'.$mailto : ''; $attributes['ATTENDEE'][] = $info['email'] ? 'MAILTO:'.$info['email'] : '';
// ROLE={CHAIR|REQ-PARTICIPANT|OPT-PARTICIPANT|NON-PARTICIPANT} NOT used by eGW atm. // ROLE={CHAIR|REQ-PARTICIPANT|OPT-PARTICIPANT|NON-PARTICIPANT} NOT used by eGW atm.
$role = $uid == $event['owner'] ? 'CHAIR' : 'REQ-PARTICIPANT'; $role = $uid == $event['owner'] ? 'CHAIR' : 'REQ-PARTICIPANT';
// RSVP={TRUE|FALSE} // resonse expected, not set in eGW => status=U // RSVP={TRUE|FALSE} // resonse expected, not set in eGW => status=U
@ -206,7 +201,7 @@
// PARTSTAT={NEEDS-ACTION|ACCEPTED|DECLINED|TENTATIVE|DELEGATED|COMPLETED|IN-PROGRESS} everything from delegated is NOT used by eGW atm. // PARTSTAT={NEEDS-ACTION|ACCEPTED|DECLINED|TENTATIVE|DELEGATED|COMPLETED|IN-PROGRESS} everything from delegated is NOT used by eGW atm.
$status = $this->status_egw2ical[$status]; $status = $this->status_egw2ical[$status];
// CUTYPE={INDIVIDUAL|GROUP|RESOURCE|ROOM|UNKNOWN} // CUTYPE={INDIVIDUAL|GROUP|RESOURCE|ROOM|UNKNOWN}
switch (is_numeric($uid) ? $GLOBALS['egw']->accounts->get_type($uid) : $uid{0}) switch ($info['type'])
{ {
case 'g': case 'g':
$cutype = 'GROUP'; $cutype = 'GROUP';
@ -214,21 +209,22 @@
case 'r': case 'r':
$cutype = 'RESOURCE'; $cutype = 'RESOURCE';
break; break;
case 'u': case 'u': // account
case 'c': // contact
case 'e': // email address
$cutype = 'INDIVIDUAL'; $cutype = 'INDIVIDUAL';
break; break;
default: default:
$cutype = 'UNKNOWN'; $cutype = 'UNKNOWN';
$cutype = 'INDIVIDUAL';
break; break;
}; };
$parameters['ATTENDEE'][] = array( $parameters['ATTENDEE'][] = array(
'CN' => $cn, 'CN' => $info['name'],
'ROLE' => $role, 'ROLE' => $role,
'PARTSTAT' => $status, 'PARTSTAT' => $status,
'CUTYPE' => $cutype, 'CUTYPE' => $cutype,
'RSVP' => $rsvp, 'RSVP' => $rsvp,
); )+($info['type'] != 'e' ? array('X-EGROUPWARE-UID' => $uid) : array());
} }
break; break;
@ -563,7 +559,7 @@
break; break;
case 'RRULE': case 'RRULE':
$recurence = $attributes['value']; $recurence = $attributes['value'];
$type = preg_match('/FREQ=([^;: ]+)/i',$recurence,$matches) ? $matches[1] : $recurence{0}; $type = preg_match('/FREQ=([^;: ]+)/i',$recurence,$matches) ? $matches[1] : $recurence[0];
// vCard 2.0 values for all types // vCard 2.0 values for all types
if (preg_match('/UNTIL=([0-9T]+)/',$recurence,$matches)) if (preg_match('/UNTIL=([0-9T]+)/',$recurence,$matches))
{ {
@ -768,28 +764,46 @@
} }
break; break;
case 'ATTENDEE': case 'ATTENDEE':
if (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$attributes['value'],$matches) && if (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$attributes['value'],$matches) ||
($uid = $GLOBALS['egw']->accounts->name2id($matches[1],'account_email'))) preg_match('/<([@.a-z0-9_-]+)>/i',$attributes['value'],$matches))
{
$email = $matches[1];
}
elseif(strpos($attributes['value'],'@') !== false)
{
$email = $attributes['value'];
}
if (($uid = $attributes['params']['X-EGROUPWARE-UID']) &&
($info = $this->resource_info($uid)) && $info['email'] == $email)
{ {
$event['participants'][$uid] = isset($attributes['params']['PARTSTAT']) ? // we use the (checked) X-EGROUPWARE-UID
}
/*elseif($attributes['params']['CUTYPE'] == 'RESOURCE')
{
}*/
elseif($attributes['value'] == 'Unknown')
{
$uid = $GLOBALS['egw_info']['user']['account_id'];
}
elseif (($uid = $GLOBALS['egw']->accounts->name2id($email,'account_email')))
{
// we use the account we found
}
elseif ((list($data) = ExecMethod2('addressbook.bocontacts.search',array(
'email' => $email,
'email_home' => $email,
),true,'','','',false,'OR')))
{
$uid = 'c'.$data['id'];
}
else
{
$uid = 'e'.($attributes['params']['CN'] ? $attributes['params']['CN'].' <'.$email.'>' : $email);
}
$event['participants'][$uid] = isset($attributes['params']['PARTSTAT']) ?
$this->status_ical2egw[strtoupper($attributes['params']['PARTSTAT'])] : $this->status_ical2egw[strtoupper($attributes['params']['PARTSTAT'])] :
($uid == $event['owner'] ? 'A' : 'U'); ($uid == $event['owner'] ? 'A' : 'U');
}
if (preg_match('/<([@.a-z0-9_-]+)>/i',$attributes['value'],$matches)) {
$uid = '';
$uid = $GLOBALS['egw']->accounts->name2id($matches[1],'account_email');
if(!empty($uid)) {
$event['participants'][$uid] = isset($attributes['params']['PARTSTAT']) ?
$this->status_ical2egw[strtoupper($attributes['params']['PARTSTAT'])] :
($uid == $event['owner'] ? 'A' : 'U');
}
}
if($attributes['value'] == 'Unknown') {
$event['participants'][$GLOBALS['egw_info']['user']['account_id']] = 'A';
}
break; break;
case 'ORGANIZER': // will be written direct to the event case 'ORGANIZER': // will be written direct to the event
if (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$attributes['value'],$matches) && if (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$attributes['value'],$matches) &&
@ -1195,7 +1209,7 @@
break; break;
case 'RRULE': case 'RRULE':
$recurence = $attributes['value']; $recurence = $attributes['value'];
$type = preg_match('/FREQ=([^;: ]+)/i',$recurence,$matches) ? $matches[1] : $recurence{0}; $type = preg_match('/FREQ=([^;: ]+)/i',$recurence,$matches) ? $matches[1] : $recurence[0];
// vCard 2.0 values for all types // vCard 2.0 values for all types
if (preg_match('/UNTIL=([0-9T]+)/',$recurence,$matches)) if (preg_match('/UNTIL=([0-9T]+)/',$recurence,$matches))
{ {

View File

@ -690,8 +690,8 @@ ORDER BY cal_user_type, cal_usre_id
* combines user_type and user_id into a single string or integer (for users) * combines user_type and user_id into a single string or integer (for users)
* *
* @param string $user_type 1-char type: 'u' = user, ... * @param string $user_type 1-char type: 'u' = user, ...
* @param int $user_id id * @param string|int $user_id id
* @return string/int combined id * @return string|int combined id
*/ */
function combine_user($user_type,$user_id) function combine_user($user_type,$user_id)
{ {
@ -705,9 +705,9 @@ ORDER BY cal_user_type, cal_usre_id
/** /**
* splits the combined user_type and user_id into a single values * splits the combined user_type and user_id into a single values
* *
* @param string $user_type 1-char type: 'u' = user, ... * @param string|int $uid
* @param int $user_id id * @param string &$user_type 1-char type: 'u' = user, ...
* @return string/int * @param string|int &$user_id id
*/ */
function split_user($uid,&$user_type,&$user_id) function split_user($uid,&$user_type,&$user_id)
{ {
@ -719,7 +719,7 @@ ORDER BY cal_user_type, cal_usre_id
else else
{ {
$user_type = $uid[0]; $user_type = $uid[0];
$user_id = (int) substr($uid,1); $user_id = substr($uid,1);
} }
} }

View File

@ -30,7 +30,7 @@ class uical
var $debug=false; var $debug=false;
/** /**
* instance of the bocal or bocalupdate class * instance of the bocal or bocalupdate class
* *
* @var bocalupdate * @var bocalupdate
*/ */
var $bo; var $bo;
@ -116,7 +116,7 @@ class uical
* @var string $view menuaction of the selected view * @var string $view menuaction of the selected view
*/ */
var $view_menuaction; var $view_menuaction;
/** /**
* @var int $first first day of the shown view * @var int $first first day of the shown view
*/ */
@ -162,11 +162,11 @@ class uical
$this->manage_states($set_states); $this->manage_states($set_states);
$GLOBALS['uical'] = &$this; // make us available for ExecMethod, else it creates a new instance $GLOBALS['uical'] = &$this; // make us available for ExecMethod, else it creates a new instance
// calendar does not work with hidden sidebox atm. // calendar does not work with hidden sidebox atm.
unset($GLOBALS['egw_info']['user']['preferences']['common']['auto_hide_sidebox']); unset($GLOBALS['egw_info']['user']['preferences']['common']['auto_hide_sidebox']);
} }
/** /**
* Checks and terminates (or returns for home) with a message if $this->owner include a user/resource we have no read-access to * Checks and terminates (or returns for home) with a message if $this->owner include a user/resource we have no read-access to
* *
@ -187,7 +187,7 @@ class uical
if (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS,0,$member)) if (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS,0,$member))
{ {
$no_access_group[$member] = $this->bo->participant_name($member); $no_access_group[$member] = $this->bo->participant_name($member);
} }
} }
} }
elseif (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS,0,$owner)) elseif (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS,0,$owner))
@ -198,7 +198,7 @@ class uical
if (count($no_access)) if (count($no_access))
{ {
$msg = '<p class="redItalic" align="center">'.lang('Access denied to the calendar of %1 !!!',implode(', ',$no_access))."</p>\n"; $msg = '<p class="redItalic" align="center">'.lang('Access denied to the calendar of %1 !!!',implode(', ',$no_access))."</p>\n";
if ($GLOBALS['egw_info']['flags']['currentapp'] == 'home') if ($GLOBALS['egw_info']['flags']['currentapp'] == 'home')
{ {
return $msg; return $msg;
@ -217,7 +217,7 @@ class uical
} }
return false; return false;
} }
/** /**
* show the egw-framework plus possible messages ($_GET['msg'] and $this->group_warning from check_owner_access) * show the egw-framework plus possible messages ($_GET['msg'] and $this->group_warning from check_owner_access)
*/ */
@ -225,7 +225,7 @@ class uical
{ {
$GLOBALS['egw_info']['flags']['include_xajax'] = true; $GLOBALS['egw_info']['flags']['include_xajax'] = true;
$GLOBALS['egw']->common->egw_header(); $GLOBALS['egw']->common->egw_header();
if ($_GET['msg']) echo '<p class="redItalic" align="center">'.html::htmlspecialchars($_GET['msg'])."</p>\n"; if ($_GET['msg']) echo '<p class="redItalic" align="center">'.html::htmlspecialchars($_GET['msg'])."</p>\n";
if ($this->group_warning) echo '<p class="redItalic" align="center">'.$this->group_warning."</p>\n"; if ($this->group_warning) echo '<p class="redItalic" align="center">'.$this->group_warning."</p>\n";
@ -282,11 +282,11 @@ class uical
} }
else // change only the owners of the given type else // change only the owners of the given type
{ {
$res_type = is_numeric($set_owners[0]) ? false : $set_owners[0]{0}; $res_type = is_numeric($set_owners[0]) ? false : $set_owners[0][0];
$owners = explode(',',$states['owner'] ? $states['owner'] : $default); $owners = explode(',',$states['owner'] ? $states['owner'] : $default);
foreach($owners as $key => $owner) foreach($owners as $key => $owner)
{ {
if (!$res_type && is_numeric($owner) || $res_type && $owner{0} == $res_type) if (!$res_type && is_numeric($owner) || $res_type && $owner[0] == $res_type)
{ {
unset($owners[$key]); unset($owners[$key]);
} }
@ -342,7 +342,7 @@ class uical
{ {
if ($this->cal_prefs['planner_start_with_group'] > 0) $this->cal_prefs['planner_start_with_group'] *= -1; // fix old 1.0 pref if ($this->cal_prefs['planner_start_with_group'] > 0) $this->cal_prefs['planner_start_with_group'] *= -1; // fix old 1.0 pref
if (!$states_session && !$_GET['menuaction']) $this->view = ''; // first call to calendar if (!$states_session && !$_GET['menuaction']) $this->view = ''; // first call to calendar
if ($func == 'planner' && $this->view != 'planner' && $this->owner == $this->user) if ($func == 'planner' && $this->view != 'planner' && $this->owner == $this->user)
{ {
@ -390,7 +390,7 @@ class uical
// icons for single user, multiple users or group(s) and resources // icons for single user, multiple users or group(s) and resources
foreach($event['participants'] as $uid => $status) foreach($event['participants'] as $uid => $status)
{ {
if(is_numeric($uid) || $uid{0} == 'c') if(is_numeric($uid) || !isset($this->bo->resources[$uid[0]]['icon']))
{ {
if (isset($icons['single']) || $GLOBALS['egw']->accounts->get_type($uid) == 'g') if (isset($icons['single']) || $GLOBALS['egw']->accounts->get_type($uid) == 'g')
{ {
@ -401,12 +401,12 @@ class uical
{ {
$icons['single'] = html::image('calendar','single'); $icons['single'] = html::image('calendar','single');
} }
} }
elseif(!isset($icons[$uid{0}]) && isset($this->bo->resources[$uid{0}]) && isset($this->bo->resources[$uid{0}]['icon'])) elseif(!isset($icons[$uid[0]]) && isset($this->bo->resources[$uid[0]]) && isset($this->bo->resources[$uid[0]]['icon']))
{ {
$icons[$uid{0}] = html::image($this->bo->resources[$uid{0}]['app'], $icons[$uid[0]] = html::image($this->bo->resources[$uid[0]]['app'],
($this->bo->resources[$uid{0}]['icon'] ? $this->bo->resources[$uid{0}]['icon'] : 'navbar'), ($this->bo->resources[$uid[0]]['icon'] ? $this->bo->resources[$uid[0]]['icon'] : 'navbar'),
lang($this->bo->resources[$uid{0}]['app']), lang($this->bo->resources[$uid[0]]['app']),
'width="16px" height="16px"'); 'width="16px" height="16px"');
} }
} }
@ -475,7 +475,7 @@ class uical
return html::a_href($content,'/index.php',$vars,' target="_blank" title="'.html::htmlspecialchars(lang('Add')). return html::a_href($content,'/index.php',$vars,' target="_blank" title="'.html::htmlspecialchars(lang('Add')).
'" onclick="'.$this->popup('this.href','this.target').'; return false;"'); '" onclick="'.$this->popup('this.href','this.target').'; return false;"');
} }
/** /**
* returns javascript to open a popup window: window.open(...) * returns javascript to open a popup window: window.open(...)
* *
@ -487,7 +487,7 @@ class uical
*/ */
function popup($link,$target='_blank',$width=750,$height=410,$Link_confirm_abort='',$Link_confirm_text='') function popup($link,$target='_blank',$width=750,$height=410,$Link_confirm_abort='',$Link_confirm_text='')
{ {
//Handle Exception for Calandar //Handle Exception for Calandar
if (($Link_confirm_abort) && ($Link_confirm_text)) if (($Link_confirm_abort) && ($Link_confirm_text))
{ {
$returnvalue = 'javascript:var check=confirm(\''.$Link_confirm_text.'\');'; $returnvalue = 'javascript:var check=confirm(\''.$Link_confirm_text.'\');';
@ -495,21 +495,21 @@ class uical
// open confirm =0kay // open confirm =0kay
$returnvalue .= 'egw_openWindowCentered2('.($link == 'this.href' ? $link : "'".$link."'").','. $returnvalue .= 'egw_openWindowCentered2('.($link == 'this.href' ? $link : "'".$link."'").','.
($target == 'this.target' ? $target : "'".$target."'").",$width,$height,'yes')"; ($target == 'this.target' ? $target : "'".$target."'").",$width,$height,'yes')";
$returnvalue .= '}'; $returnvalue .= '}';
//open confirm =Abort //open confirm =Abort
$returnvalue .=' else {'; $returnvalue .=' else {';
$returnvalue .= 'egw_openWindowCentered2('.($Link_confirm_abort == 'this.href' ? $Link_confirm_abort : "'".$Link_confirm_abort."'").','. $returnvalue .= 'egw_openWindowCentered2('.($Link_confirm_abort == 'this.href' ? $Link_confirm_abort : "'".$Link_confirm_abort."'").','.
($target == 'this.target' ? $target : "'".$target."'").",$width,$height,'yes')"; ($target == 'this.target' ? $target : "'".$target."'").",$width,$height,'yes')";
$returnvalue .= '}'; $returnvalue .= '}';
return $returnvalue; return $returnvalue;
} }
else { else {
return 'egw_openWindowCentered2('.($link == 'this.href' ? $link : "'".$link."'").','. return 'egw_openWindowCentered2('.($link == 'this.href' ? $link : "'".$link."'").','.
($target == 'this.target' ? $target : "'".$target."'").",$width,$height,'yes')"; ($target == 'this.target' ? $target : "'".$target."'").",$width,$height,'yes')";
} }
} }
@ -631,7 +631,7 @@ class uical
'week' => 'calendar.uiviews.week', 'week' => 'calendar.uiviews.week',
'month' => 'calendar.uiviews.month') as $view => $menuaction) 'month' => 'calendar.uiviews.month') as $view => $menuaction)
{ {
if ($this->view == 'planner' || $this->view == 'listview') if ($this->view == 'planner' || $this->view == 'listview')
{ {
switch($view) switch($view)
{ {
@ -743,12 +743,12 @@ function load_cal(url,id) {
)), )),
'target' => '_blank', 'target' => '_blank',
); );
} }
*/ */
$appname = 'calendar'; $appname = 'calendar';
$menu_title = lang('Calendar Menu'); $menu_title = lang('Calendar Menu');
display_sidebox($appname,$menu_title,$file); display_sidebox($appname,$menu_title,$file);
// resources menu hooks // resources menu hooks
foreach ($this->bo->resources as $resource) foreach ($this->bo->resources as $resource)
{ {

View File

@ -123,16 +123,16 @@ class uiforms extends uical
{ {
$participants[$uid] = $participant_types['u'][$uid] = $uid == $this->user ? 'A' : 'U'; $participants[$uid] = $participant_types['u'][$uid] = $uid == $this->user ? 'A' : 'U';
} }
elseif (is_array($this->bo->resources[$uid{0}])) elseif (is_array($this->bo->resources[$uid[0]]))
{ {
$res_data = $this->bo->resources[$uid{0}]; $res_data = $this->bo->resources[$uid[0]];
list($id,$quantity) = explode(':',substr($uid,1)); list($id,$quantity) = explode(':',substr($uid,1));
$participants[$uid] = $participant_types[$uid{0}][$id] = ($res_data['new_status'] ? ExecMethod($res_data['new_status'],$id) : 'U'). $participants[$uid] = $participant_types[$uid[0]][$id] = ($res_data['new_status'] ? ExecMethod($res_data['new_status'],$id) : 'U').
((int) $quantity > 1 ? (int)$quantity : ''); ((int) $quantity > 1 ? (int)$quantity : '');
// if new_status == 'x', resource is not bookable // if new_status == 'x', resource is not bookable
if(strpos($participant_types[$uid{0}][$id],'x') !== false) if(strpos($participant_types[$uid[0]][$id],'x') !== false)
{ {
unset($participant_types[$uid{0}][$id]); unset($participant_types[$uid[0]][$id]);
unset($participants[$uid]); unset($participants[$uid]);
} }
} }
@ -235,18 +235,40 @@ class uiforms extends uical
{ {
switch($key) switch($key)
{ {
case 'add':
if (!$content['participants']['account'] && !$content['participants']['resource'])
{
$msg = lang('You need to select an account, contact or resource first!');
}
break;
case 'delete': // handled in default case 'delete': // handled in default
case 'quantity': // handled in new_resource case 'quantity': // handled in new_resource
case 'cal_resources': case 'cal_resources':
break; break;
case 'add':
// email or rfc822 addresse (eg. "Ralf Becker <ralf@domain.com>") in the search field
// ToDo: get eTemplate to return that field
if (($email = $_POST['exec']['participants']['resource']['query']) &&
(preg_match('/^(.*<)?([a-z0-9_.@-]{8,})>?$/i',$email,$matches)))
{
// check if email belongs to account or contact --> prefer them over just emails
if (($data = $GLOBALS['egw']->accounts->name2id($matches[2],'account_email')))
{
$event['participants'][$data] = $event['participant_types']['u'][$data] = 'U';
}
elseif ((list($data) = ExecMethod2('addressbook.bocontacts.search',array(
'email' => $matches[2],
'email_home' => $matches[2],
),true,'','','',false,'OR')))
{
$event['participants']['c'.$data['id']] = $event['participant_types']['c'][$data['id']] = 'U';
}
else
{
$event['participants']['e'.$email] = $event['participant_types']['e'][$email] = 'U';
}
}
elseif (!$content['participants']['account'] && !$content['participants']['resource'])
{
$msg = lang('You need to select an account, contact or resource first!');
}
break;
case 'resource': case 'resource':
list($app,$id) = explode(':',$data); list($app,$id) = explode(':',$data);
foreach($this->bo->resources as $type => $data) if ($data['app'] == $app) break; foreach($this->bo->resources as $type => $data) if ($data['app'] == $app) break;
@ -288,7 +310,7 @@ class uiforms extends uical
else else
{ {
$id = substr($uid,1); $id = substr($uid,1);
$type = $uid{0}; $type = $uid[0];
} }
if ($data['old_status'] != $status) if ($data['old_status'] != $status)
{ {
@ -563,6 +585,7 @@ class uiforms extends uical
function custom_mail($event,$added) function custom_mail($event,$added)
{ {
$to = array(); $to = array();
foreach($event['participants'] as $uid => $status) foreach($event['participants'] as $uid => $status)
{ {
if ($status == 'R' || $uid == $this->user) continue; if ($status == 'R' || $uid == $this->user) continue;
@ -586,17 +609,9 @@ class uiforms extends uical
$to[] = $firstname.' '.$lastname.' <'.$email.'>'; $to[] = $firstname.' '.$lastname.' <'.$email.'>';
} }
} }
elseif ($uid{0} == 'c' ) elseif(($info = $this->bo->resource_info($uid)))
{ {
if (!is_object($GLOBALS['egw']->contacts)) $to[] = $info['email'];
{
require_once(EGW_API_INC.'/class.contacts.inc.php');
$GLOBALS['egw']->contacts = new contacts();
}
if (($contact = $GLOBALS['egw']->contacts->read(substr($uid,1))) && ($contact['email'] || $contact['email_home']))
{
$to[] = $contact['n_fn'].' <'.($contact['email']?$contact['email']:$contact['email_home']).'>';
}
} }
} }
list($subject,$body) = $this->bo->get_update_message($event,$added ? MSG_ADDED : MSG_MODIFIED); // update-message is in TZ of the user list($subject,$body) = $this->bo->get_update_message($event,$added ? MSG_ADDED : MSG_MODIFIED); // update-message is in TZ of the user
@ -767,16 +782,26 @@ class uiforms extends uical
$preserv['participants'][$row] = $content['participants'][$row] = array( $preserv['participants'][$row] = $content['participants'][$row] = array(
'app' => $name == 'accounts' ? ($GLOBALS['egw']->accounts->get_type($id) == 'g' ? 'Group' : 'User') : $name, 'app' => $name == 'accounts' ? ($GLOBALS['egw']->accounts->get_type($id) == 'g' ? 'Group' : 'User') : $name,
'uid' => $uid, 'uid' => $uid,
'status' => $status{0}, 'status' => $status[0],
'old_status' => $status{0}, 'old_status' => $status[0],
'quantity' => substr($status,1), 'quantity' => substr($status,1),
); );
$readonlys[$row.'[quantity]'] = $type == 'u' || !isset($this->bo->resources[$type]['max_quantity']); $readonlys[$row.'[quantity]'] = $type == 'u' || !isset($this->bo->resources[$type]['max_quantity']);
$readonlys[$row.'[status]'] = $readonlys[$row.'[status_recurrence]'] = !$this->bo->check_status_perms($uid,$event); $readonlys[$row.'[status]'] = $readonlys[$row.'[status_recurrence]'] = !$this->bo->check_status_perms($uid,$event);
$readonlys["delete[$uid]"] = !$this->bo->check_perms(EGW_ACL_EDIT,$event); $readonlys["delete[$uid]"] = !$this->bo->check_perms(EGW_ACL_EDIT,$event);
$content['participants'][$row++]['title'] = $name == 'accounts' ? // todo: make the participants available as links with email as title
$GLOBALS['egw']->common->grab_owner_name($id) : egw_link::title($name,$id); if ($name == 'accounts')
{
$content['participants'][$row++]['title'] = $GLOBALS['egw']->common->grab_owner_name($id);
}
elseif (($info = $this->bo->resource_info($uid)))
{
$content['participants'][$row++]['title'] = $info['name'] ? $info['name'] : $info['email'];
}
else
{
$content['participants'][$row++]['title'] = '#'.$uid;
}
// enumerate group-invitations, so people can accept/reject them // enumerate group-invitations, so people can accept/reject them
if ($name == 'accounts' && $GLOBALS['egw']->accounts->get_type($id) == 'g' && if ($name == 'accounts' && $GLOBALS['egw']->accounts->get_type($id) == 'g' &&
($members = $GLOBALS['egw']->accounts->members($id,true))) ($members = $GLOBALS['egw']->accounts->members($id,true)))

View File

@ -12,7 +12,7 @@
/* $Id$ */ /* $Id$ */
$setup_info['calendar']['name'] = 'calendar'; $setup_info['calendar']['name'] = 'calendar';
$setup_info['calendar']['version'] = '1.5.001'; $setup_info['calendar']['version'] = '1.5.002';
$setup_info['calendar']['app_order'] = 3; $setup_info['calendar']['app_order'] = 3;
$setup_info['calendar']['enable'] = 1; $setup_info['calendar']['enable'] = 1;
@ -80,3 +80,4 @@

View File

@ -67,10 +67,10 @@
), ),
'egw_cal_user' => array( 'egw_cal_user' => array(
'fd' => array( 'fd' => array(
'cal_id' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'), 'cal_id' => array('type' => 'int','precision' => '4','nullable' => False),
'cal_recur_date' => array('type' => 'int','precision' => '8','default' => '0'), 'cal_recur_date' => array('type' => 'int','precision' => '8','default' => '0'),
'cal_user_type' => array('type' => 'varchar','precision' => '1','nullable' => False,'default' => 'u'), 'cal_user_type' => array('type' => 'varchar','precision' => '1','nullable' => False,'default' => 'u'),
'cal_user_id' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0'), 'cal_user_id' => array('type' => 'varchar','precision' => '128','nullable' => False),
'cal_status' => array('type' => 'char','precision' => '1','default' => 'A'), 'cal_status' => array('type' => 'char','precision' => '1','default' => 'A'),
'cal_quantity' => array('type' => 'int','precision' => '4','default' => '1') 'cal_quantity' => array('type' => 'int','precision' => '4','default' => '1')
), ),

View File

@ -1599,4 +1599,22 @@
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.5.001'; return $GLOBALS['setup_info']['calendar']['currentver'] = '1.5.001';
} }
$test[] = '1.5.001';
function calendar_upgrade1_5_001()
{
$GLOBALS['egw_setup']->oProc->AlterColumn('egw_cal_user','cal_id',array(
'type' => 'int',
'precision' => '4',
'nullable' => False
));
$GLOBALS['egw_setup']->oProc->AlterColumn('egw_cal_user','cal_user_id',array(
'type' => 'varchar',
'precision' => '128',
'nullable' => False
));
return $GLOBALS['setup_info']['calendar']['currentver'] = '1.5.002';
}
?> ?>