1<?php
2/* end_vevent.php
3
4What happens in this file:
51. Initialization: add information not present by default
6	a.	duration
7	b.	class
8	c.	uid
9	d.	adjust start_time and end_time
102. Build recur_data array
113. Add occurrences to master_array
12*/
13if (!isset($start_date)) $start_date = "19700101";
14
15// CLASS support
16if (isset($class)) {
17	if ($class == 'PRIVATE') {
18		$summary ='**PRIVATE**';
19		$description ='**PRIVATE**';
20	} elseif ($class == 'CONFIDENTIAL') {
21		$summary ='**CONFIDENTIAL**';
22		$description ='**CONFIDENTIAL**';
23	}
24}
25
26// make sure we have some value for $uid
27if (!isset($uid)) {
28	$uid = $uid_counter;
29	$uid_counter++;
30	$uid_valid = false;
31}elseif(in_array($uid, $uid_list)) {
32	# UID seen before. If sequence is the default, bump it.
33	if ($sequence == 0) $sequence++;
34}else{
35	$uid_valid = true;
36}
37$uid_list[] = $uid;
38
39# Handle DURATION
40if (!isset($end_unixtime)) {
41	if(!isset($the_duration)) $the_duration = 0;
42	$end_unixtime 	= $start_unixtime + $the_duration;
43	$end_time 	= date ('Hi', $end_unixtime);
44}
45# at this point $end_unixtime should be set
46# adjust event start and end times
47if (isset($start_time) && isset($end_time)) {
48	// Mozilla style all-day events or just really long events
49	if (($end_unixtime - $start_unixtime) > 24*60*60) {
50		$allday_start = $start_date;
51		$allday_end = ($start_date + 1);
52	}
53}
54# look for events that span more than one day
55if (isset($start_unixtime,$end_unixtime) && date('Ymd',$start_unixtime) < date('Ymd',$end_unixtime)) {
56	$spans_day = true;
57	$bleed_check = (($start_unixtime - $end_unixtime) <= (60*60*24)) ? '-1' : '0';
58} else {
59	$spans_day = false;
60	$bleed_check = 0;
61}
62
63$length = $end_unixtime - $start_unixtime;
64if ($length < 0){
65	$length = 0;
66	$end_time = $start_time;
67}
68# get hour and minute adjusted to allowed grid times
69$drawKey = drawEventTimes($start_time, $end_time, ($length >= (60*60*24)));
70preg_match ('/([0-9]{2})([0-9]{2})/', $drawKey['draw_start'], $time3);
71preg_match ('/([0-9]{2})([0-9]{2})/', $drawKey['draw_end'], $time4);
72$hour = $time3[1];
73$minute = $time3[2];
74$end_hour = $time4[1];
75$end_minute = $time4[2];
76
77
78// RECURRENCE-ID Support
79if (isset($recurrence_d)) {
80
81	$recurrence_delete["$recurrence_d"]["$recurrence_t"] = $uid;
82}
83
84if (isset($allday_start) && $allday_start != '') {
85	$hour = '-';
86	$minute = '1';
87	$rrule_array['START_DAY'] = $allday_start;
88	# $rrule_array['END_DAY'] = $allday_end; # this doesn't seem to be used anywhere.
89#	$rrule_array['END'] = 'end';
90	$recur_start = $allday_start;
91	$start_date = $allday_start;
92	if (isset($allday_end)) {
93		$diff_allday_days = dayCompare($allday_end, $allday_start);
94	 } else {
95		$diff_allday_days = 1;
96	}
97} else {
98	$rrule_array['START_DATE'] = $start_date;
99	$rrule_array['START_TIME'] = $start_time;
100	$rrule_array['END_TIME'] = $end_time;
101#	$rrule_array['END'] = 'end';
102}
103
104$freq_type = 'none';
105# Load $rrule_array
106foreach ($rrule_array as $key => $val) {
107	switch($key) {
108		case 'FREQ':
109			switch ($val) {
110				case 'YEARLY':		$freq_type = 'year';	break;
111				case 'MONTHLY':		$freq_type = 'month';	break;
112				case 'WEEKLY':		$freq_type = 'week';	break;
113				case 'DAILY':		$freq_type = 'day';		break;
114				case 'HOURLY':		$freq_type = 'hour';	break;
115				case 'MINUTELY':	$freq_type = 'minute';	break;
116				case 'SECONDLY':	$freq_type = 'second';	break;
117			}
118			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = strtolower($val);
119			break;
120		case 'COUNT':
121			$count = $val;
122			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $count;
123			break;
124		case 'UNTIL':
125			# UNTIL must be in UTC
126			$until = date("YmdHis",strtotime($val));
127			ereg ('([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})', $until, $regs);
128			$until_unixtime = mktime($regs[4],@$regs[5],@$regs[6],$regs[2],$regs[3],$regs[1]);
129			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = localizeDate($dateFormat_week,$until);
130			break;
131		case 'INTERVAL':
132			if ($val > 0){
133			$interval = $val;
134			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $interval;
135			}
136			break;
137		case 'BYSECOND':
138			$bysecond = split (',', $val);
139			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $bysecond;
140			break;
141		case 'BYMINUTE':
142			$byminute = split (',', $val);
143			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $byminute;
144			break;
145		case 'BYHOUR':
146			$byhour = split (',', $val);
147			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $byhour;
148			break;
149		case 'BYDAY':
150			$byday = split (',', $val);
151			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $byday;
152			break;
153		case 'BYMONTHDAY':
154			$bymonthday = split (',', $val);
155			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $bymonthday;
156			break;
157		case 'BYYEARDAY':
158			$byyearday = split (',', $val);
159			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $byyearday;
160			break;
161		case 'BYWEEKNO':
162			$byweekno = split (',', $val);
163			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $byweekno;
164			break;
165		case 'BYMONTH':
166			$bymonth = split (',', $val);
167			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $bymonth;
168			break;
169		case 'BYSETPOS':
170			$bysetpos = split (',', $val);
171			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $bysetpos;
172			break;
173		case 'WKST':
174			$wkst = $val;
175			$recur_array[($start_date)][($hour.$minute)][$uid]['recur'][$key] = $wkst;
176			break;
177	}
178}
179# convert wkst to a 3 char day for strtotime to work
180$wkst3char = two2threeCharDays($wkst);
181if($current_view == 'search') $freq_type = 'none';
182# $recur is the recurrence info that goes into the master array for this VEVENT
183$recur ='';
184if (isset($recur_array[($start_date)][($hour.$minute)][$uid]['recur'])) $recur = $recur_array[($start_date)][($hour.$minute)][$uid]['recur'];
185
186/* ============================ Load $recur_data ============================
187$recur_data is an array of unix times for days of recurrences of an event.  This code handles repeats at the day level or above.  The next loop handles the times.
188RDATE is currently not supported
189
190A. Set up the time range to scan for events.
191If COUNT is not set (default is 1,000,000) then we don't have to start at start_date; we can start at the minimum interval for the view.
192variables ending in date are in phpical date format: YYYYMMDD
193variables ending with time are in phpical time format: HHMM
194variables ending in unixtime are in unixtime
195
196mArray_begin and mArray_end are set in initialization by date_range.php and may be overwritten by rss_common.php.
197
198$start_date_unixtime should be the default for starting the range.  Need this for the intervals to work out (e.g. every other day, week, month etc)
199mArray_end should be the default for end_range unixtimes.
200Conditions where overwrite these:
201	$until_unixtime < $mArray_end 	- stop iterating early
202	!isset($rrule_array['FREQ']) 	- only iterate once, set the end_range_unixtime to the end_date_unixtime
203Note that start_range_unixtime and end_range_unixtime are not the same as start_date_unixtime and end_date_unixtime */
204
205$end_range_unixtime = $mArray_end+60*60*24;
206$start_date_unixtime = strtotime($start_date);
207$next_range_unixtime = $start_date_unixtime;
208
209# conditions where we don't need to iterate over the whole range
210# 	if repeating without limit, and steps are by 1, don't go back before the mArray beginning.
211if($count == 1000000 && $interval == 1 && $mArray_begin > $next_range_unixtime) $next_range_unixtime = $mArray_begin;
212
213# 	if the beginning of our range is less than the start of the item, we may as well set the range to start at start_time
214if ($next_range_unixtime < $start_date_unixtime) $next_range_unixtime = $start_date_unixtime;
215
216# 	stop at the until limit if set
217if(isset($until) && $end_range_unixtime > $until_unixtime) $end_range_unixtime = $until_unixtime;else $until_unixtime = $mArray_end;
218
219# 	more adjustments
220switch ($freq_type){
221	case 'week':
222		# need to get the first value of $next_range_unixtime onto the right day of the week
223		$next_range_unixtime = strtotime("this ".date("D", $start_date_unixtime), $next_range_unixtime);
224		break;
225	case 'year':
226		$end_range_unixtime	+= 366*24*60*60;
227		break;
228}
229
230#nonrepeating events can stop at the first instance
231if(!isset($rrule_array['FREQ']) && isset($end_date)){
232	$end_range_unixtime = strtotime($end_date);
233	$count = 1;
234}
235
236/* The while loop below increments $next_range_time by $freq type. For the larger freq types, there is only
237one $next_range_time per repeat, but the BYXXX rules may write more than one event in that repeat cycle
238$next_date_time handles those instances within a $freq_type */
239#echo "<pre>$summary\n\tstart mArray time:".date("Ymd his",$mArray_begin)."\n\tnext_range_unixtime:".date("Ymd his",$next_range_unixtime)."\n\tend range time ".date("Ymd his",$end_range_unixtime)."\n";
240$recur_data = array();
241while ($next_range_unixtime <= $end_range_unixtime && $count > 0) {
242	$year = date("Y", $next_range_unixtime);
243	$month = date('m', $next_range_unixtime);
244	$time = mktime(12,0,0,$month,date("d",$start_unixtime),$year);
245	switch ($freq_type){
246		case 'day':
247			add_recur($next_range_unixtime);
248			break;
249		case 'week':
250			add_recur(expand_byday($next_range_unixtime));
251			break;
252		case 'month':
253			if(!empty($bymonthday)) $time = mktime(12,0,0,$month,1,$year);
254			$times = expand_bymonthday(array($time));#echo "\n $month exp bymonthday";dump_times($times);
255			foreach($times as $time){
256				add_recur(expand_byday($time));
257			}
258			break;
259		case 'year':
260			$times = expand_bymonth($time);      #echo "exp bymonth";dump_times($times);
261			$times = expand_byweekno($times);    #echo "exp byweekno";dump_times($times);
262			$times = expand_byyearday($times);   #echo "exp byyearday";dump_times($times);
263			$times = expand_bymonthday($times);  #echo "\nexp bymonthday";dump_times($times);
264			foreach($times as $time){
265				add_recur(expand_byday($time));
266			}
267			break;
268		default:
269			add_recur($start_unixtime);
270			break 2;
271	}
272	$next_range_unixtime = strtotime('+'.$interval.' '.$freq_type, $next_range_unixtime); #echo "\nnext $interval $freq_type".date("Ymd",$next_range_unixtime)."\n";
273} #end while loop
274sort($recur_data);
275
276/* ============================ Use $recur_data array to write the master array ============================
277// This used to use 5 different blocks to write the array... can it be reduced further?
278
279For each recurrence date, an event may still cross day boundaries.  So we need to loop from the start_date for that recurrence to the end of that recurrence.
280To generate $recur_data we mostly only paid attention to start times.
281
282Now, a single event must be split into multiple master array values for each day on which it occurs
283
284$hour and $minute are the values from the start_time, rounded to the nearest grid time.
285
286*/
287$recur_data_hour = @substr($start_time,0,2);
288$recur_data_minute = @substr($start_time,2,2);
289if (isset($allday_start) && $allday_start != ''){
290	$recur_data_hour = '00';
291	$recur_data_minute = '00';
292}
293foreach($recur_data as $recur_data_unixtime) {
294	$recur_data_year 	= date('Y', $recur_data_unixtime);
295	$recur_data_month 	= date('m', $recur_data_unixtime);
296	$recur_data_day 	= date('d', $recur_data_unixtime);
297	$recur_data_date 	= $recur_data_year.$recur_data_month.$recur_data_day;
298
299	# initialize the loop range	to the recur date + grid time
300	$next_range_unixtime = mktime($recur_data_hour,$recur_data_minute,0,$recur_data_month,$recur_data_day,$recur_data_year);
301	$end_range_unixtime = $next_range_unixtime + $length;
302	$end_date_tmp = date("Ymd",$end_range_unixtime);
303	#echo "<pre>$summary ".date("Ymd H:i:s",$next_range_unixtime)." ".date("Ymd H:i:s",$end_range_unixtime)."\n";
304
305	# default the time_key to -1 for allday events, overwrite as needed
306	$time_key = -1;
307
308	$start_unixtime_tmp = strtotime($recur_data_date.$start_time);
309	$end_unixtime_tmp = strtotime($end_date_tmp.$end_time);
310	while (date("Ymd", $next_range_unixtime) <= $end_date_tmp) {
311		$this_date_tmp = date('Ymd',$next_range_unixtime);
312		$next_range_unixtime = strtotime('+1 day',$next_range_unixtime);
313
314		if (!isset($allday_start) || $allday_start == '') $time_key = $hour.$minute;
315		$display_end_tmp = $end_hour.$end_minute;
316		if($time_key > -1){
317			# the day is not the first day of the recurrence
318			if ($this_date_tmp > $recur_data_date) $time_key = '0000';
319			# the day is not the last day of the recurrence
320			if ($this_date_tmp < $end_date_tmp) $display_end_tmp = '2400';
321		}
322		if($this_date_tmp == $end_date_tmp && ($end_time == '0000')) continue;
323		if(!isset($master_array[$this_date_tmp][$time_key][$uid]['sequence']) ||
324			$sequence >  $master_array[$this_date_tmp][$time_key][$uid]['sequence']
325			){
326			$master_array[$this_date_tmp][$time_key][$uid] = array (
327				'event_start' => $start_time,                	# hhmm
328				'event_end' => $end_time,                    	# hhmm
329				'display_start' => $time_key,                   # hhmm
330				'display_end' => $display_end_tmp,            	# hhmm
331				'start_unixtime' => $start_unixtime_tmp,      	# start unixtime for this recurrence
332				'end_unixtime' => $end_unixtime_tmp,          	# end unixtime for this recurrence
333				'event_text' => $summary,                    	#
334				'event_length' => $length,                    	# length in seconds
335				'event_overlap' => 0,                        	# checkOverlap modifies this
336				'description' => $description,
337				'status' => $status,
338				'class' => $class,
339				'spans_day' => $spans_day,
340				'location' => $location,
341				'categories' => $vtodo_categories,
342				'organizer' => serialize($organizer),
343				'attendee' => serialize($attendee),
344				'calnumber' => $calnumber,
345				'calname' => $actual_calname,
346				'timezone' => $start_tz,
347				'other' => trim($other),
348				'geo' => $geo,
349				'url' => $url,
350				'sequence' => $sequence,
351				'recur' => $recur
352				);
353		}
354		if($time_key > -1) checkOverlap($this_date_tmp, $time_key, $uid);
355	}
356} # end foreach recur_data
357unset($recur_data);
358
359
360// This should remove any exdates that were missed.
361// Added for version 0.9.5 modified in 2.22 remove anything that doesn't have an event_start
362if (is_array($except_dates)) {
363	foreach ($except_dates as $key => $value) {
364		if (isset ($master_array[$value])){
365			foreach ($master_array[$value] as $time => $value2){
366				if (!isset($value2[$uid]['event_start'])){
367					unset($master_array[$value][$time][$uid]);
368				}
369			}
370		}
371	}
372}
373
374// Clear event data now that it's been saved.
375unset($start_time, $start_time_tmp, $end_time, $end_time_tmp, $start_unixtime, $start_unixtime_tmp, $end_unixtime, $end_unixtime_tmp, $summary, $length, $description, $status, $class, $location, $organizer, $attendee);
376//If you want to see the values in the arrays, uncomment below.
377//print '<pre>';
378//print_r($master_array);
379//print_r($overlap_array);
380//print_r($day_array);
381//print_r($rrule_array);
382//print_r($byday_arr);
383//print_r($recurrence_delete);
384//print_r($cal_displaynames);
385//print_r($cal_filelist);
386//print_r($tz_array);
387//print '</pre>';
388?>