diff --git a/inc/CalDAVPrincipal.php b/inc/CalDAVPrincipal.php index a3b77aad..8657c68b 100644 --- a/inc/CalDAVPrincipal.php +++ b/inc/CalDAVPrincipal.php @@ -334,7 +334,7 @@ class CalDAVPrincipal break; case 'DAV::getcontentlanguage': - $locale = $c->current_locale; + $locale = (isset($c->current_locale) ? $c->current_locale : ""); if ( isset($this->locale) && $this->locale != "" ) $locale = $this->locale; $prop->NewElement("getcontentlanguage", $locale ); break; @@ -380,7 +380,7 @@ class CalDAVPrincipal break; default: - dbg_error_log( 'CalDAVPrincipal', "Request for unsupported property '%s' of principal.", $item->username ); + dbg_error_log( 'CalDAVPrincipal', "Request for unsupported property '%s' of principal.", $this->username ); $not_found[] = $reply->Tag($tag); break; } diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index f86b2576..bfa1fa9a 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -169,7 +169,7 @@ class CalDAVRequest * 4. otherwise we query the defined relationships between users and use * the minimum privileges returned from that analysis. */ - $this->path = $_SERVER['PATH_INFO']; + $this->path = (isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : ""); if ( $this->path == null || $this->path == '' ) $this->path = '/'; // dbg_error_log( "caldav", "Sanitising path '%s'", $this->path ); $bad_chars_regex = '/[\\^\\[\\(\\\\]/'; @@ -212,7 +212,7 @@ class CalDAVRequest } $this->collection_id = $row->collection_id; - $this->collection_path = $row->path; + $this->collection_path = $row->dav_name; $this->collection = $row; } else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->path, $matches ) ) { @@ -275,7 +275,7 @@ EOSQL; * If the content we are receiving is XML then we parse it here. RFC2518 says we * should reasonably expect to see either text/xml or application/xml */ - if ( preg_match( '#(application|text)/xml#', $_SERVER['CONTENT_TYPE'] ) ) { + if ( isset($_SERVER['CONTENT_TYPE']) && preg_match( '#(application|text)/xml#', $_SERVER['CONTENT_TYPE'] ) ) { $xml_parser = xml_parser_create_ns('UTF-8'); $this->xml_tags = array(); xml_parser_set_option ( $xml_parser, XML_OPTION_SKIP_WHITE, 1 ); diff --git a/inc/RSCDSSession.php b/inc/RSCDSSession.php index 5bc3beb1..a3c33883 100644 --- a/inc/RSCDSSession.php +++ b/inc/RSCDSSession.php @@ -4,8 +4,8 @@ * * @package davical * @subpackage RSCDSSession -* @author Andrew McMillan -* @copyright Catalyst .Net Ltd +* @author Andrew McMillan +* @copyright Catalyst .Net Ltd, Morphoss Ltd * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 */ @@ -41,7 +41,7 @@ EOSQL; */ require_once('Session.php'); -Session::_CheckLogout(); +@Session::_CheckLogout(); /** * A class for creating and holding session information. diff --git a/inc/always.php b/inc/always.php index 6e142765..004f9c2b 100644 --- a/inc/always.php +++ b/inc/always.php @@ -1,13 +1,13 @@ -* @copyright Catalyst .Net Ltd +* @author Andrew McMillan +* @copyright Catalyst .Net Ltd, Morphoss Ltd * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 */ // Ensure the configuration starts out as an empty object. -unset($c); +$c = (object) array(); // Ditto for a few other global things unset($session); unset($request); unset($dbconn); @@ -77,6 +77,11 @@ else { include_once("davical_configuration_missing.php"); exit; } +if ( isset($c->deny_put_collection) ) { + @dbg_error_log( "WARN", "Deprecated 'deny_put_collection' configuration item renamed to 'readonly_webdav_collections'" ); + $c->readonly_webdav_collections = $c->deny_put_collection; +} + if ( !isset($c->page_title) ) $c->page_title = $c->system_name; if ( count($c->dbg) > 0 ) { @@ -96,7 +101,7 @@ awl_set_locale($c->default_locale); * */ $c->code_version = 0; -$c->version_string = '0.9.5.4'; // The actual version # is replaced into that during the build /release process +$c->version_string = '0.9.5.90'; // 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[2]; @@ -134,7 +139,7 @@ function getUserByName( $username, $use_cache = true ) { // Provide some basic caching in case this ends up being overused. if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username]; - $qry = new PgQuery( "SELECT * FROM usr WHERE lower(username) = lower(?) ", $username ); + $qry = new PgQuery( "SELECT *, to_char(updated at time zone 'GMT','Dy, DD Mon IYYY HH24:MI:SS \"GMT\"') AS modified FROM usr WHERE lower(username) = lower(?) ", $username ); if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) { $_known_users_name[$username] = $qry->Fetch(); $id = $_known_users_name[$username]->user_no; @@ -155,7 +160,7 @@ 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) ); + $qry = new PgQuery( "SELECT *, to_char(updated at time zone 'GMT','Dy, DD Mon IYYY HH24:MI:SS \"GMT\"') AS modified 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; diff --git a/inc/always.php.in b/inc/always.php.in index 9af1ddcd..9e77ad5d 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -1,13 +1,13 @@ -* @copyright Catalyst .Net Ltd +* @author Andrew McMillan +* @copyright Catalyst .Net Ltd, Morphoss Ltd * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 */ // Ensure the configuration starts out as an empty object. -unset($c); +$c = (object) array(); // Ditto for a few other global things unset($session); unset($request); unset($dbconn); diff --git a/inc/caldav-GET.php b/inc/caldav-GET.php index de79bd49..cd6511d3 100644 --- a/inc/caldav-GET.php +++ b/inc/caldav-GET.php @@ -75,7 +75,7 @@ else if ( $qry->rows > 1 ) { } $response .= $confidential->Render( false, $event->caldav_type ); } - elseif ( $c->hide_alarm ) { + elseif ( isset($c->hide_alarm) && $c->hide_alarm ) { // Otherwise we hide the alarms (if configured to) $ical->component->ClearComponents('VALARM'); $response .= $ical->render(true, $event->caldav_type ); diff --git a/inc/caldav-MKCALENDAR.php b/inc/caldav-MKCALENDAR.php index 13dd797d..e33968ef 100644 --- a/inc/caldav-MKCALENDAR.php +++ b/inc/caldav-MKCALENDAR.php @@ -5,7 +5,7 @@ * @package davical * @subpackage caldav * @author Andrew McMillan -* @copyright Morphoss Ltd - http://www.morphoss.com/ +* @copyright Catalyst IT Ltd, Morphoss Ltd - http://www.morphoss.com/ * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 */ dbg_error_log("MKCALENDAR", "method handler"); @@ -28,6 +28,8 @@ if ( preg_match( '#^(.*/)([^/]+)(/)?$#', $request->path, $matches ) ) { $displayname = $matches[2]; } +$failure = array(); +$propertysql = ""; if ( isset($request->xml_tags) ) { /** * The MKCALENDAR request may contain XML to set some DAV properties diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 822be102..e505a9c3 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -266,8 +266,7 @@ function add_general_properties( &$prop, &$not_found, &$denied, $record ) { } if ( $allprop || isset($prop_list['DAV::getcontentlanguage']) ) { - $contentlength = strlen($item->caldav_data); - $prop->NewElement("getcontentlanguage", $c->current_locale ); + $prop->NewElement("getcontentlanguage", (isset($c->current_locale) ? $c->current_locale : "") ); } if ( isset($prop_list['DAV::supportedlock']) ) { @@ -565,7 +564,7 @@ function get_collection_contents( $depth, $user_no, $collection ) { * subsidiary collections will also be got up to $depth */ function get_collection( $depth, $user_no, $collection_path ) { - global $c; + global $c, $request; $responses = array(); dbg_error_log("PROPFIND","Getting collection: Depth %d, User: %d, Path: %s", $depth, $user_no, $collection_path ); @@ -575,6 +574,7 @@ function get_collection( $depth, $user_no, $collection_path ) { $collection->dav_etag = md5($c->system_name . $collection_path); $collection->is_calendar = 'f'; $collection->is_principal = 'f'; + $collection->user_no = 0; $collection->dav_displayname = $c->system_name; $collection->created = date('Ymd\THis'); $responses[] = collection_to_xml( $collection ); @@ -598,10 +598,12 @@ function get_collection( $depth, $user_no, $collection_path ) { $responses[] = collection_to_xml( $collection ); } elseif ( $c->collections_always_exist ) { + dbg_error_log("PROPFIND","Using $c->collections_always_exist setting is deprecated" ); $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->user_no = $user_no; $collection->dav_displayname = $collection_path; $collection->created = date('Ymd"T"His'); $responses[] = collection_to_xml( $collection ); diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php index 8700cd44..b3d1daa1 100644 --- a/inc/caldav-PUT-functions.php +++ b/inc/caldav-PUT-functions.php @@ -1,7 +1,16 @@ +* @copyright Morphoss Ltd - http://www.morphoss.com/ +* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later version +*/ /** -* Check if the user wants to put just one EVENT/TODO or a whole calendar +* Check if the user wants to put just one VEVENT/VTODO or a whole calendar * if the collection = calendar = $request_container doesn't exist then create it * return true if it's a whole calendar */ @@ -112,6 +121,26 @@ function public_events_only( $user_no, $dav_name ) { } +/** +* Create scheduling requests in the schedule inbox for the +* @param iCalendar $ic The iCalendar object we should create scheduling requests for. +*/ +function create_scheduling_requests( $ic ) { + $component =& $ic->component->FirstNonTimezone(); + $attendees = $component->GetProperties('ATTENDEE'); + if ( preg_match( '# iCal/\d#', $_SERVER['HTTP_USER_AGENT']) ) { + dbg_error_log( "POST", "Non-compliant iCal request. Using X-WR-ATTENDEE property" ); + $wr_attendees = $component->GetProperties('X-WR-ATTENDEE'); + foreach( $wr_attendees AS $k => $v ) { + $attendees[] = $v; + } + } + dbg_error_log( "PUT", "Adding to scheduling inbox %d attendees", count($attendees) ); + foreach( $attendees AS $attendee ) { + dbg_error_log( "PUT", "Not yet adding to schedule-inbox for %s", $attendee->Value() ); + } +} + /** * This function will import a whole calendar * @param string $ics_content the ics file to import @@ -122,7 +151,7 @@ function public_events_only( $user_no, $dav_name ) { * Any VEVENTs with the same UID will be concatenated together */ function import_collection( $ics_content, $user_no, $path, $caldav_context ) { - global $c; + global $c, $session; // According to RFC2445 we should always end with CRLF, but the CalDAV spec says // that normalising XML parsers often muck with it and may remove the CR. $icalendar = preg_replace('/\r?\n /', '', $ics_content ); @@ -206,7 +235,7 @@ function import_collection( $ics_content, $user_no, $path, $caldav_context ) { foreach( $events AS $k => $event ) { dbg_error_log( "PUT", "Putting event %d with data: %s", $k, $event['data'] ); - $icalendar = iCalendar::iCalHeader() . $event['data'] . $timezones[$event['tzid']] . iCalendar::iCalFooter(); + $icalendar = iCalendar::iCalHeader() . $event['data'] . (isset($timezones[$event['tzid']])?$timezones[$event['tzid']]:"") . iCalendar::iCalFooter(); $ic = new iCalendar( array( 'icalendar' => $icalendar ) ); $etag = md5($icalendar); $event_path = sprintf( "%s%d.ics", $path, $k); @@ -273,6 +302,8 @@ EOSQL; $ic->Get('due'), $ic->Get('percent-complete'), $collection->collection_id ); if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $user_no, $path); + + create_scheduling_requests( $ic ); } $qry = new PgQuery("COMMIT;"); @@ -363,6 +394,10 @@ function putCalendarResource( &$request, $author, $caldav_context ) { if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $request->user_no, $request->path); } + /** + * Build the SQL for inserting/updating the calendar_item record + */ + $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 ) ) { // We only set the timezone if it looks reasonable enough for us $sql = ( $ic->tz_locn == '' ? '' : "SET TIMEZONE TO ".qpg($ic->tz_locn).";" ); @@ -395,7 +430,7 @@ function putCalendarResource( &$request, $author, $caldav_context ) { $class = $ic->Get("class"); /* Check and see if we should over ride the class. */ - if ( public_events_only($user_no, $path) ) { + if ( public_events_only($request->user_no, $request->path) ) { $class = 'PUBLIC'; } diff --git a/inc/caldav-PUT.php b/inc/caldav-PUT.php index 87306027..12e813a4 100644 --- a/inc/caldav-PUT.php +++ b/inc/caldav-PUT.php @@ -14,7 +14,7 @@ if ( ! $request->AllowedTo("read") ) { $request->DoResponse(403); } -if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || $c->dbg['put']) ) { +if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || (isset($c->dbg['put']) && $c->dbg['put'])) ) { $fh = fopen('/tmp/PUT.txt','w'); if ( $fh ) { fwrite($fh,$request->raw_post); diff --git a/inc/caldav-REPORT-multiget.php b/inc/caldav-REPORT-multiget.php index 5877442a..b4429af4 100644 --- a/inc/caldav-REPORT-multiget.php +++ b/inc/caldav-REPORT-multiget.php @@ -57,8 +57,8 @@ if ( isset($c->hide_TODO) && $c->hide_TODO && ! $request->AllowedTo('all') ) { $where .= "AND caldav_data.caldav_type NOT IN ('VTODO') "; } +if ( isset($c->strict_result_ordering) && $c->strict_result_ordering ) $where .= " ORDER BY dav_id"; $qry = new PgQuery( "SELECT * FROM caldav_data INNER JOIN calendar_item USING(dav_id, user_no, dav_name)". $where ); -if ( isset($c->strict_result_ordering) && $c->strict_result_ordering ) $sql .= " ORDER BY dav_id"; if ( $qry->Exec("REPORT",__LINE__,__FILE__) && $qry->rows > 0 ) { while( $calendar_object = $qry->Fetch() ) { $responses[] = calendar_to_xml( $properties, $calendar_object ); diff --git a/inc/caldav-REPORT.php b/inc/caldav-REPORT.php index 5c091164..e5f81676 100644 --- a/inc/caldav-REPORT.php +++ b/inc/caldav-REPORT.php @@ -12,7 +12,7 @@ dbg_error_log("REPORT", "method handler"); require_once("XMLDocument.php"); -if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || $c->dbg['report']) ) { +if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || (isset($c->dbg['report']) && $c->dbg['report'])) ) { $fh = fopen('/tmp/REPORT.txt','w'); if ( $fh ) { fwrite($fh,$request->raw_post); @@ -96,9 +96,9 @@ function calendar_to_xml( $properties, $item ) { else { $confidential->Set('DTEND', $ical->Get('DTEND') ); } - $caldav_data = $confidential->Render( true, $caldav_type ); + $caldav_data = $confidential->Render( true, $item->caldav_type ); } - elseif ( $c->hide_alarm ) { + elseif ( isset($c->hide_alarm) && $c->hide_alarm ) { // Otherwise we hide the alarms (if configured to) $ical = new iCalendar( array( "icalendar" => $caldav_data) ); $ical->component->ClearComponents('VALARM'); diff --git a/inc/interactive-page.php b/inc/interactive-page.php index 8d0ee70d..28c7f3ad 100644 --- a/inc/interactive-page.php +++ b/inc/interactive-page.php @@ -1,4 +1,5 @@ AddOption(translate("Home"),"$c->base_url/index.php",translate("Browse all users"), false, 3900 ); @@ -17,4 +18,4 @@ $user_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); $active_menu_pattern = "#^$c->base_url/(index.*)?$#"; -?> \ No newline at end of file +error_reporting($save);