Calendar.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. <?php
  2. /**
  3. * Simple Machines Forum (SMF)
  4. *
  5. * @package SMF
  6. * @author Simple Machines http://www.simplemachines.org
  7. * @copyright 2011 Simple Machines
  8. * @license http://www.simplemachines.org/about/smf/license.php BSD
  9. *
  10. * @version 2.0
  11. */
  12. // Original module by Aaron O'Neil - [email protected]
  13. if (!defined('SMF'))
  14. die('Hacking attempt...');
  15. /* This file has only one real task... showing the calendar. Posting is done
  16. in Post.php - this just has the following functions:
  17. void CalendarMain()
  18. - loads the specified month's events, holidays, and birthdays.
  19. - requires the calendar_view permission.
  20. - depends on the cal_enabled setting, and many of the other cal_
  21. settings.
  22. - uses the calendar_start_day theme option. (Monday/Sunday)
  23. - uses the main sub template in the Calendar template.
  24. - goes to the month and year passed in 'month' and 'year' by
  25. get or post.
  26. - accessed through ?action=calendar.
  27. void CalendarPost()
  28. - processes posting/editing/deleting a calendar event.
  29. - calls Post() function if event is linked to a post.
  30. - calls insertEvent() to insert the event if not linked to post.
  31. - requires the calendar_post permission to use.
  32. - uses the event_post sub template in the Calendar template.
  33. - is accessed with ?action=calendar;sa=post.
  34. void iCalDownload()
  35. - offers up a download of an event in iCal 2.0 format.
  36. */
  37. // Show the calendar.
  38. function CalendarMain()
  39. {
  40. global $txt, $context, $modSettings, $scripturl, $options, $sourcedir;
  41. // Permissions, permissions, permissions.
  42. isAllowedTo('calendar_view');
  43. // Doing something other than calendar viewing?
  44. $subActions = array(
  45. 'ical' => 'iCalDownload',
  46. 'post' => 'CalendarPost',
  47. );
  48. if (isset($_GET['sa']) && isset($subActions[$_GET['sa']]) && !WIRELESS)
  49. return $subActions[$_GET['sa']]();
  50. // This is gonna be needed...
  51. loadTemplate('Calendar');
  52. // You can't do anything if the calendar is off.
  53. if (empty($modSettings['cal_enabled']))
  54. fatal_lang_error('calendar_off', false);
  55. // Set the page title to mention the calendar ;).
  56. $context['page_title'] = $txt['calendar'];
  57. // Is this a week view?
  58. $context['view_week'] = isset($_GET['viewweek']);
  59. // Don't let search engines index weekly calendar pages.
  60. if ($context['view_week'])
  61. $context['robot_no_index'] = true;
  62. // Get the current day of month...
  63. require_once($sourcedir . '/Subs-Calendar.php');
  64. $today = getTodayInfo();
  65. // If the month and year are not passed in, use today's date as a starting point.
  66. $curPage = array(
  67. 'day' => isset($_REQUEST['day']) ? (int) $_REQUEST['day'] : $today['day'],
  68. 'month' => isset($_REQUEST['month']) ? (int) $_REQUEST['month'] : $today['month'],
  69. 'year' => isset($_REQUEST['year']) ? (int) $_REQUEST['year'] : $today['year']
  70. );
  71. // Make sure the year and month are in valid ranges.
  72. if ($curPage['month'] < 1 || $curPage['month'] > 12)
  73. fatal_lang_error('invalid_month', false);
  74. if ($curPage['year'] < $modSettings['cal_minyear'] || $curPage['year'] > $modSettings['cal_maxyear'])
  75. fatal_lang_error('invalid_year', false);
  76. // If we have a day clean that too.
  77. if ($context['view_week'])
  78. {
  79. // Note $isValid is -1 < PHP 5.1
  80. $isValid = mktime(0, 0, 0, $curPage['month'], $curPage['day'], $curPage['year']);
  81. if ($curPage['day'] > 31 || !$isValid || $isValid == -1)
  82. fatal_lang_error('invalid_day', false);
  83. }
  84. // Load all the context information needed to show the calendar grid.
  85. $calendarOptions = array(
  86. 'start_day' => !empty($options['calendar_start_day']) ? $options['calendar_start_day'] : 0,
  87. 'show_birthdays' => in_array($modSettings['cal_showbdays'], array(1, 2)),
  88. 'show_events' => in_array($modSettings['cal_showevents'], array(1, 2)),
  89. 'show_holidays' => in_array($modSettings['cal_showholidays'], array(1, 2)),
  90. 'show_week_num' => true,
  91. 'short_day_titles' => false,
  92. 'show_next_prev' => true,
  93. 'show_week_links' => true,
  94. 'size' => 'large',
  95. );
  96. // Load up the main view.
  97. if ($context['view_week'])
  98. $context['calendar_grid_main'] = getCalendarWeek($curPage['month'], $curPage['year'], $curPage['day'], $calendarOptions);
  99. else
  100. $context['calendar_grid_main'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions);
  101. // Load up the previous and next months.
  102. $calendarOptions['show_birthdays'] = $calendarOptions['show_events'] = $calendarOptions['show_holidays'] = false;
  103. $calendarOptions['short_day_titles'] = true;
  104. $calendarOptions['show_next_prev'] = false;
  105. $calendarOptions['show_week_links'] = false;
  106. $calendarOptions['size'] = 'small';
  107. $context['calendar_grid_current'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions);
  108. // Only show previous month if it isn't pre-January of the min-year
  109. if ($context['calendar_grid_current']['previous_calendar']['year'] > $modSettings['cal_minyear'] || $curPage['month'] != 1)
  110. $context['calendar_grid_prev'] = getCalendarGrid($context['calendar_grid_current']['previous_calendar']['month'], $context['calendar_grid_current']['previous_calendar']['year'], $calendarOptions);
  111. // Only show next month if it isn't post-December of the max-year
  112. if ($context['calendar_grid_current']['next_calendar']['year'] < $modSettings['cal_maxyear'] || $curPage['month'] != 12)
  113. $context['calendar_grid_next'] = getCalendarGrid($context['calendar_grid_current']['next_calendar']['month'], $context['calendar_grid_current']['next_calendar']['year'], $calendarOptions);
  114. // Basic template stuff.
  115. $context['can_post'] = allowedTo('calendar_post');
  116. $context['current_day'] = $curPage['day'];
  117. $context['current_month'] = $curPage['month'];
  118. $context['current_year'] = $curPage['year'];
  119. $context['show_all_birthdays'] = isset($_GET['showbd']);
  120. // Set the page title to mention the month or week, too
  121. $context['page_title'] .= ' - ' . ($context['view_week'] ? sprintf($txt['calendar_week_title'], $context['calendar_grid_main']['week_number'], ($context['calendar_grid_main']['week_number'] == 53 ? $context['current_year'] - 1 : $context['current_year'])) : $txt['months'][$context['current_month']] . ' ' . $context['current_year']);
  122. // Load up the linktree!
  123. $context['linktree'][] = array(
  124. 'url' => $scripturl . '?action=calendar',
  125. 'name' => $txt['calendar']
  126. );
  127. // Add the current month to the linktree.
  128. $context['linktree'][] = array(
  129. 'url' => $scripturl . '?action=calendar;year=' . $context['current_year'] . ';month=' . $context['current_month'],
  130. 'name' => $txt['months'][$context['current_month']] . ' ' . $context['current_year']
  131. );
  132. // If applicable, add the current week to the linktree.
  133. if ($context['view_week'])
  134. $context['linktree'][] = array(
  135. 'url' => $scripturl . '?action=calendar;viewweek;year=' . $context['current_year'] . ';month=' . $context['current_month'] . ';day=' . $context['current_day'],
  136. 'name' => $txt['calendar_week'] . ' ' . $context['calendar_grid_main']['week_number']
  137. );
  138. }
  139. function CalendarPost()
  140. {
  141. global $context, $txt, $user_info, $sourcedir, $scripturl;
  142. global $modSettings, $topic, $smcFunc;
  143. // Well - can they?
  144. isAllowedTo('calendar_post');
  145. // We need this for all kinds of useful functions.
  146. require_once($sourcedir . '/Subs-Calendar.php');
  147. // Cast this for safety...
  148. if (isset($_REQUEST['eventid']))
  149. $_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
  150. // Submitting?
  151. if (isset($_POST[$context['session_var']], $_REQUEST['eventid']))
  152. {
  153. checkSession();
  154. // Validate the post...
  155. if (!isset($_POST['link_to_board']))
  156. validateEventPost();
  157. // If you're not allowed to edit any events, you have to be the poster.
  158. if ($_REQUEST['eventid'] > 0 && !allowedTo('calendar_edit_any'))
  159. isAllowedTo('calendar_edit_' . (!empty($user_info['id']) && getEventPoster($_REQUEST['eventid']) == $user_info['id'] ? 'own' : 'any'));
  160. // New - and directing?
  161. if ($_REQUEST['eventid'] == -1 && isset($_POST['link_to_board']))
  162. {
  163. $_REQUEST['calendar'] = 1;
  164. require_once($sourcedir . '/Post.php');
  165. return Post();
  166. }
  167. // New...
  168. elseif ($_REQUEST['eventid'] == -1)
  169. {
  170. $eventOptions = array(
  171. 'board' => 0,
  172. 'topic' => 0,
  173. 'title' => substr($_REQUEST['evtitle'], 0, 60),
  174. 'member' => $user_info['id'],
  175. 'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']),
  176. 'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0,
  177. );
  178. insertEvent($eventOptions);
  179. }
  180. // Deleting...
  181. elseif (isset($_REQUEST['deleteevent']))
  182. removeEvent($_REQUEST['eventid']);
  183. // ... or just update it?
  184. else
  185. {
  186. $eventOptions = array(
  187. 'title' => substr($_REQUEST['evtitle'], 0, 60),
  188. 'span' => empty($modSettings['cal_allowspan']) || empty($_POST['span']) || $_POST['span'] == 1 || empty($modSettings['cal_maxspan']) || $_POST['span'] > $modSettings['cal_maxspan'] ? 0 : min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1),
  189. 'start_date' => strftime('%Y-%m-%d', mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year'])),
  190. );
  191. modifyEvent($_REQUEST['eventid'], $eventOptions);
  192. }
  193. updateSettings(array(
  194. 'calendar_updated' => time(),
  195. ));
  196. // No point hanging around here now...
  197. redirectexit($scripturl . '?action=calendar;month=' . $_POST['month'] . ';year=' . $_POST['year']);
  198. }
  199. // If we are not enabled... we are not enabled.
  200. if (empty($modSettings['cal_allow_unlinked']) && empty($_REQUEST['eventid']))
  201. {
  202. $_REQUEST['calendar'] = 1;
  203. require_once($sourcedir . '/Post.php');
  204. return Post();
  205. }
  206. // New?
  207. if (!isset($_REQUEST['eventid']))
  208. {
  209. $today = getdate();
  210. $context['event'] = array(
  211. 'boards' => array(),
  212. 'board' => 0,
  213. 'new' => 1,
  214. 'eventid' => -1,
  215. 'year' => isset($_REQUEST['year']) ? $_REQUEST['year'] : $today['year'],
  216. 'month' => isset($_REQUEST['month']) ? $_REQUEST['month'] : $today['mon'],
  217. 'day' => isset($_REQUEST['day']) ? $_REQUEST['day'] : $today['mday'],
  218. 'title' => '',
  219. 'span' => 1,
  220. );
  221. $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']));
  222. // Get list of boards that can be posted in.
  223. $boards = boardsAllowedTo('post_new');
  224. if (empty($boards))
  225. fatal_lang_error('cannot_post_new', 'permission');
  226. // Load the list of boards and categories in the context.
  227. require_once($sourcedir . '/Subs-MessageIndex.php');
  228. $boardListOptions = array(
  229. 'included_boards' => in_array(0, $boards) ? null : $boards,
  230. 'not_redirection' => true,
  231. 'use_permissions' => true,
  232. 'selected_board' => $modSettings['cal_defaultboard'],
  233. );
  234. $context['event']['categories'] = getBoardList($boardListOptions);
  235. }
  236. else
  237. {
  238. $context['event'] = getEventProperties($_REQUEST['eventid']);
  239. if ($context['event'] === false)
  240. fatal_lang_error('no_access', false);
  241. // If it has a board, then they should be editing it within the topic.
  242. if (!empty($context['event']['topic']['id']) && !empty($context['event']['topic']['first_msg']))
  243. {
  244. // We load the board up, for a check on the board access rights...
  245. $topic = $context['event']['topic']['id'];
  246. loadBoard();
  247. }
  248. // Make sure the user is allowed to edit this event.
  249. if ($context['event']['member'] != $user_info['id'])
  250. isAllowedTo('calendar_edit_any');
  251. elseif (!allowedTo('calendar_edit_any'))
  252. isAllowedTo('calendar_edit_own');
  253. }
  254. // Template, sub template, etc.
  255. loadTemplate('Calendar');
  256. $context['sub_template'] = 'event_post';
  257. $context['page_title'] = isset($_REQUEST['eventid']) ? $txt['calendar_edit'] : $txt['calendar_post_event'];
  258. $context['linktree'][] = array(
  259. 'name' => $context['page_title'],
  260. );
  261. }
  262. function iCalDownload()
  263. {
  264. global $smcFunc, $sourcedir, $forum_version, $context, $modSettings;
  265. // Goes without saying that this is required.
  266. if (!isset($_REQUEST['eventid']))
  267. fatal_lang_error('no_access', false);
  268. // This is kinda wanted.
  269. require_once($sourcedir . '/Subs-Calendar.php');
  270. // Load up the event in question and check it exists.
  271. $event = getEventProperties($_REQUEST['eventid']);
  272. if ($event === false)
  273. fatal_lang_error('no_access', false);
  274. // Check the title isn't too long - iCal requires some formatting if so.
  275. $title = str_split($event['title'], 30);
  276. foreach ($title as $id => $line)
  277. {
  278. if ($id != 0)
  279. $title[$id] = ' ' . $title[$id];
  280. $title[$id] .= "\n";
  281. }
  282. // Format the date.
  283. $date = $event['year'] . '-' . ($event['month'] < 10 ? '0' . $event['month'] : $event['month']) . '-' . ($event['day'] < 10 ? '0' . $event['day'] : $event['day']) . 'T';
  284. $date .= '1200:00:00Z';
  285. // This is what we will be sending later.
  286. $filecontents = '';
  287. $filecontents .= 'BEGIN:VCALENDAR' . "\n";
  288. $filecontents .= 'VERSION:2.0' . "\n";
  289. $filecontents .= 'PRODID:-//SimpleMachines//SMF ' . (empty($forum_version) ? 1.0 : strtr($forum_version, array('SMF ' => ''))) . '//EN' . "\n";
  290. $filecontents .= 'BEGIN:VEVENT' . "\n";
  291. $filecontents .= 'DTSTART:' . $date . "\n";
  292. $filecontents .= 'DTEND:' . $date . "\n";
  293. $filecontents .= 'SUMMARY:' . implode('', $title);
  294. $filecontents .= 'END:VEVENT' . "\n";
  295. $filecontents .= 'END:VCALENDAR';
  296. // Send some standard headers.
  297. ob_end_clean();
  298. if (!empty($modSettings['enableCompressedOutput']))
  299. @ob_start('ob_gzhandler');
  300. else
  301. ob_start();
  302. // Send the file headers
  303. header('Pragma: ');
  304. header('Cache-Control: no-cache');
  305. if (!$context['browser']['is_gecko'])
  306. header('Content-Transfer-Encoding: binary');
  307. header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT');
  308. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . 'GMT');
  309. header('Accept-Ranges: bytes');
  310. header('Connection: close');
  311. header('Content-Disposition: attachment; filename=' . $event['title'] . '.ics');
  312. // How big is it?
  313. if (empty($modSettings['enableCompressedOutput']))
  314. header('Content-Length: ' . $smcFunc['strlen']($filecontents));
  315. // This is a calendar item!
  316. header('Content-Type: text/calendar');
  317. // Chuck out the card.
  318. echo $filecontents;
  319. // Off we pop - lovely!
  320. obExit(false);
  321. }
  322. // This is not the code you are looking for.
  323. function clock()
  324. {
  325. global $settings, $context;
  326. $context['onimg'] = $settings['images_url'] . '/bbc/bbc_bg.gif';
  327. $context['offimg'] = $settings['images_url'] . '/bbc/bbc_hoverbg.gif';
  328. $context['page_title'] = 'Anyone know what time it is?';
  329. $context['robot_no_index'] = true;
  330. $omfg = isset($_REQUEST['omfg']);
  331. $bcd = !isset($_REQUEST['rb']) && !isset($_REQUEST['omfg']) && !isset($_REQUEST['time']);
  332. loadTemplate('Calendar');
  333. if ($bcd && !$omfg)
  334. {
  335. $context['sub_template'] = 'bcd';
  336. $context['clockicons'] = unserialize(base64_decode('YTo2OntzOjI6ImgxIjthOjI6e2k6MDtpOjI7aToxO2k6MTt9czoyOiJoMiI7YTo0OntpOjA7aTo4O2k6MTtpOjQ7aToyO2k6MjtpOjM7aToxO31zOjI6Im0xIjthOjM6e2k6MDtpOjQ7aToxO2k6MjtpOjI7aToxO31zOjI6Im0yIjthOjQ6e2k6MDtpOjg7aToxO2k6NDtpOjI7aToyO2k6MztpOjE7fXM6MjoiczEiO2E6Mzp7aTowO2k6NDtpOjE7aToyO2k6MjtpOjE7fXM6MjoiczIiO2E6NDp7aTowO2k6ODtpOjE7aTo0O2k6MjtpOjI7aTozO2k6MTt9fQ=='));
  337. }
  338. elseif (!$omfg && !isset($_REQUEST['time']))
  339. {
  340. $context['sub_template'] = 'hms';
  341. $context['clockicons'] = unserialize(base64_decode('YTozOntzOjE6ImgiO2E6NTp7aTowO2k6MTY7aToxO2k6ODtpOjI7aTo0O2k6MztpOjI7aTo0O2k6MTt9czoxOiJtIjthOjY6e2k6MDtpOjMyO2k6MTtpOjE2O2k6MjtpOjg7aTozO2k6NDtpOjQ7aToyO2k6NTtpOjE7fXM6MToicyI7YTo2OntpOjA7aTozMjtpOjE7aToxNjtpOjI7aTo4O2k6MztpOjQ7aTo0O2k6MjtpOjU7aToxO319'));
  342. }
  343. elseif ($omfg)
  344. {
  345. $context['sub_template'] = 'omfg';
  346. $context['clockicons'] = unserialize(base64_decode('YTo2OntzOjQ6InllYXIiO2E6Nzp7aTowO2k6NjQ7aToxO2k6MzI7aToyO2k6MTY7aTozO2k6ODtpOjQ7aTo0O2k6NTtpOjI7aTo2O2k6MTt9czo1OiJtb250aCI7YTo0OntpOjA7aTo4O2k6MTtpOjQ7aToyO2k6MjtpOjM7aToxO31zOjM6ImRheSI7YTo1OntpOjA7aToxNjtpOjE7aTo4O2k6MjtpOjQ7aTozO2k6MjtpOjQ7aToxO31zOjQ6ImhvdXIiO2E6NTp7aTowO2k6MTY7aToxO2k6ODtpOjI7aTo0O2k6MztpOjI7aTo0O2k6MTt9czozOiJtaW4iO2E6Njp7aTowO2k6MzI7aToxO2k6MTY7aToyO2k6ODtpOjM7aTo0O2k6NDtpOjI7aTo1O2k6MTt9czozOiJzZWMiO2E6Njp7aTowO2k6MzI7aToxO2k6MTY7aToyO2k6ODtpOjM7aTo0O2k6NDtpOjI7aTo1O2k6MTt9fQ=='));
  347. }
  348. elseif (isset($_REQUEST['time']))
  349. {
  350. $context['sub_template'] = 'thetime';
  351. $time = getdate($_REQUEST['time'] == 'now' ? time() : (int) $_REQUEST['time']);
  352. $context['clockicons'] = array(
  353. 'year' => array(
  354. 64 => false,
  355. 32 => false,
  356. 16 => false,
  357. 8 => false,
  358. 4 => false,
  359. 2 => false,
  360. 1 => false
  361. ),
  362. 'month' => array(
  363. 8 => false,
  364. 4 => false,
  365. 2 => false,
  366. 1 => false
  367. ),
  368. 'day' => array(
  369. 16 => false,
  370. 4 => false,
  371. 8 => false,
  372. 2 => false,
  373. 1 => false
  374. ),
  375. 'hour' => array(
  376. 32 => false,
  377. 16 => false,
  378. 8 => false,
  379. 4 => false,
  380. 2 => false,
  381. 1 => false
  382. ),
  383. 'min' => array(
  384. 32 => false,
  385. 16 => false,
  386. 8 => false,
  387. 4 => false,
  388. 2 => false,
  389. 1 => false
  390. ),
  391. 'sec' => array(
  392. 32 => false,
  393. 16 => false,
  394. 8 => false,
  395. 4 => false,
  396. 2 => false,
  397. 1 => false
  398. ),
  399. );
  400. $year = $time['year'] % 100;
  401. $month = $time['mon'];
  402. $day = $time['mday'];
  403. $hour = $time['hours'];
  404. $min = $time['minutes'];
  405. $sec = $time['seconds'];
  406. foreach ($context['clockicons'] as $t => $vs)
  407. foreach ($vs as $v => $dumb)
  408. {
  409. if ($$t >= $v)
  410. {
  411. $$t -= $v;
  412. $context['clockicons'][$t][$v] = true;
  413. }
  414. }
  415. }
  416. }
  417. ?>