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