12 require_once(
'AwlCache.php');
25 private static $db_tablename =
'dav_principal';
26 private static $db_mandatory_fields = array(
30 public static function updateableFields() {
32 'username',
'email',
'user_active',
'modified',
'password',
'fullname',
33 'email_ok',
'date_format_type',
'locale',
'type_id',
'displayname',
'default_privileges' 42 private static $byUserno = array();
43 private static $byId = array();
44 private static $byEmail = array();
51 protected $principal_id;
60 public $date_format_type;
64 public $default_privileges;
67 public $collection_id;
68 public $is_addressbook;
69 public $resourcetypes;
86 protected $original_request_url;
101 protected $collections;
102 protected $dead_properties;
103 protected $default_calendar;
125 $this->exists =
false;
126 $this->by_email =
false;
127 $this->original_request_url = null;
136 $value = substr($value, 1, -1);
145 case 'user_no': $this->
user_no = $value;
break;
146 case 'principal_id': $this->
principal_id = $value;
break;
147 case 'email': $this->
email = $value;
break;
148 case 'username': $this->
username = $value;
break;
150 throw new Exception(
'Can only retrieve a Principal by user_no,principal_id,username or email address');
153 $cache = getCacheInstance();
154 if ( $use_cache && isset($session->principal_id) ) {
157 if ( isset(self::$byUserno[$value]) ) {
159 $value = self::$byUserno[$value];
163 if ( isset(self::$byId[$value]) ) {
165 $value = self::$byId[$value];
169 $this->by_email =
true;
170 if ( isset(self::$byEmail[$value]) ) {
172 $value = self::$byEmail[$value];
177 if ( $type ==
'username' ) {
180 $this->
url = ConstructURL( $this->
dav_name,
true );
181 $this->cacheNs =
'principal-/'.$value.
'/';
182 $this->cacheKey =
'p-'.$session->principal_id;
183 $row = $cache->get(
'principal-/'.$value.
'/',
'p-'.$session->principal_id );
184 if ( $row !==
false ) {
185 self::$byId[$row->principal_id] = $row->username;
186 self::$byUserno[$row->user_no] = $row->username;
187 self::$byEmail[$row->email] = $row->username;
188 $this->assignRowValues($row);
189 $this->
url = ConstructURL( $this->
dav_name,
true );
190 $this->exists =
true;
197 if ( isset($session->principal_id) && $session->principal_id !==
false ) {
198 $sql .=
'pprivs(:session_principal::int8,principal_id,:scan_depth::int) AS privileges ';
199 $params = array(
':session_principal' => $session->principal_id,
':scan_depth' => $c->permission_scan_depth );
202 $sql .=
'0::BIT(24) AS privileges ';
205 $sql .=
'FROM dav_principal WHERE ';
208 $sql .=
'lower(username)=lower(text(:param))';
211 $sql .=
'user_no=:param';
214 $sql .=
'principal_id=:param';
217 $this->by_email =
true;
218 $sql .=
'lower(email)=lower(:param)';
221 $params[
':param'] = $value;
223 $qry =
new AwlQuery( $sql, $params );
224 if ( $qry->Exec(
'Principal',__LINE__,__FILE__) && $qry->rows() == 1 && $row = $qry->Fetch() ) {
225 $this->exists =
true;
226 if ( isset($session->principal_id) ) {
227 self::$byId[$row->principal_id] = $row->username;
228 self::$byUserno[$row->user_no] = $row->username;
229 self::$byEmail[$row->email] = $row->username;
230 if ( !isset($this->cacheNs) ) {
231 $this->cacheNs =
'principal-'.$row->dav_name;
232 $this->cacheKey =
'p-'.$session->principal_id;
235 $this->assignRowValues($row);
236 $this->
url = ConstructURL( $this->
dav_name,
true );
237 $row = $cache->set($this->cacheNs, $this->cacheKey, $row, 864000 );
241 if ( $type ==
'username' && $value ==
'unauthenticated' ) {
242 $this->assignGuestValues();
251 public function __get( $property ) {
252 return $this->{$property};
262 return isset($this->{$property});
265 private function assignGuestValues() {
267 $this->exists =
false;
268 if ( empty($this->
username) ) $this->
username = translate(
'unauthenticated');
269 $this->fullname = $this->displayname = translate(
'Unauthenticated User');
270 $this->
email =
false;
271 $this->is_principal =
true;
272 $this->is_calendar =
false;
274 $this->privileges = $this->default_privileges = 0;
277 private function assignRowValues( $db_row ) {
278 foreach( $db_row AS $k => $v ) {
283 public function Exists() {
284 return $this->exists;
288 public function byEmail() {
289 return $this->by_email;
300 if ( $path ==
'/' || $path ==
'' ) {
301 dbg_error_log(
'Principal',
'No useful path split possible' );
302 return $session->username;
305 $path_split = explode(
'/', $path );
306 @dbg_error_log(
'Principal',
'Path split into at least /// %s /// %s /// %s', $path_split[1], $path_split[2], $path_split[3] );
309 if ( $path_split[1] ==
'principals' && isset($path_split[3]) ) {
311 $this->original_request_url = $path;
315 $this->original_request_url = $path;
318 if ( isset($c->allow_by_email) && $c->allow_by_email && preg_match(
'#^(\S+@\S+[.]\S+)$#',
$username) ) {
322 $this->by_email =
true;
342 if ( $this->exists && isset($this->
username) )
return false;
371 return (isset($this->
email)?$this->
email:
false);
382 throw new Exception(
'Can\'t calculate dav_name for unknown username');
384 $this->
dav_name =
'/'.$this->username.
'/';
386 return $this->dav_name;
394 if ( isset($this->dead_properties) )
return;
396 $this->dead_properties = array();
397 $qry =
new AwlQuery(
'SELECT property_name, property_value FROM property WHERE dav_name= :dav_name', array(
':dav_name' => $this->
dav_name()) );
398 if ( $qry->Exec(
'Principal') ) {
399 while ( $property = $qry->Fetch() ) {
411 if ( isset($this->collections) )
return;
413 $this->collections = array();
414 $qry =
new AwlQuery(
'SELECT * FROM collection WHERE user_no= :user_no', array(
':user_no' => $this->
user_no()) );
415 if ( $qry->Exec(
'Principal') ) {
416 while ( $collection = $qry->Fetch() ) {
417 $this->collections[$collection->dav_name] = $collection;
433 if ( isset($this->dead_properties[
'urn:ietf:params:xml:ns:caldav:schedule-default-calendar-URL']) ) {
434 $this->
default_calendar = $this->dead_properties[
'urn:ietf:params:xml:ns:caldav:schedule-default-calendar-URL'];
438 $dav_name = $this->
dav_name().$c->home_calendar_name.
'/';
439 if ( isset($this->collections[$dav_name]) && ($this->collections[$dav_name]->is_calendar ==
't') ) {
443 $dav_name = $this->
dav_name().
'home/';
444 if ( isset($this->collections[$dav_name]) && ($this->collections[$dav_name]->is_calendar ==
't') ) {
448 foreach( $this->collections AS $dav_name => $collection ) {
449 if ( $collection->is_calendar ==
't' ) {
457 return $this->default_calendar;
467 public function url($type =
'principal', $internal=
false ) {
473 if ( isset($this->original_request_url) && $type ==
'principal' )
474 $result = $this->original_request_url;
476 $result = $this->url;
480 case 'principal':
break;
481 case 'schedule-default-calendar': $result = $this->
default_calendar();
break;
482 case 'schedule-inbox': $result .=
'.in/';
break;
483 case 'schedule-outbox': $result .=
'.out/';
break;
484 case 'dropbox': $result .=
'.drop/';
break;
485 case 'notifications': $result .=
'.notify/';
break;
487 fatal(
'Unknown internal URL type "'.$type.
'"');
489 return ConstructURL(DeconstructURL($result));
493 public function internal_url($type =
'principal' ) {
494 return $this->
url($type,
true);
498 public function unCache() {
499 if ( !isset($this->cacheNs) )
return;
500 $cache = getCacheInstance();
501 $cache->delete($this->cacheNs, null );
505 private function Write( $field_values, $inserting=
true ) {
507 if ( is_array($field_values) ) $field_values = (object) $field_values;
509 if ( !isset($field_values->{
'user_active'}) ) {
510 if ( isset($field_values->{
'active'}) )
511 $field_values->{
'user_active'} = $field_values->{
'active'};
512 else if ( $inserting )
513 $field_values->{
'user_active'} =
true;
515 if ( !isset($field_values->{
'modified'}) && isset($field_values->{
'updated'}) )
516 $field_values->{
'modified'} = $field_values->{
'updated'};
517 if ( !isset($field_values->{
'type_id'}) && $inserting )
518 $field_values->{
'type_id'} = 1;
519 if ( !isset($field_values->{
'default_privileges'}) && $inserting )
520 $field_values->{
'default_privileges'} = sprintf(
'%024s',decbin(privilege_to_bits($c->default_privileges)));
525 $insert_fields = array();
526 $param_names = array();
529 $update_list = array();
531 $sql_params = array();
532 foreach( self::updateableFields() AS $k ) {
533 if ( !isset($field_values->{$k}) && !isset($this->{$k}) )
continue;
535 $param_name =
':'.$k;
536 $sql_params[$param_name] = (isset($field_values->{$k}) ? $field_values->{$k} : $this->{$k});
537 if ( $k ==
'default_privileges' ) {
538 $sql_params[$param_name] = sprintf(
'%024s',$sql_params[$param_name]);
539 $param_name =
'cast('.$param_name.
' as text)::BIT(24)';
541 else if ( $k ==
'modified' 542 && isset($field_values->{$k})
543 && preg_match(
'{^([23]\d\d\d[01]\d[0123]\d)T?([012]\d[0-5]\d[0-5]\d)$}', $field_values->{$k}, $matches) ) {
544 $sql_params[$param_name] = $matches[1] .
'T' . $matches[2];
548 $param_names[] = $param_name;
549 $insert_fields[] = $k;
552 $update_list[] = $k.
'='.$param_name;
556 if ( $inserting && isset(self::$db_mandatory_fields) ) {
557 foreach( self::$db_mandatory_fields AS $k ) {
558 if ( !isset($sql_params[
':'.$k]) ) {
559 throw new Exception( get_class($this).
'::Create: Mandatory field "'.$k.
'" is not set.');
563 $param_names[] =
':user_no';
564 $insert_fields[] =
'user_no';
565 $sql_params[
':user_no'] = $this->user_no;
567 if ( isset($this->created) ) {
568 $param_names[] =
':created';
569 $insert_fields[] =
'created';
570 $sql_params[
':created'] = $this->created;
572 $sql =
'INSERT INTO '.self::$db_tablename.
' ('.implode(
',',$insert_fields).
') VALUES('.implode(
',',$param_names).
')';
575 $sql =
'UPDATE '.self::$db_tablename.
' SET '.implode(
',',$update_list);
576 $sql .=
' WHERE principal_id=:principal_id';
577 $sql_params[
':principal_id'] = $this->principal_id;
580 $qry =
new AwlQuery($sql, $sql_params);
581 if ( $qry->Exec(
'Principal',__FILE__,__LINE__) ) {
583 $new_principal =
new Principal(
'username', $sql_params[
':username']);
584 foreach( $new_principal AS $k => $v ) {
591 public function Create( $field_values ) {
592 $this->Write($field_values,
true);
595 public function Update( $field_values ) {
596 if ( !$this->Exists() ) {
597 throw new Exception( get_class($this).
'::Create: Attempting to update non-existent record.');
599 $this->Write($field_values,
false);
602 static public function cacheFlush( $where, $whereparams=array() ) {
603 $cache = getCacheInstance();
604 if ( !$cache->isActive() )
return;
605 $qry =
new AwlQuery(
'SELECT dav_name FROM dav_principal WHERE '.$where, $whereparams );
606 if ( $qry->Exec(
'Principal',__FILE__,__LINE__) ) {
607 while( $row = $qry->Fetch() ) {
608 $cache->delete(
'principal-'.$row->dav_name, null);
613 static public function cacheDelete( $type, $value ) {
614 $cache = getCacheInstance();
615 if ( !$cache->isActive() )
return;
616 if ( $type ==
'username' ) {
617 $value =
'/'.$value.
'/';
619 $cache->delete(
'principal-'.$value, null);
static BuildDeadPropertyXML($property_name, $raw_string)
url($type='principal', $internal=false)
__construct( $type, $value, $use_cache=true)
setUsername($new_username)