/[drupal]/contributions/modules/event/ical.inc
ViewVC logotype

Contents of /contributions/modules/event/ical.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.17 - (show annotations) (download) (as text)
Wed Dec 31 00:07:23 2008 UTC (10 months, 4 weeks ago) by killes
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +100 -153 lines
File MIME type: text/x-php
some cleanup WRT imports
1 <?php
2 /* $Id: ical.inc,v 1.16 2008/09/06 22:20:28 killes Exp $ */
3
4 /**
5 * @file
6 * API for event import/export in iCalendar format as outlined in Internet Calendaring and Scheduling Core Object Specification
7 * http://www.ietf.org/rfc/rfc2445.txt
8 *
9 * This module is IN DEVELOPMENT and not a finished product
10 */
11
12 /**
13 * Turn an array of events into a valid iCalendar file
14 *
15 * @param $events
16 * An array of associative arrays where
17 * 'start' => Start time (Required, if no allday_start)
18 * 'end' => End time (Optional)
19 * 'allday_start' => Start date of all-day event in YYYYMMDD format (Required, if no start)
20 * 'allday_end' => End date of all-day event in YYYYMMDD format (Optional)
21 * 'summary' => Title of event (Text)
22 * 'description' => Description of event (Text)
23 * 'location' => Location of event (Text)
24 * 'uid' => ID of the event for use by calendaring program. Recommend the url of the node
25 * 'url' => URL of event information
26 *
27 * @param $calname
28 * Name of the calendar. Will use site name if none is specified.
29 *
30 * @return
31 * Text of a iCalendar file
32 */
33 function ical_export($events, $calname = NULL) {
34 $output = "BEGIN:VCALENDAR\nVERSION:2.0\n";
35 $output .= "METHOD:PUBLISH\n";
36 $output .= 'X-WR-CALNAME:'. variable_get('site_name', '') .' | '. ical_escape_text($calname) ."\n";
37 $output .= "PRODID:-//strange bird labs//Drupal iCal API//EN\n";
38 foreach ($events as $uid => $event) {
39 $output .= "BEGIN:VEVENT\n";
40 $output .= "DTSTAMP;VALUE=DATE-TIME:". gmdate("Ymd\THis\Z", time()) ."\n";
41 if (!$event['has_time']) { // all day event
42 $output .= "DTSTART;VALUE=DATE-TIME:" . event_format_date($event['start_utc'], 'custom', "Ymd\THis\Z") ."\n";
43 //If allday event, set to day after allday start
44 $end_date = event_date_later($event['start'], 1);
45 $output .= "DTEND;VALUE=DATE-TIME:" . event_format_date($end_date, 'custom', 'Ymd') ."\n";
46 }
47 else if (!empty($event['start_utc']) && !empty($event['end_utc'])) {
48 $output .= "DTSTART;VALUE=DATE-TIME:". event_format_date($event['start_utc'], 'custom', "Ymd\THis\Z") ."\n";
49 $output .= "DTEND;VALUE=DATE-TIME:". event_format_date($event['end_utc'], 'custom', "Ymd\THis\Z") ."\n";
50 }
51 else if (!empty($event['start_utc'])) {
52 $output .= "DTSTART;VALUE=DATE-TIME:". event_format_date($event['start_utc'], 'custom', "Ymd\THis\Z") ."\n";
53 }
54 $output .= "UID:". ($event['uid'] ? $event['uid'] : $uid) ."\n";
55 if (!empty($event['url'])) {
56 $output .= "URL;VALUE=URI:" . $event['url'] ."\n";
57 }
58 if (!empty($event['location'])) {
59 $output .= "LOCATION:" . ical_escape_text($event['location']) ."\n";
60 }
61 $output .= "SUMMARY:" . ical_escape_text($event['summary']) ."\n";
62 if (!empty($event['description'])) {
63 $output .= "DESCRIPTION:" . ical_escape_text($event['description']) ."\n";
64 }
65 $output .= "END:VEVENT\n";
66 }
67 $output .= "END:VCALENDAR\n";
68 return $output;
69 }
70
71 /**
72 * Escape #text elements for safe iCal use
73 *
74 * @param $text
75 * Text to escape
76 *
77 * @return
78 * Escaped text
79 *
80 */
81 function ical_escape_text($text) {
82 //$text = strip_tags($text);
83 $text = str_replace('"', '\"', $text);
84 $text = str_replace("\\", "\\\\", $text);
85 $text = str_replace(",", "\,", $text);
86 $text = str_replace(":", "\:", $text);
87 $text = str_replace(";", "\;", $text);
88 $text = str_replace("\n", "\n ", $text);
89 return $text;
90 }
91
92 /**
93 * Given the location of a valide iCalendar file, will return an array of event information
94 *
95 * @param $filename
96 * Location (local or remote) of a valid iCalendar file
97 *
98 * @return
99 * An array of associative arrays where
100 * 'start' => start time as date array
101 * 'end' => end time as date array
102 * 'summary' => Title of event
103 * 'description' => Description of event
104 * 'location' => Location of event
105 * 'uid' => ID of the event in calendaring program
106 * 'url' => URL of event information */
107 function ical_import($ical) {
108 $ical = explode("\n", $ical);
109 $items = array();
110 # $ifile = @fopen($filename, "r");
111 # if ($ifile == FALSE) exit('Invalid input file');
112 $nextline = $ical[0];
113 if (trim($nextline) != 'BEGIN:VCALENDAR') exit('Invalid calendar file:'. $nextline);
114 foreach ($ical as $line) {
115 $line = $nextline;
116 $nextline = next($ical);
117 $nextline = ereg_replace("[\r\n]", "", $nextline);
118 while (substr($nextline, 0, 1) == " ") {
119 $line .= substr($nextline, 1);
120 $nextline = next($ical);
121 $nextline = ereg_replace("[\r\n]", "", $nextline);
122 }
123 $line = trim($line);
124 switch ($line) {
125 case 'BEGIN:VEVENT':
126 unset($start_date, $start_time,
127 $end_date, $end_time,
128 $tz_dtstart, $tz_dtend,
129 $allday_start, $allday_end,
130 $uid,
131 $summary,
132 $description,
133 $url,
134 $location
135 );
136 break;
137 case 'END:VEVENT':
138 if (empty($uid)) {
139 $uid = $uid_counter;
140 $uid_counter++;
141 }
142
143 $items[$uid] = array('start' => $start_date .' '. $start_time,
144 'end' => $end_date .' '. $end_time,
145 'allday_start' => $allday_start,
146 'tz_start' => $tz_dtstart,
147 'tz_end' => $tz_dtend,
148 'allday_end' => $allday_end,
149 'summary' => $summary,
150 'description' => $description,
151 'location' => $location,
152 'url' => $url,
153 'uid' => $uid);
154 break;
155 default:
156 unset($field, $data, $prop_pos, $property);
157 ereg("([^:]+):(.*)", $line, $line);
158 $field = $line[1];
159 $data = $line[2];
160
161 $property = $field;
162 $prop_pos = strpos($property, ';');
163 if ($prop_pos !== FALSE) {
164 $property = substr($property, 0, $prop_pos);
165 }
166 $property = strtoupper($property);
167
168 switch ($property) {
169 case 'DTSTART':
170 $zulu_time = FALSE;
171 if (substr($data, -1) == 'Z') {
172 $zulu_time = TRUE;
173 }
174 $data = str_replace('T', '', $data);
175 $data = str_replace('Z', '', $data);
176 $field = str_replace(';VALUE=DATE-TIME', '', $field);
177 if ((preg_match("/^DTSTART;VALUE=DATE/i", $field)) || (ereg ('^([0-9]{4})([0-9]{2})([0-9]{2})$', $data))) {
178 ereg('([0-9]{4})([0-9]{2})([0-9]{2})', $data, $dtstart_check);
179 $allday_start = $data;
180 $start_date = $allday_start;
181 }
182 else {
183 if (preg_match("/^DTSTART;TZID=/i", $field)) {
184 $tz_tmp = explode('=', $field);
185 $tz_tmp = explode(':', $tz_tmp[1]);
186 $check = event_zone_by_name($tz_tmp[0]);
187 // Found TZ
188 if ($check['name'] === $tz_tmp[0]) {
189 $tz_dtstart = $tz_tmp[0];
190 }
191 else {
192 $messages['error'][] = t('Timezone %tz not found, using default timezone.', array('%tz' => $tz_tmp[0]));
193 }
194 unset($check, $tz_tmp);
195 }
196 elseif ($zulu_time) {
197 $tz_dtstart = 'Etc/GMT';
198 }
199 if (!isset($tz_dtstart)) {
200 $tz_dtstart = event_zonelist_by_id(variable_get('date_default_timezone_id', 487));
201 $tz_dtstart = $tz_dtstart['name'];
202 }
203 preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})/', $data, $regs);
204 $start_date = $regs[1] .'-'. $regs[2] .'-'. $regs[3];
205 $start_time = $regs[4] .':'. $regs[5] .':00';
206 unset($regs);
207 }
208 break;
209 case 'DTEND':
210 $zulu_time = FALSE;
211 if (substr($data, -1) == 'Z') {
212 $zulu_time = TRUE;
213 }
214 $data = str_replace('T', '', $data);
215 $data = str_replace('Z', '', $data);
216 $field = str_replace(';VALUE=DATE-TIME', '', $field);
217 if ((preg_match("/^DTEND;VALUE=DATE/i", $field)) || (ereg ('^([0-9]{4})([0-9]{2})([0-9]{2})$', $data))) {
218 $allday_end = $data;
219 $end_date = $allday_end;
220 }
221 else {
222 if (preg_match("/^DTEND;TZID=/i", $field)) {
223 $tz_tmp = explode('=', $field);
224 $tz_tmp = explode(':', $tz_tmp[1]);
225 $check = event_zone_by_name($tz_tmp[0]);
226 if ($check['name'] === $tz_tmp[0]) {
227 $tz_dtend = $tz_tmp[0];
228 }
229 else {
230 $messages['error'][] = t('Timezone %tz not found, using default timezone.', array('%tz' => $tz_tmp[0]));
231 }
232 unset($check, $tz_tmp);
233 }
234 elseif ($zulu_time) {
235 $tz_dtend = 'Etc/GMT';
236 }
237 if (!isset($tz_dtend)) {
238 $tz_dtend = event_zonelist_by_id(variable_get('date_default_timezone_id', 487));
239 $tz_dtend = $tz_dtend['name'];
240 }
241 preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})/', $data, $regs);
242 $end_date = $regs[1] .'-'. $regs[2] .'-'. $regs[3];
243 $end_time = $regs[4] .':'. $regs[5] .':00';
244 unset($regs);
245 }
246 break;
247 case 'SUMMARY':
248 $summary = ical_parse_text($field, $data);
249 break;
250 case 'DESCRIPTION':
251 $description = ical_parse_text($field, $data);
252 break;
253 case 'UID':
254 $uid = $data;
255 break;
256 case 'X-WR-CALNAME':
257 $actual_calname = ical_parse_text($field, $data);
258 break;
259 case 'X-WR-TIMEZONE':
260 $calendar_tz = ical_parse_text($field, $data);
261 break;
262 case 'LOCATION':
263 $location = ical_parse_text($field, $data);
264 break;
265 case 'URL':
266 $url = $data;
267 break;
268 }
269 }
270 }
271 return $items;
272 }
273
274 function ical_help($path, $arg) {
275 switch ($path) {
276 case 'admin/modules#description':
277 return t('iCalendar API for Events Modules');
278 break;
279 }
280 }
281
282 /**
283 * escape ical separators in quoted-printable encoded code
284 */
285 function ical_quoted_printable_escaped($string) {
286 $replace = array(";" => "\;", ":" => "\:");
287 return strtr(ical_quoted_printable_encode($string), $replace);
288 }
289
290 /**
291 * encode text using quoted-printable standard
292 */
293 function ical_quoted_printable_encode($text, $line_max = 76) {
294 $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
295 $lines = preg_split("/(?:\r\n|\r|\n)/", $text);
296 $eol = "\r\n";
297 $linebreak = "=0D=0A";
298 $escape = "=";
299 $output = "";
300
301 for ($x = 0; $x < count($lines); $x++) {
302 $line = $lines[$x];
303 $line_len = strlen($line);
304 $newline = "";
305 for ($i = 0; $i < $line_len; $i++) {
306 $c = substr($line, $i, 1);
307 $dec = ord($c);
308 // convert space at end of line
309 if ( ($dec == 32) && ($i == ($line_len - 1)) ) {
310 $c = $escape ."20";
311 }
312 // convert tab and special chars
313 elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) {
314 $h2 = floor($dec/16);
315 $h1 = floor($dec%16);
316 $c = $escape . $hex["$h2"] . $hex["$h1"];
317 }
318 // see if new output line is needed
319 if ( (strlen($newline) + strlen($c)) >= $line_max ) {
320 $output .= $newline . $escape . $eol;
321 $newline = "";
322 }
323 $newline .= $c;
324 }
325 $output .= $newline;
326
327 // skip last line feed
328 if ($x < count($lines) - 1) $output .= $linebreak;
329 }
330 return trim($output);
331 }
332
333 /**
334 * From date_ical_parse_text
335 *
336 * @param $field the field
337 * @param $text the text
338 *
339 * @return formatted text.
340 */
341 function ical_parse_text($field, $text) {
342 if (strstr($field, 'QUOTED-PRINTABLE')) {
343 $text = quoted_printable_decode($text);
344 }
345 // Strip line breaks within element
346 $text = str_replace(array("\r\n ", "\n ", "\r "), '', $text);
347 // Put in line breaks where encoded
348 $text = str_replace(array("\\n", "\\N"), "\n", $text);
349 // Remove other escaping
350 $text = stripslashes($text);
351 return $text;
352 }
353
354

  ViewVC Help
Powered by ViewVC 1.1.2