/[drupal]/contributions/modules/dav/dav.inc
ViewVC logotype

Contents of /contributions/modules/dav/dav.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.9 - (show annotations) (download) (as text)
Mon Nov 17 16:22:31 2008 UTC (12 months, 1 week ago) by arto
Branch: MAIN
CVS Tags: DRUPAL-6--1-0-ALPHA4, HEAD
Changes since 1.8: +9 -3 lines
File MIME type: text/x-php
Merged latest changes from http://github.com/incanus/drupal-dav (3859c2a) by Justin Miller.

Changelog (DAV API):
- Fix issue with DAV root module patch (improper variable cast).
- Added custom setting for character encoding:
  * default PEAR library encodes <space>, &, <, >
  * we now give an admin option and add | as well.
- Added MIME type icons to web listing (i.e., HTTP GET) of DAV resources.
- Fix fatal bug by replacing db_next_id(), which doesn't exist on Drupal 6.x, with db_last_insert_id().
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * DAV server implementation and API for Drupal.
7 */
8
9 //////////////////////////////////////////////////////////////////////////////
10 // DAV constants
11
12 define('STATUS_102', '102 Processing');
13 define('STATUS_200', '200 OK');
14 define('STATUS_201', '201 Created');
15 define('STATUS_204', '204 No Content');
16 define('STATUS_207', '207 Multi-Status');
17 define('STATUS_403', '403 Forbidden');
18 define('STATUS_404', '404 Not Found');
19 define('STATUS_405', '405 Method Not Allowed');
20 define('STATUS_409', '409 Conflict');
21 define('STATUS_412', '412 Precondition Failed');
22 define('STATUS_415', '415 Unsupported Media Type');
23 define('STATUS_422', '422 Unprocessable Entity');
24 define('STATUS_423', '423 Locked');
25 define('STATUS_424', '424 Failed Dependency');
26 define('STATUS_507', '507 Insufficient Storage');
27
28 define('DAV_UPLOAD_KEY', 'dav_upload');
29
30 //////////////////////////////////////////////////////////////////////////////
31 // DAV implementation
32
33 /**
34 * DAV server implementation based on HTTP_WebDAV_Server from PEAR.
35 *
36 * @package dav.module
37 * @author Arto Bendiken <http://bendiken.net/>
38 */
39 class drupal_dav_server extends HTTP_WebDAV_Server {
40 var $http_auth_realm = 'Drupal DAV';
41 var $dav_powered_by = 'Drupal (+http://drupal.org/project/dav)';
42
43 /**
44 * Called from dav.module to serve an incoming DAV request.
45 */
46 static function serve($script_name, $path) {
47 $server = new drupal_dav_server();
48 $server->http_auth_realm = variable_get('site_name', $server->http_auth_realm);
49 $server->_SERVER['SCRIPT_NAME'] = $script_name;
50 $server->_SERVER['PATH_INFO'] = $path;
51
52 return $server->serverequest();
53 }
54
55 /**
56 * Callback providing a last opportunity to override the HTTP response
57 * status.
58 *
59 * We only use it to be able to correctly handle PUT requests, which may
60 * need arbitrary forms of post-processing that DAV module may provide.
61 *
62 * @param $status
63 * Status code and message.
64 * @return void
65 */
66 function http_status($status) {
67 switch ($this->_SERVER['REQUEST_METHOD']) {
68 // Provide post-processing for PUT requests (i.e., file uploads)
69 case 'PUT':
70 $status = $this->PUT_done($status);
71 break;
72 }
73
74 // This will send the HTTP status and set the X-WebDAV-Status header
75 parent::http_status($status);
76 }
77
78 /**
79 * Checks a DAV user's authentication credentials using Drupal's
80 * extensible authentication mechanism.
81 *
82 * For DAV clients which support cookie-based sessions, HTTP
83 * authentication will only be needed in the form of an initial handshake.
84 * Most clients, however, do not support cookies and will send the
85 * credentials with every subsequent DAV request, too.
86 *
87 * @param $type
88 * Authentication type, such as 'basic' or 'digest'. Not used.
89 * @param $username
90 * Transmitted user name.
91 * @param $password
92 * Transmitted password, as plaintext.
93 * @return
94 * A boolean indicating successful or failed authentication status.
95 */
96 function check_auth($type = NULL, $username = NULL, $password = NULL) {
97 global $user;
98 if (empty($user)) {
99 _dav_trace('AUTH', array('type' => $type, 'username' => $username, 'password' => $password ? t('(hidden)') : NULL));
100 }
101
102 // Check if a user name was supplied in the request
103 if (!is_null($username)) {
104 if (!($user = _dav_authenticate($username, trim($password)))) {
105 return FALSE; // Invalid user name or password
106 }
107 }
108
109 // Check authorization for anonymous or registered user
110 $access = user_access('access DAV resources');
111 if (!is_null($username) && !$access) {
112 // We will only log failed authentication requests, since for
113 // successful authentication we have no means to distinguish the
114 // initial handshake from every subsequent request which may include
115 // HTTP authentication credentials.
116 watchdog('dav', 'Login attempt failed for %user.', array('%user' => theme('placeholder', $username)));
117 }
118 return $access;
119 }
120
121 /**
122 * Checks the LOCK status for a DAV resource, returning any current shared
123 * or exclusive locks obtained on the resource.
124 *
125 * @param $path
126 * Resource path to check LOCK status for.
127 * @return
128 * An array of lock entries, each entry being an array with the keys
129 * 'type' ('shared'/'exclusive'), 'token' and 'timeout'.
130 */
131 function checklock($path) {
132 $path = _dav_explode_path($path);
133 if (($resource = _dav_resolve($path)) && ($resource_id = dav_intern_resource($resource))) {
134 $result = db_query('SELECT l.* FROM {dav_locks} l WHERE l.resource_id = %d', $resource_id);
135 if (($lock = db_fetch_object($result))) {
136 return array(
137 'type' => !empty($lock->is_writelock) ? 'write' : 'read',
138 'scope' => !empty($lock->is_exclusive) ? 'exclusive' : 'shared',
139 'depth' => $lock->depth,
140 'owner' => $lock->user_id, // TODO: this is technically incorrect
141 'token' => $lock->token,
142 'created' => $lock->created_at,
143 'modified' => $lock->updated_at,
144 'expires' => $lock->expires_at,
145 );
146 }
147 }
148 }
149
150 /**
151 * Implementation of the HTTP GET method.
152 *
153 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_GET
154 */
155 function GET(&$options) {
156 _dav_trace('get', $options);
157
158 $path = _dav_explode_path($options['path']);
159
160 if ($resource = _dav_resolve($path)) {
161 $props = dav_propfind($resource);
162
163 // If a GET handler is provided, assume a file resource
164 if (($options = _dav_dispatch('get', $resource, $options)) !== NULL) {
165 return $options !== FALSE;
166 }
167
168 // Otherwise, the resource should be a collection
169 if ($props['resourcetype'] == 'collection') {
170 print theme('dav_page', $path, dav_list($resource, $path));
171 return FALSE;
172 }
173 }
174
175 return FALSE;
176 }
177
178 /**
179 * Implementation of the HTTP PUT method.
180 *
181 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_PUT
182 */
183 function PUT(&$options) {
184 _dav_trace('put', $options);
185
186 $path = _dav_explode_path($options['path']);
187 $name = array_pop($path);
188
189 if (!($parent = _dav_resolve($path)))
190 return STATUS_404; // Not Found
191
192 // Prevent hidden file creation if disabled by administrator
193 if (!DAV_DOT_FILES && $name[0] == '.')
194 return STATUS_403; // Forbidden
195
196 // Prevent metadata proliferation with Windows / Mac OS X clients
197 if ((DAV_WINDOWS_NO_THUMBS_DB && strtolower($name) == 'thumbs.db') ||
198 (DAV_MACOSX_NO_DS_STORE && $name == '.DS_Store'))
199 return STATUS_403; // Forbidden
200
201 // Prevent resource fork creation with Mac OS X clients
202 if (DAV_MACOSX_NO_FORKS && strpos($name, '._') === 0)
203 return STATUS_201; // Created (faked)
204
205 // Attempt to lookup an existing resource
206 if ($resource = dav_lookup($parent, $name)) {
207 // This resource will be overwritten
208 $options['new'] = FALSE;
209 if (!user_access('update DAV resources'))
210 return STATUS_403; // Forbidden
211 }
212 else {
213 // This is a new resource
214 $options['new'] = TRUE;
215 if (!user_access('create DAV resources'))
216 return STATUS_403; // Forbidden
217 }
218
219 if ($result = _dav_dispatch('put', $parent, $name, $options, NULL)) {
220 if ($result !== TRUE)
221 return $result; // Failed with status code
222 $filename = _dav_tmpname();
223 $this->_put_args = array($parent, $name, $options, $filename);
224 return fopen($filename, 'wb'); // Success
225 }
226
227 return STATUS_409; // Conflict
228 }
229
230 function PUT_done($status) {
231 if (empty($this->_put_args))
232 return $status;
233
234 $args = array_merge(array('put'), $this->_put_args);
235 if ($result = call_user_func_array('_dav_dispatch', $args)) {
236 $filename = array_pop($args);
237 if (file_exists($filename))
238 @unlink($filename); // clean up if needed
239 return is_string($result) ? $result : $status;
240 }
241
242 return STATUS_409; // Conflict
243 }
244
245 /**
246 * Implementation of the DAV COPY method.
247 *
248 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_COPY
249 */
250 function COPY($options) {
251 _dav_trace('copy', $options);
252
253 $source_path = _dav_explode_path($options['path']);
254 $target_path = _dav_explode_path($options['dest']);
255 $depth = !empty($options['depth']) ? $options['depth'] : 0;
256
257 // Ensure the source collection or resource actually exists
258 if (!($source = _dav_resolve($source_path)))
259 return STATUS_404; // Not Found
260
261 // Perform sanity checks and overwrite target if needed
262 if ($error = $this->_prepare_copy_or_move($options, $target_path))
263 return $error;
264
265 if (!user_access('create DAV resources'))
266 return STATUS_403; // Forbidden
267
268 if (!_dav_dispatch('copy', $source, $source_path, $target_path))
269 return STATUS_409; // Conflict
270
271 return STATUS_201; // Created
272 }
273
274 /**
275 * Implementation of the DAV MOVE method.
276 *
277 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_MOVE
278 */
279 function MOVE($options) {
280 _dav_trace('move', $options);
281
282 $source_path = _dav_explode_path($options['path']);
283 $target_path = _dav_explode_path($options['dest']);
284 $depth = !empty($options['depth']) ? $options['depth'] : 0;
285
286 // Ensure the source collection or resource actually exists
287 if (!($source = _dav_resolve($source_path)))
288 return STATUS_404; // Not Found
289
290 // Perform sanity checks and overwrite target if needed
291 if ($error = $this->_prepare_copy_or_move($options, $target_path))
292 return $error;
293
294 // From here on out, we can assume the target doesn't exist
295 $source_name = array_pop($source_path);
296 $target_name = array_pop($target_path);
297
298 // If the source and target collections are the same, then this becomes a simple rename operation
299 if ($source_path == $target_path) {
300 if (!user_access('rename DAV resources'))
301 return STATUS_403; // Forbidden
302
303 if (($result = _dav_dispatch('rename', $source, $source_name, $target_name)) !== TRUE)
304 return is_string($result) ? $result : STATUS_409; // Conflict
305 }
306 else {
307 if (!user_access('move DAV resources'))
308 return STATUS_403; // Forbidden
309
310 array_push($source_path, $source_name);
311 array_push($target_path, $target_name);
312 if (($result = _dav_dispatch('move', $source, $source_path, $target_path)) !== TRUE)
313 return is_string($result) ? $result : STATUS_409; // Conflict
314 }
315
316 return STATUS_201; // Created
317 }
318
319 function _prepare_copy_or_move($options, $target_path) {
320 $overwrite = !empty($options['overwrite']);
321
322 // No body parsing implemented yet
323 if (!empty($this->_SERVER['CONTENT_LENGTH']))
324 return STATUS_415; // Unsupported Media Type
325
326 // No copying to different DAV servers supported
327 if (isset($options['dest_url']))
328 return STATUS_502; // Bad Gateway
329
330 // Check if the target already exists, and ensure it can be overwritten
331 if (($target = _dav_resolve($target_path)) && !$overwrite)
332 return STATUS_412; // Precondition Failed
333
334 // Obliterate the target, if necessary and access rights to do so
335 if ($target) {
336 if (!user_access('delete DAV resources'))
337 return STATUS_403; // Forbidden
338 if (!_dav_dispatch('delete', $target))
339 return STATUS_409;
340 }
341 }
342
343 /**
344 * Implementation of the HTTP DELETE method.
345 *
346 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_DELETE
347 */
348 function DELETE($options) {
349 _dav_trace('delete', $options);
350
351 if (!user_access('delete DAV resources'))
352 return STATUS_403; // Forbidden
353
354 $path = _dav_explode_path($options['path']);
355 $name = array_pop($path);
356
357 if ($parent = _dav_resolve($path)) {
358 if ($resource = dav_lookup($parent, $name)) {
359
360 if (!_dav_dispatch('delete', $resource, $parent))
361 return STATUS_409; // Conflict
362
363 return STATUS_204; // No Content
364 }
365 }
366
367 return STATUS_404; // Not Found
368 }
369
370 /**
371 * Implementation of the DAV MKCOL method.
372 *
373 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_MKCOL
374 */
375 function MKCOL($options) {
376 _dav_trace('mkcol', $options);
377
378 if (!user_access('create DAV resources'))
379 return STATUS_403; // Forbidden
380
381 $path = _dav_explode_path($options['path']);
382 $name = array_pop($path);
383
384 // Prevent hidden collection creation if disabled by administrator
385 if (!DAV_DOT_FILES && $name[0] == '.')
386 return STATUS_403; // Forbidden
387
388 if ($parent = _dav_resolve($path)) {
389
390 if ($resource = dav_lookup($parent, $name))
391 return STATUS_409; // Conflict
392
393 if ($result = _dav_dispatch('mkcol', $parent, $name))
394 return STATUS_201; // Success
395 }
396
397 return STATUS_405; // Method Not Allowed
398 }
399
400 /**
401 * Implementation of the DAV PROPFIND method.
402 *
403 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_PROPFIND
404 */
405 function PROPFIND(&$options, &$files) {
406 _dav_trace('propfind', $options);
407
408 $path = _dav_explode_path($options['path']);
409 if ($parent = _dav_resolve($path)) {
410 $depth = !empty($options['depth']) ? $options['depth'] : 0;
411 $files['files'] = _dav_resources($path, $parent, $depth);
412 return TRUE; // found
413 }
414
415 return FALSE; // not found
416 }
417
418 /**
419 * Implementation of the DAV PROPPATCH method.
420 *
421 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_PROPPATCH
422 */
423 function PROPPATCH(&$options) {
424 _dav_trace('proppatch', $options);
425
426 $path = _dav_explode_path($options['path']);
427 if (!($resource = _dav_resolve($path)))
428 return STATUS_404; // Not Found
429
430 if (is_array($options['props'])) {
431 foreach ($options['props'] as $key => $prop) {
432 if (strtolower($prop['ns']) == 'dav:') {
433 $options['props'][$key]['status'] = STATUS_403;
434 }
435 else if (isset($prop['val'])) {
436 dav_update_property($resource, $prop['ns'], $prop['name'], $prop['val']);
437 }
438 else {
439 dav_delete_property($resource, $prop['ns'], $prop['name']);
440 }
441 }
442 }
443
444 return ''; // TODO: check return value handling in PEAR base class
445 }
446
447 /**
448 * Implementation of the DAV LOCK method.
449 *
450 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_LOCK
451 */
452 function LOCK(&$options) {
453 _dav_trace('lock', $options);
454
455 $path = _dav_explode_path($options['path']);
456 $name = end($path);
457
458 if (!($resource = _dav_resolve($path)))
459 return STATUS_404; // Not Found
460
461 // Recursive locks on collections not supported yet
462 if (!empty($options['depth']))
463 return STATUS_409; // Conflict
464
465 // Prevent hidden file creation if disabled by administrator
466 if (!DAV_DOT_FILES && $name[0] == '.')
467 return STATUS_403; // Forbidden
468
469 // Prevent metadata proliferation with Windows / Mac OS X clients
470 if ((DAV_WINDOWS_NO_THUMBS_DB && strtolower($name) == 'thumbs.db') ||
471 (DAV_MACOSX_NO_DS_STORE && $name == '.DS_Store'))
472 return STATUS_403; // Forbidden
473
474 // Prevent resource fork creation with Mac OS X clients
475 if (DAV_MACOSX_NO_FORKS && strpos($name, '._') === 0)
476 return STATUS_200; // (faked)
477
478 $options['timeout'] = time() + 600; // 10 minutes (hardcoded)
479
480 if (!empty($options['update'])) {
481 if (dav_renew_lock($resource, $options['locktoken'], $options['timeout'])) {
482 return STATUS_200; // OK
483 }
484 }
485 else {
486 $depth = ($options['depth'] == 'infinity' ? -1 : (int)$options['depth']);
487 $is_writelock = ($options['type'] == 'write');
488 $is_exclusive = ($options['scope'] == 'exclusive');
489 if (dav_obtain_lock($resource, $options['locktoken'], $options['timeout'], $is_writelock, $is_exclusive, $depth)) {
490 return STATUS_200; // OK
491 }
492 }
493
494 return STATUS_409; // Conflict
495 }
496
497 /**
498 * Implementation of the DAV UNLOCK method.
499 *
500 * @see http://www.webdav.org/specs/rfc2518.html#METHOD_UNLOCK
501 */
502 function UNLOCK(&$options) {
503 _dav_trace('unlock', $options);
504
505 $path = _dav_explode_path($options['path']);
506 if (($resource = _dav_resolve($path))) {
507 if (dav_release_lock($resource, $options['token'])) {
508 return STATUS_204; // No Content
509 }
510 }
511
512 return STATUS_409; // Conflict
513 }
514 }
515
516 //////////////////////////////////////////////////////////////////////////////
517 // DAV API
518
519 /**
520 * Looks up a DAV resource of the given name in the given path.
521 */
522 function dav_lookup($parent, $name, $path = NULL) {
523 foreach (_dav_implements('lookup') as $module) {
524 if (($entry = _dav_invoke($module, 'lookup', $parent, $name, $path)) !== NULL) {
525 return $entry;
526 }
527 }
528 }
529
530 /**
531 * Returns a list of all DAV resources in the given path.
532 */
533 function dav_list($parent, $path = NULL) {
534 return _dav_invoke_all('list', $parent, $path);
535 }
536
537 /**
538 * Retrieves properties for a DAV resource.
539 *
540 * This assumes the resource exists, i.e. it has previously been looked up
541 * via dav_lookup(), for instance.
542 */
543 function dav_propfind($resource) {
544 return _dav_invoke_all('propfind', $resource);
545 //$args = func_get_args();
546 //array_unshift($args, 'propfind');
547 //return call_user_func_array('_dav_invoke_all', $args);
548 }
549
550 //////////////////////////////////////////////////////////////////////////////
551 // DAV helpers
552
553 /**
554 * Invokes a DAV hook in all modules which implement the DAV API.
555 */
556 function _dav_dispatch($hook) {
557 $args = func_get_args();
558 //_dav_trace('dispatch', $args); // DEBUG
559
560 foreach (_dav_implements($hook, array_slice($args, 1)) as $module) {
561 $func_args = array_merge(array($module), $args);
562 if (($result = call_user_func_array('_dav_invoke', $func_args)) !== NULL)
563 return $result;
564 }
565
566 return NULL; // no handler
567 }
568
569 /**
570 * Determines which modules implement a given DAV hook.
571 *
572 * @param $hook
573 * The name of the hook.
574 * @return
575 * An array with the names of the modules which implement this hook.
576 */
577 function _dav_implements($hook, array $args = array()) {
578 $modules = module_implements('dav_'. $hook);
579 $prepend = array('dav');
580
581 // HACK: This is a special case for MKCOL/PUT requests in the root
582 // collection. It's needed to prevent ambiguity and to let the
583 // administrator select which module should handle these requests (see
584 // the option 'Root collection owner' at admin/settings/dav).
585 if (($hook == 'mkcol' || $hook == 'put') && module_exists(DAV_ROOT_MODULE)) {
586 if (isset($args[0]) && array_key_exists(0, $args[0]) && $args[0][0] == DAV_ROOT_COLLECTION) {
587 $prepend = array_merge($prepend, array(DAV_ROOT_MODULE));
588 }
589 }
590
591 // Make sure the DAV core is the first in the list, while preserving any
592 // potentially customized load order the other modules may have:
593 return array_unique(array_merge($prepend, $modules));
594 }
595
596 /**
597 * Invokes a given DAV hook in a particular module.
598 *
599 * @param $module
600 * The name of the module.
601 * @param $hook
602 * The name of the hook to invoke.
603 * @param ...
604 * Arguments to pass to the hook implementation.
605 * @return
606 * The return value of the hook implementation.
607 */
608 function _dav_invoke($module, $hook) {
609 $hook = 'dav_'. $hook;
610 if (module_hook($module, $hook)) {
611 $args = func_get_args();
612 $function = $module .'_'. $hook;
613 return call_user_func_array($function, array_slice($args, 2));
614 }
615 }
616
617 /**
618 * Invokes a given DAV hook in all enabled modules that implement it.
619 *
620 * @param $hook
621 * The name of the hook to invoke.
622 * @param ...
623 * Arguments to pass to the hook.
624 * @return
625 * TODO
626 */
627 function _dav_invoke_all($hook) {
628 $args = func_get_args();
629 $hook = array_shift($args);
630 $return = array();
631 foreach (_dav_implements($hook, $args) as $module) {
632 $function = $module .'_dav_'. $hook;
633 $result = call_user_func_array($function, $args);
634 if (is_array($result)) {
635 // Not using array_merge() here as it renumbers numerical keys
636 $return += $result;
637 }
638 }
639 return $return;
640 }
641
642 /**
643 *
644 */
645 function _dav_resolve($path) {
646 $parent = array(NULL, NULL);
647 foreach (array_values($path) as $depth => $name) {
648 if (!($entry = dav_lookup($parent, $name, array_slice($path, 0, $depth))))
649 return FALSE;
650 $parent = $entry;
651 }
652 return $parent;
653 }
654
655 /**
656 *
657 */
658 function _dav_resources($path, $parent, $depth = 0) {
659 $files = array();
660 // Current directory
661 $files[] = array('path' => _dav_urlencode(_dav_implode_path($path)), 'props' => _dav_mkprops($parent));
662 // Subdirectories and resources
663 if (!empty($depth)) {
664 foreach (dav_list($parent, $path) as $name => $entry) {
665 $files[] = array('path' => _dav_urlencode(_dav_implode_path($path, $name)), 'props' => _dav_mkprops($entry));
666 }
667 }
668 return $files;
669 }
670
671 function _dav_implode_path($path, $name = NULL) {
672 return (empty($path) ? '/' : '/'. implode('/', $path) .'/') . ($name ? $name : '');
673 }
674
675 function _dav_explode_path($path) {
676 return ($path == '/') ? array() : array_slice(explode('/', $path), 1);
677 }
678
679 function _dav_urlencode($url) {
680 $map = array();
681 for ($i = 0; $i < strlen(DAV_ENCODE); $i++) {
682 $character = substr(DAV_ENCODE, $i, 1);
683 $map[$character] = rawurlencode($character);
684 }
685
686 return strtr($url, $map);
687 }
688
689 function _dav_tmpname() {
690 return tempnam(file_directory_temp(), 'drupal_dav_');
691 }
692
693 function _dav_mkprops($resource) {
694 $props = dav_propfind($resource);
695 return array_map('_dav_mkprop', array_keys($props), array_values($props));
696 }
697
698 function _dav_mkprop($x, $y) {
699 return array('ns' => 'DAV:', 'name' => $x, 'val' => $y);
700 }
701
702 function _dav_trace($method, $options = NULL) {
703 if (DAV_TRACE) {
704 if (module_exists('trace')) {
705 $msg = strtoupper($method) .'('. trace_format_php($options) .');';
706 trace('dav', $msg);
707 }
708 else {
709 //@include_once(dirname(__FILE__) .'/debug.inc'); // DEBUG
710 //dump($method, $options); // DEBUG
711 }
712 }
713 }
714
715 //////////////////////////////////////////////////////////////////////////////
716 // DAV CRUD helpers
717
718 function dav_intern_resource($resource, $module = '', $auto_create = TRUE) {
719 list($type, $key) = $resource;
720
721 // Shortcut for the root collection, which doesn't need to be stored anywhere
722 if ($type === DAV_ROOT_COLLECTION)
723 return 0;
724
725 $result = db_query("SELECT r.id FROM {dav_resources} r WHERE r.type = '%s' AND r.key = '%s'", $type, $key);
726 if (($row = db_fetch_object($result))) {
727 return $row->id;
728 }
729 else if ($auto_create) {
730 $resource_id = db_last_insert_id('dav_resources', 'id');
731 db_query("INSERT INTO {dav_resources} (id, type, `key`, module) VALUES (%d, '%s', '%s', '%s')", $resource_id, $type, $key, $module);
732 return $resource_id;
733 }
734 }
735
736 function dav_obtain_lock($resource, $token, $timeout, $is_writelock = TRUE, $is_exclusive = FALSE, $depth = 0) {
737 global $user;
738 if (($resource_id = dav_intern_resource($resource))) {
739 db_query("INSERT INTO {dav_locks} (id, resource_id, user_id, token, depth, is_writelock, is_exclusive, created_at, updated_at, expires_at) VALUES (%d, %d, %d, '%s', %d, %d, %d, %d, %d, %d)", db_last_insert_id('dav_locks' , 'id'), $resource_id, $user->uid, $token, $depth, $is_writelock, $is_exclusive, time(), time(), $timeout);
740 return TRUE; // TODO: check affected rows
741 }
742 }
743
744 function dav_renew_lock($resource, $token, $timeout) {
745 global $user;
746 if (($resource_id = dav_intern_resource($resource))) {
747 db_query("UPDATE {dav_locks} SET expires_at = %d, updated_at = %d WHERE resource_id = %d AND token = '%s'", $timeout, time(), $resource_id, $token);
748 return TRUE; // TODO: check affected rows
749 }
750 }
751
752 function dav_release_lock($resource, $token) {
753 if (($resource_id = dav_intern_resource($resource))) {
754 db_query("DELETE FROM {dav_locks} WHERE resource_id = %d AND token = '%s'", $resource_id, $token);
755 return TRUE; // TODO: check affected rows
756 }
757 }
758
759 function dav_update_property($resource, $namespace, $name, $value) {
760 if (($resource_id = dav_intern_resource($resource))) {
761 return db_query("REPLACE INTO {dav_properties} SET resource_id = %d, namespace = '%s', name = '%s', value = '%s'", $resource_id, $namespace, $name, $value);
762 }
763 }
764
765 function dav_delete_property($resource, $namespace, $name) {
766 if (($resource_id = dav_intern_resource($resource))) {
767 return db_query("DELETE FROM {dav_properties} WHERE resource_id = %d AND namespace = '%s' AND name = '%s'", $resource_id, $namespace, $name);
768 }
769 }

  ViewVC Help
Powered by ViewVC 1.1.2