DAViCal
 All Classes Namespaces Functions Variables Pages
caldav-LOCK.php
1 <?php
6 require_once('XMLDocument.php');
7 $reply = new XMLDocument(array( 'DAV:' => '' ));
8 
9 if ( ! $request->AllowedTo('write') ) {
10  $request->NeedPrivilege( 'write', $request->path );
11 }
12 
13 if ( ! isset($request->xml_tags) ) {
14  if ( isset($request->lock_token) ) {
15  // It's OK for LOCK refresh requests to be empty.
16  $request->xml_tags = array();
17  }
18  else {
19  $request->XMLResponse( 400, new XMLElement( 'error', new XMLElement('missing-xml-for-request'), $reply->GetXmlNsArray() ) );
20  }
21 }
22 
23 
24 $unsupported = array();
25 $lockinfo = array();
26 $inside = array();
27 
28 foreach( $request->xml_tags AS $k => $v ) {
29 
30  $tag = $v['tag'];
31  dbg_error_log( "LOCK", " Handling Tag '%s' => '%s' ", $k, $v );
32  switch ( $tag ) {
33  case 'DAV::lockinfo':
34  dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
35  if ( $v['type'] == "open" ) {
36  $lockscope = "";
37  $locktype = "";
38  $lockowner = "";
39  $inside[$tag] = true;
40  }
41  else if ( $inside[$tag] && $v['type'] == "close" ) {
42  $lockinfo['scope'] = $lockscope; unset($lockscope);
43  $lockinfo['type'] = $locktype; unset($locktype);
44  $lockinfo['owner'] = $lockowner; unset($lockowner);
45  $inside[$tag] = false;
46  }
47  break;
48 
49  case 'DAV::owner':
50  case 'DAV::locktype':
51  case 'DAV::lockscope':
52  dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
53  if ( $inside['DAV::lockinfo'] ) {
54  if ( $v['type'] == "open" ) {
55  $inside[$tag] = true;
56  }
57  else if ( $inside[$tag] && $v['type'] == "close" ) {
58  $inside[$tag] = false;
59  }
60  }
61  break;
62 
63  /*case 'DAV::SHARED': */
64  case 'DAV::exclusive':
65  dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
66  if ( $inside['DAV::lockscope'] && $v['type'] == "complete" ) {
67  $lockscope = strtolower(substr($tag,5));
68  }
69  break;
70 
71  /* case 'DAV::READ': */
72  case 'DAV::write':
73  dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
74  if ( $inside['DAV::locktype'] && $v['type'] == "complete" ) {
75  $locktype = strtolower(substr($tag,5));
76  }
77  break;
78 
79  case 'DAV::href':
80  dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
81  dbg_log_array( "LOCK", "DAV:href", $v, true );
82  if ( $inside['DAV::owner'] && $v['type'] == "complete" ) {
83  $lockowner = $v['value'];
84  }
85  break;
86 
87  default:
88  if ( preg_match('/^(.*):([^:]+)$/', $tag, $matches) ) {
89  $unsupported[$matches[2]] = $matches[1];
90  }
91  else {
92  $unsupported[$tag] = "";
93  }
94  dbg_error_log( "LOCK", "Unhandled tag >>%s<<", $tag);
95  }
96 }
97 
98 
99 
100 
101 $request->UnsupportedRequest($unsupported); // Won't return if there was unsupported stuff.
102 
103 $lock_opener = $request->FailIfLocked();
104 
105 
106 if ( $request->method == "LOCK" ) {
107  dbg_error_log( "LOCK", "Attempting to lock resource '%s'", $request->path);
108  $lock_timeout = (empty($request->timeout) ? 30 : intval($request->timeout) );
109  if ( $lock_timeout < 1 ) $lock_timeout = 30;
110  else if ( $lock_timeout > 300 ) $lock_timeout = 300;
111  if ( ($lock_token = $request->IsLocked()) ) { // NOTE Assignment in if() is expected here.
112  $sql = 'UPDATE locks SET start = current_timestamp WHERE opaquelocktoken = :lock_token';
113  $params = array( ':lock_token' => $lock_token);
114  }
115  else {
119  $lock_token = uuid();
120  $sql = 'INSERT INTO locks ( dav_name, opaquelocktoken, type, scope, depth, owner, timeout, start )
121  VALUES( :dav_name, :lock_token, :type, :scope, :request_depth, :owner, :timeout::interval, current_timestamp )';
122  $params = array(
123  ':dav_name' => $request->path,
124  ':lock_token' => $lock_token,
125  ':type' => $lockinfo['type'],
126  ':scope' => $lockinfo['scope'],
127  ':request_depth' => $request->depth,
128  ':owner' => $lockinfo['owner'],
129  ':timeout' => $lock_timeout.' seconds'
130  );
131  header( "Lock-Token: <opaquelocktoken:$lock_token>" );
132  }
133  $qry = new AwlQuery($sql, $params );
134  $qry->Exec("LOCK",__LINE__,__FILE__);
135 
136  $lock_row = $request->GetLockRow($lock_token);
137  $activelock = array(
138  new XMLElement( 'locktype', new XMLElement( $lock_row->type )),
139  new XMLElement( 'lockscope', new XMLElement( $lock_row->scope )),
140  new XMLElement( 'depth', $request->GetDepthName() ),
141  new XMLElement( 'owner', new XMLElement( 'href', $lock_row->owner )),
142  new XMLElement( 'timeout', 'Second-'.$lock_timeout),
143  new XMLElement( 'locktoken', new XMLElement( 'href', 'opaquelocktoken:'.$lock_token ))
144  );
145  $response = new XMLElement("lockdiscovery", new XMLElement( "activelock", $activelock), array("xmlns" => "DAV:") );
146 }
147 elseif ( $request->method == "UNLOCK" ) {
152  dbg_error_log( "LOCK", "Attempting to unlock resource '%s'", $request->path);
153  if ( ($lock_token = $request->IsLocked()) ) { // NOTE Assignment in if() is expected here.
154  $sql = 'DELETE FROM locks WHERE opaquelocktoken = :lock_token';
155  $qry = new AwlQuery($sql, array( ':lock_token' => $lock_token) );
156  $qry->Exec("LOCK",__LINE__,__FILE__);
157  }
158  $request->DoResponse( 204 );
159 }
160 
161 
162 $prop = new XMLElement( "prop", $response, array('xmlns'=>'DAV:') );
163 // dbg_log_array( "LOCK", "XML", $response, true );
164 $xmldoc = $prop->Render(0,'<?xml version="1.0" encoding="utf-8" ?>');
165 $request->DoResponse( 200, $xmldoc, 'text/xml; charset="utf-8"' );
166