mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-22 07:53:39 +01:00
start of iSchedule implementation
This commit is contained in:
parent
5505023b50
commit
7783f1535a
292
phpgwapi/inc/class.ischedule_client.inc.php
Normal file
292
phpgwapi/inc/class.ischedule_client.inc.php
Normal file
@ -0,0 +1,292 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware: iSchedule client
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2012 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* iSchedule client: clientside of iSchedule
|
||||
*
|
||||
* @link https://tools.ietf.org/html/draft-desruisseaux-ischedule-01 iSchedule draft from 2010
|
||||
*/
|
||||
class ischedule_client
|
||||
{
|
||||
/**
|
||||
* Own iSchedule version
|
||||
*/
|
||||
const VERSION = '1.0';
|
||||
|
||||
private $url;
|
||||
|
||||
private $recipient;
|
||||
|
||||
private $originator;
|
||||
|
||||
/**
|
||||
* Private key of originators domain
|
||||
*/
|
||||
private $dkim_private_key;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $recipient=null recipient email-address
|
||||
* @param string $url=null ischedule url, if it should NOT be discovered
|
||||
* @throws Exception in case of an error or discovery failure
|
||||
*/
|
||||
public function __construct($recipient, $url=null)
|
||||
{
|
||||
$this->recipient = $recipient;
|
||||
$this->originator = $GLOBALS['egw_info']['user']['account_email'];
|
||||
|
||||
if (is_null($url))
|
||||
{
|
||||
list(,$domain) = explode('@', $recipient);
|
||||
$this->url = self::discover($domain);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
}
|
||||
|
||||
const EMAIL_PREG = '/^([a-z0-9][a-z0-9._-]*)?[a-z0-9]@([a-z0-9](|[a-z0-9_-]*[a-z0-9])\.)+[a-z]{2,6}$/i';
|
||||
|
||||
/**
|
||||
* Set originator and (optional) DKIM private key
|
||||
*
|
||||
* @param string $originator
|
||||
* @param string $dkim_private_key=null
|
||||
* @throws Exception for invalid / not an email originator
|
||||
*/
|
||||
public function setOriginator($originator, $dkim_private_key=null)
|
||||
{
|
||||
if (!preg_match(self::EMAIL_PREG, $originator))
|
||||
{
|
||||
throw new Exception("Invalid orginator '$originator'!");
|
||||
}
|
||||
$this->originator = $originator;
|
||||
|
||||
if (!is_null($dkim_private_key))
|
||||
{
|
||||
$this->dkim_private_key = $dkim_private_key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover iSchedule url of a given domain
|
||||
*
|
||||
* @param string $domain
|
||||
* @return string discovered ischedule url
|
||||
* @throws Exception in case of an error or discovery failure
|
||||
*/
|
||||
public static function discover($domain)
|
||||
{
|
||||
static $scheme2port = array(
|
||||
'https' => 443,
|
||||
'http' => 80,
|
||||
);
|
||||
|
||||
$d = $domain;
|
||||
for($n = 0; $n < 3; ++$n)
|
||||
{
|
||||
if (!($records = dns_get_record($host='_ischedules._tcp.'.$d, DNS_SRV)) &&
|
||||
!($records = dns_get_record($host='_ischedule._tcp.'.$d, DNS_SRV)))
|
||||
{
|
||||
// try without subdomain(s)
|
||||
$parts = explode('.', $d);
|
||||
if (count($parts) < 3) break;
|
||||
array_shift($parts);
|
||||
$d = implode('.', $parts);
|
||||
}
|
||||
}
|
||||
if (!$records) throw new Exception("Could not discover iSchedule service for domain '$domain'!");
|
||||
|
||||
// ToDo: do we need to use priority and weight
|
||||
$record = $records[0];
|
||||
|
||||
$url = strpos($host, '_ischedules') === 0 ? 'https' : 'http';
|
||||
if ($scheme2port[$url] == $record['port'])
|
||||
{
|
||||
$url .= '://'.$record['target'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$url .= '://'.$record['target'].':'.$record['port'];
|
||||
}
|
||||
$url .= '/.well-known/ischedule';
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post dkim signed message to recipients iSchedule server
|
||||
*
|
||||
* @param string $content
|
||||
* @param string $content_type
|
||||
* @return string
|
||||
* @throws Exception with http status code and message, if server responds other then 2xx
|
||||
*/
|
||||
public function post_msg($content, $content_type)
|
||||
{
|
||||
$url_parts = parse_url($this->url);
|
||||
$headers = array(
|
||||
'Host' => $url_parts['host'].($url_parts['port'] ? ':'.$url_parts['port'] : ''),
|
||||
'iSchedule-Version' => self::VERSION,
|
||||
'Content-Type' => $content_type,
|
||||
'Originator' => $this->originator,
|
||||
'Recipient' => $this->recipient,
|
||||
'Content-Length' => bytes($content),
|
||||
);
|
||||
$headers['DKIM-Signature'] = $this->dkim_sign($headers, $content);
|
||||
$header_string = '';
|
||||
foreach($headers as $name => $value)
|
||||
{
|
||||
$header_string .= $name.': '.$value."\r\n";
|
||||
}
|
||||
$opts = array('http' =>
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'header' => $header_string,
|
||||
//'timeout' => $timeout, // max timeout in seconds
|
||||
'content' => $content,
|
||||
)
|
||||
);
|
||||
|
||||
// need to suppress warning, if http-status not 2xx
|
||||
if (($response = @file_get_contents($this->url, false, stream_context_create($opts))) === false)
|
||||
{
|
||||
list(, $code, $message) = explode(' ', $http_response_header[0], 3);
|
||||
throw new Exception($message, $code);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate DKIM signature for headers and body using originators domains private key
|
||||
*
|
||||
* @param array $headers
|
||||
* @param string $body
|
||||
* @param string $type dkim-type
|
||||
*/
|
||||
public function dkim_sign(array $headers, $body, $type='calendar')
|
||||
{
|
||||
return 'dummy';
|
||||
}
|
||||
|
||||
/**
|
||||
* Capabilities
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $capabilities;
|
||||
|
||||
/**
|
||||
* Query capabilities of iSchedule server
|
||||
*
|
||||
* @param string $name=null name of capability to return, default null to return internal array with all capabilities
|
||||
* @return mixed
|
||||
* @throws Exception in case of an error or discovery failure
|
||||
*/
|
||||
public function capabilities($name=null)
|
||||
{
|
||||
if (!isset($this->capabilities))
|
||||
{
|
||||
$reader = new XMLReader();
|
||||
if (!$reader->open($this->url.'?query=capabilities'))
|
||||
{
|
||||
throw new Exception("Could not read iSchedule server capabilities $this->url!");
|
||||
}
|
||||
|
||||
$this->capabilities = self::xml2assoc($reader);
|
||||
$reader->close();
|
||||
|
||||
if (!isset($this->capabilities['query-result']) || !isset($this->capabilities['query-result']['capability-set']))
|
||||
{
|
||||
throw new Exception("Server returned invalid capabilities!");
|
||||
}
|
||||
$this->capabilities = $this->capabilities['query-result']['capability-set'];
|
||||
print_r($this->capabilities);
|
||||
}
|
||||
return $name ? $this->capabilities[$name] : $this->capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse capabilities xml into an associativ array
|
||||
*
|
||||
* @param XMLReader $xml
|
||||
* @param &$target=array()
|
||||
* @return mixed
|
||||
*/
|
||||
private static function xml2assoc(XMLReader $xml, &$target = array())
|
||||
{
|
||||
while ($xml->read())
|
||||
{
|
||||
switch ($xml->nodeType) {
|
||||
case XMLReader::END_ELEMENT:
|
||||
return $target;
|
||||
case XMLReader::ELEMENT:
|
||||
$name = $xml->name;
|
||||
$empty = $xml->isEmptyElement;
|
||||
$attr_name = $xml->getAttribute('name');
|
||||
if (($name_attr = $xml->getAttribute('name')))
|
||||
{
|
||||
$name = $attr_name;
|
||||
}
|
||||
if (isset($target[$name]))
|
||||
{
|
||||
if (!is_array($target[$name]))
|
||||
{
|
||||
$target[$name] = array($target[$name]);
|
||||
}
|
||||
$t = &$target[$name][count($target[$name])];
|
||||
}
|
||||
else
|
||||
{
|
||||
$t = &$target[$name];
|
||||
}
|
||||
if ($xml->isEmptyElement)
|
||||
{
|
||||
$t = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
self::xml2assoc($xml, $t);
|
||||
}
|
||||
if ($xml->hasAttributes)
|
||||
{
|
||||
while($xml->moveToNextAttribute())
|
||||
{
|
||||
if ($xml->name != 'name')
|
||||
{
|
||||
$t['@'.$xml->name] = $xml->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XMLReader::TEXT:
|
||||
case XMLReader::CDATA:
|
||||
$target = $xml->value;
|
||||
}
|
||||
}
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make private vars readable
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->$name;
|
||||
}
|
||||
}
|
260
phpgwapi/inc/class.ischedule_server.inc.php
Normal file
260
phpgwapi/inc/class.ischedule_server.inc.php
Normal file
@ -0,0 +1,260 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware: iSchedule server
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2012 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* iSchedule server: serverside of iSchedule
|
||||
*
|
||||
* @link https://tools.ietf.org/html/draft-desruisseaux-ischedule-01 iSchedule draft from 2010
|
||||
*/
|
||||
class ischedule_server
|
||||
{
|
||||
/**
|
||||
* iSchedule xml namespace
|
||||
*/
|
||||
const ISCHEDULE = 'urn:ietf:params:xml:ns:ischedule';
|
||||
|
||||
/**
|
||||
* Own iSchedule version
|
||||
*/
|
||||
const VERSION = '1.0';
|
||||
|
||||
/**
|
||||
* Serve an iSchedule request
|
||||
*/
|
||||
public function ServeRequest()
|
||||
{
|
||||
// install our own exception handler sending exceptions as http status
|
||||
set_exception_handler(array(__CLASS__, 'exception_handler'));
|
||||
|
||||
switch($_SERVER['REQUEST_METHOD'])
|
||||
{
|
||||
case 'GET':
|
||||
$this->get();
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
$this->post();
|
||||
break;
|
||||
|
||||
default:
|
||||
error_log(__METHOD__."() invalid iSchedule request using {$_SERVER['REQUEST_METHOD']}!");
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve an iSchedule POST request
|
||||
*/
|
||||
protected function post()
|
||||
{
|
||||
static $required_headers = array('Host','Recipient','Originator','Content-Type','DKIM-Signature');
|
||||
$headers = array();
|
||||
foreach($required_headers as $header)
|
||||
{
|
||||
$server_name = strtoupper(str_replace('-', '_', $header));
|
||||
if (strpos($server_name, 'CONTENT_') !== 0) $server_name = 'HTTP_'.$server_name;
|
||||
if (!empty($_SERVER[$server_name])) $headers[$header] = $_SERVER[$server_name];
|
||||
}
|
||||
if (($missing = array_diff($required_headers, array_keys($headers))))
|
||||
{
|
||||
throw new Exception ('Bad Request: missing '.implode(', ', $missing).' header(s)', 403);
|
||||
}
|
||||
if (!$this->dkim_validate($headers))
|
||||
{
|
||||
throw new Exception('Bad Request: DKIM signature invalid', 403);
|
||||
}
|
||||
// parse iCal
|
||||
|
||||
// validate originator matches organizer or attendee
|
||||
throw new exception('Not yet implemented!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate DKIM signature
|
||||
*
|
||||
* @param array $headers
|
||||
* @return boolean true if signature could be validated, false otherwise
|
||||
* @todo
|
||||
*/
|
||||
public function dkim_validate(array $headers)
|
||||
{
|
||||
return isset($headers['DKIM-Signature']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve an iSchedule GET request, currently only query=capabilities
|
||||
*
|
||||
* GET /.well-known/ischedule?query=capabilities HTTP/1.1
|
||||
* Host: cal.example.com
|
||||
*
|
||||
* HTTP/1.1 200 OK
|
||||
* Date: Mon, 15 Dec 2008 09:32:12 GMT
|
||||
* Content-Type: application/xml; charset=utf-8
|
||||
* Content-Length: xxxx
|
||||
* iSchedule-Version: 1.0
|
||||
* ETag: "afasdf-132afds"
|
||||
*
|
||||
* <?xml version="1.0" encoding="utf-8" ?>
|
||||
* <query-result xmlns="urn:ietf:params:xml:ns:ischedule">
|
||||
* <capability-set>
|
||||
* <supported-version-set>
|
||||
* <version>1.0</version>
|
||||
* </supported-version-set>
|
||||
* <supported-scheduling-message-set>
|
||||
* <comp name="VEVENT">
|
||||
* <method name="REQUEST"/>
|
||||
* <method name="ADD"/>
|
||||
* <method name="REPLY"/>
|
||||
* <method name="CANCEL"/>
|
||||
* </comp>
|
||||
* <comp name="VTODO"/>
|
||||
* <comp name="VFREEBUSY"/>
|
||||
* </supported-scheduling-message-set>
|
||||
* <supported-calendar-data-type>
|
||||
* <calendar-data-type content-type="text/calendar" version="2.0"/>
|
||||
* </supported-calendar-data-type>
|
||||
* <supported-attachment-values>
|
||||
* <inline-attachment/>
|
||||
* <external-attachment/>
|
||||
* </supported-attachment-values>
|
||||
* <supported-recipient-uri-scheme-set>
|
||||
* <scheme>mailto</scheme>
|
||||
* </supported-recipient-uri-scheme-set>
|
||||
* <max-content-length>102400</max-content-length>
|
||||
* <min-date-time>19910101T000000Z</min-date-time>
|
||||
* <max-date-time>20381231T000000Z</max-date-time>
|
||||
* <max-instances>150</max-instances>
|
||||
* <max-recipients>250</max-recipients>
|
||||
* <administrator>mailto:ischedule-admin@example.com</administrator>
|
||||
* </capability-set>
|
||||
* </query-result>
|
||||
*/
|
||||
protected function get()
|
||||
{
|
||||
if (!isset($_GET['query']) || $_GET['query'] !== 'capabilities')
|
||||
{
|
||||
error_log(__METHOD__."() invalid iSchedule request using GET without query=capabilities!");
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
return;
|
||||
}
|
||||
|
||||
// generate capabilities
|
||||
/*$xml = new XMLWriter;
|
||||
$xml->openMemory();
|
||||
$xml->setIndent(true);
|
||||
$xml->startDocument('1.0', 'UTF-8');
|
||||
$xml->startElementNs(null, 'query-result', self::ISCHEDULE);
|
||||
$xml->startElement('capability-set');
|
||||
|
||||
foreach(array(
|
||||
'supported-version-set' => array('version' => array('1.0')),
|
||||
'supported-scheduling-message-set' => array(
|
||||
'comp' => array('.name' => array(
|
||||
'VEVENT' => array('method' => array('REQUEST', 'ADD', 'REPLY', 'CANCEL')),
|
||||
'VTODO' => '',
|
||||
'VFREEBUSY' => '',
|
||||
)),
|
||||
)
|
||||
) as $name => $data)
|
||||
{
|
||||
$xml->writeElement($name, $data);
|
||||
}
|
||||
|
||||
$xml->endElement(); // capability-set
|
||||
$xml->endElement(); // query-result
|
||||
$xml->endDocument();
|
||||
$capabilities = $xml->outputMemory();*/
|
||||
|
||||
$capabilities = '<?xml version="1.0" encoding="utf-8" ?>
|
||||
<query-result xmlns="urn:ietf:params:xml:ns:ischedule">
|
||||
<capability-set>
|
||||
<supported-version-set>
|
||||
<version>1.0</version>
|
||||
</supported-version-set>
|
||||
<supported-scheduling-message-set>
|
||||
<comp name="VEVENT">
|
||||
<method name="REQUEST"/>
|
||||
<method name="ADD"/>
|
||||
<method name="REPLY"/>
|
||||
<method name="CANCEL"/>
|
||||
</comp>
|
||||
<comp name="VTODO"/>
|
||||
<comp name="VFREEBUSY"/>
|
||||
</supported-scheduling-message-set>
|
||||
<supported-calendar-data-type>
|
||||
<calendar-data-type content-type="text/calendar" version="2.0"/>
|
||||
</supported-calendar-data-type>
|
||||
<supported-attachment-values>
|
||||
<inline-attachment/>
|
||||
<external-attachment/>
|
||||
</supported-attachment-values>
|
||||
<supported-recipient-uri-scheme-set>
|
||||
<scheme>mailto</scheme>
|
||||
</supported-recipient-uri-scheme-set>
|
||||
<max-content-length>102400</max-content-length>
|
||||
<min-date-time>19910101T000000Z</min-date-time>
|
||||
<max-date-time>20381231T000000Z</max-date-time>
|
||||
<max-instances>150</max-instances>
|
||||
<max-recipients>250</max-recipients>
|
||||
<administrator>mailto:ischedule-admin@example.com</administrator>
|
||||
</capability-set>
|
||||
</query-result>';
|
||||
|
||||
// returning capabilities
|
||||
header('Content-Type: application/xml; charset=utf-8');
|
||||
header('iSchedule-Version: '.self::VERSION);
|
||||
header('Content-Length: '.bytes($capabilites));
|
||||
header('ETag: "'.md5($capabilites).'"');
|
||||
|
||||
echo $capabilities;
|
||||
common::egw_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception handler, which additionally logs the request (incl. a trace)
|
||||
*
|
||||
* Does NOT return and get installed in constructor.
|
||||
*
|
||||
* @param Exception $e
|
||||
*/
|
||||
public static function exception_handler(Exception $e)
|
||||
{
|
||||
// logging exception as regular egw_execption_hander does
|
||||
_egw_log_exception($e,$headline);
|
||||
|
||||
// exception handler sending message back to the client as http status
|
||||
$code = $e->getCode();
|
||||
$msg = $e->getMessage();
|
||||
if (!in_array($code, array(400, 403, 407, 503))) $code = 500;
|
||||
header('HTTP/1.1 '.$code.' '.$msg);
|
||||
|
||||
// if our groupdav logging is active, log the request plus a trace, if enabled in server-config
|
||||
if (self::$request_starttime && isset($GLOBALS['groupdav']) && is_a($GLOBALS['groupdav'],'groupdav'))
|
||||
{
|
||||
$GLOBALS['groupdav']->_http_status = '401 Unauthorized'; // to correctly log it
|
||||
if ($GLOBALS['egw_info']['server']['exception_show_trace'])
|
||||
{
|
||||
$GLOBALS['groupdav']->log_request("\n".$e->getTraceAsString()."\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
$GLOBALS['groupdav']->log_request();
|
||||
}
|
||||
}
|
||||
if (is_object($GLOBALS['egw']))
|
||||
{
|
||||
common::egw_exit();
|
||||
}
|
||||
exit;
|
||||
}
|
||||
}
|
99
phpgwapi/ischedule-cli.php
Executable file
99
phpgwapi/ischedule-cli.php
Executable file
@ -0,0 +1,99 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
/**
|
||||
* EGroupware: iSchedule command line client
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2012 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
if (isset($_SERVER['HTTP_HOST'])) die("This is a commandline ONLY tool!\n");
|
||||
|
||||
/**
|
||||
* iSchedule command line client, primary for testing and development purpose
|
||||
*
|
||||
* @link https://tools.ietf.org/html/draft-desruisseaux-ischedule-01 iSchedule draft from 2010
|
||||
*/
|
||||
function usage($err=null)
|
||||
{
|
||||
echo basename(__FILE__).": [--url ischedule-url] [--component (VEVENT|VFREEBUSY|VTODO) (-|ical-filename)] [--method (REQUEST(default)|RESPONSE)] recipient-email [originator-email]\n\n";
|
||||
if ($err) echo "$err\n\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$GLOBALS['egw_info'] = array(
|
||||
'flags' => array(
|
||||
'noheader' => True,
|
||||
'currentapp' => 'login',
|
||||
)
|
||||
);
|
||||
// if you move this file somewhere else, you need to adapt the path to the header!
|
||||
$egw_dir = dirname(dirname(__FILE__));
|
||||
include($egw_dir.'/header.inc.php');
|
||||
|
||||
$args = $_SERVER['argv'];
|
||||
array_shift($args);
|
||||
$method = 'REQUEST';
|
||||
while($args[0][0] == '-')
|
||||
{
|
||||
$option = array_shift($args);
|
||||
if (count($args) < 2) usage("Missing arguments for '$option'!".array2string($args));
|
||||
switch($option)
|
||||
{
|
||||
case '--url':
|
||||
$url = array_shift($args);
|
||||
break;
|
||||
|
||||
case '--component':
|
||||
if (count($args) < 3) usage('Missing arguments for --component');
|
||||
$component = strtoupper(array_shift($args));
|
||||
if (!in_array($component, array('VEVENT','VFREEBUSY','VTODO')))
|
||||
{
|
||||
usage ("Invalid component name '$component'!");
|
||||
}
|
||||
if (($filename = array_shift($args)) == '-') $filename = 'php://stdin';
|
||||
if (($content = file_get_contents($filename)) === false)
|
||||
{
|
||||
usage("Could not open '$filename'!");
|
||||
}
|
||||
break;
|
||||
|
||||
case '--method':
|
||||
$method = strtoupper(array_shift($args));
|
||||
if (!in_array($method, array('REQUEST','REPLY','CANCEL','ADD')))
|
||||
{
|
||||
usage ("Invalid method name '$method'!");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
usage("Unknown option '$option'!");
|
||||
}
|
||||
}
|
||||
if (!count($args)) usage();
|
||||
|
||||
$recipient = array_shift($args);
|
||||
if ($args) $originator = array_shift($args);
|
||||
|
||||
try {
|
||||
$client = new ischedule_client($recipient, $url);
|
||||
echo "\nUsing iSchedule URL: $client->url\n\n";
|
||||
if ($originator) $client->setOriginator($originator);
|
||||
if ($component)
|
||||
{
|
||||
$content_type = 'text/calendar; component='.$component.'; method='.$method;
|
||||
echo $client->post_msg($content, $content_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
$client->capabilities();
|
||||
}
|
||||
}
|
||||
catch(Exception $e) {
|
||||
echo "\n".($e->getCode() ? $e->getCode().' ' : '').$e->getMessage()."\n\n";
|
||||
}
|
32
phpgwapi/ischedule.php
Normal file
32
phpgwapi/ischedule.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware: iSchedule server
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2012 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* iSchedule server: serverside of iSchedule
|
||||
*
|
||||
* @link https://tools.ietf.org/html/draft-desruisseaux-ischedule-01 iSchedule draft from 2010
|
||||
*/
|
||||
|
||||
$GLOBALS['egw_info'] = array(
|
||||
'flags' => array(
|
||||
'noheader' => True,
|
||||
'currentapp' => 'login',
|
||||
'no_exception_handler' => true,
|
||||
)
|
||||
);
|
||||
// if you move this file somewhere else, you need to adapt the path to the header!
|
||||
$egw_dir = dirname(dirname(__FILE__));
|
||||
include($egw_dir.'/header.inc.php');
|
||||
|
||||
$ischedule = new ischedule_server();
|
||||
$ischedule->ServeRequest();
|
Loading…
Reference in New Issue
Block a user