Now supports user create, view & edit with role assignment. Also starts to

support the PROPFIND request that Mulberry makes but does not fully support
Mulberry yet (their timezones are non-standard).
This commit is contained in:
Andrew McMillan 2006-09-27 09:53:34 +12:00
parent 2b8b67ab0b
commit db963fadf6
18 changed files with 1913 additions and 1331 deletions

View File

@ -5,8 +5,12 @@
DBNAME="${1:-rscds}"
DBADIR="`dirname \"$0\"`"
createdb -E UTF8 "${DBNAME}"
psql -f rscds.sql "${DBNAME}"
psql -f "${DBADIR}/rscds.sql" "${DBNAME}"
psql -f sample-data.sql "${DBNAME}"
psql -f "${DBADIR}/caldav_functions.sql" "${DBNAME}"
psql -f "${DBADIR}/sample-data.sql" "${DBNAME}"

10
debian/changelog vendored
View File

@ -1,3 +1,13 @@
rscds (0.1.4) unstable; urgency=low
* Now working with both Evolution and Lightning+Thunderbird(alpha)
* Restructured database to show some sense.
* Initial support for TODO items, although either I have it wrong, or
Lighning has it wrong. Lightning can write them, but it doesn't read
them.
-- Andrew McMillan <debian@mcmillan.net.nz> Sun, 24 Sep 2006 17:18:30 +1200
rscds (0.1.3) unstable; urgency=low
* Hopefully now fairly much ready to install.

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
<?php
require_once("always.php");
dbg_error_log( "caldav", " User agent: %s", $_SERVER['HTTP_USER_AGENT'] );
require_once("BasicAuthSession.php");
$raw_headers = apache_request_headers();
@ -18,6 +19,10 @@ switch ( $_SERVER['REQUEST_METHOD'] ) {
include_once("caldav-REPORT.php");
break;
case 'PROPFIND':
include_once("caldav-PROPFIND.php");
break;
case 'PUT':
include_once("caldav-PUT.php");
break;

50
htdocs/user.php Normal file
View File

@ -0,0 +1,50 @@
<?php
require_once("always.php");
require_once("RSCDSSession.php");
// This page requires login.
$session->LoginRequired();
require_once("interactive-page.php");
require_once("RSCDSUser.php");
$user_no = intval(isset($_POST['user_no']) ? $_POST['user_no'] : $_GET['user_no'] );
$user = new RSCDSUser($user_no);
if ( $user->user_no == 0 ) {
$c->page_title = ( $user_no != "" ? "User Unavailable" : "New User" );
}
else {
$c->page_title = sprintf("%s (%s)", $user->Get("fullname"), $user->Get("username"));
}
$show = 0;
if ( !$session->just_logged_in && isset($_POST['submit']) ) {
if ( $session->AllowedTo("Admin") || $session->AllowedTo("Support")
|| ($user->user_no > 0 && $user->user_no == $session->user_no) ) {
$session->Log( "DBG: Record %s write type is %s.", $user->Table, $user->WriteType );
$user->PostToValues();
if ( $user->Validate() ) {
$user->Write();
$user = new User($user->user_no);
$user->EditMode = true;
if ( $user->user_no == 0 ) {
$c->page_title = ( $user_no != "" ? "User Unavailable" : "New User" );
}
else {
$c->page_title = $user->Get("user_no"). " - " . $user->Get("fullname");
}
}
}
}
if ( $session->AllowedTo("Admin") )
$user_menu->AddOption("New User","/user.php?create","Add a new user", false, 10);
if ( $user->user_no > 0 && $user->AllowedTo('update') ) {
$user_menu->AddOption("View","/user.php?user_no=$user->user_no","View this user record");
$user_menu->AddOption("Edit","/user.php?edit=1&user_no=$user->user_no","Edit this user record");
}
include("page-header.php");
echo $user->Render($c->page_title);
include("page-footer.php");
?>

View File

@ -28,7 +28,7 @@ require_once("interactive-page.php");
$c->page_title = "Calendar Users";
// if ( $session->AllowedTo("Support") )
if ( $session->AllowedTo("Admin") )
$user_menu->AddOption("New User","/user.php?create","Add a new user", false, 10);
$active_menu_pattern = "#^/user#";

View File

@ -62,7 +62,7 @@ class BasicAuthSession {
header( sprintf( 'WWW-Authenticate: Basic realm="%s"', $c->system_name) );
header('HTTP/1.0 401 Unauthorized');
echo 'Please log in for access to this system.';
dbg_error_log( "Login", "User is not authorised" );
dbg_error_log( "BasicAuth", ":Session: User is not authorised" );
exit;
}
}
@ -74,9 +74,9 @@ class BasicAuthSession {
*/
function CheckPassword( $username, $password ) {
$qry = new PgQuery( "SELECT * FROM usr WHERE lower(username) = ? ", $username );
if ( $qry->Exec('BAS::CheckPassword',__LINE,__FILE__) && $qry->rows == 1 ) {
if ( $qry->Exec('BasicAuth',__LINE,__FILE__) && $qry->rows == 1 ) {
$usr = $qry->Fetch();
dbg_error_log( "Login", "Name:%s, Pass:%s, File:%s", $username, $password, $usr->password );
dbg_error_log( "BasicAuth", ":CheckPassword: Name:%s, Pass:%s, File:%s", $username, $password, $usr->password );
if ( session_validate_password( $password, $usr->password ) ) {
return $usr;
}
@ -103,7 +103,7 @@ class BasicAuthSession {
function GetRoles () {
$this->roles = array();
$qry = new PgQuery( 'SELECT role_name FROM role_member m join roles r ON r.role_no = m.role_no WHERE user_no = ? ', $this->user_no );
if ( $qry->Exec('BAS::GetRoles') && $qry->rows > 0 ) {
if ( $qry->Exec('BasicAuth') && $qry->rows > 0 ) {
while( $role = $qry->Fetch() ) {
$this->roles[$role->role_name] = true;
}

71
inc/RSCDSUser.php Normal file
View File

@ -0,0 +1,71 @@
<?php
/**
* User maintain / view with RSCDS specific associated tables
*
* @package rscds
* @subpackage RSCDSUser
* @author Andrew McMillan <andrew@catalyst.net.nz>
* @copyright Catalyst .Net Ltd
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
*/
require_once("User.php");
/**
* A class for viewing and maintaining RSCDS User records
*
* @package rscds
*/
class RSCDSUser extends User
{
/**
* Constructor - nothing fancy as yet.
*/
function RSCDSUser( $id , $prefix = "") {
parent::User( $id, $prefix );
}
/**
* Render the form / viewer as HTML to show the user
* @return string An HTML fragment to display in the page.
*/
function Render($title = "" ) {
$html = "";
dbg_error_log("User", ":Render: type=$this->WriteType, edit_mode=$this->EditMode" );
$ef = new EntryForm( $REQUEST_URI, $this->Values, $this->EditMode );
$ef->NoHelp(); // Prefer this style, for the moment
$html = '<div id="entryform">';
if ( $title != "" ) {
$html .= "<h1>$title</h1>\n";
}
if ( $ef->editmode ) {
$html .= $ef->StartForm( array("autocomplete" => "off" ) );
if ( $this->user_no > 0 ) $html .= $ef->HiddenField( "user_no", $this->user_no );
}
$html .= "<table width=\"100%\" class=\"data\" cellspacing=\"0\" cellpadding=\"0\">\n";
$html .= $this->RenderFields($ef,"");
$html .= $this->RenderRoles($ef);
$html .= "</table>\n";
$html .= "</div>";
if ( $ef->editmode ) {
$html .= '<div id="footer">';
$html .= $ef->SubmitButton( "submit", (("insert" == $this->WriteType) ? "Create" : "Update") );
$html .= '</div>';
$html .= $ef->EndForm();
}
return $html;
}
}
?>

109
inc/XMLElement.php Normal file
View File

@ -0,0 +1,109 @@
<?php
/**
* A class to assist with construction of XML documents
*
* @package awl
* @subpackage XMLElement
* @author Andrew McMillan <andrew@catalyst.net.nz>
* @copyright Catalyst .Net Ltd
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
*/
require_once("AWLUtilities.php");
/**
* A class for XML elements which may have attributes, or contain
* other XML sub-elements
*
* @package awl
*/
class XMLElement {
var $tagname;
var $attributes;
var $content;
/**
* Constructor - nothing fancy as yet.
*/
function XMLElement( $tagname, $content=false, $attributes=false ) {
$this->tagname=$tagname;
$this->content=$content;
$this->attributes = $attributes;
}
/**
* Set an element attribute to a value
*
* @param string The attribute name
* @param string The attribute value
*/
function SetAttribute($k,$v) {
if ( gettype($this->attributes) != "array" ) $this->attributes = array();
$this->attributes[$k] = $v;
}
/**
* Set the whole content to a value
*
* @param mixed The element content, which may be text, or an array of sub-elements
*/
function SetContent($v) {
$this->content = $v;
}
/**
* Add a sub-element
*
* @param object An XMLElement to be appended to the array of sub-elements
*/
function AddSubTag($v) {
if ( gettype($this->content) != "array" ) $this->content = array();
$this->content[] = $v;
}
/**
* Render the document tree into (nicely formatted) XML
*
* @param int The indenting level for the pretty formatting of the element
*/
function Render($indent=0) {
$r = substr(" ",0,$indent) . '<' . $this->tagname;
if ( gettype($this->attributes) == "array" ) {
/**
* Render the element attribute values
*/
foreach( $this->attributes AS $k => $v ) {
$r .= sprintf( ' %s="%s"', $k, $v );
}
}
if ( (is_array($this->content) && count($this->content) > 0) || strlen($this->content) > 0 ) {
$r .= ">";
if ( is_array($this->content) ) {
/**
* Render the sub-elements with a deeper indent level
*/
$r .= "\n";
foreach( $this->content AS $k => $v ) {
if ( is_object($v) ) {
$r .= $v->Render($indent+1);
}
}
$r .= substr(" ",0,$indent);
}
else {
/**
* Render the content, with special characters escaped
*
* FIXME This should switch to CDATA in some situations.
*/
$r .= htmlspecialchars($this->content);
}
$r .= '</' . $this->tagname.">\n";
}
else {
$r .= "/>\n";
}
return $r;
}
}
?>

View File

@ -16,6 +16,7 @@ $c->system_name = "Really Simple CalDAV Store";
$c->domain_name = $_SERVER['SERVER_NAME'];
$c->images = "/images";
$c->save_time_zone_defs = 1;
$c->stylesheets = array( "/rscds.css" );
// Kind of private configuration values
$c->total_query_time = 0;

32
inc/caldav-MKCALENDAR.php Normal file
View File

@ -0,0 +1,32 @@
<?php
dbg_error_log("MKCALENDAR", "method handler");
$attributes = array();
$parser = xml_parser_create_ns('UTF-8');
xml_parser_set_option ( $parser, XML_OPTION_SKIP_WHITE, 1 );
function xml_start_callback( $parser, $el_name, $el_attrs ) {
dbg_error_log( "PROPFIND", "Parsing $el_name" );
dbg_log_array( "PROPFIND", "$el_name::attrs", $el_attrs, true );
$attributes[$el_name] = $el_attrs;
}
function xml_end_callback( $parser, $el_name ) {
dbg_error_log( "PROPFIND", "Finished Parsing $el_name" );
}
xml_set_element_handler ( $parser, 'xml_start_callback', 'xml_end_callback' );
$rpt_request = array();
xml_parse_into_struct( $parser, $raw_post, $rpt_request );
xml_parser_free($parser);
$make_path = $_SERVER['PATH_INFO'];
/**
* FIXME We kind of lie, at this point
*/
header("HTTP/1.1 200 Created");
?>

View File

@ -2,7 +2,7 @@
dbg_error_log("OPTIONS", "method handler");
header( "Content-type: text/plain");
// header( "Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE, PROPFIND, PROPPATCH, LOCK, UNLOCK, REPORT, ACL");
header( "Allow: OPTIONS, GET, PUT, DELETE, REPORT");
header( "Allow: OPTIONS, GET, PUT, DELETE, REPORT, PROPFIND, COPY, MOVE");
// header( "DAV: 1, 2, 3, access-control, calendar-access");
header( "DAV: 1, calendar-access");
header( "DAV: 1, 2, calendar-access");
?>

142
inc/caldav-PROPFIND.php Normal file
View File

@ -0,0 +1,142 @@
<?php
dbg_error_log("PROPFIND", "method handler");
$attributes = array();
$parser = xml_parser_create_ns('UTF-8');
xml_parser_set_option ( $parser, XML_OPTION_SKIP_WHITE, 1 );
function xml_start_callback( $parser, $el_name, $el_attrs ) {
dbg_error_log( "PROPFIND", "Parsing $el_name" );
dbg_log_array( "PROPFIND", "$el_name::attrs", $el_attrs, true );
$attributes[$el_name] = $el_attrs;
}
function xml_end_callback( $parser, $el_name ) {
dbg_error_log( "PROPFIND", "Finished Parsing $el_name" );
}
xml_set_element_handler ( $parser, 'xml_start_callback', 'xml_end_callback' );
$rpt_request = array();
xml_parse_into_struct( $parser, $raw_post, $rpt_request );
xml_parser_free($parser);
$find_path = $_SERVER['PATH_INFO'];
$href_list = array();
$attribute_list = array();
if ( isset($debugging) ) {
$attribute_list = array( 'GETETAG' => 1, 'GETCONTENTLENGTH' => 1, 'GETCONTENTTYPE' => 1, 'RESOURCETYPE' => 1 );
}
foreach( $rpt_request AS $k => $v ) {
switch ( $v['tag'] ) {
case 'DAV::PROPFIND':
dbg_log_array( "PROPFIND", "DAV-PROPFIND", $v, true );
break;
case 'DAV::PROP':
dbg_log_array( "PROPFIND", "DAV::PROP", $v, true );
break;
case 'DAV::GETETAG':
case 'DAV::GETCONTENTLENGTH':
case 'DAV::GETCONTENTTYPE':
case 'DAV::RESOURCETYPE':
$attribute = substr($v['tag'],5);
$attribute_list[$attribute] = 1;
break;
case 'DAV::HREF':
dbg_log_array( "PROPFIND", "DAV::HREF", $v, true );
$href_list[] = $v['value'];
break;
default:
dbg_error_log( "PROPFIND", "Unhandled tag >>".$v['tag']."<<");
}
}
/**
* Here is the kind of thing we are going to do, returning a top-level collection
* response, followed by a response for each calendar (or other resource) within it.
* <?xml version='1.0' encoding='UTF-8'?>
* <multistatus xmlns='DAV:'>
* <response>
* <href>/caldav.php/path/they/sent/</href>
* <propstat>
* <prop>
* <getcontentlength/>
* <getcontenttype>httpd/unix-directory</getcontenttype>
* <resourcetype>
* <collection/>
* </resourcetype>
* </prop>
* <status>HTTP/1.1 200 OK</status>
* </propstat>
* </response>
* <response>
* <href>/caldav.php/path/they/sent/calendar</href>
* <propstat>
* <prop>
* <getcontentlength/>
* <getcontenttype>httpd/unix-directory</getcontenttype>
* <resourcetype>
* <collection/>
* <calendar xmlns='urn:ietf:params:xml:ns:caldav'/>
* </resourcetype>
* </prop>
* <status>HTTP/1.1 200 OK</status>
* </propstat>
* </response>
* </multistatus>
*/
require_once("XMLElement.php");
if ( count($href_list) > 0 ) {
// Not supported at this point...
dbg_error_log("ERROR", " PROPFIND: Support for PROPFIND on specific URLs is not implemented");
}
else {
$responses = array();
$url = sprintf("http://%s:%d%s%s", $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $find_path );
$url = $_SERVER['SCRIPT_NAME'] . $find_path ;
$url = preg_replace( '#/$#', '', $url);
for ( $i=0; $i < 2; $i++ ) {
$props = array();
if ( isset($attribute_list['GETCONTENTLENGTH']) ) {
$props[] = new XMLElement("getcontentlength" );
}
if ( isset($attribute_list['GETCONTENTTYPE']) ) {
$props[] = new XMLElement("getcontenttype", "httpd/unix-directory" );
}
if ( isset($attribute_list['RESOURCETYPE']) ) {
$resourcetypes = array( new XMLElement("collection") );
if ( $i == 1 ) $resourcetypes[] = new XMLElement("calendar", false, array("xmlns" => "urn:ietf:params:xml:ns:caldav"));
$props[] = new XMLElement("resourcetype", $resourcetypes );
}
$prop = new XMLElement("prop", $props );
$status = new XMLElement("status", "HTTP/1.1 200 OK" );
$propstat = new XMLElement( "propstat", array( $prop, $status) );
if ( $i == 1 ) $url .= "/calendar";
$href = new XMLElement("href", $url );
$responses[] = new XMLElement( "response", array($href,$propstat));
}
$multistatus = new XMLElement( "multistatus", $responses, array('xmlns'=>'DAV:') );
}
header("HTTP/1.1 207 Multi-Status");
header("Content-type: text/xml;charset=UTF-8");
echo'<?xml version="1.0" encoding="UTF-8" ?>'."\n";
echo $multistatus->Render();
?>

View File

@ -114,10 +114,12 @@ foreach( $rpt_request AS $k => $v ) {
break;
case 'DAV::GETETAG':
case 'DAV::GETCONTENTLENGTH':
case 'DAV::GETCONTENTTYPE':
case 'DAV::RESOURCETYPE':
if ( isset($report_properties) ) {
if ( $v['type'] == "complete" ) {
$report_properties['GETETAG'] = 1;
}
$attribute = substr($v['tag'],5);
$report_properties[$attribute] = 1;
}
break;
@ -157,8 +159,7 @@ header("Content-type: text/xml;charset=UTF-8");
$response_tpl = <<<RESPONSETPL
<D:response>%s
<D:propstat>
<D:prop>
<D:getetag>"%s"</D:getetag>%s
<D:prop>%s
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
@ -166,6 +167,11 @@ $response_tpl = <<<RESPONSETPL
RESPONSETPL;
$property_tpl = <<<PROPERTYTPL
<D:%s>"%s"</D:%s>
PROPERTYTPL;
$calendar_href_tpl = <<<CALDATATPL
<D:href>http://%s:%d%s%s</D:href>
@ -187,7 +193,11 @@ REPORTHDR;
for ( $i=0; $i <= $reportnum; $i++ ) {
dbg_error_log("REPORT", "Report[%d] Start:%s, End: %s, Events: %d, Todos: %d, Freebusy: %d",
$i, $report[$i]['start'], $report[$i]['end'], $report[$i]['calendar-event'], $report[$i]['calendar-todo'], $report[$i]['calendar-freebusy']);
if ( isset($report[$i]['calendar-event']) ) {
/**
* Produce VEVENT data.
*/
if ( isset($report[$i]['include_href']) ) dbg_error_log( "REPORT", "Returning href event data" );
if ( isset($report[$i]['include_data']) ) dbg_error_log( "REPORT", "Returning full event data" );
$sql = "SELECT * FROM caldav_data NATURAL JOIN event WHERE caldav_type = 'VEVENT' ";
@ -201,11 +211,21 @@ REPORTHDR;
}
$sql .= $where;
$qry = new PgQuery( $sql );
if ( $qry->Exec() && $qry->rows > 0 ) {
if ( $qry->Exec("REPORT",__LINE__,__FILE__) && $qry->rows > 0 ) {
while( $event = $qry->Fetch() ) {
$calhref = ( isset($report[$i]['include_href']) ? sprintf( $calendar_href_tpl, $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $event->dav_name ) : "" );
$caldata = ( isset($report[$i]['include_data']) ? sprintf( $calendar_data_tpl, $event->caldav_data ) : "" );
printf( $response_tpl, $calhref, $event->dav_etag, $caldata );
$properties = "";
foreach( $report[$i]['properties'] AS $k => $v ) {
switch( $k ) {
case 'GETETAG': $value = $event->dav_etag; break;
case 'GETCONTENTLENGTH': $value = strlen($event->caldav_data); break;
case 'GETCONTENTTYPE': $value = "text/calendar"; break;
case 'RESOURCETYPE': $value = "VEVENT"; break;
}
$value = sprintf( $property_tpl, strtolower($k), $value, strtolower($k));
}
printf( $response_tpl, $calhref, $value, $caldata );
dbg_error_log("REPORT", "ETag >>%s<< >>http://%s:%s%s%s<<", $event->dav_etag,
$_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $event->dav_name);
}
@ -229,7 +249,7 @@ REPORTHDR;
}
$sql .= $where;
$qry = new PgQuery( $sql );
if ( $qry->Exec() && $qry->rows > 0 ) {
if ( $qry->Exec("REPORT",__LINE__,__FILE__) && $qry->rows > 0 ) {
while( $event = $qry->Fetch() ) {
$calhref = ( isset($report[$i]['include_href']) ? sprintf( $calendar_href_tpl, $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $event->dav_name ) : "" );
$caldata = ( isset($report[$i]['include_data']) ? sprintf( $calendar_data_tpl, $event->caldav_data ) : "" );

View File

@ -10,5 +10,7 @@ $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("My Details","/user.php?user_no=$session->user_no","View my own user record", false, 700);
$active_menu_pattern = '#^/(index.*)?$#'
?>

View File

@ -4,21 +4,88 @@ if ( !isset($c->title) ) {
$c->title = "Really Simple CalDAV Store";
}
echo <<<EOHDR
function make_help_link($matches)
{
// as usual: $matches[0] is the complete match
// $matches[1] the match for the first subpattern
// enclosed in '##...##' and so on
// Use like: $s = preg_replace_callback("/##([^#]+)##", "make_help_link", $s);
// $help_topic = preg_replace( '/^##(.+)##$/', '$1', $matches[1]);
$help_topic = $matches[1];
$display_url = $help_topic;
if ( $GLOBALS['session']->AllowedTo("Admin") || $GLOBALS['session']->AllowedTo("Support") ) {
if ( strlen($display_url) > 30 ) {
$display_url = substr( $display_url, 0, 28 ) . "..." ;
}
}
else {
$display_url = "help";
}
return " <a class=\"help\" href=\"/help.php?h=$help_topic\" title=\"Show help on '$help_topic'\" target=\"_new\">[$display_url]</a> ";
}
function send_page_header() {
global $session, $c, $page_menu, $user_menu, $role_menu, $relationship_menu;
// echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
echo <<<EOHDR
<html>
<head>
<meta/>
<title>$c->title</title>
<link rel="stylesheet" type="text/css" href="/rscds.css" />
</head>
<body>
<title>$c->page_title</title>
EOHDR;
if ( isset($page_menu) && is_object($page_menu) ) {
$page_menu->AddSubMenu( $relationship_menu, "Relationships", "/relationships.php", "Browse all relationships", false, 4050 );
$page_menu->AddSubMenu( $user_menu, "Users", "/users.php", "Browse all users", false, 4100 );
$page_menu->AddSubMenu( $role_menu, "Roles", "/roles.php", "Browse all roles", false, 4300 );
$page_menu->MakeSomethingActive($active_menu_pattern);
echo $page_menu->Render();
foreach ( $c->stylesheets AS $stylesheet ) {
echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"$stylesheet\" />\n";
}
if ( isset($c->local_styles) ) {
// Always load local styles last, so they can override prior ones...
foreach ( $c->local_styles AS $stylesheet ) {
echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"$stylesheet\" />\n";
}
}
if ( isset($c->print_styles) ) {
// Finally, load print styles last, so they can override all of the above...
foreach ( $c->print_styles AS $stylesheet ) {
echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"$stylesheet\" media=\"print\"/>\n";
}
}
if ( isset($c->scripts) && is_array($c->scripts) ) {
foreach ( $c->scripts AS $script ) {
echo "<script language=\"JavaScript\" src=\"$script\"></script>\n";
}
}
echo "</head>\n<body>\n";
echo "<div id=\"pageheader\">\n";
if ( isset($page_menu) && is_object($page_menu) ) {
$page_menu->AddSubMenu( $relationship_menu, "Relationships", "/relationships.php", "Browse all relationships", false, 4050 );
$page_menu->AddSubMenu( $user_menu, "Users", "/users.php", "Browse all users", false, 4100 );
$page_menu->AddSubMenu( $role_menu, "Roles", "/roles.php", "Browse all roles", false, 4300 );
$page_menu->MakeSomethingActive($active_menu_pattern);
echo $page_menu->Render();
}
echo "</div>\n";
if ( isset($c->messages) && is_array($c->messages) && count($c->messages) > 0 ) {
echo "<div id=\"messages\"><ul class=\"messages\">\n";
foreach( $c->messages AS $i => $msg ) {
// ##HelpTextKey## gets converted to a "/help.phph=HelpTextKey" link
$msg = preg_replace_callback("/##([^#]+)##/", "make_help_link", $msg);
echo "<li class=\"messages\">$msg</li>\n";
}
echo "</ul>\n</div>\n";
}
}
send_page_header();
?>

View File

@ -2,7 +2,7 @@
/**
* A Class for handling vEvent data
*
* @package rscds
* @package awl
* @subpackage iCalendar
* @author Andrew McMillan <andrew@catalyst.net.nz>
* @copyright Catalyst IT Ltd
@ -13,7 +13,7 @@
/**
* A Class for handling Events on a calendar
*
* @package rscds
* @package awl
*/
class vEvent {
/**#@+

View File

@ -41,6 +41,13 @@
<item url="htdocs/help.php" uploadstatus="1" />
<item url="htdocs/roles.php" uploadstatus="1" />
<item url="htdocs/relationships.php" uploadstatus="1" />
<item url="dba/caldav_functions.sql" />
<item url="dba/caldav_functions.sql" uploadstatus="1" />
<item url="htdocs/user.php" uploadstatus="1" />
<item url="htdocs/role.php" uploadstatus="1" />
<item url="inc/Role.php" uploadstatus="1" />
<item url="inc/RSCDSUser.php" uploadstatus="1" />
<item url="inc/caldav-PROPFIND.php" />
<item url="inc/caldav-MKCALENDAR.php" />
<item url="inc/XMLElement.php" />
</project>
</webproject>