Example #1
0
 /**
  * Get a single item from the server.
  *
  * @param string $url The URL to PROPFIND on
  */
 function DoPROPFINDRequest($url, $props, $depth = 0)
 {
     $this->SetDepth($depth);
     $xml = new XMLDocument(array('DAV:' => '', 'urn:ietf:params:xml:ns:caldav' => 'C'));
     $prop = new XMLElement('prop');
     foreach ($props as $v) {
         $xml->NSElement($prop, $v);
     }
     $this->DoRequest($url, "PROPFIND", $xml->Render('propfind', $prop), "text/xml");
     return $this->xmlResponse;
 }
Example #2
0
 /**
  * Send a need-privileges error response.  This function will only return
  * if the $href is not supplied and the current user has the specified
  * permission for the request path.
  *
  * @param string $privilege The name of the needed privilege.
  * @param string $href The unconstructed URI where we needed the privilege.
  */
 function NeedPrivilege($privileges, $href = null)
 {
     if (is_string($privileges)) {
         $privileges = array($privileges);
     }
     if (!isset($href)) {
         if ($this->HavePrivilegeTo($privileges)) {
             return;
         }
         $href = $this->path;
     }
     $reply = new XMLDocument(array('DAV:' => ''));
     $privnodes = array($reply->href(ConstructURL($href)), new XMLElement('privilege'));
     // RFC3744 specifies that we can only respond with one needed privilege, so we pick the first.
     $reply->NSElement($privnodes[1], $privileges[0]);
     $xml = new XMLElement('need-privileges', new XMLElement('resource', $privnodes));
     $xmldoc = $reply->Render('error', $xml);
     $this->DoResponse(403, $xmldoc, 'text/xml; charset="utf-8"');
     exit(0);
     // Unecessary, but might clarify things
 }
Example #3
0
 /**
  * Get a single item from the server.
  *
  * @param string $url The URL to PROPFIND on
  */
 function DoPROPFINDRequest($url, $props, $depth = 0)
 {
     $this->SetDepth($depth);
     $xml = new XMLDocument(array('DAV:' => '', 'urn:ietf:params:xml:ns:caldav' => 'C'));
     $prop = new XMLElement('prop');
     foreach ($props as $v) {
         $xml->NSElement($prop, $v);
     }
     $this->body = $xml->Render('propfind', $prop);
     $this->requestMethod = 'PROPFIND';
     $this->SetContentType('text/xml');
     $this->DoRequest($url);
     return $this->GetXmlResponse();
 }
Example #4
0
                break;
        }
    }
    /**
     * If we have encountered any instances of failure, the whole damn thing fails.
     */
    if (count($failure) > 0) {
        $props = array();
        $status = array();
        foreach ($success as $tag => $v) {
            // Unfortunately although these succeeded, we failed overall, so they didn't happen...
            $props[] = new XMLElement($reply->Tag($tag));
        }
        $status[] = new XMLElement('propstat', array(new XMLElement('prop', $props), new XMLElement('status', 'HTTP/1.1 424 Failed Dependency')));
        if ($request_type == 'extended-mkcol') {
            $request->DoResponse($failure_code, $reply->Render('mkcol-response', array_merge($status, $failure), 'text/xml; charset="utf-8"'));
        } else {
            array_unshift($failure, $reply->href(ConstructURL($request->path)));
            $failure[] = new XMLElement('responsedescription', translate('Some properties were not able to be set.'));
            $request->DoResponse(207, $reply->Render('multistatus', new XMLElement('response', $failure)), 'text/xml; charset="utf-8"');
        }
    }
}
$sql = 'SELECT * FROM collection WHERE dav_name = :dav_name';
$qry = new AwlQuery($sql, array(':dav_name' => $request->path));
if (!$qry->Exec('MKCOL', __LINE__, __FILE__)) {
    $request->DoResponse(500, translate('Error querying database.'));
}
if ($qry->rows() != 0) {
    $request->DoResponse(405, translate('A collection already exists at that location.'));
}
/**
* Deliver scheduling replies to organizer and other attendees
* @param vComponent $ical the VCALENDAR to deliver
* @return false on error
*/
function handle_schedule_reply(vCalendar $ical)
{
    global $c, $session, $request;
    $resources = $ical->GetComponents('VTIMEZONE', false);
    $ic = $resources[0];
    $etag = md5($request->raw_post);
    $organizer = $ical->GetOrganizer();
    // for now we treat events with out organizers as an error
    if (empty($organizer)) {
        return false;
    }
    $att = $ical->GetAttendees();
    $attendees = array_merge($organizer, $att);
    dbg_error_log("PUT", "Attempting to deliver scheduling request for %d attendees", count($attendees));
    foreach ($attendees as $k => $attendee) {
        $attendee_email = preg_replace('/^mailto:/i', '', $attendee->Value());
        dbg_error_log("PUT", "Delivering to %s", $attendee_email);
        $attendee_principal = new DAVPrincipal(array('email' => $attendee_email, 'options' => array('allow_by_email' => true)));
        $deliver_path = $attendee_principal->internal_url('schedule_inbox');
        $attendee_email = preg_replace('/^mailto:/i', '', $attendee->Value());
        if ($attendee_email == $request->principal->email) {
            dbg_error_log("PUT", "not delivering to owner");
            continue;
        }
        $ar = new DAVResource($deliver_path);
        if (!$ar->HavePrivilegeTo('schedule-deliver-reply')) {
            $reply = new XMLDocument(array('DAV:' => ''));
            $privnodes = array($reply->href($attendee_principal->url('schedule_inbox')), new XMLElement('privilege'));
            // RFC3744 specifies that we can only respond with one needed privilege, so we pick the first.
            $reply->NSElement($privnodes[1], 'schedule-deliver-reply');
            $xml = new XMLElement('need-privileges', new XMLElement('resource', $privnodes));
            $xmldoc = $reply->Render('error', $xml);
            $request->DoResponse(403, $xmldoc, 'text/xml; charset="utf-8"');
            continue;
        }
        $ncal = new vCalendar(array('METHOD' => 'REPLY'));
        $ncal->AddComponent(array_merge($ical->GetComponents('VEVENT', false), array($ic)));
        $content = $ncal->Render();
        write_resource(new DAVResource($deliver_path . $etag . '.ics'), $content, $ar, $request->user_no, md5($content), $put_action_type = 'INSERT', $caldav_context = true, $log_action = true, $etag);
    }
    $request->DoResponse(201, 'Created');
}
Example #6
0
*/
if (count($failure) > 0) {
    $qry->Rollback();
    $url = ConstructURL($request->path);
    $multistatus = new XMLElement('multistatus');
    array_unshift($failure, new XMLElement('responsedescription', translate("Some properties were not able to be changed.")));
    array_unshift($failure, new XMLElement('href', $url));
    $response = $reply->DAVElement($multistatus, 'response', $failure);
    if (!empty($success)) {
        $prop = new XMLElement('prop');
        foreach ($success as $tag => $v) {
            $reply->NSElement($prop, $tag);
        }
        $reply->DAVElement($response, 'propstat', array($prop, new XMLElement('status', 'HTTP/1.1 424 Failed Dependency')));
    }
    $request->DoResponse(207, $reply->Render($multistatus), 'text/xml; charset="utf-8"');
}
/**
* Otherwise we will try and do the SQL. This is inside a transaction, so PostgreSQL guarantees the atomicity
*/
if ($qry->Commit()) {
    $cache = getCacheInstance();
    $cache_ns = null;
    if ($dav_resource->IsPrincipal()) {
        $cache_ns = 'principal-' . $dav_resource->dav_name();
    } else {
        if ($dav_resource->IsCollection()) {
            // Uncache anything to do with the collection
            $cache_ns = 'collection-' . $dav_resource->dav_name();
        }
    }
Example #7
0
/**
* Deliver scheduling replies to organizer and other attendees
* @param iCalComponent $ical the VCALENDAR to deliver
* @return false on error
*/
function handle_schedule_reply($ical)
{
    global $c, $session, $request;
    $resources = $ical->GetComponents('VTIMEZONE', false);
    $ic = $resources[0];
    $etag = md5($request->raw_post);
    $organizer = $ic->GetProperties('ORGANIZER');
    // for now we treat events with out organizers as an error
    if (count($organizer) < 1) {
        return false;
    }
    $attendees = array_merge($organizer, $ic->GetProperties('ATTENDEE'));
    $wr_attendees = $ic->GetProperties('X-WR-ATTENDEE');
    if (count($wr_attendees) > 0) {
        dbg_error_log("POST", "Non-compliant iCal request.  Using X-WR-ATTENDEE property");
        foreach ($wr_attendees as $k => $v) {
            $attendees[] = $v;
        }
    }
    dbg_error_log("POST", "Attempting to deliver scheduling request for %d attendees", count($attendees));
    foreach ($attendees as $k => $attendee) {
        $attendee_email = preg_replace('/^mailto:/', '', $attendee->Value());
        dbg_error_log("POST", "Delivering to %s", $attendee_email);
        $attendee_principal = new CalDAVPrincipal(array('email' => $attendee_email, 'options' => array('allow_by_email' => true)));
        $deliver_path = preg_replace('/^.*caldav.php/', '', $attendee_principal->schedule_inbox_url);
        $attendee_email = preg_replace('/^mailto:/', '', $attendee->Value());
        if ($attendee_email == $request->principal->email) {
            dbg_error_log("POST", "not delivering to owner");
            continue;
        }
        $ar = new DAVResource($deliver_path);
        if (!$ar->HavePrivilegeTo('schedule-deliver-reply')) {
            $reply = new XMLDocument(array('DAV:' => ''));
            $privnodes = array($reply->href(ConstructURL($attendee_principal->schedule_inbox_url)), new XMLElement('privilege'));
            // RFC3744 specifies that we can only respond with one needed privilege, so we pick the first.
            $reply->NSElement($privnodes[1], 'schedule-deliver-reply');
            $xml = new XMLElement('need-privileges', new XMLElement('resource', $privnodes));
            $xmldoc = $reply->Render('error', $xml);
            $request->DoResponse(403, $xmldoc, 'text/xml; charset="utf-8"');
            continue;
        }
        $ncal = new iCalComponent();
        $ncal->VCalendar();
        $ncal->AddProperty('METHOD', 'REPLY');
        $ncal->AddComponent(array_merge($ical->GetComponents('VEVENT', false), array($ic)));
        $content = $ncal->Render();
        write_resource($attendee_principal->user_no, $deliver_path . $etag . '.ics', $content, $ar->GetProperty('collection_id'), $request->user_no, md5($content), $ncal, $put_action_type = 'INSERT', $caldav_context = true, $log_action = true, $etag);
    }
    $request->DoResponse(201, 'Created');
}
Example #8
0
            continue;
        }
        $onsets[$utc] = array('from' => $comp->GetPValue('TZOFFSETFROM'), 'to' => $comp->GetPValue('TZOFFSETTO'), 'name' => $comp->GetPValue('TZNAME'), 'type' => $comp->GetType());
    }
    return $onsets;
}
header('ETag: "' . $tz->etag . '"');
header('Last-Modified', $tz->last_modified);
header('Content-Type: application/xml; charset="utf-8"');
$vtz = new vCalendar($tz->vtimezone);
$response = new XMLDocument(array("urn:ietf:params:xml:ns:timezone-service" => ""));
$timezones = $response->NewXMLElement('urn:ietf:params:xml:ns:timezone-service:timezones');
$qry = new AwlQuery('SELECT to_char(max(last_modified),\'YYYY-MM-DD"T"HH24:MI:SS"Z"\') AS dtstamp FROM timezones');
if ($qry->Exec('tz/list', __LINE__, __FILE__) && $qry->rows() > 0) {
    $row = $qry->Fetch();
    $timezones->NewElement('dtstamp', $row->dtstamp);
} else {
    $timezones->NewElement('dtstamp', gmdate('Y-m-d\\TH:i:s\\Z'));
}
$from = new RepeatRuleDateTime($start);
$until = new RepeatRuleDateTime($end);
$observances = expand_timezone_onsets($vtz, $from, $until);
$tzdata = array();
$tzdata[] = new XMLElement('tzid', $tzid);
$tzdata[] = new XMLElement('calscale', 'Gregorian');
foreach ($observances as $onset => $details) {
    $tzdata[] = new XMLElement('observance', array(new XMLElement('name', empty($details['name']) ? $details['type'] : $details['name']), new XMLElement('onset', $onset), new XMLElement('utc-offset-from', substr($details['from'], 0, -2) . ':' . substr($details['from'], -2)), new XMLElement('utc-offset-to', substr($details['to'], 0, -2) . ':' . substr($details['to'], -2))));
}
$timezones->NewElement('tzdata', $tzdata);
echo $response->Render($timezones);
exit(0);
Example #9
0
if ($qry->Exec('tz/list', __LINE__, __FILE__) && $qry->rows() > 0) {
    while ($tz = $qry->Fetch()) {
        $elements = array(new XMLElement('tzid', $tz->tzid), new XMLElement('last-modified', $tz->last_modified));
        if ($tz->active != 't') {
            $elements[] = new XMLElement('inactive');
        }
        if ($tz->tzid != $tz->olson_name) {
            $elements[] = new XMLElement('alias', $tz->olson_name);
        }
        if ($q2->QDo('SELECT * FROM tz_aliases WHERE our_tzno = ?', array($tz->our_tzno))) {
            while ($alias = $q2->Fetch()) {
                $elements[] = new XMLElement('alias', $alias->tzalias);
            }
        }
        if (!empty($lang) && $q2->QDo('SELECT * FROM tz_localnames WHERE our_tzno = ? AND locale = ?', array($tz->our_tzno, $lang)) && $q2->rows() > 0) {
            while ($local = $q2->Fetch()) {
                $attr = array('lang' => $local->locale);
                if ($local->preferred == 't') {
                    $attr['preferred'] = 'true';
                }
                $elements[] = new XMLElement('local-name', $local->localised_name, $attr);
            }
        } else {
            $elements[] = new XMLElement('local-name', $tz->tzid, empty($lang) ? null : array('lang' => $lang));
        }
        $tzlist->NewElement('summary', $elements);
    }
}
header('Content-Type: application/xml; charset="utf-8"');
echo $response->Render($tzlist);
exit(0);
Example #10
0
 /**
  * Applies a properties change to a DAV resource
  *
  * @return boolean  TRUE on successful creation, i18n array (msg,
  * [params]) otherwise
  */
 function proppatch($user, $passwd, $calendar = '', $props = array())
 {
     $this->prepare_client($user, $passwd, '');
     // Preconditions
     $logmsg = '';
     $usermsg = '';
     $params = array();
     // Empty calendar?
     if (empty($calendar)) {
         $logmsg = 'no internal name specified';
         $usermsg = 'error_internalcalnamemissing';
     }
     if (!isset($props['displayname'])) {
         $logmsg = 'no display name specified';
         $usermsg = 'error_calnamemissing';
     }
     if (!isset($props['color'])) {
         $logmsg = 'no color specified';
         $usermsg = 'error_calcolormissing';
     }
     if (!empty($logmsg)) {
         $this->CI->extended_logs->message('ERROR', 'Invalid call to proppatch(): ' . $logmsg);
         return array($usermsg, $params);
     }
     $url = $this->build_calendar_url($user, $calendar);
     // Create XML body
     $ns = array('DAV:' => '', 'urn:ietf:params:xml:ns:caldav' => 'C', 'http://apple.com/ns/ical/' => 'ical');
     $xml = new XMLDocument($ns);
     $set = $xml->NewXMLElement('set');
     $prop = $set->NewElement('prop');
     $xml->NSElement($prop, 'displayname', $props['displayname']);
     $xml->NSElement($prop, 'http://apple.com/ns/ical/:calendar-color', $props['color']);
     // TODO: associate timezone? AWL doesn't like <CDATA,
     // gets replaced by html entity
     $xml_text = $xml->Render('propertyupdate', $set, null, 'http://apple.com/ns/ical/:calendar-color');
     $result = $this->client->DoPROPPATCH($xml_text, $url);
     $success = FALSE;
     $logmsg = '';
     $usermsg = '';
     if ($result === TRUE) {
         $success = TRUE;
     } else {
         $logmsg = $result;
         $usermsg = 'error_modfailed';
     }
     if ($success === FALSE) {
         $this->CI->extended_logs->message('INTERNALS', 'Calendar ' . $calendar . ' not modified.' . ' Found unexpected status on some properties: ' . $logmsg);
         return array($usermsg, $params);
     } else {
         $this->CI->extended_logs->message('INTERNALS', 'Calendar ' . $calendar . ' successfully modified');
         return TRUE;
     }
 }