* * -------------------------------------------- * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 2 of the License, or (at your * * option) any later version. * \**************************************************************************/ /* $Id$ */ define('FOLD_LENGTH',75); define('VEVENT',1); define('VTODO',2); define('NONE',0); define('CHAIR',1); define('REQ_PARTICIPANT',2); define('OPT_PARTICIPANT',3); define('NON_PARTICIPANT',4); define('INDIVIDUAL',1); define('GROUP',2); define('RESOURCE',4); define('ROOM',8); define('UNKNOWN',16); /* event status */ define('NEEDS_ACTION',0); define('ACCEPTED',1); define('DECLINED',2); define('TENTATIVE',3); define('DELEGATED',4); define('COMPLETED',5); define('IN_PROCESS',6); /* class */ define('PRIVATE',0); define('PUBLIC',1); define('CONFIDENTIAL',3); /* transparency */ define('TRANSPARENT',0); define('OPAQUE',1); /* frequency */ define('SECONDLY',1); define('MINUTELY',2); define('HOURLY',3); define('DAILY',4); define('WEEKLY',5); define('MONTHLY',6); define('YEARLY',7); define('FREE',0); define('BUSY',1); define('BUSY_UNAVAILABLE',2); define('BUSY_TENTATIVE',3); define('THISANDPRIOR',0); define('THISANDFUTURE',1); define('START',0); define('END',1); define('_8BIT',0); define('_BASE64',1); define('OTHER',99); class boicalendar { var $public_functions = array( 'import' => True, 'export' => True, 'freebusy' => True, ); var $ical; var $line = 0; var $event = Array(); var $todo = Array(); var $journal = Array(); var $freebusy = Array(); var $timezone = Array(); var $property = Array(); var $parameter = Array(); var $debug_str = False; var $api = True; var $chunk_split = True; /* * Base Functions */ function boicalendar() { $this->property = Array( 'action' => Array( 'type' => 'text', 'to_text' => True, 'valarm' => Array( 'state' => 'required', 'multiples' => False ) ), 'attach' => Array( 'type' => 'uri', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => True ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => True ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ), 'valarm' => Array( 'state' => 'optional', 'multiples' => True ) ), 'attendee' => Array( 'type' => 'cal-address', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => True ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => True ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ), 'valarm' => Array( 'state' => 'optional', 'multiples' => True ), 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => True ) ), 'categories' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => True ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ) ), 'class' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ) ), 'comment' => Array( 'type' => 'text', 'to_text' => True, 'daylight' => Array( 'state' => 'optional', 'multiples' => True ), 'standard' => Array( 'state' => 'optional', 'multiples' => True ), 'valarm' => Array( 'state' => 'optional', 'multiples' => True ), 'vevent' => Array( 'state' => 'optional', 'multiples' => True ), 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => True ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => True ) ), 'completed' => Array( 'type' => 'date-time', 'to_text' => False, 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'contact' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => True ), 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ) ), 'created' => Array( 'type' => 'date-time', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ) ), 'description' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ), 'valarm' => Array( 'state' => 'optional', 'multiples' => False ) ), 'dtend' => Array( 'type' => 'date-time', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => False ) ), 'dtstamp' => Array( 'type' => 'date-time', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ), 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => False ) ), 'dtstart' => Array( 'type' => 'date-time', 'to_text' => False, 'daylight' => Array( 'state' => 'required', 'multiples' => False ), 'standard' => Array( 'state' => 'required', 'multiples' => False ), 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'due' => Array( 'type' => 'date-time', 'to_text' => False, 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'duration' => Array( 'type' => 'duration', 'to_text' => False, 'valarm' => Array( 'state' => 'optional', 'multiples' => False ), 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'exdate' => Array( 'type' => 'date-time', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => True ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => True ) ), 'exrule' => Array( 'type' => 'recur', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => True ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => True ) ), 'freebusy' => Array( 'type' => 'freebusy', 'to_text' => False, 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => True ) ), 'geo' => Array( 'type' => 'float', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'last_modified' => Array( 'type' => 'date-time', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ), 'vtimezone' => Array( 'state' => 'optional', 'multiples' => False ) ), 'location' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'method' => Array( 'type' => 'text', 'to_text' => True, 'ical' => Array( 'state' => 'required', 'multiples' => False ) ), 'organizer' => Array( 'type' => 'cal-address', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ), 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => False ) ), 'percent_complete' => Array( 'type' => 'integer', 'to_text' => False, 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'priority' => Array( 'type' => 'integer', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'prodid' => Array( 'type' => 'text', 'to_text' => True, 'ical' => Array( 'state' => 'required', 'multiples' => False ) ), 'rdate' => Array( 'type' => 'date-time', 'to_text' => False, 'daylight' => Array( 'state' => 'optional', 'multiples' => True ), 'standard' => Array( 'state' => 'optional', 'multiples' => True ), 'vevent' => Array( 'state' => 'optional', 'multiples' => True ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => True ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ) ), 'recurrence_id' => Array( 'type' => 'date-time', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'related_to' => Array( 'type' => 'text', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => True ) ), 'request_status' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => True ), 'vfreebusy' => Array( 'state' => 'optional', 'multiples' => True ) ), 'resources' => Array( 'type' => 'text', 'to_text' => False, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'rrule' => Array( 'type' => 'recur', 'to_text' => False, 'daylight' => Array( 'state' => 'optional', 'multiples' => False ), 'standard' => Array( 'state' => 'optional', 'multiples' => False ), 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ) ), 'sequence' => Array( 'type' => 'integer', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'status' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ) ), 'summary' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'optional', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ), 'valarm' => Array( 'state' => 'optional', 'multiples' => False ) ), 'transp' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'optional', 'multiples' => False ) ), 'trigger' => Array( 'type' => 'text', 'to_text' => True, 'valarm' => Array( 'state' => 'optional', 'multiples' => False ) ), 'tzid' => Array( 'type' => 'text', 'to_text' => True, 'vtimezone' => Array( 'state' => 'required', 'multiples' => False ) ), 'tzname' => Array( 'type' => 'text', 'to_text' => True, 'daylight' => Array( 'state' => 'optional', 'multiples' => True ), 'standard' => Array( 'state' => 'optional', 'multiples' => True ) ), 'tzoffsetfrom' => Array( 'type' => 'utc-offset', 'to_text' => True, 'daylight' => Array( 'state' => 'required', 'multiples' => False ), 'standard' => Array( 'state' => 'required', 'multiples' => False ) ), 'tzoffsetto' => Array( 'type' => 'utc-offset', 'to_text' => True, 'daylight' => Array( 'state' => 'required', 'multiples' => False ), 'standard' => Array( 'state' => 'required', 'multiples' => False ) ), 'tzurl' => Array( 'type' => 'uri', 'to_text' => True, 'vtimezone' => Array( 'state' => 'optional', 'multiples' => False ) ), 'uid' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'required', 'multiples' => False ), 'vfreebusy' => Array( 'state' => 'required', 'multiples' => False ), 'vjournal' => Array( 'state' => 'required', 'multiples' => False ), 'vtodo' => Array( 'state' => 'required', 'multiples' => False ) ), 'url' => Array( 'type' => 'text', 'to_text' => True, 'vevent' => Array( 'state' => 'required', 'multiples' => False ), 'vfreebusy' => Array( 'state' => 'required', 'multiples' => False ), 'vjournal' => Array( 'state' => 'optional', 'multiples' => False ), 'vtodo' => Array( 'state' => 'required', 'multiples' => False ) ), 'version' => Array( 'type' => 'text', 'to_text' => True, 'ical' => Array( 'state' => 'required', 'multiples' => False ) ) ); $this->parameter = Array( 'altrep' => Array( 'type' => 'uri', 'quoted' => True, 'to_text' => True, 'properties' => Array( 'comment' => True, 'description' => True, 'location' => True, 'prodid' => True, 'resources' => True, 'summary' => True, 'contact' => True ) ), 'byday' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'byhour' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'byminute' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'bymonth' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'bymonthday' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'bysecond' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'bysetpos' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'byweekno' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'byyearday' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'class' => Array( 'type' => 'function', 'function' => 'switch_class', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'class' => True ) ), 'cn' => Array( 'type' => 'text', 'quoted' => True, 'to_text' => False, 'properties' => Array( 'attendee' => True, 'organizer' => True ) ), 'count' => Array( 'type' => 'integer', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'cu' => Array( 'type' => 'function', 'function' => 'switch_cu', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'attendee' => True ) ), 'delegated_from' => Array( 'type' => 'function', 'function' => 'switch_mailto', 'quoted' => True, 'to_text' => False, 'properties' => Array( 'attendee' => True ) ), 'delegated_to' => Array( 'type' => 'function', 'function' => 'switch_mailto', 'quoted' => True, 'to_text' => False, 'properties' => Array( 'attendee' => True ) ), 'dir' => Array( 'type' => 'dir', 'quoted' => True, 'to_text' => True, 'properties' => Array( 'attendee' => True, 'organizer' => True ) ), 'dtend' => Array( 'type' => 'function', 'function' => 'switch_date', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'dtend' => True ) ), 'dtstamp' => Array( 'type' => 'function', 'function' => 'switch_date', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'dtstamp' => True ) ), 'dtstart' => Array( 'type' => 'function', 'function' => 'switch_date', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'dtstart' => True ) ), 'encoding' => Array( 'type' => 'function', 'function' => 'switch_encoding', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'attach' => True ) ), 'fmttype' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'attach' => True ) ), 'fbtype' => Array( 'type' => 'function', 'function' => 'switch_fbtype', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'attach' => True ) ), 'freq' => Array( 'type' => 'function', 'function' => 'switch_freq', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'interval' => Array( 'type' => 'integer', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'language' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'categories' => True, 'comment' => True, 'description' => True, 'location' => True, 'resources' => True, 'summary' => True, 'tzname' => True, 'attendee' => True, 'contact' => True, 'organizer' => True, 'x-type' => True ) ), 'last_modified' => Array( 'type' => 'function', 'function' => 'switch_date', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'last_modified' => True ) ), 'mailto' => Array( 'type' => 'function', 'function' => 'switch_mailto', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'attendee' => True, 'organizer' => True ) ), 'member' => Array( 'type' => 'function', 'function' => 'switch_mailto', 'quoted' => True, 'to_text' => False, 'properties' => Array( 'attendee' => True ) ), 'partstat' => Array( 'type' => 'function', 'function' => 'switch_partstat', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'attendee' => True, 'organizer' => True ) ), 'range' => Array( 'type' => 'function', 'function' => 'switch_range', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'recurrence_id' => True ) ), 'related' => Array( 'type' => 'function', 'function' => 'switch_related', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'related_to' => True ) ), 'role' => Array( 'type' => 'function', 'function' => 'switch_role', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'attendee' => True, 'organizer' => True ) ), 'rsvp' => Array( 'type' => 'function', 'function' => 'switch_rsvp', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'attendee' => True ) ), 'sent_by' => Array( 'type' => 'function', 'function' => 'switch_mailto', 'quoted' => True, 'to_text' => False, 'properties' => Array( 'attendee' => True, 'organizer' => True ) ), 'tzid' => Array( 'type' => 'text', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'dtend' => True, 'due' => True, 'dtstart' => True, 'exdate' => True, 'rdate' => True, 'recurrence_id' => True ) ), 'until' => Array( 'type' => 'function', 'function' => 'switch_date', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'value' => Array( 'type' => 'value', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'calscale' => True, 'prodid' => True, 'method' => True, 'version' => True, 'attach' => True, 'categories' => True, 'class' => True, 'comment' => True, 'description' => True, 'geo' => True, 'location' => True, 'percent' => True, 'priority' => True, 'resources' => True, 'status' => True, 'summary' => True, 'completed' => True, 'dtend' => True, 'due' => True, 'dtstart' => True, 'duration' => True, 'freebusy' => True, 'transp' => True, 'tzid' => True, 'tzname' => True, 'tzoffsetfrom' => True, 'tzoffsetto' => True, 'tzurl' => True, 'attendee' => True, 'contact' => True, 'organizer' => True, 'recurrence_id' => True, 'url' => True, 'uid' => True, 'exdate' => True, 'exrule' => True, 'rdate' => True, 'rrule' => True, 'action' => True, 'repeat' => True, 'trigger' => True, 'created' => True, 'dtstamp' => True, 'last_modified' => True, 'sequence' => True, 'x_type' => True, 'request_status'=> True ) ), 'wkst' => Array( 'type' => 'string', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'rrule' => True ) ), 'x_type' => Array( 'type' => 'x_type', 'quoted' => False, 'to_text' => False, 'properties' => Array( 'calscale' => True, 'method' => True, 'prodid' => True, 'version' => True, 'attach' => True, 'categories' => True, 'class' => True, 'comment' => True, 'description' => True, 'geo' => True, 'location' => True, 'percent' => True, 'priority' => True, 'resources' => True, 'status' => True, 'summary' => True, 'completed' => True, 'dtend' => True, 'due' => True, 'dtstart' => True, 'duration' => True, 'freebusy' => True, 'transp' => True, 'tzid' => True, 'tzname' => True, 'tzoffsetfrom' => True, 'tzoffsetto' => True, 'tzurl' => True, 'attendee' => True, 'contact' => True, 'organizer' => True, 'recurrence_id' => True, 'url' => True, 'uid' => True, 'exdate' => True, 'exrule' => True, 'rdate' => True, 'rrule' => True, 'action' => True, 'repeat' => True, 'trigger' => True, 'created' => True, 'dtstamp' => True, 'last_modified' => True, 'sequence' => True, 'x_type' => True, 'request_status'=> True ) ) ); if(!is_object($GLOBALS['phpgw']->datetime)) { $GLOBALS['phpgw']->datetime = createobject('phpgwapi.datetime'); } } function set_var(&$event,$type,$value) { $type = strtolower(str_replace('-','_',$type)); $event[$type] = $value; if(is_string($value)) { $this->debug("Setting ".$type." = ".$value); } else { $this->debug("Setting ".$type." = "._debug_array($value,False)); } } function read_line_unfold($ical_text) { if($this->line < count($ical_text)) { $str = str_replace("\r\n",'',$ical_text[$this->line]); $this->line = $this->line + 1; while(ereg("^[[:space:]]",$ical_text[$this->line])) { $str .= substr(str_replace("\r\n",'',$ical_text[$this->line]),1); $this->line = $this->line + 1; } $this->debug("LINE : ".$str); return $str; } else { return False; } } function fold($str) { return $this->chunk_split==True ? chunk_split($str,FOLD_LENGTH,"\r\n") : $str."\r\n"; } function strip_quotes($str) { return str_replace('"','',$str); } function from_text($str) { $str = str_replace("\\,",",",$str); $str = str_replace("\\;",";",$str); $str = str_replace("\\N","\n",$str); $str = str_replace("\\n","\n",$str); $str = str_replace("\\\\","\\",$str); return "$str"; } function to_text($str) { $str = str_replace("\\","\\\\",$str); $str = str_replace(",","\\,",$str); $str = str_replace(";","\\;",$str); $str = str_replace("\n","\\n",$str); return "$str"; } function from_dir($str) { return str_replace('=3D','=',str_replace('%20',' ',$str)); } function to_dir($str) { return str_replace('=','=3D',str_replace(' ','%20',$str)); } function find_parameters($property) { static $cached_returns; if(isset($cached_returns[$property])) { reset($cached_returns[$property]); return $cached_returns[$property]; } reset($this->parameter); while(list($key,$param_array) = each($this->parameter)) { if($param_array['properties'][$property]) { $param[] = $key; $this->debug('Property : '.$property.' = Parameter : '.$key); } } reset($param); $cached_returns[$property] = $param; return $param; } function find_properties($ical_type) { static $cached_returns; if(isset($cached_returns[$ical_type])) { reset($cached_returns[$ical_type]); return $cached_returns[$ical_type]; } reset($this->property); while(list($key,$param_array) = each($this->property)) { if($param_array[$ical_type]) { $prop[] = $key; } } reset($prop); $cached_returns[$ical_type] = $prop; return $prop; } function new_ical() { return Array(); } /* * Parse Functions */ function parse_geo(&$event,$value) { // $return_value = $this->explode_param($value,True); if(count($return_value) == 2) { $event['lat'] = $return_value[0]; $event['lon'] = $return_value[1]; } } function parse_xtype(&$event,$majortype,$value) { $temp_x_type['name'] = strtoupper(substr($majortype,2)); $temp_x_type['value'] = $value; $event['x_type'][] = $temp_x_type; } function parse_parameters(&$event,$majortype,$value) { if(!ereg('[\=\;]',$value)) { $return_value[] = Array( 'param' => $majortype, 'value' => $value ); $value = ''; } elseif(ereg('(.*(\:\\\\)?.*):(.*)',$value,$temp)) { $this->debug('Value : '._debug_array($temp,False)); $this->debug('Param '.$majortype.' Value : '.$temp[3]); if($temp[3]) { $return_value[] = Array( 'param' => $majortype, 'value' => $temp[3] ); $value = str_replace(':MAILTO','',$temp[1]); } while(ereg('(([A-Z\-]*)[=]([[:alnum:] \_\)\(\/\$\.\,\:\\\|\*\&\^\%\#\!\~\"\?\&\@\<\>\-]*))([\;]?)(.*)',$value,$temp)) { $this->debug('Value : '._debug_array($temp,False)); $this->debug('Param '.$temp[2].' Value : '.$temp[3]); $return_value[] = Array( 'param' => $temp[2], 'value' => $temp[3] ); $value = chop($temp[5]); $this->debug('Value would be = '.$value); } } else { while(ereg('(([A-Z\-]*)[=]([[:alnum:] \_\)\(\/\$\.\,\:\\\|\*\&\^\%\#\!\~\"\?\&\@\<\>\-]*))([\;]?)(.*)',$value,$temp)) { $this->debug('Value : '._debug_array($temp,False)); $this->debug('Param '.$temp[2].' Value : '.$temp[3]); $return_value[] = Array( 'param' => $temp[2], 'value' => $temp[3] ); $value = chop($temp[5]); $this->debug('Value would be = '.$value); } } for($i=0;$istrip_quotes($return_value[$i]['value']); if(substr($name,0,2) == 'x-') { $param = 'x_type'; $name = str_replace('-','_',$return_value[$i]['param']); } else { $param = str_replace('-','_',strtolower($name)); if(!isset($this->parameter[$param]) || $majortype == 'tzid') { if($majortype == 'attendee' || $majortype == 'organizer') { $param = 'mailto'; $name = $param; } else { $param = 'value'; } } } $this->debug('name : '.$name.' : Param = '.$param); if(@$this->parameter[$param]['properties'][$majortype]) { switch(@$this->parameter[$param]['type']) { case 'dir': $this->set_var($event,$name,$this->from_dir($value)); break; case 'text': $this->set_var($event,$name,$value); break; case 'x_type': $this->parse_xtype($event,$name,$value); break; case 'function': $function = $this->parameter[$param]['function']; $this->set_var($event,$name,$this->$function($value)); break; case 'uri': if(@$this->parameter[$param]['to_text']) { $value = $this->to_text($value); } $this->set_var($event,$name,$value); break; case 'integer': $this->set_var($event,$name,(int)$value); break; case 'value': if(@$this->property[$majortype]['type'] == 'date-time') { $this->set_var($event,$param,$this->switch_date($name)); } elseif($value <> "\\n" && $value) { $this->set_var($event[$majortype],$param,$value); } $this->debug('Event : '._debug_array($event,False)); break; } } } } function parse_value(&$event,$majortype,$value,$mode) { $var = Array(); $this->debug('Mode : '.$mode.' Majortype : '.$majortype); $this->parse_parameters($var,$majortype,$value); if($this->property[$majortype][$mode]['multiples']) { $this->debug(_debug_array($var,False)); $event[$majortype][] = $var; } else { $this->debug('Majortype : '.$majortype); $this->debug('Property : '.$this->property[$majortype]['type']); if($this->property[$majortype]['type'] == 'date-time') { $this->debug('Got a DATE-TIME type!'); $t_var = $var[$majortype]; unset($var[$majortype]); reset($t_var); while(list($key,$val) = each($t_var)) { $var[$key] = $val; } $this->debug($majortype.' : '._debug_array($var,False)); } $this->set_var($event,$majortype,$var); } } /* * Build-Card Functions */ function build_xtype($x_type,$seperator='=') { $quote = ''; if($seperator == '=') { $quote = '"'; } $return_value = $this->fold('X-'.$x_type['name'].$seperator.$quote.$x_type['value'].$quote); if($seperator == '=') { return str_replace("\r\n",'',$return_value); } else { return $return_value; } } function build_parameters($event,$property) { $str = ''; $include_mailto = False; $include_datetime = False; $param = $this->find_parameters($property); if($property == 'exdate') { while(list($key,$value) = each($event)) { $exdates[] = $this->switch_date($value); } return ':'.implode($exdates,','); } else { while(list($dumb_key,$key) = each($param)) { if($key == 'value') { continue; } if($key == 'mailto') { $include_mailto = True; continue; } $param_array = @$this->parameter[$key]; $type = @$this->parameter[$key]['type']; if($type == 'date-time') { $include_datetime = True; continue; } $quote = (@$this->parameter[$key]['quoted']?'"':''); if(isset($event[$key]) && @$this->parameter[$key]['properties'][$property]) { $change_text = @$this->parameter[$key]['to_text']; $value = $event[$key]; if($change_text && $type == 'text') { $value = $this->to_text($value); } switch($type) { case 'dir': $str .= ';'.str_replace('_','-',strtoupper($key)).'='.$quote.$this->to_dir($value).$quote; break; case 'function': $str .= ';'.str_replace('_','-',strtoupper($key)).'='; $function = $this->parameter[$key]['function']; $this->debug($key.' Function Param : '.$value); $str .= $quote.$this->$function($value).$quote; break; case 'text': case 'string': $str .= ';'.strtoupper($key).'='.$quote.$value.$quote; break; case 'date-time': $str .= ($key=='until'?':':';UNTIL=').date('Ymd\THis',mktime($event['hour'],$event['min'],$event['sec'],$event['month'],$event['mday'],$event['year'])).(!@isset($event['tzid'])?'Z':''); break; } unset($value); } } if(!empty($event['x_type'])) { $c_x_type = count($event['x_type']); for($j=0;$j<$c_x_type;$j++) { $str .= ';'.$this->build_xtype($event['x_type'][$j],'='); } } if(!empty($event['value'])) { if($property == 'trigger') { $seperator = ';'; } else { $seperator = ':'; } $str .= $seperator.($this->parameter['value']['to_text']?$this->to_text($event['value']):$event['value']); } if($include_mailto == True) { $key = 'mailto'; $function = $this->parameter[$key]['function']; $ret_value = $this->$function($event[$key]); $str .= ($ret_value?':'.$ret_value:''); } if($include_datetime == True || @$this->property[$property]['type'] == 'date-time') { $str .= ':'.date('Ymd\THis',mktime($event['hour'],$event['min'],$event['sec'],$event['month'],$event['mday'],$event['year'])).(!@isset($event['tzid'])?'Z':''); } return ($property=='rrule'?':'.substr($str,1):$str); } } function build_text($event,$property) { $str = ''; $param = $this->find_parameters($property); while(list($dumb_key,$key) = each($param)) { if(!empty($event[$key]) && $key != 'value') { $type = @$this->parameter[$key]['type']; $quote = @$this->parameter[$key]['quote']; if(@$this->parameter[$key]['to_text'] == True) { $value = $this->to_text($event[$key]); } else { $value = $event[$key]; } switch($type) { case 'text': $str .= ';'.strtoupper($key).'='.$quote.$value.$quote; break; } } } if(!empty($event['x_type'])) { $c_x_type = count($event['x_type']); for($j=0;$j<$c_x_type;$j++) { $str .= ';'.$this->build_xtype($event['x_type'][$j],'='); } } if(!empty($event['value'])) { $str .= ':'.($this->parameter['value']['to_text']?$this->to_text($event['value']):$event['value']); } return $str; } function build_card_internals($ical_item,$event) { $prop = $this->find_properties($ical_item); reset($prop); while(list($dumb_key,$key) = each($prop)) { $value = $key; $varray = $this->property[$key]; $type = $varray['type']; $to_text = $varray['to_text']; $state = @$varray[$ical_item]['state']; $multiples = @$varray[$ical_item]['multiples']; switch($type) { case 'date-time': if(!empty($event[$value])) { if($multiples && $value != 'exdate') { for($i=0;$ifold(strtoupper(str_replace('_','-',$value)).$this->build_parameters($event[$value][$i],$value)); } } else { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).$this->build_parameters($event[$value],$value)); } } elseif($value == 'dtstamp' || $value == 'created') { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).':'.gmdate('Ymd\THis\Z')); } break; case 'uri': if(!empty($event[$value])) { for($i=0;$ifold(strtoupper(str_replace('_','-',$value)).$this->build_parameters($event[$value][$i],$to_text)); } } break; case 'recur': if(!empty($event[$value])) { if($multiples) { for($i=0;$ifold(strtoupper(str_replace('_','-',$value)).$this->build_parameters($event[$value][$i],$value)); } } else { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).$this->build_parameters($event[$value],$value)); } } break; case 'integer': if(!empty($event[$value])) { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).':'.$event[$value]); } elseif($value == 'sequence' || $value == 'percent_complete') { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).':0'); } break; case 'function': $str .= ';'.str_replace('_','-',strtoupper($value)).'='; $function = @$this->parameter[$key]['function']; $str .= (@$this->parameter[$key]['quoted']?'"':'').$this->$function($event[$key]).(@$this->parameter[$key]['quoted']?'"':''); break; case 'float': if(!empty($event[$value])) { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).':'.$event[$value]['lat'].';'.$event[$value]['lon']); } break; case 'text': if(isset($event[$value])) { if(@$this->parameter[$key]['type'] != 'function') { if($multiples && count($event[$value]) > 1) { for($i=0;$ifold(strtoupper(str_replace('_','-',$value)).$this->build_parameters($event[$value][$i],$value)); } } else { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).$this->build_parameters($event[$value],$value)); } } else { $function = $this->parameter[$value]['function']; if($multiples) { for($i=0;$ifold(strtoupper(str_replace('_','-',$value)).':'.$this->$function($event[$value][$i])); } } else { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).':'.$this->$function($event[$value])); } } } break; case 'cal-address': if(is_array($event[$value][0])) { for($j=0;$jbuild_parameters($event[$value][$j],$value); if($temp_output) { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).$temp_output); } } } else { $temp_output = $this->build_parameters($event[$value],$value); if($temp_output) { $str .= $this->fold(strtoupper(str_replace('_','-',$value)).$temp_output); } } break; } } if(!empty($event['x_type'])) { for($i=0;$ibuild_xtype($event['x_type'][$i],':'); } } if($ical_item == 'vtimezone') { if($event['tzdata']) { for($k=0;$kbuild_card_internals(strtolower($event['tzdata'][$k]['type']),$event['tzdata'][$k]); $str .= 'END:'.strtoupper($event['tzdata'][$k]['type'])."\r\n"; } } } elseif($event['alarm']) { for($k=0;$kbuild_card_internals('valarm',$event['alarm'][$k]); $str .= 'END:VALARM'."\r\n"; } } return $str; } /* * Switching Functions */ function switch_class($var) { if(is_string($var)) { switch($var) { case 'PRIVATE': return PRIVATE; break; case 'PUBLIC': return PUBLIC; break; case 'CONFIDENTIAL': return CONFIDENTIAL; break; } } elseif(is_int($var)) { switch((int)$var) { case PRIVATE: return 'PRIVATE'; break; case PUBLIC: return 'PUBLIC'; break; case CONFIDENTIAL: return 'CONFIDENTIAL'; break; } } else { return $var; } } function switch_cu($var) { if(gettype($var) == 'string') { switch($var) { case 'INDIVIDUAL': return INDIVIDUAL; break; case 'GROUP': return GROUP; break; case 'RESOURCE': return RESOURCE; break; case 'ROOM': return ROOM; break; case 'UNKNOWN': return UNKNOWN; break; default: return OTHER; break; } } elseif(gettype($var) == 'integer') { switch($var) { case INDIVIDUAL: return 'INDIVIDUAL'; break; case GROUP: return 'GROUP'; break; case RESOURCE: return 'RESOURCE'; break; case ROOM: return 'ROOM'; break; case UNKNOWN: return 'UNKNOWN'; break; default: return 'X-OTHER'; break; } } else { return $var; } } function switch_date($var) { $this->debug('SWITCH_DATE: gettype = '.gettype($var)); if(is_string($var)) { $dtime = Array(); if(strpos($var,':')) { $pos = explode(':',$var); $var = $pos[1]; } $this->set_var($dtime,'year',(int)(substr($var,0,4))); $this->set_var($dtime,'month',(int)(substr($var,4,2))); $this->set_var($dtime,'mday',(int)(substr($var,6,2))); if(substr($var,8,1) == 'T') { $this->set_var($dtime,'hour',(int)(substr($var,9,2))); $this->set_var($dtime,'min',(int)(substr($var,11,2))); $this->set_var($dtime,'sec',(int)(substr($var,13,2))); if(strlen($var) > 14) { if(substr($var,14,1) != 'Z') { if($this->api) { $dtime['hour'] -= $GLOBALS['phpgw_info']['users']['common']['tz_offset']; if($dtime['hour'] < 0) { $dtime['mday'] -= 1; $dtime['hour'] = 24 - $dtime['hour']; } elseif($dtime['hour'] >= 24) { $dtime['mday'] += 1; $dtime['hour'] = $dtime['hour'] - 24; } } } } } else { $this->set_var($dtime,'hour',0); $this->set_var($dtime,'min',0); $this->set_var($dtime,'sec',0); if($this->api) { $dtime['hour'] -= $GLOBALS['phpgw_info']['users']['common']['tz_offset']; if($dtime['hour'] < 0) { $dtime['mday'] -= 1; $dtime['hour'] = 24 - $dtime['hour']; } elseif($dtime['hour'] >= 24) { $dtime['mday'] += 1; $dtime['hour'] = $dtime['hour'] - 24; } } } $this->debug('DATETIME : '._debug_array($dtime,False)); return $dtime; } elseif(is_array($var)) { return date('Ymd\THis\Z',mktime($var['hour'],$var['min'],$var['sec'],$var['month'],$var['mday'],$var['year'])); } else { return $var; } } function switch_encoding($var) { if(is_string($var)) { switch($var) { case '8BIT': return _8BIT; break; case 'BASE64': return _BASE64; break; default: return OTHER; break; } } elseif(is_int($var)) { switch($var) { case _8BIT: return '8BIT'; break; case _BASE64: return 'BASE64'; break; case OTHER: return 'OTHER'; break; } } else { return $var; } } function switch_fbtype($var) { if(is_string($var)) { switch($var) { case 'FREE': return FREE; break; case 'BUSY': return BUSY; break; case 'BUSY-UNAVAILABLE': return BUSY_UNAVAILABLE; break; case 'BUSY-TENTATIVE': return BUSY_TENTATIVE; break; default: return OTHER; break; } } elseif(is_int($var)) { switch($var) { case FREE: return 'FREE'; break; case BUSY: return 'BUSY'; break; case BUSY_UNAVAILABLE: return 'BUSY-UNAVAILABLE'; break; case BUSY_TENTATIVE: return 'BUSY-TENTATIVE'; break; default: return 'OTHER'; break; } } else { return $var; } } function switch_freq($var) { if(is_string($var)) { switch($var) { case 'SECONDLY': return SECONDLY; break; case 'MINUTELY': return MINUTELY; break; case 'HOURLY': return HOURLY; break; case 'DAILY': return DAILY; break; case 'WEEKLY': return WEEKLY; break; case 'MONTHLY': return MONTHLY; break; case 'YEARLY': return YEARLY; break; } } elseif(is_int($var)) { switch($var) { case SECONDLY: return 'SECONDLY'; break; case MINUTELY: return 'MINUTELY'; break; case HOURLY: return 'HOURLY'; break; case DAILY: return 'DAILY'; break; case WEEKLY: return 'WEEKLY'; break; case MONTHLY: return 'MONTHLY'; break; case YEARLY: return 'YEARLY'; break; } } else { return $var; } } function switch_mailto($var) { if(is_string($var)) { if(strpos(' '.$var,':')) { $parts = explode(':',$var); $var = $parts[1]; } $parts = explode('@',$var); $this->debug("Count of mailto parts : ".count($parts)); if(count($parts) == 2) { $this->debug("Splitting ".$parts[0]." @ ".$parts[1]); $temp_address = Array(); $temp_address['user'] = $parts[0]; $temp_address['host'] = $parts[1]; return $temp_address; } else { return False; } } elseif(is_array($var)) { // return 'MAILTO:'.$var['user'].'@'.$var['host']; return $var['user'].'@'.$var['host']; } } function switch_partstat($var) { // $this->debug_str = True; $this->debug('PARTSTAT = '.$var); // $this->debug_str = False; if(is_string($var)) { switch($var) { case 'NEEDS-ACTION': return 0; // NEEDS_ACTION; break; case 'ACCEPTED': return 1; // ACCEPTED; break; case 'DECLINED': return 2; // DECLINED; break; case 'TENTATIVE': return 3; // TENTATIVE; break; case 'DELEGATED': return 4; // DELEGATED; break; case 'COMPLETED': return 5; // COMPLETED; break; case 'IN-PROCESS': return 6; // IN_PROCESS; break; default: return 99; // OTHER; break; } } elseif(is_int($var)) { switch((int)$var) { case 0: // NEEDS_ACTION: return 'NEEDS-ACTION'; break; case 1: // ACCEPTED: return 'ACCEPTED'; break; case 2: // DECLINED: return 'DECLINED'; break; case 3: // TENTATIVE: return 'TENTATIVE'; break; case 4: // DELEGATED: return 'DELEGATED'; break; case 5: // COMPLETED: return 'COMPLETED'; break; case 6: // IN_PROCESS: return 'IN-PROCESS'; break; default: return 'X-OTHER'; break; } } else { return $var; } } function switch_range($var) { if(is_string($var)) { switch($var) { case 'THISANDPRIOR': return THISANDPRIOR; break; case 'THISANDFUTURE': return THISANDFUTURE; break; } } elseif(is_int($var)) { switch($var) { case THISANDPRIOR: return 'THISANDPRIOR'; break; case THISANDFUTURE: return 'THISANDFUTURE'; break; } } else { return $var; } } function switch_related($var) { if(is_string($var)) { switch($var) { case 'START': return START; break; case 'END': return END; break; } } elseif(is_int($var)) { switch($var) { case START: return 'START'; break; case END: return 'END'; break; } } else { return $var; } } function switch_reltype($var) { if(is_string($var)) { switch($var) { case 'PARENT': return PARENT; break; case 'CHILD': return CHILD; break; case 'SIBLING': return SIBLING; break; } } elseif(is_int($var)) { switch($var) { case PARENT: return 'PARENT'; break; case CHILD: return 'CHILD'; break; case SIBLING: return 'SIBLING'; break; } } else { return $var; } } function switch_role($var) { if(is_string($var)) { switch($var) { case 'NONE': return NONE; break; case 'CHAIR': return CHAIR; break; case 'REQ-PARTICIPANT': return REQ_PARTICIPANT; break; case 'OPT-PARTICIPANT': return OPT_PARTICIPANT; break; case 'NON-PARTICIPANT': return NON_PARTICIPANT; break; } } elseif(is_int($var)) { switch($var) { case NONE: return 'NONE'; break; case CHAIR: return 'CHAIR'; break; case REQ_PARTICIPANT: return 'REQ-PARTICIPANT'; break; case OPT_PARTICIPANT: return 'OPT-PARTICIPANT'; break; case NON_PARTICIPANT: return 'NON-PARTICIPANT'; break; } } else { return $var; } } function switch_rsvp($var) { if(is_string($var)) { if($var == 'TRUE') { return 1; } elseif($var == 'FALSE') { return 0; } } elseif(is_int($var) || $var == False) { if($var == 1) { return 'TRUE'; } elseif($var == 0) { return 'FALSE'; } } else { return $var; } } function switch_transp($var) { if(is_string($var)) { switch($var) { case 'TRANSPARENT': return TRANSPARENT; break; case 'OPAQUE': return OPAQUE; break; } } elseif(is_int($var)) { switch($var) { case TRANSPARENT: return 'TRANSPARENT'; break; case OPAQUE: return 'OPAQUE'; break; } } else { return $var; } } /* * The brunt of the class */ function parse($ical_text) { $begin_regexp = '^'; $semi_colon_regexp = '[\;\:]'; $colon_regexp = '[\:]'; $catch_all_regexp = '(.*)'; $end_regexp = '$'; $property_regexp = $begin_regexp.'([A-Z\-]*)'.$semi_colon_regexp.$catch_all_regexp.$end_regexp; $param_regexp = $begin_regexp.$catch_all_regexp.':'.$catch_all_regexp.$end_regexp; $mode = 'none'; $text = $this->read_line_unfold($ical_text); while($text) { // if(strlen($ical_text[$i]) > 75) // { // continue; // } ereg($property_regexp,$text,$temp); $majortype = str_replace('-','_',strtolower($temp[1])); $value = chop($temp[2]); if($mode != 'none' && ($majortype != 'begin' && $majortype != 'end')) { $this->debug('PARSE:MAJORTYPE : '.$majortype); if(isset($this->property[$majortype])) { $state = @$this->property[$majortype]["$mode"]['state']; $type = @$this->property[$majortype]['type']; $multiples = @$this->property[$majortype]["$mode"]['multiples']; $do_to_text = @$this->property[$majortype]['to_text']; } elseif(substr($majortype,0,2) == 'x_') { $state = 'optional'; $type = 'xtype'; $multiples = True; $do_to_test = True; } else { $state = ''; } } else { $state = 'required'; } if($majortype == 'duration') { unset($dur); // Split «DURATION» list($_f_['day_raw'], $_f_['time_raw']) = split('T', substr($value, 1, strlen($value)-1)); /* Datecode */ if(isset($_f_['day_raw']) OR $_f_['day_raw']) { /* Days */ if(strstr($_f_['day_raw'],'D')) { $dur['days'] = eregi_replace("([0-9]+)D(.*)", "\\1", $_f_['day_raw']); } /* Weeks */ if(strstr($_f_['day_raw'],'W')) { $dur['weeks'] = eregi_replace("([^|.*]+D)?([0-9]+)W", "\\2", $_f_['day_raw']); } } /* Timecode */ if(isset($_f_['time_raw']) OR $_f_['time_raw']) { /* Hours */ if(strstr($_f_['time_raw'],'H')) { $dur['hours'] = eregi_replace("([0-9]+)H(.*)", "\\1", $_f_['time_raw']); } /* Minutes */ if(strstr($_f_['time_raw'],'M')) { $dur['minutes'] = eregi_replace("([^|.*]+H)?([0-9]+)M(.*)", "\\2", $_f_['time_raw']); } /* Seconds */ if(strstr($_f_['time_raw'],'S')) { $dur['seconds'] = eregi_replace("([^|.*]+M)?([0-9]+)S(.*)", "\\2", $_f_['time_raw']); } } $dur['raw'] = Array( 'timecode' => $_f_['time_raw'], 'datecode' => $_f_['day_raw'], 'all' => $value ); /* Add new parameters in Event */ $this->set_var($event, $majortype, $dur); } if($majortype == 'begin') { $tmode = $mode; $mode = strtolower($value); switch(strtolower($value)) { case 'daylight': case 'standard': $t_event = Array(); $t_event = $event; $event = Array(); break; case 'valarm': if($tmode == 'vevent' || $tmode == 'vtodo') { $t_event = $event; unset($event); $event = Array(); } else { $mode = $tmode; } break; case 'vcalendar': $ical = $this->new_ical(); break; case 'vevent': case 'vfreebusy': case 'vjournal': case 'vtimezone': case 'vtodo': $event = Array(); break; } $event['type'] = strtolower($value); } elseif($majortype == 'end') { $mode = 'none'; switch(strtolower($value)) { case 'daylight': case 'standard': $tzdata[] = $event; unset($event); $event = $t_event; unset($t_event); $mode = 'vtimezone'; break; case 'valarm': $alarm[] = $event; unset($event); $event = $t_event; unset($t_event); $mode = $tmode; break; case 'vevent': if(!empty($alarm)) { $event['alarm'] = $alarm; unset($alarm); } $this->event[] = $event; unset($event); break; case 'vfreebusy': $this->freebusy[] = $event; unset($event); break; case 'vjournal': $this->journal[] = $event; unset($event); break; case 'vtimezone': if(!empty($tzdata)) { $event['tzdata'] = $tzdata; unset($tzdata); } $this->timezone[] = $event; unset($event); break; case 'vtodo': if(!empty($alarm)) { $event['alarm'] = $alarm; unset($alarm); } $this->todo[] = $event['alarm']; unset($event); break; case 'vcalendar': $this->ical = $ical; $this->ical['event'] = $this->event; $this->ical['freebusy'] = $this->freebusy; $this->ical['journal'] = $this->journal; $this->ical['timezone'] = $this->timezone; $this->ical['todo'] = $this->todo; break 2; } } elseif($majortype == 'prodid' || $majortype == 'version' || $majortype == 'method' || $majortype == 'calscale') { $this->parse_parameters($ical,$majortype,$this->from_text($value)); } elseif($state == 'optional' || $state == 'required') { $this->debug('Mode : '.$mode.' Majortype : '.$majortype); if($do_to_text) { $value = $this->from_text($value); } switch($type) { case 'text': $this->parse_parameters($event,$majortype,$value); break; case 'recur': case 'date-time': case 'cal-address': $this->parse_value($event,$majortype,$value,$mode); break; case 'integer': if($multiples) { $event[$majortype][] = (int)$value; } else { $this->set_var($event,$majortype,(int)$value); } break; case 'float': $event->$majortype = new class_geo; $this->parse_geo($event->$majortype,$value); break; case 'utc-offset': $this->set_var($event,$majortype,(int)$value); break; case 'uri': $new_var = Array(); $this->parse_parameters($new_var,$majortype,$value); if($multiples) { switch($mode) { case 'valarm': $alarm['attach'][] = $new_var; break; default: $event[$majortype][] = $new_var; break; } } else { $event[$majortype] = $new_var; } unset($new_var); break; case 'xtype': $this->parse_xtype($event,$majortype,$value); break; } } $text = $this->read_line_unfold($ical_text); } return $this->ical; } function build_ical($ical) { $var = Array( 'timezone', 'event', 'todo', 'journal', 'freebusy' ); $str = 'BEGIN:VCALENDAR'."\r\n"; $str .= $this->fold('PRODID'.$this->build_text($ical['prodid'],'prodid')); $str .= $this->fold('VERSION'.$this->build_text($ical['version'],'version')); $str .= $this->fold('METHOD'.$this->build_text($ical['method'],'method')); foreach($var as $vtype) { if($ical[$vtype]) { for($i=0;$ibuild_card_internals('v'.$vtype,$ical[$vtype][$i]); $str .= 'END:V'.strtoupper($vtype)."\r\n"; } } } $str .= 'END:VCALENDAR'."\r\n"; return $str; } function switch_to_phpgw_status($partstat) { switch($partstat) { case 0: return 'U'; break; case 1: return 'A'; break; case 2: return 'R'; break; case 3: return 'T'; break; default: return 'U'; break; } } function switch_phpgw_status($status) { switch($status) { case 'U': return 0; break; case 'A': return 1; break; case 'R': return 2; break; case 'T': return 3; break; } } function is_owner($part_record) { if(($part_record['mailto']['user'].'@'.$part_record['mailto']['host'] == $GLOBALS['phpgw_info']['user']['preferences']['email']['address']) || ($part_record['cn'] == $GLOBALS['phpgw_info']['user']['account_lid'])) { return True; } else { return False; } } function check_owner(&$event,$ical,$so_event) { if(!isset($event['participant'][$GLOBALS['phpgw_info']['user']['account_id']])) { if(isset($ical['organizer'])) { if($this->is_owner($ical['organizer'])) { $so_event->add_attribute('owner',$GLOBALS['phpgw_info']['user']['account_id']); $so_event->add_attribute('participants',$this->switch_to_phpgw_status($ical['organizer']['partstat']),$GLOBALS['phpgw_info']['user']['account_id']); } } elseif(isset($ical['attendee'])) { $attendee_count = count($ical['attendee']); for($j=0;$j<$attendee_count;$j++) { if($this->is_owner($ical['attendee'][$j])) { $so_event->add_attribute('participants',$this->switch_to_phpgw_status($ical['attendee'][$j]['partstat']),(int)$GLOBALS['phpgw_info']['user']['account_id']); } } } else { $so_event->add_attribute('owner',$GLOBALS['phpgw_info']['user']['account_id']); $so_event->add_attribute('participants','A',$GLOBALS['phpgw_info']['user']['account_id']); } } } function import_file() { if($_FILES['uploadedfile']['tmp_name'] == 'none' || $_FILES['uploadedfile']['tmp_name'] == '') { Header('Location: ' . $GLOBALS['phpgw']->link('/index.php', Array( 'menuaction' => 'calendar.uiicalendar.import', 'action' => 'GetFile' ) ) ); $GLOBALS['phpwg']->common->phpgw_exit(); } $uploaddir = $GLOBALS['phpgw_info']['server']['temp_dir'] . SEP; srand((double)microtime()*1000000); $random_number = rand(100000000,999999999); $newfilename = md5($_FILES['uploadedfile']['tmp_name'].", ".$uploadedfile_name.", " . time() . getenv("REMOTE_ADDR") . $random_number ); $filename = $uploaddir . $newfilename; move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $filename); return $filename; } function import($mime_msg='') { if($_FILES['uploadedfile']['tmp_name'] != 'none' && $_FILES['uploadedfile']['tmp_name'] != '') { $filename = $this->import_file(); $fp=fopen($filename,'rt'); $mime_msg = fread($fp, filesize($filename)); fclose($fp); unlink($filename); /* explode can fail easily, so pre-chew the ical file */ $mime_msg = preg_replace("/(\r\n|\r)/", "\n", $mime_msg); /* dos2unix */ $mime_msg = preg_replace("/\n\n+/", "\n", $mime_msg); /* strip duplicate newlines */ $mime_msg = explode("\n",$mime_msg); /* explode the sanitized message into itself */ } elseif(!$mime_msg) { Header('Location: ' . $GLOBALS['phpgw']->link('/index.php', Array( 'menuaction' => 'calendar.uiicalendar.import', 'action' => 'GetFile' ) ) ); $GLOBALS['phpwg']->common->phpgw_exit(); } if(!is_object($GLOBALS['uicalendar'])) { $so_event = createobject('calendar.socalendar', Array( 'owner' => 0, 'filter' => '', 'category' => '' ) ); } else { $so_event = $GLOBALS['uicalendar']->bo->so; } $datetime_vars = Array( 'start' => 'dtstart', 'end' => 'dtend', 'modtime' => 'dtstamp', 'modtime' => 'last_modified' ); $date_array = Array( 'Y' => 'year', 'm' => 'month', 'd' => 'mday', 'H' => 'hour', 'i' => 'min', 's' => 'sec' ); /* time limit should be controlled elsewhere */ @set_time_limit(0); $GLOBALS['phpgw_info']['user']['preferences'] = $GLOBALS['phpgw']->preferences->create_email_preferences(); $users_email = $GLOBALS['phpgw_info']['user']['preferences']['email']['address']; $cats = CreateObject('phpgwapi.categories'); $ical = $this->parse($mime_msg); switch($ical['version']['value']) { case '1.0': $cat_sep = ';'; break; case '2.0': default: $cat_sep = ','; break; } $c_events = count($ical['event']); for($i=0;$i<$c_events;$i++) { if($ical['event'][$i]['uid']['value']) { $uid_exists = $so_event->find_uid($ical['event'][$i]['uid']['value']); } else { $uid_exists = False; } if($uid_exists) { $event = $so_event->read_entry($uid_exists); $this->check_owner($event,$ical['event'][$i],$so_event); $event = $so_event->get_cached_event(); $so_event->add_entry($event); } else { $so_event->event_init(); $so_event->add_attribute('id',0); $so_event->add_attribute('reference',0); if($ical['event'][$i]['uid']['value']) { $so_event->add_attribute('uid',$ical['event'][$i]['uid']['value']); } if($ical['event'][$i]['summary']['value']) { $so_event->set_title($ical['event'][$i]['summary']['value']); } if($ical['event'][$i]['description']['value']) { $so_event->set_description($ical['event'][$i]['description']['value']); } if($ical['event'][$i]['location']['value']) { $so_event->add_attribute('location',$ical['event'][$i]['location']['value']); } if(isset($ical['event'][$i]['priority'])) { $so_event->add_attribute('priority',$ical['event'][$i]['priority']); } else { $so_event->add_attribute('priority',2); } if(!isset($ical['event'][$i]['class'])) { $ical['event'][$i]['class'] = 1; } $so_event->set_class($ical['event'][$i]['class']); @reset($datetime_vars); while(list($e_datevar,$i_datevar) = each($datetime_vars)) { if(isset($ical['event'][$i][$i_datevar])) { $temp_time = $so_event->maketime($ical['event'][$i][$i_datevar]) + $GLOBALS['phpgw']->datetime->tz_offset; @reset($date_array); while(list($key,$var) = each($date_array)) { $event[$e_datevar][$var] = (int)(date($key,$temp_time)); } $so_event->set_date($e_datevar,$event[$e_datevar]['year'],$event[$e_datevar]['month'],$event[$e_datevar]['mday'],$event[$e_datevar]['hour'],$event[$e_datevar]['min'],$event[$e_datevar]['sec']); } } if(!isset($ical['event'][$i]['categories']['value']) || !$ical['event'][$i]['categories']['value']) { $so_event->set_category(0); } else { $ical_cats = Array(); if(strpos($ical['event'][$i]['categories']['value'],$cat_sep)) { $ical_cats = explode($cat_sep,$ical['event'][$i]['categories']['value']); } else { $ical_cats[] = $ical['event'][$i]['categories']['value']; } @reset($ical_cats); $cat_id_nums = Array(); while(list($key,$cat) = each($ical_cats)) { if(!$cats->exists('appandmains',$cat)) { $cats->add( Array( 'name' => $cat, 'descr' => $cat, 'parent' => '', 'access' => 'private', 'data' => '' ) ); } $cat_id_nums[] = $cats->name2id($cat); } @reset($cat_id_nums); if(count($cat_id_nums) > 1) { $so_event->set_category(implode($cat_id_nums,',')); } else { $so_event->set_category($cat_id_nums[0]); } } /* rrule */ if(isset($ical['event'][$i]['rrule']) || isset($ical['event'][$i]['duration'])) { /* recur_enddate */ if(isset($ical['event'][$i]['rrule']['until'])) { $recur_enddate['year'] = (int)($ical['event'][$i]['rrule']['until']['year']); $recur_enddate['month'] = (int)($ical['event'][$i]['rrule']['until']['month']); $recur_enddate['mday'] = (int)($ical['event'][$i]['rrule']['until']['mday']); } elseif( isset($ical['event'][$i]['duration']) ) { /* Create timecode for strtotime */ $ptimer = mktime($ical['event'][$i]['dtstart']['hour'], $ical['event'][$i]['dtstart']['min'], $ical['event'][$i]['dtstart']['sec'], $ical['event'][$i]['dtstart']['month'], $ical['event'][$i]['dtstart']['mday'], $ical['event'][$i]['dtstart']['year']); /* * Subtract 1 second so we don't overlap with the beginning of * another event. */ /* handle events with duration in weeks */ if ($ical['event'][$i]['duration']['weeks'] && ($ical['event'][$i]['duration']['hours'] == 0) && ($ical['event'][$i]['duration']['minutes'] == 0)) { $ical['event'][$i]['duration']['days'] = ($ical['event'][$i]['duration']['days'] + ($ical['event'][$i]['duration']['weeks']*7)) - 1; unset($ical['event'][$i]['duration']['weeks']); $ical['event'][$i]['duration']['hours'] = "23"; $ical['event'][$i]['duration']['minutes'] = "59"; $ical['event'][$i]['duration']['seconds'] = "59"; } /* handle events with duration in days */ if(($ical['event'][$i]['duration']['days'] && $ical['event'][$i]['duration']['hours'] == 0) && ($ical['event'][$i]['duration']['minutes'] == 0)) { $ical['event'][$i]['duration']['days']--; $ical['event'][$i]['duration']['hours'] = "23"; $ical['event'][$i]['duration']['minutes'] = "59"; $ical['event'][$i]['duration']['seconds'] = "59"; } /* Create string contains datetime for strtotime */ $pdate = "+"; if(isset($ical['event'][$i]['duration']['weeks'])) $pdate .= $ical['event'][$i]['duration']['weeks'] . " weeks "; if(isset($ical['event'][$i]['duration']['days'])) $pdate .= $ical['event'][$i]['duration']['days'] . " days "; if(isset($ical['event'][$i]['duration']['hours'])) $pdate .= $ical['event'][$i]['duration']['hours'] . " hours "; if(isset($ical['event'][$i]['duration']['minutes'])) $pdate .= $ical['event'][$i]['duration']['minutes'] . " minutes "; if(isset($ical['event'][$i]['duration']['seconds'])) $pdate .= $ical['event'][$i]['duration']['seconds'] . " seconds "; /* What is datetime in 2192? */ $enddate = strtotime($pdate, $ptimer); list( $recur_enddate['year'], $recur_enddate['month'], $recur_enddate['mday'], $recur_enddate['hour'], $recur_enddate['min'], $recur_enddate['sec'] ) = split(":", date("Y:m:d:H:i:s", $enddate)); /* Set End of event */ $so_event->set_end( $recur_enddate['year'], $recur_enddate['month'], $recur_enddate['mday'], $recur_enddate['hour'], $recur_enddate['min'], $recur_enddate['sec'] ); } else { $recur_enddate['year'] = 0; $recur_enddate['month'] = 0; $recur_enddate['mday'] = 0; } /* recur_data */ $recur_data = 0; if(isset($ical['event'][$i]['rrule']['byday'])) { $week_days = Array( MCAL_M_SUNDAY => 'SU', MCAL_M_MONDAY => 'MO', MCAL_M_TUESDAY => 'TU', MCAL_M_WEDNESDAY => 'WE', MCAL_M_THURSDAY => 'TH', MCAL_M_FRIDAY => 'FR', MCAL_M_SATURDAY => 'SA' ); @reset($week_days); while(list($key,$val) = each($week_days)) { if(strpos(' '.$ical['event'][$i]['rrule']['byday'],$val)) { $recur_data += $key; } } } /* interval */ if(!isset($ical['event'][$i]['rrule']['interval'])) { $interval = 1; } else { $interval = (int)$ical['event'][$i]['rrule']['interval']; } // recur_type switch($ical['event'][$i]['rrule']['freq']) { case DAILY: $recur_type = MCAL_RECUR_DAILY; break; case WEEKLY: $so_event->set_recur_weekly($recur_enddate['year'],$recur_enddate['month'],$recur_enddate['mday'],$interval,$recur_data); break; case MONTHLY: // Still need to determine if this is by day or by week for the month.. // $recur_type = MCAL_RECUR_M??????; break; case YEARLY: $so_event->set_recur_yearly($recur_enddate['year'],$recur_enddate['month'],$recur_enddate['mday'],$interval); break; } } else { $so_event->set_recur_none(); } /* the organizer must be the current user doing the importing */ if(!isset($ical['event'][$i]['organizer']) || !$this->is_owner($ical['event'][$i]['organizer'])) { $so_event->add_attribute('owner',$GLOBALS['phpgw_info']['user']['account_id']); $so_event->add_attribute('participants','A',$GLOBALS['phpgw_info']['user']['account_id']); } /* if the original organizer is an egroupware user, add the original user as an event participant */ /* NB: ['mailto'] has two parts, ['user'], containing the username, and ['host'], containing the domain of the user's email address */ if (isset($ical['event'][$i]['organizer']['mailto']['user']) && $GLOBALS['phpgw']->accounts->exists($ical['event'][$i]['organizer']['mailto']['user']) == True) { $so_event->add_attribute('participants','A',(int)$GLOBALS['phpgw']->accounts->name2id($ical['event'][$i]['organizer']['mailto']['user'])); } $event = $so_event->get_cached_event(); $so_event->add_entry($event); } } Header('Location: '.$GLOBALS['phpgw']->link('/index.php', Array( 'menuaction' => 'calendar.uicalendar.view', 'cal_id' => $event['id'] ) ) ); $GLOBALS['phpgw']->common->phpgw_exit(); } function export($params) { $event_id = $params['l_event_id'] ? $params['l_event_id'] : $_GET['cal_id']; $this->chunk_split = $params['chunk_split']; $method = $params['method'] ? $params['method'] : 'publish'; $vtype = $params['vtype'] ? $params['vtype'] : 'event'; $string_array = Array( 'summary' => 'description', 'location' => 'location', 'description' => 'title', 'uid' => 'uid' ); $cats = CreateObject('phpgwapi.categories'); include(PHPGW_SERVER_ROOT.'/calendar/setup/setup.inc.php'); if(!is_array($event_id)) { $ids[] = $event_id; } else { $ids = $event_id; } $ical = $this->new_ical(); $this->set_var($ical['prodid'],'value','-//eGroupWare//eGroupWare '.$setup_info['calendar']['version'].' MIMEDIR//'.strtoupper($GLOBALS['phpgw_info']['user']['preferences']['common']['lang'])); $this->set_var($ical['version'],'value','1.0'); $this->set_var($ical['method'],'value',strtoupper($method)); if(!$GLOBALS['phpgw_info']['flags']['included_classes']['uicalendar']) { if(!$GLOBALS['phpgw_info']['flags']['included_classes']['bocalendar']) { $so_event = createobject('calendar.socalendar', Array( 'owner' => 0, 'filter' => '', 'category' => '' ) ); } else { $so_event = $GLOBALS['bocalendar']->so; } } else { $so_event = $GLOBALS['uicalendar']->bo->so; } foreach($ids as $event) { $ical_event = Array(); if (!is_array($event)) { $event = $so_event->read_entry($event); } if($event['alarm']) { foreach($event['alarm'] as $alarm) { $ical_temp = Array(); $ical_temp['action']['value'] = 'DISPLAY'; $ical_temp['description']['value'] = $alarm['text']; $this->set_var($ical_temp['trigger'],'value','VALUE=DATE-TIME:'.date('Ymd\THis\Z',$alarm['time']),'valarm'); $ical_event['alarm'][] = $ical_temp; } } // $event has times in user's time zone, so have to adjust them to GMT, which is used by ical // To do that one must substract the users time zone difference with the server and then substract the server's time zone difference with GMT $gmt_offset = date('O'); // server's offset to GMT $offset = ((int)(substr($gmt_offset, 0, 3)) + $GLOBALS['phpgw_info']['user']['preferences']['common']['tz_offset']) * 60 + (int)(substr($gmt_offset, 3, 2)); $event['start']['min'] -= $offset; $event['end']['min'] -= $offset; $event['modtime']['min'] -= $offset; $ical_event['priority'] = $event['priority']; $ical_event['class'] = (int)$event['public']; $dtstart_mktime = $so_event->maketime($event['start']); $this->parse_value($ical_event,'dtstart',date('Ymd\THis\Z',$dtstart_mktime),'vevent'); $dtend_mktime = $so_event->maketime($event['end']); $this->parse_value($ical_event,'dtend',date('Ymd\THis\Z',$dtend_mktime),'vevent'); $mod_mktime = $so_event->maketime($event['modtime']); $this->parse_value($ical_event,'last_modified',date('Ymd\THis\Z',$mod_mktime),'vevent'); foreach($string_array as $ical_value => $event_value) { if($event[$event_value]) { $this->set_var($ical_event[$ical_value],'value',$event[$event_value]); } } if ($event['category']) { $cats->categories(0,'calendar'); foreach(explode(',',$event['category']) as $cat) { $_cat = $cats->return_single($cat); $cat_string[] = $_cat[0]['name']; } @reset($cat_string); $this->set_var($ical_event['categories'],'value',implode($cat_string,',')); } if(count($event['participants']) > 1) { if(!is_object($db)) { $db = $GLOBALS['phpgw']->db; } foreach($event['participants'] as $part => $status) { $GLOBALS['phpgw']->accounts->get_account_name($part,$lid,$fname,$lname); $name = $fname.' '.$lname; $owner_status = $this->switch_partstat((int)$this->switch_phpgw_status($event['participants'][$part])); $mail_prefs = $GLOBALS['phpgw']->preferences->create_email_preferences($part); $mailto = $mail_prefs['email']['address']; $str = 'CN="'.$name.'";PARTSTAT='.$owner_status.':'.$mailto; if($part == $event['owner']) { $str = 'ROLE=CHAIR;'.$str; } else { $str = 'ROLE=REQ-PARTICIPANT;'.$str; } if ($method != 'reply' || $part == $GLOBALS['phpgw_info']['user']['account_id']) { $this->parse_value($ical_event,'attendee',$str,'vevent'); } if($part == $event['owner']) { $this->parse_value($ical_event,'organizer',$str,'vevent'); } } } if($event['recur_type']) { $str = ''; switch($event['recur_type']) { case MCAL_RECUR_DAILY: $str .= 'FREQ=DAILY'; break; case MCAL_RECUR_WEEKLY: $str .= 'FREQ=WEEKLY'; if($event['recur_data']) { $str .= ';BYDAY='; for($i=1;$imaketime($event['recur_enddate']) - $GLOBALS['phpgw']->datetime->tz_offset; $str .= ';UNTIL='.date('Ymd\THis\Z',$recur_mktime); } $this->parse_value($ical_event,'rrule',$str,'vevent'); $exceptions = $event['recur_exception']; if(is_array($exceptions)) { foreach($exceptions as $except_datetime) { $ical_event['exdate'][] = $this->switch_date(date('Ymd\THis\Z',$except_datetime)); } } } $ical_events[] = $ical_event; } $ical[$vtype] = $ical_events; // iCals are by default utf-8 return $GLOBALS['phpgw']->translation->convert($this->build_ical($ical),$GLOBALS['phpgw']->translation->charset(),'utf-8'); } function freebusy($params=False) { if (!$params) $params = $_GET; $user = is_numeric($params['user']) ? (int) $params['user'] : $GLOBALS['phpgw']->accounts->name2id($params['user']); $start = isset($params['start']) ? $params['start'] : date('Ymd'); $end = isset($params['end']) ? $params['end'] : (date('Y')+1).date('md'); $this->bo = CreateObject('calendar.bocalendar'); $events_per_day = $this->bo->store_to_cache(array( 'owner' => $user, 'syear' => (int) substr($start,0,4), 'smonth' => (int) substr($start,4,2), 'sday' => (int) substr($start,6,2), 'eyear' => (int) substr($end,0,4), 'emonth' => (int) substr($end,4,2), 'eday' => (int) substr($end,6,2), 'no_doubles' => True, // report events only on the startday )); if (!is_array($events_per_day)) $events_per_day = array(); $ids = array(); foreach($events_per_day as $day => $events) { foreach($events as $event) { $ids[] = $event; } } $browser = CreateObject('phpgwapi.browser'); $browser->content_header($GLOBALS['phpgw']->accounts->id2name($user).'.ifb','text/calendar'); echo $this->export(array( 'vtype' => 'freebusy', 'l_event_id' => $ids, )); } function debug($str='') { if($this->debug_str) { echo $str."
\n"; } } } ?>