diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index 77561511..9a47956f 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -10,7 +10,7 @@ * @package rscds * @subpackage CalDAVRequest * @author Andrew McMillan -* @copyright Andrew McMillan +* @copyright Catalyst .Net Ltd * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 */ @@ -54,7 +54,9 @@ class CalDAVRequest * LOCK things use an "If" header to hold the lock in some cases, and "Lock-token" in others */ if ( isset($_SERVER['HTTP_IF']) ) $this->if_clause = $_SERVER['HTTP_IF']; - if ( isset($_SERVER['HTTP_LOCK-TOKEN']) ) $this->lock_token = $_SERVER['HTTP_LOCK-TOKEN']; + if ( isset($_SERVER['HTTP_LOCK_TOKEN']) && preg_match( '#[<]opaquelocktoken:(.*)[>]#', $_SERVER['HTTP_LOCK_TOKEN'], $matches ) ) { + $this->lock_token = $matches[1]; + } /** * LOCK things use a "Timeout" header to set a series of reducing alternative values @@ -245,13 +247,22 @@ class CalDAVRequest function ValidateLockToken( $lock_token ) { if ( isset($this->lock_token) && $this->lock_token == $lock_token ) return true; if ( isset($this->if_clause) ) { + dbg_error_log( "caldav", "Checking lock token '%s' against '%s'", $lock_token, $this->if_clause ); $tokens = preg_split( '/[<>]/', $this->if_clause ); foreach( $tokens AS $k => $v ) { + dbg_error_log( "caldav", "Checking lock token '%s' against '%s'", $lock_token, $v ); if ( 'opaquelocktoken:' == substr( $v, 0, 16 ) ) { - if ( substr( $v, 16 ) == $lock_token ) return true; + if ( substr( $v, 16 ) == $lock_token ) { + dbg_error_log( "caldav", "Lock token '%s' validated OK against '%s'", $lock_token, $v ); + return true; + } } } } + else { + @dbg_error_log( "caldav", "Invalid lock token '%s' - not in Lock-token (%s) or If headers (%s) ", $lock_token, $this->lock_token, $this->if_clause ); + } + return false; } @@ -364,6 +375,8 @@ class CalDAVRequest case 415: $status_text = "Unsupported Media Type"; break; case 416: $status_text = "Requested Range Not Satisfiable"; break; case 417: $status_text = "Expectation Failed"; break; + case 423: $status_text = "Locked"; break; + case 424: $status_text = "Failed Dependency"; break; case 500: $status_text = "Internal Server Error"; break; case 501: $status_text = "Not Implemented"; break; case 502: $status_text = "Bad Gateway"; break; diff --git a/inc/caldav-LOCK.php b/inc/caldav-LOCK.php index 2f67e4e4..ef871c90 100644 --- a/inc/caldav-LOCK.php +++ b/inc/caldav-LOCK.php @@ -93,28 +93,42 @@ function lock_resource( $user_no, $path ) { dbg_error_log( "LOCK", "Attempting to lock resource '%s'", $path); if ( ($lock_token = $request->IsLocked()) ) { // NOTE Assignment in if() is expected here. + dbg_error_log( "LOCK", "Attempting to renew resource lock on '%s'", $path); if ( $request->ValidateLockToken($lock_token) ) { $sql = "UPDATE locks SET start = current_timestamp WHERE opaquelocktoken = ?;"; $qry = new PgQuery($sql, $lock_token ); $qry->Exec("LOCK",__LINE__,__FILE__); } else { - /** FIXME: Deny the lock */ + /** + * Already locked - deny it + */ + $response = array( + new XMLElement( 'href', $request->path ), + new XMLElement( 'status', 'HTTP/1.1 423 Resource Locked') + ); + $response = new XMLElement( "multistatus", new XMLElement( 'response', $response), array('xmlns'=>'DAV:') ); + $xmldoc = $response->Render(0,''); + $request->DoResponse( 423, $xmldoc, 'text/xml; charset="utf-8"' ); } } else { + /** + * A fresh lock + */ $lock_token = uuid(); $sql = "INSERT INTO locks ( dav_name, opaquelocktoken, type, scope, depth, owner, timeout, start ) VALUES( ?, ?, ?, ?, ?, ?, ?::interval, current_timestamp );"; $qry = new PgQuery($sql, $request->path, $lock_token, $lockinfo['type'], $lockinfo['scope'], $request->depth, $lockinfo['owner'], $request->timeout.' seconds' ); $qry->Exec("LOCK",__LINE__,__FILE__); + header( "Lock-Token: " ); } $lock_row = $request->GetLockRow($lock_token); $activelock = array( - new XMLElement( 'locktype', new XMLElement( $lockinfo['type'] )), - new XMLElement( 'lockscope', new XMLElement( $lockinfo['scope'] )), + new XMLElement( 'locktype', new XMLElement( $lock_row->type )), + new XMLElement( 'lockscope', new XMLElement( $lock_row->scope )), new XMLElement( 'depth', $request->GetDepthName() ), - new XMLElement( 'owner', new XMLElement( 'href', $lockinfo['owner'] )), + new XMLElement( 'owner', new XMLElement( 'href', $lock_row->owner )), new XMLElement( 'timeout', 'Second-'.$request->timeout), new XMLElement( 'locktoken', new XMLElement( 'href', 'opaquelocktoken:'.$lock_token )) ); @@ -153,7 +167,7 @@ else { } $prop = new XMLElement( "prop", $response, array('xmlns'=>'DAV:') ); -dbg_log_array( "LOCK", "XML", $response, true ); +// dbg_log_array( "LOCK", "XML", $response, true ); $xmldoc = $prop->Render(0,''); $request->DoResponse( 200, $xmldoc, 'text/xml; charset="utf-8"' );