2010-09-27 01:14:42 +02:00
< ? php
2011-10-16 21:33:31 +02:00
# $Id$
2010-09-27 01:14:42 +02:00
2011-10-16 21:33:31 +02:00
/**
2010-09-27 01:14:42 +02:00
* Handlers User level alias actions - e . g . add alias , get aliases , update etc .
*/
2011-03-02 23:37:22 +01:00
class DomainHandler extends PFAHandler {
2010-09-27 01:14:42 +02:00
2011-03-02 23:37:22 +01:00
protected $username = null ; # actually it's the domain - variable name kept for consistence with the other classes
2011-10-16 20:50:33 +02:00
protected $db_table = null ;
2011-03-02 23:37:22 +01:00
protected $id_field = null ;
protected $struct = array ();
protected $new = 0 ; # 1 on create, otherwise 0
2011-10-17 01:37:11 +02:00
protected $values = array ();
protected $values_valid = false ;
2010-09-27 01:14:42 +02:00
public $errormsg = array ();
2011-10-16 23:41:27 +02:00
2011-10-19 19:52:26 +02:00
# messages used in various functions
# (stored separately to make the functions reuseable)
protected $msg = array ();
2011-10-16 23:41:27 +02:00
2010-09-27 01:14:42 +02:00
/**
2011-10-19 00:11:22 +02:00
* Constructor : fill $struct etc .
* @ param string $new
2010-09-27 01:14:42 +02:00
*/
2011-10-19 00:11:22 +02:00
public function __construct ( $new = 0 ) {
2011-03-02 23:37:22 +01:00
if ( $new ) $this -> new = 1 ;
$this -> initStruct ();
2011-10-19 19:52:26 +02:00
$this -> initMsg ();
2011-10-19 00:11:22 +02:00
}
/**
* initialize with $username and check if it is valid
* @ param string $username
*/
public function init ( $username ) {
$this -> username = strtolower ( $username );
2011-10-16 23:41:27 +02:00
$exists = $this -> view ( false );
2011-10-19 00:11:22 +02:00
if ( $this -> new ) {
2011-10-16 23:41:27 +02:00
if ( $exists ) {
2011-10-19 19:52:26 +02:00
$this -> errormsg [] = Lang :: read ( $this -> msg [ 'error_already_exists' ]);
2011-10-19 00:11:22 +02:00
return false ;
2011-10-16 23:41:27 +02:00
} elseif ( ! $this -> validate_id () ) {
# errormsg filled by validate_id()
2011-10-19 00:11:22 +02:00
return false ;
2011-10-16 23:41:27 +02:00
} else {
2011-10-19 00:11:22 +02:00
return true ;
2011-10-16 23:41:27 +02:00
}
} else { # edit mode
if ( ! $exists ) {
2011-10-19 19:52:26 +02:00
$this -> errormsg [] = Lang :: read ( $this -> msg [ 'error_does_not_exist' ]);
2011-10-19 00:11:22 +02:00
return false ;
2011-10-16 23:41:27 +02:00
} else {
2011-10-19 00:11:22 +02:00
return true ;
2011-10-16 23:41:27 +02:00
}
}
2011-03-02 23:37:22 +01:00
}
2011-10-16 23:41:27 +02:00
protected function validate_id () {
$valid = check_domain ( $this -> username );
if ( $valid ) {
return true ;
} else {
2011-10-18 01:44:40 +02:00
$this -> errormsg [] = Lang :: read ( 'pAdminCreate_domain_domain_text_error2' ); # TODO: half of the errormsg is currently delivered via flash_error() in check_domain
2011-10-16 23:41:27 +02:00
return false ;
}
}
2011-10-19 19:52:26 +02:00
# init $this->struct, $this->db_table and $this->id_field
2011-10-16 23:41:27 +02:00
protected function initStruct () {
2011-10-16 20:50:33 +02:00
$this -> db_table = 'domain' ;
2011-03-02 23:37:22 +01:00
$this -> id_field = 'domain' ;
2011-07-30 00:06:52 +02:00
# TODO: shorter PALANG labels ;-)
# TODO: hardcode 'default' to Config::read in pacol()?
$transp = boolconf ( 'transport' ) ? 1 : 0 ; # TOOD: use a function or write a Config::intbool function
2011-10-16 20:50:33 +02:00
$quota = boolconf ( 'quota' ) ? 1 : 0 ; # TOOD: use a function or write a Config::intbool function
2011-07-30 00:06:52 +02:00
$dom_q = boolconf ( 'domain_quota' ) ? 1 : 0 ; # TOOD: use a function or write a Config::intbool function
2011-03-02 23:37:22 +01:00
2011-10-23 00:49:01 +02:00
# values for the "type" column:
# text one line of text
# num number
# vnum "virtual" number, coming from JOINs etc.
# bool boolean (converted to 0/1, additional column _$field with yes/no)
# ts timestamp (created/modified)
# enum list of options, must be given in column "options" as array
# NOTE: There are dependencies between alias_count, mailbox_count and total_quota.
# NOTE: If you disable "display in list" for one of them, the SQL query for the others might break.
# NOTE: (Disabling all of them shouldn't be a problem.)
2011-04-20 00:08:20 +02:00
$this -> struct = array (
2011-10-25 23:28:55 +02:00
# field name allow display in... type $PALANG label $PALANG description default / options / ...
2011-03-02 23:37:22 +01:00
# editing? form list
2011-10-16 21:33:31 +02:00
'domain' => pacol ( $this -> new , 1 , 1 , 'text' , 'pAdminEdit_domain_domain' , '' ),
'description' => pacol ( 1 , 1 , 1 , 'text' , 'pAdminEdit_domain_description' , '' ),
'aliases' => pacol ( 1 , 1 , 1 , 'num' , 'pAdminEdit_domain_aliases' , 'pAdminEdit_domain_aliases_text' , Config :: read ( 'aliases' ) ),
2011-10-25 23:28:55 +02:00
'alias_count' => pacol ( 0 , 0 , 1 , 'vnum' , '' , '' , '' , '' ,
/*not_in_db*/ 0 ,
/*dont_write_to_db*/ 1 ,
2011-10-30 01:44:37 +02:00
/*select*/ 'coalesce(__alias_count,0) - coalesce(__mailbox_count,0) as alias_count' ,
2011-10-23 00:49:01 +02:00
/*extrafrom*/ 'left join ( select count(*) as __alias_count, domain as __alias_domain from ' . table_by_key ( 'alias' ) .
' group by domain) as __alias on domain = __alias_domain' ),
2011-10-16 21:33:31 +02:00
'mailboxes' => pacol ( 1 , 1 , 1 , 'num' , 'pAdminEdit_domain_mailboxes' , 'pAdminEdit_domain_mailboxes_text' , Config :: read ( 'mailboxes' ) ),
2011-10-25 23:28:55 +02:00
'mailbox_count' => pacol ( 0 , 0 , 1 , 'vnum' , '' , '' , '' , '' ,
/*not_in_db*/ 0 ,
/*dont_write_to_db*/ 1 ,
2011-10-23 00:49:01 +02:00
/*select*/ 'coalesce(__mailbox_count,0) as mailbox_count' ,
/*extrafrom*/ 'left join ( select count(*) as __mailbox_count, sum(quota) as __total_quota, domain as __mailbox_domain from ' . table_by_key ( 'mailbox' ) .
' group by domain) as __mailbox on domain = __mailbox_domain' ),
2011-10-16 21:33:31 +02:00
'maxquota' => pacol ( $quota , $quota , $quota , 'num' , 'pAdminEdit_domain_maxquota' , 'pAdminEdit_domain_maxquota_text' , Config :: read ( 'maxquota' ) ),
2011-10-25 23:28:55 +02:00
'total_quota' => pacol ( 0 , 0 , 1 , 'vnum' , '' , '' , '' , '' ,
/*not_in_db*/ 0 ,
/*dont_write_to_db*/ 1 ,
2011-10-23 00:49:01 +02:00
/*select*/ 'round(coalesce(__total_quota/' . intval ( Config :: read ( 'quota_multiplier' )) . ',0)) as total_quota' /*extrafrom*/ /* already in mailbox_count */ ),
2011-10-16 21:33:31 +02:00
'quota' => pacol ( $dom_q , $dom_q , $dom_q , 'num' , 'pAdminEdit_domain_quota' , 'pAdminEdit_domain_maxquota_text' , Config :: read ( 'domain_quota_default' ) ),
'transport' => pacol ( $transp , $transp , $transp , 'enum' , 'pAdminEdit_domain_transport' , 'pAdminEdit_domain_transport_text' , Config :: read ( 'transport_default' ) ,
2011-07-30 00:06:52 +02:00
/*options*/ $this -> getTransports () ),
2011-10-16 21:33:31 +02:00
'backupmx' => pacol ( 1 , 1 , 1 , 'bool' , 'pAdminEdit_domain_backupmx' , '' ),
2011-10-19 00:56:33 +02:00
'active' => pacol ( 1 , 1 , 1 , 'bool' , 'pAdminEdit_domain_active' , '' , 1 ),
2011-10-25 00:17:43 +02:00
'default_aliases' => pacol ( $this -> new , $this -> new , 0 , 'bool' , 'pAdminCreate_domain_defaultaliases ' , '' , 1 , '' , /*not in db*/ 1 ),
2011-10-17 00:32:22 +02:00
'created' => pacol ( 0 , 0 , 1 , 'ts' , '' /* TODO: "created" label */ , '' ),
2011-10-16 21:33:31 +02:00
'modified' => pacol ( 0 , 0 , 1 , 'ts' , 'pAdminList_domain_modified' , '' ),
2011-03-02 23:37:22 +01:00
);
2010-09-27 01:14:42 +02:00
}
2011-10-19 19:52:26 +02:00
# messages used in various functions.
# always list the key to hand over to Lang::read
# the only exception is 'logname' which uses the key for db_log
protected function initMsg () {
$this -> msg [ 'error_already_exists' ] = 'pAdminCreate_domain_domain_text_error' ;
$this -> msg [ 'error_does_not_exist' ] = 'domain_does_not_exist' ;
if ( $this -> new ) {
$this -> msg [ 'logname' ] = 'create_domain' ;
$this -> msg [ 'store_error' ] = 'pAdminCreate_domain_result_error' ;
} else {
$this -> msg [ 'logname' ] = 'edit_domain' ;
$this -> msg [ 'store_error' ] = 'pAdminEdit_domain_result_error' ;
}
}
2011-10-18 01:44:40 +02:00
public function getStruct () {
return $this -> struct ;
}
2011-10-19 22:21:43 +02:00
public function getId_field () {
return $this -> id_field ;
}
2010-09-27 01:14:42 +02:00
public function getTransports () {
2011-02-14 00:01:44 +01:00
return Config :: read ( 'transport_options' );
2010-09-27 01:14:42 +02:00
}
2011-03-02 23:37:22 +01:00
# TODO: specific for CLI? If yes, move to CLI code
2010-09-27 01:14:42 +02:00
public function getTransport ( $id ) {
2011-02-14 00:01:44 +01:00
$transports = Config :: read ( 'transport_options' );
return $transports [ $id - 1 ];
2010-09-27 01:14:42 +02:00
}
2011-10-16 21:33:31 +02:00
2011-10-17 01:37:11 +02:00
public function set ( $values ) {
2011-03-02 23:37:22 +01:00
# TODO: make this a generic function for add and edit
2011-10-16 20:50:33 +02:00
if ( $this -> new == 1 ) {
$values [ $this -> id_field ] = $this -> username ;
}
2011-03-02 23:37:22 +01:00
# base validation
2011-10-17 01:37:11 +02:00
$this -> values = array ();
$this -> values_valid = false ;
2011-03-02 23:37:22 +01:00
foreach ( $this -> struct as $key => $row ) {
2011-10-16 21:33:31 +02:00
if ( $row [ 'editable' ] == 0 ) { # not editable
2011-10-16 20:50:33 +02:00
if ( $this -> new == 1 ) {
2011-10-17 01:37:11 +02:00
$this -> values [ $key ] = $row [ 'default' ];
2011-10-16 20:50:33 +02:00
}
2011-10-16 21:33:31 +02:00
} else {
2011-10-19 19:52:26 +02:00
if ( isset ( $values [ $key ])) {
if ( $row [ 'type' ] != " password " || strlen ( $values [ $key ]) > 0 || $this -> new == 1 ) { # skip on empty (aka unchanged) password on edit
$valid = true ; # trust input unless validator objects
2011-10-30 01:44:37 +02:00
# validate based on field type (_inp_$type)
2011-10-19 19:52:26 +02:00
$func = " _inp_ " . $row [ 'type' ];
if ( method_exists ( $this , $func ) ) {
if ( ! $this -> { $func }( $key , $values [ $key ])) $valid = false ;
} else {
# TODO: warning if no validation function exists?
}
2011-10-30 01:44:37 +02:00
# validate based on field name (_field_$fieldname)
$func = " _field_ " . $key ;
if ( method_exists ( $this , $func ) ) {
if ( ! $this -> { $func }( $key , $values [ $key ])) $valid = false ;
}
2011-10-19 19:52:26 +02:00
if ( $valid ) {
2011-10-17 01:37:11 +02:00
$this -> values [ $key ] = $values [ $key ];
}
2011-03-02 23:37:22 +01:00
}
2011-10-19 19:52:26 +02:00
} elseif ( $this -> new ) { # new, field not set in input data
$this -> errormsg [] = " field $key is missing " ;
# echo "MISSING / not set: $key\n";
} else { # edit, field unchanged
# echo "skipped / not set: $key\n";
2011-03-02 23:37:22 +01:00
}
}
}
2011-10-17 01:37:11 +02:00
if ( count ( $this -> errormsg ) == 0 ) {
$this -> values_valid = true ;
}
return $this -> values_valid ;
}
2011-10-30 01:44:37 +02:00
/**
* store $this -> values in the database
* calls $this -> storemore () where additional things can be done
*/
2011-10-18 01:44:40 +02:00
public function store () {
2011-10-17 01:37:11 +02:00
if ( $this -> values_valid == false ) {
$this -> errormsg [] = " one or more values are invalid! " ;
return false ;
}
2011-10-16 20:50:33 +02:00
2011-10-17 01:37:11 +02:00
$db_values = $this -> values ;
2011-10-16 20:50:33 +02:00
2011-10-19 19:52:26 +02:00
foreach ( array_keys ( $db_values ) as $key ) {
switch ( $this -> struct [ $key ][ 'type' ]) { # modify field content for some types
case 'bool' :
$db_values [ $key ] = db_get_boolean ( $db_values [ $key ]);
break ;
# TODO: passwords -> pacrypt()
}
if ( $this -> struct [ $key ][ 'not_in_db' ] == 1 ) unset ( $db_values [ $key ]); # remove 'not in db' columns
2011-10-25 23:28:55 +02:00
if ( $this -> struct [ $key ][ 'dont_write_to_db' ] == 1 ) unset ( $db_values [ $key ]); # remove 'dont_write_to_db' columns
2011-10-19 19:52:26 +02:00
}
if ( $this -> new ) {
$result = db_insert ( $this -> db_table , $db_values );
} else {
$result = db_update ( $this -> db_table , $this -> id_field , $this -> username , $db_values );
}
2011-02-14 00:01:44 +01:00
if ( $result != 1 ) {
2011-10-19 19:52:26 +02:00
$this -> errormsg [] = Lang :: read ( $this -> msg [ 'store_error' ]) . " \n ( " . $this -> username . " ) \n " ; # TODO: change message + use sprintf
2011-02-14 00:15:40 +01:00
return false ;
2011-10-30 01:44:37 +02:00
}
$result = $this -> storemore ();
if ( $result ) {
db_log ( $this -> username , $this -> msg [ 'logname' ], " " );
}
return $result ;
}
/**
* called by $this -> store () after storing $this -> values in the database
* can be used to update additional tables , call scripts etc .
*/
protected function storemore () {
# TODO: whitespace fix
2011-10-17 01:37:11 +02:00
if ( $this -> new && $this -> values [ 'default_aliases' ]) {
2011-02-14 00:01:44 +01:00
foreach ( Config :: read ( 'default_aliases' ) as $address => $goto ) {
2011-04-20 00:08:20 +02:00
$address = $address . " @ " . $this -> username ;
2011-02-14 00:01:44 +01:00
# TODO: use AliasHandler->add instead of writing directly to the alias table
2010-09-27 01:14:42 +02:00
$arr = array (
'address' => $address ,
'goto' => $goto ,
2011-04-20 00:08:20 +02:00
'domain' => $this -> username ,
2011-02-14 00:01:44 +01:00
);
$result = db_insert ( 'alias' , $arr );
2011-07-30 00:06:52 +02:00
# TODO: error checking
2010-09-27 01:14:42 +02:00
}
}
2011-10-19 19:52:26 +02:00
if ( $this -> new ) {
$tMessage = Lang :: read ( 'pAdminCreate_domain_result_success' ) . " ( " . $this -> username . " ) " ; # TODO: tMessage is not used/returned anywhere
} else {
# TODO: success message for edit
}
2011-10-30 01:44:37 +02:00
# TODO: END whitespace fix
2011-10-19 19:52:26 +02:00
if ( $this -> new ) {
if ( ! domain_postcreation ( $this -> username )) {
$this -> errormsg [] = Lang :: read ( 'pAdminCreate_domain_error' );
}
} else {
# we don't have domain_postedit()
2010-09-27 01:14:42 +02:00
}
2011-10-30 01:44:37 +02:00
return true ; # TODO: don't hardcode
2010-09-27 01:14:42 +02:00
}
2011-10-16 21:33:31 +02:00
2011-10-22 15:10:44 +02:00
/**
* read_from_db
* @ param array or string - condition ( an array will be AND ' ed using db_where_clause , a string will be directly used )
* @ return array - rows
*/
protected function read_from_db ( $condition ) {
2011-10-17 00:32:22 +02:00
$select_cols = array ();
2011-10-22 15:10:44 +02:00
$yes = escape_string ( Lang :: read ( 'YES' ));
$no = escape_string ( Lang :: read ( 'NO' ));
2011-10-16 21:33:31 +02:00
2011-10-25 01:32:45 +02:00
# TODO: replace hardcoded %Y-%m-%d with a country-specific date format via *.lang?
# TODO: (not too easy because pgsql uses a different formatstring format :-/ )
if ( Config :: read ( 'database_type' ) == 'pgsql' ) {
$formatted_date = " TO_DATE(text(###KEY###), 'YYYY-mm-dd') " ;
} else {
$formatted_date = " DATE_FORMAT(###KEY###, '%Y-%m-%d') " ;
}
2011-10-22 13:12:03 +02:00
$colformat = array (
2011-10-25 01:32:45 +02:00
'ts' => " $formatted_date AS ###KEY###, ###KEY### AS _###KEY### " ,
2011-10-22 15:10:44 +02:00
'bool' => " CASE ###KEY### WHEN ' " . db_get_boolean ( true ) . " ' THEN '1' WHEN ' " . db_get_boolean ( false ) . " ' THEN '0' END as ###KEY###, " .
" CASE ###KEY### WHEN ' " . db_get_boolean ( true ) . " ' THEN ' $yes ' WHEN ' " . db_get_boolean ( false ) . " ' THEN ' $no ' END as _###KEY### " ,
2011-10-22 13:12:03 +02:00
);
2011-10-17 00:32:22 +02:00
# get list of fields to display
2011-10-23 00:49:01 +02:00
$extrafrom = " " ;
2011-10-17 00:32:22 +02:00
foreach ( $this -> struct as $key => $row ) {
if ( $row [ 'display_in_list' ] != 0 && $row [ 'not_in_db' ] == 0 ) {
2011-10-23 00:49:01 +02:00
if ( $row [ 'select' ] != '' ) $key = $row [ 'select' ];
if ( $row [ 'extrafrom' ] != '' ) $extrafrom = $extrafrom . " " . $row [ 'extrafrom' ] . " \n " ;
2011-10-22 13:12:03 +02:00
if ( isset ( $colformat [ $row [ 'type' ]])) {
$select_cols [] = str_replace ( '###KEY###' , $key , $colformat [ $row [ 'type' ]] );
2011-10-17 00:32:22 +02:00
} else {
$select_cols [] = $key ;
}
2011-10-22 13:12:03 +02:00
2011-10-17 00:32:22 +02:00
}
}
$cols = join ( ',' , $select_cols );
$table = table_by_key ( $this -> db_table );
2011-10-22 15:10:44 +02:00
if ( is_array ( $condition )) {
$where = db_where_clause ( $condition , $this -> struct );
} else {
$where = " WHERE $condition " ;
}
2011-10-23 00:49:01 +02:00
$query = " SELECT $cols FROM $table $extrafrom $where ORDER BY " . $this -> id_field ;
$result = db_query ( $query );
2011-10-22 13:12:03 +02:00
2011-10-22 15:10:44 +02:00
$db_result = array ();
2010-09-27 01:14:42 +02:00
if ( $result [ 'rows' ] != 0 ) {
2011-10-22 15:10:44 +02:00
while ( $row = db_assoc ( $result [ 'result' ])) {
$db_result [] = $row ;
2011-10-17 00:32:22 +02:00
}
2011-10-22 15:10:44 +02:00
}
return $db_result ;
}
2011-10-23 00:49:01 +02:00
/**
* get the settings of a domain
* @ param array or string $condition
* @ return bool - true if at least one domain was found
* The data is stored in $this -> return ( as associative array of column => value )
*/
2011-10-22 15:10:44 +02:00
public function view ( $errors = true ) {
$result = $this -> read_from_db ( array ( $this -> id_field => $this -> username ) );
if ( count ( $result ) == 1 ) {
$this -> return = $result [ 0 ];
2011-02-14 00:15:40 +01:00
return true ;
2010-09-27 01:14:42 +02:00
}
2011-10-22 15:10:44 +02:00
2011-10-19 19:52:26 +02:00
if ( $errors ) $this -> errormsg [] = Lang :: read ( $this -> msg [ 'error_does_not_exist' ]);
2011-03-02 23:37:22 +01:00
# $this->errormsg[] = $result['error'];
2011-02-14 00:15:40 +01:00
return false ;
2010-09-27 01:14:42 +02:00
}
2011-10-23 00:49:01 +02:00
/**
* get a list of one or more domains with all settings
* @ param array or string $condition
* @ return bool - true if at least one domain was found
* The data is stored in $this -> return ( as array of rows , each row is an associative array of column => value )
*/
public function getList ( $condition ) {
$result = $this -> read_from_db ( $condition );
if ( count ( $result ) >= 1 ) {
$this -> return = $result ;
return true ;
}
# $this->errormsg[] = Lang::read($this->msg['error_does_not_exist']);
# $this->errormsg[] = $result['error'];
return false ;
}
2011-02-14 00:35:49 +01:00
/**
* @ return true on success false on failure
*/
2011-10-16 21:33:31 +02:00
public function delete () {
if ( ! $this -> view () ) {
2011-02-14 00:35:49 +01:00
$this -> errormsg [] = 'A domain with that name does not exist.' ; # TODO: make translatable
return false ;
}
$this -> errormsg [] = '*** Domain deletion not implemented yet ***' ;
return false ; # XXX function aborts here until TODO below is implemented! XXX
# TODO: recursively delete mailboxes, aliases, alias_domains, fetchmail entries etc. before deleting the domain
# TODO: move the needed code from delete.php here
2011-10-16 20:50:33 +02:00
$result = db_delete ( $this -> db_table , $this -> id_field , $this -> username );
2011-10-16 21:33:31 +02:00
if ( $result == 1 ) {
2011-02-14 00:35:49 +01:00
list ( /*NULL*/ , $domain ) = explode ( '@' , $this -> username );
2011-02-15 23:20:27 +01:00
db_log ( $domain , 'delete_domain' , $this -> username ); # TODO delete_domain is not a valid db_log keyword yet because we don't yet log add/delete domain
2011-02-14 00:35:49 +01:00
return true ;
}
}
2010-09-27 01:14:42 +02:00
}
/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */