2001-03-17 20:39:56 +01:00
|
|
|
<?php
|
|
|
|
/**************************************************************************\
|
2001-06-10 19:05:51 +02:00
|
|
|
* phpGroupWare - vCalendar Parser *
|
2001-03-17 20:39:56 +01:00
|
|
|
* http://www.phpgroupware.org *
|
2001-06-10 19:05:51 +02:00
|
|
|
* Written by Mark Peters <skeeter@phpgroupware.org> *
|
2001-03-17 20:39:56 +01:00
|
|
|
* -------------------------------------------- *
|
|
|
|
* 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$ */
|
|
|
|
|
2001-07-02 05:31:13 +02:00
|
|
|
define('FOLD_LENGTH',75);
|
2001-06-25 00:13:17 +02:00
|
|
|
|
2001-06-10 19:05:51 +02:00
|
|
|
define('VEVENT',1);
|
|
|
|
define('VTODO',2);
|
|
|
|
|
2001-05-06 02:11:12 +02:00
|
|
|
define('NONE',0);
|
2001-06-07 05:18:35 +02:00
|
|
|
define('CHAIR',1);
|
2001-06-10 06:02:50 +02:00
|
|
|
define('REQ_PARTICIPANT',2);
|
|
|
|
define('OPT_PARTICIPANT',3);
|
|
|
|
define('NON_PARTICIPANT',4);
|
2001-06-07 05:18:35 +02:00
|
|
|
|
|
|
|
define('INDIVIDUAL',1);
|
|
|
|
define('GROUP',2);
|
|
|
|
define('RESOURCE',4);
|
|
|
|
define('ROOM',8);
|
|
|
|
define('UNKNOWN',16);
|
2001-05-06 02:11:12 +02:00
|
|
|
|
2001-06-10 19:05:51 +02:00
|
|
|
define('NEEDS_ACTION',0);
|
|
|
|
define('ACCEPTED',1);
|
|
|
|
define('DECLINED',2);
|
|
|
|
define('TENTATIVE',3);
|
|
|
|
define('DELEGATED',4);
|
|
|
|
define('COMPLETED',5);
|
|
|
|
define('IN_PROCESS',6);
|
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
define('PRIVATE',0);
|
|
|
|
define('PUBLIC',1);
|
2001-06-10 19:05:51 +02:00
|
|
|
define('CONFIDENTIAL',3);
|
|
|
|
|
|
|
|
define('TRANSPARENT',0);
|
|
|
|
define('OPAQUE',1);
|
|
|
|
|
2001-07-02 05:31:13 +02:00
|
|
|
define('_8BIT',0);
|
|
|
|
define('_BASE64',1);
|
|
|
|
|
2001-06-10 19:05:51 +02:00
|
|
|
define('OTHER',99);
|
2001-06-10 06:02:50 +02:00
|
|
|
|
2001-03-17 20:39:56 +01:00
|
|
|
class mailto
|
|
|
|
{
|
|
|
|
var $user;
|
|
|
|
var $host;
|
|
|
|
}
|
|
|
|
|
|
|
|
class attendee
|
|
|
|
{
|
|
|
|
var $cn = 'Unknown';
|
2001-07-02 05:31:13 +02:00
|
|
|
var $dir;
|
2001-06-10 06:02:50 +02:00
|
|
|
var $cutype = INDIVIDUAL;
|
|
|
|
var $role = REQ_PARTICIPANT;
|
2001-06-10 19:05:51 +02:00
|
|
|
var $rsvp = 0;
|
2001-03-17 20:39:56 +01:00
|
|
|
var $mailto;
|
|
|
|
var $sent_by;
|
2001-06-07 05:18:35 +02:00
|
|
|
var $delegated_from;
|
|
|
|
var $delegated_to;
|
|
|
|
var $member;
|
2001-06-10 19:05:51 +02:00
|
|
|
var $partstat = NEEDS_ACTION;
|
2001-03-17 20:39:56 +01:00
|
|
|
}
|
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
class vCalendar_time
|
|
|
|
{
|
2001-03-17 20:39:56 +01:00
|
|
|
var $year;
|
|
|
|
var $month;
|
|
|
|
var $mday;
|
|
|
|
var $hour;
|
|
|
|
var $min;
|
|
|
|
var $sec;
|
|
|
|
var $date;
|
|
|
|
var $allday = False;
|
|
|
|
}
|
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
class rrule
|
|
|
|
{
|
|
|
|
var $freq;
|
|
|
|
var $enddate;
|
|
|
|
var $interval;
|
|
|
|
var $count;
|
|
|
|
var $wkst;
|
|
|
|
var $byday;
|
|
|
|
}
|
|
|
|
|
2001-07-02 05:31:13 +02:00
|
|
|
class class_text
|
|
|
|
{
|
|
|
|
var $cid;
|
|
|
|
var $fmttype;
|
|
|
|
var $encoding;
|
|
|
|
var $altrep;
|
|
|
|
var $value;
|
|
|
|
}
|
|
|
|
|
2001-06-25 00:13:17 +02:00
|
|
|
class vCalendar_item
|
2001-03-17 20:39:56 +01:00
|
|
|
{
|
|
|
|
var $type;
|
|
|
|
var $attendee = Array();
|
|
|
|
var $organizer;
|
|
|
|
var $dtstart;
|
|
|
|
var $dtend;
|
|
|
|
var $location;
|
2001-06-10 19:05:51 +02:00
|
|
|
var $transp = OPAQUE;
|
2001-03-17 20:39:56 +01:00
|
|
|
var $sequence;
|
2001-07-02 05:31:13 +02:00
|
|
|
var $attach;
|
2001-03-17 20:39:56 +01:00
|
|
|
var $uid;
|
|
|
|
var $dtstamp;
|
|
|
|
var $description;
|
|
|
|
var $summary;
|
|
|
|
var $priority;
|
2001-06-10 06:02:50 +02:00
|
|
|
var $class = PUBLIC;
|
|
|
|
var $rrule;
|
2001-05-06 02:11:12 +02:00
|
|
|
}
|
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
class vCal
|
|
|
|
{
|
|
|
|
var $prodid;
|
|
|
|
var $version;
|
|
|
|
var $method;
|
|
|
|
var $event = Array();
|
|
|
|
}
|
|
|
|
|
2001-05-06 02:11:12 +02:00
|
|
|
class vCalendar
|
|
|
|
{
|
2001-06-10 06:02:50 +02:00
|
|
|
var $vcal;
|
2001-06-25 00:13:17 +02:00
|
|
|
var $event = Array();
|
|
|
|
var $todo = Array();
|
2001-05-06 02:11:12 +02:00
|
|
|
|
|
|
|
function splitdate($value)
|
|
|
|
{
|
|
|
|
$dtime = new vCalendar_time;
|
2001-06-10 06:02:50 +02:00
|
|
|
if(strpos($value,':'))
|
|
|
|
{
|
|
|
|
$pos = explode(':',$value);
|
|
|
|
$value = $pos[1];
|
|
|
|
}
|
2001-05-06 02:11:12 +02:00
|
|
|
$dtime->year = intval(substr($value,0,4));
|
2001-06-10 06:02:50 +02:00
|
|
|
$dtime->month = intval(substr($value,4,2));
|
|
|
|
$dtime->mday = intval(substr($value,6,2));
|
2001-06-10 19:05:51 +02:00
|
|
|
if(substr($value,8,1) == 'T')
|
|
|
|
{
|
|
|
|
$dtime->hour = intval(substr($value,9,2));
|
|
|
|
$dtime->min = intval(substr($value,11,2));
|
|
|
|
$dtime->sec = intval(substr($value,13,2));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$dtime->hour = 0;
|
|
|
|
$dtime->min = 0;
|
|
|
|
$dtime->sec = 0;
|
|
|
|
}
|
2001-05-06 02:11:12 +02:00
|
|
|
return $dtime;
|
|
|
|
}
|
2001-03-17 20:39:56 +01:00
|
|
|
|
2001-06-07 05:18:35 +02:00
|
|
|
function split_address($address)
|
|
|
|
{
|
2001-06-25 00:13:17 +02:00
|
|
|
if(strpos(' '.$address,':'))
|
|
|
|
{
|
|
|
|
$parts = explode(':',$address);
|
|
|
|
$address = $parts[1];
|
|
|
|
}
|
|
|
|
|
2001-06-07 05:18:35 +02:00
|
|
|
$parts = explode('@',$address);
|
|
|
|
if(count($parts) == 2)
|
|
|
|
{
|
|
|
|
$temp_address = new mailto;
|
|
|
|
$temp_address->user = $parts[0];
|
|
|
|
$temp_address->host = $parts[1];
|
|
|
|
return $temp_address;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
function set_var(&$event,$type,$value)
|
2001-06-07 05:18:35 +02:00
|
|
|
{
|
2001-06-10 06:02:50 +02:00
|
|
|
// if($value != False)
|
|
|
|
// {
|
2001-06-10 19:05:51 +02:00
|
|
|
$type = strtolower(str_replace('-','_',$type));
|
2001-06-10 06:02:50 +02:00
|
|
|
$event->$type = $value;
|
|
|
|
// }
|
2001-06-07 05:18:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function unfold(&$vcal_text,$current_line)
|
|
|
|
{
|
|
|
|
$next_line = $current_line;
|
|
|
|
|
|
|
|
while(ereg("^[ \t]",substr($vcal_text[$next_line + 1],0,1)))
|
|
|
|
{
|
|
|
|
$vcal_text[$current_line] = str_replace("\r\n",'',$vcal_text[$current_line]);
|
|
|
|
$vcal_text[$current_line] .= substr($vcal_text[$next_line + 1],1);
|
2001-06-10 06:02:50 +02:00
|
|
|
$i = $next_line + 1;
|
|
|
|
while($i + 1 <= count($vcal_text))
|
2001-06-07 05:18:35 +02:00
|
|
|
{
|
2001-06-10 06:02:50 +02:00
|
|
|
$vcal_text[$i] = $vcal_text[$i + 1];
|
|
|
|
$i++;
|
2001-06-07 05:18:35 +02:00
|
|
|
}
|
2001-06-10 06:02:50 +02:00
|
|
|
$next_line++;
|
2001-06-07 05:18:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-25 00:13:17 +02:00
|
|
|
function fold($str)
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
return chunk_split($str,FOLD_LENGTH,"\r\n");
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
|
2001-06-07 05:18:35 +02:00
|
|
|
function strip_quotes($str)
|
2001-03-17 20:39:56 +01:00
|
|
|
{
|
2001-06-10 19:05:51 +02:00
|
|
|
return str_replace('"','',$str);
|
2001-06-07 05:18:35 +02:00
|
|
|
}
|
2001-05-06 02:11:12 +02:00
|
|
|
|
2001-06-07 05:18:35 +02:00
|
|
|
function strip_param($str)
|
|
|
|
{
|
|
|
|
$extra_param = explode(':',$str);
|
|
|
|
if(count($extra_param) == 1)
|
2001-03-17 20:39:56 +01:00
|
|
|
{
|
2001-06-07 05:18:35 +02:00
|
|
|
return $str;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return $extra_param[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-07-02 05:31:13 +02:00
|
|
|
function split_param(&$return_value,$str,$check_equal)
|
|
|
|
{
|
|
|
|
if($check_equal)
|
|
|
|
{
|
|
|
|
$str_len = strlen($str);
|
|
|
|
$i = 0;
|
|
|
|
$found = False;
|
|
|
|
while($i < $str_len)
|
|
|
|
{
|
|
|
|
$char = substr($str,$i,1);
|
|
|
|
if(ereg("^[\=\:]",$char))
|
|
|
|
{
|
|
|
|
$found = True;
|
2001-07-03 05:32:09 +02:00
|
|
|
$ret_str = str_replace('=3D','=',str_replace('%20',' ',substr($str,0,$i)));
|
2001-07-02 05:31:13 +02:00
|
|
|
$return_value[] = $ret_str;
|
|
|
|
$ret_array = $this->explode_param(substr($str,$i + 1),'"',False);
|
|
|
|
while(list($key,$value) = each($ret_array))
|
|
|
|
{
|
2001-07-03 05:32:09 +02:00
|
|
|
$return_value[] = str_replace('=3D','=',str_replace('%20',' ',$value));
|
2001-07-02 05:31:13 +02:00
|
|
|
}
|
|
|
|
$i = $str_len;
|
|
|
|
}
|
|
|
|
$i++;
|
|
|
|
}
|
|
|
|
if(!$found)
|
|
|
|
{
|
2001-07-03 05:32:09 +02:00
|
|
|
$return_value[] = str_replace('=3D','=',str_replace('%20',' ',$str));
|
2001-07-02 05:31:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$return_value[] = rawurldecode($str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function explode_param($str,$enclosure,$check_equal)
|
|
|
|
{
|
|
|
|
$enclosure_found = 0;
|
|
|
|
$start = 0;
|
|
|
|
$return_value = Array();
|
|
|
|
$str_len = strlen($str);
|
|
|
|
for($i=0;$i<$str_len;$i++)
|
|
|
|
{
|
|
|
|
$char = substr($str,$i,1);
|
|
|
|
if($char == $enclosure)
|
|
|
|
{
|
|
|
|
$enclosure_found = (~ $enclosure_found);
|
|
|
|
}
|
|
|
|
elseif(ereg("^[\;\:]",$char))
|
|
|
|
{
|
|
|
|
if(! $enclosure_found)
|
|
|
|
{
|
|
|
|
$this->split_param($return_value,substr($str,$start,($i - $start)),$check_equal);
|
|
|
|
$start = $i + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(! $enclosure_found)
|
|
|
|
{
|
|
|
|
$this->split_param($return_value,substr($str,$start,($i - $start)),$check_equal);
|
|
|
|
}
|
|
|
|
return $return_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
function parse_text(&$event,$value)
|
|
|
|
{
|
|
|
|
$return_value = $this->explode_param($value,'"',True);
|
|
|
|
if(count($return_value) > 0)
|
|
|
|
{
|
|
|
|
for($i=0;$i<count($return_value);$i=$i + 2)
|
|
|
|
{
|
|
|
|
$type[0] = $return_value[$i];
|
|
|
|
$type[1] = $this->strip_quotes($return_value[$i+1]);
|
|
|
|
switch(strtolower($type[0]))
|
|
|
|
{
|
|
|
|
case 'altrep':
|
|
|
|
case 'fmttype':
|
|
|
|
case 'cid':
|
|
|
|
$this->set_var($event,strtolower($type[0]),$type[1]);
|
|
|
|
break;
|
|
|
|
case 'encoding':
|
|
|
|
$this->set_var($event,strtolower($type[0]),$this->switch_encoding($type[1]));
|
|
|
|
break;
|
|
|
|
case 'value':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$this->set_var($event,'value',$type[0]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif($value <> '\n')
|
|
|
|
{
|
|
|
|
$this->set_var($event,'value',$value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function switch_encoding($var)
|
|
|
|
{
|
|
|
|
if(gettype($var) == 'string')
|
|
|
|
{
|
|
|
|
switch($var)
|
|
|
|
{
|
|
|
|
case '8BIT':
|
|
|
|
return _8BIT;
|
|
|
|
break;
|
|
|
|
case 'BASE64':
|
|
|
|
return _BASE64;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return OTHER;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif(gettype($var) == 'integer')
|
|
|
|
{
|
|
|
|
switch($var)
|
|
|
|
{
|
|
|
|
case _8BIT:
|
|
|
|
return '8BIT';
|
|
|
|
break;
|
|
|
|
case _BASE64:
|
|
|
|
return 'BASE64';
|
|
|
|
break;
|
|
|
|
case OTHER:
|
|
|
|
return 'OTHER';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return $var;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-10 19:05:51 +02:00
|
|
|
function switch_role($var)
|
2001-06-07 05:18:35 +02:00
|
|
|
{
|
2001-06-10 19:05:51 +02:00
|
|
|
if(gettype($var) == 'string')
|
2001-06-07 05:18:35 +02:00
|
|
|
{
|
2001-06-10 19:05:51 +02:00
|
|
|
switch($var)
|
2001-06-07 05:18:35 +02:00
|
|
|
{
|
2001-06-10 19:05:51 +02:00
|
|
|
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(gettype($var) == 'integer')
|
|
|
|
{
|
|
|
|
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_partstat($var)
|
|
|
|
{
|
|
|
|
if(gettype($var) == 'string')
|
|
|
|
{
|
|
|
|
switch($var)
|
|
|
|
{
|
|
|
|
case 'NEEDS-ACTION':
|
|
|
|
return NEEDS_ACTION;
|
|
|
|
break;
|
|
|
|
case 'ACCEPTED':
|
|
|
|
return ACCEPTED;
|
|
|
|
break;
|
|
|
|
case 'DECLINED':
|
|
|
|
return DECLINED;
|
|
|
|
break;
|
|
|
|
case 'TENTATIVE':
|
|
|
|
return TENTATIVE;
|
|
|
|
break;
|
|
|
|
case 'DELEGATED':
|
|
|
|
return DELEGATED;
|
|
|
|
break;
|
|
|
|
case 'COMPLETED':
|
|
|
|
return COMPLETED;
|
|
|
|
break;
|
|
|
|
case 'IN-PROCESS':
|
|
|
|
return IN_PROCESS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return OTHER;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif(gettype($var) == 'integer')
|
|
|
|
{
|
|
|
|
switch($var)
|
|
|
|
{
|
|
|
|
case NEEDS_ACTION:
|
|
|
|
return 'NEEDS-ACTION';
|
|
|
|
break;
|
|
|
|
case ACCEPTED:
|
|
|
|
return 'ACCEPTED';
|
|
|
|
break;
|
|
|
|
case DECLINED:
|
|
|
|
return 'DECLINED';
|
|
|
|
break;
|
|
|
|
case TENTATIVE:
|
|
|
|
return 'TENTATIVE';
|
|
|
|
break;
|
|
|
|
case DELEGATED:
|
|
|
|
return 'DELEGATED';
|
|
|
|
break;
|
|
|
|
case COMPLETED:
|
|
|
|
return 'COMPLETED';
|
|
|
|
break;
|
|
|
|
case IN_PROCESS:
|
|
|
|
return 'IN-PROCESS';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 'X-OTHER';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return $var;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function switch_rsvp($var)
|
|
|
|
{
|
|
|
|
if(gettype($var) == 'string')
|
|
|
|
{
|
|
|
|
if($var == 'TRUE')
|
|
|
|
{
|
|
|
|
return 1;
|
2001-06-07 05:18:35 +02:00
|
|
|
}
|
2001-06-10 06:02:50 +02:00
|
|
|
else
|
|
|
|
{
|
2001-06-10 19:05:51 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2001-06-25 00:13:17 +02:00
|
|
|
elseif(gettype($var) == 'integer')
|
2001-06-10 19:05:51 +02:00
|
|
|
{
|
|
|
|
if($var == 1)
|
|
|
|
{
|
|
|
|
return 'TRUE';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 'FALSE';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return $var;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-25 00:13:17 +02:00
|
|
|
function switch_class($var)
|
|
|
|
{
|
|
|
|
if(gettype($var) == 'string')
|
|
|
|
{
|
|
|
|
switch($var)
|
|
|
|
{
|
|
|
|
case 'PRIVATE':
|
|
|
|
return PRIVATE;
|
|
|
|
break;
|
|
|
|
case 'PUBLIC':
|
|
|
|
return PUBLIC;
|
|
|
|
break;
|
|
|
|
case 'CONFIDENTIAL':
|
|
|
|
return CONFIDENTIAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif(gettype($var) == 'integer')
|
|
|
|
{
|
|
|
|
switch($var)
|
|
|
|
{
|
|
|
|
case PRIVATE:
|
|
|
|
return 'PRIVATE';
|
|
|
|
break;
|
|
|
|
case PUBLIC:
|
|
|
|
return 'PUBLIC';
|
|
|
|
break;
|
|
|
|
case CONFIDENTIAL:
|
|
|
|
return 'CONFIDENTIAL';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return $var;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function switch_transp($var)
|
|
|
|
{
|
|
|
|
if(gettype($var) == 'string')
|
|
|
|
{
|
|
|
|
switch($var)
|
|
|
|
{
|
|
|
|
case 'TRANSPARENT':
|
|
|
|
return TRANSPARENT;
|
|
|
|
break;
|
|
|
|
case 'OPAQUE':
|
|
|
|
return OPAQUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif(gettype($var) == 'integer')
|
|
|
|
{
|
|
|
|
switch($var)
|
|
|
|
{
|
|
|
|
case TRANSPARENT:
|
|
|
|
return 'TRANSPARENT';
|
|
|
|
break;
|
|
|
|
case OPAQUE:
|
|
|
|
return 'OPAQUE';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return $var;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-10 19:05:51 +02:00
|
|
|
function parse_attendee(&$event,$value)
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$param = $this->explode_param($value,'"',True);
|
2001-06-25 00:13:17 +02:00
|
|
|
|
2001-07-02 05:31:13 +02:00
|
|
|
for($j=0;$j<count($param);$j += 2)
|
2001-06-10 19:05:51 +02:00
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$type[0] = strtolower($param[$j]);
|
|
|
|
$type[1] = $this->strip_quotes($param[$j+1]);
|
|
|
|
switch($type[0])
|
2001-06-10 19:05:51 +02:00
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
case 'role':
|
|
|
|
$val = $this->switch_role($type[1]);
|
|
|
|
break;
|
|
|
|
case 'partstat':
|
|
|
|
$val = $this->switch_partstat($type[1]);
|
|
|
|
break;
|
|
|
|
case 'rsvp':
|
|
|
|
$val = $this->switch_rsvp($type[1]);
|
|
|
|
break;
|
|
|
|
case 'delegated-from':
|
|
|
|
case 'delegated-to':
|
|
|
|
case 'mailto':
|
|
|
|
$type[0] = str_replace('-','_',$type[0]);
|
|
|
|
$val = $this->split_address($type[1]);
|
|
|
|
break;
|
2001-07-03 05:32:09 +02:00
|
|
|
case 'dir':
|
|
|
|
$val = $type[1];
|
|
|
|
break;
|
2001-07-02 05:31:13 +02:00
|
|
|
default:
|
|
|
|
$val = $type[1];
|
|
|
|
break;
|
2001-06-10 06:02:50 +02:00
|
|
|
}
|
2001-07-02 05:31:13 +02:00
|
|
|
$this->set_var($event,$type[0],$val);
|
2001-06-10 06:02:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function parse_recurrence(&$event,$value)
|
|
|
|
{
|
|
|
|
$param = explode(';',$value);
|
|
|
|
for($j=0;$j<count($param);$j++)
|
|
|
|
{
|
|
|
|
if(strpos($param[$j],'='))
|
|
|
|
{
|
|
|
|
$type = explode('=',$param[$j]);
|
|
|
|
$type[0] = strtolower($type[0]);
|
|
|
|
$type[1] = $this->strip_quotes($type[1]);
|
|
|
|
$this->set_var($event,$type[0],$type[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-07-03 05:32:09 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2001-06-25 00:13:17 +02:00
|
|
|
function new_vcal()
|
|
|
|
{
|
|
|
|
return new vCal;
|
|
|
|
}
|
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
function read($vcal_text)
|
|
|
|
{
|
|
|
|
$i = 0;
|
|
|
|
while(chop($vcal_text[$i]) != '')
|
|
|
|
{
|
|
|
|
// if(strlen($vcal_text[$i]) > 75)
|
|
|
|
// {
|
|
|
|
// continue;
|
|
|
|
// }
|
2001-06-07 05:18:35 +02:00
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
$this->unfold($vcal_text,$i);
|
2001-06-07 05:18:35 +02:00
|
|
|
|
2001-07-02 05:31:13 +02:00
|
|
|
$vcal_text[$i] = str_replace("\r\n",'',$vcal_text[$i]);
|
|
|
|
|
2001-06-07 05:18:35 +02:00
|
|
|
// Example #1
|
|
|
|
//vcal_text[$i] = 'BEGIN:VCALENDAR'
|
|
|
|
|
|
|
|
// Example #2
|
|
|
|
//vcal_text[$i] = 'METHOD:REQUEST'
|
|
|
|
|
|
|
|
// Example #3
|
|
|
|
//vcal_text[$i] = 'ATTENDEE;CN="John Doe";ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:john.doe@somewhere.com'
|
|
|
|
|
|
|
|
// Example #4
|
2001-07-02 05:31:13 +02:00
|
|
|
//vcal_text[$i] = 'ORGANIZER;DIR="ldap://host.com:6666/o=eDABC%20Industries,c=3DUS??(cn=3DBJim%20Dolittle)":MAILTO:John.Doe@somewhere.com'
|
2001-06-07 05:18:35 +02:00
|
|
|
|
|
|
|
// Example #5
|
|
|
|
//vcal_text[$i] = 'DTSTART:20010302T150000Z'
|
|
|
|
|
|
|
|
// Example #6
|
|
|
|
//vcal_text[$i] = 'UID:040000008200E00074C5B7101A82E0080000000040A12C0042A2C0010000000000000000100'
|
|
|
|
//vcal_text[$i+1] = ' 000009BDFF7C7650ED5118DD700805FA71291'
|
|
|
|
|
|
|
|
// When unfolded becomes,
|
|
|
|
//vcal_text[$i] = 'UID:040000008200E00074C5B7101A82E0080000000040A12C0042A2C0010000000000000000100000009BDFF7C7650ED5118DD700805FA71291'
|
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
$colon = strpos($vcal_text[$i],':');
|
2001-06-07 05:18:35 +02:00
|
|
|
if($colon == 0)
|
|
|
|
{
|
|
|
|
$colon = 65535;
|
|
|
|
}
|
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
$semi_colon = strpos($vcal_text[$i],';');
|
2001-06-07 05:18:35 +02:00
|
|
|
if($semi_colon == 0)
|
|
|
|
{
|
|
|
|
$semi_colon = 65535;
|
|
|
|
}
|
|
|
|
|
|
|
|
if($colon == 65535 && $semi_colon == 65535)
|
2001-03-17 20:39:56 +01:00
|
|
|
{
|
2001-05-06 02:11:12 +02:00
|
|
|
continue;
|
|
|
|
}
|
2001-06-07 05:18:35 +02:00
|
|
|
else
|
2001-05-06 02:11:12 +02:00
|
|
|
{
|
2001-06-07 05:18:35 +02:00
|
|
|
$min_value = min($colon,$semi_colon);
|
2001-06-10 06:02:50 +02:00
|
|
|
$majortype = strtolower(substr($vcal_text[$i],0,$min_value));
|
|
|
|
$vcal_text[$i] = chop(substr($vcal_text[$i],$min_value + 1));
|
2001-06-07 05:18:35 +02:00
|
|
|
$value = $vcal_text[$i];
|
|
|
|
}
|
|
|
|
|
2001-06-10 06:02:50 +02:00
|
|
|
switch($majortype)
|
2001-06-07 05:18:35 +02:00
|
|
|
{
|
|
|
|
case 'begin':
|
2001-06-10 06:02:50 +02:00
|
|
|
switch(strtolower($value))
|
2001-03-17 20:39:56 +01:00
|
|
|
{
|
2001-06-10 06:02:50 +02:00
|
|
|
case 'vcalendar':
|
2001-06-25 00:13:17 +02:00
|
|
|
$vcal = $this->new_vcal();
|
2001-06-10 06:02:50 +02:00
|
|
|
break;
|
|
|
|
case 'vevent':
|
2001-06-25 00:13:17 +02:00
|
|
|
case 'vtodo':
|
|
|
|
$event = new vCalendar_item;
|
2001-06-10 06:02:50 +02:00
|
|
|
$event->type = strtolower($value);
|
|
|
|
break;
|
2001-03-17 20:39:56 +01:00
|
|
|
}
|
2001-06-07 05:18:35 +02:00
|
|
|
break;
|
2001-06-10 06:02:50 +02:00
|
|
|
case 'prodid':
|
|
|
|
case 'version':
|
|
|
|
case 'method':
|
|
|
|
$this->set_var($vcal,$majortype,$value);
|
|
|
|
break;
|
2001-07-02 05:31:13 +02:00
|
|
|
case 'description':
|
|
|
|
$event->$majortype = new class_text;
|
2001-07-03 05:32:09 +02:00
|
|
|
$this->parse_text($event->$majortype,$this->from_text($value));
|
|
|
|
break;
|
|
|
|
case 'location':
|
|
|
|
$this->set_var($event,$majortype,$this->from_text($value));
|
2001-07-02 05:31:13 +02:00
|
|
|
break;
|
|
|
|
case 'attach':
|
|
|
|
$attach = new class_text;
|
|
|
|
$this->parse_text($attach,$value);
|
|
|
|
$event->attach[] = $attach;
|
|
|
|
unset($attach);
|
|
|
|
break;
|
2001-06-07 05:18:35 +02:00
|
|
|
case 'attendee':
|
2001-07-02 05:31:13 +02:00
|
|
|
$attendee = new attendee;
|
2001-06-10 06:02:50 +02:00
|
|
|
$this->parse_attendee($attendee,$value);
|
2001-06-07 05:18:35 +02:00
|
|
|
$event->attendee[] = $attendee;
|
|
|
|
unset($attendee);
|
|
|
|
break;
|
|
|
|
case 'organizer':
|
2001-07-02 05:31:13 +02:00
|
|
|
$event->$majortype = new attendee;
|
2001-06-10 06:02:50 +02:00
|
|
|
$this->parse_attendee($event->$majortype,$value);
|
2001-06-07 05:18:35 +02:00
|
|
|
break;
|
|
|
|
case 'end':
|
|
|
|
switch(strtolower($value))
|
|
|
|
{
|
|
|
|
case 'vevent':
|
|
|
|
$this->event[] = $event;
|
2001-06-25 00:13:17 +02:00
|
|
|
unset($event);
|
|
|
|
break;
|
|
|
|
case 'vtodo':
|
|
|
|
$this->todo[] = $event;
|
|
|
|
unset($event);
|
2001-06-07 05:18:35 +02:00
|
|
|
break;
|
|
|
|
case 'vcalendar':
|
2001-06-10 06:02:50 +02:00
|
|
|
$this->vcal = $vcal;
|
|
|
|
$this->vcal->event = $this->event;
|
2001-06-25 00:13:17 +02:00
|
|
|
$this->vcal->todo = $this->todo;
|
2001-06-07 05:18:35 +02:00
|
|
|
break 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'dtstart':
|
|
|
|
case 'dtend':
|
|
|
|
case 'dtstamp':
|
2001-06-10 06:02:50 +02:00
|
|
|
$this->set_var($event,$majortype,$this->splitdate($value));
|
|
|
|
break;
|
2001-06-10 19:05:51 +02:00
|
|
|
case 'class':
|
2001-06-25 00:13:17 +02:00
|
|
|
$this->set_var($event,$majortype,$this->switch_class($value));
|
2001-06-10 19:05:51 +02:00
|
|
|
break;
|
|
|
|
case 'transp':
|
2001-06-25 00:13:17 +02:00
|
|
|
$this->set_var($event,$majortype,$this->switch_transp($value));
|
2001-06-10 19:05:51 +02:00
|
|
|
break;
|
2001-06-10 06:02:50 +02:00
|
|
|
case 'rrule':
|
|
|
|
$event->$majortype = new $majortype;
|
|
|
|
$this->parse_recurrence($event->$majortype,$value);
|
2001-06-07 05:18:35 +02:00
|
|
|
break;
|
|
|
|
default:
|
2001-06-10 06:02:50 +02:00
|
|
|
$this->set_var($event,$majortype,$value);
|
2001-06-07 05:18:35 +02:00
|
|
|
break;
|
|
|
|
}
|
2001-06-10 06:02:50 +02:00
|
|
|
$i++;
|
2001-03-17 20:39:56 +01:00
|
|
|
}
|
2001-06-10 06:02:50 +02:00
|
|
|
return $this->vcal;
|
2001-03-17 20:39:56 +01:00
|
|
|
}
|
2001-06-25 00:13:17 +02:00
|
|
|
|
|
|
|
function out_organizer_attendee($event)
|
|
|
|
{
|
|
|
|
$str = '';
|
2001-07-02 05:31:13 +02:00
|
|
|
if(!empty($event->cn) && $event->cn <> 'Unknown')
|
2001-06-25 00:13:17 +02:00
|
|
|
{
|
|
|
|
$str .= ';CN="'.$event->cn.'"';
|
|
|
|
}
|
2001-07-02 05:31:13 +02:00
|
|
|
if(!empty($event->dir))
|
|
|
|
{
|
2001-07-03 05:32:09 +02:00
|
|
|
$str .= ';DIR="'.str_replace('=','=3D',str_replace(' ','%20',$event->dir)).'"';
|
2001-07-02 05:31:13 +02:00
|
|
|
}
|
2001-06-25 00:13:17 +02:00
|
|
|
if(!empty($event->role))
|
|
|
|
{
|
|
|
|
$str .= ';ROLE='.$this->switch_role($event->role);
|
|
|
|
}
|
|
|
|
if(!empty($event->rsvp))
|
|
|
|
{
|
|
|
|
$str .= ';RSVP='.$this->switch_rsvp($event->rsvp);
|
|
|
|
}
|
|
|
|
if(!empty($event->delegated_from->user) && !empty($event->delegated_from->host))
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= ';DELEGATED-FROM="MAILTO:'.$event->delegated_from->user.'@'.$event->delegated_from->host.'"';
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
if(!empty($event->delegated_to->user) && !empty($event->delegated_to->host))
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= ';DELEGATED-TO="MAILTO:'.$event->delegated_to->user.'@'.$event->delegated_to->host.'"';
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
if(!empty($event->mailto->user) && !empty($event->mailto->host))
|
|
|
|
{
|
|
|
|
$str .= ':MAILTO:'.$event->mailto->user.'@'.$event->mailto->host;
|
|
|
|
}
|
|
|
|
return $str;
|
|
|
|
}
|
|
|
|
|
2001-07-02 05:31:13 +02:00
|
|
|
function build_text($event)
|
|
|
|
{
|
|
|
|
$str = '';
|
|
|
|
if(!empty($event->cid))
|
|
|
|
{
|
|
|
|
$str .= ';CID="'.$event->cid.'"';
|
|
|
|
}
|
|
|
|
if(!empty($event->altrep))
|
|
|
|
{
|
|
|
|
$str .= ';ALTREP="'.$event->altrep.'"';
|
|
|
|
}
|
|
|
|
if(!empty($event->fmttype))
|
|
|
|
{
|
|
|
|
$str .= ';FMTTYPE='.$event->fmttype;
|
|
|
|
}
|
|
|
|
if(!empty($event->encoding))
|
|
|
|
{
|
|
|
|
$str .= ';ENCODING='.$this->switch_encoding($event->encoding);
|
|
|
|
}
|
|
|
|
if(!empty($event->value))
|
|
|
|
{
|
2001-07-03 05:32:09 +02:00
|
|
|
$str .= ':'.$this->to_text($event->value);
|
2001-07-02 05:31:13 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$str .= ':\n';
|
|
|
|
}
|
|
|
|
|
|
|
|
return $str;
|
|
|
|
}
|
|
|
|
|
2001-06-25 00:13:17 +02:00
|
|
|
function build_card_internals($event)
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str = 'DTSART:'.sprintf("%4d%02d%02dT%02d%02d%02dZ",$event->dtstart->year,$event->dtstart->month,$event->dtstart->mday,$event->dtstart->hour,$event->dtstart->min,$event->dtstart->sec)."\r\n";
|
|
|
|
$str .= 'DTEND:'.sprintf("%4d%02d%02dT%02d%02d%02dZ",$event->dtend->year,$event->dtend->month,$event->dtend->mday,$event->dtend->hour,$event->dtend->min,$event->dtend->sec)."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
// Still need to build recurrence portion......
|
|
|
|
iF(!empty($event->location))
|
|
|
|
{
|
2001-07-03 05:32:09 +02:00
|
|
|
$str .= $this->fold('LOCATION:'.$this->to_text($event->location));
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'LOCATION:\n'."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'TRANSP:'.$this->switch_transp($event->transp)."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
if(!empty($event->sequence))
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'SEQUENCE:'.$event->sequence."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
if(!empty($event->uid))
|
|
|
|
{
|
|
|
|
$str .= $this->fold('UID:'.$event->uid);
|
|
|
|
}
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'DTSTAMP:'.gmdate('Ymd\THms\Z')."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
if(!empty($event->description))
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= $this->fold('DESCRIPTION'.$this->build_text($event->description));
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'DESCRIPTION:\n'."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
if(!empty($event->summary))
|
|
|
|
{
|
|
|
|
$str .= $this->fold('SUMMARY:'.$event->summary);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'SUMMARY:\n'."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
if(!empty($event->priority))
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'PRIORITY:'.$event->priority."\r\n";
|
|
|
|
}
|
|
|
|
$str .= 'CLASS:'.$this->switch_class($event->class)."\r\n";
|
|
|
|
|
|
|
|
if(!empty($event->attach))
|
|
|
|
{
|
|
|
|
for($i=0;$i<count($event->attach);$i++)
|
|
|
|
{
|
|
|
|
$str .= $this->fold('ATTACH'.$this->build_text($event->atttach[$i]));
|
|
|
|
}
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $str;
|
|
|
|
}
|
|
|
|
|
|
|
|
function build_vcal($vcal)
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str = 'BEGIN:VCALENDAR'."\r\n";
|
|
|
|
$str .= 'PRODID:'.$vcal->prodid."\r\n";
|
|
|
|
$str .= 'VERSION:'.$vcal->version."\r\n";
|
|
|
|
$str .= 'METHOD:'.$vcal->method."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
if($vcal->event)
|
|
|
|
{
|
|
|
|
for($i=0;$i<count($vcal->event);$i++)
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'BEGIN:VEVENT'."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
for($j=0;$j<count($vcal->event[$i]->attendee);$j++)
|
|
|
|
{
|
|
|
|
$temp_attendee = $this->out_organizer_attendee($vcal->event[$i]->attendee[$j]);
|
|
|
|
|
|
|
|
if($temp_attendee)
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= $this->fold('ATTENDEE'.$temp_attendee);
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!empty($vcal->event[$i]->organizer))
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= $this->fold('ORGANIZER'.$this->out_organizer_attendee($vcal->event[$i]->organizer));
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
$str .= $this->build_card_internals($vcal->event[$i]);
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'END:VEVENT'."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if($vcal->todo)
|
|
|
|
{
|
|
|
|
for($i=0;$i<count($vcal->todo);$i++)
|
|
|
|
{
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'BEGIN:VTODO'."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
$str .= $this->build_card_internals($vcal->todo[$i]);
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'END:VTODO'."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
}
|
|
|
|
}
|
2001-07-02 05:31:13 +02:00
|
|
|
$str .= 'END:VCALENDAR'."\r\n";
|
2001-06-25 00:13:17 +02:00
|
|
|
|
|
|
|
return $str;
|
|
|
|
}
|
2001-03-17 20:39:56 +01:00
|
|
|
}
|
|
|
|
?>
|