12require_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 );
238 if (isset($this->cacheNs))
239 $cache->set($this->cacheNs, $this->cacheKey, $row, 864000 );
244 if ( $type ==
'username' && $value ==
'unauthenticated' ) {
245 $this->assignGuestValues();
254 public function __get( $property ) {
255 return $this->{$property};
265 return isset($this->{$property});
268 private function assignGuestValues() {
270 $this->exists =
false;
271 if ( empty($this->
username) ) $this->
username = translate(
'unauthenticated');
272 $this->fullname = $this->displayname = translate(
'Unauthenticated User');
273 $this->
email =
false;
274 $this->is_principal =
true;
275 $this->is_calendar =
false;
277 $this->privileges = $this->default_privileges = 0;
280 private function assignRowValues( $db_row ) {
281 foreach( $db_row AS $k => $v ) {
286 public function Exists() {
287 return $this->exists;
291 public function byEmail() {
292 return $this->by_email;
303 if ( $path ==
'/' || $path ==
'' ) {
304 dbg_error_log(
'Principal',
'No useful path split possible' );
305 return $session->username;
308 $path_split = explode(
'/', $path );
309 @dbg_error_log(
'Principal',
'Path split into at least /// %s /// %s /// %s', $path_split[1], $path_split[2], $path_split[3] );
312 if ( $path_split[1] ==
'principals' && isset($path_split[3]) ) {
314 $this->original_request_url = $path;
318 $this->original_request_url = $path;
321 if ( isset($c->allow_by_email) && $c->allow_by_email && preg_match(
'#^(\S+@\S+[.]\S+)$#',
$username) ) {
325 $this->by_email =
true;
345 if ( $this->exists && isset($this->
username) )
return false;
374 return (isset($this->
email)?$this->
email:
false);
385 throw new Exception(
'Can\'t calculate dav_name for unknown username');
387 $this->
dav_name =
'/'.$this->username.
'/';
389 return $this->dav_name;
397 if ( isset($this->dead_properties) )
return;
399 $this->dead_properties = array();
400 $qry =
new AwlQuery(
'SELECT property_name, property_value FROM property WHERE dav_name= :dav_name', array(
':dav_name' => $this->
dav_name()) );
401 if ( $qry->Exec(
'Principal') ) {
402 while ( $property = $qry->Fetch() ) {
414 if ( isset($this->collections) )
return;
416 $this->collections = array();
417 $qry =
new AwlQuery(
'SELECT * FROM collection WHERE user_no= :user_no', array(
':user_no' => $this->
user_no()) );
418 if ( $qry->Exec(
'Principal') ) {
419 while ( $collection = $qry->Fetch() ) {
420 $this->collections[$collection->dav_name] = $collection;
436 if ( isset($this->dead_properties[
'urn:ietf:params:xml:ns:caldav:schedule-default-calendar-URL']) ) {
437 $this->
default_calendar = $this->dead_properties[
'urn:ietf:params:xml:ns:caldav:schedule-default-calendar-URL'];
441 $dav_name = $this->
dav_name().$c->home_calendar_name.
'/';
442 if ( isset($this->collections[$dav_name]) && ($this->collections[$dav_name]->is_calendar ==
't') ) {
446 $dav_name = $this->
dav_name().
'home/';
447 if ( isset($this->collections[$dav_name]) && ($this->collections[$dav_name]->is_calendar ==
't') ) {
451 foreach( $this->collections AS $dav_name => $collection ) {
452 if ( $collection->is_calendar ==
't' ) {
460 return $this->default_calendar;
470 public function url($type =
'principal', $internal=
false ) {
476 if ( isset($this->original_request_url) && $type ==
'principal' )
477 $result = $this->original_request_url;
479 $result = $this->url;
483 case 'principal':
break;
484 case 'schedule-default-calendar': $result = $this->
default_calendar();
break;
485 case 'schedule-inbox': $result .=
'.in/';
break;
486 case 'schedule-outbox': $result .=
'.out/';
break;
487 case 'dropbox': $result .=
'.drop/';
break;
488 case 'notifications': $result .=
'.notify/';
break;
490 fatal(
'Unknown internal URL type "'.$type.
'"');
492 return ConstructURL(DeconstructURL($result));
496 public function internal_url($type =
'principal' ) {
497 return $this->
url($type,
true);
501 public function unCache() {
502 if ( !isset($this->cacheNs) )
return;
503 $cache = getCacheInstance();
504 $cache->delete($this->cacheNs,
null );
508 private function Write( $field_values, $inserting=
true ) {
510 if ( is_array($field_values) ) $field_values = (object) $field_values;
512 if ( !isset($field_values->{
'user_active'}) ) {
513 if ( isset($field_values->{
'active'}) )
514 $field_values->{
'user_active'} = $field_values->{
'active'};
515 else if ( $inserting )
516 $field_values->{
'user_active'} =
true;
518 if ( !isset($field_values->{
'modified'}) && isset($field_values->{
'updated'}) )
519 $field_values->{
'modified'} = $field_values->{
'updated'};
520 if ( !isset($field_values->{
'type_id'}) && $inserting )
521 $field_values->{
'type_id'} = 1;
522 if ( !isset($field_values->{
'default_privileges'}) && $inserting )
523 $field_values->{
'default_privileges'} = sprintf(
'%024s',decbin(privilege_to_bits($c->default_privileges)));
528 $insert_fields = array();
529 $param_names = array();
532 $update_list = array();
534 $sql_params = array();
535 foreach( self::updateableFields() AS $k ) {
536 if ( !isset($field_values->{$k}) && !isset($this->{$k}) )
continue;
538 $param_name =
':'.$k;
539 $sql_params[$param_name] = (isset($field_values->{$k}) ? $field_values->{$k} : $this->{$k});
540 if ( $k ==
'default_privileges' ) {
541 $sql_params[$param_name] = sprintf(
'%024s',$sql_params[$param_name]);
542 $param_name =
'cast('.$param_name.
' as text)::BIT(24)';
544 else if ( $k ==
'modified'
545 && isset($field_values->{$k})
546 && preg_match(
'{^([23]\d\d\d[01]\d[0123]\d)T?([012]\d[0-5]\d[0-5]\d)$}', $field_values->{$k}, $matches) ) {
547 $sql_params[$param_name] = $matches[1] .
'T' . $matches[2];
551 $param_names[] = $param_name;
552 $insert_fields[] = $k;
555 $update_list[] = $k.
'='.$param_name;
559 if ( $inserting && isset(self::$db_mandatory_fields) ) {
560 foreach( self::$db_mandatory_fields AS $k ) {
561 if ( !isset($sql_params[
':'.$k]) ) {
562 throw new Exception( get_class($this).
'::Create: Mandatory field "'.$k.
'" is not set.');
565 if ( isset($this->user_no) ) {
566 $param_names[] =
':user_no';
567 $insert_fields[] =
'user_no';
568 $sql_params[
':user_no'] = $this->user_no;
570 if ( isset($this->created) ) {
571 $param_names[] =
':created';
572 $insert_fields[] =
'created';
573 $sql_params[
':created'] = $this->created;
575 $sql =
'INSERT INTO '.self::$db_tablename.
' ('.implode(
',',$insert_fields).
') VALUES('.implode(
',',$param_names).
')';
578 $sql =
'UPDATE '.self::$db_tablename.
' SET '.implode(
',',$update_list);
579 $sql .=
' WHERE principal_id=:principal_id';
580 $sql_params[
':principal_id'] = $this->principal_id;
583 $qry =
new AwlQuery($sql, $sql_params);
584 if ( $qry->Exec(
'Principal',__FILE__,__LINE__) ) {
586 $new_principal =
new Principal(
'username', $sql_params[
':username']);
587 foreach( $new_principal AS $k => $v ) {
594 public function Create( $field_values ) {
595 $this->Write($field_values,
true);
598 public function Update( $field_values ) {
599 if ( !$this->Exists() ) {
600 throw new Exception( get_class($this).
'::Create: Attempting to update non-existent record.');
602 $this->Write($field_values,
false);
605 static public function cacheFlush( $where, $whereparams=array() ) {
606 $cache = getCacheInstance();
607 if ( !$cache->isActive() )
return;
608 $qry =
new AwlQuery(
'SELECT dav_name FROM dav_principal WHERE '.$where, $whereparams );
609 if ( $qry->Exec(
'Principal',__FILE__,__LINE__) ) {
610 while( $row = $qry->Fetch() ) {
611 $cache->delete(
'principal-'.$row->dav_name,
null);
616 static public function cacheDelete( $type, $value ) {
617 $cache = getCacheInstance();
618 if ( !$cache->isActive() )
return;
619 if ( $type ==
'username' ) {
620 $value =
'/'.$value.
'/';
622 $cache->delete(
'principal-'.$value,
null);
static BuildDeadPropertyXML($property_name, $raw_string)
__construct( $type, $value, $use_cache=true)
url($type='principal', $internal=false)
setUsername($new_username)