* @copyright Catalyst .Net Ltd, Morphoss Ltd * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 */ // Ensure the configuration starts out as an empty object. $c = (object) array(); // Ditto for a few other global things unset($session); unset($request); unset($dbconn); // An ultra-simple exception handler to catch errors that occur // before we get a more functional exception handler in place... function early_exception_handler($exception) { echo "Uncaught early exception: ", $exception->getMessage(), "\n"; } set_exception_handler('early_exception_handler'); // Default some of the configurable values $c->sysabbr = 'davical'; $c->admin_email = 'admin@davical.example.com'; $c->system_name = 'DAViCal CalDAV Server'; $c->domain_name = (isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:$_SERVER['SERVER_ADDR']); $c->save_time_zone_defs = true; $c->collections_always_exist = false; $c->allow_get_email_visibility = false; $c->home_calendar_name = 'home'; $c->enable_row_linking = true; $c->http_auth_mode = 'Basic'; // $c->default_locale = array('es_MX', 'es_AR', 'es', 'pt'); // An array of locales to try, or just a single locale // $c->local_tzid = 'Pacific/Auckland'; // Perhaps we should read from /etc/timezone - I wonder how standard that is? $c->default_locale = 'en'; $c->base_url = preg_replace('#/[^/]+\.php.*$#', '', $_SERVER['SCRIPT_NAME']); $c->base_directory = preg_replace('#/[^/]*$#', '', $_SERVER['DOCUMENT_ROOT']); $c->stylesheets = array( $c->base_url.'/davical.css' ); $c->images = $c->base_url . '/images'; // Add a default for newly created users $c->template_usr = array( 'active' => true, 'locale' => 'en_EN', 'date_format_type' => 'E', 'email_ok' => date('Y-m-d') ); $c->hide_TODO = true; // VTODO only visible to collection owner $c->readonly_webdav_collections = true; // WebDAV access is readonly // Ensure that ../inc is in our included paths as early as possible set_include_path( '../inc'. PATH_SEPARATOR. get_include_path()); // Kind of private configuration values $c->total_query_time = 0; $c->dbg = array(); // Utilities require_once('AWLUtilities.php'); /** We actually discovered this and worked around it earlier, but we can't log it until the utilties are loaded */ if ( !isset($_SERVER['SERVER_NAME']) ) { @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..." ); } /** * Calculate the simplest form of reference to this page, excluding the PATH_INFO following the script name. */ $c->protocol_server_port_script = sprintf( '%s://%s%s%s', (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'? 'https' : 'http'), $_SERVER['SERVER_NAME'], ( ( (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on') && $_SERVER['SERVER_PORT'] == 80 ) || (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' && $_SERVER['SERVER_PORT'] == 443 ) ? '' : ':'.$_SERVER['SERVER_PORT'] ), ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']) ); init_gettext( 'davical', '../locale' ); /** * We use @file_exists because things like open_basedir might noisily deny * access which could break DAViCal completely by causing output to start * too early. */ if ( @file_exists('/etc/davical/'.$_SERVER['SERVER_NAME'].'-conf.php') ) { include('/etc/davical/'.$_SERVER['SERVER_NAME'].'-conf.php'); } else if ( @file_exists('/etc/davical/config.php') ) { include('/etc/davical/config.php'); } else if ( @file_exists('../config/config.php') ) { include('../config/config.php'); } else { include('davical_configuration_missing.php'); exit; } if ( isset($c->deny_put_collection) ) { @dbg_error_log( 'WARN', 'Deprecated "deny_put_collection" configuration item renamed to "readonly_webdav_collections"' ); $c->readonly_webdav_collections = $c->deny_put_collection; } if ( !isset($c->page_title) ) $c->page_title = $c->system_name; if ( count($c->dbg) > 0 ) { // Only log this if debugging of some sort is turned on, somewhere @dbg_error_log( 'LOG', '==========> method =%s= =%s= =%s= =%s= =%s=', $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory ); } /** * Now that we have loaded the configuration file we can switch to a * default site locale. This may be overridden by each user. */ awl_set_locale($c->default_locale); /** * Work out our version * */ $c->code_version = 0; $c->version_string = '0.9.7.4'; // The actual version # is replaced into that during the build /release process if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) { $c->code_major = $matches[1]; $c->code_minor = $matches[2]; $c->code_patch = $matches[3]; $c->code_version = (($c->code_major * 1000) + $c->code_minor).'.'.$c->code_patch; dbg_error_log('caldav', 'Version (%d.%d.%d) == %s', $c->code_major, $c->code_minor, $c->code_patch, $c->code_version); header( sprintf('Server: %d.%d', $c->code_major, $c->code_minor) ); } /** * Force the domain name to what was in the configuration file */ $_SERVER['SERVER_NAME'] = $c->domain_name; require_once('PgQuery.php'); $c->want_dbversion = array(1,2,7); $c->schema_version = 0; $qry = new PgQuery( 'SELECT schema_major, schema_minor, schema_patch FROM awl_db_revision ORDER BY schema_id DESC LIMIT 1;' ); if ( $qry->Exec('always') && $row = $qry->Fetch() ) { $c->schema_version = doubleval( sprintf( '%d%03d.%03d', $row->schema_major, $row->schema_minor, $row->schema_patch) ); $c->wanted_version = doubleval( sprintf( '%d%03d.%03d', $c->want_dbversion[0], $c->want_dbversion[1], $c->want_dbversion[2]) ); $c->schema_major = $row->schema_major; $c->schema_minor = $row->schema_minor; $c->schema_patch = $row->schema_patch; if ( $c->schema_version < $c->wanted_version ) { $c->messages[] = sprintf( 'Database schema needs upgrading. Current: %d.%d.%d, Desired: %d.%d.%d', $row->schema_major, $row->schema_minor, $row->schema_patch, $c->want_dbversion[0], $c->want_dbversion[1], $c->want_dbversion[2]); } } $_known_users_name = array(); $_known_users_id = array(); /** * Return a user record identified by a username, caching it for any subsequent lookup * @param string $username The username of the record to retrieve * @param boolean $use_cache Whether or not to use the cache (default: yes) */ function getUserByName( $username, $use_cache = true ) { // Provide some basic caching in case this ends up being overused. if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username]; $qry = new PgQuery( "SELECT *, to_char(updated at time zone 'GMT','Dy, DD Mon IYYY HH24:MI:SS \"GMT\"') AS modified FROM usr WHERE lower(username) = lower(?) ", $username ); if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) { $_known_users_name[$username] = $qry->Fetch(); $id = $_known_users_name[$username]->user_no; $_known_users_id[$id] = $_known_users_name[$username]; return $_known_users_name[$username]; } return false; } /** * Return a user record identified by a user_no, caching it for any subsequent lookup * @param int $user_no The ID of the record to retrieve * @param boolean $use_cache Whether or not to use the cache (default: yes) */ function getUserByID( $user_no, $use_cache = true ) { // Provide some basic caching in case this ends up being overused. if ( $use_cache && isset( $_known_users_id[$user_no] ) ) return $_known_users_id[$user_no]; $qry = new PgQuery( "SELECT *, to_char(updated at time zone 'GMT','Dy, DD Mon IYYY HH24:MI:SS \"GMT\"') AS modified FROM usr WHERE user_no = ? ", intval($user_no) ); if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) { $_known_users_id[$user_no] = $qry->Fetch(); $name = $_known_users_id[$user_no]->username; $_known_users_name[$name] = $_known_users_id[$user_no]; return $_known_users_id[$user_no]; } return false; } /** * Return the HTTP status code description for a given code. Hopefully * this is an efficient way to code this. * @return string The text for a give HTTP status code, in english */ function getStatusMessage($status) { switch( $status ) { case 100: $ans = 'Continue'; break; case 101: $ans = 'Switching Protocols'; break; case 200: $ans = 'OK'; break; case 201: $ans = 'Created'; break; case 202: $ans = 'Accepted'; break; case 203: $ans = 'Non-Authoritative Information'; break; case 204: $ans = 'No Content'; break; case 205: $ans = 'Reset Content'; break; case 206: $ans = 'Partial Content'; break; case 207: $ans = 'Multi-Status'; break; case 300: $ans = 'Multiple Choices'; break; case 301: $ans = 'Moved Permanently'; break; case 302: $ans = 'Found'; break; case 303: $ans = 'See Other'; break; case 304: $ans = 'Not Modified'; break; case 305: $ans = 'Use Proxy'; break; case 307: $ans = 'Temporary Redirect'; break; case 400: $ans = 'Bad Request'; break; case 401: $ans = 'Unauthorized'; break; case 402: $ans = 'Payment Required'; break; case 403: $ans = 'Forbidden'; break; case 404: $ans = 'Not Found'; break; case 405: $ans = 'Method Not Allowed'; break; case 406: $ans = 'Not Acceptable'; break; case 407: $ans = 'Proxy Authentication Required'; break; case 408: $ans = 'Request Timeout'; break; case 409: $ans = 'Conflict'; break; case 410: $ans = 'Gone'; break; case 411: $ans = 'Length Required'; break; case 412: $ans = 'Precondition Failed'; break; case 413: $ans = 'Request Entity Too Large'; break; case 414: $ans = 'Request-URI Too Long'; break; case 415: $ans = 'Unsupported Media Type'; break; case 416: $ans = 'Requested Range Not Satisfiable'; break; case 417: $ans = 'Expectation Failed'; break; case 422: $ans = 'Unprocessable Entity'; break; case 423: $ans = 'Locked'; break; case 424: $ans = 'Failed Dependency'; break; case 500: $ans = 'Internal Server Error'; break; case 501: $ans = 'Not Implemented'; break; case 502: $ans = 'Bad Gateway'; break; case 503: $ans = 'Service Unavailable'; break; case 504: $ans = 'Gateway Timeout'; break; case 505: $ans = 'HTTP Version Not Supported'; break; default: $ans = 'Unknown HTTP Status Code '.$status; } return $ans; } /** * Construct a URL from the supplied dav_name. The URL will be urlencoded, * except for any '/' characters in it. * @param string $partial_path The part of the path after the script name */ function ConstructURL( $partial_path, $force_script = false ) { global $c; $partial_path = rawurlencode($partial_path); $partial_path = str_replace( '%2F', '/', $partial_path); if ( ! isset($c->_url_script_path) ) { $c->_url_script_path = (preg_match('#/$#', $c->protocol_server_port_script) ? 'caldav.php' : ''); $c->_url_script_path = $c->protocol_server_port_script . $c->_url_script_path; } $url = $c->_url_script_path; if ( $force_script ) { if ( ! preg_match( '#/caldav\.php$#', $url ) ) $url .= '/caldav.php'; } $url .= $partial_path; $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' $url = preg_replace('#^https?://[^/]+#', '', $url ); // Remove any protocol + hostname portion return $url; } /** * Convert a date from ISO format into the sad old HTTP format. * @param string $isodate The date to convert */ function ISODateToHTTPDate( $isodate ) { // Use strtotime since strptime is not available on Windows platform. return( gmstrftime('%a, %d %b %Y %T GMT', strtotime($isodate)) ); }