Esempio n. 1
0
function fetch_db_zone($tzid)
{
    $tzrow = null;
    $qry = new AwlQuery('SELECT * FROM timezones WHERE tzid=:tzid', array(':tzid' => $tzid));
    if ($qry->Exec('tz/update', __LINE__, __FILE__) && $qry->rows() > 0) {
        $tzrow = $qry->Fetch();
    }
    return $tzrow;
}
Esempio n. 2
0
 /**
  * Method used to get the user's roles
  */
 function GetRoles()
 {
     $this->roles = array();
     $sql = 'SELECT role_name FROM roles JOIN role_member ON roles.role_no=role_member.role_no WHERE user_no = ' . $this->user_no;
     $qry = new AwlQuery($sql);
     if ($qry->Exec('DAViCalSession') && $qry->rows() > 0) {
         while ($role = $qry->Fetch()) {
             $this->roles[$role->role_name] = 1;
         }
     }
 }
Esempio n. 3
0
function delete_collection($id)
{
    $params = array(':collection_id' => $id);
    $qry = new AwlQuery('SELECT child.collection_id AS child_id FROM collection child JOIN collection parent ON (parent.dav_name = child.parent_container) WHERE parent.collection_id = :collection_id', $params);
    if ($qry->Exec('DELETE', __LINE__, __FILE__) && $qry->rows() > 0) {
        while ($row = $qry->Fetch()) {
            delete_collection($row->child_id);
        }
    }
    if ($qry->QDo("SELECT write_sync_change(collection_id, 404, caldav_data.dav_name) FROM caldav_data WHERE collection_id = :collection_id", $params) && $qry->QDo("DELETE FROM property WHERE dav_name LIKE (SELECT dav_name FROM collection WHERE collection_id = :collection_id) || '%'", $params) && $qry->QDo("DELETE FROM locks WHERE dav_name LIKE (SELECT dav_name FROM collection WHERE collection_id = :collection_id) || '%'", $params) && $qry->QDo("DELETE FROM caldav_data WHERE collection_id = :collection_id", $params) && $qry->QDo("DELETE FROM collection WHERE collection_id = :collection_id", $params)) {
        @dbg_error_log("DELETE", "DELETE (collection): User: %d, ETag: %s, Path: %s", $session->user_no, $request->etag_if_match, $request->path);
        return true;
    }
    return false;
}
Esempio n. 4
0
 static function getInstance($name)
 {
     $qry = new AwlQuery('SELECT * FROM timezones WHERE tzid = ? ORDER BY active DESC', $name);
     if ($qry->Exec('VTimezone', __LINE__, __FILE__) && $qry->rows() > 0 && ($row = $qry->Fetch())) {
         $vtz = new vComponent($row->vtimezone);
         if ($vtz->GetType() == 'VTIMEZONE') {
             return $vtz;
         }
         $tmp = $vtz->GetComponents('VTIMEZONE');
         if (count($tmp) < 1 || $tmp[0]->GetType() != 'VTIMEZONE') {
             return null;
         }
         $vtz = $tmp[0];
         return $vtz;
     }
     return null;
 }
Esempio n. 5
0
 function SQLTest()
 {
     $result = '';
     $sql = "SELECT event_instances::timestamp AS event_date FROM event_instances(?,?) LIMIT 30;";
     $qry = new AwlQuery($sql, $this->dtstart, $this->recur);
     // printf( "%s\n", $qry->querystring);
     if ($qry->Exec("test") && $qry->rows > 0) {
         $i = 0;
         while ($row = $qry->Fetch()) {
             if ($i++ % 4 == 0) {
                 $result .= "\n";
             }
             $result .= "   " . $row->event_date;
         }
     }
     return $result;
 }
Esempio n. 6
0
 function SQLTest()
 {
     $result = '';
     $sql = "SELECT event_instances::timestamp AS event_date FROM event_instances(:dtstart,:rrule) LIMIT " . $this->result_limit;
     $start = microtime(true);
     $qry = new AwlQuery($sql, array(':dtstart' => $this->dtstart, ':rrule' => $this->recur));
     // printf( "%s\n", $qry->querystring);
     if ($qry->Exec("test") && $qry->rows() > 0) {
         $i = 0;
         while ($row = $qry->Fetch()) {
             if ($i++ % 4 == 0) {
                 $result .= "\n";
             }
             $result .= "   " . $row->event_date;
         }
     }
     $this->SQL_time = microtime(true) - $start;
     return $result;
 }
Esempio n. 7
0
/**
* Authenticate against a different PostgreSQL database which contains a usr table in
* the AWL format.
*
* Use this as in the following example config snippet:
*
* require_once('auth-functions.php');
*  $c->authenticate_hook = array(
*      'call'   => 'AuthExternalAwl',
*      'config' => array(
*           // A PgSQL database connection string for the database containing user records
*          'connection[]' => 'dbname=wrms host=otherhost port=5433 user=general',
*           // Which columns should be fetched from the database
*          'columns'    => "user_no, active, email_ok, joined, last_update AS updated, last_used, username, password, fullname, email",
*           // a WHERE clause to limit the records returned.
*          'where'    => "active AND org_code=7"
*      )
*  );
*
*/
function AuthExternalAWL($username, $password)
{
    global $c;
    $persistent = isset($c->authenticate_hook['config']['use_persistent']) && $c->authenticate_hook['config']['use_persistent'];
    if (isset($c->authenticate_hook['config']['columns'])) {
        $cols = $c->authenticate_hook['config']['columns'];
    } else {
        $cols = '*';
    }
    if (isset($c->authenticate_hook['config']['where'])) {
        $andwhere = ' AND ' . $c->authenticate_hook['config']['where'];
    } else {
        $andwhere = '';
    }
    $qry = new AwlQuery('SELECT ' . $cols . ' FROM usr WHERE lower(username) = :username ' . $andwhere, array(':username' => strtolower($username)));
    $authconn = $qry->SetConnection($c->authenticate_hook['config']['connection'], $persistent ? array(PDO::ATTR_PERSISTENT => true) : null);
    if (!$authconn) {
        echo <<<EOERRMSG
  <html><head><title>Database Connection Failure</title></head><body>
  <h1>Database Error</h1>
  <h3>Could not connect to PostgreSQL database</h3>
  </body>
  </html>
EOERRMSG;
        exit(1);
    }
    if ($qry->Exec('Login', __LINE__, __FILE__) && $qry->rows() == 1) {
        $usr = $qry->Fetch();
        if (session_validate_password($password, $usr->password)) {
            UpdateUserFromExternal($usr);
            /**
             * We disallow login by inactive users _after_ we have updated the local copy
             */
            if (isset($usr->active) && $usr->active == 'f') {
                return false;
            }
            $qry = new AwlQuery('SELECT * FROM dav_principal WHERE username = :username', array(':username' => $usr->username));
            if ($qry->Exec() && $qry->rows() == 1) {
                $principal = $qry->Fetch();
                return $principal;
            }
            return $usr;
            // Somewhat optimistically
        }
    }
    return false;
}
Esempio n. 8
0
 /**
  * Returns the locked row, either from the cache or from the database
  *
  * @param string $dav_name The resource which we want to know the lock status for
  */
 function GetLockRow($lock_token)
 {
     if (isset($this->_locks_found) && isset($this->_locks_found[$lock_token])) {
         return $this->_locks_found[$lock_token];
     }
     $qry = new AwlQuery('SELECT * FROM locks WHERE opaquelocktoken = :lock_token', array(':lock_token' => $lock_token));
     if ($qry->Exec('caldav', __LINE__, __FILE__)) {
         $lock_row = $qry->Fetch();
         $this->_locks_found = array($lock_token => $lock_row);
         return $this->_locks_found[$lock_token];
     } else {
         $this->DoResponse(500, translate("Database Error"));
     }
     return false;
     // Nothing matched
 }
Esempio n. 9
0
 if (!$qry->Exec("GET", __LINE__, __FILE__)) {
     $request->DoResponse(500, translate("Database Error"));
 }
 /**
  * Here we are constructing a whole calendar response for this collection, including
  * the timezones that are referred to by the events we have selected.
  */
 $vcal = new iCalComponent();
 $vcal->VCalendar();
 $displayname = $dav_resource->GetProperty('displayname');
 if (isset($displayname)) {
     $vcal->AddProperty("X-WR-CALNAME", $displayname);
 }
 $need_zones = array();
 $timezones = array();
 while ($event = $qry->Fetch()) {
     $ical = new iCalComponent($event->caldav_data);
     /** Save the timezone component(s) into a minimal set for inclusion later */
     $event_zones = $ical->GetComponents('VTIMEZONE', true);
     foreach ($event_zones as $k => $tz) {
         $tzid = $tz->GetPValue('TZID');
         if (!isset($tzid)) {
             continue;
         }
         if ($tzid != '' && !isset($timezones[$tzid])) {
             $timezones[$tzid] = $tz;
         }
     }
     /** Work out which ones are actually used here */
     $comps = $ical->GetComponents('VTIMEZONE', false);
     foreach ($comps as $k => $comp) {
Esempio n. 10
0
 /**
  * Do what must be done with time zones from on file.  Attempt to turn
  * them into something that PostgreSQL can understand...
  *
  * @DEPRECATED: This class will be removed soon.
  * @todo Remove this function.
  */
 function DealWithTimeZones()
 {
     global $c;
     deprecated('iCalendar::DealWithTimeZones');
     $tzid = $this->Get('TZID');
     if (isset($c->save_time_zone_defs) && $c->save_time_zone_defs) {
         $qry = new AwlQuery("SELECT tz_locn FROM time_zone WHERE tz_id = ?;", $tzid);
         if ($qry->Exec('iCalendar') && $qry->rows() == 1) {
             $row = $qry->Fetch();
             $this->tz_locn = $row->tz_locn;
         }
         dbg_error_log('iCalendar', " TZCrap2: TZID '%s', DB Rows=%d, Location '%s'", $tzid, $qry->rows(), $this->tz_locn);
     }
     if ((!isset($this->tz_locn) || $this->tz_locn == '') && $tzid != '') {
         /**
          * In case there was no X-LIC-LOCATION defined, let's hope there is something in the TZID
          * that we can use.  We are looking for a string like "Pacific/Auckland" if possible.
          */
         $tzname = preg_replace('#^(.*[^a-z])?([a-z]+/[a-z]+)$#i', '$1', $tzid);
         /**
         * Unfortunately this kind of thing will never work well :-(
         *
         if ( strstr( $tzname, ' ' ) ) {
           $words = preg_split('/\s/', $tzname );
           $tzabbr = '';
           foreach( $words AS $i => $word ) {
             $tzabbr .= substr( $word, 0, 1);
           }
           $this->tz_locn = $tzabbr;
         }
         */
         if (preg_match('#\\S+/\\S+#', $tzname)) {
             $this->tz_locn = $tzname;
         }
         dbg_error_log('iCalendar', " TZCrap3: TZID '%s', Location '%s', Perhaps: %s", $tzid, $this->tz_locn, $tzname);
     }
     if ($tzid != '' && isset($c->save_time_zone_defs) && $c->save_time_zone_defs && $qry->rows() != 1 && isset($this->vtimezone) && $this->vtimezone != "") {
         $qry2 = new AwlQuery("INSERT INTO time_zone (tz_id, tz_locn, tz_spec) VALUES( ?, ?, ? );", $tzid, $this->tz_locn, $this->vtimezone);
         $qry2->Exec('iCalendar');
     }
     if ((!isset($this->tz_locn) || $this->tz_locn == "") && isset($c->local_tzid)) {
         $this->tz_locn = $c->local_tzid;
     }
 }
Esempio n. 11
0
$qry->Begin();
$etag = md5($request->raw_post);
$params = array(':user_no' => $dest->GetProperty('user_no'), ':dav_name' => $dest->bound_from(), ':etag' => $etag, ':dav_data' => $request->raw_post, ':session_user' => $session->user_no);
if ($dest->Exists()) {
    $sql = 'UPDATE caldav_data SET caldav_data=:dav_data, dav_etag=:etag, logged_user=:session_user,
          modified=current_timestamp, user_no=:user_no, caldav_type=\'VCARD\' WHERE dav_name=:dav_name';
    $response_code = 200;
    $qry->QDo($sql, $params);
    $qry->QDo("SELECT dav_id FROM caldav_data WHERE dav_name = :dav_name ", array(':dav_name' => $params[':dav_name']));
} else {
    $sql = 'INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified, collection_id )
          VALUES( :user_no, :dav_name, :etag, :dav_data, \'VCARD\', :session_user, current_timestamp, current_timestamp, :collection_id )';
    $params[':collection_id'] = $collection_id;
    $response_code = 201;
    $qry->QDo($sql, $params);
    $qry->QDo("SELECT currval('dav_id_seq') AS dav_id");
}
$row = $qry->Fetch();
require_once 'vcard.php';
$vcard = new vCard($request->raw_post);
$vcard->Write($row->dav_id, $dest->Exists());
$qry->QDo("SELECT write_sync_change( {$collection_id}, {$response_code}, :dav_name)", array(':dav_name' => $dest->bound_from()));
if (!$qry->Commit()) {
    $qry->Rollback();
    $request->DoResponse(500, "A database error occurred");
}
header('ETag: "' . $etag . '"');
if ($response_code == 200) {
    $response_code = 204;
}
$request->DoResponse($response_code);
Esempio n. 12
0
    $components = array();
    $filter_fragment = SqlFilterCardDAV($qry_filters, $components);
    if ($filter_fragment !== false) {
        $where .= ' ' . $filter_fragment['sql'];
        $params = $filter_fragment['params'];
    }
} else {
    dbg_error_log('cardquery', 'No query filters');
}
$sql = 'SELECT * FROM caldav_data INNER JOIN addressbook_resource USING(dav_id)' . $where;
if (isset($c->strict_result_ordering) && $c->strict_result_ordering) {
    $sql .= " ORDER BY dav_id";
}
$qry = new AwlQuery($sql, $params);
if ($qry->Exec("cardquery", __LINE__, __FILE__) && $qry->rows() > 0) {
    while ($address_object = $qry->Fetch()) {
        if (!$need_post_filter || apply_filter($qry_filters, $address_object)) {
            if ($bound_from != $target_collection->dav_name()) {
                $address_object->dav_name = str_replace($bound_from, $target_collection->dav_name(), $address_object->dav_name);
            }
            if (count($address_data_properties) > 0) {
                $vcard = new VCard($address_object->caldav_data);
                $vcard->MaskProperties($address_data_properties);
                $address_object->caldav_data = $vcard->Render();
            }
            $responses[] = component_to_xml($properties, $address_object);
        }
    }
}
$multistatus = new XMLElement("multistatus", $responses, $reply->GetXmlNsArray());
$request->XMLResponse(207, $multistatus);
Esempio n. 13
0
 /**
  * Write the User record.
  * @return Success.
  */
 function Write()
 {
     global $c, $session;
     if (parent::Write()) {
         $c->messages[] = i18n('User record written.');
         if ($this->WriteType == 'insert') {
             $qry = new AwlQuery("SELECT currval('usr_user_no_seq');");
             $qry->Exec("User::Write");
             $sequence_value = $qry->Fetch(true);
             // Fetch as an array
             $this->user_no = $sequence_value[0];
         } else {
             if ($this->user_no == $session->user_no && $this->Get("date_format_type") != $session->date_format_type) {
                 // Ensure we match the date style setting
                 $session->date_format_type = $this->Get("date_format_type");
                 unset($_POST['email_ok']);
                 $qry = new AwlQuery("SET DATESTYLE TO ?;", $this->Get("date_format_type") == 'E' ? 'European,ISO' : ($this->Get("date_format_type") == 'U' ? 'US,ISO' : 'ISO'));
                 $qry->Exec();
             }
         }
         return $this->WriteRoles();
     }
     return false;
 }
Esempio n. 14
0
        $dav_id = $row->collection_id;
    } else {
        create_external('/.external/' . md5($href), true, false);
        $qry->QDo('SELECT collection_id FROM collection WHERE dav_name = :dav_name ', array(':dav_name' => '/.external/' . md5($href)));
        if ($qry->rows() != 1 || !($row = $qry->Fetch())) {
            $request->DoResponse(500, translate('Database Error'));
        }
        $dav_id = $row->collection_id;
    }
    $sql = 'INSERT INTO dav_binding ( bound_source_id, access_ticket_id, dav_owner_id, parent_container, dav_name, dav_displayname, external_url, type )
  VALUES( :target_id, :ticket_id, :session_principal, :parent_container, :dav_name, :displayname, :external_url, :external_type )';
    $params = array(':target_id' => $dav_id, ':ticket_id' => null, ':parent_container' => $parent->dav_name(), ':session_principal' => $session->principal_id, ':dav_name' => $destination_path, ':displayname' => $segment, ':external_url' => $href, ':external_type' => 'calendar');
    $qry = new AwlQuery($sql, $params);
    if ($qry->Exec('BIND', __LINE__, __FILE__)) {
        $qry = new AwlQuery('SELECT bind_id from dav_binding where dav_name = :dav_name', array(':dav_name' => $destination_path));
        if (!$qry->Exec('BIND', __LINE__, __FILE__) || $qry->rows() != 1 || !($row = $qry->Fetch())) {
            $request->DoResponse(500, translate('Database Error'));
        }
        fetch_external($row->bind_id, '');
        $request->DoResponse(201);
    } else {
        $request->DoResponse(500, translate('Database Error'));
    }
} else {
    $source = new DAVResource($href);
    if (!$source->Exists()) {
        $request->PreconditionFailed(403, 'DAV::bind-source-exists', translate('The BIND Request MUST identify an existing resource.'));
    }
    if ($source->IsPrincipal() || !$source->IsCollection()) {
        $request->PreconditionFailed(403, 'DAV::binding-allowed', translate('DAViCal only allows BIND requests for collections at present.'));
    }
Esempio n. 15
0
function build_site_statistics()
{
    $principals = translate('No. of Principals');
    $collections = translate('No. of Collections');
    $resources = translate('No. of Resources');
    $table = <<<EOTABLE
<table class="statistics">
<tr><th>{$principals}</th><th>{$collections}</th><th>{$resources}</th></tr>
<tr>%s</tr>
</table>
EOTABLE;
    if (!check_database_connection()) {
        return sprintf($table, '<td colspan="3">' . translate('Site Statistics require the database to be available!') . '</td>');
    }
    $sql = 'SELECT
(SELECT count(1) FROM principal) AS principals,
(SELECT count(1) FROM collection) AS collections,
(SELECT count(1) FROM caldav_data) AS resources';
    $qry = new AwlQuery($sql);
    if ($qry->Exec('setup', __LINE__, __FILE__) && ($s = $qry->Fetch())) {
        $row = sprintf('<td align="center">%s</td><td align="center">%s</td><td align="center">%s</td>', $s->principals, $s->collections, $s->resources);
        return sprintf($table, $row);
    }
    return sprintf($table, '<td colspan="3">' . translate('Site Statistics require the database to be available!') . '</td>');
}
if ($target_collection->Privileges() != privilege_to_bits('DAV::all')) {
    $where .= " AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL) ";
}
if (isset($c->hide_TODO) && ($c->hide_TODO === true || is_string($c->hide_TODO) && preg_match($c->hide_TODO, $_SERVER['HTTP_USER_AGENT'])) && !$target_collection->HavePrivilegeTo('all')) {
    $where .= " AND caldav_data.caldav_type NOT IN ('VTODO') ";
}
if (isset($c->hide_older_than) && intval($c->hide_older_than > 0)) {
    $where .= " AND (CASE WHEN caldav_data.caldav_type<>'VEVENT' OR calendar_item.dtstart IS NULL THEN true ELSE calendar_item.dtstart > (now() - interval '" . intval($c->hide_older_than) . " days') END) ";
}
$sql = 'SELECT ' . $distinct . ' caldav_data.*,calendar_item.*  FROM collection INNER JOIN caldav_data USING(collection_id) INNER JOIN calendar_item USING(dav_id) ' . $where;
if (isset($c->strict_result_ordering) && $c->strict_result_ordering) {
    $sql .= " ORDER BY caldav_data.dav_id";
}
$qry = new AwlQuery($sql, $params);
if ($qry->Exec("calquery", __LINE__, __FILE__) && $qry->rows() > 0) {
    while ($dav_object = $qry->Fetch()) {
        try {
            if (!$need_post_filter || apply_filter($qry_filters, $dav_object)) {
                if ($bound_from != $target_collection->dav_name()) {
                    $dav_object->dav_name = str_replace($bound_from, $target_collection->dav_name(), $dav_object->dav_name);
                }
                if ($need_expansion) {
                    $vResource = new vComponent($dav_object->caldav_data);
                    $expanded = getVCalendarRange($vResource);
                    if (!$expanded->overlaps($range_filter)) {
                        continue;
                    }
                    $expanded = expand_event_instances($vResource, $expand_range_start, $expand_range_end, $expand_as_floating);
                    if ($expanded->ComponentCount() == 0) {
                        continue;
                    }
EOSQL;
        if (isset($c->strict_result_ordering) && $c->strict_result_ordering) {
            $sql .= " ORDER BY collection.collection_id, lower(sync_changes.dav_name), sync_changes.sync_time";
        } else {
            $sql .= " ORDER BY collection.collection_id, sync_changes.dav_name, sync_changes.sync_time";
        }
    }
    $qry = new AwlQuery($sql, $params);
    $last_dav_name = '';
    $first_status = 0;
    if ($qry->Exec("REPORT", __LINE__, __FILE__)) {
        if ($qry->rows() > 50) {
            // If there are more than 50 rows to send we should not send full data in response ...
            $c->sync_resource_data_ok = false;
        }
        while ($object = $qry->Fetch()) {
            if ($request_via_binding) {
                $object->dav_name = str_replace($bound_from, $collection_path, $object->dav_name);
            }
            if ($object->dav_name == $last_dav_name) {
                /** The complex case: this is the second or subsequent for this dav_id */
                if ($object->sync_status == 404) {
                    array_pop($responses);
                    $resultset = array(new XMLElement('href', ConstructURL($object->dav_name)), new XMLElement('status', display_status($object->sync_status)));
                    $responses[] = new XMLElement('response', $resultset);
                    $first_status = 404;
                } else {
                    if ($object->sync_status == 201 && $first_status == 404) {
                        // ... Delete ... Create ... is indicated as a create, but don't forget we started with a delete
                        array_pop($responses);
                        $dav_resource = new DAVResource($object);
Esempio n. 18
0
if ($target_collection->Privileges() != privilege_to_bits('DAV::all')) {
    $where .= " AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL) ";
}
if (isset($c->hide_TODO) && $c->hide_TODO && !$target_collection->HavePrivilegeTo('DAV::write-content')) {
    $where .= " AND caldav_data.caldav_type NOT IN ('VTODO') ";
}
if (isset($c->hide_older_than) && intval($c->hide_older_than > 0)) {
    $where .= " AND calendar_item.dtstart > (now() - interval '" . intval($c->hide_older_than) . " days') ";
}
$sql = 'SELECT caldav_data.*,calendar_item.*  FROM collection INNER JOIN caldav_data USING(collection_id) INNER JOIN calendar_item USING(dav_id) ' . $where;
if (isset($c->strict_result_ordering) && $c->strict_result_ordering) {
    $sql .= " ORDER BY caldav_data.dav_id";
}
$qry = new AwlQuery($sql, $params);
if ($qry->Exec("calquery", __LINE__, __FILE__) && $qry->rows() > 0) {
    while ($calendar_object = $qry->Fetch()) {
        if (!$need_post_filter || apply_filter($qry_filters, $calendar_object)) {
            if ($bound_from != $target_collection->dav_name()) {
                $calendar_object->dav_name = str_replace($bound_from, $target_collection->dav_name(), $calendar_object->dav_name);
            }
            if ($need_expansion) {
                $vResource = new vComponent($calendar_object->caldav_data);
                $expanded = expand_event_instances($vResource, $expand_range_start, $expand_range_end);
                if ($expanded->ComponentCount() == 0) {
                    continue;
                }
                $calendar_object->caldav_data = $expanded->Render();
            }
            $responses[] = calendar_to_xml($properties, $calendar_object);
        }
    }
Esempio n. 19
0
/**
* sync LDAP against the DB
*/
function sync_LDAP()
{
    global $c;
    $ldapDriver = getStaticLdap();
    if ($ldapDriver->valid) {
        $mapping = $c->authenticate_hook['config']['mapping_field'];
        $attributes = array_values($mapping);
        $ldap_users_tmp = $ldapDriver->getAllUsers($attributes);
        if (sizeof($ldap_users_tmp) == 0) {
            return;
        }
        foreach ($ldap_users_tmp as $key => $ldap_user) {
            $ldap_users_info[$ldap_user[$mapping["username"]]] = $ldap_user;
            unset($ldap_users_tmp[$key]);
        }
        $qry = new AwlQuery("SELECT username, user_no, modified as updated FROM dav_principal where type_id=1");
        $qry->Exec('sync_LDAP', __LINE__, __FILE__);
        while ($db_user = $qry->Fetch()) {
            $db_users[] = $db_user->username;
            $db_users_info[$db_user->username] = array('user_no' => $db_user->user_no, 'updated' => $db_user->updated);
        }
        $ldap_users = array_keys($ldap_users_info);
        // users only in ldap
        $users_to_create = array_diff($ldap_users, $db_users);
        // users only in db
        $users_to_deactivate = array_diff($db_users, $ldap_users);
        // users present in ldap and in the db
        $users_to_update = array_intersect($db_users, $ldap_users);
        // creation of all users;
        if (sizeof($users_to_create)) {
            $c->messages[] = sprintf(i18n('- creating record for users :  %s'), join(', ', $users_to_create));
            foreach ($users_to_create as $username) {
                $user = (object) array('user_no' => 0, 'username' => $username);
                $valid = $ldap_users_info[$username];
                $ldap_timestamp = $valid[$mapping["updated"]];
                /**
                 * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S
                 */
                foreach ($c->authenticate_hook['config']['format_updated'] as $k => $v) {
                    ${$k} = substr($ldap_timestamp, $v[0], $v[1]);
                }
                $ldap_timestamp = "{$Y}" . "{$m}" . "{$d}" . "{$H}" . "{$M}" . "{$S}";
                $valid[$mapping["updated"]] = "{$Y}-{$m}-{$d} {$H}:{$M}:{$S}";
                sync_user_from_LDAP($user, $mapping, $valid);
            }
        }
        // deactivating all users
        $params = array();
        $i = 0;
        foreach ($users_to_deactivate as $v) {
            if (isset($c->do_not_sync_from_ldap) && isset($c->do_not_sync_from_ldap[$v])) {
                continue;
            }
            $params[':u' . $i++] = strtolower($v);
        }
        if (count($params) > 0) {
            $c->messages[] = sprintf(i18n('- deactivating users : %s'), join(', ', $users_to_deactivate));
            $qry = new AwlQuery('UPDATE usr SET active = FALSE WHERE lower(username) IN (' . implode(',', array_keys($params)) . ')', $params);
            $qry->Exec('sync_LDAP', __LINE__, __FILE__);
        }
        // updating all users
        if (sizeof($users_to_update)) {
            foreach ($users_to_update as $key => $username) {
                $valid = $ldap_users_info[$username];
                $ldap_timestamp = $valid[$mapping["updated"]];
                $valid["user_no"] = $db_users_info[$username]["user_no"];
                $mapping["user_no"] = "user_no";
                /**
                 * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S
                 */
                foreach ($c->authenticate_hook['config']['format_updated'] as $k => $v) {
                    ${$k} = substr($ldap_timestamp, $v[0], $v[1]);
                }
                $ldap_timestamp = "{$Y}" . "{$m}" . "{$d}" . "{$H}" . "{$M}" . "{$S}";
                $valid[$mapping["updated"]] = "{$Y}-{$m}-{$d} {$H}:{$M}:{$S}";
                $db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '', ' ' => '', '-' => '')), 0, 14);
                if ($ldap_timestamp > $db_timestamp) {
                    sync_user_from_LDAP($usr, $mapping, $valid);
                } else {
                    unset($users_to_update[$key]);
                    $users_nothing_done[] = $username;
                }
            }
            if (sizeof($users_to_update)) {
                $c->messages[] = sprintf(i18n('- updating user records : %s'), join(', ', $users_to_update));
            }
            if (sizeof($users_nothing_done)) {
                $c->messages[] = sprintf(i18n('- nothing done on : %s'), join(', ', $users_nothing_done));
            }
        }
        $admins = 0;
        $qry = new AwlQuery("select count(*) as admins from usr join role_member using ( user_no ) join roles using (role_no) where usr.active = true and role_name='Admin'");
        $qry->Exec('sync_LDAP', __LINE__, __FILE__);
        while ($db_user = $qry->Fetch()) {
            $admins = $db_user->admins;
        }
        if ($admins == 0) {
            $c->messages[] = sprintf(i18n('Warning: there are no active admin users, you should fix this before logging out.'));
        }
    }
}
Esempio n. 20
0
/**
 * * Log the action
 * * @param string $action_type INSERT / UPDATE or DELETE
 * * @param string $uid The UID of the modified item
 * * @param integer $user_no The user owning the containing collection.
 * * @param integer $collection_id The ID of the containing collection.
 * * @param string $dav_name The DAV path of the item, relative to the DAViCal base path
 * */
function log_caldav_action($action_type, $uid, $user_no, $collection_id, $dav_name)
{
    global $c;
    $t = new xmpp();
    $t->tls = 'none';
    $t->idle = false;
    if (1 == $c->dbg["ALL"] || 1 == $c->dbg["push"]) {
        $t->debug = true;
    } else {
        $t->debug = false;
    }
    // for now use a flat node tree layout
    $t->pubsubLayout = 'flat';
    // get the principal_id for this collection, that's what the client will be looking for
    $qry = new AwlQuery('SELECT principal_id FROM principal JOIN collection USING (user_no) WHERE collection_id= :collection_id', array(':collection_id' => $collection_id));
    $qry->Exec('pubsub');
    $row = $qry->Fetch();
    $t->open($c->notifications_server['jid'], $c->notifications_server['password']);
    if (isset($c->notifications_server['debug_jid'])) {
        $t->sendMessage($c->notifications_server['debug_jid'], "ACTION: {$action_type}\nUSER: {$user_no}\nDAV NAME: {$dav_name}\nPRINCIPAL ID: " . $row->principal_id);
    }
    $t->pubsubCreate('', 'set', '/davical-' . $row->principal_id, '<x xmlns="jabber:x:data" type="submit"><field var="FORM_TYPE" type="hidden"><value>http://jabber.org/protocol/pubsub#node_config</value></field><field var="pubsub#access_model"><value>open</value></field><field var=\'pubsub#type\'>plist-apple<value></value></field></x>');
    $t->pubsubPublish('', 'set', '/davical-' . $row->principal_id, '<item xmlns="plist-apple" id="' . $uid . ' " ><plistfrag xmlns="plist-apple"><key>davical</key><string>' . $uid . '</string></plistfrag></item>', $uid);
    $t->close();
}
Esempio n. 21
0
function get_freebusy($path_match, $range_start, $range_end, $bin_privs = null)
{
    global $request, $c;
    $debugging = false;
    //    if ( $debugging ) {
    //        printf( "Path: %s\n", $path_match );
    //        print_r( $range_start );
    //        print_r( $range_end );
    //    }
    if (!isset($bin_privs)) {
        $bin_privs = $request->Privileges();
    }
    if (!isset($range_start) || !isset($range_end)) {
        $request->DoResponse(400, 'All valid freebusy requests MUST contain a time-range filter');
    }
    $params = array(':path_match' => $path_match, ':start' => $range_start->UTC(), ':end' => $range_end->UTC());
    $where = ' WHERE caldav_data.dav_name ~ :path_match ';
    $where .= 'AND rrule_event_overlaps( dtstart, dtend, rrule, :start, :end) ';
    $where .= "AND caldav_data.caldav_type IN ( 'VEVENT', 'VTODO' ) ";
    $where .= "AND (calendar_item.transp != 'TRANSPARENT' OR calendar_item.transp IS NULL) ";
    $where .= "AND (calendar_item.status != 'CANCELLED' OR calendar_item.status IS NULL) ";
    $where .= "AND collection.is_calendar AND collection.schedule_transp = 'opaque' ";
    if ($bin_privs != privilege_to_bits('all')) {
        $where .= "AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL) ";
    }
    $fbtimes = array();
    $sql = 'SELECT caldav_data.caldav_data, calendar_item.rrule, calendar_item.transp, calendar_item.status, ';
    $sql .= "to_char(calendar_item.dtstart at time zone 'GMT'," . AWLDatabase::SqlUTCFormat . ') AS start, ';
    $sql .= "to_char(calendar_item.dtend at time zone 'GMT'," . AWLDatabase::SqlUTCFormat . ') AS finish, ';
    $sql .= "calendar_item.class, calendar_item.dav_id ";
    $sql .= 'FROM caldav_data INNER JOIN calendar_item USING(dav_id,user_no,dav_name,collection_id) ';
    $sql .= 'INNER JOIN collection USING(collection_id)';
    $sql .= $where;
    if (isset($c->strict_result_ordering) && $c->strict_result_ordering) {
        $sql .= ' ORDER BY dav_id';
    }
    $qry = new AwlQuery($sql, $params);
    if ($qry->Exec("REPORT", __LINE__, __FILE__) && $qry->rows() > 0) {
        while ($calendar_object = $qry->Fetch()) {
            $extra = '';
            if ($calendar_object->status == 'TENTATIVE') {
                $extra = ';BUSY-TENTATIVE';
            } else {
                if (isset($c->_workaround_client_freebusy_bug) && $c->_workaround_client_freebusy_bug) {
                    $extra = ';BUSY';
                }
            }
            //      if ( $debugging ) {
            //        $extra = ';'.$calendar_object->dav_id;
            //      }
            //      dbg_error_log( "REPORT", " FreeBusy: Not transparent, tentative or cancelled: %s, %s, %s", $calendar_object->start, $calendar_object->finish, $calendar_object->class );
            $ics = new vComponent($calendar_object->caldav_data);
            $expanded = expand_event_instances($ics, $range_start, $range_end);
            $expansion = $expanded->GetComponents(array('VEVENT' => true, 'VTODO' => true, 'VJOURNAL' => true));
            //      if ( $debugging ) echo "===================   $calendar_object->dav_id   ========================\n";
            $dtstart_type = 'DTSTART';
            foreach ($expansion as $k => $v) {
                //        if ( $debugging ) print $k."\n".$v->Render();
                $start_date = $v->GetProperty($dtstart_type);
                if (!isset($start_date) && $v->GetType() != 'VTODO') {
                    $dtstart_type = 'DUE';
                    $start_date = $v->GetProperty($dtstart_type);
                }
                $start_date = new RepeatRuleDateTime($start_date);
                $duration = $v->GetProperty('DURATION');
                $duration = !isset($duration) ? 'P1D' : $duration->Value();
                $end_date = clone $start_date;
                $end_date->modify($duration);
                if ($end_date == $start_date || $end_date < $range_start || $start_date > $range_end) {
                    //            if ( $debugging )
                    //              echo "-----------------------------------------------------\n";
                    continue;
                }
                //        if ( $debugging )
                //            echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
                $thisfb = $start_date->UTC() . '/' . $end_date->UTC() . $extra;
                array_push($fbtimes, $thisfb);
            }
        }
    }
    $freebusy = new vComponent();
    $freebusy->setType('VFREEBUSY');
    $freebusy->AddProperty('DTSTAMP', date('Ymd\\THis\\Z'));
    $freebusy->AddProperty('DTSTART', $range_start->UTC());
    $freebusy->AddProperty('DTEND', $range_end->UTC());
    sort($fbtimes);
    foreach ($fbtimes as $k => $v) {
        $text = explode(';', $v, 2);
        $freebusy->AddProperty('FREEBUSY', $text[0], isset($text[1]) ? array('FBTYPE' => $text[1]) : null);
    }
    return $freebusy;
}
Esempio n. 22
0
/**
* sync LDAP against the DB
*/
function sync_LDAP()
{
    global $c;
    $ldapDriver = getStaticLdap();
    if (!$ldapDriver->valid) {
        return;
    }
    $mapping = $c->authenticate_hook['config']['mapping_field'];
    $attributes = array_values_mapping($mapping);
    $ldap_users_tmp = $ldapDriver->getAllUsers($attributes);
    if (sizeof($ldap_users_tmp) == 0) {
        return;
    }
    foreach ($ldap_users_tmp as $key => $ldap_user) {
        $ldap_users_info[$ldap_user[$mapping['username']]] = $ldap_user;
        unset($ldap_users_tmp[$key]);
    }
    $qry = new AwlQuery("SELECT username, user_no, modified as updated FROM dav_principal where type_id=1");
    $qry->Exec('sync_LDAP', __LINE__, __FILE__);
    while ($db_user = $qry->Fetch()) {
        $db_users[] = $db_user->username;
        $db_users_info[$db_user->username] = array('user_no' => $db_user->user_no, 'updated' => $db_user->updated);
    }
    // all users from ldap
    $ldap_users = array_keys($ldap_users_info);
    // users only in ldap
    $users_to_create = array_diff($ldap_users, $db_users);
    // users only in db
    $users_to_deactivate = array_diff($db_users, $ldap_users);
    // users present in ldap and in the db
    $users_to_update = array_intersect($db_users, $ldap_users);
    // creation of all users;
    if (sizeof($users_to_create)) {
        $c->messages[] = sprintf(i18n('- creating record for users :  %s'), join(', ', $users_to_create));
        foreach ($users_to_create as $username) {
            $principal = new Principal('username', $username);
            $valid = $ldap_users_info[$username];
            $ldap_timestamp = $valid[$mapping['modified']];
            if (!empty($c->authenticate_hook['config']['format_updated'])) {
                /**
                 * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S
                 */
                foreach ($c->authenticate_hook['config']['format_updated'] as $k => $v) {
                    ${$k} = substr($ldap_timestamp, $v[0], $v[1]);
                }
                $ldap_timestamp = $Y . $m . $d . $H . $M . $S;
            } else {
                if (preg_match('{^(\\d{8})(\\d{6})(Z)?$', $ldap_timestamp, $matches)) {
                    $ldap_timestamp = $matches[1] . 'T' . $matches[2] . $matches[3];
                } else {
                    if (empty($ldap_timestamp)) {
                        $ldap_timestamp = date('c');
                    }
                }
            }
            $valid[$mapping['modified']] = $ldap_timestamp;
            sync_user_from_LDAP($principal, $mapping, $valid);
        }
    }
    // deactivating all users
    $params = array();
    $i = 0;
    $paramstring = '';
    foreach ($users_to_deactivate as $v) {
        if (isset($c->do_not_sync_from_ldap) && isset($c->do_not_sync_from_ldap[$v])) {
            continue;
        }
        if ($i > 0) {
            $paramstring .= ',';
        }
        $paramstring .= ':u' . $i . '::text';
        $params[':u' . $i++] = strtolower($v);
    }
    if (count($params) > 0) {
        $c->messages[] = sprintf(i18n('- deactivating users : %s'), join(', ', $users_to_deactivate));
        $qry = new AwlQuery('UPDATE usr SET active = FALSE WHERE lower(username) IN (' . $paramstring . ')', $params);
        $qry->Exec('sync_LDAP', __LINE__, __FILE__);
        Principal::cacheFlush('lower(username) IN (' . $paramstring . ')', $params);
    }
    // updating all users
    if (sizeof($users_to_update)) {
        foreach ($users_to_update as $key => $username) {
            $principal = new Principal('username', $username);
            $valid = $ldap_users_info[$username];
            $ldap_timestamp = $valid[$mapping['modified']];
            $valid['user_no'] = $db_users_info[$username]['user_no'];
            $mapping['user_no'] = 'user_no';
            /**
             * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S
             */
            foreach ($c->authenticate_hook['config']['format_updated'] as $k => $v) {
                ${$k} = substr($ldap_timestamp, $v[0], $v[1]);
            }
            $ldap_timestamp = $Y . $m . $d . $H . $M . $S;
            $valid[$mapping['modified']] = "{$Y}-{$m}-{$d} {$H}:{$M}:{$S}";
            $db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '', ' ' => '', '-' => '')), 0, 14);
            if ($ldap_timestamp > $db_timestamp) {
                sync_user_from_LDAP($principal, $mapping, $valid);
            } else {
                unset($users_to_update[$key]);
                $users_nothing_done[] = $username;
            }
        }
        if (sizeof($users_to_update)) {
            $c->messages[] = sprintf(i18n('- updating user records : %s'), join(', ', $users_to_update));
        }
        if (sizeof($users_nothing_done)) {
            $c->messages[] = sprintf(i18n('- nothing done on : %s'), join(', ', $users_nothing_done));
        }
    }
    $admins = 0;
    $qry = new AwlQuery("SELECT count(*) AS admins FROM usr JOIN role_member USING ( user_no ) JOIN roles USING (role_no) WHERE usr.active=TRUE AND role_name='Admin'");
    $qry->Exec('sync_LDAP', __LINE__, __FILE__);
    while ($db_user = $qry->Fetch()) {
        $admins = $db_user->admins;
    }
    if ($admins == 0) {
        $c->messages[] = sprintf(i18n('Warning: there are no active admin users! You should fix this before logging out.  Consider using the $c->do_not_sync_from_ldap configuration setting.'));
    }
}
Esempio n. 23
0
function ticket_row_editor()
{
    global $c, $id, $editor, $can_write_principal, $privilege_names;
    $ticketrow = new Editor("Tickets", "access_ticket");
    $ticketrow->SetSubmitName('ticketrow');
    if ($can_write_principal && $ticketrow->IsSubmit()) {
        $username = $editor->Value('username');
        $ugly_path = $_POST['target'];
        if ($ugly_path == '/' . $username || $ugly_path == '/' . $username . '/') {
            $target_collection = $id;
        } else {
            $username_len = strlen($username) + 2;
            $sql = "SELECT collection_id FROM collection WHERE dav_name = :exact_name";
            $sql .= " AND substring(dav_name FROM 1 FOR {$username_len}) = '/{$username}/'";
            $params = array(':exact_name' => $ugly_path);
            if (!preg_match('#/$#', $ugly_path)) {
                $sql .= " OR dav_name = :truncated_name OR dav_name = :trailing_slash_name";
                $params[':truncated_name'] = preg_replace('#[^/]*$#', '', $ugly_path);
                $params[':trailing_slash_name'] = $ugly_path . "/";
            }
            $sql .= " ORDER BY LENGTH(dav_name) DESC LIMIT 1";
            $qry = new AwlQuery($sql, $params);
            if ($qry->Exec() && $qry->rows() > 0) {
                $row = $qry->Fetch();
                $target_collection = $row->collection_id;
            } else {
                $c->messages[] = translate('Can only add tickets for existing collection paths which you own');
                return $ticketrow;
            }
        }
        $_POST['dav_owner_id'] = $id;
        $_POST['target_collection_id'] = $target_collection;
        $ticket_id = check_by_regex($_POST['ticket_id'], '/[A-Za-z0-9]+/');
        $ticketrow->SetWhere('dav_owner_id=' . $id . ' AND ticket_id=' . AwlQuery::quote($ticket_id));
        if (isset($_POST['ticket_privileges'])) {
            $privilege_bitpos = array_flip($privilege_names);
            $priv_names = array_keys($_POST['ticket_privileges']);
            $privs_dec = privilege_to_bits($priv_names);
            $_POST['privileges'] = sprintf('%024s', decbin($privs_dec));
            $ticketrow->Assign('privileges', $privs_dec);
        }
        $c->messages[] = translate('Creating new ticket granting privileges to this Principal');
        $ticketrow->Write();
    }
    return $ticketrow;
}
Esempio n. 24
0
function export_iCalendar(DAVResource $dav_resource)
{
    global $session, $c, $request;
    if (!$dav_resource->IsCalendar() && !(isset($c->get_includes_subcollections) && $c->get_includes_subcollections)) {
        /** RFC2616 says we must send an Allow header if we send a 405 */
        header("Allow: PROPFIND,PROPPATCH,OPTIONS,MKCOL,REPORT,DELETE");
        $request->DoResponse(405, translate("GET requests on collections are only supported for calendars."));
    }
    /**
     * The CalDAV specification does not define GET on a collection, but typically this is
     * used as a .ics download for the whole collection, which is what we do also.
     */
    if (isset($c->get_includes_subcollections) && $c->get_includes_subcollections) {
        $where = 'caldav_data.collection_id IN ';
        $where .= '(SELECT bound_source_id FROM dav_binding WHERE dav_binding.dav_name ~ :path_match ';
        $where .= 'UNION ';
        $where .= 'SELECT collection_id FROM collection WHERE collection.dav_name ~ :path_match) ';
        $params = array(':path_match' => '^' . $dav_resource->dav_name());
        $distinct = 'DISTINCT ON (calendar_item.uid) ';
    } else {
        $where = 'caldav_data.collection_id = :collection_id ';
        $params = array(':collection_id' => $dav_resource->resource_id());
        $distinct = '';
    }
    $sql = 'SELECT ' . $distinct . ' caldav_data, class, caldav_type, calendar_item.user_no, logged_user ';
    $sql .= 'FROM collection INNER JOIN caldav_data USING(collection_id) ';
    $sql .= 'INNER JOIN calendar_item USING ( dav_id ) WHERE ' . $where;
    if (isset($c->strict_result_ordering) && $c->strict_result_ordering) {
        $sql .= ' ORDER BY calendar_item.uid, calendar_item.dav_id';
    }
    $qry = new AwlQuery($sql, $params);
    if (!$qry->Exec("GET", __LINE__, __FILE__)) {
        $request->DoResponse(500, translate("Database Error"));
    }
    /**
     * Here we are constructing a whole calendar response for this collection, including
     * the timezones that are referred to by the events we have selected.
     */
    $vcal = new iCalComponent();
    $vcal->VCalendar();
    $displayname = $dav_resource->GetProperty('displayname');
    if (isset($displayname)) {
        $vcal->AddProperty("X-WR-CALNAME", $displayname);
    }
    if (!empty($c->auto_refresh_duration)) {
        $vcal->AddProperty("X-APPLE-AUTO-REFRESH-INTERVAL", $c->auto_refresh_duration);
        $vcal->AddProperty("AUTO-REFRESH", $c->auto_refresh_duration);
        $vcal->AddProperty("X-PUBLISHED-TTL", $c->auto_refresh_duration);
    }
    $need_zones = array();
    $timezones = array();
    while ($event = $qry->Fetch()) {
        $ical = new iCalComponent($event->caldav_data);
        /** Save the timezone component(s) into a minimal set for inclusion later */
        $event_zones = $ical->GetComponents('VTIMEZONE', true);
        foreach ($event_zones as $k => $tz) {
            $tzid = $tz->GetPValue('TZID');
            if (!isset($tzid)) {
                continue;
            }
            if ($tzid != '' && !isset($timezones[$tzid])) {
                $timezones[$tzid] = $tz;
            }
        }
        /** Work out which ones are actually used here */
        $comps = $ical->GetComponents('VTIMEZONE', false);
        foreach ($comps as $k => $comp) {
            $tzid = $comp->GetPParamValue('DTSTART', 'TZID');
            if (isset($tzid) && !isset($need_zones[$tzid])) {
                $need_zones[$tzid] = 1;
            }
            $tzid = $comp->GetPParamValue('DUE', 'TZID');
            if (isset($tzid) && !isset($need_zones[$tzid])) {
                $need_zones[$tzid] = 1;
            }
            $tzid = $comp->GetPParamValue('DTEND', 'TZID');
            if (isset($tzid) && !isset($need_zones[$tzid])) {
                $need_zones[$tzid] = 1;
            }
            if ($dav_resource->HavePrivilegeTo('all', false) || $session->user_no == $event->user_no || $session->user_no == $event->logged_user || isset($session->email) && $c->allow_get_email_visibility && $comp->IsAttendee($session->email)) {
                /**
                 * These people get to see all of the event, and they should always
                 * get any alarms as well.
                 */
                $vcal->AddComponent($comp);
                continue;
            }
            /** No visibility even of the existence of these events if they aren't admin/owner/attendee */
            if ($event->class == 'PRIVATE') {
                continue;
            }
            if (!$dav_resource->HavePrivilegeTo('DAV::read') || $event->class == 'CONFIDENTIAL') {
                $vcal->AddComponent(obfuscated_event($comp));
            } elseif (isset($c->hide_alarm) && $c->hide_alarm) {
                // Otherwise we hide the alarms (if configured to)
                $comp->ClearComponents('VALARM');
                $vcal->AddComponent($comp);
            } else {
                $vcal->AddComponent($comp);
            }
        }
    }
    /** Put the timezones on there that we need */
    foreach ($need_zones as $tzid => $v) {
        if (isset($timezones[$tzid])) {
            $vcal->AddComponent($timezones[$tzid]);
        }
    }
    return $vcal->Render();
}
Esempio n. 25
0
    /**
     * Writes the data to a member in the collection and returns the segment_name of the resource in our internal namespace. 
     * @param $data iCalendar The resource to be written.
     * @param $create_resource boolean True if this is a new resource.
     * @param $segment_name The name of the resource within the collection.
     */
    function WriteCalendarMember($data, $create_resource, $segment_name = null)
    {
        if (!$this->IsSchedulingCollection() && !$this->IsCalendar()) {
            return false;
        }
        // function write_resource( $user_no, $path, $caldav_data, $collection_id, $author, $etag, $ic, $put_action_type, $caldav_context, $log_action=true, $weak_etag=null ) {
        global $tz_regex;
        $resources = $ic->GetComponents('VTIMEZONE', false);
        // Not matching VTIMEZONE
        if (!isset($resources[0])) {
            $resource_type = 'Unknown';
            /** @TODO: Handle writing non-calendar resources, like address book entries or random file data */
            rollback_on_error($caldav_context, $user_no, $path, translate('No calendar content'), 412);
            return false;
        } else {
            $first = $resources[0];
            $resource_type = $first->GetType();
        }
        $qry = new AwlQuery();
        $qry->Begin();
        $params = array(':dav_name' => $path, ':user_no' => $user_no, ':etag' => $etag, ':dav_data' => $caldav_data, ':caldav_type' => $resource_type, ':session_user' => $author, ':weak_etag' => $weak_etag);
        if ($put_action_type == 'INSERT') {
            create_scheduling_requests($vcal);
            $sql = 'INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified, collection_id, weak_etag )
            VALUES( :user_no, :dav_name, :etag, :dav_data, :caldav_type, :session_user, current_timestamp, current_timestamp, :collection_id, :weak_etag )';
            $params[':collection_id'] = $collection_id;
        } else {
            update_scheduling_requests($vcal);
            $sql = 'UPDATE caldav_data SET caldav_data=:dav_data, dav_etag=:etag, caldav_type=:caldav_type, logged_user=:session_user,
            modified=current_timestamp, weak_etag=:weak_etag WHERE user_no=:user_no AND dav_name=:dav_name';
        }
        if (!$qry->QDo($sql, $params)) {
            rollback_on_error($caldav_context, $user_no, $path);
            return false;
        }
        $qry->QDo('SELECT dav_id FROM caldav_data WHERE dav_name = :dav_name ', array(':dav_name' => $path));
        if ($qry->rows() == 1 && ($row = $qry->Fetch())) {
            $dav_id = $row->dav_id;
        }
        $calitem_params = array(':dav_name' => $path, ':user_no' => $user_no, ':etag' => $etag);
        $dtstart = $first->GetPValue('DTSTART');
        $calitem_params[':dtstart'] = $dtstart;
        if ((!isset($dtstart) || $dtstart == '') && $first->GetPValue('DUE') != '') {
            $dtstart = $first->GetPValue('DUE');
        }
        $dtend = $first->GetPValue('DTEND');
        if (isset($dtend) && $dtend != '') {
            dbg_error_log('PUT', ' DTEND: "%s", DTSTART: "%s", DURATION: "%s"', $dtend, $dtstart, $first->GetPValue('DURATION'));
            $calitem_params[':dtend'] = $dtend;
            $dtend = ':dtend';
        } else {
            $dtend = 'NULL';
            if ($first->GetPValue('DURATION') != '' and $dtstart != '') {
                $duration = preg_replace('#[PT]#', ' ', $first->GetPValue('DURATION'));
                $dtend = '(:dtstart::timestamp with time zone + :duration::interval)';
                $calitem_params[':duration'] = $duration;
            } elseif ($first->GetType() == 'VEVENT') {
                /**
                 * From RFC2445 4.6.1:
                 * For cases where a "VEVENT" calendar component specifies a "DTSTART"
                 * property with a DATE data type but no "DTEND" property, the events
                 * non-inclusive end is the end of the calendar date specified by the
                 * "DTSTART" property. For cases where a "VEVENT" calendar component specifies
                 * a "DTSTART" property with a DATE-TIME data type but no "DTEND" property,
                 * the event ends on the same calendar date and time of day specified by the
                 * "DTSTART" property.
                 *
                 * So we're looking for 'VALUE=DATE', to identify the duration, effectively.
                 *
                 */
                $value_type = $first->GetPParamValue('DTSTART', 'VALUE');
                dbg_error_log('PUT', 'DTSTART without DTEND. DTSTART value type is %s', $value_type);
                if (isset($value_type) && $value_type == 'DATE') {
                    $dtend = '(:dtstart::timestamp with time zone::date + \'1 day\'::interval)';
                } else {
                    $dtend = ':dtstart';
                }
            }
        }
        $last_modified = $first->GetPValue('LAST-MODIFIED');
        if (!isset($last_modified) || $last_modified == '') {
            $last_modified = gmdate('Ymd\\THis\\Z');
        }
        $calitem_params[':modified'] = $last_modified;
        $dtstamp = $first->GetPValue('DTSTAMP');
        if (!isset($dtstamp) || $dtstamp == '') {
            $dtstamp = $last_modified;
        }
        $calitem_params[':dtstamp'] = $dtstamp;
        $class = $first->GetPValue('CLASS');
        /* Check and see if we should over ride the class. */
        /** @TODO: is there some way we can move this out of this function? Or at least get rid of the need for the SQL query here. */
        if (public_events_only($user_no, $path)) {
            $class = 'PUBLIC';
        }
        /*
         * It seems that some calendar clients don't set a class...
         * RFC2445, 4.8.1.3:
         * Default is PUBLIC
         */
        if (!isset($class) || $class == '') {
            $class = 'PUBLIC';
        }
        $calitem_params[':class'] = $class;
        /** Calculate what timezone to set, first, if possible */
        $last_tz_locn = 'Turkmenikikamukau';
        // I really hope this location doesn't exist!
        $tzid = $first->GetPParamValue('DTSTART', 'TZID');
        if (!isset($tzid) || $tzid == '') {
            $tzid = $first->GetPParamValue('DUE', 'TZID');
        }
        $timezones = $ic->GetComponents('VTIMEZONE');
        foreach ($timezones as $k => $tz) {
            if ($tz->GetPValue('TZID') != $tzid) {
                /**
                 * We'll pretend they didn't forget to give us a TZID and that they
                 * really hope the server is running in the timezone they supplied... but be noisy about it.
                 */
                dbg_error_log('ERROR', ' Event includes TZID[%s] but uses TZID[%s]!', $tz->GetPValue('TZID'), $tzid);
                $tzid = $tz->GetPValue('TZID');
            }
            // This is the one
            $tz_locn = $tz->GetPValue('X-LIC-LOCATION');
            if (!isset($tz_locn)) {
                if (preg_match('#([^/]+/[^/]+)$#', $tzid, $matches)) {
                    $tz_locn = $matches[1];
                } else {
                    if (isset($tzid) && $tzid != '') {
                        dbg_error_log('ERROR', ' Couldn\'t guess Olsen TZ from TZID[%s].  This may end in tears...', $tzid);
                    }
                }
            } else {
                if (!preg_match($tz_regex, $tz_locn)) {
                    if (preg_match('#([^/]+/[^/]+)$#', $tzid, $matches)) {
                        $tz_locn = $matches[1];
                    }
                }
            }
            dbg_error_log('PUT', ' Using TZID[%s] and location of [%s]', $tzid, isset($tz_locn) ? $tz_locn : '');
            if (isset($tz_locn) && $tz_locn != $last_tz_locn && preg_match($tz_regex, $tz_locn)) {
                dbg_error_log('PUT', ' Setting timezone to %s', $tz_locn);
                if ($tz_locn != '') {
                    $qry->QDo('SET TIMEZONE TO \'' . $tz_locn . "'");
                }
                $last_tz_locn = $tz_locn;
            }
            $params = array(':tzid' => $tzid);
            $qry = new AwlQuery('SELECT tz_locn FROM time_zone WHERE tz_id = :tzid', $params);
            if ($qry->Exec('PUT', __LINE__, __FILE__) && $qry->rows() == 0) {
                $params[':tzlocn'] = $tz_locn;
                $params[':tzspec'] = isset($tz) ? $tz->Render() : null;
                $qry->QDo('INSERT INTO time_zone (tz_id, tz_locn, tz_spec) VALUES(:tzid,:tzlocn,:tzspec)', $params);
            }
            if (!isset($tz_locn) || $tz_locn == '') {
                $tz_locn = $tzid;
            }
        }
        $created = $first->GetPValue('CREATED');
        if ($created == '00001231T000000Z') {
            $created = '20001231T000000Z';
        }
        $calitem_params[':created'] = $created;
        $calitem_params[':tzid'] = $tzid;
        $calitem_params[':uid'] = $first->GetPValue('UID');
        $calitem_params[':summary'] = $first->GetPValue('SUMMARY');
        $calitem_params[':location'] = $first->GetPValue('LOCATION');
        $calitem_params[':transp'] = $first->GetPValue('TRANSP');
        $calitem_params[':description'] = $first->GetPValue('DESCRIPTION');
        $calitem_params[':rrule'] = $first->GetPValue('RRULE');
        $calitem_params[':url'] = $first->GetPValue('URL');
        $calitem_params[':priority'] = $first->GetPValue('PRIORITY');
        $calitem_params[':due'] = $first->GetPValue('DUE');
        $calitem_params[':percent_complete'] = $first->GetPValue('PERCENT-COMPLETE');
        $calitem_params[':status'] = $first->GetPValue('STATUS');
        if ($put_action_type == 'INSERT') {
            $sql = <<<EOSQL
INSERT INTO calendar_item (user_no, dav_name, dav_id, dav_etag, uid, dtstamp,
                dtstart, dtend, summary, location, class, transp,
                description, rrule, tz_id, last_modified, url, priority,
                created, due, percent_complete, status, collection_id )
   VALUES ( :user_no, :dav_name, currval('dav_id_seq'), :etag, :uid, :dtstamp,
                :dtstart, {$dtend}, :summary, :location, :class, :transp,
                :description, :rrule, :tzid, :modified, :url, :priority,
                :created, :due, :percent_complete, :status, {$collection_id} )
EOSQL;
            $sync_change = 201;
        } else {
            $sql = <<<EOSQL
UPDATE calendar_item SET dav_etag=:etag, uid=:uid, dtstamp=:dtstamp,
                dtstart=:dtstart, dtend={$dtend}, summary=:summary, location=:location, class=:class, transp=:transp,
                description=:description, rrule=:rrule, tz_id=:tzid, last_modified=:modified, url=:url, priority=:priority,
                created=:created, due=:due, percent_complete=:percent_complete, status=:status
       WHERE user_no=:user_no AND dav_name=:dav_name
EOSQL;
            $sync_change = 200;
        }
        write_alarms($dav_id, $first);
        write_attendees($dav_id, $first);
        if ($log_action && function_exists('log_caldav_action')) {
            log_caldav_action($put_action_type, $first->GetPValue('UID'), $user_no, $collection_id, $path);
        } else {
            if ($log_action) {
                dbg_error_log('PUT', 'No log_caldav_action( %s, %s, %s, %s, %s) can be called.', $put_action_type, $first->GetPValue('UID'), $user_no, $collection_id, $path);
            }
        }
        $qry = new AwlQuery($sql, $calitem_params);
        if (!$qry->Exec('PUT', __LINE__, __FILE__)) {
            rollback_on_error($caldav_context, $user_no, $path);
            return false;
        }
        $qry->QDo("SELECT write_sync_change( {$collection_id}, {$sync_change}, :dav_name)", array(':dav_name' => $path));
        $qry->Commit();
        dbg_error_log('PUT', 'User: %d, ETag: %s, Path: %s', $author, $etag, $path);
        return $segment_name;
    }
Esempio n. 26
0
 /**
  * Get the calendar_free_busy_set, as lazily as possible
  */
 function calendar_free_busy_set()
 {
     if (!isset($this->calendar_free_busy_set)) {
         /**
          * calendar-free-busy-set has been dropped from draft 5 of the scheduling extensions for CalDAV
          * in favour of
          */
         $this->calendar_free_busy_set = array();
         $qry = new AwlQuery('SELECT dav_name FROM collection WHERE user_no = :user_no AND is_calendar AND (schedule_transp = \'opaque\' OR schedule_transp IS NULL) ORDER BY user_no, collection_id', array(':user_no' => $this->user_no));
         if ($qry->Exec('principal', __LINE__, __FILE__)) {
             while ($calendar = $qry->Fetch()) {
                 $this->calendar_free_busy_set[] = ConstructURL($calendar->dav_name, true);
             }
         }
     }
     return $this->calendar_free_busy_set;
 }
Esempio n. 27
0
/**
* Get XML response for items in the collection
* If '/' is requested, a list of visible users is given, otherwise
* a list of calendars for the user which are parented by this path.
*/
function get_collection_contents($depth, $collection, $parent_path = null)
{
    global $c, $session, $request, $reply, $property_list;
    $bound_from = $collection->bound_from();
    $bound_to = $collection->dav_name();
    if (!isset($parent_path)) {
        $parent_path = $collection->dav_name();
    }
    dbg_error_log('PROPFIND', 'Getting collection contents: Depth %d, Path: %s, Bound from: %s, Bound to: %s', $depth, $collection->dav_name(), $bound_from, $bound_to);
    $date_format = AwlDatabase::HttpDateFormat;
    $responses = array();
    if (!$collection->IsCalendar() && !$collection->IsAddressbook()) {
        /**
         * Calendar/Addressbook collections may not contain collections, so we are only looking in the other ones
         */
        $params = array(':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth);
        if ($bound_from == '/') {
            $sql = "SELECT usr.*, '/' || username || '/' AS dav_name, md5(username || updated::text) AS dav_etag, ";
            $sql .= "to_char(joined at time zone 'GMT',{$date_format}) AS created, ";
            $sql .= "to_char(updated at time zone 'GMT',{$date_format}) AS modified, ";
            $sql .= 'FALSE AS is_calendar, TRUE AS is_principal, FALSE AS is_addressbook, \'principal\' AS type, ';
            $sql .= 'principal_id AS collection_id, ';
            $sql .= 'principal.* ';
            $sql .= 'FROM usr JOIN principal USING (user_no) ';
            $sql .= "WHERE (pprivs(:session_principal::int8,principal.principal_id,:scan_depth::int) & 1::BIT(24))::INT4::BOOLEAN ";
            $sql .= 'ORDER BY usr.user_no';
        } else {
            $qry = new AwlQuery('SELECT * FROM dav_binding WHERE dav_binding.parent_container = :this_dav_name ORDER BY bind_id', array(':this_dav_name' => $bound_from));
            if ($qry->Exec('PROPFIND', __LINE__, __FILE__) && $qry->rows() > 0) {
                while ($binding = $qry->Fetch()) {
                    $resource = new DAVResource($binding->dav_name);
                    if ($resource->IsExternal()) {
                        require_once "external-fetch.php";
                        update_external($resource);
                    }
                    if ($resource->HavePrivilegeTo('DAV::read', false)) {
                        $resource->set_bind_location(str_replace($bound_from, $bound_to, $binding->dav_name));
                        $responses[] = $resource->RenderAsXML($property_list, $reply);
                        if ($depth > 0) {
                            $responses = array_merge($responses, get_collection_contents($depth - 1, $resource, $binding->dav_name));
                        }
                    }
                }
            }
            $sql = 'SELECT principal.*, collection.*, \'collection\' AS type ';
            $sql .= 'FROM collection LEFT JOIN principal USING (user_no) ';
            $sql .= 'WHERE parent_container = :this_dav_name ';
            $sql .= ' ORDER BY collection_id';
            $params[':this_dav_name'] = $bound_from;
            unset($params[':session_principal']);
            unset($params[':scan_depth']);
        }
        $qry = new AwlQuery($sql, $params);
        if ($qry->Exec('PROPFIND', __LINE__, __FILE__) && $qry->rows() > 0) {
            while ($subcollection = $qry->Fetch()) {
                $resource = new DAVResource($subcollection);
                if (!$resource->HavePrivilegeTo('DAV::read')) {
                    continue;
                }
                $resource->set_bind_location(str_replace($bound_from, $bound_to, $subcollection->dav_name));
                $responses[] = $resource->RenderAsXML($property_list, $reply);
                if ($depth > 0) {
                    $responses = array_merge($responses, get_collection_contents($depth - 1, $resource, str_replace($resource->parent_path(), $parent_path, $resource->dav_name())));
                }
            }
        }
        if ((!isset($c->disable_caldav_proxy) || $c->disable_caldav_proxy == false) && $collection->IsPrincipal()) {
            // Caldav Proxy: 5.1 par. 2: Add child resources calendar-proxy-(read|write)
            dbg_error_log('PROPFIND', 'Adding calendar-proxy-read and write. Path: %s', $bound_from);
            $response = add_proxy_response('read', $bound_from);
            if (isset($response)) {
                $responses[] = $response;
            }
            $response = add_proxy_response('write', $bound_from);
            if (isset($response)) {
                $responses[] = $response;
            }
        }
    }
    /**
     * freebusy permission is not allowed to see the items in a collection.  Must have at least read permission.
     */
    if ($collection->HavePrivilegeTo('DAV::read', false)) {
        dbg_error_log('PROPFIND', 'Getting collection items: Depth %d, Path: %s', $depth, $bound_from);
        $privacy_clause = ' ';
        $todo_clause = ' ';
        $time_limit_clause = ' ';
        if ($collection->IsCalendar()) {
            if (!$collection->HavePrivilegeTo('all', false)) {
                $privacy_clause = " AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL) ";
            }
            if (isset($c->hide_TODO) && ($c->hide_TODO === true || is_string($c->hide_TODO) && preg_match($c->hide_TODO, $_SERVER['HTTP_USER_AGENT'])) && !$collection->HavePrivilegeTo('all')) {
                $todo_clause = " AND caldav_data.caldav_type NOT IN ('VTODO') ";
            }
            if (isset($c->hide_older_than) && intval($c->hide_older_than > 0)) {
                $time_limit_clause = " AND (CASE WHEN caldav_data.caldav_type<>'VEVENT' OR calendar_item.dtstart IS NULL THEN true ELSE calendar_item.dtstart > (now() - interval '" . intval($c->hide_older_than) . " days') END) ";
            }
        }
        $sql = 'SELECT collection.*, principal.*, calendar_item.*, caldav_data.*, ';
        $sql .= "to_char(coalesce(calendar_item.created, caldav_data.created) at time zone 'GMT',{$date_format}) AS created, ";
        $sql .= "to_char(coalesce(calendar_item.last_modified, caldav_data.modified) at time zone 'GMT',{$date_format}) AS modified, ";
        $sql .= 'summary AS dav_displayname ';
        $sql .= 'FROM caldav_data LEFT JOIN calendar_item USING( dav_id, user_no, dav_name, collection_id) ';
        $sql .= 'LEFT JOIN collection USING(collection_id,user_no) LEFT JOIN principal USING(user_no) ';
        $sql .= 'WHERE collection.dav_name = :collection_dav_name ' . $time_limit_clause . ' ' . $todo_clause . ' ' . $privacy_clause;
        if (isset($c->strict_result_ordering) && $c->strict_result_ordering) {
            $sql .= " ORDER BY caldav_data.dav_id";
        }
        $qry = new AwlQuery($sql, array(':collection_dav_name' => $bound_from));
        if ($qry->Exec('PROPFIND', __LINE__, __FILE__) && $qry->rows() > 0) {
            while ($item = $qry->Fetch()) {
                if ($bound_from != $bound_to) {
                    $item->bound_from = $item->dav_name;
                    $item->dav_name = str_replace($bound_from, $bound_to, $item->dav_name);
                }
                $resource = new DAVResource($item);
                $responses[] = $resource->RenderAsXML($property_list, $reply, $parent_path);
            }
        }
    }
    return $responses;
}
Esempio n. 28
0
/**
* Actually write the resource to the database.  All checking of whether this is reasonable
* should be done before this is called.
* 
* @param DAVResource $resource The resource being written
* @param string $caldav_data The actual data to be written
* @param DAVResource $collection The collection containing the resource being written
* @param int $author The user_no who wants to put this resource on the server
* @param string $etag An etag unique for this event
* @param string $put_action_type INSERT or UPDATE depending on what we are to do
* @param boolean $caldav_context True, if we are responding via CalDAV, false for other ways of calling this
* @param string Either 'INSERT' or 'UPDATE': the type of action we are doing
* @param boolean $log_action Whether to log the fact that we are writing this into an action log (if configured)
* @param string $weak_etag An etag that is NOT modified on ATTENDEE changes for this event
* 
* @return boolean True for success, false for failure.
*/
function write_resource(DAVResource $resource, $caldav_data, DAVResource $collection, $author, &$etag, $put_action_type, $caldav_context, $log_action = true, $weak_etag = null)
{
    global $tz_regex, $session;
    $path = $resource->bound_from();
    $user_no = $collection->user_no();
    $vcal = new vCalendar($caldav_data);
    $resources = $vcal->GetComponents('VTIMEZONE', false);
    // Not matching VTIMEZONE
    if (!isset($resources[0])) {
        $resource_type = 'Unknown';
        /** @todo Handle writing non-calendar resources, like address book entries or random file data */
        rollback_on_error($caldav_context, $user_no, $path, translate('No calendar content'), 412);
        return false;
    } else {
        $first = $resources[0];
        if (!$first instanceof vComponent) {
            print $vcal->Render();
            fatal('This is not a vComponent!');
        }
        $resource_type = $first->GetType();
    }
    $collection_id = $collection->collection_id();
    $qry = new AwlQuery();
    $qry->Begin();
    $dav_params = array(':etag' => $etag, ':dav_data' => $caldav_data, ':caldav_type' => $resource_type, ':session_user' => $author, ':weak_etag' => $weak_etag);
    $calitem_params = array(':etag' => $etag);
    if ($put_action_type == 'INSERT') {
        $qry->QDo('SELECT nextval(\'dav_id_seq\') AS dav_id, null AS caldav_data');
    } else {
        $qry->QDo('SELECT dav_id, caldav_data FROM caldav_data WHERE dav_name = :dav_name ', array(':dav_name' => $path));
    }
    if ($qry->rows() != 1 || !($row = $qry->Fetch())) {
        // No dav_id?  => We're toast!
        trace_bug('No dav_id for "%s" on %s!!!', $path, $create_resource ? 'create' : 'update');
        rollback_on_error($caldav_context, $user_no, $path);
        return false;
    }
    $dav_id = $row->dav_id;
    $old_dav_data = $row->caldav_data;
    $dav_params[':dav_id'] = $dav_id;
    $calitem_params[':dav_id'] = $dav_id;
    $due = null;
    if ($first->GetType() == 'VTODO') {
        $due = $first->GetPValue('DUE');
    }
    $calitem_params[':due'] = $due;
    $dtstart = $first->GetPValue('DTSTART');
    if (empty($dtstart)) {
        $dtstart = $due;
    }
    $calitem_params[':dtstart'] = $dtstart;
    $dtend = $first->GetPValue('DTEND');
    if (isset($dtend) && $dtend != '') {
        dbg_error_log('PUT', ' DTEND: "%s", DTSTART: "%s", DURATION: "%s"', $dtend, $dtstart, $first->GetPValue('DURATION'));
        $calitem_params[':dtend'] = $dtend;
        $dtend = ':dtend';
    } else {
        // In this case we'll construct the SQL directly as a calculation relative to :dtstart
        $dtend = 'NULL';
        if ($first->GetPValue('DURATION') != '' and $dtstart != '') {
            $duration = trim(preg_replace('#[PT]#', ' ', $first->GetPValue('DURATION')));
            if ($duration == '') {
                $duration = '0 seconds';
            }
            $dtend = '(:dtstart::timestamp with time zone + :duration::interval)';
            $calitem_params[':duration'] = $duration;
        } elseif ($first->GetType() == 'VEVENT') {
            /**
             * From RFC2445 4.6.1:
             * For cases where a "VEVENT" calendar component specifies a "DTSTART"
             * property with a DATE data type but no "DTEND" property, the events
             * non-inclusive end is the end of the calendar date specified by the
             * "DTSTART" property. For cases where a "VEVENT" calendar component specifies
             * a "DTSTART" property with a DATE-TIME data type but no "DTEND" property,
             * the event ends on the same calendar date and time of day specified by the
             * "DTSTART" property.
             *
             * So we're looking for 'VALUE=DATE', to identify the duration, effectively.
             *
             */
            $dtstart_prop = $first->GetProperty('DTSTART');
            $value_type = $dtstart_prop->GetParameterValue('VALUE');
            dbg_error_log('PUT', 'DTSTART without DTEND. DTSTART value type is %s', $value_type);
            if (isset($value_type) && $value_type == 'DATE') {
                $dtend = '(:dtstart::timestamp with time zone::date + \'1 day\'::interval)';
            } else {
                $dtend = ':dtstart';
            }
        }
    }
    $dtstamp = $first->GetPValue('DTSTAMP');
    if (!isset($dtstamp) || $dtstamp == '') {
        // Strictly, we're dealing with an out of spec component here, but we'll try and survive
        $dtstamp = gmdate('Ymd\\THis\\Z');
    }
    $calitem_params[':dtstamp'] = $dtstamp;
    $last_modified = $first->GetPValue('LAST-MODIFIED');
    if (!isset($last_modified) || $last_modified == '') {
        $last_modified = $dtstamp;
    }
    $dav_params[':modified'] = $last_modified;
    $calitem_params[':modified'] = $last_modified;
    $created = $first->GetPValue('CREATED');
    if ($created == '00001231T000000Z') {
        $created = '20001231T000000Z';
    }
    $class = $first->GetPValue('CLASS');
    /* Check and see if we should over ride the class. */
    /** @todo is there some way we can move this out of this function? Or at least get rid of the need for the SQL query here. */
    if (public_events_only($user_no, $path)) {
        $class = 'PUBLIC';
    }
    /*
     * It seems that some calendar clients don't set a class...
     * RFC2445, 4.8.1.3:
     * Default is PUBLIC
     */
    if (!isset($class) || $class == '') {
        $class = 'PUBLIC';
    }
    $calitem_params[':class'] = $class;
    /** Calculate what timezone to set, first, if possible */
    $last_olson = 'Turkmenikikamukau';
    // I really hope this location doesn't exist!
    $tzid = GetTZID($first);
    if (!empty($tzid)) {
        $timezones = $vcal->GetComponents('VTIMEZONE');
        foreach ($timezones as $k => $tz) {
            if ($tz->GetPValue('TZID') != $tzid) {
                /**
                 * We'll skip any tz definitions that are for a TZID other than the DTSTART/DUE on the first VEVENT/VTODO 
                 */
                dbg_error_log('ERROR', ' Event uses TZID[%s], skipping included TZID[%s]!', $tz->GetPValue('TZID'), $tzid);
                continue;
            }
            $olson = olson_from_tzstring($tzid);
            if (empty($olson)) {
                $olson = $tz->GetPValue('X-LIC-LOCATION');
                if (!empty($olson)) {
                    $olson = olson_from_tzstring($olson);
                }
            }
        }
        dbg_error_log('PUT', ' Using TZID[%s] and location of [%s]', $tzid, isset($olson) ? $olson : '');
        if (!empty($olson) && $olson != $last_olson && preg_match($tz_regex, $olson)) {
            dbg_error_log('PUT', ' Setting timezone to %s', $olson);
            if ($olson != '') {
                $qry->QDo('SET TIMEZONE TO \'' . $olson . "'");
            }
            $last_olson = $olson;
        }
        $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'] = $olson;
            $params[':vtimezone'] = isset($tz) ? $tz->Render() : null;
            $qry->QDo('INSERT INTO timezones (tzid, olson_name, active, vtimezone) VALUES(:tzid,:olson_name,false,:vtimezone)', $params);
        }
        if (!isset($olson) || $olson == '') {
            $olson = $tzid;
        }
    }
    $qry->QDo('SELECT new_sync_token(0,' . $collection_id . ')');
    $calitem_params[':tzid'] = $tzid;
    $calitem_params[':uid'] = $first->GetPValue('UID');
    $calitem_params[':summary'] = $first->GetPValue('SUMMARY');
    $calitem_params[':location'] = $first->GetPValue('LOCATION');
    $calitem_params[':transp'] = $first->GetPValue('TRANSP');
    $calitem_params[':description'] = $first->GetPValue('DESCRIPTION');
    $calitem_params[':rrule'] = $first->GetPValue('RRULE');
    $calitem_params[':url'] = $first->GetPValue('URL');
    $calitem_params[':priority'] = $first->GetPValue('PRIORITY');
    $calitem_params[':percent_complete'] = $first->GetPValue('PERCENT-COMPLETE');
    $calitem_params[':status'] = $first->GetPValue('STATUS');
    if (!$collection->IsSchedulingCollection()) {
        if (do_scheduling_requests($vcal, $put_action_type == 'INSERT', $old_dav_data, true)) {
            $dav_params[':dav_data'] = $vcal->Render(null, true);
            $etag = null;
        }
    }
    if (!isset($dav_params[':modified'])) {
        $dav_params[':modified'] = 'now';
    }
    if ($put_action_type == 'INSERT') {
        $sql = 'INSERT INTO caldav_data ( dav_id, user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified, collection_id, weak_etag )
            VALUES( :dav_id, :user_no, :dav_name, :etag, :dav_data, :caldav_type, :session_user, :created, :modified, :collection_id, :weak_etag )';
        $dav_params[':collection_id'] = $collection_id;
        $dav_params[':user_no'] = $user_no;
        $dav_params[':dav_name'] = $path;
        $dav_params[':created'] = isset($created) && $created != '' ? $created : $dtstamp;
    } else {
        $sql = 'UPDATE caldav_data SET caldav_data=:dav_data, dav_etag=:etag, caldav_type=:caldav_type, logged_user=:session_user,
            modified=:modified, weak_etag=:weak_etag WHERE dav_id=:dav_id';
    }
    $qry = new AwlQuery($sql, $dav_params);
    if (!$qry->Exec('PUT', __LINE__, __FILE__)) {
        fatal('Insert into calendar_item failed...');
        rollback_on_error($caldav_context, $user_no, $path);
        return false;
    }
    if ($put_action_type == 'INSERT') {
        $sql = <<<EOSQL
INSERT INTO calendar_item (user_no, dav_name, dav_id, dav_etag, uid, dtstamp,
                dtstart, dtend, summary, location, class, transp,
                description, rrule, tz_id, last_modified, url, priority,
                created, due, percent_complete, status, collection_id )
   VALUES ( :user_no, :dav_name, :dav_id, :etag, :uid, :dtstamp,
                :dtstart, {$dtend}, :summary, :location, :class, :transp,
                :description, :rrule, :tzid, :modified, :url, :priority,
                :created, :due, :percent_complete, :status, :collection_id )
EOSQL;
        $sync_change = 201;
        $calitem_params[':collection_id'] = $collection_id;
        $calitem_params[':user_no'] = $user_no;
        $calitem_params[':dav_name'] = $path;
        $calitem_params[':created'] = $dav_params[':created'];
    } else {
        $sql = <<<EOSQL
UPDATE calendar_item SET dav_etag=:etag, uid=:uid, dtstamp=:dtstamp,
                dtstart=:dtstart, dtend={$dtend}, summary=:summary, location=:location,
                class=:class, transp=:transp, description=:description, rrule=:rrule,
                tz_id=:tzid, last_modified=:modified, url=:url, priority=:priority,
                due=:due, percent_complete=:percent_complete, status=:status
       WHERE dav_id=:dav_id
EOSQL;
        $sync_change = 200;
    }
    write_alarms($dav_id, $first);
    write_attendees($dav_id, $vcal);
    if ($log_action && function_exists('log_caldav_action')) {
        log_caldav_action($put_action_type, $first->GetPValue('UID'), $user_no, $collection_id, $path);
    } else {
        if ($log_action) {
            dbg_error_log('PUT', 'No log_caldav_action( %s, %s, %s, %s, %s) can be called.', $put_action_type, $first->GetPValue('UID'), $user_no, $collection_id, $path);
        }
    }
    $qry = new AwlQuery($sql, $calitem_params);
    if (!$qry->Exec('PUT', __LINE__, __FILE__)) {
        rollback_on_error($caldav_context, $user_no, $path);
        return false;
    }
    $qry->QDo("SELECT write_sync_change( {$collection_id}, {$sync_change}, :dav_name)", array(':dav_name' => $path));
    $qry->Commit();
    if (function_exists('post_commit_action')) {
        post_commit_action($put_action_type, $first->GetPValue('UID'), $user_no, $collection_id, $path);
    }
    // Uncache anything to do with the collection
    $cache = getCacheInstance();
    $cache_ns = 'collection-' . preg_replace('{/[^/]*$}', '/', $path);
    $cache->delete($cache_ns, null);
    dbg_error_log('PUT', 'User: %d, ETag: %s, Path: %s', $author, $etag, $path);
    return true;
    // Success!
}
                break;
            default:
                /**
                 * @todo We should handle a lot more properties here.  principal-URL seems a likely one to be used.
                 * @todo We should catch the unsupported properties in the query and fire back an error indicating so.
                 */
                dbg_error_log("principal", "Unhandled tag '%s' to match '%s'\n", $v1->GetNSTag(), $match);
        }
    }
    if ($subwhere != "") {
        $where .= sprintf("%s(%s)", $where == "" ? "" : $clause_joiner, $subwhere);
    }
}
if ($where != "") {
    $where = "WHERE {$where}";
}
$sql = "SELECT * FROM dav_principal {$where} ORDER BY principal_id LIMIT 100";
$qry = new AwlQuery($sql, $params);
$get_props = $xmltree->GetPath('/DAV::principal-property-search/DAV::prop/*');
$properties = array();
foreach ($get_props as $k1 => $v1) {
    $properties[] = $v1->GetNSTag();
}
if ($qry->Exec("REPORT", __LINE__, __FILE__) && $qry->rows() > 0) {
    while ($row = $qry->Fetch()) {
        $principal = new DAVResource($row);
        $responses[] = $principal->RenderAsXML($properties, $reply);
    }
}
$multistatus = new XMLElement("multistatus", $responses, $reply->GetXmlNsArray());
$request->XMLResponse(207, $multistatus);
Esempio n. 30
0
    $c->code_major = $matches[1];
    $c->code_minor = $matches[2];
    $c->code_patch = $matches[3];
    $c->code_version = $c->code_major * 1000 + $c->code_minor . '.' . $c->code_patch;
    dbg_error_log('caldav', 'Version (%d.%d.%d) == %s', $c->code_major, $c->code_minor, $c->code_patch, $c->code_version);
    @header(sprintf('Server: %d.%d', $c->code_major, $c->code_minor));
}
/**
* Force the domain name to what was in the configuration file
*/
$_SERVER['SERVER_NAME'] = $c->domain_name;
require_once 'AwlQuery.php';
$c->want_dbversion = array(1, 2, 11);
$c->schema_version = 0;
$qry = new AwlQuery('SELECT schema_major, schema_minor, schema_patch FROM awl_db_revision ORDER BY schema_id DESC LIMIT 1;');
if ($qry->Exec('always', __LINE__, __FILE__) && ($row = $qry->Fetch())) {
    $c->schema_version = doubleval(sprintf('%d%03d.%03d', $row->schema_major, $row->schema_minor, $row->schema_patch));
    $c->wanted_version = doubleval(sprintf('%d%03d.%03d', $c->want_dbversion[0], $c->want_dbversion[1], $c->want_dbversion[2]));
    $c->schema_major = $row->schema_major;
    $c->schema_minor = $row->schema_minor;
    $c->schema_patch = $row->schema_patch;
    if ($c->schema_version < $c->wanted_version) {
        $c->messages[] = sprintf('Database schema needs upgrading. Current: %d.%d.%d, Desired: %d.%d.%d', $row->schema_major, $row->schema_minor, $row->schema_patch, $c->want_dbversion[0], $c->want_dbversion[1], $c->want_dbversion[2]);
    }
    if (isset($c->default_timezone)) {
        $qry->QDo('SET TIMEZONE TO ?', $c->default_timezone);
    }
}
require_once 'Principal.php';
/**
 * Return the HTTP status code description for a given code. Hopefully