addError("No url is given", true); return false; } $this->location = $this->mangleProperty('baseUrl', $data['baseUrl']); $this->verifyHostname = $data['verifyHostname']; $this->verifyCert = $data['verifyCert']; return true; } public function getCredentialDefinitions() { return [ new BackendProperty('baseUrl', 'string'), new BackendProperty('verifyCert', 'bool', true), new BackendProperty('verifyHostname', 'bool', true) ]; } public function mangleProperty($prop, $value) { if ($prop === 'baseUrl') { // Update form SOAP to iCal url if (preg_match(',^(http.*?)/qisserver,', $value, $out)) { $value = $out[1] . '/qisserver/pages/cm/exa/timetable/roomScheduleCalendarExport.faces?roomId='; } elseif (preg_match(',(.*[/=])\d*$', $value, $out)) { $value = $out[1]; } elseif (substr_count($value, '/') <= 3) { if (substr($value, -1) !== '/') { $value .= '/'; } $value .= 'qisserver/pages/cm/exa/timetable/roomScheduleCalendarExport.faces?roomId='; } } return $value; } public function checkConnection() { if (empty($this->location)) { $this->addError("Credentials are not set", true); return false; } // Unfortunately HisInOne returns an internal server error if you pass an invalid roomId. // So we just try a bunch and see if anything works. Even if this fails, using // the backend should work, given the URL is actually correct. foreach ([60, 100, 5, 10, 50, 110, 200, 210, 250, 300, 333, 500, 1000, 2000] as $roomId) { if ($this->downloadIcal($roomId) !== null) return true; } return false; } /** * @param int $roomId room id * @return ICalEvent[]|null all events for this room in the range -7 days to +7 days, or NULL on error */ private function downloadIcal($roomId) { if ($this->curlHandle === false) { $this->curlHandle = curl_init(); } $ical = new ICalParser(['filterDaysBefore' => 7, 'filterDaysAfter' => 7]); $options = array( 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 => $this->location . $roomId, CURLOPT_TIMEOUT => 60, CURLOPT_CONNECTTIMEOUT => 4, ); curl_setopt_array($this->curlHandle, $options); if (!curl_exec($this->curlHandle)) { $this->addError('Curl error: ' . curl_error($this->curlHandle), false); } $ical->finish(); if (!$ical->isValid()) { $this->addError("Did not find a VCALENDAR in returned data for {$this->location}$roomId", false); return null; } return $ical->events(); } public function getCacheTime() { return 30 * 60; } public function getRefreshTime() { return 60 * 60; } public function getDisplayName() { return "HisInOne"; } public function fetchSchedulesInternal($requestedRoomIds) { if (empty($requestedRoomIds)) { 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 * @param ICalEvent $event */ private function toTitle($event) { $title = $event->summary; if (empty($title)) { $title = $event->description; } if (empty($title)) { $title = 'Unknown'; } return preg_replace([',(\s*\s*|\r|\n|\\\r|\\\n)+,', '/\\\\([,;:])/'], ["\n", '$1'], $title); } public function __destruct() { if ($this->curlHandle !== false) { curl_close($this->curlHandle); } } }