<?php
abstract class ICalCourseBackend extends CourseBackend
{
/** @var string */
private $location;
/** @var string */
private $authMethod;
/** @var string */
private $user;
/** @var string */
private $pass;
/** @var bool */
private $verifyHostname;
/** @var bool */
private $verifyCert;
/** @var bool|resource */
private $curlHandle = false;
protected function init(
string $location, bool $verifyCert, bool $verifyHostname,
string $authMethod = 'NONE', string $user = '', string $pass = '')
{
$this->verifyCert = $verifyCert;
$this->verifyHostname = $verifyHostname;
if (strpos($location, '%ID%') === false) {
$location .= '%ID%';
}
$this->location = $location;
$this->authMethod = $authMethod;
$this->user = $user;
$this->pass = $pass;
}
/**
* @param string $roomId room id
* @param callable $errorFunc
* @return ICalEvent[]|null all events for this room in the range -7 days to +7 days, or NULL on error
*/
protected function downloadIcal(string $roomId): ?array
{
if (!$this->isOK())
return null;
try {
$ical = new ICalParser(['filterDaysBefore' => 7, 'filterDaysAfter' => 7]);
} catch (Exception $e) {
$this->addError('Error instantiating ICalParser: ' . $e->getMessage(), true);
return null;
}
if ($this->curlHandle === false) {
$this->curlHandle = curl_init();
}
$options = [
CURLOPT_WRITEFUNCTION => function ($ch, $data) use ($ical) {
$ical->feedData($data);
return strlen($data);
},
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYHOST => $this->verifyHostname ? 2 : 0,
CURLOPT_SSL_VERIFYPEER => $this->verifyCert ? 1 : 0,
CURLOPT_URL => str_replace('%ID%', $roomId, $this->location),
CURLOPT_TIMEOUT => 60,
CURLOPT_CONNECTTIMEOUT => 4,
];
if ($this->authMethod !== 'NONE' && defined('CURLAUTH_' . $this->authMethod)) {
$options[CURLOPT_HTTPAUTH] = constant('CURLAUTH_' . $this->authMethod);
$options[CURLOPT_USERPWD] = $this->user;
if (!empty($this->pass)) {
$options[CURLOPT_USERPWD] .= ':' . $this->pass;
}
}
curl_setopt_array($this->curlHandle, $options);
$curlRet = curl_exec($this->curlHandle);
if (!$curlRet) {
$this->addError('Curl error: ' . curl_error($this->curlHandle) . ' for ' . $roomId, false);
}
$ical->finish();
if (!$ical->isValid()) {
if ($curlRet) {
$this->addError("Did not find a VCALENDAR in returned data for $roomId", false);
}
return null;
}
return $ical->events();
}
public function fetchSchedulesInternal(array $requestedRoomIds): array
{
if (empty($requestedRoomIds) || !$this->isOK()) {
return array();
}
$tTables = [];
foreach ($requestedRoomIds as $roomId) {
$data = $this->downloadIcal($roomId);
if ($data === null) {
$this->addError("Downloading ical for $roomId failed", false);
continue;
}
foreach ($data as $event) {
$tTables[$roomId][] = array(
'title' => $this->toTitle($event),
'start' => $event->dtstart,
'end' => $event->dtend,
'cancelled' => false, // ??? How
);
}
}
return $tTables;
}
/**
* Get a usable title from either SUMMARY or DESCRIPTION
*/
protected function toTitle(ICalEvent $event): string
{
$title = $event->summary;
if (empty($title)) {
$title = $event->description;
}
if (empty($title)) {
$title = 'Unknown';
}
return (string)preg_replace([',(\s*<br\s*/?>\s*|\r|\n|\\\r|\\\n)+,', '/\\\\([,;:])/'], ["\n", '$1'], $title);
}
protected function isOK(): bool
{
if (empty($this->location)) {
$this->addError("Credentials are not set", true);
return false;
}
return true;
}
public function __destruct()
{
if ($this->curlHandle !== false) {
curl_close($this->curlHandle);
}
}
}