]> git.mxchange.org Git - friendica.git/blob - include/event.php
Fix require_once format
[friendica.git] / include / event.php
1 <?php
2 /**
3  * @file include/event.php
4  * @brief functions specific to event handling
5  */
6
7 use Friendica\App;
8
9 require_once 'include/bbcode.php';
10 require_once 'include/map.php';
11 require_once 'include/datetime.php';
12
13 function format_event_html($ev, $simple = false) {
14
15         if (! ((is_array($ev)) && count($ev))) {
16                 return '';
17         }
18
19         $bd_format = t('l F d, Y \@ g:i A') ; // Friday January 18, 2011 @ 8 AM
20
21         $event_start = (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(),
22                         $ev['start'] , $bd_format ))
23                         : day_translate(datetime_convert('UTC', 'UTC',
24                         $ev['start'] , $bd_format)));
25
26         $event_end = (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(),
27                                 $ev['finish'] , $bd_format ))
28                                 : day_translate(datetime_convert('UTC', 'UTC',
29                                 $ev['finish'] , $bd_format )));
30
31         if ($simple) {
32                 $o = "<h3>" . bbcode($ev['summary']) . "</h3>";
33
34                 $o .= "<p>" . bbcode($ev['desc']) . "</p>";
35
36                 $o .= "<h4>" . t('Starts:') . "</h4><p>" . $event_start . "</p>";
37
38                 if (! $ev['nofinish']) {
39                         $o .= "<h4>" . t('Finishes:') . "</h4><p>" . $event_end  ."</p>";
40                 }
41
42                 if (strlen($ev['location'])) {
43                         $o .= "<h4>" . t('Location:') . "</h4><p>" . $ev['location'] . "</p>";
44                 }
45
46                 return $o;
47         }
48
49         $o = '<div class="vevent">' . "\r\n";
50
51
52         $o .= '<p class="summary event-summary">' . bbcode($ev['summary']) . '</p>' . "\r\n";
53
54         $o .= '<p class="description event-description">' . bbcode($ev['desc']) . '</p>' . "\r\n";
55
56         $o .= '<p class="event-start">' . t('Starts:') . ' <abbr class="dtstart" title="'
57                 . datetime_convert('UTC', 'UTC', $ev['start'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' ))
58                 . '" >'.$event_start
59                 . '</abbr></p>' . "\r\n";
60
61         if (! $ev['nofinish']) {
62                 $o .= '<p class="event-end" >' . t('Finishes:') . ' <abbr class="dtend" title="'
63                         . datetime_convert('UTC', 'UTC', $ev['finish'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' ))
64                         . '" >'.$event_end
65                         . '</abbr></p>' . "\r\n";
66         }
67
68         if (strlen($ev['location'])) {
69                 $o .= '<p class="event-location"> ' . t('Location:') . ' <span class="location">'
70                         . bbcode($ev['location'])
71                         . '</span></p>' . "\r\n";
72
73                 // Include a map of the location if the [map] BBCode is used
74                 if (strpos($ev['location'], "[map") !== false) {
75                         $map = generate_named_map($ev['location']);
76                         if ($map !== $ev['location']) {
77                                 $o.= $map;
78                         }
79                 }
80         }
81
82         $o .= '</div>' . "\r\n";
83         return $o;
84 }
85
86 /*
87 @TODO old-lost code found?
88 function parse_event($h) {
89
90         require_once('include/Scrape.php');
91         require_once 'include/html2bbcode';
92
93         $h = '<html><body>' . $h . '</body></html>';
94
95         $ret = array();
96
97
98         try {
99                 $dom = HTML5_Parser::parse($h);
100         } catch (DOMException $e) {
101                 logger('parse_event: parse error: ' . $e);
102         }
103
104         if (! $dom)
105                 return $ret;
106
107         $items = $dom->getElementsByTagName('*');
108
109         foreach ($items as $item) {
110                 if (attribute_contains($item->getAttribute('class'), 'vevent')) {
111                         $level2 = $item->getElementsByTagName('*');
112                         foreach ($level2 as $x) {
113                                 if (attribute_contains($x->getAttribute('class'),'dtstart') && $x->getAttribute('title')) {
114                                         $ret['start'] = $x->getAttribute('title');
115                                         if (! strpos($ret['start'],'Z'))
116                                                 $ret['adjust'] = true;
117                                 }
118                                 if (attribute_contains($x->getAttribute('class'),'dtend') && $x->getAttribute('title'))
119                                         $ret['finish'] = $x->getAttribute('title');
120
121                                 if (attribute_contains($x->getAttribute('class'),'description'))
122                                         $ret['desc'] = $x->textContent;
123                                 if (attribute_contains($x->getAttribute('class'),'location'))
124                                         $ret['location'] = $x->textContent;
125                         }
126                 }
127         }
128
129         // sanitise
130
131         if ((x($ret,'desc')) && ((strpos($ret['desc'],'<') !== false) || (strpos($ret['desc'],'>') !== false))) {
132                 $config = HTMLPurifier_Config::createDefault();
133                 $config->set('Cache.DefinitionImpl', null);
134                 $purifier = new HTMLPurifier($config);
135                 $ret['desc'] = html2bbcode($purifier->purify($ret['desc']));
136         }
137
138         if ((x($ret,'location')) && ((strpos($ret['location'],'<') !== false) || (strpos($ret['location'],'>') !== false))) {
139                 $config = HTMLPurifier_Config::createDefault();
140                 $config->set('Cache.DefinitionImpl', null);
141                 $purifier = new HTMLPurifier($config);
142                 $ret['location'] = html2bbcode($purifier->purify($ret['location']));
143         }
144
145         if (x($ret,'start'))
146                 $ret['start'] = datetime_convert('UTC','UTC',$ret['start']);
147         if (x($ret,'finish'))
148                 $ret['finish'] = datetime_convert('UTC','UTC',$ret['finish']);
149
150         return $ret;
151 }
152 */
153
154 function format_event_bbcode($ev) {
155
156         $o = '';
157
158         if ($ev['summary']) {
159                 $o .= '[event-summary]' . $ev['summary'] . '[/event-summary]';
160         }
161
162         if ($ev['desc']) {
163                 $o .= '[event-description]' . $ev['desc'] . '[/event-description]';
164         }
165
166         if ($ev['start']) {
167                 $o .= '[event-start]' . $ev['start'] . '[/event-start]';
168         }
169
170         if (($ev['finish']) && (! $ev['nofinish'])) {
171                 $o .= '[event-finish]' . $ev['finish'] . '[/event-finish]';
172         }
173
174         if ($ev['location']) {
175                 $o .= '[event-location]' . $ev['location'] . '[/event-location]';
176         }
177
178         if ($ev['adjust']) {
179                 $o .= '[event-adjust]' . $ev['adjust'] . '[/event-adjust]';
180         }
181
182         return $o;
183 }
184
185 function bbtovcal($s) {
186         $o = '';
187         $ev = bbtoevent($s);
188
189         if ($ev['desc']) {
190                 $o = format_event_html($ev);
191         }
192
193         return $o;
194 }
195
196 function bbtoevent($s) {
197
198         $ev = array();
199
200         $match = '';
201         if (preg_match("/\[event\-summary\](.*?)\[\/event\-summary\]/is", $s, $match)) {
202                 $ev['summary'] = $match[1];
203         }
204
205         $match = '';
206         if (preg_match("/\[event\-description\](.*?)\[\/event\-description\]/is", $s, $match)) {
207                 $ev['desc'] = $match[1];
208         }
209
210         $match = '';
211         if (preg_match("/\[event\-start\](.*?)\[\/event\-start\]/is", $s, $match)) {
212                 $ev['start'] = $match[1];
213         }
214
215         $match = '';
216         if (preg_match("/\[event\-finish\](.*?)\[\/event\-finish\]/is", $s, $match)) {
217                 $ev['finish'] = $match[1];
218         }
219
220         $match = '';
221         if (preg_match("/\[event\-location\](.*?)\[\/event\-location\]/is", $s, $match)) {
222                 $ev['location'] = $match[1];
223         }
224
225         $match = '';
226         if (preg_match("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is", $s, $match)) {
227                 $ev['adjust'] = $match[1];
228         }
229
230         $ev['nofinish'] = (((x($ev, 'start') && $ev['start']) && (!x($ev, 'finish') || !$ev['finish'])) ? 1 : 0);
231
232         return $ev;
233 }
234
235
236 function sort_by_date($a) {
237
238         usort($a,'ev_compare');
239         return $a;
240 }
241
242 function ev_compare($a,$b) {
243
244         $date_a = (($a['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $a['start']) : $a['start']);
245         $date_b = (($b['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $b['start']) : $b['start']);
246
247         if ($date_a === $date_b) {
248                 return strcasecmp($a['desc'], $b['desc']);
249         }
250
251         return strcmp($date_a, $date_b);
252 }
253
254 function event_delete($event_id) {
255         if ($event_id == 0) {
256                 return;
257         }
258
259         q("DELETE FROM `event` WHERE `id` = %d", intval($event_id));
260         logger("Deleted event ".$event_id, LOGGER_DEBUG);
261 }
262
263 function event_store($arr) {
264
265         require_once 'include/datetime.php';
266         require_once 'include/items.php';
267         require_once 'include/bbcode.php';
268
269         $a = get_app();
270
271         $arr['created'] = (($arr['created'])     ? $arr['created']         : datetime_convert());
272         $arr['edited']  = (($arr['edited'])      ? $arr['edited']          : datetime_convert());
273         $arr['type']    = (($arr['type'])        ? $arr['type']            : 'event' );
274         $arr['cid']     = ((intval($arr['cid'])) ? intval($arr['cid'])     : 0);
275         $arr['uri']     = (x($arr, 'uri')        ? $arr['uri']             : item_new_uri($a->get_hostname(), $arr['uid']));
276         $arr['private'] = ((x($arr, 'private'))  ? intval($arr['private']) : 0);
277         $arr['guid']    = get_guid(32);
278
279         if ($arr['cid']) {
280                 $c = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
281                         intval($arr['cid']),
282                         intval($arr['uid'])
283                 );
284         } else {
285                 $c = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
286                         intval($arr['uid'])
287                 );
288         }
289
290         if (dbm::is_result($c)) {
291                 $contact = $c[0];
292         }
293
294
295         // Existing event being modified
296
297         if ($arr['id']) {
298
299                 // has the event actually changed?
300
301                 $r = q("SELECT * FROM `event` WHERE `id` = %d AND `uid` = %d LIMIT 1",
302                         intval($arr['id']),
303                         intval($arr['uid'])
304                 );
305                 if ((! dbm::is_result($r)) || ($r[0]['edited'] === $arr['edited'])) {
306
307                         // Nothing has changed. Grab the item id to return.
308
309                         $r = q("SELECT * FROM `item` WHERE `event-id` = %d AND `uid` = %d LIMIT 1",
310                                 intval($arr['id']),
311                                 intval($arr['uid'])
312                         );
313                         return ((dbm::is_result($r)) ? $r[0]['id'] : 0);
314                 }
315
316                 // The event changed. Update it.
317
318                 $r = q("UPDATE `event` SET
319                         `edited` = '%s',
320                         `start` = '%s',
321                         `finish` = '%s',
322                         `summary` = '%s',
323                         `desc` = '%s',
324                         `location` = '%s',
325                         `type` = '%s',
326                         `adjust` = %d,
327                         `nofinish` = %d
328                         WHERE `id` = %d AND `uid` = %d",
329
330                         dbesc($arr['edited']),
331                         dbesc($arr['start']),
332                         dbesc($arr['finish']),
333                         dbesc($arr['summary']),
334                         dbesc($arr['desc']),
335                         dbesc($arr['location']),
336                         dbesc($arr['type']),
337                         intval($arr['adjust']),
338                         intval($arr['nofinish']),
339                         intval($arr['id']),
340                         intval($arr['uid'])
341                 );
342                 $r = q("SELECT * FROM `item` WHERE `event-id` = %d AND `uid` = %d LIMIT 1",
343                         intval($arr['id']),
344                         intval($arr['uid'])
345                 );
346                 if (dbm::is_result($r)) {
347                         $object = '<object><type>' . xmlify(ACTIVITY_OBJ_EVENT) . '</type><title></title><id>' . xmlify($arr['uri']) . '</id>';
348                         $object .= '<content>' . xmlify(format_event_bbcode($arr)) . '</content>';
349                         $object .= '</object>' . "\n";
350
351                         q("UPDATE `item` SET `body` = '%s', `object` = '%s', `edited` = '%s' WHERE `id` = %d AND `uid` = %d",
352                                 dbesc(format_event_bbcode($arr)),
353                                 dbesc($object),
354                                 dbesc($arr['edited']),
355                                 intval($r[0]['id']),
356                                 intval($arr['uid'])
357                         );
358
359                         $item_id = $r[0]['id'];
360                 } else {
361                         $item_id = 0;
362                 }
363
364                 call_hooks("event_updated", $arr['id']);
365
366                 return $item_id;
367         } else {
368
369                 // New event. Store it.
370
371                 $r = q("INSERT INTO `event` (`uid`,`cid`,`guid`,`uri`,`created`,`edited`,`start`,`finish`,`summary`, `desc`,`location`,`type`,
372                         `adjust`,`nofinish`,`allow_cid`,`allow_gid`,`deny_cid`,`deny_gid`)
373                         VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s' ) ",
374                         intval($arr['uid']),
375                         intval($arr['cid']),
376                         dbesc($arr['guid']),
377                         dbesc($arr['uri']),
378                         dbesc($arr['created']),
379                         dbesc($arr['edited']),
380                         dbesc($arr['start']),
381                         dbesc($arr['finish']),
382                         dbesc($arr['summary']),
383                         dbesc($arr['desc']),
384                         dbesc($arr['location']),
385                         dbesc($arr['type']),
386                         intval($arr['adjust']),
387                         intval($arr['nofinish']),
388                         dbesc($arr['allow_cid']),
389                         dbesc($arr['allow_gid']),
390                         dbesc($arr['deny_cid']),
391                         dbesc($arr['deny_gid'])
392
393                 );
394
395                 $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
396                         dbesc($arr['uri']),
397                         intval($arr['uid'])
398                 );
399                 if (dbm::is_result($r)) {
400                         $event = $r[0];
401                 }
402
403                 $item_arr = array();
404
405                 $item_arr['uid']           = $arr['uid'];
406                 $item_arr['contact-id']    = $arr['cid'];
407                 $item_arr['uri']           = $arr['uri'];
408                 $item_arr['parent-uri']    = $arr['uri'];
409                 $item_arr['guid']          = $arr['guid'];
410                 $item_arr['type']          = 'activity';
411                 $item_arr['wall']          = (($arr['cid']) ? 0 : 1);
412                 $item_arr['contact-id']    = $contact['id'];
413                 $item_arr['owner-name']    = $contact['name'];
414                 $item_arr['owner-link']    = $contact['url'];
415                 $item_arr['owner-avatar']  = $contact['thumb'];
416                 $item_arr['author-name']   = $contact['name'];
417                 $item_arr['author-link']   = $contact['url'];
418                 $item_arr['author-avatar'] = $contact['thumb'];
419                 $item_arr['title']         = '';
420                 $item_arr['allow_cid']     = $arr['allow_cid'];
421                 $item_arr['allow_gid']     = $arr['allow_gid'];
422                 $item_arr['deny_cid']      = $arr['deny_cid'];
423                 $item_arr['deny_gid']      = $arr['deny_gid'];
424                 $item_arr['private']       = $arr['private'];
425                 $item_arr['last-child']    = 1;
426                 $item_arr['visible']       = 1;
427                 $item_arr['verb']          = ACTIVITY_POST;
428                 $item_arr['object-type']   = ACTIVITY_OBJ_EVENT;
429                 $item_arr['origin']        = ((intval($arr['cid']) == 0) ? 1 : 0);
430                 $item_arr['body']          = format_event_bbcode($event);
431
432
433                 $item_arr['object']  = '<object><type>' . xmlify(ACTIVITY_OBJ_EVENT) . '</type><title></title><id>' . xmlify($arr['uri']) . '</id>';
434                 $item_arr['object'] .= '<content>' . xmlify(format_event_bbcode($event)) . '</content>';
435                 $item_arr['object'] .= '</object>' . "\n";
436
437                 $item_id = item_store($item_arr);
438
439                 $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
440                         intval($arr['uid'])
441                 );
442                 //if (dbm::is_result($r))
443                 //      $plink = App::get_baseurl() . '/display/' . $r[0]['nickname'] . '/' . $item_id;
444
445
446                 if ($item_id) {
447                         //q("UPDATE `item` SET `plink` = '%s', `event-id` = %d  WHERE `uid` = %d AND `id` = %d",
448                         //      dbesc($plink),
449                         //      intval($event['id']),
450                         //      intval($arr['uid']),
451                         //      intval($item_id)
452                         //);
453                         q("UPDATE `item` SET `event-id` = %d  WHERE `uid` = %d AND `id` = %d",
454                                 intval($event['id']),
455                                 intval($arr['uid']),
456                                 intval($item_id)
457                         );
458                 }
459
460                 call_hooks("event_created", $event['id']);
461
462                 return $item_id;
463         }
464 }
465
466 function get_event_strings() {
467
468         // First day of the week (0 = Sunday)
469         $firstDay = get_pconfig(local_user(), 'system', 'first_day_of_week');
470         if ($firstDay === false) {
471                 $firstDay = 0;
472         }
473
474         $i18n = array(
475                         "firstDay" => $firstDay,
476                         "allday"   => t("all-day"),
477
478                         "Sun" => t("Sun"),
479                         "Mon" => t("Mon"),
480                         "Tue" => t("Tue"),
481                         "Wed" => t("Wed"),
482                         "Thu" => t("Thu"),
483                         "Fri" => t("Fri"),
484                         "Sat" => t("Sat"),
485
486                         "Sunday"    => t("Sunday"),
487                         "Monday"    => t("Monday"),
488                         "Tuesday"   => t("Tuesday"),
489                         "Wednesday" => t("Wednesday"),
490                         "Thursday"  => t("Thursday"),
491                         "Friday"    => t("Friday"),
492                         "Saturday"  => t("Saturday"),
493
494                         "Jan" => t("Jan"),
495                         "Feb" => t("Feb"),
496                         "Mar" => t("Mar"),
497                         "Apr" => t("Apr"),
498                         "May" => t("May"),
499                         "Jun" => t("Jun"),
500                         "Jul" => t("Jul"),
501                         "Aug" => t("Aug"),
502                         "Sep" => t("Sept"),
503                         "Oct" => t("Oct"),
504                         "Nov" => t("Nov"),
505                         "Dec" => t("Dec"),
506
507                         "January"   => t("January"),
508                         "February"  => t("February"),
509                         "March"     => t("March"),
510                         "April"     => t("April"),
511                         "May"       => t("May"),
512                         "June"      => t("June"),
513                         "July"      => t("July"),
514                         "August"    => t("August"),
515                         "September" => t("September"),
516                         "October"   => t("October"),
517                         "November"  => t("November"),
518                         "December"  => t("December"),
519
520                         "today" => t("today"),
521                         "month" => t("month"),
522                         "week"  => t("week"),
523                         "day"   => t("day"),
524
525                         "noevent" => t("No events to display"),
526
527                         "dtstart_label"  => t("Starts:"),
528                         "dtend_label"    => t("Finishes:"),
529                         "location_label" => t("Location:")
530                 );
531
532         return $i18n;
533 }
534
535 /**
536  * @brief Removes duplicated birthday events
537  *
538  * @param array $dates Array of possibly duplicated events
539  * @return array Cleaned events
540  *
541  * @todo We should replace this with a separate update function if there is some time left
542  */
543 function event_remove_duplicates($dates) {
544         $dates2 = array();
545
546         foreach ($dates AS $date) {
547                 if ($date['type'] == 'birthday') {
548                         $dates2[$date['uid'] . "-" . $date['cid'] . "-" . $date['start']] = $date;
549                 } else {
550                         $dates2[] = $date;
551                 }
552         }
553         return $dates2;
554 }
555
556 /**
557  * @brief Get an event by its event ID
558  *
559  * @param type $owner_uid The User ID of the owner of the event
560  * @param type $event_params An assoziative array with
561  *      int 'event_id' => The ID of the event in the event table
562  * @param type $sql_extra
563  * @return array Query result
564  */
565 function event_by_id($owner_uid = 0, $event_params, $sql_extra = '') {
566         // ownly allow events if there is a valid owner_id
567         if ($owner_uid == 0) {
568                 return;
569         }
570
571         // Query for the event by event id
572         $r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
573                         `item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
574                 LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
575                 WHERE `event`.`uid` = %d AND `event`.`id` = %d $sql_extra",
576                 intval($owner_uid),
577                 intval($event_params["event_id"])
578         );
579
580         if (dbm::is_result($r)) {
581                 return event_remove_duplicates($r);
582         }
583 }
584
585 /**
586  * @brief Get all events in a specific timeframe
587  *
588  * @param int $owner_uid The User ID of the owner of the events
589  * @param array $event_params An assoziative array with
590  *      int 'ignored' =>
591  *      string 'start' => Start time of the timeframe
592  *      string 'finish' => Finish time of the timeframe
593  *      string 'adjust_start' =>
594  *      string 'adjust_start' =>
595  *
596  * @param string $sql_extra Additional sql conditions (e.g. permission request)
597  * @return array Query results
598  */
599 function events_by_date($owner_uid = 0, $event_params, $sql_extra = '') {
600         // Only allow events if there is a valid owner_id
601         if ($owner_uid == 0) {
602                 return;
603         }
604
605         // Query for the event by date
606         $r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
607                                 `item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
608                         LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
609                         WHERE `event`.`uid` = %d AND event.ignore = %d
610                         AND ((`adjust` = 0 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s')
611                         OR  (`adjust` = 1 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s'))
612                         $sql_extra ",
613                         intval($owner_uid),
614                         intval($event_params["ignored"]),
615                         dbesc($event_params["start"]),
616                         dbesc($event_params["start"]),
617                         dbesc($event_params["finish"]),
618                         dbesc($event_params["adjust_start"]),
619                         dbesc($event_params["adjust_start"]),
620                         dbesc($event_params["adjust_finish"])
621         );
622
623         if (dbm::is_result($r)) {
624                 return event_remove_duplicates($r);
625         }
626 }
627
628 /**
629  * @brief Convert an array query results in an arry which could be used by the events template
630  *
631  * @param array $arr Event query array
632  * @return array Event array for the template
633  */
634 function process_events($arr) {
635         $events=array();
636
637         $last_date = '';
638         $fmt = t('l, F j');
639         if (count($arr)) {
640                 foreach ($arr as $rr) {
641
642                         $j = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['start'], 'j') : datetime_convert('UTC', 'UTC', $rr['start'], 'j'));
643                         $d = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['start'], $fmt) : datetime_convert('UTC', 'UTC', $rr['start'], $fmt));
644                         $d = day_translate($d);
645
646                         $start = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['start'], 'c') : datetime_convert('UTC', 'UTC', $rr['start'], 'c'));
647                         if ($rr['nofinish']) {
648                                 $end = null;
649                         } else {
650                                 $end = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['finish'], 'c') : datetime_convert('UTC', 'UTC', $rr['finish'], 'c'));
651                         }
652
653                         $is_first = ($d !== $last_date);
654
655                         $last_date = $d;
656
657                         // Show edit and drop actions only if the user is the owner of the event and the event
658                         // is a real event (no bithdays)
659                         if (local_user() && local_user() == $rr['uid'] && $rr['type'] == 'event') {
660                                 $edit = ((! $rr['cid']) ? array(App::get_baseurl() . '/events/event/' . $rr['id'], t('Edit event'), '', '') : null);
661                                 $drop = array(App::get_baseurl() . '/events/drop/' . $rr['id'], t('Delete event'), '', '');
662                         }
663
664                         $title = strip_tags(html_entity_decode(bbcode($rr['summary']), ENT_QUOTES, 'UTF-8'));
665                         if (! $title) {
666                                 list($title, $_trash) = explode("<br", bbcode($rr['desc']), 2);
667                                 $title = strip_tags(html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
668                         }
669
670                         $html = format_event_html($rr);
671                         $rr['desc'] = bbcode($rr['desc']);
672                         $rr['location'] = bbcode($rr['location']);
673                         $events[] = array(
674                                 'id'     => $rr['id'],
675                                 'start'  => $start,
676                                 'end'    => $end,
677                                 'allDay' => false,
678                                 'title'  => $title,
679
680                                 'j'        => $j,
681                                 'd'        => $d,
682                                 'edit'     => $edit,
683                                 'drop'     => $drop,
684                                 'is_first' => $is_first,
685                                 'item'     => $rr,
686                                 'html'     => $html,
687                                 'plink'    => array($rr['plink'], t('link to source'), '', ''),
688                         );
689                 }
690         }
691
692         return $events;
693 }
694
695 /**
696  * @brief Format event to export format (ical/csv)
697  *
698  * @param array $events Query result for events
699  * @param string $format The output format (ical/csv)
700  * @param string $timezone The timezone of the user (not implemented yet)
701  *
702  * @return string Content according to selected export format
703  */
704 function event_format_export ($events, $format = 'ical', $timezone) {
705         if (! ((is_array($events)) && count($events))) {
706                 return;
707         }
708
709         switch ($format) {
710                 // Format the exported data as a CSV file
711                 case "csv":
712                         header("Content-type: text/csv");
713                         $o = '"Subject", "Start Date", "Start Time", "Description", "End Date", "End Time", "Location"' . PHP_EOL;
714
715                         foreach ($events as $event) {
716                                 /// @todo The time / date entries don't include any information about the
717                                 /// timezone the event is scheduled in :-/
718                                 $tmp1 = strtotime($event['start']);
719                                 $tmp2 = strtotime($event['finish']);
720                                 $time_format = "%H:%M:%S";
721                                 $date_format = "%Y-%m-%d";
722
723                                 $o .= '"' . $event['summary'] . '", "' . strftime($date_format, $tmp1) .
724                                         '", "' . strftime($time_format, $tmp1) . '", "' . $event['desc'] .
725                                         '", "' . strftime($date_format, $tmp2) .
726                                         '", "' . strftime($time_format, $tmp2) .
727                                         '", "' . $event['location'] . '"' . PHP_EOL;
728                         }
729                         break;
730
731                 // Format the exported data as a ics file
732                 case "ical":
733                         header("Content-type: text/ics");
734                         $o = 'BEGIN:VCALENDAR' . PHP_EOL
735                                 . 'VERSION:2.0' . PHP_EOL
736                                 . 'PRODID:-//friendica calendar export//0.1//EN' . PHP_EOL;
737                         ///  @todo include timezone informations in cases were the time is not in UTC
738                         //  see http://tools.ietf.org/html/rfc2445#section-4.8.3
739                         //              . 'BEGIN:VTIMEZONE' . PHP_EOL
740                         //              . 'TZID:' . $timezone . PHP_EOL
741                         //              . 'END:VTIMEZONE' . PHP_EOL;
742                         //  TODO instead of PHP_EOL CRLF should be used for long entries
743                         //       but test your solution against http://icalvalid.cloudapp.net/
744                         //       also long lines SHOULD be split at 75 characters length
745                         foreach ($events as $event) {
746
747                                 if ($event['adjust'] == 1) {
748                                         $UTC = 'Z';
749                                 } else {
750                                         $UTC = '';
751                                 }
752                                 $o .= 'BEGIN:VEVENT' . PHP_EOL;
753
754                                 if ($event['start']) {
755                                         $tmp = strtotime($event['start']);
756                                         $dtformat = "%Y%m%dT%H%M%S" . $UTC;
757                                         $o .= 'DTSTART:' . strftime($dtformat, $tmp) . PHP_EOL;
758                                 }
759
760                                 if (!$event['nofinish']) {
761                                         $tmp = strtotime($event['finish']);
762                                         $dtformat = "%Y%m%dT%H%M%S" . $UTC;
763                                         $o .= 'DTEND:' . strftime($dtformat, $tmp) . PHP_EOL;
764                                 }
765
766                                 if ($event['summary']) {
767                                         $tmp = $event['summary'];
768                                         $tmp = str_replace(PHP_EOL, PHP_EOL . ' ', $tmp);
769                                         $tmp = addcslashes($tmp, ',;');
770                                         $o .= 'SUMMARY:' . $tmp . PHP_EOL;
771                                 }
772
773                                 if ($event['desc']) {
774                                         $tmp = $event['desc'];
775                                         $tmp = str_replace(PHP_EOL, PHP_EOL . ' ', $tmp);
776                                         $tmp = addcslashes($tmp, ',;');
777                                         $o .= 'DESCRIPTION:' . $tmp . PHP_EOL;
778                                 }
779
780                                 if ($event['location']) {
781                                         $tmp = $event['location'];
782                                         $tmp = str_replace(PHP_EOL, PHP_EOL . ' ', $tmp);
783                                         $tmp = addcslashes($tmp, ',;');
784                                         $o .= 'LOCATION:' . $tmp . PHP_EOL;
785                                 }
786
787                                 $o .= 'END:VEVENT' . PHP_EOL;
788                                 $o .= PHP_EOL;
789                         }
790
791                         $o .= 'END:VCALENDAR' . PHP_EOL;
792                         break;
793         }
794
795         return $o;
796 }
797
798 /**
799  * @brief Get all events for a user ID
800  *
801  *    The query for events is done permission sensitive
802  *    If the user is the owner of the calendar he/she
803  *    will get all of his/her available events.
804  *    If the user is only a visitor only the public events will
805  *    be available
806  *
807  * @param int $uid The user ID
808  * @param int $sql_extra Additional sql conditions for permission
809  *
810  * @return array Query results
811  */
812 function events_by_uid($uid = 0, $sql_extra = '') {
813         if ($uid == 0) {
814                 return;
815         }
816
817         // The permission condition if no condition was transmitted
818         if ($sql_extra == '') {
819                 $sql_extra = " AND `allow_cid` = '' AND `allow_gid` = '' ";
820         }
821
822         // Does the user who requests happen to be the owner of the events
823         // requested? then show all of your events, otherwise only those that
824         // don't have limitations set in allow_cid and allow_gid
825         if (local_user() == $uid) {
826                 $r = q("SELECT `start`, `finish`, `adjust`, `summary`, `desc`, `location`, `nofinish`
827                         FROM `event` WHERE `uid`= %d AND `cid` = 0 ",
828                         intval($uid)
829                 );
830         } else {
831                 $r = q("SELECT `start`, `finish`, `adjust`, `summary`, `desc`, `location`, `nofinish`
832                         FROM `event` WHERE `uid`= %d AND `cid` = 0 $sql_extra ",
833                         intval($uid)
834                 );
835         }
836
837         if (dbm::is_result($r)) {
838                 return $r;
839         }
840 }
841
842 /**
843  *
844  * @param int $uid The user ID
845  * @param string $format Output format (ical/csv)
846  * @return array With the results
847  *      bool 'success' => True if the processing was successful
848  *      string 'format' => The output format
849  *      string 'extension' => The file extension of the output format
850  *      string 'content' => The formatted output content
851  *
852  * @todo Respect authenticated users with events_by_uid()
853  */
854 function event_export($uid, $format = 'ical') {
855
856         $process = false;
857
858         // We are allowed to show events
859         // get the timezone the user is in
860         $r = q("SELECT `timezone` FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid));
861         if (dbm::is_result($r)) {
862                 $timezone = $r[0]['timezone'];
863         }
864
865         // Get all events which are owned by a uid (respects permissions);
866         $events = events_by_uid($uid);
867
868         // We have the events that are available for the requestor
869         // now format the output according to the requested format
870         if (count($events)) {
871                 $res = event_format_export($events, $format, $timezone);
872         }
873
874         // If there are results the precess was successfull
875         if (x($res)) {
876                 $process = true;
877         }
878
879         // Get the file extension for the format
880         switch ($format) {
881                 case "ical":
882                         $file_ext = "ics";
883                         break;
884
885                 case "csv":
886                         $file_ext = "csv";
887                         break;
888
889                 default:
890                         $file_ext = "";
891         }
892
893         $arr = array(
894                 'success'   => $process,
895                 'format'    => $format,
896                 'extension' => $file_ext,
897                 'content'   => $res,
898         );
899
900         return $arr;
901 }
902
903 /**
904  * @brief Get the events widget
905  *
906  * @return string Formated html of the evens widget
907  */
908 function widget_events() {
909         $a = get_app();
910
911         $owner_uid = $a->data['user']['uid'];
912         // $a->data is only available if the profile page is visited. If the visited page is not part
913         // of the profile page it should be the personal /events page. So we can use $a->user
914         $user = ($a->data['user']['nickname'] ? $a->data['user']['nickname'] : $a->user['nickname']);
915
916
917         // The permission testing is a little bit tricky because we have to respect many cases
918
919         // It's not the private events page (we don't get the $owner_uid for /events)
920         if (! local_user() && ! $owner_uid) {
921                 return;
922         }
923
924         // Cal logged in user (test permission at foreign profile page)
925         // If the $owner uid is available we know it is part of one of the profile pages (like /cal)
926         // So we have to test if if it's the own profile page of the logged in user
927         // or a foreign one. For foreign profile pages we need to check if the feature
928         // for exporting the cal is enabled (otherwise the widget would appear for logged in users
929         // on foreigen profile pages even if the widget is disabled)
930         if (intval($owner_uid) && local_user() !== $owner_uid && ! feature_enabled($owner_uid, "export_calendar")) {
931                 return;
932         }
933
934         // If it's a kind of profile page (intval($owner_uid)) return if the user not logged in and
935         // export feature isn't enabled
936         if (intval($owner_uid) && ! local_user() && ! feature_enabled($owner_uid, "export_calendar")) {
937                 return;
938         }
939
940         return replace_macros(get_markup_template("events_aside.tpl"), array(
941                 '$etitle' => t("Export"),
942                 '$export_ical' => t("Export calendar as ical"),
943                 '$export_csv' => t("Export calendar as csv"),
944                 '$user' => $user
945         ));
946 }