Issues (1061)

Sources/Calendar.php (2 issues)

1
<?php
2
3
/**
4
 * This file has only one real task, showing the calendar.
5
 * Original module by Aaron O'Neil - [email protected]
6
 *
7
 * Simple Machines Forum (SMF)
8
 *
9
 * @package SMF
10
 * @author Simple Machines https://www.simplemachines.org
11
 * @copyright 2020 Simple Machines and individual contributors
12
 * @license https://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 RC2
15
 */
16
17
if (!defined('SMF'))
18
	die('No direct access...');
19
20
/**
21
 * Show the calendar.
22
 * It loads the specified month's events, holidays, and birthdays.
23
 * It requires the calendar_view permission.
24
 * It depends on the cal_enabled setting, and many of the other cal_ settings.
25
 * It uses the calendar_start_day theme option. (Monday/Sunday)
26
 * It uses the main sub template in the Calendar template.
27
 * It goes to the month and year passed in 'month' and 'year' by get or post.
28
 * It is accessed through ?action=calendar.
29
 *
30
 * @return void
31
 */
32
function CalendarMain()
33
{
34
	global $txt, $context, $modSettings, $scripturl, $options, $sourcedir, $user_info, $smcFunc;
35
36
	// Permissions, permissions, permissions.
37
	isAllowedTo('calendar_view');
38
39
	// Some global template resources.
40
	$context['calendar_resources'] = array(
41
		'min_year' => $modSettings['cal_minyear'],
42
		'max_year' => $modSettings['cal_maxyear'],
43
	);
44
45
	// Doing something other than calendar viewing?
46
	$subActions = array(
47
		'ical' => 'iCalDownload',
48
		'post' => 'CalendarPost',
49
	);
50
51
	if (isset($_GET['sa']) && isset($subActions[$_GET['sa']]))
52
		return call_helper($subActions[$_GET['sa']]);
53
54
	// You can't do anything if the calendar is off.
55
	if (empty($modSettings['cal_enabled']))
56
		fatal_lang_error('calendar_off', false);
57
58
	// This is gonna be needed...
59
	loadTemplate('Calendar');
60
	loadCSSFile('calendar.css', array('force_current' => false, 'validate' => true, 'rtl' => 'calendar.rtl.css'), 'smf_calendar');
61
62
	// Did the specify an individual event ID? If so, let's splice the year/month in to what we would otherwise be doing.
63
	if (isset($_GET['event']))
64
	{
65
		$evid = (int) $_GET['event'];
66
		if ($evid > 0)
67
		{
68
			$request = $smcFunc['db_query']('', '
69
				SELECT start_date
70
				FROM {db_prefix}calendar
71
				WHERE id_event = {int:event_id}',
72
				array(
73
					'event_id' => $evid,
74
				)
75
			);
76
			if ($row = $smcFunc['db_fetch_assoc']($request))
77
			{
78
				$_REQUEST['start_date'] = $row['start_date'];
79
80
				// We might use this later.
81
				$context['selected_event'] = $evid;
82
			}
83
			$smcFunc['db_free_result']($request);
84
		}
85
		unset ($_GET['event']);
86
	}
87
88
	// Set the page title to mention the calendar ;).
89
	$context['page_title'] = $txt['calendar'];
90
91
	// Ensure a default view is defined
92
	if (empty($options['calendar_default_view']))
93
		$options['calendar_default_view'] = 'viewlist';
94
95
	// What view do we want?
96
	if (isset($_GET['viewweek']))
97
		$context['calendar_view'] = 'viewweek';
98
	elseif (isset($_GET['viewmonth']))
99
		$context['calendar_view'] = 'viewmonth';
100
	elseif (isset($_GET['viewlist']))
101
		$context['calendar_view'] = 'viewlist';
102
	else
103
		$context['calendar_view'] = $options['calendar_default_view'];
104
105
	// Don't let search engines index the non-default calendar pages
106
	if ($context['calendar_view'] !== $options['calendar_default_view'])
107
		$context['robot_no_index'] = true;
108
109
	// Get the current day of month...
110
	require_once($sourcedir . '/Subs-Calendar.php');
111
	$today = getTodayInfo();
112
113
	// Need a start date for all views
114
	if (!empty($_REQUEST['start_date']))
115
	{
116
		$start_parsed = date_parse($_REQUEST['start_date']);
117
		if (empty($start_parsed['error_count']) && empty($start_parsed['warning_count']))
118
		{
119
			$_REQUEST['year'] = $start_parsed['year'];
120
			$_REQUEST['month'] = $start_parsed['month'];
121
			$_REQUEST['day'] = $start_parsed['day'];
122
		}
123
	}
124
	$year = !empty($_REQUEST['year']) ? (int) $_REQUEST['year'] : $today['year'];
125
	$month = !empty($_REQUEST['month']) ? (int) $_REQUEST['month'] : $today['month'];
126
	$day = !empty($_REQUEST['day']) ? (int) $_REQUEST['day'] : (!empty($_REQUEST['month']) ? 1 : $today['day']);
127
128
	$start_object = checkdate($month, $day, $year) === true ? date_create(implode('-', array($year, $month, $day))) : date_create(implode('-', array($today['year'], $today['month'], $today['day'])));
129
130
	// Need an end date for the list view
131
	if (!empty($_REQUEST['end_date']))
132
	{
133
		$end_parsed = date_parse($_REQUEST['end_date']);
134
		if (empty($end_parsed['error_count']) && empty($end_parsed['warning_count']))
135
		{
136
			$_REQUEST['end_year'] = $end_parsed['year'];
137
			$_REQUEST['end_month'] = $end_parsed['month'];
138
			$_REQUEST['end_day'] = $end_parsed['day'];
139
		}
140
	}
141
	$end_year = !empty($_REQUEST['end_year']) ? (int) $_REQUEST['end_year'] : null;
142
	$end_month = !empty($_REQUEST['end_month']) ? (int) $_REQUEST['end_month'] : null;
143
	$end_day = !empty($_REQUEST['end_day']) ? (int) $_REQUEST['end_day'] : null;
144
145
	$end_object = checkdate($end_month, $end_day, $end_year) === true ? date_create(implode('-', array($end_year, $end_month, $end_day))) : null;
146
147
	if (empty($end_object) || $start_object >= $end_object)
148
	{
149
		$num_days_shown = empty($modSettings['cal_days_for_index']) || $modSettings['cal_days_for_index'] < 1 ? 1 : $modSettings['cal_days_for_index'];
150
151
		$end_object = date_create(date_format($start_object, 'Y-m-d'));
152
153
		date_add($end_object, date_interval_create_from_date_string($num_days_shown . ' days'));
154
	}
155
156
	$curPage = array(
157
		'year' => date_format($start_object, 'Y'),
158
		'month' => date_format($start_object, 'n'),
159
		'day' => date_format($start_object, 'j'),
160
		'start_date' => date_format($start_object, 'Y-m-d'),
161
		'end_year' => date_format($end_object, 'Y'),
162
		'end_month' => date_format($end_object, 'n'),
163
		'end_day' => date_format($end_object, 'j'),
164
		'end_date' => date_format($end_object, 'Y-m-d'),
165
	);
166
167
	// Make sure the year and month are in valid ranges.
168
	if ($curPage['month'] < 1 || $curPage['month'] > 12)
169
		fatal_lang_error('invalid_month', false);
170
	if ($curPage['year'] < $modSettings['cal_minyear'] || $curPage['year'] > $modSettings['cal_maxyear'])
171
		fatal_lang_error('invalid_year', false);
172
	// If we have a day clean that too.
173
	if ($context['calendar_view'] != 'viewmonth')
174
	{
175
		$isValid = checkdate($curPage['month'], $curPage['day'], $curPage['year']);
176
		if (!$isValid)
177
			fatal_lang_error('invalid_day', false);
178
	}
179
180
	// Load all the context information needed to show the calendar grid.
181
	$calendarOptions = array(
182
		'start_day' => !empty($options['calendar_start_day']) ? $options['calendar_start_day'] : 0,
183
		'show_birthdays' => in_array($modSettings['cal_showbdays'], array(1, 2)),
184
		'show_events' => in_array($modSettings['cal_showevents'], array(1, 2)),
185
		'show_holidays' => in_array($modSettings['cal_showholidays'], array(1, 2)),
186
		'show_week_num' => true,
187
		'short_day_titles' => !empty($modSettings['cal_short_days']),
188
		'short_month_titles' => !empty($modSettings['cal_short_months']),
189
		'show_next_prev' => !empty($modSettings['cal_prev_next_links']),
190
		'show_week_links' => isset($modSettings['cal_week_links']) ? $modSettings['cal_week_links'] : 0,
191
	);
192
193
	// Load up the main view.
194
	if ($context['calendar_view'] == 'viewlist')
195
		$context['calendar_grid_main'] = getCalendarList($curPage['start_date'], $curPage['end_date'], $calendarOptions);
196
	elseif ($context['calendar_view'] == 'viewweek')
197
		$context['calendar_grid_main'] = getCalendarWeek($curPage['start_date'], $calendarOptions);
198
	else
199
		$context['calendar_grid_main'] = getCalendarGrid($curPage['start_date'], $calendarOptions);
200
201
	// Load up the previous and next months.
202
	$context['calendar_grid_current'] = getCalendarGrid($curPage['start_date'], $calendarOptions);
203
204
	// Only show previous month if it isn't pre-January of the min-year
205
	if ($context['calendar_grid_current']['previous_calendar']['year'] > $modSettings['cal_minyear'] || $curPage['month'] != 1)
206
		$context['calendar_grid_prev'] = getCalendarGrid($context['calendar_grid_current']['previous_calendar']['start_date'], $calendarOptions, true);
207
208
	// Only show next month if it isn't post-December of the max-year
209
	if ($context['calendar_grid_current']['next_calendar']['year'] < $modSettings['cal_maxyear'] || $curPage['month'] != 12)
210
		$context['calendar_grid_next'] = getCalendarGrid($context['calendar_grid_current']['next_calendar']['start_date'], $calendarOptions);
211
212
	// Basic template stuff.
213
	$context['allow_calendar_event'] = allowedTo('calendar_post');
214
215
	// If you don't allow events not linked to posts and you're not an admin, we have more work to do...
216
	if ($context['allow_calendar_event'] && empty($modSettings['cal_allow_unlinked']) && !$user_info['is_admin'])
217
	{
218
		$boards_can_post = boardsAllowedTo('post_new');
219
		$context['allow_calendar_event'] &= !empty($boards_can_post);
220
	}
221
222
	$context['can_post'] = $context['allow_calendar_event'];
223
	$context['current_day'] = $curPage['day'];
224
	$context['current_month'] = $curPage['month'];
225
	$context['current_year'] = $curPage['year'];
226
	$context['show_all_birthdays'] = isset($_GET['showbd']);
227
	$context['blocks_disabled'] = !empty($modSettings['cal_disable_prev_next']) ? 1 : 0;
228
229
	// Set the page title to mention the month or week, too
230
	if ($context['calendar_view'] != 'viewlist')
231
		$context['page_title'] .= ' - ' . ($context['calendar_view'] == 'viewweek' ? $context['calendar_grid_main']['week_title'] : $txt['months'][$context['current_month']] . ' ' . $context['current_year']);
232
233
	// Load up the linktree!
234
	$context['linktree'][] = array(
235
		'url' => $scripturl . '?action=calendar',
236
		'name' => $txt['calendar']
237
	);
238
	// Add the current month to the linktree.
239
	$context['linktree'][] = array(
240
		'url' => $scripturl . '?action=calendar;year=' . $context['current_year'] . ';month=' . $context['current_month'],
241
		'name' => $txt['months'][$context['current_month']] . ' ' . $context['current_year']
242
	);
243
	// If applicable, add the current week to the linktree.
244
	if ($context['calendar_view'] == 'viewweek')
245
		$context['linktree'][] = array(
246
			'url' => $scripturl . '?action=calendar;viewweek;year=' . $context['current_year'] . ';month=' . $context['current_month'] . ';day=' . $context['current_day'],
247
			'name' => $context['calendar_grid_main']['week_title'],
248
		);
249
250
	// Build the calendar button array.
251
	$context['calendar_buttons'] = array();
252
253
	if ($context['can_post'])
254
		$context['calendar_buttons']['post_event'] = array('text' => 'calendar_post_event', 'image' => 'calendarpe.png', 'url' => $scripturl . '?action=calendar;sa=post;month=' . $context['current_month'] . ';year=' . $context['current_year'] . ';' . $context['session_var'] . '=' . $context['session_id']);
255
256
	// Allow mods to add additional buttons here
257
	call_integration_hook('integrate_calendar_buttons');
258
}
259
260
/**
261
 * This function processes posting/editing/deleting a calendar event.
262
 *
263
 * 	- calls {@link Post.php|Post() Post()} function if event is linked to a post.
264
 *  - calls {@link Subs-Calendar.php|insertEvent() insertEvent()} to insert the event if not linked to post.
265
 *
266
 * It requires the calendar_post permission to use.
267
 * It uses the event_post sub template in the Calendar template.
268
 * It is accessed with ?action=calendar;sa=post.
269
 */
270
function CalendarPost()
271
{
272
	global $context, $txt, $user_info, $sourcedir, $scripturl;
273
	global $modSettings, $topic, $smcFunc;
274
275
	// Well - can they?
276
	isAllowedTo('calendar_post');
277
278
	// We need these for all kinds of useful functions.
279
	require_once($sourcedir . '/Subs-Calendar.php');
280
	require_once($sourcedir . '/Subs.php');
281
282
	// Cast this for safety...
283
	if (isset($_REQUEST['eventid']))
284
		$_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
285
286
	// We want a fairly compact version of the time, but as close as possible to the user's settings.
287
	$time_string = strtr(get_date_or_time_format('time'), array(
288
		'%I' => '%l',
289
		'%H' => '%k',
290
		'%S' => '',
291
		'%r' => '%l:%M %p',
292
		'%R' => '%k:%M',
293
		'%T' => '%l:%M',
294
	));
295
296
	// Submitting?
297
	if (isset($_POST[$context['session_var']], $_REQUEST['eventid']))
298
	{
299
		checkSession();
300
301
		// Validate the post...
302
		if (!isset($_POST['link_to_board']))
303
			validateEventPost();
304
305
		// If you're not allowed to edit any events, you have to be the poster.
306
		if ($_REQUEST['eventid'] > 0 && !allowedTo('calendar_edit_any'))
307
			isAllowedTo('calendar_edit_' . (!empty($user_info['id']) && getEventPoster($_REQUEST['eventid']) == $user_info['id'] ? 'own' : 'any'));
308
309
		// New - and directing?
310
		if (isset($_POST['link_to_board']) || empty($modSettings['cal_allow_unlinked']))
311
		{
312
			$_REQUEST['calendar'] = 1;
313
			require_once($sourcedir . '/Post.php');
314
			return Post();
315
		}
316
		// New...
317
		elseif ($_REQUEST['eventid'] == -1)
318
		{
319
			$eventOptions = array(
320
				'board' => 0,
321
				'topic' => 0,
322
				'title' => $smcFunc['substr']($_REQUEST['evtitle'], 0, 100),
323
				'location' => $smcFunc['substr']($_REQUEST['event_location'], 0, 255),
324
				'member' => $user_info['id'],
325
			);
326
			insertEvent($eventOptions);
327
		}
328
329
		// Deleting...
330
		elseif (isset($_REQUEST['deleteevent']))
331
			removeEvent($_REQUEST['eventid']);
332
333
		// ... or just update it?
334
		else
335
		{
336
			$eventOptions = array(
337
				'title' => $smcFunc['substr']($_REQUEST['evtitle'], 0, 100),
338
				'location' => $smcFunc['substr']($_REQUEST['event_location'], 0, 255),
339
			);
340
			modifyEvent($_REQUEST['eventid'], $eventOptions);
341
		}
342
343
		updateSettings(array(
344
			'calendar_updated' => time(),
345
		));
346
347
		// No point hanging around here now...
348
		if (isset($_POST['start_date']))
349
		{
350
			$d = date_parse($_POST['start_date']);
351
			$year = $d['year'];
352
			$month = $d['month'];
353
			$day = $d['day'];
354
		}
355
		elseif (isset($_POST['start_datetime']))
356
		{
357
			$d = date_parse($_POST['start_datetime']);
358
			$year = $d['year'];
359
			$month = $d['month'];
360
			$day = $d['day'];
361
		}
362
		else
363
		{
364
			$today = getdate();
365
			$year = isset($_POST['year']) ? $_POST['year'] : $today['year'];
366
			$month = isset($_POST['month']) ? $_POST['month'] : $today['mon'];
367
			$day = isset($_POST['day']) ? $_POST['day'] : $today['mday'];
368
		}
369
		redirectexit($scripturl . '?action=calendar;month=' . $month . ';year=' . $year . ';day=' . $day);
370
	}
371
372
	// If we are not enabled... we are not enabled.
373
	if (empty($modSettings['cal_allow_unlinked']) && empty($_REQUEST['eventid']))
374
	{
375
		$_REQUEST['calendar'] = 1;
376
		require_once($sourcedir . '/Post.php');
377
		return Post();
0 ignored issues
show
Are you sure the usage of Post() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
378
	}
379
380
	// New?
381
	if (!isset($_REQUEST['eventid']))
382
	{
383
		$context['event'] = array(
384
			'boards' => array(),
385
			'board' => 0,
386
			'new' => 1,
387
			'eventid' => -1,
388
			'title' => '',
389
			'location' => '',
390
		);
391
392
		$eventDatetimes = getNewEventDatetimes();
393
		$context['event'] = array_merge($context['event'], $eventDatetimes);
394
395
		$context['event']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['event']['month'] == 12 ? 1 : $context['event']['month'] + 1, 0, $context['event']['month'] == 12 ? $context['event']['year'] + 1 : $context['event']['year']));
396
	}
397
	else
398
	{
399
		$context['event'] = getEventProperties($_REQUEST['eventid']);
400
401
		if ($context['event'] === false)
402
			fatal_lang_error('no_access', false);
403
404
		// If it has a board, then they should be editing it within the topic.
405
		if (!empty($context['event']['topic']['id']) && !empty($context['event']['topic']['first_msg']))
406
		{
407
			// We load the board up, for a check on the board access rights...
408
			$topic = $context['event']['topic']['id'];
409
			loadBoard();
410
		}
411
412
		// Make sure the user is allowed to edit this event.
413
		if ($context['event']['member'] != $user_info['id'])
414
			isAllowedTo('calendar_edit_any');
415
		elseif (!allowedTo('calendar_edit_any'))
416
			isAllowedTo('calendar_edit_own');
417
	}
418
419
	// An all day event? Set up some nice defaults in case the user wants to change that
420
	if ($context['event']['allday'] == true)
421
	{
422
		$context['event']['tz'] = getUserTimezone();
423
		$context['event']['start_time'] = timeformat(time(), $time_string);
424
		$context['event']['end_time'] = timeformat(time() + 3600, $time_string);
425
	}
426
	// Otherwise, just adjust these to look nice on the input form
427
	else
428
	{
429
		$context['event']['start_time'] = $context['event']['start_time_orig'];
430
		$context['event']['end_time'] = $context['event']['end_time_orig'];
431
	}
432
433
	// Need this so the user can select a timezone for the event.
434
	$context['all_timezones'] = smf_list_timezones($context['event']['start_date']);
435
436
	// If the event's timezone is not in SMF's standard list of time zones, try to fix it.
437
	if (!isset($context['all_timezones'][$context['event']['tz']]))
438
	{
439
		$later = strtotime('@' . $context['event']['start_timestamp'] . ' + 1 year');
440
		$tzinfo = timezone_transitions_get(timezone_open($context['event']['tz']), $context['event']['start_timestamp'], $later);
441
442
		$found = false;
443
		foreach ($context['all_timezones'] as $possible_tzid => $dummy)
444
		{
445
			$possible_tzinfo = timezone_transitions_get(timezone_open($possible_tzid), $context['event']['start_timestamp'], $later);
446
447
			if ($tzinfo === $possible_tzinfo)
448
			{
449
				$context['event']['tz'] = $possible_tzid;
450
				$found = true;
451
				break;
452
			}
453
		}
454
455
		// Hm. That's weird. Well, just prepend it to the list and let the user deal with it.
456
		if (!$found)
457
		{
458
			$d = date_create($context['event']['start_datetime'] . ' ' . $context['event']['tz']);
459
			$context['all_timezones'] = array($context['event']['tz'] => '[UTC' . date_format($d, 'P') . '] - ' . $context['event']['tz']) + $context['all_timezones'];
460
		}
461
	}
462
463
	// Get list of boards that can be posted in.
464
	$boards = boardsAllowedTo('post_new');
465
	if (empty($boards))
466
	{
467
		// You can post new events but can't link them to anything...
468
		$context['event']['categories'] = array();
469
	}
470
	else
471
	{
472
		// Load the list of boards and categories in the context.
473
		require_once($sourcedir . '/Subs-MessageIndex.php');
474
		$boardListOptions = array(
475
			'included_boards' => in_array(0, $boards) ? null : $boards,
476
			'not_redirection' => true,
477
			'use_permissions' => true,
478
			'selected_board' => $modSettings['cal_defaultboard'],
479
		);
480
		$context['event']['categories'] = getBoardList($boardListOptions);
481
	}
482
483
	// Template, sub template, etc.
484
	loadTemplate('Calendar');
485
	$context['sub_template'] = 'event_post';
486
487
	$context['page_title'] = isset($_REQUEST['eventid']) ? $txt['calendar_edit'] : $txt['calendar_post_event'];
488
	$context['linktree'][] = array(
489
		'name' => $context['page_title'],
490
	);
491
492
	loadDatePicker('#event_time_input .date_input');
493
	loadTimePicker('#event_time_input .time_input', $time_string);
494
	loadDatePair('#event_time_input', 'date_input', 'time_input');
495
	addInlineJavaScript('
496
	$("#allday").click(function(){
497
		$("#start_time").attr("disabled", this.checked);
498
		$("#end_time").attr("disabled", this.checked);
499
		$("#tz").attr("disabled", this.checked);
500
	});', true);
501
}
502
503
/**
504
 * This function offers up a download of an event in iCal 2.0 format.
505
 *
506
 * Follows the conventions in {@link https://tools.ietf.org/html/rfc5546 RFC5546}
507
 * Sets events as all day events since we don't have hourly events
508
 * Will honor and set multi day events
509
 * Sets a sequence number if the event has been modified
510
 *
511
 * @todo .... allow for week or month export files as well?
512
 */
513
function iCalDownload()
514
{
515
	global $smcFunc, $sourcedir, $modSettings, $webmaster_email, $mbname;
516
517
	// You can't export if the calendar export feature is off.
518
	if (empty($modSettings['cal_export']))
519
		fatal_lang_error('calendar_export_off', false);
520
521
	// Goes without saying that this is required.
522
	if (!isset($_REQUEST['eventid']))
523
		fatal_lang_error('no_access', false);
524
525
	// This is kinda wanted.
526
	require_once($sourcedir . '/Subs-Calendar.php');
527
528
	// Load up the event in question and check it exists.
529
	$event = getEventProperties($_REQUEST['eventid']);
530
531
	if ($event === false)
0 ignored issues
show
The condition $event === false is always false.
Loading history...
532
		fatal_lang_error('no_access', false);
533
534
	// Check the title isn't too long - iCal requires some formatting if so.
535
	$title = str_split($event['title'], 30);
536
	foreach ($title as $id => $line)
537
	{
538
		if ($id != 0)
539
			$title[$id] = ' ' . $title[$id];
540
		$title[$id] .= "\n";
541
	}
542
543
	// Format the dates.
544
	$datestamp = date('Ymd\THis\Z', time());
545
	$start_date = date_create($event['start_date'] . (isset($event['start_time']) ? ' ' . $event['start_time'] : '') . (isset($event['tz']) ? ' ' . $event['tz'] : ''));
546
	$end_date = date_create($event['end_date'] . (isset($event['end_time']) ? ' ' . $event['end_time'] : '') . (isset($event['tz']) ? ' ' . $event['tz'] : ''));
547
548
	if (!empty($event['start_time']))
549
	{
550
		$datestart = date_format($start_date, 'Ymd\THis');
551
		$dateend = date_format($end_date, 'Ymd\THis');
552
	}
553
	else
554
	{
555
		$datestart = date_format($start_date, 'Ymd');
556
557
		date_add($end_date, date_interval_create_from_date_string('1 day'));
558
		$dateend = date_format($end_date, 'Ymd');
559
	}
560
561
	// This is what we will be sending later
562
	$filecontents = '';
563
	$filecontents .= 'BEGIN:VCALENDAR' . "\n";
564
	$filecontents .= 'METHOD:PUBLISH' . "\n";
565
	$filecontents .= 'PRODID:-//SimpleMachines//' . SMF_FULL_VERSION . '//EN' . "\n";
566
	$filecontents .= 'VERSION:2.0' . "\n";
567
	$filecontents .= 'BEGIN:VEVENT' . "\n";
568
	// @TODO - Should be the members email who created the event rather than $webmaster_email.
569
	$filecontents .= 'ORGANIZER;CN="' . $event['realname'] . '":MAILTO:' . $webmaster_email . "\n";
570
	$filecontents .= 'DTSTAMP:' . $datestamp . "\n";
571
	$filecontents .= 'DTSTART' . (!empty($event['start_time']) ? ';TZID=' . $event['tz'] : ';VALUE=DATE') . ':' . $datestart . "\n";
572
573
	// event has a duration
574
	if ($event['start_iso_gmdate'] != $event['end_iso_gmdate'])
575
		$filecontents .= 'DTEND' . (!empty($event['end_time']) ? ';TZID=' . $event['tz'] : ';VALUE=DATE') . ':' . $dateend . "\n";
576
577
	// event has changed? advance the sequence for this UID
578
	if ($event['sequence'] > 0)
579
		$filecontents .= 'SEQUENCE:' . $event['sequence'] . "\n";
580
581
	if (!empty($event['location']))
582
		$filecontents .= 'LOCATION:' . str_replace(',', '\,', $event['location']) . "\n";
583
584
	$filecontents .= 'SUMMARY:' . implode('', $title);
585
	$filecontents .= 'UID:' . $event['eventid'] . '@' . str_replace(' ', '-', $mbname) . "\n";
586
	$filecontents .= 'END:VEVENT' . "\n";
587
	$filecontents .= 'END:VCALENDAR';
588
589
	// Send some standard headers.
590
	ob_end_clean();
591
	if (!empty($modSettings['enableCompressedOutput']))
592
		@ob_start('ob_gzhandler');
593
	else
594
		ob_start();
595
596
	// Send the file headers
597
	header('pragma: ');
598
	header('cache-control: no-cache');
599
	if (!isBrowser('gecko'))
600
		header('content-transfer-encoding: binary');
601
	header('expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT');
602
	header('last-modified: ' . gmdate('D, d M Y H:i:s', time()) . 'GMT');
603
	header('accept-ranges: bytes');
604
	header('connection: close');
605
	header('content-disposition: attachment; filename="' . $event['title'] . '.ics"');
606
	if (empty($modSettings['enableCompressedOutput']))
607
		header('content-length: ' . $smcFunc['strlen']($filecontents));
608
609
	// This is a calendar item!
610
	header('content-type: text/calendar');
611
612
	// Chuck out the card.
613
	echo $filecontents;
614
615
	// Off we pop - lovely!
616
	obExit(false);
617
}
618
619
/**
620
 * Nothing to see here. Move along.
621
 */
622
function clock()
623
{
624
	global $smcFunc, $settings, $context, $scripturl;
625
626
	$context['onimg'] = $settings['images_url'] . '/bbc/bbc_hoverbg.png';
627
	$context['offimg'] = $settings['images_url'] . '/bbc/bbc_bg.png';
628
629
	$context['page_title'] = 'Anyone know what time it is?';
630
	$context['linktree'][] = array(
631
		'url' => $scripturl . '?action=clock',
632
		'name' => 'Clock',
633
	);
634
	$context['robot_no_index'] = true;
635
636
	$omfg = isset($_REQUEST['omfg']);
637
	$bcd = !isset($_REQUEST['rb']) && !isset($_REQUEST['omfg']) && !isset($_REQUEST['time']);
638
639
	loadTemplate('Calendar');
640
641
	if ($bcd)
642
	{
643
		$context['sub_template'] = 'bcd';
644
		$context['linktree'][] = array('url' => $scripturl . '?action=clock;bcd', 'name' => 'BCD');
645
		$context['clockicons'] = $smcFunc['json_decode'](base64_decode('eyJoMSI6WzIsMV0sImgyIjpbOCw0LDIsMV0sIm0xIjpbNCwyLDFdLCJtMiI6WzgsNCwyLDFdLCJzMSI6WzQsMiwxXSwiczIiOls4LDQsMiwxXX0='), true);
646
	}
647
	elseif (!$omfg && !isset($_REQUEST['time']))
648
	{
649
		$context['sub_template'] = 'hms';
650
		$context['linktree'][] = array('url' => $scripturl . '?action=clock', 'name' => 'Binary');
651
		$context['clockicons'] = $smcFunc['json_decode'](base64_decode('eyJoIjpbMTYsOCw0LDIsMV0sIm0iOlszMiwxNiw4LDQsMiwxXSwicyI6WzMyLDE2LDgsNCwyLDFdfQ'), true);
652
	}
653
	elseif ($omfg)
654
	{
655
		$context['sub_template'] = 'omfg';
656
		$context['linktree'][] = array('url' => $scripturl . '?action=clock;omfg', 'name' => 'OMFG');
657
		$context['clockicons'] = $smcFunc['json_decode'](base64_decode('eyJ5ZWFyIjpbNjQsMzIsMTYsOCw0LDIsMV0sIm1vbnRoIjpbOCw0LDIsMV0sImRheSI6WzE2LDgsNCwyLDFdLCJob3VyIjpbMTYsOCw0LDIsMV0sIm1pbiI6WzMyLDE2LDgsNCwyLDFdLCJzZWMiOlszMiwxNiw4LDQsMiwxXX0='), true);
658
	}
659
	elseif (isset($_REQUEST['time']))
660
	{
661
		$context['sub_template'] = 'thetime';
662
		$time = getdate($_REQUEST['time'] == 'now' ? time() : (int) $_REQUEST['time']);
663
		$context['linktree'][] = array('url' => $scripturl . '?action=clock;time=' . $_REQUEST['time'], 'name' => 'Requested Time');
664
		$context['clockicons'] = array(
665
			'year' => array(
666
				64 => false,
667
				32 => false,
668
				16 => false,
669
				8 => false,
670
				4 => false,
671
				2 => false,
672
				1 => false
673
			),
674
			'month' => array(
675
				8 => false,
676
				4 => false,
677
				2 => false,
678
				1 => false
679
			),
680
			'day' => array(
681
				16 => false,
682
				4 => false,
683
				8 => false,
684
				2 => false,
685
				1 => false
686
			),
687
			'hour' => array(
688
				32 => false,
689
				16 => false,
690
				8 => false,
691
				4 => false,
692
				2 => false,
693
				1 => false
694
			),
695
			'min' => array(
696
				32 => false,
697
				16 => false,
698
				8 => false,
699
				4 => false,
700
				2 => false,
701
				1 => false
702
			),
703
			'sec' => array(
704
				32 => false,
705
				16 => false,
706
				8 => false,
707
				4 => false,
708
				2 => false,
709
				1 => false
710
			),
711
		);
712
713
		foreach ($context['clockicons'] as $t => $vs)
714
			foreach ($vs as $v => $dumb)
715
			{
716
				if ($$t >= $v)
717
				{
718
					$$t -= $v;
719
					$context['clockicons'][$t][$v] = true;
720
				}
721
			}
722
	}
723
}
724
725
?>