2009-03-13 21:48:24 +01:00
< ? php
2011-02-28 00:21:54 +01:00
# $Id$
2009-03-13 21:48:24 +01:00
/**
* Simple class to represent a user .
*/
2012-04-09 17:02:16 +02:00
class MailboxHandler extends PFAHandler {
2013-06-23 17:04:05 +02:00
protected $db_table = 'mailbox' ;
protected $id_field = 'username' ;
2012-04-09 17:02:16 +02:00
protected $domain_field = 'domain' ;
# init $this->struct, $this->db_table and $this->id_field
protected function initStruct () {
$this -> struct = array (
# field name allow display in... type $PALANG label $PALANG description default / options / ...
# editing? form list
2013-02-05 00:18:01 +01:00
'username' => pacol ( $this -> new , 1 , 1 , 'mail' , 'pEdit_mailbox_username' , '' , '' ),
2012-04-10 00:43:30 +02:00
'local_part' => pacol ( $this -> new , 0 , 0 , 'text' , 'pEdit_mailbox_username' , '' , '' ),
'domain' => pacol ( $this -> new , 0 , 0 , 'enum' , '' , '' , '' ,
/*options*/ $this -> allowed_domains ),
2012-12-29 00:48:33 +01:00
# TODO: maildir: display in list is needed to include maildir in SQL result (for post_edit hook)
# TODO: (not a perfect solution, but works for now - maybe we need a separate "include in SELECT query" field?)
2013-02-05 00:18:01 +01:00
'maildir' => pacol ( $this -> new , 0 , 1 , 'text' , '' , '' , '' ),
2013-07-28 21:46:50 +02:00
'password' => pacol ( 1 , 1 , 0 , 'pass' , 'password' , 'pCreate_mailbox_password_text' , '' ),
2013-07-29 00:51:28 +02:00
'password2' => pacol ( 1 , 1 , 0 , 'pass' , 'password_again' , '' , '' ,
2012-04-09 17:02:16 +02:00
/*options*/ '' ,
/*not_in_db*/ 0 ,
/*dont_write_to_db*/ 1 ,
/*select*/ 'password as password2'
),
2013-07-30 00:08:07 +02:00
'name' => pacol ( 1 , 1 , 1 , 'text' , 'name' , 'pCreate_mailbox_name_text' , '' ),
2012-12-29 00:48:33 +01:00
'quota' => pacol ( 1 , 1 , 1 , 'int' , 'pEdit_mailbox_quota' , 'pEdit_mailbox_quota_text' , '' ), # in MB
# read_from_db_postprocess() also sets 'quotabytes' for use in init()
2013-07-28 21:24:00 +02:00
'active' => pacol ( 1 , 1 , 1 , 'bool' , 'active' , '' , 1 ),
2012-04-10 00:43:30 +02:00
'welcome_mail' => pacol ( $this -> new , $this -> new , 0 , 'bool' , 'pCreate_mailbox_mail' , '' , 1 ,
/*options*/ '' ,
/*not_in_db*/ 1 ),
'created' => pacol ( 0 , 0 , 1 , 'ts' , 'created' , '' ),
2013-07-27 23:52:52 +02:00
'modified' => pacol ( 0 , 0 , 1 , 'ts' , 'last_modified' , '' ),
2012-04-09 17:02:16 +02:00
# TODO: add virtual 'notified' column and allow to display who received a vacation response?
);
2013-02-10 00:52:03 +01:00
# update allowed quota
if ( count ( $this -> struct [ 'domain' ][ 'options' ]) > 0 ) $this -> prefill ( 'domain' , $this -> struct [ 'domain' ][ 'options' ][ 0 ]);
2012-04-09 17:02:16 +02:00
}
2012-12-29 00:48:33 +01:00
public function init ( $id ) {
2013-02-10 00:52:03 +01:00
if ( ! parent :: init ( $id )) {
return false ;
}
2012-12-29 00:48:33 +01:00
2013-06-06 00:48:29 +02:00
list ( /*NULL*/ , $domain ) = explode ( '@' , $this -> id );
2012-12-29 00:48:33 +01:00
if ( $this -> new ) {
2013-02-10 00:52:03 +01:00
$currentquota = 0 ;
2012-12-29 00:48:33 +01:00
} else {
2013-10-13 17:26:37 +02:00
$currentquota = $this -> result [ 'quotabytes' ]; # parent::init called ->view()
2012-12-29 00:48:33 +01:00
}
2013-02-10 00:52:03 +01:00
$this -> updateMaxquota ( $domain , $currentquota );
return true ; # still here? good.
}
/**
* show max allowed quota in quota field description
* @ param string - domain
* @ param int - current quota
*/
protected function updateMaxquota ( $domain , $currentquota ) {
if ( $domain == '' ) return false ;
2013-08-07 22:05:18 +02:00
$maxquota = $this -> allowed_quota ( $domain , $currentquota );
2013-02-10 00:52:03 +01:00
if ( $maxquota == 0 ) {
# TODO: show 'unlimited'
# } elseif ($maxquota < 0) {
# TODO: show 'disabled' - at the moment, just shows '-1'
} else {
2013-10-13 20:11:18 +02:00
$this -> struct [ 'quota' ][ 'desc' ] = Config :: lang_f ( 'mb_max' , $maxquota );
2013-02-10 00:52:03 +01:00
}
2012-12-29 00:48:33 +01:00
}
2012-04-09 17:02:16 +02:00
protected function initMsg () {
2013-07-29 00:51:28 +02:00
$this -> msg [ 'error_already_exists' ] = 'email_address_already_exists' ;
2012-04-09 17:02:16 +02:00
$this -> msg [ 'error_does_not_exist' ] = 'pCreate_mailbox_username_text_error1' ;
if ( $this -> new ) {
$this -> msg [ 'logname' ] = 'create_mailbox' ;
$this -> msg [ 'store_error' ] = 'pCreate_mailbox_result_error' ;
2013-02-16 21:42:17 +01:00
$this -> msg [ 'successmessage' ] = 'pCreate_mailbox_result_success' ;
2012-04-09 17:02:16 +02:00
} else {
$this -> msg [ 'logname' ] = 'edit_mailbox' ;
$this -> msg [ 'store_error' ] = 'pCreate_mailbox_result_error' ; # TODO: better error message
2013-02-16 21:42:17 +01:00
$this -> msg [ 'successmessage' ] = 'pCreate_mailbox_result_success' ; # TODO: better message
2012-04-09 17:02:16 +02:00
}
}
public function webformConfig () {
2012-04-10 00:43:30 +02:00
if ( $this -> new ) { # the webform will display a local_part field + domain dropdown on $new
$this -> struct [ 'username' ][ 'display_in_form' ] = 0 ;
$this -> struct [ 'local_part' ][ 'display_in_form' ] = 1 ;
$this -> struct [ 'domain' ][ 'display_in_form' ] = 1 ;
}
return array (
2012-04-09 17:02:16 +02:00
# $PALANG labels
'formtitle_create' => 'pCreate_mailbox_welcome' ,
'formtitle_edit' => 'pEdit_mailbox_welcome' ,
2013-07-29 00:51:28 +02:00
'create_button' => 'add_mailbox' ,
2012-04-09 17:02:16 +02:00
# various settings
'required_role' => 'admin' ,
2013-01-27 20:52:19 +01:00
'listview' => 'list-virtual.php' ,
'early_init' => 0 ,
'prefill' => array ( 'domain' ),
2012-04-09 17:02:16 +02:00
);
}
protected function validate_new_id () {
if ( $this -> id == '' ) {
2013-10-13 20:11:18 +02:00
$this -> errormsg [ $this -> id_field ] = Config :: lang ( 'pCreate_mailbox_username_text_error1' );
2012-04-09 17:02:16 +02:00
return false ;
}
2013-04-01 23:22:30 +02:00
$email_check = check_email ( $this -> id );
if ( $email_check != '' ) {
$this -> errormsg [ $this -> id_field ] = $email_check ;
2013-02-05 00:18:01 +01:00
return false ;
}
list ( /*NULL*/ , $domain ) = explode ( '@' , $this -> id );
2012-04-09 17:02:16 +02:00
if ( ! $this -> create_allowed ( $domain )) {
2013-10-13 20:11:18 +02:00
$this -> errormsg [] = Config :: lang ( 'pCreate_mailbox_username_text_error3' );
2012-04-09 17:02:16 +02:00
return false ;
}
# check if an alias with this name already exists - if yes, don't allow to create the mailbox
$handler = new AliasHandler ( 1 );
if ( ! $handler -> init ( $this -> id )) {
2013-10-13 20:11:18 +02:00
$this -> errormsg [] = Config :: lang ( 'email_address_already_exists' );
2012-04-09 17:02:16 +02:00
return false ;
}
2013-02-05 00:18:01 +01:00
return true ; # still here? good!
2012-04-09 17:02:16 +02:00
}
/**
* check number of existing mailboxes for this domain - is one more allowed ?
*/
private function create_allowed ( $domain ) {
$limit = get_domain_properties ( $domain );
2009-03-16 20:49:36 +01:00
2012-04-09 17:02:16 +02:00
if ( $limit [ 'mailboxes' ] == 0 ) return true ; # unlimited
if ( $limit [ 'mailboxes' ] < 0 ) return false ; # disabled
if ( $limit [ 'mailbox_count' ] >= $limit [ 'mailboxes' ]) return false ;
return true ;
}
2011-10-11 00:15:16 +02:00
2012-04-10 00:43:30 +02:00
/**
* merge local_part and domain to address
* called by edit . php ( if id_field is editable and hidden in editform ) _before_ -> init
*/
public function mergeId ( $values ) {
if ( $this -> struct [ 'local_part' ][ 'display_in_form' ] == 1 && $this -> struct [ 'domain' ][ 'display_in_form' ]) { # webform mode - combine to 'address' field
return $values [ 'local_part' ] . '@' . $values [ 'domain' ];
} else {
return $values [ $this -> id_field ];
}
}
2009-03-16 20:49:36 +01:00
2012-12-29 00:48:33 +01:00
protected function read_from_db_postprocess ( $db_result ) {
foreach ( $db_result as $key => $row ) {
$db_result [ $key ][ 'quotabytes' ] = $row [ 'quota' ];
$db_result [ $key ][ 'quota' ] = divide_quota ( $row [ 'quota' ]); # convert quota to MB
}
return $db_result ;
}
2013-02-05 00:18:01 +01:00
protected function beforestore () {
if ( isset ( $this -> values [ 'quota' ]) && $this -> values [ 'quota' ] != - 1 ) {
$this -> values [ 'quota' ] = $this -> values [ 'quota' ] * Config :: read ( 'quota_multiplier' ); # convert quota from MB to bytes
}
2013-04-01 21:57:25 +02:00
$ah = new AliasHandler ( $this -> new , $this -> admin_username );
2013-02-05 00:18:01 +01:00
2013-04-01 21:57:25 +02:00
$ah -> calledBy ( 'MailboxHandler' );
2013-02-05 00:18:01 +01:00
2013-04-01 21:57:25 +02:00
if ( ! $ah -> init ( $this -> id ) ) {
2013-05-01 21:05:32 +02:00
$arraykeys = array_keys ( $ah -> errormsg );
$this -> errormsg [] = $ah -> errormsg [ $arraykeys [ 0 ]]; # TODO: implement this as PFAHandler->firstErrormsg()
2013-04-01 21:57:25 +02:00
return false ;
}
2013-02-05 00:18:01 +01:00
2013-04-01 21:57:25 +02:00
$alias_data = array ();
2013-02-05 00:18:01 +01:00
2013-04-01 21:57:25 +02:00
if ( isset ( $this -> values [ 'active' ])) { # might not be set in edit mode
$alias_data [ 'active' ] = $this -> values [ 'active' ];
}
2013-02-05 00:18:01 +01:00
2013-04-01 21:57:25 +02:00
if ( $this -> new ) {
2013-06-11 00:18:53 +02:00
$alias_data [ 'goto' ] = array ( $this -> id ); # 'goto_mailbox' = 1; # would be technically correct, but setting 'goto' is easier
2013-04-01 21:57:25 +02:00
}
if ( ! $ah -> set ( $alias_data )) {
$this -> errormsg [] = $ah -> errormsg [ 0 ];
return false ;
}
if ( ! $ah -> store ()) {
$this -> errormsg [] = $ah -> errormsg [ 0 ];
return false ;
2013-02-05 00:18:01 +01:00
}
2012-12-29 00:48:33 +01:00
2013-02-05 00:18:01 +01:00
return true ; # still here? good!
}
2012-12-29 00:48:33 +01:00
protected function storemore () {
2013-02-05 00:18:01 +01:00
2013-08-07 22:39:37 +02:00
if ( $this -> new ) {
2013-02-05 00:18:01 +01:00
2013-08-07 22:39:37 +02:00
if ( ! $this -> mailbox_post_script () ) {
2013-02-05 00:18:01 +01:00
# return false; # TODO: should this be fatal?
}
if ( $this -> values [ 'welcome_mail' ] == true ) {
if ( ! $this -> send_welcome_mail () ) {
# return false; # TODO: should this be fatal?
}
}
2013-08-07 23:46:53 +02:00
if ( ! $this -> create_mailbox_subfolders () ) {
2013-02-05 00:18:01 +01:00
# TODO: implement $tShowpass
2013-10-13 20:11:18 +02:00
$this -> infomsg [] = Config :: lang_f ( 'pCreate_mailbox_result_succes_nosubfolders' , " $fUsername $tShowpass " );
2013-02-05 00:18:01 +01:00
} else { # everything ok
# TODO: implement $tShowpass
2013-10-13 20:11:18 +02:00
# $this->infomsg[] = Config::lang_f('pCreate_mailbox_result_success'], "$fUsername$tShowpass");
2013-02-05 00:18:01 +01:00
# TODO: currently edit.php displays the default success message from webformConfig
}
} else { # edit mode
2013-06-23 22:23:02 +02:00
# alias active status is updated in before_store()
2013-01-27 20:52:19 +01:00
2012-12-29 00:48:33 +01:00
# postedit hook
2013-02-05 00:18:01 +01:00
# TODO: implement a poststore() function? - would make handling of old and new values much easier...
2012-12-29 00:48:33 +01:00
$old_mh = new MailboxHandler ();
if ( ! $old_mh -> init ( $this -> id )) {
$this -> errormsg [] = $old_mh -> errormsg [ 0 ];
} elseif ( ! $old_mh -> view ()) {
$this -> errormsg [] = $old_mh -> errormsg [ 0 ];
} else {
$oldvalues = $old_mh -> result ();
$maildir = $oldvalues [ 'maildir' ];
if ( isset ( $this -> values [ 'quota' ])) {
$quota = $this -> values [ 'quota' ];
} else {
$quota = $oldvalues [ 'quota' ];
}
2013-08-07 22:39:37 +02:00
if ( ! $this -> mailbox_post_script () ) {
# TODO: should this be fatal?
2012-12-29 00:48:33 +01:00
}
}
}
return true ; # even if a hook failed, mark the overall operation as OK
}
2012-04-09 17:02:16 +02:00
/* function already exists ( see old code below
public function delete () {
$this -> errormsg [] = '*** deletion not implemented yet ***' ;
return false ; # XXX function aborts here! XXX
2010-12-17 23:53:46 +01:00
}
2012-04-09 17:02:16 +02:00
*/
2013-02-10 00:52:03 +01:00
protected function _prefill_domain ( $field , $val ) {
if ( in_array ( $val , $this -> struct [ $field ][ 'options' ])) {
$this -> struct [ $field ][ 'default' ] = $val ;
$this -> updateMaxquota ( $val , 0 );
}
}
2012-12-29 00:48:33 +01:00
/**
* check if quota is allowed
*/
2013-11-08 22:26:46 +01:00
protected function _validate_quota ( $field , $val ) {
2013-08-07 22:58:02 +02:00
if ( ! $this -> check_quota ( $val ) ) {
2013-10-13 20:11:18 +02:00
$this -> errormsg [ $field ] = Config :: lang ( 'pEdit_mailbox_quota_text_error' );
2012-12-29 00:48:33 +01:00
return false ;
}
2013-02-05 00:18:01 +01:00
return true ;
2012-12-29 00:48:33 +01:00
}
2013-02-19 23:48:02 +01:00
/**
* - compare password / password2 field ( error message will be displayed at password2 field )
* - autogenerate password if enabled in config and $new
* - display password on $new if enabled in config or autogenerated
*/
2013-11-08 22:26:46 +01:00
protected function _validate_password ( $field , $val ) {
if ( ! $this -> _validate_password2 ( $field , $val )) return false ;
2013-02-19 23:48:02 +01:00
if ( $this -> new && Config :: read ( 'generate_password' ) == 'YES' && $val == '' ) {
# auto-generate new password
unset ( $this -> errormsg [ $field ]); # remove "password too short" error message
$val = generate_password ();
$this -> values [ $field ] = $val ; # we are doing this "behind the back" of set()
$this -> infomsg [] = " Password: $val " ; # TODO: make translateable
return false ; # to avoid that set() overwrites $this->values[$field]
} elseif ( $this -> new && Config :: read ( 'show_password' ) == 'YES' ) {
$this -> infomsg [] = " Password: $val " ; # TODO: make translateable
}
2013-02-26 01:07:34 +01:00
return true ; # still here? good.
2013-02-19 23:48:02 +01:00
}
2012-04-10 00:43:30 +02:00
/**
* compare password / password2 field
* error message will be displayed at the password2 field
*/
2013-11-08 22:26:46 +01:00
protected function _validate_password2 ( $field , $val ) {
2012-04-10 00:43:30 +02:00
return $this -> compare_password_fields ( 'password' , 'password2' );
}
2013-02-05 00:18:01 +01:00
/**
* on $this -> new , set localpart based on address
*/
protected function _missing_local_part ( $field ) {
list ( $local_part , $domain ) = explode ( '@' , $this -> id );
2013-02-25 21:23:00 +01:00
$this -> RAWvalues [ 'local_part' ] = $local_part ;
2013-02-05 00:18:01 +01:00
}
/**
* on $this -> new , set domain based on address
*/
protected function _missing_domain ( $field ) {
list ( $local_part , $domain ) = explode ( '@' , $this -> id );
2013-02-25 21:23:00 +01:00
$this -> RAWvalues [ 'domain' ] = $domain ;
2013-02-05 00:18:01 +01:00
}
/**
* calculate maildir path for the mailbox
*/
protected function _missing_maildir ( $field ) {
list ( $local_part , $domain ) = explode ( '@' , $this -> id );
2013-10-13 22:07:34 +02:00
$maildir_name_hook = Config :: read ( 'maildir_name_hook' );
if ( $maildir_name_hook != 'NO' && function_exists ( $maildir_name_hook ) ) {
$maildir = $maildir_name_hook ( $domain , $this -> id );
} elseif ( Config :: bool ( 'domain_path' )) {
if ( Config :: bool ( 'domain_in_mailbox' )) {
2013-02-05 00:18:01 +01:00
$maildir = $domain . " / " . $this -> id . " / " ;
} else {
$maildir = $domain . " / " . $local_part . " / " ;
}
} else {
# If $CONF['domain_path'] is set to NO, $CONF['domain_in_mailbox] is forced to YES.
# Otherwise user@example.com and user@foo.bar would be mixed up in the same maildir "user/".
$maildir = $this -> id . " / " ;
}
$this -> RAWvalues [ 'maildir' ] = $maildir ;
}
private function send_welcome_mail () {
$fTo = $this -> id ;
$fFrom = smtp_get_admin_email ();
if ( empty ( $fFrom ) || $fFrom == 'CLI' ) $fFrom = $this -> id ;
2013-10-13 20:11:18 +02:00
$fSubject = Config :: lang ( 'pSendmail_subject_text' );
2013-02-05 00:18:01 +01:00
$fBody = Config :: read ( 'welcome_text' );
if ( ! smtp_mail ( $fTo , $fFrom , $fSubject , $fBody )) {
2013-10-13 20:11:18 +02:00
$this -> errormsg [] = Config :: lang ( 'pSendmail_result_error' );
2013-02-05 00:18:01 +01:00
return false ;
} else {
# TODO flash_info($PALANG['pSendmail_result_success']);
}
return true ;
}
2012-04-09 17:02:16 +02:00
2013-08-07 22:05:18 +02:00
/**
* Check if the user is creating a mailbox within the quota limits of the domain
*
* @ param Integer $quota - quota wanted for the mailbox
* @ return Boolean - true if requested quota is OK , otherwise false
*/
# TODO: merge with allowed_quota?
2013-08-07 22:58:02 +02:00
protected function check_quota ( $quota ) {
2013-08-07 22:05:18 +02:00
$rval = false ;
if ( ! Config :: bool ( 'quota' ) ) {
return true ; # enforcing quotas is disabled - just allow it
}
2013-08-07 22:58:02 +02:00
list ( /*NULL*/ , $domain ) = explode ( '@' , $this -> id );
2013-08-07 22:05:18 +02:00
$limit = get_domain_properties ( $domain );
if ( $limit [ 'maxquota' ] == 0 ) {
$rval = true ; # maxquota unlimited -> OK, but domain level quota could still be hit
}
if (( $limit [ 'maxquota' ] < 0 ) and ( $quota < 0 )) {
return true ; # maxquota and $quota are both disabled -> OK, no need for more checks
}
if (( $limit [ 'maxquota' ] > 0 ) and ( $quota == 0 )) {
return false ; # mailbox with unlimited quota on a domain with maxquota restriction -> not allowed, no more checks needed
}
if ( $limit [ 'maxquota' ] != 0 && $quota > $limit [ 'maxquota' ]) {
return false ; # mailbox bigger than maxquota restriction (and maxquota != unlimited) -> not allowed, no more checks needed
} else {
$rval = true ; # mailbox size looks OK, but domain level quota could still be hit
}
if ( ! $rval ) {
return false ; # over quota - no need to check domain_quota
}
# TODO: detailed error message ("domain quota exceeded", "mailbox quota too big" etc.) via flash_error? Or "available quota: xxx MB"?
if ( ! Config :: bool ( 'domain_quota' ) ) {
return true ; # enforcing domain_quota is disabled - just allow it
} elseif ( $limit [ 'quota' ] <= 0 ) { # TODO: CHECK - 0 (unlimited) is fine, not sure about <= -1 (disabled)...
$rval = true ;
} else {
$table_mailbox = table_by_key ( 'mailbox' );
$query = " SELECT SUM(quota) FROM $table_mailbox WHERE domain = ' " . escape_string ( $domain ) . " ' " ;
2013-08-07 22:58:02 +02:00
$query .= " AND username != ' " . escape_string ( $this -> id ) . " ' " ;
2013-08-07 22:05:18 +02:00
$result = db_query ( $query );
$row = db_row ( $result [ 'result' ]);
$cur_quota_total = divide_quota ( $row [ 0 ]); # convert to MB
if ( ( $quota + $cur_quota_total ) > $limit [ 'quota' ] ) {
$rval = false ;
} else {
$rval = true ;
}
}
return $rval ;
2013-08-07 22:58:02 +02:00
}
2013-08-07 22:05:18 +02:00
/**
* Get allowed maximum quota for a mailbox
*
* @ param String $domain
* @ param Integer $current_user_quota ( in bytes )
* @ return Integer allowed maximum quota ( in MB )
*/
2013-08-07 22:58:02 +02:00
protected function allowed_quota ( $domain , $current_user_quota ) {
2013-08-07 22:05:18 +02:00
if ( ! Config :: bool ( 'quota' ) ) {
return 0 ; # quota disabled means no limits - no need for more checks
}
$domain_properties = get_domain_properties ( $domain );
$tMaxquota = $domain_properties [ 'maxquota' ];
if ( Config :: bool ( 'domain_quota' ) && $domain_properties [ 'quota' ]) {
$dquota = $domain_properties [ 'quota' ] - $domain_properties [ 'total_quota' ] + divide_quota ( $current_user_quota );
if ( $dquota < $tMaxquota ) {
$tMaxquota = $dquota ;
}
if ( $tMaxquota == 0 ) {
$tMaxquota = $dquota ;
}
}
return $tMaxquota ;
}
/**
2013-08-07 22:39:37 +02:00
* Called after a mailbox has been created or edited in the DBMS .
2013-08-07 22:05:18 +02:00
*
* @ return Boolean success / failure status
*/
2013-08-07 22:58:02 +02:00
protected function mailbox_post_script () {
2013-08-07 22:05:18 +02:00
2013-08-07 22:39:37 +02:00
if ( $this -> new ) {
$cmd = Config :: read ( 'mailbox_postcreation_script' );
$warnmsg = 'WARNING: Problems running mailbox postcreation script!' ; # TODO: make translateable
} else {
$cmd = Config :: read ( 'mailbox_postedit_script' );
$warnmsg = 'WARNING: Problems running mailbox postedit script!' ; # TODO: make translateable
2013-08-07 22:05:18 +02:00
}
2013-08-07 22:39:37 +02:00
if ( empty ( $cmd ) ) return TRUE ; # nothing to do
2013-08-07 22:05:18 +02:00
2013-08-07 22:39:37 +02:00
list ( /*NULL*/ , $domain ) = explode ( '@' , $this -> id );
$quota = $this -> values [ 'quota' ];
if ( empty ( $this -> id ) || empty ( $domain ) || empty ( $this -> values [ 'maildir' ]) ) {
2013-08-07 22:05:18 +02:00
trigger_error ( 'In ' . __FUNCTION__ . ': empty username, domain and/or maildir parameter' , E_USER_ERROR );
return FALSE ;
}
2013-08-07 22:39:37 +02:00
$cmdarg1 = escapeshellarg ( $this -> id );
2013-08-07 22:05:18 +02:00
$cmdarg2 = escapeshellarg ( $domain );
2013-08-07 22:39:37 +02:00
$cmdarg3 = escapeshellarg ( $this -> values [ 'maildir' ]);
if ( $quota <= 0 ) $quota = 0 ; # TODO: check if this is correct behaviour
2013-08-07 22:05:18 +02:00
$cmdarg4 = escapeshellarg ( $quota );
2013-08-07 22:39:37 +02:00
$command = " $cmd $cmdarg1 $cmdarg2 $cmdarg3 $cmdarg4 " ;
2013-08-07 22:05:18 +02:00
$retval = 0 ;
$output = array ();
$firstline = '' ;
$firstline = exec ( $command , $output , $retval );
if ( 0 != $retval ) {
error_log ( " Running $command yielded return value= $retval , first line of output= $firstline " );
2013-08-07 22:39:37 +02:00
$this -> errormsg [] = $warnmsg ;
2013-08-07 22:05:18 +02:00
return FALSE ;
}
return TRUE ;
}
/**
2013-08-07 22:39:37 +02:00
* Called by storemore () after a mailbox has been created .
* Immediately returns , unless configuration indicates
2013-08-07 22:05:18 +02:00
* that one or more sub - folders should be created .
*
* Triggers E_USER_ERROR if configuration error is detected .
*
* If IMAP login fails , the problem is logged to the system log
* ( such as / var / log / httpd / error_log ), and the function returns
* FALSE .
*
* Doesn ' t clean up , if only some of the folders could be
* created .
*
* @ return Boolean TRUE if everything succeeds , FALSE on all errors
*/
2013-08-07 22:58:02 +02:00
protected function create_mailbox_subfolders () {
2013-08-07 22:05:18 +02:00
$create_mailbox_subdirs = Config :: read ( 'create_mailbox_subdirs' );
if ( empty ( $create_mailbox_subdirs ) ) return TRUE ;
if ( ! is_array ( $create_mailbox_subdirs ) ) {
trigger_error ( 'create_mailbox_subdirs must be an array' , E_USER_ERROR );
return FALSE ;
}
$s_host = Config :: read ( 'create_mailbox_subdirs_host' );
if ( empty ( $s_host ) ) {
trigger_error ( 'An IMAP/POP server host ($CONF["create_mailbox_subdirs_host"]) must be configured, if sub-folders are to be created' , E_USER_ERROR );
return FALSE ;
}
$s_options = '' ;
$create_mailbox_subdirs_hostoptions = Config :: read ( 'create_mailbox_subdirs_hostoptions' );
if ( ! empty ( $create_mailbox_subdirs_hostoptions )) {
if ( ! is_array ( $create_mailbox_subdirs_hostoptions ) ) {
trigger_error ( 'The $CONF["create_mailbox_subdirs_hostoptions"] parameter must be an array' , E_USER_ERROR );
return FALSE ;
}
foreach ( $create_mailbox_subdirs_hostoptions as $o ) {
$s_options .= '/' . $o ;
}
}
$s_port = '' ;
$create_mailbox_subdirs_hostport = Config :: read ( 'create_mailbox_subdirs_hostport' );
if ( ! empty ( $create_mailbox_subdirs_hostport ) ) {
$s_port = $create_mailbox_subdirs_hostport ;
if ( intval ( $s_port ) != $s_port ) {
trigger_error ( 'The $CONF["create_mailbox_subdirs_hostport"] parameter must be an integer' , E_USER_ERROR );
return FALSE ;
}
$s_port = ':' . $s_port ;
}
$s = '{' . $s_host . $s_port . $s_options . '}' ;
sleep ( 1 ); # give the mail triggering the mailbox creation a chance to do its job
2013-08-07 22:58:02 +02:00
$i =@ imap_open ( $s , $this -> id , $this -> values [ 'password' ]);
2013-08-07 22:05:18 +02:00
if ( FALSE == $i ) {
error_log ( 'Could not log into IMAP/POP server: ' . imap_last_error ());
return FALSE ;
}
$s_prefix = Config :: read ( 'create_mailbox_subdirs_prefix' );
foreach ( $create_mailbox_subdirs as $f ) {
$f = '{' . $s_host . '}' . $s_prefix . $f ;
$res = imap_createmailbox ( $i , $f );
if ( ! $res ) {
error_log ( 'Could not create IMAP folder $f: ' . imap_last_error ());
@ imap_close ( $i );
return FALSE ;
}
@ imap_subscribe ( $i , $f );
}
@ imap_close ( $i );
return TRUE ;
}
2012-04-09 17:02:16 +02:00
/********************************************************************************************************************
old functions - we ' ll see what happens to them
( at least they should use the * Handler functions instead of doing SQL )
/********************************************************************************************************************/
2010-12-17 23:53:46 +01:00
2009-03-13 21:48:24 +01:00
/**
2011-10-11 00:15:16 +02:00
* @ return boolean true on success ; false on failure
2009-03-13 21:48:24 +01:00
* @ param string $old_password
* @ param string $new_passwords
2010-12-25 23:29:44 +01:00
* @ param bool $match = true
2009-03-13 21:48:24 +01:00
*
* All passwords need to be plain text ; they ' ll be hashed appropriately
* as per the configuration in config . inc . php
*/
2010-12-17 23:53:46 +01:00
public function change_pw ( $new_password , $old_password , $match = true ) {
2012-04-09 17:02:16 +02:00
list ( /*NULL*/ , $domain ) = explode ( '@' , $this -> id );
2011-10-11 00:15:16 +02:00
2010-12-17 23:53:46 +01:00
if ( $match == true ) {
2012-04-09 17:02:16 +02:00
if ( ! $this -> login ( $this -> id , $old_password )) {
db_log ( $domain , 'edit_password' , " MATCH FAILURE: " . $this -> id );
2010-12-25 23:29:44 +01:00
$this -> errormsg [] = 'Passwords do not match' ; # TODO: make translatable
return false ;
2012-04-09 17:02:16 +02:00
}
2010-12-17 23:53:46 +01:00
}
2011-10-11 00:15:16 +02:00
2010-12-17 23:53:46 +01:00
$set = array (
2010-12-31 21:13:53 +01:00
'password' => pacrypt ( $new_password ) ,
2010-12-25 23:29:44 +01:00
);
2010-12-26 21:35:00 +01:00
2012-04-09 17:02:16 +02:00
$result = db_update ( 'mailbox' , 'username' , $this -> id , $set );
2009-03-13 21:48:24 +01:00
2010-12-17 23:53:46 +01:00
if ( $result != 1 ) {
2012-04-09 17:02:16 +02:00
db_log ( $domain , 'edit_password' , " FAILURE: " . $this -> id );
2013-10-13 20:11:18 +02:00
$this -> errormsg [] = Config :: lang ( 'pEdit_mailbox_result_error' );
2010-12-25 23:29:44 +01:00
return false ;
2010-12-17 23:53:46 +01:00
}
2011-10-11 00:15:16 +02:00
2012-04-09 17:02:16 +02:00
db_log ( $domain , 'edit_password' , $this -> id );
2010-12-25 23:29:44 +01:00
return true ;
2009-03-13 21:48:24 +01:00
}
2010-12-26 23:00:22 +01:00
#TODO: more self explaining language strings!
2010-12-17 23:53:46 +01:00
public function delete () {
2012-04-09 17:02:16 +02:00
$username = $this -> id ;
2010-12-25 23:29:44 +01:00
list ( /*$local_part*/ , $domain ) = explode ( '@' , $username );
2010-12-17 23:53:46 +01:00
2010-12-25 23:29:44 +01:00
$E_username = escape_string ( $username );
$E_domain = escape_string ( $domain );
2011-10-11 00:15:16 +02:00
2010-12-26 23:00:22 +01:00
#TODO: At this level of table by key calls we should think about a solution in our query function and drupal like {mailbox} {alias}.
# Pseudocode for db_query etc.
# if {} in query then
# table_by_key( content between { and } )
# else error
2010-12-17 23:53:46 +01:00
$table_mailbox = table_by_key ( 'mailbox' );
$table_alias = table_by_key ( 'alias' );
$table_vacation = table_by_key ( 'vacation' );
$table_vacation_notification = table_by_key ( 'vacation_notification' );
2010-12-25 23:29:44 +01:00
db_begin ();
2011-10-11 00:15:16 +02:00
#TODO: true/false replacement!
2010-12-25 23:29:44 +01:00
$error = 0 ;
2011-10-30 00:29:16 +02:00
$result = db_query ( " SELECT * FROM $table_alias WHERE address = ' $E_username ' AND domain = ' $E_domain ' " );
2010-12-17 23:53:46 +01:00
if ( $result [ 'rows' ] == 1 ) {
$result = db_delete ( 'alias' , 'address' , $username );
2011-02-15 23:20:27 +01:00
db_log ( $domain , 'delete_alias' , $username );
2010-12-25 23:29:44 +01:00
} else {
$this -> errormsg [] = " no alias $username " ; # todo: better message, make translatable
$error = 1 ;
2010-12-17 23:53:46 +01:00
}
/* is there a mailbox? if do delete it from orbit; it's the only way to be sure */
2011-10-30 00:29:16 +02:00
$result = db_query ( " SELECT * FROM $table_mailbox WHERE username=' $E_username ' AND domain=' $E_domain ' " );
2011-10-11 00:15:16 +02:00
if ( $result [ 'rows' ] == 1 ) {
2010-12-17 23:53:46 +01:00
$result = db_delete ( 'mailbox' , 'username' , $username );
$postdel_res = mailbox_postdeletion ( $username , $domain );
2011-10-11 00:15:16 +02:00
if ( $result != 1 || ! $postdel_res ) {
2010-12-17 23:53:46 +01:00
2013-10-13 20:11:18 +02:00
$tMessage = Config :: lang ( 'pDelete_delete_error' ) . " $username ( " ;
2011-10-11 00:15:16 +02:00
if ( $result [ 'rows' ] != 1 ) { # TODO: invalid test, $result is from db_delete and only contains the number of deleted rows
2010-12-17 23:53:46 +01:00
$tMessage .= 'mailbox' ;
if ( ! $postdel_res ) $tMessage .= ', ' ;
2010-12-25 23:29:44 +01:00
$this -> errormsg [] = " no mailbox $username " ; # todo: better message, make translatable
$error = 1 ;
2010-12-17 23:53:46 +01:00
}
2011-10-11 00:15:16 +02:00
if ( ! $postdel_res ) {
2010-12-17 23:53:46 +01:00
$tMessage .= 'post-deletion' ;
2010-12-25 23:29:44 +01:00
$this -> errormsg [] = " post-deletion script failed " ; # todo: better message, make translatable
$error = 1 ;
2010-12-17 23:53:46 +01:00
}
$this -> errormsg [] = $tMessage . ')' ;
2010-12-25 23:29:44 +01:00
# TODO: does db_rollback(); make sense? Not sure because mailbox_postdeletion was already called (move the call checking the db_delete result?)
# TODO: maybe mailbox_postdeletion should be run after all queries, just before commit/rollback
$error = 1 ;
# return false; # TODO: does this make sense? Or should we still cleanup vacation and vacation_notification?
2010-12-17 23:53:46 +01:00
}
2011-02-15 23:20:27 +01:00
db_log ( $domain , 'delete_mailbox' , $username );
2010-12-25 23:29:44 +01:00
} else {
$this -> errormsg [] = " no mailbox $username " ; # TODO: better message, make translatable
$error = 1 ;
2010-12-17 23:53:46 +01:00
}
2011-10-30 00:29:16 +02:00
$result = db_query ( " SELECT * FROM $table_vacation WHERE email = ' $E_username ' AND domain = ' $E_domain ' " );
2010-12-17 23:53:46 +01:00
if ( $result [ 'rows' ] == 1 ) {
db_delete ( 'vacation' , 'email' , $username );
2010-12-25 23:29:44 +01:00
db_delete ( 'vacation_notification' , 'on_vacation' , $username ); # TODO: delete vacation_notification independent of vacation? (in case of "forgotten" vacation_notification entries)
2010-12-17 23:53:46 +01:00
}
2010-12-25 23:29:44 +01:00
db_commit ();
if ( $error != 0 ) return false ;
return true ;
2010-12-17 23:53:46 +01:00
}
2009-03-13 21:48:24 +01:00
}
2010-12-17 23:53:46 +01:00
/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */