Overview

Packages

  • awl
    • caldav-client-v2
    • RRule
  • davical
    • authentication
      • drivers
    • caldav
    • DAViCalSession
    • DAVTicket
    • external-bind
    • feed
    • HTTPAuthSession
    • iSchedule
    • iSchedule-POST
    • logging
    • metrics
    • Principal
    • propfind
    • PublicSession
    • Request
    • Resource
    • tzservice
  • None
  • PHP

Classes

  • WritableCollection

Functions

  • bits_to_privilege
  • ConstructURL
  • DateToISODate
  • DeconstructURL
  • early_catch_fatal_error
  • early_exception_handler
  • getStatusMessage
  • ISODateToHTTPDate
  • privilege_to_bits
  • privileges_to_XML
  • Overview
  • Package
  • Function
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: /**
  3: * @package davical
  4: * @author Andrew McMillan <andrew@mcmillan.net.nz>
  5: * @copyright Catalyst .Net Ltd, Morphoss Ltd <http://www.morphoss.com/>
  6: * @license   http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
  7: */
  8: 
  9: if ( preg_match('{/always.php$}', $_SERVER['SCRIPT_NAME'] ) ) header('Location: index.php');
 10: 
 11: // Ensure the configuration starts out as an empty object.
 12: $c = (object) array();
 13: $c->script_start_time = microtime(true);
 14: 
 15: // Ditto for a few other global things
 16: unset($session); unset($request); unset($dbconn); unset($_awl_dbconn); unset($include_properties);
 17: 
 18: // An ultra-simple exception handler to catch errors that occur
 19: // before we get a more functional exception handler in place...
 20: function early_exception_handler($e) {
 21:   if ( !headers_sent() ) {
 22:     header("Content-type: text/plain");
 23:     header( sprintf("HTTP/1.1 %d %s", 500, getStatusMessage(500)) );
 24:   }
 25:   else {
 26:     echo "<pre>\n";
 27:     // Too late to set resultcode :-(
 28:   }
 29:   try {
 30:     @ob_flush(); // Seems like it should be better to do the following but is problematic on PHP5.3 at least: while ( ob_get_level() > 0 ) ob_end_flush();
 31:   }
 32:   catch( Exception $ignored ) {}
 33:   echo "Exception [".$e->getCode()."] ".$e->getmessage()."\n";
 34:   echo "At line ", $e->getLine(), " of ", $e->getFile(), "\n";
 35:   echo "================= Stack Trace ===================\n";
 36: 
 37:   $trace = array_reverse($e->getTrace());
 38:   foreach( $trace AS $k => $v ) {
 39:     printf( "%s[%d] %s%s%s()\n", $v['file'], $v['line'], (isset($v['class'])?$v['class']:''), (isset($v['type'])?$v['type']:''), (isset($v['function'])?$v['function']:'') );
 40:   }
 41: 
 42: }
 43: set_exception_handler('early_exception_handler');
 44: 
 45: function early_catch_fatal_error() {
 46:   global $request;
 47: 
 48:   if ( !empty($request) ) return;
 49: 
 50:   // Getting Last Error
 51:   $e =  error_get_last();
 52: 
 53:   // Check if Last error is of type FATAL
 54:   if (isset($e['type']) && $e['type'] == E_ERROR) {
 55:     if ( !headers_sent() ) {
 56:       header("Content-type: text/plain");
 57:       header( sprintf("HTTP/1.1 %d %s", 500, getStatusMessage(500)) );
 58:     }
 59:     echo "PHP Fatal error: ".$e['message']."\n";
 60:     echo "At line ", $e['line'], " of ", $e['file'], "\n";
 61:     error_log("PHP Fatal Error: '".$e['message']. "' at line ". $e['line']. " of ". $e['file']);
 62:   }
 63: }
 64: register_shutdown_function('early_catch_fatal_error');
 65: 
 66: $c->default_timezone = ini_get ( 'date.timezone' );
 67: if (empty ( $c->default_timezone )) {
 68:     $c->default_timezone = 'UTC';
 69:     if (isset ( $_SERVER ['HTTP_X_DAVICAL_TESTCASE'] )) {
 70:         $c->default_timezone = 'Pacific/Auckland';
 71:     }
 72: }
 73: 
 74: // Default some of the configurable values
 75: $c->sysabbr     = 'davical';
 76: $c->admin_email = 'admin@davical.example.com';
 77: $c->system_name = 'DAViCal CalDAV Server';
 78: $c->domain_name = (isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:$_SERVER['SERVER_ADDR']);
 79: $c->save_time_zone_defs = true;
 80: $c->collections_always_exist = false;
 81: $c->allow_get_email_visibility = false;
 82: $c->permission_scan_depth = 2;
 83: $c->expand_pdo_parameters = true;
 84: $c->home_calendar_name    = 'calendar';
 85: $c->home_addressbook_name = 'addresses';
 86: $c->enable_row_linking = true;
 87: $c->enable_scheduling = false;
 88: $c->http_auth_mode = 'Basic';
 89: // $c->default_locale = array('es_MX', 'es_AR', 'es', 'pt');  // An array of locales to try, or just a single locale
 90: $c->default_locale = 'en';
 91: $c->locale_path = '../locale';
 92: $c->base_url = preg_replace('#/[^/]+\.php.*$#', '', $_SERVER['SCRIPT_NAME']);
 93: $c->base_directory = preg_replace('#/[^/]*$#', '', $_SERVER['DOCUMENT_ROOT']);
 94: $c->default_privileges = array('read-free-busy', 'schedule-deliver');
 95: 
 96: $c->enable_auto_schedule = true;
 97: 
 98: $c->schema_major = $c->schema_minor = $c->schema_patch = 0;
 99: 
100: $c->stylesheets = array( $c->base_url.'/davical.css' );
101: $c->images      = $c->base_url . '/images';
102: 
103: // Add a default for newly created users
104: $c->template_usr = array( 'active' => true,
105:                           'locale' => 'en_GB',
106:                           'date_format_type' => 'E',
107:                           'email_ok' => date('Y-m-d')
108:                         );
109: 
110: $c->hide_TODO = true;                      // VTODO only visible to collection owner
111: $c->readonly_webdav_collections = true;    // WebDAV access is readonly
112: 
113: // Kind of private configuration values
114: $c->total_query_time = 0;
115: 
116: $c->dbg = array();
117: 
118: 
119: // Utilities
120: if ( isset($skip_errors) ) $skip_errors = true;
121: if ( ! @include_once('AWLUtilities.php') ) {
122:   if ( isset($skip_errors) ) $skip_errors = false;
123:   $try_paths = array(
124:         '../../awl/inc'
125:       , '/usr/share/awl/inc'        // Where it ends up on Debian
126:       , '/usr/share/php/awl/inc'    // Fedora's standard for PHP libraries
127:       , '/usr/local/share/awl/inc'
128:   );
129:   foreach( $try_paths AS $awl_include_path ) {
130:     if ( @file_exists($awl_include_path.'/AWLUtilities.php') ) {
131:       set_include_path( $awl_include_path. PATH_SEPARATOR. get_include_path());
132:       break;
133:     }
134:   }
135:   if ( ! @include_once('AWLUtilities.php') ) {
136:     echo "Could not find the AWL libraries. Are they installed? Check your include_path in php.ini!\n";
137:     @ob_flush(); exit(0);
138:   }
139: }
140: if ( isset($skip_errors) ) $skip_errors = false;
141: 
142: // Ensure that ../inc is in our included paths as early as possible
143: set_include_path( '../inc'. PATH_SEPARATOR. get_include_path());
144: 
145: 
146: /** We actually discovered this and worked around it earlier, but we can't log it until the utilties are loaded */
147: if ( !isset($_SERVER['SERVER_NAME']) ) {
148:   @dbg_error_log( 'WARN', "Your webserver is not setting the SERVER_NAME parameter. You may need to set \$c->domain_name in your configuration.  Using IP address meanhwhile..." );
149: }
150: 
151: 
152: /**
153: * We use @file_exists because things like open_basedir might noisily deny
154: * access which could break DAViCal completely by causing output to start
155: * too early.
156: */
157: ob_start( );
158: if ( @file_exists('/etc/davical/'.$_SERVER['SERVER_NAME'].'-conf.php') ) {
159:   include('/etc/davical/'.$_SERVER['SERVER_NAME'].'-conf.php');
160: }
161: else if ( @file_exists('/etc/davical/config.php') ) {
162:   include('/etc/davical/config.php');
163: }
164: else if ( @file_exists('/usr/local/etc/davical/'.$_SERVER['SERVER_NAME'].'-conf.php') ) {
165:   include('/usr/local/etc/davical/'.$_SERVER['SERVER_NAME'].'-conf.php');
166: }
167: else if ( @file_exists('/usr/local/etc/davical/config.php') ) {
168:   include('/usr/local/etc/davical/config.php');
169: }
170: else if ( @file_exists('../config/config.php') ) {
171:   include('../config/config.php');
172: }
173: else if ( @file_exists('config/config.php') ) {
174:   include('config/config.php');
175: }
176: else {
177:   include('davical_configuration_missing.php');
178:   @ob_flush();  exit(0);
179: }
180: $config_warnings = trim(ob_get_contents());
181: ob_end_clean();
182: 
183: /**
184: * Override server-detected variables with those from X-Forwarded headers
185: */
186: if ( isset($c->trust_x_forwarded) && $c->trust_x_forwarded ) {
187:   if ( isset($_SERVER['X-Real-IP']) ) {
188:     $_SERVER['REMOTE_ADDR'] = $_SERVER['X-Real-IP'];
189:   } elseif ( isset($_SERVER['X-Forwarded-For']) ) {
190:     list($_SERVER['REMOTE_ADDR'], $rest) = explode( ',', $_SERVER['X-Forwarded-For']);
191:   }
192:   if ( isset($_SERVER['X-Forwarded-Proto']) ) {
193:     if ($_SERVER['X-Forwarded-Proto'] == 'https') {
194:       $_SERVER['HTTPS'] = 'on';
195:     } else {
196:       $_SERVER['HTTPS'] = 'off';
197:     }
198:   }
199:   if ( isset($_SERVER['X-Forwarded-Port']) ) {
200:     $_SERVER['SERVER_PORT'] = $_SERVER['X-Forwarded-Port'];
201:   }
202: }
203: 
204: /**
205: * Calculate the simplest form of reference to this page, excluding the PATH_INFO following the script name.
206: */
207: $c->protocol_server_port = sprintf( '%s://%s%s',
208:                  (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'? 'https' : 'http'),
209:                  $_SERVER['SERVER_NAME'],
210:                  (
211:                      ( (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on')
212:                           && (!isset($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == 80) )
213:                      || ( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'
214:                           && (!isset($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == 443) )
215:                      ? ''
216:                      : ':'.$_SERVER['SERVER_PORT']
217:                  ) );
218: $c->protocol_server_port_script = $c->protocol_server_port . ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']);
219: 
220: 
221: if ( !isset($c->page_title) ) $c->page_title = $c->system_name;
222: 
223: if ( isset($_SERVER['HTTP_X_DAVICAL_TESTCASE']) ) {
224:   @dbg_error_log( 'LOG', '==========> Test case =%s=', $_SERVER['HTTP_X_DAVICAL_TESTCASE'] );
225: }
226: else if ( isset($c->dbg['script_start']) && $c->dbg['script_start'] ) {
227:   // Only log this if more than a little debugging of some sort is turned on, somewhere
228:   @dbg_error_log( 'LOG', '==========> method =%s= =%s= =%s= =%s= =%s=',
229:          $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, (isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '$_SERVER[PATH_INFO] undefined'), $c->base_url, $c->base_directory );
230: }
231: 
232: /**
233: * Now that we have loaded the configuration file we can switch to a
234: * default site locale.  This may be overridden by each user.
235: */
236: putenv("LANG=". $c->default_locale);
237: if ( function_exists('awl_set_locale') ) {
238:   awl_set_locale($c->default_locale);
239:   init_gettext( 'davical', $c->locale_path );
240: }
241: 
242: /**
243: * Work out our version
244: *
245: */
246: $c->code_version = 0;
247: $c->want_awl_version = '0.57';
248: $c->version_string = '1.1.5'; // The actual version # is replaced into that during the build /release process
249: if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) {
250:   $c->code_major = $matches[1];
251:   $c->code_minor = $matches[2];
252:   $c->code_patch = $matches[3];
253:   $c->code_version = (($c->code_major * 1000) + $c->code_minor).'.'.$c->code_patch;
254:   dbg_error_log('caldav', 'Version (%d.%d.%d) == %s', $c->code_major, $c->code_minor, $c->code_patch, $c->code_version);
255:   @header( sprintf('Server: %d.%d', $c->code_major, $c->code_minor) );
256: }
257: 
258: /**
259: * Force the domain name to what was in the configuration file
260: */
261: $_SERVER['SERVER_NAME'] = $c->domain_name;
262: 
263: require_once('AwlQuery.php');
264: 
265: $c->want_dbversion = array(1,3,2);
266: $c->schema_version = 0;
267: $qry = new AwlQuery( 'SELECT schema_major, schema_minor, schema_patch FROM awl_db_revision ORDER BY schema_id DESC LIMIT 1;' );
268: if ( $qry->Exec('always',__LINE__,__FILE__) && $row = $qry->Fetch() ) {
269:   $c->schema_version = doubleval( sprintf( '%d%03d.%03d', $row->schema_major, $row->schema_minor, $row->schema_patch) );
270:   $c->wanted_version = doubleval( sprintf( '%d%03d.%03d', $c->want_dbversion[0], $c->want_dbversion[1], $c->want_dbversion[2]) );
271:   $c->schema_major = $row->schema_major;
272:   $c->schema_minor = $row->schema_minor;
273:   $c->schema_patch = $row->schema_patch;
274:   if ( $c->schema_version < $c->wanted_version ) {
275:     $c->messages[] = sprintf( 'Database schema needs upgrading. Current: %d.%d.%d, Desired: %d.%d.%d',
276:              $row->schema_major, $row->schema_minor, $row->schema_patch, $c->want_dbversion[0], $c->want_dbversion[1], $c->want_dbversion[2]);
277:   }
278:   if ( isset($c->default_timezone) ) {
279:     $qry->QDo('SET TIMEZONE TO ?', $c->default_timezone );
280:   }
281: }
282: date_default_timezone_set ( $c->default_timezone );
283: 
284: require_once('Principal.php');
285: 
286: /**
287:  * Return the HTTP status code description for a given code. Hopefully
288:  * this is an efficient way to code this.
289:  * @return string The text for a give HTTP status code, in english
290:  */
291: function getStatusMessage($status) {
292:   switch( $status ) {
293:     case 100:  $ans = 'Continue';                             break;
294:     case 101:  $ans = 'Switching Protocols';                  break;
295:     case 200:  $ans = 'OK';                                   break;
296:     case 201:  $ans = 'Created';                              break;
297:     case 202:  $ans = 'Accepted';                             break;
298:     case 203:  $ans = 'Non-Authoritative Information';        break;
299:     case 204:  $ans = 'No Content';                           break;
300:     case 205:  $ans = 'Reset Content';                        break;
301:     case 206:  $ans = 'Partial Content';                      break;
302:     case 207:  $ans = 'Multi-Status';                         break;
303:     case 300:  $ans = 'Multiple Choices';                     break;
304:     case 301:  $ans = 'Moved Permanently';                    break;
305:     case 302:  $ans = 'Found';                                break;
306:     case 303:  $ans = 'See Other';                            break;
307:     case 304:  $ans = 'Not Modified';                         break;
308:     case 305:  $ans = 'Use Proxy';                            break;
309:     case 307:  $ans = 'Temporary Redirect';                   break;
310:     case 400:  $ans = 'Bad Request';                          break;
311:     case 401:  $ans = 'Unauthorized';                         break;
312:     case 402:  $ans = 'Payment Required';                     break;
313:     case 403:  $ans = 'Forbidden';                            break;
314:     case 404:  $ans = 'Not Found';                            break;
315:     case 405:  $ans = 'Method Not Allowed';                   break;
316:     case 406:  $ans = 'Not Acceptable';                       break;
317:     case 407:  $ans = 'Proxy Authentication Required';        break;
318:     case 408:  $ans = 'Request Timeout';                      break;
319:     case 409:  $ans = 'Conflict';                             break;
320:     case 410:  $ans = 'Gone';                                 break;
321:     case 411:  $ans = 'Length Required';                      break;
322:     case 412:  $ans = 'Precondition Failed';                  break;
323:     case 413:  $ans = 'Request Entity Too Large';             break;
324:     case 414:  $ans = 'Request-URI Too Long';                 break;
325:     case 415:  $ans = 'Unsupported Media Type';               break;
326:     case 416:  $ans = 'Requested Range Not Satisfiable';      break;
327:     case 417:  $ans = 'Expectation Failed';                   break;
328:     case 422:  $ans = 'Unprocessable Entity';                 break;
329:     case 423:  $ans = 'Locked';                               break;
330:     case 424:  $ans = 'Failed Dependency';                    break;
331:     case 500:  $ans = 'Internal Server Error';                break;
332:     case 501:  $ans = 'Not Implemented';                      break;
333:     case 502:  $ans = 'Bad Gateway';                          break;
334:     case 503:  $ans = 'Service Unavailable';                  break;
335:     case 504:  $ans = 'Gateway Timeout';                      break;
336:     case 505:  $ans = 'HTTP Version Not Supported';           break;
337:     default:   $ans = 'Unknown HTTP Status Code '.$status;
338:   }
339:   return $ans;
340: }
341: 
342: 
343: /**
344: * Construct a URL from the supplied dav_name.  The URL will be urlencoded,
345: * except for any '/' characters in it.
346: * @param string $partial_path  The part of the path after the script name
347: */
348: function ConstructURL( $partial_path, $force_script = false ) {
349:   global $c;
350: 
351:   if ( ! isset($c->_url_script_path) ) {
352:     $c->protocol_server_port_script = str_replace( 'index.php', 'caldav.php', $c->protocol_server_port_script);
353:     $c->_url_script_path = (preg_match('#/$#', $c->protocol_server_port_script) ? 'caldav.php' : '');
354:     $c->_url_script_path = $c->protocol_server_port_script . $c->_url_script_path;
355:   }
356: 
357:   $url = $c->_url_script_path;
358:   if ( $force_script ) {
359:     if ( ! preg_match( '#/caldav\.php$#', $url ) ) $url .= '/caldav.php';
360:   }
361:   $url .= str_replace( '%2F', '/', rawurlencode($partial_path));
362:   $url = preg_replace( '#^(https?://.+)//#', '$1/', $url );  // Ensure we don't double any '/'
363:   $url = preg_replace('#^https?://[^/]+#', '', $url );       // Remove any protocol + hostname portion
364: 
365:   if ( strstr($url, 'caldav.php/caldav.php') !== false ) {
366: //    trace_bug('Duplicated caldav.php/ in URL "%s" from partial_path=%s, force_script=%s', $url, $partial_path, ($force_script?'true':'false'));
367:     $url = str_replace( 'caldav.php/caldav.php', 'caldav.php', $url );  // Ensure we don't double any 'caldav.php/'
368:   }
369: 
370:   return $url;
371: }
372: 
373: 
374: /**
375: * Deconstruct a dav_name from the supplied URL.  The dav_name will be urldecoded.
376: *
377: * @param string $partial_path  The part of the path after the script name
378: */
379: function DeconstructURL( $url, $force_script = false ) {
380:   global $c;
381: 
382:   $dav_name = rawurldecode($url);
383:   $dav_name = trim($dav_name);
384: 
385:   /** Allow a path like .../username/calendar.ics to translate into the calendar URL */
386:   if ( preg_match( '#^(/[^/]+/[^/]+).ics$#', $dav_name, $matches ) ) {
387:     $dav_name = $matches[1]. '/';
388:   }
389: 
390:   /** remove any leading protocol/server/port/prefix... */
391:   if ( !isset($c->deconstruction_base_path) ) $c->deconstruction_base_path = ConstructURL('/');
392:   if ( preg_match( '%^(.*?)'.str_replace('%', '\\%',$c->deconstruction_base_path).'(.*)$%', $dav_name, $matches ) ) {
393:     if ( $matches[1] == '' || $matches[1] == $c->protocol_server_port ) {
394:       $dav_name = $matches[2];
395:     }
396:   }
397: 
398:   /** strip doubled slashes */
399:   if ( strstr($dav_name,'//') ) $dav_name = preg_replace( '#//+#', '/', $dav_name);
400: 
401:   if ( substr($dav_name,0,1) != '/' ) $dav_name = '/'.$dav_name;
402: 
403:   return $dav_name;
404: }
405: 
406: 
407: /**
408: * Convert a date from ISO format into the sad old HTTP format.
409: * @param string $isodate The date to convert
410: */
411: function ISODateToHTTPDate( $isodate ) {
412:   // It is necessary to use English for this, explicitly.  See Debian BTS Bug#661985 for more info.
413:   $month = gmstrftime('%m', strtotime($isodate));
414:   switch( intval($month) ) {
415:     case 1: $month = 'Jan'; break;
416:     case 2: $month = 'Feb'; break;
417:     case 3: $month = 'Mar'; break;
418:     case 4: $month = 'Apr'; break;
419:     case 5: $month = 'May'; break;
420:     case 6: $month = 'Jun'; break;
421:     case 7: $month = 'Jul'; break;
422:     case 8: $month = 'Aug'; break;
423:     case 9: $month = 'Sep'; break;
424:     case 10: $month = 'Oct'; break;
425:     case 11: $month = 'Nov'; break;
426:     case 12: $month = 'Dec'; break;
427:     default:
428:       throw new Exception('Invalid month '.$month);
429:   }
430:   // Use strtotime since strptime is not available on Windows platform.
431:   return( gmstrftime('%a, %d '.$month.' %Y %H:%M:%S GMT', strtotime($isodate)) );
432: }
433: 
434: /**
435: * Convert a date into ISO format into the sparkly new ISO format.
436: * @param string $indate The date to convert
437: */
438: function DateToISODate( $indate, $in_utc=false ) {
439:   // Use strtotime since strptime is not available on Windows platform.
440:   if ( $in_utc ) return( gmdate('Ymd\THis\Z', strtotime($indate)) );
441:   return( date('c', strtotime($indate)) );
442: }
443: 
444: /**
445: * Given a privilege string, or an array of privilege strings, return a bit mask
446: * of the privileges.
447: * @param mixed $raw_privs The string (or array of strings) of privilege names
448: * @return integer A bit mask of the privileges.
449: */
450: define("DAVICAL_MAXPRIV", "65535");
451: define("DAVICAL_ADDRESSBOOK_MAXPRIV", "1023");
452: function privilege_to_bits( $raw_privs ) {
453:   $out_priv = 0;
454: 
455:   if ( gettype($raw_privs) == 'string' ) $raw_privs = array( $raw_privs );
456: 
457:   if ( ! is_array($raw_privs) ) $raw_privs = array($raw_privs);
458: 
459:   foreach( $raw_privs AS $priv ) {
460:     $trim_priv = trim(strtolower(preg_replace( '/^.*:/', '', $priv)));
461:     switch( $trim_priv ) {
462:       case 'read'                            : $out_priv |=     1;  break;
463:       case 'write-properties'                : $out_priv |=     2;  break;
464:       case 'write-content'                   : $out_priv |=     4;  break;
465:       case 'unlock'                          : $out_priv |=     8;  break;
466:       case 'read-acl'                        : $out_priv |=    16;  break;
467:       case 'read-current-user-privilege-set' : $out_priv |=    32;  break;
468:       case 'bind'                            : $out_priv |=    64;  break;
469:       case 'unbind'                          : $out_priv |=   128;  break;
470:       case 'write-acl'                       : $out_priv |=   256;  break;
471:       case 'read-free-busy'                  : $out_priv |=   512;  break;
472:       case 'schedule-deliver-invite'         : $out_priv |=  1024;  break;
473:       case 'schedule-deliver-reply'          : $out_priv |=  2048;  break;
474:       case 'schedule-query-freebusy'         : $out_priv |=  4096;  break;
475:       case 'schedule-send-invite'            : $out_priv |=  8192;  break;
476:       case 'schedule-send-reply'             : $out_priv |= 16384;  break;
477:       case 'schedule-send-freebusy'          : $out_priv |= 32768;  break;
478: 
479:       /** Aggregates of Privileges */
480:       case 'write'                           : $out_priv |=   198;  break; // 2 + 4 + 64 + 128
481:       case 'schedule-deliver'                : $out_priv |=  7168;  break; // 1024 + 2048 + 4096
482:       case 'schedule-send'                   : $out_priv |= 57344;  break; // 8192 + 16384 + 32768
483:       case 'all'                             : $out_priv  = DAVICAL_MAXPRIV;  break;
484:       case 'fake_privilege_for_input'        : break;
485:       default:
486:         dbg_error_log( 'ERROR', 'Cannot convert privilege of "%s" into bits.', $priv );
487: 
488:     }
489:   }
490: 
491:   // 'all' will include future privileges
492:   if ( ($out_priv & DAVICAL_MAXPRIV) >= DAVICAL_MAXPRIV ) $out_priv = pow(2,24) - 1;
493:   return $out_priv;
494: }
495: 
496: 
497: /**
498: * Given a bit mask of the privileges, will return an array of the
499: * text values of privileges.
500: * @param integer $raw_bits A bit mask of the privileges.
501: * @return mixed The string (or array of strings) of privilege names
502: */
503: function bits_to_privilege( $raw_bits, $resourcetype = 'resource' ) {
504:   $out_priv = array();
505: 
506:   if ( is_string($raw_bits) ) {
507:     $raw_bits = bindec($raw_bits);
508:   }
509: 
510:   if ( ($raw_bits & DAVICAL_MAXPRIV) == DAVICAL_MAXPRIV ) $out_priv[] = 'all';
511: 
512:   if ( ($raw_bits &   1) != 0 ) $out_priv[] = 'DAV::read';
513:   if ( ($raw_bits &   8) != 0 ) $out_priv[] = 'DAV::unlock';
514:   if ( ($raw_bits &  16) != 0 ) $out_priv[] = 'DAV::read-acl';
515:   if ( ($raw_bits &  32) != 0 ) $out_priv[] = 'DAV::read-current-user-privilege-set';
516:   if ( ($raw_bits & 256) != 0 ) $out_priv[] = 'DAV::write-acl';
517:   if ( ($resourcetype == 'calendar' || $resourcetype == 'proxy' || $resourcetype == '*') && ($raw_bits & 512) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:read-free-busy';
518: 
519:   if ( ($raw_bits & 198) != 0 ) {
520:     if ( ($raw_bits & 198) == 198 ) $out_priv[] = 'DAV::write';
521:     if ( ($raw_bits &   2) != 0 ) $out_priv[] = 'DAV::write-properties';
522:     if ( ($raw_bits &   4) != 0 ) $out_priv[] = 'DAV::write-content';
523:     if ( ($raw_bits &  64) != 0 ) $out_priv[] = 'DAV::bind';
524:     if ( ($raw_bits & 128) != 0 ) $out_priv[] = 'DAV::unbind';
525:   }
526: 
527:   if ( ($resourcetype == 'schedule-inbox' || $resourcetype == '*') && ($raw_bits & 7168) != 0 ) {
528:     if ( ($raw_bits & 7168) == 7168 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-deliver';
529:     if ( ($raw_bits & 1024) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-deliver-invite';
530:     if ( ($raw_bits & 2048) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-deliver-reply';
531:     if ( ($raw_bits & 4096) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-query-freebusy';
532:   }
533: 
534:   if ( ($resourcetype == 'schedule-outbox' || $resourcetype == '*') && ($raw_bits & 57344) != 0 ) {
535:     if ( ($raw_bits & 57344) == 57344 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send';
536:     if ( ($raw_bits &  8192) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send-invite';
537:     if ( ($raw_bits & 16384) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send-reply';
538:     if ( ($raw_bits & 32768) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send-freebusy';
539:   }
540: 
541: //  dbg_error_log( 'DAVResource', ' Privilege bit "%s" is "%s".', $raw_bits, implode(', ', $out_priv) );
542: 
543:   return $out_priv;
544: }
545: 
546: 
547: /**
548: * Returns the array of privilege names converted into XMLElements
549: */
550: function privileges_to_XML( $privilege_names, &$xmldoc=null ) {
551:   if ( !isset($xmldoc) && isset($GLOBALS['reply']) ) $xmldoc = $GLOBALS['reply'];
552:   $privileges = array();
553:   foreach( $privilege_names AS $k ) {
554:     $privilege = new XMLElement('privilege');
555:     if ( isset($xmldoc) )
556:       $xmldoc->NSElement($privilege,$k);
557:     else
558:       $privilege->NewElement($k);
559:     $privileges[] = $privilege;
560:   }
561:   return $privileges;
562: }
563: 
564: 
DAViCal API documentation generated by ApiGen 2.8.0