Merge remote-tracking branch 'svnexport/master'

pull/12/head
David Goodwin 8 years ago
commit 491df198cc

@ -9,6 +9,15 @@
# Last update:
# $Id$
Changes since the 3.0.1 release
-------------------------------------------------
- AliasHandler: restrict mailbox subquery to allowed and specified domains
to improve performance on setups with lots of mailboxes
- allow switching between dovecot:* password schemes while still accepting
passwords hashed using the previous dovecot:* scheme
- FetchmailHandler: use a valid date as default for 'date'
Version 3.0.1 - 2016/09/19 - SVN r1870
-------------------------------------------------

@ -22,7 +22,7 @@ If you need to setup Postfix to be able to handle Virtual Domains and Virtual
Users check out:
- the PostfixAdmin documentation in the DOCUMENTS/ directory
- our wiki at http://sourceforge.net/apps/mediawiki/postfixadmin/
- our wiki at https://sourceforge.net/p/postfixadmin/wiki/
There are also lots of HOWTOs around the web. Be warned that many of them
(even those listed below) may be outdated or incomplete.

@ -262,7 +262,7 @@ function maildir_name_hook($domain, $user) {
PostfixAdmin, but it does not create it in the database. You have to do
that yourself.
Please follow the naming policy for custom database fields and tables on
http://sourceforge.net/apps/mediawiki/postfixadmin/index.php?title=Custom_fields
https://sourceforge.net/p/postfixadmin/wiki/Custom_fields/
to avoid clashes with future versions of PostfixAdmin.
See initStruct() in the *Handler class for the default $struct.

@ -933,7 +933,9 @@ function pacrypt ($pw, $pw_db="") {
elseif (preg_match("/^dovecot:/", $CONF['encrypt'])) {
$split_method = preg_split ('/:/', $CONF['encrypt']);
$method = strtoupper($split_method[1]); # TODO: if $pw_db starts with {method}, change $method accordingly
$method = strtoupper($split_method[1]);
# If $pw_db starts with {method}, change $method accordingly
if (!empty($pw_db) && preg_match('/^\{([A-Z0-9.-]+)\}.+/', $pw_db, $method_matches)) { $method = $method_matches[1]; }
if (! preg_match("/^[A-Z0-9.-]+$/", $method)) { die("invalid dovecot encryption method"); } # TODO: check against a fixed list?
# if (strtolower($method) == 'md5-crypt') die("\$CONF['encrypt'] = 'dovecot:md5-crypt' will not work because dovecotpw generates a random salt each time. Please use \$CONF['encrypt'] = 'md5crypt' instead.");
# $crypt_method = preg_match ("/.*-CRYPT$/", $method);
@ -1686,11 +1688,13 @@ function db_in_clause($field, $values) {
* db_where_clause
* Action: builds and returns a WHERE clause for database queries. All given conditions will be AND'ed.
* Call: db_where_clause (array $conditions, array $struct)
* param array $conditios: array('field' => 'value', 'field2' => 'value2, ...)
* param array $condition: array('field' => 'value', 'field2' => 'value2, ...)
* param array $struct - field structure, used for automatic bool conversion
* param string $additional_raw_where - raw sniplet to include in the WHERE part - typically needs to start with AND
* param array $searchmode - operators to use (=, <, > etc.) - defaults to = if not specified for a field (see
* $allowed_operators for available operators)
* Note: the $searchmode operator will only be used if a $condition for that field is set.
* This also means you'll need to set a (dummy) condition for NULL and NOTNULL.
*/
function db_where_clause($condition, $struct, $additional_raw_where = '', $searchmode = array()) {
if (!is_array($condition)) {
@ -1703,7 +1707,7 @@ function db_where_clause($condition, $struct, $additional_raw_where = '', $searc
die('db_where_cond: parameter $struct is not an array!');
}
$allowed_operators = explode(' ', '< > >= <= = != <> CONT LIKE');
$allowed_operators = explode(' ', '< > >= <= = != <> CONT LIKE NULL NOTNULL');
$where_parts = array();
$having_parts = array();
@ -1724,7 +1728,15 @@ function db_where_clause($condition, $struct, $additional_raw_where = '', $searc
die('db_where_clause: Invalid searchmode for ' . $field);
}
}
if ($operator == "NULL") {
$querypart = $field . ' IS NULL';
} elseif ($operator == "NOTNULL") {
$querypart = $field . ' IS NOT NULL';
} else {
$querypart = $field . $operator . "'" . escape_string($value) . "'";
}
if($struct[$field]['select'] != '') {
$having_parts[$field] = $querypart;
} else {

@ -136,10 +136,9 @@ $table_alias = table_by_key('alias');
$table_mailbox = table_by_key('mailbox');
if (count($search) == 0 || !isset($search['_'])) {
$list_param = "domain='$fDomain'";
$search_alias = array('domain' => $fDomain);
} else {
$searchterm = escape_string($search['_']);
$list_param = "(address LIKE '%$searchterm%' OR goto LIKE '%$searchterm%')";
$search_alias = array('_' => $search['_']);
}
$handler = new AliasHandler(0, $admin_username);
@ -153,8 +152,8 @@ $alias_data['struct']['goto_mailbox']['display_in_list'] = 0; # not useful/defin
$alias_data['struct']['on_vacation']['display_in_list'] = 0;
$alias_data['msg']['show_simple_search'] = False; # hide search box
$handler->getList($list_param, array(), $page_size, $fDisplay);
$pagebrowser_alias = $handler->getPagebrowser($list_param, array());
$handler->getList($search_alias, array(), $page_size, $fDisplay);
$pagebrowser_alias = $handler->getPagebrowser($search_alias, array());
$tAlias = $handler->result();

@ -42,13 +42,9 @@ class AliasHandler extends PFAHandler {
/*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' ),
/*select*/ 'coalesce(__is_mailbox,0) as is_mailbox' ),
/*extrafrom set via set_is_mailbox_extrafrom() */
'__mailbox_username' => pacol( 0, 0, 1, 'vtxt', '' , '' , 0), # filled via is_mailbox
'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
@ -64,8 +60,37 @@ class AliasHandler extends PFAHandler {
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.
);
$this->set_is_mailbox_extrafrom();
}
/*
* set $this->struct['is_mailbox']['extrafrom'] based on the search conditions.
* If a listing for a specific domain is requested, optimize the subquery to only return mailboxes from that domain.
* This doesn't change the result of the main query, but improves the performance a lot on setups with lots of mailboxes.
* When using this function to optimize the is_mailbox extrafrom, don't forget to reset it to the default value
* (all domains for this admin) afterwards.
*/
private function set_is_mailbox_extrafrom($condition=array(), $searchmode=array()) {
$extrafrom = 'LEFT JOIN ( ' .
' SELECT 1 as __is_mailbox, username as __mailbox_username ' .
' FROM ' . table_by_key('mailbox') .
' WHERE username IS NOT NULL ';
if(isset($condition['domain']) && !isset($searchmode['domain']) && in_array($condition['domain'], $this->allowed_domains)) {
# listing for a specific domain, so restrict subquery to that domain
$extrafrom .= ' AND ' . db_in_clause($this->domain_field, array($condition['domain']));
} else {
# restrict subquery to all domains accessible to this admin
$extrafrom .= ' AND ' . db_in_clause($this->domain_field, $this->allowed_domains);
}
$extrafrom .= ' ) AS __mailbox ON __mailbox_username = address';
$this->struct['is_mailbox']['extrafrom'] = $extrafrom;
}
protected function initMsg() {
$this->msg['error_already_exists'] = 'email_address_already_exists';
$this->msg['error_does_not_exist'] = 'alias_does_not_exist';
@ -303,22 +328,34 @@ class AliasHandler extends PFAHandler {
return $db_result;
}
public function getList($condition, $searchmode = array(), $limit=-1, $offset=-1) {
private function condition_ignore_mailboxes($condition, $searchmode) {
# only list aliases that do not belong to mailboxes
# TODO: breaks if $condition is an array
if (is_array($condition)) {
$condition['__mailbox_username'] = 1;
$searchmode['__mailbox_username'] = 'NULL';
} else {
if ($condition != '') {
$condition = " AND ( $condition ) ";
$condition = " ( $condition ) AND ";
}
$condition = " $condition __mailbox_username IS NULL ";
}
return parent::getList( "__mailbox_username IS NULL $condition", $searchmode, $limit, $offset);
return array($condition, $searchmode);
}
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 ) ";
public function getList($condition, $searchmode = array(), $limit=-1, $offset=-1) {
list($condition, $searchmode) = $this->condition_ignore_mailboxes($condition, $searchmode);
$this->set_is_mailbox_extrafrom($condition, $searchmode);
$result = parent::getList($condition, $searchmode, $limit, $offset);
$this->set_is_mailbox_extrafrom(); # reset to default
return $result;
}
return parent::getPagebrowser( "__mailbox_username IS NULL $condition", $searchmode);
public function getPagebrowser($condition, $searchmode = array()) {
list($condition, $searchmode) = $this->condition_ignore_mailboxes($condition, $searchmode);
$this->set_is_mailbox_extrafrom($condition, $searchmode);
$result = parent::getPagebrowser($condition, $searchmode);
$this->set_is_mailbox_extrafrom(); # reset to default
return $result;
}

@ -565,7 +565,7 @@ abstract class PFAHandler {
$no = escape_string(Config::lang('NO'));
if (db_pgsql()) {
$formatted_date = "TO_DATE(text(###KEY###), '" . escape_string(Config::Lang('dateformat_pgsql')) . "')";
$formatted_date = "TO_CHAR(###KEY###, '" . escape_string(Config::Lang('dateformat_pgsql')) . "')";
# $base64_decode = "DECODE(###KEY###, 'base64')";
} elseif (db_sqlite()) {
$formatted_date = "strftime(###KEY###, '" . escape_string(Config::Lang('dateformat_mysql')) . "')";

@ -21,7 +21,6 @@ class VacationHandler extends PFAHandler {
'body' => pacol( 1, 1, 0, 'text', 'pUsersVacation_body' , '' , '' ),
'activefrom' => pacol( 1, 1, 1, 'text', 'pUsersVacation_activefrom' , '' , '' ),
'activeuntil' => pacol( 1, 1, 1, 'text', 'pUsersVacation_activeuntil' , '' , '' ),
'cache' => pacol( 0, 0, 0, 'text', '' , '' , '' ), # leftover from 2.2
'active' => pacol( 1, 1, 1, 'bool', 'active' , '' , 1 ),
'created' => pacol( 0, 0, 1, 'ts', 'created' , '' ),
'modified' => pacol( 0, 0, 1, 'ts', 'last_modified' , '' ),
@ -180,7 +179,6 @@ class VacationHandler extends PFAHandler {
'active' => db_get_boolean(true),
'activefrom' => $activeFrom,
'activeuntil' => $activeUntil,
'cache' => '',
);
// is there an entry in the vacaton table for the user, or do we need to insert?

@ -64,6 +64,7 @@
{if $tCanAddMailbox}
<br /><a href="{#url_create_mailbox#}&amp;domain={$fDomain|escape:"url"}" class="button">{$PALANG.add_mailbox}</a><br />
{/if}
<br /><br /><a href="list.php?table=mailbox&amp;output=csv">{$PALANG.download_csv}</a>
{/if}
{if $CONF.show_status===YES && $CONF.show_status_key===YES}
<br/><br/>

@ -1619,14 +1619,14 @@ function upgrade_1824_sqlite() {
function upgrade_1835_mysql() {
# change default values for existing datetime fields with a 0000-00-00 default to {DATETIME}
foreach (array('admin', 'alias', 'alias_domain', 'domain', 'mailbox', 'domain_admins', 'vacation') as $table_to_change) {
foreach (array('domain_admins', 'vacation') as $table_to_change) {
$table = table_by_key($table_to_change);
db_query_parsed("ALTER TABLE `$table` CHANGE `created` `created` {DATETIME}");
}
foreach (array('admin', 'alias', 'alias_domain', 'domain', 'mailbox') as $table_to_change) {
$table = table_by_key($table_to_change);
db_query_parsed("ALTER TABLE `$table` CHANGE `modified` `modified` {DATETIME}");
db_query_parsed("ALTER TABLE `$table` CHANGE `created` `created` {DATETIME}, CHANGE `modified` `modified` {DATETIME}");
}
$table = table_by_key('log');

Loading…
Cancel
Save