| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 | 
							- <?php
 - # $Id: AliasHandler.php 1777 2015-04-06 22:09:18Z christian_boltz $ 
 - 
 - /** 
 -  * Handlers User level alias actions - e.g. add alias, get aliases, update etc.
 -  * @property $username name of alias
 -  * @property $return return of methods
 -  */
 - class AliasHandler extends PFAHandler {
 - 
 -     protected $db_table = 'alias';
 -     protected $id_field = 'address';
 -     protected $domain_field = 'domain';
 -     protected $searchfields = array('address', 'goto');
 - 
 -     /**
 -      *
 -      * @public
 -      */
 -     public $return = null;
 - 
 -     protected function initStruct() {
 -         # hide 'goto_mailbox' if $this->new
 -         # (for existing aliases, init() hides it for non-mailbox aliases)
 -         $mbgoto = 1 - $this->new;
 - 
 -         $this->struct=array(
 -             # field name                allow       display in...   type    $PALANG label                     $PALANG description                 default / ...
 -             #                           editing?    form    list
 -             'status'        => pacol(   0,          0,      0,      'html', ''                              , ''                                , '', '',
 -                 array('not_in_db' => 1)  ),
 -             'address'       => pacol(   $this->new, 1,      1,      'mail', 'alias'                         , 'pCreate_alias_catchall_text'     ),
 -             'localpart'     => pacol(   $this->new, 0,      0,      'text', 'alias'                         , 'pCreate_alias_catchall_text'     , '', 
 -                 /*options*/ '', 
 -                 /*not_in_db*/ 1                         ),
 -             'domain'        => pacol(   $this->new, 0,      1,      'enum', ''                              , ''                                , '', 
 -                 /*options*/ $this->allowed_domains      ),
 -             'goto'          => pacol(   1,          1,      1,      'txtl', 'to'                            , 'pEdit_alias_help'                , array() ),
 -             'is_mailbox'    => pacol(   0,          0,      1,      'int', ''                             , ''                                , 0 ,
 -                 # technically 'is_mailbox' is bool, but the automatic bool conversion breaks the query. Flagging it as int avoids this problem.
 -                 # Maybe having a vbool type (without the automatic conversion) would be cleaner - we'll see if we need it.
 -                 /*options*/ '',
 -                 /*not_in_db*/ 0,
 -                 /*dont_write_to_db*/ 1,
 -                 /*select*/ 'coalesce(__is_mailbox,0) as is_mailbox, __mailbox_username', 
 -                            # __mailbox_username is unused, but needed as workaround for a MariaDB bug
 -                 /*extrafrom*/ 'LEFT JOIN ( ' .
 -                     ' SELECT 1 as __is_mailbox, username as __mailbox_username ' .
 -                     ' FROM ' . table_by_key('mailbox') .
 -                     ' WHERE username IS NOT NULL ' .
 -                     ' ) AS __mailbox ON __mailbox_username = address' ),
 -             'goto_mailbox'  => pacol(   $mbgoto,    $mbgoto,$mbgoto,'bool', 'pEdit_alias_forward_and_store' , ''                                , 0,
 -                 /*options*/ '',
 -                 /*not_in_db*/ 1                         ), # read_from_db_postprocess() sets the value
 -             'on_vacation'   => pacol(   1,          0,      1,      'bool', 'pUsersMenu_vacation'           , ''                                , 0 ,
 -                 /*options*/ '', 
 -                 /*not_in_db*/ 1                         ), # read_from_db_postprocess() sets the value - TODO: read active flag from vacation table instead?
 -             'created'       => pacol(   0,          0,      0,      'ts',   'created'                       , ''                                ),
 -             'modified'      => pacol(   0,          0,      1,      'ts',   'last_modified'                 , ''                                ),
 -             'active'        => pacol(   1,          1,      1,      'bool', 'active'                        , ''                                , 1     ),
 -             '_can_edit'     => pacol(   0,          0,      1,      'vnum', ''                              , ''                                , 0 , '',
 -                 array('select' => '1 as _can_edit')  ),
 -             '_can_delete'   => pacol(   0,          0,      1,      'vnum', ''                              , ''                                , 0 , '',
 -                 array('select' => '1 as _can_delete')  ), # read_from_db_postprocess() updates the value
 -                 # aliases listed in $CONF[default_aliases] are read-only for domain admins if $CONF[special_alias_control] is NO.
 -         );
 -     }
 - 
 -     protected function initMsg() {
 -         $this->msg['error_already_exists'] = 'email_address_already_exists';
 -         $this->msg['error_does_not_exist'] = 'alias_does_not_exist';
 -         $this->msg['confirm_delete'] = 'confirm_delete_alias';
 -         $this->msg['list_header'] = 'pOverview_alias_title';
 - 
 -         if ($this->new) {
 -             $this->msg['logname'] = 'create_alias';
 -             $this->msg['store_error'] = 'pCreate_alias_result_error';
 -             $this->msg['successmessage'] = 'pCreate_alias_result_success';
 -         } else {
 -             $this->msg['logname'] = 'edit_alias';
 -             $this->msg['store_error'] = 'pEdit_alias_result_error';
 -             $this->msg['successmessage'] = 'alias_updated';
 -         }
 -     }
 - 
 - 
 -     public function webformConfig() {
 -         if ($this->new) { # the webform will display a localpart field + domain dropdown on $new
 -             $this->struct['address']['display_in_form'] = 0;
 -             $this->struct['localpart']['display_in_form'] = 1;
 -             $this->struct['domain']['display_in_form'] = 1;
 -         }
 - 
 -         if (Config::bool('show_status')) {
 -             $this->struct['status']['display_in_list'] = 1;
 -             $this->struct['status']['label'] = ' ';
 -         }
 - 
 -         return array(
 -             # $PALANG labels
 -             'formtitle_create'  => 'pMain_create_alias',
 -             'formtitle_edit'    => 'pEdit_alias_welcome',
 -             'create_button'     => 'add_alias',
 - 
 -             # various settings
 -             'required_role' => 'admin',
 -             'listview'      => 'list-virtual.php',
 -             'early_init'    => 0,
 -             'prefill'       => array('domain'),
 -         );
 -     }
 - 
 -     /**
 -      * AliasHandler needs some special handling in init() and therefore overloads the function.
 -      * It also calls parent::init()
 -      */
 -     public function init($id) {
 -         @list($local_part,$domain) = explode ('@', $id); # supress error message if $id doesn't contain '@'
 - 
 -         if ($local_part == '*') { # catchall - postfix expects '@domain', not '*@domain'
 -             $id = '@' . $domain;
 -         }
 - 
 -         $retval = parent::init($id);
 - 
 -         if (!$retval) return false; # parent::init() failed, no need to continue
 -         
 -         # hide 'goto_mailbox' for non-mailbox aliases
 -         # parent::init called view() before, so we can rely on having $this->result filled
 -         # (only validate_new_id() is called from parent::init and could in theory change $this->result)
 -         if ($this->new || $this->result['is_mailbox'] == 0) {
 -             $this->struct['goto_mailbox']['editable']        = 0;
 -             $this->struct['goto_mailbox']['display_in_form'] = 0;
 -             $this->struct['goto_mailbox']['display_in_list'] = 0;
 -         }
 - 
 -         if ( !$this->new && $this->result['is_mailbox'] && $this->admin_username != ''&& !authentication_has_role('global-admin') ) {
 -             # domain admins are not allowed to change mailbox alias $CONF['alias_control_admin'] = NO
 -             # TODO: apply the same restriction to superadmins?
 -             if (!Config::bool('alias_control_admin')) {
 -                 # TODO: make translateable
 -                 $this->errormsg[] = "Domain administrators do not have the ability to edit user's aliases (check config.inc.php - alias_control_admin)";
 -                 return false;
 -             }
 -         }
 - 
 -         return $retval;
 -     }
 - 
 -     protected function domain_from_id() {
 -         list(/*NULL*/,$domain) = explode('@', $this->id);
 -         return $domain;
 -     }
 - 
 -     protected function validate_new_id() {
 -         if ($this->id == '') {
 -             $this->errormsg[$this->id_field] = Config::lang('pCreate_alias_address_text_error1');
 -             return false;
 -         }
 - 
 -         list($local_part,$domain) = explode ('@', $this->id);
 - 
 -         if(!$this->create_allowed($domain)) {
 -             $this->errormsg[$this->id_field] = Config::lang('pCreate_alias_address_text_error3');
 -             return false;
 -         }
 -  
 -         # TODO: already checked in set() - does it make sense to check it here also? Only advantage: it's an early check
 - #        if (!in_array($domain, $this->allowed_domains)) { 
 - #            $this->errormsg[] = Config::lang('pCreate_alias_address_text_error1');
 - #            return false;
 - #        }
 - 
 -         if ($local_part == '') { # catchall
 -             $valid = true;
 -         } else {
 -             $email_check = check_email($this->id);
 -             if ($email_check == '') {
 -                 $valid = true;
 -             } else {
 -                 $this->errormsg[$this->id_field] = $email_check;
 -                 $valid = false;
 -             }
 -         }
 - 
 -         return $valid;
 -     }
 - 
 -     /**
 -      * check number of existing aliases for this domain - is one more allowed?
 -      */
 -     private function create_allowed($domain) {
 -         if ($this->called_by == 'MailboxHandler') return true; # always allow creating an alias for a mailbox
 - 
 -         $limit = get_domain_properties ($domain);
 - 
 -         if ($limit['aliases'] == 0) return true; # unlimited
 -         if ($limit['aliases'] < 0) return false; # disabled
 -         if ($limit['alias_count'] >= $limit['aliases']) return false;
 -         return true;
 -     }
 - 
 - 
 -    /**
 -     * merge localpart 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['localpart']['display_in_form'] == 1 && $this->struct['domain']['display_in_form']) { # webform mode - combine to 'address' field
 -             if (empty($values['localpart']) || empty($values['domain']) ) { # localpart or domain not set
 -                 return "";
 -             }
 -             if ($values['localpart'] == '*') $values['localpart'] = ''; # catchall
 -             return $values['localpart'] . '@' . $values['domain'];
 -         } else {
 -             return $values[$this->id_field];
 -         }
 -     }
 - 
 -     protected function setmore($values) {
 -         if ($this->new) {
 -             if ($this->struct['address']['display_in_form'] == 1) { # default mode - split off 'domain' field from 'address' # TODO: do this unconditional?
 -                 list(/*NULL*/,$domain) = explode('@', $values['address']);
 -                 $this->values['domain'] = $domain;
 -             }
 -         }
 - 
 -         if (! $this->new) { # edit mode - preserve vacation and mailbox alias if they were included before
 -             $old_ah = new AliasHandler();
 - 
 -             if (!$old_ah->init($this->id)) {
 -                 $this->errormsg[] = $old_ah->errormsg[0];
 -             } elseif (!$old_ah->view()) {
 -                 $this->errormsg[] = $old_ah->errormsg[0];
 -             } else {
 -                 $oldvalues = $old_ah->result();
 - 
 -                 if (!isset($values['goto'])) { # no new value given?
 -                     $values['goto'] = $oldvalues['goto'];
 -                 }
 - 
 -                 if (!isset($values['on_vacation'])) { # no new value given?
 -                     $values['on_vacation'] = $oldvalues['on_vacation'];
 -                 }
 - 
 -                 if ($values['on_vacation']) { 
 -                     $values['goto'][] = $this->getVacationAlias();
 -                 }
 - 
 -                 if ($oldvalues['is_mailbox']) { # alias belongs to a mailbox - add/keep mailbox to/in goto
 -                     if (!isset($values['goto_mailbox'])) { # no new value given?
 -                         $values['goto_mailbox'] = $oldvalues['goto_mailbox'];
 -                     }
 -                     if ($values['goto_mailbox']) {
 -                         $values['goto'][] = $this->id;
 - 
 -                         # if the alias points to the mailbox, don't display the "empty goto" error message
 -                         if (isset($this->errormsg['goto']) && $this->errormsg['goto'] == Config::lang('pEdit_alias_goto_text_error1') ) {
 -                             unset($this->errormsg['goto']);
 -                         }
 -                     }
 -                 }
 -             }
 -         }
 - 
 -         $this->values['goto'] = join(',', $values['goto']);
 -     }
 - 
 -     protected function storemore() {
 -         # TODO: if alias belongs to a mailbox, update mailbox active status
 -         return true;
 -     }
 - 
 -     protected function read_from_db_postprocess($db_result) {
 -         foreach ($db_result as $key => $value) {
 -             # split comma-separated 'goto' into an array
 -             $db_result[$key]['goto'] = explode(',', $db_result[$key]['goto']);
 - 
 -             # Vacation enabled?
 -             list($db_result[$key]['on_vacation'], $db_result[$key]['goto']) = remove_from_array($db_result[$key]['goto'], $this->getVacationAlias() );
 - 
 -             # if it is a mailbox, does the alias point to the mailbox?
 -             if ($db_result[$key]['is_mailbox']) {
 -                 # this intentionally does not match mailbox targets with recipient delimiter.
 -                 # if it would, we would have to make goto_mailbox a text instead of a bool (which would annoy 99% of the users)
 -                 list($db_result[$key]['goto_mailbox'], $db_result[$key]['goto']) = remove_from_array($db_result[$key]['goto'], $key);
 -             } else { # not a mailbox
 -                 $db_result[$key]['goto_mailbox'] = 0;
 -             }
 - 
 -             # editing a default alias (postmaster@ etc.) is only allowed if special_alias_control is allowed or if the user is a superadmin
 -             $tmp = preg_split('/\@/', $db_result[$key]['address']);
 -             if (!$this->is_superadmin && !Config::bool('special_alias_control') && array_key_exists($tmp[0], Config::Read('default_aliases'))) {
 -                         $db_result[$key]['_can_edit'] = 0;
 -                         $db_result[$key]['_can_delete'] = 0;
 -             }
 - 
 -             if ($this->struct['status']['display_in_list'] && Config::Bool('show_status')) {
 -                 $db_result[$key]['status'] = gen_show_status($db_result[$key]['address']);
 -             }
 -         }
 - 
 -         return $db_result;
 -     }
 - 
 -     public function getList($condition, $searchmode = array(), $limit=-1, $offset=-1) {
 -         # only list aliases that do not belong to mailboxes
 -         # TODO: breaks if $condition is an array
 -         if ($condition != '') {
 -             $condition = "  AND ( $condition ) ";
 -         }
 -         return parent::getList( "__mailbox_username IS NULL $condition", $searchmode, $limit, $offset);
 -     }
 - 
 -     public function getPagebrowser($condition, $searchmode = array()) {
 -         # only list aliases that do not belong to mailboxes
 -         # TODO: breaks if $condition is an array
 -         if ($condition != '') {
 -             $condition = "  AND ( $condition ) ";
 -         }
 -         return parent::getPagebrowser( "__mailbox_username IS NULL $condition", $searchmode);
 -     }
 - 
 - 
 - 
 -     protected function _validate_goto($field, $val) {
 -         if (count($val) == 0) {
 -             # empty is ok for mailboxes - this is checked in setmore() which can clear the error message
 -             $this->errormsg[$field] = Config::lang('pEdit_alias_goto_text_error1');
 -             return false;
 -         }
 - 
 -         $errors = array();
 - 
 -         foreach ($val as $singlegoto) {
 -             if (substr($this->id, 0, 1) == '@' && substr($singlegoto, 0, 1) == '@') { # domain-wide forward - check only the domain part
 -                 # only allowed if $this->id is a catchall
 -                 # Note: alias domains are better, but we should keep this way supported for backward compatibility
 -                 #       and because alias domains can't forward to external domains
 -                 list (/*NULL*/, $domain) = explode('@', $singlegoto);
 -                 $domain_check = check_domain($domain);
 -                 if ($domain_check != '') {
 -                      $errors[] = "$singlegoto: $domain_check";
 -                 }
 -             } else {
 -                 $email_check = check_email($singlegoto);
 -                 if ($email_check != '') {
 -                     $errors[] = "$singlegoto: $email_check";
 -                 }
 -             }
 -         }
 - 
 -         if (count($errors)) {
 -             $this->errormsg[$field] = join("   ", $errors); # TODO: find a way to display multiple error messages per field
 -             return false;
 -         } else {
 -             return true;
 -         }
 -     }
 - 
 -     /**
 -      * on $this->new, set localpart based on address
 -      */
 -     protected function _missing_localpart  ($field) {
 -         if (isset($this->RAWvalues['address'])) {
 -             $parts = explode('@', $this->RAWvalues['address']);
 -             if (count($parts) == 2) $this->RAWvalues['localpart'] = $parts[0];
 -         }
 -     }
 - 
 -     /**
 -      * on $this->new, set domain based on address
 -      */
 -     protected function _missing_domain     ($field) {
 -         if (isset($this->RAWvalues['address'])) {
 -             $parts = explode('@', $this->RAWvalues['address']);
 -             if (count($parts) == 2) $this->RAWvalues['domain'] = $parts[1];
 -         }
 -     }
 - 
 - 
 -      /**
 -      * Returns the vacation alias for this user. 
 -      * i.e. if this user's username was roger@example.com, and the autoreply domain was set to
 -      * autoreply.fish.net in config.inc.php we'd return roger#example.com@autoreply.fish.net
 -      * @return string an email alias.
 -      */
 -     protected function getVacationAlias() {
 -         $vacation_goto = str_replace('@', '#', $this->id); 
 -         return $vacation_goto . '@' . Config::read('vacation_domain');
 -     }
 -  
 -     /**
 -      *  @return true on success false on failure
 -      */
 -     public function delete() {
 -         if( ! $this->view() ) {
 -             $this->errormsg[] = Config::Lang('alias_does_not_exist');
 -             return false;
 -         }
 - 
 -         if ($this->result['is_mailbox']) {
 -             $this->errormsg[] = Config::Lang('mailbox_alias_cant_be_deleted');
 -             return false;
 -         }
 - 
 -         db_delete('alias', 'address', $this->id);
 - 
 -         list(/*NULL*/,$domain) = explode('@', $this->id);
 -         db_log ($domain, 'delete_alias', $this->id);
 -         $this->infomsg[] = Config::Lang_f('pDelete_delete_success', $this->id);
 -         return true;
 -     }
 - 
 - }
 - 
 - /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
 
 
  |