Merge branch 'master' of https://github.com/andryyy/mailcow-dockerized
This commit is contained in:
commit
6ebb216cf2
|
@ -4,7 +4,7 @@ data/conf/dovecot/dovecot-master.passwd
|
|||
mailcow.conf
|
||||
mailcow.conf_backup
|
||||
data/conf/nginx/listen*active
|
||||
data/conf/nginx/server_name*active
|
||||
data/conf/nginx/server_name.active
|
||||
data/conf/postfix/sql
|
||||
data/conf/dovecot/sql
|
||||
data/web/inc/vars.local.inc.php
|
||||
|
|
|
@ -6,6 +6,8 @@ sed -i "/^\$DBUSER/c\\\$DBUSER='${DBUSER}';" /usr/local/bin/imapsync_cron.pl
|
|||
sed -i "/^\$DBPASS/c\\\$DBPASS='${DBPASS}';" /usr/local/bin/imapsync_cron.pl
|
||||
sed -i "/^\$DBNAME/c\\\$DBNAME='${DBNAME}';" /usr/local/bin/imapsync_cron.pl
|
||||
|
||||
[[ ! -d /etc/dovecot/sql/ ]] && mkdir -p /etc/dovecot/sql/
|
||||
|
||||
# Set Dovecot sql config parameters, escape " in db password
|
||||
DBPASS=$(echo ${DBPASS} | sed 's/"/\\"/g')
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ user = ${DBUSER}
|
|||
password = ${DBPASS}
|
||||
hosts = mysql
|
||||
dbname = ${DBNAME}
|
||||
query = SELECT goto FROM alias WHERE address='%s' AND active='1' AND domain IN(SELECT domain FROM domain WHERE domain='%d' AND active='1') UNION SELECT logged_in_as FROM sender_acl WHERE send_as='@%d' OR send_as='%s' OR send_as IN ( SELECT CONCAT ('@',target_domain) FROM alias_domain WHERE alias_domain = '%d') OR send_as IN ( SELECT CONCAT ('%u','@',target_domain) FROM alias_domain WHERE alias_domain = '%d' ) AND logged_in_as NOT IN (SELECT goto FROM alias WHERE address='%s') UNION SELECT username 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 goto FROM alias WHERE address='%s' AND active='1' AND (domain IN (SELECT domain FROM domain WHERE domain='%d' AND active='1') OR domain in (SELECT target_domain FROM alias_domain WHERE alias_domain='%d' AND active='1')) UNION SELECT logged_in_as FROM sender_acl WHERE send_as='@%d' OR send_as='%s' OR send_as IN ( SELECT CONCAT ('@',target_domain) FROM alias_domain WHERE alias_domain = '%d') OR send_as IN ( SELECT CONCAT ('%u','@',target_domain) FROM alias_domain WHERE alias_domain = '%d' ) AND logged_in_as NOT IN (SELECT goto FROM alias WHERE address='%s') UNION SELECT username 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'
|
||||
EOF
|
||||
|
||||
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf
|
||||
|
|
|
@ -30,8 +30,6 @@ cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
|||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_cache_folder</string>
|
||||
<key>OCSEMailAlarmsFolderURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_alarms_folder</string>
|
||||
<key>DomainFieldName</key>
|
||||
<string>domain</string>
|
||||
<key>OCSFolderInfoURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_folder_info</string>
|
||||
<key>OCSSessionsFolderURL</key>
|
||||
|
@ -63,6 +61,8 @@ while read line
|
|||
</array>
|
||||
<key>KindFieldName</key>
|
||||
<string>kind</string>
|
||||
<key>DomainFieldName</key>
|
||||
<string>domain</string>
|
||||
<key>MultipleBookingsFieldName</key>
|
||||
<string>multiple_bookings</string>
|
||||
<key>canAuthenticate</key>
|
||||
|
|
|
@ -131,6 +131,9 @@ namespace inbox {
|
|||
auto = subscribe
|
||||
special_use = \Junk
|
||||
}
|
||||
mailbox "Junk-E-mail" {
|
||||
special_use = \Junk
|
||||
}
|
||||
mailbox "Junk E-mail" {
|
||||
special_use = \Junk
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
connect = "host=mysql dbname=mailcow user=mailcow password=mysafepasswd"
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
driver = mysql
|
||||
connect = "host=mysql dbname=mailcow user=mailcow password=mysafepasswd"
|
||||
default_pass_scheme = SSHA256
|
||||
password_query = SELECT password FROM mailbox WHERE username = '%u' AND domain IN (SELECT domain FROM domain WHERE domain='%d' AND active='1')
|
||||
user_query = SELECT CONCAT('maildir:/var/vmail/',maildir) AS mail, 5000 AS uid, 5000 AS gid, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1'
|
||||
iterate_query = SELECT username FROM mailbox WHERE active='1';
|
|
@ -1 +0,0 @@
|
|||
server_name logs.servercow.de autodiscover.* autoconfig.*;
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT DISTINCT CASE WHEN '%d' IN (SELECT domain FROM domain WHERE relay_all_recipients=1 AND domain='%d' AND backupmx=1) THEN '%s' ELSE (SELECT goto FROM alias WHERE address='%s' AND active='1') END AS result;
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT IF( EXISTS( SELECT 'TLS_ACTIVE' FROM alias LEFT OUTER JOIN mailbox ON mailbox.username = alias.address WHERE (address='%s' OR address IN (SELECT CONCAT('%u', '@', target_domain) FROM alias_domain WHERE alias_domain='%d')) AND mailbox.tls_enforce_in = '1' AND mailbox.active = '1'), 'reject_plaintext_session', 'DUNNO') AS 'tls_enforce_in';
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT IF( EXISTS( SELECT 'TLS_ACTIVE' FROM alias LEFT OUTER JOIN mailbox ON mailbox.username = alias.address WHERE (address='%s' OR address IN (SELECT CONCAT('%u', '@', target_domain) FROM alias_domain WHERE alias_domain='%d')) AND mailbox.tls_enforce_out = '1' AND mailbox.active = '1'), 'smtp_enforced_tls:', 'DUNNO') AS 'tls_enforce_out';
|
|
@ -1,6 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
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'
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT username 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'
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT goto FROM alias WHERE address='%s' AND active='1';
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT alias_domain from alias_domain WHERE alias_domain='%s' AND active='1' UNION SELECT domain FROM domain WHERE domain='%s' AND active = '1' AND backupmx = '0'
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '1' AND active = '1'
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT goto FROM alias WHERE address='%s' AND active='1' AND domain IN(SELECT domain FROM domain WHERE domain='%d' AND active='1') UNION SELECT logged_in_as FROM sender_acl WHERE send_as='@%d' OR send_as='%s' OR send_as IN ( SELECT CONCAT ('@',target_domain) FROM alias_domain WHERE alias_domain = '%d') OR send_as IN ( SELECT CONCAT ('%u','@',target_domain) FROM alias_domain WHERE alias_domain = '%d' ) AND logged_in_as NOT IN (SELECT goto FROM alias WHERE address='%s') UNION SELECT username 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'
|
|
@ -1,5 +0,0 @@
|
|||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT goto FROM spamalias WHERE address='%s' AND validity >= UNIX_TIMESTAMP()
|
|
@ -12,16 +12,23 @@ $opt = [
|
|||
try {
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
$stmt = $pdo->query("SELECT `username` FROM `mailbox` WHERE `wants_tagged_subject` = '1'");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
$rows_a = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row_a = array_shift($rows_a)) {
|
||||
$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` REGEXP :username AND goto != `address` AND `address` NOT LIKE '@%'");
|
||||
$stmt->execute(array(':username' => '(^|,)'.$row_a['username'].'($|,)'));
|
||||
$rows_a_a = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row_a_a = array_shift($rows_a_a)) {
|
||||
echo strtolower(trim($row_a_a['address'])) . PHP_EOL;
|
||||
}
|
||||
$has_object = 1;
|
||||
echo strtolower(trim($row['username'])) . PHP_EOL;
|
||||
echo strtolower(trim($row_a['username'])) . PHP_EOL;
|
||||
}
|
||||
$stmt = $pdo->query("SELECT CONCAT(mailbox.local_part, '@', alias_domain.alias_domain) as `tag_ad` FROM `mailbox` INNER JOIN `alias_domain` ON mailbox.domain = alias_domain.target_domain WHERE mailbox.wants_tagged_subject='1';");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
$stmt = $pdo->query("SELECT CONCAT(`mailbox`.`local_part`, '@', `alias_domain`.`alias_domain`) AS `tag_ad` FROM `mailbox`
|
||||
INNER JOIN `alias_domain` ON `mailbox`.`domain` = `alias_domain`.`target_domain` WHERE `mailbox`.`wants_tagged_subject` = '1';");
|
||||
$rows_b = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row_b = array_shift($rows_b)) {
|
||||
$has_object = 1;
|
||||
echo strtolower(trim($row['tag_ad'])) . PHP_EOL;
|
||||
echo strtolower(trim($row_b['tag_ad'])) . PHP_EOL;
|
||||
}
|
||||
if ($has_object == 0) {
|
||||
echo "dummy@domain.local";
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
rates {
|
||||
# Limit for all mail per recipient (burst 100, rate 2 per minute)
|
||||
to = [100, 0.033333333];
|
||||
# Limit for all mail per one source ip (burst 30, rate 1.5 per minute)
|
||||
to_ip = [30, 0.025];
|
||||
# Limit for all mail per one source ip and from address (burst 20, rate 1 per minute)
|
||||
to_ip_from = [20, 0.01666666667];
|
||||
# Limit for all bounce mail (burst 10, rate 2 per hour)
|
||||
bounce_to = [10, 0.000555556];
|
||||
# Limit for bounce mail per one source ip (burst 5, rate 1 per hour)
|
||||
bounce_to_ip = [5, 0.000277778];
|
||||
# Limit for all mail per authenticated user (burst 20, rate 1 per minute)
|
||||
user = [20, 0.01666666667];
|
||||
}
|
||||
# If symbol is specified, then it is inserted instead of setting result
|
||||
#symbol = "R_RATELIMIT";
|
||||
whitelisted_rcpts = "postmaster,mailer-daemon";
|
||||
max_rcpt = 5;
|
|
@ -1 +1,2 @@
|
|||
# rspamd.conf.local
|
||||
history_redis {}
|
||||
|
|
|
@ -23,40 +23,57 @@ auth_domain_map = rspamd_config:add_map({
|
|||
description = 'Map of domains we are authoritative for'
|
||||
})
|
||||
|
||||
rspamd_config.ADD_DELIMITER_TAG = {
|
||||
rspamd_config:register_symbol({
|
||||
name = 'TAG_MOO',
|
||||
type = 'postfilter',
|
||||
callback = function(task)
|
||||
local tag = nil
|
||||
local util = require("rspamd_util")
|
||||
local rspamd_logger = require "rspamd_logger"
|
||||
local user_tagged = task:get_recipients(2)[1]['user']
|
||||
local domain = task:get_recipients(1)[1]['domain']
|
||||
local user, tag = user_tagged:match("([^+]+)+(.*)")
|
||||
|
||||
local tagged_rcpt = task:get_symbol("TAGGED_RCPT")
|
||||
local user = task:get_recipients(0)[1]['user']
|
||||
local domain = task:get_recipients(0)[1]['domain']
|
||||
local rcpt = user .. '@' .. domain
|
||||
local authdomain = auth_domain_map:get_key(domain)
|
||||
|
||||
if tag and authdomain then
|
||||
rspamd_logger.infox("domain: %1, tag: %2", domain, tag)
|
||||
local user_untagged = user .. '@' .. domain
|
||||
rspamd_logger.infox("querying tag settings for user %1", user_untagged)
|
||||
if modify_subject_map:get_key(user_untagged) then
|
||||
rspamd_logger.infox("found user in map for subject rewrite")
|
||||
local sbj = task:get_header('Subject')
|
||||
new_sbj = '=?UTF-8?B?' .. tostring(util.encode_base64('[' .. tag .. '] ' .. sbj)) .. '?='
|
||||
task:set_rmilter_reply({
|
||||
remove_headers = {['Subject'] = 1},
|
||||
add_headers = {['Subject'] = new_sbj}
|
||||
})
|
||||
else
|
||||
rspamd_logger.infox("add X-Moo-Tag header")
|
||||
task:set_rmilter_reply({
|
||||
add_headers = {['X-Moo-Tag'] = 'YES'}
|
||||
})
|
||||
if tagged_rcpt then
|
||||
local tag = tagged_rcpt[1].options[1]
|
||||
rspamd_logger.infox("found tag: %s", tag)
|
||||
local action = task:get_metric_action('default')
|
||||
rspamd_logger.infox("metric action now: %s", action)
|
||||
|
||||
if action ~= 'no action' and action ~= 'greylist' then
|
||||
rspamd_logger.infox("skipping tag handler for action: %s", action)
|
||||
task:set_metric_action('default', action)
|
||||
return true
|
||||
end
|
||||
else
|
||||
rspamd_logger.infox("skip delimiter handling for untagged message or authenticated user")
|
||||
|
||||
if authdomain then
|
||||
rspamd_logger.infox("found mailcow domain %s", domain)
|
||||
rspamd_logger.infox("querying tag settings for user %s", rcpt)
|
||||
|
||||
if modify_subject_map:get_key(rcpt) then
|
||||
rspamd_logger.infox("user wants subject modified for tagged mail")
|
||||
local sbj = task:get_header('Subject')
|
||||
new_sbj = '=?UTF-8?B?' .. tostring(util.encode_base64('[' .. tag .. '] ' .. sbj)) .. '?='
|
||||
task:set_rmilter_reply({
|
||||
remove_headers = {['Subject'] = 1},
|
||||
add_headers = {['Subject'] = new_sbj}
|
||||
})
|
||||
else
|
||||
rspamd_logger.infox("Add X-Moo-Tag header")
|
||||
task:set_rmilter_reply({
|
||||
add_headers = {['X-Moo-Tag'] = 'YES'}
|
||||
})
|
||||
end
|
||||
else
|
||||
rspamd_logger.infox("skip delimiter handling for unknown domain")
|
||||
end
|
||||
return false
|
||||
end
|
||||
return false
|
||||
end
|
||||
}
|
||||
end,
|
||||
priority = 10
|
||||
})
|
||||
|
||||
rspamd_config.MRAPTOR = {
|
||||
callback = function(task)
|
||||
|
|
|
@ -292,7 +292,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] ==
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="port1">Port</label>
|
||||
<label class="control-label col-sm-2" for="port1"><?=$lang['add']['port'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="port1" id="port1" min="1" max="65535" value="143" required>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ header("Content-Type: application/xml");
|
|||
<?='<?xml version="1.0"?>';?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="<?=$mailcow_hostname;?>">
|
||||
|
||||
<domain>%EMAILDOMAIN%</domain>
|
||||
<displayName>A mailcow mail server</displayName>
|
||||
<displayShortName>mail server</displayShortName>
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -43,4 +43,10 @@
|
|||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
|
||||
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
|
||||
.footable-sortable {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
|
|
@ -1467,7 +1467,7 @@ function user_get_alias_details($username) {
|
|||
try {
|
||||
$data['address'] = $username;
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '✘') AS `aliases` FROM `alias`
|
||||
WHERE `goto` LIKE :username_goto
|
||||
WHERE `goto` REGEXP :username_goto
|
||||
AND `address` NOT LIKE '@%'
|
||||
AND `address` != :username_address");
|
||||
$stmt->execute(array(':username_goto' => '(^|,)'.$username.'($|,)', ':username_address' => $username));
|
||||
|
@ -1495,8 +1495,8 @@ function user_get_alias_details($username) {
|
|||
while ($row = array_shift($run)) {
|
||||
$data['aliases_send_as_all'] = $row['send_as'];
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '✘') as `address` FROM `alias` WHERE `goto` LIKE :username AND `address` LIKE '@%';");
|
||||
$stmt->execute(array(':username' => '%' . $username . '%'));
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '✘') as `address` FROM `alias` WHERE `goto` REGEXP :username AND `address` LIKE '@%';");
|
||||
$stmt->execute(array(':username' => '(^|,)'.$username.'($|,)'));
|
||||
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($run)) {
|
||||
$data['is_catch_all'] = $row['address'];
|
||||
|
@ -3320,7 +3320,7 @@ function mailbox_edit_alias_domain($postarray) {
|
|||
$stmt = $pdo->prepare("UPDATE `alias_domain` SET
|
||||
`alias_domain` = :alias_domain,
|
||||
`active` = :active,
|
||||
`modified` = :modified,
|
||||
`modified` = :modified
|
||||
WHERE `alias_domain` = :alias_domain_now");
|
||||
$stmt->execute(array(
|
||||
':alias_domain' => $alias_domain,
|
||||
|
@ -4422,7 +4422,7 @@ function mailbox_get_resource_details($resource) {
|
|||
$resourcedata['name'] = $row['username'];
|
||||
$resourcedata['kind'] = $row['kind'];
|
||||
$resourcedata['multiple_bookings'] = $row['multiple_bookings'];
|
||||
$resourcedata['multiple_bookings_int'] = $row['multiple_bookings'];
|
||||
$resourcedata['multiple_bookings_int'] = $row['multiple_bookings_int'];
|
||||
$resourcedata['description'] = $row['name'];
|
||||
$resourcedata['active'] = $row['active'];
|
||||
$resourcedata['active_int'] = $row['active_int'];
|
||||
|
@ -4878,7 +4878,7 @@ function mailbox_get_sender_acl_handles($mailbox) {
|
|||
|
||||
try {
|
||||
// Fixed addresses
|
||||
$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` LIKE :goto AND `address` NOT LIKE '@%'");
|
||||
$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` REGEXP :goto AND `address` NOT LIKE '@%'");
|
||||
$stmt->execute(array(':goto' => '(^|,)'.$mailbox.'($|,)'));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<link rel="stylesheet" href="/css/bootstrap-select.min.css">
|
||||
<link rel="stylesheet" href="/css/bootstrap-slider.min.css">
|
||||
<link rel="stylesheet" href="/css/bootstrap-switch.min.css">
|
||||
<link rel="stylesheet" href="/css/footable.bootstrap.min.css">
|
||||
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600,700&subset=latin,latin-ext">
|
||||
<link rel="stylesheet" href="/inc/languages.min.css">
|
||||
<link rel="stylesheet" href="/css/mailcow.css">
|
||||
|
@ -48,6 +49,7 @@
|
|||
<li <?=($_SESSION['mailcow_locale'] == 'es') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "es"))) ?>"><span class="lang-xs lang-lbl-full" lang="es"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'nl') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "nl"))) ?>"><span class="lang-xs lang-lbl-full" lang="nl"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'pt') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "pt"))) ?>"><span class="lang-xs lang-lbl-full" lang="pt"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'ru') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "ru"))) ?>"><span class="lang-xs lang-lbl-full" lang="ru"></span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<?php
|
||||
|
|
|
@ -26,8 +26,7 @@ require_once 'inc/lib/Yubico.php';
|
|||
|
||||
// U2F API
|
||||
require_once 'inc/lib/U2F.php';
|
||||
$scheme = isset($_SERVER['HTTPS']) ? "https://" : "http://";
|
||||
$u2f = new u2flib_server\U2F($scheme . $_SERVER['HTTP_HOST']);
|
||||
$u2f = new u2flib_server\U2F('https://' . $_SERVER['SERVER_NAME']);
|
||||
|
||||
// PDO
|
||||
$dsn = "$database_type:host=$database_host;dbname=$database_name";
|
||||
|
@ -70,6 +69,10 @@ if (isset($_COOKIE['language'])) {
|
|||
$_SESSION['mailcow_locale'] = 'pt';
|
||||
setcookie('language', 'pt');
|
||||
break;
|
||||
case "ru":
|
||||
$_SESSION['mailcow_locale'] = 'ru';
|
||||
setcookie('language', 'ru');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($_GET['lang'])) {
|
||||
|
@ -94,6 +97,10 @@ if (isset($_GET['lang'])) {
|
|||
$_SESSION['mailcow_locale'] = 'pt';
|
||||
setcookie('language', 'pt');
|
||||
break;
|
||||
case "ru":
|
||||
$_SESSION['mailcow_locale'] = 'ru';
|
||||
setcookie('language', 'ru');
|
||||
break;
|
||||
}
|
||||
}
|
||||
require_once 'lang/lang.en.php';
|
||||
|
|
|
@ -26,7 +26,7 @@ $FORM_ACTION = "previous";
|
|||
$MC_DKIM_TXTS = "/data/dkim/txt";
|
||||
$MC_DKIM_KEYS = "/data/dkim/keys";
|
||||
|
||||
// Change default language, "en", "pt", "de" or "nl"
|
||||
// Change default language, "en", "es" "pt", "de", "ru" or "nl"
|
||||
$DEFAULT_LANG = "en";
|
||||
|
||||
// Change theme (default: lumen)
|
||||
|
@ -37,4 +37,21 @@ $DEFAULT_THEME = "lumen";
|
|||
|
||||
// Password complexity as regular expression
|
||||
$PASSWD_REGEP = '.{4,}';
|
||||
|
||||
// mailcow Apps - buttons on login screen
|
||||
$MAILCOW_APPS = array(
|
||||
array(
|
||||
'name' => 'SOGo',
|
||||
'link' => '/SOGo/'
|
||||
),
|
||||
// array(
|
||||
// 'name' => 'Roundcube',
|
||||
// 'link' => '/rc/'
|
||||
// ),
|
||||
);
|
||||
|
||||
// Rows until pagination begins
|
||||
$PAGINATION_SIZE = 10;
|
||||
|
||||
|
||||
?>
|
||||
|
|
|
@ -29,7 +29,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
<label class="sr-only" for="login_user"><?=$lang['login']['username'];?></label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><i class="glyphicon glyphicon-user"></i></div>
|
||||
<input name="login_user" autocorrect="off" autocapitalize="none" type="name" id="login_user" class="form-control" placeholder="<?=$lang['login']['username'];?>" required="" autofocus="">
|
||||
<input name="login_user" autocorrect="off" autocapitalize="none" type="text" id="login_user" class="form-control" placeholder="<?=$lang['login']['username'];?>" required="" autofocus="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
@ -51,6 +51,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
<li <?=($_SESSION['mailcow_locale'] == 'es') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "es"))) ?>"><span class="lang-xs lang-lbl-full" lang="es"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'nl') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "nl"))) ?>"><span class="lang-xs lang-lbl-full" lang="nl"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'pt') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "pt"))) ?>"><span class="lang-xs lang-lbl-full" lang="pt"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'ru') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "ru"))) ?>"><span class="lang-xs lang-lbl-full" lang="ru"></span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -63,7 +64,11 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
endif;
|
||||
?>
|
||||
<legend>mailcow Apps</legend>
|
||||
<a href="/SOGo/" role="button" class="btn btn-lg btn-default"><?=$lang['start']['start_sogo'];?></a>
|
||||
<?php
|
||||
foreach ($MAILCOW_APPS as $app) {
|
||||
echo '<a href="' . $app['link'] . '" role="button" class="btn btn-lg btn-default">' . $app['name'] . '</a> ';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,54 +1,256 @@
|
|||
$(document).ready(function() {
|
||||
// Show element counter for tables
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
var rowCountDomainAlias = $('#domainaliastable >tbody >#data').length;
|
||||
var rowCountDomain = $('#domaintable >tbody >#data').length;
|
||||
var rowCountMailbox = $('#mailboxtable >tbody >#data').length;
|
||||
var rowCountAlias = $('#aliastable >tbody >#data').length;
|
||||
var rowCountResource = $('#resourcetable >tbody >#data').length;
|
||||
$("#numRowsDomainAlias").text(rowCountDomainAlias);
|
||||
$("#numRowsDomain").text(rowCountDomain);
|
||||
$("#numRowsMailbox").text(rowCountMailbox);
|
||||
$("#numRowsAlias").text(rowCountAlias);
|
||||
$("#numRowsResource").text(rowCountResource);
|
||||
function humanFileSize(bytes) {
|
||||
if(Math.abs(bytes) < 1024) {
|
||||
return bytes + ' B';
|
||||
}
|
||||
var units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
|
||||
var u = -1;
|
||||
do {
|
||||
bytes /= 1024;
|
||||
++u;
|
||||
} while(Math.abs(bytes) >= 1024 && u < units.length - 1);
|
||||
return bytes.toFixed(1)+' '+units[u];
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
dataType: 'json',
|
||||
url: '/json_api.php?action=domain_table_data',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
alert('Cannot draw domain table');
|
||||
},
|
||||
success: function (data) {
|
||||
$.each(data, function (i, item) {
|
||||
item.aliases = item.aliases_in_domain + " / " + item.max_num_aliases_for_domain;
|
||||
item.mailboxes = item.mboxes_in_domain + " / " + item.max_num_mboxes_for_domain;
|
||||
item.quota = humanFileSize(item.quota_used_in_domain) + " / " + humanFileSize(item.max_quota_for_domain);
|
||||
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
|
||||
if (role == "admin") {
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<a href="/edit.php?domain=' + encodeURI(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
|
||||
'<a href="/delete.php?domain=' + encodeURI(item.domain_name) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
|
||||
'</div>';
|
||||
}
|
||||
else {
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<a href="/edit.php?domain=' + encodeURI(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
|
||||
'</div>';
|
||||
}
|
||||
});
|
||||
$('#domain_table').footable({
|
||||
"columns": [
|
||||
{"sorted": true,"name":"domain_name","title":lang.domain,"style":{"width":"250px"}},
|
||||
{"name":"aliases","title":lang.aliases,"breakpoints":"xs sm"},
|
||||
{"name":"mailboxes","title":lang.mailboxes},
|
||||
{"name":"quota","title":lang.domain_quota},
|
||||
{"name":"max_quota_for_mbox","title":lang.mailbox_quota,"breakpoints":"xs sm"},
|
||||
{"name":"backupmx","filterable": false,"style":{"maxWidth":"120px","width":"120px"},"title":lang.backup_mx,"breakpoints":"xs sm"},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"rows": data,
|
||||
"empty": lang.empty,
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"filtering": {
|
||||
"enabled": true,
|
||||
"position": "left",
|
||||
"placeholder": lang.filter_table
|
||||
},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Filter table function
|
||||
$.fn.extend({
|
||||
filterTable: function(){
|
||||
return this.each(function(){
|
||||
$(this).on('keyup', function(e){
|
||||
var $this = $(this),
|
||||
search = $this.val().toLowerCase(),
|
||||
target = $this.attr('data-filters'),
|
||||
$target = $(target),
|
||||
$rows = $target.find('tbody #data');
|
||||
$target.find('tbody .filterTable_no_results').remove();
|
||||
if(search == '') {
|
||||
$target.find('tbody #no-data').show();
|
||||
$rows.show();
|
||||
} else {
|
||||
$target.find('tbody #no-data').hide();
|
||||
$rows.each(function(){
|
||||
var $this = $(this);
|
||||
$this.text().toLowerCase().indexOf(search) === -1 ? $this.hide() : $this.show();
|
||||
})
|
||||
if($target.find('tbody #data:visible').size() === 0) {
|
||||
var col_count = $target.find('#data').first().find('td').size();
|
||||
var no_results = $('<tr class="filterTable_no_results"><td colspan="100%">-</td></tr>')
|
||||
$target.find('tbody').prepend(no_results);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
$('[data-action="filter"]').filterTable();
|
||||
$('.container').on('click', '.panel-heading span.filter', function(e){
|
||||
var $this = $(this),
|
||||
$panel = $this.parents('.panel');
|
||||
$panel.find('.panel-body').slideToggle("fast");
|
||||
if($this.css('display') != 'none') {
|
||||
$panel.find('.panel-body input').focus();
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
dataType: 'json',
|
||||
url: '/json_api.php?action=mailbox_table_data',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
alert('Cannot draw mailbox table');
|
||||
},
|
||||
success: function (data) {
|
||||
$.each(data, function (i, item) {
|
||||
item.quota = humanFileSize(item.quota_used) + " / " + humanFileSize(item.quota);
|
||||
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
|
||||
if (role == "admin") {
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<a href="/edit.php?mailbox=' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
|
||||
'<a href="/delete.php?mailbox=' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
|
||||
'<a href="/index.php?duallogin=' + encodeURI(item.username) + '" class="btn btn-xs btn-success"><span class="glyphicon glyphicon-user"></span> Login</a>' +
|
||||
'</div>';
|
||||
}
|
||||
else {
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<a href="/edit.php?mailbox=' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
|
||||
'<a href="/delete.php?mailbox=' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
|
||||
'</div>';
|
||||
}
|
||||
item.in_use = '<div class="progress">' +
|
||||
'<div class="progress-bar progress-bar-' + item.percent_class + ' role="progressbar" aria-valuenow="' + item.percent_in_use + '" aria-valuemin="0" aria-valuemax="100" ' +
|
||||
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>';
|
||||
|
||||
});
|
||||
$('#mailbox_table').footable({
|
||||
"columns": [
|
||||
{"sorted": true,"name":"username","title":lang.username,"style":{"width":"250px"}},
|
||||
{"name":"name","title":lang.fname,"breakpoints":"xs sm"},
|
||||
{"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
|
||||
{"name":"quota","title":lang.domain_quota},
|
||||
{"name":"spam_aliases","filterable": false,"title":lang.spam_aliases,"breakpoints":"xs sm"},
|
||||
{"name":"in_use","filterable": false,"type":"html","title":lang.in_use},
|
||||
{"name":"messages","filterable": false,"style":{"width":"90px"},"title":lang.msg_num,"breakpoints":"xs sm"},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","width":"290px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"empty": lang.empty,
|
||||
"rows": data,
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"filtering": {
|
||||
"enabled": true,
|
||||
"position": "left",
|
||||
"placeholder": lang.filter_table
|
||||
},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
dataType: 'json',
|
||||
url: '/json_api.php?action=resource_table_data',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
alert('Cannot draw resource table');
|
||||
},
|
||||
success: function (data) {
|
||||
$.each(data, function (i, item) {
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<a href="/edit.php?resource=' + encodeURI(item.name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
|
||||
'<a href="/delete.php?resource=' + encodeURI(item.name) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
|
||||
'</div>';
|
||||
});
|
||||
$('#resources_table').footable({
|
||||
"columns": [
|
||||
{"sorted": true,"name":"description","title":lang.description,"style":{"width":"250px"}},
|
||||
{"name":"kind","title":lang.kind},
|
||||
{"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
|
||||
{"name":"multiple_bookings","filterable": false,"style":{"maxWidth":"120px","width":"120px"},"title":lang.multiple_bookings,"breakpoints":"xs sm"},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"empty": lang.empty,
|
||||
"rows": data,
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"filtering": {
|
||||
"enabled": true,
|
||||
"position": "left",
|
||||
"placeholder": lang.filter_table
|
||||
},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
dataType: 'json',
|
||||
url: '/json_api.php?action=domain_alias_table_data',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
alert('Cannot draw alias domain table');
|
||||
},
|
||||
success: function (data) {
|
||||
$.each(data, function (i, item) {
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<a href="/edit.php?aliasdomain=' + encodeURI(item.alias_domain) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
|
||||
'<a href="/delete.php?aliasdomain=' + encodeURI(item.alias_domain) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
|
||||
'</div>';
|
||||
});
|
||||
$('#aliasdomain_table').footable({
|
||||
"columns": [
|
||||
{"sorted": true,"name":"alias_domain","title":lang.alias,"style":{"width":"250px"}},
|
||||
{"name":"target_domain","title":lang.target_domain},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"50px","width":"70px"},"title":lang.active},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"empty": lang.empty,
|
||||
"rows": data,
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"filtering": {
|
||||
"enabled": true,
|
||||
"position": "left",
|
||||
"placeholder": lang.filter_table
|
||||
},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
dataType: 'json',
|
||||
url: '/json_api.php?action=alias_table_data',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
alert('Cannot draw alias table');
|
||||
},
|
||||
success: function (data) {
|
||||
$.each(data, function (i, item) {
|
||||
if (item.is_catch_all == 1) {
|
||||
item.address = '<div class="label label-default">Catch-All</div> ' + item.address;
|
||||
}
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<a href="/edit.php?alias=' + encodeURI(item.address) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
|
||||
'<a href="/delete.php?alias=' + encodeURI(item.address) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
|
||||
'</div>';
|
||||
});
|
||||
$('#alias_table').footable({
|
||||
"columns": [
|
||||
{"sorted": true,"name":"address","title":lang.alias,"style":{"width":"250px"}},
|
||||
{"name":"goto","title":lang.target_address},
|
||||
{"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"50px","width":"70px"},"title":lang.active},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"empty": lang.empty,
|
||||
"rows": data,
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"filtering": {
|
||||
"enabled": true,
|
||||
"position": "left",
|
||||
"placeholder": lang.filter_table
|
||||
},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,13 +2,119 @@
|
|||
require_once 'inc/prerequisites.inc.php';
|
||||
error_reporting(E_ALL);
|
||||
if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_username'])) {
|
||||
if ($_GET['action'] && $_GET['object']) {
|
||||
if (isset($_GET['action'])) {
|
||||
$action = $_GET['action'];
|
||||
$object = $_GET['object'];
|
||||
switch ($action) {
|
||||
case "domain_table_data":
|
||||
$domains = mailbox_get_domains();
|
||||
if (!empty($domains)) {
|
||||
foreach ($domains as $domain) {
|
||||
$data[] = mailbox_get_domain_details($domain);
|
||||
}
|
||||
if (!isset($data) || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo '{}';
|
||||
}
|
||||
break;
|
||||
case "mailbox_table_data":
|
||||
$domains = mailbox_get_domains();
|
||||
if (!empty($domains)) {
|
||||
foreach ($domains as $domain) {
|
||||
$mailboxes = mailbox_get_mailboxes($domain);
|
||||
if (!empty($mailboxes)) {
|
||||
foreach ($mailboxes as $mailbox) {
|
||||
$data[] = mailbox_get_mailbox_details($mailbox);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isset($data) || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo '{}';
|
||||
}
|
||||
break;
|
||||
case "resource_table_data":
|
||||
$domains = mailbox_get_domains();
|
||||
if (!empty($domains)) {
|
||||
foreach ($domains as $domain) {
|
||||
$resources = mailbox_get_resources($domain);
|
||||
if (!empty($resources)) {
|
||||
foreach ($resources as $resource) {
|
||||
$data[] = mailbox_get_resource_details($resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isset($data) || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo '{}';
|
||||
}
|
||||
break;
|
||||
case "domain_alias_table_data":
|
||||
$domains = mailbox_get_domains();
|
||||
if (!empty($domains)) {
|
||||
foreach ($domains as $domain) {
|
||||
$alias_domains = mailbox_get_alias_domains($domain);
|
||||
if (!empty($alias_domains)) {
|
||||
foreach ($alias_domains as $alias_domain) {
|
||||
$data[] = mailbox_get_alias_domain_details($alias_domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isset($data) || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo '{}';
|
||||
}
|
||||
break;
|
||||
case "alias_table_data":
|
||||
$domains = array_merge(mailbox_get_domains(), mailbox_get_alias_domains());
|
||||
if (!empty($domains)) {
|
||||
foreach ($domains as $domain) {
|
||||
$aliases = mailbox_get_aliases($domain);
|
||||
if (!empty($aliases)) {
|
||||
foreach ($aliases as $alias) {
|
||||
$data[] = mailbox_get_alias_details($alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isset($data) || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo '{}';
|
||||
}
|
||||
break;
|
||||
case "get_mailbox_details":
|
||||
if (!isset($_GET['object'])) { return false; }
|
||||
$object = $_GET['object'];
|
||||
$data = mailbox_get_mailbox_details($object);
|
||||
if (!$data || empty($data)) {
|
||||
if (!isset($data) || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
|
@ -16,8 +122,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
|||
}
|
||||
break;
|
||||
case "get_domain_details":
|
||||
if (!isset($_GET['object'])) { return false; }
|
||||
$object = $_GET['object'];
|
||||
$data = mailbox_get_domain_details($object);
|
||||
if (!$data || empty($data)) {
|
||||
if (!isset($data) || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
|
@ -25,6 +133,8 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
|||
}
|
||||
break;
|
||||
case "get_u2f_reg_challenge":
|
||||
if (!isset($_GET['object'])) { return false; }
|
||||
$object = $_GET['object'];
|
||||
if (
|
||||
($_SESSION["mailcow_cc_role"] == "admin" || $_SESSION["mailcow_cc_role"] == "domainadmin")
|
||||
&&
|
||||
|
@ -40,6 +150,8 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
|||
}
|
||||
break;
|
||||
case "get_u2f_auth_challenge":
|
||||
if (!isset($_GET['object'])) { return false; }
|
||||
$object = $_GET['object'];
|
||||
if (isset($_SESSION['pending_mailcow_cc_username']) && $_SESSION['pending_mailcow_cc_username'] == $object) {
|
||||
$reqs = json_encode($u2f->getAuthenticateData(get_u2f_registrations($object)));
|
||||
$_SESSION['authReq'] = $reqs;
|
||||
|
|
|
@ -318,6 +318,7 @@ $lang['edit']['resource'] = 'Ressource';
|
|||
$lang['add']['syncjob'] = 'Sync-Job erstellen';
|
||||
$lang['add']['syncjob_hint'] = 'Passwörter werden unverschlüsselt abgelegt!';
|
||||
$lang['add']['hostname'] = 'Servername';
|
||||
$lang['add']['port'] = 'Port';
|
||||
$lang['add']['username'] = 'Benutzername';
|
||||
$lang['add']['enc_method'] = 'Verschlüsselungsmethode';
|
||||
$lang['add']['maxage'] = 'Maximum age of messages that will be polled from remote (0 = ignore age)';
|
||||
|
|
|
@ -322,6 +322,7 @@ $lang['edit']['resource'] = 'Resource';
|
|||
$lang['add']['syncjob'] = 'Add sync job';
|
||||
$lang['add']['syncjob_hint'] = 'Be aware that passwords need to be saved plain-text!';
|
||||
$lang['add']['hostname'] = 'Hostname';
|
||||
$lang['add']['port'] = 'Port';
|
||||
$lang['add']['username'] = 'Username';
|
||||
$lang['add']['enc_method'] = 'Encryption method';
|
||||
$lang['add']['mins_interval'] = 'Polling interval (minutes)';
|
||||
|
@ -387,7 +388,7 @@ $lang['tfa']['api_register'] = 'mailcow uses the Yubico Cloud API. Please get an
|
|||
$lang['tfa']['u2f'] = "U2F authentication";
|
||||
$lang['tfa']['hotp'] = "HOTP authentication";
|
||||
$lang['tfa']['totp'] = "TOTP authentication";
|
||||
$lang['tfa']['none'] = "Deaktiviert";
|
||||
$lang['tfa']['none'] = "Deactivate";
|
||||
$lang['tfa']['delete_tfa'] = "Disable TFA";
|
||||
$lang['tfa']['disable_tfa'] = "Disable TFA until next successful login";
|
||||
$lang['tfa']['confirm_tfa'] = "Please confirm your one-time password in the below field";
|
||||
|
|
|
@ -299,7 +299,7 @@ $lang['add']['password'] = 'Constraseña:';
|
|||
$lang['add']['password_repeat'] = 'Confirmación de contraseña (repetir):';
|
||||
$lang['add']['previous'] = 'Página anterior';
|
||||
$lang['add']['restart_sogo_hint'] = '¡Necesitas reiniciar el contenedor del servicio SOGo antes de agregar un nuevo dominio!';
|
||||
|
||||
$lang['add']['port'] = 'Port';
|
||||
$lang['login']['title'] = 'Inicio de sesión';
|
||||
$lang['login']['administration'] = 'Administración';
|
||||
$lang['login']['administration_details'] = 'Por favor utiliza tu inicio de sesión de Administrador para realizar tareas administrativas.';
|
||||
|
|
|
@ -259,6 +259,7 @@ $lang['edit']['previous'] = 'Vorige pagina';
|
|||
$lang['edit']['unchanged_if_empty'] = 'Leeg laten indien niet veranderd.';
|
||||
$lang['edit']['dont_check_sender_acl'] = 'Geen zenderverificatie uitvoeren voor domein %s.';
|
||||
|
||||
$lang['add']['port'] = 'Port';
|
||||
$lang['add']['title'] = 'Object toevoegen';
|
||||
$lang['add']['domain'] = 'Domein';
|
||||
$lang['add']['active'] = 'Actief';
|
||||
|
|
|
@ -279,6 +279,7 @@ $lang['add']['select_domain'] = 'Selecione um domínio antes';
|
|||
$lang['add']['password'] = 'Senha:';
|
||||
$lang['add']['password_repeat'] = 'Confirmar a senha (repetir):';
|
||||
$lang['add']['previous'] = 'Voltar';
|
||||
$lang['add']['port'] = 'Port';
|
||||
$lang['login']['title'] = 'Entrar';
|
||||
$lang['login']['administration'] = 'Administração';
|
||||
$lang['login']['administration_details'] = 'Utilize o login de Administrador para efetuar tarefas de administração.';
|
||||
|
|
|
@ -0,0 +1,450 @@
|
|||
<?php
|
||||
/*
|
||||
//
|
||||
// Russian language file
|
||||
//
|
||||
*/
|
||||
$lang['footer']['loading'] = "Пожалуйста, подождите...";
|
||||
$lang['header']['restart_sogo'] = "Перезагрузить SOGo";
|
||||
$lang['footer']['restart_sogo'] = "Перезагрузить SOGo";
|
||||
$lang['footer']['restart_now'] = "Перезагрузить сейчас";
|
||||
$lang['footer']['restart_sogo_info'] = "Некоторые операции, например при добавлении домена, требуют перезагрузить SOGo, для вступления в силу внесенных изменений.<br /><br /><b>Важно:</b> Перезагрузка может занять некоторое время, дождитесь ее окончания.";
|
||||
$lang['dkim']['confirm'] = "Вы уверены?";
|
||||
$lang['danger']['dkim_not_found'] = "DKIM ключ не найден";
|
||||
$lang['danger']['dkim_remove_failed'] = "Не удается удалить выбранный DKIM ключ";
|
||||
$lang['danger']['dkim_add_failed'] = "Невозможно добавить данный DKIM ключ";
|
||||
$lang['danger']['dkim_domain_or_sel_invalid'] = "Недопустимый домен";
|
||||
$lang['danger']['dkim_key_length_invalid'] = "Недопустимая длина DKIM ключа";
|
||||
$lang['success']['dkim_removed'] = "DKIM ключ удален";
|
||||
$lang['success']['dkim_added'] = "DKIM ключ сохранен";
|
||||
$lang['danger']['access_denied'] = "Доступ запрещен или неверные данные формы";
|
||||
$lang['danger']['whitelist_from_invalid'] = "Недопустимая запись белого списка";
|
||||
$lang['danger']['domain_invalid'] = "Недопустимое имя домена";
|
||||
$lang['danger']['mailbox_quota_exceeds_domain_quota'] = "Максимальная квота превышает квоту домена";
|
||||
$lang['danger']['object_is_not_numeric'] = "Значение %s не является числовым";
|
||||
$lang['success']['domain_added'] = "Добавлен домен %s";
|
||||
$lang['danger']['alias_empty'] = "Псевдоним адрес не может быть пустым";
|
||||
$lang['danger']['last_key'] = "Невозможно удалить послений ключ";
|
||||
$lang['danger']['goto_empty'] = "Основной адрес не может быть пустым";
|
||||
$lang['danger']['policy_list_from_exists'] = "Запись с указанным именем уже существует";
|
||||
$lang['danger']['policy_list_from_invalid'] = "Запись имеет недопустимый формат";
|
||||
$lang['danger']['whitelist_exists'] = "Указанная запись уже существует в белом списке";
|
||||
$lang['danger']['whitelist_from_invalid'] = "Указанная запись белого списка имеет недопустимый формат";
|
||||
$lang['danger']['alias_invalid'] = "Недопустимый псевдоним адрес";
|
||||
$lang['danger']['goto_invalid'] = "Неверный основной адрес";
|
||||
$lang['danger']['alias_domain_invalid'] = "Недопустимый псевдоним домена";
|
||||
$lang['danger']['target_domain_invalid'] = "Неверный основной домен";
|
||||
$lang['danger']['object_exists'] = "Объект %s уже существует";
|
||||
$lang['danger']['domain_exists'] = "Домен %s уже существует";
|
||||
$lang['danger']['alias_goto_identical'] = "Псевдоним адрес и основной адрес не могут быть одинаковыми";
|
||||
$lang['danger']['aliasd_targetd_identical'] = "Псевдоним домена и основной домен не могут быть одинаковыми";
|
||||
$lang['success']['alias_added'] = "Псевдоним адрес(а) был(и) добавлен(ы)";
|
||||
$lang['success']['alias_modified'] = "Изменения псевдоним адреса сохранены";
|
||||
$lang['success']['aliasd_modified'] = "Изменения псевдоним домена сохранены";
|
||||
$lang['success']['mailbox_modified'] = "Изменения почтового ящика %s сохранены";
|
||||
$lang['success']['resource_modified'] = "Изменения почтового ящика %s сохранены";
|
||||
$lang['success']['object_modified'] = "Изменения объекта %s сохранены";
|
||||
$lang['success']['msg_size_saved'] = "Установлен новый максимальный размер письма";
|
||||
$lang['danger']['aliasd_not_found'] = "Псевдоним домена не найден";
|
||||
$lang['danger']['targetd_not_found'] = "Основной домен не найден";
|
||||
$lang['danger']['aliasd_exists'] = "Псевдоним домена уже существует";
|
||||
$lang['success']['aliasd_added'] = "Добавлен псевдоним домена %s";
|
||||
$lang['success']['aliasd_modified'] = "Изменения псевдоним домена %s сохранены";
|
||||
$lang['success']['domain_modified'] = "Изменения домена %s сохранены";
|
||||
$lang['success']['domain_admin_modified'] = "Изменения администратора домена %s сохранены";
|
||||
$lang['success']['domain_admin_added'] = "Администратор домена %s добавлен";
|
||||
$lang['success']['changes_general'] = "Изменения сохранены";
|
||||
$lang['success']['admin_modified'] = "Изменения администратора сохранены";
|
||||
$lang['danger']['exit_code_not_null'] = "Ошибка: код ошибки %d";
|
||||
$lang['danger']['mailbox_not_available'] = "Почтовый ящик недоступен";
|
||||
$lang['danger']['username_invalid'] = "Нельзя использовать этот логин";
|
||||
$lang['danger']['password_mismatch'] = "Введенные пароли не совпадают";
|
||||
$lang['danger']['password_complexity'] = "Пароль не соответствует требованиям";
|
||||
$lang['danger']['password_empty'] = "Пароль не может быть пустым";
|
||||
$lang['danger']['login_failed'] = "Введен неверный логин или пароль";
|
||||
$lang['danger']['mailbox_invalid'] = "Недопустимое имя почтового ящика";
|
||||
$lang['danger']['description_invalid'] = "Недопустимое описание ресурса";
|
||||
$lang['danger']['resource_invalid'] = "Недопустимое имя ресурса";
|
||||
$lang['danger']['mailbox_invalid_suggest'] = "Имя почтового ящика недействительно, возможно вы имели в виду %s?";
|
||||
$lang['danger']['is_alias'] = "%s уже известен как псевдоним адреса";
|
||||
$lang['danger']['is_alias_or_mailbox'] = "%s уже известен как псевдоним адреса или почтовый ящик";
|
||||
$lang['danger']['is_spam_alias'] = "%s уже известен как спам псевдоним адрес";
|
||||
$lang['danger']['quota_not_0_not_numeric'] = "Размер квоты должен быть больше нуля";
|
||||
$lang['danger']['domain_not_found'] = "Домен не найден";
|
||||
$lang['danger']['max_mailbox_exceeded'] = "Превышено максимальное количество почтовых ящиков (%d из %d)";
|
||||
$lang['danger']['mailbox_quota_exceeded'] = "Квота превышает лимит домена (максимум %d MiB)";
|
||||
$lang['danger']['mailbox_quota_left_exceeded'] = "Недостаточно свободного места (места осталось: %d MiB)";
|
||||
$lang['success']['mailbox_added'] = "Почтовый ящик %s добавлен";
|
||||
$lang['success']['resource_added'] = "Ресурс %s добавлен";
|
||||
$lang['success']['domain_removed'] = "Домен %s удален";
|
||||
$lang['success']['alias_removed'] = "Псевдоним адрес %s удален";
|
||||
$lang['success']['alias_domain_removed'] = "Псевдоним домена %s удален";
|
||||
$lang['success']['domain_admin_removed'] = "Администратор домена %s удален";
|
||||
$lang['success']['mailbox_removed'] = "Почтовый ящик %s удален";
|
||||
$lang['success']['eas_reset'] = "Устройства ActiveSync для пользователя %s были сброшены";
|
||||
$lang['success']['resource_removed'] = "Ресурс %s удален";
|
||||
$lang['danger']['max_quota_in_use'] = "Квота почтового ящика должна быть больше или равна %d MiB";
|
||||
$lang['danger']['domain_quota_m_in_use'] = "Квота домена должна быть больше или равна %s MiB";
|
||||
$lang['danger']['mailboxes_in_use'] = "Максимальный лимит почтовых ящиков должен быть больше или равен %d";
|
||||
$lang['danger']['aliases_in_use'] = "Максимальный лимит псевдоним адресов должен быть больше или равен %d";
|
||||
$lang['danger']['sender_acl_invalid'] = "Недопустимое значение ACL отправителя";
|
||||
$lang['danger']['domain_not_empty'] = "Нельзя удалить непустой домен";
|
||||
$lang['warning']['spam_alias_temp_error'] = "Временная ошибка: Не удается добавить спам псевдоним, пожалуйста, попробуй снова позже";
|
||||
$lang['danger']['spam_alias_max_exceeded'] = "Превышение максимально разрешенных спам псевдонимов";
|
||||
$lang['danger']['validity_missing'] = "Пожалуйста, назначьте срок действия";
|
||||
$lang['user']['on'] = "Вкл.";
|
||||
$lang['user']['off'] = "Выкл.";
|
||||
$lang['user']['messages'] = "писем"; // "123 messages"
|
||||
$lang['user']['in_use'] = "Занято";
|
||||
$lang['user']['user_change_fn'] = "";
|
||||
$lang['user']['user_settings'] = "Настройки пользователя";
|
||||
$lang['user']['mailbox_settings'] = "Настройки почтового ящика";
|
||||
$lang['user']['mailbox_details'] = "Данные почтового ящика";
|
||||
$lang['user']['change_password'] = "Сменить пароль";
|
||||
$lang['user']['new_password'] = "Новый пароль";
|
||||
$lang['user']['save_changes'] = "Сохранить изменения";
|
||||
$lang['user']['password_now'] = "Текущий пароль";
|
||||
$lang['user']['new_password_repeat'] = "Повторить пароль";
|
||||
$lang['user']['new_password_description'] = "Требование: 6 символов, буквы и цифры.";
|
||||
$lang['user']['did_you_know'] = '<b>Вы знали?</b> You can use tags in your email address ("me+<b>privat</b>@example.com") to move messages to a folder automatically (example: "privat").';
|
||||
$lang['user']['spam_aliases'] = "Временные псевдонимы электронной почты";
|
||||
$lang['user']['alias'] = "Псевдоним";
|
||||
$lang['user']['aliases'] = "Псевдонимы";
|
||||
$lang['user']['domain_aliases'] = "Адреса псевдонимов домена";
|
||||
$lang['user']['is_catch_all'] = 'Catch-all for domain/s';
|
||||
$lang['user']['aliases_also_send_as'] = 'Also allowed to send as user';
|
||||
$lang['user']['aliases_send_as_all'] = 'Do not check sender access for the following domain(s) and its alias domains';
|
||||
$lang['user']['alias_create_random'] = "Генерировать случайный псевдоним адрес";
|
||||
$lang['user']['alias_extend_all'] = "Продлить псевдоним адреса на 1 час";
|
||||
$lang['user']['alias_valid_until'] = "Действителен до";
|
||||
$lang['user']['alias_remove_all'] = "Удалить все псевдоним адреса";
|
||||
$lang['user']['alias_time_left'] = "Осталось времени";
|
||||
$lang['user']['alias_full_date'] = "d.m.Y, H:i:s T";
|
||||
$lang['user']['syncjob_full_date'] = "d.m.Y, H:i:s T";
|
||||
$lang['user']['alias_select_validity'] = "Срок действия";
|
||||
$lang['user']['sync_jobs'] = "Синхронизировать задания";
|
||||
$lang['user']['hour'] = "час";
|
||||
$lang['user']['hours'] = "часов";
|
||||
$lang['user']['day'] = "день";
|
||||
$lang['user']['week'] = "неделя";
|
||||
$lang['user']['weeks'] = "недели";
|
||||
$lang['user']['spamfilter'] = "Спам-фильтр";
|
||||
$lang['user']['spamfilter_wl'] = "Белый список";
|
||||
$lang['user']['spamfilter_wl_desc'] = 'Whitelisted email addresses to <b>never</b> classify as spam. Wildcards maybe used.';
|
||||
$lang['user']['spamfilter_bl'] = "Черный список";
|
||||
$lang['user']['spamfilter_bl_desc'] = 'Blacklisted email addresses to <b>always</b> classify as spam and reject. Wildcards maybe used.';
|
||||
$lang['user']['spamfilter_behavior'] = "Рейтинг";
|
||||
$lang['user']['spamfilter_table_rule'] = "Правила";
|
||||
$lang['user']['spamfilter_table_action'] = "Действие";
|
||||
$lang['user']['spamfilter_table_empty'] = "Нет данных для отображения";
|
||||
$lang['user']['spamfilter_table_remove'] = "Удалить";
|
||||
$lang['user']['spamfilter_table_add'] = "Добавить";
|
||||
$lang['user']['spamfilter_default_score'] = "Оценки спама";
|
||||
$lang['user']['spamfilter_green'] = 'Green: this message is not spam';
|
||||
$lang['user']['spamfilter_yellow'] = 'Yellow: this message may be spam, will be tagged as spam and moved to your junk folder';
|
||||
$lang['user']['spamfilter_red'] = 'Red: This message is spam and will be rejected by the server';
|
||||
$lang['user']['spamfilter_default_score'] = "Значения по умолчанию";
|
||||
$lang['user']['spamfilter_hint'] = 'The first value describes the "low spam score", the second represents the "high spam score".';
|
||||
$lang['user']['spamfilter_table_domain_policy'] = "n/a (domain policy)";
|
||||
$lang['user']['tls_policy_warning'] = '<strong>Warning:</strong> If you decide to enforce encrypted mail transfer, you may lose emails.<br />Messages to not satisfy the policy will be bounced with a hard fail by the mail system.';
|
||||
$lang['user']['tls_policy'] = "Настройки TLS шифрования";
|
||||
$lang['user']['tls_enforce_in'] = "Принудительное TLS входящих";
|
||||
$lang['user']['tls_enforce_out'] = "Принудительное TLS исходящих";
|
||||
$lang['user']['no_record'] = "Нет записи";
|
||||
$lang['user']['misc_settings'] = "Другие настройки профиля";
|
||||
$lang['user']['misc_delete_profile'] = "Другие настройки профиля";
|
||||
$lang['user']['tag_handling'] = 'Set handling for tagged mail';
|
||||
$lang['user']['tag_in_subfolder'] = "В подпапке";
|
||||
$lang['user']['tag_in_subject'] = "В теме";
|
||||
$lang['user']['tag_help_explain'] = 'In subfolder: a new subfolder named after the tag will be created below INBOX ("INBOX/Facebook").<br />
|
||||
In subject: the tags name will be prepended to the mails subject, example: "[Facebook] Meine Neuigkeiten".';
|
||||
$lang['user']['tag_help_example'] = 'Example for a tagged email address: ich<b>+Facebook</b>@example.org';
|
||||
$lang['user']['eas_reset'] = "Сбросить кеш ActiveSync устройств";
|
||||
$lang['user']['eas_reset_now'] = "Сбросить сейчас";
|
||||
$lang['user']['eas_reset_help'] = 'In many cases a device cache reset will help to recover a broken ActiveSync profile.<br /><b>Attention:</b> All elements will be redownloaded!';
|
||||
$lang['user']['encryption'] = "Шифрование";
|
||||
$lang['user']['username'] = "Логин";
|
||||
$lang['user']['password'] = "Пароль";
|
||||
$lang['user']['last_run'] = "Последний запуск";
|
||||
$lang['user']['excludes'] = "Исключает";
|
||||
$lang['user']['interval'] = "Интервал";
|
||||
$lang['user']['active'] = "Статус";
|
||||
$lang['user']['action'] = "Действия";
|
||||
$lang['user']['edit'] = "Изменить";
|
||||
$lang['user']['remove'] = "Удалить";
|
||||
$lang['user']['delete_now'] = "Удалить сейчас";
|
||||
$lang['user']['create_syncjob'] = "Создание новой задачи синхронизации";
|
||||
$lang['start']['dashboard'] = '%s - dashboard';
|
||||
$lang['start']['start_rc'] = 'Открыть Roundcube';
|
||||
$lang['start']['start_sogo'] = "Открыть SOGo";
|
||||
$lang['start']['mailcow_apps_detail'] = "Приложения для доступа к электронной почте, календарю, контактам и т.д.";
|
||||
$lang['start']['mailcow_panel'] = 'Start mailcow UI';
|
||||
$lang['start']['mailcow_panel_description'] = "Пользовательский интерфейс mailcow доступен для администраторов и пользователей почтовых ящиков.";
|
||||
$lang['start']['mailcow_panel_detail'] = "<b>Администраторы</b> могут создавать, изменять или удалять почтовые ящики, псевдонимы и другие административные настройки.<br />
|
||||
<b>Пользователи</b> могут изменять пароль, создавать временные псевдонимы (спам псевдонимы), фильтры спама и другие доступные настройки своего профиля.";
|
||||
$lang['start']['recommended_config'] = "Рекомендуемые настройки (без ActiveSync)";
|
||||
$lang['start']['imap_smtp_server'] = 'IMAP- and SMTP server data';
|
||||
$lang['start']['imap_smtp_server_description'] = 'For the best experience we recommend to use <a href="%s" target="_blank"><b>Mozilla Thunderbird</b></a>.';
|
||||
$lang['start']['imap_smtp_server_badge'] = 'Read/Write emails';
|
||||
$lang['start']['imap_smtp_server_auth_info'] = 'Please use your full email address and the PLAIN authentication mechanism.<br />
|
||||
Your login data will be encrypted by the server-side mandatory encryption.';
|
||||
$lang['start']['managesieve'] = 'ManageSieve';
|
||||
$lang['start']['managesieve_badge'] = "Фильтр почты";
|
||||
$lang['start']['managesieve_description'] = 'Please use <b>Mozilla Thunderbird</b> with the <a style="text-decoration:none" target="_blank" href="%s"><b>nightly sieve extension</b></a>.<br />Start Thunderbird, open the add-on settings and drop the newly downloaded xpi file into the opened window.<br />The server name is <b>%s</b>, use port <b>4190</b> if you are asked for. The login data match your email login.';
|
||||
$lang['start']['service'] = "Сервисы";
|
||||
$lang['start']['encryption'] = "Метод шифрования";
|
||||
$lang['start']['help'] = "Справка";
|
||||
$lang['start']['hostname'] = "Имя хоста";
|
||||
$lang['start']['port'] = "Порт";
|
||||
$lang['start']['footer'] = '';
|
||||
$lang['header']['mailcow_settings'] = "Меню";
|
||||
$lang['header']['administration'] = "Административные настройки";
|
||||
$lang['header']['mailboxes'] = "Управление почтовым сервером";
|
||||
$lang['header']['user_settings'] = "Настройки пользователя";
|
||||
$lang['header']['login'] = "Логин";
|
||||
$lang['header']['logged_in_as_logout'] = "Вы вошли как <b>%s</b> (выйти)";
|
||||
$lang['header']['logged_in_as_logout_dual'] = 'Вы вошли как <b>%s <span class="text-info">[%s]</span></b>';
|
||||
$lang['header']['locale'] = "Язык";
|
||||
$lang['mailbox']['domain'] = "Домен";
|
||||
$lang['mailbox']['spam_aliases'] = "Временный псевдоним";
|
||||
$lang['mailbox']['multiple_bookings'] = 'Multiple bookings';
|
||||
$lang['mailbox']['kind'] = "Вид";
|
||||
$lang['mailbox']['description'] = "Описание";
|
||||
$lang['mailbox']['alias'] = "Псевдоним";
|
||||
$lang['mailbox']['resource_name'] = 'Resource name';
|
||||
$lang['mailbox']['aliases'] = "Псевдонимы";
|
||||
$lang['mailbox']['domains'] = "Домены";
|
||||
$lang['mailbox']['mailboxes'] = "Почтовые ящики";
|
||||
$lang['mailbox']['resources'] = "Ресурсы";
|
||||
$lang['mailbox']['mailbox_quota'] = "Макс. квота почтового ящика";
|
||||
$lang['mailbox']['domain_quota'] = "Квота";
|
||||
$lang['mailbox']['active'] = "Статус";
|
||||
$lang['mailbox']['action'] = "Действия";
|
||||
$lang['mailbox']['ratelimit'] = 'Outgoing rate limit/h';
|
||||
$lang['mailbox']['backup_mx'] = "Резервный MX";
|
||||
$lang['mailbox']['domain_aliases'] = "Псевдонимы домена";
|
||||
$lang['mailbox']['target_domain'] = 'Target domain';
|
||||
$lang['mailbox']['target_address'] = "Goto address";
|
||||
$lang['mailbox']['username'] = "Почтовый ящик";
|
||||
$lang['mailbox']['fname'] = "Имя";
|
||||
$lang['mailbox']['filter_table'] = "Поиск";
|
||||
$lang['mailbox']['yes'] = '✔';
|
||||
$lang['mailbox']['no'] = '✘';
|
||||
$lang['mailbox']['quota'] = "Квота";
|
||||
$lang['mailbox']['in_use'] = "Занято";
|
||||
$lang['mailbox']['msg_num'] = "Письма";
|
||||
$lang['mailbox']['remove'] = "Удалить";
|
||||
$lang['mailbox']['edit'] = "Изменить";
|
||||
$lang['mailbox']['archive'] = "Архив";
|
||||
$lang['mailbox']['no_record'] = 'No record for object %s';
|
||||
$lang['mailbox']['no_record_single'] = "Нет записи";
|
||||
$lang['mailbox']['add_domain'] = "Добавить домен";
|
||||
$lang['mailbox']['add_domain_alias'] = "Добавить псевдоним домена";
|
||||
$lang['mailbox']['add_mailbox'] = "Добавить почтовый ящик";
|
||||
$lang['mailbox']['add_resource'] = "Добавить ресурс";
|
||||
$lang['mailbox']['add_alias'] = "Добавить псевдоним";
|
||||
$lang['mailbox']['add_domain_record_first'] = "Сначала добавьте домен";
|
||||
$lang['info']['no_action'] = "Действий не предусмотрено";
|
||||
$lang['delete']['title'] = "Удалить объект";
|
||||
$lang['delete']['remove_domain_warning'] = "<b>Внимание:</b> Вы собираетесь удалить домен <b>%s</b>!";
|
||||
$lang['delete']['remove_syncjob_warning'] = "<b>Внимание:</b> Вы собираетесь удалить задание синхронизации для пользователя <b>%s</b>!";
|
||||
$lang['delete']['remove_domainalias_warning'] = "<b>Внимание:</b> Вы собираетесь удалить псевдоним домена <b>%s</b>!";
|
||||
$lang['delete']['remove_domainadmin_warning'] = "<b>Внимание:</b> Вы собираетесь удалить администратора домена <b>%s</b>!";
|
||||
$lang['delete']['remove_alias_warning'] = "<b>Внимание:</b> Вы собираетесь удалить псевдоним адрес <b>%s</b>!";
|
||||
$lang['delete']['remove_mailbox_warning'] = "<b>Внимание:</b> Вы собираетесь удалить почтовый ящик <b>%s</b>!";
|
||||
$lang['delete']['remove_mailbox_details'] = "Почтовый ящик будет <b>очищен навсегда</b>!";
|
||||
$lang['delete']['remove_resource_warning'] = "<b>Внимание:</b> Вы собираетесь удалить ресурс <b>%s</b>!";
|
||||
$lang['delete']['remove_resource_details'] = "Ресурс будет <b>очищен навсегда</b>!";
|
||||
$lang['delete']['remove_domain_details'] = "Это также удаляет псевдонимы доменов.<br /><br /><b>Домен должен быть пустым для удаления.</b>";
|
||||
$lang['delete']['remove_syncjob_details'] = "Объекты из этого задания синхронизации больше не будут извлекаться с удаленного сервера.";
|
||||
$lang['delete']['remove_alias_details'] = "Пользователи больше не смогут получать почту или отправлять почту с этого адреса.</b>";
|
||||
$lang['delete']['remove_button'] = "Удалить";
|
||||
$lang['delete']['previous'] = "Предыдущая страница";
|
||||
$lang['edit']['syncjob'] = "Изменить задание синхронизации";
|
||||
$lang['edit']['save'] = "Сохранить";
|
||||
$lang['edit']['username'] = "Логин";
|
||||
$lang['edit']['hostname'] = "Имя хоста";
|
||||
$lang['edit']['encryption'] = "Шифрование";
|
||||
$lang['edit']['maxage'] = 'Maximum age of messages in days that will be polled from remote<br /><small>(0 = ignore age)</small>';
|
||||
$lang['edit']['subfolder2'] = 'Sync into subfolder on destination<br /><small>(empty = do not use subfolder)</small>';
|
||||
$lang['edit']['mins_interval'] = "Интервал (минуты)";
|
||||
$lang['edit']['exclude'] = 'Exclude objects (regex)';
|
||||
$lang['edit']['save'] = "Сохранить";
|
||||
$lang['edit']['archive'] = "Доступ к архиву";
|
||||
$lang['edit']['max_mailboxes'] = "Максимум почтовых ящиков";
|
||||
$lang['edit']['title'] = "Добавить объект";
|
||||
$lang['edit']['target_address'] = 'Goto address/es <small>(comma-separated)</small>';
|
||||
$lang['edit']['active'] = "Активность";
|
||||
$lang['edit']['target_domain'] = "Основной домен";
|
||||
$lang['edit']['password'] = "Пароль";
|
||||
$lang['edit']['ratelimit'] = 'Outgoing rate limit/h';
|
||||
$lang['danger']['ratelimt_less_one'] = 'Outgoing rate limit/h must not be less than 1';
|
||||
$lang['edit']['password_repeat'] = "Повторить пароль";
|
||||
$lang['edit']['domain_admin'] = "Редактирование администратора домена";
|
||||
$lang['edit']['domain'] = "Изменить домен";
|
||||
$lang['edit']['alias_domain'] = "Псевдоним домена";
|
||||
$lang['edit']['edit_alias_domain'] = "Изменить псевдоним домена";
|
||||
$lang['edit']['domains'] = "Домены";
|
||||
$lang['edit']['destroy'] = "Ручной ввод данных";
|
||||
$lang['edit']['alias'] = "Изменить псевдоним";
|
||||
$lang['edit']['mailbox'] = "Редактирование почтового ящика";
|
||||
$lang['edit']['description'] = "Описание";
|
||||
$lang['edit']['max_aliases'] = "Максимум псевдонимов";
|
||||
$lang['edit']['max_quota'] = "Максимальная квота на почтовый ящик (MiB)";
|
||||
$lang['edit']['domain_quota'] = "Квота домена";
|
||||
$lang['edit']['backup_mx_options'] = "Настройки резервного MX";
|
||||
$lang['edit']['relay_domain'] = 'Relay domain';
|
||||
$lang['edit']['relay_all'] = 'Relay all recipients';
|
||||
$lang['edit']['dkim_signature'] = "DKIM подпись";
|
||||
$lang['edit']['dkim_record_info'] = '<small>Please add a TXT record with the given value to your DNS settings.</small>';
|
||||
$lang['edit']['relay_all_info'] = '<small>If you choose <b>not</b> to relay all recipients, you will need to add a ("blind") mailbox for every single recipient that should be relayed.</small>';
|
||||
$lang['edit']['full_name'] = "Имя";
|
||||
$lang['edit']['quota_mb'] = "Квота (MiB)";
|
||||
$lang['edit']['sender_acl'] = "Отправлять письма от <small>(выбрать какой адрес(а) можно использовать в качестве отправителя)</small>";
|
||||
$lang['edit']['sender_acl_info'] = "Псевдонимы не могут быть отменены";
|
||||
$lang['edit']['dkim_txt_name'] = "Имя TXT записи";
|
||||
$lang['edit']['dkim_txt_value'] = "Значение TXT записи";
|
||||
$lang['edit']['previous'] = "Предыдущая страница";
|
||||
$lang['edit']['unchanged_if_empty'] = "Если без изменений, оставьте поле пустым";
|
||||
$lang['edit']['dont_check_sender_acl'] = "Disable sender check for domain %s + alias domains";
|
||||
$lang['edit']['multiple_bookings'] = 'Multiple bookings';
|
||||
$lang['edit']['kind'] = "Вид";
|
||||
$lang['edit']['resource'] = "Ресурс";
|
||||
$lang['add']['syncjob'] = "Добавить задание синхронизации";
|
||||
$lang['add']['syncjob_hint'] = "Помните, что пароли должны быть сохранены как обычный текст!";
|
||||
$lang['add']['hostname'] = "Имя хоста";
|
||||
$lang['add']['port'] = "Порт";
|
||||
$lang['add']['username'] = "Логин";
|
||||
$lang['add']['enc_method'] = "Метод шифрования";
|
||||
$lang['add']['mins_interval'] = "Интервал опроса (в минутах)";
|
||||
$lang['add']['maxage'] = 'Maximum age of messages that will be polled from remote (0 = ignore age)';
|
||||
$lang['add']['subfolder2'] = "Синхронизировать в подпапку по назначению";
|
||||
$lang['add']['exclude'] = "Исключить объекты (regex)";
|
||||
$lang['add']['delete2duplicates'] = "Удалить дубликаты в получателях";
|
||||
$lang['add']['title'] = "Добавить объект";
|
||||
$lang['add']['domain'] = "Домен";
|
||||
$lang['add']['active'] = "Активный";
|
||||
$lang['add']['multiple_bookings'] = 'Multiple bookings';
|
||||
$lang['add']['save'] = "Сохранить изменения";
|
||||
$lang['add']['description'] = "Описание";
|
||||
$lang['add']['max_aliases'] = "Максимум псевдонимов";
|
||||
$lang['add']['resource_name'] = "Имя ресурса";
|
||||
$lang['add']['max_mailboxes'] = "Максимум почтовых ящиков";
|
||||
$lang['add']['mailbox_quota_m'] = "Максимальная квота на почтовый ящик (MiB)";
|
||||
$lang['add']['domain_quota_m'] = "Общая квота домена (MiB)";
|
||||
$lang['add']['backup_mx_options'] = "Настройки резервного MX";
|
||||
$lang['add']['relay_all'] = "Relay all recipients";
|
||||
$lang['add']['relay_domain'] = "Relay this domain";
|
||||
$lang['add']['relay_all_info'] = '<small>If you choose <b>not</b> to relay all recipients, you will need to add a ("blind") mailbox for every single recipient that should be relayed.</small>';
|
||||
$lang['add']['alias'] = "Псевдоним(ы)";
|
||||
$lang['add']['alias_spf_fail'] = '<b>Заметка:</b> If your chosen destination address is an external mailbox, the <b>receiving mailserver</b> may reject your message due to an SPF failure.</a>';
|
||||
$lang['add']['alias_address'] = "Псевдоним адрес(а)";
|
||||
$lang['add']['alias_address_info'] = '<small>Full email address/es or @example.com, to catch all messages for a domain (comma-separated). <b>mailcow domains only</b>.</small>';
|
||||
$lang['add']['alias_domain_info'] = '<small>Только допустимые доменные имена (через запятую).</small>';
|
||||
$lang['add']['target_address'] = "Основной адрес";
|
||||
$lang['add']['target_address_info'] = "<small>Адрес(а) электронной почты (через запятую).</small>";
|
||||
$lang['add']['alias_domain'] = "Псевдоним домена";
|
||||
$lang['add']['select'] = "Пожалуйста, выберите...";
|
||||
$lang['add']['target_domain'] = "Основной домен";
|
||||
$lang['add']['mailbox'] = "Почтовый ящик";
|
||||
$lang['add']['resource'] = "Ресурс";
|
||||
$lang['add']['kind'] = "Вид";
|
||||
$lang['add']['mailbox_username'] = "Адрес электронной почты, без @example.com";
|
||||
$lang['add']['full_name'] = "Имя";
|
||||
$lang['add']['quota_mb'] = "Квота (MiB):";
|
||||
$lang['add']['select_domain'] = "Выберите основной домен";
|
||||
$lang['add']['password'] = "Пароль";
|
||||
$lang['add']['password_repeat'] = "Повторить пароль";
|
||||
$lang['add']['previous'] = "Предыдущая страница";
|
||||
$lang['add']['restart_sogo_hint'] = "После добавления нового домена потребуется перезагрузить SOGo!";
|
||||
$lang['login']['title'] = "Логин";
|
||||
$lang['login']['administration'] = "Администрирование";
|
||||
$lang['login']['administration_details'] = "Пожалуйста, используйте вашу учетную запись администратора для выполнения административных задач";
|
||||
$lang['login']['user_settings'] = "Настройки пользователя";
|
||||
$lang['login']['user_settings_details'] = "Пользователи почтовых ящиков могут использовать пользовательский интерфейс mailcow, чтобы изменять свой пароль, создавать временные псевдонимы (псевдонимы спама), настраивать поведение спам-фильтра или импортировать сообщения с удаленного сервера IMAP.";
|
||||
$lang['login']['username'] = "Логин";
|
||||
$lang['login']['password'] = "Пароль";
|
||||
$lang['login']['reset_password'] = "Сбросить пароль";
|
||||
$lang['login']['login'] = "Войти";
|
||||
$lang['login']['previous'] = "Предыдущая страница";
|
||||
$lang['login']['delayed'] = 'Login was delayed by %s seconds.';
|
||||
$lang['tfa']['tfa'] = "Двухфакторная проверка подлинности";
|
||||
$lang['tfa']['set_tfa'] = "Использовать двухфакторный метод проверки подлинности";
|
||||
$lang['tfa']['yubi_otp'] = "Yubico OTP аутентификация";
|
||||
$lang['tfa']['key_id'] = "Идентификатор для вашего YubiKey";
|
||||
$lang['tfa']['api_register'] = 'mailcow использует Yubico Cloud API. Пожалуйста, получите ключ API для вашего ключа <a href="https://upgrade.yubico.com/getapikey/" target="_blank">тут</a>.';
|
||||
$lang['tfa']['u2f'] = "U2F проверка подлинности";
|
||||
$lang['tfa']['hotp'] = "HOTP проверка подлинности";
|
||||
$lang['tfa']['totp'] = "TOTP проверка подлинности";
|
||||
$lang['tfa']['none'] = "Отключен";
|
||||
$lang['tfa']['delete_tfa'] = "Отключить TFA";
|
||||
$lang['tfa']['disable_tfa'] = "Отключить TFA до следующего удачного входа";
|
||||
$lang['tfa']['confirm_tfa'] = "Пожалуйста, подтвердите свой одноразовый пароль в поле ниже";
|
||||
$lang['tfa']['confirm'] = "Подтвердить";
|
||||
$lang['tfa']['otp'] = "Одноразовый пароль";
|
||||
$lang['tfa']['trash_login'] = "Некорректный логин";
|
||||
$lang['tfa']['select'] = "Пожалуйста выберите";
|
||||
$lang['tfa']['waiting_usb_auth'] = "<i>Ждем USB-устройства...</i><br /><br />Пожалуйста, нажмите кнопку на USB-устройстве U2F.";
|
||||
$lang['tfa']['waiting_usb_register'] = "<i>Ждем USB-устройства...</i><br /><br />Пожалуйста, введите свой пароль выше и подтвердите регистрацию U2F, нажав кнопку на USB-устройстве U2F.";
|
||||
$lang['admin']['search_domain_da'] = "Поиск домена";
|
||||
$lang['admin']['restrictions'] = "Настройки Postfix";
|
||||
$lang['admin']['rr'] = "Настройки получателя";
|
||||
$lang['admin']['sr'] = "Настройки отправителя";
|
||||
$lang['admin']['reset_defaults'] = "Сброс по умолчанию";
|
||||
$lang['admin']['sr'] = "Настройки отправителя";
|
||||
$lang['admin']['r_inactive'] = "Неактивные элементы";
|
||||
$lang['admin']['r_active'] = "Активные элементы";
|
||||
$lang['admin']['r_info'] = "Выделенные серым цветом элементы в списке активных элементов заблокированы от перемещения в список неактивных элементов, так как их отключение может непредсказуемо повлиять на работу mailcow. Unknown restrictions will be set in order of appearance anyway. <br />Вы можете добавить новые элементы в <code>inc/vars.local.inc.php</code>, что бы иметь возможно переключать их.";
|
||||
$lang['admin']['public_folders'] = "Общие папки";
|
||||
$lang['admin']['public_folders_text'] = 'A namespace "Public" is created. Below\'s public folder name indicates the name of the first auto-created mailbox within this namespace.';
|
||||
$lang['admin']['public_folder_name'] = "Имя папки";
|
||||
$lang['admin']['public_folder_enable'] = "Включение общих папок";
|
||||
$lang['admin']['public_folder_enable_text'] = "Отключение этой опции не приведет к удалению почты из общих папок";
|
||||
$lang['admin']['public_folder_pusf'] = 'Enable per-user seen flag';
|
||||
$lang['admin']['public_folder_pusf_text'] = 'A "per-user seen flag"-enabled system will not mark a mail as read for User B, when User A has seen it, but User B did not.';
|
||||
$lang['admin']['privacy'] = "Конфедоциальность";
|
||||
$lang['admin']['privacy_text'] = 'This option enables a PCRE table to remove "User-Agent", "X-Enigmail", "X-Mailer", "X-Originating-IP" and replaces "Received: from" headers with localhost/127.0.0.1.';
|
||||
$lang['admin']['privacy_anon_mail'] = "Анонимизировать исходящую почту";
|
||||
$lang['admin']['dkim_txt_name'] = "Имя TXT записи";
|
||||
$lang['admin']['dkim_txt_value'] = "Значение TXT записи";
|
||||
$lang['admin']['dkim_key_length'] = "Длина ключа";
|
||||
$lang['admin']['dkim_key_valid'] = "Ключ действителен";
|
||||
$lang['admin']['dkim_key_unused'] = "Неиспользованный ключ";
|
||||
$lang['admin']['dkim_key_missing'] = "Ключ отсутствует";
|
||||
$lang['admin']['dkim_key_hint'] = "Селектор для DKIM ключей <code>dkim</code>. Подсказка: При добавлении записи на DNS-сервере, укажите Имя TXT записи <code>dkim._domainkey</code>.";
|
||||
$lang['admin']['previous'] = "Предыдущая страница";
|
||||
$lang['admin']['quota_mb'] = "Квота (MiB)";
|
||||
$lang['admin']['sender_acl'] = "Разрешить отправлять письма от";
|
||||
$lang['admin']['msg_size'] = "Максимальный размер письма";
|
||||
$lang['admin']['msg_size_limit'] = "Сейчас максимальный размер письма";
|
||||
$lang['admin']['msg_size_limit_details'] = "Применение нового ограничения перезагрузит Postfix и веб-сервер";
|
||||
$lang['admin']['save'] = "Сохранить изменения";
|
||||
$lang['admin']['maintenance'] = "Техническое обслуживание и информация";
|
||||
$lang['admin']['sys_info'] = "Системная информация";
|
||||
$lang['admin']['dkim_add_key'] = "Добавить DKIM ключ";
|
||||
$lang['admin']['dkim_keys'] = "DKIM ключи";
|
||||
$lang['admin']['add'] = "Добавить";
|
||||
$lang['admin']['configuration'] = "Конфигурации";
|
||||
$lang['admin']['password'] = "Пароль";
|
||||
$lang['admin']['password_repeat'] = "Повторить пароль";
|
||||
$lang['admin']['active'] = "Активный";
|
||||
$lang['admin']['action'] = "Действия";
|
||||
$lang['admin']['add_domain_admin'] = "Добавить администратора домена";
|
||||
$lang['admin']['admin_domains'] = "Домен";
|
||||
$lang['admin']['domain_admins'] = "Администраторы домена";
|
||||
$lang['admin']['username'] = "Логин";
|
||||
$lang['admin']['edit'] = "Изменить";
|
||||
$lang['admin']['remove'] = "Удалить";
|
||||
$lang['admin']['save'] = "Сохранить изменения";
|
||||
$lang['admin']['admin'] = "Администратор";
|
||||
$lang['admin']['admin_details'] = "Изменить данные администратора";
|
||||
$lang['admin']['unchanged_if_empty'] = "Если без изменений, оставьте поле пустым";
|
||||
$lang['admin']['yes'] = '✔';
|
||||
$lang['admin']['no'] = '✘';
|
||||
$lang['admin']['access'] = "Права доступа";
|
||||
$lang['admin']['invalid_max_msg_size'] = "Неверно указан максимальный размер письма";
|
||||
$lang['admin']['site_not_found'] = "Не удается найти конфигурацию mailcow";
|
||||
$lang['admin']['public_folder_empty'] = "Имя общей папки не может быть пустым";
|
||||
$lang['admin']['set_rr_failed'] = "Не установить настройки Postfix";
|
||||
$lang['admin']['no_record'] = "Нет записей";
|
||||
?>
|
|
@ -5,16 +5,34 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
|||
require_once "inc/header.inc.php";
|
||||
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
?>
|
||||
<style>
|
||||
table.footable>tbody>tr.footable-empty>td {
|
||||
font-size:15px !important;
|
||||
font-style:italic;
|
||||
}
|
||||
.pagination a {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.panel panel-default {
|
||||
overflow: visible !important;
|
||||
}
|
||||
.table-responsive {
|
||||
overflow: visible !important;
|
||||
}
|
||||
.footer-add-item {
|
||||
text-align:center;
|
||||
font-style: italic;
|
||||
display:block;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['domains'];?> <span class="badge" id="numRowsDomain"></span></h3>
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['domains'];?></h3>
|
||||
<div class="pull-right">
|
||||
<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
|
||||
<i class="glyphicon glyphicon-filter"></i>
|
||||
</span>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin"):
|
||||
?>
|
||||
|
@ -24,93 +42,10 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<input type="text" class="form-control" id="domaintable-filter" data-action="filter" data-filters="#domaintable" placeholder="Filter" />
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="domaintable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 86px;"><?=$lang['mailbox']['domain'];?></th>
|
||||
<th class="sort-table" style="min-width: 81px;"><?=$lang['mailbox']['aliases'];?></th>
|
||||
<th class="sort-table" style="min-width: 99px;"><?=$lang['mailbox']['mailboxes'];?></th>
|
||||
<th class="sort-table" style="min-width: 172px;"><?=$lang['mailbox']['mailbox_quota'];?></th>
|
||||
<th class="sort-table" style="min-width: 117px;"><?=$lang['mailbox']['domain_quota'];?></th>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin"):
|
||||
?>
|
||||
<th class="sort-table" style="min-width: 105px;"><?=$lang['mailbox']['backup_mx'];?></th>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$domains = mailbox_get_domains();
|
||||
if (!empty($domains)):
|
||||
foreach ($domains as $domain):
|
||||
$domaindata = mailbox_get_domain_details($domain);
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars($domaindata['domain_name']);?></td>
|
||||
<td><?=$domaindata['aliases_in_domain'];?> / <?=$domaindata['max_num_aliases_for_domain'];?></td>
|
||||
<td><?=$domaindata['mboxes_in_domain'];?> / <?=$domaindata['max_num_mboxes_for_domain'];?></td>
|
||||
<td><?=formatBytes($domaindata['max_quota_for_mbox']);?></td>
|
||||
<td><?=formatBytes($domaindata['quota_used_in_domain'], 2);?> / <?=formatBytes($domaindata['max_quota_for_domain'], 2);?></td>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin"):
|
||||
?>
|
||||
<td><?=$domaindata['backupmx'];?></td>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<td><?=$domaindata['active'];?></td>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin"):
|
||||
?>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?domain=<?=urlencode($domaindata['domain_name']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?domain=<?=urlencode($domaindata['domain_name']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?domain=<?=urlencode($domaindata['domain_name']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endif;
|
||||
endforeach;
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="999" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['no_record_single'];?></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</tbody>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin"):
|
||||
?>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
<td colspan="999" style="text-align: center; font-style: normal; border-top: 1px solid #e7e7e7;">
|
||||
<a href="/add.php?domain"><?=$lang['mailbox']['add_domain'];?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table id="domain_table" class="table table-striped"></table>
|
||||
</div>
|
||||
<span class="footer-add-item"><a href="/add.php?domain"><?=$lang['mailbox']['add_domain'];?></a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -118,91 +53,15 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['mailboxes'];?> <span class="badge" id="numRowsMailbox"></span></h3>
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['mailboxes'];?></h3>
|
||||
<div class="pull-right">
|
||||
<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
|
||||
<i class="glyphicon glyphicon-filter"></i>
|
||||
</span>
|
||||
<a href="/add.php?mailbox"><span class="glyphicon glyphicon-plus"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<input type="text" class="form-control" id="mailboxtable-filter" data-action="filter" data-filters="#mailboxtable" placeholder="Filter" />
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="mailboxtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 100px;"><?=$lang['mailbox']['username'];?></th>
|
||||
<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['fname'];?></th>
|
||||
<th class="sort-table" style="min-width: 86px;"><?=$lang['mailbox']['domain'];?></th>
|
||||
<th class="sort-table" style="min-width: 75px;"><?=$lang['mailbox']['quota'];?></th>
|
||||
<th class="sort-table" style="min-width: 75px;"><?=$lang['mailbox']['spam_aliases'];?></th>
|
||||
<th class="sort-table" style="min-width: 99px;"><?=$lang['mailbox']['in_use'];?></th>
|
||||
<th class="sort-table" style="min-width: 100px;"><?=$lang['mailbox']['msg_num'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
if (!empty($domains)) {
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
$mailboxes = mailbox_get_mailboxes($domain);
|
||||
if (!empty($mailboxes)) {
|
||||
foreach ($mailboxes as $mailbox) {
|
||||
$mailboxdata = mailbox_get_mailbox_details($mailbox);
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=($mailboxdata['is_relayed'] == "0") ? htmlspecialchars($mailboxdata['username']) : '<span data-toggle="tooltip" title="Relayed"><i class="glyphicon glyphicon-forward"></i>' . htmlspecialchars($mailboxdata['username']) . '</span>';?></td>
|
||||
<td><?=htmlspecialchars($mailboxdata['name'], ENT_QUOTES, 'UTF-8');?></td>
|
||||
<td><?=htmlspecialchars($mailboxdata['domain']);?></td>
|
||||
<td><?=formatBytes($mailboxdata['quota_used'], 2);?> / <?=formatBytes($mailboxdata['quota'], 2);?></td>
|
||||
<td><?=$mailboxdata['spam_aliases'];?></td>
|
||||
<td style="min-width:120px;">
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-<?=$mailboxdata['percent_class'];?>" role="progressbar" aria-valuenow="<?=$mailboxdata['percent_in_use'];?>" aria-valuemin="0" aria-valuemax="100" style="min-width:2em;width: <?=$mailboxdata['percent_in_use'];?>%;">
|
||||
<?=$mailboxdata['percent_in_use'];?>%
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td><?=$mailboxdata['messages'];?></td>
|
||||
<td><?=$mailboxdata['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?mailbox=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?mailbox=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
<?php if ($_SESSION['mailcow_cc_role'] == "admin"): ?>
|
||||
<a href="/index.php?duallogin=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-success"><span class="glyphicon glyphicon-user"></span> Login</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="999" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="999" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['add_domain_record_first'];?></td></tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
<td colspan="999" style="text-align: center; border-top: 1px solid #e7e7e7;">
|
||||
<a href="/add.php?mailbox"><?=$lang['mailbox']['add_mailbox'];?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table id="mailbox_table" class="table table-striped"></table>
|
||||
</div>
|
||||
<span class="footer-add-item"><a href="/add.php?mailbox"><?=$lang['mailbox']['add_mailbox'];?></a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -210,150 +69,30 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['resources'];?> <span class="badge" id="numRowsResource"></span></h3>
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['resources'];?></h3>
|
||||
<div class="pull-right">
|
||||
<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
|
||||
<i class="glyphicon glyphicon-filter"></i>
|
||||
</span>
|
||||
<a href="/add.php?resource"><span class="glyphicon glyphicon-plus"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<input type="text" class="form-control" id="resourcetable-filter" data-action="filter" data-filters="#resourcetable" placeholder="Filter" />
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="resourcetable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['description'];?></th>
|
||||
<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['kind'];?></th>
|
||||
<th class="sort-table" style="min-width: 86px;"><?=$lang['mailbox']['domain'];?></th>
|
||||
<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['multiple_bookings'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
if (!empty($domains)) {
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
$resources = mailbox_get_resources($domain);
|
||||
if (!empty($resources)) {
|
||||
foreach ($resources as $resource) {
|
||||
$resourcedata = mailbox_get_resource_details($resource);
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars($resourcedata['description'], ENT_QUOTES, 'UTF-8');?></td>
|
||||
<td><?=$resourcedata['kind'];?></td>
|
||||
<td><?=htmlspecialchars($resourcedata['domain']);?></td>
|
||||
<td><?=$resourcedata['multiple_bookings'];?></td>
|
||||
<td><?=$resourcedata['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?resource=<?=urlencode($resourcedata['name']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?resource=<?=urlencode($resourcedata['name']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="999" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="999" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['add_domain_record_first'];?></td></tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
<td colspan="999" style="text-align: center; border-top: 1px solid #e7e7e7;">
|
||||
<a href="/add.php?resource"><?=$lang['mailbox']['add_resource'];?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table id="resources_table" class="table table-striped"></table>
|
||||
</div>
|
||||
<span class="footer-add-item"><a href="/add.php?resource"><?=$lang['mailbox']['add_resource'];?></a></span> </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['domain_aliases'];?> <span class="badge" id="numRowsDomainAlias"></span></h3>
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['domain_aliases'];?></h3>
|
||||
<div class="pull-right">
|
||||
<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
|
||||
<i class="glyphicon glyphicon-filter"></i>
|
||||
</span>
|
||||
<a href="/add.php?aliasdomain"><span class="glyphicon glyphicon-plus"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<input type="text" class="form-control" id="domainaliastable-filter" data-action="filter" data-filters="#domainaliastable" placeholder="Filter" />
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="domainaliastable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 67px;"><?=$lang['mailbox']['alias'];?></th>
|
||||
<th class="sort-table" style="min-width: 127px;"><?=$lang['mailbox']['target_domain'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
if (!empty($domains)) {
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
$alias_domains = mailbox_get_alias_domains($domain);
|
||||
if (!empty($alias_domains)) {
|
||||
foreach ($alias_domains as $alias_domain) {
|
||||
$aliasdomaindata = mailbox_get_alias_domain_details($alias_domain);
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars($aliasdomaindata['alias_domain']);?></td>
|
||||
<td><?=htmlspecialchars($aliasdomaindata['target_domain']);?></td>
|
||||
<td><?=$aliasdomaindata['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?aliasdomain=<?=urlencode($aliasdomaindata['alias_domain']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?aliasdomain=<?=urlencode($aliasdomaindata['alias_domain']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="999" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="999" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['add_domain_record_first'];?></td></tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
<td colspan="999" style="text-align: center; border-top: 1px solid #e7e7e7;">
|
||||
<a href="/add.php?aliasdomain"><?=$lang['mailbox']['add_domain_alias'];?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table id="aliasdomain_table" class="table table-striped"></table>
|
||||
</div>
|
||||
<span class="footer-add-item"><a href="/add.php?aliasdomain"><?=$lang['mailbox']['add_domain_alias'];?></a></span> </div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -361,87 +100,28 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['aliases'];?> <span class="badge" id="numRowsAlias"></span></h3>
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['aliases'];?></h3>
|
||||
<div class="pull-right">
|
||||
<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
|
||||
<i class="glyphicon glyphicon-filter"></i>
|
||||
</span>
|
||||
<a href="/add.php?alias"><span class="glyphicon glyphicon-plus"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<input type="text" class="form-control" id="aliastable-filter" data-action="filter" data-filters="#aliastable" placeholder="Filter" />
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="aliastable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 67px;"><?=$lang['mailbox']['alias'];?></th>
|
||||
<th class="sort-table" style="min-width: 119px;"><?=$lang['mailbox']['target_address'];?></th>
|
||||
<th class="sort-table" style="min-width: 86px;"><?=$lang['mailbox']['domain'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
if (!empty($domains)) {
|
||||
foreach (array_merge(mailbox_get_domains(), mailbox_get_alias_domains()) as $domain) {
|
||||
$aliases = mailbox_get_aliases($domain);
|
||||
if (!empty($aliases)) {
|
||||
foreach ($aliases as $alias) {
|
||||
$aliasdata = mailbox_get_alias_details($alias);
|
||||
?>
|
||||
<tr id="data">
|
||||
<td>
|
||||
<?= ($aliasdata['is_catch_all'] == "1") ? '<span class="glyphicon glyphicon-pushpin" aria-hidden="true"></span> Catch-all ' . htmlspecialchars($aliasdata['address']) : htmlspecialchars($aliasdata['address']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
foreach(explode(",", $aliasdata['goto']) as $goto) {
|
||||
echo nl2br(htmlspecialchars($goto.PHP_EOL));
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td><?=htmlspecialchars($aliasdata['domain']);?></td>
|
||||
<td><?=$aliasdata['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?alias=<?=urlencode($aliasdata['address']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?alias=<?=urlencode($aliasdata['address']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="999" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="999" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['add_domain_record_first'];?></td></tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
<td colspan="999" style="text-align: center; border-top: 1px solid #e7e7e7;">
|
||||
<a href="/add.php?alias"><?=$lang['mailbox']['add_alias'];?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table id="alias_table" class="table table-striped"></table>
|
||||
</div>
|
||||
<span class="footer-add-item"><a href="/add.php?alias"><?=$lang['mailbox']['add_alias'];?></a></span> </div>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
<script src="js/sorttable.js"></script>
|
||||
<script type='text/javascript'>
|
||||
<?php
|
||||
$lang_mailbox = json_encode($lang['mailbox']);
|
||||
echo "var lang = ". $lang_mailbox . ";\n";
|
||||
$role = ($_SESSION['mailcow_cc_role'] == "admin") ? 'admin' : 'domainadmin';
|
||||
echo "var role = '". $role . "';\n";
|
||||
echo "var pagination_size = '". $PAGINATION_SIZE . "';\n";
|
||||
?>
|
||||
</script>
|
||||
<script src="js/footable.min.js"></script>
|
||||
<script src="js/mailbox.js"></script>
|
||||
<?php
|
||||
require_once("inc/footer.inc.php");
|
||||
|
|
|
@ -3,8 +3,7 @@ require_once('inc/prerequisites.inc.php');
|
|||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
|
||||
|
||||
$scheme = isset($_SERVER['HTTPS']) ? "https://" : "http://";
|
||||
$u2f = new u2flib_server\U2F($scheme . $_SERVER['HTTP_HOST']);
|
||||
$u2f = new u2flib_server\U2F('https://' . $_SERVER['SERVER_NAME']);
|
||||
|
||||
function getRegs($username) {
|
||||
global $pdo;
|
||||
|
@ -154,4 +153,4 @@ Action: <br />
|
|||
}
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -17,7 +17,7 @@ This is just an example of how to obtain certificates with certbot. There are se
|
|||
wget https://dl.eff.org/certbot-auto -O /usr/local/sbin/certbot && chmod +x /usr/local/sbin/certbot
|
||||
```
|
||||
|
||||
2\. Make sure you set `HTTP_BIND=0.0.0.0` in `mailcow.conf` or setup a reverse proxy to enable connections to port 80. If you changed HTTP_BIND, then restart Nginx:
|
||||
2\. Make sure you set `HTTP_BIND=0.0.0.0` and `HTTP_PORT=80` in `mailcow.conf` or setup a reverse proxy to enable connections to port 80. If you changed HTTP_BIND, then restart Nginx:
|
||||
``` bash
|
||||
docker-compose restart nginx-mailcow
|
||||
```
|
||||
|
@ -64,6 +64,8 @@ docker-compose exec rspamd-mailcow rspamadm pw
|
|||
enable_password = "myhash";
|
||||
```
|
||||
|
||||
You can use `password = "myhash";` instead of `enable_password` to disable write-access in the web UI.
|
||||
|
||||
3\. Restart rspamd:
|
||||
```
|
||||
docker-compose restart rspamd-mailcow
|
||||
|
@ -83,6 +85,7 @@ HTTP_PORT=8080
|
|||
HTTPS_PORT=127.0.0.1
|
||||
HTTPS_PORT=8443
|
||||
```
|
||||
** IMPORTANT: Do not use port 8081 **
|
||||
|
||||
Recreate affected containers by running `docker-compose up -d`.
|
||||
|
||||
|
|
|
@ -35,8 +35,9 @@ nano mailcow.conf
|
|||
```
|
||||
If you plan to use a reverse proxy, you can, for example, bind HTTPS to 127.0.0.1 on port 8443 and HTTP to 127.0.0.1 on port 8080.
|
||||
|
||||
5\. Run the composer file. It will pull images and build containers.
|
||||
5\. Pull the images and run the composer file. The paramter `-d` will start mailcow: dockerized detached:
|
||||
```
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
|
@ -48,8 +49,10 @@ The database will be initialized right after a connection to MySQL can be establ
|
|||
|
||||
## Update mailcow
|
||||
|
||||
There is no update routine. You need to refresh your pulled repository clone and apply your local changes (if any). Actually there are many ways to merge local changes. Here is one to
|
||||
stash all local changes, pull changes from the remote master branch and apply your stash on top of it. You will most likely see warnings about non-commited changes; you can ignore them:
|
||||
There is no update routine. You need to refresh your pulled repository clone and apply your local changes (if any). Actually there are many ways to merge local changes.
|
||||
|
||||
### Step 1, method 1
|
||||
Stash all local changes, pull changes from the remote master branch and apply your stash on top of it. You will most likely see warnings about non-commited changes; you can ignore them:
|
||||
|
||||
```
|
||||
# Stash local changes
|
||||
|
@ -60,6 +63,49 @@ git pull
|
|||
git stash pop
|
||||
```
|
||||
|
||||
### Step 1, method 2
|
||||
Fetch new data from GitHub, commit changes and merge remote repository:
|
||||
|
||||
```
|
||||
# Get updates/changes
|
||||
git fetch
|
||||
# Add all changed files to local clone
|
||||
git add -A
|
||||
# Commit changes, ignore git complaining about username and mail address
|
||||
git commit -m "Local config aat $(date)"
|
||||
# Merge changes
|
||||
git merge
|
||||
```
|
||||
|
||||
If git complains about conflicts, solve them! Example:
|
||||
```
|
||||
CONFLICT (content): Merge conflict in data/web/index.php
|
||||
```
|
||||
|
||||
Open `data/web/index.php`, solve the conflict, close the file and run `git add -A` + `git commit -m "Solved conflict"`.
|
||||
|
||||
### Step 1, method 3
|
||||
|
||||
Thanks to fabreg @ GitHub!
|
||||
|
||||
In case both methods do not work (for many reason like you're unable to fix the CONFLICTS or any other reasons) you can simply start all over again.
|
||||
|
||||
Keep in mind that all local changes _to configuration files_ will be lost. However, your volumes will not be removed.
|
||||
|
||||
- Copy mailcow.conf somewhere outside the mailcow-dockerized directory
|
||||
- Stop and remove mailcow containers: `docker-compose down`
|
||||
- Delete the directory or rename it
|
||||
- Clone the remote repository again (`git clone https://github.com/andryyy/mailcow-dockerized && cd mailcow-dockerized`). **Pay attention** to this step - the folder must have the same name of the previous one!
|
||||
- Copy back your previous `mailcow.conf` into the mailcow-dockerizd folder
|
||||
|
||||
If you forgot to stop Docker before deleting the cloned directoy, you can use the following commands:
|
||||
```
|
||||
docker stop $(docker ps -a -q)
|
||||
docker rm $(docker ps -a -q)
|
||||
```
|
||||
|
||||
### Step 2
|
||||
|
||||
Pull new images (if any) and recreate changed containers:
|
||||
|
||||
```
|
||||
|
@ -67,6 +113,7 @@ docker-compose pull
|
|||
docker-compose up -d --remove-orphans
|
||||
```
|
||||
|
||||
### Step 3
|
||||
Clean-up dangling (unused) images and volumes:
|
||||
|
||||
```
|
||||
|
|
713
docs/u_and_e.md
713
docs/u_and_e.md
|
@ -1,3 +1,20 @@
|
|||
## mailcow UI configuration
|
||||
|
||||
Several configuration parameters of the mailcow UI can be changed by creating a file `data/web/inc/vars.local.inc.php` which overrides defaults settings found in `data/web/inc/vars.inc.php`.
|
||||
|
||||
The local configuration file is persistent over updates of mailcow. Try not to change values inside `data/web/inc/vars.inc.php`, but use them as template for the local override.
|
||||
|
||||
mailcow UI configuration parameters can be to...
|
||||
|
||||
- ...change the default language*
|
||||
- ...change the default bootstrap theme
|
||||
- ...set a password complexity regex
|
||||
- ...add mailcow app buttons to the login screen
|
||||
- ...set a pagination trigger
|
||||
- ...set action after submitting forms (stay in form, return to previous page)
|
||||
|
||||
\* To change SOGos default language, you will need to edit `data/conf/sogo/sogo.conf` and replace "English" by your preferred language.
|
||||
|
||||
## Anonymize headers
|
||||
|
||||
Save as `data/conf/postfix/mailcow_anonymize_headers.pcre`:
|
||||
|
@ -17,263 +34,245 @@ Add this to `data/conf/postfix/main.cf`:
|
|||
smtp_header_checks = pcre:/opt/postfix/conf/mailcow_anonymize_headers.pcre
|
||||
```
|
||||
|
||||
## Backup and restore maildir (simple tar file)
|
||||
|
||||
### Backup
|
||||
|
||||
This line backups the vmail directory to a file backup_vmail.tar.gz in the mailcow root directory:
|
||||
```
|
||||
cd /path/to/mailcow-dockerized
|
||||
source mailcow.conf
|
||||
DATE=$(date +"%Y%m%d_%H%M%S")
|
||||
docker run --rm -it -v $(docker inspect --format '{{ range .Mounts }}{{ if eq .Destination "/var/vmail" }}{{ .Name }}{{ end }}{{ end }}' $(docker-compose ps -q dovecot-mailcow)):/vmail -v ${PWD}:/backup debian:jessie tar cvfz /backup/backup_vmail.tar.gz /vmail
|
||||
```
|
||||
|
||||
You can change the path by adjusting ${PWD} (which equals to the current directory) to any path you have write-access to.
|
||||
Set the filename `backup_vmail.tar.gz` to any custom name, but leave the path as it is. Example: `[...] tar cvfz /backup/my_own_filename_.tar.gz`
|
||||
|
||||
### Restore
|
||||
```
|
||||
cd /path/to/mailcow-dockerized
|
||||
source mailcow.conf
|
||||
DATE=$(date +"%Y%m%d_%H%M%S")
|
||||
docker run --rm -it -v $(docker inspect --format '{{ range .Mounts }}{{ if eq .Destination "/var/vmail" }}{{ .Name }}{{ end }}{{ end }}' $(docker-compose ps -q dovecot-mailcow)):/vmail -v ${PWD}:/backup debian:jessie tar xvfz /backup/backup_vmail.tar.gz
|
||||
```
|
||||
|
||||
## Backup and restore maildir (simple tar file)
|
||||
|
||||
### Backup
|
||||
|
||||
This line backups the vmail directory to a file backup_vmail.tar.gz in the mailcow root directory:
|
||||
```
|
||||
cd /path/to/mailcow-dockerized
|
||||
source mailcow.conf
|
||||
DATE=$(date +"%Y%m%d_%H%M%S")
|
||||
docker run --rm -it -v $(docker inspect --format '{{ range .Mounts }}{{ if eq .Destination "/var/vmail" }}{{ .Name }}{{ end }}{{ end }}' $(docker-compose ps -q dovecot-mailcow)):/vmail -v ${PWD}:/backup debian:jessie tar cvfz /backup/backup_vmail.tar.gz /vmail
|
||||
```
|
||||
|
||||
You can change the path by adjusting ${PWD} (which equals to the current directory) to any path you have write-access to.
|
||||
Set the filename `backup_vmail.tar.gz` to any custom name, but leave the path as it is. Example: `[...] tar cvfz /backup/my_own_filename_.tar.gz`
|
||||
|
||||
### Restore
|
||||
```
|
||||
cd /path/to/mailcow-dockerized
|
||||
source mailcow.conf
|
||||
DATE=$(date +"%Y%m%d_%H%M%S")
|
||||
docker run --rm -it -v $(docker inspect --format '{{ range .Mounts }}{{ if eq .Destination "/var/vmail" }}{{ .Name }}{{ end }}{{ end }}' $(docker-compose ps -q dovecot-mailcow)):/vmail -v ${PWD}:/backup debian:jessie tar xvfz /backup/backup_vmail.tar.gz
|
||||
```
|
||||
|
||||
## Docker Compose Bash completion
|
||||
|
||||
For the tab-tab... :-)
|
||||
|
||||
```
|
||||
curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose
|
||||
```
|
||||
## Black and Whitelist
|
||||
|
||||
Edit a domain as (domain) administrator to add an item to the filter table.
|
||||
|
||||
Beware that a mailbox user can login to mailcow and override a domain policy filter item.
|
||||
|
||||
## Change default language
|
||||
For the tab-tab... :-)
|
||||
|
||||
Change `data/conf/sogo/sogo.conf` and replace "English" by your preferred language.
|
||||
```
|
||||
curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose
|
||||
```
|
||||
## Black and Whitelist
|
||||
|
||||
Edit a domain as (domain) administrator to add an item to the filter table.
|
||||
|
||||
Beware that a mailbox user can login to mailcow and override a domain policy filter item.
|
||||
|
||||
## Customize Dockerfiles
|
||||
|
||||
Make your changes in `data/Dockerfiles/$service` and build the image locally:
|
||||
|
||||
Create a file `data/web/inc/vars.local.inc.php` and add "DEFAULT_LANG" with either "en", "pt", "de" or "nl":
|
||||
```
|
||||
<?php
|
||||
$DEFAULT_LANG = "de";
|
||||
docker build data/Dockerfiles/service -t andryyy/mailcow-dockerized:$service
|
||||
```
|
||||
## Change UI theme
|
||||
|
||||
mailcow uses [Bootstrap](http://getbootstrap.com/), a HTML, CSS, and JS framework.
|
||||
|
||||
Open or create the file `data/web/inc/vars.local.inc.php` and change `DEFAULT_THEME` to either cerulean, cosmo, custom, cyborg, darkly, flatly, journal, paper, readable, sandstone, simplex, slate, spacelab, superhero, united or yeti (see https://bootswatch.com/):
|
||||
```
|
||||
<?php
|
||||
$DEFAULT_THEME = "paper";
|
||||
```
|
||||
## Customize Dockerfiles
|
||||
|
||||
Make your changes in `data/Dockerfiles/$service` and build the image locally:
|
||||
|
||||
```
|
||||
docker build data/Dockerfiles/service -t andryyy/mailcow-dockerized:$service
|
||||
```
|
||||
|
||||
Now auto-recreate modified containers:
|
||||
|
||||
```
|
||||
docker-compose up -d
|
||||
|
||||
Now auto-recreate modified containers:
|
||||
|
||||
```
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Disable sender addresses verification
|
||||
|
||||
This option is not best-practice and should only be implemented when there is no other option available to archive whatever you are trying to do.
|
||||
|
||||
Simply create a file `data/conf/postfix/check_sender_access` and enter the following content:
|
||||
```
|
||||
user-to-allow-everything@example.com OK
|
||||
```
|
||||
|
||||
Open `data/conf/postfix/main.cf` and find `smtpd_sender_restrictions`. Prepend `check_sasl_access hash:/opt/postfix/conf/check_sender_access` like this:
|
||||
```
|
||||
smtpd_sender_restrictions = check_sasl_access hash:/opt/postfix/conf/check_sender_access reject_authenticated_sender [...]
|
||||
```
|
||||
|
||||
Run postmap on check_sasl_access:
|
||||
|
||||
```
|
||||
docker-compose exec postfix-mailcow postmap /opt/postfix/conf/check_sasl_access
|
||||
```
|
||||
|
||||
Restart the Postfix container.
|
||||
|
||||
## Install Roundcube
|
||||
|
||||
Download Roundcube 1.3.x (beta at the time of Feb 2017) to the web htdocs directory and extract it (here `rc/`):
|
||||
```
|
||||
cd data/web/rc
|
||||
wget -O - https://github.com/roundcube/roundcubemail/releases/download/1.3-beta/roundcubemail-1.3-beta-complete.tar.gz | tar xfvz -
|
||||
# Change folder name
|
||||
mv roundcubemail-1.3* rc
|
||||
# Change permissions
|
||||
chown -R root: rc/
|
||||
```
|
||||
|
||||
Create a file `data/web/rc/config/config.inc.php` with the following content.
|
||||
|
||||
**Change the `des_key` parameter to a random value.** It is used to temporarily store your IMAP password.
|
||||
|
||||
```
|
||||
<?php
|
||||
error_reporting(0);
|
||||
if (!file_exists('/tmp/mime.types')) {
|
||||
file_put_contents("/tmp/mime.types", fopen("http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types", 'r'));
|
||||
}
|
||||
$config = array();
|
||||
$config['db_dsnw'] = 'mysql://' . getenv('DBUSER') . ':' . getenv('DBPASS') . '@mysql/' . getenv('DBNAME');
|
||||
$config['default_host'] = 'tls://dovecot';
|
||||
$config['default_port'] = '143';
|
||||
$config['smtp_server'] = 'tls://postfix';
|
||||
$config['smtp_port'] = 587;
|
||||
$config['smtp_user'] = '%u';
|
||||
$config['smtp_pass'] = '%p';
|
||||
$config['support_url'] = '';
|
||||
$config['product_name'] = 'Roundcube Webmail';
|
||||
$config['des_key'] = 'rcmail-!24ByteDESkey*Str';
|
||||
$config['log_dir'] = '/dev/null';
|
||||
$config['temp_dir'] = '/tmp';
|
||||
$config['plugins'] = array(
|
||||
'archive',
|
||||
);
|
||||
$config['skin'] = 'larry';
|
||||
$config['mime_types'] = '/tmp/mime.types';
|
||||
$config['imap_conn_options'] = array(
|
||||
'ssl' => array('verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true)
|
||||
);
|
||||
$config['enable_installer'] = false;
|
||||
$config['smtp_conn_options'] = array(
|
||||
'ssl' => array('verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true)
|
||||
);
|
||||
```
|
||||
|
||||
Point your browser to `https://myserver/rc/installer` and follow the instructions.
|
||||
Initialize the database and leave the installer.
|
||||
|
||||
**Delete the directory `data/web/rc/installer` after a successful installation!**
|
||||
|
||||
### Enable change password function in Roundcube
|
||||
|
||||
Open `data/web/rc/config/config.inc.php` and enable the password plugin:
|
||||
|
||||
```
|
||||
...
|
||||
$config['plugins'] = array(
|
||||
'archive',
|
||||
'password',
|
||||
);
|
||||
...
|
||||
```
|
||||
|
||||
Open `data/web/rc/plugins/password/password.php`, search for `case 'ssha':` and add above:
|
||||
|
||||
```
|
||||
case 'ssha256':
|
||||
$salt = rcube_utils::random_bytes(8);
|
||||
$crypted = base64_encode( hash('sha256', $password . $salt, TRUE ) . $salt );
|
||||
$prefix = '{SSHA256}';
|
||||
break;
|
||||
```
|
||||
|
||||
Open `data/web/rc/plugins/password/config.inc.php` and change the following parameters (or add them at the bottom of that file):
|
||||
|
||||
```
|
||||
$config['password_driver'] = 'sql';
|
||||
$config['password_algorithm'] = 'ssha256';
|
||||
$config['password_algorithm_prefix'] = '{SSHA256}';
|
||||
$config['password_query'] = "UPDATE mailbox SET password = %P WHERE username = %u";
|
||||
|
||||
This option is not best-practice and should only be implemented when there is no other option available to archive whatever you are trying to do.
|
||||
|
||||
Simply create a file `data/conf/postfix/check_sasl_access` and enter the following content. This user must exist in your installation and needs to authenticate before sending mail.
|
||||
```
|
||||
user-to-allow-everything@example.com OK
|
||||
```
|
||||
|
||||
## MySQL
|
||||
|
||||
### Connect
|
||||
```
|
||||
source mailcow.conf
|
||||
docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME}
|
||||
```
|
||||
|
||||
### Backup
|
||||
```
|
||||
cd /path/to/mailcow-dockerized
|
||||
source mailcow.conf
|
||||
DATE=$(date +"%Y%m%d_%H%M%S")
|
||||
docker-compose exec mysql-mailcow mysqldump --default-character-set=utf8mb4 -u${DBUSER} -p${DBPASS} ${DBNAME} > backup_${DBNAME}_${DATE}.sql
|
||||
```
|
||||
|
||||
### Restore
|
||||
```
|
||||
cd /path/to/mailcow-dockerized
|
||||
source mailcow.conf
|
||||
docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} < backup_file.sql
|
||||
Open `data/conf/postfix/main.cf` and find `smtpd_sender_restrictions`. Prepend `check_sasl_access hash:/opt/postfix/conf/check_sasl_access` like this:
|
||||
```
|
||||
smtpd_sender_restrictions = check_sasl_access hash:/opt/postfix/conf/check_sasl_access reject_authenticated_sender_login_mismatch [...]
|
||||
```
|
||||
|
||||
Run postmap on check_sasl_access:
|
||||
|
||||
```
|
||||
docker-compose exec postfix-mailcow postmap /opt/postfix/conf/check_sasl_access
|
||||
```
|
||||
|
||||
Restart the Postfix container.
|
||||
|
||||
## Install Roundcube
|
||||
|
||||
Download Roundcube 1.3.x (beta at the time of Feb 2017) to the web htdocs directory and extract it (here `rc/`):
|
||||
```
|
||||
cd data/web/rc
|
||||
wget -O - https://github.com/roundcube/roundcubemail/releases/download/1.3-beta/roundcubemail-1.3-beta-complete.tar.gz | tar xfvz -
|
||||
# Change folder name
|
||||
mv roundcubemail-1.3* rc
|
||||
# Change permissions
|
||||
chown -R root: rc/
|
||||
```
|
||||
|
||||
Create a file `data/web/rc/config/config.inc.php` with the following content.
|
||||
|
||||
**Change the `des_key` parameter to a random value.** It is used to temporarily store your IMAP password.
|
||||
|
||||
```
|
||||
<?php
|
||||
error_reporting(0);
|
||||
if (!file_exists('/tmp/mime.types')) {
|
||||
file_put_contents("/tmp/mime.types", fopen("http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types", 'r'));
|
||||
}
|
||||
$config = array();
|
||||
$config['db_dsnw'] = 'mysql://' . getenv('DBUSER') . ':' . getenv('DBPASS') . '@mysql/' . getenv('DBNAME');
|
||||
$config['default_host'] = 'tls://dovecot';
|
||||
$config['default_port'] = '143';
|
||||
$config['smtp_server'] = 'tls://postfix';
|
||||
$config['smtp_port'] = 587;
|
||||
$config['smtp_user'] = '%u';
|
||||
$config['smtp_pass'] = '%p';
|
||||
$config['support_url'] = '';
|
||||
$config['product_name'] = 'Roundcube Webmail';
|
||||
$config['des_key'] = 'rcmail-!24ByteDESkey*Str';
|
||||
$config['log_dir'] = '/dev/null';
|
||||
$config['temp_dir'] = '/tmp';
|
||||
$config['plugins'] = array(
|
||||
'archive',
|
||||
);
|
||||
$config['skin'] = 'larry';
|
||||
$config['mime_types'] = '/tmp/mime.types';
|
||||
$config['imap_conn_options'] = array(
|
||||
'ssl' => array('verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true)
|
||||
);
|
||||
$config['enable_installer'] = false;
|
||||
$config['smtp_conn_options'] = array(
|
||||
'ssl' => array('verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true)
|
||||
);
|
||||
```
|
||||
|
||||
Point your browser to `https://myserver/rc/installer` and follow the instructions.
|
||||
Initialize the database and leave the installer.
|
||||
|
||||
**Delete the directory `data/web/rc/installer` after a successful installation!**
|
||||
|
||||
### Enable change password function in Roundcube
|
||||
|
||||
Open `data/web/rc/config/config.inc.php` and enable the password plugin:
|
||||
|
||||
```
|
||||
...
|
||||
$config['plugins'] = array(
|
||||
'archive',
|
||||
'password',
|
||||
);
|
||||
...
|
||||
```
|
||||
|
||||
Open `data/web/rc/plugins/password/password.php`, search for `case 'ssha':` and add above:
|
||||
|
||||
```
|
||||
case 'ssha256':
|
||||
$salt = rcube_utils::random_bytes(8);
|
||||
$crypted = base64_encode( hash('sha256', $password . $salt, TRUE ) . $salt );
|
||||
$prefix = '{SSHA256}';
|
||||
break;
|
||||
```
|
||||
|
||||
Open `data/web/rc/plugins/password/config.inc.php` and change the following parameters (or add them at the bottom of that file):
|
||||
|
||||
```
|
||||
$config['password_driver'] = 'sql';
|
||||
$config['password_algorithm'] = 'ssha256';
|
||||
$config['password_algorithm_prefix'] = '{SSHA256}';
|
||||
$config['password_query'] = "UPDATE mailbox SET password = %P WHERE username = %u";
|
||||
```
|
||||
|
||||
## MySQL
|
||||
|
||||
### Connect
|
||||
```
|
||||
source mailcow.conf
|
||||
docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME}
|
||||
```
|
||||
|
||||
### Backup
|
||||
```
|
||||
cd /path/to/mailcow-dockerized
|
||||
source mailcow.conf
|
||||
DATE=$(date +"%Y%m%d_%H%M%S")
|
||||
docker-compose exec mysql-mailcow mysqldump --default-character-set=utf8mb4 -u${DBUSER} -p${DBPASS} ${DBNAME} > backup_${DBNAME}_${DATE}.sql
|
||||
```
|
||||
|
||||
### Restore
|
||||
```
|
||||
cd /path/to/mailcow-dockerized
|
||||
source mailcow.conf
|
||||
docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} < backup_file.sql
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
You can use `docker-compose logs $service-name` for all containers.
|
||||
|
||||
Run `docker-compose logs` for all logs at once.
|
||||
|
||||
Follow the log output by running docker-compose with `logs -f`.
|
||||
|
||||
## Redirect port 80 to 443
|
||||
|
||||
Since February the 28th 2017 mailcow does come with port 80 and 443 enabled.
|
||||
|
||||
Open `mailcow.conf` and set `HTTP_BIND=0.0.0.0`.
|
||||
|
||||
Open `data/conf/nginx/site.conf` and add a new "catch-all" site at the top of that file:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
```
|
||||
|
||||
Restart the stack, changed containers will be updated:
|
||||
|
||||
|
||||
You can use `docker-compose logs $service-name` for all containers.
|
||||
|
||||
Run `docker-compose logs` for all logs at once.
|
||||
|
||||
Follow the log output by running docker-compose with `logs -f`.
|
||||
|
||||
## Redirect port 80 to 443
|
||||
|
||||
Since February the 28th 2017 mailcow does come with port 80 and 443 enabled.
|
||||
|
||||
Open `mailcow.conf` and set `HTTP_BIND=0.0.0.0`.
|
||||
|
||||
Open `data/conf/nginx/site.conf` and add a new "catch-all" site at the top of that file:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80 default_server;
|
||||
include /etc/nginx/conf.d/server_name.active;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
```
|
||||
|
||||
Restart the stack, changed containers will be updated:
|
||||
|
||||
`docker-compose up -d`
|
||||
|
||||
## Redis
|
||||
|
||||
### Client
|
||||
|
||||
```
|
||||
docker-compose exec redis-mailcow redis-cli
|
||||
|
||||
### Client
|
||||
|
||||
```
|
||||
docker-compose exec redis-mailcow redis-cli
|
||||
```
|
||||
|
||||
## Remove persistent data
|
||||
|
||||
- Remove volume `mysql-vol-1` to remove all MySQL data.
|
||||
- Remove volume `redis-vol-1` to remove all Redis data.
|
||||
- Remove volume `vmail-vol-1` to remove all contents of `/var/vmail` mounted to `dovecot-mailcow`.
|
||||
- Remove volume `dkim-vol-1` to remove all DKIM keys.
|
||||
- Remove volume `rspamd-vol-1` to remove all Rspamd data.
|
||||
|
||||
|
||||
- Remove volume `mysql-vol-1` to remove all MySQL data.
|
||||
- Remove volume `redis-vol-1` to remove all Redis data.
|
||||
- Remove volume `vmail-vol-1` to remove all contents of `/var/vmail` mounted to `dovecot-mailcow`.
|
||||
- Remove volume `dkim-vol-1` to remove all DKIM keys.
|
||||
- Remove volume `rspamd-vol-1` to remove all Rspamd data.
|
||||
|
||||
Running `docker-compose down -v` will **destroy all mailcow: dockerized volumes** and delete any related containers.
|
||||
|
||||
## Reset admin password
|
||||
Reset mailcow admin to `admin:moohoo`:
|
||||
|
||||
1\. Drop admin table
|
||||
```
|
||||
source mailcow.conf
|
||||
docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP TABLE admin;"
|
||||
```
|
||||
|
||||
2\. Open mailcow UI to auto-init the db
|
||||
|
||||
## Rspamd
|
||||
Reset mailcow admin to `admin:moohoo`:
|
||||
|
||||
1\. Drop admin table
|
||||
```
|
||||
source mailcow.conf
|
||||
docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP TABLE admin;"
|
||||
```
|
||||
|
||||
2\. Open mailcow UI to auto-init the db
|
||||
|
||||
## Rspamd
|
||||
|
||||
### Learn spam and ham
|
||||
|
||||
|
@ -286,128 +285,144 @@ The bayes statistics are written to Redis as keys `BAYES_HAM` and `BAYES_SPAM`.
|
|||
|
||||
You can also use Rspamd's web ui to learn ham and/or spam.
|
||||
|
||||
### Learn ham or spam from existing directory
|
||||
|
||||
You can use a one-liner to learn mail in plain-text (uncompressed) format:
|
||||
```
|
||||
# Ham
|
||||
for file in /my/folder/cur/*; do docker exec -i $(docker-compose ps -q rspamd-mailcow) rspamc learn_ham < $file; done
|
||||
# Spam
|
||||
for file in /my/folder/.Junk/cur/*; do docker exec -i $(docker-compose ps -q rspamd-mailcow) rspamc learn_spam < $file; done
|
||||
```
|
||||
|
||||
Consider attaching a local folder as new volume to `rspamd-mailcow` in `docker-compose.yml` and learn given files inside the container. This can be used as workaround to parse compressed data with zcat. Example:
|
||||
|
||||
```
|
||||
for file in /data/old_mail/.Junk/cur/*; do rspamc learn_spam < zcat $file; done
|
||||
```
|
||||
|
||||
### CLI tools
|
||||
|
||||
```
|
||||
docker-compose exec rspamd-mailcow rspamc --help
|
||||
docker-compose exec rspamd-mailcow rspamadm --help
|
||||
```
|
||||
|
||||
```
|
||||
docker-compose exec rspamd-mailcow rspamc --help
|
||||
docker-compose exec rspamd-mailcow rspamadm --help
|
||||
```
|
||||
|
||||
See [Rspamd documentation](https://rspamd.com/doc/index.html)
|
||||
|
||||
## Adjust service configurations
|
||||
## Adjust service configurations
|
||||
|
||||
The most important configuration files are mounted from the host into the related containers:
|
||||
|
||||
```
|
||||
data/conf
|
||||
├── bind9
|
||||
│ └── named.conf
|
||||
├── dovecot
|
||||
│ ├── dovecot.conf
|
||||
│ ├── dovecot-master.passwd
|
||||
│ ├── sieve_after
|
||||
│ └── sql
|
||||
│ ├── dovecot-dict-sql.conf
|
||||
│ └── dovecot-mysql.conf
|
||||
├── mysql
|
||||
│ └── my.cnf
|
||||
├── nginx
|
||||
│ ├── dynmaps.conf
|
||||
│ ├── site.conf
|
||||
│ └── templates
|
||||
│ ├── listen_plain.template
|
||||
│ ├── listen_ssl.template
|
||||
│ └── server_name.template
|
||||
├── pdns
|
||||
│ ├── pdns_custom.lua
|
||||
│ └── recursor.conf
|
||||
├── postfix
|
||||
│ ├── main.cf
|
||||
│ ├── master.cf
|
||||
│ ├── postscreen_access.cidr
|
||||
│ ├── smtp_dsn_filter
|
||||
│ └── sql
|
||||
│ ├── mysql_relay_recipient_maps.cf
|
||||
│ ├── mysql_tls_enforce_in_policy.cf
|
||||
│ ├── mysql_tls_enforce_out_policy.cf
|
||||
│ ├── mysql_virtual_alias_domain_catchall_maps.cf
|
||||
│ ├── mysql_virtual_alias_domain_maps.cf
|
||||
│ ├── mysql_virtual_alias_maps.cf
|
||||
│ ├── mysql_virtual_domains_maps.cf
|
||||
│ ├── mysql_virtual_mailbox_maps.cf
|
||||
│ ├── mysql_virtual_relay_domain_maps.cf
|
||||
│ ├── mysql_virtual_sender_acl.cf
|
||||
│ └── mysql_virtual_spamalias_maps.cf
|
||||
├── rmilter
|
||||
│ └── rmilter.conf
|
||||
├── rspamd
|
||||
│ ├── dynmaps
|
||||
│ │ ├── authoritative.php
|
||||
│ │ ├── settings.php
|
||||
│ │ ├── tags.php
|
||||
│ │ └── vars.inc.php -> ../../../web/inc/vars.inc.php
|
||||
│ ├── local.d
|
||||
│ │ ├── dkim.conf
|
||||
│ │ ├── metrics.conf
|
||||
│ │ ├── options.inc
|
||||
│ │ ├── redis.conf
|
||||
│ │ ├── rspamd.conf.local
|
||||
│ │ └── statistic.conf
|
||||
│ ├── lua
|
||||
│ │ └── rspamd.local.lua
|
||||
│ └── override.d
|
||||
│ ├── logging.inc
|
||||
│ ├── worker-controller.inc
|
||||
│ └── worker-normal.inc
|
||||
└── sogo
|
||||
├── sieve.creds
|
||||
└── sogo.conf
|
||||
|
||||
```
|
||||
|
||||
Just change the according configuration file on the host and restart the related service:
|
||||
```
|
||||
docker-compose restart service-mailcow
|
||||
```
|
||||
|
||||
## Tagging
|
||||
|
||||
Mailbox users can tag their mail address like in `me+facebook@example.org` and choose between to setups to handle this tag:
|
||||
|
||||
1\. Move this message to a subfolder "facebook" (will be created lower case if not existing)
|
||||
|
||||
2\. Prepend the tag to the subject: "[facebook] Subject"
|
||||
|
||||
## Two-factor authentication
|
||||
|
||||
So far two methods for TFA are implemented. Both work with the fantastic [Yubikey](https://www.yubico.com).
|
||||
|
||||
While Yubi OTP needs an active internet connection and an API ID and key, U2F will work with any FIDO U2F USB key out of the box, but can only be used when mailcow is accessed over HTTPS.
|
||||
|
||||
Both methods support multiple YubiKeys.
|
||||
|
||||
As administrator you are able to temporary disable a domain administrators TFA login until they successfully logged in.
|
||||
|
||||
The key used to login will be displayed in green, while other keys remain grey.
|
||||
|
||||
### Yubi OTP
|
||||
|
||||
The Yubi API ID and Key will be checked against the Yubico Cloud API. When setting up TFA you will be asked for your personal API account for this key.
|
||||
The API ID, API key and the first 12 characters (your YubiKeys ID in modhex) are stored in the MySQL table as secret.
|
||||
|
||||
### U2F
|
||||
|
||||
Only Google Chrome (+derivates) and Opera support U2F authentication to this day natively.
|
||||
For Firefox you will need to install the "U2F Support Add-on" as provided on [mozilla.org](https://addons.mozilla.org/en-US/firefox/addon/u2f-support-add-on/).
|
||||
|
||||
```
|
||||
data/conf
|
||||
├── bind9
|
||||
│ └── named.conf
|
||||
├── dovecot
|
||||
│ ├── dovecot.conf
|
||||
│ ├── dovecot-master.passwd
|
||||
│ ├── sieve_after
|
||||
│ └── sql
|
||||
│ ├── dovecot-dict-sql.conf
|
||||
│ └── dovecot-mysql.conf
|
||||
├── mysql
|
||||
│ └── my.cnf
|
||||
├── nginx
|
||||
│ ├── dynmaps.conf
|
||||
│ ├── site.conf
|
||||
│ └── templates
|
||||
│ ├── listen_plain.template
|
||||
│ ├── listen_ssl.template
|
||||
│ └── server_name.template
|
||||
├── pdns
|
||||
│ ├── pdns_custom.lua
|
||||
│ └── recursor.conf
|
||||
├── postfix
|
||||
│ ├── main.cf
|
||||
│ ├── master.cf
|
||||
│ ├── postscreen_access.cidr
|
||||
│ ├── smtp_dsn_filter
|
||||
│ └── sql
|
||||
│ ├── mysql_relay_recipient_maps.cf
|
||||
│ ├── mysql_tls_enforce_in_policy.cf
|
||||
│ ├── mysql_tls_enforce_out_policy.cf
|
||||
│ ├── mysql_virtual_alias_domain_catchall_maps.cf
|
||||
│ ├── mysql_virtual_alias_domain_maps.cf
|
||||
│ ├── mysql_virtual_alias_maps.cf
|
||||
│ ├── mysql_virtual_domains_maps.cf
|
||||
│ ├── mysql_virtual_mailbox_maps.cf
|
||||
│ ├── mysql_virtual_relay_domain_maps.cf
|
||||
│ ├── mysql_virtual_sender_acl.cf
|
||||
│ └── mysql_virtual_spamalias_maps.cf
|
||||
├── rmilter
|
||||
│ └── rmilter.conf
|
||||
├── rspamd
|
||||
│ ├── dynmaps
|
||||
│ │ ├── authoritative.php
|
||||
│ │ ├── settings.php
|
||||
│ │ ├── tags.php
|
||||
│ │ └── vars.inc.php -> ../../../web/inc/vars.inc.php
|
||||
│ ├── local.d
|
||||
│ │ ├── dkim.conf
|
||||
│ │ ├── metrics.conf
|
||||
│ │ ├── options.inc
|
||||
│ │ ├── redis.conf
|
||||
│ │ ├── rspamd.conf.local
|
||||
│ │ └── statistic.conf
|
||||
│ ├── lua
|
||||
│ │ └── rspamd.local.lua
|
||||
│ └── override.d
|
||||
│ ├── logging.inc
|
||||
│ ├── worker-controller.inc
|
||||
│ └── worker-normal.inc
|
||||
└── sogo
|
||||
├── sieve.creds
|
||||
└── sogo.conf
|
||||
|
||||
```
|
||||
|
||||
Just change the according configuration file on the host and restart the related service:
|
||||
```
|
||||
docker-compose restart service-mailcow
|
||||
```
|
||||
|
||||
## Tagging
|
||||
|
||||
Mailbox users can tag their mail address like in `me+facebook@example.org` and choose between to setups to handle this tag:
|
||||
|
||||
1\. Move this message to a subfolder "facebook" (will be created lower case if not existing)
|
||||
|
||||
2\. Prepend the tag to the subject: "[facebook] Subject"
|
||||
|
||||
## Two-factor authentication
|
||||
|
||||
So far two methods for TFA are implemented. Both work with the fantastic [Yubikey](https://www.yubico.com).
|
||||
|
||||
While Yubi OTP needs an active internet connection and an API ID and key, U2F will work with any FIDO U2F USB key out of the box, but can only be used when mailcow is accessed over HTTPS.
|
||||
|
||||
Both methods support multiple YubiKeys.
|
||||
|
||||
As administrator you are able to temporary disable a domain administrators TFA login until they successfully logged in.
|
||||
|
||||
The key used to login will be displayed in green, while other keys remain grey.
|
||||
|
||||
### Yubi OTP
|
||||
|
||||
The Yubi API ID and Key will be checked against the Yubico Cloud API. When setting up TFA you will be asked for your personal API account for this key.
|
||||
The API ID, API key and the first 12 characters (your YubiKeys ID in modhex) are stored in the MySQL table as secret.
|
||||
|
||||
### U2F
|
||||
|
||||
Only Google Chrome (+derivates) and Opera support U2F authentication to this day natively.
|
||||
For Firefox you will need to install the "U2F Support Add-on" as provided on [mozilla.org](https://addons.mozilla.org/en-US/firefox/addon/u2f-support-add-on/).
|
||||
|
||||
U2F works without an internet connection.
|
||||
|
||||
## Why Bind?
|
||||
|
||||
For DNS blacklist lookups and DNSSEC.
|
||||
|
||||
Most systems use either a public or a local caching DNS resolver.
|
||||
That's a very bad idea when it comes to filter spam using DNS-based blackhole lists (DNSBL) or similar technics.
|
||||
Most if not all providers apply a rate limit based on the DNS resolver that is used to query their service.
|
||||
Using a public resolver like Googles 4x8, OpenDNS or any other shared DNS resolver like your ISPs will hit that limit very soon.
|
||||
|
||||
For DNS blacklist lookups and DNSSEC.
|
||||
|
||||
Most systems use either a public or a local caching DNS resolver.
|
||||
That's a very bad idea when it comes to filter spam using DNS-based blackhole lists (DNSBL) or similar technics.
|
||||
Most if not all providers apply a rate limit based on the DNS resolver that is used to query their service.
|
||||
Using a public resolver like Googles 4x8, OpenDNS or any other shared DNS resolver like your ISPs will hit that limit very soon.
|
||||
|
|
Loading…
Reference in New Issue