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