예제 #1
0
 * @package     com_icagenda
 * @copyright   Copyright (c)2012-2015 Cyril Rezé, Jooml!C - All rights reserved
 *
 * @license     GNU General Public License version 3 or later; see LICENSE.txt
 * @author      Tom-Henning (MaW) / Cyril Rezé (Lyr!C)
 * @link        http://www.joomlic.com
 *
 * @version     3.5.6 2015-05-11
 * @since       3.2.9
 *------------------------------------------------------------------------------
*/
// No direct access to this file
defined('_JEXEC') or die;
require_once JPATH_COMPONENT . '/helpers/iCalcreator.class.php';
//$v = new vCalendar($config);
$v = new vCalendar();
$v->setConfig('filename', 'icagenda.ics');
$v->prodid = 'iCagenda';
$config = JFactory::getConfig();
// Joomla 3.x / 2.5 SWITCH
if (version_compare(JVERSION, '3.0', 'ge')) {
    $offset = $config->get('offset');
} else {
    $offset = $config->getValue('config.offset');
}
$dateTimeZone = new DateTimeZone($offset);
$dateTime = new DateTime("now", $dateTimeZone);
$timeOffset = $dateTimeZone->getOffset($dateTime);
$timezone = $timeOffset / 3600;
$tz = 'UTC';
$v->setProperty('method', 'PUBLISH');
예제 #2
0
function handle_remote_attendee_reply(vCalendar $ical)
{
    $attendees = $ical->GetAttendees();
    // attendee reply have just one attendee
    if (count($attendees) != 1) {
        return;
    }
    $attendee = $attendees[0];
    $uidparam = $ical->GetPropertiesByPath("VCALENDAR/*/UID");
    $uid = $uidparam[0]->Value();
    $qry = new AwlQuery('UPDATE calendar_attendee SET email_status=:statusTo WHERE attendee=:attendee AND dav_id = (SELECT dav_id FROM calendar_item WHERE uid = :uid)');
    // user accepted
    $qry->Bind(':statusTo', EMAIL_STATUS::NORMAL);
    $qry->Bind(':attendee', $attendee->Value());
    $qry->Bind(':uid', $uid);
    $qry->Exec('changeStatusTo');
    return true;
}
/**
* While we can construct our SQL to apply some filters in the query, other filters
* need to be checked against the retrieved record.  This is for handling those ones.
*
* @param array $filter An array of XMLElement which is the filter definition
* @param string $item The database row retrieved for this calendar item
*
* @return boolean True if the check succeeded, false otherwise.
*/
function apply_filter($filters, $item)
{
    global $session, $c, $request;
    if (count($filters) == 0) {
        return true;
    }
    dbg_error_log("calquery", "Applying filter for item '%s'", $item->dav_name);
    $ical = new vCalendar($item->caldav_data);
    return $ical->StartFilter($filters);
}
예제 #4
0
 /**
  * parses a STRING represeting an iCalendar (vCalendar 2)
  * @param STRING $str - iCalendar formatted String
  * @return
  */
 function parse($str)
 {
     $this->data = array();
     $lines = explode("\n", $str);
     $cur = null;
     for ($i = 0; $i < count($lines); $i++) {
         $line = trim($lines[$i]);
         while (!empty($lines[$i + 1]) && substr($lines[$i + 1], 0, 1) == " ") {
             $line .= trim(substr($lines[$i + 1], 1));
             $i++;
         }
         $kv = explode(':', $line, 2);
         if (count($kv) == 1) {
             continue;
         }
         $key = trim($kv[0]);
         $value = trim($kv[1]);
         switch ($key) {
             case 'END':
                 switch ($value) {
                     case 'VCALENDAR':
                         if ($cur) {
                             $this->data['calendar'][] = $cur;
                             $cur = null;
                         }
                         break;
                     default:
                         if ($cur) {
                             $cur->process($key, $value);
                         } else {
                             throw new Exception('Invalid END Tag - ' . $line);
                         }
                 }
                 break;
             case 'BEGIN':
                 switch ($value) {
                     case 'VCALENDAR':
                         $cur = new vCalendar();
                         break;
                     default:
                         if ($cur) {
                             $cur->process($key, $value);
                         } else {
                             throw new Exception('Invalid BEGIN Tag - ' . $line);
                         }
                 }
                 break;
             default:
                 if ($cur) {
                     $cur->process($key, $value);
                 } else {
                     throw new Exception('Invalid Tag - ' . $line);
                 }
         }
     }
 }
예제 #5
0
function write_updated_zone($vtimezone, $tzid)
{
    global $new_zones, $modified_zones;
    if (empty($vtimezone)) {
        dbg_error_log('tz/updatecheck', 'Skipping zone "%s" - no data from server', $tzid);
        return;
    }
    $tzrow = fetch_db_zone($tzid);
    if (isset($tzrow) && $vtimezone == $tzrow->vtimezone) {
        dbg_error_log('tz/updatecheck', 'Skipping zone "%s" - no change', $tzid);
        return;
    }
    $vtz = new vCalendar($vtimezone);
    $last_modified = $vtz->GetPValue('LAST-MODIFIED');
    if (empty($last_modified)) {
        $last_modified = gmdate('Ymd\\THis\\Z');
        // Then it was probably that way when we last updated the data, too :-(
        if (!empty($tzrow)) {
            $old_vtz = new vCalendar($tzrow->vtimezone);
            $old_vtz->ClearProperties('LAST-MODIFIED');
            // We need to add & remove this property so the Render is equivalent.
            $vtz->AddProperty('LAST-MODIFIED', $last_modified);
            $vtz->ClearProperties('LAST-MODIFIED');
            if ($vtz->Render() == $old_vtz->Render()) {
                dbg_error_log('tz/updatecheck', 'Skipping zone "%s" - no change', $tzid);
                return;
            }
        }
        $vtz->AddProperty('LAST-MODIFIED', $last_modified);
    }
    dbg_error_log('tz/updatecheck', 'Writing %s zone for "%s"', empty($tzrow) ? "new" : "updated", $tzid);
    printf("Writing %s zone for '%s'\n", empty($tzrow) ? "new" : "updated", $tzid);
    $params = array(':tzid' => $tzid, ':olson_name' => $tzid, ':vtimezone' => $vtz->Render(), ':last_modified' => $last_modified, ':etag' => md5($vtz->Render()));
    if (empty($tzrow)) {
        $new_zones++;
        $sql = 'INSERT INTO timezones(tzid,active,olson_name,last_modified,etag,vtimezone) ';
        $sql .= 'VALUES(:tzid,TRUE,:olson_name,:last_modified,:etag,:vtimezone)';
    } else {
        $modified_zones++;
        $sql = 'UPDATE timezones SET active=TRUE, olson_name=:olson_name, last_modified=:last_modified, ';
        $sql .= 'etag=:etag, vtimezone=:vtimezone WHERE tzid=:tzid';
    }
    $qry = new AwlQuery($sql, $params);
    $qry->Exec('tz/update', __LINE__, __FILE__);
}
예제 #6
0
         $transparency = $setting->GetPath('urn:ietf:params:xml:ns:caldav:schedule-calendar-transp/*');
         $transparency = preg_replace('{^.*:}', '', $transparency[0]->GetNSTag());
         $qry->QDo('UPDATE collection SET schedule_transp = :transparency WHERE dav_name = :dav_name', array(':dav_name' => $dav_resource->dav_name(), ':transparency' => $transparency));
         $success[$tag] = 1;
     } else {
         add_failure('set', $tag, 'HTTP/1.1 409 Conflict', translate("The CalDAV:schedule-calendar-transp property may only be set on calendars."));
     }
     break;
 case 'urn:ietf:params:xml:ns:caldav:calendar-free-busy-set':
     add_failure('set', $tag, 'HTTP/1.1 409 Conflict', translate("The calendar-free-busy-set is superseded by the  schedule-calendar-transp property of a calendar collection."));
     break;
 case 'urn:ietf:params:xml:ns:caldav:calendar-timezone':
     if ($dav_resource->IsCollection() && $dav_resource->IsCalendar() && !$dav_resource->IsBinding()) {
         $tzcomponent = $setting->GetPath('urn:ietf:params:xml:ns:caldav:calendar-timezone');
         $tzstring = $tzcomponent[0]->GetContent();
         $calendar = new vCalendar($tzstring);
         $timezones = $calendar->GetComponents('VTIMEZONE');
         if (count($timezones) == 0) {
             break;
         }
         $tz = $timezones[0];
         // Backward compatibility
         $tzid = $tz->GetPValue('TZID');
         $params = array(':tzid' => $tzid);
         $qry = new AwlQuery('SELECT 1 FROM timezones WHERE tzid = :tzid', $params);
         if ($qry->Exec('PUT', __LINE__, __FILE__) && $qry->rows() == 0) {
             $params[':olson_name'] = $calendar->GetOlsonName($tz);
             $params[':vtimezone'] = isset($tz) ? $tz->Render() : null;
             $qry->QDo('INSERT INTO timezones (tzid, olson_name, active, vtimezone) VALUES(:tzid,:olson_name,false,:vtimezone)', $params);
         }
         $qry->QDo('UPDATE collection SET timezone = :tzid WHERE dav_name = :dav_name', array(':tzid' => $tzid, ':dav_name' => $dav_resource->dav_name()));
예제 #7
0
function handle_freebusy_request($ic)
{
    global $c, $session, $request, $ical;
    $request->NeedPrivilege('CALDAV:schedule-send-freebusy');
    $reply = new XMLDocument(array("DAV:" => "", "urn:ietf:params:xml:ns:caldav" => "C"));
    $responses = array();
    $fbq_start = $ic->GetPValue('DTSTART');
    $fbq_end = $ic->GetPValue('DTEND');
    if (!(isset($fbq_start) || isset($fbq_end))) {
        $request->DoResponse(400, 'All valid freebusy requests MUST contain a DTSTART and a DTEND');
    }
    $range_start = new RepeatRuleDateTime($fbq_start);
    $range_end = new RepeatRuleDateTime($fbq_end);
    $attendees = $ic->GetProperties('ATTENDEE');
    if (preg_match('# iCal/\\d#', $_SERVER['HTTP_USER_AGENT'])) {
        dbg_error_log("POST", "Non-compliant iCal request.  Using X-WR-ATTENDEE property");
        $wr_attendees = $ic->GetProperties('X-WR-ATTENDEE');
        foreach ($wr_attendees as $k => $v) {
            $attendees[] = $v;
        }
    }
    dbg_error_log("POST", "Responding with free/busy for %d attendees", count($attendees));
    foreach ($attendees as $k => $attendee) {
        $attendee_email = preg_replace('/^mailto:/', '', $attendee->Value());
        dbg_error_log("POST", "Calculating free/busy for %s", $attendee_email);
        /** @todo Refactor this so we only do one query here and loop through the results */
        $params = array(':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth, ':email' => $attendee_email);
        $qry = new AwlQuery('SELECT pprivs(:session_principal::int8,principal_id,:scan_depth::int) AS p, username FROM usr JOIN principal USING(user_no) WHERE lower(usr.email) = lower(:email)', $params);
        if (!$qry->Exec('POST', __LINE__, __FILE__)) {
            $request->DoResponse(501, 'Database error');
        }
        if ($qry->rows() > 1) {
            // Unlikely, but if we get more than one result we'll do an exact match instead.
            if (!$qry->QDo('SELECT pprivs(:session_principal::int8,principal_id,:scan_depth::int) AS p, username FROM usr JOIN principal USING(user_no) WHERE usr.email = :email', $params)) {
                $request->DoResponse(501, 'Database error');
            }
            if ($qry->rows() == 0) {
                /** Sigh... Go back to the original case-insensitive match */
                $qry->QDo('SELECT pprivs(:session_principal::int8,principal_id,:scan_depth::int) AS p, username FROM usr JOIN principal USING(user_no) WHERE lower(usr.email) = lower(:email)', $params);
            }
        }
        $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:caldav');
        $reply->CalDAVElement($response, "recipient", $reply->href($attendee->Value()));
        if ($qry->rows() == 0) {
            $remote = new iSchedule();
            $answer = $remote->sendRequest($attendee->Value(), 'VFREEBUSY/REQUEST', $ical->Render());
            if ($answer === false) {
                $reply->CalDAVElement($response, "request-status", "3.7;Invalid Calendar User");
                $reply->CalDAVElement($response, "calendar-data");
                $responses[] = $response;
                continue;
            }
            foreach ($answer as $a) {
                if ($a === false) {
                    $reply->CalDAVElement($response, "request-status", "3.7;Invalid Calendar User");
                    $reply->CalDAVElement($response, "calendar-data");
                } elseif (substr($a, 0, 1) >= 1) {
                    $reply->CalDAVElement($response, "request-status", $a);
                    $reply->CalDAVElement($response, "calendar-data");
                } else {
                    $reply->CalDAVElement($response, "request-status", "2.0;Success");
                    $reply->CalDAVElement($response, "calendar-data", $a);
                }
                $responses[] = $response;
            }
            continue;
        }
        if (!($attendee_usr = $qry->Fetch())) {
            $request->DoResponse(501, 'Database error');
        }
        if ((privilege_to_bits('schedule-query-freebusy') & bindec($attendee_usr->p)) == 0) {
            $reply->CalDAVElement($response, "request-status", "3.8;No authority");
            $reply->CalDAVElement($response, "calendar-data");
            $responses[] = $response;
            continue;
        }
        $attendee_path_match = '^/' . $attendee_usr->username . '/';
        $fb = get_freebusy($attendee_path_match, $range_start, $range_end, bindec($attendee_usr->p));
        $fb->AddProperty('UID', $ic->GetPValue('UID'));
        $fb->SetProperties($ic->GetProperties('ORGANIZER'), 'ORGANIZER');
        $fb->AddProperty($attendee);
        $vcal = new vCalendar(array('METHOD' => 'REPLY'));
        $vcal->AddComponent($fb);
        $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:caldav');
        $reply->CalDAVElement($response, "recipient", $reply->href($attendee->Value()));
        $reply->CalDAVElement($response, "request-status", "2.0;Success");
        // Cargo-cult setting
        $reply->CalDAVElement($response, "calendar-data", $vcal->Render());
        $responses[] = $response;
    }
    $response = $reply->NewXMLElement("schedule-response", $responses, $reply->GetXmlNsArray(), 'urn:ietf:params:xml:ns:caldav');
    $request->XMLResponse(200, $response);
}
예제 #8
0
/**
* Expand the instances for a STANDARD or DAYLIGHT component of a VTIMEZONE 
*
* @param object $vResource is a VCALENDAR with a VTIMEZONE containing components needing expansion
* @param object $range_start A RepeatRuleDateTime which is the beginning of the range for events.
* @param object $range_end A RepeatRuleDateTime which is the end of the range for events.
* @param int $offset_from The offset from UTC in seconds at the onset time.
*
* @return array of onset datetimes with UTC from/to offsets
*/
function expand_timezone_onsets(vCalendar $vResource, RepeatRuleDateTime $range_start, RepeatRuleDateTime $range_end)
{
    global $c;
    $vtimezones = $vResource->GetComponents();
    $vtz = $vtimezones[0];
    $components = $vtz->GetComponents();
    $instances = array();
    $dtstart = null;
    $is_date = false;
    $has_repeats = false;
    $zone_tz = $vtz->GetPValue('TZID');
    foreach ($components as $k => $comp) {
        if (DEBUG_EXPAND) {
            printf("Starting TZ expansion for component '%s' in timezone '%s'\n", $comp->GetType(), $zone_tz);
            foreach ($instances as $k => $v) {
                print ' : ' . $k;
            }
            print "\n";
        }
        $dtstart_prop = $comp->GetProperty('DTSTART');
        if (!isset($dtstart_prop)) {
            continue;
        }
        $dtstart = new RepeatRuleDateTime($dtstart_prop);
        $dtstart->setTimeZone('UTC');
        $offset_from = $comp->GetPValue('TZOFFSETFROM');
        $offset_from = $offset_from / 100 * 3600 + abs($offset_from) % 100 * 60 * ($offset_from < 0 ? -1 : 0);
        $offset_from *= -1;
        $offset_from = "{$offset_from} seconds";
        dbg_error_log('tz/update', "%s of offset\n", $offset_from);
        $dtstart->modify($offset_from);
        $is_date = $dtstart->isDate();
        $instances[$dtstart->UTC('Y-m-d\\TH:i:s\\Z')] = $comp;
        $rrule = $comp->GetProperty('RRULE');
        $has_repeats = isset($rrule);
        if (!$has_repeats) {
            continue;
        }
        $recur = $comp->GetProperty('RRULE');
        if (isset($recur)) {
            $recur = $recur->Value();
            $this_start = clone $dtstart;
            $rule = new RepeatRule($this_start, $recur, $is_date);
            $i = 0;
            $result_limit = 1000;
            while ($date = $rule->next()) {
                $instances[$date->UTC('Y-m-d\\TH:i:s\\Z')] = $comp;
                if ($i++ >= $result_limit || $date > $range_end) {
                    break;
                }
            }
            if (DEBUG_EXPAND) {
                print "After rrule_expand";
                foreach ($instances as $k => $v) {
                    print ' : ' . $k;
                }
                print "\n";
            }
        }
        $properties = $comp->GetProperties('RDATE');
        if (count($properties)) {
            foreach ($properties as $p) {
                $timezone = $p->GetParameterValue('TZID');
                $rdate = $p->Value();
                $rdates = explode(',', $rdate);
                foreach ($rdates as $k => $v) {
                    $rdate = new RepeatRuleDateTime($v, $timezone, $is_date);
                    if ($return_floating_times) {
                        $rdate->setAsFloat();
                    }
                    $instances[$rdate->UTC('Y-m-d\\TH:i:s\\Z')] = $comp;
                    if ($rdate > $range_end) {
                        break;
                    }
                }
            }
            if (DEBUG_EXPAND) {
                print "After rdate_expand";
                foreach ($instances as $k => $v) {
                    print ' : ' . $k;
                }
                print "\n";
            }
        }
    }
    ksort($instances);
    $onsets = array();
    $start_utc = $range_start->UTC('Y-m-d\\TH:i:s\\Z');
    $end_utc = $range_end->UTC('Y-m-d\\TH:i:s\\Z');
    foreach ($instances as $utc => $comp) {
        if ($utc > $end_utc) {
            if (DEBUG_EXPAND) {
                printf("We're done: {$utc} is out of the range.\n");
            }
            break;
        }
        if ($utc < $start_utc) {
            continue;
        }
        $onsets[$utc] = array('from' => $comp->GetPValue('TZOFFSETFROM'), 'to' => $comp->GetPValue('TZOFFSETTO'), 'name' => $comp->GetPValue('TZNAME'), 'type' => $comp->GetType());
    }
    return $onsets;
}
예제 #9
0
<?php

/**
* CalDAV Server - handle PUT method
*
* @package   davical
* @subpackage   caldav
* @author    Andrew McMillan <*****@*****.**>
* @copyright Catalyst .Net Ltd, Morphoss Ltd
* @license   http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
*/
dbg_error_log("PUT", "method handler");
require_once 'DAVResource.php';
include_once 'caldav-PUT-functions.php';
$vcalendar = new vCalendar($request->raw_post);
$uid = $vcalendar->GetUID();
if (empty($uid)) {
    $uid = uuid();
    $vcalendar->SetUID($uid);
}
if ($add_member) {
    $request->path = $request->dav_name() . $uid . '.ics';
    $dav_resource = new DAVResource($request->path);
    if ($dav_resource->Exists()) {
        $uid = uuid();
        $vcalendar->SetUID($uid);
        $request->path = $request->dav_name() . $uid . '.ics';
        $dav_resource = new DAVResource($request->path);
        if ($dav_resource->Exists()) {
            throw new Exception("Failed to generate unique segment name for add-member!");
        }
예제 #10
0
 /**
  * Parse out the attendee property and write a row to the
  * calendar_attendee table for each one.
  * @param int $dav_id The dav_id of the caldav_data we're processing
  * @param vComponent The VEVENT or VTODO containing the ATTENDEEs
  * @return null
  */
 function WriteCalendarAttendees($dav_id, vCalendar $vcal)
 {
     $qry = new AwlQuery('DELETE FROM calendar_attendee WHERE dav_id = ' . $dav_id);
     $qry->Exec('PUT', __LINE__, __FILE__);
     $attendees = $vcal->GetAttendees();
     if (count($attendees) < 1) {
         return;
     }
     $qry->SetSql('INSERT INTO calendar_attendee ( dav_id, status, partstat, cn, attendee, role, rsvp, params )
         VALUES( ' . $dav_id . ', :status, :partstat, :cn, :attendee, :role, :rsvp, :params )');
     $qry->Prepare();
     $processed = array();
     foreach ($attendees as $v) {
         $attendee = $v->Value();
         if (isset($processed[$attendee])) {
             dbg_error_log('LOG', 'Duplicate attendee "%s" in resource "%d"', $attendee, $dav_id);
             dbg_error_log('LOG', 'Original:  "%s"', $processed[$attendee]);
             dbg_error_log('LOG', 'Duplicate: "%s"', $v->Render());
             continue;
             /** @todo work out why we get duplicate ATTENDEE on one VEVENT */
         }
         $qry->Bind(':attendee', $attendee);
         $qry->Bind(':status', $v->GetParameterValue('STATUS'));
         $qry->Bind(':partstat', $v->GetParameterValue('PARTSTAT'));
         $qry->Bind(':cn', $v->GetParameterValue('CN'));
         $qry->Bind(':role', $v->GetParameterValue('ROLE'));
         $qry->Bind(':rsvp', $v->GetParameterValue('RSVP'));
         $qry->Bind(':params', $v->Parameters());
         $qry->Exec('PUT', __LINE__, __FILE__);
         $processed[$attendee] = $v->Render();
     }
 }
예제 #11
0
 function handle_remote_attendee_reply(vCalendar $ical)
 {
     $attendees = $ical->GetAttendees();
     // attendee reply have just one attendee
     if (count($attendees) != 1) {
         return;
     }
     $attendee = $attendees[0];
     $uidparam = $ical->GetPropertiesByPath("VCALENDAR/*/UID");
     $uid = $uidparam[0]->Value();
     $parameters = $attendee->Parameters();
     $propertyText = '';
     foreach ($parameters as $key => $param) {
         if (!empty($propertyText)) {
             $propertyText .= ';';
         }
         $propertyText .= $key . '=' . $param;
     }
     //$propertyText .= ':' . $attendee->Value();
     $qry = new AwlQuery('SELECT dav_id, calendar_item.collection_id AS collection_id, calendar_item.dav_name AS dav_name, caldav_data FROM calendar_item LEFT JOIN caldav_data USING(dav_id) WHERE uid = :uid');
     $qry->Bind(':uid', $uid);
     $qry->Exec('select dav_id, collection_id');
     if ($row = $qry->Fetch()) {
         $qry = new AwlQuery('UPDATE calendar_attendee SET email_status=:statusTo, partstat=:partstat, params=:params WHERE attendee=:attendee AND dav_id = :dav_id');
         // user accepted
         $qry->Bind(':statusTo', EMAIL_STATUS::NORMAL);
         $qry->Bind(':attendee', $attendee->Value());
         $qry->Bind(':dav_id', $row->dav_id);
         $qry->Bind(':params', $propertyText);
         $qry->Bind(':partstat', $parameters['PARTSTAT']);
         $qry->Exec('changeStatusTo');
         //'(SELECT dav_id FROM calendar_item WHERE uid = :uid)';
         $collection_id = $row->collection_id;
         $dav_name = $row->dav_name;
         //$qry->QDo("SELECT write_sync_change( $collection_id, 200, :dav_name)", array(':dav_name' => $dav_name ) );
         //$qry->Execute();
         $this->update_caldav_data($row->caldav_data, $row->dav_id);
     }
     return true;
 }
예제 #12
0
파일: get.php 프로젝트: derekyu1437/davical
$qry = new AwlQuery($sql, $params);
if (!$qry->Exec()) {
    exit(1);
}
if ($qry->rows() < 1) {
    $sql = 'SELECT our_tzno, tzid, active, olson_name, vtimezone, etag, ';
    $sql .= 'to_char(last_modified,\'Dy, DD Mon IYYY HH24:MI:SS "GMT"\') AS last_modified ';
    $sql .= 'FROM timezones JOIN tz_aliases USING(our_tzno) WHERE tzalias=:tzid';
    if (!$qry->Exec()) {
        exit(1);
    }
    if ($qry->rows() < 1) {
        $request->DoResponse(404);
    }
}
$tz = $qry->Fetch();
$vtz = new vCalendar($tz->vtimezone);
$vtz->AddProperty('TZ-URL', $c->protocol_server_port . $_SERVER['REQUEST_URI']);
$vtz->AddProperty('TZNAME', $tz->olson_name);
if ($qry->QDo('SELECT * FROM tz_localnames WHERE our_tzno = :our_tzno', array(':our_tzno' => $tz->our_tzno)) && $qry->rows()) {
    while ($name = $qry->Fetch()) {
        if (strpos($_SERVER['QUERY_STRING'], 'lang=' . $name->locale) !== false) {
            $vtz->AddProperty('TZNAME', $name->localised_name, array('LANGUAGE', str_replace('_', '-', $name->locale)));
        }
    }
}
header('ETag: "' . $tz->etag . '"');
header('Last-Modified: ' . $tz->last_modified);
header('Content-Disposition: Attachment; Filename="' . str_replace('/', '-', $tzid . '.ics"'));
$request->DoResponse(200, $vtz->Render(), 'text/calendar; charset=UTF-8');
exit(0);
예제 #13
0
function ischedule_freebusy_request($ic, $attendees, $attendees_fail)
{
    global $c, $session, $request;
    $reply = new XMLDocument(array("urn:ietf:params:xml:ns:ischedule" => "I"));
    $icalAttendees = $ic->GetAttendees();
    $responses = array();
    $ical = $ic->GetComponents('VFREEBUSY');
    $ical = $ical[0];
    $fbq_start = $ical->GetPValue('DTSTART');
    $fbq_end = $ical->GetPValue('DTEND');
    if (!(isset($fbq_start) || isset($fbq_end))) {
        $request->DoResponse(400, 'All valid freebusy requests MUST contain a DTSTART and a DTEND');
    }
    $range_start = new RepeatRuleDateTime($fbq_start);
    $range_end = new RepeatRuleDateTime($fbq_end);
    foreach ($attendees as $k => $attendee) {
        $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule');
        $fb = get_freebusy('^' . $attendee->dav_name, $range_start, $range_end);
        $fb->AddProperty('UID', $ical->GetPValue('UID'));
        $fb->SetProperties($ical->GetProperties('ORGANIZER'), 'ORGANIZER');
        foreach ($ical->GetProperties('ATTENDEE') as $at) {
            if ($at->Value() == 'mailto:' . $attendee->email) {
                $fb->AddProperty($at);
            }
        }
        $vcal = new vCalendar(array('METHOD' => 'REPLY'));
        $vcal->AddComponent($fb);
        $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule');
        $response->NewElement("recipient", 'mailto:' . $attendee->email, false, 'urn:ietf:params:xml:ns:ischedule');
        $response->NewElement("request-status", "2.0;Success", false, 'urn:ietf:params:xml:ns:ischedule');
        $response->NewElement("calendar-data", $vcal->Render(), false, 'urn:ietf:params:xml:ns:ischedule');
        $responses[] = $response;
    }
    foreach ($attendees_fail as $k => $attendee) {
        $XMLresponse = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule');
        $XMLresponse->NewElement("recipient", $reply->href('mailto:' . $attendee));
        $XMLresponse->NewElement("request-status", '5.3;cannot schedule this user, unknown or access denied');
        $responses[] = $XMLresponse;
    }
    $response = $reply->NewXMLElement("schedule-response", $responses, $reply->GetXmlNsArray(), 'urn:ietf:params:xml:ns:ischedule');
    $request->XMLResponse(200, $response);
}
예제 #14
0
/**
 * Send an iMIP message since they look like a non-local user.
 *  
 * @param string $method The METHOD parameter from the iTIP
 * @param string $to_email The e-mail address we're going to send to
 * @param vCalendar $vcal The iTIP part of the message.
 */
function doImipMessage($method, $to_email, vCalendar $itip)
{
    global $c, $request;
    header('Debug: Sending iMIP ' . $method . ' message to ' . $to_email);
    $mime = new MultiPart();
    $mime->addPart($itip->Render(), 'text/calendar; charset=UTF-8; method=' . $method);
    $friendly_part = isset($c->iMIP->template[$method]) ? $c->iMIP->template[$method] : <<<EOTEMPLATE
This is a meeting ##METHOD## which your e-mail program should be able to
import into your calendar.  Alternatively you could save the attachment
and load that into your calendar instead.
EOTEMPLATE;
    $components = $itip->GetComponents('VTIMEZONE', false);
    $replaceable = array('METHOD', 'DTSTART', 'DTEND', 'SUMMARY', 'DESCRIPTION', 'URL');
    foreach ($replaceable as $pname) {
        $search = '##' . $pname . '##';
        if (strstr($friendly_part, $search) !== false) {
            $property = $itip->GetProperty($pname);
            if (empty($property)) {
                $property = $components[0]->GetProperty($pname);
            }
            if (empty($property)) {
                $replace = '';
            } else {
                switch ($pname) {
                    case 'DTSTART':
                    case 'DTEND':
                        $when = new RepeatRuleDateTime($property);
                        $replace = $when->format('c');
                        break;
                    default:
                        $replace = $property->GetValue();
                }
            }
            $friendly_part = str_replace($search, $replace, $friendly_part);
        }
    }
    $mime->addPart($friendly_part, 'text/plain');
    $email = new EMail();
    $email->SetFrom($request->principal->email());
    $email->AddTo($to_email);
    $email->SetSubject($components[0]->GetPValue('SUMMARY'));
    $email->SetBody($mime->getMimeParts());
    if (isset($c->iMIP->pretend_email)) {
        $email->Pretend($mime->getMimeHeaders());
    } else {
        if (!isset($c->iMIP->send_email) || !$c->iMIP->send_email) {
            $email->PretendLog($mime->getMimeHeaders());
        } else {
            $email->Send($mime->getMimeHeaders());
        }
    }
}
예제 #15
0
if (preg_match('{^/(\\S+@[a-z0-9][a-z0-9-]*[.][a-z0-9.-]+)/?$}i', $request->path, $matches)) {
    $principal = new Principal('email', $matches[1]);
    $path_match = '^' . $principal->dav_name();
}
if (isset($fb_format) && $fb_format != 'text/calendar') {
    $request->DoResponse(406, translate('This server only supports the text/calendar format for freebusy URLs'));
}
if (!$request->HavePrivilegeTo('read-free-busy')) {
    $request->DoResponse(404);
}
require_once "freebusy-functions.php";
switch ($_SERVER['REQUEST_METHOD']) {
    case 'GET':
        $range_start = new RepeatRuleDateTime($fb_start);
        if (!isset($fb_end)) {
            $range_end = clone $range_start;
            $range_end->modify($fb_period);
        } else {
            $range_end = new RepeatRuleDateTime($fb_end);
        }
        $freebusy = get_freebusy($path_match, $range_start, $range_end);
        $result = new vCalendar();
        $result->AddComponent($freebusy);
        $request->DoResponse(200, $result->Render(), 'text/calendar');
        break;
    default:
        dbg_error_log("freebusy", "Unhandled request method >>%s<<", $_SERVER['REQUEST_METHOD']);
        dbg_log_array("freebusy", 'HEADERS', $raw_headers);
        dbg_log_array("freebusy", '_SERVER', $_SERVER, true);
        @dbg_error_log("freebusy", "RAW: %s", str_replace("\n", "", str_replace("\r", "", $request->raw_post)));
}
예제 #16
0
/**
* Return XML for a single component from the DB
*
* @param array $properties The properties for this component
* @param string $item The DB row data for this component
*
* @return string An XML document which is the response for the component
*/
function component_to_xml($properties, $item)
{
    global $session, $c, $request, $reply;
    dbg_error_log("REPORT", "Building XML Response for item '%s'", $item->dav_name);
    $denied = array();
    $unsupported = array();
    $caldav_data = $item->caldav_data;
    $displayname = preg_replace('{^.*/}', '', $item->dav_name);
    $type = 'unknown';
    $contenttype = 'text/plain';
    switch (strtoupper($item->caldav_type)) {
        case 'VJOURNAL':
        case 'VEVENT':
        case 'VTODO':
            $displayname = $item->summary;
            $type = 'calendar';
            $contenttype = 'text/calendar';
            if (isset($properties['urn:ietf:params:xml:ns:caldav:calendar-data']) || isset($properties['DAV::displayname'])) {
                if (!$request->AllowedTo('all') && $session->user_no != $item->user_no) {
                    // the user is not admin / owner of this calendar looking at his calendar and can not admin the other cal
                    if ($item->class == 'CONFIDENTIAL' || !$request->AllowedTo('read')) {
                        dbg_error_log("REPORT", "Anonymising confidential event for: %s", $item->dav_name);
                        $vcal = new vCalendar($caldav_data);
                        $caldav_data = $vcal->Confidential()->Render();
                        $displayname = translate('Busy');
                    }
                }
            }
            if (isset($c->hide_alarm) && $c->hide_alarm) {
                $dav_resource = new DAVResource($item->dav_name);
                if (isset($properties['urn:ietf:params:xml:ns:caldav:calendar-data']) && !$dav_resource->HavePrivilegeTo('write')) {
                    dbg_error_log("REPORT", "Stripping event alarms for: %s", $item->dav_name);
                    $vcal = new vCalendar($caldav_data);
                    $vcal->ClearComponents('VALARM');
                    $caldav_data = $vcal->Render();
                }
            }
            break;
        case 'VCARD':
            $displayname = $item->fn;
            $type = 'vcard';
            $contenttype = 'text/vcard';
            break;
    }
    $url = ConstructURL($item->dav_name);
    $prop = new XMLElement("prop");
    $need_resource = false;
    foreach ($properties as $full_tag => $v) {
        $base_tag = preg_replace('{^.*:}', '', $full_tag);
        switch ($full_tag) {
            case 'DAV::getcontentlength':
                $contentlength = strlen($caldav_data);
                $prop->NewElement($base_tag, $contentlength);
                break;
            case 'DAV::getlastmodified':
                $prop->NewElement($base_tag, ISODateToHTTPDate($item->modified));
                break;
            case 'urn:ietf:params:xml:ns:caldav:calendar-data':
                if ($type == 'calendar') {
                    $reply->CalDAVElement($prop, $base_tag, $caldav_data);
                } else {
                    $unsupported[] = $base_tag;
                }
                break;
            case 'urn:ietf:params:xml:ns:carddav:address-data':
                if ($type == 'vcard') {
                    $reply->CardDAVElement($prop, $base_tag, $caldav_data);
                } else {
                    $unsupported[] = $base_tag;
                }
                break;
            case 'DAV::getcontenttype':
                $prop->NewElement($base_tag, $contenttype);
                break;
            case 'DAV::current-user-principal':
                $prop->NewElement("current-user-principal", $request->current_user_principal_xml);
                break;
            case 'DAV::displayname':
                $prop->NewElement($base_tag, $displayname);
                break;
            case 'DAV::resourcetype':
                $prop->NewElement($base_tag);
                // Just an empty resourcetype for a non-collection.
                break;
            case 'DAV::getetag':
                $prop->NewElement($base_tag, '"' . $item->dav_etag . '"');
                break;
            case '"current-user-privilege-set"':
                $prop->NewElement($base_tag, privileges($request->permissions));
                break;
            default:
                // It's harder.  We need the DAVResource() to get this one.
                $need_resource = true;
        }
        if ($need_resource) {
            break;
        }
    }
    $href = new XMLElement("href", $url);
    if ($need_resource) {
        if (!isset($dav_resource)) {
            $dav_resource = new DAVResource($item->dav_name);
        }
        $elements = $dav_resource->GetPropStat(array_keys($properties), $reply);
        array_unshift($elements, $href);
    } else {
        $elements = array($href);
        $status = new XMLElement("status", "HTTP/1.1 200 OK");
        $elements[] = new XMLElement("propstat", array($prop, $status));
        if (count($denied) > 0) {
            $status = new XMLElement("status", "HTTP/1.1 403 Forbidden");
            $noprop = new XMLElement("prop");
            foreach ($denied as $k => $v) {
                $reply->NSElement($noprop, $v);
            }
            $elements[] = new XMLElement("propstat", array($noprop, $status));
        }
        if (!$request->PreferMinimal() && count($unsupported) > 0) {
            $status = new XMLElement("status", "HTTP/1.1 404 Not Found");
            $noprop = new XMLElement("prop");
            foreach ($unsupported as $k => $v) {
                $reply->NSElement($noprop, $v);
            }
            $elements[] = new XMLElement("propstat", array($noprop, $status));
        }
    }
    $response = new XMLElement("response", $elements);
    return $response;
}