2004-08-01 17:36:04 +02:00
< ? php
2007-03-09 12:39:47 +01:00
/**
2011-04-06 21:26:10 +02:00
* EGroupware - Calendar ' s buisness - object - access only
2007-03-09 12:39:47 +01:00
*
* @ link http :// www . egroupware . org
* @ package calendar
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de >
2009-07-15 22:35:56 +02:00
* @ author Joerg Lehrke < jlehrke @ noc . de >
2012-09-27 11:02:43 +02:00
* @ copyright ( c ) 2004 - 12 by RalfBecker - At - outdoor - training . de
2007-03-09 12:39:47 +01:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
2008-05-08 17:02:35 +02:00
* @ version $Id $
2007-03-09 12:39:47 +01:00
*/
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
if ( ! defined ( 'ACL_TYPE_IDENTIFER' )) // used to mark ACL-values for the debug_message methode
{
define ( 'ACL_TYPE_IDENTIFER' , '***ACL***' );
}
2010-02-19 18:10:15 +01:00
define ( 'HOUR_s' , 60 * 60 );
define ( 'DAY_s' , 24 * HOUR_s );
define ( 'WEEK_s' , 7 * DAY_s );
2007-06-19 19:04:58 +02:00
/**
* Gives read access to the calendar , but all events the user is not participating are private !
2009-08-04 19:14:16 +02:00
* Used by addressbook .
2007-06-19 19:04:58 +02:00
*/
define ( 'EGW_ACL_READ_FOR_PARTICIPANTS' , EGW_ACL_CUSTOM_1 );
2009-06-09 14:16:15 +02:00
define ( 'EGW_ACL_FREEBUSY' , EGW_ACL_CUSTOM_2 );
2009-11-19 19:56:04 +01:00
/**
* Allows to invite an other user ( if configured to be used ! )
*/
define ( 'EGW_ACL_INVITE' , EGW_ACL_CUSTOM_3 );
2007-06-19 19:04:58 +02:00
2008-06-12 09:03:06 +02:00
/**
* Required ( ! ) include , as we use the MCAL_ * constants , BEFORE instanciating ( and therefore autoloading ) the class
*/
require_once ( EGW_INCLUDE_ROOT . '/calendar/inc/class.calendar_so.inc.php' );
2004-08-01 17:36:04 +02:00
/**
2005-11-09 00:15:14 +01:00
* Class to access all calendar data
2004-08-01 17:36:04 +02:00
*
2005-11-09 00:15:14 +01:00
* For updating calendar data look at the bocalupdate class , which extends this class .
2004-08-01 17:36:04 +02:00
*
* The new UI , BO and SO classes have a strikt definition , in which time - zone they operate :
* UI only operates in user - time , so there have to be no conversation at all !!!
* BO ' s functions take and return user - time only ( ! ), they convert internaly everything to servertime , because
2005-11-09 00:15:14 +01:00
* SO operates only in server - time
2004-08-01 17:36:04 +02:00
*
* As this BO class deals with dates / times of several types and timezone , each variable should have a postfix
* appended , telling with type it is : _s = seconds , _su = secs in user - time , _ss = secs in server - time , _h = hours
*
* All new BO code ( should be true for eGW in general ) NEVER use any $_REQUEST ( $_POST or $_GET ) vars itself .
2005-11-09 00:15:14 +01:00
* Nor does it store the state of any UI - elements ( eg . cat - id selectbox ) . All this is the task of the UI class ( es ) !!!
2004-08-01 17:36:04 +02:00
*
2005-11-09 00:15:14 +01:00
* All permanent debug messages of the calendar - code should done via the debug - message method of this class ! ! !
2004-08-01 17:36:04 +02:00
*/
2008-06-07 19:45:33 +02:00
class calendar_bo
2004-08-01 17:36:04 +02:00
{
/**
* @ var int $debug name of method to debug or level of debug - messages :
* False = Off as higher as more messages you get ; - )
* 1 = function - calls incl . parameters to general functions like search , read , write , delete
* 2 = function - calls to exported helper - functions like check_perms
* 4 = function - calls to exported conversation - functions like date2ts , date2array , ...
* 5 = function - calls to private functions
*/
2004-11-07 15:38:00 +01:00
var $debug = false ;
2004-08-01 17:36:04 +02:00
2010-06-07 19:54:29 +02:00
/**
* @ var int $now timestamp in server - time
*/
var $now ;
2010-11-04 14:30:11 +01:00
2004-08-01 17:36:04 +02:00
/**
* @ var int $now_su timestamp of actual user - time
*/
var $now_su ;
/**
* @ var array $cal_prefs calendar - specific prefs
*/
var $cal_prefs ;
/**
* @ var array $common_prefs common preferences
*/
var $common_prefs ;
2013-05-10 12:54:36 +02:00
/**
* Custom fields read from the calendar config
*
* @ var array
*/
var $customfields = array ();
2004-08-01 17:36:04 +02:00
/**
* @ var int $user nummerical id of the current user - id
*/
var $user = 0 ;
/**
* @ var array $grants grants of the current user , array with user - id / ored - ACL - rights pairs
*/
var $grants = array ();
/**
* @ var array $verbose_status translated 1 - char status values to a verbose name , run through lang () by the constructor
*/
var $verbose_status = array (
2009-07-08 12:22:11 +02:00
'A' => 'Accepted' ,
'R' => 'Rejected' ,
'T' => 'Tentative' ,
'U' => 'No Response' ,
2010-02-17 14:29:28 +01:00
'D' => 'Delegated' ,
2009-07-08 12:22:11 +02:00
'G' => 'Group invitation' ,
2004-08-01 17:36:04 +02:00
);
2005-11-09 00:15:14 +01:00
/**
* @ var array recur_types translates MCAL recur - types to verbose labels
*/
var $recur_types = Array (
2009-11-25 21:16:41 +01:00
MCAL_RECUR_NONE => 'No recurrence' ,
2009-07-08 12:22:11 +02:00
MCAL_RECUR_DAILY => 'Daily' ,
MCAL_RECUR_WEEKLY => 'Weekly' ,
MCAL_RECUR_MONTHLY_WDAY => 'Monthly (by day)' ,
MCAL_RECUR_MONTHLY_MDAY => 'Monthly (by date)' ,
MCAL_RECUR_YEARLY => 'Yearly'
2005-11-09 00:15:14 +01:00
);
/**
* @ var array recur_days translates MCAL recur - days to verbose labels
*/
var $recur_days = array (
2009-07-08 12:22:11 +02:00
MCAL_M_MONDAY => 'Monday' ,
MCAL_M_TUESDAY => 'Tuesday' ,
MCAL_M_WEDNESDAY => 'Wednesday' ,
MCAL_M_THURSDAY => 'Thursday' ,
MCAL_M_FRIDAY => 'Friday' ,
MCAL_M_SATURDAY => 'Saturday' ,
MCAL_M_SUNDAY => 'Sunday' ,
2005-11-09 00:15:14 +01:00
);
2009-10-12 21:16:42 +02:00
/**
* Standard iCal attendee roles
*
* @ var array
*/
var $roles = array (
'REQ-PARTICIPANT' => 'Requested' ,
'CHAIR' => 'Chair' ,
'OPT-PARTICIPANT' => 'Optional' ,
'NON-PARTICIPANT' => 'None' ,
);
2005-11-09 00:15:14 +01:00
/**
2010-12-17 04:40:55 +01:00
* @ var array $resources registered scheduling resources of the calendar ( gets cached in the session for performance reasons )
2005-11-09 00:15:14 +01:00
*/
var $resources ;
/**
* @ var array $cached_event here we do some caching to read single events only once
*/
2008-05-10 22:10:45 +02:00
protected static $cached_event = array ();
protected static $cached_event_date_format = false ;
2009-07-15 22:35:56 +02:00
protected static $cached_event_date = 0 ;
2005-11-09 00:15:14 +01:00
/**
* @ var array $cached_holidays holidays plus birthdays ( gets cached in the session for performance reasons )
*/
var $cached_holidays ;
2011-04-05 17:32:20 +02:00
/**
* @ var boholiday
*/
var $holidays ;
2006-12-22 20:51:56 +01:00
/**
* Instance of the socal class
*
2009-03-20 08:55:22 +01:00
* @ var calendar_so
2006-12-22 20:51:56 +01:00
*/
var $so ;
/**
* Instance of the datetime class
*
* @ var egw_datetime
*/
var $datetime ;
2009-11-25 13:55:59 +01:00
/**
* Instance of the categories class
*
2009-12-03 19:20:07 +01:00
* @ var categories
2009-11-25 13:55:59 +01:00
*/
var $categories ;
2004-08-01 17:36:04 +02:00
2009-11-19 19:56:04 +01:00
/**
* Does a user require an extra invite grant , to be able to invite an other user , default no
*
2013-01-24 13:54:08 +01:00
* @ var string 'all' , 'groups' or null
2009-11-19 19:56:04 +01:00
*/
2013-01-24 13:54:08 +01:00
public $require_acl_invite = null ;
2009-11-19 19:56:04 +01:00
2010-12-10 12:03:35 +01:00
/**
* if the number of selected users for a view exeeds this number a view is consolidated ( 5 is set as default )
* @ var int
*/
public $calview_no_consolidate = 5 ;
2011-06-14 20:33:26 +02:00
/**
* Warnings to show in regular UI
*
* @ var array
*/
var $warnings = array ();
2004-08-01 17:36:04 +02:00
/**
* Constructor
*/
2008-06-07 19:45:33 +02:00
function __construct ()
2004-08-01 17:36:04 +02:00
{
2010-11-28 12:01:44 +01:00
if ( $this -> debug > 0 ) $this -> debug_message ( 'calendar_bo::bocal() started' , True , $param );
2008-05-08 17:02:35 +02:00
2008-06-07 19:45:33 +02:00
$this -> so = new calendar_so ();
2008-03-22 10:23:14 +01:00
$this -> datetime = $GLOBALS [ 'egw' ] -> datetime ;
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
$this -> common_prefs =& $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ];
$this -> cal_prefs =& $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'calendar' ];
2004-08-01 17:36:04 +02:00
2010-06-07 19:54:29 +02:00
$this -> now = time ();
$this -> now_su = egw_time :: server2user ( $this -> now , 'ts' );
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
$this -> user = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
$this -> grants = $GLOBALS [ 'egw' ] -> acl -> get_grants ( 'calendar' );
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
if ( ! is_array ( $this -> resources = $GLOBALS [ 'egw' ] -> session -> appsession ( 'resources' , 'calendar' )))
{
$this -> resources = array ();
foreach ( $GLOBALS [ 'egw' ] -> hooks -> process ( 'calendar_resources' ) as $app => $data )
{
if ( $data && $data [ 'type' ])
{
$this -> resources [ $data [ 'type' ]] = $data + array ( 'app' => $app );
}
}
2008-05-08 17:02:35 +02:00
$this -> resources [ 'e' ] = array (
2009-07-08 12:22:11 +02:00
'type' => 'e' ,
'info' => __CLASS__ . '::email_info' ,
'app' => 'email' ,
2008-05-08 17:02:35 +02:00
);
2011-09-07 16:47:51 +02:00
$this -> resources [ '' ] = array (
'type' => '' ,
'app' => 'home-accounts' ,
);
2005-11-09 00:15:14 +01:00
$GLOBALS [ 'egw' ] -> session -> appsession ( 'resources' , 'calendar' , $this -> resources );
2008-05-08 17:02:35 +02:00
}
2005-11-09 00:15:14 +01:00
//echo "registered resources="; _debug_array($this->resources);
2009-11-19 19:56:04 +01:00
$this -> config = config :: read ( 'calendar' ); // only used for horizont, regular calendar config is under phpgwapi
2010-12-10 12:03:35 +01:00
$this -> calview_no_consolidate = ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'calview_no_consolidate' ] ? $GLOBALS [ 'egw_info' ][ 'server' ][ 'calview_no_consolidate' ] : 5 );
2009-11-19 19:56:04 +01:00
$this -> require_acl_invite = $GLOBALS [ 'egw_info' ][ 'server' ][ 'require_acl_invite' ];
2009-12-01 11:24:55 +01:00
$this -> categories = new categories ( $this -> user , 'calendar' );
2013-05-10 12:54:36 +02:00
$this -> customfields = config :: get_customfields ( 'calendar' );
2004-08-01 17:36:04 +02:00
}
2008-05-08 17:02:35 +02:00
/**
* returns info about email addresses as participants
*
2009-08-04 19:14:16 +02:00
* @ param int | array $ids single contact - id or array of id ' s
2008-05-08 17:02:35 +02:00
* @ return array
*/
static function email_info ( $ids )
{
if ( ! $ids ) return null ;
$data = array ();
2011-04-28 19:55:44 +02:00
foreach (( array ) $ids as $id )
2008-05-08 17:02:35 +02:00
{
$email = $id ;
$name = '' ;
if ( preg_match ( '/^(.*) *<([a-z0-9_.@-]{8,})>$/i' , $email , $matches ))
{
$name = $matches [ 1 ];
$email = $matches [ 2 ];
}
$data [] = array (
2009-07-08 12:22:11 +02:00
'res_id' => $id ,
'email' => $email ,
'rights' => EGW_ACL_READ_FOR_PARTICIPANTS ,
'name' => $name ,
2008-05-08 17:02:35 +02:00
);
}
2011-04-28 19:55:44 +02:00
//error_log(__METHOD__.'('.array2string($ids).')='.array2string($data).' '.function_backtrace());
2008-05-08 17:02:35 +02:00
return $data ;
}
2005-11-23 15:21:20 +01:00
/**
* Add group - members as participants with status 'G'
*
* @ param array $event event - array
* @ return int number of added participants
*/
function enum_groups ( & $event )
{
$added = 0 ;
foreach ( $event [ 'participants' ] as $uid => $status )
{
if ( is_numeric ( $uid ) && $GLOBALS [ 'egw' ] -> accounts -> get_type ( $uid ) == 'g' &&
2009-07-08 12:29:06 +02:00
( $members = $GLOBALS [ 'egw' ] -> accounts -> member ( $uid )))
2005-11-23 15:21:20 +01:00
{
foreach ( $members as $member )
{
$member = $member [ 'account_id' ];
if ( ! isset ( $event [ 'participants' ][ $member ]))
{
$event [ 'participants' ][ $member ] = 'G' ;
++ $added ;
}
}
}
}
return $added ;
}
2004-08-01 17:36:04 +02:00
/**
2011-04-06 14:46:21 +02:00
* Resolve users to add memberships for users and members for groups
2004-08-01 17:36:04 +02:00
*
2011-04-06 14:46:21 +02:00
* @ param int | array $_users
* @ param boolean $no_enum_groups = true
* @ param boolean $ignore_acl = false
2011-08-16 12:20:40 +02:00
* @ param boolean $use_freebusy = true should freebusy rights are taken into account , default true , can be set to false eg . for a search
2011-04-06 14:46:21 +02:00
* @ return array of user - ids
2004-08-01 17:36:04 +02:00
*/
2011-08-16 12:20:40 +02:00
private function resolve_users ( $_users , $no_enum_groups = true , $ignore_acl = false , $use_freebusy = true )
2004-08-01 17:36:04 +02:00
{
2011-04-06 14:46:21 +02:00
if ( ! is_array ( $_users ))
2004-08-01 17:36:04 +02:00
{
2011-04-06 14:46:21 +02:00
$_users = $_users ? array ( $_users ) : array ();
2004-08-01 17:36:04 +02:00
}
// only query calendars of users, we have READ-grants from
$users = array ();
2011-04-06 14:46:21 +02:00
foreach ( $_users as $user )
2004-08-01 17:36:04 +02:00
{
2009-12-04 11:22:33 +01:00
$user = trim ( $user );
2011-08-16 12:20:40 +02:00
if ( $ignore_acl || $this -> check_perms ( EGW_ACL_READ | EGW_ACL_READ_FOR_PARTICIPANTS | ( $use_freebusy ? EGW_ACL_FREEBUSY : 0 ), 0 , $user ))
2004-08-01 17:36:04 +02:00
{
2006-10-11 20:52:39 +02:00
if ( $user && ! in_array ( $user , $users )) // already added?
2005-12-02 17:43:23 +01:00
{
$users [] = $user ;
}
2005-11-24 12:21:29 +01:00
}
elseif ( $GLOBALS [ 'egw' ] -> accounts -> get_type ( $user ) != 'g' )
{
continue ; // for non-groups (eg. users), we stop here if we have no read-rights
}
2006-03-05 11:26:03 +01:00
// the further code is only for real users
if ( ! is_numeric ( $user )) continue ;
2005-11-24 12:21:29 +01:00
// for groups we have to include the members
if ( $GLOBALS [ 'egw' ] -> accounts -> get_type ( $user ) == 'g' )
{
2013-08-15 18:02:32 +02:00
if ( $no_enum_groups ) continue ;
2009-11-19 19:56:04 +01:00
2005-11-24 12:21:29 +01:00
$members = $GLOBALS [ 'egw' ] -> accounts -> member ( $user );
if ( is_array ( $members ))
2005-11-09 00:15:14 +01:00
{
2005-11-24 12:21:29 +01:00
foreach ( $members as $member )
2005-11-09 00:15:14 +01:00
{
2005-11-24 12:21:29 +01:00
// use only members which gave the user a read-grant
2008-05-08 17:02:35 +02:00
if ( ! in_array ( $member [ 'account_id' ], $users ) &&
2011-08-16 12:20:40 +02:00
( $params [ 'ignore_acl' ] || $this -> check_perms ( EGW_ACL_READ | ( $use_freebusy ? EGW_ACL_FREEBUSY : 0 ), 0 , $member [ 'account_id' ])))
2005-11-09 00:15:14 +01:00
{
2005-11-24 12:21:29 +01:00
$users [] = $member [ 'account_id' ];
2005-11-09 00:15:14 +01:00
}
}
}
2005-11-24 12:21:29 +01:00
}
else // for users we have to include all the memberships, to get the group-events
{
$memberships = $GLOBALS [ 'egw' ] -> accounts -> membership ( $user );
if ( is_array ( $memberships ))
2005-11-23 15:21:20 +01:00
{
2005-11-24 12:21:29 +01:00
foreach ( $memberships as $group )
2005-11-23 15:21:20 +01:00
{
2005-11-24 12:21:29 +01:00
if ( ! in_array ( $group [ 'account_id' ], $users ))
2005-11-23 15:21:20 +01:00
{
2005-11-24 12:21:29 +01:00
$users [] = $group [ 'account_id' ];
2005-11-23 15:21:20 +01:00
}
}
}
2004-08-01 17:36:04 +02:00
}
}
2011-04-06 14:46:21 +02:00
return $users ;
}
/**
* Searches / lists calendar entries , including repeating ones
*
* @ param array $params array with the following keys
* start date startdate of the search / list , defaults to today
* end date enddate of the search / list , defaults to start + one day
* users int | array integer user - id or array of user - id ' s to use , defaults to the current user
* cat_id int | array category - id or array of cat - id ' s ( incl . all sub - categories ), default 0 = all
2012-09-26 16:30:47 +02:00
* filter string all ( not rejected ), accepted , unknown , tentative , rejected , hideprivate or everything ( incl . rejected , deleted )
2011-04-06 14:46:21 +02:00
* query string pattern so search for , if unset or empty all matching entries are returned ( no search )
* Please Note : a search never returns repeating events more then once AND does not honor start + end date !!!
* daywise boolean on True it returns an array with YYYYMMDD strings as keys and an array with events
* ( events spanning multiple days are returned each day again ( ! )) otherwise it returns one array with
* the events ( default ), not honored in a search ==> always returns an array of events !
* date_format string date - formats : 'ts' = timestamp ( default ), 'array' = array , or string with format for date
* offset boolean | int false ( default ) to return all entries or integer offset to return only a limited result
* enum_recuring boolean if true or not set ( default ) or daywise is set , each recurence of a recuring events is returned ,
* otherwise the original recuring event ( with the first start - + enddate ) is returned
* num_rows int number of entries to return , default or if 0 , max_entries from the prefs
* order column - names plus optional DESC | ASC separted by comma
* 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'
* cols string | array columns to select , if set an iterator will be returned
* append string to append to the query , eg . GROUP BY
* cfs array if set , query given custom fields or all for empty array , none are returned , if not set ( default )
2012-03-12 09:20:36 +01:00
* master_only boolean default false , true only take into account participants / status from master ( for AS )
2011-04-06 14:46:21 +02:00
* @ param string $sql_filter = null sql to be and ' ed into query ( fully quoted ), default none
* @ return iterator | array | boolean array of events or array with YYYYMMDD strings / array of events pairs ( depending on $daywise param )
* or false if there are no read - grants from _any_ of the requested users or iterator / recordset if cols are given
*/
function & search ( $params , $sql_filter = null )
{
$params_in = $params ;
$params [ 'sql_filter' ] = $sql_filter ; // dont allow to set it via UI or xmlrpc
// check if any resource wants to hook into
foreach ( $this -> resources as $app => $data )
{
if ( isset ( $data [ 'search_filter' ]))
{
$params = ExecMethod ( $data [ 'search_filter' ], $params );
}
}
if ( ! isset ( $params [ 'users' ]) || ! $params [ 'users' ] ||
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
$params [ 'users' ] = $params [ 'query' ] ? array_keys ( $this -> grants ) : $this -> user ;
}
// resolve users to add memberships for users and members for groups
2011-08-16 12:20:40 +02:00
// for search, do NOT use freebusy rights, as it would allow to probe the content of event entries
$users = $this -> resolve_users ( $params [ 'users' ], $params [ 'filter' ] == 'no-enum-groups' , $params [ 'ignore_acl' ], empty ( $params [ 'query' ]));
// supply so with private_grants, to not query them again from the database
if ( ! empty ( $params [ 'query' ]))
{
$params [ 'private_grants' ] = array ();
foreach ( $this -> grants as $user => $rights )
{
if ( $rights & EGW_ACL_PRIVATE ) $params [ 'private_grants' ][] = $user ;
}
}
2011-04-06 14:46:21 +02:00
2009-11-19 19:56:04 +01:00
// replace (by so not understood filter 'no-enum-groups' with 'default' filter
if ( $params [ 'filter' ] == 'no-enum-groups' )
{
$params [ 'filter' ] = 'default' ;
}
2008-05-08 17:02:35 +02:00
// if we have no grants from the given user(s), we directly return no events / an empty array,
2005-11-09 00:15:14 +01:00
// as calling the so-layer without users would give the events of all users (!)
if ( ! count ( $users ))
{
2006-03-05 11:26:03 +01:00
return false ;
2005-11-09 00:15:14 +01:00
}
if ( isset ( $params [ 'start' ])) $start = $this -> date2ts ( $params [ 'start' ]);
if ( isset ( $params [ 'end' ]))
{
$end = $this -> date2ts ( $params [ 'end' ]);
$this -> check_move_horizont ( $end );
}
2004-08-01 17:36:04 +02:00
$daywise = ! isset ( $params [ 'daywise' ]) ? False : !! $params [ 'daywise' ];
2011-04-05 17:32:20 +02:00
$params [ 'enum_recuring' ] = $enum_recuring = $daywise || ! isset ( $params [ 'enum_recuring' ]) || !! $params [ 'enum_recuring' ];
2004-08-01 17:36:04 +02:00
$cat_id = isset ( $params [ 'cat_id' ]) ? $params [ 'cat_id' ] : 0 ;
$filter = isset ( $params [ 'filter' ]) ? $params [ 'filter' ] : 'all' ;
2005-11-09 00:15:14 +01:00
$offset = isset ( $params [ 'offset' ]) && $params [ 'offset' ] !== false ? ( int ) $params [ 'offset' ] : false ;
2011-04-05 17:32:20 +02:00
// 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
2011-04-09 16:41:15 +02:00
$users_in = ( array ) $params_in [ 'users' ];
2012-09-26 16:30:47 +02:00
$remove_rejected_by_user = ! in_array ( $filter , array ( 'all' , 'rejected' , 'everything' )) &&
2011-04-09 16:41:15 +02:00
count ( $users_in ) == 1 && $users_in [ 0 ] > 0 ? $users_in [ 0 ] : null ;
//error_log(__METHOD__.'('.array2string($params_in).", $sql_filter) params[users]=".array2string($params['users']).' --> remove_rejected_by_user='.array2string($remove_rejected_by_user));
2011-04-05 17:32:20 +02:00
2004-08-01 17:36:04 +02:00
if ( $this -> debug && ( $this -> debug > 1 || $this -> debug == 'search' ))
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::search(%1) start=%2, end=%3, daywise=%4, cat_id=%5, filter=%6, query=%7, offset=%8, num_rows=%9, order=%10, sql_filter=%11)' ,
2009-09-29 21:58:51 +02:00
True , $params , $start , $end , $daywise , $cat_id , $filter , $params [ 'query' ], $offset ,( int ) $params [ 'num_rows' ], $params [ 'order' ], $params [ 'sql_filter' ]);
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
// date2ts(,true) converts to server time, db2data converts again to user-time
$events =& $this -> so -> search ( isset ( $start ) ? $this -> date2ts ( $start , true ) : null , isset ( $end ) ? $this -> date2ts ( $end , true ) : null ,
2011-04-05 17:32:20 +02:00
$users , $cat_id , $filter , $offset ,( int ) $params [ 'num_rows' ], $params , $remove_rejected_by_user );
2009-05-05 00:52:48 +02:00
if ( isset ( $params [ 'cols' ]))
{
return $events ;
}
2005-11-09 00:15:14 +01:00
$this -> total = $this -> so -> total ;
$this -> db2data ( $events , isset ( $params [ 'date_format' ]) ? $params [ 'date_format' ] : 'ts' );
2008-05-08 17:02:35 +02:00
2009-09-29 21:58:51 +02:00
//echo "<p align=right>remove_rejected_by_user=$remove_rejected_by_user, filter=$filter, params[users]=".print_r($param['users'])."</p>\n";
2005-11-09 00:15:14 +01:00
foreach ( $events as $id => $event )
2004-08-01 17:36:04 +02:00
{
2005-11-23 15:21:20 +01:00
if ( $params [ 'enum_groups' ] && $this -> enum_groups ( $event ))
{
$events [ $id ] = $event ;
}
2010-01-22 00:36:05 +01:00
if ( ! ( int ) $event [ 'id' ] && preg_match ( '/^([a-z_]+)([0-9]+)$/' , $event [ 'id' ], $matches ))
{
$is_private = self :: integration_get_private ( $matches [ 1 ], $matches [ 2 ], $event );
}
else
{
$is_private = ! $this -> check_perms ( EGW_ACL_READ , $event );
}
if ( $is_private || ( ! $event [ 'public' ] && $filter == 'hideprivate' ))
2004-08-01 17:36:04 +02:00
{
2011-03-01 00:43:34 +01:00
$this -> clear_private_infos ( $events [ $id ], $users );
2004-08-01 17:36:04 +02:00
}
}
2005-11-09 00:15:14 +01:00
if ( $daywise )
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'search' ))
{
$this -> debug_message ( 'socalendar::search daywise sorting from %1 to %2 of %3' , False , $start , $end , $events );
}
// create empty entries for each day in the reported time
2010-02-07 15:37:27 +01:00
for ( $ts = $start ; $ts <= $end ; $ts += DAY_s ) // good enough for array creation, but see while loop below.
2005-11-09 00:15:14 +01:00
{
$daysEvents [ $this -> date2string ( $ts )] = array ();
}
foreach ( $events as $k => $event )
{
$e_start = max ( $this -> date2ts ( $event [ 'start' ]), $start );
// $event['end']['raw']-1 to allow events to end on a full hour/day without the need to enter it as minute=59
$e_end = min ( $this -> date2ts ( $event [ 'end' ]) - 1 , $end );
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
// add event to each day in the reported time
2010-02-07 15:37:27 +01:00
$ts = $e_start ;
// $ts += DAY_s in a 'for' loop does not work for daylight savings in week view
// because the day is longer than DAY_s: Fullday events will be added twice.
while ( $ts <= $e_end )
2005-11-09 00:15:14 +01:00
{
$daysEvents [ $ymd = $this -> date2string ( $ts )][] =& $events [ $k ];
2010-02-07 15:37:27 +01:00
$ts = strtotime ( " +1 day " , $ts );
2005-11-09 00:15:14 +01:00
}
if ( $ymd != ( $last = $this -> date2string ( $e_end )))
{
$daysEvents [ $last ][] =& $events [ $k ];
2008-05-08 17:02:35 +02:00
}
2005-11-09 00:15:14 +01:00
}
$events =& $daysEvents ;
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'search' ))
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
$this -> debug_message ( 'socalendar::search daywise events=%1' , False , $events );
2004-08-01 17:36:04 +02:00
}
}
2005-11-09 00:15:14 +01:00
if ( $this -> debug && ( $this -> debug > 0 || $this -> debug == 'search' ))
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::search(%1)=%2' , True , $params , $events );
2005-11-09 00:15:14 +01:00
}
2011-04-05 17:32:20 +02:00
//error_log(__METHOD__."() returning ".count($events)." entries, total=$this->total ".function_backtrace());
2005-11-09 00:15:14 +01:00
return $events ;
}
2008-05-08 17:02:35 +02:00
2010-01-22 00:36:05 +01:00
/**
* Get integration data for a given app of a part ( value for a certain key ) of it
2010-01-29 22:42:54 +01:00
*
2010-01-22 00:36:05 +01:00
* @ param string $app
* @ param string $part
* @ return array
*/
static function integration_get_data ( $app , $part = null )
{
static $integration_data ;
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
if ( ! isset ( $integration_data ))
{
$integration_data = calendar_so :: get_integration_data ();
}
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
if ( ! isset ( $integration_data [ $app ])) return null ;
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
return $part ? $integration_data [ $app ][ $part ] : $integration_data [ $app ];
}
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
/**
* Get private attribute for an integration event
2010-01-29 22:42:54 +01:00
*
2010-01-22 00:36:05 +01:00
* Attribute 'is_private' is either a boolean value , eg . false to make all events of $app public
* or an ExecMethod callback with parameters $id , $event
2010-01-29 22:42:54 +01:00
*
2010-01-22 00:36:05 +01:00
* @ param string $app
* @ param int | string $id
* @ return string
*/
static function integration_get_private ( $app , $id , $event )
{
$app_data = self :: integration_get_data ( $app , 'is_private' );
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
// no method, fall back to link title
if ( is_null ( $app_data ))
{
$is_private = ! egw_link :: title ( $app , $id );
}
// boolean value to make all events of $app public (false) or private (true)
elseif ( is_bool ( $app_data ))
{
$is_private = $app_data ;
}
else
{
$is_private = ( bool ) ExecMethod2 ( $app_data , $id , $event );
}
2010-01-31 00:54:08 +01:00
//echo '<p>'.__METHOD__."($app,$id,) app_data=".array2string($app_data).' returning '.array2string($is_private)."</p>\n";
2010-01-22 00:36:05 +01:00
return $is_private ;
}
2005-11-09 00:15:14 +01:00
/**
* Clears all non - private info from a privat event
*
* That function only returns the infos allowed to be viewed by people without EGW_ACL_PRIVATE grants
*
* @ param array & $event
* @ param array $allowed_participants ids of the allowed participants , eg . the ones the search is over or eg . the owner of the calendar
*/
function clear_private_infos ( & $event , $allowed_participants = array ())
{
2012-07-25 10:07:10 +02:00
if ( $event == false ) return ;
2012-03-12 09:20:36 +01:00
if ( ! is_array ( $event [ 'participants' ])) error_log ( __METHOD__ . '(' . array2string ( $event ) . ', ' . array2string ( $allowed_participants ) . ') NO PARTICIPANTS ' . function_backtrace ());
2005-11-09 00:15:14 +01:00
$event = array (
2009-07-08 12:22:11 +02:00
'id' => $event [ 'id' ],
'start' => $event [ 'start' ],
'end' => $event [ 'end' ],
2009-11-26 11:27:46 +01:00
'tzid' => $event [ 'tzid' ],
2009-07-08 12:22:11 +02:00
'title' => lang ( 'private' ),
2010-05-14 10:35:16 +02:00
'modified' => $event [ 'modified' ],
'owner' => $event [ 'owner' ],
'recur_type' => MCAL_RECUR_NONE ,
'etag' => $event [ 'etag' ],
2009-07-08 12:22:11 +02:00
'participants' => array_intersect_key ( $event [ 'participants' ], array_flip ( $allowed_participants )),
'public' => 0 ,
'category' => $event [ 'category' ], // category is visible anyway, eg. by using planner by cat
'non_blocking' => $event [ 'non_blocking' ],
2012-09-27 11:02:43 +02:00
'caldav_name' => $event [ 'caldav_name' ],
2005-11-09 00:15:14 +01:00
);
}
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
/**
* check and evtl . move the horizont ( maximum date for unlimited recuring events ) to a new date
*
* @ internal automaticaly called by search
* @ param mixed $new_horizont time to set the horizont to ( user - time )
*/
function check_move_horizont ( $new_horizont )
{
if (( int ) $this -> debug >= 2 || $this -> debug == 'check_move_horizont' )
{
2011-06-14 20:33:26 +02:00
$this -> debug_message ( 'calendar_bo::check_move_horizont(%1) horizont=%2' , true , $new_horizont ,( int ) $this -> config [ 'horizont' ]);
2005-11-09 00:15:14 +01:00
}
$new_horizont = $this -> date2ts ( $new_horizont , true ); // now we are in server-time, where this function operates
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
if ( $new_horizont <= $this -> config [ 'horizont' ]) // no move necessary
{
2011-06-14 20:33:26 +02:00
if ( $this -> debug == 'check_move_horizont' ) $this -> debug_message ( 'calendar_bo::check_move_horizont(%1) horizont=%2 is bigger ==> nothing to do' , true , $new_horizont ,( int ) $this -> config [ 'horizont' ]);
2005-11-09 00:15:14 +01:00
return ;
2004-08-01 17:36:04 +02:00
}
2010-05-03 18:43:42 +02:00
if ( ! empty ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'calendar_horizont' ]))
{
$maxdays = abs ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'calendar_horizont' ]);
}
if ( empty ( $maxdays )) $maxdays = 1000 ; // old default
if ( $new_horizont > time () + $maxdays * DAY_s ) // some user tries to "look" more then the maximum number of days in the future
{
2011-06-14 20:33:26 +02:00
if ( $this -> debug == 'check_move_horizont' ) $this -> debug_message ( 'calendar_bo::check_move_horizont(%1) horizont=%2 new horizont more then %3 days from now --> ignoring it' , true , $new_horizont ,( int ) $this -> config [ 'horizont' ], $maxdays );
$this -> warnings [ 'horizont' ] = lang ( 'Requested date %1 outside allowed range of %2 days: recurring events obmitted!' , egw_time :: to ( $new_horizont , true ), $maxdays );
return ;
2010-05-03 18:43:42 +02:00
}
2005-11-09 00:15:14 +01:00
if ( $new_horizont < time () + 31 * DAY_s )
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
$new_horizont = time () + 31 * DAY_s ;
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
$old_horizont = $this -> config [ 'horizont' ];
$this -> config [ 'horizont' ] = $new_horizont ;
2010-02-22 11:02:33 +01:00
// create further recurrences for all recurring and not yet (at the old horizont) ended events
2005-11-09 00:15:14 +01:00
if (( $recuring = $this -> so -> unfinished_recuring ( $old_horizont )))
2004-08-01 17:36:04 +02:00
{
2011-06-14 20:33:26 +02:00
@ set_time_limit ( 0 ); // disable time-limit, in case it takes longer to calculate the recurrences
2005-11-09 00:15:14 +01:00
foreach ( $this -> read ( array_keys ( $recuring )) as $cal_id => $event )
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
if ( $this -> debug == 'check_move_horizont' )
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::check_move_horizont(%1): calling set_recurrences(%2,%3)' , true , $new_horizont , $event , $old_horizont );
2005-11-09 00:15:14 +01:00
}
// insert everything behind max(cal_start), which can be less then $old_horizont because of bugs in the past
2009-11-04 16:00:08 +01:00
$this -> set_recurrences ( $event , egw_time :: server2user ( $recuring [ $cal_id ] + 1 )); // set_recurences operates in user-time!
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
}
// update the horizont
2011-06-14 20:33:26 +02:00
config :: save_value ( 'horizont' , $this -> config [ 'horizont' ], 'calendar' );
2008-05-08 17:02:35 +02:00
2011-06-14 20:33:26 +02:00
if ( $this -> debug == 'check_move_horizont' ) $this -> debug_message ( 'calendar_bo::check_move_horizont(%1) new horizont=%2, exiting' , true , $new_horizont ,( int ) $this -> config [ 'horizont' ]);
2005-11-09 00:15:14 +01:00
}
/**
2010-02-22 11:02:33 +01:00
* set all recurrences for an event until the defined horizont $this -> config [ 'horizont' ]
2009-11-12 11:11:23 +01:00
*
* This methods operates in usertime , while $this -> config [ 'horizont' ] is in servertime !
2005-11-09 00:15:14 +01:00
*
* @ param array $event
2009-11-12 11:11:23 +01:00
* @ param mixed $start = 0 minimum start - time for new recurrences or ! $start = since the start of the event
2005-11-09 00:15:14 +01:00
*/
function set_recurrences ( $event , $start = 0 )
{
2010-01-29 22:42:54 +01:00
if ( $this -> debug && (( int ) $this -> debug >= 2 || $this -> debug == 'set_recurrences' || $this -> debug == 'check_move_horizont' ))
2005-11-09 00:15:14 +01:00
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::set_recurrences(%1,%2)' , true , $event , $start );
2005-11-09 00:15:14 +01:00
}
2010-01-29 22:42:54 +01:00
// check if the caller gave us enough information and if not read it from the DB
if ( ! isset ( $event [ 'participants' ]) || ! isset ( $event [ 'start' ]) || ! isset ( $event [ 'end' ]))
2006-03-09 22:40:35 +01:00
{
list (, $event_read ) = each ( $this -> so -> read ( $event [ 'id' ]));
2010-01-29 22:42:54 +01:00
if ( ! isset ( $event [ 'participants' ]))
{
$event [ 'participants' ] = $event_read [ 'participants' ];
}
if ( ! isset ( $event [ 'start' ]) || ! isset ( $event [ 'end' ]))
{
$event [ 'start' ] = $event_read [ 'start' ];
$event [ 'end' ] = $event_read [ 'end' ];
}
2006-03-09 22:40:35 +01:00
}
2005-11-09 00:15:14 +01:00
if ( ! $start ) $start = $event [ 'start' ];
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
$events = array ();
2009-11-12 11:11:23 +01:00
$this -> insert_all_recurrences ( $event , $start , $this -> date2usertime ( $this -> config [ 'horizont' ]), $events );
2011-05-03 19:33:50 +02:00
$limit = min ( $this -> config [ 'horizont' ], $event [ 'end' ]);
2013-08-15 14:23:38 +02:00
$exceptions = array ();
foreach (( array ) $event [ 'recur_exception' ] as $exception )
{
$exceptions [] = egw_time :: to ( $exception , true ); // true = date
}
//error_log(__METHOD__."(".array2string($event).", $start) exceptions=".array2string($exceptions));
2005-11-09 00:15:14 +01:00
foreach ( $events as $event )
{
2013-08-15 14:23:38 +02:00
$is_exception = in_array ( egw_time :: to ( $event [ 'start' ], true ), $exceptions );
2010-05-01 18:25:10 +02:00
$start = $this -> date2ts ( $event [ 'start' ], true );
if ( $event [ 'whole_day' ])
{
$time = new egw_time ( $event [ 'end' ], egw_time :: $user_timezone );
2013-06-07 13:53:45 +02:00
$time = $this -> so -> startOfDay ( $time );
2010-05-01 18:25:10 +02:00
$time -> setTime ( 23 , 59 , 59 );
$end = $this -> date2ts ( $time , true );
}
else
{
$end = $this -> date2ts ( $event [ 'end' ], true );
}
2013-08-15 14:23:38 +02:00
//error_log(__METHOD__."() start=".egw_time::to($start).", is_exception=".array2string($is_exception));
$this -> so -> recurrence ( $event [ 'id' ], $start , $end , $event [ 'participants' ], $is_exception );
2005-11-09 00:15:14 +01:00
}
}
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
/**
2010-11-04 14:30:11 +01:00
* Convert data read from the db , eg . convert server to user - time
*
* Also make sure all timestamps comming from DB as string are converted to integer ,
* to avoid misinterpretation by egw_time as Ymd string .
2005-11-09 00:15:14 +01:00
*
* @ param array & $events array of event - arrays ( reference )
* @ param $date_format = 'ts' date - formats : 'ts' = timestamp , 'server' = timestamp in server - time , 'array' = array or string with date - format
*/
function db2data ( & $events , $date_format = 'ts' )
{
2010-11-28 12:01:44 +01:00
if ( ! is_array ( $events )) echo " <p>calendar_bo::db2data( \$ events, $date_format ) \$ events is no array<br /> \n " . function_backtrace () . " </p> \n " ;
2010-04-23 15:52:45 +02:00
foreach ( $events as & $event )
2005-11-09 00:15:14 +01:00
{
2009-11-04 16:00:08 +01:00
// convert timezone id of event to tzid (iCal id like 'Europe/Berlin')
2012-03-22 15:02:06 +01:00
if ( empty ( $event [ 'tzid' ]) && ( ! $event [ 'tz_id' ] || ! ( $event [ 'tzid' ] = calendar_timezones :: id2tz ( $event [ 'tz_id' ]))))
2009-11-04 16:00:08 +01:00
{
$event [ 'tzid' ] = egw_time :: $server_timezone -> getName ();
}
2010-11-04 14:30:11 +01:00
// database returns timestamps as string, convert them to integer
// to avoid misinterpretation by egw_time as Ymd string
// (this will fail on 32bit systems for times > 2038!)
$event [ 'start' ] = ( int ) $event [ 'start' ]; // this is for isWholeDay(), which also calls egw_time
$event [ 'end' ] = ( int ) $event [ 'end' ];
2010-12-21 03:45:40 +01:00
$event [ 'whole_day' ] = self :: isWholeDay ( $event );
2010-04-23 15:52:45 +02:00
if ( $event [ 'whole_day' ] && $date_format != 'server' )
2010-04-23 08:15:18 +02:00
{
// Adjust dates to user TZ
2010-11-04 14:30:11 +01:00
$time = new egw_time (( int ) $event [ 'start' ], egw_time :: $server_timezone );
2010-04-23 08:15:18 +02:00
$time =& $this -> so -> startOfDay ( $time , $event [ 'tzid' ]);
$event [ 'start' ] = egw_time :: to ( $time , $date_format );
2010-11-04 14:30:11 +01:00
$time = new egw_time (( int ) $event [ 'end' ], egw_time :: $server_timezone );
2010-04-23 08:15:18 +02:00
$time =& $this -> so -> startOfDay ( $time , $event [ 'tzid' ]);
$time -> setTime ( 23 , 59 , 59 );
$event [ 'end' ] = egw_time :: to ( $time , $date_format );
2010-05-06 21:16:43 +02:00
if ( ! empty ( $event [ 'recurrence' ]))
{
2010-11-04 14:30:11 +01:00
$time = new egw_time (( int ) $event [ 'recurrence' ], egw_time :: $server_timezone );
2010-05-06 21:16:43 +02:00
$time =& $this -> so -> startOfDay ( $time , $event [ 'tzid' ]);
$event [ 'recurrence' ] = egw_time :: to ( $time , $date_format );
}
2010-05-03 18:43:42 +02:00
if ( ! empty ( $event [ 'recur_enddate' ]))
{
2010-11-04 14:30:11 +01:00
$time = new egw_time (( int ) $event [ 'recur_enddate' ], egw_time :: $server_timezone );
2010-05-03 18:43:42 +02:00
$time =& $this -> so -> startOfDay ( $time , $event [ 'tzid' ]);
$time -> setTime ( 23 , 59 , 59 );
$event [ 'recur_enddate' ] = egw_time :: to ( $time , $date_format );
}
2012-09-25 13:54:41 +02:00
$timestamps = array ( 'modified' , 'created' );
2010-04-23 08:15:18 +02:00
}
else
{
2012-09-25 13:54:41 +02:00
$timestamps = array ( 'start' , 'end' , 'modified' , 'created' , 'recur_enddate' , 'recurrence' );
2010-04-23 08:15:18 +02:00
}
2005-11-09 00:15:14 +01:00
// we convert here from the server-time timestamps to user-time and (optional) to a different date-format!
2010-04-23 08:15:18 +02:00
foreach ( $timestamps as $ts )
2004-08-01 17:36:04 +02:00
{
2010-04-23 08:15:18 +02:00
if ( ! empty ( $event [ $ts ]))
{
2010-11-04 14:30:11 +01:00
$event [ $ts ] = $this -> date2usertime (( int ) $event [ $ts ], $date_format );
2010-04-23 08:15:18 +02:00
}
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
// same with the recur exceptions
if ( isset ( $event [ 'recur_exception' ]) && is_array ( $event [ 'recur_exception' ]))
2004-08-01 17:36:04 +02:00
{
2010-02-22 11:02:33 +01:00
foreach ( $event [ 'recur_exception' ] as & $date )
2004-08-01 17:36:04 +02:00
{
2010-04-23 08:15:18 +02:00
if ( $event [ 'whole_day' ] && $date_format != 'server' )
{
// Adjust dates to user TZ
2010-11-04 14:30:11 +01:00
$time = new egw_time (( int ) $date , egw_time :: $server_timezone );
2010-04-23 08:15:18 +02:00
$time =& $this -> so -> startOfDay ( $time , $event [ 'tzid' ]);
$date = egw_time :: to ( $time , $date_format );
}
else
{
2010-11-04 14:30:11 +01:00
$date = $this -> date2usertime (( int ) $date , $date_format );
2010-04-23 08:15:18 +02:00
}
2004-08-01 17:36:04 +02:00
}
}
2005-11-09 00:15:14 +01:00
// same with the alarms
if ( isset ( $event [ 'alarm' ]) && is_array ( $event [ 'alarm' ]))
2004-08-01 17:36:04 +02:00
{
2010-02-22 11:02:33 +01:00
foreach ( $event [ 'alarm' ] as & $alarm )
2005-11-09 00:15:14 +01:00
{
2010-11-04 14:30:11 +01:00
$alarm [ 'time' ] = $this -> date2usertime (( int ) $alarm [ 'time' ], $date_format );
2005-11-09 00:15:14 +01:00
}
2004-08-01 17:36:04 +02:00
}
}
2005-11-09 00:15:14 +01:00
}
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
/**
* convert a date from server to user - time
*
2009-11-04 22:16:08 +01:00
* @ param int $ts timestamp in server - time
2009-08-04 19:14:16 +02:00
* @ param string $date_format = 'ts' date - formats : 'ts' = timestamp , 'server' = timestamp in server - time , 'array' = array or string with date - format
2009-11-04 16:00:08 +01:00
* @ return mixed depending of $date_format
2005-11-09 00:15:14 +01:00
*/
function date2usertime ( $ts , $date_format = 'ts' )
{
2009-10-07 15:29:06 +02:00
if ( empty ( $ts ) || $date_format == 'server' ) return $ts ;
2008-05-08 17:02:35 +02:00
2009-10-07 15:29:06 +02:00
return egw_time :: server2user ( $ts , $date_format );
2004-08-01 17:36:04 +02:00
}
/**
* Reads a calendar - entry
*
2009-08-04 19:14:16 +02:00
* @ param int | array | string $ids id or array of id ' s of the entries to read , or string with a single uid
2005-11-09 00:15:14 +01:00
* @ param mixed $date = null date to specify a single event of a series
* @ param boolean $ignore_acl should we ignore the acl , default False for a single id , true for multiple id ' s
* @ param string $date_format = 'ts' date - formats : 'ts' = timestamp , 'server' = timestamp in servertime , 'array' = array , or string with date - format
2010-12-19 00:58:11 +01:00
* @ param array | int $clear_privat_infos_users = null if not null , return events with EGW_ACL_FREEBUSY too ,
2010-12-02 22:50:22 +01:00
* but call clear_private_infos () with the given users
2010-02-22 11:02:33 +01:00
* @ return boolean | array event or array of id => event pairs , false if the acl - check went wrong , null if $ids not found
2004-08-01 17:36:04 +02:00
*/
2010-12-02 22:50:22 +01:00
function read ( $ids , $date = null , $ignore_acl = False , $date_format = 'ts' , $clear_private_infos_users = null )
2004-08-01 17:36:04 +02:00
{
2011-04-08 16:20:01 +02:00
if ( ! $ids ) return false ;
2005-11-09 00:15:14 +01:00
if ( $date ) $date = $this -> date2ts ( $date );
2010-05-20 17:12:59 +02:00
2010-05-18 12:03:21 +02:00
$return = null ;
2004-08-01 17:36:04 +02:00
2010-12-02 22:50:22 +01:00
$check = $clear_private_infos_users ? EGW_ACL_FREEBUSY : EGW_ACL_READ ;
if ( $ignore_acl || is_array ( $ids ) || ( $return = $this -> check_perms ( $check , $ids , 0 , $date_format , $date )))
2004-08-01 17:36:04 +02:00
{
2008-05-10 22:10:45 +02:00
if ( is_array ( $ids ) || ! isset ( self :: $cached_event [ 'id' ]) || self :: $cached_event [ 'id' ] != $ids ||
2009-07-15 22:35:56 +02:00
self :: $cached_event_date_format != $date_format ||
2010-04-14 10:49:49 +02:00
self :: $cached_event [ 'recur_type' ] != MCAL_RECUR_NONE && self :: $cached_event_date != $date )
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
$events = $this -> so -> read ( $ids , $date ? $this -> date2ts ( $date , true ) : 0 );
2006-12-22 20:51:56 +01:00
2005-11-09 00:15:14 +01:00
if ( $events )
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
$this -> db2data ( $events , $date_format );
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
if ( is_array ( $ids ))
2004-11-07 15:38:00 +01:00
{
2005-11-09 00:15:14 +01:00
$return =& $events ;
}
else
{
2008-05-10 22:10:45 +02:00
self :: $cached_event = array_shift ( $events );
self :: $cached_event_date_format = $date_format ;
2009-07-15 22:35:56 +02:00
self :: $cached_event_date = $date ;
2010-12-02 22:50:22 +01:00
$return = self :: $cached_event ;
2004-11-07 15:38:00 +01:00
}
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
}
else
{
2010-04-14 10:49:49 +02:00
$return = self :: $cached_event ;
2004-08-01 17:36:04 +02:00
}
}
2010-12-02 22:50:22 +01:00
if ( $clear_private_infos_users && ! is_array ( $ids ) && ! $this -> check_perms ( EGW_ACL_READ , $return ))
{
$this -> clear_private_infos ( $return , ( array ) $clear_private_infos_users );
}
2004-08-01 17:36:04 +02:00
if ( $this -> debug && ( $this -> debug > 1 || $this -> debug == 'read' ))
{
2010-12-02 23:11:05 +01:00
$this -> debug_message ( 'calendar_bo::read(%1,%2,%3,%4,%5)=%6' , True , $ids , $date , $ignore_acl , $date_format , $clear_private_infos_users , $return );
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
return $return ;
2004-08-01 17:36:04 +02:00
}
/**
* Inserts all repetions of $event in the timespan between $start and $end into $events
*
2009-11-12 11:11:23 +01:00
* The new entries are just appended to $events , so $events is no longer sorted by startdate !!!
2004-08-01 17:36:04 +02:00
*
2009-11-12 11:11:23 +01:00
* Recurrences get calculated by rrule iterator implemented in calendar_rrule class .
2004-08-01 17:36:04 +02:00
*
2009-08-04 19:14:16 +02:00
* @ param array $event repeating event whos repetions should be inserted
* @ param mixed $start start - date
* @ param mixed $end end - date
* @ param array $events where the repetions get inserted
2009-11-12 11:11:23 +01:00
* @ param array $recur_exceptions with date ( in Ymd ) as key ( and True as values ), seems not to be used anymore
2004-08-01 17:36:04 +02:00
*/
2009-11-12 11:11:23 +01:00
function insert_all_recurrences ( $event , $start , $end , & $events )
2004-08-01 17:36:04 +02:00
{
2009-11-12 11:11:23 +01:00
if (( int ) $this -> debug >= 3 || $this -> debug == 'set_recurrences' || $this -> debug == 'check_move_horizont' || $this -> debug == 'insert_all_recurrences' )
2005-11-09 00:15:14 +01:00
{
2013-06-07 13:53:45 +02:00
$this -> debug_message ( __METHOD__ . '(%1,%2,%3,&$events)' , true , $event , $start , $end );
2005-11-09 00:15:14 +01:00
}
2004-08-01 17:36:04 +02:00
$start_in = $start ; $end_in = $end ;
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
$start = $this -> date2ts ( $start );
$event_start_ts = $this -> date2ts ( $event [ 'start' ]);
2009-11-12 11:11:23 +01:00
$event_length = $this -> date2ts ( $event [ 'end' ]) - $event_start_ts ; // we use a constant event-length, NOT a constant end-time!
2004-08-01 17:36:04 +02:00
2009-11-12 11:11:23 +01:00
// if $end is before recur_enddate, use it instead
if ( ! $event [ 'recur_enddate' ] || $this -> date2ts ( $event [ 'recur_enddate' ]) > $this -> date2ts ( $end ))
2004-08-01 17:36:04 +02:00
{
2009-11-12 11:11:23 +01:00
//echo "<p>recur_enddate={$event['recur_enddate']}=".egw_time::to($event['recur_enddate'])." > end=$end=".egw_time::to($end)." --> using end instead of recur_enddate</p>\n";
2011-06-14 20:33:26 +02:00
// insert at least the event itself, if it's behind the horizont
$event [ 'recur_enddate' ] = $this -> date2ts ( $end ) < $this -> date2ts ( $event [ 'end' ]) ? $event [ 'end' ] : $end ;
2004-08-01 17:36:04 +02:00
}
2013-08-15 14:23:38 +02:00
// unset exceptions, as we need to add them as recurrence too, but marked as exception
unset ( $event [ 'recur_exception' ]);
2009-11-12 11:11:23 +01:00
// loop over all recurrences and insert them, if they are after $start
2010-05-01 18:25:10 +02:00
$rrule = calendar_rrule :: event2rrule ( $event , true ); // true = we operate in usertime, like the rest of calendar_bo
2009-11-12 11:11:23 +01:00
foreach ( $rrule as $time )
2004-08-01 17:36:04 +02:00
{
2009-11-12 11:11:23 +01:00
$time -> setUser (); // $time is in timezone of event, convert it to usertime used here
if (( $ts = $this -> date2ts ( $time )) < $start - $event_length )
2005-02-10 01:13:37 +01:00
{
2009-11-12 11:11:23 +01:00
//echo "<p>".$time." --> ignored as $ts < $start-$event_length</p>\n";
continue ; // to early or original event (returned by interator too)
2005-02-10 01:13:37 +01:00
}
2010-02-25 18:05:24 +01:00
$ts_end = $ts + $event_length ;
// adjust ts_end for whole day events in case it does not fit due to
// spans over summer/wintertime adjusted days
if ( $event [ 'whole_day' ] && ( $arr_end = $this -> date2array ( $ts_end )) &&
! ( $arr_end [ 'hour' ] == 23 && $arr_end [ 'minute' ] == 59 && $arr_end [ 'second' ] == 59 ))
{
$arr_end [ 'hour' ] = 23 ;
$arr_end [ 'minute' ] = 59 ;
$arr_end [ 'second' ] = 59 ;
$ts_end_guess = $this -> date2ts ( $arr_end );
if ( $ts_end_guess - $ts_end > DAY_s / 2 )
{
$ts_end = $ts_end_guess - DAY_s ; // $ts_end_guess was one day too far in the future
}
else
{
$ts_end = $ts_end_guess ; // $ts_end_guess was ok
}
}
2010-04-14 10:49:49 +02:00
2009-11-12 11:11:23 +01:00
$event [ 'start' ] = $ts ;
2010-02-25 18:05:24 +01:00
$event [ 'end' ] = $ts_end ;
2009-11-12 11:11:23 +01:00
$events [] = $event ;
}
if ( $this -> debug && (( int ) $this -> debug > 2 || $this -> debug == 'set_recurrences' || $this -> debug == 'check_move_horizont' || $this -> debug == 'insert_all_recurrences' ))
2004-08-01 17:36:04 +02:00
{
2009-11-12 11:11:23 +01:00
$event [ 'start' ] = $event_start_ts ;
$event [ 'end' ] = $event_start_ts + $event_length ;
$this -> debug_message ( __METHOD__ . '(%1,start=%2,end=%3,events) events=%5' , True , $event , $start_in , $end_in , $events );
2004-08-01 17:36:04 +02:00
}
}
/**
* Adds one repetion of $event for $date_ymd to the $events array , after adjusting its start - and end - time
*
2009-08-04 19:14:16 +02:00
* @ param array $events array in which the event gets inserted
* @ param array $event event to insert , it has start - and end - date of the first recurrence , not of $date_ymd
* @ param int | string $date_ymd of the date of the event
2004-08-01 17:36:04 +02:00
*/
function add_adjusted_event ( & $events , $event , $date_ymd )
{
$event_in = $event ;
// calculate the new start- and end-time
2005-11-09 00:15:14 +01:00
$length_s = $this -> date2ts ( $event [ 'end' ]) - $this -> date2ts ( $event [ 'start' ]);
$event_start_arr = $this -> date2array ( $event [ 'start' ]);
2004-08-01 17:36:04 +02:00
$date_arr = $this -> date2array (( string ) $date_ymd );
2005-11-09 00:15:14 +01:00
$date_arr [ 'hour' ] = $event_start_arr [ 'hour' ];
$date_arr [ 'minute' ] = $event_start_arr [ 'minute' ];
$date_arr [ 'second' ] = $event_start_arr [ 'second' ];
2004-08-01 17:36:04 +02:00
unset ( $date_arr [ 'raw' ]); // else date2ts would use it
2005-11-09 00:15:14 +01:00
$event [ 'start' ] = $this -> date2ts ( $date_arr );
$event [ 'end' ] = $event [ 'start' ] + $length_s ;
2004-08-01 17:36:04 +02:00
$events [] = $event ;
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'add_adjust_event' ))
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::add_adjust_event(,%1,%2) as %3' , True , $event_in , $date_ymd , $event );
2004-08-01 17:36:04 +02:00
}
}
2006-03-05 11:26:03 +01:00
/**
* Fetch information about a resource
*
* We do some caching here , as the resource itself might not do it .
*
* @ param string $uid string with one - letter resource - type and numerical resource - id , eg . " r19 "
2009-08-04 19:14:16 +02:00
* @ return array | boolean array with keys res_id , cat_id , name , useable ( name definied by max_quantity in $this -> resources ), rights , responsible or false if $uid is not found
2006-03-05 11:26:03 +01:00
*/
function resource_info ( $uid )
{
static $res_info_cache = array ();
2008-05-08 17:02:35 +02:00
2011-03-28 14:04:34 +02:00
if ( ! is_scalar ( $uid )) throw new egw_exception_wrong_parameter ( __METHOD__ . '(' . array2string ( $uid ) . ') parameter must be scalar' );
2006-03-05 11:26:03 +01:00
if ( ! isset ( $res_info_cache [ $uid ]))
{
2008-05-08 17:02:35 +02:00
if ( is_numeric ( $uid ))
{
2009-07-15 22:35:56 +02:00
$info = array (
2009-07-08 12:29:06 +02:00
'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 ),
2011-10-17 17:44:26 +02:00
'app' => 'accounts' ,
2008-05-08 17:02:35 +02:00
);
}
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' );
}
2011-10-17 17:44:26 +02:00
$info [ 'app' ] = $this -> resources [ $uid [ 0 ]][ 'app' ];
2008-05-08 17:02:35 +02:00
}
}
$res_info_cache [ $uid ] = $info ;
2006-03-05 11:26:03 +01:00
}
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'resource_info' ))
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::resource_info(%1) = %2' , True , $uid , $res_info_cache [ $uid ]);
2006-03-05 11:26:03 +01:00
}
return $res_info_cache [ $uid ];
}
2004-08-01 17:36:04 +02:00
/**
* Checks if the current user has the necessary ACL rights
*
* The check is performed on an event or generally on the cal of an other user
*
* Note : Participating in an event is considered as haveing read - access on that event ,
* even if you have no general read - grant from that user .
*
2005-11-09 00:15:14 +01:00
* @ param int $needed necessary ACL right : EGW_ACL_ { READ | EDIT | DELETE }
* @ param mixed $event event as array or the event - id or 0 for a general check
* @ param int $other uid to check ( if event == 0 ) or 0 to check against $this -> user
2006-12-22 20:51:56 +01:00
* @ param string $date_format = 'ts' date - format used for reading : 'ts' = timestamp , 'array' = array , 'string' = iso8601 string for xmlrpc
* @ param mixed $date_to_read = null date used for reading , internal param for the caching
2011-06-26 17:41:21 +02:00
* @ param int $user = null for which user to check , default current user
2006-06-24 18:04:06 +02:00
* @ return boolean true permission granted , false for permission denied or null if event not found
2004-08-01 17:36:04 +02:00
*/
2011-06-26 17:41:21 +02:00
function check_perms ( $needed , $event = 0 , $other = 0 , $date_format = 'ts' , $date_to_read = null , $user = null )
2004-08-01 17:36:04 +02:00
{
2011-06-26 17:41:21 +02:00
if ( ! $user ) $user = $this -> user ;
if ( $user == $this -> user )
{
$grants = $this -> grants ;
}
else
{
$grants = $GLOBALS [ 'egw' ] -> acl -> get_grants ( 'calendar' , true , $user );
}
2004-08-01 17:36:04 +02:00
$event_in = $event ;
2005-11-09 00:15:14 +01:00
if ( $other && ! is_numeric ( $other ))
{
2006-03-05 11:26:03 +01:00
$resource = $this -> resource_info ( $other );
return $needed & $resource [ 'rights' ];
2005-11-09 00:15:14 +01:00
}
2004-08-01 17:36:04 +02:00
if ( is_int ( $event ) && $event == 0 )
{
2011-06-26 17:41:21 +02:00
$owner = $other ? $other : $user ;
2004-08-01 17:36:04 +02:00
}
else
{
if ( ! is_array ( $event ))
{
2010-05-18 12:03:21 +02:00
$event = $this -> read ( $event , $date_to_read , true , $date_format ); // = no ACL check !!!
2004-08-01 17:36:04 +02:00
}
if ( ! is_array ( $event ))
{
if ( $this -> xmlrpc )
{
$GLOBALS [ 'server' ] -> xmlrpc_error ( $GLOBALS [ 'xmlrpcerr' ][ 'not_exist' ], $GLOBALS [ 'xmlrpcstr' ][ 'not_exist' ]);
}
2006-06-24 18:04:06 +02:00
return null ; // event not found
2004-08-01 17:36:04 +02:00
}
$owner = $event [ 'owner' ];
$private = ! $event [ 'public' ];
}
2011-06-26 17:41:21 +02:00
$grant = $grants [ $owner ];
2010-11-04 14:30:11 +01:00
2011-01-04 20:27:17 +01:00
// now any ACL rights (but invite rights!) implicate FREEBUSY rights (at least READ has to include FREEBUSY)
2011-06-26 17:41:21 +02:00
if ( $grant & ~ EGW_ACL_INVITE ) $grant |= EGW_ACL_FREEBUSY ;
2010-11-04 14:30:11 +01:00
2010-05-21 17:53:06 +02:00
if ( is_array ( $event ) && ( $needed == EGW_ACL_READ || $needed == EGW_ACL_FREEBUSY ))
2004-08-01 17:36:04 +02:00
{
// Check if the $user is one of the participants or has a read-grant from one of them
2004-09-08 14:20:56 +02:00
// in that case he has an implicite READ grant for that event
2004-08-01 17:36:04 +02:00
//
2008-12-11 14:44:47 +01:00
if ( $event [ 'participants' ] && is_array ( $event [ 'participants' ]))
2004-08-01 17:36:04 +02:00
{
2008-12-11 14:44:47 +01:00
foreach ( $event [ 'participants' ] as $uid => $accept )
2004-08-01 17:36:04 +02:00
{
2012-08-09 10:41:29 +02:00
if ( $uid == $user || $uid < 0 && in_array ( $user , ( array ) $GLOBALS [ 'egw' ] -> accounts -> members ( $uid , true )))
2008-12-11 14:44:47 +01:00
{
2011-06-26 17:46:30 +02:00
// if we are a participant, we have an implicite FREEBUSY, READ and PRIVAT grant
$grant |= EGW_ACL_FREEBUSY | EGW_ACL_READ | EGW_ACL_PRIVATE ;
2008-12-11 14:44:47 +01:00
break ;
}
2011-06-26 17:41:21 +02:00
elseif ( $grants [ $uid ] & EGW_ACL_READ )
2008-12-11 14:44:47 +01:00
{
// if we have a READ grant from a participant, we dont give an implicit privat grant too
2011-06-26 17:41:21 +02:00
$grant |= EGW_ACL_READ ;
2008-12-11 14:44:47 +01:00
// we cant break here, as we might be a participant too, and would miss the privat grant
}
elseif ( ! is_numeric ( $uid ))
{
2011-06-26 17:41:21 +02:00
// if the owner only grants EGW_ACL_FREEBUSY we are not interested in the recources explicit rights
2013-03-14 15:47:06 +01:00
if ( $grant == EGW_ACL_FREEBUSY ) continue ;
2008-12-11 14:44:47 +01:00
// if we have a resource as participant
$resource = $this -> resource_info ( $uid );
2011-06-26 17:41:21 +02:00
$grant |= $resource [ 'rights' ];
2008-12-11 14:44:47 +01:00
}
2008-05-08 17:02:35 +02:00
}
2004-08-01 17:36:04 +02:00
}
}
2005-11-09 00:15:14 +01:00
if ( $GLOBALS [ 'egw' ] -> accounts -> get_type ( $owner ) == 'g' && $needed == EGW_ACL_ADD )
2004-08-01 17:36:04 +02:00
{
$access = False ; // a group can't be the owner of an event
}
else
{
2011-06-26 17:41:21 +02:00
$access = $user == $owner || $grant & $needed
&& ( $needed == EGW_ACL_FREEBUSY || ! $private || $grant & EGW_ACL_PRIVATE );
2004-08-01 17:36:04 +02:00
}
2012-05-15 12:35:40 +02:00
// do NOT allow users to purge deleted events, if we dont have 'userpurge' enabled
2011-04-27 18:28:38 +02:00
if ( $access && $needed == EGW_ACL_DELETE && $event [ 'deleted' ] &&
2013-01-22 16:54:23 +01:00
! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ] &&
2012-05-15 12:35:40 +02:00
$GLOBALS [ 'egw_info' ][ 'server' ][ 'calendar_delete_history' ] != 'userpurge' )
2011-04-27 18:28:38 +02:00
{
$access = false ;
}
2004-08-01 17:36:04 +02:00
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'check_perms' ))
{
2011-06-26 17:41:21 +02:00
$this -> debug_message ( 'calendar_bo::check_perms(%1,%2,other=%3,%4,%5,user=%6)=%7' , True , ACL_TYPE_IDENTIFER . $needed , $event , $other , $date_format , $date_to_read , $user , $access );
2004-08-01 17:36:04 +02:00
}
2011-06-26 17:41:21 +02:00
//error_log(__METHOD__."($needed,".array2string($event).",$other,...,$user) returning ".array2string($access));
2004-08-01 17:36:04 +02:00
return $access ;
}
/**
2010-02-25 18:05:24 +01:00
* Converts several date - types to a timestamp and optionally converts user - to server - time
2004-08-01 17:36:04 +02:00
*
2009-08-04 19:14:16 +02:00
* @ param mixed $date date to convert , should be one of the following types
2005-11-09 00:15:14 +01:00
* string ( ! ) in form YYYYMMDD or iso8601 YYYY - MM - DDThh : mm : ss or YYYYMMDDThhmmss
2004-08-01 17:36:04 +02:00
* int already a timestamp
* array with keys 'second' , 'minute' , 'hour' , 'day' or 'mday' ( depricated ! ), 'month' and 'year'
2010-02-04 13:08:03 +01:00
* @ param boolean $user2server = False conversion between user - and server - time ; default False == Off
2004-08-01 17:36:04 +02:00
*/
2009-10-07 15:29:06 +02:00
static function date2ts ( $date , $user2server = False )
2004-08-01 17:36:04 +02:00
{
2009-10-07 15:29:06 +02:00
return $user2server ? egw_time :: user2server ( $date , 'ts' ) : egw_time :: to ( $date , 'ts' );
2004-08-01 17:36:04 +02:00
}
/**
2010-02-25 18:05:24 +01:00
* Converts a date to an array and optionally converts server - to user - time
2004-08-01 17:36:04 +02:00
*
2009-08-04 19:14:16 +02:00
* @ param mixed $date date to convert
* @ param boolean $server2user_time conversation between user - and server - time default False == Off
2004-10-08 00:11:18 +02:00
* @ return array with keys 'second' , 'minute' , 'hour' , 'day' , 'month' , 'year' , 'raw' ( timestamp ) and 'full' ( Ymd - string )
2004-08-01 17:36:04 +02:00
*/
2009-10-07 15:29:06 +02:00
static function date2array ( $date , $server2user = False )
2004-08-01 17:36:04 +02:00
{
2009-10-07 15:29:06 +02:00
return $server2user ? egw_time :: server2user ( $date , 'array' ) : egw_time :: to ( $date , 'array' );
2004-08-01 17:36:04 +02:00
}
/**
* Converts a date as timestamp or array to a date - string and optionaly converts server - to user - time
*
2005-11-09 00:15:14 +01:00
* @ param mixed $date integer timestamp or array with ( 'year' , 'month' , .. , 'second' ) to convert
* @ param boolean $server2user_time conversation between user - and server - time default False == Off , not used if $format ends with \Z
* @ param string $format = 'Ymd' format of the date to return , eg . 'Y-m-d\TH:i:sO' ( 2005 - 11 - 01 T15 : 30 : 00 + 0100 )
* @ return string date formatted according to $format
2004-08-01 17:36:04 +02:00
*/
2009-10-07 15:29:06 +02:00
static function date2string ( $date , $server2user = False , $format = 'Ymd' )
2004-08-01 17:36:04 +02:00
{
2009-10-07 15:29:06 +02:00
return $server2user ? egw_time :: server2user ( $date , $format ) : egw_time :: to ( $date , $format );
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
/**
* Formats a date given as timestamp or array
*
* @ param mixed $date integer timestamp or array with ( 'year' , 'month' , .. , 'second' ) to convert
2009-08-04 19:14:16 +02:00
* @ param string | boolean $format = '' default common_prefs [ dateformat ], common_prefs [ timeformat ], false = time only , true = date only
2005-11-09 00:15:14 +01:00
* @ return string the formated date ( incl . time )
*/
2009-10-07 15:29:06 +02:00
static function format_date ( $date , $format = '' )
2005-11-09 00:15:14 +01:00
{
2009-10-07 15:29:06 +02:00
return egw_time :: to ( $date , $format );
2005-11-09 00:15:14 +01:00
}
2004-08-01 17:36:04 +02:00
/**
* Gives out a debug - message with certain parameters
*
* All permanent debug - messages in the calendar should be done by this function !!!
* ( In future they may be logged or sent as xmlrpc - faults back . )
*
* Permanent debug - message need to make sure NOT to give secret information like passwords !!!
*
* This function do NOT honor the setting of the debug variable , you may use it like
* if ( $this -> debug > N ) $this -> debug_message ( 'Error ;-)' );
*
* The parameters get formated depending on their type . ACL - values need a ACL_TYPE_IDENTIFER prefix .
*
2009-08-04 19:14:16 +02:00
* @ param string $msg message with parameters / variables like lang (), eg . '%1'
* @ param boolean $backtrace = True include a function - backtrace , default True = On
2004-08-01 17:36:04 +02:00
* should only be set to False = Off , if your code ensures a call with backtrace = On was made before !!!
2009-08-04 19:14:16 +02:00
* @ param mixed $param a variable number of parameters , to be inserted in $msg
2004-08-01 17:36:04 +02:00
* arrays get serialized with print_r () !
*/
2009-12-03 19:20:07 +01:00
static function debug_message ( $msg , $backtrace = True )
2004-08-01 17:36:04 +02:00
{
static $acl2string = array (
2009-07-08 12:22:11 +02:00
0 => 'ACL-UNKNOWN' ,
EGW_ACL_READ => 'ACL_READ' ,
EGW_ACL_ADD => 'ACL_ADD' ,
EGW_ACL_EDIT => 'ACL_EDIT' ,
EGW_ACL_DELETE => 'ACL_DELETE' ,
EGW_ACL_PRIVATE => 'ACL_PRIVATE' ,
EGW_ACL_FREEBUSY => 'ACL_FREEBUSY' ,
2004-08-01 17:36:04 +02:00
);
for ( $i = 2 ; $i < func_num_args (); ++ $i )
{
$param = func_get_arg ( $i );
if ( is_null ( $param ))
{
$param = 'NULL' ;
}
else
{
switch ( gettype ( $param ))
{
case 'string' :
if ( substr ( $param , 0 , strlen ( ACL_TYPE_IDENTIFER )) == ACL_TYPE_IDENTIFER )
{
$param = ( int ) substr ( $param , strlen ( ACL_TYPE_IDENTIFER ));
2006-12-22 20:51:56 +01:00
$param = ( isset ( $acl2string [ $param ]) ? $acl2string [ $param ] : $acl2string [ 0 ]) . " ( $param ) " ;
2004-08-01 17:36:04 +02:00
}
else
{
$param = " ' $param ' " ;
}
break ;
2009-11-12 11:11:23 +01:00
case 'egw_time' :
case 'datetime' :
$p = $param ;
unset ( $param );
$param = $p -> format ( 'l, Y-m-d H:i:s' ) . ' (' . $p -> getTimeZone () -> getName () . ')' ;
break ;
2004-08-01 17:36:04 +02:00
case 'array' :
case 'object' :
list (, $content ) = @ each ( $param );
$do_pre = is_array ( $param ) ? count ( $param ) > 6 || is_array ( $content ) && count ( $content ) : True ;
$param = ( $do_pre ? '<pre>' : '' ) . print_r ( $param , True ) . ( $do_pre ? '</pre>' : '' );
break ;
case 'boolean' :
$param = $param ? 'True' : 'False' ;
break ;
2004-12-12 13:24:24 +01:00
case 'integer' :
2005-11-09 00:15:14 +01:00
if ( $param >= mktime ( 0 , 0 , 0 , 1 , 1 , 2000 )) $param = adodb_date ( 'Y-m-d H:i:s' , $param ) . " ( $param ) " ;
2004-12-12 13:24:24 +01:00
break ;
2004-08-01 17:36:04 +02:00
}
}
$msg = str_replace ( '%' . ( $i - 1 ), $param , $msg );
}
2010-11-28 12:01:44 +01:00
//echo '<p>'.$msg."<br>\n".($backtrace ? 'Backtrace: '.function_backtrace(1)."</p>\n" : '').str_repeat(' ',4096);
error_log ( $msg );
if ( $backtrace ) error_log ( function_backtrace ( 1 ));
2004-08-01 17:36:04 +02:00
}
/**
2005-11-09 00:15:14 +01:00
* Formats one or two dates ( range ) as long date ( full monthname ), optionaly with a time
2004-08-01 17:36:04 +02:00
*
2005-11-09 00:15:14 +01:00
* @ param mixed $first first date
2006-06-20 21:55:06 +02:00
* @ param mixed $last = 0 last date if != 0 ( default )
* @ param boolean $display_time = false should a time be displayed too
* @ param boolean $display_day = false should a day - name prefix the date , eg . monday June 20 , 2006
2004-08-01 17:36:04 +02:00
* @ return string with formated date
*/
2006-06-20 21:55:06 +02:00
function long_date ( $first , $last = 0 , $display_time = false , $display_day = false )
2004-08-01 17:36:04 +02:00
{
$first = $this -> date2array ( $first );
if ( $last )
{
$last = $this -> date2array ( $last );
}
$datefmt = $this -> common_prefs [ 'dateformat' ];
2005-11-09 00:15:14 +01:00
$timefmt = $this -> common_prefs [ 'timeformat' ] == 12 ? 'h:i a' : 'H:i' ;
2004-08-01 17:36:04 +02:00
$month_before_day = strtolower ( $datefmt [ 0 ]) == 'm' ||
2009-07-08 12:29:06 +02:00
strtolower ( $datefmt [ 2 ]) == 'm' && $datefmt [ 4 ] == 'd' ;
2004-08-01 17:36:04 +02:00
2006-06-20 21:55:06 +02:00
if ( $display_day )
{
2008-05-08 17:02:35 +02:00
$range = lang ( adodb_date ( 'l' , $first [ 'raw' ])) . ( $this -> common_prefs [ 'dateformat' ][ 0 ] != 'd' ? ' ' : ', ' );
2006-06-20 21:55:06 +02:00
}
2004-08-01 17:36:04 +02:00
for ( $i = 0 ; $i < 5 ; $i += 2 )
{
switch ( $datefmt [ $i ])
{
case 'd' :
$range .= $first [ 'day' ] . ( $datefmt [ 1 ] == '.' ? '.' : '' );
if ( $first [ 'month' ] != $last [ 'month' ] || $first [ 'year' ] != $last [ 'year' ])
{
if ( ! $month_before_day )
{
$range .= ' ' . lang ( strftime ( '%B' , $first [ 'raw' ]));
}
if ( $first [ 'year' ] != $last [ 'year' ] && $datefmt [ 0 ] != 'Y' )
{
$range .= ( $datefmt [ 0 ] != 'd' ? ', ' : ' ' ) . $first [ 'year' ];
}
2005-11-09 00:15:14 +01:00
if ( $display_time )
{
$range .= ' ' . adodb_date ( $timefmt , $first [ 'raw' ]);
}
2004-08-01 17:36:04 +02:00
if ( ! $last )
{
return $range ;
}
$range .= ' - ' ;
if ( $first [ 'year' ] != $last [ 'year' ] && $datefmt [ 0 ] == 'Y' )
{
$range .= $last [ 'year' ] . ', ' ;
}
if ( $month_before_day )
{
$range .= lang ( strftime ( '%B' , $last [ 'raw' ]));
}
}
else
{
2005-11-09 00:15:14 +01:00
if ( $display_time )
{
$range .= ' ' . adodb_date ( $timefmt , $first [ 'raw' ]);
}
2004-08-01 17:36:04 +02:00
$range .= ' - ' ;
}
$range .= ' ' . $last [ 'day' ] . ( $datefmt [ 1 ] == '.' ? '.' : '' );
break ;
case 'm' :
case 'M' :
$range .= ' ' . lang ( strftime ( '%B' , $month_before_day ? $first [ 'raw' ] : $last [ 'raw' ])) . ' ' ;
break ;
case 'Y' :
2006-06-20 21:55:06 +02:00
if ( $datefmt [ 0 ] != 'm' )
{
$range .= ' ' . ( $datefmt [ 0 ] == 'Y' ? $first [ 'year' ] . ( $datefmt [ 2 ] == 'd' ? ', ' : ' ' ) : $last [ 'year' ] . ' ' );
}
2004-08-01 17:36:04 +02:00
break ;
}
}
2005-11-09 00:15:14 +01:00
if ( $display_time && $last )
{
$range .= ' ' . adodb_date ( $timefmt , $last [ 'raw' ]);
}
2006-06-20 21:55:06 +02:00
if ( $datefmt [ 4 ] == 'Y' && $datefmt [ 0 ] == 'm' )
{
$range .= ', ' . $last [ 'year' ];
}
2004-08-01 17:36:04 +02:00
return $range ;
}
2008-05-08 17:02:35 +02:00
2006-06-20 21:55:06 +02:00
/**
* Displays a timespan , eg . $both ? " 10:00 - 13:00: 3h " ( 10 : 00 am - 1 pm : 3 h ) : " 10:00 3h " ( 10 : 00 am 3 h )
*
* @ param int $start_m start time in minutes since 0 h
* @ param int $end_m end time in minutes since 0 h
* @ param boolean $both = false display the end - time too , duration is always displayed
*/
function timespan ( $start_m , $end_m , $both = false )
{
$duration = $end_m - $start_m ;
if ( $end_m == 24 * 60 - 1 ) ++ $duration ;
$duration = floor ( $duration / 60 ) . lang ( 'h' ) . ( $duration % 60 ? $duration % 60 : '' );
2011-03-24 10:26:39 +01:00
$timespan = $t = common :: formattime ( sprintf ( '%02d' , $start_m / 60 ), sprintf ( '%02d' , $start_m % 60 ));
2008-05-08 17:02:35 +02:00
2006-06-20 21:55:06 +02:00
if ( $both ) // end-time too
{
2011-03-24 10:26:39 +01:00
$timespan .= ' - ' . common :: formattime ( sprintf ( '%02d' , $end_m / 60 ), sprintf ( '%02d' , $end_m % 60 ));
2006-06-20 21:55:06 +02:00
// dont double am/pm if they are the same in both times
if ( $this -> common_prefs [ 'timeformat' ] == 12 && substr ( $timespan , - 2 ) == substr ( $t , - 2 ))
{
$timespan = str_replace ( $t , substr ( $t , 0 , - 3 ), $timespan );
}
$timespan .= ':' ;
}
return $timespan . ' ' . $duration ;
}
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
/**
* Converts a participant into a ( readable ) user - or resource - name
*
2009-08-04 19:14:16 +02:00
* @ param string | int $id id of user or resource
2011-05-26 18:50:57 +02:00
* @ param string | boolean $use_type = false type - letter or false
2011-05-27 22:32:46 +02:00
* @ param boolean $append_email = false append email ( Name < email > )
2005-11-09 00:15:14 +01:00
* @ return string with name
*/
2011-05-27 22:32:46 +02:00
function participant_name ( $id , $use_type = false , $append_email = false )
2005-11-09 00:15:14 +01:00
{
static $id2lid = array ();
2011-05-27 22:32:46 +02:00
static $id2email = array ();
2008-05-08 17:02:35 +02:00
2006-03-05 11:26:03 +01:00
if ( $use_type && $use_type != 'u' ) $id = $use_type . $id ;
2005-11-09 00:15:14 +01:00
if ( ! isset ( $id2lid [ $id ]))
{
2006-03-05 11:26:03 +01:00
if ( ! is_numeric ( $id ))
2005-11-09 00:15:14 +01:00
{
2008-05-08 17:02:35 +02:00
$id2lid [ $id ] = '#' . $id ;
if (( $info = $this -> resource_info ( $id )))
{
$id2lid [ $id ] = $info [ 'name' ] ? $info [ 'name' ] : $info [ 'email' ];
2011-05-27 22:32:46 +02:00
if ( $info [ 'name' ]) $id2email [ $id ] = $info [ 'email' ];
2008-05-08 17:02:35 +02:00
}
2005-11-09 00:15:14 +01:00
}
else
{
2009-12-03 19:20:07 +01:00
$id2lid [ $id ] = common :: grab_owner_name ( $id );
2011-05-27 22:32:46 +02:00
$id2email [ $id ] = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $id , 'account_email' );
2005-11-09 00:15:14 +01:00
}
}
2011-05-27 22:32:46 +02:00
return $id2lid [ $id ] . ( $append_email && $id2email [ $id ] ? ' <' . $id2email [ $id ] . '>' : '' );
2005-11-09 00:15:14 +01:00
}
2004-08-01 17:36:04 +02:00
/**
* Converts participants array of an event into array of ( readable ) participant - names with status
*
2005-11-23 15:21:20 +01:00
* @ param array $event event - data
2006-12-13 08:28:20 +01:00
* @ param boolean $long_status = false should the long / verbose status or an icon be use
2006-03-16 19:03:43 +01:00
* @ param boolean $show_group_invitation = false show group - invitations ( status == 'G' ) or not ( default )
2004-08-01 17:36:04 +02:00
* @ return array with id / names with status pairs
*/
2006-12-13 08:28:20 +01:00
function participants ( $event , $long_status = false , $show_group_invitation = false )
2004-08-01 17:36:04 +02:00
{
2006-12-13 08:28:20 +01:00
//_debug_array($event);
$names = array ();
2011-09-13 11:05:33 +02:00
foreach (( array ) $event [ 'participants' ] as $id => $status )
2004-08-01 17:36:04 +02:00
{
2009-08-06 13:29:05 +02:00
calendar_so :: split_status ( $status , $quantity , $role );
2009-08-04 19:14:16 +02:00
2006-03-16 19:03:43 +01:00
if ( $status == 'G' && ! $show_group_invitation ) continue ; // dont show group-invitation
2005-11-23 15:21:20 +01:00
2012-05-15 15:23:11 +02:00
$lang_status = lang ( $this -> verbose_status [ $status ]);
2006-12-13 08:28:20 +01:00
if ( ! $long_status )
2006-12-06 14:56:17 +01:00
{
2009-08-04 19:14:16 +02:00
switch ( $status [ 0 ])
2006-12-13 08:28:20 +01:00
{
case 'A' : // accepted
2014-02-04 11:34:40 +01:00
$status = html :: image ( 'calendar' , 'accepted' , $lang_status );
2009-07-08 12:22:11 +02:00
break ;
2006-12-13 08:28:20 +01:00
case 'R' : // rejected
2014-02-04 11:34:40 +01:00
$status = html :: image ( 'calendar' , 'rejected' , $lang_status );
2009-07-08 12:22:11 +02:00
break ;
2006-12-13 08:28:20 +01:00
case 'T' : // tentative
2012-05-15 15:23:11 +02:00
$status = html :: image ( 'calendar' , 'tentative' , $lang_status );
2009-07-08 12:22:11 +02:00
break ;
2006-12-13 08:28:20 +01:00
case 'U' : // no response = unknown
2014-02-04 11:34:40 +01:00
$status = html :: image ( 'calendar' , 'needs-action' , $lang_status );
2009-07-08 12:22:11 +02:00
break ;
2010-02-17 14:29:28 +01:00
case 'D' : // delegated
2012-05-15 15:23:11 +02:00
$status = html :: image ( 'calendar' , 'forward' , $lang_status );
2010-02-17 14:29:28 +01:00
break ;
2006-12-13 08:28:20 +01:00
case 'G' : // group invitation
2009-07-08 12:22:11 +02:00
// Todo: Image, seems not to be used
2012-05-15 15:23:11 +02:00
$status = '(' . $lang_status . ')' ;
2009-07-08 12:22:11 +02:00
break ;
2006-12-13 08:28:20 +01:00
}
2006-12-06 14:56:17 +01:00
}
2006-12-13 08:28:20 +01:00
else
2004-08-01 17:36:04 +02:00
{
2012-05-15 15:23:11 +02:00
$status = '(' . $lang_status . ')' ;
2004-08-01 17:36:04 +02:00
}
2009-08-06 13:29:05 +02:00
$names [ $id ] = $this -> participant_name ( $id ) . ( $quantity > 1 ? ' (' . $quantity . ')' : '' ) . ' ' . $status ;
// add role, if not a regular participant
if ( $role != 'REQ-PARTICIPANT' )
{
2009-10-12 21:16:42 +02:00
if ( isset ( $this -> roles [ $role ]))
{
2009-10-13 10:58:06 +02:00
$role = lang ( $this -> roles [ $role ]);
2009-10-12 21:16:42 +02:00
}
2009-08-06 13:29:05 +02:00
// allow to use cats as roles (beside regular iCal ones)
2009-10-12 21:16:42 +02:00
elseif ( substr ( $role , 0 , 6 ) == 'X-CAT-' && ( $cat_id = ( int ) substr ( $role , 6 )) > 0 )
2009-08-06 13:29:05 +02:00
{
$role = $GLOBALS [ 'egw' ] -> categories -> id2name ( $cat_id );
}
else
{
$role = lang ( str_replace ( 'X-' , '' , $role ));
}
$names [ $id ] .= ' ' . $role ;
}
2004-08-01 17:36:04 +02:00
}
2012-11-13 12:23:29 +01:00
natcasesort ( $names );
2004-08-01 17:36:04 +02:00
return $names ;
}
/**
* Converts category string of an event into array of ( readable ) category - names
*
2009-08-04 19:14:16 +02:00
* @ param string $category cat - id ( multiple id ' s commaseparated )
* @ param int $color color of the category , if multiple cats , the color of the last one with color is returned
2004-08-01 17:36:04 +02:00
* @ return array with id / names
*/
function categories ( $category , & $color )
{
static $id2cat = array ();
$cats = array ();
$color = 0 ;
2009-12-01 11:24:55 +01:00
2004-08-01 17:36:04 +02:00
foreach ( explode ( ',' , $category ) as $cat_id )
{
if ( ! $cat_id ) continue ;
if ( ! isset ( $id2cat [ $cat_id ]))
{
2010-01-31 00:54:08 +01:00
$id2cat [ $cat_id ] = categories :: read ( $cat_id );
2004-08-01 17:36:04 +02:00
}
$cat = $id2cat [ $cat_id ];
2013-08-15 14:23:38 +02:00
if ( is_array ( $cat [ 'data' ]) && ! empty ( $cat [ 'data' ][ 'color' ]))
{
$color = $cat [ 'data' ][ 'color' ];
}
elseif ( preg_match ( '/(#[0-9A-Fa-f]{6})/' , $cat [ 'description' ], $parts ))
2004-08-01 17:36:04 +02:00
{
2013-08-15 14:23:38 +02:00
$color = $parts [ 1 ];
2004-08-01 17:36:04 +02:00
}
$cats [ $cat_id ] = stripslashes ( $cat [ 'name' ]);
}
return $cats ;
}
2009-05-05 00:39:27 +02:00
/**
* This is called only by list_cals () . It was moved here to remove fatal error in php5 beta4
*/
2004-08-01 17:36:04 +02:00
function _list_cals_add ( $id , & $users , & $groups )
{
2011-03-24 10:26:39 +01:00
$name = common :: grab_owner_name ( $id );
if ( ! ( $egw_name = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $id )))
{
return ; // do not return no longer existing accounts which eg. still mentioned in acl
}
2005-11-09 00:15:14 +01:00
if (( $type = $GLOBALS [ 'egw' ] -> accounts -> get_type ( $id )) == 'g' )
2004-08-01 17:36:04 +02:00
{
$arr = & $groups ;
}
else
{
$arr = & $users ;
}
2011-03-24 18:19:31 +01:00
$arr [ $id ] = array (
2009-07-08 12:22:11 +02:00
'grantor' => $id ,
'value' => ( $type == 'g' ? 'g_' : '' ) . $id ,
2010-10-10 00:49:10 +02:00
'name' => $name ,
'sname' => $egw_name
2004-08-01 17:36:04 +02:00
);
}
/**
2009-05-05 00:39:27 +02:00
* generate list of user - / group - calendars for the selectbox in the header
*
2011-03-24 10:26:39 +01:00
* @ return array alphabeticaly sorted array with users first and then groups : array ( 'grantor' => $id , 'value' => [ 'g_' . ] $id , 'name' => $name )
2009-05-05 00:39:27 +02:00
*/
2004-08-01 17:36:04 +02:00
function list_cals ()
{
$users = $groups = array ();
foreach ( $this -> grants as $id => $rights )
{
$this -> _list_cals_add ( $id , $users , $groups );
}
2011-03-24 10:26:39 +01:00
if (( $memberships = $GLOBALS [ 'egw' ] -> accounts -> membership ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ])))
2004-08-01 17:36:04 +02:00
{
foreach ( $memberships as $group_info )
{
$this -> _list_cals_add ( $group_info [ 'account_id' ], $users , $groups );
2005-11-09 00:15:14 +01:00
if ( $account_perms = $GLOBALS [ 'egw' ] -> acl -> get_ids_for_location ( $group_info [ 'account_id' ], EGW_ACL_READ , 'calendar' ))
2004-08-01 17:36:04 +02:00
{
foreach ( $account_perms as $id )
{
$this -> _list_cals_add ( $id , $users , $groups );
}
}
}
}
2011-03-24 10:26:39 +01:00
usort ( $users , array ( $this , 'name_cmp' ));
usort ( $groups , array ( $this , 'name_cmp' ));
2004-08-01 17:36:04 +02:00
2011-03-24 10:26:39 +01:00
return array_merge ( $users , $groups ); // users first and then groups, both alphabeticaly
}
/**
* Compare function for sort by value of key 'name'
*
* @ param array $a
* @ param array $b
* @ return int
*/
function name_cmp ( array $a , array $b )
{
return strnatcasecmp ( $a [ 'name' ], $b [ 'name' ]);
2004-08-01 17:36:04 +02:00
}
2008-05-08 17:02:35 +02:00
2005-12-02 16:34:45 +01:00
/**
2009-11-12 11:11:23 +01:00
* Convert the recurrence - information of an event , into a human readable string
2005-12-02 16:34:45 +01:00
*
* @ param array $event
2008-05-08 17:02:35 +02:00
* @ return string
2005-12-02 16:34:45 +01:00
*/
function recure2string ( $event )
{
2010-10-04 12:07:52 +02:00
if ( ! is_array ( $event )) return false ;
2009-11-12 11:11:23 +01:00
return ( string ) calendar_rrule :: event2rrule ( $event );
2005-12-02 16:34:45 +01:00
}
2004-08-01 17:36:04 +02:00
/**
* Read the holidays for a given $year
*
2005-11-09 00:15:14 +01:00
* The holidays get cached in the session ( performance ), so changes in holidays or birthdays do NOT affect a current session !!!
*
2009-08-04 19:14:16 +02:00
* @ param int $year = 0 year , defaults to 0 = current year
2004-08-01 17:36:04 +02:00
* @ return array indexed with Ymd of array of holidays . A holiday is an array with the following fields :
2005-11-09 00:15:14 +01:00
* index : numerical unique id
2004-08-01 17:36:04 +02:00
* locale : string , 2 - char short for the nation
* name : string
* day : numerical day in month
* month : numerical month
2005-11-09 00:15:14 +01:00
* occurence : numerical year or 0 for every year
2004-08-01 17:36:04 +02:00
* dow : day of week , 0 = sunday , .. , 6 = saturday
* observande_rule : boolean
*/
function read_holidays ( $year = 0 )
{
2005-11-09 00:15:14 +01:00
if ( ! $year ) $year = ( int ) date ( 'Y' , $this -> now_su );
if ( ! $this -> cached_holidays ) // try reading the holidays from the session
{
$this -> cached_holidays = $GLOBALS [ 'egw' ] -> session -> appsession ( 'holidays' , 'calendar' );
}
2004-08-01 17:36:04 +02:00
if ( ! isset ( $this -> cached_holidays [ $year ]))
{
if ( ! is_object ( $this -> holidays ))
{
2009-08-04 19:14:16 +02:00
$this -> holidays = CreateObject ( 'calendar.boholiday' );
2004-08-01 17:36:04 +02:00
}
$this -> holidays -> prepare_read_holidays ( $year );
$this -> cached_holidays [ $year ] = $this -> holidays -> read_holiday ();
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
// search for birthdays
2008-01-17 06:58:10 +01:00
if ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'hide_birthdays' ] != 'yes' )
2005-11-09 00:15:14 +01:00
{
2010-12-06 19:25:35 +01:00
$contacts = new addressbook_bo ();
$filter = array (
'n_family' => " !'' " ,
'bday' => " !'' " ,
);
2010-12-06 19:40:08 +01:00
$bdays =& $contacts -> search ( '' , array ( 'id' , 'n_family' , 'n_given' , 'n_prefix' , 'n_middle' , 'bday' ),
2013-07-23 17:09:37 +02:00
'contact_bday ASC' , $extra_cols = '' , $wildcard = '' , $empty = False , $op = 'AND' , $start = false , $filter );
2010-12-06 19:40:08 +01:00
// search accounts too, if not stored in contacts repository
$extra_accounts_search = $contacts -> account_repository == 'ldap' && ! is_null ( $contacts -> so_accounts ) &&
! $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'addressbook' ][ 'hide_accounts' ];
if ( $extra_accounts_search && ( $bdays2 =& $contacts -> search ( '' , array ( 'id' , 'n_family' , 'n_given' , 'n_prefix' , 'n_middle' , 'bday' ),
2013-07-23 17:03:41 +02:00
'contact_bday ASC' , $extra_cols = '' , $wildcard = '' , $empty = False , $op = 'AND' , $start = false , $filter + array ( 'owner' => 0 ))))
2010-12-06 19:40:08 +01:00
{
$bdays = ! $bdays ? $bdays2 : array_merge ( $bdays , $bdays2 );
}
2008-01-17 06:58:10 +01:00
if ( $bdays )
2005-11-09 00:15:14 +01:00
{
2008-01-17 06:58:10 +01:00
// sort by month and day only
usort ( $bdays , create_function ( '$a,$b' , 'return (int) $a[\'bday\'] == (int) $b[\'bday\'] ? strcmp($a[\'bday\'],$b[\'bday\']) : (int) $a[\'bday\'] - (int) $b[\'bday\'];' ));
foreach ( $bdays as $pers )
{
2010-12-06 19:25:35 +01:00
if ( empty ( $pers [ 'bday' ]) || $pers [ 'bday' ] == '0000-00-00 0' || $pers [ 'bday' ] == '0000-00-00' || $pers [ 'bday' ] == '0.0.00' )
2010-09-30 11:32:34 +02:00
{
//error_log(__METHOD__.__LINE__.' Skipping entry for invalid birthday:'.array2string($pers));
continue ;
}
2010-12-06 19:25:35 +01:00
list ( $y , $m , $d ) = explode ( '-' , $pers [ 'bday' ]);
2008-01-17 06:58:10 +01:00
if ( $y > $year ) continue ; // not yet born
$this -> cached_holidays [ $year ][ sprintf ( '%04d%02d%02d' , $year , $m , $d )][] = array (
2009-07-08 12:22:11 +02:00
'day' => $d ,
'month' => $m ,
'occurence' => 0 ,
'name' => lang ( 'Birthday' ) . ' ' . ( $pers [ 'n_given' ] ? $pers [ 'n_given' ] : $pers [ 'n_prefix' ]) . ' ' . $pers [ 'n_middle' ] . ' ' .
$pers [ 'n_family' ] . ( $y && ! $GLOBALS [ 'egw_info' ][ 'server' ][ 'hide_birthdays' ] ? ' (' . $y . ')' : '' ),
'birthyear' => $y , // this can be used to identify birthdays from holidays
2008-01-17 06:58:10 +01:00
);
}
2005-11-09 00:15:14 +01:00
}
}
2008-05-08 17:02:35 +02:00
// store holidays and birthdays in the session
2005-11-09 00:15:14 +01:00
$this -> cached_holidays = $GLOBALS [ 'egw' ] -> session -> appsession ( 'holidays' , 'calendar' , $this -> cached_holidays );
}
if (( int ) $this -> debug >= 2 || $this -> debug == 'read_holidays' )
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::read_holidays(%1)=%2' , true , $year , $this -> cached_holidays [ $year ]);
2004-08-01 17:36:04 +02:00
}
return $this -> cached_holidays [ $year ];
}
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
/**
* get title for an event identified by $event
2008-05-08 17:02:35 +02:00
*
2005-11-09 00:15:14 +01:00
* Is called as hook to participate in the linking
*
2009-08-04 19:14:16 +02:00
* @ param int | array $entry int cal_id or array with event
* @ param string | boolean string with title , null if not found or false if not read perms
2005-11-09 00:15:14 +01:00
*/
function link_title ( $event )
{
2010-09-03 20:04:48 +02:00
if ( ! is_array ( $event ) && strpos ( $event , '-' ) !== false )
{
list ( $id , $recur ) = explode ( '-' , $event , 2 );
$event = $this -> read ( $id , $recur );
2010-11-04 14:30:11 +01:00
}
2010-09-03 20:04:48 +02:00
else if ( ! is_array ( $event ) && ( int ) $event > 0 )
2005-11-09 00:15:14 +01:00
{
$event = $this -> read ( $event );
}
if ( ! is_array ( $event ))
{
2006-06-24 18:04:06 +02:00
return $event ;
2005-11-09 00:15:14 +01:00
}
return $this -> format_date ( $event [ 'start' ]) . ': ' . $event [ 'title' ];
}
/**
* query calendar for events matching $pattern
*
* Is called as hook to participate in the linking
*
* @ param string $pattern pattern to search
2009-08-04 19:14:16 +02:00
* @ return array with cal_id - title pairs of the matching entries
2005-11-09 00:15:14 +01:00
*/
2009-12-08 23:36:43 +01:00
function link_query ( $pattern , Array & $options = array ())
2005-11-09 00:15:14 +01:00
{
$result = array ();
2009-12-08 23:36:43 +01:00
$query = array (
'query' => $pattern ,
2012-05-22 19:08:00 +02:00
'offset' => $options [ 'start' ],
'order' => 'cal_start DESC' ,
2009-12-08 23:36:43 +01:00
);
if ( $options [ 'num_rows' ]) {
$query [ 'num_rows' ] = $options [ 'num_rows' ];
}
foreach (( array ) $this -> search ( $query ) as $event )
2005-11-09 00:15:14 +01:00
{
$result [ $event [ 'id' ]] = $this -> link_title ( $event );
}
2009-12-08 23:36:43 +01:00
$options [ 'total' ] = $this -> total ;
2005-11-09 00:15:14 +01:00
return $result ;
}
2008-05-08 17:02:35 +02:00
2008-10-07 11:03:01 +02:00
/**
2011-06-26 17:41:21 +02:00
* Check access to the file store
2008-10-07 11:03:01 +02:00
*
* @ param int $id id of entry
* @ param int $check EGW_ACL_READ for read and EGW_ACL_EDIT for write or delete access
2011-06-26 17:41:21 +02:00
* @ param string $rel_path = null currently not used in calendar
* @ param int $user = null for which user to check , default current user
2008-10-07 11:03:01 +02:00
* @ return boolean true if access is granted or false otherwise
*/
2011-06-26 17:41:21 +02:00
function file_access ( $id , $check , $rel_path , $user = null )
2008-10-07 11:03:01 +02:00
{
2011-06-26 17:41:21 +02:00
return $this -> check_perms ( $check , $id , 0 , 'ts' , null , $user );
2008-10-07 11:03:01 +02:00
}
2005-11-09 00:15:14 +01:00
/**
* sets the default prefs , if they are not already set ( on a per pref . basis )
*
* It sets a flag in the app - session - data to be called only once per session
*/
function check_set_default_prefs ()
{
2006-04-05 16:38:07 +02:00
if ( $this -> cal_prefs [ 'interval' ] && ( $set = $GLOBALS [ 'egw' ] -> session -> appsession ( 'default_prefs_set' , 'calendar' )))
2005-11-09 00:15:14 +01:00
{
return ;
}
$GLOBALS [ 'egw' ] -> session -> appsession ( 'default_prefs_set' , 'calendar' , 'set' );
$default_prefs =& $GLOBALS [ 'egw' ] -> preferences -> default [ 'calendar' ];
2009-10-19 19:04:11 +02:00
$forced_prefs =& $GLOBALS [ 'egw' ] -> preferences -> forced [ 'calendar' ];
2005-11-09 00:15:14 +01:00
2006-08-25 10:17:40 +02:00
if ( ! ( $planner_start_with_group = $GLOBALS [ 'egw' ] -> accounts -> name2id ( 'Default' )))
{
$planner_start_with_group = '0' ;
}
2005-11-09 00:15:14 +01:00
$subject = lang ( 'Calendar Event' ) . ' - $$action$$: $$startdate$$ $$title$$' . " \n " ;
2009-10-19 19:04:11 +02:00
$values = array (
2009-07-08 12:22:11 +02:00
'notifyAdded' => $subject . lang ( 'You have a meeting scheduled for %1' , '$$startdate$$' ),
'notifyCanceled' => $subject . lang ( 'Your meeting scheduled for %1 has been canceled' , '$$startdate$$' ),
'notifyModified' => $subject . lang ( 'Your meeting that had been scheduled for %1 has been rescheduled to %2' , '$$olddate$$' , '$$startdate$$' ),
'notifyDisinvited' => $subject . lang ( 'You have been disinvited from the meeting at %1' , '$$startdate$$' ),
'notifyResponse' => $subject . lang ( 'On %1 %2 %3 your meeting request for %4' , '$$date$$' , '$$fullname$$' , '$$action$$' , '$$startdate$$' ),
'notifyAlarm' => lang ( 'Alarm for %1 at %2 in %3' , '$$title$$' , '$$startdate$$' , '$$location$$' ) . " \n " . lang ( 'Here is your requested alarm.' ),
'planner_start_with_group' => $planner_start_with_group ,
2009-10-19 19:04:11 +02:00
'interval' => 30 ,
2005-11-09 00:15:14 +01:00
);
2009-10-19 19:04:11 +02:00
foreach ( $values as $var => $default )
2005-11-09 00:15:14 +01:00
{
2009-10-19 19:04:11 +02:00
$type = substr ( $var , 0 , 6 ) == 'notify' ? 'forced' : 'default' ;
// only set, if neither default nor forced pref exists
if (( ! isset ( $default_prefs [ $var ]) || ( string ) $default_prefs [ $var ] === '' ) && ( ! isset ( $forced_prefs [ $var ]) || ( string ) $forced_prefs [ $var ] === '' ))
2005-11-09 00:15:14 +01:00
{
2009-10-19 19:04:11 +02:00
$GLOBALS [ 'egw' ] -> preferences -> add ( 'calendar' , $var , $default , 'default' ); // always store default, even if we have a forced too
if ( $type == 'forced' ) $GLOBALS [ 'egw' ] -> preferences -> add ( 'calendar' , $var , $default , 'forced' );
2005-11-09 00:15:14 +01:00
$this -> cal_prefs [ $var ] = $default ;
$need_save = True ;
}
}
if ( $need_save )
{
$GLOBALS [ 'egw' ] -> preferences -> save_repository ( False , 'default' );
2009-10-19 19:04:11 +02:00
$GLOBALS [ 'egw' ] -> preferences -> save_repository ( False , 'forced' );
2005-11-09 00:15:14 +01:00
}
}
2008-05-08 17:02:35 +02:00
2006-07-15 01:24:56 +02:00
/**
* Get the freebusy URL of a user
*
2009-08-04 19:14:16 +02:00
* @ param int | string $user account_id or account_lid
2006-07-15 01:24:56 +02:00
* @ param string $pw = null password
*/
2010-06-26 13:35:11 +02:00
static function freebusy_url ( $user = '' , $pw = null )
2006-07-15 01:24:56 +02:00
{
if ( is_numeric ( $user )) $user = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $user );
2010-11-04 14:30:11 +01:00
2010-06-26 13:35:11 +02:00
$credentials = '' ;
2010-11-04 14:30:11 +01:00
2010-06-26 13:35:11 +02:00
if ( $pw )
{
$credentials = '&password=' . urlencode ( $pw );
}
elseif ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'calendar' ][ 'freebusy' ] == 2 )
{
$credentials = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lid' ]
. ':' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'passwd' ];
$credentials = '&cred=' . base64_encode ( $credentials );
}
2008-05-08 17:02:35 +02:00
return ( ! $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] || $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ][ 0 ] == '/' ?
2009-07-08 12:22:11 +02:00
( $_SERVER [ 'HTTPS' ] ? 'https://' : 'http://' ) . $_SERVER [ 'HTTP_HOST' ] : '' ) .
2010-06-26 13:35:11 +02:00
$GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . '/calendar/freebusy.php/?user=' . urlencode ( $user ) . $credentials ;
2006-07-15 01:24:56 +02:00
}
2009-07-15 22:35:56 +02:00
/**
* Check if the event is the whole day
*
2009-08-04 19:14:16 +02:00
* @ param array $event event
* @ return boolean true if whole day event , false othwerwise
2009-07-15 22:35:56 +02:00
*/
2010-12-21 03:45:40 +01:00
public static function isWholeDay ( $event )
2009-07-15 22:35:56 +02:00
{
// check if the event is the whole day
2010-12-21 03:45:40 +01:00
$start = self :: date2array ( $event [ 'start' ]);
$end = self :: date2array ( $event [ 'end' ]);
2009-08-04 19:14:16 +02:00
return ! $start [ 'hour' ] && ! $start [ 'minute' ] && $end [ 'hour' ] == 23 && $end [ 'minute' ] == 59 ;
2009-07-15 22:35:56 +02:00
}
2010-11-26 22:32:10 +01:00
/**
2010-12-21 03:45:40 +01:00
* Get the etag for an entry
2010-11-26 22:32:10 +01:00
*
2013-02-26 09:48:50 +01:00
* As all update routines ( incl . set_status and add / delete alarms ) update ( series master ) modified timestamp ,
* we do NOT need any special handling for series master anymore
*
2010-12-21 03:45:40 +01:00
* @ param array | int | string $event array with event or cal_id , or cal_id : recur_date for virtual exceptions
2011-10-20 22:10:04 +02:00
* @ param string & $schedule_tag = null on return schedule - tag ( egw_cal . cal_id : egw_cal . cal_etag , no participant modifications ! )
2010-11-26 22:32:10 +01:00
* @ return string | boolean string with etag or false
*/
2013-02-26 09:48:50 +01:00
function get_etag ( $entry , & $schedule_tag = null )
2010-11-26 22:32:10 +01:00
{
if ( ! is_array ( $entry ))
{
2010-12-21 03:45:40 +01:00
list ( $entry , $recur_date ) = explode ( ':' , $entry );
2010-11-26 22:32:10 +01:00
if ( ! $this -> check_perms ( EGW_ACL_FREEBUSY , $entry , 0 , 'server' )) return false ;
2010-12-21 03:45:40 +01:00
$entry = $this -> read ( $entry , $recur_date , true , 'server' );
2010-11-26 22:32:10 +01:00
}
2012-09-26 13:09:28 +02:00
$etag = $schedule_tag = $entry [ 'id' ] . ':' . $entry [ 'etag' ];
$etag .= ':' . $entry [ 'modified' ];
2010-11-26 22:32:10 +01:00
2011-03-24 23:18:30 +01:00
//error_log(__METHOD__ . "($entry[id],$client_share_uid_excpetions) entry=".array2string($entry)." --> etag=$etag");
2010-11-26 22:32:10 +01:00
return $etag ;
}
2010-12-02 23:27:32 +01:00
/**
* Query ctag for calendar
*
2012-09-27 17:46:08 +02:00
* @ param int | string | array $user integer user - id or array of user - id ' s to use , defaults to the current user
2012-03-12 09:20:36 +01:00
* @ param string $filter = 'owner' all ( not rejected ), accepted , unknown , tentative , rejected or hideprivate
* @ param boolean $master_only = false only check recurance master ( egw_cal_user . recur_date = 0 )
* @ return integer
2010-12-02 23:27:32 +01:00
*/
2012-03-12 09:20:36 +01:00
public function get_ctag ( $user , $filter = 'owner' , $master_only = false )
2010-12-02 23:27:32 +01:00
{
2011-04-06 14:46:21 +02:00
if ( $this -> debug > 1 ) $startime = microtime ( true );
2010-12-02 23:27:32 +01:00
2011-04-06 14:46:21 +02:00
// resolve users to add memberships for users and members for groups
$users = $this -> resolve_users ( $user );
2012-03-12 09:20:36 +01:00
$ctag = $users ? $this -> so -> get_ctag ( $users , $filter == 'owner' , $master_only ) : 0 ; // no rights, return 0 as ctag (otherwise we get SQL error!)
2010-12-02 23:27:32 +01:00
2011-04-06 14:46:21 +02:00
if ( $this -> debug > 1 ) error_log ( __METHOD__ . " ( $user , ' $filter ') = $ctag = " . date ( 'Y-m-d H:i:s' , $ctag ) . " took " . ( microtime ( true ) - $startime ) . " secs " );
2010-12-02 23:27:32 +01:00
return $ctag ;
}
2011-05-30 16:21:27 +02:00
2013-05-10 12:54:36 +02:00
/**
* Hook for infolog to set some extra data and links
*
* @ param array $data event - array preset by infolog plus
* @ param int $data [ id ] cal_id
* @ return array with key => value pairs to set in new event and link_app / link_id arrays
*/
function infolog_set ( $data )
{
if ( ! ( $calendar = $this -> read ( $data [ 'id' ])))
{
return array ();
}
$content = array (
'info_cat' => $GLOBALS [ 'egw' ] -> categories -> check_list ( EGW_ACL_READ , $calendar [ 'category' ]),
'info_priority' => $calendar [ 'priority' ] ,
'info_public' => $calendar [ 'public' ] != 'private' ,
'info_subject' => $calendar [ 'title' ],
'info_des' => $calendar [ 'description' ],
'info_location' => $calendar [ 'location' ],
'info_startdate' => $calendar [ 'range_start' ],
//'info_enddate' => $calendar['range_end'] ? $calendar['range_end'] : $calendar['uid']
'info_contact' => 'calendar:' . $data [ 'id' ],
);
unset ( $content [ 'id' ]);
// Add calendar link to infolog entry
$content [ 'link_app' ][] = $calendar [ 'info_link' ][ 'app' ];
$content [ 'link_id' ][] = $calendar [ 'info_link' ][ 'id' ];
// Copy claendar's links
foreach ( egw_link :: get_links ( 'calendar' , $calendar [ 'id' ], '' , 'link_lastmod DESC' , true ) as $link )
{
if ( $link [ 'app' ] != egw_link :: VFS_APPNAME )
{
$content [ 'link_app' ][] = $link [ 'app' ];
$content [ 'link_id' ][] = $link [ 'id' ];
}
if ( $link [ 'app' ] == 'addressbook' ) // prefering contact as primary contact over calendar entry set above
{
$content [ 'info_contact' ] = 'addressbook:' . $link [ 'id' ];
}
}
// Copy same custom fields
foreach ( config :: get_customfields ( 'infolog' ) as $name => $settings )
{
if ( $this -> customfields [ $name ]) $content [ '#' . $name ] = $calendar [ '#' . $name ];
}
//error_log(__METHOD__.'('.array2string($data).') calendar='.array2string($calendar).' returning '.array2string($content));
return $content ;
}
2011-05-30 16:21:27 +02:00
/**
* Hook for timesheet to set some extra data and links
*
* @ param array $data
* @ param int $data [ id ] cal_id : recurrence
* @ return array with key => value pairs to set in new timesheet and link_app / link_id arrays
*/
function timesheet_set ( $data )
{
$set = array ();
list ( $id , $recurrence ) = explode ( ':' , $data [ 'id' ]);
if (( int ) $id && ( $event = $this -> read ( $id , $recurrence )))
{
$set [ 'ts_start' ] = $event [ 'start' ];
$set [ 'ts_title' ] = $this -> link_title ( $event );
$set [ 'start_time' ] = egw_time :: to ( $event [ 'start' ], 'H:i' );
$set [ 'ts_description' ] = $event [ 'description' ];
if ( $this -> isWholeDay ( $event )) $event [ 'end' ] ++ ; // whole day events are 1sec short
$set [ 'ts_duration' ] = ( $event [ 'end' ] - $event [ 'start' ]) / 60 ;
$set [ 'ts_quantity' ] = ( $event [ 'end' ] - $event [ 'start' ]) / 3600 ;
$set [ 'end_time' ] = null ; // unset end-time
$set [ 'cat_id' ] = ( int ) $event [ 'category' ];
2012-10-08 16:53:51 +02:00
foreach ( egw_link :: get_links ( 'calendar' , $id , '' , 'link_lastmod DESC' , true ) as $link )
{
if ( $link [ 'app' ] != 'timesheet' && $link [ 'app' ] != egw_link :: VFS_APPNAME )
{
$set [ 'link_app' ][] = $link [ 'app' ];
$set [ 'link_id' ][] = $link [ 'id' ];
}
}
2011-05-30 16:21:27 +02:00
}
return $set ;
}
2005-11-09 00:15:14 +01:00
}