Loading...
Searching...
No Matches
Principal.php
<?php
require_once('AwlCache.php');
class Principal {
private static $db_tablename = 'dav_principal';
private static $db_mandatory_fields = array(
'username',
);
public static function updateableFields() {
return array(
'username', 'email', 'user_active', 'modified', 'password', 'fullname',
'email_ok', 'date_format_type', 'locale', 'type_id', 'displayname', 'default_privileges'
);
}
private static $byUserno = array();
private static $byId = array();
private static $byEmail = array();
protected $username;
protected $user_no;
protected $principal_id;
protected $email;
protected $dav_name;
public $user_active;
public $created;
public $modified;
public $password;
public $fullname;
public $email_ok;
public $date_format_type;
public $locale;
public $type_id;
public $type_label;
public $displayname;
public $default_privileges;
public $is_principal;
public $is_calendar;
public $collection_id;
public $is_addressbook;
public $resourcetypes;
public $privileges;
protected $exists;
protected $url;
protected $original_request_url;
protected $by_email;
private $cacheNs;
private $cacheKey;
protected $collections;
protected $dead_properties;
protected $default_calendar;
function __construct( $type, $value, $use_cache=true ) {
global $c, $session;
$this->exists = false;
$this->by_email = false;
$this->original_request_url = null;
switch( $type ) {
case 'path':
$type = 'username';
$value = $this->usernameFromPath($value);
break;
case 'dav_name':
$type = 'username';
$value = substr($value, 1, -1);
break;
}
switch ( $type ) {
case 'user_no': $this->user_no = $value; break;
case 'principal_id': $this->principal_id = $value; break;
case 'email': $this->email = $value; break;
case 'username': $this->username = $value; break;
default:
throw new Exception('Can only retrieve a Principal by user_no,principal_id,username or email address');
}
$cache = getCacheInstance();
if ( $use_cache && isset($session->principal_id) ) {
switch ( $type ) {
case 'user_no':
if ( isset(self::$byUserno[$value]) ) {
$type = 'username';
$value = self::$byUserno[$value];
}
break;
case 'principal_id':
if ( isset(self::$byId[$value]) ) {
$type = 'username';
$value = self::$byId[$value];
}
break;
case 'email':
$this->by_email = true;
if ( isset(self::$byEmail[$value]) ) {
$type = 'username';
$value = self::$byEmail[$value];
}
break;
}
if ( $type == 'username' ) {
$this->username = $value;
$this->dav_name = '/'.$value.'/';
$this->url = ConstructURL( $this->dav_name, true );
$this->cacheNs = 'principal-/'.$value.'/';
$this->cacheKey = 'p-'.$session->principal_id;
$row = $cache->get('principal-/'.$value.'/', 'p-'.$session->principal_id );
if ( $row !== false ) {
self::$byId[$row->principal_id] = $row->username;
self::$byUserno[$row->user_no] = $row->username;
self::$byEmail[$row->email] = $row->username;
$this->assignRowValues($row);
$this->url = ConstructURL( $this->dav_name, true );
$this->exists = true;
return $this;
}
}
}
$sql = 'SELECT dav_principal.*, principal_type.label AS type_label, ';
if ( isset($session->principal_id) && $session->principal_id !== false ) {
$sql .= 'pprivs(:session_principal::int8,principal_id,:scan_depth::int) AS privileges ';
$params = array( ':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth );
}
else {
$sql .= '0::BIT(24) AS privileges ';
$params = array( );
}
$sql .= 'FROM dav_principal LEFT JOIN principal_type ON (type_id = principal_type_id) WHERE ';
switch ( $type ) {
case 'username':
$sql .= 'lower(username)=lower(text(:param))';
break;
case 'user_no':
$sql .= 'user_no=:param';
break;
case 'principal_id':
$sql .= 'principal_id=:param';
break;
case 'email':
$this->by_email = true;
$sql .= 'lower(email)=lower(:param)';
break;
}
$params[':param'] = $value;
$qry = new AwlQuery( $sql, $params );
if ( $qry->Exec('Principal',__LINE__,__FILE__) && $qry->rows() == 1 && $row = $qry->Fetch() ) {
$this->exists = true;
if ( isset($session->principal_id) ) {
self::$byId[$row->principal_id] = $row->username;
self::$byUserno[$row->user_no] = $row->username;
self::$byEmail[$row->email] = $row->username;
if ( !isset($this->cacheNs) ) {
$this->cacheNs = 'principal-'.$row->dav_name;
$this->cacheKey = 'p-'.$session->principal_id;
}
}
$this->assignRowValues($row);
$this->url = ConstructURL( $this->dav_name, true );
if (isset($this->cacheNs))
$cache->set($this->cacheNs, $this->cacheKey, $row, 864000 );
return $this;
}
if ( $type == 'username' && $value == 'unauthenticated' ) {
$this->assignGuestValues();
}
}
public function __get( $property ) {
return $this->{$property};
}
public function __isset( $property ) {
return isset($this->{$property});
}
private function assignGuestValues() {
$this->user_no = -1;
$this->exists = false;
if ( empty($this->username) ) $this->username = translate('unauthenticated');
$this->fullname = $this->displayname = translate('Unauthenticated User');
$this->email = false;
$this->is_principal = true;
$this->is_calendar = false;
$this->principal_id = -1;
$this->privileges = $this->default_privileges = 0;
}
private function assignRowValues( $db_row ) {
foreach( $db_row AS $k => $v ) {
$this->{$k} = $v;
}
}
public function Exists() {
return $this->exists;
}
public function byEmail() {
return $this->by_email;
}
private function usernameFromPath( $path ) {
global $session, $c;
if ( $path == '/' || $path == '' ) {
dbg_error_log( 'Principal', 'No useful path split possible' );
return $session->username;
}
$path_split = explode('/', $path );
@dbg_error_log( 'Principal', 'Path split into at least /// %s /// %s /// %s', $path_split[1], $path_split[2], $path_split[3] );
$username = $path_split[1];
if ( $path_split[1] == 'principals' && isset($path_split[3]) ) {
$username = $path_split[3];
$this->original_request_url = $path;
}
if ( substr($username,0,1) == '~' ) {
$username = substr($username,1);
$this->original_request_url = $path;
}
if ( isset($c->allow_by_email) && $c->allow_by_email && preg_match( '#^(\S+@\S+[.]\S+)$#', $username) ) {
// This might seem inefficient, but we cache the result, so the second time will not read from the DB
$p = new Principal('email',$username);
$username = $p->username;
$this->by_email = true;
}
return $username;
}
function username() {
return (isset($this->username)?$this->username:false);
}
function setUsername($new_username) {
if ( $this->exists && isset($this->username) ) return false;
$this->username = $new_username;
return $this->username;
}
function user_no() {
return (isset($this->user_no)?$this->user_no:false);
}
function principal_id() {
return (isset($this->principal_id)?$this->principal_id:false);
}
function email() {
return (isset($this->email)?$this->email:false);
}
function dav_name() {
if ( !isset($this->dav_name) ) {
if ( !isset($this->username) ) {
throw new Exception('Can\'t calculate dav_name for unknown username');
}
$this->dav_name = '/'.$this->username.'/';
}
return $this->dav_name;
}
protected function FetchDeadProperties() {
if ( isset($this->dead_properties) ) return;
$this->dead_properties = array();
$qry = new AwlQuery('SELECT property_name, property_value FROM property WHERE dav_name= :dav_name', array(':dav_name' => $this->dav_name()) );
if ( $qry->Exec('Principal') ) {
while ( $property = $qry->Fetch() ) {
$this->dead_properties[$property->property_name] = DAVResource::BuildDeadPropertyXML($property->property_name,$property->property_value);
}
}
}
protected function FetchCollections() {
if ( isset($this->collections) ) return;
// If this is an external binding, then user_no will most likely be empty.
if ( ! isset($this->user_no) ) return;
$this->collections = array();
$qry = new AwlQuery('SELECT * FROM collection WHERE user_no= :user_no', array(':user_no' => $this->user_no()) );
if ( $qry->Exec('Principal') ) {
while ( $collection = $qry->Fetch() ) {
$this->collections[$collection->dav_name] = $collection;
}
}
}
function default_calendar() {
global $c;
if ( !isset($this->default_calendar) ) {
$this->default_calendar = false;
if ( !isset($this->dead_properties) ) $this->FetchDeadProperties();
if ( isset($this->dead_properties['urn:ietf:params:xml:ns:caldav:schedule-default-calendar-URL']) ) {
$this->default_calendar = $this->dead_properties['urn:ietf:params:xml:ns:caldav:schedule-default-calendar-URL'];
}
else {
if ( !isset($this->collections) ) $this->FetchCollections();
$dav_name = $this->dav_name().$c->home_calendar_name.'/';
if ( isset($this->collections[$dav_name]) && ($this->collections[$dav_name]->is_calendar == 't') ) {
$this->default_calendar = $dav_name;
}
else {
$dav_name = $this->dav_name().'home/';
if ( isset($this->collections[$dav_name]) && ($this->collections[$dav_name]->is_calendar == 't') ) {
$this->default_calendar = $dav_name;
}
else if ( isset($this->collections) ) {
foreach( $this->collections AS $dav_name => $collection ) {
if ( $collection->is_calendar == 't' ) {
$this->default_calendar = $dav_name;
}
}
}
}
}
}
return $this->default_calendar;
}
public function url($type = 'principal', $internal=false ) {
global $c;
if ( $internal )
$result = $this->dav_name();
else {
if ( isset($this->original_request_url) && $type == 'principal' )
$result = $this->original_request_url;
else
$result = $this->url;
}
switch( $type ) {
case 'principal': break;
case 'schedule-default-calendar': $result = $this->default_calendar(); break;
case 'schedule-inbox': $result .= '.in/'; break;
case 'schedule-outbox': $result .= '.out/'; break;
case 'dropbox': $result .= '.drop/'; break;
case 'notifications': $result .= '.notify/'; break;
default:
fatal('Unknown internal URL type "'.$type.'"');
}
return ConstructURL(DeconstructURL($result));
}
public function internal_url($type = 'principal' ) {
return $this->url($type,true);
}
public function unCache() {
if ( !isset($this->cacheNs) ) return;
$cache = getCacheInstance();
$cache->delete($this->cacheNs, null );
}
private function Write( $field_values, $inserting=true ) {
global $c;
if ( is_array($field_values) ) $field_values = (object) $field_values;
if ( !isset($field_values->{'user_active'}) ) {
if ( isset($field_values->{'active'}) )
$field_values->{'user_active'} = $field_values->{'active'};
else if ( $inserting )
$field_values->{'user_active'} = true;
}
if ( !isset($field_values->{'modified'}) && isset($field_values->{'updated'}) )
$field_values->{'modified'} = $field_values->{'updated'};
if ( !isset($field_values->{'type_id'}) && $inserting )
$field_values->{'type_id'} = 1; // Default to 'person'
if ( !isset($field_values->{'default_privileges'}) && $inserting )
$field_values->{'default_privileges'} = sprintf('%024s',decbin(privilege_to_bits($c->default_privileges)));
$sql = '';
if ( $inserting ) {
$insert_fields = array();
$param_names = array();
}
else {
$update_list = array();
}
$sql_params = array();
foreach( self::updateableFields() AS $k ) {
if ( !isset($field_values->{$k}) && !isset($this->{$k}) ) continue;
$param_name = ':'.$k;
$sql_params[$param_name] = (isset($field_values->{$k}) ? $field_values->{$k} : $this->{$k});
if ( $k == 'default_privileges' ) {
$sql_params[$param_name] = sprintf('%024s',$sql_params[$param_name]);
$param_name = 'cast('.$param_name.' as text)::BIT(24)';
}
else if ( $k == 'modified'
&& isset($field_values->{$k})
&& preg_match('{^([23]\d\d\d[01]\d[0123]\d)T?([012]\d[0-5]\d[0-5]\d)$}', $field_values->{$k}, $matches) ) {
$sql_params[$param_name] = $matches[1] . 'T' . $matches[2];
}
if ( $inserting ) {
$param_names[] = $param_name;
$insert_fields[] = $k;
}
else {
$update_list[] = $k.'='.$param_name;
}
}
if ( $inserting && isset(self::$db_mandatory_fields) ) {
foreach( self::$db_mandatory_fields AS $k ) {
if ( !isset($sql_params[':'.$k]) ) {
throw new Exception( get_class($this).'::Create: Mandatory field "'.$k.'" is not set.');
}
}
if ( isset($this->user_no) ) {
$param_names[] = ':user_no';
$insert_fields[] = 'user_no';
$sql_params[':user_no'] = $this->user_no;
}
if ( isset($this->created) ) {
$param_names[] = ':created';
$insert_fields[] = 'created';
$sql_params[':created'] = $this->created;
}
$sql = 'INSERT INTO '.self::$db_tablename.' ('.implode(',',$insert_fields).') VALUES('.implode(',',$param_names).')';
}
else {
$sql = 'UPDATE '.self::$db_tablename.' SET '.implode(',',$update_list);
$sql .= ' WHERE principal_id=:principal_id';
$sql_params[':principal_id'] = $this->principal_id;
}
$qry = new AwlQuery($sql, $sql_params);
if ( $qry->Exec('Principal',__FILE__,__LINE__) ) {
$this->unCache();
$new_principal = new Principal('username', $sql_params[':username']);
foreach( $new_principal AS $k => $v ) {
$this->{$k} = $v;
}
}
}
public function Create( $field_values ) {
$this->Write($field_values, true);
}
public function Update( $field_values ) {
if ( !$this->Exists() ) {
throw new Exception( get_class($this).'::Create: Attempting to update non-existent record.');
}
$this->Write($field_values, false);
}
static public function cacheFlush( $where, $whereparams=array() ) {
$cache = getCacheInstance();
if ( !$cache->isActive() ) return;
$qry = new AwlQuery('SELECT dav_name FROM dav_principal WHERE '.$where, $whereparams );
if ( $qry->Exec('Principal',__FILE__,__LINE__) ) {
while( $row = $qry->Fetch() ) {
$cache->delete('principal-'.$row->dav_name, null);
}
}
}
static public function cacheDelete( $type, $value ) {
$cache = getCacheInstance();
if ( !$cache->isActive() ) return;
if ( $type == 'username' ) {
$value = '/'.$value.'/';
}
$cache->delete('principal-'.$value, null);
}
}
DAVResource\BuildDeadPropertyXML
static BuildDeadPropertyXML($property_name, $raw_string)
Definition DAVResource.php:724
Principal
Definition Principal.php:19
Principal\__isset
__isset( $property)
Definition Principal.php:265
Principal\__construct
__construct( $type, $value, $use_cache=true)
Definition Principal.php:123
Principal\__get
__get( $property)
Definition Principal.php:255
Principal\usernameFromPath
usernameFromPath( $path)
Definition Principal.php:301
Principal\FetchDeadProperties
FetchDeadProperties()
Definition Principal.php:397
Principal\email
email()
Definition Principal.php:374
Principal\$username
$username
Definition Principal.php:49
Principal\FetchCollections
FetchCollections()
Definition Principal.php:414
Principal\user_no
user_no()
Definition Principal.php:356
Principal\principal_id
principal_id()
Definition Principal.php:365
Principal\default_calendar
default_calendar()
Definition Principal.php:434
Principal\dav_name
dav_name()
Definition Principal.php:383
Principal\username
username()
Definition Principal.php:336
Principal\setUsername
setUsername($new_username)
Definition Principal.php:345