Compare commits

..

6 Commits

Author SHA1 Message Date
Christian Boltz 29f588ae9f branches/ contained several version tags. Moved them to tags/ where they belong.
This affects:
- 2.3beta
- 2.3rcX
- 2.2.1.1
- 2.2.1


git-svn-id: https://svn.code.sf.net/p/postfixadmin/code/tags/postfixadmin-2.3beta@986 a1433add-5e2c-0410-b055-b7f2511e0802
15 years ago
David Goodwin 5e169b9544 debian/changelog: bump up svn number; change date etc
git-svn-id: https://svn.code.sf.net/p/postfixadmin/code/branches/postfixadmin-2.3beta@540 a1433add-5e2c-0410-b055-b7f2511e0802
17 years ago
David Goodwin 74dfe63b9f functions.inc.php: merge in r538 from trunk - remove dev comment
git-svn-id: https://svn.code.sf.net/p/postfixadmin/code/branches/postfixadmin-2.3beta@539 a1433add-5e2c-0410-b055-b7f2511e0802
17 years ago
David Goodwin 07b82d2ead re-creating branch after more updates on trunk
git-svn-id: https://svn.code.sf.net/p/postfixadmin/code/branches/postfixadmin-2.3beta@536 a1433add-5e2c-0410-b055-b7f2511e0802
17 years ago
David Goodwin 316884b6e8 quota_usage.pl: copying in from trunk
git-svn-id: https://svn.code.sf.net/p/postfixadmin/code/branches/postfixadmin-2.3beta@530 a1433add-5e2c-0410-b055-b7f2511e0802
17 years ago
David Goodwin 187e4d9a0b branch to 2.3beta
git-svn-id: https://svn.code.sf.net/p/postfixadmin/code/branches/postfixadmin-2.3beta@528 a1433add-5e2c-0410-b055-b7f2511e0802
17 years ago

@ -1,34 +0,0 @@
name: GitHubBuild
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Validate composer.json and composer.lock
run: composer validate
- name: setup templates_c
run: mkdir templates_c || true
- name: touch config.local.php
run: touch config.local.php && php -v
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
- name: Build/test
run: composer build
- name: setup coveralls
run: mkdir -p build/logs || true
- name: Coveralls
run: vendor/bin/coveralls ./clover.xml || true
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}

7
.gitignore vendored

@ -1,7 +0,0 @@
/config.local.php
/templates_c/*.tpl.php
/templates_c/*menu.conf.php
/vendor/
/.php_cs.cache
/.idea
/composer.lock

@ -1,23 +0,0 @@
<?php
$finder = PhpCsFixer\Finder::create()
->exclude('lib')
->exclude('vendor')
->exclude('templates')
->exclude('templates_c')
->exclude('debian')
->files()->notName('config.inc.php')->notName('config.local.php')
->in(__DIR__);
return PhpCsFixer\Config::create()
->setFinder($finder)
->setRules(array(
'@PSR2' => true,
'braces' => array(
'position_after_functions_and_oop_constructs' => 'same',
),
'method_argument_space' => false, # don't break formatting in initStruct()
'no_spaces_inside_parenthesis' => false, # don't break formatting in initStruct()
));
/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4 ft=php: */

@ -1,32 +0,0 @@
language: php
php:
- 7.2
- 7.3
- 7.4
services:
- mysql
- postgresql
cache:
directories:
- $HOME/.composer/cache
- $HOME/vendor
before_install:
- mysql -e 'CREATE DATABASE postfixadmin;'
- psql -c 'create database postfixadmin;' -U postgres
before_script:
- travis_retry composer install --no-interaction --prefer-source --dev
- mkdir -p build/logs
script:
- composer build
- DATABASE=sqlite vendor/bin/phpunit tests/
- DATABASE=mysql vendor/bin/phpunit --coverage-clover=build/logs/clover.xml tests/
- DATABASE=postgresql vendor/bin/phpunit tests/
after_success:
- travis_retry php vendor/bin/php-coveralls

@ -42,21 +42,13 @@ use File::Path;
use Getopt::Long; use Getopt::Long;
### change settings as needed, see notes above ################################# ### change settings as needed, see notes above #################################
our $root_path = "/home/vmail"; my $root_path = "/home/vmail";
our $logfile = "/var/log/removed_maildirs.log"; my $logfile = "/var/log/removed_maildirs.log";
our $db_hostname = "localhost"; my $db_hostname = "localhost";
our $db_port = "3306"; # this script currently supports MySQL only my $db_port = "3306";
our $db_database = "postfix"; my $db_database = "postfix";
our $db_username = "someuser"; my $db_username = "someuser";
our $db_password = "somepass"; my $db_password = "somepass";
# instead of changing this script, you can put your settings to /etc/mail/postfixadmin/cleanupdirs.conf
# just use perl syntax there to fill the variables listed above (without the "our" keyword). Example:
# $db_username = 'mail';
if (-f "/etc/mail/postfixadmin/cleanupdirs.conf") {
require "/etc/mail/postfixadmin/cleanupdirs.conf";
}
################################################################################ ################################################################################
### begin program ############################################################## ### begin program ##############################################################
@ -71,7 +63,6 @@ opendir DOMAINDIR, $root_path
or die "Unable to access directory '$root_path' ($!)"; or die "Unable to access directory '$root_path' ($!)";
foreach my $domain_dir (sort readdir DOMAINDIR) { foreach my $domain_dir (sort readdir DOMAINDIR) {
next if $domain_dir =~ /^\./; # skip dotted dirs next if $domain_dir =~ /^\./; # skip dotted dirs
next if (! -d "$root_path/$domain_dir"); # skip everything that is not a directory
my $full_domain_dir = "$root_path/$domain_dir"; my $full_domain_dir = "$root_path/$domain_dir";
opendir USERDIR, $full_domain_dir opendir USERDIR, $full_domain_dir
or die "Unable to access directory '$full_domain_dir' ($!)"; or die "Unable to access directory '$full_domain_dir' ($!)";

@ -6,7 +6,8 @@
# This source file is subject to the GPL license that is bundled with # This source file is subject to the GPL license that is bundled with
# this package in the file LICENSE.TXT. # this package in the file LICENSE.TXT.
# #
# Further details on the project are available at http://postfixadmin.sf.net # Further details on the project are available at :
# http://www.postfixadmin.com or http://postfixadmin.sf.net
# #
# @version $Id$ # @version $Id$
# @license GNU GPL v2 or later. # @license GNU GPL v2 or later.

@ -1,8 +0,0 @@
Version 0.1 -- 26/10/2009
---------------------------
* Public Release.
* Postcreation, Postdeletion and Postedit hooks.

@ -1,7 +0,0 @@
Configuración
-------------
- Edita el fichero cyrus.conf y modifica las variables $cyrus_*. El usuario debe tener permisos sobre todas las cuentas.
- Edita los ficheros cyrus-*.pl y cambia la ruta de cyrus.conf (linea require '/path/to/cyrus.conf';)

@ -1,7 +0,0 @@
Configuration
-------------
- Edit cyrus.conf and set $cyrus_* variables correctly. User must have permission over all accounts.
- Edit cyrus-*.pl and change path to cyrus.conf (require '/path/to/cyrus.conf'; line)

@ -1,36 +0,0 @@
#!/usr/bin/perl
# Cyrus Mailbox creation
#
# Iñaki Rodriguez (irodriguez@virtualminds.es / irodriguez@ackstorm.es)
#
# LICENSE
# This source file is subject to the GPL license that is bundled with
# this package in the file LICENSE.TXT.
#
# (26/10/2009)
use Cyrus::IMAP::Admin;
require '/etc/mail/postfixadmin/cyrus.conf';
use strict;
use vars qw($cyrus_user $cyrus_password $cyrus_host);
my %opts;
my $mailbox = mailbox_name($ARGV[0]);
my $client = Cyrus::IMAP::Admin->new($cyrus_host);
die_on_error($client);
$opts{-user} = $cyrus_user;
$opts{-password} = $cyrus_password;
$client->authenticate(%opts);
die_on_error($client);
$client->create($mailbox);
die_on_error($client);
$client->setquota($mailbox,'STORAGE',scalar $ARGV[3]) if ($ARGV[3] > 0);
die_on_error($client);

@ -1,36 +0,0 @@
#!/usr/bin/perl
# Cyrus Mailbox deletion
#
# Iñaki Rodriguez (irodriguez@virtualminds.es / irodriguez@ackstorm.es)
#
# LICENSE
# This source file is subject to the GPL license that is bundled with
# this package in the file LICENSE.TXT.
#
# (26/10/2009)
use Cyrus::IMAP::Admin;
require '/etc/mail/postfixadmin/cyrus.conf';
use strict;
use vars qw($cyrus_user $cyrus_password $cyrus_host);
my %opts;
my $mailbox = mailbox_name($ARGV[0]);
my $client = Cyrus::IMAP::Admin->new($cyrus_host);
die_on_error($client);
$opts{-user} = $cyrus_user;
$opts{-password} = $cyrus_password;
$client->authenticate(%opts);
die_on_error($client);
$client->setacl($mailbox,$cyrus_user => 'all');
die_on_error($client);
$client->deletemailbox($mailbox);
die_on_error($client);

@ -1,33 +0,0 @@
#!/usr/bin/perl
# Cyrus Mailbox edition
#
# Iñaki Rodriguez (irodriguez@virtualminds.es / irodriguez@ackstorm.es)
#
# LICENSE
# This source file is subject to the GPL license that is bundled with
# this package in the file LICENSE.TXT.
#
# (26/10/2009)
use Cyrus::IMAP::Admin;
require '/etc/mail/postfixadmin/cyrus.conf';
use strict;
use vars qw($cyrus_user $cyrus_password $cyrus_host);
my %opts;
my $mailbox = mailbox_name($ARGV[0]);
my $client = Cyrus::IMAP::Admin->new($cyrus_host);
die_on_error($client);
$opts{-user} = $cyrus_user;
$opts{-password} = $cyrus_password;
$client->authenticate(%opts);
die_on_error($client);
$client->setquota($mailbox,'STORAGE',scalar $ARGV[3]) if ($ARGV[3] > 0);
die_on_error($client);

@ -1,31 +0,0 @@
#!/usr/bin/perl
# Config
$cyrus_user = 'cyrus';
$cyrus_password = 'cyruspass';
$cyrus_host = 'localhost';
# unixhierarchysep => 1 (yes) / 0 (no)
$unixhierarchysep = 1;
# Common routines
sub mailbox_name {
my $mailbox = shift;
if($unixhierarchysep) {
$mailbox = 'user/'.$ARGV[0];
} else {
$mailbox = 'user.'.$ARGV[0];
}
return $mailbox;
}
sub die_on_error {
my $cyradm = shift;
if($cyradm->error) { die $cyradm->error; }
}
1;

@ -1,77 +0,0 @@
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
$ENV{'PATH'} = "/sbin:/bin:/usr/sbin:/usr/bin";
my ($domain);
my $list = 0;
(help()) if (!$ARGV[0]);
GetOptions ('l' => \$list, 'd=s' => \$domain) or (help());
(list_queue()) if ($list == 1);
(delete_queue()) if ($domain);
sub delete_queue {
my $ids = `postqueue -p`;
my @ids = split /\n/, $ids;
for my $id (@ids) {
next if $id =~ /^[\s\(-]/;
chomp $id;
next unless $id;
$id =~ s/(.*?)\**\s.*/$1/;
#print "$id\n";
my $match = `postcat -q $id | grep '$domain'`;
next unless $match;
#print "Deleting ID: $id\n";
my $saida = `postsuper -d $id`;
print $saida;
}
}
sub list_queue {
my %hash_mail = ();
my @queue = `postqueue -p`;
my($queue,$key,$total);
foreach $queue(@queue) {
chomp $queue;
if ( $queue =~ /^\s+.*\@(.*)/ ) {
$hash_mail{$1}++;
}
}
print"\nTOTAL\tTO\n";
print"-----
----------------------------------------------------------------\n";
foreach $key (reverse sort { $hash_mail{$a} <=> $hash_mail{$b}} keys
%hash_mail) {
$total += $hash_mail{$key};
print"$hash_mail{$key} - $key\n";
}
print"\n$total -> TOTAL QUEUE\n";
}
sub help {
print "Usage $0 -l To list a row of E-mail
Usage $0 -d domain.com To delete the mensgens the Domain\n";
}

@ -8,48 +8,10 @@ use Sys::Syslog;
# require liblockfile-simple-perl # require liblockfile-simple-perl
use LockFile::Simple qw(lock trylock unlock); use LockFile::Simple qw(lock trylock unlock);
######################################################################
########## Change the following variables to fit your needs ##########
# database settings
# database backend - uncomment one of these
our $db_type = 'Pg';
#my $db_type = 'mysql';
# host name
our $db_host="127.0.0.1";
# database name
our $db_name="postfix";
# database username
our $db_username="mail";
# database password
our $db_password="CHANGE_ME!";
# Where to create a lockfile; please ensure path exists.
our $run_dir="/var/lock/fetchmail";
# in case you want to use dovecot deliver to put the mail directly into the users mailbox,
# set "mda" in the fetchmail table to the keyword "dovecot".
# Where the delivery binary is located
$dovecot_deliver = "/usr/lib/dovecot/deliver";
# instead of changing this script, you can put your settings to /etc/mail/postfixadmin/fetchmail.conf
# just use perl syntax there to fill the variables listed above (without the "our" keyword). Example:
# $db_username = 'mail';
if (-f "/etc/mail/postfixadmin/fetchmail.conf") {
require "/etc/mail/postfixadmin/fetchmail.conf";
}
#################### Don't change anything below! ####################
######################################################################
openlog("fetchmail-all", "pid", "mail"); openlog("fetchmail-all", "pid", "mail");
sub log_and_die { sub log_and_die {
my($message) = @_; my($message) = @_;
syslog("err", $message); syslog("err", $message);
die $message; die $message;
} }
@ -68,69 +30,51 @@ while ($_ = shift @ARGS1) {
} }
} }
# mysql settings
$database="mailadmin";
$hostname="127.0.0.1";
$user="mail";
$run_dir="/var/run/fetchmail";
# use specified config file # use specified config file
if (-e $configfile) { if (-e $configfile) {
do $configfile; do $configfile;
} }
if($db_type eq "Pg" || $db_type eq "mysql") { $dsn = "DBI:mysql:database=$database;host=$hostname";
$dsn = "DBI:$db_type:database=$db_name;host=$db_host";
} else {
log_and_die "unsupported db_type $db_type";
}
if(!-d $run_dir) {
log_and_die("Please create: $run_dir");
}
$lock_file=$run_dir . "/fetchmail-all.lock"; $lock_file=$run_dir . "/fetchmail-all.lock";
$lockmgr = LockFile::Simple->make(-autoclean => 1, -max => 1); $lockmgr = LockFile::Simple->make(-autoclean => 1, -max => 1);
$lockmgr->lock($lock_file) || log_and_die "can't lock ${lock_file}"; $lockmgr->lock($lock_file) || log_and_die "can't lock ${lock_file}";
# database connect #mysql connect
$dbh = DBI->connect($dsn, $db_username, $db_password) || log_and_die "cannot connect the database"; $dbh = DBI->connect($dsn, $user, $password) || log_and_die "cannot connect the database";
if($db_type eq "Pg") {
$sql_cond = "active = 't' AND date_part('epoch',now())-date_part('epoch',date)";
} elsif($db_type eq "mysql") {
$sql_cond = "active = 1 AND unix_timestamp(now())-unix_timestamp(date)";
}
$sql = " $sql=<<SQL;
SELECT id,mailbox,src_server,src_auth,src_user,src_password,src_folder,fetchall,keep,protocol,mda,extra_options,usessl, sslcertck, sslcertpath, sslfingerprint SELECT id,mailbox,src_server,src_auth,src_user,src_password,src_folder,fetchall,keep,protocol,mda,extra_options,usessl
FROM fetchmail FROM fetchmail
WHERE $sql_cond > poll_time*60 WHERE unix_timestamp(now())-unix_timestamp(date) > poll_time*60
"; SQL
my (%config); my (%config);
map{ map{
my ($id,$mailbox,$src_server,$src_auth,$src_user,$src_password,$src_folder,$fetchall,$keep,$protocol,$mda,$extra_options,$usessl,$sslcertck,$sslcertpath,$sslfingerprint)=@$_; my ($id,$mailbox,$src_server,$src_auth,$src_user,$src_password,$src_folder,$fetchall,$keep,$protocol,$mda,$extra_options,$usessl)=@$_;
syslog("info","fetch ${src_user}@${src_server} for ${mailbox}");
syslog("info","fetch ${src_user}@${src_server} for ${mailbox}");
$cmd="user '${src_user}' there with password '".decode_base64($src_password)."'"; $cmd="user '${src_user}' there with password '".decode_base64($src_password)."'";
$cmd.=" folder '${src_folder}'" if ($src_folder); $cmd.=" folder '${src_folder}'" if ($src_folder);
$cmd.=" mda ".$mda if ($mda);
if ($mda) {
if ($mda eq "dovecot") {
$cmd.=" mda \"${dovecot_deliver} -d ${mailbox}\" ";
} else {
$cmd.=" mda ".$mda
}
}
# $cmd.=" mda \"/usr/local/libexec/dovecot/deliver -m ${mailbox}\""; # $cmd.=" mda \"/usr/local/libexec/dovecot/deliver -m ${mailbox}\"";
$cmd.=" is '${mailbox}' here"; $cmd.=" is '${mailbox}' here";
$cmd.=" keep" if ($keep); $cmd.=" keep" if ($keep);
$cmd.=" fetchall" if ($fetchall); $cmd.=" fetchall" if ($fetchall);
$cmd.=" ssl" if ($usessl); $cmd.=" ssl" if ($usessl);
$cmd.=" sslcertck" if($sslcertck);
$cmd.=" sslcertpath $sslcertpath" if ($sslcertck && $sslcertpath);
$cmd.=" sslfingerprint \"$sslfingerprint\"" if ($sslfingerprint);
$cmd.=" ".$extra_options if ($extra_options); $cmd.=" ".$extra_options if ($extra_options);
$text=<<TXT; $text=<<TXT;
set postmaster "postmaster" set postmaster "postmaster"
set nobouncemail set nobouncemail
@ -138,11 +82,10 @@ set no spambounce
set properties "" set properties ""
set syslog set syslog
poll ${src_server} with proto ${protocol}
$cmd
TXT TXT
$text.="poll ${src_server} with proto ${protocol}";
$text.=" service ${src_port}" if ($src_port);
$text.="\n $cmd";
($file_handler, $filename) = mkstemp( "/tmp/fetchmail-all-XXXXX" ) or log_and_die "cannot open/create fetchmail temp file"; ($file_handler, $filename) = mkstemp( "/tmp/fetchmail-all-XXXXX" ) or log_and_die "cannot open/create fetchmail temp file";
print $file_handler $text; print $file_handler $text;

@ -1,231 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Script takes a CSV list of users and does a 'bulk' insertion into mysql.
#
# Copyright (C) 2009 Simone Piccardi
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
import csv
import getopt
import sys
import re
import time
import random, string
from datetime import datetime
from crypt import crypt
try:
import MySQLdb
except ImportError ,e:
print 'Cannot import the needed MySQLdb module, you must install it'
print 'on Debian systems just use the command'
print ' apt-get install python-mysqldb'
def usage():
print "Usage: inspostadmusers.py [options] users.csv"
print " -h print this help"
print " -t test run, do not insert, just print"
print " -u DB user"
print " -p DB password"
print " -D DB name"
print " -H DB host"
print " -q Quota in Mb (0 => no limit)"
print " -n char in seed"
print " -d debug info on"
print " -A create default alias for each domain"
print
print "the users.csv file must contains the user list with a line"
print "for each user, first line should be a title line with at least"
print "the following column names: "
print " * user - user part of the email (like user in user@domain.com)"
print " * password - cleartext password"
print " * domain - domain name (like 'domain.com')"
print " * name - full user name ('Name Surname')"
print
print "the 'name' column is optional, other columns will be ignored"
print
print "Known restrictions:"
print "* this script only works with MySQL"
print "* mailbox paths are hardcoded to domain/username/"
# option parsing
try:
opts, args = getopt.getopt(sys.argv[1:], 'u:p:d:D:H:htdA')
optval={}
for opt, val in opts:
if opt == "-h":
usage()
sys.exit(0)
else:
optval[opt]=val
except getopt.GetoptError:
usage()
sys.exit(2)
#
# Setup DB connection
#
MYSQLDB="postfixadmin"
MYSQLUSER="postfixadmin"
MYSQLPASSWORD=""
MYSQLHOST="localhost"
# settings by command line options
if optval.has_key('-u'):
MYSQLUSER = optval['-u']
if optval.has_key('-p'):
MYSQLPASSWORD = optval['-p']
if optval.has_key('-D'):
MYSQLDB = optval['-D']
if optval.has_key('-H'):
MYSQLHOST = optval['-H']
if optval.has_key('-q'):
quota = optval['-q']
else:
quota = 0
if optval.has_key('-n'):
seed_len = optval['-n']
else:
seed_len = 8
# check arguments, only the user list file must be present
if len(args) !=1:
print 'Need just one argument'
usage()
sys.exit(1)
# MySQL connection (skipped in test run)
if optval.has_key('-t'):
print "Test Run"
else:
try:
connection = MySQLdb.connect(host=MYSQLHOST, user=MYSQLUSER,
db=MYSQLDB, passwd=MYSQLPASSWORD)
except MySQLdb.MySQLError, e:
print "Database connection error"
print e
sys.exit(1)
cursor = connection.cursor()
#
# Main body
#
NOW = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# read and convert CSV data
lista = csv.DictReader(open(args[0]))
def gen_seed(seed_len, chars):
return '$1$'+''.join([random.choice(chars) for _ in xrange(seed_len)])+'$'
def insert_record(cursor,table,record):
columns = record.keys()
query = "INSERT INTO " + table + "(" + ','.join(columns) + ") VALUES (" + ','.join(len(columns)*['%s']) + ")"
try:
cursor.execute(query, record.values())
return 0
except MySQLdb.MySQLError, e:
print "Database insertion error"
print e
print "Record was:"
print record.values()
print "Query was:"
print query
# defining default values for tables (mailbox, alias and domain)
mailbox = {
'created': NOW,
'modified': NOW,
'active': 1,
'quota': quota
}
aliases = {
'created': NOW,
'modified': NOW,
'active': 1
}
domain = {
'description': "",
'aliases': 0,
'mailboxes': 0,
'quota': 0,
'transport': 'virtual',
'backupmx': 0,
'created': NOW,
'modified': NOW,
'active': 1
}
# list of default alias
def_alias = ['abuse','hostmaster','postmaster','webmaster']
domain_list = {}
chars = string.letters + string.digits
# loop over the CSV
for row in lista:
# create domain if it does not exists
if domain_list.has_key(row["domain"]):
if optval.has_key('-d'):
print "Domain " + row["domain"] + "already exixts"
else:
domain_list[row["domain"]] = 1
domain['domain'] = row["domain"]
if optval.has_key('-t'):
print "Inserting domain"
print domain
else:
insert_record(cursor,'domain',domain)
if optval.has_key('-A'):
for i in def_alias:
aliases['address']= i+'@'+row["domain"]
aliases['goto']= aliases['address']
aliases['domain'] = row["domain"]
if optval.has_key('-t'):
print "Inserting alias"
print aliases
else:
insert_record(cursor,'alias',aliases)
# build query data for mailbox table
mailbox['username']=row["user"]+'@'+row["domain"]
encpass=crypt(row["password"], gen_seed(seed_len,chars))
mailbox['password'] = encpass
mailbox['name'] = row["name"]
mailbox['maildir'] = row["domain"]+'/'+row["user"]+'/'
mailbox['local_part'] =row["user"]
mailbox['domain'] = row["domain"]
# build query data for alias table
aliases['address']= mailbox['username']
aliases['goto']= mailbox['username']
aliases['domain'] = row["domain"]
# inserting data for mailbox (and relate alias)
if optval.has_key('-t'):
print "Inserting mailbox"
print mailbox
print aliases
else:
insert_record(cursor,'mailbox',mailbox)
insert_record(cursor,'alias',aliases)
sys.exit(0)

@ -52,17 +52,7 @@ if [ -e "$maildir" ]; then
exit 1 exit 1
fi fi
maildirmake "$maildir"
# try looking for maildirmake ...
MDM=`which maildirmake || which courier-maildirmake`
if [ "x${MDM}" = "x" ]; then
echo "Couldn't find maildirmake or courier-maildirmake in your PATH etc (via which)" >/dev/stderr
exit 1
fi
"${MDM}" "${maildir}"
if [ ! -d "$maildir" ]; then if [ ! -d "$maildir" ]; then
echo "$0: maildirmake didn't produce a directory; bailing out." echo "$0: maildirmake didn't produce a directory; bailing out."
exit 1 exit 1

@ -1,18 +1,16 @@
#!/usr/bin/perl #!/usr/bin/perl
# vim:ts=4:sw=4:et # vim:ts=4:sw=4:et
# Virtual quota_usage 0.3 #
# Contributed to Postfixadmin by Jose Nilton <jniltinho@gmail.com> # Contributed to Postfixadmin by Jose Nilton <jniltinho@gmail.com>
# #
# See also : http://www.russelldare.net/media/perl/dirsizeSource.pdf # See also : http://www.russelldare.net/media/perl/dirsizeSource.pdf
# License: GPL v2. # License: GPL v2.
# Usage: # Usage:
# perl quota_usage.pl --list # perl quota_usage.pl --list or
# perl quota_usage.pl --list --addmysql # perl quota_usage.pl --addmysql for add mysql database postfix
# for add mysql database postfix
# #
# Requirements - the following perl modules are required: # Requires: perl perl-DBD-mysql perl-DBD (may be named differently depending on your platform).
# DBD::Pg or DBD::mysql; perl perl-DBD-mysql perl-DBD (may be named differently depending on your platform).
# and the 'du' binary in $ENV{'PATH'} (see below). # and the 'du' binary in $ENV{'PATH'} (see below).
# #
# You will need to modify the postfix DATABASE to add a quota_usage column. # You will need to modify the postfix DATABASE to add a quota_usage column.
@ -37,43 +35,25 @@ my $db_user = 'postfix';
my $db_password = '123456'; my $db_password = '123456';
my $root_path = '/home/vmail'; my $root_path = '/home/vmail';
# Pg or mysql # Pg or mysql
my $db_type = 'mysql'; my $db_type = 'Pg';
##END EDIT## ##END EDIT##
(help()) if (!$ARGV[0]);
$ENV{'PATH'} = "/sbin:/bin:/usr/sbin:/usr/bin"; $ENV{'PATH'} = "/sbin:/bin:/usr/sbin:/usr/bin";
my($domain_dir, $full_domain_dir, $user_dir, $usage, $email, $sql, $dbh); my($domain_dir, $full_domain_dir, $user_dir, $usage, $email, $sql, $dbh);
my $list = 0; GetOptions ('list' => \&list_quota_usage, 'addmysql' => \&insert_to_db);
my $insert_db = 0;
my $total_mailbox = 0;
my $total_domain = 0;
GetOptions ('l|list' => \$list, 'i|addmysql' => \$insert_db, 'help|h|man' => \&help) or (help());
(list_quota_usage()) if ($list == 1 || $insert_db == 1 );
sub list_quota_usage { sub list_quota_usage {
opendir(DOMAINDIR, $root_path) or die ("Unable to access directory '$root_path' ($!)"); opendir(DOMAINDIR, $root_path) or die ("Unable to access directory '$root_path' ($!)");
if($insert_db == 1){
$dbh = DBI->connect("DBI:$db_type:database=$db_database;host=$db_host", $db_user, $db_password) or die ("cannot connect the database");
execSql("UPDATE mailbox set quota_usage = 0");
}
foreach $domain_dir (sort readdir DOMAINDIR) { foreach $domain_dir (sort readdir DOMAINDIR) {
next if $domain_dir =~ /^\./; # skip dotted dirs next if $domain_dir =~ /^\./; # skip dotted dirs
$full_domain_dir = "$root_path/$domain_dir"; #print "$full_domain_dir\n"; $full_domain_dir = "$root_path/$domain_dir"; #print "$full_domain_dir\n";
$total_domain++;
opendir(USERDIR, $full_domain_dir) or die ("Unable to access directory '$full_domain_dir' ($!)"); opendir(USERDIR, $full_domain_dir) or die ("Unable to access directory '$full_domain_dir' ($!)");
foreach $user_dir (sort readdir USERDIR) { foreach $user_dir (sort readdir USERDIR) {
next if $user_dir =~ /^\./; # skip dotted dirs next if $user_dir =~ /^\./; # skip dotted dirs
$email = "$user_dir\@$domain_dir"; $email = "$user_dir\@$domain_dir";
$total_mailbox++;
my $i = `du -0 --summarize $full_domain_dir/$user_dir`; my $i = `du -0 --summarize $full_domain_dir/$user_dir`;
($usage) = split(" ", $i); ($usage) = split(" ", $i);
@ -86,66 +66,75 @@ sub list_quota_usage {
$usage = $usage + 500; $usage = $usage + 500;
$usage = int $usage / 1000; $usage = int $usage / 1000;
} }
if($insert_db == 1){execSql("UPDATE mailbox set quota_usage = $usage, quota_usage_date = CAST(NOW() AS DATE) WHERE username = '$email'");}
print_list() if ($list == 1);
list_out();
} }
} }
close(DOMAINDIR); close(DOMAINDIR);
close(USERDIR); close(USERDIR);
}
(print_total()) if ($list == 1);
} sub insert_to_db {
opendir(DOMAINDIR, $root_path) or die ("Unable to access directory '$root_path' ($!)");
$dbh = DBI->connect("DBI:$db_type:database=$db_database;host=$db_host", $db_user, $db_password) or die ("cannot connect the database");
execSql("UPDATE mailbox set quota_usage = 0");
foreach $domain_dir (sort readdir DOMAINDIR) {
next if $domain_dir =~ /^\./; # skip dotted dirs
$full_domain_dir = "$root_path/$domain_dir"; #print "$full_domain_dir\n";
opendir(USERDIR, $full_domain_dir) or die ("Unable to access directory '$full_domain_dir' ($!)");
foreach $user_dir (sort readdir USERDIR) {
next if $user_dir =~ /^\./; # skip dotted dirs
$email = "$user_dir\@$domain_dir";
sub execSql { my $i = `du -0 --summarize $full_domain_dir/$user_dir`;
my $sql = shift; ($usage) = split(" ", $i);
my $ex;
$ex = $dbh->do($sql) or die ("error when running $sql"); if ($usage < 100) {
} $usage = 0;
} elsif ($usage < 1000) {
$usage = 1;
} else {
$usage = $usage + 500;
$usage = int $usage / 1000;
}
execSql("UPDATE mailbox set quota_usage = $usage, quota_usage_date = CAST(NOW() AS DATE) WHERE username = '$email'");
#list_out(); #Debug
}
}
close(DOMAINDIR);
close(USERDIR);
sub print_total{
print "---------------------------------------------------------\n";
print "TOTAL DOMAIN\t\t\t\tTOTAL MAILBOX\n";
print "---------------------------------------------------------\n";
print "$total_domain\t\t\t\t\t\t$total_mailbox\n";
} }
sub execSql {
my $sql = shift;
my $ex;
$ex = $dbh->do($sql) or die ("error when running $sql");
}
sub print_list { sub list_out {
format STDOUT_TOP = format STDOUT_TOP =
Report of Quota Used Report of Quota Used
--------------------------------------------------------- --------------------------
EMAIL QUOTA USED EMAIL QUOTA USED
--------------------------------------------------------- ------------------------------------------------------------------
. .
format = format =
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<
$email, "$usage MB" $email, "$usage\bMB"
. .
write; write;
} }
sub help {
print "$0 [options...]\n";
print "-l|--list List quota used\n";
print "-i|--addmysql For insert quota used in database mysql\n";
}

@ -1,38 +0,0 @@
Installing the postfixadmin Plugin
======================================
Requirements:
=============
- PHP 5.[234].* with php5-xmlrpc installed (if available; it should be available by default anyway)
- http access to a local/remote postfixadmin interface
- Zend Framework (1.12.x) - needs adding to the include path within common.php,
or installing in a system include path directory (e.g. /usr/share/php)
(e.g. from within the directory containing this file ...
wget https://packages.zendframework.com/releases/ZendFramework-1.12.3/ZendFramework-1.12.3-minimal.tar.gz
tar -zxf ZendFramework-1.12.3-minimal.tar.gz
mv ZendFramework-1.12.3-minimal/library/Zend . )
NOTE: This plugin is _not compatible_ with Zend Framework version 2.x.
Installation :
==============
- Copy this code into the Squirrelmail plugins directory - your life will be easiest if it's in a directory called 'postfixadmin'
- Install Zend Framework (see above under Requirements for example)
- Edit config.php and specify the remote URL for the Postfixadmin XmlRpc service.
- Edit common.php and (if you need to) change the include path(s) so they are correct.
- Edit the remote Postfixadmin's XmlRpc service config file and ensure 'xmlrpc_enabled' is set to boolean true.
- Enable the plugin through 'squirrelmail-configure' or 'config/conf.pl'.
Choose option 8 and move the plugin from the "Available Plugins"
category to the "Installed Plugins" category. Save and exit.
Security :
==========
- The XmlRpc client needs to get the user's mailbox password before it will be able to connect to the
XmlRpc server (postfixadmin). The plugin prompts the user for their mailbox password, and caches it in their session
($_SESSION['password']). This password is then sent once on every page load to the remote XmlRpc server.
- You should consider doing any of the following :
- Using https if the server and client are on seperate servers. This will probably require a signed certificate etc, and may require changes to the Zend_XmlRpc_Client's HttpClient.
- Using something like stunnel to encrypt traffic between server(s).

@ -1,40 +0,0 @@
2007/03/29 :
Before I (David Goodwin) customised this plugin, it contained the following within all
files as a header.
/****************************************************************************************
Author ......... Florian Kimmerl
Contact ........ info@spacekoeln.de
Home Site ...... http://www.spacekoeln.de/
Program ........ postfixadmin
Purpose ........ Allows you to change your postfixadmin settings within squirrelmail
*************************************************************************************
The Original Code is Postfix Admin.
The Initial Developer of the Original Code is Mischa Peters .
Portions created by Mischa Peters are Copyright (c) 2002, 2003, 2004.
All Rights Reserved.
Contributor(s):
This project includes work by Mischa Peters and others that is:
Copyright (c) 2002,2003,2004 Mischa Peters
All rights reserved.
****************************************************************************************/
Contacting the author provided no success, so I took over maintainership.
Please note:
1) Changes made by myself (David Goodwin) will be licensed under the GPL
2) PostfixAdmin has itself been relicensed under the GPL; however this took place _after_
this plugin was written.
3) Squirrelmail itself is released under http://squirrelmail.org/wiki/SquirrelMailGPL (GPL)
The GNU public license can be found online at :
http://www.gnu.org/licenses/gpl.txt

@ -1,31 +0,0 @@
# Squirrelmail Plugin Postfixadmin
The Postfixadmin SquirrelMail plugin let users change their virtual alias,
vacation status/message and password
Your users can therefore use this plugin within Squirrelmail to :
* Turn vacation on/off
* Change their email password
* Setup forwarding rules
Note, this plugin does not require access to the Postfixadmin database. It communicates with Postfixadmin using the XMLRPC protocol.
## Notes
* We now depend upon the Zend Framework (preferably v1.9.x at the time of writing) (Download from http://framework.zend.com/download/latest - the minimal one should be sufficient)
* Traffic to the XmlRpc interface needs encrypting (e.g. https) - this is something _you_ need to do
* When trying to use the plugin, the user will be prompted to enter their mailbox password - this is necessary to authenticate with the remote XmlRpc? interface
## REQUIREMENTS
* SquirrelMail 1.4x
* PostfixAdmin version 3 or higher.
* PHP 5.4+ with XMLRPC support

@ -1,51 +0,0 @@
<?php
// vim:ts=4:sw=4:et
ini_set('include_path', get_include_path() . ':' . dirname(__FILE__));
@include_once('Zend/Version.php');
if (!class_exists('Zend_Version', false)) {
die("Zend Framework not found. Please check the INSTALL File.");
}
chdir("..");
if (!defined('SM_PATH')) {
define('SM_PATH', '../');
}
$config_file = dirname(__FILE__ ) . '/config.php';
$validate_file = dirname(__FILE__) . '/../include/validate.php';
if (!file_exists($config_file)) {
die("$config_file is missing");
}
include_once($config_file);
include_once(dirname(__FILE__) . '/functions.inc.php');
if (file_exists($validate_file)) {
include_once($validate_file);
} else {
$validate_file = SM_PATH . '/src/validate.php';
if (file_exists($validate_file)) {
include_once($validate_file);
}
}
include_once(SM_PATH . 'functions/page_header.php');
include_once(SM_PATH . 'functions/display_messages.php');
include_once(SM_PATH . 'functions/imap.php');
include_if_exists(SM_PATH . 'functions/array.php');
if (file_exists(SM_PATH . 'src/load_prefs.php')) {
include_once(SM_PATH . 'src/load_prefs.php');
} else {
include_if_exists(SM_PATH . 'include/load_prefs.php');
}
// overwrite squirrelmail's content type to utf8...
header("Content-Type: text/html; charset=utf8");
//global $VACCONFMESSAGE;
bindtextdomain('postfixadmin', dirname(__FILE__) . '/postfixadmin/locale');
textdomain('postfixadmin');

@ -1,22 +0,0 @@
<?php
$CONF = array();
$CONF['xmlrpc_url'] = 'http://postfixadmin.local/postfixadmin/xmlrpc.php';
// Virtual Vacation
// If you use virtual vacation for you mailbox users set this to 'true'.
// NOTE: Make sure that you install the vacation module!!
//$AllowVacation = true; // true or false
global $AllowVacation;
$AllowVacation = true;
// Change Password
// Enables user to change the POP3/IMAP Password.
//$AllowChangePass = true; // true or false
global $AllowChangePass;
$AllowChangePass = true;
// Minimum password length - set to Zero to not care, otherwise the number of
// characters a password must be longer than.
$CONF['min_password_length'] = 5;

@ -1,20 +0,0 @@
Squirrelmail PostfixAdmin Plugin for Debian
===========================================
After installing the package, you will need to :
1) Edit the config.inc.php file to point to the PostfixAdmin server.
2) Ensure the xmlrpc interface is available and enabled on the Postfixadmin server
3) Run the squirrelmail-configure script.
Where to get help
=================
See http://squirrelmail-postfixadmin.palepurple.co.uk
Try also : david [at] pale purple dot co dot uk
Or #postfixadmin on irc.freenode.net might be a good bet.

@ -1,27 +0,0 @@
squirrelmail-postfixadmin (2.3.0) stable; urgency=low
* Using XMLRPC backend (no SQL here)
-- David Goodwin <david.goodwin@palepurple.co.uk> Mon, 01 Feb 2010 09:56:00 +0000
squirrelmail-postfixadmin (2.2.0) stable; urgency=low
* Changed DB backend to use prepared statements
* Changed vacation handling to match that of Postfixadmin (vacation.active
etc)
* Changed vacation page to support UTF8
-- David Goodwin <david.goodwin@palepurple.co.uk> Wed, 20 Aug 2008 15:25:00 +0000
squirrelmail-postfixadmin (2.1.1-1) stable; urgency=low
* Add NL language support
* Better db error logging (e.g. if wrong mdb2 driver specified etc)
-- David Goodwin <david.goodwin@palepurple.co.uk> Wed, 12 Dec 2007 16:00:00 +0000
squirrelmail-postfixadmin (2.1.0-1) stable; urgency=low
* Initial release.
-- David Goodwin <david.goodwin@palepurple.co.uk> Thu, 8 Nov 2007 20:00:00 +0000

@ -1 +0,0 @@
/etc/squirrelmail/plugins/postfixadmin-config.php

@ -1,19 +0,0 @@
Source: squirrelmail-postfixadmin
Section: mail
Priority: optional
Maintainer: David Goodwin <david.goodwin@palepurple.co.uk>
Standards-Version: 3.6.1
Package: squirrelmail-postfixadmin
Architecture: all
Depends: squirrelmail, php-pear
Suggests: postfixadmin
Description: Plugin for Squirrelmail to integrate with Postfixadmin
Postfixadmin is a web based interface for managing mail domains
and users. This package integrates Squirrelmail with it.
Users can change their password, forwarding and vacation settings
from within Squirrelmail when this package is installed, and
enabled through the ./squirrelmail-configure command.
.
For further information see
http://squirrelmail-postfixadmin.palepurple.co.uk

@ -1,11 +0,0 @@
This package was debianized by David Goodwin <david@palepurple.co.uk>
2007/11/08
It was downloaded from: http://squirremail-postfixadmin.palepurple.co.uk
Upstream Author(s): n/a
Copyright:
Copyright (C) 2007+ by David Goodwin <david@palepurple.co.uk>
License: GPL v2+

@ -1,4 +0,0 @@
LICENSE.txt
README
INSTALL
debian/README.Debian

@ -1 +0,0 @@
squirrelmail-postfixadmin_2.2.0_all.deb mail optional

@ -1,3 +0,0 @@
usr/share/squirrelmail/plugins/postfixadmin
usr/share/doc/squirrelmail-postfixadmin
etc/squirrelmail/plugins

@ -1,5 +0,0 @@
#!/bin/sh
echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
echo "WARNING: You need to read /usr/share/doc/squirrelmail-postfixadmin/README.Debian!"
echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

@ -1,56 +0,0 @@
#!/usr/bin/make -f
# debian/rules makefile for squirrelmail
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
build: build-stamp
build-stamp:
dh_testdir
clean:
dh_testdir
dh_testroot
dh_clean
install: build
$(checkdir)
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
dh_install
mkdir -p debian/tmp/usr/share/squirrelmail/plugins/postfixadmin
cp -a *.php version debian/tmp/usr/share/squirrelmail/plugins/postfixadmin
cp -a locale debian/tmp/usr/share/squirrelmail/plugins/postfixadmin
cp -a po debian/tmp/usr/share/squirrelmail/plugins/postfixadmin
mkdir -p debian/tmp/etc/squirrelmail/plugins/
cp -a *.sample debian/tmp/etc/squirrelmail/plugins/postfixadmin-config.php
mkdir -p debian/tmp/DEBIAN
cp debian/postinst debian/tmp/DEBIAN/postinst
chmod 555 debian/tmp/DEBIAN/postinst
ln -s /etc/squirrelmail/plugins/postfixadmin-config.php debian/tmp/usr/share/squirrelmail/plugins/postfixadmin/config.php
find debian/tmp -name .svn | xargs -r rm -r
# Build architecture-independent files here.
binary-indep: build install
dh_testdir
dh_testroot
dh_installdebconf
dh_installdocs -X.svn
dh_installexamples
dh_installman
dh_installcron
dh_link
dh_compress
dh_fixperms -X/var
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
# Build architecture-dependent files here.
binary-arch:
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

@ -1,96 +0,0 @@
<?php
/**
* Postfixadmin (http://postfixadmin.sf.net) integration with Squirrelmail.
* See http://squirrelmail-postfixadmin.palepurple.co.uk
* @author David Goodwin and many others
*/
function do_header() {
global $color;
displayPageHeader($color, 'None');
}
function do_footer() {
echo "</body></html>";
}
function _display_password_form() {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
do_header('Postfixadmin Squirrelmail - Login');
echo _('The PostfixAdmin plugin needs your current mailbox password');
echo "<form action='' method='post'>";
echo _('Password for');
echo " " . $_SESSION['username'] . " :";
echo "<input type='password' name='password' value=''>";
echo "<input type='submit' value='" . _('Submit') . "'></form>";
do_footer();
}
/**
* This returns a Zend_XmlRpc_Client instance - unless we can't log you in...
*/
function get_xmlrpc() {
global $CONF;
require_once('Zend/XmlRpc/Client.php');
$client = new Zend_XmlRpc_Client($CONF['xmlrpc_url']);
$http_client = $client->getHttpClient();
$http_client->setCookieJar();
$login_object = $client->getProxy('login');
if (empty($_SESSION['password'])) {
if (empty($_POST['password'])) {
_display_password_form();
exit(0);
} else {
try {
$success = $login_object->login($_SESSION['username'], $_POST['password']);
} catch (Exception $e) {
//var_dump($client->getHttpClient()->getLastResponse()->getBody());
error_log("Failed to login to xmlrpc instance - " . $e->getMessage());
die('Failed to login to xmlrpc instance');
}
if ($success) {
$_SESSION['password'] = $_POST['password'];
// reload the current page as a GET request.
header("Location: {$_SERVER['REQUEST_URI']}");
exit(0);
} else {
_display_password_form();
exit(0);
}
}
} else {
$success = $login_object->login($_SESSION['username'], $_SESSION['password']);
}
if (!$success) {
unset($_SESSION['password']);
die("Invalid details cached... refresh this page and re-enter your mailbox password");
}
return $client;
}
function include_if_exists($filename) {
if (file_exists($filename)) {
include_once($filename);
}
return;
}
global $optmode;
$optmode = 'display';
//
// check_email
// Action: Checks if email is valid and returns TRUE if this is the case.
// Call: check_email (string email)
//
function check_email($email) {
$return = filter_var($email, FILTER_VALIDATE_EMAIL);
if ($return === false) {
return false;
}
return true;
}

@ -1,25 +0,0 @@
<?php
/****************************************************************************************
Author ......... Florian Kimmerl
Contact ........ info@spacekoeln.de
Home Site ...... http://www.spacekoeln.de/
Program ........ postfixadmin
Version ........ 0.3-1.4
Purpose ........ Allows you to change your postfixadmin settings within squirrelmail
/**
* index.php
*
* Copyright (c) 1999-2003 The SquirrelMail Project Team
* Licensed under the GNU GPL. For full terms see the file COPYING.
*
* This file simply takes any attempt to view source files and sends those
* people to the login screen. At this point no attempt is made to see if
* the person is logged or not.
*
*
****************************************************************************************/
header("Location: ../../index.php");

@ -1,6 +0,0 @@
#!/bin/bash
for f in $(find . -name postfixadmin.po)
do
msgfmt -o $(dirname $f)/postfixadmin.mo $f
done

@ -1,132 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2004-01-29 17:35+0100\n"
"PO-Revision-Date: 2007-07-20 20:46+0100\n"
"Last-Translator: Michael Heca <michael.heca@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
#: setup.php
msgid "Forwarding"
msgstr "Pøesmìrování"
msgid "Here you can create and edit E-Mail forwards."
msgstr "Zde mù¾ete vytvoøit a nastavit pøesmìrování"
msgid "Set an OUT OF OFFICE message or auto responder for your mail."
msgstr "Zde mù¾ete nastavit automatickou odpovìd, pokud nebudete k zasti¾ení."
msgid "Change your mailbox password."
msgstr "Zmìnít heslo k Va¹emu e-mailovému úètu"
#: postfixadmin_changepass.php
msgid "Alias"
msgstr "Úèet"
msgid "Change Password"
msgstr "Zmìnit heslo"
msgid "Change your login password"
msgstr "Zmìnít heslo k Va¹emu e-mailovému úètu"
#: postfixadmin_forward.php
msgid "Edit Alias"
msgstr "Editace adresy pro pøesmìrování"
msgid "Edit an alias* for your domain.<br />One entry per line."
msgstr "Editace pøesmìrování pro Vá¹ úèet. <br/> Ka¾dá adresa na novém øádku."
msgid "The email address that you have entered is not valid:"
msgstr "Zadaná e-mailová adresa je chybná:"
msgid "Unable to locate alias!"
msgstr "Neni mo¾né nalézt úèet!"
msgid "Unable to modify the alias!"
msgstr "Není mo¾né zmìnit úèet!"
msgid "*Additional forward-aliase always recieve messages BBC!"
msgstr "Dal¹í aliasy dostanou e-mail jako BBC!"
msgid "Alias successfully changend!"
msgstr "Pøesmìrování bylo zmìnìno!"
msgid "To remove an alias, simply delete it's line from the text box."
msgstr "Pro odstranení pøesmìrování sma¾te v¹echny øádky v textovém boxu."
#: postfixadmin_vacation.php
msgid "Auto Response"
msgstr "Automatická odpovìï"
msgid "Going Away"
msgstr "Jsem mimo"
msgid "Coming Back"
msgstr "Jsem zpìt"
msgid "Options"
msgstr "Nastavení"
msgid "Out of Office"
msgstr "Mimo kanceláø"
msgid "Subject"
msgstr "Pøedmìt"
msgid "Body"
msgstr "Tìlo mailu"
msgid "Your auto response has been removed!"
msgstr "Va¹e automatická odpovìï byla odstranìna!"
msgid "Your auto response has been set!"
msgstr "Va¹e automatická odpovìï byla nastavena!"
msgid "You already have an auto response configured!"
msgstr "U¾ máte nastavenu automatickou odpovìï!"
#: postfixadmin_changepass.php:81
#: postfixadmin_changepass.php:87
msgid "The passwords that you supplied don't match!<br />Or are empty!"
msgstr "Zadaná hesla nejsou stejná a nebo jsou prázdná!"
#: postfixadmin_forward.php:70
#: postfixadmin_forward.php:152
msgid "To"
msgstr "Komu"
#: postfixadmin_changepass.php:101
msgid "Unable to change your password!"
msgstr "Není mo¾né zmìnit heslo!"
#: postfixadmin_changepass.php:75
msgid "You didn't supply your current password!"
msgstr "Stávající heslo neodpovídá!"
#: postfixadmin_changepass.php:96
msgid "Your password has been changed!"
msgstr "Va¹e heslo bylo zmìnìno!"
msgid "Password current"
msgstr "Stávající heslo"
msgid "Password new"
msgstr "Nové heslo"
msgid "Password new again"
msgstr "Nové heslo znovu"
msgid "Please sign out and log back again with your new password!"
msgstr "Prosím odhla¹te se a pøihla¹te se s novým heslem!"
msgid "I will be away from <date> until <date>. For urgent matters you can contact <contact person>."
msgstr "Nebudy k zasti¾ení od <date> do <date>. Pro naléhané po¾adavky prosím kontaktujte <contact person>."

@ -1,127 +0,0 @@
# Danish translation for Squirrelmail Plugin Postfixadmin.
# Copyright (C) 2004 Florian Kimmerl, 2007 David Goodwin
# This file is distributed under the same license as the Squirrelmail Plugin Postfixadmin package.
# Jesper R. Meyer <jrm@upthere.dk>, 2007.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.4.3\n"
"POT-Creation-Date: 2004-01-29 17:35+0100\n"
"PO-Revision-Date: 2007-11-09 16:07+0100\n"
"Last-Translator: JESPER MEYER <jrm@upthere.dk>\n"
"Language-Team: DANISH <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: setup.php
msgid "Forwarding"
msgstr "Videresending"
msgid "Here you can create and edit E-Mail forwards."
msgstr "Her kan du oprette og ændre email-videresendinger."
msgid "Set an OUT OF OFFICE message or auto responder for your mail."
msgstr "Tilføj en 'ikke tilstede' besked eller et autosvar til din emailadresse."
msgid "Change your mailbox password."
msgstr "Ændre adgangskoden til din postboks"
#: postfixadmin_changepass.php
msgid "Alias"
msgstr "Alias"
msgid "Change Password"
msgstr "Ændre adgangskode"
msgid "Change your login password"
msgstr "Ændre din login-adgangskode"
#: postfixadmin_forward.php
msgid "Edit Alias"
msgstr "Rediger alias"
msgid "Edit an alias* for your domain.<br />One entry per line."
msgstr "Rediger et alias* for dit domæne.<br />En modtager pr. linje."
msgid "The email address that you have entered is not valid:"
msgstr "Emailadressen du angav er ugyldig"
msgid "Unable to locate alias!"
msgstr "Aliaset eksistere ikke!"
msgid "Unable to modify the alias!"
msgstr "Kunne ikke ændre aliaset!"
msgid "*Additional forward-aliase always recieve messages BBC!"
msgstr "*Eksta vidersendingsalias modtager altid meddelelser BCC!"
msgid "Alias successfully changend!"
msgstr "Alias ændret!"
#: postfixadmin_vacation.php
msgid "Auto Response"
msgstr "Autosvar"
msgid "Going Away"
msgstr "Tager afsted"
msgid "Coming Back"
msgstr "Kommer tilbage"
msgid "Options"
msgstr "Indstillinger"
msgid "Out of Office"
msgstr "Ikke tilstede"
msgid "Subject"
msgstr "Emne"
msgid "Body"
msgstr "Meddelelse"
msgid "Your auto response has been removed!"
msgstr "Autosvar er fjernet!"
msgid "Your auto response has been set!"
msgstr "Autosvar er aktiveret!"
msgid "You already have an auto response configured!"
msgstr "Du har allerede et autosvar indstillet!"
#: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87
msgid "The passwords that you supplied don't match!<br />Or are empty!"
msgstr "Adgangskoderne er ikke ens!<br />Eller er tomme!"
#: postfixadmin_forward.php:70 postfixadmin_forward.php:152
msgid "To"
msgstr "Til"
#: postfixadmin_changepass.php:101
msgid "Unable to change your password!"
msgstr "Kan ikke ændre adgangskoden!"
#: postfixadmin_changepass.php:75
msgid "You didn't supply your current password!"
msgstr "Du glemte at skrive din nuværende adgangskode!"
#: postfixadmin_changepass.php:96
msgid "Your password has been changed!"
msgstr "Din adgangskode er ændret!"
msgid "Password current"
msgstr "Nuværende adgangskode"
msgid "Password new"
msgstr "Ny adgangskode"
msgid "Password new again"
msgstr "Ny adgangskode (igen)"
msgid "Please sign out and log back again with your new password!"
msgstr "Log af og log ind igen med din nye adgangskode!"
msgid "I will be away from <date> until <date>. For urgent matters you can contact <contact person>."
msgstr "Jeg er ikke tilstede i perioden <dato> til <dato>. I nødstilfælde kan <kontaktperson> kontaktes."

@ -1,127 +0,0 @@
# postfixadmin - Plugin for Squirrelmail.
# Copyright (C) 2004 FLORIAN KIMMERL
# This file is distributed under the same license as the PACKAGE package.
# Florian Kimmerl <info@spacekoeln.de>, 2004.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.3-1.4\n"
"POT-Creation-Date: 2004-01-28 16:32+0100\n"
"PO-Revision-Date: 2004-01-28 16:32+0100\n"
"Last-Translator: FLORIAN KIMMERL <info@spacekoeln.de>\n"
"Language-Team: GERMAN <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
#: setup.php
msgid "Forwarding"
msgstr "Weiterleitungen"
msgid "Here you can create and edit E-Mail forwards."
msgstr "Hier können Sie E-Mail-Weiterleitungen erstellen und bearbeiten."
msgid "Set an OUT OF OFFICE message or auto responder for your mail."
msgstr "Hier können Sie den Abwesenheits-Assistenten konfigurieren."
msgid "Change your mailbox password."
msgstr "Hier können Sie Passwort ändern. Nach der Änderung müssen Sie sich neu anmelden!"
#: postfixadmin_changepass.php
msgid "Alias"
msgstr "E-Mail"
msgid "Change Password"
msgstr "Passwort ändern"
msgid "Change your login password"
msgstr "Ändern Sie Ihr Zugangspasswort für POP3/IMAP"
#: postfixadmin_forward.php
msgid "Edit Alias"
msgstr "E-Mail Weiterleitungen bearbeiten"
msgid "Edit an alias* for your domain.<br />One entry per line."
msgstr "Bearbeiten Sie hier Ihre E-Mail Weiterleitungen*.<br />Ein Eintrag pro Zeile."
msgid "The email address that you have entered is not valid:"
msgstr "Die angegebene E-Mail-Adresse ist ungültig:"
msgid "Unable to locate alias!"
msgstr "Ihre Weiterleitungen können nicht angefordert werden! Versuchen Sie es später erneut."
msgid "Unable to modify the alias!"
msgstr "Ihre Weiterleitungen können nicht modifiziert werden! Versuchen Sie es später erneut."
msgid "*Additional forward-aliase always recieve messages BBC!"
msgstr "*Zusätzliche Weiterleitungen erhalten alle Nachrichten als Kopie (BCC)!"
msgid "Alias successfully changend!"
msgstr "Weiterleitungen wurden erfolgreich geändert!"
#: postfixadmin_vacation.php
msgid "Auto Response"
msgstr "Abwesenheits-Assistent"
msgid "Going Away"
msgstr "Ich bin weg"
msgid "Coming Back"
msgstr "Ich bin zurück"
msgid "Options"
msgstr "Optionen"
msgid "Out of Office"
msgstr ""
msgid "Subject"
msgstr "Betreff"
msgid "Body"
msgstr "Nachrichtentext"
msgid "Your auto response has been removed!"
msgstr "Iher Abwesenheits-Nachricht wurde deaktiviert!"
msgid "Your auto response has been set!"
msgstr "Ihre Abwesenheits-Nachricht wurde aktiviert!"
msgid "You already have an auto response configured!"
msgstr "Ihre Abwesenheits-Nachricht ist bereits aktiviert!"
msgid "back"
msgstr "zurück"
#: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87
msgid "The passwords that you supplied don't match!<br />Or are empty!"
msgstr "Die beiden neuen Passwörter stimmen nicht überein!<br />Oder die Felder wurden nicht ausgefüllt!"
#: postfixadmin_forward.php:70 postfixadmin_forward.php:152
msgid "To"
msgstr "An"
#: postfixadmin_changepass.php:101
msgid "Unable to change your password!"
msgstr "Ihr Passwort kann nicht geändert werden!"
#: postfixadmin_changepass.php:75
msgid "You didn't supply your current password!"
msgstr "Ihr aktuelles Passwort wurde nicht angegeben oder ist falsch!"
#: postfixadmin_changepass.php:96
msgid "Your password has been changed!"
msgstr "Ihr Passwort wurde ergolgreich geändert!"
msgid "Password current"
msgstr "Passwort aktuell"
msgid "Password new"
msgstr "Passwort neu"
msgid "Password new again"
msgstr "Passwort neu nochmal"
msgid "Please sign out and log back again with your new password!"
msgstr "Bitte melden Sie sich hier ab und loggen sich mit Ihrem neuen Passwort erneut ein! "

@ -1,135 +0,0 @@
# postfixadmin - Plugin for Squirrelmail.
# Copyright (C) 2004 FLORIAN KIMMERL
# This file is distributed under the same license as the PACKAGE package.
# Florian Kimmerl <info@spacekoeln.de>, 2004.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.3-1.4\n"
"POT-Creation-Date: 2004-01-28 16:32+0100\n"
"PO-Revision-Date: 2004-01-28 16:32+0100\n"
"Last-Translator: FLORIAN KIMMERL <info@spacekoeln.de>\n"
"Language-Team: HUNGARIAN <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
#: setup.php
msgid "Forwarding"
msgstr "Levéltovábbítás"
msgid "Here you can create and edit E-Mail forwards."
msgstr "Itt tudod létrehozni és szerkeszteni az E-mail továbbításokat."
msgid "Set an OUT OF OFFICE message or auto responder for your mail."
msgstr "Itt lehet beállítani az automatikus válasz levél szövegét, ha az ember távol van."
msgid "Change your mailbox password."
msgstr "Itt tudod megváltoztatni a belépéshez szükséges jelszót."
#: postfixadmin_changepass.php
msgid "Alias"
msgstr "E-mail"
msgid "Change Password"
msgstr "Jelszó megváltoztatása"
msgid "Change your login password"
msgstr "Bejelentkezési jelszó megváltoztatása"
#: postfixadmin_forward.php
msgid "Edit Forward"
msgstr "Levéltovábbítás szerkesztése"
msgid "Edit Alias"
msgstr "Levéltovábbítás szerkesztése"
msgid "The email address that you have entered is not valid:"
msgstr "Az E-mail cím amit beírtál hibás:"
msgid "Unable to locate alias!"
msgstr "Hiba az e-mail címmel."
msgid "Unable to modify the alias!"
msgstr "A módosítás sikertelen!"
msgid "Alias successfully changed!"
msgstr "A módosítás sikeres!"
#: postfixadmin_vacation.php
msgid "Auto Response"
msgstr "Automatikus válasz"
msgid "Going Away"
msgstr "Házonkívül vagyok"
msgid "Coming Back"
msgstr "Visszajöttem"
msgid "Options"
msgstr "Opciók"
msgid "Out of Office"
msgstr "Házonkívül"
msgid "Subject"
msgstr "Tárgy"
msgid "Body"
msgstr "Levéltörzs"
msgid "Your auto response has been removed!"
msgstr "Az automatikus válasz törölve lett!"
msgid "Your auto response has been set!"
msgstr "Az automatikus válasz be lett állítva!"
msgid "You already have an auto response configured!"
msgstr "Már létezik egy automatikus válasz!"
#: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87
msgid "The passwords that you supplied don't match!<br />Or are empty!"
msgstr "A jelszavak nem egyeznek!<br />Vagy üresen hagytad a mezõket!"
#: postfixadmin_changepass.php:101
msgid "Unable to change your password!"
msgstr "A jelszó megváltoztatása sikertelen!"
#: postfixadmin_changepass.php:75
msgid "You didn't supply your current password!"
msgstr "Az aktuális jelszó nem megfelelõ!"
#: postfixadmin_changepass.php:96
msgid "Your password has been changed!"
msgstr "A jelszó változtatása sikeres volt!"
msgid "Password current"
msgstr "Aktuális jelszó"
msgid "Password new"
msgstr "Új jelszó"
msgid "Password new again"
msgstr "Új jelszó mégegyszer"
msgid "Please sign out and log back again with your new password!"
msgstr "Kérjük, jelentkezzen ki, majd újra be az új jelszavával!"
msgid "I will be away from <date> until <date>. For urgent matters you can contact <contact person>."
msgstr "Házonkívül leszek <date> és <date> között. Sürgõs esetben értesítendõ: <contact person>."
msgid "One copy always goes to"
msgstr "Egy másolat mindig ide"
msgid "Another copy also goes to"
msgstr "További másolatok ide"
msgid "Enter an email address (or addresses) where you would like an additional copy of messages addressed to you sent.<br> Enter only one address per line."
msgstr "Sorolja fel azokat az e-mail címeket, amelyekre az Önhöz érkezõ leveleket továbbítani szeretné.<br>Soronként csak egy címet adjon meg!"
msgid "A copy of each message will go to both your mailbox and the forwarded address(es)."
msgstr "Minden Önnek címzett levél meg fog érkezni a saját postafiókjába és a továbbított e-mail címekre is."
msgid "To remove a Forward, simply delete its line from the text box."
msgstr "Ahhoz, hogy töröljön egy továbbítást, ki kell törölnie az adott sort a felsorolásból."

@ -1,129 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2004-01-29 17:35+0100\n"
"PO-Revision-Date: 2010-02-19 11:30+0100\n"
"Last-Translator: valentina <ruggiolona@tiscali.it>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: setup.php
msgid "Forwarding"
msgstr "Inoltro E-MAIL"
msgid "Here you can create and edit E-Mail forwards."
msgstr "Qui puoi creare e modificare l'inoltro dell' E-MAIL."
msgid "Set an OUT OF OFFICE message or auto responder for your mail."
msgstr "Imposta un messaggio OUT OF OFFICE / ASSENTE o un risponditore automatico per la tua mail."
msgid "Change your mailbox password."
msgstr "Modifica la tua password di accesso alla mail"
#: postfixadmin_changepass.php
msgid "Alias"
msgstr "Alias"
msgid "Change Password"
msgstr "Modifica password"
msgid "Change your login password"
msgstr "Modifica la tua password di accesso"
#: postfixadmin_forward.php
msgid "Edit Alias"
msgstr "Modifica Alias"
msgid "Edit an alias* for your domain.<br />One entry per line."
msgstr "Modifica un Alias per il tuo dominio.<br />Un record per linea."
msgid "The email address that you have entered is not valid:"
msgstr "L'indirizzo email che hai inserito non è corretto:"
msgid "Unable to locate alias!"
msgstr "Impossibile trovare l'alias!"
msgid "Unable to modify the alias!"
msgstr "Impossibile modificare l'alias!"
msgid "*Additional forward-aliase always recieve messages BBC!"
msgstr "* L'inoltro ad un alias aggiuntivo comporta l'invio del messaggio in BCC!"
msgid "Alias successfully changend!"
msgstr "Alias modificato correttamente!"
#: postfixadmin_vacation.php
msgid "Auto Response"
msgstr "Risponditore automatico"
msgid "Going Away"
msgstr "Going Away"
msgid "Coming Back"
msgstr "Coming Back"
msgid "Options"
msgstr "Opzioni"
msgid "Out of Office"
msgstr "Out of Office/Assente"
msgid "Subject"
msgstr "Oggetto"
msgid "Body"
msgstr "Messaggio"
msgid "Your auto response has been removed!"
msgstr "Il risponditore automatico è stato disattivato!"
msgid "Your auto response has been set!"
msgstr "Il risponditore automatico è stato configurato!"
msgid "You already have an auto response configured!"
msgstr "Hai gia configurato il risponditore automatico !"
#: postfixadmin_changepass.php:81
#: postfixadmin_changepass.php:87
msgid "The passwords that you supplied don't match!<br />Or are empty!"
msgstr "Le password inserite non coincidono!<br />O i campi sono vuoti!"
#: postfixadmin_forward.php:70
#: postfixadmin_forward.php:152
msgid "To"
msgstr "A"
#: postfixadmin_changepass.php:101
msgid "Unable to change your password!"
msgstr "Impossibile modificare la password"
#: postfixadmin_changepass.php:75
msgid "You didn't supply your current password!"
msgstr "Non hai indicato la password attuale!"
#: postfixadmin_changepass.php:96
msgid "Your password has been changed!"
msgstr "La tua password è stata modificata!"
msgid "Password current"
msgstr "Password attuale"
msgid "Password new"
msgstr "Nuova password"
msgid "Password new again"
msgstr "Insierisci nuovamente la nuova password"
msgid "Please sign out and log back again with your new password!"
msgstr "Per favore fai log out e riaccedi alla tua mail con la nuova password!"
msgid "I will be away from <date> until <date>. For urgent matters you can contact <contact person>."
msgstr "Mi dispiace sarò assente dal <date> al <date>. Per richieste urgenti vi prego di contattare <nome e indirizzo email>. I will be away from <date> until <date>. For urgent matters you can contact <contact person>."

@ -1,131 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: postfixadmin-squirrelmail 2.1.0\n"
"POT-Creation-Date: 2007-11-16 17:35+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Johan <johan@double-l.nl>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
#: setup.php
msgid "Forwarding"
msgstr "Doorsturen"
msgid "Here you can create and edit E-Mail forwards."
msgstr "Hier kunt u uw doorstuur adres bewerken"
msgid "Set an OUT OF OFFICE message or auto responder for your mail."
msgstr "Configureer hier uw automatisch beantwoorden"
msgid "Change your mailbox password."
msgstr "Verander uw wachtwoord"
#: postfixadmin_changepass.php
msgid "Alias"
msgstr "Alias"
msgid "Change Password"
msgstr "Verander wachtwoord"
msgid "Change your login password"
msgstr "Verander uw login wachtwoord"
#: postfixadmin_forward.php
msgid "Edit Forwards"
msgstr "Bewerk aliassen"
msgid "Edit an alias* for your email address.<br />One entry per line."
msgstr "Bewerk uw alias(sen) voor uw emailadres.<br />1 alias per regel."
msgid "The email address that you have entered is not valid:"
msgstr "Het ingevoerde adres is geen geldig adres"
msgid "Unable to locate alias!"
msgstr "Niet in staat opgeven alias te vinden!"
msgid "Unable to modify the alias!"
msgstr "Niet in staat de alias aan te passen"
msgid "*Additional forward-aliases always receive messages BBC!"
msgstr "Aliassen ontvangen altijd per BCC! "
msgid "To remove an alias, simply delete its line from the text box."
msgstr "Verwijder de regel om de alias(sen) te verwijderen."
msgid "Alias successfully changed!"
msgstr "Alias succesvol aangepast"
#: postfixadmin_vacation.php
msgid "Auto Response"
msgstr "Automatisch beantwoorden"
msgid "Going Away"
msgstr "Ik ben weg, schakel Out of Office IN"
msgid "Coming Back"
msgstr "Ik ben terug, schakel Out of Office UIT"
msgid "Options"
msgstr "Opties"
msgid "Out of Office"
msgstr "Out of office"
msgid "Subject"
msgstr "Onderwerp"
msgid "Body"
msgstr "Tekst"
msgid "Your auto response has been removed!"
msgstr "Uw automatisch beantwoorden is verwijderd!"
msgid "Your auto response has been set!"
msgstr "Uw automatisch beantwoorden is geactiveerd!"
msgid "You already have an auto response configured!"
msgstr "Automatisch beantwoorden is al geconfigureerd!"
#: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87
msgid "The passwords that you supplied don't match!<br />Or are empty!"
msgstr "De wachtwoorden komen niet overeen!<br />Of er is geen wachtwoord opgegeven!"
#: postfixadmin_forward.php:70 postfixadmin_forward.php:152
msgid "To"
msgstr "Aan"
#: postfixadmin_changepass.php:101
msgid "Unable to change your password!"
msgstr "Niet in staat uw wachtwoord te wijzigen!"
#: postfixadmin_changepass.php:75
msgid "You didn't supply your current password!"
msgstr "U moet uw huidige wachtwoord opgeven!"
#: postfixadmin_changepass.php:96
msgid "Your password has been changed!"
msgstr "Uw wachtwoord is gewijzigd!"
msgid "Password current"
msgstr "Huidig wachtwoord"
msgid "Password new"
msgstr "Nieuw wachtwoord"
msgid "Password new again"
msgstr "Nieuw wachtwoord nogmaals"
msgid "Please sign out and log back again with your new password!"
msgstr "Log uit en opnieuw in met het nieuwe wachtwoord"
msgid "I will be away from <date> until <date>. For urgent matters you can contact <contact person>."
msgstr "Ik ben niet aanwezig van <datum> tot <datum>. Voor dringende zaken kunt u contact opnemen met <Contact persoon>."

@ -1,132 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2004-01-29 17:35+0100\n"
"PO-Revision-Date: 2007-07-20 20:46+0100\n"
"Last-Translator: Krzysztof Laska <krzysiek@dip.pl>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
#: setup.php
msgid "Forwarding"
msgstr "Przekazywanie"
msgid "Here you can create and edit E-Mail forwards."
msgstr "Tutaj mo¿esz ustawiæ i edytowaæ opcje przekazywania wiadomo¶ci"
msgid "Set an OUT OF OFFICE message or auto responder for your mail."
msgstr "Ustaw wiadomo¶æ wysy³an± nadawcom podczas Twojej nieobecno¶ci (Vacation)"
msgid "Change your mailbox password."
msgstr "Zmieñ has³o do swojego konta pocztowego"
#: postfixadmin_changepass.php
msgid "Alias"
msgstr "Konto"
msgid "Change Password"
msgstr "Zmieñ has³o"
msgid "Change your login password"
msgstr "Zmieñ has³o do swojego konta pocztowego"
#: postfixadmin_forward.php
msgid "Edit Alias"
msgstr "Edytuj adresy do przekazywania"
msgid "Edit an alias* for your domain.<br />One entry per line."
msgstr "Edytuj forward* dla swojego konta. <br/> Ka¿dy adres w nowym wierszu."
msgid "The email address that you have entered is not valid:"
msgstr "Adres e-mail jaki poda³e¶ jest niepoprawny:"
msgid "Unable to locate alias!"
msgstr "Nie mo¿na zlokalizowaæ aliasu!"
msgid "Unable to modify the alias!"
msgstr "Nie mo¿na zmodyfikowaæ aliasu!"
msgid "*Additional forward-aliase always recieve messages BBC!"
msgstr "*Wszystkie dodatkowe adresy zawsze odbieraj± wiadomo¶ci przesy³ane jako BCC! Ca³a poczta jest przekazywana i nie jest przechowywana na koncie podstawowym!"
msgid "Alias successfully changend!"
msgstr "Zmiana zachowana!"
msgid "To remove an alias, simply delete it's line from the text box."
msgstr "¯eby wy³±czyæ forward na dane konto po prostu usuñ liniê z adresem na który nie chcesz ju¿ przekazywaæ poczty."
#: postfixadmin_vacation.php
msgid "Auto Response"
msgstr "Autoodpowied¼"
msgid "Going Away"
msgstr "W³±cz autoodpowied¼"
msgid "Coming Back"
msgstr "Wy³±cz autoodpowied¼"
msgid "Options"
msgstr "Opcje"
msgid "Out of Office"
msgstr "Autoodpowied¼"
msgid "Subject"
msgstr "Temat"
msgid "Body"
msgstr "Tre¶æ"
msgid "Your auto response has been removed!"
msgstr "Twoja autoodpowied¼ zosta³a wy³±czona!"
msgid "Your auto response has been set!"
msgstr "Twoja autoodpowied¼ zosta³a w³±czona!"
msgid "You already have an auto response configured!"
msgstr "Masz ju¿ skonfigurowan± autoodpowied¼!"
#: postfixadmin_changepass.php:81
#: postfixadmin_changepass.php:87
msgid "The passwords that you supplied don't match!<br />Or are empty!"
msgstr "Has³a które poda³e¶ nie pasuj± lub s± puste!"
#: postfixadmin_forward.php:70
#: postfixadmin_forward.php:152
msgid "To"
msgstr "Do"
#: postfixadmin_changepass.php:101
msgid "Unable to change your password!"
msgstr "Nie mo¿na zmieniæ has³a!"
#: postfixadmin_changepass.php:75
msgid "You didn't supply your current password!"
msgstr "Nie poda³e¶ aktualnego has³a!"
#: postfixadmin_changepass.php:96
msgid "Your password has been changed!"
msgstr "Twoje has³o zosta³o zmienione!"
msgid "Password current"
msgstr "Bie¿±ce has³o"
msgid "Password new"
msgstr "Nowe has³o"
msgid "Password new again"
msgstr "Powtórz nowe has³o"
msgid "Please sign out and log back again with your new password!"
msgstr "Wyloguj siê i zaloguj z nowym has³em!"
msgid "I will be away from <date> until <date>. For urgent matters you can contact <contact person>."
msgstr "Nie bêdê odbieraæ poczty pomiêdzy <data> a <data>. W sprawach pilnych proszê kontaktowaæ siê z <osoba kontaktowa>"

@ -1,127 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2004-01-29 17:35+0100\n"
"PO-Revision-Date: 2008-10-16 20:30+3\n"
"Last-Translator: Julio Covolato <julio@psi.com.br>\n"
"Language-Team: BRAZILIAN PORTUGUESE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: setup.php
msgid "Forwarding"
msgstr "Encaminhar"
msgid "Here you can create and edit E-Mail forwards."
msgstr "Aqui Voc&ecirc; pode criar e editar alias."
msgid "Set an OUT OF OFFICE message or auto responder for your mail."
msgstr "Configurar mensagem de f&eacute;rias para seu email."
msgid "Change your mailbox password."
msgstr "Troque a senha de seu email."
#: postfixadmin_changepass.php
msgid "Alias"
msgstr ""
msgid "Change Password"
msgstr "Mudar Senha"
msgid "Change your login password"
msgstr "Mude sua senha de login"
#: postfixadmin_forward.php
msgid "Edit Alias"
msgstr "Editar Alias"
msgid "Edit an alias* for your domain.<br />One entry per line."
msgstr "Editar um alias* para seu dom&iacute;nio.<br /> Uma entrada por linha."
msgid "The email address that you have entered is not valid:"
msgstr "Este endere&ccedil;o de email informado n&atilde;o &eacute; v&aacute;lido:"
msgid "Unable to locate alias!"
msgstr "Alias n&atilde;o encontrado!"
msgid "Unable to modify the alias!"
msgstr "Imposs&iacute;vel modificar o alias!"
msgid "*Additional forward-aliase always recieve messages BBC!"
msgstr "*Alias adicionais sempre recebem mensagens em BCC"
msgid "Alias successfully changend!"
msgstr "Alias alterado com sucesso!"
#: postfixadmin_vacation.php
msgid "Auto Response"
msgstr "Auto resposta"
msgid "Going Away"
msgstr "Ativar"
msgid "Coming Back"
msgstr "Desativar"
msgid "Options"
msgstr "Op&ccedil;&otilde;es"
msgid "Out of Office"
msgstr "Fora do escrit&oacute;rio"
msgid "Subject"
msgstr "Assunto"
msgid "Body"
msgstr "Mensagem"
msgid "Your auto response has been removed!"
msgstr "Sua auto resporta foi removida!"
msgid "Your auto response has been set!"
msgstr "Sua auto resposta foi ativada!"
msgid "You already have an auto response configured!"
msgstr "Voc&ecirc; ainda tem uma auto resposta ativa"
#: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87
msgid "The passwords that you supplied don't match!<br />Or are empty!"
msgstr "A senha digitada n&atilde;o confere!<br />Ou est&aacute; vazia"
#: postfixadmin_forward.php:70 postfixadmin_forward.php:152
msgid "To"
msgstr "Para"
#: postfixadmin_changepass.php:101
msgid "Unable to change your password!"
msgstr "Imposs&iacute;vel alterar a sua senha!"
#: postfixadmin_changepass.php:75
msgid "You didn't supply your current password!"
msgstr "Voc&ecirc; n&atilde;o forneceu a sua senha atual!"
#: postfixadmin_changepass.php:96
msgid "Your password has been changed!"
msgstr "Sua senha foi alterada com sucesso!"
msgid "Password current"
msgstr "senha atual"
msgid "Password new"
msgstr "Nova senha"
msgid "Password new again"
msgstr "Confirme a nova senha"
msgid "Please sign out and log back again with your new password!"
msgstr "Por favor, saia e entre novamente no webmail com a nova senha"
msgid "I will be away from <date> until <date>. For urgent matters you can contact <contact person>."
msgstr "Estarei fora do escrit&oacute;rio entre os dias <data> e <data> do m&ecirc;s de <m&ecirc;s>.<br /> Qualquer mensagem urgente, favor enviar para o email <email>."

@ -1,127 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2004-01-29 17:35+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: setup.php
msgid "Forwarding"
msgstr ""
msgid "Here you can create and edit E-Mail forwards."
msgstr ""
msgid "Set an OUT OF OFFICE message or auto responder for your mail."
msgstr ""
msgid "Change your mailbox password."
msgstr ""
#: postfixadmin_changepass.php
msgid "Alias"
msgstr ""
msgid "Change Password"
msgstr ""
msgid "Change your login password"
msgstr ""
#: postfixadmin_forward.php
msgid "Edit Alias"
msgstr ""
msgid "Edit an alias* for your domain.<br />One entry per line."
msgstr ""
msgid "The email address that you have entered is not valid:"
msgstr ""
msgid "Unable to locate alias!"
msgstr ""
msgid "Unable to modify the alias!"
msgstr ""
msgid "*Additional forward-aliase always recieve messages BBC!"
msgstr ""
msgid "Alias successfully changend!"
msgstr ""
#: postfixadmin_vacation.php
msgid "Auto Response"
msgstr ""
msgid "Going Away"
msgstr ""
msgid "Coming Back"
msgstr ""
msgid "Options"
msgstr ""
msgid "Out of Office"
msgstr ""
msgid "Subject"
msgstr ""
msgid "Body"
msgstr ""
msgid "Your auto response has been removed!"
msgstr ""
msgid "Your auto response has been set!"
msgstr ""
msgid "You already have an auto response configured!"
msgstr ""
#: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87
msgid "The passwords that you supplied don't match!<br />Or are empty!"
msgstr ""
#: postfixadmin_forward.php:70 postfixadmin_forward.php:152
msgid "To"
msgstr ""
#: postfixadmin_changepass.php:101
msgid "Unable to change your password!"
msgstr ""
#: postfixadmin_changepass.php:75
msgid "You didn't supply your current password!"
msgstr ""
#: postfixadmin_changepass.php:96
msgid "Your password has been changed!"
msgstr ""
msgid "Password current"
msgstr ""
msgid "Password new"
msgstr ""
msgid "Password new again"
msgstr ""
msgid "Please sign out and log back again with your new password!"
msgstr ""
msgid "I will be away from <date> until <date>. For urgent matters you can contact <contact person>."
msgstr ""

@ -1,125 +0,0 @@
<?php
require_once(dirname(__FILE__) . '/common.php');
$xmlrpc = get_xmlrpc();
$user = $xmlrpc->getProxy('user');
global $username;
do_header();
$USERID_USERNAME = $username;
$tmp = preg_split('/@/', $USERID_USERNAME);
$USERID_DOMAIN = $tmp[1];
$stMessage = '';
$tMessage = '';
$pPassword_admin_text = '';
$pPassword_password_current_text = '';
$pPassword_password_text = '';
$error = 0;
if ($_SERVER['REQUEST_METHOD'] == "POST") {
//$pPassword_password_text = _("pPassword_password_text");
$fPassword_current = $_POST['fPassword_current'];
$fPassword = $_POST['fPassword'];
$fPassword2 = $_POST['fPassword2'];
$username = $USERID_USERNAME;
if (!$user->login($_SESSION['username'], $_POST['fPassword_current'])) {
$error = 1;
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$pPassword_password_current_text = _("You didn't supply your current password!");
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
}
$min_length = 0;
if (isset($CONF['min_password_length'])) {
$min_length = $CONF['min_password_length'];
}
if (empty($fPassword) or ($fPassword != $fPassword2) or ($min_length > 0 && strlen($fPassword) < $min_length)) {
$error = 1;
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
if (empty($fPassword)) {
$pPassword_password_text .= _("The passwords that you supplied are empty!");
}
if ($fPassword != $fPassword2) {
$pPassword_password_text .= _("The passwords that you supplied don't match!");
}
if ($min_length > 0 && strlen($fPassword) < $min_length) {
$pPassword_password_text .= _("The password you supplied is too short!");
}
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
}
if ($error != 1) {
$success = $user->changePassword($fPassword_current, $fPassword);
if ($success) {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$tMessage = _("Your password has been changed!");
$stMessage = _("Please sign out and log back again with your new password!");
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
} else {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$tMessage = _("Unable to change your password!");
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
}
}
}
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
echo "<table bgcolor=\"$color[0]\" align=\"center\" width=\"95%\" cellpadding=\"1\" cellspacing=\"0\" border=\"0\">
<tr>
<td align=\"center\"><b>". _("Options") ." - ". _("Change Password")." </b>
<table align=\"center\" width=\"100%\" cellpadding=\"5\" cellspacing=\"0\" border=\"0\">
<tr><td bgcolor=\"$color[4]\" align=\"center\"><br>
<table align=\"center\" width=\"95%\" cellpadding=\"4\" cellspacing=\"0\" border=\"0\"><tr>
<td bgcolor=\"$color[3]\" align=\"center\"><b>" ._("Change your login password") ."\n
</b></td>
</tr>
<tr>
<td bgcolor=\"$color[0]\" align=\"center\"><form name=\"mailbox\" method=\"post\">
<b>$tMessage<b><font color=red><br>
<a href=\"../../src/signout.php\" target=\"_top\">$stMessage</a>
".$pPassword_admin_text."\n
".$pPassword_password_current_text."\n
".$pPassword_password_text."\n
</b><table width=\"95%\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\">
<tr>
<td width=\"37%\"><b>". _("Alias") . ":\n</td>
<td width=\"63%\">{$_SESSION['username']}</td>
</tr>
<tr>
<td><b>". _("Password current"). ":\n</td>
<td><input type=\"password\" name=\"fPassword_current\" size=\"30\" /></td>
</tr>
<tr>
<td><b>". _("Password new"). ":\n</td>
<td><input type=\"password\" name=\"fPassword\" size=\"30\" /></td>
</tr>
<tr>
<td><b>". _("Password new again"). ":\n</td>
<td><input type=\"password\" name=\"fPassword2\" size=\"30\" /></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type=\"submit\" name=\"submit\" value=\"" ._("Change Password") . "\" /></td>
<td>&nbsp;</td>
</tr>
</table>
<TT></TT></FORM></td>
</tr><tr><td bgcolor=\"$color[4]\" align=\"left\">&nbsp;</td>
</tr></table><BR>
</td>
</tr></table></td></tr></table>";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');

@ -1,159 +0,0 @@
<?php
require_once(dirname(__FILE__) . '/common.php');
$USERID_USERNAME = $username;
$tmp = preg_split('/@/', $USERID_USERNAME);
$USERID_LOCALPART = $tmp[0];
$USERID_DOMAIN = $tmp[1];
$xmlrpc = get_xmlrpc();
$alias = $xmlrpc->getProxy('alias');
do_header();
// Normal page request (GET)
if ($_SERVER['REQUEST_METHOD'] == "GET") {
$row = $alias->get();
if ($row === false) {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$tMessage = _("Unable to locate alias!");
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
exit(0);
}
}
if ($_SERVER['REQUEST_METHOD'] == "POST") {
$pEdit_alias_goto = _("To");
$fGoto = $_POST['fGoto'];
// reform string into a list...
$goto = preg_replace('/\r\n/', ',', $fGoto);
$goto = preg_replace('/[\s]+/i', '', $goto);
$goto = preg_replace('/\,*$/', '', $goto);
$array = preg_split('/,/', $goto);
$error = 0;
// check that we have valid addresses in the list
foreach ($array as $key => $email_address) {
if (empty($email_address)) {
unset($array[$key]);
continue;
}
if (check_email($email_address) != "") {
$error = 1;
$tGoto = $goto;
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$tMessage = _("The email address that you have entered is not valid:") . " $email_address</font>";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
}
}
if ($error != 1) {
$flag = 'forward_and_store'; // goto = $USERID_USERNAME;
$success = $alias->update($array, $flag);
if (!$success) {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$tMessage = _("Unable to modify the alias!");
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
} else {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
echo "<p align=center><b>". _("Alias successfully changed!"). "\n</b></p>";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
echo "<p align=center><a href=\"javascript:history.go(-1)\">". _("Click here to go back") ."</a></p>";
exit;
}
}
}
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
if (!isset($tMessage)) {
$tMessage = '';
}
echo "<table bgcolor=\"$color[0]\" align=\"center\" width=\"95%\" cellpadding=\"1\" cellspacing=\"0\" border=\"0\">
<tr>
<td align=\"center\" bgcolor=\"$color[0]\" colspan=\"2\">
<b>". _("Options") ." - ". _("Edit Alias"). " </b>
<table align=\"center\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">
<tr>
<td bgcolor=\"$color[4]\" align=\"center\">
<table align=\"center\" width=\"100%\">
<tr>
<td align=\"left\">". _("Edit an alias* for your email address.<br />One entry per line."). " </td>
</tr>
<tr>
<td align=\"left\">". _("*Additional forward-aliases always receive messages BCC!"). "\n
</tr>
<tr>
<td align=\"left\">" . _("To remove an alias, simply delete its line from the text box.") . "</td>
</tr>
</table>
<table align=\"center\" width\"95%\" cellpadding=\"5\" cellspacing=\"1\">
<form name=\"mailbox\" method=\"post\">
<tr>
<td bgcolor=\"$color[3]\" align=\"center\"><b>". _("Edit Forwards"). "</b>
</td>
</tr>
<tr>
<td bgcolor=\"$color[5]\" align=\"center\">$tMessage
<table cellpadding=\"5\" cellspacing=\"1\">
<tr>
<th align=\"left\">". _("Alias"). ":\n
</th>
<td align=\"left\">" . $_SESSION['username'] . "</td>
</tr>
<tr>
<th>&nbsp;</th>
<td>&nbsp;</td>
</tr>
<tr>
<th align=\"left\" valign=\"top\">". _("To"). ":\n</th>
<td>
<textarea rows=\"8\" cols=\"50\" name=\"fGoto\">";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
$aliases = $alias->get();
foreach ($aliases as $address) {
if ($address == "" || $address == null) {
continue;
}
print "$address\n";
}
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
echo "
</textarea>
</td>
</tr>
<tr>
<th>&nbsp;</th>
<td>&nbsp;</td>
</tr>
<tr>
<th>&nbsp;</th>
<td align=\"left\"colspan=\"2\">
<input type=\"submit\" name=\"submit\" value=\"" . _("Edit Alias") . "\">
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</td>
</tr>
</table>
</td></tr>
</table>
";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');

@ -1,141 +0,0 @@
<?php
require_once(dirname(__FILE__) . '/common.php');
$xmlrpc = get_xmlrpc();
$vacation = $xmlrpc->getProxy('vacation');
$VACCONFTXT = _("I will be away from <date> until <date>. For urgent matters you can contact <contact person>.");
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
$VACCONF = <<<EOM
$VACCONFTXT
EOM;
do_header();
$USERID_USERNAME = $username;
$tmp = preg_split('/@/', $USERID_USERNAME);
$USERID_DOMAIN = $tmp[1];
if ($_SERVER['REQUEST_METHOD'] == "GET") {
$details = $vacation->getDetails();
if ($vacation->checkVacation()) {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$tMessage = _("You already have an auto response configured!");
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
echo "<table bgcolor=\"#b8cbdc\" align=\"center\" width=\"95%\" cellpadding=\"1\" cellspacing=\"0\" border=\"0\"><tr>
<td align=\"center\"><b>". _("Options") ." - ". _("Auto Response") ."</b>
<table align=\"center\" width=\"100%\" cellpadding=\"5\" cellspacing=\"0\" border=\"0\">
<tr><td bgcolor=\"$color[4]\" align=\"center\"><br>
<table align=\"center\" width=\"70%\" cellpadding=\"4\" cellspacing=\"0\" border=\"0\"><tr>
<td bgcolor=\"$color[3]\" align=\"center\"><b>". _("Auto Response") ."\n
</b></td></tr><tr>
<td bgcolor=\"$color[0]\" align=\"center\"><form name=\"vacation\" method=\"post\">
<table width=\"95%\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\">
<tr>
<td><center>$tMessage<p></center></td>
</tr>
<tr>
<td> <div align=\"center\">
<input type=\"submit\" name=\"fBack\" value=\"" . _("Coming Back"). "\" />
</div></td>
</tr>
</table>
<TT></TT></FORM>
</td>
</tr><tr><td bgcolor=\"$color[4]\" align=\"left\">&nbsp;</td>
</tr></table><BR></td></tr></table></td></tr></table>";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
} else {
$tSubject = "Out of Office";
$tSubject = $details['subject'];
$VACCONF = $details['body'];
$tMessage = '';
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
echo "<table bgcolor=\"$color[0]\" align=\"center\" width=\"95%\" cellpadding=\"1\" cellspacing=\"0\" border=\"0\">
<tr>
<td align=\"center\"><b>". _("Options") ." - ". _("Auto Response") ." </b>
<table align=\"center\" width=\"100%\" cellpadding=\"5\" cellspacing=\"0\" border=\"0\">
<tr><td bgcolor=\"$color[4]\" align=\"center\"><br>
<table align=\"center\" width=\"70%\" cellpadding=\"4\" cellspacing=\"0\" border=\"0\"><tr>
<td bgcolor=\"$color[3]\" align=\"center\"><b>" . _("Auto Response") ."\n
</b></td></tr><tr>
<td bgcolor=\"$color[0]\" align=\"center\"><form name=\"vacation\" method=\"post\">$tMessage
<table width=\"95%\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\"><tr>
<td width=\"23%\">". _("Subject") .":\n</td>
<td width=\"2%\">&nbsp;</td>
<td width=\"69%\"><input type=\"text\" name=\"fSubject\" value=\"" . $tSubject . "\" /></td>
<td width=\"2%\">&nbsp;</td>
<td width=\"4%\">&nbsp;</td>
</tr><tr>
<td>". _("Body") .":\n</td>
<td>&nbsp;</td>
<td><textarea rows=\"10\" cols=\"80\" name=\"fBody\">$VACCONF\n
</textarea></td><td>&nbsp;</td><td>&nbsp;</td></tr><tr><td>&nbsp;</td><td>&nbsp;</td>
<td><input type=\"submit\" name=\"fAway\" value=\"" . _("Going Away") . "\" /></td>
<td>&nbsp;</td><td>&nbsp;</td></tr>
</table><TT></TT></FORM></td>
</tr><tr><td bgcolor=\"$color[4]\" align=\"left\">&nbsp;</td>
</tr></table><BR></td></tr></table></td></tr></table>";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
}
}
if ($_SERVER['REQUEST_METHOD'] == "POST") {
$fBack = null;
$fAway = null;
foreach (array('fBack', 'fAway', 'fSubject', 'fBody') as $key) {
$$key = null;
if (isset($_POST[$key])) {
$$key = $_POST[$key];
}
}
if (!empty($fBack)) {
$success = $vacation->remove();
if (!$success) {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$tMessage = _("Unable to update your auto response settings!");
echo "<p>This may signify an error; please contact support (1)</p>";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
} else {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
echo "<p align=center><b>". _("Your auto response has been removed!") ."</b></p>";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
}
}
if (!empty($fAway)) {
// add record into vacation
$success = $vacation->setAway($fSubject, $fBody);
if (!$success) {
$error = 1;
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$tMessage = _("Unable to update your auto response settings!");
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
} else {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
echo "<p align=center><b>". _("Your auto response has been set!") ."</b></p>";
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
}
}
}

@ -1,62 +0,0 @@
<?php
// vim:ts=4:sw=4:et
if (!defined('SM_PATH')) {
die("Invalid internal state (don't access file directly)");
}
include_once(SM_PATH . 'functions/i18n.php');
function squirrelmail_plugin_init_postfixadmin() {
include(dirname(__FILE__) . '/config.php');
global $squirrelmail_plugin_hooks;
$squirrelmail_plugin_hooks['optpage_register_block']['postfixadmin'] = 'postfixadmin_optpage_register_block';
}
function postfixadmin_version() {
return '2.3.0';
}
function postfixadmin_optpage_register_block() {
// Gets added to the user's OPTIONS page.
global $optpage_blocks;
global $AllowVacation;
global $AllowChangePass;
// if ( !soupNazi() ) {
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
$optpage_blocks[] = array(
'name' => _("Forwarding"),
'url' => '../plugins/postfixadmin/postfixadmin_forward.php',
'desc' => _("Here you can create and edit E-Mail forwards."),
'js' => false
);
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
if ($AllowVacation) {
$optpage_blocks[] = array(
'name' => _("Auto Response"),
'url' => '../plugins/postfixadmin/postfixadmin_vacation.php',
'desc' => _("Set an OUT OF OFFICE message or auto responder for your mail."),
'js' => false
);
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
}
bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale');
textdomain('postfixadmin');
if ($AllowChangePass) {
$optpage_blocks[] = array(
'name' => _("Change Password"),
'url' => '../plugins/postfixadmin/postfixadmin_changepass.php',
'desc' => _("Change your mailbox password."),
'js' => false
);
bindtextdomain('squirrelmail', SM_PATH . 'locale');
textdomain('squirrelmail');
}
}

@ -1,193 +1,185 @@
<?php <?php
/*
Virtual Mail Delete
by George Vieira <george at citadelcomputer dot com dot au>
You can run this from your crontab with something like
0 4 * * * * vmail php -q virtualmaildel.php >/dev/null
Changes:
2017.08.31 updated to use PHP mysqli extension.
2018.02.23 removing Sieve filters if exists.
Tadas Ustinavičius <tadas at ring dot lt> ( https://github.com/postfixadmin/postfixadmin/pull/70 )
*/
$CONF = [];
// Either, uncomment this (and change to work)
//require_once('/path/to/postfixadmin/config.inc.php');
// OR uncomment this.
/*
$CONF = [
'database_host' => 'localhost',
'database_user' => 'someone',
'database_password' => 'something',
'database_name' => 'mydb'
];
*/
$MAKE_CHANGES = false; // change to true when you're happy this isn't going to trash your server.
if (empty($CONF)) {
die("\nPlease configure me\n\n");
}
// Where's the homedir accounts stored. (GET THIS RIGHT OTHERWISE IT THINK NONE EXIST AND DELETES ALL)
$homedir = '/home/virtual';
if (! is_dir($homedir)) {
die("Cannot find home directory for virtual mailboxes in $homedir\n");
}
//
// Recursive Delete Function
// //
function deldir($dir) { // Virtual Mail Delete
$current_dir = opendir($dir); // by George Vieira <george at citadelcomputer dot com dot au>
while ($entryname = readdir($current_dir)) { //
if (is_dir("$dir/$entryname") and ($entryname != "." and $entryname!="..")) { // You can run this from your crontab with something like
deldir("{$dir}/{$entryname}"); //
} elseif ($entryname != "." and $entryname!="..") { // 0 4 * * * * vmail php -q virtualmaildel.php >/dev/null
unlink("{$dir}/{$entryname}");
} //
} // Setup location of postfixadmin config files. Needed to login to mysql
closedir($current_dir); //
@rmdir($dir); $conf = '/home/httpd/mail/admin/config.inc.php';
}
//
// Where's the homedir accounts stored. (GET THIS RIGHT OTHERWISE IT THINK NONE EXIST AND DELETES ALL)
//
$homedir = '/home/virtual';
//
// Make sure everything is everything before continuing
//
if ( ! file_exists( $conf ) )
die( "Cannot find config file $conf\n" );
if ( ! is_dir( $homedir ) )
die( "Cannot find home directory for virtual mailboxes in $homedir\n" );
//
// Load mysql authentication from postfixadmin
//
include( $conf );
//
// Recursive Delete Function
//
function deldir($dir)
{
$current_dir = opendir($dir);
while($entryname = readdir($current_dir))
{
if(is_dir("$dir/$entryname") and ($entryname != "." and $entryname!=".."))
{
deldir("${dir}/${entryname}");
}
elseif($entryname != "." and $entryname!="..")
{
unlink("${dir}/${entryname}");
}
}
closedir($current_dir);
@rmdir(${dir});
}
// --- Main Start --- // --- Main Start ---
$dir = []; //
// Get list of directories
// //
// Get list of directories $fr = opendir( $homedir );
// while ( ($domain = readdir($fr)) !== false)
$fr = opendir($homedir); {
//
// TODO: Would glob($homedir . '/**/*/new') be somewhat quicker/shorter/less effort? // Check if it's a dir
//
while (($domain = readdir($fr)) !== false) { if ( $domain != "." and $domain != ".." and filetype($homedir .'/'. $domain) == "dir" )
// {
// Check if it's a dir //
// // Open the (assumed) DOMAIN directory
if ($domain == "." || $domain == ".." || filetype($homedir .'/'. $domain) != "dir") { //
continue; $ff = opendir( $homedir .'/'. $domain );
} while ( ($user = readdir($ff)) !== false)
// {
// Open the (assumed) DOMAIN directory //
// // Check for directories assuming it's a user account
$ff = opendir($homedir .'/'. $domain); //
while (($user = readdir($ff)) !== false) { if ( $user!="." and $user!=".." and filetype($homedir .'/'. $domain .'/'. $user) == "dir" )
// {
// Check for directories assuming it's a user account //
// // if the dir 'new' exists inside then it's an account
if ($user == "." || $user == ".." || filetype($homedir .'/'. $domain .'/'. $user) != "dir") { //
continue; if ( file_exists($homedir .'/'. $domain .'/'. $user .'/'. "new") )
} {
$dir[$domain][$user] = "";
// }
// if the dir 'new' exists inside then it's an account else
// {
if (file_exists($homedir .'/'. $domain .'/'. $user .'/'. "new")) { //
$dir[$domain][$user] = ""; // Alert that the dir doesn't have a 'new' dir, possibly not an account. Leave it.
} else { //
// echo "UNKNOWN : " . $homedir ."/". $domain ."/". $user ."/new NOT FOUND. Possibly not an account. Leaving untouched\n";
// Alert that the dir doesn't have a 'new' dir, possibly not an account. Leave it. }
// }
echo "UNKNOWN : " . $homedir ."/". $domain ."/". $user ."/new NOT FOUND. Possibly not an account. Leaving untouched\n"; }
} }
} }
} //
// // OK, got an array of accounts from the dir, Now connect to the DB and check them
// OK, got an array of accounts from the dir, Now connect to the DB and check them //
// $conx = mysql_connect( $CONF['database_host'],$CONF['database_user'],$CONF['database_password'] );
$conx = mysqli_connect($CONF['database_host'], $CONF['database_user'], $CONF['database_password'], $CONF['database_name']); //
// // Is there a problem connecting?
// Is there a problem connecting? //
// if ( $conx != false )
if (! $conx || mysqli_connect_errno()) { {
echo "DB connection failed." . mysqli_connect_error() . "\n"; //
die("Problem connecting to the database. "); // Select the database
} //
mysql_select_db( $CONF['database_name'] , $conx) or die ("Can't access database postfix : " . mysql_error());
//
// Select all mailboxes to verify against dirs listed in array //
// // Select all mailboxes to verify against dirs listed in array
$query = "SELECT * FROM mailbox"; //
$result = mysqli_query($conx, $query); $query = "SELECT * FROM mailbox";
$result = mysql_query( $query );
//
// Query the mailbox table //
// // Query the mailbox table
if (! $result) { //
die("Failed to query mailbox table."); if ( $result != false )
} {
//
// // Fetch the list of results
// Fetch the list of results //
// while ( $row = mysql_fetch_assoc( $result ) )
while ($row = mysqli_fetch_assoc($result)) { {
// //
// Pull apart the maildir field, needed to figure out the directory structure to compare // Pull apart the maildir field, needed to figure out the directory structure to compare
// //
$strip = explode("/", $row['maildir']); $strip = explode("/",$row['maildir']);
// //
// Unset the array if it exists. This stops it being erased later. // Unset the array if it exists. This stops it being erased later.
// //
unset($dir[ $strip[0] ][ $strip[1] ]); unset( $dir[ $strip[0] ][ $strip[1] ] );
} }
// //
// If there are results. unset the domain too. // If there are results. unset the domain too.
// //
if (count($dir[$strip[0]])==0 and mysqli_num_rows($result)>0) { if ( count($dir[$strip[0]])==0 and mysql_num_rows($result)>0 )
unset($dir[$strip[0]]); unset( $dir[$strip[0]] );
} }
else
// die( "Failed SELECT in mailboxes\n" );
// OK, time to clean up. All known users/domains have been removed from the list. }
// else
die( 'Cannot connect to the database!\n' );
//
// If the array still exists (incase nothing there) //
// // OK, time to clean up. All known users/domains have been removed from the list.
if (is_array($dir)) { //
//
// Go through each dir //
// // If the array still exists (incase nothing there)
foreach ($dir as $key => $value) { //
// if ( is_array($dir) )
// Is this a user array? {
// //
if (!is_array($value)) { // Go through each dir
continue; //
} foreach ( $dir as $key => $value )
{
// //
// Go through and nuke the folders // Is this a user array?
// //
foreach ($value as $user => $value2) { if ( is_array( $value) )
// Nuke.. need any more explanations? {
$path = $homedir . '/' . $key . '/' . $user; //
$sieve_path = $homedir . '/.sieve/' . $key . '/' . $user; // Go through and nuke the folders
$sieve_exists = file_exists($sieve_path); //
// check if user has Sieve filters created foreach ( $value as $user => $value2 )
if ($MAKE_CHANGES) { {
deldir($path); //
if ($sieve_exists) { // Nuke.. need any more explanations?
deldir($sieve_path); //
} echo "REMOVING : " . $homedir."/".$key."/".$user."\n" ;
} else { deldir( $homedir."/".$key."/".$user ) ;
echo " - Would recursively delete : $path \n"; }
if ($sieve_exists) { }
echo " - Would recursively delete Sieve filters : $sieve_path \n"; }
} }
} //
} // And we are outta here....
} //
} echo "Cleanup process completed\n";
?>
echo "Cleanup process completed\n";

@ -1,775 +1,26 @@
# Postfix Admin # Postfix Admin
#
# LICENSE
# This source file is subject to the GPL license that is bundled with
# this package in the file LICENSE.TXT.
#
# Further details on the project are available at :
# http://www.postfixadmin.com or http://postfixadmin.sf.net
# #
# LICENSE # Last update:
# This source file is subject to the GPL license that is bundled with # $Id$
# this package in the file LICENSE.TXT.
#
# Further details on the project are available at http://postfixadmin.sf.net
Version X.X - master
-------------------------------------------------
- Improve vacation.pl (better utf-8 support)
- Improve DB connections (PDO, SSL)
- Add sha512.b64 password hash support (see https://github.com/postfixadmin/postfixadmin/issues/58)
- Add support for password expiration (see https://github.com/postfixadmin/postfixadmin/pull/200 and README.password_expiration )
- Improve ADDITIONS/postfixadmin-mailbox-postcreate.sh
- Add Date header into smtp_from() (see https://github.com/postfixadmin/postfixadmin/issues/203 )
- PostgreSQL fixes ( 1e158245d613fd1d8d5c1d59e26e940eb71f5b32 )
- vacation.pl fixes (perl libraries; see https://github.com/postfixadmin/postfixadmin/pull/194 )
- Add bootstrap theme (default not changed yet) ( see https://github.com/postfixadmin/postfixadmin/pull/172 )
- Improve CSV export from list.php
- Various misc. changes from static analysis (psalm)
- Update installation instructions. (see: https://github.com/postfixadmin/postfixadmin/issues/189 https://github.com/postfixadmin/postfixadmin/issues/188 )
- Encryption improvements (see: php_crypt / encrypt_difficulty in sample config)
- Sqlite improvements (see https://github.com/postfixadmin/postfixadmin/issues/177 and https://github.com/postfixadmin/postfixadmin/issues/176 )
- MySQL 8 compatibility (see https://github.com/postfixadmin/postfixadmin/pull/175 )
- Internally the database functions have been refactored to use PDO rather than the lower level mysql_, mysqli_, pg_ etc functions. ( see: https://github.com/postfixadmin/postfixadmin/pull/231 )
- Usage of dovecot deliver as fetchmail mda
Version 3.2 - 2018/05/02
-------------------------------------------------
- move public facing stuff into public/, this allows us to stop exposing
templates_c/ etc. to the world (but also means you'll need to adjust your
webserver config)
- enable users to reset their passwords by mail or SMS
($CONF['forgotten_user_password_reset'],
$CONF['forgotten_admin_password_reset'], $CONF['sms_send_function'])
- allow local alias targets (without @domain) - see #134
- add $CONF['edit_alias'] to disable "edit_alias" function for users
- add php_crypt $CONF["encrypt"] option (see #170 for examples)
- add random_compat phar (see: https://github.com/paragonie/random_compat) to
support random_int()/random_string() in older PHP versions.
- add support for MySQL connections over SSL
- language updates: sk, ja, nl, bg, fr, cz
- update bundled smarty library (lib/smarty to 3.1.32; includes security fixes)
- split up pacrypt() into different functions; add some minimal test coverage
- add id autoincrement field to log table (#89)
- add token to login.php to prevent CSRF
- lots of bugfixes and code cleanup
- drop unused code in postfixadmin-cli
- introduce PHP-CS-Fixer to enforce code style
- vacation.pl:
- avoid answering to more known autoresponders
- add $no_vacation_pattern to avoid sending autoresponders based on the To:
address
- replace Deprecated Mail::Sender by Email::Sender
- use MIME:EncWords
- remove unused MIME::Base64
- add docker repo, see https://github.com/postfixadmin/docker
Version 3.1 - 2017/06/25
-------------------------------------------------
- broadcast improvements:
- allow to send to mailboxes only
- allow to send to only some domains
- allow domain admins to send to their domains - new config option
$CONF['sendmail_all_admins']
- don't send to inactive mailboxes or aliases
- update squirrelmail plugin
- better static DB connection cache to avoid hundreds of mysqli connection
when doing lots of escape_string() calls
- use $CONF[page_size] in viewlog.php
- fix problems with utf8mb4 as default charset in setup.php/upgrade.php
- fix default for $CONF[create_mailbox_subdirs_hostoptions]
- get rid of variables.inc.php (and initialize variables where needed)
- add favicon to fix session handling in chrome (#44)
- add check to ensure templates_c/ exists and is writeable
- recommend usage of config.local.php in setup.php
- remove php4 constructor from cNav_bar (page browser)
- update fr.lang
Version 3.0.2 - 2017/02/08 - SVN r1895
-------------------------------------------------
- SECURITY: don't allow to delete protected aliases (CVE-2017-5930, PR#23)
- fix VacationHandler for PostgreSQL
- 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'
- fix date formatting in non-english languages when using PostgreSQL
- debian packaging: improve dependencies, remove old templates_c/ files
- various small fixes
Version 3.0.1 - 2016/09/19 - SVN r1870
-------------------------------------------------
- add missing Smarty files to Debian package
(no changes to PostfixAdmin, therefore only released as Debian packages)
Version 3.0 - 2016/09/11 - SVN r1861
-------------------------------------------------
- add sqlite backend option
- add configurable smtp helo (CONF["smtp_client"])
- new translation: ro (Romanian)
- language update: tw, cs, de
- fix escaping in gen_show_status() (could be used to DOS list-virtual by
creating a mail address with special chars)
- add CSRF protection for POST requests
- list.tpl: base edit/editactive/delete links in list.tpl on $RAW_item to
avoid double escaping, and fix some corner cases
- editform.tpl: add {if} block for description column for easier customization
- use smarty html_options instead of select_options()
- remove advice about using SetEnv for database password
- include_once(config.local.php) instead of include()ing it to prevent include
loops if someone copies config.inc.php to config.local.php
- vacation.pl: encode wide-chars utf8 in mail body, mime-decode original subject
- fix db_quota_text() for postgresql (concat() vs. ||)
- change default date for 'created' and 'updated' columns from 0000-00-00
(which causes problems with MySQL strict mode) to 2000-01-01
- allow punicode even in TLDs
- update Smarty to 3.1.29
- add checks to login.php and cli to ensure database layout is up to date
- whitelist '-1' as valid value for postfixadmin-cli
- don't stripslashes() the password in pacrypt
- various small bugfixes
Version 3.0 beta3 (2.93) - 2015/09/26 - SVN r1802
-------------------------------------------------
Summary of major changes:
- add list.php and list.tpl for displaying lists
- based on *Handler $struct, which means list view can now be customized with
$CONF[*_struct_hook] functions (columns with display_in_list and non-empty
label will be displayed)
- add CSV export
- replaces list-domain.php, list-admin.php and fetchmail.php (including their
*.tpl files) and the alias and alias domain lists in list-virtual
- improved / more detailed search support by using URL parameters
(list.php?search[field]=value, optionally also ?searchmode[field]=< -
no pretty search form yet, limited to fields the user/admin can access)
- only display search input box if search fields are specified in *handler
(that effectively means no search box for admin, domain and fetchmail listings)
- can also be used for users (non-admins)
- add FetchmailHandler (replaces fetchmail.php and its template), which also
means postfixadmin-cli can configure fetchmail jobs now
- add $CONF['fetchmail_struct_hook']
- remove unused $CONF['users_domain_controle']
PFAHandler:
- new field types:
- enma - associative array (value => displayed value), must be specified in
the "options" column
- html - raw HTML, used for mailbox status markers which include HTML tags
- b64p - passwords stored as base64, used by FetchmailHandler
- vtxt, vnum - "virtual", read-only text/integer
- quot - formatted quota ("5/10", read-only)
- automatically skip quot, vtxt and vnum fields in store()
- add handling of users (non-admins), including permission checks
- add and use $this->label_field and $this->label for nicer messages
- add $this->order_by to allow ordering by any field(s)
- add getMsg() function (needed by list.php)
- add $msg['can_create'] (true by default, false will hide the 'create' button)
- add $is_superadmin to make admin vs. superadmin easier to handle
- add $can_edit and $can_delete (only available in edit/delete mode, set by
init() based on the '_can_edit' and '_can_delete' from database query)
- add $searchfields[] (list of fields to search by default, $search[_])
- add $this->msg['show_simple_search'] (true if $searchfields is non-empty)
- split off build_select_query() (also used for pagebrowser) from read_from_db()
and add support for $search['_'] (searching in $searchfields[])
- read_from_db(), getList(): add $searchmode parameter (_before_ $limit and
$offset!) to be able to use query different query modes, not only "="
- add getPagebrowser() (returns an array of pagebrowser keys)
AdminHandler:
- switch to using list.php (replaces list-admin.php)
DomainHandler:
- reduce required permissions to 'admin', restrict write operations to superadmins
- add optical quota indicators for aliases, mailboxes and domain quota
- fix counting of aliases for domains without any mailbox
- use list.php for displaying domain list (replaces list-domain.php)
MailboxHandler:
- check_quota(): deny creating an unlimited mailbox if domain quota is set
- storemore(): store maildir in the correct variable to fix running
mailbox_postedit script (bug#342)
AliasHandler:
- read_from_db_postprocess(): disable _can_edit and _can_delete for default
aliases if special_alias_control is off and not superadmin
- add 'status' column, move gen_show_status handling for aliases from
list-virtual into AliasHandler db_read_from_db_potprocess()
- change getList() to work with empty $condition
- add getPagebrowser() to filter out mailboxes
edit.php:
- Newer PHP versions (noticed with 5.6.6) don't include empty fields in
$_POST, which broke changing a field to empty. Make sure all !isset()
fields are set to ''.
- for not-set bool values, set $values instead of the (wrong) $inp_values
- add user (non-admin) mode
delete.php:
- allow users (non-admins) to use delete.php (not used in PostfixAdmin yet)
list-virtual:
- use AliasHandler, AliasdomainHandler and list.tpl for aliases and alias
domains (the mailbox list still uses the old code)
- replace $alias_pagebrowser_query and the create_page_browser() call
with $handler->getPagebrowser()
- adjust search to use ?search[_]=...
- drop $check_alias_owner variable and check_alias_owner() call
(replaced by the code added in AliasHandler)
misc:
- translation updates: cs (patch#126), pl (by marcin-github), sv (patch#128)
- add CliScheme.php to display the database scheme (for usage in upgrade.php)
- error_log() a warning if nameserver queries in check_domain() take more than 2
seconds in total
- add functions db_quota_text() and db_quota_percent() to generate SQL queries
for used quota ("x/y" and percentage)
- pacol(): replace $not_in_db with $multiopt - the remaining parameters can be
specified as associative array (backwards-compatible). Also add $linkto parameter
- db_where_clause(): add $additional_raw_where and $searchmode parameters,
split query into WHERE and HAVING
- delete no longer used check_alias_owner() function
- display "view log" menu entry only if logging is enabled (patch#127)
- smarty.inc.php assign(): additionally provide the unsanitized values as RAW_$key
- setup.php: after creating a superadmin, display a note that the setup is done
and it's possible to login now
- setup.php: stop relying on subversion keyword for database upgrades
- explictly set session_cache_limiter to nocache (bug#347)
- fetchmail.pl: honor the (newly added) active column
- change fetchmail.date field to date (no auto-update) (bug#351)
- several small changes and fixes at various places - too many to list them here
Version 3.0 beta2 (2.92) - 2014/10/28 - SVN r1706
-------------------------------------------------
- AliasHandler: don't clean goto field when making alias inactive (bug#316)
- list-virtual: display quota even if $CONF[used_quotas] == NO (bug#307)
- vacation.pl: fix postgresql queries in vacation.pl (bug#315)
- fix query in AliasHandler getList() which caused an empty list and breaks
deletion of aliases in MariaDB (bug#313, bug#325)
- fetchmail.pl: fix ssl extra options (cert check, cert path, fingerprint)
- fix logging (run setup.php to fix old log entries) (bug#317)
- fetchmail.php: change error_reporting() to exclude E_NOTICE (bug#322)
- translation updates: fr (patch#123), nl (patch#122)
- $CONF[default_aliases] can now use the new domain as alias target (patch#124)
- check that vacation start/end date are not in the past (patch#122)
- update vacation INSTALL.TXT with more secure locations
- update Smarty to 3.1.21
Version 3.0 beta1 (2.91) - 2014/05/06 - SVN r1670
-------------------------------------------------
Summary of major changes:
- new command-line interface "postfixadmin-cli"
- major rewrite:
- move lots of code into *Handler classes, which are used by web and
command-line interface
- replace various edit-*.php and create-*.php with a generic editform
(edit.php/editform.tpl)
- this also means it's easy to customize forms, add fields etc.
(see $CONF['*_struct_hook'])
- lots of code cleanup, remove/merge lots of duplicated code and templates
- use smarty for templates
- add ability to choose activation date, end date and reply interval for
vacation message
- various enhancements everywhere
- redesign login page, list and edit pages (goodbye, green!) and make them wider
- several new config options and changed defaults
- NOTE: changes from the 2.3.x releases also apply to this version
new config options:
- $CONF['language_hook']
Hook function to override or add translations to $PALANG.
Example hook function included (commented out).
- $CONF['password_validation'] - array with regular expressions to check
if a password is valid/good enough.
The default configuration enforces:
- minimum length 5 characters/digits/whatever
- at least 2 characters
- at least 2 digits
- $CONF['*_struct_hook'] - make $struct in the *Handler classes customizeable
- $CONF['vacation_choice_of_reply'] - list of reply interval options
- $CONF['domain_quota'] - total quota per domain
- $CONF['theme_custom_css'] - to add some custom CSS without editing the
default CSS file
- $CONF['motd_*'] - replaces motd*.txt
changed config defaults (with their new default value):
- $CONF['database_type'] = 'mysqli';
- $CONF['dovecotpw'] = "/usr/sbin/doveadm pw";
$CONF['new_quota_table'] = 'YES'; (for dovecot 2)
- $CONF['domain_path'] = 'YES'; $CONF['domain_in_mailbox'] = 'NO';
(results in domain.tld/username/ maildirs)
- $CONF['alias_control'] = 'YES'; $CONF['alias_control_admin'] = 'YES';
- $CONF['backup'] = 'NO';
- $CONF['show_status']='YES'; $CONF['show_status_key']='YES';
$CONF['show_undeliverable']='YES'; $CONF['show_popimap']='YES';
$CONF['show_undeliverable_exceptions'] - "gmail.com" removed
- $CONF[*_post*_script] - add empty defaults
- $CONF['admin_email'] = ''
IMPORTANT: If set, this will be used as mail sender for all mails
(2.3.x used the currently logged in admin's username in most cases).
$CONF['admin_email'] = '' will match the 2.3.x behaviour.
removed config options:
- $CONF['min_password_length'] - now handled in /.{5}/ in
$CONF['password_validation']
- $CONF['postfix_admin_url'] - relative paths are now used everywhere
list-virtual.php:
- display percentage of quota usage
- display alias domains less confusing (using From/To)
- list-virtual can now display only mailboxes, only aliases or only alias
domains - or all in one page as in 2.3
- extreme speedup of page browser in list-virtual if a large number of
mailboxes or aliases exist
- include search support (replaces search.php and brings various bug fixes
for free)
- fix: delivery to mailbox with a recipient delimiter (mailbox+foo@domain)
was marked as "forward only"
- fix: don't mark mailboxes with vacation active as undeliverable
- fix: undeliverable targets were not flagged if another target pointed to a
domain in $CONF[show_undeliverable_exceptions]
fetchmail.php, fetchmail.pl:
- add sslcertck, sslcertpath, sslfingerprint fields/check
(sslcertpath and sslfingerprint require $CONF[fetchmail_extra_options]
because they don't have input validation)
functions.inc.php
- allowed_quota: if $CONF[quota] == NO, just return 0 (unlimited)
- authentification_get_username() - honor POSTFIXADMIN_SETUP to avoid
a redirect to login.php after creating an admin with setup.php and to
get "SETUP.PHP" for db_log()
- check_domain(), check_email(): instead of calling flash_error(),
return string with error message - or empty string if everything is ok
- check_email():
- replace $CONF[vacation_domain] only at the end of the mail address
- don't trim() mail address to avoid that aliases starting with a space are
allowed. This fixes http://sourceforge.net/p/postfixadmin/bugs/210/
- check_language(): remove things like ";q=0.8" before checking if
a language exists
- check_owner():
- escape_string() $username and $domain to prevent SQL injections
- db_pgsql() - new function to replace lots of
"if ($CONF[database_type] == 'pgsql')) checks
- db_delete(): allow to specify additional conditions for the WHERE clause
- db_get_boolean(): allow 0 and 1 as parameters, not only boolean true/false
- db_log():
- allow log actions create_admin and edit_admin
- add edit_admin_state and delete_admin as comment/reminder that they
should also be logged
- db_query(): error_log() failed query
- db_where_clause($condition, $struct) - new function to create a WHERE clause
(bool values are converted with db_get_boolean() based on $struct)
- _flash_string():
- also accept an array of messages, not only a string
- html-escape messages to fix XSS if the message contains user-supplied input
- generate_password(): make generated password always 8 chars long
(instead of $CONF['min_password_length'])
- get_domain_properties(): use DomainHandler (function result mostly
unchanged, only difference: instead of quota_sum in bytes it now
returns total_quota in MB)
- list_domains_for_admin():
- rewrite to work for superadmins also (will list all domains now
instead of "ALL"), which means we can drop the admin vs. superadmin
check at various places
- pacrypt():
- no longer escape_string() the result. This fixes
http://sourceforge.net/p/postfixadmin/bugs/218/
- for 'system' encryption, use full hashed password as salt
https://sourceforge.net/p/postfixadmin/bugs/2/
- dovecot:*:
- add support for dovecot *-CRYPT passwords (needs dovecot >= 2.1)
- allow "." in dovecot method (to allow a suffix like ".b64")
- Also, the {METHOD} part is no longer removed (passwords without
{METHOD} still work)
- remove_from_array() - new function
- safesession() - new function (like safeget(), but for $_SESSION)
- smtp_mail(): error_log() the error message if fsockopen() fails
- table_by_key() now always prepends $CONF['database_prefix']
NOTE: If you have/had an incomplete database_tables array and use
$CONF['database_prefix'], you might need to rename the affected tables
manually (add the database_prefix in their name).
- moved several functions to the *Handler classes
- deleted no longer used functions:
- admin_exist()
- authentication_is_admin()
- authentication_is_user()
- boolconf() (moved to Config::bool())
- check_string()
- create_admin()
- check_alias() (moved to AliasHandler->create_allowed())
- db_boolean_to_int()
- domain_exist()
- get_admin_properties()
- get_mailbox_properties()
- get rid of global $table_* variables, use table_by_key() instead
PFAHandler.php:
- parent class for all *Handler classes
- contains code shared between all classes
AdminHandler.php:
- Handler class for admins
- for now, set the superadmin column and add "ALL" in domain_admins to
keep the database backwards-compatible with 2.3.x
AdminpasswordHandler.php:
- used for the "change password" form for admins
DomainHandler.php
- handler class for domains
- delete(): do not allow to delete a domain if it is an alias domain target
AliasdomainHandler.php:
- handler class for alias domains
- alias domains can now be edited
AliasHandler.php:
- rewrite based on PFAHandler
- we even get a "deliver to local mailbox" checkbox :-)
- only allow @domain as target if $this->id is a catchall
- remove deprecated functions:
- get()
- hasStoreAndForward()
- update()
- is_mailbox_alias()
- is_vacation_address()
- hasAliasRecord()
MailboxHandler (previously named UserHandler in 2.3):
- rewrite based on PFAHandler
- drop old __construct(), view() and change_pass()
- replace check of old password in change_pw() with $this->login
- delete(): also cleanup fetchmail, quota and quota2 tables
- always check password with validate_password()
- always display correct available quota (using allowed_quota())
- do not escape the password coming from $_POST. Fixes
http://sourceforge.net/p/postfixadmin/bugs/218/
VacationHandler:
- rewrite based on PFAHandler (not useable yet)
- add ability to choose activation date, end date and reply interval for
vacation message - http://sourceforge.net/p/postfixadmin/patches/111/
vacation.pl:
- allow to use original subject in vacation reply subject ("Re: $SUBJECT")
http://sourceforge.net/p/postfixadmin/patches/117/
- encode subject - https://sourceforge.net/p/postfixadmin/bugs/272/ ,
https://sourceforge.net/p/postfixadmin/patches/119/
- add a friendly from address to vacation messages ($friendly_from)
- make error handling if we cannot send the reply more robust
- add $smtp_client config option to specify the helo name
- added custom noreply detection ($noreply_pattern, $custom_noreply_pattern)
Config.php
- new class to store $CONF
- also used to store $PALANG texts (Config::Lang())
- contains functions to read config entries in various ways (bool etc.)
edit.php
- generic edit page for everything (admins, domains, mailboxes, aliases, ...)
- use ?table= parameter to decide what will be edited (basically $tableHandler)
- read handler-specific configuration from $handler->webformConfig()
and use it at various places
- always redirect to edit.php?table=$table after adding an item to
ensure correct initialization for next item
- call $handler->mergeId if $id_field is editable, but not displayed
in form (usecase: merge localpart + domain to address)
- set $form_fields and $id_field later (after $hander->init()) - needed
for AliasHandler to decide if goto_mailbox should be displayed
- only set $values if a field is editable and displayed in the form
editform.tpl:
- generic edit form template, uses $struct to render the form
- implement handling of 'list' fields (<select> with multiple choices
allowed)
- also include alternative implementation with checkboxes (commented out)
upgrade.php
- _pgsql_field_exists(), _mysql_field_exists():
Those functions are always called with the expanded table name - don't
expand it twice. (The better solution would be to change all calling
code to provide non-expanded tablenames, but that's more work.)
- change {BIGINT} to include "NOT NULL DEFAULT 0"
- upgrade_1283(): add a "superadmin" column to the admin table
This is the first step to get rid of the "ALL" dummy domain.
- upgrade_1284(): migrate the ALL domain to the superadmin column
Note: The ALL domain is not (yet) deleted to stay backwards-compatible
for now (will be done in a later upgrade function)
- change {BOOLEAN} to include "default false"
login.php
- when login.php is requested, logout the current admin/user
https://sourceforge.net/p/postfixadmin/bugs/284/
- this also means login.php is now used for logout
- error_log() failed login attemps
https://sourceforge.net/p/postfixadmin/feature-requests/111/
delete.php, editactive.php:
- require token for CSRF protection, see
https://sourceforge.net/p/postfixadmin/bugs/269/
xmlrpc.php:
- adopt to *Handler syntax
- setAway(): add (optional) new parameters for interval_time, activeFrom and
activeUntil - https://sourceforge.net/p/postfixadmin/patches/113/
- change $_SESSION['username'] to $_SESSION['sessid']['username']
*.lang:
- get rid of several duplicate texts
- removed HTML tags from $PALANG texts
- several translation updates
documentation updates:
- SECURITY.TXT: add note about templates_c directory
- DOCUMENTS/POSTFIX_CONF.TXT is now executable and can generate the
mysql_*.cf maps for postfix
- update DOCUMENTS/DOVECOT.TXT for dovecot 2.x
squirrelmail plugin:
- various bugfixes
- documentation update
Debian packaging:
- Changed source format to 3.0 (quilt)
- simplified the DB credential patch and removing ucf registrations on package
purge...
- control: added php5-cli dependency
- rules:
- some permission fixes to postfixadmin-cli scripts
- New target prep: Create a needed tar.gz file to build a non-nativ .dpkg
- New target build-package: Call this target to build a shiny new .dpkg file
- postfixadmin.docs: removed redundant changelog file
- debian/postfixadmin.postrm: Call wwwconfig scripts only if they are existing
Version 2.3.8 - 2015/10/07 - SVN r1814 (postfixadmin-2.3 branch)
----------------------------------------------------------------
- fix query to enable/disable alias in edit-mailbox for PostgreSQL (#311)
- don't prefill username in users/ login on failed logins - fixes (probably
harmless) XSS
- fix show_gen_status() to properly escape mail addresses in query (#356)
- fix escaping in create-admin, create-mailbox and fetchmail templates -
fixes (harmless) XSS on form validation errors
- don't echo the password back to the browser in the fetchmail form
- allow MariaDB in Debian package dependencies
Version 2.3.7 - 2014/02/20 - SVN r1651 (postfixadmin-2.3 branch)
----------------------------------------------------------------
- SECURITY: fix SQL injection in show_gen_status()
- lt.lang, da.lang translation update
- when enabling/disabling a mailbox, also update the corresponding alias
- fix creating superadmin in setup.php with MariaDB (more strict SQL)
- don't trim() mail address to avoid that aliases starting with a space are
allowed. This fixes http://sourceforge.net/p/postfixadmin/bugs/210/ and
https://sourceforge.net/p/postfixadmin/feature-requests/113/
- update regex in check_domain() to support new, longer TLDs like .international
- mark vacation_notification.notified field as latin1 to avoid overlong index
- vacation.pl: encode subject
- vacation.pl: disable use of TLS by default due to a bug in Mail::Sender 0.8.22
(you can re-enable it with $smtp_tls_allowed)
Version 2.3.6 - 2013/01/02 - SVN r1417 (postfixadmin-2.3 branch)
----------------------------------------------------------------
- display domain and mailbox description with correct encoding
- fix footer link
- focus username input field in login form
- fix double inclusion of config.inc.php in setup.php
- fix bool and date handling in fetchmail
Version 2.3.5 - 2012/01/16 - SVN r1335 (postfixadmin-2.3 branch)
----------------------------------------------------------------
- fix SQL injection in pacrypt() (if $CONF[encrypt] == 'mysql_encrypt')
- fix SQL injection in backup.php - the dump was not mysql_escape()d,
therefore users could inject SQL (for example in the vacation message)
which will be executed when restoring the database dump.
WARNING: database dumps created with backup.php from 2.3.4 or older might
contain malicious SQL. Double-check before using them!
- fix XSS with $_GET[domain] in templates/menu.php and edit-vacation
- fix XSS in some create-domain input fields
- fix XSS in create-alias and edit-alias error message
- fix XSS (by values stored in the database) in fetchmail list view,
list-domain and list-virtual
- create-domain: fix SQL injection (only exploitable by superadmins)
- add missing $LANG['pAdminDelete_admin_error']
- don't mark mailbox targets with recipient delimiter as "forward only"
- wrap hex2bin with function_exists() - PHP 5.3.8 has it as native function
Version 2.3.4 - 2011/09/16 - SVN r1180 (postfixadmin-2.3 branch)
----------------------------------------------------------------
- generate more secure random passwords
- squirrelmail plugin: fix typo in variable name
- list-domain: fix SELECT query to work with PgSQL even when using custom fields
- create-domain: force domain name to lowercase to avoid problems with PgSQL
foreign keys
- fix vacation.pl to log to "mail" syslog facility
- error_log() dovecotpw error messages
Version 2.3.3 - 2011/03/14 - SVN r1010 (postfixadmin-2.3 branch)
----------------------------------------------------------------
- create-alias: allow multiple alias targets
- create-alias, edit-alias: prevent input data loss on validation errors
- list-virtual: fix displaying of 'modified' column for aliases when using
postgres
- replaced deprecated split() with preg_split() or explode()
- functions.inc.php: better error messages when database functions are missing
- create domain: fixed typo in variable name that broke the default value for
default aliases
- postgres: changed mailbox.quota, domain.quota and domain.maxquota fields
to bigint to allow mailboxes >4 GB (run setup.php to upgrade your database)
- vacation.pl logged literal $variable instead of the variable content at two
places
- edit-vacation: log enabling/disabling vacation if done by admins
- POSTFIX_CONF.txt: fixed filename for quota map
- config.inc.php: removed double $CONF['database_prefix']
- config.inc.php: fixed comments about domain_post* script parameters
- updated INSTALL.TXT and UPGRADE.TXT
- sk translation update
- some more minor fixes
Version 2.3.2 - 2010/08/24 - SVN r860 (postfixadmin-2.3 branch)
---------------------------------------------------------------
- SUMMARY: PostfixAdmin 2.3.2 is a bugfix-only release for Postfix Admin 2.3.1
- SECURITY: attackers could find out if a admin exists (login pre-filled the
username after "only" a wrong password was entered)
- SECURITY: fix sql injection in list-domain (only exploitable by superadmins)
- alias targets in users/edit-alias are now validated
- invalid alias targets in users/edit-alias are shown to the user again
instead of dropping them
- fix dovecot:* password encryption (was broken in 2.3.1)
- fix displaying used quota for dovecot <= 1.1 (was broken in 2.3.1)
- when deleting a domain that is an alias domain (on the "from" side), the
alias domain is deleted
Version 2.3.1 - 2010/07/09 - SVN r847 (postfixadmin-2.3 branch)
---------------------------------------------------------------
- SUMMARY: PostfixAdmin 2.3.1 is a bugfix-only release for Postfix Admin 2.3.
The only visible change is displaying the alias target for mailboxes which
was a longstanding issue/"missing feature".
The ADDITIONS directory contains some new scripts.
- SECURITY: users could bypass checking the old password when changing the
password by entering a too short new password. Fortunately only
"exploitable" by authentificated users.
- merge in changes to /debain (thanks normes) from trunk
- display alias targets for mailboxes (if $CONF['special_alias_control'] = YES)
- add hook for custom maildir path generation
- add import_users_from_csv.py script (by Simone Piccardi)
- add mailbox_post* scripts for cyrus
- handle dovecot passwords without any tempfile (prevents safe_mode issues)
- fix MySQL 6.0 compatibility
- fix quota display (for dovecot >= 1.2)
- fix short open tags ("<?")
- translation updates and fixes
- documentation updates and fixes
- document commandline parameters for $CONF[*_script] options in config.inc.php
- list-virtual: added error message if the check_owner query returns more
than one result (can happen with pre-2.3 databases and prevents access for
superadmins)
- add in_array() check to avoid that superadmins can enter invalid domains
- fix delete link for alias domains (when on target domain)
- delete values from quota and quota2 table when deleting a mailbox
- fix hardcoded table names in list-domain.php
- fixed edit-alias.php not to drop alias to the mailbox if
special_alias_control = NO
- fix alias handling for mailboxes (special_alias_control vs.
alias_control_admin confusion)
- fix typo in upgrade.php that broke index creation and deletion when using
non-default table names
- fix creating 'ALL' domain (dummy for superadmins) when using non-default
table names
- fix: db_query did not return number of SELECTed rows if query starts with
with whitespace
- check for $CONF['encrypt'] = 'dovecot:md5-crypt' (postfixadmin login not
working because dovecotpw uses a new salt each time), recommend
internal md5crypt instead
- replaced terribly outdated, broken squirrelmail plugin with a fresh version.
Note: The new plugin version requires the Zend framework.
Version 2.3 - 2009/10/24 - SVN r739
-----------------------------------
- automatically create quota tables for dovecot (both 1.0/1.1 and >= 1.2)
- list-virtual can now handle both table formats
- fixed upgrade.php for MySQL 6.0 compability
- changed vacation.pl syslog facility from "user" to "mail"
- added config option for postregsql database port
- added config option to enable/disable XMLRPC interface (default: off)
- Fix check/query for alias with enabled vacation in vacation.pl
- Fix db_get_boolean() to return t/f for postgresql, not true/false
- Fix missing quoting for boolean values in SQL queries at various places
- Allow SHA courier-authlib passwords
- various small bug fixes
- fixed SVN revision for 2.3rc7 in changelog (was r691, should be r694)
Version 2.3rc7 - 2009/07/27 - SVN r694
--------------------------------------
- Fix bug with confd-link.sh debian thing (breakage on Lenny with wwwconfig-common 0.1.2)
- Fix crypt() issue (see https://sourceforge.net/tracker/?func=detail&aid=2814820&group_id=191583&atid=937964 )
Version 2.3rc6 - 2009/07/20 - SVN r689
--------------------------------------
- Updates to vacation.pl
- PHP 5.3 compatibility
- Easier dependencies for .debs - should work on Lenny/Ubuntu etc without issue now.
Version 2.3rc5 - 2009/05/20 - SVN r658
--------------------------------------
- Improvements to the setup process
- Far better Debian packaging (we hope!) which should make installation much, much easier.
- Various bug fixes
- Performance enhancements (or we fixed the regressions ...) in domain listing etc.
Version 2.3rc4 - 2009/04/18 - SVN r632
--------------------------------------
- *Security fix* - on upgrade setup.php is restored; allowing a malicious
user to create their own superadmin account. We've removed the requirement to delete
setup.php, and instead a new config parameter (setup_password) is used to protect access
to this page. Password is encrypted, and setup.php can be used to generate the initial value.
- Fix undefined variables problem(s)
- Fix PostgreSQL date timestamp issues...
Version 2.3rc3 - 2009/04/06 - SVN r611
--------------------------------------
- Minor improvements to the Debian packaging, expect more soon
- Assorted bug fixes
- Partial support for per-user fetchmail.pl support
Version 2.3rc2 - 2009/02/03 - SVN r593
--------------------------------------
- Refactor /users (see /model) and provide XmlRpc interface for remote mail clients
(e.g. squirrelmail-postfixadmin)
- Add dovecotpw support - see:
https://sourceforge.net/tracker/index.php?func=detail&aid=2607332&group_id=191583&atid=937966
- Add unit tests for model/ directory (see /tests)
- Add additional scripts to ADDITIONS
- Documentation updates
- Various language updates
- added ADDITIONS/delete-mailq-by-domain.pl (by Jose Nilton)
- added ADDITIONS/quota_usage.pl (by Jose Nilton) - produces report of quota usage
- added support for courier authlib authentication flavors ($CONF['authlib_default_flavor'])
Only in SVN trunk
--------------------
Version 2.3 Beta - 2009/01/15 - SVN r527 Version 2.3 Beta - 2009/01/15 - SVN r527
----------------------------------------- -----------------------------------------
- added support for domain aliases (from lenix) (can be disabled with $CONF['alias_domain']) - added support for domain aliases (from lenix) (can be disabled with $CONF['alias_domain'])
Important: If you update from a previous version, you'll have to adapt your postfix Important: If you update from a previous version, you'll have to adapt your postfix
configuration (see DOCUMENTS/POSTFIX_CONF.txt) - or just disable alias domain support, configuration (see DOCUMENTS/POSTFIX_CONF.txt) - or just disable alias domain support,
your postfix configuration will continue to work your postfix configuration will continue to work
- updated postfix example configuration for domain aliases and to use the new mysql map format - updated postfix example configuration for domain aliases and to use the new mysql map format
- vacation.pl: - vacation.pl:
- add option for re-notification after definable timeout (patch from Luxten) - add option for re-notification after definable timeout (patch from Luxten)
@ -781,22 +32,14 @@ Version 2.3 Beta - 2009/01/15 - SVN r527
- allow to enter the configuration in /etc/mail/postfixadmin/vacation.conf - allow to enter the configuration in /etc/mail/postfixadmin/vacation.conf
instead of editing vacation.pl directly instead of editing vacation.pl directly
- bump version number of vacation.pl - bump version number of vacation.pl
- added domain-postcreation script support
- added dovecot quota support (documentation + viewing in postfixadmin)
- enhanced mailbox table to make it easier for people to customise where mailboxes live
(new column "local_part")
- enhanced fetchmail.pl script (file locking, syslog logging, configuration file etc)
- added clear error message for non-resolvable domains when creating mailboxes or aliases - added clear error message for non-resolvable domains when creating mailboxes or aliases
- check for non-resolvable domains on domain creation - check for non-resolvable domains on domain creation
- new option $CONF['create_mailbox_subdirs_prefix'] for compatibility with more IMAP servers - new option $CONF['create_mailbox_subdirs_prefix'] for compatibility with more IMAP servers
- added support for mysql encrypt() password encrpytion
- fix "illegal mix of collations" problem in MySQL by explicitely setting the charset everywhere - fix "illegal mix of collations" problem in MySQL by explicitely setting the charset everywhere
- fix: cleanup vacation_notification table when disabling vacation - fix: cleanup vacation_notification table when disabling vacation
- fix: config and fetchmail tables now honor $CONF['database_tables'] - fix: config and fetchmail tables now honor $CONF['database_tables']
- fix: several table names were hardcoded in database creation/update
- fix: "unlimited" and "disabled" for quota and limits were crossed at several places - fix: "unlimited" and "disabled" for quota and limits were crossed at several places
- fix: honor $CONF['default_transport'] even if $CONF['transport'] = "no" (patch by fabiobon) - fix: honor $CONF['default_transport'] even if $CONF['transport'] = "no" (patch by fabiobon)
- fix: transport field is no longer emptied on domain edit if editing transport is disabled
- show links to create mailboxes or alias even on disabled domains - show links to create mailboxes or alias even on disabled domains
- added support for fetchmail's "ssl" option - added support for fetchmail's "ssl" option
- superadmin can now setup fetchmail for all users, not only for himself - superadmin can now setup fetchmail for all users, not only for himself
@ -808,6 +51,10 @@ Version 2.3 Beta - 2009/01/15 - SVN r527
- dropped obsolete VIRTUAL_VACATION/mail-filter script - dropped obsolete VIRTUAL_VACATION/mail-filter script
- translation updates - translation updates
- several small bugfixes - several small bugfixes
- Added domain-postcreation script support
- Added dovecot quota support (documentation + viewing in postfixadmin)
- Enhanced mailbox table to make it easier for people to customise where mailboxes live
- Enhanced fetchmail.pl script (file locking, syslog logging, configuration file etc)
Version 2.2.1.1 - 2008/07/23 - SVN r412 Version 2.2.1.1 - 2008/07/23 - SVN r412
@ -852,20 +99,20 @@ Version 2.2.0 - 2008/04/29
- Added: Slovakian language posted on SourceForge by eszabo - Added: Slovakian language posted on SourceForge by eszabo
- Changed: searches include mailbox.name matches (GregC) - Changed: searches include mailbox.name matches (GregC)
- Fixed: function check_email will ignore vacation_domain if vacation==YES (GregC) - Fixed: function check_email will ignore vacation_domain if vacation==YES (GregC)
- Changed: applied patches from Christian Boltz posted at - Changed: applied patches from Christian Boltz posted at
http://www.cboltz.de/tmp/postfixadmin-3.patch, referenced at http://www.cboltz.de/tmp/postfixadmin-3.patch, referenced at
https://sourceforge.net/tracker/index.php?func=detail&aid=1696647&group_id=191583&atid=937966 (GregC) https://sourceforge.net/tracker/index.php?func=detail&aid=1696647&group_id=191583&atid=937966 (GregC)
- Added: main.php to admin dirctory (GregC) - Added: main.php to admin dirctory (GregC)
- Added: Item "Main" on admin menu (GregC) - Added: Item "Main" on admin menu (GregC)
- Changed: Edit-vacation now edits for admins/superadmins (GregC) - Changed: Edit-vacation now edits for admins/superadmins (GregC)
- Added: Do not store local copy when forward mail. (Mihau) [24] - Added: Do not store local copy when forward mail. (Mihau) [24]
- Added: Virtual Vacation for PostgreSQL. (Tarvin) - Added: Virtual Vacation for PostgreSQL. (Tarvin)
- Added: Virtual Vacation 3.2 (Thanx David) - Added: Virtual Vacation 3.2 (Thanx David)
- Added: SUBJECT tag for Virtual Vacation. - Added: SUBJECT tag for Virtual Vacation.
- Added: Dovecot setup document for Postfix Admin. (Thanx Massimo) - Added: Dovecot setup document for Postfix Admin. (Thanx Massimo)
- Added: SquirrelMail plugin to change_password. - Added: SquirrelMail plugin to change_password.
- Changed: Starting to merge /admin in root. (Mihau) - Changed: Starting to merge /admin in root. (Mihau)
- Changed: Moved some TXT files to DOCUMENTS. - Changed: Moved some TXT files to DOCUMENTS.
- Changed: Updated tw.lang. (Thanx Bruce) - Changed: Updated tw.lang. (Thanx Bruce)
- Fixed: Usage of mysql_real_escape_string(). (Mihau) - Fixed: Usage of mysql_real_escape_string(). (Mihau)
- Fixed: Calculating of quotas. (Mihau) - Fixed: Calculating of quotas. (Mihau)
@ -1063,7 +310,7 @@ Version 1.5.1 -- 2003/06/04
- Added: Option to completely control the stored aliases. (Thanx Alex) - Added: Option to completely control the stored aliases. (Thanx Alex)
- Changed: config.inc.php is renamed to config.inc.php.sample. (Thanx Alex) - Changed: config.inc.php is renamed to config.inc.php.sample. (Thanx Alex)
- Fixed: $PHP_SELF in config.inc.php and my_lib.php. (Thanx Jim) - Fixed: $PHP_SELF in config.inc.php and my_lib.php. (Thanx Jim)
Version 1.5.0 -- 2003/05/28 Version 1.5.0 -- 2003/05/28
---------------------------- ----------------------------
@ -1114,6 +361,3 @@ Version 1.3.8 -- 2003/03/25
Version 1.3.7 -- 2002/12/24 Version 1.3.7 -- 2002/12/24
---------------------------- ----------------------------
- Initial public release of Postfix Admin. - Initial public release of Postfix Admin.
# vim: set expandtab softtabstop=2 tabstop=2 shiftwidth=2:

@ -5,15 +5,20 @@
# Licensed under GPL for more info check GPL-LICENSE.TXT # Licensed under GPL for more info check GPL-LICENSE.TXT
# #
Please follow these steps if your mailserver is used as a backup MX for some REQUIRED!!
(or all) of your domains. ----------
- You are using Postfix 2.0 or higher.
Note: The setup described in this file only checks the domain, not the full - You are using Apache 1.3.27 / Lighttpd 1.3.15 or higher.
mail address. - You are using PHP 4.1 or higher.
You should use "reject_unverified_recipient" in your postfix config or setup - You are using MySQL 3.23 or higher.
"relay_recipient_maps" with a list of valid mail adresses on the primary mx
to avoid that your backup MX accepts mails for non-existing recipient adresses.
Without this, your backup MX might become a backscatter source. READ THIS FIRST!
----------------
When this is an upgrade from Postfix Admin 1.5.4 please read UPGRADE.TXT!!
More information is available on http://high5.net/howto/
1. Modify main.cf 1. Modify main.cf
----------------- -----------------

@ -2,7 +2,6 @@
# Dovecot configuration for Postfix Admin # Dovecot configuration for Postfix Admin
# Originally written by: Massimo <AndyCapp> Danieli # Originally written by: Massimo <AndyCapp> Danieli
# Revised by: Sampsa Hario <shario> for Dovecot v1.0 # Revised by: Sampsa Hario <shario> for Dovecot v1.0
# Revised by: David Goodwin <david@palepurple.co.uk> for Dovecot 2.1.x (2014/01/02)
# #
More complete Dovecot documentation: More complete Dovecot documentation:
@ -11,9 +10,7 @@ http://wiki.dovecot.org/Quota
http://wiki.dovecot.org/Quota/Dict http://wiki.dovecot.org/Quota/Dict
http://www.opensourcehowto.org/how-to/mysql/mysql-users-postfixadmin-postfix-dovecot--squirrelmail-with-userprefs-stored-in-mysql.html http://www.opensourcehowto.org/how-to/mysql/mysql-users-postfixadmin-postfix-dovecot--squirrelmail-with-userprefs-stored-in-mysql.html
Here are the relevant parts of Dovecot v1.0.x configuration for Postfixadmin setup.
Here are the relevant parts of Dovecot v2.1.x configuration for Postfixadmin setup.
Please refer to Dovecot documentation for complete information. Please refer to Dovecot documentation for complete information.
The setup gets userdb and passdb info from MySQL as well as quotas, and The setup gets userdb and passdb info from MySQL as well as quotas, and
@ -24,96 +21,32 @@ be viewed real-time in Postfixadmin.
1. Dovecot setup 1. Dovecot setup
----------------- -----------------
A basic /etc/dovecot/dovecot.conf is as follows, this was generated using 'dovecot -n' on a vanilla install and then default_mail_env = maildir:/usr/local/virtual/%u/
changing to talk to a PostgreSQL or MySQL database.
# BEGIN /etc/dovecot/dovecot.conf: auth default {
# Change this to where your mail root is, this needs to match whatever structure postfix expects.... userdb sql {
# See also: https://wiki.dovecot.org/MailLocation - %d domain, %u full username, %n user part (%u with no domain) # Path for SQL configuration file, see doc/dovecot-sql-example.conf
mail_location = maildir:/var/mail/vmail/%u/ args = /etc/dovecot-mysql.conf
namespace inbox {
inbox = yes
location =
mailbox Drafts {
special_use = \Drafts
}
mailbox Junk {
special_use = \Junk
} }
mailbox Sent { passdb sql {
special_use = \Sent # Path for SQL configuration file, see doc/dovecot-sql-example.conf
args = /etc/dovecot-mysql.conf
} }
mailbox "Sent Messages" {
special_use = \Sent
}
mailbox Trash {
special_use = \Trash
}
prefix =
}
protocols = "imap pop3"
# change to 'no' if you don't have ssl cert/keys, and comment out ssl_cert/ssl_key
ssl = yes
ssl_cert = </etc/dovecot/private/dovecot.pem
ssl_key = </etc/dovecot/private/dovecot.pem
# login is for outlook express smtpd auth
auth_mechanisms = plain login
# If you're having trouble, try uncommenting these:
#auth_debug = yes
#auth_debug_passwords = yes
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
}
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
} }
# Uncomment this if you want Postfix to be able to do smtpd auth through dovecot # Valid UID range for users, defaults to 500 and above.
# At a minimum Postfix probably needs smtpd_sasl_type = dovecot first_valid_uid = 1001 # Change this to your postfix UID
# And additionally: smtpd_sasl_path = private/auth
#service auth {
# unix_listener /var/spool/postfix/private/auth {
# mode = 0660
# user = postfix
# group = postfix
# }
#}
# Needs to match Postfix virtual_uid_maps
first_valid_uid = 1001
# allow plaintext auth (change to 'yes' to block plaintext passwords)
disable_plaintext_auth = no
#END
2. Dovecot *sql setup 2. Dovecot mysql setup
---------------------- ----------------------
Below you'll find the relevant part of dovecot-sql.conf file regarding our Below you'll find the relevant part of dovecot-mysql.conf file regarding our
setup. setup. Things you may need to change are db_password, uid and gid:
Things you will probably need to change are db connection settings (connect=)
and the default_pass_scheme.
#BEGIN /etc/dovecot/dovecot-sql.conf
connect = host=localhost dbname=postfix user=postfix password=postfix connect = host=localhost dbname=postfix user=postfix password=postfix
# Use either
driver = mysql
# Or
# driver = pgsql
# Default password scheme - change to match your Postfixadmin setting. # Default password scheme.
# depends on your $CONF['encrypt'] setting: # depends on your $CONF['encrypt'] setting:
# md5crypt -> MD5-CRYPT # md5crypt -> MD5-CRYPT
# md5 -> PLAIN-MD5 # md5 -> PLAIN-MD5
@ -125,18 +58,11 @@ default_pass_scheme = MD5-CRYPT
password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1' password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1'
# Query to retrieve user information, note uid matches dovecot.conf AND Postfix virtual_uid_maps parameter. # Query to retrieve user information.
# MYSQL:
user_query = SELECT CONCAT('/var/mail/vmail/', maildir) AS home, 1001 AS uid, 1001 AS gid,
CONCAT('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active='1'
# PostgreSQL:
# user_query = SELECT '/var/mail/vmail/' || maildir AS home, 1001 AS uid, 1001 AS gid,
# '*:bytes=' || quota AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1'
#END /etc/dovecot/dovecot-sql.conf
user_query = SELECT maildir, 1001 AS uid, 1001 AS gid FROM mailbox WHERE username = '%u' AND active='1'
NB! The GID and UID are for postfix user and group ID, NOT MySQL user and group ID.
3. Dovecot v1.0 quota support (optional) 3. Dovecot v1.0 quota support (optional)
@ -150,7 +76,7 @@ Add to dovecot.conf:
## IMAP quota ## IMAP quota
protocol imap { protocol imap {
mail_plugins = quota quota = dict:storage=200000 proxy::quota
} }
## POP quota ## POP quota
@ -174,18 +100,12 @@ quota = dict:storage=200000 proxy::quota
} }
Change dovecot-sql.conf to return quota values: Change dovecot-mysql.conf to return quota values:
for MySQL:
user_query = SELECT maildir, 1001 AS uid, 1001 AS gid, CONCAT('dict:storage=',floor(quota/1000),' ::proxy::quota') as quota FROM mailbox WHERE username = '%u' AND active='1'
for PostgreSQL:
user_query = SELECT maildir, 1001 AS uid, 1001 AS gid, 'dict:storage=' || floor(quota/1000) || '::proxy::quota' as quota FROM mailbox WHERE username = '%u' AND active='1'
user_query = SELECT maildir, 1001 AS uid, 1001 AS gid, CONCAT('dict:storage=',floor(quota/1000),' proxy::quota') as quota FROM mailbox WHERE username = '%u'
Create file dovecot-dict-quota.conf.
For dovecot 1.0 & 1.1, use this as a template: Create file dovecot-dict-quota.conf:
driver = mysql driver = mysql
connect = host=localhost dbname=postfix user=postfix password=postfix connect = host=localhost dbname=postfix user=postfix password=postfix
@ -195,34 +115,18 @@ select_field = current
where_field = path where_field = path
username_field = username username_field = username
If you use dovecot 1.2 or newer, use this:
connect = host=localhost dbname=postfix user=postfix password=postfix Create database in Mysql:
map {
pattern = priv/quota/storage
table = quota2
username_field = username
value_field = bytes
}
map {
pattern = priv/quota/messages
table = quota2
username_field = username
value_field = messages
}
create table quota (
username varchar(255) not null,
path varchar(100) not null,
current integer,
primary key (username, path)
);
Create database in Mysql:
(This is automatically done by postfixadmin's setup.php)
Enable quota support in Postfixadmin config.inc.php: Enable quota support in Postfixadmin config.inc.php:
$CONF['used_quotas'] = 'YES'; $CONF['used_quotas'] = 'YES';
$CONF['quota'] = 'YES'; $CONF['quota'] = 'YES';
Note: The above text describes the configuration for dovecot 1.0 & 1.1 quota table format.
If you use dovecot 1.2 or newer,
- use the 'quota2' table (also created by setup.php)
- set $CONF['new_quota_table'] = 'YES'

@ -26,11 +26,3 @@ Frequently Asked Questions:
wwwrun ALL = (courier) NOPASSWD: /usr/local/bin/postfixadmin-mailbox-postcreation.sh wwwrun ALL = (courier) NOPASSWD: /usr/local/bin/postfixadmin-mailbox-postcreation.sh
(replace usernames and path according to your setup) (replace usernames and path according to your setup)
4) I try and create a mailbox, but it keeps saying "Invalid email address"... ?
- Postfixadmin, by default, attempts to verify an email address is valid, partly by
checking that the domain exists. For most people this works as expected, but
if it doesn't for you, try editing $CONF['emailcheck_resolve_domain'] to 'NO' in
config.inc.php and try again.

@ -1,5 +1,3 @@
#!/bin/bash
content="
Postfix configuration for use with PostfixAdmin Postfix configuration for use with PostfixAdmin
@ -20,17 +18,14 @@ virtual_mailbox_maps =
proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf,
proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf
# For transport map support, also use the following configuration: # Additional for quota support
virtual_create_maildirsize = yes
relay_domains = proxy:mysql:/etc/postfix/sql/mysql_relay_domains.cf virtual_mailbox_extended = yes
transport_maps = proxy:mysql:/etc/postfix/sql/mysql_transport_maps.cf virtual_mailbox_limit_maps = mysql:/etc/postfix/mysql_virtual_mailbox_limit_maps.cf
virtual_mailbox_limit_override = yes
# Also set the config.inc.php setting transport=YES virtual_maildir_limit_message = Sorry, the user's maildir has overdrawn his
# and add the transport choices to transport_options. diskspace quota, please try again later.
virtual_overquota_bounce = yes
# if you let postfix store your mails directly (without using maildrop, dovecot deliver etc.)
virtual_mailbox_base = /var/mail/vmail
# or whereever you want to store the mails
Where you chose to store the .cf files doesn't really matter, but they will Where you chose to store the .cf files doesn't really matter, but they will
have database passwords stored in plain text so they should be readable only have database passwords stored in plain text so they should be readable only
@ -45,21 +40,10 @@ autoreply features.
Contents of the files Contents of the files
These are examples only, you will likely have to and want to make some These are examples only, you will likely have to and want to make some
customizations. You will also want to consider the config.inc.php cumtomizations. You will also want to consider the config.inc.php
settings for domain_path and domain_in_mailbox. These examples settings for domain_path and domain_in_mailbox. These examples
use values of domain_path=YES and domain_in_mailbox=NO use values of domain_path=YES and domain_in_mailbox=NO
You can create these files (with your values for user, password, hosts and
dbname) automatically by executing this file (sh POSTFIX_CONF.txt).
Please note that the generated files are for use with MySQL.
If you are using PostgreSQL, you'll need to do some changes to the queries:
- PostgreSQL uses a different implementation for boolean values, which means
you'll need to change active='1' to active='t' in all queries
- PostgreSQL does not have a concat() function, instead use e.g.
.... alias.address = '%u' || '@' || alias_domain.target_domain AND ....
mysql_virtual_alias_maps.cf: mysql_virtual_alias_maps.cf:
user = postfix user = postfix
password = password password = password
@ -73,7 +57,7 @@ user = postfix
password = password password = password
hosts = localhost hosts = localhost
dbname = postfix dbname = postfix
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active='1' AND alias_domain.active='1' query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1
mysql_virtual_alias_domain_catchall_maps.cf: mysql_virtual_alias_domain_catchall_maps.cf:
# handles catch-all settings of target-domain # handles catch-all settings of target-domain
@ -81,9 +65,7 @@ user = postfix
password = password password = password
hosts = localhost hosts = localhost
dbname = postfix dbname = postfix
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active='1' AND alias_domain.active='1' query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1
(See above note re Concat + PostgreSQL)
mysql_virtual_domains_maps.cf: mysql_virtual_domains_maps.cf:
user = postfix user = postfix
@ -94,8 +76,6 @@ query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
#query = SELECT domain FROM domain WHERE domain='%s' #query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX #optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1' #query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'
#optional query to use for transport map support
#query = SELECT domain FROM domain WHERE domain='%s' AND active = '1' AND NOT (transport LIKE 'smtp%%' OR transport LIKE 'relay%%')
#expansion_limit = 100 #expansion_limit = 100
mysql_virtual_mailbox_maps.cf: mysql_virtual_mailbox_maps.cf:
@ -103,7 +83,7 @@ user = postfix
password = password password = password
hosts = localhost hosts = localhost
dbname = postfix dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1' query = SELECT CONCAT(domain,'/',maildir) FROM mailbox WHERE username='%s' AND active = '1'
#expansion_limit = 100 #expansion_limit = 100
mysql_virtual_alias_domain_mailbox_maps.cf: mysql_virtual_alias_domain_mailbox_maps.cf:
@ -111,28 +91,11 @@ user = postfix
password = password password = password
hosts = localhost hosts = localhost
dbname = postfix dbname = postfix
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active='1' AND alias_domain.active='1' query = SELECT CONCAT(domain,'/',maildir) FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1
mysql_relay_domains.cf:
user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1' AND (transport LIKE 'smtp%%' OR transport LIKE 'relay%%')
mysql_transport_maps.cf:
user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT transport FROM domain WHERE domain='%s' AND active = '1'
(See above note re Concat + PostgreSQL)
# For quota support # For quota support
mysql_virtual_mailbox_limit_maps.cf: mysql-virtual-mailbox-limit-maps.cf:
user = postfix user = postfix
password = password password = password
hosts = localhost hosts = localhost
@ -146,47 +109,4 @@ query = SELECT quota FROM mailbox WHERE username='%s' AND active = '1'
http://postfix.wiki.xs4all.nl/index.php?title=Virtual_Users_and_Domains_with_Courier-IMAP_and_MySQL http://postfix.wiki.xs4all.nl/index.php?title=Virtual_Users_and_Domains_with_Courier-IMAP_and_MySQL
http://wiki.dovecot.org/HowTo/DovecotLDAPostfixAdminMySQL http://wiki.dovecot.org/HowTo/DovecotLDAPostfixAdminMySQL
" # end content
# generate config files out of this file
# to do this, run sh POSTFIX_CONF.txt
POSTFIX_CONF="$0"
map_files="`sed -n '/^mysql.*cf:/ s/://p' < \"$0\"`"
tmpdir="`mktemp -d /tmp/postfixadmin-XXXXXX`" || { echo "Error: could not create tempdir" >&2 ; exit 1; }
echo $tmpdir
echo 'Database host? (often localhost)'
read hosts
test -z "$hosts" && hosts=localhost
echo 'Database name?'
read dbname
test -z "$dbname" && { echo "Error: you did not enter a database name" >&2 ; exit 1; }
echo Database user?
read user
test -z "$user" && { echo "Error: you did not enter a database username" >&2 ; exit 1; }
echo Database password?
read password
test -z "$password" && { echo "Error: you did not enter a database password" >&2 ; exit 1; }
for file in $map_files ; do
(
echo "# $file"
sed -n "/$file:/,/^$/ p" < "$POSTFIX_CONF" | sed "
1d ; # filename
s/^user =.*/user = $user/ ;
s/^password =.*/password = $password/ ;
s/^hosts =.*/hosts = $hosts/ ;
s/^dbname =.*/dbname = $dbname/ ;
"
) > "$tmpdir/$file"
done
echo "Config files have been written to $tmpdir. Please check their content and move them to /etc/postfix/sql/."
echo "Do not forget to edit /etc/postfix/main.cf as described in $POSTFIX_CONF."

@ -1,221 +0,0 @@
# Example configuration
The below covers some default(ish) configuration things for using Postfix, Dovecot with PostgreSQL.
# Postfix
Assumptions :
* Mail is delivered into /var/mail/vmail/foo@example.com/
* The user with id 8 is used for ownership of mail files.
* PostgreSQL is running on the local server
* Dovecot is running on the local server, and SASL is used to allow authenticated clients to mail out.
## /etc/postfix/main.cf
The proxy: bits are optional, you may need to install an additional postfix package on your server to enable them.
i.e. proxy:pgsql:/path/to/file is equivalent to pgsql:/path/to/file. Use of 'proxy:' may lead to a small performance boost.
```
relay_domains = $mydestination, proxy:pgsql:/etc/postfix/pgsql/relay_domains.cf
virtual_alias_maps = proxy:pgsql:/etc/postfix/pgsql/virtual_alias_maps.cf
virtual_mailbox_domains = proxy:pgsql:/etc/postfix/pgsql/virtual_domains_maps.cf
virtual_mailbox_maps = proxy:pgsql:/etc/postfix/pgsql/virtual_mailbox_maps.cf
virtual_mailbox_base = /var/mail/vmail
virtual_mailbox_limit = 512000000
virtual_minimum_uid = 8
virtual_transport = virtual
virtual_uid_maps = static:8
virtual_gid_maps = static:8
local_transport = virtual
local_recipient_maps = $virtual_mailbox_maps
```
and for Postfix SASL support :
```
# SASL Auth for SMTP relaying
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_authenticated_header = yes
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
```
## /etc/postfix/pgsql/relay_domains.cf
```
user = postfix
password = whatever
hosts = localhost
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = true
```
## /etc/postfix/pgsql/virtual_alias_maps.cf
```
user = postfix
password = whatever
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = true
```
## /etc/postfix/pgsql/virtual_domains_maps.cf
```
user = postfix
password = whatever
hosts = localhost
dbname = postfix
#query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = false and active = true
```
## /etc/postfix/pgsql/virtual_mailbox_limits.cf
```
# Used for quota
user = postfix
password = whatever
hosts = localhost
dbname = postfix
query = SELECT quota FROM mailbox WHERE username='%s'
```
## /etc/postfix/pgsql/virtual_mailbox_maps.cf
```
user = postfix
password = whatever
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = true
```
# Dovecot
(This is from version 2.2.27, Debian Stretch)
## /etc/dovecot/dovecot.conf
```
mail_location = maildir:/var/mail/vmail/%u/
namespace inbox {
type = private
inbox = yes
location =
mailbox Drafts {
special_use = \Drafts
}
mailbox Junk {
special_use = \Junk
}
mailbox Sent {
special_use = \Sent
}
mailbox "Sent Messages" {
special_use = \Sent
}
mailbox Trash {
special_use = \Trash
}
prefix =
}
protocols = "imap pop3"
# Requires certificates ...
#ssl = yes
#ssl_cert = </etc/dovecot/private/something.pem
#ssl_key = </etc/letsencrypt/certs/something.key
login_greeting = My Mail Server
# http://wiki2.dovecot.org/Authentication/Mechanisms
# login is for outlook express ...
auth_mechanisms = plain login
#auth_debug = yes
#auth_debug_passwords=yes
# Postfix - Sasl auth support.
service auth {
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
# Auth process is run as this user.
user = postfix
group = postfix
}
service imap {
executable = imap
}
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
}
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
}
# Needs to match Postfix virtual_uid_maps
first_valid_uid = 8
# disallow or allow plaintext auth.
disable_plaintext_auth = yes
mail_plugins = $mail_plugins zlib
plugin {
zlib_save_level = 6
zlib_save = gz
}
protocol imap {
mail_plugins = $mail_plugins imap_zlib
}
mail_max_userip_connections = 50
log_path = /var/log/dovecot.log
```
## /etc/dovecot/dovecot-sql.conf
Ideally dovecot has a different read only database user.
```
connect = host=localhost dbname=postfix user=dovecot password=whatever
driver = pgsql
# Default password scheme - change to match your Postfixadmin setting.
# depends on your $CONF['encrypt'] setting:
# md5crypt -> MD5-CRYPT
# md5 -> PLAIN-MD5
# cleartext -> PLAIN
default_pass_scheme = MD5-CRYPT
# Query to retrieve password. user can be used to retrieve username in other
# formats also.
password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1'
# Query to retrieve user information, note uid matches dovecot.conf AND Postfix virtual_uid_maps parameter.
user_query = SELECT '/var/vmail/mail/' || maildir AS home, 8 as uid, 8 as gid FROM mailbox WHERE username = '%u' AND active = '1'
```

@ -1,48 +0,0 @@
*Description
This extension adds support for password expiration.
It is designed to have expiration on users passwords. An email is sent when the password is expiring in 30 days, then 14 days, then 7 days.
It is strongly inspired by https://abridge2devnull.com/posts/2014/09/29/dovecot-user-password-expiration-notifications-updated-4122015/, and adapted to fit with Postfix Admin & Roundcube's password plugin
Expiration unit is day
Expiration value for domain is set through Postfix Admin GUI
*Installation
Perform the following changes:
**Changes in MySQL/MariaDB mailbox table (as defined in $CONF['database_tables'] from config.inc.php):
You are invited to backup your DB first, and ensure the table name is correct.
Execute the attached SQL script (password_expiration.sql) that will add the required columns. The expiration value for existing users will be set to 90 days. If you want a different value, edit line 2 in the script and replace 90 by the required value.
**Changes in Postfix Admin :
To enable password expiration, add the following to your config.inc.php file:
$CONF['password_expiration'] = 'YES';
All my tests are performed using $CONF['encrypt'] = 'md5crypt';
**If you are using Roundcube's password plugin, you should also adapt the $config['password_query'] value.
I recommend to use:
$config['password_query'] = 'UPDATE mailbox SET password=%c, modified = now(), password_expiry = now() + interval 90 day';
of cource you may adapt to the expected expiration value
All my tests are performed using $config['password_algorithm'] = 'md5-crypt';
**Changes in Dovecot (adapt if you use another LDA)
Edit dovecot-mysql.conf file, and replace the user_query (and only this one) by this query:
password_query = SELECT username as user, password, concat('/var/vmail/', maildir) as userdb_var, concat('maildir:/var/vmail/', maildir) as userdb_mail, 20001 as userdb_uid, 20001 as userdb_gid, m.domain FROM mailbox m, domain d where d.domain = m.domain and m.username = '%u' AND m.active = '1' AND (m.password_expiry > now() or d.password_expiry = 0)
Of course you may require to adapt the uid, gid, maildir and table to your setup
**Changes in system
You need to have a script running on a daily basis to check password expiration and send emails 30, 14 and 7 days before password expiration (script attached: check_mailpass_expiration.sh).
Edit the script to adapt the variables to your setup.
This script is using postfixadmin.my.cnf to read credentials. Edit this file to enter a DB user that is allowed to access (read-write) your database. This file should be protected from any user (chmod 400).

@ -23,11 +23,6 @@ You may wish to consider the following :
the vacation_notification table (and read alias and vacation). the vacation_notification table (and read alias and vacation).
3. PostfixAdmin itself needs to be able to READ and WRITE to 3. PostfixAdmin itself needs to be able to READ and WRITE to
all the tables. all the tables.
4. PostfixAdmin's setup.php additionally needs permissions to CREATE
and ALTER tables in the PostfixAdmin database. For PostgreSQL, also
permissions for CREATE FUNCTION and CREATE TRIGGER are needed.
In other words: setup.php needs all permissions on the PostfixAdmin
database.
Using the above, you can improve security by creating separate Using the above, you can improve security by creating separate
database user accounts for each of the above roles, and limit database user accounts for each of the above roles, and limit
@ -38,7 +33,5 @@ FILE SYSTEM SECURITY
-------------------- --------------------
PostfixAdmin does not require write support on the underlying PostfixAdmin does not require write support on the underlying
filesystem with the following exceptions: filesystem - aside from PHP creating session files.
- the templates_c directory where Smarty caches the templates
- PHP's session.save_path to store session files

@ -9,8 +9,29 @@ With that login you can create new superadmins (and you should delete or change
password of admin@domain.tld). If that user is no longer there or you didn't use password of admin@domain.tld). If that user is no longer there or you didn't use
the .TXT files, you could add another manually from the database. the .TXT files, you could add another manually from the database.
In case you forgot your superadmin username or password, you can create a new (The example uses MySQL, the syntax will be similar for PostgreSQL)
superadmin account using setup.php.
If you also have forgotten your setup password, you can use setup.php to configure # mysql
a new setup password. Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8186 to server version: 5.0.27
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> use postfix
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> INSERT INTO domain_admins (username, domain, active) VALUES ('new@domain.tld','ALL','1');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO admin (username, password, active) VALUES ('new@domain.tld','$1$0fec9189$bgI6ncWrldPOsXnkUBIjl1','1');
Query OK, 1 row affected (0.00 sec)
mysql> exit
Bye
Then you can log in as new@domain.tld, password: admin
(The domain 'ALL' should already exist in the domain table; if not you'll need to recreate it)

@ -9,7 +9,7 @@ REQUIRED!!
---------- ----------
- You are using Postfix 2.0 or higher. - You are using Postfix 2.0 or higher.
- You are using Apache 1.3.27 / Lighttpd 1.3.15 or higher. - You are using Apache 1.3.27 / Lighttpd 1.3.15 or higher.
- You are using PHP 5.1.2 or higher. - You are using PHP 4.1 or higher.
- You are using MySQL 3.23 or higher OR PostgreSQL v7.4+ - You are using MySQL 3.23 or higher OR PostgreSQL v7.4+
@ -33,18 +33,17 @@ When you install from a previous version make sure you backup your database
first. There are a lot of changes in the database structure since Postfix Admin first. There are a lot of changes in the database structure since Postfix Admin
1.5.4. 1.5.4.
$ mysqldump -u root -p postfixdb > /tmp/postfixadmin-backup.sql $ mysqldump -a -u root -p > /tmp/postfixadmin-backup.sql
or or
$ pg_dump -ad -u postfix postfixdb > /tmp/postfixadmin-backup.sql $ pg_dump -ad -u postfix postfix > /tmp/postfixadmin-backup.sql
(Replace postfixdb with your Postfixadmin database's name)
2. Unarchive new Postfix Admin 2. Unarchive new Postfix Admin
------------------------------ ------------------------------
Make sure that you are in your WWW directory and then unarchive the Make sure that you are in your WWW directory and then unarchive the
Postfix Admin archive (whatever the filename is): Postfix Admin archive (whatever the filename is):
$ tar -zxvf postfixadmin-X.X.tgz $ tar -zxvf postfixadmin-2.2.tgz
3. Change permissions 3. Change permissions
@ -54,63 +53,38 @@ to have change the permissions for Postfix Admin.
$ cd /usr/local/www/postfixadmin $ cd /usr/local/www/postfixadmin
$ find -type f -print0 | xargs -0 chmod 640 $ find -type f -print0 | xargs -0 chmod 640
$ find -type f -print0 | xargs -0 chown root:www-data $ find -type f -print0 | xargs -0 chown root:www
(the last command assumes your Apache is running with group "www-data") (the last command assumes your Apache is running with group "www")
Since version 3.0 we use smarty templates. That means the templates_c directory
needs to be writeable for your webserver.
$ cd /usr/local/www/postfixadmin
$ mkdir templates_c && chmod 750 templates_c && chown -R www-data templates_c
(if your Apache runs as user "www-data")
If you have SELinux enabled, also run (adust the path to match your setup)
$ sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/utils/pfadmin/public/templates_c(/.*)?"
$ sudo restorecon -Rv /var/www/utils/pfadmin/
4. Configure 4. Configure
------------ ------------
Check the config.inc.php file. There you can specify settings that are Check the config.inc.php file. There you can specify settings that are
relevant to your setup. relevant to your setup.
Comparing config.inc.php with your previous using "diff" might save you some Comparing config.inc.php with your previous using "diff" might save you some
time. time.
You can use a config.local.php file to contain your local settings.
These will override any defined in config.inc.php - and save some time when upgrading to a new version of PostfixAdmin ;-)
5. Run setup.php 5. Perform appropriate database upgrades
---------------------------------------- ----------------------------------------
Access setup.php through a web browser.
It will attempt to upgrade your database, and also allow you to create a superadmin user.
(In case the database upgrade fails, you can run setup.php?debug=1 to see the last executed query.)
From version 2.3, you need to specify a setup_password in config.inc.php -
setup.php should guide you through this process. If you do not have a setup_password, type one
into the form, and setup.php will echo out the hashed value (which needs to go into config.inc.php).
The setup_password removes the requirement for you to delete setup.php, and also closes a security hole.
Since version 2.2 of Postfixadmin, setup.php can perform the needed database Since version 2.2 of Postfixadmin, setup.php can perform the needed database
updates automatically . updates automatically .
Open setup.php in your browser to update your database scheme.
If you update from 2.1 or older, also create a superadmin account using setup.php. If you update from 2.1 or older, also create a superadmin account using setup.php.
Note that admin/ has been merged into the main directory. Login with the Note that admin/ has been merged into the main directory. Login with the
superadmin account to setup domains and domain admins. superadmin account to setup domains and domain admins.
6. Upgrade your postfix config
------------------------------
Since version 2.3, PostfixAdmin supports alias domains ($CONF['alias_domain']). 6. Delete setup.php
If you want to use them, you have to add some queries to your postfix config - -------------------
see POSTFIX_CONF for details. Delete setup.php - it allown non-authorized users to create a superadmin
account!
7. Done 7. Done

@ -5,68 +5,36 @@
# Licensed under GPL for more info check GPL-LICENSE.TXT # Licensed under GPL for more info check GPL-LICENSE.TXT
# #
REQUIREMENTS REQUIRED!!
------------ ----------
- Postfix - You are using Postfix 2.0 or higher.
- Apache / Lighttpd - You are using Apache 1.3.27 / Lighttpd 1.3.15 or higher.
- PHP (for web server) - You are using PHP 4.1 or higher (5.X recommended)
- one of the following databases: - You are using MySQL 3.23 or higher (5.x recommended) OR PostgreSQL 7.4 (or higher)
- MariaDB/MySQL
- PostgreSQL
- SQLite
READ THIS FIRST! READ THIS FIRST!
---------------- ----------------
When this is an upgrade from a previous version of Postfix Admin, please read When this is an upgrade from Postfix Admin 1.5.4 please read DOCUMENTS/UPGRADE.TXT!!
DOCUMENTS/UPGRADE.TXT also!
If you need to setup Postfix to be able to handle Virtual Domains and Virtual If you need to setup Postfix to be able to handle Virtual Domains and Virtual
Users check out: Users check out :
- the PostfixAdmin documentation in the DOCUMENTS/ directory - http://high5.net/howto/
- our wiki at https://sourceforge.net/p/postfixadmin/wiki/ - http://codepoets.co.uk/postfixadmin-postgresql-courier-squirrelmail-debian-etch-howto-tutorial (Debian+Courier+PostgreSQL+Postfix+Postfixadmin)
There are also lots of HOWTOs around the web. Be warned that many of them
(even those listed below) may be outdated or incomplete.
Please stick to the PostfixAdmin documentation, and use those HOWTOs only if
you need some additional information that is missing in the PostfixAdmin
DOCUMENTS/ folder.
- http://bliki.rimuhosting.com/space/knowledgebase/linux/mail/postfixadmin+on+debian+sarge (Postfix+MySQL+Postfixadmin+Dovecot) - http://bliki.rimuhosting.com/space/knowledgebase/linux/mail/postfixadmin+on+debian+sarge (Postfix+MySQL+Postfixadmin+Dovecot)
- http://en.gentoo-wiki.com/wiki/Virtual_mail_server_using_Postfix,_Courier_and_PostfixAdmin (Postfix+MySQL+Postfixadmin+Courier) - http://gentoo-wiki.com/HOWTO_Setup_a_Virtual_Postfix/Courier_Mail_System_with_PostfixAdmin (Postfix+MySQL+Postfixadmin+Courier)
1. Unarchive new Postfix Admin 1. Unarchive new Postfix Admin
------------------------------ ------------------------------
Make sure that you are in your WWW directory and then unarchive the
Postfix Admin archive (whatever the filename is):
(if you installed PostfixAdmin as RPM or DEB package, you can obviously skip this step.) $ tar -zxvf postfixadmin-2.2.0.tgz
Assuming we are installing Postfixadmin into /srv/postfixadmin, then something like this should work. Please check https://github.com/postfixadmin/postfixadmin/releases to get the latest stable release first (the 3.2.4 version/url below is probably stale)
$ cd /srv/
$ wget -O postfixadmin.tgz https://github.com/postfixadmin/postfixadmin/archive/postfixadmin-3.2.4.tar.gz
$ tar -zxvf postfixadmin.tgz
$ mv postfixadmin-postfixadmin-3.2 postfixadmin
Alternatively :
$ cd /srv
$ git clone https://github.com/postfixadmin/postfixadmin.git
$ cd postfixadmin
$ git checkout postfixadmin-3.2.4
2. Setup Web Server 2. Setup a Database
-------------------
Assuming /var/www/html is where your webserver reads from, either create a symlink:
$ ln -s /srv/postfixadmin/public /var/www/html/postfixadmin
or setup an alias in your webserver config. For Apache, use:
Alias /postfixadmin /srv/postfixadmin/public
3. Setup a Database
------------------- -------------------
With your chosen/preferred database server (i.e. MySQL or PostgreSQL), With your chosen/preferred database server (i.e. MySQL or PostgreSQL),
@ -84,36 +52,16 @@ For MySQL:
CREATE DATABASE postfix; CREATE DATABASE postfix;
CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'choose_a_password'; CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'choose_a_password';
GRANT ALL PRIVILEGES ON `postfix` . * TO 'postfix'@'localhost'; GRANT ALL PRIVILEGES ON `postfix` . * TO 'postfix'@'localhost';
FLUSH PRIVILEGES;
For PostgreSQL: For PostgreSQL:
CREATE USER postfix WITH PASSWORD 'whatever'; CREATE USER postfix WITH PASSWORD 'whatever';
CREATE DATABASE postfix OWNER postfix ENCODING 'unicode'; CREATE DATABASE postfix OWNER postfix ENCODING 'unicode';
For SQLite:
$mkdir /srv/postfixadmin/database
$touch /srv/postfixadmin/database/postfixadmin.db
$sudo chown -R www-data:www-data /srv/postfixadmin/database
(both the directory and the database need to be writeable)
4. Configure PostfixAdmin so it can find the database 3. Configure PostfixAdmin so it can find the database
----------------------------------------------------- -----------------------------------------------------
Create /srv/postfixadmin/config.local.php file for your local configuration: Edit the config.inc.php file.
<?php
$CONF['database_type'] = 'mysqli';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'postfixadmin';
$CONF['database_name'] = 'postfix';
$CONF['configured'] = true;
?>
See config.inc.php for all available config options and their default value.
You can also edit config.inc.php instead of creating a config.local.php,
but this will make updates harder and is therefore not recommended.
The most important settings are those for your database server. The most important settings are those for your database server.
@ -126,22 +74,27 @@ to
$CONF['configured'] = true; $CONF['configured'] = true;
PostfixAdmin does not require write access to any files except the templates_c PostfixAdmin does not require write access to any files. You can therefore
directory (smarty cache). You can therefore leave the files owned by root (or leave the files owned as root (or a.n.other user); as long as the web server
another user); as long as the web server user (e.g. www-data) can read them, it user (e.g. www-data) can read them, it will be fine.
will be fine.
For templates_c/, allow write access (only) for the web server user (e. g. www-data). The next 'step', is optional. Only do it, if other non-trusted users have access
The easiest way to do this is to your user:
$ mkdir -p /srv/postfixadmin/templates_c Depending on your environment, you may want to protect the database username
$ chown -R www-data /srv/postfixadmin/templates_c and password stored in config.inc.php - if so, you could move them into the
Apache configuration file (which can be set to be visible only by root) using
something like the following in your VirtualHost definition :
(If you're using e.g. CentOS or another distribution which enables SELinux, something like the following may be necessary as well : SetEnv DB_USER "postfix"
```chcon -R -t httpd_sys_content_rw_t /usr/share/postfixadmin/templates_c``` SetEnv DB_PASS "opensesame"
)
5. Check settings, and create Admin user config.inc.php would then be able to access these through :
$CONF['database_user'] = $_SERVER['DB_USER']
4. Check settings, and create Admin user
---------------------------------------- ----------------------------------------
Hit http://yourserver.tld/postfixadmin/setup.php in a web browser. Hit http://yourserver.tld/postfixadmin/setup.php in a web browser.
@ -151,49 +104,22 @@ You should see a list of 'OK' messages.
The setup.php script will attempt to create the database structure The setup.php script will attempt to create the database structure
(or upgrade it if you're coming from a previous version). (or upgrade it if you're coming from a previous version).
Assuming everything is OK you can specify a password (which you'll Assuming everything is OK you can create the admin user using the form displayed.
need to use setup.php again in the future); when you submit the form,
the hashed value (which you need to enter into config.inc.php is echoed Once you submit the form, all that's left to do is to delete "setup.php"
out - with appropriate instructions on what to do with it).
create the admin user using the form displayed. e.g.
6. Use PostfixAdmin mv setup.php setup.php.disabled
5. Use PostfixAdmin
------------------- -------------------
This is all that is needed. Fire up your browser and go to the site that you This is all that is needed. Fire up your browser and go to the site that you
specified to host Postfix Admin. specified to host Postfix Admin.
7. Integration with Postfix, Dovecot etc. 6. More information
-----------------------------------------
Now that PostfixAdmin is working, you need to do some configuration in Postfix,
Dovecot etc. so that they use the domains, mailboxes and aliases you setup in
PostfixAdmin.
The files in the DOCUMENTS/ directory explain which settings you need to
do/change.
7. XMLRPC Integration (OPTIONAL!)
--------------------------------
See ADDITIONS/squirrelmail-plugin
See xmlrpc.php - only a subset of Postfixadmin's functionality is currently exposed.
See config.inc.php - see xmlrpc_enabled key (defaults to off).
You'll need to install a copy of the Zend Framework (version 1.12.x) within Postfixadmin
or your PHP include_path (see header within xmlrpc.php).
NOTE: The XMLRPC interface is _not compatible_ with Zend Framework version 2.x.
You'll need to enable the xmlrpc link (see config.inc.php)
8. More information
------------------- -------------------
As of March 2007, PostfixAdmin moved to SourceForge. For the
The code and issue tracker is on GitHub: forum posts and source updates, see:
https://github.com/postfixadmin/postfixadmin https://sourceforge.net/projects/postfixadmin
IRC - a community of people may be able to help in #postfixadmin on irc.freenode.net.
See http://webchat.freenode.net/
Legacy forum posts are on SourceForce at
https://sourceforge.net/projects/postfixadmin

@ -18,7 +18,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Postfix Admin version 2.1.1, Copyright (c) 2005 High5! (Mischa Peters & Contributors) Postfix Admin verion 2.1.1, Copyright (c) 2005 High5! (Mischa Peters & Contributors)
Postfix Admin comes with ABSOLUTELY NO WARRANTY. Postfix Admin comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
under certain conditions. under certain conditions.
@ -29,18 +29,4 @@
Contributors: Mihau, Tarvin, SteveB, DJTremors, WhiteFox, David Osborn, Contributors: Mihau, Tarvin, SteveB, DJTremors, WhiteFox, David Osborn,
David Goodwin (GingerDog), Christian Boltz (cboltz) and GregC and others. David Goodwin (GingerDog), Christian Boltz (cboltz) and GregC and others.
Postfix Admin uses some libraries that come with a different license.
a) libraries shipped with PostfixAdmin
- the Smarty templating engine is licensed under the GNU LESSER GENERAL PUBLIC
LICENSE Version 3 (see smarty/COPYING.lib)
- the CLI (commandline interface) is based on CakePHP which is licensed under
the MIT license.
b) libraries not shipped with PostfixAdmin
- the XMLRPC interface and the squirrelmail plugin use the Zend Framework which is
licensed under the New BSD License (3-clause), see http://framework.zend.com/license
- PHPUnit (used in tests/) is licensed under the BSD License (3-clause).

@ -1,41 +0,0 @@
![GitHubBuild](https://github.com/postfixadmin/postfixadmin/workflows/GitHubBuild/badge.svg)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/postfixadmin/Lobby)
[![Coverage Status](https://coveralls.io/repos/github/postfixadmin/postfixadmin/badge.svg?branch=master)](https://coveralls.io/github/postfixadmin/postfixadmin?branch=master)
![GitHub repo size](https://img.shields.io/github/repo-size/postfixadmin/postfixadmin)
[![Chat](https://img.shields.io/badge/chat-on%20freenode-brightgreen.svg)](https://kiwiirc.com/nextclient/irc.freenode.net/#postfixadmin)
# PostfixAdmin
An open source, web based interface for managing domains/mailboxes/aliases etc on a Postfix based mail server.
Integrates with :
- Postfix
- IMAP/POP3 server (e.g. Dovecot or Courier)
- Database backend (choose one of: sqlite, mysql, postgresql)
- Fetchmail (optional)
## Features
- Unlimited domains/aliases/mailboxes
- Optional storage quota support
- Optional password expiry (beta)
- Multiple password hashing formats
- Supports PostgreSQL, MySQL, MariaDB, SQLite database backends (choose one)
- Supports retrieval of mail from a remote POP3 server (via fetchmail)
- Vacation / Autoresponder / Out Of Office support
- Users have the ability to login, change their password or vacation (out of office) status.
- Integration with Squirrelmail / Roundcube (via plugins)
- Optional XMLRPC based API
- Supports PHP5.6+
## Useful Links
- [Probably all you need to read (pdf)](http://blog.cboltz.de/uploads/postfixadmin-30-english.pdf)
- http://postfixadmin.sf.net - the current homepage for the project
- [Docker Images](https://github.com/postfixadmin/docker)
- [What is it? (txt)](/DOCUMENTS/POSTFIXADMIN.txt)
- [Installation instructions](/INSTALL.TXT)
- [Wiki](https://sourceforge.net/p/postfixadmin/wiki/)
- [Mailing list](https://sourceforge.net/p/postfixadmin/discussion/676076)
- [IRC channel](irc://irc.freenode.net/postfixadmin) (#postfixadmin on irc.freenode.net).

@ -1,93 +0,0 @@
This file is not exhaustive.
Please feel free to add yourself and a summary of changes to this file at the bottom if creating a pull request.
Postfixadmin was originally written by Mischa Peters <mischa at high5 dot net>
Copyright (c) 2002 - 2005 High5!
Licensed under GPL for more info check GPL-LICENSE.TXT
Additional authors:
2004/07/13 David Osborn <ossdev at daocon.com>
strict, processes domain level aliases, more
subroutines, send reply from original to address
2004/11/09 David Osborn <ossdev at daocon.com>
Added syslog support
Slightly better logging which includes messageid
Avoid infinite loops with domain aliases
2005-01-19 Troels Arvin <troels at arvin.dk>
PostgreSQL-version.
Normalized DB schema from one vacation table ("vacation")
to two ("vacation", "vacation_notification"). Uses
referential integrity CASCADE action to simplify cleanup
when a user is no longer on vacation.
Inserting variables into queries stricly by prepare()
to try to avoid SQL injection.
International characters are now handled well.
2005-01-21 Troels Arvin <troels at arvin.dk>
Uses the Email::Valid package to avoid sending notices
to obviously invalid addresses.
2007-08-15 David Goodwin <david at palepurple.co.uk>
Use the Perl Mail::Sendmail module for sending mail
Check for headers that start with blank lines (patch from forum)
2007-08-20 Martin Ambroz <amsys at trustica.cz>
Added initial Unicode support
2008-05-09 Fabio Bonelli <fabiobonelli at libero.it>
Properly handle failed queries to vacation_notification.
Fixed log reporting.
2008-07-29 Patch from Luxten to add repeat notification after timeout. See:
https://sourceforge.net/tracker/index.php?func=detail&aid=2031631&group_id=191583&atid=937966
2008-08-01 Luigi Iotti <luigi at iotti dot biz>
Use envelope sender/recipient instead of using
From: and To: header fields;
Support to good vacation behavior as in
http://www.irbs.net/internet/postfix/0707/0954.html
(needs to be tested);
2008-08-04 David Goodwin <david at palepurple dot co dot uk>
Use Log4Perl
Added better testing (and -t option)
2009-06-29 Stevan Bajic <stevan at bajic.ch>
Add Mail::Sender for SMTP auth + more flexibility
2009-07-07 Stevan Bajic <stevan at bajic.ch>
Add better alias lookups
Check for more heades from Anti-Virus/Anti-Spam solutions
2009-08-10 Sebastian <reg9009 at yahoo dot de>
Adjust SQL query for vacation timeframe. It is now possible to set from/until date for vacation message.
2012-04-1 Nikolaos Topp <info at ichier.de>
Add configuration parameter $smtp_client in order to get mails through
postfix helo-checks, using check_helo_access whitelist without permitting 'localhost' default style stuff
2012-04-19 Jan Kruis <jan at crossreference dot nl>
change SQL query for vacation into function.
Add sub get_interval()
Gives the user the option to set the interval time ( 0 = one reply, 1 = autoreply, > 1 = Delay reply )
See https://sourceforge.net/tracker/?func=detail&aid=3508083&group_id=191583&atid=937966
2012-06-18 Christoph Lechleitner <christoph.lechleitner@iteg.at>
Add capability to include the subject of the original mail in the subject of the vacation message.
A good vacation subject could be: 'Re: $SUBJECT'
Also corrected log entry about "Already informed ..." to show the $orig_from, not $email
2017-07-14 Thomas Kempf <tkempf@hueper.de>
Replacing deprecated Mail::Sender by Email::Sender
Add configuration parameter $no_vacation_pattern in order to exlude specific alias-recipients from
sending vacation mails, even if one or multiple of the recipients the alias points to has vacation
currently active.

@ -0,0 +1,150 @@
##################################################
# Virtual Vacation for Postfix Admin Release 2.x #
##################################################
#
# Postfix Admin (Virtual Vacation)
# by Mischa Peters <mischa at high5 dot net>
# Copyright (c) 2002 - 2005 High5!
# Licensed under GPL for more info check GPL-LICENSE.TXT
#
# Modified by: Nicholas Paufler <npaufler at incentre dot net> (12/06/2004)
#
REQUIRED!
---------
There are a bunch of Perl modules which need installing, depending on your
distribution these may be available through your package management tool, or
will need installing through CPAN.
A full list of required modules can be found in the source of vacation.pl.
It obviously relies on Perl
About Virtual Vacation
----------------------
Virtual Vacation is today done with a local shell account that can receive
email. The email is then handled by a Perl script which sends the Vacation
message back to the sender.
Install Virtual Vacation
------------------------
1. Create a local account
-------------------------
Create a dedicated local user account called "vacation".
This user handles all potentially dangerous mail content - that is why it
should be a separate account.
Do not use "nobody", and most certainly do not use "root" or "postfix". The
user will never log in, and can be given a "*" password and non-existent
shell and home directory.
This should look like this:
#/etc/passwd
vacation:*:65501:65501::0:0:Virtual Vacation:/nonexistent:/sbin/nologin
#/etc/group
vacation:*:65501:
2. Create a directory
---------------------
Create a directory, for example /var/spool/vacation, that is accessible
only to the "vacation" user. This is where the vacation script is supposed
to store its temporary files.
3. Copy the files
-----------------
Copy the vacation.pl file to the directory you created above:
$ cp vacation.pl <HOME>/vacation.pl
$ chown -R vacation:vacation <HOME>
Which will then look something like:
-rwx------ 1 vacation vacation 3356 Dec 21 00:00 vacation.pl*
4. Setup the transport type
--------------------
Define the transport type in the Postfix master file:
#/etc/postfix/master.cf:
vacation unix - n n - - pipe
flags=Rq user=vacation argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${recipient}
Tell Postfix to use a transport maps file, so add the following to your
Postfix main.cf:
#/etc/postfix/main.cf:
transport_maps = hash:/etc/postfix/transport
Then add the transport definition to the newly created transport file.
Obviously, change yourdomain.com to your own domain. This can be any
arbitrary domain, and it is easiest if you just choose one that will be used
for all your domains.
#/etc/postfix/transport
autoreply.yourdomain.com vacation:
(You may need to create an entry in /etc/hosts for your non-existant domain)
Execute "postmap /etc/postfix/transport" to build the hashed database.
Execute "postfix reload" to complete the change.
5. Create the table
-------------------
The database table should have already been created for you, by running
the 'upgrade.php' script when installing Postfixadmin.
If security is an issue for you, read ../DOCUMENTS/Security.txt
6. Edit vacation.pl
-----------------
The perl vacation.pl script needs minor modification to know which database
you are using, and also how to connect to the database.
Namely :
Change any variables starting with '$db_' and '$db_type' to either 'mysql' or 'pgsql'.
Change the $vacation_domain variable to match what you entered in your /etc/postfix/transport
file.
What do these files do?
-----------------------
When a user enables a vacation message on their account, the alias
definition is changed so that in addition to delivering to their own
mailbox, it also delivers to a dummy alias which calls the vacation.pl
program. In other words, if joeuser@domain.com enables their vacation, the
entry in the alias database table will deliver mail to
joeuser@something.com, as well as
joeuser#something.com@autoreply.yourdomain.com
vacation.pl then checks the database to see wether a user is on holiday and
what message to send back. Make sure that vacation.pl is able to communicate
to your database. In the first couple of lines you have to specify the
database, username and password for it.
NOTE: Make sure that the path to perl is correct.
I'm in trouble!
---------------
When something is not working there are a couple of files that you can have
a look at. The most important one is your maillog (usually in /var/log/).
Vacation.pl also has some debugging and logging capabilties. Check the top
of vacation.pl.
Done!
-----
When this is all in place you need to have a look at the Postfix Admin
config.inc.php. Here you need to enable Virtual Vacation for the site.

@ -1,245 +0,0 @@
# About Virtual Vacation
AKA 'An out of office' automated email response.
The vacation script runs as service within Postfix's master.cf configuration file.
Mail is sent to the vacation service via a transport table mapping.
When users mark themselves as away on vacation, an alias is added to their account
sending a copy of all mail to them to the vacation service.
e.g. mail to billy@goat.com will be delivered to
* billy@goat.com AND
* billy#goat.com@autoreply.goat.com
Mail to @autoreply.goat.com is caught by the vacation.pl script and a reply
will be sent based on various settings. By default a reply is only sent once.
# Dependencies / Requirements
There are a bunch of Perl modules which need installing, depending on your
distribution these may be available through your package management tool, or
will need installing through CPAN.
```
Email::Valid
Email::Sender
Email::Simple
Email::Valid
Try::Tiny
MIME::Charset
MIME::EncWords
Log::Log4perl
Log::Dispatch
GetOpt::Std
Net::DNS;
```
You may install these via CPAN, or through your package tool.
CPAN: 'perl -MCPAN -e shell', then 'install Module::Whatever'
## Debian Systems
```bash
apt-get install libemail-sender-perl libemail-simple-perl libemail-valid-perl libtry-tiny-perl libdbd-pg-perl libemail-mime-perl liblog-log4perl-perl liblog-dispatch-perl libgetopt-argvfile-perl libmime-charset-perl libmime-encwords-perl libnet-dns-perl
```
and one of :
```bash
libdbd-pg-perl or libdbd-mysql-perl
```
# Installing Virtual Vacation
## 1. Create a local account
Create a dedicated local user account called "vacation".
This user handles all potentially dangerous mail content - that is why it
should be a separate account.
Do not use "nobody", and most certainly do not use "root" or "postfix". The
user will never log in, and can be given a "*" password and non-existent
shell and home directory.
Also create a separate "vacation" group.
This should look like this:
```raw
#/etc/passwd
vacation:*:65501:65501:Virtual Vacation:/nonexistent:/sbin/nologin
```
```raw
#/etc/group
vacation:*:65501:
```
## 2. Create a log directory or log file
If you want to log to a file ($log\_to\_file), create a log directory or an
empty log file.
This file or directory needs to be writeable for the "vacation" user.
Note: If you are logging to syslog, you can skip this step.
## 3. Install vacation.pl
Create a directory /usr/lib/postfixadmin/ and copy the vacation.pl file to it:
```bash
mkdir /usr/lib/postfixadmin
cp vacation.pl /usr/lib/postfixadmin/vacation.pl
chown -R root:vacation /usr/lib/postfixadmin
chmod 750 /usr/lib/postfixadmin/ /usr/lib/postfixadmin/vacation.pl
```
Which will then look something like:
```raw
-rwxr-x--- 1 root vacation 3356 Dec 21 00:00 vacation.pl*
```
## 4. Setup the transport type
Define the transport type in the Postfix master file:
```raw
#/etc/postfix/master.cf:
vacation unix - n n - - pipe
flags=Rq user=vacation argv=/usr/lib/postfixadmin/vacation.pl -f ${sender} -- ${recipient}
```
## 5. Setup the transport maps file
Tell Postfix to use a transport maps file, so add the following to your
Postfix main.cf:
```raw
#/etc/postfix/main.cf:
transport_maps = hash:/etc/postfix/transport
```
Then add the transport definition to the newly created transport file.
Obviously, change yourdomain.com to your own domain. This can be any
arbitrary domain, and it is easiest if you just choose one that will be used
for all your domains.
```raw
#/etc/postfix/transport
autoreply.yourdomain.com vacation:
```
(You may need to create an entry in /etc/hosts for your non-existant domain)
Execute
```bash
postmap /etc/postfix/transport
```
Execute
```bash
postfix reload
```
to complete the change.
## 6. Configure vacation.pl
The perl vacation.pl script needs to know which database you are using, and also
how to connect to the database.
Namely :
Change any variables starting with '$db\_' and '$db\_type' to either 'mysql' or 'pgsql'.
Change the $vacation\_domain variable to match what you entered in your /etc/postfix/transport
file.
You can do this in two ways:
a) edit vacation.pl directly (not recommended!)
b) create /etc/postfixadmin/vacation.conf and enter your settings there
Just use perl syntax there to fill the config variables listed in vacation.pl
(without the "our" keyword). Example:
```perl
$db_username = 'mail';
1; # required final line - keeps perl happy.
```
To make sure nobody except vacation.pl can read your vacation.conf (including the
database password), run
```bash
chown root:vacation /etc/postfixadmin/vacation.conf
chmod 640 /etc/postfixadmin/vacation.conf
```
## 7. Check the alias expansion
Depending on your setup, you may have multiple 'smtpd' service definitions within
your postfix master.cf file. This is especially the case if you are also using AMAVIS or
another content filtering system when mail is re-injected into Postfix using the smtpd daemon.
If you are, it's likely that alias expansion may happen more than once, in which case you
may see vacation-style responses duplicated. To suppress this behaviour, you need to add:
```raw
-o receive_override_options=no_address_mappings
```
For example :
```raw
smtp inet n - - - 12 smtpd
-o content_filter=amavis:[127.0.0.50]:10024
-o receive_override_options=no_address_mappings
127.0.0.1:10025 inet n - - - - smtpd
-o smtpd_autorized_xforward_hosts=127.0.0.0/8
-o smtpd_client_restrictions=
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o mynetworks=127.0.0.0/8
-o receive_override_options=no_header_body_checks
```
^^^ Alias expansion occurs here, so we don't want it to happen again for the
first smtpd daemon (above). If you have per-user settings in amavis,
you might want to have no_address_mappings in the smtpd on port 10025
instead.
## 8. Security
If security is an issue for you, read ../DOCUMENTS/Security.txt
# Postfixadmin
When this is all in place you need to have a look at the Postfix Admin
config.inc.php. Here you need to enable Virtual Vacation for the site.
# Help ! It's not working
When something is not working there are a couple of files that you can have
a look at. The most important one is your maillog (usually in /var/log/).
Vacation.pl also has some debugging and logging capabilties. Check the top
of vacation.pl.

@ -0,0 +1,22 @@
<?php
//
// Postfix Admin
// by Mischa Peters <mischa at high5 dot net>
// Copyright (c) 2002 - 2005 High5!
// Licensed under GPL for more info check GPL-LICENSE.TXT
//
// File: index.php
//
// Template File: -none-
//
// Template Variables:
//
// -none-
//
// Form POST \ GET Variables:
//
// -none-
//
header ("Location: ../login.php");
exit;
?>

@ -1,13 +1,78 @@
#!/usr/bin/perl #!/usr/bin/perl -w
# #
# Virtual Vacation 4.2 # Virtual Vacation 4.0
# $Revision$
# Originally by Mischa Peters <mischa at high5 dot net>
# #
# See Contributions.txt for a list of contributions. # Copyright (c) 2002 - 2005 High5!
# https://github.com/postfixadmin/postfixadmin/blob/master/VIRTUAL_VACATION/Contributions.txt # Licensed under GPL for more info check GPL-LICENSE.TXT
#
# See INSTALL.txt for help installing (and lists of dependent packages etc) # Additions:
# https://github.com/postfixadmin/postfixadmin/blob/master/VIRTUAL_VACATION/INSTALL.md # 2004/07/13 David Osborn <ossdev at daocon.com>
# strict, processes domain level aliases, more
# subroutines, send reply from original to address
#
# 2004/11/09 David Osborn <ossdev at daocon.com>
# Added syslog support
# Slightly better logging which includes messageid
# Avoid infinite loops with domain aliases
#
# 2005-01-19 Troels Arvin <troels@arvin.dk>
# PostgreSQL-version.
# Normalized DB schema from one vacation table ("vacation")
# to two ("vacation", "vacation_notification"). Uses
# referential integrity CASCADE action to simplify cleanup
# when a user is no longer on vacation.
# Inserting variables into queries stricly by prepare()
# to try to avoid SQL injection.
# International characters are now handled well.
#
# 2005-01-21 Troels Arvin <troels@arvin.dk>
# Uses the Email::Valid package to avoid sending notices
# to obviously invalid addresses.
#
# 2007-08-15 David Goodwin <david@palepurple.co.uk>
# Use the Perl Mail::Sendmail module for sending mail
# Check for headers that start with blank lines (patch from forum)
#
# 2007-08-20 Martin Ambroz <amsys@trustica.cz>
# Added initial Unicode support
#
# 2008-05-09 Fabio Bonelli <fabiobonelli@libero.it>
# Properly handle failed queries to vacation_notification.
# Fixed log reporting.
#
# 2008-07-29 Patch from Luxten to add repeat notification after timeout. See:
# https://sourceforge.net/tracker/index.php?func=detail&aid=2031631&group_id=191583&atid=937966
#
# 2008-08-01 Luigi Iotti <luigi at iotti dot biz>
# Use envelope sender/recipient instead of using
# From: and To: header fields;
# Support to good vacation behavior as in
# http://www.irbs.net/internet/postfix/0707/0954.html
# (needs to be tested);
#
# 2008-08-04 David Goodwin <david at palepurple dot co dot uk>
# Use Log4Perl
# Added better testing (and -t option)
#
# Requirements - the following perl modules are required:
# DBD::Pg or DBD::mysql
# Mail::Sendmail, Email::Valid MIME::Charset, Log::Log4perl, Log::Dispatch, MIME::EncWords and GetOpt::Std
#
# You may install these via CPAN, or through your package tool.
# CPAN: 'perl -MCPAN -e shell', then 'install Module::Whatever'
#
# On Debian based systems :
# libmail-sendmail-perl
# libdbd-pg-perl
# libemail-valid-perl
# libmime-perl
# liblog-log4perl-perl
# liblog-dispatch-perl
# libgetopt-argvfile-perl
# libmime-charset-perl (currently in testing, see instructions below)
# libmime-encwords-perl (currently in testing, see instructions below)
# #
# Note: When you use this module, you may start seeing error messages # Note: When you use this module, you may start seeing error messages
# like "Cannot insert a duplicate key into unique index # like "Cannot insert a duplicate key into unique index
@ -15,22 +80,13 @@
# behavior, and not an indication of trouble (see the "already_notified" # behavior, and not an indication of trouble (see the "already_notified"
# subroutine for an explanation). # subroutine for an explanation).
# #
# You must also have the Email::Valid and MIME-tools perl-packages
# installed. They are available in some package collections, under the
# names 'perl-Email-Valid' and 'perl-MIME-tools', respectively.
# One such package collection (for Linux) is:
# http://dag.wieers.com/home-made/apt/packages.php
#
use utf8;
use DBI;
use Encode qw(decode);
use MIME::EncWords qw(:all);
use Email::Valid;
use strict;
use Getopt::Std;
use Email::Sender::Simple qw(sendmail);
use Email::Sender::Transport::SMTP;
use Email::Simple;
use Email::Simple::Creator;
use Try::Tiny;
use Log::Log4perl qw(get_logger :levels);
use File::Basename;
use Net::DNS;
# ========== begin configuration ========== # ========== begin configuration ==========
# IMPORTANT: If you put passwords into this script, then remember # IMPORTANT: If you put passwords into this script, then remember
@ -39,118 +95,76 @@ use Net::DNS;
# db_type - uncomment one of these # db_type - uncomment one of these
our $db_type = 'Pg'; our $db_type = 'Pg';
#our $db_type = 'mysql'; #my $db_type = 'mysql';
# leave empty for connection via UNIX socket # leave empty for connection via UNIX socket
our $db_host = ''; our $db_host = '';
# connection details # connection details
our $db_username = 'user'; our $db_username = 'dg';
our $db_password = 'password'; our $db_password = 'gingerdog';
our $db_name = 'postfix'; our $db_name = 'postfix';
our $vacation_domain = 'autoreply.example.org'; our $vacation_domain = 'autoreply.example.org';
our $recipient_delimiter = '+'; # smtp server used to send vacation e-mails
our $smtp_server = 'localhost';
# port to connect to; defaults to 25 for non-SSL, 465 for 'ssl', 587 for 'starttls'
our $smtp_server_port = 25;
# this is the helo we [the vacation script] use on connection; you may need to change this to your hostname or something,
# depending upon what smtp helo restrictions you have in place within Postfix.
our $smtp_client = 'localhost';
# send mail encrypted or plaintext
# if 'starttls', use STARTTLS; if 'ssl' (or 1), connect securely; otherwise, no security
our $smtp_ssl = 'starttls';
# maximum time in secs to wait for server; default is 120
our $smtp_timeout = '120';
# sasl_username: the username to use for auth; optional
our $smtp_authid = '';
# sasl_password: the password to use for auth; required if username is provided
our $smtp_authpwd = '';
# This specifies the mail 'from' name which is shown to recipients of vacation replies.
# If you leave it empty, the vacation mail will contain:
# From: <original@recipient.domain>
# If you specify something here you'd instead see something like :
# From: Some Friendly Name <original@recipient.domain>
our $friendly_from = '';
# Set to 1 to enable logging to syslog. # Set to 1 to enable logging to syslog.
our $syslog = 0; our $syslog = 0;
# path to logfile, when empty logging is suppressed # path to logfile, when empty logging is supressed
# change to e.g. /dev/null if you want nothing logged. # change to e.g. /dev/null if you want nothing logged.
# if we can't write to this, and $log_to_file is 1 (below) the script will abort. # if we can't write to this, we try /tmp/vacation.log instead
our $logfile='/var/log/vacation.log'; our $logfile='/var/spool/vacation/vacation.log';
# 2 = debug + info, 1 = info only, 0 = error only # 2 = debug + info, 1 = info only, 0 = error only
our $log_level = 2; our $log_level = 2;
# Whether to log to file or not, 0 = do not write to a log file
our $log_to_file = 0;
# notification interval, in seconds # notification interval, in seconds
# set to 0 to notify only once # set to 0 to notify only once
# e.g. 1 day ... # e.g. 1 day ...
#our $interval = 60*60*24; #my $interval = 60*60*24;
# disabled by default # disabled by default
our $interval = 0; our $interval = 0;
# Send vacation mails to do-not-reply email addresses.
# By default vacation email addresses will be sent.
# For now emails from bounce|do-not-reply|facebook|linkedin|list-|myspace|twitter won't
# be answered when $custom_noreply_pattern is set to 1.
# default = 0
our $custom_noreply_pattern = 0;
our $noreply_pattern = 'bounce|do-not-reply|facebook|linkedin|list-|myspace|twitter';
# Never send vacation mails for the following recipient email addresses.
# Useful for e.g. aliases pointing to multiple recipients which have vacation active
# hence an email to the alias should not trigger vacation messages.
# By default vacation email addresses will be sent for all recipients.
# default = ''
# preventing vacation notifications for recipient info@example.org would look like this:
# our $no_vacation_pattern = 'info\@example\.org';
our $no_vacation_pattern = 'info\@example\.org';
# instead of changing this script, you can put your settings to /etc/mail/postfixadmin/vacation.conf # instead of changing this script, you can put your settings to /etc/mail/postfixadmin/vacation.conf
# or /etc/postfixadmin/vacation.conf just use Perl syntax there to fill the variables listed above # just use perl syntax there to fill the variables listed above (without the "our" keyword). Example:
# (without the "our" keyword). Example:
# $db_username = 'mail'; # $db_username = 'mail';
if (-f '/etc/mail/postfixadmin/vacation.conf') { if (-f "/etc/mail/postfixadmin/vacation.conf") {
require '/etc/mail/postfixadmin/vacation.conf'; require "/etc/mail/postfixadmin/vacation.conf";
} elsif (-f '/etc/postfixadmin/vacation.conf') {
require '/etc/postfixadmin/vacation.conf';
} elsif (-f './vacation.conf') {
require './vacation.conf';
} }
# =========== end configuration =========== # =========== end configuration ===========
if($log_to_file == 1) { if ( ! -w $logfile ) {
if (( ! -w $logfile ) && (! -w dirname($logfile))) { $logfile = "/tmp/vacation.log";
# Cannot log; no where to write to.
die("Cannot create logfile : $logfile");
}
} }
my ($from, $to, $cc, $replyto , $subject, $messageid, $lastheader, $smtp_sender, $smtp_recipient, %opts, $test_mode, $logger); use DBI;
use MIME::Base64;
use MIME::EncWords qw(:all);
use Email::Valid;
use strict;
use Mail::Sendmail;
use Getopt::Std;
use Log::Log4perl qw(get_logger :levels);
my ($from, $to, $cc, $replyto , $subject, $messageid, $lastheader, $smtp_sender, $smtp_recipient, %opts, $spam, $test_mode, $logger);
$subject=''; $subject='';
$messageid='unknown'; $messageid='unknown';
# Setup a logger... # Setup a logger...
# #
getopts('f:t:', \%opts) or die "Usage: $0 [-t yes] -f sender -- recipient\n\t-t for testing only\n"; getopts('f:t:', \%opts) or die "Usage: $0 [-t yes] -f sender -- recipient\n -t for testing only\n";
$opts{f} and $smtp_sender = $opts{f} or die '-f sender not present on command line'; $opts{f} and $smtp_sender = $opts{f} or die "-f sender not present on command line";
$test_mode = 0; $test_mode = 0;
$opts{t} and $test_mode = 1; $opts{t} and $test_mode = 1;
$smtp_recipient = shift or die 'recipient not given on command line'; $smtp_recipient = shift or die "recipient not given on command line";
my $log_layout = Log::Log4perl::Layout::PatternLayout->new('%d %p> %F:%L %M - %m%n'); my $log_layout = Log::Log4perl::Layout::PatternLayout->new("%d %p> %F:%L %M - %m%n");
if($test_mode == 1) { if($test_mode == 1) {
$logger = get_logger(); $logger = get_logger();
@ -158,26 +172,23 @@ if($test_mode == 1) {
my $appender = Log::Log4perl::Appender->new('Log::Dispatch::Screen'); my $appender = Log::Log4perl::Appender->new('Log::Dispatch::Screen');
$appender->layout($log_layout); $appender->layout($log_layout);
$logger->add_appender($appender); $logger->add_appender($appender);
$logger->debug('Test mode enabled'); $logger->debug("Test mode enabled");
}
} else { else {
# log to file.
my $appender = Log::Log4perl::Appender->new(
'Log::Dispatch::File',
filename => $logfile,
mode => 'append');
$logger = get_logger(); $logger = get_logger();
if($log_to_file == 1) { $appender->layout($log_layout);
# log to file $logger->add_appender($appender);
my $appender = Log::Log4perl::Appender->new(
'Log::Dispatch::File',
filename => $logfile,
mode => 'append');
$appender->layout($log_layout);
$logger->add_appender($appender);
}
if($syslog == 1) { if($syslog == 1) {
my $syslog_appender = Log::Log4perl::Appender->new( my $syslog_appender = Log::Log4perl::Appender->new(
'Log::Dispatch::Syslog', 'Log::Dispatch::Syslog',
facility => 'mail', Facility => 'user',
ident => 'vacation',
); );
$logger->add_appender($syslog_appender); $logger->add_appender($syslog_appender);
} }
@ -192,7 +203,8 @@ if($log_level == 2) {
$logger->level($DEBUG); $logger->level($DEBUG);
} }
binmode (STDIN,':encoding(UTF-8)');
binmode (STDIN,':utf8');
my $dbh; my $dbh;
if ($db_host) { if ($db_host) {
@ -202,62 +214,27 @@ if ($db_host) {
} }
if (!$dbh) { if (!$dbh) {
$logger->error('Could not connect to database'); # eval { } etc better here? $logger->error("Could not connect to database"); # eval { } etc better here?
exit(0); exit(0);
} }
my $db_true; # MySQL and PgSQL use different values for TRUE, and unicode support... my $db_true; # MySQL and PgSQL use different values for TRUE, and unicode support...
if ($db_type eq 'mysql') { if ($db_type eq "mysql") {
$dbh->do('SET CHARACTER SET utf8;'); $dbh->do("SET CHARACTER SET utf8;");
$db_true = '1'; $db_true = '1';
} else { # Pg } else { # Pg
$dbh->do("SET CLIENT_ENCODING TO 'UTF8'"); $dbh->do("SET CLIENT_ENCODING TO 'UTF8'");
$dbh->{pg_enable_utf8} = 1;
$db_true = 'True'; $db_true = 'True';
} }
# used to detect infinite address lookup loops # used to detect infinite address lookup loops
my $loopcount=0; my $loopcount=0;
#
# Get interval_time for email user from the vacation table
#
sub get_interval {
my ($to) = @_;
my $query = qq{SELECT interval_time FROM vacation WHERE email=? };
my $stm = $dbh->prepare($query) or panic_prepare($query);
$stm->execute($to) or panic_execute($query," 'email='$to'");
my $rv = $stm->rows;
if ($rv == 1) {
my @row = $stm->fetchrow_array;
my $interval = $row[0] ;
return $interval ;
} else {
return 0 ;
}
}
sub already_notified { sub already_notified {
my ($to, $from) = @_; my ($to, $from) = @_;
my $logger = get_logger(); my $logger = get_logger();
my $query; my $query = qq{INSERT into vacation_notification (on_vacation,notified) values (?,?)};
# delete old notifications
if ($db_type eq 'Pg') {
$query = qq{DELETE FROM vacation_notification USING vacation WHERE vacation.email = vacation_notification.on_vacation AND on_vacation = ? AND notified = ? AND notified_at < vacation.activefrom;};
} else { # mysql
$query = qq{DELETE vacation_notification.* FROM vacation_notification LEFT JOIN vacation ON vacation.email = vacation_notification.on_vacation WHERE on_vacation = ? AND notified = ? AND notified_at < vacation.activefrom};
}
my $stm = $dbh->prepare($query); my $stm = $dbh->prepare($query);
if (!$stm) {
$logger->error("Could not prepare query (trying to delete old vacation notifications) :'$query' to: $to, from:$from");
return 1;
}
$stm->execute($to,$from);
$query = qq{INSERT into vacation_notification (on_vacation,notified) values (?,?)};
$stm = $dbh->prepare($query);
if (!$stm) { if (!$stm) {
$logger->error("Could not prepare query '$query' to: $to, from:$from"); $logger->error("Could not prepare query '$query' to: $to, from:$from");
return 1; return 1;
@ -267,28 +244,21 @@ sub already_notified {
if (!$stm->execute($to,$from)) { if (!$stm->execute($to,$from)) {
my $e=$dbh->errstr; my $e=$dbh->errstr;
# Violation of a primary key constraint may happen here, and that's # Violation of a primay key constraint may happen here, and that's
# fine. All other error conditions are not fine, however. # fine. All other error conditions are not fine, however.
if ($e !~ /(?:_pkey|^Duplicate entry)/) { if ($e !~ /(?:_pkey|^Duplicate entry)/) {
$logger->error("Failed to insert into vacation_notification table (to:$to from:$from error:'$e' query:'$query')"); $logger->error("Failed to insert into vacation_notification table (to:$to from:$from error:'$e' query:'$query')");
# Let's play safe and notify anyway # Let's play safe and notify anyway
return 1; return 1;
} }
$interval = get_interval($to);
if ($interval) { if ($interval) {
if ($db_type eq 'Pg') { $query = qq{SELECT NOW()-notified_at FROM vacation_notification WHERE on_vacation=? AND notified=?};
$query = qq{SELECT extract( epoch from (NOW()-notified_at))::int FROM vacation_notification WHERE on_vacation=? AND notified=?};
} else { # mysql
$query = qq{SELECT UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(notified_at) FROM vacation_notification WHERE on_vacation=? AND notified=?};
}
$stm = $dbh->prepare($query) or panic_prepare($query); $stm = $dbh->prepare($query) or panic_prepare($query);
$stm->execute($to,$from) or panic_execute($query,"on_vacation='$to', notified='$from'"); $stm->execute($to,$from) or panic_execute($query,"on_vacation='$to', notified='$from'");
my @row = $stm->fetchrow_array; my @row = $stm->fetchrow_array;
my $int = $row[0]; my $int = $row[0];
if ($int > $interval) { if ($int > $interval) {
$logger->info("[Interval elapsed, sending the message]: From: $from To:$to"); $logger->debug("[Interval elapsed, sending the message]: From: $from To:$to");
$query = qq{UPDATE vacation_notification SET notified_at=NOW() WHERE on_vacation=? AND notified=?}; $query = qq{UPDATE vacation_notification SET notified_at=NOW() WHERE on_vacation=? AND notified=?};
$stm = $dbh->prepare($query); $stm = $dbh->prepare($query);
if (!$stm) { if (!$stm) {
@ -311,110 +281,76 @@ sub already_notified {
return 0; return 0;
} }
#
# Check to see if there is a vacation record against a specific email address.
#
sub check_for_vacation {
my ($email_to_check) =@_;
my $query = qq{SELECT email FROM vacation WHERE email=? and active=$db_true and activefrom <= NOW() and activeuntil >= NOW()};
my $stm = $dbh->prepare($query) or panic_prepare($query);
$stm->execute($email_to_check) or panic_execute($query,"email='$email_to_check'");
my $rv = $stm->rows;
return $rv;
}
# try and determine if email address has vacation turned on; we
# try and determine if email address has vacation turned on; we
# have to do alias searching, and domain aliasing resolution for this. # have to do alias searching, and domain aliasing resolution for this.
# If found, return ($num_matches, $real_email); # If found, return ($num_matches, $real_email);
sub find_real_address { sub find_real_address {
my ($email) = @_; my ($email) = @_;
my $logger = get_logger(); my $logger = get_logger();
if (++$loopcount > 20) { if (++$loopcount > 20) {
$logger->error("find_real_address loop! (more than 20 attempts!) currently: $email"); $logger->error("find_real_address loop! (more than 20 attempts!) currently: $email");
exit(1); exit(1);
} }
my $realemail = ''; my $realemail = '';
my $rv = check_for_vacation($email); my $query = qq{SELECT email FROM vacation WHERE email=? and active=$db_true};
my $stm = $dbh->prepare($query) or panic_prepare($query);
$stm->execute($email) or panic_execute($query,"email='$email'");
my $rv = $stm->rows;
# Recipient has vacation # Recipient has vacation
if ($rv == 1) { if ($rv == 1) {
$realemail = $email; $realemail = $email;
$logger->debug("Found '$email' has vacation active"); $logger->debug("Found $email has vacation active");
} else { } else {
my $vemail = $email; # XXX why aren't we doing a join here?
$vemail =~ s/\@/#/g; $logger->debug("Looking for alias records that $email resolves to with vacation turned on");
$vemail = $vemail . "\@" . $vacation_domain; $query = qq{SELECT goto FROM alias WHERE address=?};
$logger->debug("Looking for alias records that '$email' resolves to with vacation turned on"); $stm = $dbh->prepare($query) or panic_prepare($query);
my $query = qq{SELECT goto FROM alias WHERE address=? AND (goto LIKE ? OR goto LIKE ? OR goto LIKE ? OR goto = ?)}; $stm->execute($email) or panic_execute($query,"address='$email'");
my $stm = $dbh->prepare($query) or panic_prepare($query);
$stm->execute($email,"$vemail,%","%,$vemail","%,$vemail,%", "$vemail") or panic_execute($query,"address='$email'");
$rv = $stm->rows; $rv = $stm->rows;
# Recipient is an alias, check if mailbox has vacation # Recipient is an alias, check if mailbox has vacation
if ($rv == 1) { if ($rv == 1) {
my @row = $stm->fetchrow_array; my @row = $stm->fetchrow_array;
my $alias = $row[0]; my $alias = $row[0];
if ($alias =~ /,/) { $query = qq{SELECT email FROM vacation WHERE email=? and active=$db_true};
for (split(/\s*,\s*/, lc($alias))) { $stm = $dbh->prepare($query) or panic_prepare($query);
my $singlealias = $_; $stm->execute($alias) or panic_prepare($query,"email='$alias'");
$logger->debug("Found alias \'$singlealias\' for email \'$email\'. Looking if vacation is on for alias."); $rv = $stm->rows;
$rv = check_for_vacation($singlealias);
# Alias has vacation
if ($rv == 1) {
$realemail = $singlealias;
last;
}
}
} else {
$rv = check_for_vacation($alias);
# Alias has vacation # Alias has vacation
if ($rv == 1) { if ($rv == 1) {
$realemail = $alias; $realemail = $alias;
}
} }
# We have to look for alias domain (domain1 -> domain2) # We still have to look for domain level aliases...
} else { } else {
my ($user, $domain) = split(/@/, $email); my ($user, $domain) = split(/@/, $email);
$logger->debug("Looking for alias domain for $domain / $email / $user"); $query = qq{SELECT goto FROM alias WHERE address=?};
$query = qq{SELECT target_domain FROM alias_domain WHERE alias_domain=?};
$stm = $dbh->prepare($query) or panic_prepare($query); $stm = $dbh->prepare($query) or panic_prepare($query);
$stm->execute($domain) or panic_execute($query,"alias_domain='$domain'"); $stm->execute("\@$domain") or panic_execute($query,"address='\@$domain'");
$rv = $stm->rows; $rv = $stm->rows;
$logger->debug("Looking for domain level aliases for $domain / $email / $user");
# The domain has a alias domain level alias # The receipient has a domain level alias
if ($rv == 1) { if ($rv == 1) {
my @row = $stm->fetchrow_array; my @row = $stm->fetchrow_array;
my $alias_domain_dest = $row[0]; my $wildcard_dest = $row[0];
($rv, $realemail) = find_real_address ("$user\@$alias_domain_dest"); my ($wilduser, $wilddomain) = split(/@/, $wildcard_dest);
# We still have to look for domain level aliases...
} else {
my ($user, $domain) = split(/@/, $email);
$logger->debug("Looking for domain level aliases for $domain / $email / $user");
$query = qq{SELECT goto FROM alias WHERE address=?};
$stm = $dbh->prepare($query) or panic_prepare($query);
$stm->execute("\@$domain") or panic_execute($query,"address='\@$domain'");
$rv = $stm->rows;
# The recipient has a domain level alias
if ($rv == 1) {
my @row = $stm->fetchrow_array;
my $wildcard_dest = $row[0];
my ($wilduser, $wilddomain) = split(/@/, $wildcard_dest);
# Check domain alias # Check domain alias
if ($wilduser) { if ($wilduser) {
($rv, $realemail) = find_real_address ($wildcard_dest); ($rv, $realemail) = find_real_address ($wildcard_dest);
} else {
($rv, $realemail) = find_real_address ("$user\@$wilddomain");
}
} else { } else {
$logger->debug("No domain level alias present for $domain / $email / $user"); my $new_email = $user . '@' . $wilddomain;
($rv, $realemail) = find_real_address ($new_email);
} }
} }
else {
$logger->debug("No domain level alias present for $domain / $email / $user");
}
} }
} }
return ($rv, $realemail); return ($rv, $realemail);
@ -423,7 +359,7 @@ sub find_real_address {
# sends the vacation mail to the original sender. # sends the vacation mail to the original sender.
# #
sub send_vacation_email { sub send_vacation_email {
my ($email, $orig_from, $orig_to, $orig_messageid, $orig_subject, $test_mode) = @_; my ($email, $orig_from, $orig_to, $orig_messageid, $test_mode) = @_;
my $logger = get_logger(); my $logger = get_logger();
$logger->debug("Asked to send vacation reply to $email thanks to $orig_messageid"); $logger->debug("Asked to send vacation reply to $email thanks to $orig_messageid");
my $query = qq{SELECT subject,body FROM vacation WHERE email=?}; my $query = qq{SELECT subject,body FROM vacation WHERE email=?};
@ -432,97 +368,43 @@ sub send_vacation_email {
my $rv = $stm->rows; my $rv = $stm->rows;
if ($rv == 1) { if ($rv == 1) {
my @row = $stm->fetchrow_array; my @row = $stm->fetchrow_array;
if (already_notified($email, $orig_from) == 1) { if (already_notified($email, $orig_from) == 1) {
$logger->debug("Already notified $orig_from, or some error prevented us from doing so"); $logger->debug("Already notified $email, or some error prevented us from doing so");
return; return;
} }
$logger->debug("Will send vacation response for $orig_messageid: FROM: $email (orig_to: $orig_to), TO: $orig_from; VACATION SUBJECT: $row[0] ; VACATION BODY: $row[1]"); $logger->debug("Will send vacation response for $orig_messageid: FROM: $email (orig_to: $orig_to), TO: $orig_from; VACATION SUBJECT: $row[0] ; VACATION BODY: $row[1]");
my $subject = $row[0]; my $subject = $row[0];
$subject = Encode::decode_utf8( $subject ) if( !Encode::is_utf8( $subject ) );
$orig_subject = decode("mime-header", $orig_subject);
$subject =~ s/\$SUBJECT/$orig_subject/g;
if ($subject ne $row[0]) {
$logger->debug("Patched Subject of vacation message to: $subject");
}
my $body = $row[1]; my $body = $row[1];
$body = Encode::decode_utf8( $body ) if( !Encode::is_utf8( $body ) );
my $from = $email; my $from = $email;
my $to = $orig_from; my $to = $orig_from;
my $vacation_subject = encode_mimewords($subject, 'Encoding'=> 'q', 'Charset'=>'utf-8', 'Field'=>'Subject');
# part of the username in the email && part of the domain in the email my %mail;
my ($email_username_part, $email_domain_part) = split(/@/, $email); %mail = (
'smtp' => $smtp_server,
my $resolver = Net::DNS::Resolver->new; 'Subject' => $vacation_subject,
my @mx = mx($resolver, $email_domain_part); 'From' => $from,
my $smtp_server; 'To' => $to,
if (@mx) { 'MIME-Version' => '1.0',
$smtp_server = @mx[0]->exchange; 'Content-Type' => 'text/plain; charset=UTF-8',
$logger->debug("Found MX record <$smtp_server> for user <$email>!"); 'Content-Transfer-Encoding' => 'base64',
} else { 'Precedence' => 'junk',
$logger->error("Unable to find MX record for user <$email>, error message: ".$resolver->errorstring); 'X-Loop' => 'Postfix Admin Virtual Vacation',
exit(0); 'Message' => encode_base64($body)
}
my $smtp_params = {
host => $smtp_server,
port => $smtp_server_port,
ssl_options => {
SSL_verifycn_name => $smtp_server
},
ssl => $smtp_ssl,
timeout => $smtp_timeout,
localaddr => $smtp_client,
debug => 0,
};
if($smtp_authid ne ''){
$smtp_params->{sasl_username}=$smtp_authid;
$smtp_params->{sasl_password}=$smtp_authpwd;
$logger->info("Doing SASL Authentication with user $smtp_params->{sasl_username}\n");
};
my $transport = Email::Sender::Transport::SMTP->new($smtp_params);
$subject = Encode::encode_utf8( $subject ) if( Encode::is_utf8( $subject ) );
$body = Encode::encode_utf8( $body ) if( Encode::is_utf8( $body ) );
$email = Email::Simple->create(
header => [
To => $to,
From => $from,
Subject => encode_mimewords($subject, 'Charset', 'UTF-8'),
Precedence => 'junk',
'Content-Type' => "text/plain; charset=utf-8",
'X-Loop' => 'Postfix Admin Virtual Vacation',
],
body => $body,
); );
if($test_mode == 1) { if($test_mode == 1) {
$logger->info("** TEST MODE ** : Vacation response sent to $to from $from subject $subject (not) sent\n"); $logger->info("** TEST MODE ** : Vacation response sent to $to from $from subject $subject (not) sent\n");
$logger->info($email); $logger->info(%mail);
return 0; return 0;
} }
sendmail(%mail) or $logger->error("Failed to send vacation response: " . $Mail::Sendmail::error);
try { $logger->debug("Vacation response sent, Mail::Sendmail said : " . $Mail::Sendmail::log);
sendmail($email, { transport => $transport });
} finally {
if (@_) {
$logger->error("Failed to send vacation response to $to from $from subject $subject: @_");
} else {
$logger->debug("Vacation response sent to $to from $from subject $subject sent\n");
}
}
} }
} }
# Convert a (list of) email address(es) from RFC 822 style addressing to # Remove textual stuff from a (list of) email address(es)
# RFC 821 style addressing. e.g. convert: # e.g. convert: "aardvark" <a@b.com>, "Danger Mouse" <c@d.com>, e@f.com to
# "John Jones" <JJones@acme.com>, "Jane Doe/Sales/ACME" <JDoe@acme.com> # a@b.com, c@d.com, e@f.com
# to:
# jjones@acme.com, jdoe@acme.com
sub strip_address { sub strip_address {
my ($arg) = @_; my ($arg) = @_;
if(!$arg) { if(!$arg) {
@ -531,24 +413,26 @@ sub strip_address {
my @ok; my @ok;
$logger = get_logger(); $logger = get_logger();
my @list; my @list;
@list = $arg =~ m/([\w\.\-\+\'\=_\^\|\$\/\{\}~\?\*\\&\!`\%]+\@[\w\.\-]+\w+)/g; @list = $arg =~ m/([\w\.\-\']+\@[\w\.\-]+\w+)/g;
foreach(@list) { foreach(@list) {
#$logger->debug("Checking: $_"); #$logger->debug("Checking: $_");
my $temp = Email::Valid->address( -address => $_, -mxcheck => 0); my $temp = Email::Valid->address( -address => $_, -mxcheck => 0);
if($temp) { if($temp) {
push(@ok, $temp); push(@ok, $temp);
} else { }
else {
$logger->debug("Email not valid : $Email::Valid::Details"); $logger->debug("Email not valid : $Email::Valid::Details");
} }
} }
# remove duplicates # remove duplicates
my %seen = (); my %seen = ();
my @uniq; my @uniq;
foreach my $item (@ok) { my $item;
foreach $item (@ok) {
push(@uniq, $item) unless $seen{$item}++ push(@uniq, $item) unless $seen{$item}++
} }
my $result = lc(join(', ', @uniq)); my $result = join(", ", @uniq);
#$logger->debug("Result: $result"); #$logger->debug("Result: $result");
return $result; return $result;
} }
@ -573,14 +457,13 @@ sub check_and_clean_from_address {
my ($address) = @_; my ($address) = @_;
my $logger = get_logger(); my $logger = get_logger();
if($address =~ /^(noreply|postmaster|mailer\-daemon|listserv|majordomo|owner\-|request\-|bounces\-)/i || if($address =~ /^(noreply|postmaster|mailer-daemon|listserv|majordomo|owner-|request-|bounces-)/i ||
$address =~ /\-(owner|request|bounces)\@/i || $address =~ /-(owner|request|bounces)\@/i ) {
($custom_noreply_pattern == 1 && $address =~ /^.*($noreply_pattern).*/i) ) { $logger->debug("sender $address contains $1 - will not send vacation message");
$logger->debug("sender $address contains $1 - will not send vacation message"); exit(0);
exit(0); }
}
$address = strip_address($address); $address = strip_address($address);
if($address eq '') { if($address eq "") {
$logger->error("Address $address is not valid; exiting"); $logger->error("Address $address is not valid; exiting");
exit(0); exit(0);
} }
@ -594,89 +477,84 @@ $cc = '';
$replyto = ''; $replyto = '';
$logger->debug("Script argument SMTP recipient is : '$smtp_recipient' and smtp_sender : '$smtp_sender'"); $logger->debug("Script argument SMTP recipient is : '$smtp_recipient' and smtp_sender : '$smtp_sender'");
while (<STDIN>) { while (<STDIN>) {
last if (/^$/); last if (/^$/);
if (/^\s+(.*)/ and $lastheader) { $$lastheader .= " $1"; next; } if (/^\s+(.*)/ and $lastheader) { $$lastheader .= " $1"; next; }
elsif (/^from:\s*(.*)\n$/i) { $from = $1; $lastheader = \$from; } elsif (/^from:\s*(.*)\n$/i) { $from = $1; $lastheader = \$from; }
elsif (/^to:\s*(.*)\n$/i) { $to = $1; $lastheader = \$to; } elsif (/^to:\s*(.*)\n$/i) { $to = $1; $lastheader = \$to; }
elsif (/^cc:\s*(.*)\n$/i) { $cc = $1; $lastheader = \$cc; } elsif (/^cc:\s*(.*)\n$/i) { $cc = $1; $lastheader = \$cc; }
elsif (/^Reply\-to:\s*(.*)\s*\n$/i) { $replyto = $1; $lastheader = \$replyto; } elsif (/^Reply-to:\s*(.*)\s*\n$/i) { $replyto = $1; $lastheader = \$replyto; }
elsif (/^subject:\s*(.*)\n$/i) { $subject = $1; $lastheader = \$subject; } elsif (/^subject:\s*(.*)\n$/i) { $subject = $1; $lastheader = \$subject; }
elsif (/^message\-id:\s*(.*)\s*\n$/i) { $messageid = $1; $lastheader = \$messageid; } elsif (/^message-id:\s*(.*)\s*\n$/i) { $messageid = $1; $lastheader = \$messageid; }
elsif (/^x\-spam\-(flag|status):\s+yes/i) { $logger->debug("x-spam-$1: yes found; exiting"); exit (0); } elsif (/^x-spam-(flag|status):\s+yes/i) { $logger->debug("x-spam-$1: yes found; exiting"); exit (0); }
elsif (/^x\-facebook\-notify:/i) { $logger->debug('Mail from facebook, ignoring'); exit(0); } elsif (/^x-facebook-notify:/i) { $logger->debug('Mail from facebook, ignoring'); exit(0); }
elsif (/^precedence:\s+(bulk|list|junk)/i) { $logger->debug("precedence: $1 found; exiting"); exit (0); } elsif (/^precedence:\s+(bulk|list|junk)/i) { $logger->debug("precedence: $1 found; exiting"); exit (0); }
elsif (/^x\-loop:\s+postfix\ admin\ virtual\ vacation/i) { $logger->debug('x-loop: postfix admin virtual vacation found; exiting'); exit (0); } elsif (/^x-loop:\s+postfix\ admin\ virtual\ vacation/i) { $logger->debug("x-loop: postfix admin virtual vacation found; exiting"); exit (0); }
elsif (/^Auto\-Submitted:\s*no/i) { next; } elsif (/^Auto-Submitted:\s*no/i) { next; }
elsif (/^Auto\-Submitted:/i) { $logger->debug('Auto-Submitted: something found; exiting'); exit (0); } elsif (/^Auto-Submitted:/i) { $logger->debug("Auto-Submitted: something found; exiting"); exit (0); }
elsif (/^List\-(Id|Post|Unsubscribe):/i) { $logger->debug("List-$1: found; exiting"); exit (0); } elsif (/^List-(Id|Post):/i) { $logger->debug("List-$1: found; exiting"); exit (0); }
elsif (/^(x\-(barracuda\-)?spam\-status):\s+(yes)/i) { $logger->debug("$1: $3 found; exiting"); exit (0); } else {$lastheader = "" ; }
elsif (/^(x\-dspam\-result):\s+(spam|bl[ao]cklisted)/i) { $logger->debug("$1: $2 found; exiting"); exit (0); }
elsif (/^(x\-(anti|avas\-)?virus\-status):\s+(infected)/i) { $logger->debug("$1: $3 found; exiting"); exit (0); }
elsif (/^(x\-(avas\-spam|spamtest|crm114|razor|pyzor)\-status):\s+(spam)/i) { $logger->debug("$1: $3 found; exiting"); exit (0); }
elsif (/^(x\-osbf\-lua\-score):\s+[0-9\/\.\-\+]+\s+\[([-S])\]/i) { $logger->debug("$1: $2 found; exiting"); exit (0); }
elsif (/^x\-autogenerated:\s*reply/i) { $logger->debug('x-autogenerated found; exiting'); exit (0); }
elsif (/^x\-auto\-response\-suppress:\s*oof/i) { $logger->debug('x-auto-response-suppress: oof found; exiting'); exit (0); }
else {$lastheader = '' ; }
} }
if($smtp_recipient =~ /\@$vacation_domain/) { if($smtp_recipient =~ /\@$vacation_domain/) {
# the regexp used here could probably be improved somewhat, for now hope that people won't use # as a valid mailbox character. # the regexp used here could probably be improved somewhat, for now hope that people won't use # as a valid mailbox character.
my $tmp = $smtp_recipient; my $tmp = $smtp_recipient;
$tmp =~ s/\@$vacation_domain//; $tmp =~ s/\@$vacation_domain//;
$tmp =~ s/#/\@/; $tmp =~ s/#/\@/;
if ($recipient_delimiter) {
$tmp =~ s/[\Q$recipient_delimiter\E].+$//;
}
$logger->debug("Converted autoreply mailbox back to normal style - from $smtp_recipient to $tmp"); $logger->debug("Converted autoreply mailbox back to normal style - from $smtp_recipient to $tmp");
$smtp_recipient = $tmp; $smtp_recipient = $tmp;
undef $tmp; undef $tmp;
} }
# If either From: or To: are not set, exit # If either From: or To: are not set, exit
if(!$from || !$to || !$messageid || !$smtp_sender || !$smtp_recipient) { if(!$from || !$to || !$messageid || !$smtp_sender || !$smtp_recipient) {
$logger->info("One of from=$from, to=$to, messageid=$messageid, smtp sender=$smtp_sender, smtp recipient=$smtp_recipient empty"); $logger->info("One of from=$from, to=$to, messageid=$messageid, smtp sender=$smtp_sender, smtp recipient=$smtp_recipient empty");
exit(0); exit(0);
} }
$logger->debug("Email headers have to: '$to' and From: '$from'"); $logger->debug("Email headers have to: '$to' and From: '$from'");
if ($to =~ /^.*($no_vacation_pattern).*/i) {
$logger->debug("Will not send vacation reply for messages to $to");
exit(0);
}
$to = strip_address($to); $to = strip_address($to);
$cc = strip_address($cc); $from = lc ($from);
$from = check_and_clean_from_address($from); $from = check_and_clean_from_address($from);
if($replyto ne '') { if($replyto ne "") {
# if reply-to is invalid, or looks like a mailing list, then we probably don't want to send a reply. # if reply-to is invalid, or looks like a mailing list, then we probably don't want to send a reply.
$replyto = check_and_clean_from_address($replyto); $replyto = check_and_clean_from_address($replyto);
} }
$smtp_sender = check_and_clean_from_address($smtp_sender); $smtp_sender = check_and_clean_from_address($smtp_sender);
$smtp_recipient = check_and_clean_from_address($smtp_recipient); $smtp_recipient = check_and_clean_from_address($smtp_recipient);
if ($smtp_sender eq $smtp_recipient) {
$logger->debug("smtp sender $smtp_sender and recipient $smtp_recipient are the same; aborting"); if ($smtp_sender eq $smtp_recipient) {
exit(0); $logger->debug("smtp sender $smtp_sender and recipient $smtp_recipient are the same; aborting");
exit(0);
} }
my $recipfound = 0;
for (split(/,\s*/, lc($to)), split(/,\s*/, lc($cc))) { for (split(/,\s*/, lc($to)), split(/,\s*/, lc($cc))) {
my $header_recipient = strip_address($_); my $destinatario = strip_address($_);
if ($smtp_sender eq $header_recipient) { if ($smtp_sender eq $destinatario) {
$logger->debug("sender header $smtp_sender contains recipient $header_recipient (mailing myself?)"); $logger->debug("sender header $smtp_sender contains recipient $destinatario (mailing myself?)");
exit(0); exit(0);
} }
if ($smtp_recipient eq $destinatario) { $recipfound++; }
} }
if (!$recipfound) {
$logger->debug("smtp envelope recipient $smtp_recipient not found in the header recipients ($to & $cc) (therefore they were bcc'ed, so won't send vacation message)");
exit (0);
}
my ($rv, $email) = find_real_address($smtp_recipient); my ($rv, $email) = find_real_address($smtp_recipient);
if ($rv == 1) { if ($rv == 1) {
$logger->debug("Attempting to send vacation response for: $messageid to: $smtp_sender, $smtp_recipient, $email (test_mode = $test_mode)"); $logger->debug("Attempting to send vacation response for: $messageid to: $smtp_sender, $smtp_recipient, $email (test_mode = $test_mode)");
send_vacation_email($email, $smtp_sender, $smtp_recipient, $messageid, $subject, $test_mode); send_vacation_email($email, $smtp_sender, $smtp_recipient, $messageid, $test_mode);
} else { }
else {
$logger->debug("SMTP recipient $smtp_recipient which resolves to $email does not have an active vacation (rv: $rv, email: $email)"); $logger->debug("SMTP recipient $smtp_recipient which resolves to $email does not have an active vacation (rv: $rv, email: $email)");
} }
0; 0;
#/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ #/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */

@ -0,0 +1,4 @@
<?php
header ("Location: ../login.php");
exit(0);
?>

@ -0,0 +1,131 @@
<?php
/**
* Postfix Admin
*
* LICENSE
* This source file is subject to the GPL license that is bundled with
* this package in the file LICENSE.TXT.
*
* Further details on the project are available at :
* http://www.postfixadmin.com or http://postfixadmin.sf.net
*
* @version $Id$
* @license GNU GPL v2 or later.
*
* File: backup.php
* Used to save all settings - but only works for MySQL databases.
* Template File: -none-
*
* Template Variables: -none-
*
* Form POST \ GET Variables: -none-
*/
require_once('common.php');
authentication_require_role('global-admin');
(($CONF['backup'] == 'NO') ? header("Location: " . $CONF['postfix_admin_url'] . "/main.php") && exit : '1');
// TODO: make backup supported for postgres
if ('pgsql'==$CONF['database_type'])
{
print '<p>Sorry: Backup is currently not supported for your DBMS.</p>';
}
/*
SELECT attnum,attname,typname,atttypmod-4,attnotnull,atthasdef,adsrc
AS def FROM pg_attribute,pg_class,pg_type,pg_attrdef
WHERE pg_class.oid=attrelid AND pg_type.oid=atttypid
AND attnum>0 AND pg_class.oid=adrelid AND adnum=attnum AND atthasdef='t' AND lower(relname)='admin'
UNION SELECT attnum,attname,typname,atttypmod-4,attnotnull,atthasdef,''
AS def FROM pg_attribute,pg_class,pg_type
WHERE pg_class.oid=attrelid
AND pg_type.oid=atttypid
AND attnum>0
AND atthasdef='f'
AND lower(relname)='admin'
$db = $_GET['db'];
$cmd = "pg_dump -c -D -f /tix/miner/miner.sql -F p -N -U postgres $db";
$res = `$cmd`;
// Alternate: $res = shell_exec($cmd);
echo $res;
*/
if ($_SERVER['REQUEST_METHOD'] == "GET")
{
umask (077);
$path = (ini_get('upload_tmp_dir') != '') ? ini_get('upload_tmp_dir') : '/tmp/';
$filename = "postfixadmin-" . date ("Ymd") . "-" . getmypid() . ".sql";
$backup = $path . $filename;
$header = "#\n# Postfix Admin $version\n# Date: " . date ("D M j G:i:s T Y") . "\n#\n";
if (!$fh = fopen ($backup, 'w'))
{
$tMessage = "<div class=\"error_msg\">Cannot open file ($backup)</div>";
include ("templates/header.php");
include ("templates/menu.php");
include ("templates/message.php");
include ("templates/footer.php");
}
else
{
fwrite ($fh, $header);
$tables = array(
'admin',
'alias',
'alias_domain',
'config',
'domain',
'domain_admins',
'fetchmail',
'log',
'mailbox',
'vacation',
'vacation_notification'
);
for ($i = 0 ; $i < sizeof ($tables) ; ++$i)
{
$result = db_query ("SHOW CREATE TABLE " . table_by_key($tables[$i]));
if ($result['rows'] > 0)
{
while ($row = db_array ($result['result']))
{
fwrite ($fh, "$row[1];\n\n");
}
}
}
for ($i = 0 ; $i < sizeof ($tables) ; ++$i)
{
$result = db_query ("SELECT * FROM " . table_by_key($tables[$i]));
if ($result['rows'] > 0)
{
while ($row = db_assoc ($result['result']))
{
foreach ($row as $key=>$val)
{
$fields[] = $key;
$values[] = $val;
}
fwrite ($fh, "INSERT INTO ". $tables[$i] . " (". implode (',',$fields) . ") VALUES ('" . implode ('\',\'',$values) . "');\n");
$fields = "";
$values = "";
}
}
}
}
header ("Content-Type: text/plain");
header ("Content-Disposition: attachment; filename=\"$filename\"");
header ("Content-Transfer-Encoding: binary");
header ("Content-Length: " . filesize("$backup"));
header ("Content-Description: Postfix Admin");
$download_backup = fopen ("$backup", "r");
unlink ("$backup");
fpassthru ($download_backup);
}
/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */
?>

@ -0,0 +1,97 @@
<?php
/**
* Postfix Admin
*
* LICENSE
* This source file is subject to the GPL license that is bundled with
* this package in the file LICENSE.TXT.
*
* Further details on the project are available at :
* http://www.postfixadmin.com or http://postfixadmin.sf.net
*
* @version $Id$
* @license GNU GPL v2 or later.
*
* File: broadcast-message.php
* Used to send a message to _ALL_ users with mailboxes on this server.
*
* Template File: broadcast-message.php
*
* Template Variables: -none-
*
* Form POST \ GET Variables:
*
* name
* subject
* message
*/
require_once('common.php');
authentication_require_role('global-admin');
if ($CONF['sendmail'] != 'YES') {
header("Location: " . $CONF['postfix_admin_url'] . "/main.php");
exit;
}
$SESSID_USERNAME = authentication_get_username();
if ($_SERVER['REQUEST_METHOD'] == "POST")
{
if (empty($_POST['subject']) || empty($_POST['message']) || empty($_POST['name']))
{
$error = 1;
}
else
{
$q = 'select username from mailbox union '.
'select goto from alias '.
'where goto not in (select username from mailbox)';
$result = db_query ($q);
if ($result['rows'] > 0)
{
$b_name = mb_encode_mimeheader( $_POST['name'], 'UTF-8', 'Q');
$b_subject = mb_encode_mimeheader( $_POST['subject'], 'UTF-8', 'Q');
$b_message = base64_encode($_POST['message']);
$i = 0;
while ($row = db_array ($result['result'])) {
$fTo = $row[0];
$fHeaders = 'To: ' . $fTo . "\n";
$fHeaders .= 'From: ' . $b_name . ' <' . $CONF['admin_email'] . ">\n";
$fHeaders .= 'Subject: ' . $b_subject . "\n";
$fHeaders .= 'MIME-Version: 1.0' . "\n";
$fHeaders .= 'Content-Type: text/plain; charset=UTF-8' . "\n";
$fHeaders .= 'Content-Transfer-Encoding: base64' . "\n";
$fHeaders .= $b_message;
if (!smtp_mail ($fTo, $CONF['admin_email'], $fHeaders))
{
$tMessage .= "<br />" . $PALANG['pSendmail_result_error'] . "<br />";
}
else
{
$tMessage .= "<br />" . $PALANG['pSendmail_result_success'] . "<br />";
}
}
}
include ("templates/header.php");
include ("templates/menu.php");
echo '<p>'.$PALANG['pBroadcast_success'].'</p>';
include ("templates/footer.php");
}
}
if ($_SERVER['REQUEST_METHOD'] == "GET" || $error == 1)
{
include ("templates/header.php");
include ("templates/menu.php");
include ("templates/broadcast-message.php");
include ("templates/footer.php");
}
/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */
?>

@ -1,20 +0,0 @@
#!/bin/bash
#Adapt to your setup
POSTFIX_DB="postfix_test"
MYSQL_CREDENTIALS_FILE="postfixadmin.my.cnf"
REPLY_ADDRESS=noreply@example.com
# Change this list to change notification times and when ...
for INTERVAL in 30 14 7
do
LOWER=$(( $INTERVAL - 1 ))
QUERY="SELECT username,password_expiry FROM mailbox WHERE password_expiry > now() + interval $LOWER DAY AND password_expiry < NOW() + interval $INTERVAL DAY"
mysql --defaults-extra-file="$MYSQL_CREDENTIALS_FILE" "$POSTFIX_DB" -B -e "$QUERY" | while read -a RESULT ; do
echo -e "Dear User, \n Your password will expire on ${RESULT[1]}" | mail -s "Password 30 days before expiration notication" -r $REPLY_ADDRESS ${RESULT[0]}
done
done

@ -1,101 +1,63 @@
<?php <?php
/** /**
* Postfix Admin * Postfix Admin
* *
* LICENSE * LICENSE
* This source file is subject to the GPL license that is bundled with * This source file is subject to the GPL license that is bundled with
* this package in the file LICENSE.TXT. * this package in the file LICENSE.TXT.
* *
* Further details on the project are available at http://postfixadmin.sf.net * Further details on the project are available at :
* * http://www.postfixadmin.com or http://postfixadmin.sf.net
* @license GNU GPL v2 or later. *
* * @version $Id$
* @license GNU GPL v2 or later.
*
* File: common.php * File: common.php
* All pages should include this file - which itself sets up the necessary * All pages should include this file - which itself sets up the necessary
* environment and ensures other functions are loaded. * environment and ensures other functions are loaded.
*/ */
if (!defined('POSTFIXADMIN')) { # already defined if called from setup.php if(!defined('POSTFIXADMIN')) {
define('POSTFIXADMIN', 1); # checked in included files session_start();
}
if (!defined('POSTFIXADMIN_CLI')) { define('POSTFIXADMIN', 1); # checked in included files
// this is the default; see also https://sourceforge.net/p/postfixadmin/bugs/347/
session_cache_limiter('nocache'); function incorrect_setup() {
session_name('postfixadmin_session'); global $incpath;
session_start(); # we ask the user to delete setup.php, which makes a blind redirect a bad idea
if(!is_file("$incpath/setup.php")) {
if (empty($_SESSION['flash'])) { die ("config.inc.php does not exist or is not configured correctly. Please re-install setup.php and create/fix your config.");
$_SESSION['flash'] = array(); } else {
# common.php is indirectly included in setup.php (via upgrade.php) - avoid endless redirect loop
if (!preg_match('/setup\.php$/', $_SERVER['SCRIPT_NAME'])) {
header("Location: setup.php");
exit(0);
} }
} }
} }
$incpath = dirname(__FILE__); $incpath = dirname(__FILE__);
(ini_get('magic_quotes_gpc') ? ini_set('magic_quotes_runtime', '0') : '1');
(ini_get('magic_quotes_gpc') ? ini_set('magic_quotes_sybase', '0') : '1');
/** if(ini_get('register_globals')) {
* @param string $class die("Please turn off register_globals; edit your php.ini");
* __autoload implementation, for use with spl_autoload_register().
*/
function postfixadmin_autoload($class) {
$PATH = dirname(__FILE__) . '/model/' . $class . '.php';
if (is_file($PATH)) {
require_once($PATH);
return true;
}
return false;
} }
spl_autoload_register('postfixadmin_autoload'); require_once("$incpath/variables.inc.php");
if (!is_file("$incpath/config.inc.php")) { if(!is_file("$incpath/config.inc.php")) {
die("config.inc.php is missing!"); // incorrectly setup...
incorrect_setup();
} }
global $CONF;
require_once("$incpath/config.inc.php"); require_once("$incpath/config.inc.php");
if(isset($CONF['configured'])) {
if($CONF['configured'] == FALSE) {
if (isset($CONF['configured']) && !defined('PHPUNIT_TEST')) { incorrect_setup();
if ($CONF['configured'] == false) {
die("Please edit config.local.php - change \$CONF['configured'] to true after specifying appropriate local settings (database_type etc)");
} }
} }
Config::write($CONF);
$PALANG = [];
require_once("$incpath/languages/language.php"); require_once("$incpath/languages/language.php");
require_once("$incpath/functions.inc.php"); require_once("$incpath/functions.inc.php");
if (extension_loaded('Phar') && ( version_compare(PHP_VERSION, '7.0.0') < 0)) { require_once("$incpath/languages/" . check_language () . ".lang");
require_once("$incpath/lib/random_compat.phar");
}
if (defined('POSTFIXADMIN_CLI')) {
$language = 'en'; # TODO: make configurable or autodetect from locale settings
} else {
$language = check_language(); # TODO: storing the language only at login instead of calling check_language() on every page would save some processor cycles ;-)
$_SESSION['lang'] = $language;
}
if (!empty($language)) {
require_once("$incpath/languages/" . $language . ".lang");
}
if (!empty($CONF['language_hook']) && function_exists($CONF['language_hook'])) {
$hook_func = $CONF['language_hook'];
$PALANG = $hook_func($PALANG, $language);
}
Config::write('__LANG', $PALANG);
unset($incpath);
if (!defined('POSTFIXADMIN_CLI')) {
if (!is_file(dirname(__FILE__) . "/lib/smarty.inc.php")) {
die("smarty.inc.php is missing! Something is wrong...");
}
require_once(dirname(__FILE__) . "/lib/smarty.inc.php");
}
/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */

@ -1,47 +0,0 @@
{
"name": "postfixadmin/postfixadmin",
"description": "web based administration interface for Postfix mail servers",
"type": "project",
"license": "GPL-2.0",
"scripts": {
"build" : [
"@check-format",
"@lint",
"@test-fixup",
"@psalm",
"@test"
],
"check-format": "php-cs-fixer fix --ansi --dry-run --diff",
"format": "php-cs-fixer fix --ansi",
"lint": "@php ./vendor/bin/parallel-lint --exclude vendor/ --exclude lib/block_random_int.php --exclude lib/array_column.php .",
"test": "DATABASE=sqlite ./vendor/bin/phpunit --coverage-clover ./clover.xml tests/",
"test-fixup": "mkdir -p templates_c ; test -f config.local.php || touch config.local.php",
"psalm": "@php ./vendor/bin/psalm --show-info=false "
},
"require": {
"php": ">=7.0"
},
"require-dev": {
"ext-mysqli": "*",
"ext-sqlite3": "*",
"friendsofphp/php-cs-fixer": "*",
"php-parallel-lint/php-parallel-lint": "^1.0",
"php": ">7.2.0",
"cedx/coveralls": "^11.0",
"phpunit/phpunit": "8.*",
"vimeo/psalm":"^3.0",
"shardj/zf1-future" : "^1.12"
},
"autoload": {
"files": [
"config.inc.php",
"functions.inc.php",
"lib/smarty/libs/bootstrap.php"
]
},
"support": {
"irc": "irc://irc.freenode.org/postfixadmin",
"issues": "https://github.com/postfixadmin/postfixadmin/issues",
"chat": "https://gitter.im/postfixadmin/Lobby"
}
}

@ -6,125 +6,53 @@
* This source file is subject to the GPL license that is bundled with * This source file is subject to the GPL license that is bundled with
* this package in the file LICENSE.TXT. * this package in the file LICENSE.TXT.
* *
* Further details on the project are available at http://postfixadmin.sf.net * Further details on the project are available at :
* http://www.postfixadmin.com or http://postfixadmin.sf.net
* *
* @version $Id$
* @license GNU GPL v2 or later. * @license GNU GPL v2 or later.
* *
* File: config.inc.php * File: config.inc.php
* Contains configuration options. * Contains configuration options.
*/ */
if (ereg ("config.inc.php", $_SERVER['PHP_SELF']))
################################################################################ {
# # header ("Location: login.php");
# PostfixAdmin default configuration # exit;
# # }
# This file contains the PostfixAdmin default configuration settings. #
# #
# Please do not edit this file. #
# #
# Instead, add the options you want to change/override to #
# config.local.php (if it doesn't exist, create it). #
# This will make version upgrades much easier. #
# #
################################################################################
global $CONF;
/***************************************************************** /*****************************************************************
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* You have to set $CONF['configured'] = true; before the * The following line needs commenting out or removing before the
* application will run! * application will run!
* Doing this implies you have changed this file as required. * Doing this implies you have changed this file as required.
* i.e. configuring database etc; specifying setup.php password etc.
*/ */
$CONF['configured'] = false; $CONF['configured'] = false;
// In order to setup Postfixadmin, you MUST specify a hashed password here.
// To create the hash, visit setup.php in a browser and type a password into the field, // Postfix Admin Path
// on submission it will be echoed out to you as a hashed value. // Set the location of your Postfix Admin installation here.
$CONF['setup_password'] = 'changeme'; // YOU MUST ENTER THE COMPLETE URL e.g. http://domain.tld/postfixadmin
$CONF['postfix_admin_url'] = '';
// shouldn't need changing.
$CONF['postfix_admin_path'] = dirname(__FILE__);
// Language config // Language config
// Language files are located in './languages', change as required.. // Language files are located in './languages', change as required..
$CONF['default_language'] = 'en'; $CONF['default_language'] = 'en';
// Hook to override or add translations in $PALANG
// Set to the function name you want to use as hook function (see language_hook example function below)
$CONF['language_hook'] = '';
/*
language_hook example function
Called if $CONF['language_hook'] == '<name_of_the_function>'
Allows to add or override $PALANG interface texts.
If you add new texts, please always prefix them with 'x_' (for example
$PALANG['x_mytext'] = 'foo') to avoid they clash with texts that might be
added to languages/*.lang in future versions of PostfixAdmin.
Please also make sure that all your added texts are included in all
sections - that includes all 'case "XY":' sections and the 'default:'
section (for users that don't have any of the languages specified
in the 'case "XY":' section).
Usually the 'default:' section should contain english text.
If you modify an existing text/translation, please consider to report it
to the bugtracker on http://sf.net/projects/postfixadmin so that all users
can benefit from the corrected text/translation.
Returns: modified $PALANG array
*/
/*
function language_hook($PALANG, $language) {
switch ($language) {
case "de":
$PALANG['x_whatever'] = 'foo';
break;
case "fr":
$PALANG['x_whatever'] = 'bar';
break;
default:
$PALANG['x_whatever'] = 'foobar';
}
return $PALANG;
}
*/
// Database Config // Database Config
// mysql = MySQL 3.23 and 4.0, 4.1 or 5 // mysql = MySQL 3.23 and 4.0, 4.1 or 5
// mysqli = MySQL 4.1+ or MariaDB // mysqli = MySQL 4.1+
// pgsql = PostgreSQL // pgsql = PostgreSQL
// sqlite = SQLite 3 $CONF['database_type'] = 'mysql';
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost'; $CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix'; $CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'postfixadmin'; $CONF['database_password'] = 'postfixadmin';
$CONF['database_name'] = 'postfix'; $CONF['database_name'] = 'postfix';
$CONF['database_prefix'] = '';
// Database SSL Config (PDO/MySQLi only)
$CONF['database_use_ssl'] = false;
$CONF['database_ssl_key'] = NULL;
$CONF['database_ssl_cert'] = NULL;
$CONF['database_ssl_ca'] = NULL;
$CONF['database_ssl_ca_path'] = NULL;
$CONF['database_ssl_cipher'] = NULL;
$CONF['database_ssl_verify_server_cert'] = true;
// If you need to specify a different port for a MYSQL database connection, use e.g.
// $CONF['database_host'] = '172.30.33.66:3308';
//
// If you need to specify a different port for MySQLi(3306)/POSTGRESQL(5432) database connection
// uncomment and change the following
// $CONF['database_port'] = '5432';
//
// If you wish to connect using a local socket file (e.g /var/run/mysql.sock) set this to the socket path.
// $CONF['database_socket'] = '/var/run/mysql/mysqld.sock';
$CONF['database_socket'] = '';
// If sqlite is used, specify the database file path:
// $CONF['database_name'] = '/etc/postfix/sqlite/postfixadmin.db'
// Here, if you need, you can customize table names. // Here, if you need, you can customize table names.
$CONF['database_prefix'] = ''; $CONF['database_prefix'] = '';
@ -141,25 +69,12 @@ $CONF['database_tables'] = array (
'vacation' => 'vacation', 'vacation' => 'vacation',
'vacation_notification' => 'vacation_notification', 'vacation_notification' => 'vacation_notification',
'quota' => 'quota', 'quota' => 'quota',
'quota2' => 'quota2',
); );
// Site Admin // Site Admin
// Define the Site Admin's email address below. // Define the Site Admins email address below.
// This will be used to send emails from to create mailboxes and // This will be used to send emails from to create mailboxes.
// from Send Email / Broadcast message pages. $CONF['admin_email'] = 'postmaster@change-this-to-your.domain.tld';
// Leave blank to send email from the logged-in Admin's Email address.
$CONF['admin_email'] = '';
// Define the smtp password for admin_email.
// This will be used to send emails from to create mailboxes and
// from Send Email / Broadcast message pages.
// Leave blank to send emails without authentification
$CONF['admin_smtp_password'] = '';
// Site admin name
// This will be used as signature in notification messages
$CONF['admin_name'] = 'Postmaster';
// Mail Server // Mail Server
// Hostname (FQDN) of your mail server. // Hostname (FQDN) of your mail server.
@ -167,14 +82,6 @@ $CONF['admin_name'] = 'Postmaster';
$CONF['smtp_server'] = 'localhost'; $CONF['smtp_server'] = 'localhost';
$CONF['smtp_port'] = '25'; $CONF['smtp_port'] = '25';
// SMTP Client
// Hostname (FQDN) of the server hosting Postfix Admin
// Used in the HELO when sending emails from Postfix Admin
$CONF['smtp_client'] = '';
// Set 'YES' to use TLS when sending emails.
$CONF['smtp_sendmail_tls'] = 'NO';
// Encrypt // Encrypt
// In what way do you want the passwords to be crypted? // In what way do you want the passwords to be crypted?
// md5crypt = internal postfix admin md5 // md5crypt = internal postfix admin md5
@ -182,57 +89,15 @@ $CONF['smtp_sendmail_tls'] = 'NO';
// system = whatever you have set as your PHP system default // system = whatever you have set as your PHP system default
// cleartext = clear text passwords (ouch!) // cleartext = clear text passwords (ouch!)
// mysql_encrypt = useful for PAM integration // mysql_encrypt = useful for PAM integration
// authlib = support for courier-authlib style passwords - also set $CONF['authlib_default_flavor']
// dovecot:CRYPT-METHOD = use dovecotpw -s 'CRYPT-METHOD'. Example: dovecot:CRAM-MD5
// php_crypt:CRYPT-METHOD:DIFFICULTY = use PHP built in crypt()-function. Example: php_crypt:SHA512:50000
// - php_crypt CRYPT-METHOD: Supported values are DES, MD5, BLOWFISH, SHA256, SHA512
// - php_crypt DIFFICULTY: Larger value is more secure, but uses more CPU and time for each login.
// - php_crypt DIFFICULTY: Set this according to your CPU processing power.
// - php_crypt DIFFICULTY: Supported values are BLOWFISH:4-31, SHA256:1000-999999999, SHA512:1000-999999999
// - php_crypt DIFFICULTY: leave empty to use default values (BLOWFISH:10, SHA256:5000, SHA512:5000). Example: php_crypt:SHA512
// IMPORTANT:
// - don't use dovecot:* methods that include the username in the hash - you won't be able to login to PostfixAdmin in this case
// - you'll need at least dovecot 2.1 for salted passwords ('doveadm pw' 2.0.x doesn't support the '-t' option)
// - dovecot 2.0.0 - 2.0.7 is not supported
// sha512.b64 - {SHA512-CRYPT.B64} (base64 encoded sha512) (no dovecot dependency; should support migration from md5crypt)
$CONF['encrypt'] = 'md5crypt'; $CONF['encrypt'] = 'md5crypt';
// In what flavor should courier-authlib style passwords be encrypted? // Minimum length required for passwords. Postfixadmin will not
// (only used if $CONF['encrypt'] == 'authlib') // allow users to set passwords which are shorter than this value.
// md5 = {md5} + base64 encoded md5 hash $CONF['min_password_length'] = 5;
// md5raw = {md5raw} + plain encoded md5 hash
// SHA = {SHA} + base64-encoded sha1 hash
// crypt = {crypt} + Standard UNIX DES-encrypted with 2-character salt
$CONF['authlib_default_flavor'] = 'md5raw';
// If you use the dovecot encryption method: where is the dovecotpw binary located?
// for dovecot 1.x
// $CONF['dovecotpw'] = "/usr/sbin/dovecotpw";
// for dovecot 2.x (dovecot 2.0.0 - 2.0.7 is not supported!)
$CONF['dovecotpw'] = "/usr/sbin/doveadm pw";
if(@file_exists('/usr/bin/doveadm')) { // @ to silence openbase_dir stuff; see https://github.com/postfixadmin/postfixadmin/issues/171
$CONF['dovecotpw'] = "/usr/bin/doveadm pw"; # debian
}
// Password validation
// New/changed passwords will be validated using all regular expressions in the array.
// If a password doesn't match one of the regular expressions, the corresponding
// error message from $PALANG (see languages/*.lang) will be displayed.
// See http://de3.php.net/manual/en/reference.pcre.pattern.syntax.php for details
// about the regular expression syntax.
// If you need custom error messages, you can add them using $CONF['language_hook'].
// If a $PALANG text contains a %s, you can add its value after the $PALANG key
// (separated with a space).
$CONF['password_validation'] = array(
# '/regular expression/' => '$PALANG key (optional: + parameter)',
'/.{5}/' => 'password_too_short 5', # minimum length 5 characters
'/([a-zA-Z].*){3}/' => 'password_no_characters 3', # must contain at least 3 characters
'/([0-9].*){2}/' => 'password_no_digits 2', # must contain at least 2 digits
);
// Generate Password // Generate Password
// Generate a random password for a mailbox or admin and display it. // Generate a random password for a mailbox or admin and display it.
// If you want to automagically generate passwords set this to 'YES'. // If you want to automagically generate paswords set this to 'YES'.
$CONF['generate_password'] = 'NO'; $CONF['generate_password'] = 'NO';
// Show Password // Show Password
@ -247,9 +112,6 @@ $CONF['page_size'] = '10';
// Default Aliases // Default Aliases
// The default aliases that need to be created for all domains. // The default aliases that need to be created for all domains.
// You can specify the target address in two ways:
// a) a full mail address
// b) only a localpart ('postmaster' => 'admin') - the alias target will point to the same domain
$CONF['default_aliases'] = array ( $CONF['default_aliases'] = array (
'abuse' => 'abuse@change-this-to-your.domain.tld', 'abuse' => 'abuse@change-this-to-your.domain.tld',
'hostmaster' => 'hostmaster@change-this-to-your.domain.tld', 'hostmaster' => 'hostmaster@change-this-to-your.domain.tld',
@ -262,103 +124,25 @@ $CONF['default_aliases'] = array (
// Examples: // Examples:
// YES: /usr/local/virtual/domain.tld/username@domain.tld // YES: /usr/local/virtual/domain.tld/username@domain.tld
// NO: /usr/local/virtual/username@domain.tld // NO: /usr/local/virtual/username@domain.tld
$CONF['domain_path'] = 'YES'; $CONF['domain_path'] = 'NO';
// If you don't want to have the domain in your mailbox set this to 'NO'. // If you don't want to have the domain in your mailbox set this to 'NO'.
// Examples: // Examples:
// YES: /usr/local/virtual/domain.tld/username@domain.tld // YES: /usr/local/virtual/domain.tld/username@domain.tld
// NO: /usr/local/virtual/domain.tld/username // NO: /usr/local/virtual/domain.tld/username
// Note: If $CONF['domain_path'] is set to NO, this setting will be forced to YES. // Note: If $CONF['domain_path'] is set to NO, this setting will be forced to YES.
$CONF['domain_in_mailbox'] = 'NO'; $CONF['domain_in_mailbox'] = 'YES';
// If you want to define your own function to generate a maildir path set this to the name of the function.
// Notes:
// - this configuration directive will override both domain_path and domain_in_mailbox
// - the maildir_name_hook() function example is present below, commented out
// - if the function does not exist the program will default to the above domain_path and domain_in_mailbox settings
$CONF['maildir_name_hook'] = 'NO';
/*
maildir_name_hook example function
Called when creating a mailbox if $CONF['maildir_name_hook'] == '<name_of_the_function>'
- allows for customized maildir paths determined by a custom function
- the example below will prepend a single-character directory to the
beginning of the maildir, splitting domains more or less evenly over
36 directories for improved filesystem performance with large numbers
of domains.
Returns: maildir path
ie. I/example.com/user/
*/
/*
function maildir_name_hook($domain, $user) {
$chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$dir_index = hexdec(substr(md5($domain), 28)) % strlen($chars);
$dir = substr($chars, $dir_index, 1);
return sprintf("%s/%s/%s/", $dir, $domain, $user);
}
*/
/*
*_struct_hook - change, add or remove fields
If you need additional fields or want to change or remove existing fields,
you can write a hook function to modify $struct in the *Handler classes.
The edit form will automatically be updated according to the modified
$struct. The list page is not yet updated automatically.
You can define one hook function per class, named like the primary database
table of that class.
The hook function is called with $struct as parameter and must return the
modified $struct.
Note: Adding a field to $struct adds the handling of this field in
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
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.
See pacol() in functions.inc.php for the available flags on each column.
Example:
function x_struct_admin_modify($struct) {
$struct['superadmin']['editable'] = 0; # make the 'superadmin' flag read-only
$struct['superadmin']['display_in_form'] = 0; # don't display the 'superadmin' flag in edit form
$struct['x_newfield'] = pacol( [...] ); # additional field 'x_newfield'
return $struct; # important!
}
$CONF['admin_struct_hook'] = 'x_struct_admin_modify';
*/
$CONF['admin_struct_hook'] = '';
$CONF['domain_struct_hook'] = '';
$CONF['alias_struct_hook'] = '';
$CONF['mailbox_struct_hook'] = '';
$CONF['alias_domain_struct_hook'] = '';
$CONF['fetchmail_struct_hook'] = '';
// Default Domain Values // Default Domain Values
// Specify your default values below. Quota in MB. // Specify your default values below. Quota in MB.
$CONF['aliases'] = '10'; $CONF['aliases'] = '10';
$CONF['mailboxes'] = '10'; $CONF['mailboxes'] = '10';
$CONF['maxquota'] = '10'; $CONF['maxquota'] = '10';
$CONF['domain_quota_default'] = '2048';
// Quota // Quota
// When you want to enforce quota for your mailbox users set this to 'YES'. // When you want to enforce quota for your mailbox users set this to 'YES'.
$CONF['quota'] = 'NO'; $CONF['quota'] = 'NO';
// If you want to enforce domain-level quotas set this to 'YES'.
$CONF['domain_quota'] = 'YES';
// You can either use '1024000' or '1048576' // You can either use '1024000' or '1048576'
$CONF['quota_multiplier'] = '1024000'; $CONF['quota_multiplier'] = '1024000';
// fill state threshold (in per cent) for medium level (displayed as orange)
$CONF['quota_level_med_pct'] = 55;
// fill state threshold (in per cent) for high level (displayed as red)
$CONF['quota_level_high_pct'] = 90;
// Transport // Transport
// If you want to define additional transport options for a domain set this to 'YES'. // If you want to define additional transport options for a domain set this to 'YES'.
@ -375,21 +159,13 @@ $CONF['transport_options'] = array (
// You should define default transport. It must be in array above. // You should define default transport. It must be in array above.
$CONF['transport_default'] = 'virtual'; $CONF['transport_default'] = 'virtual';
// Virtual Vacation
//
//
// Virtual Vacation Stuff
//
//
// If you want to use virtual vacation for you mailbox users set this to 'YES'. // If you want to use virtual vacation for you mailbox users set this to 'YES'.
// NOTE: Make sure that you install the vacation module. (See VIRTUAL-VACATION/) // NOTE: Make sure that you install the vacation module. http://high5.net/postfixadmin/
$CONF['vacation'] = 'NO'; $CONF['vacation'] = 'NO';
// This is the autoreply domain that you will need to set in your Postfix // This is the autoreply domain that you will need to set in your Postfix
// transport maps to handle virtual vacations. It does not need to be a // transport maps to handle virtual vacations. It does not need to be a
// real domain (i.e. you don't need to setup DNS for it). // real domain (i.e. you don't need to setup DNS for it).
// This domain must exclusively be used for vacation. Do NOT use it for "normal" mail addresses.
$CONF['vacation_domain'] = 'autoreply.change-this-to-your.domain.tld'; $CONF['vacation_domain'] = 'autoreply.change-this-to-your.domain.tld';
// Vacation Control // Vacation Control
@ -400,41 +176,19 @@ $CONF['vacation_control'] ='YES';
// Set to 'YES' if your domain admins should be able to edit user vacation. // Set to 'YES' if your domain admins should be able to edit user vacation.
$CONF['vacation_control_admin'] = 'YES'; $CONF['vacation_control_admin'] = 'YES';
// ReplyType options
// If you want to define additional reply options put them in array below.
// The array has the format seconds between replies => $PALANG text
// Special values for seconds are:
// 0 => only reply to the first mail while on vacation
// 1 => reply on every mail
$CONF['vacation_choice_of_reply'] = array (
0 => 'reply_once', // Sends only Once the message during Out of Office
# considered annoying - only send a reply on every mail if you really need it
# 1 => 'reply_every_mail', // Reply on every email
60*60 *24*7 => 'reply_once_per_week' // Reply if last autoreply was at least a week ago
);
//
// End Vacation Stuff.
//
// Alias Control // Alias Control
// Postfix Admin inserts an alias in the alias table for every mailbox it creates. // Postfix Admin inserts an alias in the alias table for every mailbox it creates.
// The reason for this is that when you want catch-all and normal mailboxes // The reason for this is that when you want catch-all and normal mailboxes
// to work you need to have the mailbox replicated in the alias table. // to work you need to have the mailbox replicated in the alias table.
// If you want to take control of these aliases as well set this to 'YES'. // If you want to take control of these aliases as well set this to 'YES'.
$CONF['alias_control'] = 'NO';
// If you don't want edit alias tab (user mode) set this to 'NO'; // Alias Control for admins
$CONF['edit_alias'] = 'YES'; // Set to 'NO' if your domain admins shouldn't be able to edit user aliases.
$CONF['alias_control_admin'] = 'NO';
// Alias control for superadmins
$CONF['alias_control'] = 'YES';
// Alias Control for domain admins
$CONF['alias_control_admin'] = 'YES';
// Special Alias Control // Special Alias Control
// Set to 'NO' if your domain admins shouldn't be able to edit the default aliases // Set to 'NO' if your domain admins shouldn't be able to edit default aliases.
// as defined in $CONF['default_aliases']
$CONF['special_alias_control'] = 'NO'; $CONF['special_alias_control'] = 'NO';
// Alias Goto Field Limit // Alias Goto Field Limit
@ -453,14 +207,11 @@ $CONF['alias_domain'] = 'YES';
// Backup // Backup
// If you don't want backup tab set this to 'NO'; // If you don't want backup tab set this to 'NO';
$CONF['backup'] = 'NO'; $CONF['backup'] = 'YES';
// Send Mail // Send Mail
// If you don't want sendmail tab set this to 'NO'; // If you don't want sendmail tab set this to 'NO';
$CONF['sendmail'] = 'YES'; $CONF['sendmail'] = 'YES';
// Set this to YES if you want to allow non-super-admins to
// send mails to their users
$CONF['sendmail_all_admins'] = 'NO';
// Logging // Logging
// If you don't want logging set this to 'NO'; // If you don't want logging set this to 'NO';
@ -479,6 +230,9 @@ $CONF['fetchmail_extra_options'] = 'NO';
$CONF['show_header_text'] = 'NO'; $CONF['show_header_text'] = 'NO';
$CONF['header_text'] = ':: Postfix Admin ::'; $CONF['header_text'] = ':: Postfix Admin ::';
// link to display under 'Main' menu when logged in as a user.
$CONF['user_footer_link'] = "http://change-this-to-your.domain.tld/main";
// Footer // Footer
// Below information will be on all pages. // Below information will be on all pages.
// If you don't want the footer information to appear set this to 'NO'. // If you don't want the footer information to appear set this to 'NO'.
@ -486,13 +240,6 @@ $CONF['show_footer_text'] = 'YES';
$CONF['footer_text'] = 'Return to change-this-to-your.domain.tld'; $CONF['footer_text'] = 'Return to change-this-to-your.domain.tld';
$CONF['footer_link'] = 'http://change-this-to-your.domain.tld'; $CONF['footer_link'] = 'http://change-this-to-your.domain.tld';
// MOTD ("Motto of the day")
// You can display a MOTD below the menu on all pages.
// This can be configured seperately for users, domain admins and superadmins
$CONF['motd_user'] = '';
$CONF['motd_admin'] = '';
$CONF['motd_superadmin'] = '';
// Welcome Message // Welcome Message
// This message is send to every newly created mailbox. // This message is send to every newly created mailbox.
// Change the text between EOM. // Change the text between EOM.
@ -518,85 +265,62 @@ $CONF['emailcheck_resolve_domain']='YES';
// color names available on most browsers // color names available on most browsers
//set to YES to enable this feature //set to YES to enable this feature
$CONF['show_status']='YES'; $CONF['show_status']='NO';
//display a guide to what these colors mean //display a guide to what these colors mean
$CONF['show_status_key']='YES'; $CONF['show_status_key']='NO';
// 'show_status_text' will be displayed with the background colors // 'show_status_text' will be displayed with the background colors
// associated with each status, you can customize it here // associated with each status, you can customize it here
$CONF['show_status_text']='&nbsp;&nbsp;'; $CONF['show_status_text']='&nbsp;&nbsp;';
// show_undeliverable is useful if most accounts are delivered to this // show_undeliverable is useful if most accounts are delivered to this
// postfix system. If many aliases and mailboxes are forwarded // postfix system. If many aliases and mailboxes are forwarded
// elsewhere, you will probably want to disable this. // elsewhere, you will probably want to disable this.
$CONF['show_undeliverable']='YES'; $CONF['show_undeliverable']='NO';
$CONF['show_undeliverable_color']='tomato'; $CONF['show_undeliverable_color']='tomato';
// mails to these domains will never be flagged as undeliverable // mails to these domains will never be flagged as undeliverable
$CONF['show_undeliverable_exceptions']=array("unixmail.domain.ext","exchangeserver.domain.ext"); $CONF['show_undeliverable_exceptions']=array("unixmail.domain.ext","exchangeserver.domain.ext","gmail.com");
// show mailboxes with expired password; requires password_expiration to be enabled $CONF['show_popimap']='NO';
$CONF['show_expired']='YES';
$CONF['show_expired_color']='orange';
// show vacation enabled mailboxes
$CONF['show_vacation']='YES';
$CONF['show_vacation_color']='turquoise';
// show disabled accounts
$CONF['show_disabled']='YES';
$CONF['show_disabled_color']='grey';
// show POP/IMAP mailboxes
$CONF['show_popimap']='YES';
$CONF['show_popimap_color']='darkgrey'; $CONF['show_popimap_color']='darkgrey';
// you can assign special colors to some domains. To do this, // you can assign special colors to some domains. To do this,
// - add the domain to show_custom_domains // - add the domain to show_custom_domains
// - add the corresponding color to show_custom_colors // - add the corresponding color to show_custom_colors
$CONF['show_custom_domains']=array("subdomain.domain.ext","domain2.ext"); $CONF['show_custom_domains']=array("subdomain.domain.ext","domain2.ext");
$CONF['show_custom_colors']=array("lightgreen","lightblue"); $CONF['show_custom_colors']=array("lightgreen","lightblue");
// If you use a recipient_delimiter in your postfix config, you can also honor it when aliases are checked.
// Example: $CONF['recipient_delimiter'] = "+";
// Set to "" to disable this check.
$CONF['recipient_delimiter'] = "";
// Optional: // Optional:
// Script to run after creation of mailboxes. // Script to run after creation of mailboxes.
// Note that this may fail if PHP is run in "safe mode", or if // Note that this may fail if PHP is run in "safe mode", or if
// operating system features (such as SELinux) or limitations // operating system features (such as SELinux) or limitations
// prevent the web-server from executing external scripts. // prevent the web-server from executing external scripts.
// Parameters: (1) username (2) domain (3) maildir (4) quota
// $CONF['mailbox_postcreation_script']='sudo -u courier /usr/local/bin/postfixadmin-mailbox-postcreation.sh'; // $CONF['mailbox_postcreation_script']='sudo -u courier /usr/local/bin/postfixadmin-mailbox-postcreation.sh';
$CONF['mailbox_postcreation_script'] = '';
// Optional: // Optional:
// Script to run after alteration of mailboxes. // Script to run after alteration of mailboxes.
// Note that this may fail if PHP is run in "safe mode", or if // Note that this may fail if PHP is run in "safe mode", or if
// operating system features (such as SELinux) or limitations // operating system features (such as SELinux) or limitations
// prevent the web-server from executing external scripts. // prevent the web-server from executing external scripts.
// Parameters: (1) username (2) domain (3) maildir (4) quota
// $CONF['mailbox_postedit_script']='sudo -u courier /usr/local/bin/postfixadmin-mailbox-postedit.sh'; // $CONF['mailbox_postedit_script']='sudo -u courier /usr/local/bin/postfixadmin-mailbox-postedit.sh';
$CONF['mailbox_postedit_script'] = '';
// Optional: // Optional:
// Script to run after deletion of mailboxes. // Script to run after deletion of mailboxes.
// Note that this may fail if PHP is run in "safe mode", or if // Note that this may fail if PHP is run in "safe mode", or if
// operating system features (such as SELinux) or limitations // operating system features (such as SELinux) or limitations
// prevent the web-server from executing external scripts. // prevent the web-server from executing external scripts.
// Parameters: (1) username (2) domain
// $CONF['mailbox_postdeletion_script']='sudo -u courier /usr/local/bin/postfixadmin-mailbox-postdeletion.sh'; // $CONF['mailbox_postdeletion_script']='sudo -u courier /usr/local/bin/postfixadmin-mailbox-postdeletion.sh';
$CONF['mailbox_postdeletion_script'] = '';
// Optional: // Optional:
// Script to run after creation of domains. // Script to run after creation of domains.
// Note that this may fail if PHP is run in "safe mode", or if // Note that this may fail if PHP is run in "safe mode", or if
// operating system features (such as SELinux) or limitations // operating system features (such as SELinux) or limitations
// prevent the web-server from executing external scripts. // prevent the web-server from executing external scripts.
// Parameters: (1) domain
//$CONF['domain_postcreation_script']='sudo -u courier /usr/local/bin/postfixadmin-domain-postcreation.sh'; //$CONF['domain_postcreation_script']='sudo -u courier /usr/local/bin/postfixadmin-domain-postcreation.sh';
$CONF['domain_postcreation_script'] = '';
// Optional: // Optional:
// Script to run after deletion of domains. // Script to run after deletion of domains.
// Note that this may fail if PHP is run in "safe mode", or if // Note that this may fail if PHP is run in "safe mode", or if
// operating system features (such as SELinux) or limitations // operating system features (such as SELinux) or limitations
// prevent the web-server from executing external scripts. // prevent the web-server from executing external scripts.
// Parameters: (1) domain
// $CONF['domain_postdeletion_script']='sudo -u courier /usr/local/bin/postfixadmin-domain-postdeletion.sh'; // $CONF['domain_postdeletion_script']='sudo -u courier /usr/local/bin/postfixadmin-domain-postdeletion.sh';
$CONF['domain_postdeletion_script'] = '';
// Optional: // Optional:
// Sub-folders which should automatically be created for new users. // Sub-folders which should automatically be created for new users.
@ -605,10 +329,9 @@ $CONF['domain_postdeletion_script'] = '';
// Will not work with POP3. // Will not work with POP3.
// If you define create_mailbox_subdirs, then the // If you define create_mailbox_subdirs, then the
// create_mailbox_subdirs_host must also be defined. // create_mailbox_subdirs_host must also be defined.
// Note: requires imap extension within PHP //
// $CONF['create_mailbox_subdirs']=array('Spam'); // $CONF['create_mailbox_subdirs']=array('Spam');
$CONF['create_mailbox_subdirs'] = array(); // $CONF['create_mailbox_subdirs_host']='localhost';
$CONF['create_mailbox_subdirs_host']='localhost';
// //
// Specify '' for Dovecot and 'INBOX.' for Courier. // Specify '' for Dovecot and 'INBOX.' for Courier.
$CONF['create_mailbox_subdirs_prefix']='INBOX.'; $CONF['create_mailbox_subdirs_prefix']='INBOX.';
@ -619,11 +342,7 @@ $CONF['create_mailbox_subdirs_prefix']='INBOX.';
// See: DOCUMENTATION/DOVECOT.txt // See: DOCUMENTATION/DOVECOT.txt
// http://wiki.dovecot.org/Quota/Dict // http://wiki.dovecot.org/Quota/Dict
// //
$CONF['used_quotas'] = 'NO'; // $CONF['used_quotas'] = 'YES';
// if you use dovecot >= 1.2, set this to yes.
// Note about dovecot config: table "quota" is for 1.0 & 1.1, table "quota2" is for dovecot 1.2 and newer
$CONF['new_quota_table'] = 'YES';
// //
// Normally, the TCP port number does not have to be specified. // Normally, the TCP port number does not have to be specified.
@ -636,68 +355,19 @@ $CONF['new_quota_table'] = 'YES';
// $CONF['create_mailbox_subdirs_hostoptions']=array('novalidate-cert','norsh'); // $CONF['create_mailbox_subdirs_hostoptions']=array('novalidate-cert','norsh');
// See also the "Optional flags for names" table at // See also the "Optional flags for names" table at
// http://www.php.net/manual/en/function.imap-open.php // http://www.php.net/manual/en/function.imap-open.php
$CONF['create_mailbox_subdirs_hostoptions'] = array();
// Optional:
// Allows a user to reset his forgotten password with a code sent by email/SMS
$CONF['forgotten_user_password_reset'] = true;
// Allows an admin to reset his forgotten password with a code sent by email/SMS
$CONF['forgotten_admin_password_reset'] = false;
// Name of the function to send a SMS
// Please use a name that begins with "x_" to prevent collisions
// This function must accept 2 parameters: phone number and message,
// and return true on success or false on failure
// Note: if no sms_send_function is defined, the input field for the mobile
// number won't be displayed
$CONF['sms_send_function'] = '';
/*
// Example of send SMS function using Clickatell HTTP API
function x_send_sms_clickatell($to, $message) {
$clickatell_api_id = 'CHANGEME';
$clickatell_user = 'CHANGEME';
$clickatell_password = 'CHANGEME';
$clickatell_sender = 'CHANGEME';
$url = 'https://api.clickatell.com/http/sendmsg?api_id=%s&user=%s&password=%s&to=%s&from=%s&text=%s';
$url = sprintf($url, $clickatell_api_id, $clickatell_user, $clickatell_password, $to, $clickatell_sender, urlencode($message));
$result = file_get_contents($url);
return $result !== false;
}
*/
// Theme Config // Theme Config
$CONF['theme'] = 'default'; // Specify your own logo and CSS file
// Specify your own favicon, logo and CSS file
$CONF['theme_favicon'] = 'images/favicon.ico';
$CONF['theme_logo'] = 'images/logo-default.png'; $CONF['theme_logo'] = 'images/logo-default.png';
$CONF['theme_css'] = 'css/default.css'; $CONF['theme_css'] = 'css/default.css';
// If you want to customize some styles without editing the $CONF['theme_css'] file,
// you can add a custom CSS file. It will be included after $CONF['theme_css']. // If you want to keep most settings at default values and/or want to ensure
$CONF['theme_custom_css'] = '';
// XMLRPC Interface.
// This should be only of use if you wish to use e.g the
// Postfixadmin-Squirrelmail package
// change to boolean true to enable xmlrpc
$CONF['xmlrpc_enabled'] = false;
//Account expiration info
//If enabled, mailbox passwords have a password_expiry field set, which is updated each time the password is changed, based on the parent domain's password_expiry (days) value.
//More details in README.password_expiration
$CONF['password_expiration'] = 'YES';
// If you want to keep most settings at default values and/or want to ensure
// that future updates work without problems, you can use a separate config // that future updates work without problems, you can use a separate config
// file (config.local.php) instead of editing this file and override some // file (config.local.php) instead of editing this file and override some
// settings there. // settings there.
if (file_exists(dirname(__FILE__) . '/config.local.php')) { if (file_exists(dirname(__FILE__) . '/config.local.php')) { # for /
require_once(dirname(__FILE__) . '/config.local.php'); include(dirname(__FILE__) . '/config.local.php');
} }
// //

@ -1,45 +0,0 @@
url_main = main.php
url_editactive = editactive.php?table=
# list_admin
url_list_admin = list.php?table=admin
url_create_admin = edit.php?table=admin
# list-domain
url_list_domain = list.php?table=domain
url_edit_domain = edit.php?table=domain
# list-virtual
url_list_virtual = list-virtual.php
url_create_mailbox = edit.php?table=mailbox
url_create_alias = edit.php?table=alias
url_create_alias_domain = edit.php?table=aliasdomain
# fetchmail
url_fetchmail = list.php?table=fetchmail
url_fetchmail_new_entry = edit.php?table=fetchmail
# sendmail
url_sendmail = sendmail.php
url_broadcast_message = broadcast-message.php
# password
url_password = edit.php?table=adminpassword
# backup
url_backup = backup.php
# viewlog
url_viewlog = viewlog.php
# logout
url_logout = login.php
# user-menu
url_user_main = main.php
url_user_edit_alias = edit-alias.php
url_user_vacation = vacation.php
url_user_password = password.php
url_user_logout = login.php
tr_header = <tr class="header">
tr_hilightoff = <tr class="hilightoff" onmouseover="className='hilighton';" onmouseout="className='hilightoff';">
url_delete = delete.php
url_search = list-virtual.php
form_search = <form name="search" method="post" action="list-virtual.php"><input class="form-control" name="search[_]" size="10" /></form>
[adminlistadmin]
url_edit_admin = edit.php?table=admin

@ -0,0 +1,69 @@
<?php
/**
* Postfix Admin
*
* LICENSE
* This source file is subject to the GPL license that is bundled with
* this package in the file LICENSE.TXT.
*
* Further details on the project are available at :
* http://www.postfixadmin.com or http://postfixadmin.sf.net
*
* @version $Id$
* @license GNU GPL v2 or later.
*
* File: create-admin.php
* Used to create new administrators.
* Template File: admin_create-admin.php
*
*
* Template Variables:
*
* tMessage
* tUsername
* tDomains
*
* Form POST \ GET Variables:
*
* fUsername
* fPassword
* fPassword2
* fDomains
*/
require_once('common.php');
authentication_require_role('global-admin');
$list_domains = list_domains ();
$tDomains = array();
if ($_SERVER['REQUEST_METHOD'] == "GET")
{
$pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text'];
$tDomains = array ();
}
if ($_SERVER['REQUEST_METHOD'] == "POST")
{
if (isset ($_POST['fUsername'])) $fUsername = escape_string ($_POST['fUsername']);
if (isset ($_POST['fPassword'])) $fPassword = escape_string ($_POST['fPassword']);
if (isset ($_POST['fPassword2'])) $fPassword2 = escape_string ($_POST['fPassword2']);
$fDomains = array();
if (!empty ($_POST['fDomains'])) $fDomains = $_POST['fDomains'];
list ($error, $tMessage, $pAdminCreate_admin_username_text, $pAdminCreate_admin_password_text) = create_admin($fUsername, $fPassword, $fPassword2, $fDomains);
if ($error != 0) {
if (isset ($_POST['fUsername'])) $tUsername = escape_string ($_POST['fUsername']);
if (isset ($_POST['fDomains'])) $tDomains = $_POST['fDomains'];
}
}
include ("templates/header.php");
include ("templates/menu.php");
include ("templates/admin_create-admin.php");
include ("templates/footer.php");
/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */
?>

@ -0,0 +1,139 @@
<?php
/**
* Postfix Admin
*
* LICENSE
*
* This source file is subject to the GPL license that is bundled with
* this package in the file LICENSE.TXT.
*
* Further details on the project are available at :
* http://www.postfixadmin.com or http://postfixadmin.sf.net
*
* File: create-alias-domain.php
* Template File: create-alias-domain.php
* Responsible for allowing for the creation of alias domains.
*
* @version $Id$
* @license GNU GPL v2 or later.
*
* Template Variables:
*
* tMessage
*
* Form POST \ GET Variables:
*
* fAliasDomain
* fTargetDomain
* fActive
*
*/
require_once('common.php');
authentication_require_role('admin');
if (!boolconf('alias_domain')) {
header("Location: " . $CONF['postfix_admin_url'] . "/main.php");
exit;
}
$username = authentication_get_username();
$SESSID_USERNAME = $username;
if(authentication_has_role('global-admin')) {
$list_domains = list_domains ();
}
else {
$list_domains = list_domains_for_admin ($username);
}
# read alias_domain table to see which domains in $list_domains
# are still available as an alias- or target-domain
$list_aliases = Array();
$result = db_query ("SELECT alias_domain, target_domain FROM $table_alias_domain");
if ($result['rows'] > 0) {
while ($row = db_array ($result['result']))
{
$list_aliases[ $row['alias_domain'] ] = $row['target_domain'];
}
}
# filter available alias domains
$alias_domains = array();
foreach ($list_domains as $dom) {
if (isset($list_aliases[$dom]) || in_array($dom,$list_aliases)) continue;
$alias_domains[] = $dom;
}
if (count($alias_domains) == 0) {
$error = 1;
$tMessage = $PALANG['pCreate_alias_domain_error4'];
}
# filter available target domains
foreach ($list_domains as $dom) {
if (isset($list_aliases[$dom])) continue;
$target_domains[] = $dom;
}
if (isset ($_REQUEST['alias_domain'])) {
$fAliasDomain = escape_string ($_REQUEST['alias_domain']);
$fAliasDomain = strtolower ($fAliasDomain);
}
if (isset ($_REQUEST['target_domain'])) {
$fTargetDomain = escape_string ($_REQUEST['target_domain']);
$fTargetDomain = strtolower ($fTargetDomain);
}
if (isset ($_REQUEST['active'])) {
$fActive = (bool)$_REQUEST['active'];
} else {
$fActive = true;
}
if ($_SERVER['REQUEST_METHOD'] == "POST")
{
if(!authentication_has_role ('global-admin') &&
!(check_owner ($SESSID_USERNAME, $fAliasDomain) &&
check_owner ($SESSID_USERNAME, $fTargetDomain)))
{
$error = 1;
$tMessage = $PALANG['pCreate_alias_domain_error1'];
}
if (isset($list_aliases[$fAliasDomain]) || // alias_domain is unique (primary key, a domain can't be an alias for multiple others)
in_array($fAliasDomain,$list_aliases) || // an alias_domain can't be a target_domain for a third domain.
isset($list_aliases[$fTargetDomain]) || // same as above, other way around
($fAliasDomain == $fTargetDomain) || // i really don't have to
empty($fAliasDomain) || empty($fTargetDomain)) // explain this, do i?
{
$error = 1;
$tMessage = $PALANG['pCreate_alias_domain_error2'];
}
$sqlActive = db_get_boolean($fActive);
if ($error != 1) {
$result = db_query ("INSERT INTO $table_alias_domain (alias_domain,target_domain,created,modified,active) VALUES ('$fAliasDomain','$fTargetDomain',NOW(),NOW(),'$sqlActive')");
if ($result['rows'] != 1) {
$error = 1;
$tMessage = $PALANG['pCreate_alias_domain_error3'];
}
else {
db_log ($SESSID_USERNAME, $fAliasDomain, 'create_alias_domain', "$fAliasDomain -> $fTargetDomain");
flash_info($PALANG['pCreate_alias_domain_success']);
# we would have to update the list of domains available for aliasing. Doing a redirect is easier.
header("Location: " . $CONF['postfix_admin_url'] . "/create-alias-domain.php");
exit;
}
}
$tMessage .= "<br />($fAliasDomain -> $fTargetDomain)<br />\n";
}
include ("templates/header.php");
include ("templates/menu.php");
include ("templates/create-alias-domain.php");
include ("templates/footer.php");
/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */
?>

@ -0,0 +1,159 @@
<?php
/**
* Postfix Admin
*
* LICENSE
*
* This source file is subject to the GPL license that is bundled with
* this package in the file LICENSE.TXT.
*
* Further details on the project are available at :
* http://www.postfixadmin.com or http://postfixadmin.sf.net
*
* File: create-alias.php
* Template File: create-alias.php
* Responsible for allowing for the creation of mail aliases.
*
* @version $Id$
* @license GNU GPL v2 or later.
*
* Template Variables:
*
* tMessage
* tAddress
* tGoto
* tDomain
*
* Form POST \ GET Variables:
*
* fAddress
* fGoto
* fDomain
*
*/
require_once('common.php');
authentication_require_role('admin');
$username = authentication_get_username();
$SESSID_USERNAME = $username;
if(authentication_has_role('global-admin')) {
$list_domains = list_domains ();
}
else {
$list_domains = list_domains_for_admin ($username);
}
$pCreate_alias_goto_text = $PALANG['pCreate_alias_goto_text'];
if ($_SERVER['REQUEST_METHOD'] == "GET")
{
if (isset ($_GET['domain'])) {
$tDomain = escape_string ($_GET['domain']);
}
}
if ($_SERVER['REQUEST_METHOD'] == "POST")
{
if (isset ($_POST['fAddress']) && isset ($_POST['fDomain'])) {
$fAddress = escape_string($_POST['fAddress']) . "@" . escape_string ($_POST['fDomain']);
$fAddress = strtolower ($fAddress);
}
if (isset ($_POST['fGoto'])) {
$fGoto = escape_string ($_POST['fGoto']);
$fGoto = strtolower ($fGoto);
}
if(isset($_POST['fActive'])) {
$fActive = escape_string ($_POST['fActive']);
}
else {
$fActive = "1";
}
if(isset($_POST['fDomain'])) {
$fDomain = escape_string ($_POST['fDomain']);
}
if(!preg_match ('/@/',$fGoto)) {
$fGoto = $fGoto . "@" . escape_string ($_POST['fDomain']);
}
if(!(authentication_has_role('global-admin') ||
check_owner ($SESSID_USERNAME, $fDomain) ))
{
$error = 1;
$tAddress = escape_string ($_POST['fAddress']);
$tGoto = $fGoto;
$tDomain = $fDomain;
$pCreate_alias_address_text = $PALANG['pCreate_alias_address_text_error1'];
}
if(!check_alias($fDomain)) {
$error = 1;
$tAddress = escape_string ($_POST['fAddress']);
$tGoto = $fGoto;
$tDomain = $fDomain;
$pCreate_alias_address_text = $PALANG['pCreate_alias_address_text_error3'];
}
if(empty ($fAddress) || !check_email ($fAddress)) {
$error = 1;
$tAddress = escape_string ($_POST['fAddress']);
$tGoto = $fGoto;
$tDomain = $fDomain;
$pCreate_alias_address_text = $PALANG['pCreate_alias_address_text_error1'];
}
if (empty($fGoto) || !check_email ($fGoto)) {
$error = 1;
$tAddress = escape_string ($_POST['fAddress']);
$tGoto = $fGoto;
$tDomain = $fDomain;
$pCreate_alias_goto_text = $PALANG['pCreate_alias_goto_text_error'];
}
if (escape_string($_POST['fAddress']) == "*") {
$fAddress = "@" . escape_string ($_POST['fDomain']);
}
$result = db_query ("SELECT * FROM $table_alias WHERE address='$fAddress'");
if ($result['rows'] == 1) {
$error = 1;
$tAddress = escape_string ($_POST['fAddress']);
$tGoto = $fGoto;
$tDomain = $fDomain;
$pCreate_alias_address_text = $PALANG['pCreate_alias_address_text_error2'];
}
if ($fActive == "on") {
$sqlActive = db_get_boolean(True);
}
else {
$sqlActive = db_get_boolean(False);
}
if ($error != 1) {
if (preg_match('/^\*@(.*)$/', $fGoto, $match)) {
$fGoto = "@" . $match[1];
}
$result = db_query ("INSERT INTO $table_alias (address,goto,domain,created,modified,active) VALUES ('$fAddress','$fGoto','$fDomain',NOW(),NOW(),'$sqlActive')");
if ($result['rows'] != 1) {
$tDomain = $fDomain;
$tMessage = $PALANG['pCreate_alias_result_error'] . "<br />($fAddress -> $fGoto)<br />\n";
}
else {
db_log ($SESSID_USERNAME, $fDomain, 'create_alias', "$fAddress -> $fGoto");
$tDomain = $fDomain;
$tMessage = $PALANG['pCreate_alias_result_success'] . "<br />($fAddress -> $fGoto)<br />\n";
}
}
}
include ("templates/header.php");
include ("templates/menu.php");
include ("templates/create-alias.php");
include ("templates/footer.php");
?>

@ -0,0 +1,152 @@
<?php
/**
* Postfix Admin
*
* LICENSE
* This source file is subject to the GPL license that is bundled with
* this package in the file LICENSE.TXT.
*
* Further details on the project are available at :
* http://www.postfixadmin.com or http://postfixadmin.sf.net
*
* @version $Id$
* @license GNU GPL v2 or later.
*
* File: create-domain.php
* Allows administrators to create new domains.
* Template File: admin_create-domain.php
*
* Template Variables:
*
* tMessage
* tDomain
* tDescription
* tAliases
* tMailboxes
* tMaxquota
* tDefaultaliases
*
* Form POST \ GET Variables:
*
* fDomain
* fDescription
* fAliases
* fMailboxes
* fMaxquota
* fDefaultaliases
*/
require_once('common.php');
authentication_require_role('global-admin');
$form_fields = array(
'fDomain' => array('type' => 'str', 'default' => null),
'fDescription' => array('type' => 'str', 'default' =>''),
'fAliases' => array('type' => 'int', 'default' => $CONF['aliases']),
'fMailboxes' => array('type' => 'int', 'default' => $CONF['mailboxes']),
'fMaxquota' => array('type' => 'int', 'default' => $CONF['maxquota']),
'fTransport' => array('type' => 'str', 'default' => $CONF['transport_default'], 'options' => $CONF['transport_options']),
'fDefaultaliases' => array('type' => 'str', 'default' => 'off', 'options' => array('on', 'off')),
'fBackupmx' => array('type' => 'str', 'default' => 'off', 'options' => array('on', 'off'))
);
foreach($form_fields as $key => $default) {
if(isset($_POST[$key]) && (!empty($_POST[$key]))) {
$$key = escape_string($_POST[$key]);
}
else {
$$key = $default['default'];
}
if($default['type'] == 'int') {
$$key = intval($$key);
}
if($default['type'] == 'str') {
$$key = strip_tags($$key); /* should we even bother? */
}
if(isset($default['options'])) {
if(!in_array($$key, $default['options'])) {
die("Invalid parameter given for $key");
}
}
}
if ($_SERVER['REQUEST_METHOD'] == "GET")
{
/* default values as set above */
$tTransport = $fTransport;
$tAliases = $fAliases;
$tMaxquota = $fMaxquota;
$tMailboxes = $fMailboxes;
$tDefaultAliases = $fDefaultaliases;
$tBackupmx = $fBackupmx;
}
if ($_SERVER['REQUEST_METHOD'] == "POST")
{
if ($fDomain == null or domain_exist($fDomain) or !check_domain($fDomain))
{
$error = 1;
$tDomain = $fDomain;
$tDescription = $fDescription;
$tAliases = $fAliases;
$tMailboxes = $fMailboxes;
if (isset ($_POST['fMaxquota'])) $tMaxquota = $fMaxquota;
if (isset ($_POST['fTransport'])) $tTransport = $fTransport;
if (isset ($_POST['fDefaultaliases'])) $tDefaultaliases = $fDefaultaliases;
if (isset ($_POST['fBackupmx'])) $tBackupmx = $fBackupmx;
$pAdminCreate_domain_domain_text = $PALANG['pAdminCreate_domain_domain_text_error2'];
if (domain_exist ($fDomain)) $pAdminCreate_domain_domain_text = $PALANG['pAdminCreate_domain_domain_text_error'];
}
if ($error != 1)
{
$tAliases = $CONF['aliases'];
$tMailboxes = $CONF['mailboxes'];
$tMaxquota = $CONF['maxquota'];
if ($fBackupmx == "on")
{
$fAliases = -1;
$fMailboxes = -1;
$fMaxquota = -1;
$fBackupmx = 1;
$sqlBackupmx = db_get_boolean(true);
}
else
{
$fBackupmx = 0;
$sqlBackupmx = db_get_boolean(false);
}
$sql_query = "INSERT INTO $table_domain (domain,description,aliases,mailboxes,maxquota,transport,backupmx,created,modified) VALUES ('$fDomain','$fDescription',$fAliases,$fMailboxes,$fMaxquota,'$fTransport',$sqlBackupmx,NOW(),NOW())";
$result = db_query($sql_query);
if ($result['rows'] != 1)
{
$tMessage = $PALANG['pAdminCreate_domain_result_error'] . "<br />($fDomain)<br />";
}
else
{
if ($fDefaultaliases == "on")
{
foreach ($CONF['default_aliases'] as $address=>$goto)
{
$address = $address . "@" . $fDomain;
$result = db_query ("INSERT INTO $table_alias (address,goto,domain,created,modified) VALUES ('$address','$goto','$fDomain',NOW(),NOW())");
}
}
$tMessage = $PALANG['pAdminCreate_domain_result_success'] . "<br />($fDomain)</br />";
}
if (!domain_postcreation($fDomain))
{
$tMessage = $PALANG['pAdminCreate_domain_error'];
}
}
}
include ("templates/header.php");
include ("templates/menu.php");
include ("templates/admin_create-domain.php");
include ("templates/footer.php");
/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */
?>

@ -0,0 +1,332 @@
<?php
/**
* Postfix Admin
*
* LICENSE
* This source file is subject to the GPL license that is bundled with
* this package in the file LICENSE.TXT.
*
* Further details on the project are available at :
* http://www.postfixadmin.com or http://postfixadmin.sf.net
*
* File: create-mailbox.php
* Responsible for allowing for the creation of mail boxes
*
* @version $Id$
* @license GNU GPL v2 or later.
*
* Template Variables:
*
* tMessage
* tUsername
* tName
* tQuota
* tDomain
*
* Form POST \ GET Variables:
*
* fUsername
* fPassword
* fPassword2
* fName
* fQuota
* fDomain
* fActive
* fMail
*/
require_once('common.php');
authentication_require_role('admin');
$SESSID_USERNAME = authentication_get_username();
if(authentication_has_role('global-admin')) {
$list_domains = list_domains ();
}
else {
$list_domains = list_domains_for_admin($SESSID_USERNAME);
}
$pCreate_mailbox_password_text = $PALANG['pCreate_mailbox_password_text'];
$pCreate_mailbox_name_text = $PALANG['pCreate_mailbox_name_text'];
$pCreate_mailbox_quota_text = $PALANG['pCreate_mailbox_quota_text'];
if ($_SERVER['REQUEST_METHOD'] == "GET")
{
$fDomain = $list_domains[0];
if (isset ($_GET['domain'])) $fDomain = escape_string ($_GET['domain']);
if(!in_array($fDomain, $list_domains)) {
die("Invalid domain name selected, or you tried to select a domain you are not an admin for");
}
$tDomain = $fDomain;
$result = db_query ("SELECT * FROM $table_domain WHERE domain='$fDomain'");
if ($result['rows'] == 1)
{
$row = db_array ($result['result']);
$tQuota = $row['maxquota'];
}
}
if ($_SERVER['REQUEST_METHOD'] == "POST")
{
if (isset ($_POST['fUsername']) && isset ($_POST['fDomain'])) $fUsername = escape_string ($_POST['fUsername']) . "@" . escape_string ($_POST['fDomain']);
$fUsername = strtolower ($fUsername);
if (isset ($_POST['fPassword'])) $fPassword = escape_string ($_POST['fPassword']);
if (isset ($_POST['fPassword2'])) $fPassword2 = escape_string ($_POST['fPassword2']);
isset ($_POST['fName']) ? $fName = escape_string ($_POST['fName']) : $fName = "";
if (isset ($_POST['fDomain'])) $fDomain = escape_string ($_POST['fDomain']);
isset ($_POST['fQuota']) ? $fQuota = intval($_POST['fQuota']) : $fQuota = 0;
isset ($_POST['fActive']) ? $fActive = escape_string ($_POST['fActive']) : $fActive = "1";
if (isset ($_POST['fMail'])) $fMail = escape_string ($_POST['fMail']);
if ( (!check_owner ($SESSID_USERNAME, $fDomain)) && (!authentication_has_role('global-admin')) )
{
$error = 1;
$tUsername = escape_string ($_POST['fUsername']);
$tName = $fName;
$tQuota = $fQuota;
$tDomain = $fDomain;
$pCreate_mailbox_username_text = $PALANG['pCreate_mailbox_username_text_error1'];
}
if (!check_mailbox ($fDomain))
{
$error = 1;
$tUsername = escape_string ($_POST['fUsername']);
$tName = $fName;
$tQuota = $fQuota;
$tDomain = $fDomain;
$pCreate_mailbox_username_text = $PALANG['pCreate_mailbox_username_text_error3'];
}
if (empty ($fUsername) or !check_email ($fUsername))
{
$error = 1;
$tUsername = escape_string ($_POST['fUsername']);
$tName = $fName;
$tQuota = $fQuota;
$tDomain = $fDomain;
$pCreate_mailbox_username_text = $PALANG['pCreate_mailbox_username_text_error1'];
}
$tPassGenerated = 0;
if (empty ($fPassword) or empty ($fPassword2) or ($fPassword != $fPassword2))
{
if (empty ($fPassword) and empty ($fPassword2) and $CONF['generate_password'] == "YES")
{
$fPassword = generate_password ();
$tPassGenerated = 1;
}
else
{
$error = 1;
$tUsername = escape_string ($_POST['fUsername']);
$tName = $fName;
$tQuota = $fQuota;
$tDomain = $fDomain;
$pCreate_mailbox_password_text = $PALANG['pCreate_mailbox_password_text_error'];
}
}
if ($CONF['quota'] == "YES")
{
if (!check_quota ($fQuota, $fDomain))
{
$error = 1;
$tUsername = escape_string ($_POST['fUsername']);
$tName = $fName;
$tQuota = $fQuota;
$tDomain = $fDomain;
$pCreate_mailbox_quota_text = $PALANG['pCreate_mailbox_quota_text_error'];
}
}
$result = db_query ("SELECT * FROM $table_alias WHERE address='$fUsername'");
if ($result['rows'] == 1)
{
$error = 1;
$tUsername = escape_string ($_POST['fUsername']);
$tName = $fName;
$tQuota = $fQuota;
$tDomain = $fDomain;
$pCreate_mailbox_username_text = $PALANG['pCreate_mailbox_username_text_error2'];
}
if ($error != 1)
{
$password = pacrypt ($fPassword);
if ($CONF['domain_path'] == "YES")
{
if ($CONF['domain_in_mailbox'] == "YES")
{
$maildir = $fDomain . "/" . $fUsername . "/";
}
else
{
$maildir = $fDomain . "/" . escape_string (strtolower($_POST['fUsername'])) . "/";
}
}
else
{
$maildir = $fUsername . "/";
}
if (!empty ($fQuota))
{
$quota = multiply_quota ($fQuota);
}
else
{
$quota = 0;
}
if ($fActive == "on")
{
$sqlActive = db_get_boolean(True);
}
else
{
$sqlActive = db_get_boolean(False);
}
if ('pgsql'==$CONF['database_type'])
{
db_query('BEGIN');
}
$result = db_query ("INSERT INTO $table_alias (address,goto,domain,created,modified,active) VALUES ('$fUsername','$fUsername','$fDomain',NOW(),NOW(),'$sqlActive')");
if ($result['rows'] != 1)
{
$tDomain = $fDomain;
$tMessage = $PALANG['pAlias_result_error'] . "<br />($fUsername -> $fUsername)</br />";
}
/*
# TODO: The following code segment is from admin/create-mailbox.php. To be compared/merged with the code from /create-mailbox.php.
Lines starting with /* were inserted to keep this section in commented mode.
if ($result['rows'] != 1)
{
$tDomain = $fDomain;
$tMessage .= $PALANG['pCreate_mailbox_result_error'] . "<br />($fUsername)<br />";
}
else
{
$error=TRUE; // Being pessimistic
if (mailbox_postcreation($fUsername,$fDomain,$maildir))
{
if ('pgsql'==$CONF['database_type'])
{
$result=db_query("COMMIT");
/* should really not be possible: */
/*
if (!$result) die('COMMIT-query failed.');
}
$error=FALSE;
} else {
$tMessage .= $PALANG['pCreate_mailbox_result_error'] . "<br />($fUsername)<br />";
if ('pgsql'==$CONF['database_type'])
{
$result=db_query("ROLLBACK");
/* should really not be possible: */
/*
if (!$result) die('ROLLBACK-query failed.');
} else {
/*
When we cannot count on transactions, we need to move forward, despite
the problems.
*/
/*
$error=FALSE;
}
}
if (!$error)
{
db_log ($CONF['admin_email'], $fDomain, 'create_mailbox', $fUsername);
*/
/*
TODO: this is the start of /create-mailbox code segment that was originally used in /create-mailbox.php instead
of the above from admin/create-mailbox.php.
To be compared / merged.
*/
// apparently uppercase usernames really confuse some IMAP clients.
$fUsername = strtolower($fUsername);
$local_part = '';
if(preg_match('/^(.*)@/', $fUsername, $matches)) {
$local_part = $matches[1];
}
$result = db_query ("INSERT INTO $table_mailbox (username,password,name,maildir,local_part,quota,domain,created,modified,active) VALUES ('$fUsername','$password','$fName','$maildir','$local_part','$quota','$fDomain',NOW(),NOW(),'$sqlActive')");
if ($result['rows'] != 1 || !mailbox_postcreation($fUsername,$fDomain,$maildir, $quota))
{
$tDomain = $fDomain;
$tMessage .= $PALANG['pCreate_mailbox_result_error'] . "<br />($fUsername)<br />";
db_query('ROLLBACK');
}
else
{
db_query('COMMIT');
db_log ($SESSID_USERNAME, $fDomain, 'create_mailbox', "$fUsername");
/*
TODO: this is the end of /create-mailbox.php code segment
*/
$tDomain = $fDomain;
$tQuota = $CONF['maxquota'];
if ($fMail == "on")
{
$fTo = $fUsername;
$fFrom = $SESSID_USERNAME;
$fHeaders = "To: " . $fTo . "\n";
$fHeaders .= "From: " . $fFrom . "\n";
$fHeaders .= "Subject: " . encode_header ($PALANG['pSendmail_subject_text']) . "\n";
$fHeaders .= "MIME-Version: 1.0\n";
$fHeaders .= "Content-Type: text/plain; charset=utf-8\n";
$fHeaders .= "Content-Transfer-Encoding: 8bit\n";
$fHeaders .= $CONF['welcome_text'];
if (!smtp_mail ($fTo, $fFrom, $fHeaders))
{
$tMessage .= "<br />" . $PALANG['pSendmail_result_error'] . "<br />";
}
else
{
$tMessage .= "<br />" . $PALANG['pSendmail_result_success'] . "<br />";
}
}
$tShowpass = "";
if ( $tPassGenerated == 1 || $CONF['show_password'] == "YES") $tShowpass = " / $fPassword";
if (create_mailbox_subfolders($fUsername,$fPassword))
{
$tMessage .= $PALANG['pCreate_mailbox_result_success'] . "<br />($fUsername$tShowpass)";
} else {
$tMessage .= $PALANG['pCreate_mailbox_result_succes_nosubfolders'] . "<br />($fUsername$tShowpass)";
}
}
}
}
include ("templates/header.php");
include ("templates/menu.php");
include ("templates/create-mailbox.php");
include ("templates/footer.php");
/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */
?>

@ -98,14 +98,14 @@ ul.flash-error {
font-size: 13px; font-size: 13px;
} }
#menu, #tabbar { #menu {
width: 750px; width: 750px;
margin: 0 auto; margin: 0 auto;
padding-top: 10px; padding-top: 10px;
white-space: nowrap; white-space: nowrap;
} }
#menu ul, #tabbar ul { #menu ul {
padding: 0; padding: 0;
margin: 0; margin: 0;
margin-left:auto; margin-left:auto;
@ -113,18 +113,18 @@ ul.flash-error {
list-style: none; list-style: none;
} }
#menu li, #tabbar li { #menu li {
float: left; float: left;
background: #efefef; background: #efefef;
margin-right: 3px; margin-right: 3px;
border-top: 4px solid #aaaaaa; border-top: 4px solid #aaaaaa;
} }
#menu li:hover, #menu li.sfhover, #tabbar li:hover, #tabbar li.sfhover { #menu li:hover, #menu li.sfhover {
background: #BFFF00; background: #BFFF00;
} }
#menu li ul, #tabbar li ul { #menu li ul {
position: absolute; position: absolute;
width: auto; width: auto;
left: -999em; left: -999em;
@ -132,12 +132,12 @@ ul.flash-error {
border:2px solid white; border:2px solid white;
border-top:none; border-top:none;
} }
#menu li:hover ul, #menu li.sfhover ul, #tabbar li:hover ul, #tabbar li.sfhover ul { #menu li:hover ul, #menu li.sfhover ul {
left: auto; left: auto;
} }
#menu li ul li, #tabbar li ul li { #menu li ul li {
float: none; float: none;
margin-right: 0px; margin-right: 0px;
border-top:2px solid white;; border-top:2px solid white;;
@ -145,20 +145,22 @@ ul.flash-error {
} }
#menu a, #tabbar a {
#menu a {
display: block; display: block;
width: auto; width: auto;
padding: 20px 5px 5px 5px; padding: 20px 5px 5px 5px;
color: #888888; color: #888888;
} }
#menu a:hover, #tabbar a:hover { #menu a:hover {
color: #888888; color: #888888;
} }
#menu li ul li a, #tabbar li ul li a { #menu li ul li a {
padding: 5px 5px 5px 5px; padding: 5px 5px 5px 5px;
} }
@ -238,6 +240,12 @@ ul.flash-error {
line-height: 30px; line-height: 30px;
} }
#nav_bar {
text-align: right;
width: 750px;
margin: 0 auto;
}
#alias_domain_table, #alias_table, #mailbox_table, #overview_table, #log_table, #admin_table { #alias_domain_table, #alias_table, #mailbox_table, #overview_table, #log_table, #admin_table {
width: 750px; width: 750px;
margin: 0px auto; margin: 0px auto;
@ -273,10 +281,6 @@ ul.flash-error {
margin: 0; margin: 0;
} }
#alias_domain_table td, #alias_table td, #mailbox_table td, #overview_table td, #log_table td, #admin_table td {
text-align : left;
}
#footer { #footer {
width: 750px; width: 750px;
margin: 20px auto; margin: 20px auto;
@ -309,9 +313,3 @@ div.setup {
div.setup li { div.setup li {
padding-bottom:1em; padding-bottom:1em;
} }
div.nav_bar {
text-align: left;
width: 750px;
margin: 0 auto;
}

@ -1,22 +1,30 @@
PostfixAdmin for Debian PostfixAdmin for Debian
======================= =======================
After installing the package, you should find that : After installing the package, you should find that :
http://youserver/postfixadmin/setup.php works. This should http://youserver/postfixadmin/setup.php works. This should
guide you through the appropriate process. guide you through the appropriate process.
You will need to create a database (either MySQL or PostgreSQL)
and know the username and password for it. The Database does not need
to be on the same server as the Postfixadmin install.
Recommended and Suggested Packages Recommended and Suggested Packages
================================== ==================================
- Postfix - Postfix
- MySQL or PostgreSQL - MySQL or PostgreSQL
- Courier or Dovecot - Courier or Dovecot
Where to get help Where to get help
================= =================
The first stop would be the Postfixadmin Website, Forum or IRC channel. The first stop would be the Postfixadmin Website, Forum or IRC channel.
See : See :
- http://postfixadmin.sf.net - http://postfixadmin.sf.net
- #postfixadmin on irc.freenode.net - #postfixadmin on irc.freenode.net

@ -1,27 +0,0 @@
This package is using the quilt framework.
All patches are located in debian/patches.
Adding a new patch: quilt new <date-patch_name>
This will create a new file debian/patches/patch/date-patch_name.
Please use the current date (e.g. 20100221 - YYYYMMDD) as prefix!
Editing a file to include it into the patch: quilt edit <filename>
This will open your $EDITOR.
To write your changes into the new patchfile: quilt refresh.
quilt push:
Apply patch(es) from the series file. Without options, the next
patch in the series file is applied. When a number is specified,
apply the specified number of patches. When a patch name is
specified, apply all patches up to and including the specified patch.
Patch names may include the patches/ prefix, which means that
filename completion can be used.
quilt pop:
Remove patch(es) from the stack of applied patches. Without options,
the topmost patch is removed. When a number is specified, remove the
specified number of patches. When a patch name is specified, remove
patches until the specified patch end up on top of the stack.
Patch names may include the patches/ prefix, which means that
filename completion can be used.

21
debian/README.txt vendored

@ -1,21 +0,0 @@
Random instructions for help:
This 'debian' directory is used by dpkg-buildpackage when creating a .deb.
You'll need to install :
apt-get install dpkg-dev quilt debhelper
Then from within the trunk directory (or whatever forms the root of the
postfixadmin project), do the following :
1. Update debian/changelog; include your email address in the last change
(this is used to determine a gpg key to use)
2. debian/rules prep
3. dpkg-buildpackage -rfakeroot
4. Look in ../ at the shiny .deb / .tar.gz
5. Profit.

3
debian/TODO vendored

@ -1,3 +0,0 @@
* DebTags
* dbconfig: DOCUMENTS/SECURITY.txt
* include postfix configuration templates

@ -0,0 +1,6 @@
# BEGIN FOR POSTFIXADMIN
Alias /postfixadmin /usr/share/postfixadmin
# END FOR POSTFIXADMIN

@ -1,5 +0,0 @@
# BEGIN FOR POSTFIXADMIN
Alias /postfixadmin /usr/share/postfixadmin/public
# END FOR POSTFIXADMIN

113
debian/changelog vendored

@ -1,77 +1,88 @@
postfixadmin (3.2-1) unstable; urgency=low postfixadmin (2.3beta) unstable; urgency=low
* New upstream release - PostfixAdmin v3.2 * Subversion revision 539
* Fixes for MySQL upgrade issues
* Improved vacation.pl (renotification options, use SMTP headers, better
logging, optional external config file)
* Improved fetchmail.pl
* Domain aliases - new implementation should reduce backscatter etc.
* translation updates
* Added domain-postcreation script support
* Enhanced mailbox table to make it easier for people to customise where mailboxes live
* and much more
-- David Goodwin <david@palepurple.co.uk> Wed, 02 May 2018 21:36:01 +0100 -- David Goodwin <david.goodwin@palepurple.co.uk> Tue, 20 Jan 2009 20:50:00 +0000
postfixadmin (3.1-1) unstable; urgency=low postfixadmin (2.2.1.1) unstable; urgency=low
* New upstream release * Subversion revision 412 (from branches/postfixadmin-2.2.1)
* THIS IS EFFECTIVELY THE SAME AS 2.2.1 (which should probably be ignored)
-- David Goodwin <david@palepurple.co.uk> Sun, 25 Jun 2017 16:27:01 +0000 -- David Goodwin <david.goodwin@palepurple.co.uk> Wed, 23 Jul 2008 12:37:00 +0000
postfixadmin (3.0.2-1) unstable; urgency=low postfixadmin (2.2.1) unstable; urgency=low
* Security fix (don't delete protected aliases, CVE-2017-5930) * Various bug fixes (MySQL charset issue(s))
* Fix MySQL vacation.cache column (regression fix) * Updated translations (pl, bg, ru, nb, tw etc)
* added quota parameter to mailbox_postcreation hook
* new hook to update the quota after editing a mailbox
($CONF['mailbox_postedit_script'])
* fixed subfolder creation order and timing
* allow smtp server to be specified in vacation.pl
* fixed MySQL charset issues
* several small bugfixes
* Norwegian (bokmal) translation added
* Updated translations (pl, bg, ru, nb, tw etc)
* Subversion revision 408
-- David Goodwin <david@palepurple.co.uk> Wed, 08 Feb 2017 19:30:00 +0000 -- David Goodwin <david.goodwin@palepurple.co.uk> Mon, 21 Jul 2008 22:44:00 +0000
postfixadmin (2.2.0) unstable; urgency=low
postfixadmin (3.0.1-2) unstable; urgency=low * 2.2.0 Released.
* Fix fetchmail script to work with PostgreSQL
* Fix fetchmail table creation in MySQL and PostgreSQL
* Documentation fixups
* Subversion revision 356
* Try and make dependencies less strict (and perhaps work for Ubuntu Precise as well) -- David Goodwin <david.goodwin@palepurple.co.uk> Thu, 29 Apr 2008 15:47:00 +0000
-- David Goodwin <david@palepurple.co.uk> Mon, 10 Oct 2016 20:00:00 +0100 postfixadmin (2.2.0-rc5) unstable; urgency=low
postfixadmin (3.0.1-1) unstable; urgency=low * Fix MySQL installation issues (schema not being created!)
* Fix MySQL vacation_notification timestamp issue
* SVN revision: 340
* Fix packaging issues (missing: smarty/ and configs/) -- David Goodwin <david.goodwin@palepurple.co.uk> Wed, 23 Apr 2008 16:27:00 +0000
-- David Goodwin <david@palepurple.co.uk> Mon, 19 Sep 2016 10:08:00 +0100 postfixadmin (2.2.0-1rc4) unstable; urgency=low
postfixadmin (3.0-1) unstable; urgency=low * Removal of standalone database schema files (see upgrade.php)
* Various bug fixes
* Better/Move documentation on installation
* setup.php/upgrade.php works for PostgreSQL and MySQL
* MySQL Unicode problems fixed
* I think this is effectively v2.2.0
* SVN revision: 336
* New upstream release -- David Goodwin <david.goodwin@palepurple.co.uk> Sun, 20 Apr 2008 20:19:00 +0000
-- David Goodwin <david@palepurple.co.uk> Sun, 11 Sep 2016 18:42:00 +0100 postfixadmin (2.2.0-1rc3) unstable; urgency=low
postfixadmin (2.93-2) unstable; urgency=low * Various bug fixes
* Replace debian/ using Debian v2.3.7-2. See Debian's #821643 -- David Goodwin <david.goodwin@palepurple.co.uk> Thu, 28 Feb 2008 12:00:00 +0000
* This adds : PHP7 and Apache 2.4 support.
-- David Goodwin <david@palepurple.co.uk> Sun, 22 May 2016 19:41:01 +0100 postfixadmin (2.2.0-1rc2) unstable; urgency=low
postfixadmin (2.93-1) unstable; urgency=low * Improved CSS
* Improved upgrade procedure (should work for PGSQL) (see upgrade.php)
* Various bug fixes
* New upstream release (effectively beta3 for v3.0) -- David Goodwin <david.goodwin@palepurple.co.uk> Sat, 29 Dec 2007 21:14:00 +0000
* update dependencies to allow mariadb as database
-- David Goodwin <david@palepurple.co.uk> Sat, 26 Sep 2015 15:05:00 +0100 postfixadmin (2.2.0-1rc1) unstable; urgency=low
postfixadmin (2.92-1) unstable; urgency=low * Initial Release (via dpkg)
* New upstream release (effectively beta2 for v3.0) -- David Goodwin <david.goodwin@palepurple.co.uk> Sun, 04 Nov 2007 15:36:00 +0000
-- David Goodwin <david@palepurple.co.uk> Wed, 28 Oct 2014 21:02:00 +0100
postfixadmin (2.91-1) unstable; urgency=low
* New upstream release (effectively beta for v3.0)
-- David Goodwin <david@palepurple.co.uk> Tue, 06 May 2014 21:36:00 +0100
postfixadmin (2.3.5-2) unstable; urgency=low
* Added .po translation files (Closes: 667951, #667962, #668202, #668288)
* Closes: #668298, #668301, #668405, #668635
* Updated standards version to 3.9.3 without changes.
-- Norman Messtorff <normes@normes.org> Thu, 26 Apr 2012 20:55:57 +0200
postfixadmin (2.3.5-1) unstable; urgency=low
* Initial Debian release (Closes: #247225)
-- Norman Messtorff <normes@normes.org> Sun, 15 Jan 2012 12:27:28 +0100

2
debian/compat vendored

@ -1 +1 @@
7 5

2
debian/conffiles vendored

@ -0,0 +1,2 @@
/etc/apache2/conf.d/postfixadmin
/etc/postfixadmin/config.inc.php

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save