1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
<?php
/* DISPLAY - iCal export
*
*/
function communievents_escape_ical_text($text) {
return strtr($text, array(
"\\" => "\\\\",
',' => '\,',
';' => '\;',
"\r\n" => "\\n", // spec says line breaks need to be \n only
"\n" => "\\n"
));
}
// FIXME! this assumes valid utf-8
function communievents_fold_ical_line_helper($text, $index, $maxlength) {
$length = 0;
$i = $index;
while ($i < strlen($text) && $length < $maxlength) {
$c = ord($text[$i]);
if ($c < 128) {
$clen = 1;
} else if ($c < 224) {
$clen = 2;
} else if ($c < 240) {
$clen = 3;
} else {
$clen = 4;
}
if ($length + $clen > $maxlength)
break;
$i += $clen;
$length += $clen;
}
return substr($text, $index, $length);
}
function communievents_fold_ical_text($text) {
//XXX: the iCal spec wants the lines to be at most 75 octets,
// but we must not split UTF-8 because some readers (notably
// thunderbird) choke on it, even though the RFC says you
// should handle it gracefully :-(
if (strlen($text) <= 75) {
return $text;
} else {
$text_arr = array();
$text_arr[0] = communievents_fold_ical_line_helper($text, 0, 75);
$i = strlen($text_arr[0]);
while ($i < strlen($text)) {
$s = communievents_fold_ical_line_helper($text, $i, 74);
$i += strlen($s);
$text_arr[] = $s;
}
return join("\r\n ", $text_arr);
}
}
function communievents_write_ical_line($field, $text) {
echo communievents_fold_ical_text("$field:" . communievents_escape_ical_text($text)) . "\r\n";
}
function communievents_print_ical_feed() {
global $wpdb;
$tz = new DateTimeZone(CommuniApi::TIMEZONE);
$tz_utc = new DateTimeZone('UTC');
$now_utc = new DateTime('now', $tz_utc);
$dtstamp = $now_utc->format('Ymd\THis\Z');
header('Content-Type: text/calendar');
header('Content-Disposition: attachment; filename="communievents.ics"');
communievents_write_ical_line('BEGIN', 'VCALENDAR');
communievents_write_ical_line('VERSION', '2.0');
communievents_write_ical_line('PRODID', '-//' . get_bloginfo('name') . '//NONSGML Events//EN');
communievents_write_ical_line('CALSCALE', 'GREGORIAN');
communievents_write_ical_line('X-WR-TIMEZONE', CommuniApi::TIMEZONE);
$table_name = $wpdb->prefix . 'communievents_events';
$list = $wpdb->get_results("SELECT * FROM $table_name WHERE official=1 ORDER BY start");
if ($list) {
foreach ($list as $event) {
$start_dt = new DateTime($event->start, $tz);
$end_dt = new DateTime($event->end, $tz);
communievents_write_ical_line('BEGIN', 'VEVENT');
communievents_write_ical_line('UID', 'communi-event-' . $event->id . '-' . $start_dt->format('U'));
communievents_write_ical_line('STATUS', 'CONFIRMED');
communievents_write_ical_line('DTSTAMP', $dtstamp);
if ($event->allday) {
communievents_write_ical_line('DTSTART;VALUE=DATE', $start_dt->format('Ymd'));
if ($end_dt->format('Ymd') != $start_dt->format('Ymd')) {
// end is non-inclusive! move it into the next day
$end_dt->modify('+1 minute');
communievents_write_ical_line('DTEND;VALUE=DATE', $end_dt->format('Ymd'));
}
} else {
communievents_write_ical_line('DTSTART', $start_dt->format('Ymd\THis'));
if ($event->end != $event->start) {
communievents_write_ical_line('DTEND', $end_dt->format('Ymd\THis'));
}
}
communievents_write_ical_line('SUMMARY', $event->title);
if (!empty($event->description)) {
communievents_write_ical_line('DESCRIPTION', html_entity_decode(strip_tags($event->description), ENT_QUOTES|ENT_SUBSTITUTE|ENT_HTML5, 'UTF-8'));
communievents_write_ical_line('X-ALT-DESC;FMTTYPE=text/html', $event->description);
}
if (!empty($event->location)) {
communievents_write_ical_line('LOCATION', $event->location);
}
communievents_write_ical_line('URL;VALUE=URI', $event->url);
communievents_write_ical_line('END', 'VEVENT');
}
}
communievents_write_ical_line('END', 'VCALENDAR');
}
function communievents_setup_ical_feed() {
add_feed('communievents-ics', 'communievents_print_ical_feed');
// FIXME: emklahr.de compat HACK
add_feed('eo-events', 'communievents_print_ical_feed');
}
|