mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-04-17 13:50:17 +00:00
Resolve merge conflicts.
Conflicts: docs/website/inc/page-header.php docs/website/installation.php
This commit is contained in:
commit
4f444d8bfa
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,8 +1,13 @@
|
||||
caldav.session
|
||||
rscds.session
|
||||
davical.session
|
||||
build
|
||||
rscds.bfproject
|
||||
davical.bfproject
|
||||
locale
|
||||
built-docs
|
||||
built-po
|
||||
.settings
|
||||
*~
|
||||
testing/dumps
|
||||
testing/regression.conf
|
||||
|
||||
33
INSTALL
33
INSTALL
@ -50,15 +50,15 @@ I'm available to answer questions, anyway :-)
|
||||
Pre-requisites
|
||||
==============
|
||||
|
||||
RSCDS depends on a number of things. Firstly, it depends
|
||||
DAViCal depends on a number of things. Firstly, it depends
|
||||
on Andrew's Web Libraries (AWL) which is a set of useful
|
||||
PHP functions and objects written by Andrew McMillan over
|
||||
a number of years.
|
||||
|
||||
The following other software is also needed:
|
||||
Apache: 1.3.x or 2.x.x
|
||||
PHP: 4.3 or greater, including PHP5
|
||||
PostgreSQL: 7.4 or greater
|
||||
PHP: 5.0 or greater
|
||||
PostgreSQL: 8.1 or greater
|
||||
|
||||
The PostgreSQL database may be installed on a server other
|
||||
than the web server, and that kind of situation is recommended
|
||||
@ -102,22 +102,24 @@ Apache VHost Configuration
|
||||
Your Apache instance needs to be configured for Virtual Hosts. If
|
||||
this is not already the case you may want to read some documentation
|
||||
about that, and you most likely will want to ensure that any existing
|
||||
site becomes the **default** virtual host, with RSCDS only being a
|
||||
site becomes the **default** virtual host, with DAViCal only being a
|
||||
single virtual host.
|
||||
|
||||
I use a Virtual Host stanza like this:
|
||||
|
||||
#
|
||||
# Virtual Host def for Debian packaged RSCDS
|
||||
# Virtual Host def for Debian packaged DAViCal
|
||||
<VirtualHost 123.4.56.78 >
|
||||
DocumentRoot /usr/share/rscds/htdocs
|
||||
DirectoryIndex index.php index.html
|
||||
ServerName rscds.example.net
|
||||
ServerName davical.example.net
|
||||
ServerAlias calendar.example.net
|
||||
Alias /images/ /usr/share/rscds/htdocs/images/
|
||||
php_value include_path /usr/share/rscds/inc:/usr/share/awl/inc
|
||||
php_value magic_quotes_gpc 0
|
||||
php_value register_globals 1
|
||||
php_value register_globals 0
|
||||
php_value error_reporting "E_ALL & ~E_NOTICE"
|
||||
php_value default_charset "utf-8"
|
||||
</VirtualHost>
|
||||
|
||||
Replace 123.4.56.78 with your own IP address, of course (you can
|
||||
@ -135,25 +137,24 @@ installed from a package.
|
||||
|
||||
Once your VHost is installed an working correctly, you should be
|
||||
able to browse to that address and see a page telling you that
|
||||
you need to configure RSCDS.
|
||||
you need to configure DAViCal.
|
||||
|
||||
|
||||
|
||||
RSCDS Configuration
|
||||
===================
|
||||
DAViCal Configuration
|
||||
=====================
|
||||
|
||||
The RSCDS configuration generally resides in /etc/rscds/<domain>-conf.php
|
||||
The DAViCal configuration generally resides in /etc/davical/<domain>-conf.php
|
||||
and is a regular PHP file which sets (or overrides) some specific variables.
|
||||
|
||||
<?php
|
||||
// $c->domainname = "calendar.example.net";
|
||||
// $c->sysabbr = 'rscds';
|
||||
// $c->sysabbr = 'davical';
|
||||
// $c->admin_email = 'admin@example.net';
|
||||
// $c->system_name = "Really Simple CalDAV Store";
|
||||
// $c->system_name = "DAViCal CalDAV Server";
|
||||
// $c->collections_always_exist = false;
|
||||
|
||||
$c->pg_connect[] = 'dbname=caldav port=5433 user=general';
|
||||
$c->pg_connect[] = 'dbname=caldav port=5432 user=general';
|
||||
$c->pg_connect[] = 'dbname=davical port=5432 user=general';
|
||||
|
||||
?>
|
||||
|
||||
@ -180,7 +181,7 @@ If all is going well you should now be able to browse to the admin
|
||||
pages and log in as 'admin' (the password is the bit after the '**'
|
||||
in the 'password' field of the 'usr' table so:
|
||||
|
||||
psql rscds -c 'select username, password from usr;'
|
||||
psql davical -c 'select username, password from usr;'
|
||||
|
||||
should show you a list. Note that once you change a password it
|
||||
won't be readable in this way - only the initial configuration
|
||||
|
||||
10
Makefile
10
Makefile
@ -4,12 +4,16 @@
|
||||
package=rscds
|
||||
version=$(shell cat VERSION)
|
||||
|
||||
all: inc/always.php built-docs
|
||||
all: inc/always.php built-docs built-po
|
||||
|
||||
built-docs: docs/api/phpdoc.ini htdocs/*.php inc/*.php
|
||||
phpdoc -c docs/api/phpdoc.ini
|
||||
phpdoc -c docs/api/phpdoc.ini || echo "WARNING: failed to build docs"
|
||||
touch built-docs
|
||||
|
||||
built-po: inc/always.php scripts/po/rebuild-translations.sh scripts/po/extract.pl
|
||||
scripts/po/rebuild-translations.sh
|
||||
touch built-po
|
||||
|
||||
#
|
||||
# Insert the current version number into always.php
|
||||
#
|
||||
@ -28,7 +32,7 @@ release: built-docs
|
||||
rm $(package)-$(version)
|
||||
|
||||
clean:
|
||||
rm -f built-docs
|
||||
rm -f built-docs built-po
|
||||
-find docs/api/* ! -name "phpdoc.ini" ! -name ".gitignore" -delete
|
||||
-find . -name "*~" -delete
|
||||
|
||||
|
||||
10
README
10
README
@ -1 +1,9 @@
|
||||
Really Simple CalDAV Store by Andrew McMillan.
|
||||
DAViCal CalDAV Server by Andrew McMillan.
|
||||
|
||||
For documentation you are best advised to visit the sourceforge pages
|
||||
or to start searching from http://davical.org/ and see where you end
|
||||
up.
|
||||
|
||||
Good luck!
|
||||
|
||||
Andrew McMillan
|
||||
10
TODO
10
TODO
@ -1,10 +1,12 @@
|
||||
Desirable
|
||||
- accept the free/busy information as a PUT
|
||||
- accept the free/busy information as a POST
|
||||
- more translations of the administration interface
|
||||
- translations of the website.
|
||||
- the ability to see a basic list of event data in the admin interface
|
||||
- the ability to see a better list of event data in the admin interface
|
||||
- allow a specific CalDAV access permission to delegate free/busy viewability.
|
||||
- rename everything to "DAViCal"
|
||||
|
||||
Important
|
||||
- allow for some sort of modular authentication methods
|
||||
-
|
||||
- Fix the relationships code so relationships are controlled by the person
|
||||
affected (or the admin).
|
||||
- Implement draft-desruisseaux-caldav-sched specifications.
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* if this is set then any e-mail that would normally be sent by RSCDS will be
|
||||
* if this is set then any e-mail that would normally be sent by DAViCal will be
|
||||
* sent to this e-mail address for debugging.
|
||||
*/
|
||||
//$c->debug_email
|
||||
@ -29,21 +29,23 @@
|
||||
// $c->dbg['querystring'] = 1;
|
||||
// $c->dbg['icalendar'] = 1;
|
||||
// $c->dbg['ics'] = 1;
|
||||
// $c->dbg['Login'] = 1;
|
||||
// $c->dbg['login'] = 1;
|
||||
// $c->dbg['options'] = 1;
|
||||
// $c->dbg['get'] = 1;
|
||||
// $c->dbg['put'] = 1;
|
||||
// $c->dbg['propfind'] = 1;
|
||||
// $c->dbg['proppatch'] = 1;
|
||||
// $c->dbg['report'] = 1;
|
||||
// $c->dbg['principal'] = 1;
|
||||
// $c->dbg['user'] = 1;
|
||||
// $c->dbg['vevent'] = 1;
|
||||
// $c->dbg['rrule'] = 1;
|
||||
|
||||
/**
|
||||
* default is 'rscds' used to prefix debugging messages but will only need to change
|
||||
* if you are running multiple RSCDS servers logging into the same place.
|
||||
* default is 'davical' used to prefix debugging messages but will only need to change
|
||||
* if you are running multiple DAViCal servers logging into the same place.
|
||||
*/
|
||||
// $c->sysabbr
|
||||
// $c->sysabbr = 'davical';
|
||||
|
||||
/**
|
||||
* As yet we only support quite a limited range of options. When we see clients looking
|
||||
@ -55,4 +57,3 @@
|
||||
*/
|
||||
// $c->override_allowed_methods = "PROPPATCH, OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT"
|
||||
|
||||
?>
|
||||
@ -10,14 +10,14 @@
|
||||
*****************************/
|
||||
|
||||
/**
|
||||
* Ex : $c->pg_connect[] = 'dbname=rscds port=5432 user=general'
|
||||
* Ex : $c->pg_connect[] = 'dbname=davical port=5432 user=general'
|
||||
* The application will attempt to
|
||||
* connect to the database, successively applying connection parameters from
|
||||
* the array in $c->pg_connect.
|
||||
* used in the web interface but also the caldav Server
|
||||
*/
|
||||
$c->pg_connect[] = "dbname=rscds user=general";
|
||||
// $c->pg_connect[] = "dbname=rscds user=general port=5433 host=somehost password=mypass";
|
||||
$c->pg_connect[] = "dbname=davical user=general";
|
||||
// $c->pg_connect[] = "dbname=davical user=general port=5433 host=somehost password=mypass";
|
||||
|
||||
|
||||
/****************************
|
||||
@ -66,7 +66,7 @@ $c->admin_email ='calendar-admin@example.com';
|
||||
* <p>The "enable_row_linking" option controls whether javascript is used
|
||||
* to make the entire row clickable in browse lists in the administration
|
||||
* pages. Since this doesn't work in Konqueror you may want to set this
|
||||
* to false if you expect people to be using Konqueror with the RSCDS
|
||||
* to false if you expect people to be using Konqueror with the DAViCal
|
||||
* administration pages.</p>
|
||||
*/
|
||||
// $c->enable_row_linking = true;
|
||||
@ -149,19 +149,20 @@ $c->admin_email ='calendar-admin@example.com';
|
||||
/********************************/
|
||||
/******* Other AWL hook *********/
|
||||
/********************************/
|
||||
//require_once('AuthPlugins.php');
|
||||
// require_once('auth-functions.php');
|
||||
// $c->authenticate_hook = array(
|
||||
// 'call' => 'auth_other_awl',
|
||||
// 'call' => 'AuthExternalAwl',
|
||||
// 'config' => array(
|
||||
/** A PgSQL database connection string for the database containing user records */
|
||||
// 'connection' => 'dbname=wrms host=otherhose 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 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"
|
||||
// )
|
||||
// );
|
||||
|
||||
|
||||
|
||||
/********************************/
|
||||
/*********** LDAP hook **********/
|
||||
/********************************/
|
||||
@ -169,8 +170,12 @@ $c->admin_email ='calendar-admin@example.com';
|
||||
//$c->authenticate_hook['config'] = array(
|
||||
// 'host' => 'www.tennaxia.net', //host name of your LDAP Server
|
||||
// 'port' => '389', //port
|
||||
|
||||
/* For the initial bind to be anonymous leave bindDN and passDN
|
||||
commented out */
|
||||
// 'bindDN'=> 'cn=manager,cn=internal,dc=tennaxia,dc=net', //DN to bind to this server enabling to perform request
|
||||
// 'passDN'=> 'xxxxxxxx', //Password of the previous bindDN to bind to this server enabling to perform request
|
||||
|
||||
// 'protocolVersion' => '3', //Version of LDAP protocol to use
|
||||
// 'baseDNUsers'=> 'dc=tennaxia,dc=net', //where to look at valid user
|
||||
// 'filterUsers' => 'objectClass=kolabInetOrgPerson', //filter which must validate a user according to RFC4515, i.e. surrounded by brackets
|
||||
@ -193,6 +198,16 @@ $c->admin_email ='calendar-admin@example.com';
|
||||
//include('drivers_ldap.php');
|
||||
|
||||
|
||||
/**
|
||||
* Authentication against PAM using the Squid helper script.
|
||||
*/
|
||||
//$c->authenticate_hook = array(
|
||||
// 'call' => 'SQUID_PAM_check',
|
||||
// 'config' => array( 'script' => '/usr/bin/pam_auth', 'email_base' => 'example.com' );
|
||||
// );
|
||||
//include('drivers_squid_pam.php');
|
||||
|
||||
|
||||
/**
|
||||
* The default locale will be "en_NZ";
|
||||
* If you are in a non-English locale, you can set the default_locale
|
||||
@ -225,6 +240,3 @@ $c->admin_email ='calendar-admin@example.com';
|
||||
* of a VEVENT. The local (server) time zone will be used as a default.
|
||||
*/
|
||||
// $c->local_tzid;
|
||||
|
||||
|
||||
?>
|
||||
@ -84,4 +84,3 @@
|
||||
// $c->schema_patch
|
||||
// $c->schema_version
|
||||
|
||||
?>
|
||||
@ -23,13 +23,11 @@
|
||||
<item url="htdocs/caldav.php" uploadstatus="1" />
|
||||
<item url="debian/" uploadstatus="1" />
|
||||
<item url="debian/rules" uploadstatus="1" />
|
||||
<item url="dba/rscds.sql" uploadstatus="1" />
|
||||
<item url="htdocs/freebusy.php" uploadstatus="1" />
|
||||
<item url="htdocs/index.php" uploadstatus="1" />
|
||||
<item url="inc/RSCDSSession.php" uploadstatus="1" />
|
||||
<item url="inc/page-header.php" uploadstatus="1" />
|
||||
<item url="inc/page-footer.php" uploadstatus="1" />
|
||||
<item url="inc/rscds_configuration_missing.php" uploadstatus="1" />
|
||||
<item url="htdocs/rscds.css" uploadstatus="1" />
|
||||
<item url="inc/interactive-page.php" uploadstatus="1" />
|
||||
<item url="htdocs/users.php" uploadstatus="1" />
|
||||
@ -236,6 +234,19 @@
|
||||
<item url="inc/caldav-REPORT-calquery.php" uploadstatus="1" />
|
||||
<item url="inc/caldav-REPORT-freebusy.php" uploadstatus="1" />
|
||||
<item url="inc/caldav-REPORT-multiget.php" uploadstatus="1" />
|
||||
<item url="inc/caldav-PUT-functions.php" uploadstatus="1" />
|
||||
<item url="inc/HTTPAuthSession.php" uploadstatus="1" />
|
||||
<item url="inc/caldav-REPORT-principal.php" uploadstatus="1" />
|
||||
<item url="dba/patches/1.1.10.sql" uploadstatus="1" />
|
||||
<item url="inc/auth-functions.php" uploadstatus="1" />
|
||||
<item url="htdocs/tools.php" uploadstatus="1" />
|
||||
<item url="inc/CalDAVPrincipal.php" uploadstatus="1" />
|
||||
<item url="dba/patches/1.1.11.sql" uploadstatus="1" />
|
||||
<item url="docs/website/clients/iCal-details.php" uploadstatus="1" />
|
||||
<item url="inc/davical_configuration_missing.php" uploadstatus="1" />
|
||||
<item url="dba/davical.sql" uploadstatus="1" />
|
||||
<item url="inc/drivers_squid_pam.php" uploadstatus="1" />
|
||||
<item url="dba/patches/1.1.11a.sql" uploadstatus="1" />
|
||||
<item url="dba/patches/1.1.12.sql" uploadstatus="1" />
|
||||
</project>
|
||||
</webproject>
|
||||
@ -8,20 +8,65 @@ ADMINPW="${2}"
|
||||
|
||||
DBADIR="`dirname \"$0\"`"
|
||||
|
||||
testawldir() {
|
||||
[ -f "${1}/dba/awl-tables.sql" ]
|
||||
}
|
||||
|
||||
#
|
||||
# Attempt to locate the AWL directory
|
||||
AWLDIR="${DBADIR}/../../awl"
|
||||
if ! testawldir "${AWLDIR}"; then
|
||||
AWLDIR="/usr/share/awl"
|
||||
if ! testawldir "${AWLDIR}"; then
|
||||
AWLDIR="/usr/local/share/awl"
|
||||
if ! testawldir "${AWLDIR}"; then
|
||||
echo "Unable to find AWL libraries"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
export AWL_DBAUSER=davical_dba
|
||||
export AWL_APPUSER=davical_app
|
||||
|
||||
# Get the major version for PostgreSQL
|
||||
export DBVERSION="`psql -qAt template1 -c "SELECT version();" | cut -f2 -d' ' | cut -f1-2 -d'.'`"
|
||||
|
||||
db_users() {
|
||||
psql -qAt template1 -c "SELECT usename FROM pg_user;";
|
||||
}
|
||||
|
||||
create_db_user() {
|
||||
if ! db_users | grep "^${1}$" >/dev/null ; then
|
||||
createuser --no-superuser --no-createdb --no-createrole "${1}"
|
||||
fi
|
||||
}
|
||||
|
||||
create_plpgsql_language() {
|
||||
if ! psql -qAt template1 -c "SELECT lanname FROM pg_language;" | grep "^plpgsql$" >/dev/null; then
|
||||
createlang plpgsql "${DBNAME}"
|
||||
fi
|
||||
}
|
||||
|
||||
create_db_user "${AWL_DBAUSER}"
|
||||
create_db_user "${AWL_APPUSER}"
|
||||
|
||||
# FIXME: Need to check that the database was actually created.
|
||||
if ! createdb -E UTF8 "${DBNAME}" -T template0 ; then
|
||||
if ! createdb --encoding UTF8 "${DBNAME}" --template template0 --owner "${AWL_DBAUSER}"; then
|
||||
echo "Unable to create database"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# This will fail if the language already exists, but it should not
|
||||
# because we created from template0.
|
||||
createlang plpgsql "${DBNAME}"
|
||||
create_plpgsql_language
|
||||
|
||||
#
|
||||
# FIXME: filter non-error output
|
||||
psql -q -f "${DBADIR}/rscds.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )"
|
||||
# Load the AWL base tables and schema management tables
|
||||
psql -q -f "${AWLDIR}/dba/awl-tables.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )"
|
||||
psql -q -f "${AWLDIR}/dba/schema-management.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )"
|
||||
|
||||
#
|
||||
# Load the DAViCal tables
|
||||
psql -q -f "${DBADIR}/davical.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )"
|
||||
|
||||
psql -q -f "${DBADIR}/caldav_functions.sql" "${DBNAME}"
|
||||
|
||||
@ -39,7 +84,7 @@ fi
|
||||
if [ "$ADMINPW" = "" ] ; then
|
||||
# OK. They didn't supply one, and pwgen didn't work, so we hack something
|
||||
# together from /dev/random ...
|
||||
ADMINPW="`dd if=/dev/urandom bs=512 count=1 2>/dev/null | tr -c -d "a-zA-HJ-NP-Y0-9" | cut -c2-9`"
|
||||
ADMINPW="`dd if=/dev/urandom bs=512 count=1 2>/dev/null | tr -c -d "a-km-zA-HJ-NP-Y0-9" | cut -c2-9`"
|
||||
fi
|
||||
|
||||
if [ "$ADMINPW" = "" ] ; then
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
-- Really Simple CalDAV Store - Database Schema
|
||||
--
|
||||
|
||||
-- Use the usr, group and schema management stufffrom libawl-php
|
||||
\i /usr/share/awl/dba/awl-tables.sql
|
||||
\i /usr/share/awl/dba/schema-management.sql
|
||||
|
||||
-- The main event. Where we store the things the calendar throws at us.
|
||||
CREATE TABLE caldav_data (
|
||||
user_no INT references usr(user_no),
|
||||
user_no INT references usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE,
|
||||
dav_name TEXT,
|
||||
dav_etag TEXT,
|
||||
created TIMESTAMP WITH TIME ZONE,
|
||||
@ -69,7 +65,7 @@ GRANT SELECT,INSERT,UPDATE,DELETE ON calendar_item TO general;
|
||||
|
||||
-- Something that can look like a filesystem hierarchy where we store stuff
|
||||
CREATE TABLE collection (
|
||||
user_no INT references usr(user_no),
|
||||
user_no INT references usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE,
|
||||
parent_container TEXT,
|
||||
dav_name TEXT,
|
||||
dav_etag TEXT,
|
||||
@ -77,6 +73,7 @@ CREATE TABLE collection (
|
||||
is_calendar BOOLEAN,
|
||||
created TIMESTAMP WITH TIME ZONE,
|
||||
modified TIMESTAMP WITH TIME ZONE,
|
||||
public_events_only BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
PRIMARY KEY ( user_no, dav_name )
|
||||
);
|
||||
@ -141,4 +138,4 @@ CREATE TABLE freebusy_ticket (
|
||||
|
||||
GRANT INSERT,SELECT,UPDATE,DELETE ON TABLE freebusy_ticket TO general;
|
||||
|
||||
SELECT new_db_revision(1,1,9, 'September' );
|
||||
SELECT new_db_revision(1,1,11, 'November' );
|
||||
20
dba/patches/1.1.10.sql
Normal file
20
dba/patches/1.1.10.sql
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
-- Sort out accessing calendar entries.
|
||||
|
||||
BEGIN;
|
||||
SELECT check_db_revision(1,1,9);
|
||||
|
||||
-- Make sure that class is set to something, by default PUBLIC.
|
||||
-- According to RFC2445, 4.8.1.3.
|
||||
UPDATE calendar_item SET class = 'PUBLIC' WHERE class IS NULL;
|
||||
|
||||
-- Allow forcing all events in a calendar to be public
|
||||
ALTER TABLE collection ADD COLUMN public_events_only BOOLEAN;
|
||||
UPDATE collection SET public_events_only = FALSE;
|
||||
ALTER TABLE collection ALTER public_events_only SET NOT NULL;
|
||||
ALTER TABLE collection ALTER public_events_only SET DEFAULT FALSE;
|
||||
|
||||
SELECT new_db_revision(1,1,10, 'October' );
|
||||
COMMIT;
|
||||
ROLLBACK;
|
||||
|
||||
16
dba/patches/1.1.11.sql
Normal file
16
dba/patches/1.1.11.sql
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
-- Sort out accessing calendar entries.
|
||||
|
||||
BEGIN;
|
||||
SELECT check_db_revision(1,1,10);
|
||||
|
||||
ALTER TABLE caldav_data DROP CONSTRAINT "$1";
|
||||
ALTER TABLE caldav_data ADD CONSTRAINT "$1" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE;
|
||||
|
||||
ALTER TABLE collection DROP CONSTRAINT "$1";
|
||||
ALTER TABLE collection ADD CONSTRAINT "$1" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE;
|
||||
|
||||
SELECT new_db_revision(1,1,11, 'November' );
|
||||
COMMIT;
|
||||
ROLLBACK;
|
||||
|
||||
17
dba/patches/1.1.11a.sql
Normal file
17
dba/patches/1.1.11a.sql
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
-- Sort out accessing calendar entries.
|
||||
-- This alternative patch file is the same in/out revision as 1.1.11 but it works with newer databases (8.x)
|
||||
|
||||
BEGIN;
|
||||
SELECT check_db_revision(1,1,10);
|
||||
|
||||
ALTER TABLE caldav_data DROP CONSTRAINT "caldav_data_user_no_fkey";
|
||||
ALTER TABLE caldav_data ADD CONSTRAINT "caldav_data_user_no_fkey" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE;
|
||||
|
||||
ALTER TABLE collection DROP CONSTRAINT "collection_user_no_fkey";
|
||||
ALTER TABLE collection ADD CONSTRAINT "collection_user_no_fkey" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE;
|
||||
|
||||
SELECT new_db_revision(1,1,11, 'November' );
|
||||
COMMIT;
|
||||
ROLLBACK;
|
||||
|
||||
70
dba/patches/1.1.12.sql
Normal file
70
dba/patches/1.1.12.sql
Normal file
@ -0,0 +1,70 @@
|
||||
|
||||
-- Add a numeric foreign key link between caldav_data and calendar_item to
|
||||
-- provide more efficient linking when the db has been initialised with a
|
||||
-- non POSIX collation.
|
||||
|
||||
|
||||
BEGIN;
|
||||
SELECT check_db_revision(1,1,11);
|
||||
|
||||
-- Add a column to the collection table to allow us to mark collections
|
||||
-- as publicly readable
|
||||
ALTER TABLE collection ADD COLUMN publicly_readable BOOLEAN DEFAULT FALSE;
|
||||
|
||||
-- Add a numeric dav_id to link the caldav_data and calendar_item tables
|
||||
ALTER TABLE caldav_data ADD COLUMN dav_id INT8;
|
||||
ALTER TABLE calendar_item ADD COLUMN dav_id INT8;
|
||||
CREATE SEQUENCE caldav_data_dav_id_seq;
|
||||
GRANT SELECT,UPDATE ON caldav_data_dav_id_seq TO general;
|
||||
|
||||
CREATE or REPLACE FUNCTION sync_dav_id ( ) RETURNS TRIGGER AS '
|
||||
DECLARE
|
||||
BEGIN
|
||||
|
||||
IF TG_OP = ''DELETE'' THEN
|
||||
-- Just let the ON DELETE CASCADE handle this case
|
||||
RETURN OLD;
|
||||
END IF;
|
||||
|
||||
IF NEW.dav_id IS NULL THEN
|
||||
NEW.dav_id = nextval(''caldav_data_dav_id_seq'');
|
||||
END IF;
|
||||
|
||||
IF TG_OP = ''UPDATE'' THEN
|
||||
IF OLD.dav_id = NEW.dav_id THEN
|
||||
-- Nothing to do
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF TG_RELNAME = ''caldav_data'' THEN
|
||||
UPDATE calendar_item SET dav_id = NEW.dav_id WHERE user_no = NEW.user_no AND dav_name = NEW.dav_name;
|
||||
ELSE
|
||||
UPDATE caldav_data SET dav_id = NEW.dav_id WHERE user_no = NEW.user_no AND dav_name = NEW.dav_name;
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
|
||||
END
|
||||
' LANGUAGE 'plpgsql';
|
||||
|
||||
CREATE TRIGGER caldav_data_sync_dav_id AFTER INSERT OR UPDATE ON caldav_data
|
||||
FOR EACH ROW EXECUTE PROCEDURE sync_dav_id();
|
||||
|
||||
CREATE TRIGGER calendar_item_sync_dav_id AFTER INSERT OR UPDATE ON calendar_item
|
||||
FOR EACH ROW EXECUTE PROCEDURE sync_dav_id();
|
||||
|
||||
-- Now, using the trigger, magically assign dav_id to all rows in caldav_data and calendar_item
|
||||
UPDATE caldav_data SET dav_id = dav_id;
|
||||
|
||||
ALTER TABLE caldav_data ALTER COLUMN dav_id SET DEFAULT nextval('caldav_data_dav_id_seq');
|
||||
ALTER TABLE caldav_data ALTER COLUMN dav_id SET NOT NULL;
|
||||
ALTER TABLE caldav_data ADD CONSTRAINT caldav_data_dav_id_key UNIQUE (dav_id);
|
||||
|
||||
ALTER TABLE calendar_item ADD CONSTRAINT calendar_item_dav_id_key UNIQUE (dav_id);
|
||||
|
||||
SELECT new_db_revision(1,1,12, 'December' );
|
||||
|
||||
COMMIT;
|
||||
ROLLBACK;
|
||||
|
||||
@ -46,18 +46,32 @@ my $current_revision = get_current_revision();
|
||||
printf( "The database is currently at revision %d.%d.%d.\n", $current_revision->{'schema_major'}, $current_revision->{'schema_minor'}, $current_revision->{'schema_patch'} );
|
||||
|
||||
opendir( PATCHDIR, $patchdir ) or die "Can't open patch directory $patchdir";
|
||||
my @patches = grep { /^([0-9]+)\.([0-9]+)\.([0-9]+)\.sql$/ } readdir(PATCHDIR);
|
||||
my @patches = grep { /^([0-9]+)\.([0-9]+)\.([0-9]+)([a-z]?)\.sql$/ } readdir(PATCHDIR);
|
||||
closedir(PATCHDIR);
|
||||
|
||||
@patches = sort { compare_revisions(revision_hash($a),revision_hash($b)); } @patches;
|
||||
@patches = sort { compare_revisions(revision_hash($a),revision_hash($b), 1); } @patches;
|
||||
|
||||
my $applied = 0;
|
||||
my $last_results = ''; # Will hold the last SQL result from applying a patch
|
||||
|
||||
for ( my $i=0; $i <= $#patches; $i++ ) {
|
||||
printf( "Looking at patches[%d] (%s)\n", $i, $patches[$i]) if ( $debug );
|
||||
if ( compare_revisions(revision_hash($patches[$i]),$current_revision) > 0 ) {
|
||||
print "Applying patch $patches[$i]\n";
|
||||
last unless( apply_patch( $patches[$i] ) );
|
||||
print "Applying patch $patches[$i] ... ";
|
||||
if ( !apply_patch( $patches[$i] ) ) {
|
||||
# Skip to the end unless the next patch is an alternate for the same version.
|
||||
if ( defined($patches[$i+1]) && compare_revisions(revision_hash($patches[$i]),revision_hash($patches[$i+1])) == 0 ) {
|
||||
print "failed. Attempting next alternative.\n";
|
||||
$applied--;
|
||||
}
|
||||
else {
|
||||
print "failed!\n$last_results ==> No further patches will be attempted!\n";
|
||||
last;
|
||||
}
|
||||
}
|
||||
else {
|
||||
print "succeeded.\n";
|
||||
}
|
||||
$applied++;
|
||||
}
|
||||
else {
|
||||
@ -91,17 +105,20 @@ exit 0;
|
||||
# which is of the form "1.2.3" or we have three parameters.
|
||||
############################################################
|
||||
sub revision_hash {
|
||||
my $rev = +{};
|
||||
my $rev = +{ 'schema_major', => 0, 'schema_minor' => 0, 'schema_patch' => 0, 'alternative' => '0' };
|
||||
my $first = shift;
|
||||
if ( $first =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)([^0-9]|$)/ ) {
|
||||
return $rev unless ( defined($first) );
|
||||
if ( $first =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)([a-z]?)([^0-9]|$)/ ) {
|
||||
$rev->{'schema_major'} = $1;
|
||||
$rev->{'schema_minor'} = $2;
|
||||
$rev->{'schema_patch'} = $3;
|
||||
$rev->{'alternative'} = $4;
|
||||
}
|
||||
else {
|
||||
$rev->{'schema_major'} = $first;
|
||||
$rev->{'schema_minor'} = shift;
|
||||
$rev->{'schema_patch'} = shift;
|
||||
$rev->{'alternative'} = '0';
|
||||
}
|
||||
return $rev;
|
||||
}
|
||||
@ -113,6 +130,7 @@ sub revision_hash {
|
||||
sub compare_revisions {
|
||||
my $a = shift;
|
||||
my $b = shift;
|
||||
my $test_alt = shift;
|
||||
|
||||
return -1 if ( $a->{'schema_major'} < $b->{'schema_major'} );
|
||||
return 1 if ( $a->{'schema_major'} > $b->{'schema_major'} );
|
||||
@ -123,6 +141,11 @@ sub compare_revisions {
|
||||
return -1 if ( $a->{'schema_patch'} < $b->{'schema_patch'} );
|
||||
return 1 if ( $a->{'schema_patch'} > $b->{'schema_patch'} );
|
||||
|
||||
if ( defined($test_alt) ) {
|
||||
return -1 if ( $a->{'alternative'} lt $b->{'alternative'} );
|
||||
return 1 if ( $a->{'alternative'} gt $b->{'alternative'} );
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -165,7 +188,7 @@ sub apply_patch {
|
||||
|
||||
$current_revision = get_current_revision();
|
||||
if ( compare_revisions($current_revision,revision_hash($patch)) != 0 ) {
|
||||
printf( "Failed to apply revision %s to the database!\n", $patch );
|
||||
printf( "Failed to apply revision %s to the database!\n", $patch ) if ( $debug );
|
||||
return 0;
|
||||
}
|
||||
return 1; # Success
|
||||
@ -188,11 +211,10 @@ sub apply_sql_file {
|
||||
$ENV{'PGPASS'} = $dbpass if ( $dbpass ne "" );
|
||||
|
||||
my $command = join ' ', @psql_opts;
|
||||
my $results = `$command 2>&1 1>/dev/null`;
|
||||
$last_results = `$command 2>&1 1>/dev/null`;
|
||||
|
||||
$results =~ s/^.*WARNING: there is no transaction in progress\s$//m;
|
||||
|
||||
print $results;
|
||||
$last_results =~ s/^.*WARNING: there is no transaction in progress\s$//m;
|
||||
$last_results =~ s/^.*NOTICE: //m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
debian/changelog
vendored
27
debian/changelog
vendored
@ -1,3 +1,30 @@
|
||||
rscds (0.9.2) unstable; urgency=low
|
||||
|
||||
* Add support for principal-url and calendar-home-set properties.
|
||||
* All events should be PUBLIC unless CLASS specifies otherwise.
|
||||
* Calendars can now be set such that all events are PUBLIC.
|
||||
* Add support for automatically added relationships.
|
||||
* Make some use of the improvements to the iCalendar class.
|
||||
* Working with iCal 3.0 from Mac OS 10.5.
|
||||
* Refactoring of driver code for LDAP and external AWL DB.
|
||||
|
||||
-- Andrew McMillan <debian@mcmillan.net.nz> Sun, 04 Nov 2007 23:31:10 +1300
|
||||
|
||||
rscds (0.9.1) unstable; urgency=low
|
||||
|
||||
* Reduce debug logging noise when debugging is iff
|
||||
* When class is NULL we should consider it to be PUBLIC.
|
||||
* Clean up some uninitialised variable warnings.
|
||||
* Refactoring caldav-PUT to allow calling from a different code path.
|
||||
* State how to make LDAP use an anonymous bind initially.
|
||||
* Include any VTODO in GET for a collection.
|
||||
* Minor permissions changes.
|
||||
* Fix VTODO handling by time-range queries.
|
||||
* Various fixes to LDAP authentication.
|
||||
* Fix permissions for RW access.
|
||||
|
||||
-- Andrew McMillan <debian@mcmillan.net.nz> Thu, 25 Oct 2007 16:30:06 +1300
|
||||
|
||||
rscds (0.9.0) unstable; urgency=low
|
||||
|
||||
* Changes preparatory to renaming to DAViCal
|
||||
|
||||
@ -43,6 +43,7 @@
|
||||
sort($clients);
|
||||
foreach( $clients AS $k => $v ) {
|
||||
if ( $v == "Interoperability" ) continue;
|
||||
if ( $v == "Other" ) continue;
|
||||
$style = (strcmp($client_page,$v) == 0 ? ' class="selected"' : '' );
|
||||
printf( '<p%s><a%s href="clients.php?client=%s">', $style, $style, urlencode($v) );
|
||||
if ( isset($icons[$v]) ) {
|
||||
@ -51,6 +52,9 @@
|
||||
echo "$v</a></p>\n";
|
||||
}
|
||||
|
||||
$style = ($client_page == "Other" ? ' class="selected"' : '' );
|
||||
printf( '<p%s><a%s href="clients.php?client=Other">Other</a></p>', $style, $style );
|
||||
|
||||
include("inc/page-middle.php");
|
||||
|
||||
include("clients/".$details[$client_page]);
|
||||
|
||||
@ -5,7 +5,7 @@ was little in the way of a repository available to test against until recently.<
|
||||
|
||||
<ol>
|
||||
<li>Select "File" then "New" then "Calendar" from the menus.</li>
|
||||
<li>Choose a type of "CalDAV", enter a name, and a URL such as <code>caldav://server.domain.name/caldav.php/username/home/</code>, enter your user name for RSCDS and click "OK".<img src="clients/Evolution-dialog1.png" /> <br /> </li>
|
||||
<li>Choose a type of "CalDAV", enter a name, and a URL such as <code>caldav://server.domain.name/caldav.php/username/home/</code>, enter your user name for DAViCal and click "OK".<img src="clients/Evolution-dialog1.png" /> <br /> </li>
|
||||
<li>You should now be prompted for a password for that username. Enter the password and your calendar should now show.</li>
|
||||
</ol>
|
||||
|
||||
@ -15,11 +15,11 @@ restart. If you still have problems try doing that, but killing evolution-data-
|
||||
</p>
|
||||
<p>Sometimes Evolution writes error messages into the cache file, so if you have ongoing problems you may want to
|
||||
take a look inside that.</p>
|
||||
<p>There are some quirks with Evolution's handling of CalDAV too, so perhaps take a look at the following
|
||||
bugs:</p>
|
||||
<p>There are some quirks with Evolution's handling of CalDAV too, prior to 2.12.0, so perhaps take a look at the following
|
||||
bugs (fixed in 2.12.0):</p>
|
||||
<ul>
|
||||
<li><a href="http://bugzilla.gnome.org/show_bug.cgi?id=355659">New appointments disappear for 1 minute, and then reappear</a></li>
|
||||
<li><a href="http://bugzilla.gnome.org/show_bug.cgi?id=354855">Support Response with Relative URLs</a></li>
|
||||
</ul>
|
||||
<p>There may also be bugs in Evolution's handling of SSL with CalDAV - I couldn't get it to work reliably.</p>
|
||||
<p>Hopefully those will be fixed before too long...</p>
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<h1>Cross-client Interoperability Considerations</h1>
|
||||
<p>If you intend to have users accessing the Really Simple CalDAV Store with more than one client
|
||||
<p>If you intend to have users accessing the DAViCal CalDAV Server with more than one client
|
||||
then you should attempt to structure the URLs which they use to access the system in the way
|
||||
that Mulberry does it.</p>
|
||||
<p>Basically, Mulberry breaks the URL into three parts:</p>
|
||||
|
||||
23
docs/website/clients/iCal-details.php
Normal file
23
docs/website/clients/iCal-details.php
Normal file
@ -0,0 +1,23 @@
|
||||
<h1>iCal</h1>
|
||||
<p><a href="http://www.apple.com/macosx/features/300.html#ical">iCal</a>, from version 3.0 (released with OS 10.5) is generally well-behaved
|
||||
and will discover your own calendars when configured. It will not allow you to manipulate other calendars on
|
||||
the same server, however, unless you use different credentials to access them.</p>
|
||||
|
||||
<ol>
|
||||
<li>Open the "Preferences" dialog.</li>
|
||||
<li>Choose the "Accounts" tab</li>
|
||||
<li>Click on the "+" and a new panel will appear.</li>
|
||||
<li>Enter a "Description" for the account.</li>
|
||||
<li>The "Username" and "Password" are the relevant ones for your CalDAV server.</li>
|
||||
<li>Open the "Server Options" area and set your account URL to point to http://host.../caldav.php/username/.<img src="clients/iCal-dialog.png" /> <br /> </li>
|
||||
<li>Click "Add" to confirm the new account</li>
|
||||
<li>Your own calendars will be automatically discovered.</li>
|
||||
<li>If you don't already have a calendar for your own user, go to the calendar view and long-click on the "+" will display a menu letting you create a new one.</li>
|
||||
</ol>
|
||||
|
||||
<h2>Caveats</h2>
|
||||
<p>DAViCal does not support the draft scheduling extensions to CalDAV, so you will not see the full functionality
|
||||
of iCal.</p>
|
||||
<p>iCal does not let you browse the calendar hierarchy to find other calendars you could view, so you will not
|
||||
see the full functionality of DAViCal either.</p>
|
||||
|
||||
BIN
docs/website/clients/iCal-dialog.png
Normal file
BIN
docs/website/clients/iCal-dialog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
BIN
docs/website/clients/iCal-icon.png
Normal file
BIN
docs/website/clients/iCal-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/website/clients/iCal-screenshot.png
Normal file
BIN
docs/website/clients/iCal-screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 201 KiB |
@ -11,7 +11,7 @@ echo $tags_to_be_closed;
|
||||
<a href="http://validator.w3.org/check?uri=referer" class="flink">XHTML</a> | <a href="http://jigsaw.w3.org/css-validator/check/referer" class="flink">CSS</a>
|
||||
</p>
|
||||
<p class="right">
|
||||
Copyright 2006 | Andrew McMillan
|
||||
Copyright 2007 | Andrew McMillan
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="http://andrew.mcmillan.net.nz/"><img src="http://sf-rscds.mcmillan.net.nz/clear-1.png" width="1" height="1" border="0" title="DAViCal CalDAV Server by Andrew McMillan" alt=" " /></a>
|
||||
|
||||
@ -6,6 +6,9 @@
|
||||
if ( isset($title) ) {
|
||||
echo " - ". $title;
|
||||
}
|
||||
else {
|
||||
echo " CalDAV Server";
|
||||
}
|
||||
?></title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
</head>
|
||||
@ -17,7 +20,7 @@ if ( isset($title) ) {
|
||||
echo $title;
|
||||
}
|
||||
else {
|
||||
echo "DAViCal";
|
||||
echo "DAViCal CalDAV Server";
|
||||
}
|
||||
?></div>
|
||||
<div id="subTitle">A CalDAV Store</div>
|
||||
|
||||
@ -40,9 +40,9 @@ few releases as we come to understand the particular problems people experience.
|
||||
<p>In general DAViCal should not need significant maintenance to keep it operating.</p>
|
||||
<p>Administrative functionality will be kept as simple as possible, within the target of supporting
|
||||
organisations of up to several hundred staff.</p>
|
||||
<p>This is called a <em>Store</em> rather than a <em>Server</em> because the server-side smarts are intended to be
|
||||
minimised to support CalDAV only in a manner sufficient to inter-operate with clients, and with the focus primarily
|
||||
on the storage of calendar resources.</p>
|
||||
<p>The server-side smarts in DAViCal are intended to be fairly minimal in order to support CalDAV
|
||||
only in a manner sufficient to inter-operate with clients, and with the focus primarily
|
||||
on the storage of calendar resources.</p>
|
||||
|
||||
<h2>Web-based Administration</h2>
|
||||
<p>General administration of the system should be through a web-based application.</p>
|
||||
@ -51,7 +51,7 @@ maintainable through a web-based client, although the server should support the
|
||||
works using the CalDAV protocol.</p>
|
||||
|
||||
<h1>Credits</h1>
|
||||
<p>The Really Simple CalDAV Store was conceived and written by <a href="http://andrew.mcmillan.net.nz/">Andrew McMillan</a>.</p>
|
||||
<p>DAViCal CalDAV Server was conceived and written by <a href="http://andrew.mcmillan.net.nz/">Andrew McMillan</a>.</p>
|
||||
<p>Translations of the administration interface have been done by:</p>
|
||||
<ul>
|
||||
<li>Lorena Paoletti (Spanish)</li>
|
||||
@ -62,7 +62,8 @@ works using the CalDAV protocol.</p>
|
||||
</ul>
|
||||
<p>Other contributors:</p>
|
||||
<ul>
|
||||
<li>Maxime Delorme (CSS for Administration Pages)</li>
|
||||
<li>Maxime Delorme (CSS, LDAP, SyncML, French translations)</li>
|
||||
<li>Andrew Ruthven (Various enhancements)</li>
|
||||
</ul>
|
||||
|
||||
<h1>Your Name Here!</h1>
|
||||
|
||||
@ -164,8 +164,11 @@ database on a different server, you should read the
|
||||
<a href="http://www.postgresql.org/docs/8.1/interactive/client-authentication.html">PostgreSQL documentation on pg_hba.conf</a>
|
||||
for the version you are using.</p>
|
||||
|
||||
<h1>Apache Configuration</h1>
|
||||
<p>Once you have changed the pg_hba.conf file you will need to
|
||||
reload or restart the PostgreSQL process for the change to come
|
||||
into effect.</p>
|
||||
|
||||
<h1>Apache Configuration</h1>
|
||||
<h2>Relative to an existing DocumentRoot</h2>
|
||||
|
||||
<p>You can create a symlink from an existing web root directory to the
|
||||
@ -204,6 +207,7 @@ single virtual host.</p>
|
||||
php_value magic_quotes_gpc 0
|
||||
php_value register_globals 0
|
||||
php_value error_reporting "E_ALL & ~E_NOTICE"
|
||||
php_value default_charset "utf-8"
|
||||
</VirtualHost>
|
||||
</pre>
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
/**
|
||||
* CalDAV Server - main program
|
||||
*
|
||||
* @package rscds
|
||||
* @package davical
|
||||
* @subpackage caldav
|
||||
* @author Andrew McMillan <andrew@catalyst.net.nz>
|
||||
* @copyright Catalyst .Net Ltd
|
||||
@ -14,6 +14,18 @@ require_once("HTTPAuthSession.php");
|
||||
$session = new HTTPAuthSession();
|
||||
dbg_log_array( "headers", '_SERVER', $_SERVER, true );
|
||||
|
||||
/**
|
||||
* From reading the "Scheduling Extensions to CalDAV" draft I don't think that we will
|
||||
* be doing 'calendar-schedule' any time soon. The current spec is at:
|
||||
* http://www.ietf.org/internet-drafts/draft-desruisseaux-caldav-sched-03.txt
|
||||
*
|
||||
* access-control is rfc3744, so we will say we do it, but I doubt if we do it
|
||||
* in all (or even much of) it's glory really.
|
||||
*/
|
||||
$dav = "1, 2, access-control, calendar-access";
|
||||
header( "DAV: $dav");
|
||||
// header( "DAV: 1, 2, access-control, calendar-access, calendar-schedule");
|
||||
|
||||
require_once("CalDAVRequest.php");
|
||||
$request = new CalDAVRequest();
|
||||
|
||||
@ -41,4 +53,3 @@ switch ( $request->method ) {
|
||||
|
||||
$request->DoResponse( 500, translate("The application program does not understand that request.") );
|
||||
|
||||
?>
|
||||
@ -1,4 +1,4 @@
|
||||
/* CSS for browse pages in RSCDS */
|
||||
/* CSS for browse pages in DAViCal */
|
||||
|
||||
tr.header th, td {
|
||||
padding: 1px 4px;
|
||||
|
||||
@ -5,13 +5,14 @@ $session->LoginRequired();
|
||||
|
||||
require_once("interactive-page.php");
|
||||
|
||||
$c->page_title = "Really Simple CalDAV Store - Configuration Help";
|
||||
$c->page_title = "DAViCal CalDAV Server - Configuration Help";
|
||||
include("page-header.php");
|
||||
|
||||
?>
|
||||
<h1>Help</h1>
|
||||
<p>For initial help you should visit the <a href="http://rscds.sourceforge.net/">RSCDS Home Page</a>. If you can't
|
||||
find the answers there, then you should post your problem in the RSCDS forums on Sourceforge itself.</p>
|
||||
<p>For initial help you should visit the <a href="http://rscds.sourceforge.net/">DAViCal Home Page</a>. If you can't
|
||||
find the answers there, visit the #davical IRC channel on irc.oftc.net, send a question to the mailing list or
|
||||
post your problem in the DAViCal forums on Sourceforge itself.</p>
|
||||
<?php
|
||||
|
||||
include("page-footer.php");
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
<?php
|
||||
require_once("../inc/always.php");
|
||||
require_once("RSCDSSession.php");
|
||||
if ( $_SERVER['REQUEST_METHOD'] != "GET" && $_SERVER['REQUEST_METHOD'] != "POST" ) {
|
||||
/**
|
||||
* If the request is not a GET or POST then they must really want caldav.php!
|
||||
*/
|
||||
include("./caldav.php");
|
||||
exit; // Not that it should return from that!
|
||||
}
|
||||
|
||||
include("../inc/always.php");
|
||||
include("RSCDSSession.php");
|
||||
$session->LoginRequired();
|
||||
|
||||
require_once("interactive-page.php");
|
||||
include("interactive-page.php");
|
||||
include("page-header.php");
|
||||
|
||||
echo <<<EOBODY
|
||||
@ -48,16 +56,15 @@ and then the group is linked to each resource with the "Administers Resource" re
|
||||
<li>Where a set of users link to a group, which then links to other users/resources, the access restrictions will apply as the lesser of their link to that group, or the link from the group. They will have no access to each other's calendars.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Configuring Calendar Clients for RSCDS</h2>
|
||||
<p>The <a href="http://rscds.sourceforge.net/clients.php">RSCDS client setup page on sourceforge</a> have information on how
|
||||
<h2>Configuring Calendar Clients for DAViCal</h2>
|
||||
<p>The <a href="http://rscds.sourceforge.net/clients.php">DAViCal client setup page on sourceforge</a> have information on how
|
||||
to configure Evolution, Sunbird, Lightning and Mulberry to use remotely hosted calendars.</p>
|
||||
<p>The administrative interface has no facility for viewing or modifying calendar data.</p>
|
||||
|
||||
<h2>Configuring RSCDS</h2>
|
||||
<h2>Configuring DAViCal</h2>
|
||||
<p>If you can read this then things must be mostly working already.</p>
|
||||
<p>The <a href="http://rscds.sourceforge.net/installation.php">RSCDS installation page</a> on sourceforge has
|
||||
<p>The <a href="http://rscds.sourceforge.net/installation.php">DAViCal installation page</a> on sourceforge has
|
||||
some further information on how to install and configure this application.</p>
|
||||
|
||||
<?php
|
||||
include("page-footer.php");
|
||||
?>
|
||||
@ -11,7 +11,7 @@ function Go( url ) {
|
||||
*/
|
||||
function LinkTo( tag, url ) {
|
||||
tag.style.cursor = "pointer";
|
||||
tag.setAttribute('onClick', "Go('" + url + "')");
|
||||
tag.setAttribute('onClick', "Go('" + url.replace('&','&') + "')");
|
||||
tag.setAttribute('onMouseOut', "window.status='';return true;");
|
||||
window.status = window.location.protocol + '//' + document.domain + url;
|
||||
tag.setAttribute('onMouseover', "window.status = window.location.protocol + '//' + document.domain + '" + url + "';return true;");
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Tools for manipulating calendars
|
||||
*
|
||||
* @package rscds
|
||||
* @package davical
|
||||
* @subpackage RSCDSSession
|
||||
* @author Maxime Delorme <mdelorme@tennaxia.com>
|
||||
* @copyright Maxime Delorme
|
||||
@ -20,7 +20,7 @@ require_once("classBrowser.php");
|
||||
if ( !$session->AllowedTo("Admin" ) )
|
||||
exit;
|
||||
|
||||
if(isset($_POST['Sync_LDAP'])){
|
||||
if( function_exists("sync_LDAP") && isset($_POST['Sync_LDAP'])){
|
||||
sync_LDAP();
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ class Tools {
|
||||
function render(){
|
||||
global $c;
|
||||
echo $this->renderImportFromDirectory();
|
||||
if($c->authenticate_hook['call'] == 'LDAP_check'){
|
||||
if ( $c->authenticate_hook['call'] == 'LDAP_check' && function_exists("sync_LDAP") ) {
|
||||
echo $this->renderSyncLDAP();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
/**
|
||||
* Display a list of all users
|
||||
*
|
||||
* @package rscds
|
||||
* @subpackage RSCDSSession
|
||||
* @package davical
|
||||
* @subpackage Admin
|
||||
* @author Andrew McMillan <andrew@catalyst.net.nz>
|
||||
* @copyright Catalyst .Net Ltd
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
|
||||
163
inc/CalDAVPrincipal.php
Normal file
163
inc/CalDAVPrincipal.php
Normal file
@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* An object representing a DAV 'Principal'
|
||||
*
|
||||
* @package davical
|
||||
* @subpackage Principal
|
||||
* @author Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Catalyst .Net Ltd
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var $_CalDAVPrincipalCache
|
||||
* A global variable holding a cache of any DAV Principals which are
|
||||
* read from the DB.
|
||||
*/
|
||||
$_CalDAVPrincipalCache = (object) array( 'p' => array(), 'u' => array() );
|
||||
|
||||
|
||||
/**
|
||||
* A class for things to do with a DAV Principal
|
||||
*
|
||||
* @package davical
|
||||
*/
|
||||
class CalDAVPrincipal
|
||||
{
|
||||
/**
|
||||
* @var The home URL of the principal
|
||||
*/
|
||||
var $url;
|
||||
|
||||
/**
|
||||
* @var RFC4791: Identifies the URL(s) of any WebDAV collections that contain
|
||||
* calendar collections owned by the associated principal resource.
|
||||
*/
|
||||
var $calendar_home_set;
|
||||
|
||||
/**
|
||||
* @var draft-desruisseaux-caldav-sched-03: Identify the URL of the scheduling
|
||||
* Inbox collection owned by the associated principal resource.
|
||||
*/
|
||||
var $schedule_inbox_url;
|
||||
|
||||
/**
|
||||
* @var draft-desruisseaux-caldav-sched-03: Identify the URL of the scheduling
|
||||
* Outbox collection owned by the associated principal resource.
|
||||
*/
|
||||
var $schedule_outbox_url;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param mixed $parameters If null, an empty Principal is created. If it
|
||||
* is an integer then that ID is read (if possible). If it is
|
||||
* an array then the Principal matching the supplied elements is read.
|
||||
*
|
||||
* @return boolean Whether we actually read data from the DB to initialise the record.
|
||||
*/
|
||||
function CalDAVPrincipal( $parameters = null ) {
|
||||
global $session, $c;
|
||||
|
||||
if ( $parameters == null ) return false;
|
||||
if ( is_int($parameters) ) {
|
||||
dbg_error_log( "principal", "Principal: %d", $parameters );
|
||||
$usr = getUserByID($parameters);
|
||||
}
|
||||
else if ( is_array($parameters) ) {
|
||||
if ( isset($parameters['username']) ) {
|
||||
$usr = getUserByName($parameters['username']);
|
||||
}
|
||||
else if ( isset($parameters['user_no']) ) {
|
||||
$usr = getUserByID($parameters['user_no']);
|
||||
}
|
||||
else if ( isset($parameters['path']) ) {
|
||||
dbg_error_log( "principal", "Finding Principal from path: '%s', options.allow_by_email: '%s'", $parameters['path'], $parameters['options']['allow_by_email'] );
|
||||
if ( $username = $this->UsernameFromPath($parameters['path'], $parameters['options']) ) {
|
||||
$usr = getUserByName($username);
|
||||
if ( isset($parameters['options']['allow_by_email']) && is_object($usr) && preg_match( '#/(\S+@\S+[.]\S+)$#', $parameters['path']) ) {
|
||||
$this->by_email = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( isset($parameters['principal-property-search']) ) {
|
||||
$usr = $this->PropertySearch($parameters['principal-property-search']);
|
||||
}
|
||||
}
|
||||
if ( !isset($usr) || !is_object($usr) ) return false;
|
||||
|
||||
$this->InitialiseRecord($usr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialise the Principal object from a $usr record from the DB.
|
||||
* @param object $usr The usr record from the DB.
|
||||
*/
|
||||
function InitialiseRecord($usr) {
|
||||
global $c;
|
||||
foreach( $usr AS $k => $v ) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
|
||||
$this->url = ConstructURL( "/".$this->username."/" );
|
||||
// $this->url = ConstructURL( "/__uuids__/" . $this->username . "/" );
|
||||
|
||||
$this->calendar_home_set = ConstructURL( "/".$this->username."/" );
|
||||
|
||||
$this->user_address_set = array(
|
||||
ConstructURL( "/".$this->username."/" ),
|
||||
// ConstructURL( "/~".$this->username."/" ),
|
||||
// ConstructURL( "/__uuids__/".$this->username."/" ),
|
||||
);
|
||||
$this->schedule_inbox_url = sprintf( "%s.in/", $this->calendar_home_set);
|
||||
$this->schedule_outbox_url = sprintf( "%s.out/", $this->calendar_home_set);
|
||||
$this->dropbox_url = sprintf( "%s.drop/", $this->calendar_home_set);
|
||||
$this->notifications_url = sprintf( "%s.notify/", $this->calendar_home_set);
|
||||
|
||||
dbg_error_log( "principal", "User: %s (%d) URL: %s, Home: %s, By Email: %d", $this->username, $this->user_no, $this->url, $this->calendar_home_set, $this->by_email );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Work out the username, based on elements of the path.
|
||||
* @param string $path The path to be used.
|
||||
* @param array $options The request options, controlling whether e-mail paths are allowed.
|
||||
*/
|
||||
function UsernameFromPath( $path, $options = null ) {
|
||||
global $session, $c;
|
||||
|
||||
if ( $path == '/' || $path == '' ) {
|
||||
dbg_error_log( "principal", "No useful path split possible" );
|
||||
return $session->username;
|
||||
}
|
||||
|
||||
$path_split = explode('/', $path );
|
||||
@dbg_error_log( "principal", "Path split into at least /// %s /// %s /// %s", $path_split[1], $path_split[2], $path_split[3] );
|
||||
|
||||
if ( substr($path,0,1) == '~' ) {
|
||||
// URL is for a principal, by name
|
||||
$username = substr($path_split[1],1);
|
||||
$user = getUserByID($username);
|
||||
$user_no = $user->user_no;
|
||||
}
|
||||
else {
|
||||
$username = $path_split[1];
|
||||
|
||||
if ( isset($options['allow_by_email']) && preg_match( '#/(\S+@\S+[.]\S+)$#', $path, $matches) ) {
|
||||
$email = $matches[1];
|
||||
$qry = new PgQuery("SELECT user_no, username FROM usr WHERE email = ?;", $email );
|
||||
if ( $qry->Exec("principal") && $user = $qry->Fetch() ) {
|
||||
$user_no = $user->user_no;
|
||||
$username = $user->username;
|
||||
}
|
||||
}
|
||||
elseif( $user = getUserByName( $username, 'caldav') ) {
|
||||
$user_no = $user->user_no;
|
||||
}
|
||||
}
|
||||
return $username;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -7,26 +7,53 @@
|
||||
* - Utility functions which we can use to decide whether this
|
||||
* is a permitted activity for this user.
|
||||
*
|
||||
* @package rscds
|
||||
* @subpackage CalDAVRequest
|
||||
* @package davical
|
||||
* @subpackage Request
|
||||
* @author Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Catalyst .Net Ltd
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
*/
|
||||
|
||||
require_once("XMLElement.php");
|
||||
require_once("CalDAVPrincipal.php");
|
||||
|
||||
define('DEPTH_INFINITY', 9999);
|
||||
|
||||
/**
|
||||
* A class for collecting things to do with this request.
|
||||
*
|
||||
* @package rscds
|
||||
* @package davical
|
||||
*/
|
||||
class CalDAVRequest
|
||||
{
|
||||
var $options;
|
||||
|
||||
/**
|
||||
* The raw data sent along with the request
|
||||
*/
|
||||
var $raw_post;
|
||||
|
||||
/**
|
||||
* The HTTP request method: PROPFIND, LOCK, REPORT, OPTIONS, etc...
|
||||
*/
|
||||
var $method;
|
||||
|
||||
/**
|
||||
* The depth parameter from the request headers, coerced into a valid integer: 0, 1
|
||||
* or DEPTH_INFINITY which is defined above. The default is set per various RFCs.
|
||||
*/
|
||||
var $depth;
|
||||
|
||||
/**
|
||||
* The 'principal' (user/resource/...) which this request seeks to access
|
||||
*/
|
||||
var $principal;
|
||||
|
||||
/**
|
||||
* The user agent making the request.
|
||||
*/
|
||||
var $user_agent;
|
||||
|
||||
/**
|
||||
* Create a new CalDAVRequest object.
|
||||
*/
|
||||
@ -34,6 +61,7 @@ class CalDAVRequest
|
||||
global $session, $c, $debugging;
|
||||
|
||||
$this->options = $options;
|
||||
$this->principal = (object) array( 'username' => $session->username, 'user_no' => $session->user_no );
|
||||
|
||||
$this->raw_post = file_get_contents ( 'php://input');
|
||||
|
||||
@ -42,6 +70,8 @@ class CalDAVRequest
|
||||
}
|
||||
$this->method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
$this->user_agent = ((isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "Probably Mulberry"));
|
||||
|
||||
/**
|
||||
* A variety of requests may set the "Depth" header to control recursion
|
||||
*/
|
||||
@ -117,6 +147,7 @@ class CalDAVRequest
|
||||
* the minimum privileges returned from that analysis.
|
||||
*/
|
||||
$this->path = $_SERVER['PATH_INFO'];
|
||||
if ( $this->path == null || $this->path == '' ) $this->path = '/';
|
||||
// dbg_error_log( "caldav", "Sanitising path '%s'", $this->path );
|
||||
$bad_chars_regex = '/[\\^\\[\\(\\\\]/';
|
||||
if ( preg_match( $bad_chars_regex, $this->path ) ) {
|
||||
@ -138,10 +169,17 @@ class CalDAVRequest
|
||||
}
|
||||
}
|
||||
|
||||
$this->user_no = $session->user_no;
|
||||
$this->username = $session->username;
|
||||
|
||||
/**
|
||||
* Extract the user whom we are accessing
|
||||
*/
|
||||
$this->UserFromPath();
|
||||
$this->principal = new CalDAVPrincipal( array( "path" => $this->path, "options" => $this->options ) );
|
||||
if ( isset($this->principal->user_no) ) $this->user_no = $this->principal->user_no;
|
||||
if ( isset($this->principal->username)) $this->username = $this->principal->username;
|
||||
if ( isset($this->principal->by_email)) $this->by_email = true;
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate our permissions for accessing the target
|
||||
@ -200,7 +238,8 @@ class CalDAVRequest
|
||||
$this->user_no = $user->user_no;
|
||||
}
|
||||
}
|
||||
elseif( $user = getUserByName($this->username,'caldav',__LINE__,__FILE__)){
|
||||
elseif( $user = getUserByName($this->username,'caldav',__LINE__,__FILE__)) {
|
||||
$this->principal = $user;
|
||||
$this->user_no = $user->user_no;
|
||||
}
|
||||
}
|
||||
@ -481,9 +520,14 @@ class CalDAVRequest
|
||||
break;
|
||||
|
||||
case 'create':
|
||||
return isset($this->permissions['write']) || isset($this->permissions['bind']);
|
||||
break;
|
||||
|
||||
case 'mkcalendar':
|
||||
case 'mkcol':
|
||||
return isset($this->permissions['write']) || isset($this->permissions['bind']);
|
||||
if ( !isset($this->permissions['write']) || !isset($this->permissions['bind']) ) return false;
|
||||
if ( $this->is_principal ) return false;
|
||||
if ( $this->path == '/' ) return false;
|
||||
break;
|
||||
|
||||
case 'read':
|
||||
@ -566,4 +610,3 @@ class CalDAVRequest
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@ -50,7 +50,7 @@ class HTTPAuthSession {
|
||||
function HTTPAuthSession() {
|
||||
global $c;
|
||||
|
||||
if ( $c->http_auth_mode == "Digest" ) {
|
||||
if ( isset($c->http_auth_mode) && $c->http_auth_mode == "Digest" ) {
|
||||
$this->DigestAuthSession();
|
||||
}
|
||||
else {
|
||||
|
||||
@ -282,23 +282,25 @@ class iCalDate {
|
||||
function AddDuration( $duration ) {
|
||||
list( $sign, $days, $time ) = preg_split( '/[PT]/', $duration );
|
||||
$sign = ( $sign == "-" ? -1 : 1);
|
||||
dbg_error_log( "RRule", " Adding duration to '%s' of sign: %d, days: %s, time: %s", $this->_text, $sign, $days, $time );
|
||||
if ( preg_match( '/(\d)+(D|W)/', $days, $matches ) ) {
|
||||
$days = intval($matches[1]);
|
||||
if ( $matches[2] == 'W' ) $days *= 7;
|
||||
$this->AddDays( $days * $sign );
|
||||
}
|
||||
if ( preg_match( '/(\d)+(H)/', $time, $matches ) ) $hh = $matches[1];
|
||||
if ( preg_match( '/(\d)+(M)/', $time, $matches ) ) $mi = $matches[1];
|
||||
if ( preg_match( '/(\d)+(S)/', $time, $matches ) ) $ss = $matches[1];
|
||||
if ( preg_match( '/(\d+)(H)/', $time, $matches ) ) $hh = $matches[1];
|
||||
if ( preg_match( '/(\d+)(M)/', $time, $matches ) ) $mi = $matches[1];
|
||||
if ( preg_match( '/(\d+)(S)/', $time, $matches ) ) $ss = $matches[1];
|
||||
|
||||
dbg_error_log( "RRule", " Adding %02d:%02d:%02d * %d to %02d:%02d:%02d", $hh, $mi, $ss, $sign, $this->_hh, $this->_mi, $this->_ss );
|
||||
$this->_hh += ($hh * $sign);
|
||||
$this->_mi += ($mi * $sign);
|
||||
$this->_ss += ($ss * $sign);
|
||||
|
||||
if ( $this->_ss < 0 ) { $this->_mi -= (intval(abs($this->ss/60))+1); $this->_ss += ((intval(abs($this->mi/60))+1) * 60); }
|
||||
if ( $this->_ss > 59) { $this->_mi += (intval(abs($this->ss/60))+1); $this->_ss -= ((intval(abs($this->mi/60))+1) * 60); }
|
||||
if ( $this->_mi < 0 ) { $this->_hh -= (intval(abs($this->mi/60))+1); $this->_mi += ((intval(abs($this->mi/60))+1) * 60); }
|
||||
if ( $this->_mi > 59) { $this->_hh += (intval(abs($this->mi/60))+1); $this->_mi -= ((intval(abs($this->mi/60))+1) * 60); }
|
||||
if ( $this->_ss < 0 ) { $this->_mi -= (intval(abs($this->_ss/60))+1); $this->_ss += ((intval(abs($this->_mi/60))+1) * 60); }
|
||||
if ( $this->_ss > 59) { $this->_mi += (intval(abs($this->_ss/60))+1); $this->_ss -= ((intval(abs($this->_mi/60))+1) * 60); }
|
||||
if ( $this->_mi < 0 ) { $this->_hh -= (intval(abs($this->_mi/60))+1); $this->_mi += ((intval(abs($this->_mi/60))+1) * 60); }
|
||||
if ( $this->_mi > 59) { $this->_hh += (intval(abs($this->_mi/60))+1); $this->_mi -= ((intval(abs($this->_mi/60))+1) * 60); }
|
||||
if ( $this->_hh < 0 ) { $this->AddDays( -1 * (intval(abs($this->_hh/24))+1) ); $this->_hh += ((intval(abs($this->_hh/24))+1)*24); }
|
||||
if ( $this->_hh > 23) { $this->AddDays( (intval(abs($this->_hh/24))+1) ); $this->_hh -= ((intval(abs($this->_hh/24))+1)*24); }
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
require_once("User.php");
|
||||
require_once("classBrowser.php");
|
||||
require_once("auth-functions.php");
|
||||
|
||||
$c->stylesheets[] = "$c->base_url/css/browse.css";
|
||||
$c->scripts[] = "$c->base_url/js/browse.js";
|
||||
@ -306,24 +307,11 @@ EOSQL;
|
||||
|
||||
if ( parent::Write() ) {
|
||||
if ( $this->WriteType == 'insert' ) {
|
||||
if ( isset($c->home_calendar_name) && strlen($c->home_calendar_name) > 0 ) {
|
||||
$parent_path = "/".$this->Get('username')."/";
|
||||
$calendar_path = $parent_path . $c->home_calendar_name."/";
|
||||
$dav_etag = md5($this->user_no . $calendar_path);
|
||||
$sql = "INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, ";
|
||||
$sql .= "created, modified) VALUES( ?, ?, ?, ?, ?, true, current_timestamp, current_timestamp );";
|
||||
$qry = new PgQuery( $sql, $this->user_no, $parent_path, $calendar_path, $dav_etag, $this->Get('fullname') );
|
||||
if ( $qry->Exec() ) {
|
||||
$c->messages[] = i18n("Home calendar added.");
|
||||
dbg_error_log("User",":Write: Created user's home calendar at '%s'", $calendar_path );
|
||||
}
|
||||
else {
|
||||
$c->messages[] = i18n("There was an error writing to the database.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$username = $this->Get('username');
|
||||
CreateHomeCalendar($username);
|
||||
CreateDefaultRelationships($username);
|
||||
}
|
||||
if ( $this->AllowedTo("Admin") && isset($_POST['relate_to']) && isset($_POST['relate_as']) && isset($_POST['submit']) && $_POST['submit'] == htmlspecialchars(translate('Add Relationship')) ) {
|
||||
if ( $this->AllowedTo("Admin") && isset($_POST['relate_to']) && $_POST['relate_to'] != '' && isset($_POST['relate_as']) && $_POST['relate_as'] != '' && isset($_POST['submit']) && $_POST['submit'] == htmlspecialchars(translate('Add Relationship')) ) {
|
||||
dbg_error_log("User",":Write: Adding relationship as %d to %d", $_POST['relate_as'], isset($_POST['relate_to'] ) );
|
||||
$qry = new PgQuery("INSERT INTO relationship (from_user, to_user, rt_id ) VALUES( $this->user_no, ?, ? )", $_POST['relate_to'], $_POST['relate_as'] );
|
||||
if ( $qry->Exec() ) {
|
||||
@ -338,6 +326,6 @@ EOSQL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@ -11,13 +11,14 @@ unset($c);
|
||||
|
||||
// Default some of the configurable values
|
||||
$c->sysabbr = 'davical';
|
||||
$c->admin_email = 'andrew@catalyst.net.nz';
|
||||
$c->admin_email = 'admin@davical.example.com';
|
||||
$c->system_name = "DAViCal CalDAV Server";
|
||||
$c->domain_name = $_SERVER['SERVER_NAME'];
|
||||
$c->save_time_zone_defs = true;
|
||||
$c->collections_always_exist = true;
|
||||
$c->home_calendar_name = 'home';
|
||||
$c->enable_row_linking = true;
|
||||
$c->http_auth_mode = 'Basic';
|
||||
// $c->default_locale = array('es_MX', 'es_MX.UTF-8', 'es');
|
||||
// $c->local_tzid = 'Pacific/Auckland'; // Perhaps we should read from /etc/timezone - I wonder how standard that is?
|
||||
$c->default_locale = "en_NZ";
|
||||
@ -48,9 +49,7 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS
|
||||
? ''
|
||||
: ':'.$_SERVER['SERVER_PORT']
|
||||
),
|
||||
$_SERVER['SCRIPT_NAME'] );
|
||||
|
||||
@dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory );
|
||||
($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']) );
|
||||
|
||||
init_gettext( 'rscds', '../locale' );
|
||||
|
||||
@ -64,11 +63,17 @@ else if ( file_exists("../config/config.php") ) {
|
||||
include_once("../config/config.php");
|
||||
}
|
||||
else {
|
||||
include_once("rscds_configuration_missing.php");
|
||||
include_once("davical_configuration_missing.php");
|
||||
exit;
|
||||
}
|
||||
if ( !isset($c->page_title) ) $c->page_title = $c->system_name;
|
||||
|
||||
if ( count($c->dbg) > 0 ) {
|
||||
// Only log this if debugging of some sort is turned on, somewhere
|
||||
@dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=",
|
||||
$_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory );
|
||||
}
|
||||
|
||||
/**
|
||||
* Now that we have loaded the configuration file we can switch to a
|
||||
* default site locale. This may be overridden by each user.
|
||||
@ -80,15 +85,15 @@ awl_set_locale($c->default_locale);
|
||||
*
|
||||
*/
|
||||
$c->code_version = 0;
|
||||
$c->version_string = '0.9.0'; // The actual version # is replaced into that during the build /release process
|
||||
$c->version_string = '0.9.2'; // The actual version # is replaced into that during the build /release process
|
||||
if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) {
|
||||
$c->code_major = $matches[1];
|
||||
$c->code_minor = $matches[1];
|
||||
$c->code_patch = $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 %s (%d.%d.%d) == %s", $c->code_pkgver, $c->code_major, $c->code_minor, $c->code_patch, $c->code_version);
|
||||
header( sprintf("Server: %s/%d.%d", $c->code_pkgver, $c->code_major, $c->code_minor) );
|
||||
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
|
||||
@ -106,15 +111,45 @@ if ( $qry->Exec("always") && $row = $qry->Fetch() ) {
|
||||
$c->schema_patch = $row->schema_patch;
|
||||
}
|
||||
|
||||
$_known_users = array();
|
||||
function getUserByName( $username ) {
|
||||
|
||||
$_known_users_name = array();
|
||||
$_known_users_id = array();
|
||||
/**
|
||||
* Return a user record identified by a username, caching it for any subsequent lookup
|
||||
* @param string $username The username of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByName( $username, $use_cache = true ) {
|
||||
// Provide some basic caching in case this ends up being overused.
|
||||
if ( isset( $_known_users[$username] ) ) return $_known_users[$username];
|
||||
if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username];
|
||||
|
||||
$qry = new PgQuery( "SELECT * FROM usr WHERE lower(username) = lower(?) ", $username );
|
||||
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) {
|
||||
$_known_users[$username] = $qry->Fetch();
|
||||
return $_known_users[$username];
|
||||
$_known_users_name[$username] = $qry->Fetch();
|
||||
$id = $_known_users_name[$username]->user_no;
|
||||
$_known_users_id[$id] = $_known_users_name[$username];
|
||||
return $_known_users_name[$username];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a user record identified by a user_no, caching it for any subsequent lookup
|
||||
* @param int $user_no The ID of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByID( $user_no, $use_cache = true ) {
|
||||
// Provide some basic caching in case this ends up being overused.
|
||||
if ( $use_cache && isset( $_known_users_id[$user_no] ) ) return $_known_users_id[$user_no];
|
||||
|
||||
$qry = new PgQuery( "SELECT * FROM usr WHERE user_no = ? ", intval($user_no) );
|
||||
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) {
|
||||
$_known_users_id[$user_no] = $qry->Fetch();
|
||||
$name = $_known_users_id[$user_no]->username;
|
||||
$_known_users_name[$name] = $_known_users_id[$user_no];
|
||||
return $_known_users_id[$user_no];
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -178,4 +213,24 @@ function getStatusMessage($status) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a URL from the supplied dav_name
|
||||
* @param string $partial_path The part of the path after the script name
|
||||
*/
|
||||
function ConstructURL( $partial_path ) {
|
||||
global $c;
|
||||
|
||||
if ( ! isset($c->_url_script_path) ) {
|
||||
$c->_url_script_path = (preg_match('#/$#', $c->protocol_server_port_script) ? 'caldav.php' : '');
|
||||
$c->_url_script_path = $c->protocol_server_port_script . $c->_url_script_path;
|
||||
}
|
||||
|
||||
$url = $c->_url_script_path . $partial_path;
|
||||
$url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/'
|
||||
$url = preg_replace('#^https?://[^/]+#', '', $url );
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@ -11,13 +11,14 @@ unset($c);
|
||||
|
||||
// Default some of the configurable values
|
||||
$c->sysabbr = 'davical';
|
||||
$c->admin_email = 'andrew@catalyst.net.nz';
|
||||
$c->admin_email = 'admin@davical.example.com';
|
||||
$c->system_name = "DAViCal CalDAV Server";
|
||||
$c->domain_name = $_SERVER['SERVER_NAME'];
|
||||
$c->save_time_zone_defs = true;
|
||||
$c->collections_always_exist = true;
|
||||
$c->home_calendar_name = 'home';
|
||||
$c->enable_row_linking = true;
|
||||
$c->http_auth_mode = 'Basic';
|
||||
// $c->default_locale = array('es_MX', 'es_MX.UTF-8', 'es');
|
||||
// $c->local_tzid = 'Pacific/Auckland'; // Perhaps we should read from /etc/timezone - I wonder how standard that is?
|
||||
$c->default_locale = "en_NZ";
|
||||
@ -48,9 +49,7 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS
|
||||
? ''
|
||||
: ':'.$_SERVER['SERVER_PORT']
|
||||
),
|
||||
$_SERVER['SCRIPT_NAME'] );
|
||||
|
||||
@dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory );
|
||||
($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']) );
|
||||
|
||||
init_gettext( 'rscds', '../locale' );
|
||||
|
||||
@ -64,11 +63,17 @@ else if ( file_exists("../config/config.php") ) {
|
||||
include_once("../config/config.php");
|
||||
}
|
||||
else {
|
||||
include_once("rscds_configuration_missing.php");
|
||||
include_once("davical_configuration_missing.php");
|
||||
exit;
|
||||
}
|
||||
if ( !isset($c->page_title) ) $c->page_title = $c->system_name;
|
||||
|
||||
if ( count($c->dbg) > 0 ) {
|
||||
// Only log this if debugging of some sort is turned on, somewhere
|
||||
@dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=",
|
||||
$_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory );
|
||||
}
|
||||
|
||||
/**
|
||||
* Now that we have loaded the configuration file we can switch to a
|
||||
* default site locale. This may be overridden by each user.
|
||||
@ -83,12 +88,12 @@ $c->code_version = 0;
|
||||
$c->version_string = '0.7.0~rc3'; // The actual version # is replaced into that during the build /release process
|
||||
if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) {
|
||||
$c->code_major = $matches[1];
|
||||
$c->code_minor = $matches[1];
|
||||
$c->code_patch = $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 %s (%d.%d.%d) == %s", $c->code_pkgver, $c->code_major, $c->code_minor, $c->code_patch, $c->code_version);
|
||||
header( sprintf("Server: %s/%d.%d", $c->code_pkgver, $c->code_major, $c->code_minor) );
|
||||
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
|
||||
@ -106,15 +111,45 @@ if ( $qry->Exec("always") && $row = $qry->Fetch() ) {
|
||||
$c->schema_patch = $row->schema_patch;
|
||||
}
|
||||
|
||||
$_known_users = array();
|
||||
function getUserByName( $username ) {
|
||||
|
||||
$_known_users_name = array();
|
||||
$_known_users_id = array();
|
||||
/**
|
||||
* Return a user record identified by a username, caching it for any subsequent lookup
|
||||
* @param string $username The username of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByName( $username, $use_cache = true ) {
|
||||
// Provide some basic caching in case this ends up being overused.
|
||||
if ( isset( $_known_users[$username] ) ) return $_known_users[$username];
|
||||
if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username];
|
||||
|
||||
$qry = new PgQuery( "SELECT * FROM usr WHERE lower(username) = lower(?) ", $username );
|
||||
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) {
|
||||
$_known_users[$username] = $qry->Fetch();
|
||||
return $_known_users[$username];
|
||||
$_known_users_name[$username] = $qry->Fetch();
|
||||
$id = $_known_users_name[$username]->user_no;
|
||||
$_known_users_id[$id] = $_known_users_name[$username];
|
||||
return $_known_users_name[$username];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a user record identified by a user_no, caching it for any subsequent lookup
|
||||
* @param int $user_no The ID of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByID( $user_no, $use_cache = true ) {
|
||||
// Provide some basic caching in case this ends up being overused.
|
||||
if ( $use_cache && isset( $_known_users_id[$user_no] ) ) return $_known_users_id[$user_no];
|
||||
|
||||
$qry = new PgQuery( "SELECT * FROM usr WHERE user_no = ? ", intval($user_no) );
|
||||
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) {
|
||||
$_known_users_id[$user_no] = $qry->Fetch();
|
||||
$name = $_known_users_id[$user_no]->username;
|
||||
$_known_users_name[$name] = $_known_users_id[$user_no];
|
||||
return $_known_users_id[$user_no];
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -178,4 +213,21 @@ function getStatusMessage($status) {
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
/**
|
||||
* Construct a URL from the supplied dav_name
|
||||
* @param string $partial_path The part of the path after the script name
|
||||
*/
|
||||
function ConstructURL( $partial_path ) {
|
||||
global $c;
|
||||
|
||||
if ( ! isset($c->_url_script_path) ) {
|
||||
$c->_url_script_path = (preg_match('#/$#', $c->protocol_server_port_script) ? 'caldav.php' : '');
|
||||
$c->_url_script_path = $c->protocol_server_port_script . $c->_url_script_path;
|
||||
}
|
||||
|
||||
$url = $c->_url_script_path . $partial_path;
|
||||
$url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/'
|
||||
$url = preg_replace('#^https?://[^/]+#', '', $url );
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
||||
179
inc/auth-functions.php
Normal file
179
inc/auth-functions.php
Normal file
@ -0,0 +1,179 @@
|
||||
<?php
|
||||
/**
|
||||
* The authentication handling plugins can be used by the Session class to
|
||||
* provide authentication.
|
||||
*
|
||||
* Each authenticate hook needs to:
|
||||
* - Accept a username / password
|
||||
* - Confirm the username / password are correct
|
||||
* - Create (or update) a 'usr' record in our database
|
||||
* - Return the 'usr' record as an object
|
||||
* - Return === false when authentication fails
|
||||
*
|
||||
* It can expect that:
|
||||
* - Configuration data will be in $c->authenticate_hook['config'], which might be an array, or whatever is needed.
|
||||
*
|
||||
* In order to be called:
|
||||
* - This file should be included
|
||||
* - $c->authenticate_hook['call'] should be set to the name of the plugin
|
||||
* - $c->authenticate_hook['config'] should be set up with any configuration data for the plugin
|
||||
*
|
||||
* @package davical
|
||||
* @subpackage authentication
|
||||
* @author Andrew McMillan <andrew@catalyst.net.nz>
|
||||
* @copyright Catalyst IT Ltd
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
*/
|
||||
|
||||
require_once("AWLUtilities.php");
|
||||
require_once("DataUpdate.php");
|
||||
|
||||
|
||||
/**
|
||||
* Create a default home calendar for the user.
|
||||
* @param string $username The username of the user we are creating relationships for.
|
||||
*/
|
||||
function CreateHomeCalendar( $username ) {
|
||||
global $session, $c;
|
||||
if ( ! isset($c->home_calendar_name) || strlen($c->home_calendar_name) == 0 ) return true;
|
||||
|
||||
$usr = getUserByName( $username );
|
||||
$parent_path = "/".$username."/";
|
||||
$calendar_path = $parent_path . $c->home_calendar_name."/";
|
||||
$dav_etag = md5($usr->user_no . $calendar_path);
|
||||
$sql = "INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, ";
|
||||
$sql .= "created, modified) VALUES( ?, ?, ?, ?, ?, true, current_timestamp, current_timestamp );";
|
||||
$qry = new PgQuery( $sql, $usr->user_no, $parent_path, $calendar_path, $dav_etag, $usr->fullname);
|
||||
if ( $qry->Exec() ) {
|
||||
$c->messages[] = i18n("Home calendar added.");
|
||||
dbg_error_log("User",":Write: Created user's home calendar at '%s'", $calendar_path );
|
||||
}
|
||||
else {
|
||||
$c->messages[] = i18n("There was an error writing to the database.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create default relationships
|
||||
* @param string $username The username of the user we are creating relationships for.
|
||||
*/
|
||||
function CreateDefaultRelationships( $username ) {
|
||||
global $session, $c;
|
||||
if ( ! isset($c->default_relationships) || !is_array($c->default_relationships) || count($c->default_relationships) == 0 ) return false;
|
||||
|
||||
$usr = getUserByName( $username );
|
||||
$sql = "";
|
||||
foreach( $c->default_relationships AS $to_user => $permission ) {
|
||||
$sql .= "INSERT INTO relationship (from_user, to_user, rt_id) ";
|
||||
$sql .= "VALUES( $usr->user_no, $to_user, (select rt_id from relationship_type where confers = '$permission' order by rt_id limit 1) );";
|
||||
}
|
||||
$qry = new PgQuery( $sql );
|
||||
if ( $qry->Exec() ) {
|
||||
$c->messages[] = i18n("Default relationships added.");
|
||||
dbg_error_log("User",":Write: Added default relationships" );
|
||||
}
|
||||
else {
|
||||
$c->messages[] = i18n("There was an error writing to the database.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the local cache of the remote user details
|
||||
* @param object $usr The user details we read from the remote.
|
||||
*/
|
||||
function UpdateUserFromExternal( &$usr ) {
|
||||
/**
|
||||
* When we're doing the create we will usually need to generate a user number
|
||||
*/
|
||||
if ( !isset($usr->user_no) || intval($usr->user_no) == 0 ) {
|
||||
$qry = new PgQuery( "SELECT nextval('usr_user_no_seq');" );
|
||||
$qry->Exec('Login',__LINE,__FILE__);
|
||||
$sequence_value = $qry->Fetch(true); // Fetch as an array
|
||||
$usr->user_no = $sequence_value[0];
|
||||
}
|
||||
|
||||
$qry = new PgQuery("SELECT * FROM usr WHERE user_no = $usr->user_no;" );
|
||||
if ( $qry->Exec('Login',__LINE,__FILE__) && $qry->rows == 1 )
|
||||
$type = "UPDATE";
|
||||
else
|
||||
$type = "INSERT";
|
||||
|
||||
$qry = new PgQuery( sql_from_object( $usr, $type, 'usr', "WHERE user_no=$usr->user_no" ) );
|
||||
$qry->Exec('Login',__LINE,__FILE__);
|
||||
|
||||
/**
|
||||
* We disallow login by inactive users _after_ we have updated the local copy
|
||||
*/
|
||||
if ( isset($usr->active) && $usr->active == 'f' ) return false;
|
||||
|
||||
if ( $type == 'INSERT' ) {
|
||||
CreateHomeCalendar($usr->username);
|
||||
CreateDefaultRelationships($usr->username);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
$authconn = pg_Connect($c->authenticate_hook['config']['connection']);
|
||||
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 ( 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 PgQuery("SELECT $cols FROM usr WHERE lower(username) = ? $andwhere", strtolower($username) );
|
||||
$qry->SetConnection($authconn);
|
||||
if ( $qry->Exec('Login',__LINE,__FILE__) && $qry->rows == 1 ) {
|
||||
$usr = $qry->Fetch();
|
||||
if ( session_validate_password( $password, $usr->password ) ) {
|
||||
UpdateUserFromExternal();
|
||||
return $usr;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
@ -15,7 +15,7 @@ if ( ! $request->AllowedTo('read') ) {
|
||||
}
|
||||
$privacy_clause = "";
|
||||
if ( ! $request->AllowedTo('all') ) {
|
||||
$privacy_clause = "AND calendar_item.class != 'PRIVATE'";
|
||||
$privacy_clause = "AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL) ";
|
||||
}
|
||||
|
||||
if ( $request->IsCollection() ) {
|
||||
@ -45,6 +45,10 @@ else if ( $qry->rows > 1 ) {
|
||||
*/
|
||||
include_once("iCalendar.php");
|
||||
$response = iCalendar::iCalHeader();
|
||||
$collqry = new PgQuery( "SELECT * FROM collection WHERE collection.user_no = ? AND collection.dav_name = ?;", $request->user_no, $request->path);
|
||||
if ( $collqry->Exec("GET") && $collection = $collqry->Fetch() ) {
|
||||
$response .= "X-WR-CALNAME:$collection->dav_displayname\r\n";
|
||||
}
|
||||
$timezones = array();
|
||||
while( $event = $qry->Fetch() ) {
|
||||
$ical = new iCalendar( array( "icalendar" => $event->caldav_data ) );
|
||||
@ -57,13 +61,27 @@ else if ( $qry->rows > 1 ) {
|
||||
// the user is not admin / owner of this calendarlooking at his calendar and can not admin the other cal
|
||||
if ( $event->class == 'CONFIDENTIAL' ) {
|
||||
// if the event is confidential we fake one that just says "Busy"
|
||||
$displayname = translate("Busy");
|
||||
$ical->Put( 'SUMMARY', $displayname );
|
||||
$response .= $ical->Render( false, $event->caldav_type, $ical->DefaultPropertyList() );
|
||||
$confidential = new iCalendar( array(
|
||||
'SUMMARY' => translate('Busy'), 'CLASS' => 'CONFIDENTIAL',
|
||||
'DTSTART' => $ical->Get('DTSTART'),
|
||||
'RRULE' => $ical->Get('RRULE')
|
||||
) );
|
||||
$duration = $ical->Get('DURATION');
|
||||
if ( isset($duration) && $duration != "" ) {
|
||||
$confidential->Set('DURATION', $duration );
|
||||
}
|
||||
else {
|
||||
$confidential->Set('DTEND', $ical->Get('DTEND') );
|
||||
}
|
||||
$response .= $confidential->Render( false, $event->caldav_type );
|
||||
}
|
||||
elseif ( $c->hide_alarm ) {
|
||||
// Otherwise we hide the alarms (if configured to)
|
||||
$response .= $ical->Render( false, $event->caldav_type, $ical->DefaultPropertyList() );
|
||||
$ical->component->ClearComponents('VALARM');
|
||||
$response .= $ical->render(true, $event->caldav_type );
|
||||
}
|
||||
else {
|
||||
$response .= $ical->Render( false, $event->caldav_type );
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -81,4 +99,3 @@ else {
|
||||
$request->DoResponse( 500, translate("Database Error") );
|
||||
}
|
||||
|
||||
?>
|
||||
@ -15,6 +15,13 @@ if ( ! $request->AllowedTo('mkcalendar') ) {
|
||||
}
|
||||
|
||||
$displayname = $request->path;
|
||||
|
||||
// Enforce trailling '/' on collection name
|
||||
if ( ! preg_match( '#/$#', $request->path ) ) {
|
||||
dbg_error_log( "MKCALENDAR", "Add trailling '/' to '%s'", $request->path);
|
||||
$request->path .= '/';
|
||||
}
|
||||
|
||||
$parent_container = '/';
|
||||
if ( preg_match( '#^(.*/)([^/]+)(/)?$#', $request->path, $matches ) ) {
|
||||
$parent_container = $matches[1];
|
||||
@ -42,13 +49,26 @@ if ( isset($request->xml_tags) ) {
|
||||
|
||||
case 'DAV::DISPLAYNAME':
|
||||
$displayname = $content;
|
||||
/**
|
||||
* TODO: This is definitely a bug in SOHO Organizer and we probably should respond
|
||||
* with an error, rather than silently doing what they *seem* to want us to do.
|
||||
*/
|
||||
if ( preg_match( '/^SOHO.Organizer.6\./', $_SERVER['HTTP_USER_AGENT'] ) ) {
|
||||
dbg_error_log( "MKCALENDAR", "Displayname is '/' to '%s'", $request->path);
|
||||
$parent_container = $request->path;
|
||||
$request->path .= $content . '/';
|
||||
}
|
||||
$success[$tag] = 1;
|
||||
break;
|
||||
|
||||
case 'DAV::RESOURCETYPE':
|
||||
/**
|
||||
* Any value for resourcetype is ignored
|
||||
*/
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET': /** Ignored, since we will support all component types */
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-DATA': /** Ignored, since we will support iCalendar 2.0 */
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DATA': /** Ignored, since we will support iCalendar 2.0 */
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-RESOURCE-SIZE': /** Ignored, since we will support arbitrary size */
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MIN-DATE-TIME': /** Ignored, since we will support arbitrary time */
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-DATE-TIME': /** Ignored, since we will support arbitrary time */
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-INSTANCES': /** Ignored, since we will support arbitrary instances */
|
||||
case 'DAV::RESOURCETYPE': /** Any value for resourcetype is ignored */
|
||||
$success[$tag] = 1;
|
||||
break;
|
||||
|
||||
@ -109,7 +129,7 @@ if ( $qry->rows != 0 ) {
|
||||
$request->DoResponse( 405, translate("A collection already exists at that location.") );
|
||||
}
|
||||
|
||||
$sql = "INSERT INTO collection ( user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp );";
|
||||
$sql = "BEGIN; INSERT INTO collection ( user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp ); $propertysql; COMMIT;";
|
||||
$qry = new PgQuery( $sql, $request->user_no, $parent_container, $request->path, md5($request->user_no. $request->path), $displayname, ($request->method == 'MKCALENDAR') );
|
||||
|
||||
if ( $qry->Exec("MKCALENDAR",__LINE__,__FILE__) ) {
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
dbg_error_log("OPTIONS", "method handler");
|
||||
|
||||
if ( ! $request->AllowedTo('read') ) {
|
||||
$request->DoResponse( 403, translate("You may not access that calendar") );
|
||||
$request->DoResponse( 403, translate("You may not access that collection") );
|
||||
}
|
||||
|
||||
$exists = false;
|
||||
@ -55,21 +55,13 @@ if ( isset($c->override_allowed_methods) )
|
||||
$allowed = $c->override_allowed_methods;
|
||||
else {
|
||||
$allowed = "OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH";
|
||||
if ( $request->path == '/' ) {
|
||||
$exists = true;
|
||||
$allowed = "OPTIONS, GET, HEAD, PROPFIND, REPORT";
|
||||
}
|
||||
}
|
||||
header( "Allow: $allowed");
|
||||
|
||||
/**
|
||||
* From reading the "Scheduling Extensions to CalDAV" draft I don't think that we will
|
||||
* be doing 'calendar-schedule' any time soon. The current spec is at:
|
||||
* http://www.ietf.org/internet-drafts/draft-desruisseaux-caldav-sched-02.txt
|
||||
*
|
||||
* access-control is rfc3744, so we will say we do it, but I doubt if we do it
|
||||
* in all (or even much of) it's glory really.
|
||||
*/
|
||||
$dav = "1, 2, access-control, calendar-access";
|
||||
header( "Allow: $allowed");
|
||||
header( "DAV: $dav");
|
||||
// header( "DAV: 1, 2, access-control, calendar-access, calendar-schedule");
|
||||
|
||||
$request->DoResponse( 200, "" );
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
/**
|
||||
* CalDAV Server - handle PROPFIND method
|
||||
*
|
||||
* @package rscds
|
||||
* @subpackage caldav
|
||||
* @package davical
|
||||
* @subpackage propfind
|
||||
* @author Andrew McMillan <andrew@catalyst.net.nz>
|
||||
* @copyright Catalyst .Net Ltd
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
@ -22,78 +22,211 @@ $attribute_list = array();
|
||||
$unsupported = array();
|
||||
$arbitrary = array();
|
||||
|
||||
$namespaces = array( "DAV:" => "" );
|
||||
$prefixes = array();
|
||||
function add_namespace( $prefix, $namespace ) {
|
||||
global $namespaces;
|
||||
global $prefixes;
|
||||
|
||||
if ( !isset($namespaces[$namespace]) ) {
|
||||
if ( $prefix == "" || isset($prefixes[$prefix]) ) {
|
||||
dbg_error_log("ERROR", "Cannot assign the same prefix to two different namespaces");
|
||||
exit;
|
||||
}
|
||||
else {
|
||||
$prefixes[$prefix] = $prefix;
|
||||
$namespaces[$namespace] = $prefix;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( $namespaces[$namespace] != $prefix ) {
|
||||
dbg_error_log("ERROR", "Cannot use the same namespace with two different prefixes");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function ns_tag( $in_tag, $namespace=null, $prefix=null ) {
|
||||
global $namespaces, $prefixes;
|
||||
|
||||
if ( $namespace == null ) {
|
||||
// Attempt to split out from namespace:tag
|
||||
if ( preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
|
||||
$namespace = $matches[1];
|
||||
$tag = $matches[2];
|
||||
}
|
||||
else {
|
||||
// There is nothing we can do here
|
||||
return $in_tag;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$tag = $in_tag;
|
||||
}
|
||||
$namespace = strtolower($namespace);
|
||||
if ( $namespace == 'dav:' ) $namespace = 'DAV:'; // Special case for conventional naming
|
||||
$tag = strtolower($tag);
|
||||
|
||||
if ( $prefix == null ) {
|
||||
// Attempt to assign one
|
||||
if ( isset($namespaces[$namespace]) ) {
|
||||
$prefix = $namespaces[$namespace];
|
||||
}
|
||||
else {
|
||||
// Try and build a prefix based on the first alphabetic character of the last element of the namespace
|
||||
if ( preg_match('/^(.*):([^:]+)$/', $namespace, $matches) ) {
|
||||
$alpha = preg_replace( '/[^a-z]/i', '', $matches[2] );
|
||||
$prefix = strtoupper(substr($alpha,0,1));
|
||||
}
|
||||
else {
|
||||
$prefix = 'x';
|
||||
}
|
||||
$i = "";
|
||||
if ( isset($prefixes[$prefix]) ) {
|
||||
for ( $i=1; $i<10 && isset($prefixes["$prefix$i"]); $i++ ) {
|
||||
}
|
||||
}
|
||||
if ( isset($prefixes["$prefix$i"]) ) {
|
||||
dbg_error_log("ERROR", "Cannot find a free prefix for this namespace");
|
||||
exit;
|
||||
}
|
||||
$prefix = "$prefix$i";
|
||||
$namespaces[$namespace] = $prefix;
|
||||
$prefixes[$prefix] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isset($namespaces[$namespace]) ) {
|
||||
add_namespace( $prefix, $namespace );
|
||||
}
|
||||
|
||||
return $prefix . ($prefix == "" ? "" : ":") . $tag;
|
||||
}
|
||||
|
||||
|
||||
function namespace_array() {
|
||||
global $namespaces;
|
||||
|
||||
$ns = array();
|
||||
foreach( $namespaces AS $n => $p ) {
|
||||
if ( $p == "" ) $ns["xmlns"] = $n; else $ns["xmlns:$p"] = $n;
|
||||
}
|
||||
|
||||
return $ns;
|
||||
}
|
||||
|
||||
|
||||
function caldav_tag( $tag ) {
|
||||
return ns_tag( $tag, 'urn:ietf:params:xml:ns:caldav' );
|
||||
}
|
||||
|
||||
|
||||
foreach( $request->xml_tags AS $k => $v ) {
|
||||
|
||||
$tag = $v['tag'];
|
||||
$ns_tag = $v['tag'];
|
||||
if ( preg_match('/^(.*):([^:]+)$/', $ns_tag, $matches) ) {
|
||||
$namespace = $matches[1];
|
||||
$tag = $matches[2];
|
||||
}
|
||||
else {
|
||||
$namespace = "";
|
||||
$tag = $ns_tag;
|
||||
}
|
||||
dbg_error_log( "PROPFIND", " Handling Tag '%s' => '%s' ", $k, $v );
|
||||
|
||||
switch ( $tag ) {
|
||||
case 'DAV::PROPFIND':
|
||||
case 'DAV::PROP':
|
||||
case 'PROPFIND':
|
||||
case 'PROP':
|
||||
dbg_error_log( "PROPFIND", ":Request: %s -> %s", $v['type'], $tag );
|
||||
break;
|
||||
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DESCRIPTION':
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-TIMEZONE':
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-DATA':
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-RESOURCE-SIZE':
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MIN-DATE-TIME':
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-DATE-TIME':
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-INSTANCES':
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-ATTENDEES-PER-INSTANCE':
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-HOME-SET':
|
||||
case 'HTTP://APACHE.ORG/DAV/PROPS/:EXECUTABLE':
|
||||
case 'DAV::CHECKED-OUT':
|
||||
case 'DAV::CHECKED-IN':
|
||||
case 'DAV::SOURCE':
|
||||
case 'DAV::LOCKDISCOVERY':
|
||||
/** These are ignored */
|
||||
break;
|
||||
|
||||
case 'DAV::ACL': /** acl - only vaguely supported */
|
||||
case 'DAV::CREATIONDATE': /** creationdate - should work fine */
|
||||
case 'DAV::GETLASTMODIFIED': /** getlastmodified - should work fine */
|
||||
case 'DAV::DISPLAYNAME': /** displayname - should work fine */
|
||||
case 'DAV::GETCONTENTLENGTH': /** getcontentlength- should work fine */
|
||||
case 'DAV::GETCONTENTTYPE': /** getcontenttype - should work fine */
|
||||
case 'DAV::GETETAG': /** getetag - should work fine */
|
||||
case 'DAV::SUPPORTEDLOCK': /** supportedlock - should work fine */
|
||||
case 'DAV::RESOURCETYPE': /** resourcetype - should work fine */
|
||||
case 'DAV::GETCONTENTLANGUAGE': /** resourcetype - should return the user's chosen locale, or default locale */
|
||||
case 'DAV::SUPPORTED-PRIVILEGE-SET': /** supported-privilege-set - should work fine */
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-COLLATION-SET': /** fixed server definition - should work fine */
|
||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET': /** fixed server definition - should work fine */
|
||||
case 'DAV::CURRENT-USER-PRIVILEGE-SET': /** current-user-privilege-set - only vaguely supported */
|
||||
case 'DAV::ALLPROP': /** allprop - limited support */
|
||||
$attribute = substr($v['tag'],5);
|
||||
$attribute_list[$attribute] = 1;
|
||||
dbg_error_log( "PROPFIND", "Adding attribute '%s'", $attribute );
|
||||
break;
|
||||
|
||||
case 'DAV::HREF':
|
||||
// dbg_log_array( "PROPFIND", "DAV::HREF", $v, true );
|
||||
case 'HREF':
|
||||
// dbg_log_array( "PROPFIND", "HREF", $v, true );
|
||||
$href_list[] = $v['value'];
|
||||
dbg_error_log( "PROPFIND", "Adding attribute '%s'", $attribute );
|
||||
dbg_error_log( "PROPFIND", "Adding href '%s'", $v['value'] );
|
||||
break;
|
||||
|
||||
|
||||
/**
|
||||
* Add the ones that are specifically unsupported here.
|
||||
* Handled DAV properties
|
||||
*/
|
||||
case 'UNSUPPORTED':
|
||||
if ( preg_match('/^(.*):([^:]+)$/', $tag, $matches) ) {
|
||||
$unsupported[$matches[2]] = $matches[1];
|
||||
case 'ACL': /** acl - only vaguely supported */
|
||||
case 'CREATIONDATE': /** creationdate - should work fine */
|
||||
case 'GETLASTMODIFIED': /** getlastmodified - should work fine */
|
||||
case 'DISPLAYNAME': /** displayname - should work fine */
|
||||
case 'GETCONTENTLENGTH': /** getcontentlength- should work fine */
|
||||
case 'GETCONTENTTYPE': /** getcontenttype - should work fine */
|
||||
case 'GETETAG': /** getetag - should work fine */
|
||||
case 'SUPPORTEDLOCK': /** supportedlock - should work fine */
|
||||
case 'PRINCIPAL-URL': /** principal-url - should work fine */
|
||||
case 'RESOURCETYPE': /** resourcetype - should work fine */
|
||||
case 'GETCONTENTLANGUAGE': /** resourcetype - should return the user's chosen locale, or default locale */
|
||||
case 'SUPPORTED-PRIVILEGE-SET': /** supported-privilege-set - should work fine */
|
||||
case 'CURRENT-USER-PRIVILEGE-SET': /** current-user-privilege-set - only vaguely supported */
|
||||
case 'ALLPROP': /** allprop - limited support */
|
||||
|
||||
/**
|
||||
* Handled CalDAV properties
|
||||
*/
|
||||
case 'CALENDAR-HOME-SET': /** calendar-home-set is used by iCal in Leopard - should work fine */
|
||||
$attribute_list[$tag] = 1;
|
||||
dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag );
|
||||
break;
|
||||
|
||||
|
||||
case 'SUPPORTED-COLLATION-SET': /** fixed server definition - should work fine */
|
||||
case 'SUPPORTED-CALENDAR-COMPONENT-SET': /** fixed server definition - should work fine */
|
||||
|
||||
/**
|
||||
* Handled calendar-schedule properties
|
||||
*/
|
||||
case 'CALENDAR-USER-ADDRESS-SET': /** CalDAV+s: slightly supported */
|
||||
// case 'SCHEDULE-INBOX-URL': /** CalDAV+s: not supported */
|
||||
// case 'SCHEDULE-OUTBOX-URL': /** CalDAV+s: not supported */
|
||||
// case 'DROPBOX-HOME-URL': // HTTP://CALENDARSERVER.ORG/NS/
|
||||
// case 'NOTIFICATIONS-URL': // HTTP://CALENDARSERVER.ORG/NS/
|
||||
if ( $_SERVER['PATH_INFO'] == '/' || $_SERVER['PATH_INFO'] == '' ) {
|
||||
$arbitrary[$ns_tag] = $ns_tag;
|
||||
dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $ns_tag );
|
||||
}
|
||||
else {
|
||||
$unsupported[$tag] = "";
|
||||
$attribute_list[$tag] = 1;
|
||||
dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag );
|
||||
}
|
||||
dbg_error_log( "PROPFIND", "Unsupported tag >>%s<<", $tag);
|
||||
break;
|
||||
|
||||
|
||||
case 'CALENDAR-TIMEZONE': // CalDAV
|
||||
case 'SUPPORTED-CALENDAR-DATA': // CalDAV
|
||||
case 'MAX-RESOURCE-SIZE': // CalDAV
|
||||
case 'MIN-DATE-TIME': // CalDAV
|
||||
case 'MAX-DATE-TIME': // CalDAV
|
||||
case 'MAX-INSTANCES': // CalDAV
|
||||
case 'MAX-ATTENDEES-PER-INSTANCE': // CalDAV
|
||||
// case 'CHECKED-OUT': // DAV:
|
||||
// case 'CHECKED-IN': // DAV:
|
||||
// case 'SOURCE': // DAV:
|
||||
// case 'LOCKDISCOVERY': // DAV:
|
||||
// case 'EXECUTABLE': // HTTP://APACHE.ORG/DAV/PROPS/
|
||||
/** These are ignored specifically */
|
||||
break;
|
||||
|
||||
/**
|
||||
* Add the ones that are specifically unsupported here.
|
||||
*/
|
||||
case 'This is not a supported property': // an impossible example
|
||||
$unsupported[$tag] = "";
|
||||
dbg_error_log( "PROPFIND", "Unsupported tag >>%s<< in xmlns >>%s<<", $tag, $namespace);
|
||||
break;
|
||||
|
||||
/**
|
||||
* Arbitrary DAV properties may also be reported
|
||||
*/
|
||||
case 'CALENDAR-DESCRIPTION': // CalDAV, informational
|
||||
default:
|
||||
$arbitrary[$tag] = $tag;
|
||||
dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $attribute );
|
||||
$arbitrary[$ns_tag] = $ns_tag;
|
||||
dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $ns_tag );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -119,7 +252,7 @@ function privileges($privilege_names, $container="privilege") {
|
||||
function get_arbitrary_properties($dav_name) {
|
||||
global $arbitrary;
|
||||
|
||||
$results = array();
|
||||
$results = (object) array( 'found' => array(), 'missing' => $arbitrary );
|
||||
|
||||
if ( count($arbitrary) > 0 ) {
|
||||
$sql = "";
|
||||
@ -128,7 +261,8 @@ function get_arbitrary_properties($dav_name) {
|
||||
}
|
||||
$qry = new PgQuery("SELECT property_name, property_value FROM property WHERE dav_name=? AND property_name IN ($sql)", $dav_name );
|
||||
while( $qry->Exec("PROPFIND") && $property = $qry->Fetch() ) {
|
||||
$results[$property->property_name] = $property->property_value;
|
||||
$results->found[$property->property_name] = $property->property_value;
|
||||
unset($results->missing[$property->property_name]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,6 +270,45 @@ function get_arbitrary_properties($dav_name) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles any properties related to the DAV::PRINCIPAL in the request
|
||||
*/
|
||||
function add_principal_properties( &$prop, &$not_found, &$denied ) {
|
||||
global $attribute_list, $session, $c, $request;
|
||||
|
||||
if ( isset($attribute_list['PRINCIPAL-URL'] ) ) {
|
||||
$prop->NewElement("principal-url", new XMLElement('href', $request->principal->url ) );
|
||||
}
|
||||
|
||||
if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) {
|
||||
$prop->NewElement(caldav_tag("calendar-home-set"), new XMLElement('href', $request->principal->calendar_home_set ) );
|
||||
}
|
||||
if ( isset($attribute_list['SCHEDULE-INBOX-URL'] ) ) {
|
||||
$prop->NewElement(caldav_tag("schedule-inbox-url"), new XMLElement('href', $request->principal->schedule_inbox_url) );
|
||||
}
|
||||
if ( isset($attribute_list['SCHEDULE-OUTBOX-URL'] ) ) {
|
||||
$prop->NewElement(caldav_tag("schedule-outbox-url"), new XMLElement('href', $request->principal->schedule_outbox_url) );
|
||||
}
|
||||
|
||||
if ( isset($attribute_list['DROPBOX-HOME-URL'] ) ) {
|
||||
add_namespace("A", "http://calendarserver.org/ns/");
|
||||
$prop->NewElement("A:dropbox-home-url", new XMLElement('href', $request->principal->dropbox_url) );
|
||||
}
|
||||
if ( isset($attribute_list['NOTIFICATIONS-URL'] ) ) {
|
||||
add_namespace("A", "http://calendarserver.org/ns/");
|
||||
$prop->NewElement("A:notifications-url", new XMLElement('href', $request->principal->notifications_url) );
|
||||
}
|
||||
|
||||
if ( isset($attribute_list['CALENDAR-USER-ADDRESS-SET'] ) ) {
|
||||
$addr_set = array();
|
||||
foreach( $request->principal->user_address_set AS $k => $v ) {
|
||||
$addr_set[] = new XMLElement('href', $v );
|
||||
}
|
||||
$prop->NewElement(caldav_tag("calendar-user-address-set"), $addr_set );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an XML sub-tree for a single collection record from the DB
|
||||
*/
|
||||
@ -144,13 +317,15 @@ function collection_to_xml( $collection ) {
|
||||
|
||||
dbg_error_log("PROPFIND","Building XML Response for collection '%s'", $collection->dav_name );
|
||||
|
||||
$collection->properties = get_arbitrary_properties($collection->dav_name);
|
||||
$arbitrary_results = get_arbitrary_properties($collection->dav_name);
|
||||
$collection->properties = $arbitrary_results->found;
|
||||
|
||||
$url = ConstructURL($collection->dav_name);
|
||||
|
||||
$url = $_SERVER['SCRIPT_NAME'] . $collection->dav_name;
|
||||
$resourcetypes = array( new XMLElement("collection") );
|
||||
$contentlength = false;
|
||||
if ( $collection->is_calendar == 't' ) {
|
||||
$resourcetypes[] = new XMLElement("calendar", false, array("xmlns" => "urn:ietf:params:xml:ns:caldav"));
|
||||
$resourcetypes[] = new XMLElement(caldav_tag("calendar"), false);
|
||||
$lqry = new PgQuery("SELECT sum(length(caldav_data)) FROM caldav_data WHERE user_no = ? AND dav_name ~ ?;", $collection->user_no, $collection->dav_name.'[^/]+$' );
|
||||
if ( $lqry->Exec("PROPFIND",__LINE__,__FILE__) && $row = $lqry->Fetch() ) {
|
||||
$contentlength = $row->sum;
|
||||
@ -160,21 +335,23 @@ function collection_to_xml( $collection ) {
|
||||
$resourcetypes[] = new XMLElement("principal");
|
||||
}
|
||||
$prop = new XMLElement("prop");
|
||||
$not_found = new XMLElement("prop");
|
||||
$denied = new XMLElement("prop");
|
||||
|
||||
/**
|
||||
* First process any static values we do support
|
||||
*/
|
||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-COLLATION-SET']) ) {
|
||||
$collations = array();
|
||||
$collations[] = new XMLElement("supported-collation", 'i;ascii-casemap');
|
||||
$collations[] = new XMLElement("supported-collation", 'i;octet');
|
||||
$prop->NewElement("supported-collation-set", $collations, array("xmlns" => "urn:ietf:params:xml:ns:caldav") );
|
||||
$collations[] = new XMLElement(caldav_tag("supported-collation"), 'i;ascii-casemap');
|
||||
$collations[] = new XMLElement(caldav_tag("supported-collation"), 'i;octet');
|
||||
$prop->NewElement(caldav_tag("supported-collation-set"), $collations );
|
||||
}
|
||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-CALENDAR-COMPONENT-SET']) ) {
|
||||
$components = array();
|
||||
$components[] = new XMLElement("comp", '', array("name" => "VEVENT"));
|
||||
$components[] = new XMLElement("comp", '', array("name" => "VTODO"));
|
||||
$prop->NewElement("supported-calendar-component-set", $components, array("xmlns" => "urn:ietf:params:xml:ns:caldav") );
|
||||
$components[] = new XMLElement(caldav_tag("comp"), '', array("name" => "VEVENT"));
|
||||
$components[] = new XMLElement(caldav_tag("comp"), '', array("name" => "VTODO"));
|
||||
$prop->NewElement(caldav_tag("supported-calendar-component-set"), $components );
|
||||
}
|
||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETCONTENTTYPE']) ) {
|
||||
$prop->NewElement("getcontenttype", "httpd/unix-directory" );
|
||||
@ -206,9 +383,31 @@ function collection_to_xml( $collection ) {
|
||||
$prop->NewElement("current-user-privilege-set", privileges($request->permissions) );
|
||||
}
|
||||
|
||||
if ( count($arbitrary) > 0 ) {
|
||||
foreach( $arbitrary AS $k => $v ) {
|
||||
$prop->NewElement($k, $collection->properties[$k]);
|
||||
if ( isset($attribute_list['CALENDAR-FREE-BUSY-SET'] ) ) {
|
||||
if ( isset($collection->is_inbox) && $collection->is_inbox && $session->user_no == $collection->user_no ) {
|
||||
$fb_set = array();
|
||||
foreach( $collection->free_busy_set AS $k => $v ) {
|
||||
$fb_set[] = new XMLElement('href', $v );
|
||||
}
|
||||
$prop->NewElement(caldav_tag("calendar-free-busy-set"), $fb_set );
|
||||
}
|
||||
else if ( $session->user_no == $collection->user_no ) {
|
||||
$not_found->NewElement(caldav_tag("calendar-free-busy-set") );
|
||||
}
|
||||
else {
|
||||
$denied->NewElement(caldav_tag("calendar-free-busy-set") );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Then look at any properties related to the principal
|
||||
*/
|
||||
add_principal_properties( $prop, $not_found, $denied );
|
||||
|
||||
if ( count($collection->properties) > 0 ) {
|
||||
foreach( $collection->properties AS $k => $v ) {
|
||||
$prop->NewElement(ns_tag($k), $v);
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,8 +444,23 @@ function collection_to_xml( $collection ) {
|
||||
|
||||
$propstat = new XMLElement( "propstat", array( $prop, $status) );
|
||||
$href = new XMLElement("href", $url );
|
||||
$response = array($href,$propstat);
|
||||
|
||||
$response = new XMLElement( "response", array($href,$propstat));
|
||||
if ( count($arbitrary_results->missing) > 0 ) {
|
||||
foreach( $arbitrary_results->missing AS $k => $v ) {
|
||||
$not_found->NewElement(ns_tag($k), '');
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_array($not_found->content) && count($not_found->content) > 0 ) {
|
||||
$response[] = new XMLElement( "propstat", array( $not_found, new XMLElement("status", "HTTP/1.1 404 Not Found" )) );
|
||||
}
|
||||
|
||||
if ( is_array($denied->content) && count($denied->content) > 0 ) {
|
||||
$response[] = new XMLElement( "propstat", array( $denied, new XMLElement("status", "HTTP/1.1 403 Forbidden" )) );
|
||||
}
|
||||
|
||||
$response = new XMLElement( "response", $response );
|
||||
|
||||
return $response;
|
||||
}
|
||||
@ -262,8 +476,13 @@ function item_to_xml( $item ) {
|
||||
|
||||
$item->properties = get_arbitrary_properties($item->dav_name);
|
||||
|
||||
$url = $_SERVER['SCRIPT_NAME'] . $item->dav_name;
|
||||
$url = ConstructURL($item->dav_name);
|
||||
|
||||
$prop = new XMLElement("prop");
|
||||
$not_found = new XMLElement("prop");
|
||||
$denied = new XMLElement("prop");
|
||||
|
||||
|
||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETLASTMODIFIED']) ) {
|
||||
$prop->NewElement("getlastmodified", ( isset($item->modified)? $item->modified : false ));
|
||||
}
|
||||
@ -290,6 +509,11 @@ function item_to_xml( $item ) {
|
||||
$prop->NewElement("getetag", '"'.$item->dav_etag.'"' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Then look at any properties related to the principal
|
||||
*/
|
||||
add_principal_properties( $prop, $not_found, $denied );
|
||||
|
||||
if ( isset($attribute_list['ACL']) ) {
|
||||
/**
|
||||
* FIXME: This information is semantically valid but presents an incorrect picture.
|
||||
@ -322,8 +546,17 @@ function item_to_xml( $item ) {
|
||||
|
||||
$propstat = new XMLElement( "propstat", array( $prop, $status) );
|
||||
$href = new XMLElement("href", $url );
|
||||
$response = array($href,$propstat);
|
||||
|
||||
$response = new XMLElement( "response", array($href,$propstat));
|
||||
if ( is_array($not_found->content) && count($not_found->content) > 0 ) {
|
||||
$response[] = new XMLElement( "propstat", array( $not_found, new XMLElement("status", "HTTP/1.1 404 Not Found" )) );
|
||||
}
|
||||
|
||||
if ( is_array($denied->content) && count($denied->content) > 0 ) {
|
||||
$response[] = new XMLElement( "propstat", array( $denied, new XMLElement("status", "HTTP/1.1 403 Forbidden" )) );
|
||||
}
|
||||
|
||||
$response = new XMLElement( "response", $response );
|
||||
|
||||
return $response;
|
||||
}
|
||||
@ -363,7 +596,7 @@ function get_collection_contents( $depth, $user_no, $collection ) {
|
||||
while( $subcollection = $qry->Fetch() ) {
|
||||
$responses[] = collection_to_xml( $subcollection );
|
||||
if ( $depth > 0 ) {
|
||||
$responses = array_merge( $responses, get_collection( $depth - 1, $user_no, $subcollection->dav_name ) );
|
||||
$responses = array_merge( $responses, get_collection_contents( $depth - 1, $user_no, $subcollection ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -380,7 +613,7 @@ function get_collection_contents( $depth, $user_no, $collection ) {
|
||||
$sql .= "to_char(last_modified at time zone 'GMT',?) AS modified, ";
|
||||
$sql .= "summary AS dav_displayname ";
|
||||
$sql .= "FROM caldav_data JOIN calendar_item USING( user_no, dav_name) WHERE dav_name ~ ".qpg('^'.$collection->dav_name.'[^/]+$');
|
||||
$sql .= "AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL OR get_permissions($session->user_no,caldav_data.user_no) ~ 'A') "; // Must have 'all' permissions to see confidential items
|
||||
$sql .= " AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL OR get_permissions($session->user_no,caldav_data.user_no) ~ 'A') "; // Must have 'all' permissions to see confidential items
|
||||
$sql .= "ORDER BY caldav_data.dav_name ";
|
||||
$qry = new PgQuery($sql, PgQuery::Plain(iCalendar::HttpDateFormat()), PgQuery::Plain(iCalendar::HttpDateFormat()));
|
||||
if( $qry->Exec("PROPFIND",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
||||
@ -404,12 +637,13 @@ function get_collection( $depth, $user_no, $collection_path ) {
|
||||
|
||||
dbg_error_log("PROPFIND","Getting collection: Depth %d, User: %d, Path: %s", $depth, $user_no, $collection_path );
|
||||
|
||||
if ( $collection_path == '/' ) {
|
||||
if ( $collection_path == null || $collection_path == '/' || $collection_path == '' ) {
|
||||
$collection->dav_name = $collection_path;
|
||||
$collection->dav_etag = md5($c->system_name . $collection_path);
|
||||
$collection->is_calendar = 'f';
|
||||
$collection->is_principal = 'f';
|
||||
$collection->dav_displayname = $c->system_name;
|
||||
$collection->created = date('Ymd"T"His');
|
||||
$collection->created = date('Ymd\THis');
|
||||
$responses[] = collection_to_xml( $collection );
|
||||
}
|
||||
else {
|
||||
@ -434,6 +668,7 @@ function get_collection( $depth, $user_no, $collection_path ) {
|
||||
$collection->dav_name = $collection_path;
|
||||
$collection->dav_etag = md5($collection_path);
|
||||
$collection->is_calendar = 't'; // Everything is a calendar, if it always exists!
|
||||
$collection->is_principal = 'f';
|
||||
$collection->dav_displayname = $collection_path;
|
||||
$collection->created = date('Ymd"T"His');
|
||||
$responses[] = collection_to_xml( $collection );
|
||||
@ -445,6 +680,7 @@ function get_collection( $depth, $user_no, $collection_path ) {
|
||||
return $responses;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get XML response for a single item. Depth is irrelevant for this.
|
||||
*/
|
||||
@ -458,7 +694,7 @@ function get_item( $item_path ) {
|
||||
$sql .= "to_char(coalesce(calendar_item.created, caldav_data.created) at time zone 'GMT',?) AS created, ";
|
||||
$sql .= "to_char(last_modified at time zone 'GMT',?) AS modified, ";
|
||||
$sql .= "summary AS dav_displayname ";
|
||||
$sql .= "FROM caldav_data JOIN calendar_item USING( user_no, dav_name) WHERE dav_name = ?";
|
||||
$sql .= "FROM caldav_data JOIN calendar_item USING( user_no, dav_name) WHERE dav_name = ? ";
|
||||
$sql .= "AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL OR get_permissions($session->user_no,caldav_data.user_no) ~ 'A') "; // Must have 'all' permissions to see confidential items
|
||||
$qry = new PgQuery($sql, PgQuery::Plain(iCalendar::HttpDateFormat()), PgQuery::Plain(iCalendar::HttpDateFormat()), $item_path);
|
||||
if( $qry->Exec("PROPFIND",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
||||
@ -487,7 +723,7 @@ else {
|
||||
$request->DoResponse( 403, translate("You do not have appropriate rights to view that resource.") );
|
||||
}
|
||||
|
||||
$multistatus = new XMLElement( "multistatus", $responses, array('xmlns'=>'DAV:') );
|
||||
$multistatus = new XMLElement( "multistatus", $responses, namespace_array() );
|
||||
|
||||
// dbg_log_array( "PROPFIND", "XML", $multistatus, true );
|
||||
$xmldoc = $multistatus->Render(0,'<?xml version="1.0" encoding="utf-8" ?>');
|
||||
@ -495,4 +731,3 @@ $etag = md5($xmldoc);
|
||||
header("ETag: \"$etag\"");
|
||||
$request->DoResponse( 207, $xmldoc, 'text/xml; charset="utf-8"' );
|
||||
|
||||
?>
|
||||
@ -195,7 +195,8 @@ if ( count($failure) > 0 ) {
|
||||
));
|
||||
}
|
||||
|
||||
array_unshift( $failure, new XMLElement('href', $c->protocol_server_port_script . $request->path ) );
|
||||
$url = ConstructURL($request->path);
|
||||
array_unshift( $failure, new XMLElement('href', $url ) );
|
||||
$failure[] = new XMLElement('responsedescription', translate("Some properties were not able to be changed.") );
|
||||
|
||||
$multistatus = new XMLElement( "multistatus", new XMLElement( 'response', $failure ), array('xmlns'=>'DAV:') );
|
||||
@ -209,7 +210,8 @@ if ( count($failure) > 0 ) {
|
||||
$sql .= "COMMIT;";
|
||||
$qry = new PgQuery( $sql );
|
||||
if ( $qry->Exec() ) {
|
||||
$href = new XMLElement('href', $c->protocol_server_port_script . $request->path );
|
||||
$url = ConstructURL($request->path);
|
||||
$href = new XMLElement('href', $url );
|
||||
$desc = new XMLElement('responsedescription', translate("All requested changes were made.") );
|
||||
|
||||
$multistatus = new XMLElement( "multistatus", new XMLElement( 'response', array( $href, $desc ) ), array('xmlns'=>'DAV:') );
|
||||
|
||||
@ -8,7 +8,38 @@
|
||||
|
||||
include_once("iCalendar.php");
|
||||
|
||||
function controlRequestContainer( $username, $user_no, $path, $context ) {
|
||||
/**
|
||||
* This function launches an error
|
||||
* @param boolean $caldav_context Whether we are responding via CalDAV or interactively
|
||||
* @param int $user_no the user wich will receive this ics file
|
||||
* @param string $path the $path where the PUT failed to store such as /user_foo/home/
|
||||
* @param string $message An optional error message to return to the client
|
||||
* @param int $error_no An optional value for the HTTP error code
|
||||
*/
|
||||
function rollback_on_error( $caldav_context, $user_no, $path, $message='', $error_no=500 ) {
|
||||
if ( !$message ) $message = translate("Database error");
|
||||
$qry = new PgQuery("ROLLBACK;"); $qry->Exec("PUT-collection");
|
||||
if ( $caldav_context ) {
|
||||
global $request;
|
||||
$request->DoResponse( $error_no, $message );
|
||||
}
|
||||
else {
|
||||
global $c;
|
||||
$c->messages[] = sprintf("Status: %d, Message: %s, User: %d, Path: %s", $error_no, $message, $user_no, $path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Work out the location we are doing the PUT to, and check that we have the rights to
|
||||
* do the needful.
|
||||
* @param string $username The name of the destination user
|
||||
* @param int $user_no The user making the change
|
||||
* @param string $path The DAV path the resource is bing PUT to
|
||||
* @param boolean $caldav_context Whether we are responding via CalDAV or interactively
|
||||
*/
|
||||
function controlRequestContainer( $username, $user_no, $path, $caldav_context ) {
|
||||
|
||||
// Check to see if the path is like /foo /foo/bar or /foo/bar/baz etc. (not ending with a '/', but contains at least one)
|
||||
if ( preg_match( '#^(.*/)([^/]+)$#', $path, $matches ) ) {//(
|
||||
@ -34,14 +65,7 @@ function controlRequestContainer( $username, $user_no, $path, $context ) {
|
||||
$sql = "SELECT * FROM collection WHERE user_no = ? AND dav_name = ?;";
|
||||
$qry = new PgQuery( $sql, $user_no, $request_container );
|
||||
if ( ! $qry->Exec("PUT") ) {
|
||||
if($context){
|
||||
global $request;
|
||||
$request->DoResponse( 500, translate("Error querying database.") );
|
||||
}
|
||||
else {
|
||||
global $c;
|
||||
$c->messages[] = sprintf("Status: %d, Message: %s, User: %d, Path: %s", 500, translate("Error querying database."),$user_no,$path);
|
||||
}
|
||||
rollback_on_error( $caldav_context, $user_no, $path );
|
||||
}
|
||||
if ( $qry->rows == 0 ) {
|
||||
if ( preg_match( '#^(.*/)([^/]+/)$#', $request_container, $matches ) ) {//(
|
||||
@ -59,21 +83,32 @@ function controlRequestContainer( $username, $user_no, $path, $context ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This function launches an error
|
||||
* @param int $user_no the user wich will receive this ics file
|
||||
* @param string $path the $path where it will be store such as /user_foo/home/
|
||||
* @param boolean $context is true if this function is called from a way where $request is defined
|
||||
* Check if this collection should force all events to be PUBLIC.
|
||||
* @param string $user_no the user that owns the collection
|
||||
* @param string $dav_name the collection to check
|
||||
* @return boolean Return true if public events only are allowed.
|
||||
*/
|
||||
function rollback_on_error($context,$user_no,$path) {
|
||||
$qry = new PgQuery("ROLLBACK;"); $qry->Exec("PUT-collection");
|
||||
if($context){
|
||||
global $request;
|
||||
$request->DoResponse( 500, translate("Database error") );
|
||||
}
|
||||
else {
|
||||
global $c;
|
||||
$c->messages[] = sprintf("Status: %d, Message: %s, User: %d, Path: %s", 500, translate("Database error"),$user_no,$path);
|
||||
function public_events_only( $user_no, $dav_name ) {
|
||||
global $c;
|
||||
// Not supported until DB versions from 1.001.010
|
||||
if ( $c->schema_version < 1001.010 ) return false;
|
||||
|
||||
$sql = "SELECT public_events_only ";
|
||||
$sql .= "FROM collection ";
|
||||
$sql .= "WHERE user_no=? AND dav_name=?";
|
||||
|
||||
$qry = new PgQuery($sql, $user_no, $dav_name);
|
||||
|
||||
if( $qry->Exec('PUT') && $qry->rows == 1 ) {
|
||||
$collection = $qry->Fetch();
|
||||
|
||||
if ($collection->public_events_only == 't') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Something went wrong, must be false.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -82,15 +117,18 @@ function rollback_on_error($context,$user_no,$path) {
|
||||
* @param string $ics_content the ics file to import
|
||||
* @param int $user_no the user wich will receive this ics file
|
||||
* @param string $path the $path where it will be store such as /user_foo/home/
|
||||
* @param boolean $context is true if this function is called from a way where $request is defined
|
||||
* @param boolean $caldav_context Whether we are responding via CalDAV or interactively
|
||||
*/
|
||||
function import_collection($ics_content, $user_no, $path,$context){
|
||||
function import_collection( $ics_content, $user_no, $path, $caldav_context ) {
|
||||
global $c;
|
||||
// According to RFC2445 we should always end with CRLF, but the CalDAV spec says
|
||||
// that normalising XML parses often muck with it and may remove the CR.
|
||||
$icalendar = preg_replace('/\r?\n /', '', $ics_content );
|
||||
$fh = fopen('/tmp/PUT-2.txt','w');
|
||||
fwrite($fh,$icalendar);
|
||||
fclose($fh);
|
||||
if ( isset($c->dbg['ALL']) || isset($c->dbg['put']) ) {
|
||||
$fh = fopen('/tmp/PUT-2.txt','w');
|
||||
fwrite($fh,$icalendar);
|
||||
fclose($fh);
|
||||
}
|
||||
|
||||
$lines = preg_split('/\r?\n/', $icalendar );
|
||||
|
||||
@ -132,7 +170,7 @@ function import_collection($ics_content, $user_no, $path,$context){
|
||||
}
|
||||
}
|
||||
$qry = new PgQuery("BEGIN; DELETE FROM calendar_item WHERE user_no=? AND dav_name ~ ?; DELETE FROM caldav_data WHERE user_no=? AND dav_name ~ ?;", $user_no, $path.'[^/]+$', $user_no, $path.'[^/]+$');
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error($context,$user_no,$path);
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $user_no, $path );
|
||||
|
||||
foreach( $events AS $k => $event ) {
|
||||
dbg_error_log( "PUT", "Putting event %d with data: %s", $k, $event['data'] );
|
||||
@ -142,7 +180,7 @@ function import_collection($ics_content, $user_no, $path,$context){
|
||||
$event_path = sprintf( "%s%d.ics", $path, $k);
|
||||
$qry = new PgQuery( "INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp )",
|
||||
$user_no, $event_path, $etag, $icalendar, $ic->type, $session->user_no );
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error($context,$user_no,$path);
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $user_no, $path );
|
||||
|
||||
$sql = "";
|
||||
if ( preg_match(':^(Africa|America|Antarctica|Arctic|Asia|Atlantic|Australia|Brazil|Canada|Chile|Etc|Europe|Indian|Mexico|Mideast|Pacific|US)/[a-z]+$:i', $ic->tz_locn ) ) {
|
||||
@ -175,6 +213,21 @@ function import_collection($ics_content, $user_no, $path,$context){
|
||||
$dtstamp = $last_modified;
|
||||
}
|
||||
|
||||
$class = $ic->Get("class");
|
||||
/* Check and see if we should over ride the class. */
|
||||
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';
|
||||
}
|
||||
|
||||
$sql .= <<<EOSQL
|
||||
INSERT INTO calendar_item (user_no, dav_name, dav_etag, uid, dtstamp, dtstart, dtend, summary, location, class, transp,
|
||||
description, rrule, tz_id, last_modified, url, priority, created, due, percent_complete )
|
||||
@ -183,14 +236,165 @@ EOSQL;
|
||||
|
||||
$qry = new PgQuery( $sql, $user_no, $event_path, $etag, $ic->Get('uid'), $dtstamp,
|
||||
$ic->Get('dtstart'), $ic->Get('summary'), $ic->Get('location'),
|
||||
$ic->Get('class'), $ic->Get('transp'), $ic->Get('description'), $ic->Get('rrule'), $ic->Get('tz_id'),
|
||||
$class, $ic->Get('transp'), $ic->Get('description'), $ic->Get('rrule'), $ic->Get('tz_id'),
|
||||
$last_modified, $ic->Get('url'), $ic->Get('priority'), $ic->Get('created'),
|
||||
$ic->Get('due'), $ic->Get('percent-complete')
|
||||
);
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error($context,$user_no,$path);
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $user_no, $path);
|
||||
}
|
||||
|
||||
$qry = new PgQuery("COMMIT;");
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error($context,$user_no,$path);
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $user_no, $path);
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
/**
|
||||
* Put the resource from this request
|
||||
* @param object $request A reference to the request object
|
||||
* @param int $author The user_no who wants to put this resource on the server
|
||||
* @param boolean $caldav_context Whether we are responding via CalDAV or interactively
|
||||
* @return string Either 'INSERT' or 'UPDATE': the type of action that the PUT resulted in
|
||||
*/
|
||||
function putCalendarResource( &$request, $author, $caldav_context ) {
|
||||
$etag = md5($request->raw_post);
|
||||
$ic = new iCalendar(array( 'icalendar' => $request->raw_post ));
|
||||
|
||||
dbg_log_array( "PUT", 'EVENT', $ic->properties['VCALENDAR'][0], true );
|
||||
|
||||
/**
|
||||
* We read any existing object so we can check the ETag.
|
||||
*/
|
||||
unset($put_action_type);
|
||||
$qry = new PgQuery( "SELECT * FROM caldav_data WHERE user_no=? AND dav_name=?", $request->user_no, $request->path );
|
||||
if ( !$qry->Exec("PUT") || $qry->rows > 1 ) {
|
||||
rollback_on_error( $caldav_context, $request->user_no, $request->path );
|
||||
}
|
||||
elseif ( $qry->rows < 1 ) {
|
||||
if ( isset($request->etag_if_match) && $request->etag_if_match != '' ) {
|
||||
/**
|
||||
* RFC2068, 14.25:
|
||||
* If none of the entity tags match, or if "*" is given and no current
|
||||
* entity exists, the server MUST NOT perform the requested method, and
|
||||
* MUST return a 412 (Precondition Failed) response.
|
||||
*/
|
||||
rollback_on_error( $caldav_context, $request->user_no, $request->path, 412, translate("Resource changed on server - not changed.") );
|
||||
}
|
||||
|
||||
$put_action_type = 'INSERT';
|
||||
|
||||
if ( ! $request->AllowedTo("create") ) {
|
||||
rollback_on_error( $caldav_context, $request->user_no, $request->path, 403, translate("You may not add entries to this calendar.") );
|
||||
}
|
||||
}
|
||||
elseif ( $qry->rows == 1 ) {
|
||||
$icalendar = $qry->Fetch();
|
||||
|
||||
if ( ( isset($request->etag_if_match) && $request->etag_if_match != '' && $request->etag_if_match != $icalendar->dav_etag )
|
||||
|| ( isset($request->etag_none_match) && $request->etag_none_match != '' && ($request->etag_none_match == $icalendar->dav_etag || $request->etag_none_match == '*') ) ) {
|
||||
/**
|
||||
* RFC2068, 14.25:
|
||||
* If none of the entity tags match, or if "*" is given and no current
|
||||
* entity exists, the server MUST NOT perform the requested method, and
|
||||
* MUST return a 412 (Precondition Failed) response.
|
||||
*
|
||||
* RFC2068, 14.26:
|
||||
* If any of the entity tags match the entity tag of the entity that
|
||||
* would have been returned in the response to a similar GET request
|
||||
* (without the If-None-Match header) on that resource, or if "*" is
|
||||
* given and any current entity exists for that resource, then the
|
||||
* server MUST NOT perform the requested method.
|
||||
*/
|
||||
if ( isset($request->etag_if_match) && $request->etag_if_match != $icalendar->dav_etag ) {
|
||||
$error = translate( "Existing resource does not match 'If-Match' header - not accepted.");
|
||||
}
|
||||
if ( isset($etag_none_match) && $etag_none_match != '' && ($etag_none_match == $icalendar->dav_etag || $etag_none_match == '*') ) {
|
||||
$error = translate( "Existing resource matches 'If-None-Match' header - not accepted.");
|
||||
}
|
||||
$request->DoResponse( 412, $error );
|
||||
}
|
||||
|
||||
$put_action_type = 'UPDATE';
|
||||
|
||||
if ( ! $request->AllowedTo("modify") ) {
|
||||
$request->DoResponse( 403, translate("You may not modify entries on this calendar.") );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $put_action_type == 'INSERT' ) {
|
||||
$qry = new PgQuery( "BEGIN; INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp )",
|
||||
$request->user_no, $request->path, $etag, $request->raw_post, $ic->type, $author );
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $request->user_no, $request->path);
|
||||
}
|
||||
else {
|
||||
$qry = new PgQuery( "BEGIN;UPDATE caldav_data SET caldav_data=?, dav_etag=?, caldav_type=?, logged_user=?, modified=current_timestamp WHERE user_no=? AND dav_name=?",
|
||||
$request->raw_post, $etag, $ic->type, $author, $request->user_no, $request->path );
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $request->user_no, $request->path);
|
||||
}
|
||||
|
||||
$sql = ( $ic->tz_locn == '' ? '' : "SET TIMEZONE TO ".qpg($ic->tz_locn).";" );
|
||||
|
||||
$dtstart = $ic->Get('DTSTART');
|
||||
if ( (!isset($dtstart) || $dtstart == "") && $ic->Get('DUE') != "" ) {
|
||||
$dtstart = $ic->Get('DUE');
|
||||
}
|
||||
|
||||
$dtend = $ic->Get('DTEND');
|
||||
if ( (!isset($dtend) || "$dtend" == "") && $ic->Get('DURATION') != "" AND $dtstart != "" ) {
|
||||
$duration = preg_replace( '#[PT]#', ' ', $ic->Get('DURATION') );
|
||||
$dtend = '('.qpg($dtstart).'::timestamp with time zone + '.qpg($duration).'::interval)';
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "PUT", " DTEND: '%s', DTSTART: '%s', DURATION: '%s'", $dtend, $dtstart, $ic->Get('DURATION') );
|
||||
$dtend = qpg($dtend);
|
||||
}
|
||||
|
||||
$last_modified = $ic->Get("LAST-MODIFIED");
|
||||
if ( !isset($last_modified) || $last_modified == '' ) {
|
||||
$last_modified = gmdate( 'Ymd\THis\Z' );
|
||||
}
|
||||
|
||||
$dtstamp = $ic->Get("DTSTAMP");
|
||||
if ( !isset($dtstamp) || $dtstamp == '' ) {
|
||||
$dtstamp = $last_modified;
|
||||
}
|
||||
|
||||
$class = $ic->Get("class");
|
||||
/* Check and see if we should over ride the class. */
|
||||
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';
|
||||
}
|
||||
|
||||
|
||||
if ( $put_action_type != 'INSERT' ) {
|
||||
$sql .= "DELETE FROM calendar_item WHERE user_no=$request->user_no AND dav_name=".qpg($request->path).";";
|
||||
}
|
||||
$sql .= <<<EOSQL
|
||||
INSERT INTO calendar_item (user_no, dav_name, dav_etag, uid, dtstamp, dtstart, dtend, summary, location, class, transp,
|
||||
description, rrule, tz_id, last_modified, url, priority, created, due, percent_complete, status )
|
||||
VALUES ( ?, ?, ?, ?, ?, ?, $dtend, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
COMMIT;
|
||||
EOSQL;
|
||||
|
||||
$qry = new PgQuery( $sql, $request->user_no, $request->path, $etag, $ic->Get('UID'), $dtstamp,
|
||||
$ic->Get('DTSTART'), $ic->Get('SUMMARY'), $ic->Get('LOCATION'),
|
||||
$class, $ic->Get('TRANSP'), $ic->Get('DESCRIPTION'), $ic->Get('RRULE'), $ic->Get('TZ_ID'),
|
||||
$last_modified, $ic->Get('URL'), $ic->Get('PRIORITY'), $ic->Get('CREATED'),
|
||||
$ic->Get('DUE'), $ic->Get('PERCENT-COMPLETE'), $ic->Get('STATUS')
|
||||
);
|
||||
if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $request->user_no, $request->path);
|
||||
dbg_error_log( "PUT", "User: %d, ETag: %s, Path: %s", $author, $etag, $request->path);
|
||||
|
||||
header(sprintf('ETag: "%s"', (isset($bogus_etag) ? $bogus_etag : $etag) ) );
|
||||
|
||||
return $put_action_type;
|
||||
}
|
||||
|
||||
|
||||
@ -36,128 +36,5 @@ if ( $is_collection ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$etag = md5($request->raw_post);
|
||||
$ic = new iCalendar(array( 'icalendar' => $request->raw_post ));
|
||||
|
||||
dbg_log_array( "PUT", 'EVENT', $ic->properties['VCALENDAR'][0], true );
|
||||
|
||||
|
||||
/**
|
||||
* We read any existing object so we can check the ETag.
|
||||
*/
|
||||
unset($put_action_type);
|
||||
$qry = new PgQuery( "SELECT * FROM caldav_data WHERE user_no=? AND dav_name=?", $request->user_no, $request->path );
|
||||
if ( !$qry->Exec("PUT") || $qry->rows > 1 ) {
|
||||
$request->DoResponse( 500, translate("Error querying database.") );
|
||||
}
|
||||
elseif ( $qry->rows < 1 ) {
|
||||
if ( isset($request->etag_if_match) && $request->etag_if_match != '' ) {
|
||||
/**
|
||||
* RFC2068, 14.25:
|
||||
* If none of the entity tags match, or if "*" is given and no current
|
||||
* entity exists, the server MUST NOT perform the requested method, and
|
||||
* MUST return a 412 (Precondition Failed) response.
|
||||
*/
|
||||
$request->DoResponse( 412, translate("Resource changed on server - not changed.") );
|
||||
}
|
||||
|
||||
$put_action_type = 'INSERT';
|
||||
|
||||
if ( ! $request->AllowedTo("create") ) {
|
||||
$request->DoResponse( 403, translate("You may not add entries to this calendar.") );
|
||||
}
|
||||
}
|
||||
elseif ( $qry->rows == 1 ) {
|
||||
$icalendar = $qry->Fetch();
|
||||
|
||||
if ( ( isset($request->etag_if_match) && $request->etag_if_match != '' && $request->etag_if_match != $icalendar->dav_etag )
|
||||
|| ( isset($request->etag_none_match) && $request->etag_none_match != '' && ($request->etag_none_match == $icalendar->dav_etag || $request->etag_none_match == '*') ) ) {
|
||||
/**
|
||||
* RFC2068, 14.25:
|
||||
* If none of the entity tags match, or if "*" is given and no current
|
||||
* entity exists, the server MUST NOT perform the requested method, and
|
||||
* MUST return a 412 (Precondition Failed) response.
|
||||
*
|
||||
* RFC2068, 14.26:
|
||||
* If any of the entity tags match the entity tag of the entity that
|
||||
* would have been returned in the response to a similar GET request
|
||||
* (without the If-None-Match header) on that resource, or if "*" is
|
||||
* given and any current entity exists for that resource, then the
|
||||
* server MUST NOT perform the requested method.
|
||||
*/
|
||||
if ( isset($request->etag_if_match) && $request->etag_if_match != $icalendar->dav_etag ) {
|
||||
$error = translate( "Existing resource does not match 'If-Match' header - not accepted.");
|
||||
}
|
||||
if ( isset($etag_none_match) && $etag_none_match != '' && ($etag_none_match == $icalendar->dav_etag || $etag_none_match == '*') ) {
|
||||
$error = translate( "Existing resource matches 'If-None-Match' header - not accepted.");
|
||||
}
|
||||
$request->DoResponse( 412, $error );
|
||||
}
|
||||
|
||||
$put_action_type = 'UPDATE';
|
||||
|
||||
if ( ! $request->AllowedTo("modify") ) {
|
||||
$request->DoResponse( 403, translate("You may not modify entries on this calendar.") );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $put_action_type == 'INSERT' ) {
|
||||
$qry = new PgQuery( "INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp )",
|
||||
$request->user_no, $request->path, $etag, $request->raw_post, $ic->type, $session->user_no );
|
||||
$qry->Exec("PUT");
|
||||
}
|
||||
else {
|
||||
$qry = new PgQuery( "UPDATE caldav_data SET caldav_data=?, dav_etag=?, caldav_type=?, logged_user=?, modified=current_timestamp WHERE user_no=? AND dav_name=?",
|
||||
$request->raw_post, $etag, $ic->type, $session->user_no, $request->user_no, $request->path );
|
||||
$qry->Exec("PUT");
|
||||
}
|
||||
|
||||
$sql = "BEGIN;".( $ic->tz_locn == '' ? '' : "SET TIMEZONE TO ".qpg($ic->tz_locn).";" );
|
||||
|
||||
$dtstart = $ic->Get('DTSTART');
|
||||
if ( (!isset($dtstart) || $dtstart == "") && $ic->Get('DUE') != "" ) {
|
||||
$dtstart = $ic->Get('DUE');
|
||||
}
|
||||
|
||||
$dtend = $ic->Get('DTEND');
|
||||
if ( (!isset($dtend) || "$dtend" == "") && $ic->Get('DURATION') != "" AND $dtstart != "" ) {
|
||||
$duration = preg_replace( '#[PT]#', ' ', $ic->Get('DURATION') );
|
||||
$dtend = '('.qpg($dtstart).'::timestamp with time zone + '.qpg($duration).'::interval)';
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "PUT", " DTEND: '%s', DTSTART: '%s', DURATION: '%s'", $dtend, $dtstart, $ic->Get('DURATION') );
|
||||
$dtend = qpg($dtend);
|
||||
}
|
||||
|
||||
$last_modified = $ic->Get("LAST-MODIFIED");
|
||||
if ( !isset($last_modified) || $last_modified == '' ) {
|
||||
$last_modified = gmdate( 'Ymd\THis\Z' );
|
||||
}
|
||||
|
||||
$dtstamp = $ic->Get("DTSTAMP");
|
||||
if ( !isset($dtstamp) || $dtstamp == '' ) {
|
||||
$dtstamp = $last_modified;
|
||||
}
|
||||
|
||||
if ( $put_action_type != 'INSERT' ) {
|
||||
$sql .= "DELETE FROM calendar_item WHERE user_no=$request->user_no AND dav_name=".qpg($request->path).";";
|
||||
}
|
||||
$sql .= <<<EOSQL
|
||||
INSERT INTO calendar_item (user_no, dav_name, dav_etag, uid, dtstamp, dtstart, dtend, summary, location, class, transp,
|
||||
description, rrule, tz_id, last_modified, url, priority, created, due, percent_complete, status )
|
||||
VALUES ( ?, ?, ?, ?, ?, ?, $dtend, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
COMMIT;
|
||||
EOSQL;
|
||||
|
||||
$qry = new PgQuery( $sql, $request->user_no, $request->path, $etag, $ic->Get('UID'), $dtstamp,
|
||||
$ic->Get('DTSTART'), $ic->Get('SUMMARY'), $ic->Get('LOCATION'),
|
||||
$ic->Get('CLASS'), $ic->Get('TRANSP'), $ic->Get('DESCRIPTION'), $ic->Get('RRULE'), $ic->Get('TZ_ID'),
|
||||
$last_modified, $ic->Get('URL'), $ic->Get('PRIORITY'), $ic->Get('CREATED'),
|
||||
$ic->Get('DUE'), $ic->Get('PERCENT-COMPLETE'), $ic->Get('STATUS')
|
||||
);
|
||||
$qry->Exec("PUT");
|
||||
dbg_error_log( "PUT", "User: %d, ETag: %s, Path: %s", $session->user_no, $etag, $request->path);
|
||||
|
||||
header(sprintf('ETag: "%s"', (isset($bogus_etag) ? $bogus_etag : $etag) ) );
|
||||
$put_action_type = putCalendarResource( $request, $session->user_no, true );
|
||||
$request->DoResponse( ($put_action_type == 'INSERT' ? 201 : 204) );
|
||||
?>
|
||||
@ -6,8 +6,8 @@ include_once("iCalendar.php");
|
||||
include_once("RRule.php");
|
||||
|
||||
$fbq_content = $xmltree->GetContent('URN:IETF:PARAMS:XML:NS:CALDAV:FREE-BUSY-QUERY');
|
||||
$fbq_start = $fbq_content[0]->GetAttribute('START');
|
||||
$fbq_end = $fbq_content[0]->GetAttribute('END');
|
||||
$fbq_start = $fbq_content[0]->GetAttribute('START');
|
||||
$fbq_end = $fbq_content[0]->GetAttribute('END');
|
||||
|
||||
if ( ! ( isset($fbq_start) || isset($fbq_end) ) ) {
|
||||
$request->DoResponse( 400, 'All valid freebusy requests MUST contain a time-range filter' );
|
||||
@ -64,11 +64,13 @@ foreach( $busy_tentative AS $k => $v ) {
|
||||
while ( $date = $rrule->GetNext() ) {
|
||||
if ( ! $date->GreaterThan($fbq_start) ) continue;
|
||||
if ( $date->GreaterThan($fbq_end) ) break;
|
||||
$freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $date->Render('Ymd\THis'), $duration );
|
||||
$todate = clone($date);
|
||||
$todate->AddDuration($duration);
|
||||
$freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $date->Render('Ymd\THis'), $todate->Render('Ymd\THis') );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $start->Render('Ymd\THis'), $duration );
|
||||
$freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $start->Render('Ymd\THis'), $v->finish );
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,11 +82,13 @@ foreach( $busy AS $k => $v ) {
|
||||
while ( $date = $rrule->GetNext() ) {
|
||||
if ( ! $date->GreaterThan($fbq_start) ) continue;
|
||||
if ( $date->GreaterThan($fbq_end) ) break;
|
||||
$freebusy .= sprintf("FREEBUSY:%s/%s\n", $date->Render('Ymd\THis'), $duration );
|
||||
$todate = clone($date);
|
||||
$todate->AddDuration($duration);
|
||||
$freebusy .= sprintf("FREEBUSY:%s/%s\n", $date->Render('Ymd\THis'), $todate->Render('Ymd\THis') );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$freebusy .= sprintf("FREEBUSY:%s/%s\n", $start->Render('Ymd\THis'), $duration );
|
||||
$freebusy .= sprintf("FREEBUSY:%s/%s\n", $start->Render('Ymd\THis'), $v->finish );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ $responses = array();
|
||||
|
||||
/**
|
||||
* Return XML for a single Principal (user) from the DB
|
||||
* TODO: Refactor this functionality into the CalDAVPrincipal object
|
||||
*
|
||||
* @param array $properties The requested properties for this principal
|
||||
* @param string $item The user data for this calendar
|
||||
@ -15,16 +16,13 @@ function principal_to_xml( $properties, $item ) {
|
||||
|
||||
dbg_error_log("REPORT","Building XML Response for principal '%s'", $item->username );
|
||||
|
||||
$this_url = $c->protocol_server_port_script . $request->dav_name;
|
||||
$principal_url = sprintf( "%s/%s/", $c->protocol_server_port_script, $item->username);
|
||||
$home_calendar = sprintf( "%s/%s/%s/", $c->protocol_server_port_script, $item->username, $c->home_calendar_name);
|
||||
$this_url = ConstructURL( $request->dav_name );
|
||||
$principal_url = ConstructURL( "/".$item->username."/");
|
||||
$home_calendar = ConstructURL( "/".$item->username."/");
|
||||
$prop = new XMLElement("prop");
|
||||
$denied = array();
|
||||
foreach( $properties AS $k => $v ) {
|
||||
switch( $v ) {
|
||||
// case 'DAV::GETCONTENTTYPE':
|
||||
// $prop->NewElement("getcontenttype", "text/x-vcard" );
|
||||
// break;
|
||||
case 'DAV::RESOURCETYPE':
|
||||
$prop->NewElement("resourcetype", new XMLElement("principal") );
|
||||
break;
|
||||
@ -42,7 +40,7 @@ function principal_to_xml( $properties, $item ) {
|
||||
$group = array();
|
||||
if ( $qry->Exec("REPORT-principal") && $qry->rows > 0 ) {
|
||||
while( $membership = $qry->Fetch() ) {
|
||||
$group[] = new XMLElement("href", sprintf( "%s/%s/", $c->protocol_server_port_script, $membership->username) );
|
||||
$group[] = new XMLElement("href", ConstructURL( "/". $membership->username . "/") );
|
||||
}
|
||||
}
|
||||
$prop->NewElement("group-member-set", $group );
|
||||
@ -52,7 +50,7 @@ function principal_to_xml( $properties, $item ) {
|
||||
$group = array();
|
||||
if ( $qry->Exec("REPORT-principal") && $qry->rows > 0 ) {
|
||||
while( $membership = $qry->Fetch() ) {
|
||||
$group[] = new XMLElement("href", sprintf( "%s/%s/", $c->protocol_server_port_script, $membership->username) );
|
||||
$group[] = new XMLElement("href", ConstructURL( "/". $membership->username . "/") );
|
||||
}
|
||||
}
|
||||
$prop->NewElement("group-membership", $group );
|
||||
@ -71,7 +69,7 @@ function principal_to_xml( $properties, $item ) {
|
||||
$status = new XMLElement("status", "HTTP/1.1 200 OK" );
|
||||
|
||||
$propstat = new XMLElement( "propstat", array( $prop, $status) );
|
||||
$href = new XMLElement("href", $url );
|
||||
$href = new XMLElement("href", $principal_url );
|
||||
|
||||
$elements = array($href,$propstat);
|
||||
|
||||
|
||||
@ -29,6 +29,8 @@ require_once("iCalendar.php");
|
||||
|
||||
$reportnum = -1;
|
||||
$report = array();
|
||||
$denied = array();
|
||||
$unsupported = array();
|
||||
if ( isset($prop_filter) ) unset($prop_filter);
|
||||
|
||||
$position = 0;
|
||||
@ -69,26 +71,38 @@ function calendar_to_xml( $properties, $item ) {
|
||||
if ( !is_numeric(strpos($item->permissions,'A')) && $session->user_no != $item->user_no ){
|
||||
// the user is not admin / owner of this calendarlooking at his calendar and can not admin the other cal
|
||||
if ( $item->class == 'CONFIDENTIAL' ) {
|
||||
$ical = new iCalendar( array( "icalendar" => $caldav_data) );
|
||||
// if the event is confidential we fake one that just says "Busy"
|
||||
$displayname = translate("Busy");
|
||||
$ical = new iCalendar( array( "icalendar" => $item->caldav_data) );
|
||||
$ical->Put( 'SUMMARY', $displayname );
|
||||
$caldav_data = $ical->render(true, $item->caldav_type, $ical->DefaultPropertyList() );
|
||||
$confidential = new iCalendar( array(
|
||||
'SUMMARY' => translate('Busy'), 'CLASS' => 'CONFIDENTIAL',
|
||||
'DTSTART' => $ical->Get('DTSTART'),
|
||||
'RRULE' => $ical->Get('RRULE')
|
||||
) );
|
||||
$duration = $ical->Get('DURATION');
|
||||
if ( isset($duration) && $duration != "" ) {
|
||||
$confidential->Set('DURATION', $duration );
|
||||
}
|
||||
else {
|
||||
$confidential->Set('DTEND', $ical->Get('DTEND') );
|
||||
}
|
||||
$caldav_data = $confidential->Render( true, $caldav_type );
|
||||
}
|
||||
elseif ( $c->hide_alarm ) {
|
||||
// Otherwise we hide the alarms (if configured to)
|
||||
$ical = new iCalendar( array( "icalendar" => $item->caldav_data) );
|
||||
$caldav_data = $ical->render(true, $item->caldav_type, $ical->DefaultPropertyList() );
|
||||
$ical = new iCalendar( array( "icalendar" => $caldav_data) );
|
||||
$ical->component->ClearComponents('VALARM');
|
||||
$caldav_data = $ical->render(true, $caldav_type );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$url = $c->protocol_server_port_script . $item->dav_name;
|
||||
$url = ConstructURL($item->dav_name);
|
||||
|
||||
$prop = new XMLElement("prop");
|
||||
foreach( $properties AS $k => $v ) {
|
||||
switch( $k ) {
|
||||
case 'GETCONTENTLENGTH':
|
||||
$contentlength = strlen($item->caldav_data);
|
||||
$contentlength = strlen($caldav_data);
|
||||
$prop->NewElement("getcontentlength", $contentlength );
|
||||
break;
|
||||
case 'CALENDAR-DATA':
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
include("page-header.php");
|
||||
|
||||
echo <<<EOBODY
|
||||
<h1>RSCDS Not Configured</h1>
|
||||
<h1>DAViCal Not Configured</h1>
|
||||
<h2>The Bad News</h2>
|
||||
<p>There is no configuration file present in <b>/etc/rscds/$_SERVER[SERVER_NAME]-conf.php</b> so
|
||||
<p>There is no configuration file present in <b>/etc/davical/$_SERVER[SERVER_NAME]-conf.php</b> so
|
||||
your installation is not fully set up.</p>
|
||||
<h2>The Good News</h2>
|
||||
<p>Well, you're seeing this! At least you have RSCDS <i>installed</i> :-) You also have Apache and PHP working
|
||||
<p>Well, you're seeing this! At least you have DAViCal <i>installed</i> :-) You also have Apache and PHP working
|
||||
and so really you are well on the road to success!</p>
|
||||
<h2>The Dubious News</h2>
|
||||
<p>You could try and <a href="http://$_SERVER[SERVER_NAME]/docs/rscds/configuring.html">click here</a> and
|
||||
@ -17,18 +17,16 @@ include("page-header.php");
|
||||
<p>The configuration file should look something like this:</p>
|
||||
<pre>
|
||||
<?php
|
||||
// \$c->domain_name = 'rscds.example.com';
|
||||
// \$c->sysabbr = 'rscds';
|
||||
// \$c->system_name = 'Really Simple CalDAV Store';
|
||||
// \$c->domain_name = 'davical.example.com';
|
||||
// \$c->sysabbr = 'davical';
|
||||
// \$c->system_name = 'DAViCal CalDAV Server';
|
||||
|
||||
\$c->admin_email = 'admin@example.com';
|
||||
\$c->pg_connect[] = 'dbname=rscds port=5432 user=general';
|
||||
\$c->pg_connect[] = 'dbname=davical port=5432 user=general';
|
||||
|
||||
?>
|
||||
</pre>
|
||||
<p>The only really <em>essential</em> thing there is that connect string for the database, although
|
||||
configuring someone for the admin e-mail is a really good idea.</p>
|
||||
EOBODY;
|
||||
|
||||
include("page-footer.php");
|
||||
?>
|
||||
@ -2,14 +2,15 @@
|
||||
/**
|
||||
* Manages LDAP repository connection
|
||||
*
|
||||
* @package rscds
|
||||
* @package davical
|
||||
* @category Technical
|
||||
* @subpackage caldav
|
||||
* @subpackage ldap
|
||||
* @author Maxime Delorme <mdelorme@tennaxia.net>
|
||||
* @copyright Maxime Delorme
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
*/
|
||||
|
||||
require_once("auth-functions.php");
|
||||
|
||||
class ldapDrivers
|
||||
{
|
||||
@ -49,14 +50,19 @@ class ldapDrivers
|
||||
$this->valid=false;
|
||||
return ;
|
||||
}
|
||||
if ($port) $this->connect=ldap_connect($host, $port);
|
||||
else $this->connect=ldap_connect($host);
|
||||
if ($port)
|
||||
$this->connect=ldap_connect($host, $port);
|
||||
else
|
||||
$this->connect=ldap_connect($host);
|
||||
|
||||
if (! $this->connect){
|
||||
$c->messages[] = sprintf(i18n( "drivers_ldap : Unable to connect to LDAP with port %s on host %s"), $port,$host );
|
||||
$this->valid=false;
|
||||
return ;
|
||||
}
|
||||
|
||||
dbg_error_log( "LDAP", "drivers_ldap : Connected to LDAP server %s",$host );
|
||||
|
||||
//Set LDAP protocol version
|
||||
if (isset($config['protocolVersion'])) ldap_set_option($this->connect,LDAP_OPT_PROTOCOL_VERSION, $config['protocolVersion']);
|
||||
|
||||
@ -80,20 +86,20 @@ class ldapDrivers
|
||||
/**
|
||||
* Retrieve all users from the LDAP directory
|
||||
*/
|
||||
function getAllUsers($attributs){
|
||||
function getAllUsers($attributes){
|
||||
global $c;
|
||||
$entry = ldap_list($this->connect,$this->baseDNUsers,$this->filterUsers,$attributs);
|
||||
$entry = ldap_list($this->connect,$this->baseDNUsers,$this->filterUsers,$attributes);
|
||||
if (!ldap_first_entry($this->connect,$entry))
|
||||
$c->messages[] = sprintf(i18n("Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"),$this->filterUsers,join(', ',$attributs), $this->baseDNUsers);
|
||||
$c->messages[] = sprintf(i18n("Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"),$this->filterUsers,join(', ',$attributes), $this->baseDNUsers);
|
||||
for($i=ldap_first_entry($this->connect,$entry);
|
||||
$i&&$arr=ldap_get_attributes($this->connect,$i);
|
||||
$i=ldap_next_entry($this->connect,$i)
|
||||
)
|
||||
{
|
||||
for($j=0;$j<$arr['count'];$j++){
|
||||
$row[$arr[$j]] = $arr[$arr[$j]][0];
|
||||
}
|
||||
$ret[]=$row;
|
||||
for($j=0;$j<$arr['count'];$j++){
|
||||
$row[$arr[$j]] = $arr[$arr[$j]][0];
|
||||
}
|
||||
$ret[]=$row;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
@ -102,30 +108,36 @@ class ldapDrivers
|
||||
* Returns the result of the LDAP query
|
||||
*
|
||||
* @param string $filter The filter used to search entries
|
||||
* @param array $attributs Attributes to be returned
|
||||
* @param array $attributes Attributes to be returned
|
||||
* @param string $passwd password to check
|
||||
* @return array Contains selected attributes from all entries corresponding to the given filter
|
||||
*/
|
||||
function requestUser($filter,$attributs=NULL,$passwd)
|
||||
{
|
||||
function requestUser( $filter, $attributes=NULL, $passwd) {
|
||||
|
||||
$entry=NULL;
|
||||
// We get the DN of the USER
|
||||
$entry = ldap_search($this->connect,$this->baseDNUsers,$filter,$attributs);
|
||||
if ( !ldap_first_entry($this->connect,$entry) ){
|
||||
dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter );
|
||||
return false;
|
||||
}
|
||||
$dnUser = ldap_get_dn($this->connect, ldap_first_entry($this->connect,$entry));
|
||||
if(!@ldap_bind($this->connect,$dnUser,$passwd))
|
||||
return false;
|
||||
$entry=NULL;
|
||||
// We get the DN of the USER
|
||||
$entry = ldap_search($this->connect, $this->baseDNUsers, $filter,$attributes);
|
||||
if ( !ldap_first_entry($this->connect, $entry) ){
|
||||
dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter );
|
||||
return false;
|
||||
} else {
|
||||
dbg_error_log( "LDAP", "drivers_ldap : Found a user using filter %s",$filter );
|
||||
}
|
||||
|
||||
$i=ldap_first_entry($this->connect,$entry);
|
||||
$arr=ldap_get_attributes($this->connect,$i);
|
||||
for($i=0;$i<$arr['count'];$i++){
|
||||
$ret[$arr[$i]]=$arr[$arr[$i]][0];
|
||||
}
|
||||
return $ret;
|
||||
$dnUser = ldap_get_dn($this->connect, ldap_first_entry($this->connect,$entry));
|
||||
if ( !@ldap_bind($this->connect, $dnUser, $passwd) ) {
|
||||
dbg_error_log( "LDAP", "drivers_ldap : Failed to bind to user %s using password %s", $dnUser, $passwd );
|
||||
return false;
|
||||
}
|
||||
|
||||
dbg_error_log( "LDAP", "drivers_ldap : Bound to user %s using password %s", $dnUser, $passwd );
|
||||
|
||||
$i = ldap_first_entry($this->connect,$entry);
|
||||
$arr = ldap_get_attributes($this->connect,$i);
|
||||
for( $i=0; $i<$arr['count']; $i++ ) {
|
||||
$ret[$arr[$i]]=$arr[$arr[$i]][0];
|
||||
}
|
||||
return $ret;
|
||||
|
||||
}
|
||||
}
|
||||
@ -146,70 +158,106 @@ function getStaticLdap() {
|
||||
return $ldapDrivers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Synchronise a cached user with one from LDAP
|
||||
* @param object $usr A user record to be updated (or created)
|
||||
*/
|
||||
function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) {
|
||||
global $c;
|
||||
|
||||
dbg_error_log( "LDAP", "Going to sync the user from LDAP" );
|
||||
$validUserFields = get_fields('usr');
|
||||
|
||||
foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) {
|
||||
if ( isset($validUserFields[$field]) ) {
|
||||
$usr->{$field} = $value;
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $value );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $mapping as $field => $value ) {
|
||||
dbg_error_log( "LDAP", "Considering copying %s", $field );
|
||||
if ( isset($validUserFields[$field]) ) {
|
||||
$usr->{$field} = $ldap_values[$value];
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$value], $value );
|
||||
}
|
||||
}
|
||||
|
||||
UpdateUserFromExternal( $usr );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the username / password against the LDAP server
|
||||
*/
|
||||
function LDAP_check($username, $password ){
|
||||
global $c;
|
||||
|
||||
$ldapDriver = getStaticLdap();
|
||||
if ( $ldapDriver->valid ) {
|
||||
$mapping = $c->authenticate_hook['config']['mapping_field'];
|
||||
$attributs=array_values($mapping);
|
||||
|
||||
// If the config contains a filter that starts with a ( then believe
|
||||
// them and don't modify it, otherwise wrap the filter.
|
||||
$filter_munge = "";
|
||||
if ( preg_match( '/^\(/', $ldapDriver->filterUsers ) ) {
|
||||
$filter_munge = $ldapDriver->filterUsers;
|
||||
} else {
|
||||
$filter_munge = "($ldapDriver->filterUsers)";
|
||||
}
|
||||
|
||||
$filter="(&$filter_munge(".$mapping["username"]."=$username))";
|
||||
dbg_error_log( "LDAP", "checking user %s for password %s against LDAP",$username,$password );
|
||||
$valid = $ldapDriver->requestUser($filter,$attributs,$password);
|
||||
|
||||
//is a valid user or not
|
||||
if ( !$valid ) return false;
|
||||
|
||||
|
||||
$ldap_timestamp = $valid[$mapping["updated"]];
|
||||
foreach($c->authenticate_hook['config']['format_updated'] as $k => $v)
|
||||
$$k = substr($ldap_timestamp,$v[0],$v[1]);
|
||||
|
||||
//ok it is valid is already exist in db ?
|
||||
$ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S";
|
||||
if ( $usr = getUserByName($username) ){
|
||||
//should we update it ?
|
||||
$db_timestamp = $usr->updated;
|
||||
$db_timestamp = substr(strtr($db_timestamp, array(':' => '',' '=>'','-'=>'')),0,14);
|
||||
if($ldap_timestamp <= $db_timestamp){
|
||||
return $usr;//no need to update
|
||||
}
|
||||
//we should update the user record
|
||||
}
|
||||
|
||||
//it doesn't exist so we create the new user or if we should be updated the user record
|
||||
require_once("RSCDSUser.php");
|
||||
|
||||
$user_no = ( isset($usr->user_no) ? $usr->user_no:0);
|
||||
$user = new RSCDSUser($user_no);
|
||||
$validUserField = array_keys($user->Fields);
|
||||
|
||||
foreach($c->authenticate_hook['config']['default_value'] as $field => $value)
|
||||
if(in_array($field,$validUserField)) $user->Set($field, $value);
|
||||
|
||||
foreach($mapping as $field => $value)
|
||||
if(in_array($field,$validUserField)) $user->Set($field, $valid[$value]);
|
||||
|
||||
$user->Set("updated", "$Y-$m-$d $H:$M:$S");
|
||||
$user->write();
|
||||
if ( !$ldapDriver->valid ) {
|
||||
dbg_error_log( "ERROR", "Couldn't contact LDAP server for authentication" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $return = getUserByName($username) ){
|
||||
return $return;
|
||||
$mapping = $c->authenticate_hook['config']['mapping_field'];
|
||||
$attributes = array_values($mapping);
|
||||
|
||||
/**
|
||||
* If the config contains a filter that starts with a ( then believe
|
||||
* them and don't modify it, otherwise wrap the filter.
|
||||
*/
|
||||
$filter_munge = "";
|
||||
if ( preg_match( '/^\(/', $ldapDriver->filterUsers ) ) {
|
||||
$filter_munge = $ldapDriver->filterUsers;
|
||||
}
|
||||
else {
|
||||
$filter_munge = "($ldapDriver->filterUsers)";
|
||||
}
|
||||
|
||||
$filter = "(&$filter_munge(".$mapping["username"]."=$username))";
|
||||
dbg_error_log( "LDAP", "checking user %s for password %s against LDAP",$username,$password );
|
||||
$valid = $ldapDriver->requestUser( $filter, $attributes, $password );
|
||||
|
||||
// is a valid user or not
|
||||
if ( !$valid ) {
|
||||
dbg_error_log( "LDAP", "user %s is not a valid user",$username );
|
||||
return false;
|
||||
}
|
||||
|
||||
$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";
|
||||
|
||||
if ( $usr = getUserByName($username) ) {
|
||||
// should we update it ?
|
||||
$db_timestamp = $usr->updated;
|
||||
$db_timestamp = substr(strtr($db_timestamp, array(':' => '',' '=>'','-'=>'')),0,14);
|
||||
if($ldap_timestamp <= $db_timestamp) {
|
||||
return $usr; // no need to update
|
||||
}
|
||||
// we will need to update the user record
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "LDAP", "user %s doesn't exist in local DB, we need to create it",$username );
|
||||
$usr = (object) array( 'user_no' => 0 );
|
||||
}
|
||||
|
||||
// The local cached user doesn't exist, or is older, so we create/update their details
|
||||
sync_user_from_LDAP($usr, $mapping, $valid );
|
||||
|
||||
return $usr;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sync LDAP against the DB
|
||||
*/
|
||||
@ -218,80 +266,86 @@ function sync_LDAP(){
|
||||
$ldapDriver = getStaticLdap();
|
||||
if($ldapDriver->valid){
|
||||
$mapping = $c->authenticate_hook['config']['mapping_field'];
|
||||
$attributs=array_values($mapping);
|
||||
$ldap_users_tmp = $ldapDriver->getAllUsers($attributs);
|
||||
$attributes = array_values($mapping);
|
||||
$ldap_users_tmp = $ldapDriver->getAllUsers($attributes);
|
||||
foreach($ldap_users_tmp as $key => $ldap_user){
|
||||
$ldap_users_info[$ldap_user[$mapping["username"]]] = $ldap_user;
|
||||
unset($ldap_users_tmp[$key]);
|
||||
}
|
||||
$qry = new PgQuery( "SELECT username ,user_no, updated FROM usr ");
|
||||
$qry = new PgQuery( "SELECT username, user_no, updated FROM usr ");
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
while($db_user = $qry->Fetch(true)){
|
||||
$db_users[] = $db_user['username'];
|
||||
$db_users_info[$db_user['username']] = array('user_no' => $db_user['user_no'], 'updated' => $db_user['updated']);
|
||||
}
|
||||
require_once("RSCDSUser.php");
|
||||
include_once("RSCDSUser.php");
|
||||
|
||||
$ldap_users = array_keys($ldap_users_info);
|
||||
//users only in ldap
|
||||
// users only in ldap
|
||||
$users_to_create = array_diff($ldap_users,$db_users);
|
||||
//users only in db
|
||||
$users_to_desactivate = array_diff($db_users,$ldap_users);
|
||||
//users present in ldap and in the db
|
||||
// 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){
|
||||
$valid=$ldap_users_info[$username];
|
||||
$ldap_timestamp = $valid[$mapping["updated"]];
|
||||
foreach($c->authenticate_hook['config']['format_updated'] as $k => $v)
|
||||
$$k = substr($ldap_timestamp,$v[0],$v[1]);
|
||||
$user = new RSCDSUser(0);
|
||||
$validUserField = array_keys($user->Fields);
|
||||
foreach($c->authenticate_hook['config']['default_value'] as $field => $value)
|
||||
if(in_array($field,$validUserField)) $user->Set($field, $value);
|
||||
foreach($mapping as $field => $value)
|
||||
if(in_array($field,$validUserField)) $user->Set($field, $valid[$value]);
|
||||
$user->Set("updated", "$Y-$m-$d $H:$M:$S");
|
||||
$messages = $c->messages;
|
||||
$user->write();
|
||||
$c->messages = $messages;
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
//desactivating all users
|
||||
if(sizeof($users_to_desactivate)){
|
||||
foreach( $users_to_desactivate AS $v ) {
|
||||
|
||||
// deactivating all users
|
||||
if ( sizeof($users_to_deactivate) ) {
|
||||
foreach( $users_to_deactivate AS $v ) {
|
||||
$usr_in .= ', ' . qpg($v);
|
||||
}
|
||||
$usr_in = substr($usr_in,1);
|
||||
$c->messages[] = sprintf(i18n('- desactivating users : %s'),$usr_in);
|
||||
$qry = new PgQuery( "UPDATE usr set active = FALSE WHERE lower(username) in ($usr_in)");
|
||||
$c->messages[] = sprintf(i18n('- deactivating users : %s'),$usr_in);
|
||||
$qry = new PgQuery( "UPDATE usr SET active = FALSE WHERE lower(username) IN ($usr_in)");
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
}
|
||||
//updating all users
|
||||
foreach($users_to_update as $key=> $username){
|
||||
$valid=$ldap_users_info[$username];
|
||||
$ldap_timestamp = $valid[$mapping["updated"]];
|
||||
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";
|
||||
$db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '',' '=>'','-'=>'')),0,14);
|
||||
if($ldap_timestamp > $db_timestamp){
|
||||
$user = new RSCDSUser($db_users_info[$username]['user_no']);
|
||||
$validUserField = array_keys($user->Fields);
|
||||
foreach($c->authenticate_hook['config']['default_value'] as $field => $value)
|
||||
if(in_array($field,$validUserField)) $user->Set($field, $value);
|
||||
foreach($mapping as $field => $value)
|
||||
if(in_array($field,$validUserField)) $user->Set($field, $valid[$value]);
|
||||
$user->Set("updated", "$Y-$m-$d $H:$M:$S");
|
||||
$user->write();
|
||||
} else {
|
||||
unset($users_to_update[$key]);
|
||||
$users_nothing_done[] = $username;
|
||||
|
||||
// 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"]];
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
$c->messages[] = sprintf(i18n('- updating user record %s'),join(', ',$users_to_update));
|
||||
if ( sizeof($users_nothing_done) )
|
||||
$c->messages[] = sprintf(i18n('- nothing done on %s'),join(', ', $users_nothing_done));
|
||||
}
|
||||
if(sizeof($users_to_update)) $c->messages[] = sprintf(i18n('- updating user record %s'),join(', ',$users_to_update));
|
||||
if(sizeof($users_nothing_done))$c->messages[] = sprintf(i18n('- nothing done on %s'),join(', ', $users_nothing_done));
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
83
inc/drivers_squid_pam.php
Normal file
83
inc/drivers_squid_pam.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Manages PAM repository connection with SQUID help
|
||||
*
|
||||
* @package davical
|
||||
* @category Technical
|
||||
* @subpackage ldap
|
||||
* @author Eric Seigne <eric.seigne@ryxeo.com>
|
||||
* @copyright Eric Seigne
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
*/
|
||||
|
||||
require_once("auth-functions.php");
|
||||
|
||||
class squidPamDrivers
|
||||
{
|
||||
/**#@+
|
||||
* @access private
|
||||
*/
|
||||
|
||||
/**#@-*/
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param string $config path where /usr/lib/squid/pam_auth is
|
||||
*/
|
||||
function squidPamDrivers($config){
|
||||
$this->__construct($config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @param string $config path where /usr/lib/squid/pam_auth is
|
||||
*/
|
||||
function __construct($config)
|
||||
{
|
||||
global $c;
|
||||
if (! file_exists($config)){
|
||||
$c->messages[] = sprintf(i18n( "drivers_squid_pam : Unable to find %s file"), $config );
|
||||
$this->valid=false;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the username / password against the PAM system
|
||||
*/
|
||||
function SQUID_PAM_check($username, $password ){
|
||||
global $c;
|
||||
|
||||
$cmd = "echo '" . $username . "' '" . $password . "' | " . $c->authenticate_hook['config']['script'] . " -n common-auth";
|
||||
$auth_result = exec($cmd);
|
||||
if ( $auth_result == "OK") {
|
||||
if ( $usr = getUserByName($username) ) {
|
||||
return $usr;
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "PAM", "user %s doesn't exist in local DB, we need to create it",$username );
|
||||
$fullname = trim( exec("getent passwd | grep ^" . $username ." | cut -d \":\" -f5"), ' ,' );
|
||||
$usr = (object) array(
|
||||
'user_no' => 0,
|
||||
'username' => $username,
|
||||
'active' => 't',
|
||||
'email' => $username . "@" . $c->authenticate_hook['config']['email_base'],
|
||||
'updated' => date(),
|
||||
'fullname' => $fullname
|
||||
);
|
||||
|
||||
UpdateUserFromExternal( $usr );
|
||||
return $usr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "PAM", "User %s is not a valid username (or password was wrong)", $username );
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -73,11 +73,13 @@ foreach( $busy_tentative AS $k => $v ) {
|
||||
while ( $date = $rrule->GetNext() ) {
|
||||
if ( ! $date->GreaterThan($start) ) continue;
|
||||
if ( $date->GreaterThan($finish) ) break;
|
||||
$freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $date->Render('Ymd\THis'), $duration );
|
||||
$todate = clone($date);
|
||||
$todate->AddDuration($duration);
|
||||
$freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $date->Render('Ymd\THis'), $todate->Render('Ymd\THis') );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $start->Render('Ymd\THis'), $duration );
|
||||
$freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $v->start, $v->finish );
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,11 +91,13 @@ foreach( $busy AS $k => $v ) {
|
||||
while ( $date = $rrule->GetNext() ) {
|
||||
if ( ! $date->GreaterThan($start) ) continue;
|
||||
if ( $date->GreaterThan($finish) ) break;
|
||||
$freebusy .= sprintf("FREEBUSY:%s/%s\n", $date->Render('Ymd\THis'), $duration );
|
||||
$todate = clone($date);
|
||||
$todate->AddDuration($duration);
|
||||
$freebusy .= sprintf("FREEBUSY:%s/%s\n", $date->Render('Ymd\THis'), $todate->Render('Ymd\THis') );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$freebusy .= sprintf("FREEBUSY:%s/%s\n", $start->Render('Ymd\THis'), $duration );
|
||||
$freebusy .= sprintf("FREEBUSY:%s/%s\n", $v->start, $v->finish );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,14 +5,14 @@ $page_menu->AddOption(translate("Home"),"$c->base_url/index.php",translate("Brow
|
||||
if ( $session->AllowedTo("Admin" )) {
|
||||
// $page_menu->AddOption(translate("Setup"),"$c->base_url/setup.php",translate("Setup RSCDS"), false, 5000 );
|
||||
$page_menu->AddOption(translate("Operations"),"$c->base_url/tools.php",translate("Operations on your calendar"), false, 5200 );
|
||||
|
||||
$relationship_menu = new MenuSet('submenu', 'submenu', 'submenu_active');
|
||||
}
|
||||
$page_menu->AddOption(translate("Logout"),"$c->base_url/index.php?logout",translate("Log out of the").$c->system_name, false, 5400 );
|
||||
$page_menu->AddOption(translate("Help"),"$c->base_url/help.php",translate("Help on something or other"), false, 8500 );
|
||||
$page_menu->AddOption(translate("Report Bug"),"http://sourceforge.net/tracker/?func=add&group_id=179845&atid=890785",translate("Report a bug in the system"), false, 9000 );
|
||||
|
||||
$relationship_menu = new MenuSet('submenu', 'submenu', 'submenu_active');
|
||||
$user_menu = new MenuSet('submenu', 'submenu', 'submenu_active');
|
||||
// $role_menu = new MenuSet('submenu', 'submenu', 'submenu_active');
|
||||
|
||||
$user_menu->AddOption(translate("My Details"),"$c->base_url/usr.php?user_no=$session->user_no",translate("View my own user record"), false, 700);
|
||||
|
||||
|
||||
@ -69,8 +69,10 @@ EOHDR;
|
||||
echo "<div id=\"pageheader\">\n";
|
||||
|
||||
if ( isset($page_menu) && is_object($page_menu) ) {
|
||||
$page_menu->AddSubMenu( $relationship_menu, translate("Relationships"),
|
||||
if ( isset($relationship_menu) && is_object($relationship_menu) ) {
|
||||
$page_menu->AddSubMenu( $relationship_menu, translate("Relationships"),
|
||||
"$c->base_url/relationship_types.php", translate("Browse all relationship types"), false, 4050 );
|
||||
}
|
||||
$page_menu->AddSubMenu( $user_menu, translate("Users"), "$c->base_url/users.php", translate("Browse all users"), false, 4100 );
|
||||
// $page_menu->AddSubMenu( $role_menu, "Roles", "/roles.php", "Browse all roles", false, 4300 );
|
||||
$page_menu->MakeSomethingActive($active_menu_pattern);
|
||||
|
||||
22
po/de_DE.po
22
po/de_DE.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: RSCDS 0.2.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: 2006-11-06 17:24+1300\n"
|
||||
"Last-Translator: Cristina Radalescu <andrew@mcmillan.net.nz>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -19,9 +19,9 @@ msgstr ""
|
||||
msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgstr ""
|
||||
#, fuzzy, c-format
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr "Benutzerdaten bearbeiten"
|
||||
|
||||
#, c-format
|
||||
msgid "- nothing done on %s"
|
||||
@ -161,6 +161,10 @@ msgstr "Datenbank Error"
|
||||
msgid "Date Style"
|
||||
msgstr "Datumsformat"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Default relationships added."
|
||||
msgstr "Verhältnis hinzugefuegt"
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Löschen"
|
||||
|
||||
@ -196,7 +200,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -562,6 +566,10 @@ msgstr ""
|
||||
msgid "You may not access that calendar"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not access that collection"
|
||||
msgstr "Sie sind nicht berechtigt diese Funktion zu benutzen"
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr "Sie sind nicht berechtigt diese Funktion zu benutzen"
|
||||
@ -602,6 +610,10 @@ msgstr ""
|
||||
msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
16
po/en_NZ.po
16
po/en_NZ.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -21,7 +21,7 @@ msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
@ -153,6 +153,9 @@ msgstr ""
|
||||
msgid "Date Style"
|
||||
msgstr ""
|
||||
|
||||
msgid "Default relationships added."
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
@ -188,7 +191,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -549,6 +552,9 @@ msgstr ""
|
||||
msgid "You may not access that calendar"
|
||||
msgstr ""
|
||||
|
||||
msgid "You may not access that collection"
|
||||
msgstr ""
|
||||
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr ""
|
||||
|
||||
@ -588,6 +594,10 @@ msgstr ""
|
||||
msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
22
po/es_AR.po
22
po/es_AR.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: RSCDS 0.2.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: 2006-11-06 17:12+1300\n"
|
||||
"Last-Translator: Lorena Paoletti <andrew@mcmillan.net.nz>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -20,9 +20,9 @@ msgstr ""
|
||||
msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgstr ""
|
||||
#, fuzzy, c-format
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr "Mostrar el registro de éste usuario"
|
||||
|
||||
#, c-format
|
||||
msgid "- nothing done on %s"
|
||||
@ -162,6 +162,10 @@ msgstr "Error en la Base de Datos."
|
||||
msgid "Date Style"
|
||||
msgstr "Formato de Fecha"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Default relationships added."
|
||||
msgstr "Relación incorporada."
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Borrar"
|
||||
|
||||
@ -197,7 +201,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -560,6 +564,10 @@ msgstr ""
|
||||
msgid "You may not access that calendar"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not access that collection"
|
||||
msgstr "No está autorizado a utilizar ésta función."
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr "No está autorizado a utilizar ésta función."
|
||||
@ -600,6 +608,10 @@ msgstr ""
|
||||
msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
22
po/es_ES.po
22
po/es_ES.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: RSCDS 0.2.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: 2006-11-06 17:12+1300\n"
|
||||
"Last-Translator: Lorena Paoletti <andrew@mcmillan.net.nz>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -20,9 +20,9 @@ msgstr ""
|
||||
msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgstr ""
|
||||
#, fuzzy, c-format
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr "Mostrar el registro de éste usuario"
|
||||
|
||||
#, c-format
|
||||
msgid "- nothing done on %s"
|
||||
@ -162,6 +162,10 @@ msgstr "Error en la Base de Datos."
|
||||
msgid "Date Style"
|
||||
msgstr "Formato de Fecha"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Default relationships added."
|
||||
msgstr "Relación incorporada."
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Borrar"
|
||||
|
||||
@ -197,7 +201,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -560,6 +564,10 @@ msgstr ""
|
||||
msgid "You may not access that calendar"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not access that collection"
|
||||
msgstr "No está autorizado a utilizar ésta función."
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr "No está autorizado a utilizar ésta función."
|
||||
@ -600,6 +608,10 @@ msgstr ""
|
||||
msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
22
po/es_MX.po
22
po/es_MX.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: RSCDS 0.2.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: 2006-11-06 17:12+1300\n"
|
||||
"Last-Translator: Lorena Paoletti <andrew@mcmillan.net.nz>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -20,9 +20,9 @@ msgstr ""
|
||||
msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgstr ""
|
||||
#, fuzzy, c-format
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr "Mostrar el registro de éste usuario"
|
||||
|
||||
#, c-format
|
||||
msgid "- nothing done on %s"
|
||||
@ -162,6 +162,10 @@ msgstr "Error en la Base de Datos."
|
||||
msgid "Date Style"
|
||||
msgstr "Formato de Fecha"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Default relationships added."
|
||||
msgstr "Relación incorporada."
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Borrar"
|
||||
|
||||
@ -197,7 +201,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -560,6 +564,10 @@ msgstr ""
|
||||
msgid "You may not access that calendar"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not access that collection"
|
||||
msgstr "No está autorizado a utilizar ésta función."
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr "No está autorizado a utilizar ésta función."
|
||||
@ -600,6 +608,10 @@ msgstr ""
|
||||
msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
22
po/fr_FR.po
22
po/fr_FR.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rscds 0.3.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: 2006-11-13 13:03+1300\n"
|
||||
"Last-Translator: maxime delorme <mdelorme@tennaxia.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -20,8 +20,8 @@ msgstr ""
|
||||
msgid "- creating record for users : %s"
|
||||
msgstr "- création des utilisateurs : %s"
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
#, fuzzy, c-format
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr "- desactivation des utilisateurs : %s"
|
||||
|
||||
#, c-format
|
||||
@ -165,6 +165,10 @@ msgstr "Erreur base de données"
|
||||
msgid "Date Style"
|
||||
msgstr "Format des dates"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Default relationships added."
|
||||
msgstr "Relation ajoutée"
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Supprimer"
|
||||
|
||||
@ -203,8 +207,8 @@ msgstr "Tapez un nom pour ce type de ressource"
|
||||
msgid "Enter your username and password then click here to log in."
|
||||
msgstr "Tapez votre nom d'utilisateur et votre mot de passe puis cliquez ici pour vous connecter"
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
#, fuzzy, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr "Erreur NoUserFound avec le filtre >%s<, attributs >%s<, dn >%s<"
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -627,6 +631,10 @@ msgstr "Vous n'avez pas suffisamment d'accès pour verrouiller ça"
|
||||
msgid "You may not access that calendar"
|
||||
msgstr "Vous ne pouvez accéder à ce calendrier"
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not access that collection"
|
||||
msgstr "Vous ne pouvez accéder à ce calendrier"
|
||||
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr "Vous n'êtes pas autorisé à utiliser cette fonction."
|
||||
|
||||
@ -670,6 +678,10 @@ msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap mod
|
||||
msgstr ""
|
||||
"drivers_ldap : la fonction ldap_connect n'est pas définie, vérifier que vous avez l'extension php_ldap"
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
22
po/hu_HU.po
22
po/hu_HU.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rscds 0.7.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: 2007-05-03 15:00+0001\n"
|
||||
"Last-Translator: David Takacs <david.takacs@cafeopen.eu>\n"
|
||||
"Language-Team: \n"
|
||||
@ -20,9 +20,9 @@ msgstr ""
|
||||
msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgstr ""
|
||||
#, fuzzy, c-format
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr "Felhasználó szerkesztése"
|
||||
|
||||
#, c-format
|
||||
msgid "- nothing done on %s"
|
||||
@ -155,6 +155,10 @@ msgstr "Adatbázis-hiba"
|
||||
msgid "Date Style"
|
||||
msgstr "Dátumformátum"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Default relationships added."
|
||||
msgstr "Kapcsolat hozzáadva."
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Törlés"
|
||||
|
||||
@ -190,7 +194,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr "Írja be a felhasználónevét és jelszavát a belépéshez"
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -553,6 +557,10 @@ msgstr "Nincs jogosultsága zárolni"
|
||||
msgid "You may not access that calendar"
|
||||
msgstr "Nincs jogosultsága hozzáférni a naptárhoz"
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not access that collection"
|
||||
msgstr "Nincs jogosultsága hozzáférni a naptárhoz"
|
||||
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr "Nincs jogosultsága új bejegyzéseket írni a naptárba."
|
||||
|
||||
@ -593,6 +601,10 @@ msgstr ""
|
||||
msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -21,7 +21,7 @@ msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
@ -158,6 +158,9 @@ msgstr ""
|
||||
msgid "Date Style"
|
||||
msgstr ""
|
||||
|
||||
msgid "Default relationships added."
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
@ -195,7 +198,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -562,6 +565,9 @@ msgstr ""
|
||||
msgid "You may not access that calendar"
|
||||
msgstr ""
|
||||
|
||||
msgid "You may not access that collection"
|
||||
msgstr ""
|
||||
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr ""
|
||||
|
||||
@ -602,6 +608,10 @@ msgid ""
|
||||
"drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a "
|
||||
"flower) and is an option allowing people to log in automatically in future --"
|
||||
|
||||
22
po/nl_NL.po
22
po/nl_NL.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Eelco Maljaars <http://eelco.maljaars.net/>\n"
|
||||
"Language-Team: nl_NL <LL@li.org>\n"
|
||||
@ -20,9 +20,9 @@ msgstr ""
|
||||
msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgstr ""
|
||||
#, fuzzy, c-format
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr "Verander deze gebruiker"
|
||||
|
||||
#, c-format
|
||||
msgid "- nothing done on %s"
|
||||
@ -158,6 +158,10 @@ msgstr "Database fout"
|
||||
msgid "Date Style"
|
||||
msgstr "Datum stijl"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Default relationships added."
|
||||
msgstr "Relatie toegevoegd"
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Verwijder"
|
||||
|
||||
@ -194,7 +198,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr "Voer je gebruikersnaam en wachtwoord in en klik hier om in te loggen"
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -557,6 +561,10 @@ msgstr ""
|
||||
msgid "You may not access that calendar"
|
||||
msgstr "Je mag die agenda niet benaderen"
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not access that collection"
|
||||
msgstr "Je mag die agenda niet benaderen"
|
||||
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr "Je mag geen items toevoegen aan deze agenda"
|
||||
|
||||
@ -597,6 +605,10 @@ msgstr ""
|
||||
msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
22
po/pl_PL.po
22
po/pl_PL.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rscds-messages\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: 2007-03-31 00:24+0200\n"
|
||||
"Last-Translator: Rafal Slubowski <rafalslubowski@gmail.com>\n"
|
||||
"Language-Team: polski <pl@li.org>\n"
|
||||
@ -22,9 +22,9 @@ msgstr ""
|
||||
msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgstr ""
|
||||
#, fuzzy, c-format
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr "Zmień dane tego użytkownika "
|
||||
|
||||
#, c-format
|
||||
msgid "- nothing done on %s"
|
||||
@ -157,6 +157,10 @@ msgstr "Błąd bazy danych"
|
||||
msgid "Date Style"
|
||||
msgstr "Format daty"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Default relationships added."
|
||||
msgstr "Zależność została dodana."
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Usuń"
|
||||
|
||||
@ -192,7 +196,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr "Wpisz nazwę użytkownika oraz hasło i naciśnij tutaj aby się zalogować."
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -555,6 +559,10 @@ msgstr "Nie masz wystarczających uprawnień aby zarezerwować ten"
|
||||
msgid "You may not access that calendar"
|
||||
msgstr "Nie masz dostępu do tego kalendarza"
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not access that collection"
|
||||
msgstr "Nie masz dostępu do tego kalendarza"
|
||||
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr "Nie możesz dodawać zdarzeń do tego kalendarza."
|
||||
|
||||
@ -595,6 +603,10 @@ msgstr ""
|
||||
msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
22
po/ru_RU.po
22
po/ru_RU.po
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rscds 0.3.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-10-16 13:28+1300\n"
|
||||
"POT-Creation-Date: 2007-11-17 22:06+1300\n"
|
||||
"PO-Revision-Date: 2006-11-13 23:07+0500\n"
|
||||
"Last-Translator: Nick Khazov <m2k3d0n@users.sourceforge.net>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -19,9 +19,9 @@ msgstr ""
|
||||
msgid "- creating record for users : %s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "- desactivating users : %s"
|
||||
msgstr ""
|
||||
#, fuzzy, c-format
|
||||
msgid "- deactivating users : %s"
|
||||
msgstr "Посмотреть мою учетную запись"
|
||||
|
||||
#, c-format
|
||||
msgid "- nothing done on %s"
|
||||
@ -160,6 +160,10 @@ msgstr ""
|
||||
msgid "Date Style"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "Default relationships added."
|
||||
msgstr "Связь добавлена."
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Удалить"
|
||||
|
||||
@ -197,7 +201,7 @@ msgid "Enter your username and password then click here to log in."
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"
|
||||
msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error querying database."
|
||||
@ -570,6 +574,10 @@ msgstr ""
|
||||
msgid "You may not access that calendar"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not access that collection"
|
||||
msgstr "Вы не авторизованы для использоования этой функции."
|
||||
|
||||
#, fuzzy
|
||||
msgid "You may not add entries to this calendar."
|
||||
msgstr "Вы не авторизованы для использоования этой функции."
|
||||
@ -610,6 +618,10 @@ msgstr ""
|
||||
msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "drivers_squid_pam : Unable to find %s file"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option "
|
||||
"allowing people to log in automatically in future -->"
|
||||
|
||||
@ -18,14 +18,14 @@ sed -e 's/CHARSET/UTF-8/' <${PODIR}/messages.tmp >${PODIR}/messages.po
|
||||
rm ${PODIR}/messages.tmp
|
||||
|
||||
|
||||
for LOCALE in `psql -qAt -c 'SELECT locale FROM supported_locales;' caldav` ; do
|
||||
for LOCALE in `grep VALUES dba/supported_locales.sql | cut -f2 -d"'"` ; do
|
||||
if [ ! -f ${PODIR}/${LOCALE}.po ] ; then
|
||||
cp ${PODIR}/messages.po ${PODIR}/${LOCALE}.po
|
||||
fi
|
||||
msgmerge --quiet --width 105 --update ${PODIR}/${LOCALE}.po ${PODIR}/messages.po
|
||||
done
|
||||
|
||||
for LOCALE in `psql -qAt -c 'SELECT locale FROM supported_locales;' caldav` ; do
|
||||
for LOCALE in `grep VALUES dba/supported_locales.sql | cut -f2 -d"'"` ; do
|
||||
mkdir -p ${LOCALEDIR}/${LOCALE}/LC_MESSAGES
|
||||
msgfmt ${PODIR}/${LOCALE}.po -o ${LOCALEDIR}/${LOCALE}/LC_MESSAGES/${APPLICATION}.mo
|
||||
done
|
||||
|
||||
@ -10,11 +10,9 @@ use Getopt::Long qw(:config permute); # allow mixed args.
|
||||
|
||||
# Options variables
|
||||
my $debug = 0;
|
||||
my $dbname = "rscds";
|
||||
my $dbport = 5432;
|
||||
my $dsn = "davical";
|
||||
my $dbuser = "";
|
||||
my $dbpass = "";
|
||||
my $dbhost = "";
|
||||
my $suite;
|
||||
my $test;
|
||||
my $helpmeplease = 0;
|
||||
@ -25,11 +23,9 @@ my $patchdir = $dbadir . "/patches";
|
||||
|
||||
|
||||
GetOptions ('debug!' => \$debug,
|
||||
'dbname=s' => \$dbname,
|
||||
'dsn=s' => \$dsn,
|
||||
'dbuser=s' => \$dbuser,
|
||||
'dbpass=s' => \$dbpass,
|
||||
'dbport=s' => \$dbport,
|
||||
'dbhost=s' => \$dbhost,
|
||||
'suite=s' => \$suite,
|
||||
'case=s' => \$test,
|
||||
'help' => \$helpmeplease );
|
||||
@ -40,14 +36,13 @@ usage() if ( $helpmeplease || !defined($suite) || !defined($test));
|
||||
# Open database connection. Note that the standard PostgreSQL
|
||||
# environment variables will also work with DBD::Pg.
|
||||
############################################################
|
||||
my $dsn = "dbi:Pg:dbname=$dbname";
|
||||
$dsn .= ";host=$dbhost" if ( "$dbhost" ne "" );
|
||||
$dsn .= ";port=$dbport" if ( $dbport != 5432 );
|
||||
my $dbh = DBI->connect($dsn, $dbuser, $dbpass, { AutoCommit => 0 } ) or die "Can't connect to database $dbname";
|
||||
$dsn = "dbi:Pg:dbname=$dsn";
|
||||
my $dbh = DBI->connect($dsn, $dbuser, $dbpass, { AutoCommit => 0 } ) or die "Can't connect to database $dsn";
|
||||
|
||||
|
||||
my @arguments = ( "--basic", "--proxy", "", "--silent" );
|
||||
push @arguments, "--verbose" if ( defined($ARGV[2]) );
|
||||
my @arguments = ( "--basic", "--proxy", "" );
|
||||
push @arguments, "--silent" unless ( $debug );
|
||||
push @arguments, "--verbose" if ( $debug );
|
||||
|
||||
my $url;
|
||||
my $is_head_request = 0;
|
||||
@ -204,6 +199,7 @@ if ( defined(@{$queries}) && @{$queries} ) {
|
||||
print STDERR "Processing results row\n" if ( $debug );
|
||||
my $sep = "";
|
||||
foreach my $column ( @$row ) {
|
||||
$column = 'NULL' unless ( defined($column) );
|
||||
print $sep, $column;
|
||||
$sep = " --- ";
|
||||
}
|
||||
@ -242,11 +238,9 @@ and follow the instructions there.
|
||||
|
||||
The following options are available for controlling the database, for
|
||||
those test cases which might require it:
|
||||
--dbname <database>
|
||||
--dsn <database>[;port=NNNN][;host=example.com]
|
||||
--dbuser <user>
|
||||
--dbpass <password>
|
||||
--dbport <port>
|
||||
--dbhost <host>
|
||||
|
||||
|
||||
The test instructions will include lines defining the test like:
|
||||
|
||||
7
testing/regression.conf.example
Normal file
7
testing/regression.conf.example
Normal file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# A configuration file for the regression testing.
|
||||
#
|
||||
DBNAME=regression
|
||||
PGPOOL=inactive
|
||||
HOSTNAME=mycaldav
|
||||
DSN="regression;port=5432"
|
||||
@ -2,7 +2,15 @@
|
||||
#
|
||||
# Run the regression tests and display differences
|
||||
#
|
||||
DBNAME=caldav
|
||||
DBNAME=regression
|
||||
PGPOOL=inactive
|
||||
HOSTNAME=regression
|
||||
|
||||
. regression.conf
|
||||
|
||||
[ -z "${DSN}" ] && DSN="${DBNAME}"
|
||||
|
||||
|
||||
UNTIL=${1:-"99999"}
|
||||
ACCEPT_ALL=${2:-""}
|
||||
|
||||
@ -40,7 +48,7 @@ drop_database() {
|
||||
# Restart PGPool to ensure we can drop and recreate the database
|
||||
# FIXME: We should really drop everything *from* the database and create it
|
||||
# from that, so we don't need to do this.
|
||||
sudo /etc/init.d/pgpool restart
|
||||
[ "${PGPOOL}" = "inactive" ] || sudo /etc/init.d/pgpool restart
|
||||
dropdb $1
|
||||
if psql -ltA | cut -f1 -d'|' | grep "^$1$" >/dev/null ; then
|
||||
echo "Failed to drop $1 database"
|
||||
@ -69,7 +77,7 @@ for T in ${REGRESSION}/*.test ; do
|
||||
if [ "${TESTNUM}" -gt "${UNTIL}" ] ; then
|
||||
break;
|
||||
fi
|
||||
./dav_test --dbname caldav --suite regression-suite --case "${TEST}" | ./normalise_result > "${RESULTS}/${TEST}"
|
||||
./dav_test --dsn "${DSN}" --suite regression-suite --case "${TEST}" | ./normalise_result > "${RESULTS}/${TEST}"
|
||||
|
||||
check_result "${TEST}"
|
||||
|
||||
|
||||
132
testing/sniffstream
Executable file
132
testing/sniffstream
Executable file
@ -0,0 +1,132 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Sniff traffic and format as a stream of packet contents
|
||||
#
|
||||
use strict;
|
||||
|
||||
use Getopt::Long qw(:config permute); # allow mixed args.
|
||||
|
||||
# Options variables
|
||||
my $debug = 0;
|
||||
my $saveto;
|
||||
my $readfrom;
|
||||
my $interface = 'any';
|
||||
my $dumpspec = 'tcp port 80';
|
||||
my $helpmeplease = 0;
|
||||
|
||||
GetOptions ('debug!' => \$debug,
|
||||
'write=s' => \$saveto,
|
||||
'file=s' => \$readfrom,
|
||||
'interface=s' => \$interface,
|
||||
'dumpspec=s' => \$dumpspec,
|
||||
'help' => \$helpmeplease );
|
||||
|
||||
usage() if ( $helpmeplease );
|
||||
|
||||
if ( defined($saveto) ) {
|
||||
open( SAVETO, '>>', $saveto ) or die "Couldn't save to '$saveto'";
|
||||
}
|
||||
|
||||
if ( defined($readfrom) ) {
|
||||
if ( $readfrom ne '-' ) {
|
||||
open( STDIN, '<', $readfrom ) or die "Couldn't open '$readfrom'";
|
||||
}
|
||||
}
|
||||
else {
|
||||
my @tcpdumpoptions = ('-i', $interface, '-s0', '-l', '-xx', '-n', '-q', $dumpspec );
|
||||
open( STDIN, '-|', "tcpdump", @tcpdumpoptions ) or die "Couldn't start tcpdump process";
|
||||
}
|
||||
|
||||
my $timestamp;
|
||||
my $source = '';
|
||||
my $dest = '';
|
||||
my $lastsource = '';
|
||||
my $lastdest = '';
|
||||
my $show;
|
||||
my $packet;
|
||||
my $stream;
|
||||
|
||||
while( <STDIN> ) {
|
||||
$show = 0;
|
||||
if ( /^([012]\d:[0-5]\d:[0-5]\d\.\d{6})\sIP\s([0-9.:]+)\s>\s([0-9.:]+):\ tcp/ ) {
|
||||
$timestamp = $1;
|
||||
$source = $2;
|
||||
$dest = $3;
|
||||
}
|
||||
elsif ( /^\s+(0x....):\s(( [0-9a-f]{4}){1,8})/i ) {
|
||||
my $pos = hex($1);
|
||||
my $hex = $2;
|
||||
next unless defined($hex);
|
||||
|
||||
if ( $pos == 64 ) {
|
||||
$hex = substr( $hex, 10 );
|
||||
$pos += 4;
|
||||
}
|
||||
|
||||
if ( $pos >= 68 ) {
|
||||
my @hex = split /\s+/, $hex;
|
||||
my $ascii = "";
|
||||
foreach my $xch ( @hex ) {
|
||||
next if ( $xch eq '' );
|
||||
$ascii .= chr(hex(substr($xch,0,2)));
|
||||
$ascii .= chr(hex(substr($xch,2,2)));
|
||||
}
|
||||
$show = 1;
|
||||
$_ = $ascii;
|
||||
}
|
||||
}
|
||||
elsif ( /^\.\./ ) {
|
||||
s/^\.\.......//;
|
||||
$show = 1;
|
||||
}
|
||||
else {
|
||||
$show = 1;
|
||||
}
|
||||
|
||||
if ( $show ) {
|
||||
if ( $source ne $lastsource || $dest ne $lastdest ) {
|
||||
putline( "\n\n=============== $timestamp $source ==> $dest\n" );
|
||||
$lastsource = $source;
|
||||
$lastdest = $dest;
|
||||
}
|
||||
putline( $_ );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
###########################################################
|
||||
sub putline {
|
||||
my $line = shift;
|
||||
print $line;
|
||||
print SAVETO $line if ( defined($saveto) );
|
||||
}
|
||||
|
||||
|
||||
###########################################################
|
||||
sub usage {
|
||||
print <<EOERROR ;
|
||||
|
||||
Usage: sniffstream [options]
|
||||
|
||||
The sniffstream program will format the output of "tcpdump -s0 -n -q -xx"
|
||||
for easier reading and comparison, with a view to seeing the actions
|
||||
involved in a DAV communication session. By default it will run the
|
||||
tcpdump command internally.
|
||||
|
||||
It will also somewhat format the output of "tcpdump -s0 -n -q -A".
|
||||
|
||||
Options:
|
||||
|
||||
--write <filename> Append the stream to the named file.
|
||||
--file (-|<filename>) Format the input from the named file, or stdin.
|
||||
--interface <ifname> Run tcpdump against the specified interface.
|
||||
--dumpspec <spec> Run tcpdump with that capture specification .
|
||||
|
||||
The default interface is 'any' and the default dumpspec is 'tcp port 80'.
|
||||
|
||||
EOERROR
|
||||
exit 1;
|
||||
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
HTTP/1.1 200 OK
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Allow: OPTIONS, GET, HEAD, PROPFIND, REPORT
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "373430133d9c51260783bc61177aa1d3"
|
||||
Content-Length: 1880
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "cc0f368288b5b8373d00e28f842190e6"
|
||||
Content-Length: 383
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
ETag: "4bbc059be0ae780aa041d72b2ee837a6"
|
||||
Content-Length: 726
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "a30e9b8f2662cd1da17252d3b814ef04"
|
||||
Content-Length: 730
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<multistatus xmlns="DAV:">
|
||||
<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<response>
|
||||
<href>/caldav.php/user1/</href>
|
||||
<propstat>
|
||||
@ -28,7 +29,7 @@ Content-Type: text/xml; charset="utf-8"
|
||||
<getcontentlength/>
|
||||
<resourcetype>
|
||||
<collection/>
|
||||
<calendar xmlns="urn:ietf:params:xml:ns:caldav"/>
|
||||
<C:calendar/>
|
||||
</resourcetype>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
ETag: "63c4632cd1f99190e4613ed7912bc44a"
|
||||
Content-Length: 483
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "7364b32495feb0c9bbe89cdb10988762"
|
||||
Content-Length: 487
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<multistatus xmlns="DAV:">
|
||||
<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<response>
|
||||
<href>/caldav.php/user1/home/</href>
|
||||
<propstat>
|
||||
@ -14,7 +15,7 @@ Content-Type: text/xml; charset="utf-8"
|
||||
<getcontentlength/>
|
||||
<resourcetype>
|
||||
<collection/>
|
||||
<calendar xmlns="urn:ietf:params:xml:ns:caldav"/>
|
||||
<C:calendar/>
|
||||
</resourcetype>
|
||||
<getetag>"faf25336de0e470a54075c14cbcf5272"</getetag>
|
||||
</prop>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 405 Method Not Allowed
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Content-Length: 45
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "b000d7defa19ccb7cd21e546b54155ee"
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 204 No Content
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "b000d7defa19ccb7cd21e546b54155ee"
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "22158fc45876987b2b00749a3a1684d8"
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
ETag: "3f528a647491c5f1bd3e5ac60dc7d471"
|
||||
Content-Length: 1051
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "4cd4df7d08592927b92bcd697c2cdde7"
|
||||
Content-Length: 1055
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<multistatus xmlns="DAV:">
|
||||
<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<response>
|
||||
<href>/caldav.php/user1/home/</href>
|
||||
<propstat>
|
||||
@ -14,7 +15,7 @@ Content-Type: text/xml; charset="utf-8"
|
||||
<getcontentlength>1425</getcontentlength>
|
||||
<resourcetype>
|
||||
<collection/>
|
||||
<calendar xmlns="urn:ietf:params:xml:ns:caldav"/>
|
||||
<C:calendar/>
|
||||
</resourcetype>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 204 No Content
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "2c32a2f8aba853654eb17fe037a4db4d"
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
ETag: "c195de52b2e0c2e02fb1da08051bde14"
|
||||
Content-Length: 1051
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "d880baf3102a9de9bcea4d5f71a6b500"
|
||||
Content-Length: 1055
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<multistatus xmlns="DAV:">
|
||||
<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<response>
|
||||
<href>/caldav.php/user1/home/</href>
|
||||
<propstat>
|
||||
@ -14,7 +15,7 @@ Content-Type: text/xml; charset="utf-8"
|
||||
<getcontentlength>1467</getcontentlength>
|
||||
<resourcetype>
|
||||
<collection/>
|
||||
<calendar xmlns="urn:ietf:params:xml:ns:caldav"/>
|
||||
<C:calendar/>
|
||||
</resourcetype>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 403 Forbidden
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Content-Length: 36
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "75a75e1c7c4546074aab7645b5323738"
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 400 Bad Request
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Content-Length: 46
|
||||
Connection: close
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 412 Precondition Failed
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Content-Length: 44
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 204 No Content
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "81979ab45975368d619171a4c3e1e5e2"
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 204 No Content
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
HTTP/1.1 200 OK
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH
|
||||
Content-Length: 0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
ETag: "7dd087918d1ab4ba7e7861307b57c6dd"
|
||||
Content-Length: 341
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
ETag: "5d903e7367fc5fd8975cd2a2f12c94ef"
|
||||
Content-Length: 326
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<multistatus xmlns="DAV:">
|
||||
<response>
|
||||
<href>http://mycaldav/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href>
|
||||
<href>/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"2c32a2f8aba853654eb17fe037a4db4d"</getetag>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
HTTP/1.1 200 OK
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, access-control, calendar-access
|
||||
Etag: "2c32a2f8aba853654eb17fe037a4db4d"
|
||||
Content-Length: 747
|
||||
Content-Type: text/calendar
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user