mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-02-26 10:56:23 +00:00
Compare commits
1 Commits
dragoangel
...
feat/sogo-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aaa23d2dc1 |
2
.github/workflows/pr_to_nightly.yml
vendored
2
.github/workflows/pr_to_nightly.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run the Action
|
||||
uses: devops-infra/action-pull-request@v1.0.2
|
||||
uses: devops-infra/action-pull-request@v0.6.1
|
||||
with:
|
||||
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
|
||||
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Contribution Guidelines
|
||||
**_Last modified on 12th November 2025_**
|
||||
**_Last modified on 15th August 2024_**
|
||||
|
||||
First of all, thank you for wanting to provide a bugfix or a new feature for the mailcow community, it's because of your help that the project can continue to grow!
|
||||
|
||||
As we want to keep mailcow's development structured we setup these Guidelines which helps you to create your issue/pull request accordingly.
|
||||
|
||||
**PLEASE NOTE, THAT WE WILL CLOSE ISSUES/PULL REQUESTS IF THEY DON'T FULLFIL OUR WRITTEN GUIDELINES WRITTEN INSIDE THIS DOCUMENT**. So please check this guidelines before you propose a Issue/Pull Request.
|
||||
**PLEASE NOTE, THAT WE MIGHT CLOSE ISSUES/PULL REQUESTS IF THEY DON'T FULLFIL OUR WRITTEN GUIDELINES WRITTEN INSIDE THIS DOCUMENT**. So please check this guidelines before you propose a Issue/Pull Request.
|
||||
|
||||
## Topics
|
||||
|
||||
@@ -27,18 +27,14 @@ However, please note the following regarding pull requests:
|
||||
6. Please **ALWAYS** create the actual pull request against the staging branch and **NEVER** directly against the master branch. *If you forget to do this, our moobot will remind you to switch the branch to staging.*
|
||||
7. Wait for a merge commit: It may happen that we do not accept your pull request immediately or sometimes not at all for various reasons. Please do not be disappointed if this is the case. We always endeavor to incorporate any meaningful changes from the community into the mailcow project.
|
||||
8. If you are planning larger and therefore more complex pull requests, it would be advisable to first announce this in a separate issue and then start implementing it after the idea has been accepted in order to avoid unnecessary frustration and effort!
|
||||
9. If your PR requires a Docker image rebuild (changes to Dockerfiles or files in data/Dockerfiles/), update the image tag in docker-compose.yml. Use the base-image versioning (e.g. ghcr.io/mailcow/sogo:5.12.4 → :5.12.5 for version bumps; append a letter for patch fixes, e.g. :5.12.4a). Follow this scheme.
|
||||
|
||||
---
|
||||
|
||||
## Issue Reporting
|
||||
**_Last modified on 12th November 2025_**
|
||||
**_Last modified on 15th August 2024_**
|
||||
|
||||
If you plan to report a issue within mailcow please read and understand the following rules:
|
||||
|
||||
### Security disclosures / Security-related fixes
|
||||
- Security vulnerabilities and security fixes must always be reported confidentially first to the contact address specified in SECURITY.md before they are integrated, published, or publicly disclosed in issues/PRs. Please wait for a response from the specified contact to ensure coordinated and responsible disclosure.
|
||||
|
||||
### Issue Reporting Guidelines
|
||||
|
||||
1. **ONLY** use the issue tracker for bug reports or improvement requests and NOT for support questions. For support questions you can either contact the [mailcow community on Telegram](https://docs.mailcow.email/#community-support-and-chat) or the mailcow team directly in exchange for a [support fee](https://docs.mailcow.email/#commercial-support).
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
FROM debian:trixie-slim
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
RUN apt update && apt install pigz zstd -y --no-install-recommends
|
||||
RUN apt update && apt install pigz -y --no-install-recommends
|
||||
@@ -204,17 +204,16 @@ EOF
|
||||
# Create random master Password for SOGo SSO
|
||||
RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1)
|
||||
echo -n ${RAND_PASS} > /etc/phpfpm/sogo-sso.pass
|
||||
# Creating additional creds file for SOGo notify crons (calendars, etc)
|
||||
echo -n ${RAND_USER}@mailcow.local:${RAND_PASS} > /etc/sogo/cron.creds
|
||||
cat <<EOF > /etc/dovecot/sogo-sso.conf
|
||||
# Autogenerated by mailcow
|
||||
passdb {
|
||||
driver = static
|
||||
args = allow_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
|
||||
args = allow_real_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Creating additional creds file for SOGo notify crons (calendars, etc) (dummy user, sso password)
|
||||
echo -n ${RAND_USER}@mailcow.local:${RAND_PASS} > /etc/sogo/cron.creds
|
||||
|
||||
if [[ "${MASTER}" =~ ^([nN][oO]|[nN])+$ ]]; then
|
||||
# Toggling MASTER will result in a rebuild of containers, so the quota script will be recreated
|
||||
cat <<'EOF' > /usr/local/bin/quota_notify.py
|
||||
|
||||
@@ -167,7 +167,7 @@ DELIMITER //
|
||||
CREATE EVENT clean_spamalias
|
||||
ON SCHEDULE EVERY 1 DAY DO
|
||||
BEGIN
|
||||
DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP() AND permanent = 0;
|
||||
DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP();
|
||||
END;
|
||||
//
|
||||
DELIMITER ;
|
||||
|
||||
@@ -18,15 +18,11 @@ done
|
||||
|
||||
# Do not attempt to write to slave
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
export REDIS_SERVER="${REDIS_SLAVEOF_IP}"
|
||||
export REDIS_PORT="${REDIS_SLAVEOF_PORT}"
|
||||
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
else
|
||||
export REDIS_SERVER="redis"
|
||||
export REDIS_PORT="6379"
|
||||
export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
||||
fi
|
||||
|
||||
export REDIS_CMDLINE="redis-cli -h ${REDIS_SERVER} -p ${REDIS_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
|
||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis..."
|
||||
sleep 2
|
||||
@@ -41,13 +37,16 @@ echo "Postfix OK"
|
||||
cat <<EOF > /etc/postfix-tlspol/config.yaml
|
||||
server:
|
||||
address: 0.0.0.0:8642
|
||||
|
||||
log-level: ${LOGLVL}
|
||||
|
||||
prefetch: true
|
||||
|
||||
cache-file: /var/lib/postfix-tlspol/cache.db
|
||||
|
||||
dns:
|
||||
# must support DNSSEC
|
||||
address: 127.0.0.11:53
|
||||
redis:
|
||||
address: ${REDIS_SERVER}:${REDIS_PORT}
|
||||
db: 2
|
||||
EOF
|
||||
|
||||
/usr/local/bin/postfix-tlspol -config /etc/postfix-tlspol/config.yaml
|
||||
/usr/local/bin/postfix-tlspol -config /etc/postfix-tlspol/config.yaml
|
||||
@@ -390,7 +390,7 @@ hosts = unix:/var/run/mysqld/mysqld.sock
|
||||
dbname = ${DBNAME}
|
||||
query = SELECT goto FROM spamalias
|
||||
WHERE address='%s'
|
||||
AND (validity >= UNIX_TIMESTAMP() OR permanent != 0)
|
||||
AND validity >= UNIX_TIMESTAMP()
|
||||
EOF
|
||||
|
||||
if [ ! -f /opt/postfix/conf/dns_blocklists.cf ]; then
|
||||
@@ -524,4 +524,4 @@ if [[ $? != 0 ]]; then
|
||||
else
|
||||
postfix -c /opt/postfix/conf start
|
||||
sleep 126144000
|
||||
fi
|
||||
fi
|
||||
@@ -50,6 +50,10 @@ cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
<string>YES</string>
|
||||
<key>SOGoEncryptionKey</key>
|
||||
<string>${RAND_PASS}</string>
|
||||
<key>SOGoURLEncryptionEnabled</key>
|
||||
<string>YES</string>
|
||||
<key>SOGoURLEncryptionPassphrase</key>
|
||||
<string>${SOGO_URL_ENCRYPTION_KEY}</string>
|
||||
<key>OCSAdminURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_admin</string>
|
||||
<key>OCSCacheFolderURL</key>
|
||||
|
||||
@@ -13,7 +13,6 @@ events {
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
server_tokens off;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
|
||||
@@ -14,6 +14,7 @@ ssl_session_tickets off;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=15768000;";
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header X-Robots-Tag none;
|
||||
add_header X-Download-Options noopen;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
|
||||
@@ -66,7 +66,7 @@ $_SESSION['acl']['tls_policy'] = "1";
|
||||
$_SESSION['acl']['quarantine_notification'] = "1";
|
||||
$_SESSION['acl']['quarantine_category'] = "1";
|
||||
$_SESSION['acl']['ratelimit'] = "1";
|
||||
$_SESSION['acl']['sogo_access'] = "1";
|
||||
$_SESSION['acl']['sogo_redirection'] = "1";
|
||||
$_SESSION['acl']['protocol_access'] = "1";
|
||||
$_SESSION['acl']['mailbox_relayhost'] = "1";
|
||||
$_SESSION['acl']['unlimited_quota'] = "1";
|
||||
|
||||
@@ -66,7 +66,7 @@ $_SESSION['acl']['tls_policy'] = "1";
|
||||
$_SESSION['acl']['quarantine_notification'] = "1";
|
||||
$_SESSION['acl']['quarantine_category'] = "1";
|
||||
$_SESSION['acl']['ratelimit'] = "1";
|
||||
$_SESSION['acl']['sogo_access'] = "1";
|
||||
$_SESSION['acl']['sogo_redirection'] = "1";
|
||||
$_SESSION['acl']['protocol_access'] = "1";
|
||||
$_SESSION['acl']['mailbox_relayhost'] = "1";
|
||||
$_SESSION['acl']['unlimited_quota'] = "1";
|
||||
|
||||
@@ -7,10 +7,9 @@ opcache.interned_strings_buffer=16
|
||||
opcache.max_accelerated_files=10000
|
||||
opcache.memory_consumption=128
|
||||
opcache.save_comments=1
|
||||
opcache.revalidate_freq=120
|
||||
opcache.validate_timestamps=0
|
||||
|
||||
; JIT
|
||||
; Disabled for now due to some PHP segmentation faults observed
|
||||
; in certain environments. Possibly some PHP or PHP extension bug.
|
||||
opcache.jit=disable
|
||||
opcache.jit_buffer_size=0
|
||||
opcache.jit=1255
|
||||
opcache.jit_buffer_size=8M
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Whitelist generated by Postwhite v3.4 on Sat Nov 1 00:21:43 UTC 2025
|
||||
# Whitelist generated by Postwhite v3.4 on Wed Oct 1 00:21:33 UTC 2025
|
||||
# https://github.com/stevejenkins/postwhite/
|
||||
# 2161 total rules
|
||||
# 2216 total rules
|
||||
2a00:1450:4000::/36 permit
|
||||
2a01:111:f400::/48 permit
|
||||
2a01:111:f403:2800::/53 permit
|
||||
@@ -50,11 +50,14 @@
|
||||
8.25.194.0/23 permit
|
||||
8.25.196.0/23 permit
|
||||
8.36.116.0/24 permit
|
||||
8.39.54.0/23 permit
|
||||
8.39.54.250/31 permit
|
||||
8.39.144.0/24 permit
|
||||
8.40.222.0/23 permit
|
||||
8.40.222.250/31 permit
|
||||
12.130.86.238 permit
|
||||
13.107.213.69 permit
|
||||
13.107.246.69 permit
|
||||
13.108.16.0/20 permit
|
||||
13.107.213.41 permit
|
||||
13.107.246.41 permit
|
||||
13.110.208.0/21 permit
|
||||
13.110.209.0/24 permit
|
||||
13.110.216.0/22 permit
|
||||
@@ -166,6 +169,7 @@
|
||||
34.215.104.144 permit
|
||||
34.218.115.239 permit
|
||||
34.225.212.172 permit
|
||||
34.241.242.183 permit
|
||||
35.83.148.184 permit
|
||||
35.155.198.111 permit
|
||||
35.158.23.94 permit
|
||||
@@ -189,6 +193,7 @@
|
||||
40.233.64.216 permit
|
||||
40.233.83.78 permit
|
||||
40.233.88.28 permit
|
||||
43.239.212.33 permit
|
||||
44.206.138.57 permit
|
||||
44.210.169.44 permit
|
||||
44.217.45.156 permit
|
||||
@@ -270,6 +275,7 @@
|
||||
50.112.246.219 permit
|
||||
52.1.14.157 permit
|
||||
52.5.230.59 permit
|
||||
52.6.74.205 permit
|
||||
52.12.53.23 permit
|
||||
52.13.214.179 permit
|
||||
52.26.1.71 permit
|
||||
@@ -296,6 +302,7 @@
|
||||
52.96.91.34 permit
|
||||
52.96.111.82 permit
|
||||
52.96.172.98 permit
|
||||
52.96.214.50 permit
|
||||
52.96.222.194 permit
|
||||
52.96.222.226 permit
|
||||
52.96.223.2 permit
|
||||
@@ -334,6 +341,7 @@
|
||||
54.244.54.130 permit
|
||||
54.244.242.0/24 permit
|
||||
54.255.61.23 permit
|
||||
56.124.6.228 permit
|
||||
57.103.64.0/18 permit
|
||||
57.129.93.249 permit
|
||||
62.13.128.0/24 permit
|
||||
@@ -418,6 +426,7 @@
|
||||
65.110.161.77 permit
|
||||
65.123.29.213 permit
|
||||
65.123.29.220 permit
|
||||
65.154.166.0/24 permit
|
||||
65.212.180.36 permit
|
||||
66.102.0.0/20 permit
|
||||
66.119.150.192/26 permit
|
||||
@@ -1224,6 +1233,8 @@
|
||||
99.83.190.102 permit
|
||||
103.9.96.0/22 permit
|
||||
103.28.42.0/24 permit
|
||||
103.84.217.238 permit
|
||||
103.89.75.238 permit
|
||||
103.151.192.0/23 permit
|
||||
103.168.172.128/27 permit
|
||||
103.237.104.0/22 permit
|
||||
@@ -1389,6 +1400,9 @@
|
||||
117.120.16.0/21 permit
|
||||
119.42.242.52/31 permit
|
||||
119.42.242.156 permit
|
||||
121.244.91.48 permit
|
||||
121.244.91.52 permit
|
||||
122.15.156.182 permit
|
||||
123.126.78.64/29 permit
|
||||
124.108.96.24/31 permit
|
||||
124.108.96.28/31 permit
|
||||
@@ -1416,7 +1430,6 @@
|
||||
128.245.248.0/21 permit
|
||||
129.41.77.70 permit
|
||||
129.41.169.249 permit
|
||||
129.77.16.0/20 permit
|
||||
129.80.5.164 permit
|
||||
129.80.64.36 permit
|
||||
129.80.67.121 permit
|
||||
@@ -1453,8 +1466,21 @@
|
||||
134.170.141.64/26 permit
|
||||
134.170.143.0/24 permit
|
||||
134.170.174.0/24 permit
|
||||
135.84.80.0/24 permit
|
||||
135.84.81.0/24 permit
|
||||
135.84.82.0/24 permit
|
||||
135.84.83.0/24 permit
|
||||
135.84.216.0/22 permit
|
||||
136.146.128.0/20 permit
|
||||
136.143.160.0/24 permit
|
||||
136.143.161.0/24 permit
|
||||
136.143.162.0/24 permit
|
||||
136.143.176.0/24 permit
|
||||
136.143.177.0/24 permit
|
||||
136.143.178.49 permit
|
||||
136.143.182.0/23 permit
|
||||
136.143.184.0/24 permit
|
||||
136.143.188.0/24 permit
|
||||
136.143.190.0/23 permit
|
||||
136.147.128.0/20 permit
|
||||
136.147.135.0/24 permit
|
||||
136.147.176.0/20 permit
|
||||
@@ -1469,6 +1495,7 @@
|
||||
139.138.46.219 permit
|
||||
139.138.57.55 permit
|
||||
139.138.58.119 permit
|
||||
139.167.79.86 permit
|
||||
139.180.17.0/24 permit
|
||||
140.238.148.191 permit
|
||||
141.148.159.229 permit
|
||||
@@ -1591,6 +1618,9 @@
|
||||
164.152.23.32 permit
|
||||
164.152.25.241 permit
|
||||
164.177.132.168/30 permit
|
||||
165.173.128.0/24 permit
|
||||
165.173.180.250/31 permit
|
||||
165.173.182.250/31 permit
|
||||
166.78.68.0/22 permit
|
||||
166.78.68.221 permit
|
||||
166.78.69.169 permit
|
||||
@@ -1620,12 +1650,23 @@
|
||||
168.245.12.252 permit
|
||||
168.245.46.9 permit
|
||||
168.245.127.231 permit
|
||||
169.148.129.0/24 permit
|
||||
169.148.131.0/24 permit
|
||||
169.148.138.0/24 permit
|
||||
169.148.142.10 permit
|
||||
169.148.142.33 permit
|
||||
169.148.144.0/25 permit
|
||||
169.148.144.10 permit
|
||||
169.148.146.0/23 permit
|
||||
169.148.175.3 permit
|
||||
169.148.188.0/24 permit
|
||||
169.148.188.182 permit
|
||||
170.10.128.0/24 permit
|
||||
170.10.129.0/24 permit
|
||||
170.10.132.56/29 permit
|
||||
170.10.132.64/29 permit
|
||||
170.10.133.0/24 permit
|
||||
172.217.32.0/21 permit
|
||||
172.217.32.0/20 permit
|
||||
172.253.56.0/21 permit
|
||||
172.253.112.0/20 permit
|
||||
173.0.84.0/29 permit
|
||||
@@ -1805,7 +1846,16 @@
|
||||
199.16.156.0/22 permit
|
||||
199.33.145.1 permit
|
||||
199.33.145.32 permit
|
||||
199.34.22.36 permit
|
||||
199.59.148.0/22 permit
|
||||
199.67.80.2 permit
|
||||
199.67.80.20 permit
|
||||
199.67.82.2 permit
|
||||
199.67.82.20 permit
|
||||
199.67.84.0/24 permit
|
||||
199.67.86.0/24 permit
|
||||
199.67.88.0/24 permit
|
||||
199.67.90.0/24 permit
|
||||
199.101.161.130 permit
|
||||
199.101.162.0/25 permit
|
||||
199.122.120.0/21 permit
|
||||
@@ -1862,6 +1912,8 @@
|
||||
204.92.114.187 permit
|
||||
204.92.114.203 permit
|
||||
204.92.114.204/31 permit
|
||||
204.141.32.0/23 permit
|
||||
204.141.42.0/23 permit
|
||||
204.216.164.202 permit
|
||||
204.220.160.0/21 permit
|
||||
204.220.168.0/21 permit
|
||||
@@ -2149,6 +2201,9 @@
|
||||
2603:1030:20e:3::23c permit
|
||||
2603:1030:b:3::152 permit
|
||||
2603:1030:c02:8::14 permit
|
||||
2607:13c0:0001:0000:0000:0000:0000:7000/116 permit
|
||||
2607:13c0:0002:0000:0000:0000:0000:1000/116 permit
|
||||
2607:13c0:0004:0000:0000:0000:0000:0000/116 permit
|
||||
2607:f8b0:4000::/36 permit
|
||||
2620:109:c003:104::/64 permit
|
||||
2620:109:c003:104::215 permit
|
||||
|
||||
@@ -86,12 +86,6 @@
|
||||
SOGoMaximumFailedLoginInterval = 900;
|
||||
SOGoFailedLoginBlockInterval = 900;
|
||||
|
||||
// Enable SOGo URL Description for GDPR compliance, this may cause some issues with calendars and contacts. Also uncomment the encryption key below to use it.
|
||||
//SOGoURLEncryptionEnabled = NO;
|
||||
|
||||
// Set a 16 character encryption key for SOGo URL Description, change this to your own value
|
||||
//SOGoURLPathEncryptionKey = "SOGoSuperSecret0";
|
||||
|
||||
GCSChannelCollectionTimer = 60;
|
||||
GCSChannelExpireAge = 60;
|
||||
|
||||
|
||||
@@ -754,7 +754,7 @@ paths:
|
||||
- syncjobs
|
||||
- quarantine
|
||||
- login_as
|
||||
- sogo_access
|
||||
- sogo_redirection
|
||||
- app_passwds
|
||||
- bcc_maps
|
||||
- pushover
|
||||
@@ -807,7 +807,7 @@ paths:
|
||||
- syncjobs
|
||||
- quarantine
|
||||
- login_as
|
||||
- sogo_access
|
||||
- sogo_redirection
|
||||
- app_passwds
|
||||
- bcc_maps
|
||||
- pushover
|
||||
@@ -3339,7 +3339,7 @@ paths:
|
||||
- info@domain2.tld
|
||||
- domain3.tld
|
||||
- "*"
|
||||
sogo_access: "1"
|
||||
sogo_redirection: "1"
|
||||
username:
|
||||
- info@domain.tld
|
||||
tags: ["tag3", "tag4"]
|
||||
@@ -3390,7 +3390,7 @@ paths:
|
||||
- info@domain2.tld
|
||||
- domain3.tld
|
||||
- "*"
|
||||
sogo_access: "1"
|
||||
sogo_redirection: "1"
|
||||
tags: ["tag3", "tag4"]
|
||||
items:
|
||||
- info@domain.tld
|
||||
@@ -3422,8 +3422,8 @@ paths:
|
||||
sender_acl:
|
||||
description: list of allowed send from addresses
|
||||
type: object
|
||||
sogo_access:
|
||||
description: is access to SOGo webmail active or not
|
||||
sogo_redirection:
|
||||
description: is redirection to SOGo webmail active or not
|
||||
type: boolean
|
||||
type: object
|
||||
items:
|
||||
@@ -4799,7 +4799,7 @@ paths:
|
||||
force_pw_update: "0"
|
||||
mailbox_format: "maildir:"
|
||||
quarantine_notification: never
|
||||
sogo_access: "1"
|
||||
sogo_redirection: "1"
|
||||
tls_enforce_in: "0"
|
||||
tls_enforce_out: "0"
|
||||
domain: doman3.tld
|
||||
@@ -5723,7 +5723,7 @@ paths:
|
||||
force_pw_update: "0"
|
||||
mailbox_format: "maildir:"
|
||||
quarantine_notification: never
|
||||
sogo_access: "1"
|
||||
sogo_redirection: "1"
|
||||
tls_enforce_in: "0"
|
||||
tls_enforce_out: "0"
|
||||
custom_attributes: {}
|
||||
|
||||
@@ -3371,9 +3371,14 @@ function set_user_loggedin_session($user) {
|
||||
session_regenerate_id(true);
|
||||
$_SESSION['mailcow_cc_username'] = $user;
|
||||
$_SESSION['mailcow_cc_role'] = 'user';
|
||||
$sogo_sso_pass = file_get_contents("/etc/sogo-sso/sogo-sso.pass");
|
||||
$_SESSION['sogo-sso-user-allowed'][] = $user;
|
||||
$_SESSION['sogo-sso-pass'] = $sogo_sso_pass;
|
||||
|
||||
acl('to_session');
|
||||
if (hasACLAccess("sogo_access")) {
|
||||
$sogo_sso_pass = file_get_contents("/etc/sogo-sso/sogo-sso.pass");
|
||||
$_SESSION['sogo-sso-user-allowed'][] = $user;
|
||||
$_SESSION['sogo-sso-pass'] = $sogo_sso_pass;
|
||||
}
|
||||
|
||||
unset($_SESSION['pending_mailcow_cc_username']);
|
||||
unset($_SESSION['pending_mailcow_cc_role']);
|
||||
unset($_SESSION['pending_tfa_methods']);
|
||||
|
||||
@@ -49,12 +49,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
// Default to 1 yr
|
||||
$_data["validity"] = 8760;
|
||||
}
|
||||
if (isset($_data["permanent"]) && filter_var($_data["permanent"], FILTER_VALIDATE_BOOL)) {
|
||||
$permanent = 1;
|
||||
}
|
||||
else {
|
||||
$permanent = 0;
|
||||
}
|
||||
$domain = $_data['domain'];
|
||||
$description = $_data['description'];
|
||||
$valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
|
||||
@@ -71,14 +65,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
return false;
|
||||
}
|
||||
$validity = strtotime("+" . $_data["validity"] . " hour");
|
||||
$stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`, `permanent`) VALUES
|
||||
(:address, :description, :goto, :validity, :permanent)");
|
||||
$stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`) VALUES
|
||||
(:address, :description, :goto, :validity)");
|
||||
$stmt->execute(array(
|
||||
':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain,
|
||||
':description' => $description,
|
||||
':goto' => $username,
|
||||
':validity' => $validity,
|
||||
':permanent' => $permanent
|
||||
':validity' => $validity
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
@@ -1080,7 +1073,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
||||
$tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
|
||||
$tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
|
||||
$sogo_access = (isset($_data['sogo_access'])) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
|
||||
$sogo_redirection = (isset($_data['sogo_redirection'])) ? intval($_data['sogo_redirection']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_redirection']);
|
||||
$imap_access = (isset($_data['imap_access'])) ? intval($_data['imap_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
|
||||
$pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
|
||||
$smtp_access = (isset($_data['smtp_access'])) ? intval($_data['smtp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
|
||||
@@ -1098,7 +1091,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
'force_pw_update' => strval($force_pw_update),
|
||||
'tls_enforce_in' => strval($tls_enforce_in),
|
||||
'tls_enforce_out' => strval($tls_enforce_out),
|
||||
'sogo_access' => strval($sogo_access),
|
||||
'sogo_redirection' => strval($sogo_redirection),
|
||||
'imap_access' => strval($imap_access),
|
||||
'pop3_access' => strval($pop3_access),
|
||||
'smtp_access' => strval($smtp_access),
|
||||
@@ -1287,6 +1280,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$_data['syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
|
||||
$_data['eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
|
||||
$_data['sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
|
||||
$_data['sogo_access'] = (in_array('sogo_access', $_data['acl'])) ? 1 : 0;
|
||||
$_data['pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
|
||||
$_data['quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
|
||||
$_data['quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
|
||||
@@ -1303,6 +1297,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$_data['syncjobs'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_syncjobs']);
|
||||
$_data['eas_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_eas_reset']);
|
||||
$_data['sogo_profile_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_sogo_profile_reset']);
|
||||
$_data['sogo_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_sogo_access']);
|
||||
$_data['pushover'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_pushover']);
|
||||
$_data['quarantine'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine']);
|
||||
$_data['quarantine_attachments'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_attachments']);
|
||||
@@ -1711,7 +1706,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
|
||||
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
|
||||
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
||||
$attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
|
||||
$attr["sogo_redirection"] = isset($_data['sogo_redirection']) ? intval($_data['sogo_redirection']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_redirection']);
|
||||
$attr["active"] = isset($_data['active']) ? intval($_data['active']) : 1;
|
||||
$attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
|
||||
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
|
||||
@@ -1738,6 +1733,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_sogo_access'] = (in_array('sogo_access', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
|
||||
@@ -1755,6 +1751,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$attr['acl_syncjobs'] = 0;
|
||||
$attr['acl_eas_reset'] = 0;
|
||||
$attr['acl_sogo_profile_reset'] = 0;
|
||||
$attr['acl_sogo_access'] = 0;
|
||||
$attr['acl_pushover'] = 0;
|
||||
$attr['acl_quarantine'] = 0;
|
||||
$attr['acl_quarantine_attachments'] = 0;
|
||||
@@ -2110,23 +2107,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (empty($_data['validity']) && empty($_data['permanent'])) {
|
||||
if (empty($_data['validity'])) {
|
||||
continue;
|
||||
}
|
||||
if (isset($_data['permanent']) && filter_var($_data['permanent'], FILTER_VALIDATE_BOOL)) {
|
||||
$permanent = 1;
|
||||
$validity = 0;
|
||||
}
|
||||
else if (isset($_data['validity'])) {
|
||||
$permanent = 0;
|
||||
$validity = round((int)time() + ($_data['validity'] * 3600));
|
||||
}
|
||||
$stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity, `permanent` = :permanent WHERE
|
||||
$validity = round((int)time() + ($_data['validity'] * 3600));
|
||||
$stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity WHERE
|
||||
`address` = :address");
|
||||
$stmt->execute(array(
|
||||
':address' => $address,
|
||||
':validity' => $validity,
|
||||
':permanent' => $permanent
|
||||
':validity' => $validity
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
@@ -3045,23 +3034,23 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||
}
|
||||
if (!empty($is_now)) {
|
||||
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
|
||||
(int)$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($is_now['attributes']['force_pw_update']);
|
||||
(int)$sogo_access = (isset($_data['sogo_access']) && hasACLAccess("sogo_access")) ? intval($_data['sogo_access']) : intval($is_now['attributes']['sogo_access']);
|
||||
(int)$imap_access = (isset($_data['imap_access']) && hasACLAccess("protocol_access")) ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']);
|
||||
(int)$pop3_access = (isset($_data['pop3_access']) && hasACLAccess("protocol_access")) ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']);
|
||||
(int)$smtp_access = (isset($_data['smtp_access']) && hasACLAccess("protocol_access")) ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']);
|
||||
(int)$sieve_access = (isset($_data['sieve_access']) && hasACLAccess("protocol_access")) ? intval($_data['sieve_access']) : intval($is_now['attributes']['sieve_access']);
|
||||
(int)$relayhost = (isset($_data['relayhost']) && hasACLAccess("mailbox_relayhost")) ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']);
|
||||
(int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576);
|
||||
$name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name'];
|
||||
$domain = $is_now['domain'];
|
||||
$quota_b = $quota_m * 1048576;
|
||||
$password = (!empty($_data['password'])) ? $_data['password'] : null;
|
||||
$password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
|
||||
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
|
||||
$attribute_hash = (!empty($_data['attribute_hash'])) ? $_data['attribute_hash'] : '';
|
||||
$authsource = $is_now['authsource'];
|
||||
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
|
||||
(int)$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($is_now['attributes']['force_pw_update']);
|
||||
(int)$sogo_redirection = (isset($_data['sogo_redirection'])) ? intval($_data['sogo_redirection']) : intval($is_now['attributes']['sogo_redirection']);
|
||||
(int)$imap_access = (isset($_data['imap_access']) && hasACLAccess("protocol_access")) ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']);
|
||||
(int)$pop3_access = (isset($_data['pop3_access']) && hasACLAccess("protocol_access")) ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']);
|
||||
(int)$smtp_access = (isset($_data['smtp_access']) && hasACLAccess("protocol_access")) ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']);
|
||||
(int)$sieve_access = (isset($_data['sieve_access']) && hasACLAccess("protocol_access")) ? intval($_data['sieve_access']) : intval($is_now['attributes']['sieve_access']);
|
||||
(int)$relayhost = (isset($_data['relayhost']) && hasACLAccess("mailbox_relayhost")) ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']);
|
||||
(int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576);
|
||||
$name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name'];
|
||||
$domain = $is_now['domain'];
|
||||
$quota_b = $quota_m * 1048576;
|
||||
$password = (!empty($_data['password'])) ? $_data['password'] : null;
|
||||
$password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
|
||||
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
|
||||
$attribute_hash = (!empty($_data['attribute_hash'])) ? $_data['attribute_hash'] : '';
|
||||
$authsource = $is_now['authsource'];
|
||||
if ($_data['authsource'] == "mailcow" ||
|
||||
in_array($_data['authsource'], array('keycloak', 'generic-oidc', 'ldap')) && $iam_settings['authsource'] == $_data['authsource']){
|
||||
$authsource = $_data['authsource'];
|
||||
@@ -3329,7 +3318,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
`quota` = :quota_b,
|
||||
`authsource` = :authsource,
|
||||
`attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update),
|
||||
`attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access),
|
||||
`attributes` = JSON_SET(`attributes`, '$.sogo_redirection', :sogo_redirection),
|
||||
`attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access),
|
||||
`attributes` = JSON_SET(`attributes`, '$.sieve_access', :sieve_access),
|
||||
`attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access),
|
||||
@@ -3344,7 +3333,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
':quota_b' => $quota_b,
|
||||
':attribute_hash' => $attribute_hash,
|
||||
':force_pw_update' => $force_pw_update,
|
||||
':sogo_access' => $sogo_access,
|
||||
':sogo_redirection' => $sogo_redirection,
|
||||
':imap_access' => $imap_access,
|
||||
':pop3_access' => $pop3_access,
|
||||
':sieve_access' => $sieve_access,
|
||||
@@ -3721,7 +3710,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
|
||||
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value'];
|
||||
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update'];
|
||||
$attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access'];
|
||||
$attr["sogo_redirection"] = isset($_data['sogo_redirection']) ? intval($_data['sogo_redirection']) : $is_now['sogo_redirection'];
|
||||
$attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active'];
|
||||
$attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
|
||||
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
|
||||
@@ -3747,6 +3736,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
|
||||
$attr["acl_sogo_access"] = (in_array('sogo_access', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
|
||||
@@ -4599,12 +4589,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
`description`,
|
||||
`validity`,
|
||||
`created`,
|
||||
`modified`,
|
||||
`permanent`
|
||||
`modified`
|
||||
FROM `spamalias`
|
||||
WHERE `goto` = :username
|
||||
AND (`validity` >= :unixnow
|
||||
OR `permanent` != 0)");
|
||||
AND `validity` >= :unixnow");
|
||||
$stmt->execute(array(':username' => $_data, ':unixnow' => time()));
|
||||
$tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
return $tladata;
|
||||
@@ -5179,7 +5167,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain AND `username` != :username");
|
||||
$stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
|
||||
$MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND (`validity` >= :unixnow OR `permanent` != 0)");
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
|
||||
$stmt->execute(array(':address' => $_data, ':unixnow' => time()));
|
||||
$SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
|
||||
|
||||
@@ -4,7 +4,7 @@ function init_db_schema()
|
||||
try {
|
||||
global $pdo;
|
||||
|
||||
$db_version = "10312025_0525";
|
||||
$db_version = "16102025_1340";
|
||||
|
||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
@@ -504,6 +504,7 @@ function init_db_schema()
|
||||
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||
"eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"sogo_profile_reset" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||
"sogo_access" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"pushover" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
// quarantine is for quarantine actions, todo: rename
|
||||
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
@@ -554,8 +555,7 @@ function init_db_schema()
|
||||
"description" => "TEXT NOT NULL",
|
||||
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
|
||||
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
|
||||
"validity" => "INT(11)",
|
||||
"permanent" => "TINYINT(1) NOT NULL DEFAULT '0'"
|
||||
"validity" => "INT(11)"
|
||||
),
|
||||
"keys" => array(
|
||||
"primary" => array(
|
||||
@@ -703,7 +703,7 @@ function init_db_schema()
|
||||
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"login_as" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"sogo_access" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"sogo_redirection" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"app_passwds" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"bcc_maps" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"pushover" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||
@@ -1390,7 +1390,8 @@ function init_db_schema()
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.relayhost', \"0\") WHERE JSON_VALUE(`attributes`, '$.relayhost') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.force_pw_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.force_pw_update') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.sieve_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.sieve_access') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.sogo_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.sogo_access') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.sogo_redirection', JSON_VALUE(`attributes`, '$.sogo_access')) WHERE JSON_VALUE(`attributes`, '$.sogo_access') IS NOT NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_REMOVE(`attributes`, '$.sogo_access') WHERE JSON_VALUE(`attributes`, '$.sogo_access') IS NOT NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.imap_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.imap_access') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.pop3_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.pop3_access') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.smtp_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.smtp_access') IS NULL;");
|
||||
@@ -1446,7 +1447,7 @@ function init_db_schema()
|
||||
"rl_frame" => "s",
|
||||
"rl_value" => "",
|
||||
"force_pw_update" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['force_pw_update']),
|
||||
"sogo_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sogo_access']),
|
||||
"sogo_redirection" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sogo_redirection']),
|
||||
"active" => 1,
|
||||
"tls_enforce_in" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_in']),
|
||||
"tls_enforce_out" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_out']),
|
||||
@@ -1462,6 +1463,7 @@ function init_db_schema()
|
||||
"acl_syncjobs" => 0,
|
||||
"acl_eas_reset" => 1,
|
||||
"acl_sogo_profile_reset" => 0,
|
||||
"acl_sogo_access" => 1,
|
||||
"acl_pushover" => 1,
|
||||
"acl_quarantine" => 1,
|
||||
"acl_quarantine_attachments" => 1,
|
||||
@@ -1500,6 +1502,14 @@ function init_db_schema()
|
||||
":attributes" => json_encode($default_mailbox_template["attributes"])
|
||||
));
|
||||
}
|
||||
$pdo->query("UPDATE `templates`
|
||||
SET `attributes` = JSON_SET(`attributes`, '$.sogo_redirection', JSON_VALUE(`attributes`, '$.sogo_access'))
|
||||
WHERE `type` = 'mailbox' AND JSON_VALUE(`attributes`, '$.sogo_access') IS NOT NULL;
|
||||
");
|
||||
$pdo->query("UPDATE `templates`
|
||||
SET `attributes` = JSON_REMOVE(`attributes`, '$.sogo_access')
|
||||
WHERE `type` = 'mailbox' AND JSON_VALUE(`attributes`, '$.sogo_access') IS NOT NULL;
|
||||
");
|
||||
|
||||
// remove old sogo views and triggers
|
||||
$pdo->query("DROP TRIGGER IF EXISTS sogo_update_password");
|
||||
|
||||
@@ -76,8 +76,9 @@ if (isset($_POST["verify_tfa_login"])) {
|
||||
|
||||
$user_details = mailbox("get", "mailbox_details", $_SESSION['mailcow_cc_username']);
|
||||
$is_dual = (!empty($_SESSION["dual-login"]["username"])) ? true : false;
|
||||
if (intval($user_details['attributes']['sogo_access']) == 1 &&
|
||||
if (intval($user_details['attributes']['sogo_redirection']) == 1 &&
|
||||
intval($user_details['attributes']['force_pw_update']) != 1 &&
|
||||
hasACLAccess('sogo_access') &&
|
||||
getenv('SKIP_SOGO') != "y" &&
|
||||
!$is_dual) {
|
||||
header("Location: /SOGo/so/");
|
||||
@@ -142,8 +143,9 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
|
||||
|
||||
$user_details = mailbox("get", "mailbox_details", $login_user);
|
||||
$is_dual = (!empty($_SESSION["dual-login"]["username"])) ? true : false;
|
||||
if (intval($user_details['attributes']['sogo_access']) == 1 &&
|
||||
if (intval($user_details['attributes']['sogo_redirection']) == 1 &&
|
||||
intval($user_details['attributes']['force_pw_update']) != 1 &&
|
||||
hasACLAccess('sogo_access') &&
|
||||
getenv('SKIP_SOGO') != "y" &&
|
||||
!$is_dual) {
|
||||
header("Location: /SOGo/so/");
|
||||
|
||||
@@ -85,7 +85,7 @@ $AVAILABLE_LANGUAGES = array(
|
||||
// 'ca-es' => 'Català (Catalan)',
|
||||
'bg-bg' => 'Български (Bulgarian)',
|
||||
'cs-cz' => 'Čeština (Czech)',
|
||||
'da-dk' => 'Dansk (Danish)',
|
||||
'da-dk' => 'Danish (Dansk)',
|
||||
'de-de' => 'Deutsch (German)',
|
||||
'en-gb' => 'English',
|
||||
'es-es' => 'Español (Spanish)',
|
||||
@@ -110,7 +110,6 @@ $AVAILABLE_LANGUAGES = array(
|
||||
'sv-se' => 'Svenska (Swedish)',
|
||||
'tr-tr' => 'Türkçe (Turkish)',
|
||||
'uk-ua' => 'Українська (Ukrainian)',
|
||||
'vi-vn' => 'Tiếng Việt (Vietnamese)',
|
||||
'zh-cn' => '简体中文 (Simplified Chinese)',
|
||||
'zh-tw' => '繁體中文 (Traditional Chinese)',
|
||||
);
|
||||
@@ -191,8 +190,8 @@ $MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out'] = false;
|
||||
// Force password change on next login (only allows login to mailcow UI)
|
||||
$MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update'] = false;
|
||||
|
||||
// Enable SOGo access - Users will be redirected to SOGo after login (set to false to disable redirect by default)
|
||||
$MAILBOX_DEFAULT_ATTRIBUTES['sogo_access'] = true;
|
||||
// Enable SOGo redirection - Users will be redirected to SOGo after login (set to false to disable redirect by default)
|
||||
$MAILBOX_DEFAULT_ATTRIBUTES['sogo_redirection'] = true;
|
||||
|
||||
// How to handle tagged emails
|
||||
// none - No special handling
|
||||
|
||||
@@ -11,7 +11,10 @@ if (isset($_SESSION['mailcow_cc_role']) && isset($_SESSION['oauth2_request'])) {
|
||||
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user') {
|
||||
$user_details = mailbox("get", "mailbox_details", $_SESSION['mailcow_cc_username']);
|
||||
$is_dual = (!empty($_SESSION["dual-login"]["username"])) ? true : false;
|
||||
if (intval($user_details['attributes']['sogo_access']) == 1 && !$is_dual && getenv('SKIP_SOGO') != "y") {
|
||||
if (intval($user_details['attributes']['sogo_redirection']) == 1 &&
|
||||
hasACLAccess('sogo_access') &&
|
||||
!$is_dual &&
|
||||
getenv('SKIP_SOGO') != "y") {
|
||||
header("Location: /SOGo/so/");
|
||||
} else {
|
||||
header("Location: /user");
|
||||
|
||||
@@ -379,6 +379,9 @@ $(document).ready(function() {
|
||||
if (template.acl_sogo_profile_reset == 1){
|
||||
acl.push("sogo_profile_reset");
|
||||
}
|
||||
if (template.acl_sogo_access == 1){
|
||||
acl.push("sogo_access");
|
||||
}
|
||||
if (template.acl_pushover == 1){
|
||||
acl.push("pushover");
|
||||
}
|
||||
@@ -418,10 +421,10 @@ $(document).ready(function() {
|
||||
} else {
|
||||
$('#force_pw_update').prop('checked', false);
|
||||
}
|
||||
if (template.sogo_access == 1){
|
||||
$('#sogo_access').prop('checked', true);
|
||||
if (template.sogo_redirection == 1){
|
||||
$('#sogo_redirection').prop('checked', true);
|
||||
} else {
|
||||
$('#sogo_access').prop('checked', false);
|
||||
$('#sogo_redirection').prop('checked', false);
|
||||
}
|
||||
|
||||
// load tags
|
||||
@@ -1209,7 +1212,7 @@ jQuery(function($){
|
||||
item.attributes.imap_access = '<i class="text-' + (item.attributes.imap_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.imap_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.imap_access == 1 ? '1' : '0') + '</span></i>';
|
||||
item.attributes.smtp_access = '<i class="text-' + (item.attributes.smtp_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.smtp_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.smtp_access == 1 ? '1' : '0') + '</span></i>';
|
||||
item.attributes.sieve_access = '<i class="text-' + (item.attributes.sieve_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.sieve_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.sieve_access == 1 ? '1' : '0') + '</span></i>';
|
||||
item.attributes.sogo_access = '<i class="text-' + (item.attributes.sogo_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.sogo_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.sogo_access == 1 ? '1' : '0') + '</span></i>';
|
||||
item.attributes.sogo_redirection = '<i class="text-' + (item.attributes.sogo_redirection == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.sogo_redirection == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.sogo_redirection == 1 ? '1' : '0') + '</span></i>';
|
||||
if (item.attributes.quarantine_notification === 'never') {
|
||||
item.attributes.quarantine_notification = lang.never;
|
||||
} else if (item.attributes.quarantine_notification === 'hourly') {
|
||||
@@ -1318,8 +1321,8 @@ jQuery(function($){
|
||||
defaultContent: '',
|
||||
},
|
||||
{
|
||||
title: 'SOGO',
|
||||
data: 'attributes.sogo_access',
|
||||
title: 'SOGO redirection',
|
||||
data: 'attributes.sogo_redirection',
|
||||
defaultContent: '',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -175,10 +175,6 @@ jQuery(function($){
|
||||
'</div>';
|
||||
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
|
||||
item.address = escapeHtml(item.address);
|
||||
item.validity = {
|
||||
value: item.validity,
|
||||
permanent: item.permanent
|
||||
};
|
||||
}
|
||||
else {
|
||||
item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
|
||||
@@ -222,21 +218,9 @@ jQuery(function($){
|
||||
title: lang.alias_valid_until,
|
||||
data: 'validity',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
var date = new Date(data.value ? data.value * 1000 : 0);
|
||||
switch (type) {
|
||||
case "sort":
|
||||
if (data.permanent) {
|
||||
return 0;
|
||||
}
|
||||
return date.getTime();
|
||||
default:
|
||||
if (data.permanent) {
|
||||
return lang.forever;
|
||||
}
|
||||
return date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
|
||||
}
|
||||
},
|
||||
createdCell: function(td, cellData) {
|
||||
createSortableDate(td, cellData)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.created_on,
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"ratelimit": "Ограничение на скоростта",
|
||||
"recipient_maps": "Карти на получатели",
|
||||
"smtp_ip_access": "Промяна на разрешените хостове за SMTP",
|
||||
"sogo_access": "Разрешаване на управление на достъпа до SOGo",
|
||||
"sogo_redirection": "Разрешаване на управление на достъпа до SOGo",
|
||||
"sogo_profile_reset": "Нулиране на профила на SOGo",
|
||||
"spam_alias": "Временни псевдоними",
|
||||
"spam_policy": "Черен/Бял списък",
|
||||
@@ -736,8 +736,8 @@
|
||||
"sieve_desc": "Кратко описание",
|
||||
"sieve_type": "Тип на филтър",
|
||||
"skipcrossduplicates": "Пропускане на дублирани съобщения между папки (първи дошъл, първи обслужен)",
|
||||
"sogo_access": "Директно препращане към SOGo",
|
||||
"sogo_access_info": "След влизане, потребителят се пренасочва автоматично към SOGo.",
|
||||
"sogo_redirection": "Директно препращане към SOGo",
|
||||
"sogo_redirection_info": "След влизане, потребителят се пренасочва автоматично към SOGo.",
|
||||
"sogo_visible": "Псевдонимът е видим в SOGo",
|
||||
"sogo_visible_info": "Тази опция засяга само обекти, които могат да бъдат показани в SOGo (споделени или несподелени адреси на псевдоними, сочещи поне една локална пощенска кутия). Ако е скрит, псевдонимът няма да се появи като избираем адрес на изпращач в SOGo.",
|
||||
"spam_alias": "Създаване или промяна на временни псевдоними",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"ratelimit": "Omezení provozu",
|
||||
"recipient_maps": "Mapy příjemců",
|
||||
"smtp_ip_access": "Spravovat povolené hostitele pro SMTP",
|
||||
"sogo_access": "Správa přístupu do SOGo",
|
||||
"sogo_redirection": "Správa přístupu do SOGo",
|
||||
"sogo_profile_reset": "Resetování profilu SOGo",
|
||||
"spam_alias": "Dočasné aliasy",
|
||||
"spam_policy": "Denylist/Allowlist",
|
||||
@@ -727,8 +727,8 @@
|
||||
"sieve_desc": "Krátký popis",
|
||||
"sieve_type": "Typ filtru",
|
||||
"skipcrossduplicates": "Přeskočit duplicitní zprávy (\"první přijde, první mele\")",
|
||||
"sogo_access": "Přímé předání na SOGo",
|
||||
"sogo_access_info": "Po přihlášení je uživatel automaticky přesměrován do služby SOGo.",
|
||||
"sogo_redirection": "Přímé předání na SOGo",
|
||||
"sogo_redirection_info": "Po přihlášení je uživatel automaticky přesměrován do služby SOGo.",
|
||||
"sogo_visible": "Alias dostupný v SOGo",
|
||||
"sogo_visible_info": "Tato volba určuje objekty, jež lze zobrazit v SOGo (sdílené nebo nesdílené aliasy, jež ukazuje alespoň na jednu schránku).",
|
||||
"spam_alias": "Vytvořit nebo změnit dočasné aliasy",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"ratelimit": "Satsgrænse",
|
||||
"recipient_maps": "Modtagerkort",
|
||||
"smtp_ip_access": "Skift tilladte værter til SMTP",
|
||||
"sogo_access": "Tillad styring af SOGo-adgang",
|
||||
"sogo_redirection": "Tillad styring af SOGo-adgang",
|
||||
"sogo_profile_reset": "Nulstil SOGo-profil",
|
||||
"spam_alias": "Midlertidige aliasser",
|
||||
"spam_policy": "Sortliste/hvidliste",
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
"ratelimit": "Rate limit",
|
||||
"recipient_maps": "Empfängerumschreibungen",
|
||||
"smtp_ip_access": "Verwalten der erlaubten Hosts für SMTP",
|
||||
"sogo_access": "Verwalten des SOGo-Zugriffsrechts erlauben",
|
||||
"sogo_access": "Zugriff auf SOGo erlauben",
|
||||
"sogo_redirection": "Leite den Benutzer nach dem Login zu SOGo weiter",
|
||||
"sogo_profile_reset": "SOGo-Profil zurücksetzen",
|
||||
"spam_alias": "Temporäre E-Mail-Aliasse",
|
||||
"spam_policy": "Deny/Allowlist",
|
||||
@@ -763,8 +764,9 @@
|
||||
"sieve_desc": "Kurze Beschreibung",
|
||||
"sieve_type": "Filtertyp",
|
||||
"skipcrossduplicates": "Duplikate auch über Ordner hinweg überspringen (\"first come, first serve\")",
|
||||
"sogo_access": "Direktes weiterleiten an SOGo",
|
||||
"sogo_access_info": "Nach dem Einloggen wird der Benutzer automatisch an SOGo weitergeleitet.",
|
||||
"sogo_access": "Erlaube Zugriff auf SOGo",
|
||||
"sogo_redirection": "Direktes weiterleiten an SOGo",
|
||||
"sogo_redirection_info": "Nach dem Einloggen wird der Benutzer automatisch an SOGo weitergeleitet.",
|
||||
"sogo_visible": "Alias in SOGo sichtbar",
|
||||
"sogo_visible_info": "Diese Option hat lediglich Einfluss auf Objekte, die in SOGo darstellbar sind (geteilte oder nicht-geteilte Alias-Adressen mit dem Ziel mindestens einer lokalen Mailbox).",
|
||||
"spam_alias": "Anpassen temporärer Alias-Adressen",
|
||||
@@ -987,7 +989,7 @@
|
||||
"sogo_visible": "Alias Sichtbarkeit in SOGo",
|
||||
"sogo_visible_n": "Alias in SOGo verbergen",
|
||||
"sogo_visible_y": "Alias in SOGo anzeigen",
|
||||
"spam_aliases": "Spam-Alias",
|
||||
"spam_aliases": "Temp. Alias",
|
||||
"stats": "Statistik",
|
||||
"status": "Status",
|
||||
"sync_jobs": "Synchronisationen",
|
||||
@@ -1281,9 +1283,7 @@
|
||||
"encryption": "Verschlüsselung",
|
||||
"excludes": "Ausschlüsse",
|
||||
"expire_in": "Ungültig in",
|
||||
"expire_never": "Niemals ungültig",
|
||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
||||
"forever": "Für immer",
|
||||
"force_pw_update": "Das Passwort für diesen Benutzer <b>muss</b> geändert werden, damit die Zugriffssperre auf die Groupware-Komponenten wieder freigeschaltet wird.",
|
||||
"from": "von",
|
||||
"generate": "generieren",
|
||||
@@ -1348,8 +1348,7 @@
|
||||
"sogo_profile_reset": "SOGo-Profil zurücksetzen",
|
||||
"sogo_profile_reset_help": "Das Profil wird inklusive <b>aller</b> Kalender- und Kontaktdaten <b>unwiederbringlich gelöscht</b>.",
|
||||
"sogo_profile_reset_now": "Profil jetzt zurücksetzen",
|
||||
"spam_aliases": "Spam E-Mail-Aliasse",
|
||||
"spam_aliases_info": "Ein Spam-Alias ist eine temporäre E-Mailadresse, die benutzt werden kann, um eine echte E-Mail Adressen zu schützen. <br>Optional kann eine Ablaufzeit gesetzt werden, sodass der Alias nach dem definierten Zeitraum automatisch deaktiviert wird, was missbrauchte oder geleakte Adressen effektiv entsorgt.",
|
||||
"spam_aliases": "Temporäre E-Mail-Aliasse",
|
||||
"spam_score_reset": "Auf Server-Standard zurücksetzen",
|
||||
"spamfilter": "Spamfilter",
|
||||
"spamfilter_behavior": "Bewertung",
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
"ratelimit": "Rate limit",
|
||||
"recipient_maps": "Recipient maps",
|
||||
"smtp_ip_access": "Change allowed hosts for SMTP",
|
||||
"sogo_access": "Allow management of SOGo access",
|
||||
"sogo_access": "Allow access to SOGo",
|
||||
"sogo_redirection": "Redirect User to SOGo after login",
|
||||
"sogo_profile_reset": "Reset SOGo profile",
|
||||
"spam_alias": "Temporary aliases",
|
||||
"spam_policy": "Denylist/Allowlist",
|
||||
@@ -764,8 +765,9 @@
|
||||
"sieve_desc": "Short description",
|
||||
"sieve_type": "Filter type",
|
||||
"skipcrossduplicates": "Skip duplicate messages across folders (first come, first serve)",
|
||||
"sogo_access": "Direct forwarding to SOGo",
|
||||
"sogo_access_info": "After logging in, the user is automatically redirected to SOGo.",
|
||||
"sogo_access": "Allow SOGo access",
|
||||
"sogo_redirection": "Direct forwarding to SOGo",
|
||||
"sogo_redirection_info": "After logging in, the user is automatically redirected to SOGo.",
|
||||
"sogo_visible": "Alias is visible in SOGo",
|
||||
"sogo_visible_info": "This option only affects objects, that can be displayed in SOGo (shared or non-shared alias addresses pointing to at least one local mailbox). If hidden, an alias will not appear as selectable sender in SOGo.",
|
||||
"spam_alias": "Create or change time limited alias addresses",
|
||||
@@ -1288,9 +1290,7 @@
|
||||
"encryption": "Encryption",
|
||||
"excludes": "Excludes",
|
||||
"expire_in": "Expire in",
|
||||
"expire_never": "Never Expire",
|
||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
||||
"forever": "Forever",
|
||||
"force_pw_update": "You <b>must</b> set a new password to be able to access groupware related services.",
|
||||
"from": "from",
|
||||
"generate": "generate",
|
||||
@@ -1357,8 +1357,7 @@
|
||||
"sogo_profile_reset": "Reset SOGo profile",
|
||||
"sogo_profile_reset_help": "This will destroy a user's SOGo profile and <b>delete all contact and calendar data irretrievable</b>.",
|
||||
"sogo_profile_reset_now": "Reset profile now",
|
||||
"spam_aliases": "Spam email aliases",
|
||||
"spam_aliases_info": "A spam alias is a temporary email address that can be used to protect real email addresses. <br>Optionally, an expiration time can be set so that the alias is automatically deactivated after the defined period, effectively disposing of abused or leaked addresses.",
|
||||
"spam_aliases": "Temporary email aliases",
|
||||
"spam_score_reset": "Reset to server default",
|
||||
"spamfilter": "Spam filter",
|
||||
"spamfilter_behavior": "Rating",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"domain_relayhost": "Cambiar relayhost por un dominio",
|
||||
"extend_sender_acl": "Permitir extender la ACL del remitente por direcciones externas",
|
||||
"pw_reset": "Permitir el restablecimiento de la contraseña del usuario mailcow",
|
||||
"sogo_access": "Permitir la gestión del acceso a SOGo",
|
||||
"sogo_redirection": "Permitir la gestión del acceso a SOGo",
|
||||
"mailbox_relayhost": "Cambiar el host de reenvío para un buzón",
|
||||
"smtp_ip_access": "Cambiar hosts permitidos para SMTP"
|
||||
},
|
||||
@@ -662,10 +662,10 @@
|
||||
"app_passwd_protocols": "Protocolos permitidos con contraseña de aplicación",
|
||||
"domain_footer_info": "Los pies de página de dominio se añaden a todos los mensajes salientes remitidos por una dirección de dicho dominio.<br> Están disponibles las siguientes variables para el pie de página:",
|
||||
"sender_acl_info": "Si el usuario del buzón A tiene permitido enviar como el buzón B, la dirección de remitente no se mostrará automáticamente como seleccionable en el campo \"De\" en SOGo.<br>\n El usuario del buzón B necesitará crear una delegación en SOGo para permitir al usuario A seleccionar su dirección como remitente. Para delegar un buzón en SOGo, utilice el menú (tres puntos) a la derecha del nombre del buzón en la esquina superior izquierda, en la vista de correo. Este comportamiento no se aplica a direcciones alias.",
|
||||
"sogo_access_info": "Tras iniciar sesión, el usuario será redirigido automáticamente a SOGo.",
|
||||
"sogo_redirection_info": "Tras iniciar sesión, el usuario será redirigido automáticamente a SOGo.",
|
||||
"comment_info": "Un comentario privado no es visible para el usuario, mientras que un comentario público se muestra como descripción emergente al pasar el ratón en la vista general del usuario",
|
||||
"quota_warning_bcc_info": "Los avisos se enviarán como copias separadas a los siguientes destinatarios. Se indicará en el asunto el usuario afectado entre paréntesis, como por ejemplo: <code>Aviso de cuota (usuario@ejemplo.com)</code>.",
|
||||
"sogo_access": "Redirección directa a SOGo",
|
||||
"sogo_redirection": "Redirección directa a SOGo",
|
||||
"sogo_visible_info": "Esta opción solamente afecta a objetos que puedan ser visualizados en SOGo (alias compartidos o no compartidos que apunten al menos a un buzón interno). Si se oculta, el alias no aparecerá como seleccionable en SOGo.",
|
||||
"extended_sender_acl_info": "Se aconseja importar una clave de dominio DKIM, si está disponible.<br>\n Recuerde añadir este servidor al registro SPF correspondiente.<br>\n Siempre que se añada un dominio o alias a este servidor, que se superponga con una dirección externa, se eliminará la dirección externa.<br>\n Utilice @dominio.tld para permitir enviar como *@dominio.tld.",
|
||||
"pushover_info": "La configuración de notificaciones push se aplicará a todos los mensajes limpios (no spam) entregados a <b>%s</b> incluyendo alias (compartidos, no compartidos, etiquetados).",
|
||||
@@ -1084,7 +1084,6 @@
|
||||
"aliases_send_as_all": "No verificar permisos del remitente para los siguientes dominios (y sus aliases)",
|
||||
"change_password": "Cambiar contraseña",
|
||||
"create_syncjob": "Crear nuevo trabajo de sincronización",
|
||||
"created_on": "Creado",
|
||||
"daily": "Cada día",
|
||||
"day": "Día",
|
||||
"description": "Descripción",
|
||||
@@ -1096,9 +1095,6 @@
|
||||
"edit": "Editar",
|
||||
"encryption": "Cifrado",
|
||||
"excludes": "Excluye",
|
||||
"expire_in": "Expirará en",
|
||||
"expire_never": "Nunca expirará",
|
||||
"forever": "Siempre",
|
||||
"hour": "Hora",
|
||||
"hourly": "Cada hora",
|
||||
"hours": "Horas",
|
||||
@@ -1119,8 +1115,7 @@
|
||||
"shared_aliases": "Alias compartidos",
|
||||
"shared_aliases_desc": "Los alias compartidos no se ven afectados por la configuración específica del usuario, como el filtro de correo no deseado o la política de cifrado. Los filtros de spam correspondientes solo pueden ser realizados por un administrador como una política de dominio.",
|
||||
"sogo_profile_reset": "Resetear perfil SOGo",
|
||||
"spam_aliases": "Alias de email de spam",
|
||||
"spam_aliases_info": "Un alias de spam es una dirección de correo electrónico temporal que se puede usar para proteger direcciones de correo electrónico reales. <br>Opcionalmente, se puede establecer un tiempo de expiración para que el alias se desactive automáticamente después del período definido, eliminando efectivamente las direcciones abusadas o filtradas.",
|
||||
"spam_aliases": "Alias de email temporales",
|
||||
"spamfilter": "Filtro anti-spam",
|
||||
"spamfilter_behavior": "Clasificación",
|
||||
"spamfilter_bl": "Lista negra",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"quarantine_notification": "Muuta karanteeni-ilmoituksia",
|
||||
"ratelimit": "Määrä raja",
|
||||
"recipient_maps": "Vastaanottajakartat",
|
||||
"sogo_access": "Salli SOGo-pääsyn hallintaan",
|
||||
"sogo_redirection": "Salli SOGo-pääsyn hallintaan",
|
||||
"sogo_profile_reset": "Nollaa SOGo-profiili",
|
||||
"spam_alias": "Väliaikaiset aliakset",
|
||||
"spam_policy": "Musta lista / sallitut lista",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"ratelimit": "Limite d'envoi",
|
||||
"recipient_maps": "Cartes destinataire",
|
||||
"smtp_ip_access": "Changer les hôtes autorisés pour SMTP",
|
||||
"sogo_access": "Autoriser la gestion des accès à SOGo",
|
||||
"sogo_redirection": "Autoriser la gestion des accès à SOGo",
|
||||
"sogo_profile_reset": "Réinitialiser le profil SOGo",
|
||||
"spam_alias": "Alias temporaires",
|
||||
"spam_policy": "Liste Noire/Liste Blanche",
|
||||
@@ -724,7 +724,7 @@
|
||||
"none_inherit": "Aucun / Héritage",
|
||||
"quota_warning_bcc": "Avertissement sur les quotas BCC",
|
||||
"quota_warning_bcc_info": "Les avertissements seront envoyés en copies séparées aux destinataires suivants. Le sujet sera précédé du nom d'utilisateur correspondant entre parenthèses, par exemple : <code>Avertissement sur les quotas (user@example.com)</code>.",
|
||||
"sogo_access_info": "Après s'être connecté, l'utilisateur est automatiquement redirigé vers SOGo.",
|
||||
"sogo_redirection_info": "Après s'être connecté, l'utilisateur est automatiquement redirigé vers SOGo.",
|
||||
"admin": "Modifier l'administrateur",
|
||||
"password_recovery_email": "Adresse email de récupération",
|
||||
"mailbox_rename_title": "Nouveau nom de la partie locale de la boîte de réception",
|
||||
@@ -732,7 +732,7 @@
|
||||
"mailbox_rename_agree": "J'ai fait une sauvegarde.",
|
||||
"mailbox_rename_warning": "IMPORTANT ! Faites une sauvegarde avant de renommer la boîte de réception.",
|
||||
"mailbox_rename_alias": "Créer un alias automatiquement",
|
||||
"sogo_access": "Redirection directe vers SOGo",
|
||||
"sogo_redirection": "Redirection directe vers SOGo",
|
||||
"pushover": "Pushover",
|
||||
"pushover_sound": "Son"
|
||||
},
|
||||
|
||||
@@ -415,8 +415,8 @@
|
||||
"sieve_desc": "Rövid leírás",
|
||||
"sieve_type": "Szűrő típusa",
|
||||
"skipcrossduplicates": "Átugrani a duplikált üzeneteket a mappák között (aki előbb jön, előbb kapja)",
|
||||
"sogo_access": "Közvetlen továbbítás a SOGo-ra",
|
||||
"sogo_access_info": "A bejelentkezés után a felhasználó automatikusan átirányításra kerül a SOGo-ra.",
|
||||
"sogo_redirection": "Közvetlen továbbítás a SOGo-ra",
|
||||
"sogo_redirection_info": "A bejelentkezés után a felhasználó automatikusan átirányításra kerül a SOGo-ra.",
|
||||
"sogo_visible": "Alias látható a SOGo-ban",
|
||||
"sogo_visible_info": "Ez az opció csak azokra az objektumokra vonatkozik, amelyek megjeleníthetők a SOGo-ban (megosztott vagy nem megosztott alias címek, amelyek legalább egy helyi postafiókra mutatnak). Ha el van rejtve, egy alias nem jelenik meg választható feladóként a SOGo-ban.",
|
||||
"spam_alias": "Időkorlátos alias címek létrehozása vagy módosítása",
|
||||
@@ -1048,7 +1048,7 @@
|
||||
"syncjobs": "Szinkronizálási feladatok",
|
||||
"tls_policy": "TLS szabályzat",
|
||||
"unlimited_quota": "Korlátlan kvóta a postafiókok számára",
|
||||
"sogo_access": "A SOGo-hozzáférés kezelésének lehetővé tétele",
|
||||
"sogo_redirection": "A SOGo-hozzáférés kezelésének lehetővé tétele",
|
||||
"pw_reset": "Lehetővé teszi a mailcow felhasználói jelszavak visszaállítását"
|
||||
},
|
||||
"diagnostics": {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"ratelimit": "Limite di invio",
|
||||
"recipient_maps": "Mappe dei destinatari",
|
||||
"smtp_ip_access": "Modifica gli host consentiti per SMTP",
|
||||
"sogo_access": "Consenti la gestione dell'accesso SOGo",
|
||||
"sogo_redirection": "Consenti la gestione dell'accesso SOGo",
|
||||
"sogo_profile_reset": "Ripristina profilo SOGo",
|
||||
"spam_alias": "Alias temporanei",
|
||||
"spam_policy": "Blacklist/Whitelist",
|
||||
@@ -671,8 +671,8 @@
|
||||
"validate_save": "Convalida e salva",
|
||||
"pushover": "Pushover",
|
||||
"none_inherit": "Nessuno / Eredita",
|
||||
"sogo_access": "Inoltro diretto a SOGo",
|
||||
"sogo_access_info": "Dopo aver effettuato il login, l'utente viene automaticamente reindirizzato a SOGo.",
|
||||
"sogo_redirection": "Inoltro diretto a SOGo",
|
||||
"sogo_redirection_info": "Dopo aver effettuato il login, l'utente viene automaticamente reindirizzato a SOGo.",
|
||||
"acl": "ACL (autorizzazione)",
|
||||
"app_passwd_protocols": "Protocolli consentiti per la password dell'app",
|
||||
"last_modified": "Ultima modifica",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"ratelimit": "レート制限",
|
||||
"recipient_maps": "受信者マップ",
|
||||
"smtp_ip_access": "SMTPで許可されるホストの変更",
|
||||
"sogo_access": "SOGoアクセス管理を許可",
|
||||
"sogo_redirection": "SOGoアクセス管理を許可",
|
||||
"sogo_profile_reset": "SOGoプロファイルをリセット",
|
||||
"spam_alias": "一時的なエイリアス",
|
||||
"spam_policy": "ブラックリスト/ホワイトリスト",
|
||||
@@ -691,8 +691,8 @@
|
||||
"sieve_desc": "簡単な説明",
|
||||
"sieve_type": "フィルタータイプ",
|
||||
"skipcrossduplicates": "フォルダー間で重複するメッセージをスキップ(先着順)",
|
||||
"sogo_access": "SOGoへの直接ログインアクセスを許可",
|
||||
"sogo_access_info": "メールUI内からのシングルサインオンは引き続き動作します。この設定は他のすべてのサービスへのアクセスには影響しません。また、ユーザーの既存のSOGoプロファイルを削除または変更するものでもありません。",
|
||||
"sogo_redirection": "SOGoへの直接ログインアクセスを許可",
|
||||
"sogo_redirection_info": "メールUI内からのシングルサインオンは引き続き動作します。この設定は他のすべてのサービスへのアクセスには影響しません。また、ユーザーの既存のSOGoプロファイルを削除または変更するものでもありません。",
|
||||
"sogo_visible": "SOGoにエイリアスが表示される",
|
||||
"sogo_visible_info": "このオプションは、SOGoで表示可能なオブジェクト(ローカルメールボックスを指す共有または非共有のエイリアスアドレス)にのみ影響します。非表示にすると、SOGoで選択可能な送信者としてエイリアスは表示されません。",
|
||||
"spam_alias": "時間制限付きエイリアスアドレスを作成または変更",
|
||||
@@ -1187,7 +1187,6 @@
|
||||
"created_on": "作成日",
|
||||
"daily": "毎日",
|
||||
"day": "日",
|
||||
"description": "説明",
|
||||
"delete_ays": "削除プロセスを確認してください。",
|
||||
"direct_aliases": "直接エイリアスアドレス",
|
||||
"direct_aliases_desc": "直接エイリアスアドレスは、スパムフィルターおよびTLSポリシー設定の影響を受けます。",
|
||||
@@ -1202,9 +1201,7 @@
|
||||
"encryption": "暗号化",
|
||||
"excludes": "除外",
|
||||
"expire_in": "有効期限まで",
|
||||
"expire_never": "有効期限なし",
|
||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
||||
"forever": "有効期限なし",
|
||||
"force_pw_update": "グループウェア関連サービスにアクセスするには、新しいパスワードを<b>必ず</b>設定する必要があります。",
|
||||
"from": "送信元",
|
||||
"generate": "生成",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"ratelimit": "요청 제한",
|
||||
"recipient_maps": "수신자 맵",
|
||||
"smtp_ip_access": "SMTP에 허용된 호스트 변경",
|
||||
"sogo_access": "SOGo 접근 관리 허용",
|
||||
"sogo_redirection": "SOGo 접근 관리 허용",
|
||||
"sogo_profile_reset": "SOGo 프로필 초기화",
|
||||
"spam_alias": "일임시 별칭",
|
||||
"spam_policy": "블랙리스트/화이트리스트",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"ratelimit": "Prieigos limitas",
|
||||
"recipient_maps": "Gavėjų sąsajos",
|
||||
"smtp_ip_access": "Pakeisti prieinamuosius SMTP serverius",
|
||||
"sogo_access": "Leisti SOGo prieigos valdymą",
|
||||
"sogo_redirection": "Leisti SOGo prieigos valdymą",
|
||||
"spam_policy": "Juodasis/Baltasis sąrašas",
|
||||
"spam_score": "Šlamsto balas",
|
||||
"tls_policy": "TLS politika",
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"quarantine_category": "Mainīt karantīnas paziņojumu kategoriju",
|
||||
"quarantine_notification": "Mainīt karantīnas paziņojumus",
|
||||
"smtp_ip_access": "Mainīt SMTP atļautos saimniekdatorus",
|
||||
"sogo_access": "Atļaut SOGo piekļuves pārvaldību",
|
||||
"sogo_redirection": "Atļaut SOGo piekļuves pārvaldību",
|
||||
"sogo_profile_reset": "Atiestatīt SOGo profilu"
|
||||
},
|
||||
"add": {
|
||||
@@ -319,7 +319,7 @@
|
||||
"sogo_visible": "Aizstājvārds ir redzams SOGo",
|
||||
"sogo_visible_info": "Šī iespēja ietekmē tikai tos objektus, kurus var parādīt SOGo (koplietojamās vai nekoplietojamās aizstājadreses, kas norāda uz vismaz vienu vietējo pastkasti). Ja paslēpts, netiks parādīts SOGo kā atlasāms sūtītājs.",
|
||||
"mbox_rl_info": "Šis pieprasījumu ierobežojums tiek piemērots SASL pieteikšanās vārdam, tas atbilst jebkurai \"from\" adresei, ko izmanto lietotājs, kurš ir pieteicies. Pastkastes pieprasījumu ierobežojums pārraksta domēna mēroga pieprasījumu ierobežojumu.",
|
||||
"sogo_access": "Tieša pārvirzīšana uz SOGo",
|
||||
"sogo_redirection": "Tieša pārvirzīšana uz SOGo",
|
||||
"disable_login": "Neļaut pieteikšanos (ienākošais pasts joprojām tiks pieņemts)",
|
||||
"app_passwd_protocols": "Atļautie lietotnes paroles protokoli",
|
||||
"allowed_protocols": "Atļautie protokoli tiešai lietotāja piekļuvei (neietekmē lietotnes paroles protokolus)",
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
"spam_alias": "Midlertidige alias",
|
||||
"spam_policy": "Svarteliste/Hvitliste",
|
||||
"unlimited_quota": "Ubegrenset kvote for postkasser",
|
||||
"sogo_access": "Tillat administrasjon av SOGo-tilgang",
|
||||
"sogo_redirection": "Tillat administrasjon av SOGo-tilgang",
|
||||
"syncjobs": "Synkroniser jobber",
|
||||
"spam_score": "Spam-resultat",
|
||||
"recipient_maps": "Mottakerkart",
|
||||
@@ -185,12 +185,11 @@
|
||||
"protocol_access": "Endre protokolltilgang",
|
||||
"pushover": "Pushover",
|
||||
"quarantine": "Karantenehandlinger",
|
||||
"quarantine_attachments": "Se vedlegg i karantene",
|
||||
"quarantine_attachments": "Sett vedlegg i karantene",
|
||||
"quarantine_category": "Endre varslingskategori for karantene",
|
||||
"quarantine_notification": "Endre karantenevarslinger",
|
||||
"domain_desc": "Endre domenebeskrivelse",
|
||||
"extend_sender_acl": "Tillat utvidelse av sender-ACL fra eksterne adresser",
|
||||
"pw_reset": "Tillat endring av brukerpassord"
|
||||
"extend_sender_acl": "Tillat utvidelse av sender-ACL fra eksterne adresser"
|
||||
},
|
||||
"add": {
|
||||
"app_passwd_protocols": "Tillatte protokoller for app-passord",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"ratelimit": "Ratelimit",
|
||||
"recipient_maps": "Ontvanger-maps",
|
||||
"smtp_ip_access": "Wijzig toegestane hosts voor SMTP",
|
||||
"sogo_access": "Sta beheer van SOGo-toegang toe",
|
||||
"sogo_redirection": "Sta beheer van SOGo-toegang toe",
|
||||
"sogo_profile_reset": "Verwijder SOGo-profiel",
|
||||
"spam_alias": "Tijdelijke aliassen",
|
||||
"spam_policy": "Blacklist/Whitelist",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@
|
||||
"ratelimit": "Limite de taxa",
|
||||
"recipient_maps": "Mapas de destinatários",
|
||||
"smtp_ip_access": "Alterar hosts permitidos para SMTP",
|
||||
"sogo_access": "Permitir o gerenciamento do acesso ao SoGo",
|
||||
"sogo_redirection": "Permitir o gerenciamento do acesso ao SoGo",
|
||||
"sogo_profile_reset": "Redefinir perfil SoGo",
|
||||
"spam_alias": "Aliases temporários",
|
||||
"spam_policy": "Lista negra/lista branca",
|
||||
@@ -746,8 +746,8 @@
|
||||
"sieve_desc": "Breve descrição",
|
||||
"sieve_type": "Tipo de filtro",
|
||||
"skipcrossduplicates": "Ignore mensagens duplicadas entre pastas (primeiro a chegar, primeiro a ser servido)",
|
||||
"sogo_access": "Encaminhamento direto para o SOGoo",
|
||||
"sogo_access_info": "Depois de fazer login, o usuário é automaticamente redirecionado para o SOGo.",
|
||||
"sogo_redirection": "Encaminhamento direto para o SOGoo",
|
||||
"sogo_redirection_info": "Depois de fazer login, o usuário é automaticamente redirecionado para o SOGo.",
|
||||
"sogo_visible": "O alias é visível no SoGo",
|
||||
"sogo_visible_info": "Essa opção afeta somente objetos, que podem ser exibidos no SoGo (endereços de alias compartilhados ou não compartilhados apontando para pelo menos uma mailbox local). Se estiver oculto, um alias não aparecerá como remetente selecionável no SoGo.",
|
||||
"spam_alias": "Crie ou altere endereços de alias com limite de tempo",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"ratelimit": "Rata limită",
|
||||
"recipient_maps": "Hărți recipient",
|
||||
"smtp_ip_access": "Schimbați gazdele permise pentru SMTP",
|
||||
"sogo_access": "Permiteți gestionarea accesului SOGo",
|
||||
"sogo_redirection": "Permiteți gestionarea accesului SOGo",
|
||||
"sogo_profile_reset": "Resetează profilul SOGo",
|
||||
"spam_alias": "Aliasuri temporare",
|
||||
"spam_policy": "Lista neagră/Lista albă",
|
||||
@@ -604,8 +604,8 @@
|
||||
"sieve_desc": "Descriere scurtă",
|
||||
"sieve_type": "Tip filtru",
|
||||
"skipcrossduplicates": "Sari peste mesajele duplicate din toate folderele (primul venit, primul servit)",
|
||||
"sogo_access": "Redirecționare directă către SOGo",
|
||||
"sogo_access_info": "După logare, utilizatorul este redirecționat automat către SOGo.",
|
||||
"sogo_redirection": "Redirecționare directă către SOGo",
|
||||
"sogo_redirection_info": "După logare, utilizatorul este redirecționat automat către SOGo.",
|
||||
"sogo_visible": "Aliasul este vizibil în SOGo",
|
||||
"sogo_visible_info": "Această opțiune afectează doar obiecte, care pot fi afișate în SOGo (adrese alias partajate sau ne-partajate cu cel puțin o căsuță poștală locală). Dacă este ascuns, un alias nu va apărea ca expeditor selectabil în SOGo.",
|
||||
"spam_alias": "Crează sau modifică adrese alias limitate în funcție de timp",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"ratelimit": "Лимиты отправки",
|
||||
"recipient_maps": "Перезапись получателя",
|
||||
"smtp_ip_access": "Настройка разрешенных IP для SMTP",
|
||||
"sogo_access": "Управление доступом к SOGo",
|
||||
"sogo_redirection": "Управление доступом к SOGo",
|
||||
"sogo_profile_reset": "Сброс профиля SOGo",
|
||||
"spam_alias": "Временные псевдонимы",
|
||||
"spam_policy": "Черные и белый списки",
|
||||
@@ -745,8 +745,8 @@
|
||||
"sieve_desc": "Краткое описание",
|
||||
"sieve_type": "Тип фильтра",
|
||||
"skipcrossduplicates": "Пропускать повторяющиеся сообщения в папках",
|
||||
"sogo_access": "Прямая переадресация в SOGo",
|
||||
"sogo_access_info": "После входа в систему пользователь автоматически перенаправляется в SOGo.",
|
||||
"sogo_redirection": "Прямая переадресация в SOGo",
|
||||
"sogo_redirection_info": "После входа в систему пользователь автоматически перенаправляется в SOGo.",
|
||||
"sogo_visible": "Отображать псевдоним в SOGo",
|
||||
"sogo_visible_info": "Влияет только на объекты, которые могут отображаться в SOGo (персональные или общие псевдонимы, указывающие как минимум на один локальный почтовый аккаунт). Учтите, что если функция отключена, у пользователей не будет возможности выбрать адрес псевдонима в качестве отправителя в SOGo.",
|
||||
"spam_alias": "Создать или изменить временные (спам) псевдонимы",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"ratelimit": "Omejitev pošiljanja",
|
||||
"recipient_maps": "Preslikave prejemnikov",
|
||||
"smtp_ip_access": "Spremeni dovoljene gostitelje za SMTP",
|
||||
"sogo_access": "Dovoli upravljanje SOGo dostopa",
|
||||
"sogo_redirection": "Dovoli upravljanje SOGo dostopa",
|
||||
"sogo_profile_reset": "Ponastavi SOGo profil",
|
||||
"spam_alias": "Začasni vzdevki",
|
||||
"spam_policy": "Seznam zavrnjenih/dovoljenih",
|
||||
@@ -746,8 +746,8 @@
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Preverjanje pošiljatelja je onemogočeno</span>",
|
||||
"sieve_type": "Vrsta filtra",
|
||||
"skipcrossduplicates": "Preskoči podvojena sporočila med mapami (po principu \"kdor prej pride, prej melje\")",
|
||||
"sogo_access": "Neposredno posredovanje na SOGo",
|
||||
"sogo_access_info": "Po prijavi je uporabnik samodejno preusmerjen na SOGo.",
|
||||
"sogo_redirection": "Neposredno posredovanje na SOGo",
|
||||
"sogo_redirection_info": "Po prijavi je uporabnik samodejno preusmerjen na SOGo.",
|
||||
"sogo_visible": "Vzdevek je viden v SOGo",
|
||||
"sogo_visible_info": "Ta možnost vpliva samo na objekte, ki jih je mogoče prikazati v SOGo (naslovi vzdevkov v skupni rabi ali brez nje, ki kažejo na vsaj en lokalni poštni predal). Če je skrita, vzdevek ne bo prikazan kot izbirni pošiljatelj v SOGo.",
|
||||
"spam_alias": "Ustvarjanje ali spreminjanje časovno omejenih vzdevkovnih naslovov",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"ratelimit": "Obmedzenie prenosu",
|
||||
"recipient_maps": "Mapy príjemcu",
|
||||
"smtp_ip_access": "Spravovať povolených hostiteľov pre SMTP",
|
||||
"sogo_access": "Povoliť spravovanie prístupu do SOGo",
|
||||
"sogo_redirection": "Povoliť spravovanie prístupu do SOGo",
|
||||
"sogo_profile_reset": "Znovu nastaviť SOGo profil",
|
||||
"spam_alias": "Dočasné aliasy",
|
||||
"spam_policy": "Čierna listina/Biela listina",
|
||||
@@ -622,8 +622,8 @@
|
||||
"sieve_desc": "Krátky popis",
|
||||
"sieve_type": "Typ filtru",
|
||||
"skipcrossduplicates": "Preskočiť duplikované správy naprieč priečinkami (akceptuje sa prvý nález)",
|
||||
"sogo_access": "Priame presmerovanie na SOGo",
|
||||
"sogo_access_info": "Po prihlásení je používateľ automaticky presmerovaný na službu SOGo.",
|
||||
"sogo_redirection": "Priame presmerovanie na SOGo",
|
||||
"sogo_redirection_info": "Po prihlásení je používateľ automaticky presmerovaný na službu SOGo.",
|
||||
"sogo_visible": "Alias je viditeľný v SOGo",
|
||||
"sogo_visible_info": "Táto voľba ovplyvňuje len objekty, ktoré dokážu byť zobrazené v SOGo (zdieľané alebo nezdieľané alias adresy ukazujúc na minimálne jednu lokálnu mailovú schránku). Ak je skrytý, alias nebude prezentovaný ako voliteľný odosielateľ v SOGo.",
|
||||
"spam_alias": "Vytvoriť alebo zmeniť časovo limitované alias adresy",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"ratelimit": "Hastighetsgräns",
|
||||
"recipient_maps": "Kartor över mottagare",
|
||||
"smtp_ip_access": "Ändra tillåtna värdar för SMTP",
|
||||
"sogo_access": "Tillåt hantering av SOGo-åtkomst",
|
||||
"sogo_redirection": "Tillåt hantering av SOGo-åtkomst",
|
||||
"sogo_profile_reset": "Återställ SOGo-profil",
|
||||
"spam_alias": "Tillfälliga e-postalias",
|
||||
"spam_policy": "Svartlista/Vitlista",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"ratelimit": "Rate limit",
|
||||
"recipient_maps": "Alıcı haritaları",
|
||||
"smtp_ip_access": "SMTP için izin verilen host değerlerini değiştirme",
|
||||
"sogo_access": "SOGo erişiminin yönetilmesine izin verin",
|
||||
"sogo_redirection": "SOGo erişiminin yönetilmesine izin verin",
|
||||
"sogo_profile_reset": "SOGo profilini sıfırla",
|
||||
"spam_alias": "Geçici alias değerleri",
|
||||
"spam_policy": "Kara Liste/Beyaz Liste",
|
||||
@@ -409,7 +409,7 @@
|
||||
"footer_exclude": "Footerdan hariç tut",
|
||||
"last_modified": "Son değişiklik",
|
||||
"lookup_mx": "Hedef, MX adıyla eşleşecek normal bir ifadedir (google.com ile biten bir MX'e hedeflenen tüm postaları bu atlama üzerinden yönlendirmek için <code>.*google\\\\.com</code>)",
|
||||
"sogo_access_info": "Posta kullanıcı arayüzünden tek oturum açma çalışmaya devam eder. Bu ayar, diğer tüm hizmetlere erişimi etkilemez veya bir kullanıcının mevcut SOGo profilini silmez veya değiştirmez.",
|
||||
"sogo_redirection_info": "Posta kullanıcı arayüzünden tek oturum açma çalışmaya devam eder. Bu ayar, diğer tüm hizmetlere erişimi etkilemez veya bir kullanıcının mevcut SOGo profilini silmez veya değiştirmez.",
|
||||
"comment_info": "Gizli bir yorum kullanıcı tarafından görülmezken, genel bir yorum, kullanıcının genel bakışında üzerine gelindiğinde araç ipucu olarak gösterilir.",
|
||||
"sender_acl_info": "Posta kutusu A kullanıcısının posta kutusu kullanıcısı B olarak göndermesine izin veriliyorsa, gönderen adresi SOGo'da seçilebilir \\\"gönderen\\\" alanı olarak otomatik olarak görüntülenmez.<br>\\r\\n Posta kutusu B kullanıcısının izin vermesi için SOGo'da bir yetkilendirme oluşturması gerekir. posta kutusu kullanıcısı A, adresini gönderen olarak seçmek için. SOGo'da bir posta kutusuna yetki vermek için, posta görünümündeyken sol üstteki posta kutusu adınızın sağındaki menüyü (üç nokta) kullanın. Bu davranış, diğer ad adresleri için geçerli değildir.",
|
||||
"sogo_visible_info": "Bu seçenek yalnızca SOGo'da görüntülenebilen nesneleri etkiler (en az bir yerel posta kutusuna işaret eden paylaşılan veya paylaşılmayan diğer ad adresleri). Gizliyse, bir takma ad SOGo'da seçilebilir gönderici olarak görünmez.",
|
||||
@@ -518,7 +518,7 @@
|
||||
"relay_all_info": "↪ Tüm alıcıları geçirmek için <b>değil</b> seçerseniz, aktarılması gereken her alıcı için bir (\\\"kör\\\") posta kutusu eklemeniz gerekir.",
|
||||
"relay_domain": "Bu etki alanını aktar",
|
||||
"relay_transport_info": "<div class=\\\"label label-info\\\">Bilgi</div> Bu etki alanı için özel bir hedef için taşıma haritaları tanımlayabilirsiniz. Ayarlanmazsa, bir MX araması yapılır.",
|
||||
"sogo_access": "SOGo'ya doğrudan giriş erişimi verin",
|
||||
"sogo_redirection": "SOGo'ya doğrudan giriş erişimi verin",
|
||||
"spam_alias": "Zaman sınırlı takma ad adresleri oluşturun veya değiştirin",
|
||||
"spam_filter": "Spam filtresi",
|
||||
"disable_login": "Oturum açmaya izin verme (gelen posta hala kabul edilir)",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"quarantine_category": "Категорія повідомлень про спам",
|
||||
"recipient_maps": "Перезапис одержувача",
|
||||
"smtp_ip_access": "Налаштування дозволених IP для SMTP",
|
||||
"sogo_access": "Управління доступом до SOGo",
|
||||
"sogo_redirection": "Управління доступом до SOGo",
|
||||
"spam_score": "Політика фільтрації спаму",
|
||||
"protocol_access": "Налаштування дозволених протоколів",
|
||||
"quarantine_notification": "Сповіщення про спам",
|
||||
@@ -614,8 +614,8 @@
|
||||
"sieve_desc": "Короткий опис",
|
||||
"sieve_type": "Тип фільтра",
|
||||
"skipcrossduplicates": "Пропускати в папках повідомлення, що повторюються",
|
||||
"sogo_access": "Пряме перенаправлення до SOGo",
|
||||
"sogo_access_info": "Після входу користувач автоматично перенаправляється на SOGo.",
|
||||
"sogo_redirection": "Пряме перенаправлення до SOGo",
|
||||
"sogo_redirection_info": "Після входу користувач автоматично перенаправляється на SOGo.",
|
||||
"sogo_visible": "Відображати псевдонім у SOGo",
|
||||
"spam_alias": "Створити або змінити тимчасові (спам) псевдоніми",
|
||||
"spam_filter": "Спам фільтр",
|
||||
|
||||
@@ -1,697 +0,0 @@
|
||||
{
|
||||
"acl": {
|
||||
"alias_domains": "Thêm tên miền bí danh",
|
||||
"app_passwds": "Quản lý mật khẩu ứng dụng",
|
||||
"bcc_maps": "Ánh xạ BCC",
|
||||
"delimiter_action": "Hành động phân cách",
|
||||
"domain_desc": "Thay đổi mô tả tên miền",
|
||||
"domain_relayhost": "Thay đổi máy chủ chuyển tiếp cho tên miền",
|
||||
"eas_reset": "Đặt lại thiết bị EAS",
|
||||
"extend_sender_acl": "Cho phép mở rộng ACL người gửi bằng địa chỉ bên ngoài",
|
||||
"filters": "Bộ lọc",
|
||||
"login_as": "Đăng nhập với tư cách người dùng hộp thư",
|
||||
"mailbox_relayhost": "Thay đổi máy chủ chuyển tiếp cho hộp thư",
|
||||
"prohibited": "Bị cấm bởi ACL",
|
||||
"protocol_access": "Thay đổi quyền truy cập giao thức",
|
||||
"pushover": "Thông báo đẩy",
|
||||
"pw_reset": "Cho phép đặt lại mật khẩu người dùng mailcow",
|
||||
"quarantine": "Hành động cách ly",
|
||||
"quarantine_attachments": "Cách ly tệp đính kèm",
|
||||
"quarantine_category": "Thay đổi danh mục thông báo cách ly",
|
||||
"quarantine_notification": "Thay đổi thông báo cách ly",
|
||||
"ratelimit": "Giới hạn tốc độ",
|
||||
"recipient_maps": "Ánh xạ người nhận",
|
||||
"smtp_ip_access": "Thay đổi máy chủ được phép cho SMTP",
|
||||
"sogo_access": "Cho phép quản lý truy cập SOGo",
|
||||
"sogo_profile_reset": "Đặt lại hồ sơ SOGo",
|
||||
"spam_alias": "Bí danh tạm thời",
|
||||
"spam_policy": "Danh sách chặn/Danh sách cho phép",
|
||||
"spam_score": "Điểm thư rác",
|
||||
"syncjobs": "Công việc đồng bộ",
|
||||
"tls_policy": "Chính sách TLS",
|
||||
"unlimited_quota": "Hạn ngạch không giới hạn cho hộp thư"
|
||||
},
|
||||
"add": {
|
||||
"activate_filter_warn": "Tất cả các bộ lọc khác sẽ bị vô hiệu hóa khi tùy chọn kích hoạt được chọn.",
|
||||
"active": "Đang hoạt động",
|
||||
"add": "Thêm",
|
||||
"add_domain_only": "Chỉ thêm tên miền",
|
||||
"add_domain_restart": "Thêm tên miền và khởi động lại SOGo",
|
||||
"alias_address": "Địa chỉ bí danh",
|
||||
"alias_address_info": "<small>Địa chỉ email đầy đủ hoặc @example.com để bắt tất cả thư cho một tên miền (phân cách bằng dấu phẩy). <b>Chỉ áp dụng cho tên miền mailcow</b>.</small>",
|
||||
"alias_domain": "Tên miền bí danh",
|
||||
"alias_domain_info": "<small>Chỉ cho phép tên miền hợp lệ (phân cách bằng dấu phẩy).</small>",
|
||||
"app_name": "Tên ứng dụng",
|
||||
"app_password": "Thêm mật khẩu ứng dụng",
|
||||
"app_passwd_protocols": "Các giao thức được phép cho mật khẩu ứng dụng",
|
||||
"automap": "Thử tự động ánh xạ thư mục (\"Mục đã gửi\", \"Đã gửi\" => \"Đã gửi\" v.v.)",
|
||||
"backup_mx_options": "Tùy chọn chuyển tiếp",
|
||||
"bcc_dest_format": "Địa chỉ BCC phải là một địa chỉ email hợp lệ duy nhất.<br>Nếu bạn cần gửi bản sao đến nhiều địa chỉ, hãy tạo một bí danh và sử dụng nó ở đây.",
|
||||
"comment_info": "Bình luận riêng tư không hiển thị với người dùng, trong khi bình luận công khai được hiển thị dưới dạng chú thích khi di chuột qua trong tổng quan người dùng",
|
||||
"custom_params": "Tham số tùy chỉnh",
|
||||
"custom_params_hint": "Đúng: --param=xy, sai: --param xy",
|
||||
"delete1": "Xóa từ nguồn khi hoàn thành",
|
||||
"delete2": "Xóa thư ở đích không có ở nguồn",
|
||||
"delete2duplicates": "Xóa các bản sao ở đích",
|
||||
"description": "Mô tả",
|
||||
"destination": "Đích",
|
||||
"disable_login": "Không cho phép đăng nhập (vẫn nhận được thư đến)",
|
||||
"domain": "Tên miền",
|
||||
"domain_matches_hostname": "Tên miền %s khớp với tên máy chủ",
|
||||
"domain_quota_m": "Tổng hạn ngạch tên miền (MiB)",
|
||||
"dry": "Mô phỏng đồng bộ hóa",
|
||||
"enc_method": "Phương thức mã hóa",
|
||||
"exclude": "Loại trừ đối tượng (biểu thức chính quy)",
|
||||
"full_name": "Tên đầy đủ",
|
||||
"gal": "Danh sách địa chỉ toàn cục",
|
||||
"gal_info": "GAL chứa tất cả các đối tượng của một tên miền và không thể được chỉnh sửa bởi bất kỳ người dùng nào. Thông tin rảnh/bận trong SOGo sẽ bị thiếu nếu vô hiệu hóa! <b>Khởi động lại SOGo để áp dụng thay đổi.</b>",
|
||||
"generate": "Tạo",
|
||||
"goto_ham": "\"Học là <span class=\"text-success\"><b>thư bình thường</b></span>",
|
||||
"goto_null": "Loại bỏ thư một cách thầm lặng",
|
||||
"goto_spam": "Học là <span class=\"text-danger\"><b>thư rác</b></span>",
|
||||
"hostname": "Máy chủ",
|
||||
"inactive": "Không hoạt động",
|
||||
"internal": "Nội bộ",
|
||||
"internal_info": "Bí danh nội bộ chỉ có thể truy cập từ tên miền sở hữu hoặc tên miền bí danh.",
|
||||
"kind": "Loại",
|
||||
"mailbox_quota_def": "Hạn ngạch hộp thư mặc định",
|
||||
"mailbox_quota_m": "Hạn ngạch tối đa mỗi hộp thư (MiB)",
|
||||
"mailbox_username": "Tên người dùng (phần bên trái của địa chỉ email)",
|
||||
"max_aliases": "Số lượng bí danh tối đa có thể tạo",
|
||||
"max_mailboxes": "Số lượng hộp thư tối đa có thể tạo",
|
||||
"mins_interval": "Khoảng thời gian kiểm tra (phút)",
|
||||
"multiple_bookings": "Đặt chỗ nhiều lần",
|
||||
"nexthop": "Bước nhảy tiếp theo",
|
||||
"password": "Mật khẩu",
|
||||
"password_repeat": "Xác nhận mật khẩu (nhập lại)",
|
||||
"port": "Cổng",
|
||||
"post_domain_add": "Container SOGo, \\\"sogo-mailcow\\\", cần được khởi động lại sau khi thêm tên miền mới!<br><br>Ngoài ra, cấu hình DNS của tên miền cần được xem xét. Khi cấu hình DNS được phê duyệt, khởi động lại \\\"acme-mailcow\\\" để tự động tạo chứng chỉ cho tên miền mới của bạn (autoconfig.<domain>, autodiscover.<domain>).<br>Bước này là tùy chọn và sẽ được thử lại sau mỗi 24 giờ.",
|
||||
"private_comment": "Bình luận riêng tư",
|
||||
"public_comment": "Bình luận công khai",
|
||||
"quota_mb": "Hạn ngạch (MiB)",
|
||||
"relay_all": "Chuyển tiếp tất cả người nhận",
|
||||
"relay_all_info": "↪ Nếu bạn chọn <b>không</b> chuyển tiếp tất cả người nhận, bạn sẽ cần thêm một hộp thư (\"ẩn\") cho từng người nhận cần được chuyển tiếp.",
|
||||
"relay_domain": "Chuyển tiếp tên miền này",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Thông tin</div> Bạn có thể định nghĩa ánh xạ vận chuyển cho đích tùy chỉnh cho tên miền này. Nếu không được đặt, tra cứu MX sẽ được thực hiện.",
|
||||
"relay_unknown_only": "Chỉ chuyển tiếp hộp thư không tồn tại. Hộp thư hiện có sẽ được gửi cục bộ.",
|
||||
"relayhost_wrapped_tls_info": "Vui lòng <b>không</b> sử dụng các cổng được bọc TLS (thường được sử dụng trên cổng 465).<br>\nSử dụng bất kỳ cổng không được bọc nào và sử dụng STARTTLS. Chính sách TLS để thực thi TLS có thể được tạo trong \"Ánh xạ chính sách TLS\".",
|
||||
"select": "Vui lòng chọn...",
|
||||
"select_domain": "Vui lòng chọn tên miền trước",
|
||||
"sieve_desc": "Mô tả ngắn",
|
||||
"sieve_type": "Loại bộ lọc",
|
||||
"skipcrossduplicates": "Bỏ qua tin nhắn trùng lặp giữa các thư mục (ai đến trước được phục vụ trước)",
|
||||
"subscribeall": "Đăng ký tất cả thư mục",
|
||||
"syncjob": "Thêm công việc đồng bộ",
|
||||
"syncjob_hint": "Lưu ý rằng mật khẩu cần được lưu dưới dạng văn bản thuần!",
|
||||
"tags": "Thẻ",
|
||||
"target_address": "Địa chỉ chuyển tiếp",
|
||||
"target_address_info": "<small>Địa chỉ email đầy đủ (phân cách bằng dấu phẩy).</small>",
|
||||
"target_domain": "Tên miền đích",
|
||||
"timeout1": "Thời gian chờ kết nối đến máy chủ từ xa",
|
||||
"timeout2": "Thời gian chờ kết nối đến máy chủ cục bộ",
|
||||
"username": "Tên người dùng",
|
||||
"validate": "Xác thực",
|
||||
"validation_success": "Xác thực thành công"
|
||||
},
|
||||
"admin": {
|
||||
"access": "Truy cập",
|
||||
"action": "Hành động",
|
||||
"activate_api": "Kích hoạt API",
|
||||
"activate_send": "Kích hoạt nút gửi",
|
||||
"active": "Đang hoạt động",
|
||||
"active_rspamd_settings_map": "Ánh xạ cài đặt đang hoạt động",
|
||||
"add": "Thêm",
|
||||
"add_admin": "Thêm quản trị viên",
|
||||
"add_domain_admin": "Thêm quản trị viên tên miền",
|
||||
"add_forwarding_host": "Thêm máy chủ chuyển tiếp",
|
||||
"add_relayhost": "Thêm vận chuyển phụ thuộc người gửi",
|
||||
"add_relayhost_hint": "Vui lòng lưu ý rằng dữ liệu xác thực, nếu có, sẽ được lưu trữ dưới dạng văn bản thuần.",
|
||||
"add_row": "Thêm hàng",
|
||||
"add_settings_rule": "Thêm quy tắc cài đặt",
|
||||
"add_transport": "Thêm vận chuyển",
|
||||
"add_transports_hint": "Vui lòng lưu ý rằng dữ liệu xác thực, nếu có, sẽ được lưu trữ dưới dạng văn bản thuần.",
|
||||
"additional_rows": " hàng bổ sung đã được thêm",
|
||||
"admin": "Quản trị viên",
|
||||
"admin_details": "Chỉnh sửa chi tiết quản trị viên",
|
||||
"admin_domains": "Gán tên miền",
|
||||
"admins": "Những quản trị viên",
|
||||
"admins_ldap": "Quản trị viên LDAP",
|
||||
"admin_quicklink": "Ẩn liên kết nhanh đến trang đăng nhập quản trị",
|
||||
"advanced_settings": "Cài đặt nâng cao",
|
||||
"allowed_methods": "Phương thức cho phép kiểm soát truy cập",
|
||||
"allowed_origins": "Nguồn gốc cho phép kiểm soát truy cập",
|
||||
"api_allow_from": "Cho phép truy cập API từ các IP/ký hiệu mạng CIDR này",
|
||||
"api_info": "API đang được phát triển. Tài liệu có thể được tìm thấy tại <a href=\"/api\">/api</a>",
|
||||
"api_key": "Khóa API",
|
||||
"api_read_only": "Truy cập chỉ đọc",
|
||||
"api_read_write": "Truy cập đọc-ghi",
|
||||
"api_skip_ip_check": "Bỏ qua kiểm tra IP cho API",
|
||||
"app_hide": "Ẩn khi đăng nhập",
|
||||
"app_links": "Liên kết ứng dụng",
|
||||
"app_name": "Tên ứng dụng",
|
||||
"apps_name": "Tên \"Ứng dụng mailcow\"",
|
||||
"arrival_time": "Thời gian đến (giờ máy chủ)",
|
||||
"authed_user": "Người dùng đã xác thực",
|
||||
"ays": "Bạn có chắc chắn muốn tiếp tục không?",
|
||||
"ban_list_info": "Xem danh sách IP bị cấm bên dưới: <b>mạng (thời gian cấm còn lại) - [hành động]</b>.<br />IP trong hàng đợi bỏ cấm sẽ được xóa khỏi danh sách cấm hoạt động trong vài giây.<br />Nhãn đỏ cho biết lệnh cấm vĩnh viễn đang hoạt động bởi danh sách từ chối.",
|
||||
"change_logo": "Thay đổi logo",
|
||||
"logo_normal_label": "Bình thường",
|
||||
"logo_dark_label": "Đảo ngược cho chế độ tối",
|
||||
"configuration": "Cấu hình",
|
||||
"convert_html_to_text": "Chuyển đổi HTML thành văn bản thuần",
|
||||
"copy_to_clipboard": "Văn bản đã được sao chép vào bộ nhớ tạm!",
|
||||
"cors_settings": "Cài đặt CORS",
|
||||
"credentials_transport_warning": "<b>Cảnh báo</b>: Thêm một mục ánh xạ vận chuyển mới sẽ cập nhật thông tin xác thực cho tất cả các mục có cột bước nhảy tiếp theo khớp.",
|
||||
"customer_id": "ID Khách hàng",
|
||||
"customize": "Tùy chỉnh",
|
||||
"login_page": "Trang đăng nhập",
|
||||
"destination": "Đích đến",
|
||||
"dkim_add_key": "Thêm khóa ARC/DKIM",
|
||||
"dkim_domains_selector": "Bộ chọn",
|
||||
"dkim_domains_wo_keys": "Chọn tên miền thiếu khóa",
|
||||
"dkim_from": "Từ",
|
||||
"dkim_from_title": "Tên miền nguồn để sao chép dữ liệu",
|
||||
"dkim_key_length": "Độ dài khóa DKIM (bits)",
|
||||
"dkim_key_missing": "Thiếu khóa",
|
||||
"dkim_key_unused": "Khóa không được sử dụng",
|
||||
"dkim_key_valid": "Khóa hợp lệ",
|
||||
"dkim_keys": "Khóa ARC/DKIM",
|
||||
"dkim_overwrite_key": "Ghi đè khóa DKIM hiện có",
|
||||
"dkim_private_key": "Khóa riêng tư",
|
||||
"dkim_to": "Đến",
|
||||
"dkim_to_title": "Tên miền đích - sẽ bị ghi đè",
|
||||
"domain": "Tên miền",
|
||||
"domain_admin": "Quản trị viên tên miền",
|
||||
"domain_admins": "Các quản trị viên tên miền",
|
||||
"domainadmin_quicklink": "Ẩn liên kết nhanh đến trang đăng nhập quản trị viên tên miền",
|
||||
"domain_s": "Tên miền/s",
|
||||
"duplicate": "Nhân bản",
|
||||
"duplicate_dkim": "Nhân bản bản ghi DKIM",
|
||||
"edit": "Chỉnh sửa",
|
||||
"empty": "Không có kết quả",
|
||||
"excludes": "Loại trừ những người nhận này",
|
||||
"f2b_ban_time": "Thời gian cấm (giây)",
|
||||
"f2b_ban_time_increment": "Thời gian cấm tăng dần với mỗi lần cấm",
|
||||
"f2b_blacklist": "Mạng/máy chủ bị từ chối",
|
||||
"f2b_filter": "Bộ lọc biểu thức chính quy",
|
||||
"f2b_list_info": "Một máy chủ hoặc mạng bị từ chối sẽ luôn có quyền ưu tiên cao hơn một thực thể trong danh sách cho phép. <b>Cập nhật danh sách sẽ mất vài giây để được áp dụng.</b>",
|
||||
"f2b_manage_external": "Quản lý Fail2Ban từ bên ngoài",
|
||||
"f2b_manage_external_info": "Fail2ban sẽ vẫn duy trì danh sách cấm, nhưng sẽ không chủ động đặt quy tắc để chặn lưu lượng. Sử dụng danh sách cấm được tạo bên dưới để chặn lưu lượng từ bên ngoài.",
|
||||
"f2b_max_attempts": "Số lần thử tối đa",
|
||||
"f2b_max_ban_time": "Thời gian cấm tối đa (giây)",
|
||||
"f2b_netban_ipv4": "Kích thước mạng con IPv4 để áp dụng lệnh cấm (8-32)",
|
||||
"f2b_netban_ipv6": "Kích thước mạng con IPv6 để áp dụng lệnh cấm (8-128",
|
||||
"f2b_parameters": "Tham số Fail2ban",
|
||||
"f2b_regex_info": "Nhật ký được xem xét: SOGo, Postfix, Dovecot, PHP-FPM.",
|
||||
"f2b_retry_window": "Cửa sổ thử lại (giây) cho số lần thử tối đa",
|
||||
"f2b_whitelist": "Mạng/máy chủ được cho phép",
|
||||
"filter": "Bộ lọc",
|
||||
"filter_table": "Bảng bộ lọc",
|
||||
"force_sso_text": "Nếu nhà cung cấp OIDC bên ngoài được cấu hình, tùy chọn này sẽ ẩn biểu mẫu đăng nhập mailcow mặc định và chỉ hiển thị nút Đăng nhập một lần",
|
||||
"force_sso": "Vô hiệu hóa đăng nhập mailcow và chỉ hiển thị Đăng nhập một lần",
|
||||
"forwarding_hosts": "Máy chủ chuyển tiếp",
|
||||
"forwarding_hosts_add_hint": "Bạn có thể chỉ định địa chỉ IPv4/IPv6, mạng theo ký hiệu CIDR, tên máy chủ (sẽ được phân giải thành địa chỉ IP), hoặc tên miền (sẽ được phân giải thành địa chỉ IP bằng cách truy vấn bản ghi SPF hoặc, nếu không có, bản ghi MX).",
|
||||
"forwarding_hosts_hint": "Tin nhắn đến được chấp nhận vô điều kiện từ bất kỳ máy chủ nào được liệt kê ở đây. Các máy chủ này sau đó không bị kiểm tra với DNSBL hoặc danh sách xám. Thư rác nhận từ chúng không bao giờ bị từ chối, nhưng có thể được chuyển vào thư mục Rác. Công dụng phổ biến nhất cho việc này là chỉ định các máy chủ thư mà bạn đã thiết lập quy tắc chuyển tiếp email đến cho máy chủ mailcow của bạn.",
|
||||
"from": "Từ",
|
||||
"generate": "tạo",
|
||||
"guid": "GUID - ID phiên bản duy nhất",
|
||||
"guid_and_license": "GUID & Giấy phép",
|
||||
"hash_remove_info": "Xóa một giá trị băm giới hạn tốc độ (nếu vẫn tồn tại) sẽ đặt lại hoàn toàn bộ đếm của nó.<br\n Mỗi giá trị băm được chỉ định bằng một màu riêng biệt.",
|
||||
"help_text": "Ghi đè văn bản trợ giúp bên dưới mặt nạ đăng nhập (cho phép HTML)",
|
||||
"host": "Máy chủ",
|
||||
"html": "HTML",
|
||||
"iam": "Nhà cung cấp danh tính",
|
||||
"iam_attribute_field": "Trường thuộc tính",
|
||||
"iam_authorize_url": "Điểm cuối ủy quyền",
|
||||
"iam_auth_flow": "Luồng xác thực",
|
||||
"iam_auth_flow_info": "Ngoài Luồng mã ủy quyền (Luồng chuẩn trong Keycloak), được sử dụng cho đăng nhập một lần, mailcow còn hỗ trợ Luồng xác thực với thông tin xác thực trực tiếp. Luồng mật khẩu thư cố gắng xác thực thông tin người dùng bằng cách sử dụng API REST quản trị Keycloak. mailcow lấy mật khẩu đã băm từ thuộc tính <code>mailcow_password</code>, được ánh xạ trong Keycloak.",
|
||||
"iam_basedn": "DN cơ sở",
|
||||
"iam_client_id": "ID khách hàng",
|
||||
"iam_client_secret": "Bí mật khách hàng",
|
||||
"iam_client_scopes": "Phạm vi khách hàng",
|
||||
"iam_default_template": "Mẫu mặc định",
|
||||
"iam_default_template_description": "Nếu không có mẫu nào được gán cho người dùng, mẫu mặc định sẽ được sử dụng để tạo hộp thư, nhưng không dùng để cập nhật hộp thư.",
|
||||
"iam_description": "Cấu hình Nhà cung cấp bên ngoài cho Xác thực<br>Hộp thư của người dùng sẽ được tự động tạo khi họ đăng nhập lần đầu, với điều kiện ánh xạ thuộc tính đã được thiết lập.",
|
||||
"iam_extra_permission": "Để các cài đặt sau hoạt động, ứng dụng khách mailcow trong Keycloak cần một <code>Tài khoản dịch vụ</code> và quyền <code>xem người dùng</code>.",
|
||||
"iam_host": "Máy chủ",
|
||||
"iam_host_info": "Nhập một hoặc nhiều máy chủ LDAP, phân cách bằng dấu phẩy.",
|
||||
"iam_import_users": "Nhập người dùng",
|
||||
"iam_login_provisioning": "Tự động tạo người dùng khi đăng nhập",
|
||||
"iam_mapping": "Ánh xạ thuộc tính",
|
||||
"iam_bindpass": "Mật khẩu ràng buộc",
|
||||
"iam_periodic_full_sync": "Đồng bộ hóa đầy đủ định kỳ",
|
||||
"iam_port": "Cổng",
|
||||
"iam_realm": "Vùng",
|
||||
"iam_redirect_url": "URL chuyển hướng",
|
||||
"iam_rest_flow": "Luồng mật khẩu thư",
|
||||
"iam_server_url": "URL máy chủ",
|
||||
"iam_sso": "Đăng nhập một lần",
|
||||
"iam_sync_interval": "Khoảng thời gian đồng bộ / nhập (phút)",
|
||||
"iam_test_connection": "Kiểm tra kết nối",
|
||||
"iam_token_url": "Điểm cuối token",
|
||||
"iam_userinfo_url": "Điểm cuối thông tin người dùng",
|
||||
"iam_username_field": "Trường tên người dùng",
|
||||
"iam_binddn": "DN ràng buộc",
|
||||
"iam_use_ssl": "Sử dụng SSL",
|
||||
"iam_use_ssl_info": "Nếu bật SSL và cổng được đặt là 389, nó sẽ tự động được ghi đè để sử dụng cổng 636.",
|
||||
"iam_use_tls": "Sử dụng StartTLS",
|
||||
"iam_use_tls_info": "Nếu bật TLS, bạn phải sử dụng cổng mặc định cho máy chủ LDAP của bạn (389). Không thể sử dụng các cổng SSL.",
|
||||
"iam_version": "Phiên bản",
|
||||
"ignore_ssl_error": "Bỏ qua lỗi SSL",
|
||||
"import": "Nhập",
|
||||
"import_private_key": "Nhập khóa riêng tư",
|
||||
"in_use_by": "Đang được sử dụng bởi",
|
||||
"inactive": "Không hoạt động",
|
||||
"include_exclude": "Bao gồm/Loại trừ",
|
||||
"include_exclude_info": "Mặc định - khi không có lựa chọn - <b>tất cả hộp thư</b> được đề cập",
|
||||
"includes": "Bao gồm những người nhận này",
|
||||
"ip_check": "Kiểm tra IP",
|
||||
"ip_check_disabled": "Kiểm tra IP đã bị vô hiệu hóa. Bạn có thể bật nó trong<br> <strong>Hệ thống > Cấu hình > Tùy chọn > Tùy chỉnh</strong>",
|
||||
"ip_check_opt_in": "Chọn tham gia sử dụng dịch vụ bên thứ ba <strong>ipv4.mailcow.email</strong> và <strong>ipv6.mailcow.email</strong> để phân giải địa chỉ IP bên ngoài.",
|
||||
"is_mx_based": "Dựa trên MX",
|
||||
"last_applied": "Áp dụng lần cuối",
|
||||
"license_info": "Giấy phép không bắt buộc nhưng giúp phát triển thêm.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"Đặt hàng SAL\">Đăng ký GUID của bạn tại đây</a> hoặc <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Đặt hàng hỗ trợ\">mua hỗ trợ cho cài đặt mailcow của bạn.</a>",
|
||||
"link": "Liên kết",
|
||||
"loading": "Vui lòng đợi...",
|
||||
"login_time": "Thời gian đăng nhập",
|
||||
"logo_info": "Hình ảnh của bạn sẽ được điều chỉnh theo chiều cao 40px cho thanh điều hướng trên cùng và chiều rộng tối đa 250px cho trang bắt đầu. Khuyến nghị sử dụng đồ họa có thể thay đổi kích thước.",
|
||||
"lookup_mx": "Đích đến là một biểu thức chính quy để so khớp với tên MX (<code>.*.google.com</code> để định tuyến tất cả thư nhắm đến MX kết thúc bằng google.com qua bước nhảy này)",
|
||||
"main_name": "Tên \"Giao diện mailcow\"",
|
||||
"merged_vars_hint": "Các hàng bị mờ đã được hợp nhất từ <code>vars.(local.)inc.php</code> và không thể sửa đổi.",
|
||||
"message": "Tin nhắn",
|
||||
"message_size": "Kích thước tin nhắn",
|
||||
"nexthop": "Bước nhảy tiếp theo",
|
||||
"needs_restart": "cần khởi động lại",
|
||||
"no_active_bans": "Không có lệnh cấm đang hoạt động",
|
||||
"no_new_rows": "Không có hàng nào khác",
|
||||
"no_record": "Không có bản ghi",
|
||||
"oauth2_apps": "Ứng dụng OAuth2",
|
||||
"oauth2_add_client": "Thêm ứng dụng khách OAuth2",
|
||||
"oauth2_client_id": "ID ứng dụng khách",
|
||||
"oauth2_client_secret": "Bí mật ứng dụng khách",
|
||||
"oauth2_info": "Triển khai OAuth2 hỗ trợ loại cấp phép \"Mã ủy quyền\" và cấp token làm mới.<br>\nMáy chủ cũng tự động cấp token làm mới mới sau khi token làm mới đã được sử dụng.<br><br>\n• Phạm vi mặc định là <i>profile</i>. Chỉ người dùng hộp thư mới có thể được xác thực qua OAuth2. Nếu tham số phạm vi bị bỏ qua, nó sẽ trở về <i>profile</i>.<br>\n• Tham số <i>state</i> phải được gửi bởi ứng dụng khách như một phần của yêu cầu ủy quyền.<br><br>\nĐường dẫn cho các yêu cầu đến API OAuth2: <br>\n<ul>\n<li>Điểm cuối ủy quyền: <code>/oauth/authorize</code></li>\n<li>Điểm cuối token: <code>/oauth/token</code></li>\n<li>Trang tài nguyên: <code>/oauth/profile</code></li>\n</ul>\nTạo lại bí mật ứng dụng khách sẽ không làm hết hạn các mã ủy quyền hiện có, nhưng chúng sẽ không thể làm mới token của họ.<br><br>\nThu hồi token ứng dụng khách sẽ gây ra việc chấm dứt ngay lập tức tất cả các phiên hoạt động. Tất cả ứng dụng khách cần xác thực lại.",
|
||||
"oauth2_redirect_uri": "URI chuyển hướng",
|
||||
"oauth2_renew_secret": "Tạo bí mật ứng dụng khách mới",
|
||||
"oauth2_revoke_tokens": "Thu hồi tất cả token ứng dụng khách",
|
||||
"optional": "tùy chọn",
|
||||
"options": "Các tùy chọn",
|
||||
"password": "Mật khẩu",
|
||||
"password_length": "Độ dài mật khẩu",
|
||||
"password_policy": "Chính sách mật khẩu",
|
||||
"password_policy_chars": "Phải chứa ít nhất một ký tự chữ cái",
|
||||
"password_policy_length": "Độ dài mật khẩu tối thiểu là %d",
|
||||
"password_policy_lowerupper": "Phải chứa ký tự viết thường và viết hoa",
|
||||
"password_policy_numbers": "Phải chứa ít nhất một số",
|
||||
"password_policy_special_chars": "Phải chứa ký tự đặc biệt",
|
||||
"password_repeat": "Xác nhận mật khẩu (nhập lại)",
|
||||
"password_reset_info": "Nếu không cung cấp email khôi phục, chức năng này không thể được sử dụng.",
|
||||
"password_reset_settings": "Cài đặt khôi phục mật khẩu",
|
||||
"password_reset_tmpl_html": "Mẫu HTML",
|
||||
"password_reset_tmpl_text": "Mẫu văn bản",
|
||||
"password_settings": "Cài đặt mật khẩu",
|
||||
"priority": "Độ ưu tiên",
|
||||
"private_key": "Khóa riêng tư",
|
||||
"quarantine": "Cách ly",
|
||||
"quarantine_bcc": "Gửi một bản sao của tất cả thông báo (BCC) đến người nhận này:<br><small>Để trống để vô hiệu hóa. <b>Thư không ký, không kiểm tra. Chỉ nên gửi nội bộ.</b></small>",
|
||||
"quarantine_exclude_domains": "Loại trừ tên miền và tên miền bí danh",
|
||||
"quarantine_max_age": "Tuổi tối đa theo ngày<br><small>Giá trị phải bằng hoặc lớn hơn 1 ngày.</small>",
|
||||
"quarantine_max_score": "Bỏ thông báo nếu điểm thư rác của một thư cao hơn giá trị này:<br><small>Mặc định là 9999.0</small>",
|
||||
"quarantine_max_size": "Kích thước tối đa tính bằng MiB (các phần tử lớn hơn sẽ bị loại bỏ):<br><small>0 <b>không</b> có nghĩa là không giới hạn.</small>",
|
||||
"quarantine_notification_html": "Mẫu email thông báo:<br><small>Để trống để khôi phục mẫu mặc định.</small>",
|
||||
"quarantine_notification_sender": "Người gửi email thông báo",
|
||||
"quarantine_notification_subject": "Chủ đề email thông báo",
|
||||
"quarantine_redirect": "<b>Chuyển hướng tất cả thông báo</b> đến người nhận này:<br><small>Để trống để vô hiệu hóa. <b>Thư không ký, không kiểm tra. Chỉ nên gửi nội bộ.</b></small>",
|
||||
"quarantine_release_format": "Định dạng của các mục được phát hành",
|
||||
"quarantine_release_format_att": "Dưới dạng tệp đính kèm",
|
||||
"quarantine_release_format_raw": "Bản gốc không sửa đổi",
|
||||
"quarantine_retention_size": "ưu giữ cho mỗi hộp thư:<br><small>0 có nghĩa là <b>không hoạt động</b>.</small>",
|
||||
"quicklink_text": "Hiển thị hoặc ẩn liên kết nhanh đến các trang đăng nhập khác dưới biểu mẫu đăng nhập",
|
||||
"quota_notification_html": "Mẫu email thông báo:<br><small>Để trống để khôi phục mẫu mặc định.</small>",
|
||||
"quota_notification_sender": "Người gửi email thông báo",
|
||||
"quota_notification_subject": "Chủ đề email thông báo",
|
||||
"quota_notifications": "Thông báo hạn ngạch",
|
||||
"quota_notifications_info": "Thông báo hạn ngạch được gửi cho người dùng một lần khi vượt quá 80% và một lần khi vượt quá 95% mức sử dụng.",
|
||||
"quota_notifications_vars": "{{percent}} bằng hạn ngạch hiện tại của người dùng<br>{{username}} là tên hộp thư",
|
||||
"queue_unban": "bỏ cấm",
|
||||
"r_active": "Hạn chế đang hoạt động",
|
||||
"r_inactive": "Hạn chế không hoạt động",
|
||||
"r_info": "Các phần tử bị mờ/vô hiệu hóa trong danh sách hạn chế đang hoạt động không được mailcow công nhận là hạn chế hợp lệ và không thể di chuyển. Các hạn chế không xác định sẽ vẫn được đặt theo thứ tự xuất hiện. <br>Bạn có thể thêm phần tử mới trong <code>inc/vars.local.inc.php</code> để có thể bật/tắt chúng.",
|
||||
"rate_name": "Tên tỷ lệ",
|
||||
"recipients": "Người nhận",
|
||||
"refresh": "Làm mới",
|
||||
"regen_api_key": "Tạo lại khóa API",
|
||||
"regex_maps": "Ánh xạ biểu thức chính quy",
|
||||
"relay_from": "Địa chỉ \"Từ:\"",
|
||||
"relay_rcpt": "Địa chỉ \"Đến:\"",
|
||||
"relay_run": "Chạy thử",
|
||||
"relayhosts": "Vận chuyển phụ thuộc người gửi",
|
||||
"relayhosts_hint": "Xác định vận chuyển phụ thuộc người gửi để có thể chọn chúng trong hộp thoại cấu hình tên miền.<br>\nDịch vụ vận chuyển luôn là \"smtp:\" và do đó sẽ thử TLS khi được cung cấp. TLS được bọc (SMTPS) không được hỗ trợ. Cài đặt chính sách TLS gửi đi riêng của người dùng được tính đến.<br>\nẢnh hưởng đến các tên miền được chọn bao gồm cả tên miền bí danh.",
|
||||
"remove": "Xóa",
|
||||
"remove_row": "Xóa hàng",
|
||||
"reset_default": "Đặt lại về mặc định",
|
||||
"reset_limit": "Xóa giá trị băm",
|
||||
"reset_password_vars": "<code>{{link}}</code> Liên kết đặt lại mật khẩu đã tạo<br><code>{{username}}</code> Tên hộp thư của người dùng yêu cầu đặt lại mật khẩu<br><code>{{username2}}</code> Tên hộp thư khôi phục<br><code>{{date}}</code> Ngày yêu cầu đặt lại mật khẩu được thực hiện<br><code>{{token_lifetime}}</code> Thời gian sống của token tính bằng phút<br><code>{{hostname}}</code> Tên máy chủ mailcow",
|
||||
"restore_template": "Để trống để khôi phục mẫu mặc định.",
|
||||
"routing": "Định tuyến",
|
||||
"rsetting_add_rule": "Thêm quy tắc",
|
||||
"rsetting_content": "Nội dung quy tắc",
|
||||
"rsetting_desc": "Mô tả ngắn",
|
||||
"rsetting_no_selection": "Vui lòng chọn một quy tắc",
|
||||
"rsetting_none": "Không có quy tắc nào",
|
||||
"rsettings_insert_preset": "Chèn mẫu ví dụ \"%s\"",
|
||||
"rsettings_preset_1": "Vô hiệu hóa tất cả trừ DKIM và giới hạn tốc độ cho người dùng đã xác thực",
|
||||
"rsettings_preset_2": "Quản trị viên bưu điện muốn thư rác",
|
||||
"rsettings_preset_3": "Chỉ cho phép người gửi cụ thể cho một hộp thư (ví dụ: sử dụng như hộp thư nội bộ)",
|
||||
"rsettings_preset_4": "Vô hiệu hóa Rspamd cho một tên miền",
|
||||
"rspamd_com_settings": "Tên cài đặt sẽ được tự động tạo, vui lòng xem các mẫu ví dụ bên dưới. Để biết thêm chi tiết, xem <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Tài liệu Rspamd</a>",
|
||||
"rspamd_global_filters": "Ánh xạ bộ lọc toàn cục",
|
||||
"rspamd_global_filters_agree": "Tôi sẽ cẩn thận!",
|
||||
"rspamd_global_filters_info": "Ánh xạ bộ lọc toàn cục chứa các loại danh sách từ chối và cho phép toàn cục khác nhau.",
|
||||
"rspamd_global_filters_regex": "Tên của chúng giải thích mục đích sử dụng. Tất cả nội dung phải chứa biểu thức chính quy hợp lệ theo định dạng \"/mẫu/tùy chọn\" (ví dụ: <code>/.+@domain.tld/i</code>).<br>\nMặc dù kiểm tra cơ bản được thực hiện trên mỗi dòng của regex, chức năng của Rspamd có thể bị hỏng nếu nó không đọc được cú pháp chính xác.<br>\nRspamd sẽ cố gắng đọc nội dung ánh xạ khi thay đổi. Nếu bạn gặp vấn đề, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">khởi động lại Rspamd</a> để bắt buộc tải lại ánh xạ.<br>Các phần tử trong danh sách từ chối được loại trừ khỏi cách ly.",
|
||||
"rspamd_settings_map": "Ánh xạ cài đặt Rspamd",
|
||||
"sal_level": "Cấp độ Moo",
|
||||
"save": "Lưu thay đổi",
|
||||
"search_domain_da": "Tìm kiếm tên miền",
|
||||
"send": "Gửi",
|
||||
"sender": "Người gửi",
|
||||
"service": "Dịch vụ",
|
||||
"service_id": "ID Dịch vụ",
|
||||
"source": "Nguồn",
|
||||
"spamfilter": "Bộ lọc thư rác",
|
||||
"subject": "Chủ đề",
|
||||
"success": "Thành công",
|
||||
"sys_mails": "Thư hệ thống",
|
||||
"task": "Nhiệm vụ",
|
||||
"text": "Văn bản",
|
||||
"time": "Thời gian",
|
||||
"title": "Tiêu đề",
|
||||
"title_name": "Tiêu đề trang web \"Giao diện mailcow\"",
|
||||
"to_top": "Về đầu trang",
|
||||
"transport_dest_format": "Regex hoặc cú pháp: example.org, .example.org, *, box@example.org (nhiều giá trị có thể được phân cách bằng dấu phẩy)",
|
||||
"transport_maps": "Ánh xạ vận chuyển",
|
||||
"transport_test_rcpt_info": "• Sử dụng null@hosted.mailcow.de để kiểm tra chuyển tiếp đến đích nước ngoài.",
|
||||
"transports_hint": "• Một mục ánh xạ vận chuyển <b>ghi đè</b> một ánh xạ vận chuyển phụ thuộc người gửi</b>.<br>\n• Vận chuyển dựa trên MX được ưu tiên sử dụng.<br>\n• Cài đặt chính sách TLS gửi đi cho từng người dùng bị bỏ qua và chỉ có thể được thực thi bởi các mục ánh xạ chính sách TLS.<br>\n• Dịch vụ vận chuyển cho các vận chuyển đã định nghĩa luôn là \"smtp:\" và do đó sẽ thử TLS khi được cung cấp. TLS được bọc (SMTPS) không được hỗ trợ.<br>\n• Địa chỉ khớp với \"/localhost$/\" sẽ luôn được vận chuyển qua \"local:\", do đó đích \"*\" sẽ không áp dụng cho những địa chỉ đó.<br>\n• Để xác định thông tin xác thực cho bước nhảy tiếp theo ví dụ \"[host]:25\", Postfix <b>luôn</b> truy vấn \"host\" trước khi tìm kiếm \"[host]:25\". Hành vi này khiến không thể sử dụng \"host\" và \"[host]:25\" cùng một lúc.",
|
||||
"ui_footer": "Chân trang (cho phép HTML)",
|
||||
"ui_header_announcement": "Thông báo",
|
||||
"ui_header_announcement_active": "Đặt thông báo hoạt động",
|
||||
"ui_header_announcement_content": "Văn bản (cho phép HTML)",
|
||||
"ui_header_announcement_help": "Thông báo hiển thị cho tất cả người dùng đã đăng nhập và trên màn hình đăng nhập của giao diện người dùng.",
|
||||
"ui_header_announcement_select": "Chọn loại thông báo",
|
||||
"ui_header_announcement_type": "Loại",
|
||||
"ui_header_announcement_type_danger": "Rất quan trọng",
|
||||
"ui_header_announcement_type_info": "Thông tin",
|
||||
"ui_header_announcement_type_warning": "Quan trọng",
|
||||
"ui_texts": "Nhãn và văn bản giao diện người dùng",
|
||||
"unban_pending": "đang chờ bỏ cấm",
|
||||
"unchanged_if_empty": "Nếu không thay đổi hãy để trống",
|
||||
"upload": "Tải lên",
|
||||
"username": "Tên người dùng",
|
||||
"user_link": "Liên kết người dùng",
|
||||
"user_quicklink": "Ẩn liên kết nhanh đến trang đăng nhập người dùng",
|
||||
"validate_license_now": "Xác thực GUID với máy chủ giấy phép",
|
||||
"verify": "Xác minh",
|
||||
"yes": "✓"
|
||||
},
|
||||
"danger": {
|
||||
"access_denied": "Truy cập bị từ chối hoặc dữ liệu biểu mẫu không hợp lệ",
|
||||
"alias_domain_invalid": "Tên miền bí danh %s không hợp lệ",
|
||||
"alias_empty": "Địa chỉ bí danh không được để trống",
|
||||
"alias_goto_identical": "Địa chỉ bí danh và địa chỉ chuyển tiếp không được giống nhau",
|
||||
"alias_invalid": "Địa chỉ bí danh %s không hợp lệ",
|
||||
"aliasd_targetd_identical": "Tên miền bí danh không được giống với tên miền đích: %s",
|
||||
"aliases_in_use": "Số bí danh tối đa phải lớn hơn hoặc bằng %d",
|
||||
"app_name_empty": "Tên ứng dụng không được để trống",
|
||||
"app_passwd_id_invalid": "ID mật khẩu ứng dụng %s không hợp lệ",
|
||||
"authsource_in_use": "Nhà cung cấp danh tính không thể thay đổi hoặc xóa vì hiện đang được sử dụng bởi một hoặc nhiều người dùng.",
|
||||
"bcc_empty": "Đích BCC không được để trống",
|
||||
"bcc_exists": "Một ánh xạ BCC %s đã tồn tại cho loại %s",
|
||||
"bcc_must_be_email": "Đích BCC %s không phải là địa chỉ email hợp lệ",
|
||||
"comment_too_long": "Bình luận quá dài, cho phép tối đa 160 ký tự",
|
||||
"cors_invalid_method": "Phương thức Allow-Method được chỉ định không hợp lệ",
|
||||
"cors_invalid_origin": "Allow-Origin được chỉ định không hợp lệ",
|
||||
"defquota_empty": "Hạn ngạch mặc định cho mỗi hộp thư không được là 0.",
|
||||
"demo_mode_enabled": "Chế độ Demo đang được bật",
|
||||
"description_invalid": "Mô tả tài nguyên cho %s không hợp lệ",
|
||||
"dkim_domain_or_sel_exists": "Một khóa DKIM cho \"%s\" đã tồn tại và sẽ không bị ghi đè",
|
||||
"dkim_domain_or_sel_invalid": "Tên miền hoặc bộ chọn DKIM không hợp lệ: %s",
|
||||
"domain_cannot_match_hostname": "Tên miền không thể trùng với tên máy chủ",
|
||||
"domain_exists": "Tên miền %s đã tồn tại",
|
||||
"domain_invalid": "Tên miền trống hoặc không hợp lệ",
|
||||
"domain_not_empty": "Không thể xóa tên miền %s không trống",
|
||||
"domain_not_found": "Không tìm thấy tên miền %s",
|
||||
"domain_quota_m_in_use": "Hạn ngạch tên miền phải lớn hơn hoặc bằng %s MiB",
|
||||
"extended_sender_acl_denied": "thiếu ACL để đặt địa chỉ người gửi bên ngoài",
|
||||
"extra_acl_invalid": "Địa chỉ người gửi bên ngoài \"%s\" không hợp lệ",
|
||||
"extra_acl_invalid_domain": "Người gửi bên ngoài \"%s\" sử dụng tên miền không hợp lệ",
|
||||
"fido2_verification_failed": "Xác minh FIDO2 thất bại: %s",
|
||||
"file_open_error": "Không thể mở tệp để ghi",
|
||||
"filter_type": "Loại bộ lọc không đúng",
|
||||
"from_invalid": "Người gửi không được để trống",
|
||||
"generic_server_error": "Đã xảy ra lỗi máy chủ không mong đợi. Vui lòng liên hệ quản trị viên của bạn.",
|
||||
"global_filter_write_error": "Không thể ghi tệp bộ lọc: %s",
|
||||
"global_map_invalid": "ID ánh xạ toàn cục %s không hợp lệ",
|
||||
"global_map_write_error": "Không thể ghi ID ánh xạ toàn cục %s: %s",
|
||||
"goto_empty": "Một địa chỉ bí danh phải chứa ít nhất một địa chỉ chuyển tiếp hợp lệ",
|
||||
"goto_invalid": "Địa chỉ chuyển tiếp %s không hợp lệ",
|
||||
"ham_learn_error": "Lỗi học thư hợp lệ: %s",
|
||||
"iam_test_connection": "Kết nối thất bại",
|
||||
"imagick_exception": "Lỗi: Ngoại lệ Imagick khi đọc hình ảnh",
|
||||
"img_dimensions_exceeded": "Hình ảnh vượt quá kích thước tối đa cho phép",
|
||||
"img_invalid": "Không thể xác thực tệp hình ảnh",
|
||||
"img_size_exceeded": "Hình ảnh vượt quá kích thước tệp tối đa",
|
||||
"img_tmp_missing": "Không thể xác thực tệp hình ảnh: Không tìm thấy tệp tạm thời",
|
||||
"invalid_bcc_map_type": "Loại ánh xạ BCC không hợp lệ",
|
||||
"invalid_destination": "Định dạng đích \"%s\" không hợp lệ",
|
||||
"invalid_filter_type": "Loại bộ lọc không hợp lệ",
|
||||
"invalid_host": "Máy chủ được chỉ định không hợp lệ: %s",
|
||||
"invalid_mime_type": "Kiểu MIME không hợp lệ",
|
||||
"invalid_nexthop": "Định dạng bước nhảy tiếp theo không hợp lệ",
|
||||
"invalid_nexthop_authenticated": "Bước nhảy tiếp theo tồn tại với thông tin xác thực khác, vui lòng cập nhật thông tin xác thực hiện có cho bước nhảy này trước.",
|
||||
"invalid_recipient_map_new": "Người nhận mới được chỉ định không hợp lệ: %s",
|
||||
"invalid_recipient_map_old": "Người nhận gốc được chỉ định không hợp lệ: %s",
|
||||
"invalid_reset_token": "Token đặt lại không hợp lệ",
|
||||
"ip_list_empty": "Danh sách IP được phép không được để trống",
|
||||
"is_alias": "%s đã được biết đến như một địa chỉ bí danh",
|
||||
"is_alias_or_mailbox": "%s đã được biết đến như một bí danh, một hộp thư hoặc một địa chỉ bí danh được mở rộng từ một tên miền bí danh.",
|
||||
"is_spam_alias": "%s đã được biết đến như một địa chỉ bí danh tạm thời (địa chỉ bí danh thư rác)",
|
||||
"last_key": "Không thể xóa khóa cuối cùng, vui lòng vô hiệu hóa TFA thay thế.",
|
||||
"login_failed": "Đăng nhập không thành công",
|
||||
"mailbox_defquota_exceeds_mailbox_maxquota": "Hạn ngạch mặc định vượt quá giới hạn hạn ngạch tối đa",
|
||||
"mailbox_invalid": "Tên hộp thư không hợp lệ",
|
||||
"mailbox_quota_exceeded": "Hạn ngạch vượt quá giới hạn tên miền (tối đa %d MiB)",
|
||||
"mailbox_quota_exceeds_domain_quota": "Hạn ngạch tối đa vượt quá giới hạn hạn ngạch tên miền",
|
||||
"mailbox_quota_left_exceeded": "Không đủ dung lượng còn lại (dung lượng còn lại: %d MiB)",
|
||||
"mailboxes_in_use": "Số hộp thư tối đa phải lớn hơn hoặc bằng %d",
|
||||
"malformed_username": "Tên người dùng không đúng định dạng",
|
||||
"map_content_empty": "Nội dung ánh xạ không được để trống",
|
||||
"max_age_invalid": "Tuổi tối đa %s không hợp lệ",
|
||||
"max_alias_exceeded": "Vượt quá số bí danh tối đa",
|
||||
"max_mailbox_exceeded": "Vượt quá số hộp thư tối đa (%d trên %d)",
|
||||
"max_quota_in_use": "Hạn ngạch hộp thư phải lớn hơn hoặc bằng %d MiB",
|
||||
"maxquota_empty": "Hạn ngạch tối đa cho mỗi hộp thư không được là 0.",
|
||||
"mode_invalid": "Chế độ %s không hợp lệ",
|
||||
"mx_invalid": "Bản ghi MX %s không hợp lệ",
|
||||
"mysql_error": "Lỗi MySQL: %s",
|
||||
"network_host_invalid": "Mạng hoặc máy chủ không hợp lệ: %s",
|
||||
"next_hop_interferes": "%s xung đột với bước nhảy tiếp theo %s",
|
||||
"next_hop_interferes_any": "Một bước nhảy tiếp theo hiện có xung đột với %s",
|
||||
"nginx_reload_failed": "Tải lại Nginx thất bại: %s",
|
||||
"no_user_defined": "Không có người dùng được định nghĩa",
|
||||
"object_exists": "Đối tượng %s đã tồn tại",
|
||||
"object_is_not_numeric": "Giá trị %s không phải là số",
|
||||
"password_complexity": "Mật khẩu không đáp ứng chính sách",
|
||||
"password_empty": "Mật khẩu không được để trống",
|
||||
"password_mismatch": "Mật khẩu xác nhận không khớp",
|
||||
"password_reset_invalid_user": "Không tìm thấy hộp thư hoặc không có email khôi phục được thiết lập",
|
||||
"password_reset_na": "Tính năng khôi phục mật khẩu hiện không khả dụng. Vui lòng liên hệ quản trị viên của bạn.",
|
||||
"policy_list_from_exists": "Một bản ghi với tên đã cho tồn tại",
|
||||
"policy_list_from_invalid": "Bản ghi có định dạng không hợp lệ",
|
||||
"private_key_error": "Lỗi khóa riêng tư: %s",
|
||||
"pushover_credentials_missing": "Thiếu token hoặc khóa Pushover",
|
||||
"pushover_key": "Khóa Pushover có định dạng không đúng",
|
||||
"pushover_token": "Token Pushover có định dạng không đúng",
|
||||
"quota_not_0_not_numeric": "Hạn ngạch phải là số và >= 0",
|
||||
"recipient_map_entry_exists": "Mục ánh xạ người nhận \"%s\" đã tồn tại",
|
||||
"recovery_email_failed": "Không thể gửi email khôi phục. Vui lòng liên hệ quản trị viên của bạn.",
|
||||
"redis_error": "Lỗi Redis: %s",
|
||||
"relayhost_invalid": "Mục ánh xạ %s không hợp lệ",
|
||||
"release_send_failed": "Không thể phát hành thư: %s",
|
||||
"required_data_missing": "Thiếu dữ liệu bắt buộc %s",
|
||||
"reset_f2b_regex": "Không thể đặt lại bộ lọc biểu thức chính quy kịp thời, vui lòng thử lại hoặc đợi thêm vài giây và tải lại trang web.",
|
||||
"reset_token_limit_exceeded": "Đã vượt quá giới hạn token đặt lại. Vui lòng thử lại sau.",
|
||||
"resource_invalid": "Tên tài nguyên %s không hợp lệ",
|
||||
"rl_timeframe": "Khung thời gian giới hạn tốc độ không chính xác",
|
||||
"rspamd_ui_pw_length": "Mật khẩu giao diện Rspamd phải có ít nhất 6 ký tự",
|
||||
"script_empty": "Tập lệnh không được để trống",
|
||||
"sender_acl_invalid": "Giá trị ACL người gửi %s không hợp lệ",
|
||||
"set_acl_failed": "Không thể thiết lập ACL",
|
||||
"settings_map_invalid": "ID ánh xạ cài đặt %s không hợp lệ",
|
||||
"sieve_error": "Lỗi phân tích cú pháp Sieve: %s",
|
||||
"spam_learn_error": "Lỗi học thư rác: %s",
|
||||
"subject_empty": "Tiêu đề không được để trống",
|
||||
"target_domain_invalid": "Tên miền đích %s không hợp lệ",
|
||||
"targetd_not_found": "Không tìm thấy tên miền đích %s",
|
||||
"targetd_relay_domain": "Tên miền đích %s là tên miền chuyển tiếp",
|
||||
"template_exists": "Mẫu %s đã tồn tại",
|
||||
"template_id_invalid": "ID mẫu %s không hợp lệ",
|
||||
"template_name_invalid": "Tên mẫu không hợp lệ",
|
||||
"temp_error": "Lỗi tạm thời",
|
||||
"text_empty": "Văn bản không được để trống",
|
||||
"tfa_token_invalid": "Token xác thực hai yếu tố không hợp lệ",
|
||||
"tls_policy_map_dest_invalid": "Đích chính sách TLS không hợp lệ",
|
||||
"tls_policy_map_entry_exists": "Mục ánh xạ chính sách TLS \"%s\" đã tồn tại",
|
||||
"tls_policy_map_parameter_invalid": "Tham số chính sách không hợp lệ",
|
||||
"to_invalid": "Người nhận không được để trống",
|
||||
"totp_verification_failed": "Xác thực TOTP thất bại",
|
||||
"transport_dest_exists": "Đích vận chuyển \"%s\" đã tồn tại",
|
||||
"webauthn_verification_failed": "Xác thực WebAuthn thất bại: %s",
|
||||
"webauthn_authenticator_failed": "Không tìm thấy trình xác thực đã chọn",
|
||||
"webauthn_publickey_failed": "Không có khóa công khai nào được lưu cho trình xác thực đã chọn",
|
||||
"webauthn_username_failed": "Trình xác thực đã chọn thuộc về tài khoản khác",
|
||||
"unknown": "Đã xảy ra lỗi không xác định",
|
||||
"unknown_tfa_method": "Phương thức xác thực hai yếu tố không xác định",
|
||||
"unlimited_quota_acl": "Hạn ngạch không giới hạn bị cấm bởi ACL",
|
||||
"username_invalid": "Tên người dùng %s không thể sử dụng được",
|
||||
"validity_missing": "Vui lòng gán thời hạn hiệu lực",
|
||||
"value_missing": "Vui lòng cung cấp tất cả các giá trị",
|
||||
"version_invalid": "Phiên bản %s không hợp lệ",
|
||||
"yotp_verification_failed": "Xác thực Yubico OTP thất bại: %s"
|
||||
},
|
||||
"datatables": {
|
||||
"collapse_all": "Thu gọn tất cả",
|
||||
"emptyTable": "Không có dữ liệu trong bảng",
|
||||
"expand_all": "Mở rộng tất cả",
|
||||
"info": "Hiển thị từ _START_ đến _END_ của _TOTAL_ mục",
|
||||
"infoEmpty": "Hiển thị 0 đến 0 của 0 mục",
|
||||
"infoFiltered": "(được lọc từ tổng số _MAX_ mục)",
|
||||
"lengthMenu": "Hiển thị _MENU_ mục",
|
||||
"loadingRecords": "Đang tải...",
|
||||
"processing": "Vui lòng đợi...",
|
||||
"search": "Tìm kiếm:",
|
||||
"zeroRecords": "Không tìm thấy bản ghi phù hợp",
|
||||
"paginate": {
|
||||
"first": "Đầu",
|
||||
"last": "Cuối",
|
||||
"next": "Tiếp",
|
||||
"previous": "Trước"
|
||||
},
|
||||
"aria": {
|
||||
"sortAscending": ": kích hoạt để sắp xếp cột tăng dần",
|
||||
"sortDescending": ": kích hoạt để sắp xếp cột giảm dần"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"architecture": "Kiến trúc",
|
||||
"chart_this_server": "Biểu đồ (máy chủ này)",
|
||||
"containers_info": "Thông tin container",
|
||||
"container_running": "Đang chạy",
|
||||
"container_disabled": "Container đã dừng hoặc bị vô hiệu hóa",
|
||||
"container_stopped": "Đã dừng",
|
||||
"cores": "Nhân CPU",
|
||||
"current_time": "Thời gian hệ thống",
|
||||
"disk_usage": "Sử dụng ổ đĩa",
|
||||
"docs": "Tài liệu",
|
||||
"error_show_ip": "Không thể phân giải địa chỉ IP công khai",
|
||||
"external_logs": "Nhật ký ngoài",
|
||||
"history_all_servers": "Lịch sử (tất cả máy chủ)",
|
||||
"in_memory_logs": "Nhật ký trong bộ nhớ",
|
||||
"last_modified": "Sửa đổi lần cuối",
|
||||
"log_info": "<p>mailcow <b>nhật ký trong bộ nhớ</b> được thu thập trong danh sách Redis và được cắt giảm xuống LOG_LINES (%d) mỗi phút để giảm tải.\n<br>Nhật ký trong bộ nhớ không nhằm mục đích lưu trữ lâu dài. Tất cả các ứng dụng ghi nhật ký trong bộ nhớ cũng ghi vào Docker daemon và do đó vào trình điều khiển ghi nhật ký mặc định.r\n<br>Loại nhật ký trong bộ nhớ nên được sử dụng để gỡ lỗi các vấn đề nhỏ với các container.</p>\n<p><b>Nhật ký bên ngoài</b> được thu thập thông qua API của ứng dụng đã cho.</p>\n<p><b>Nhật ký tĩnh</b> chủ yếu là nhật ký hoạt động, không được ghi vào Dockerd nhưng vẫn cần được lưu trữ lâu dài (ngoại trừ nhật ký API).</p>",
|
||||
"login_time": "Thời gian",
|
||||
"logs": "Nhật ký",
|
||||
"memory": "Bộ nhớ",
|
||||
"online_users": "Người dùng trực tuyến",
|
||||
"restart_container": "Khởi động lại",
|
||||
"service": "Dịch vụ",
|
||||
"show_ip": "Hiển thị IP công khai",
|
||||
"size": "Kích thước",
|
||||
"started_at": "Bắt đầu lúc",
|
||||
"started_on": "Bắt đầu vào",
|
||||
"static_logs": "Nhật ký tĩnh",
|
||||
"success": "Thành công",
|
||||
"system_containers": "Hệ thống & Container",
|
||||
"timezone": "Múi giờ",
|
||||
"uptime": "Thời gian hoạt động",
|
||||
"update_available": "Có bản cập nhật mới",
|
||||
"no_update_available": "Hệ thống đang ở phiên bản mới nhất",
|
||||
"update_failed": "Không thể kiểm tra cập nhật",
|
||||
"username": "Tên người dùng",
|
||||
"wip": "Đang trong quá trình phát triển"
|
||||
},
|
||||
"diagnostics": {
|
||||
"cname_from_a": "Giá trị được lấy từ bản ghi A/AAAA. Điều này được hỗ trợ miễn là bản ghi trỏ đến tài nguyên chính xác.",
|
||||
"dns_records": "Bản ghi DNS",
|
||||
"dns_records_24hours": "Xin lưu ý rằng các thay đổi được thực hiện đối với DNS có thể mất tới 24 giờ để phản ánh chính xác trạng thái hiện tại của chúng trên trang này. Trang này nhằm giúp bạn dễ dàng xem cách cấu hình bản ghi DNS và kiểm tra xem tất cả bản ghi của bạn có được lưu trữ chính xác trong DNS hay không.",
|
||||
"dns_records_data": "Dữ liệu chính xác",
|
||||
"dns_records_docs": "Vui lòng tham khảo thêm <a target=\"_blank\" href=\"https://docs.mailcow.email/getstarted/prerequisite-dns\">tài liệu hướng dẫn</a>.",
|
||||
"dns_records_name": "Tên",
|
||||
"dns_records_status": "Trạng thái hiện tại",
|
||||
"dns_records_type": "Loại",
|
||||
"optional": "Bản ghi này là tùy chọn."
|
||||
},
|
||||
"edit": {
|
||||
"acl": "ACL (Quyền hạn)",
|
||||
"active": "Hoạt động",
|
||||
"admin": "Chỉnh sửa quản trị viên",
|
||||
"advanced_settings": "Cài đặt nâng cao",
|
||||
"alias": "Chỉnh sửa bí danh",
|
||||
"allow_from_smtp": "Chỉ cho phép các IP sau sử dụng <b>SMTP</b>",
|
||||
"allow_from_smtp_info": "Để trống để cho phép tất cả người gửi.<br>Địa chỉ và mạng IPv4/IPv6.",
|
||||
"allowed_protocols": "Các giao thức được phép truy cập trực tiếp của người dùng (không ảnh hưởng đến giao thức mật khẩu ứng dụng)",
|
||||
"app_name": "Tên ứng dụng",
|
||||
"app_passwd": "Mật khẩu ứng dụng",
|
||||
"app_passwd_protocols": "Các giao thức được phép cho mật khẩu ứng dụng",
|
||||
"automap": "Thử tự động ánh xạ thư mục (\"Mục đã gửi\", \"Đã gửi\" => \"Đã gửi\" v.v.)",
|
||||
"backup_mx_options": "Tùy chọn chuyển tiếp",
|
||||
"bcc_dest_format": "Đích BCC phải là một địa chỉ email hợp lệ duy nhất.<br>Nếu bạn cần gửi bản sao đến nhiều địa chỉ, hãy tạo một bí danh và sử dụng nó ở đây.",
|
||||
"client_id": "ID khách hàng",
|
||||
"client_secret": "Khóa bí mật khách hàng",
|
||||
"comment_info": "Bình luận riêng tư không hiển thị với người dùng, trong khi bình luận công khai được hiển thị dưới dạng chú thích khi di chuột qua trong tổng quan người dùng",
|
||||
"created_on": "Được tạo vào",
|
||||
"custom_attributes": "Thuộc tính tùy chỉnh",
|
||||
"delete1": "Xóa từ nguồn khi hoàn thành",
|
||||
"delete2": "Xóa thư ở đích không có ở nguồn",
|
||||
"delete2duplicates": "Xóa các bản sao ở đích",
|
||||
"delete_ays": "Vui lòng xác nhận quá trình xóa.",
|
||||
"description": "Mô tả",
|
||||
"disable_login": "Không cho phép đăng nhập (vẫn nhận được thư đến)",
|
||||
"domain": "Chỉnh sửa tên miền",
|
||||
"domain_admin": "Chỉnh sửa quản trị viên tên miền",
|
||||
"domain_footer": "Chân trang toàn tên miền",
|
||||
"domain_footer_html": "Chân trang HTML",
|
||||
"domain_footer_info": "Chân trang toàn tên miền được thêm vào tất cả các email gửi đi liên quan đến một địa chỉ trong tên miền này. <br> Các biến sau có thể được sử dụng cho chân trang:",
|
||||
"domain_footer_info_vars": {
|
||||
"auth_user": "{= auth_user =} - Tên người dùng đã xác thực được chỉ định bởi MTA",
|
||||
"from_user": "{= from_user =} - Phần người dùng của phong bì, ví dụ \"moo@mailcow.tld\" sẽ trả về \"moo\"",
|
||||
"from_name": "{= from_name =} - Tên từ phong bì, ví dụ \"Mailcow <moo@mailcow.tld>\" sẽ trả về \"Mailcow\"",
|
||||
"from_addr": "{= from_addr =} - Phần địa chỉ của phong bì",
|
||||
"from_domain": "{= from_domain =} - Phần tên miền của phong bì",
|
||||
"custom": "{= foo =} - Nếu hộp thư có thuộc tính tùy chỉnh \"foo\" với giá trị \"bar\" sẽ trả về \"bar\""
|
||||
},
|
||||
"domain_footer_plain": "Chân trang văn bản thuần",
|
||||
"domain_footer_skip_replies": "Bỏ qua chân trang trong email trả lời",
|
||||
"domain_quota": "Hạn ngạch tên miền",
|
||||
"domains": "Các tên miền",
|
||||
"dont_check_sender_acl": "Tắt kiểm tra người gửi cho tên miền %s (+ tên miền bí danh)",
|
||||
"edit_alias_domain": "Chỉnh sửa tên miền bí danh",
|
||||
"encryption": "Mã hóa",
|
||||
"exclude": "Loại trừ đối tượng (biểu thức chính quy)",
|
||||
"extended_sender_acl": "Địa chỉ người gửi bên ngoài",
|
||||
"extended_sender_acl_info": "Khóa tên miền DKIM nên được nhập vào, nếu có sẵn.<br>\n Nhớ thêm máy chủ này vào bản ghi SPF TXT tương ứng.<br>\n Khi một tên miền hoặc tên miền bí danh được thêm vào máy chủ này, mà trùng với một địa chỉ bên ngoài, địa chỉ bên ngoài sẽ bị xóa.<br>\n Sử dụng @domain.tld để cho phép gửi dưới dạng *@domain.tld.",
|
||||
"force_pw_update": "Bắt buộc cập nhật mật khẩu trong lần đăng nhập tiếp theo",
|
||||
"force_pw_update_info": "Người dùng này sẽ chỉ có thể đăng nhập vào %s. Mật khẩu ứng dụng vẫn có thể sử dụng được.",
|
||||
"footer_exclude": "Loại trừ khỏi chân trang",
|
||||
"full_name": "Tên đầy đủ",
|
||||
"gal": "Danh sách địa chỉ toàn cục",
|
||||
"gal_info": "GAL chứa tất cả các đối tượng của một tên miền và không thể được chỉnh sửa bởi bất kỳ người dùng nào. Thông tin rảnh/bận trong SOGo sẽ bị thiếu nếu vô hiệu hóa! <b>Khởi động lại SOGo để áp dụng thay đổi.</b>",
|
||||
"generate": "tạo",
|
||||
"grant_types": "Các loại cấp quyền",
|
||||
"hostname": "Tên máy chủ",
|
||||
"inactive": "Không hoạt động",
|
||||
"internal": "Nội bộ",
|
||||
"internal_info": "Bí danh nội bộ chỉ có thể truy cập từ tên miền sở hữu hoặc tên miền bí danh.",
|
||||
"kind": "Loại",
|
||||
"last_modified": "Sửa đổi lần cuối",
|
||||
"lookup_mx": "Đích là một biểu thức chính quy để khớp với tên MX (<code>.*.google.com</code> để định tuyến tất cả thư nhắm đến MX kết thúc bằng google.com qua bước nhảy này)"
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
"ratelimit": "频率限制",
|
||||
"recipient_maps": "收件人映射",
|
||||
"smtp_ip_access": "更改 SMTP 允许主机",
|
||||
"sogo_access": "允许管理 SOGo 访问权限",
|
||||
"sogo_redirection": "允许管理 SOGo 访问权限",
|
||||
"sogo_profile_reset": "重置 SOGo 个人资料",
|
||||
"spam_alias": "临时别名",
|
||||
"spam_policy": "阻止名单/允许名单",
|
||||
@@ -700,8 +700,8 @@
|
||||
"sieve_desc": "简短描述",
|
||||
"sieve_type": "过滤器类型",
|
||||
"skipcrossduplicates": "跳过其他文件夹中已存在的邮件(保留已经存在的邮件)",
|
||||
"sogo_access": "直接转到 SOGo",
|
||||
"sogo_access_info": "登录后,用户会自动跳转到 SOGo。",
|
||||
"sogo_redirection": "直接转到 SOGo",
|
||||
"sogo_redirection_info": "登录后,用户会自动跳转到 SOGo。",
|
||||
"sogo_visible": "SOGo 显示的别名",
|
||||
"sogo_visible_info": "此设置只影响 SOGo 上可显示的对象 (指向本地邮箱的共享或非共享别名地址)。如果设置为隐藏,则别名地址不会作为可选发件人的下拉项显示。",
|
||||
"spam_alias": "添加或更改临时别名地址",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"ratelimit": "速率限制",
|
||||
"recipient_maps": "收件人規則表",
|
||||
"smtp_ip_access": "更改允許 SMTP 的主機",
|
||||
"sogo_access": "管理 SOGo 存取權",
|
||||
"sogo_redirection": "管理 SOGo 存取權",
|
||||
"sogo_profile_reset": "重設 SOGo 個人資料",
|
||||
"spam_alias": "臨時別名",
|
||||
"spam_policy": "黑名單/白名單",
|
||||
@@ -642,8 +642,8 @@
|
||||
"sieve_desc": "簡短描述",
|
||||
"sieve_type": "過濾器類型",
|
||||
"skipcrossduplicates": "跳過在其他資料夾中重複的郵件 (優先使用先找到的郵件)",
|
||||
"sogo_access": "直接轉寄至SOGo",
|
||||
"sogo_access_info": "登入後,使用者會自動重新導向至SOGo。",
|
||||
"sogo_redirection": "直接轉寄至SOGo",
|
||||
"sogo_redirection_info": "登入後,使用者會自動重新導向至SOGo。",
|
||||
"sogo_visible": "別名會在 SOGo 中顯示",
|
||||
"sogo_visible_info": "此選項只會影響可以顯示於 SOGo 上物件 (指向至少一個本地信箱的共享或非共享別名地址)。如果設為隱藏,別名地址將不會顯示於寄件人下拉選項中。",
|
||||
"spam_alias": "新增或更改臨時別名地址",
|
||||
|
||||
@@ -24,7 +24,7 @@ if (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
$is_eas = true;
|
||||
}
|
||||
$login_check = check_login($username, $password, array('dav' => $is_dav, 'eas' => $is_eas));
|
||||
if ($login_check === 'user') {
|
||||
if ($login_check === 'user' && hasACLAccess('sogo_access')) {
|
||||
header("X-User: $username");
|
||||
header("X-Auth: Basic ".base64_encode("$username:$password"));
|
||||
header("X-Auth-Type: Basic");
|
||||
@@ -44,6 +44,7 @@ elseif (isset($_GET['login'])) {
|
||||
// check permissions (if dual_login is active, deny sso when acl is not given)
|
||||
$login = html_entity_decode(rawurldecode($_GET["login"]));
|
||||
if (isset($_SESSION['mailcow_cc_role']) &&
|
||||
hasACLAccess('sogo_access') &&
|
||||
(($_SESSION['acl']['login_as'] == "1" && $ALLOW_ADMIN_EMAIL_LOGIN !== 0) || ($is_dual === false && $login == $_SESSION['mailcow_cc_username']))) {
|
||||
if (filter_var($login, FILTER_VALIDATE_EMAIL)) {
|
||||
if (user_get_alias_details($login) !== false) {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<input type="hidden" value="default" name="sender_acl">
|
||||
<input type="hidden" value="0" name="force_pw_update">
|
||||
<input type="hidden" value="0" name="sogo_access">
|
||||
<input type="hidden" value="0" name="sogo_redirection">
|
||||
<input type="hidden" value="0" name="protocol_access">
|
||||
|
||||
<div class="row mb-4">
|
||||
@@ -123,6 +123,7 @@
|
||||
<option value="syncjobs" {% if template.attributes.acl_syncjobs == '1' %} selected{% endif %}>{{ lang.acl["syncjobs"] }}</option>
|
||||
<option value="eas_reset" {% if template.attributes.acl_eas_reset == '1' %} selected{% endif %}>{{ lang.acl["eas_reset"] }}</option>
|
||||
<option value="sogo_profile_reset" {% if template.attributes.acl_sogo_profile_reset == '1' %} selected{% endif %}>{{ lang.acl["sogo_profile_reset"] }}</option>
|
||||
<option value="sogo_access" {% if template.attributes.acl_sogo_access == '1' %} selected{% endif %}>{{ lang.acl["sogo_access"] }}</option>
|
||||
<option value="pushover" {% if template.attributes.acl_pushover == '1' %} selected{% endif %}>{{ lang.acl["pushover"] }}</option>
|
||||
<option value="quarantine" {% if template.attributes.acl_quarantine == '1' %} selected{% endif %}>{{ lang.acl["quarantine"] }}</option>
|
||||
<option value="quarantine_attachments" {% if template.attributes.acl_quarantine_attachments == '1' %} selected{% endif %}>{{ lang.acl["quarantine_attachments"] }}</option>
|
||||
@@ -167,8 +168,8 @@
|
||||
<div class="row">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_access"{% if template.attributes.sogo_access == '1' %} checked{% endif %}> {{ lang.edit.sogo_access }}</label>
|
||||
<small class="text-muted">{{ lang.edit.sogo_access_info }}</small>
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_redirection"{% if template.attributes.sogo_redirection == '1' %} checked{% endif %}> {{ lang.edit.sogo_redirection }}</label>
|
||||
<small class="text-muted">{{ lang.edit.sogo_redirection_info }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<form class="form-horizontal" data-id="editmailbox" role="form" method="post">
|
||||
<input type="hidden" value="default" name="sender_acl">
|
||||
<input type="hidden" value="0" name="force_pw_update">
|
||||
<input type="hidden" value="0" name="sogo_access">
|
||||
<input type="hidden" value="0" name="sogo_redirection">
|
||||
<input type="hidden" value="0" name="protocol_access">
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2">{{ lang.admin.iam }}</label>
|
||||
@@ -310,11 +310,11 @@
|
||||
</div>
|
||||
</div>
|
||||
{% if not skip_sogo %}
|
||||
<div data-acl="{{ acl.sogo_access }}" class="row">
|
||||
<div data-acl="{{ acl.sogo_redirection }}" class="row">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_access"{% if result.attributes.sogo_access == '1' %} checked{% endif %}> {{ lang.edit.sogo_access }}</label>
|
||||
<small class="text-muted">{{ lang.edit.sogo_access_info }}</small>
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_redirection"{% if result.attributes.sogo_redirection == '1' %} checked{% endif %}> {{ lang.edit.sogo_redirection }}</label>
|
||||
<small class="text-muted">{{ lang.edit.sogo_redirection_info }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -485,9 +485,22 @@
|
||||
</div>
|
||||
<div class="col-sm-10">
|
||||
<select id="user_acl" name="user_acl" size="10" multiple>
|
||||
{% for acl, val in user_acls %}
|
||||
<option value="{{ acl }}"{% if val == 1 %} selected{% endif %}>{{ lang.acl[acl] }}</option>
|
||||
{% endfor %}
|
||||
<option value="spam_alias" {% if user_acls.spam_alias == '1' %} selected{% endif %}>{{ lang.acl["spam_alias"] }}</option>
|
||||
<option value="tls_policy" {% if user_acls.tls_policy == '1' %} selected{% endif %}>{{ lang.acl["tls_policy"] }}</option>
|
||||
<option value="spam_score" {% if user_acls.spam_score == '1' %} selected{% endif %}>{{ lang.acl["spam_score"] }}</option>
|
||||
<option value="spam_policy" {% if user_acls.spam_policy == '1' %} selected{% endif %}>{{ lang.acl["spam_policy"] }}</option>
|
||||
<option value="delimiter_action" {% if user_acls.delimiter_action == '1' %} selected{% endif %}>{{ lang.acl["delimiter_action"] }}</option>
|
||||
<option value="syncjobs" {% if user_acls.syncjobs == '1' %} selected{% endif %}>{{ lang.acl["syncjobs"] }}</option>
|
||||
<option value="eas_reset" {% if user_acls.eas_reset == '1' %} selected{% endif %}>{{ lang.acl["eas_reset"] }}</option>
|
||||
<option value="sogo_profile_reset" {% if user_acls.sogo_profile_reset == '1' %} selected{% endif %}>{{ lang.acl["sogo_profile_reset"] }}</option>
|
||||
<option value="sogo_access" {% if user_acls.sogo_access == '1' %} selected{% endif %}>{{ lang.acl["sogo_access"] }}</option>
|
||||
<option value="pushover" {% if user_acls.pushover == '1' %} selected{% endif %}>{{ lang.acl["pushover"] }}</option>
|
||||
<option value="quarantine" {% if user_acls.quarantine == '1' %} selected{% endif %}>{{ lang.acl["quarantine"] }}</option>
|
||||
<option value="quarantine_attachments" {% if user_acls.quarantine_attachments == '1' %} selected{% endif %}>{{ lang.acl["quarantine_attachments"] }}</option>
|
||||
<option value="quarantine_notification" {% if user_acls.quarantine_notification == '1' %} selected{% endif %}>{{ lang.acl["quarantine_notification"] }}</option>
|
||||
<option value="quarantine_category" {% if user_acls.quarantine_category == '1' %} selected{% endif %}>{{ lang.acl["quarantine_category"] }}</option>
|
||||
<option value="app_passwds" {% if user_acls.app_passwds == '1' %} selected{% endif %}>{{ lang.acl["app_passwds"] }}</option>
|
||||
<option value="pw_reset" {% if user_acls.pw_reset == '1' %} selected{% endif %}>{{ lang.acl["pw_reset"] }}</option>
|
||||
</select>
|
||||
<button class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="useracl" data-item="{{ mailbox }}" data-api-url='edit/user-acl' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" data-cached-form="true" data-id="add_mailbox" role="form" autocomplete="off">
|
||||
<input type="hidden" value="0" name="force_pw_update">
|
||||
<input type="hidden" value="0" name="sogo_access">
|
||||
<input type="hidden" value="0" name="sogo_redirection">
|
||||
<input type="hidden" value="0" name="protocol_access">
|
||||
<input type="hidden" value="mailcow" name="authsource">
|
||||
|
||||
@@ -163,6 +163,7 @@
|
||||
<option value="syncjobs">{{ lang.acl["syncjobs"] }}</option>
|
||||
<option value="eas_reset" selected>{{ lang.acl["eas_reset"] }}</option>
|
||||
<option value="sogo_profile_reset">{{ lang.acl["sogo_profile_reset"] }}</option>
|
||||
<option value="sogo_access">{{ lang.acl["sogo_access"] }}</option>
|
||||
<option value="pushover" selected>{{ lang.acl["pushover"] }}</option>
|
||||
<option value="quarantine" selected>{{ lang.acl["quarantine"] }}</option>
|
||||
<option value="quarantine_attachments" selected>{{ lang.acl["quarantine_attachments"] }}</option>
|
||||
@@ -206,8 +207,8 @@
|
||||
<div class="row">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_access" id="sogo_access"> {{ lang.edit.sogo_access }}</label>
|
||||
<small class="text-muted">{{ lang.edit.sogo_access_info }}</small>
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_redirection" id="sogo_redirection"> {{ lang.edit.sogo_redirection }}</label>
|
||||
<small class="text-muted">{{ lang.edit.sogo_redirection_info }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -235,7 +236,7 @@
|
||||
<form class="form-horizontal" data-id="addmailbox_template" role="form" method="post">
|
||||
<input type="hidden" value="default" name="sender_acl">
|
||||
<input type="hidden" value="0" name="force_pw_update">
|
||||
<input type="hidden" value="0" name="sogo_access">
|
||||
<input type="hidden" value="0" name="sogo_redirection">
|
||||
<input type="hidden" value="0" name="protocol_access">
|
||||
|
||||
<div class="row mb-4">
|
||||
@@ -350,6 +351,7 @@
|
||||
<option value="syncjobs">{{ lang.acl["syncjobs"] }}</option>
|
||||
<option value="eas_reset" selected>{{ lang.acl["eas_reset"] }}</option>
|
||||
<option value="sogo_profile_reset">{{ lang.acl["sogo_profile_reset"] }}</option>
|
||||
<option value="sogo_access">{{ lang.acl["sogo_access"] }}</option>
|
||||
<option value="pushover" selected>{{ lang.acl["pushover"] }}</option>
|
||||
<option value="quarantine" selected>{{ lang.acl["quarantine"] }}</option>
|
||||
<option value="quarantine_attachments" selected>{{ lang.acl["quarantine_attachments"] }}</option>
|
||||
@@ -394,8 +396,8 @@
|
||||
<div class="row">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_access"> {{ lang.edit.sogo_access }}</label>
|
||||
<small class="text-muted">{{ lang.edit.sogo_access_info }}</small>
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_redirection"> {{ lang.edit.sogo_redirection }}</label>
|
||||
<small class="text-muted">{{ lang.edit.sogo_redirection_info }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
</div>
|
||||
<div id="collapse-tab-SpamAliases" class="card-body collapse" data-bs-parent="#user-content">
|
||||
<div class="row">
|
||||
<p>{{ lang.user.spam_aliases_info|raw }}</p>
|
||||
<div class="col-md-12 col-sm-12 col-12">
|
||||
<table id="tla_table" class="table table-striped dt-responsive w-100"></table>
|
||||
</div>
|
||||
@@ -19,13 +18,12 @@
|
||||
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="tla" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
|
||||
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"1","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.hour }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"24","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.day }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"168","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.week }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"744","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.month }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"8760","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.year }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"87600","permanent":"0"}' href="#">{{ lang.user.expire_in }} 10 {{ lang.user.years }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"permanent":"1"}' href="#">{{ lang.user.expire_never }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"1"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.hour }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"24"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.day }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"168"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.week }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"744"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.month }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"8760"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.year }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"87600"}' href="#">{{ lang.user.expire_in }} 10 {{ lang.user.years }}</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" data-action="delete_selected" data-id="tla" data-api-url='delete/time_limited_alias' href="#">{{ lang.mailbox.remove }}</a></li>
|
||||
</ul>
|
||||
|
||||
@@ -23,10 +23,14 @@
|
||||
<a href="/sogo-auth.php?login={{ mailcow_cc_username }}" role="button" class="btn btn-primary btn-lg btn-block btn-xs-lg w-100">
|
||||
{{ lang.user.open_webmail_sso }} <i class="bi bi-arrow-right"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
{% elseif acl.sogo_access == 1 %}
|
||||
<a href="/SOGo/so" role="button" class="btn btn-primary btn-lg btn-block btn-xs-lg w-100">
|
||||
{{ lang.user.open_webmail_sso }} <i class="bi bi-arrow-right"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
<button disabled class="btn btn-secondary btn-block btn-xs-lg w-100">
|
||||
{{ lang.user.open_webmail_sso }} <i class="bi bi-arrow-right"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -117,7 +117,7 @@ services:
|
||||
- rspamd
|
||||
|
||||
php-fpm-mailcow:
|
||||
image: ghcr.io/mailcow/phpfpm:8.2.29
|
||||
image: ghcr.io/mailcow/phpfpm:1.94
|
||||
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
|
||||
depends_on:
|
||||
- redis-mailcow
|
||||
@@ -188,10 +188,10 @@ services:
|
||||
restart: always
|
||||
labels:
|
||||
ofelia.enabled: "true"
|
||||
ofelia.job-exec.phpfpm_keycloak_sync.schedule: "0 * * * * *"
|
||||
ofelia.job-exec.phpfpm_keycloak_sync.schedule: "@every 1m"
|
||||
ofelia.job-exec.phpfpm_keycloak_sync.no-overlap: "true"
|
||||
ofelia.job-exec.phpfpm_keycloak_sync.command: "/bin/bash -c \"php /crons/keycloak-sync.php || exit 0\""
|
||||
ofelia.job-exec.phpfpm_ldap_sync.schedule: "0 * * * * *"
|
||||
ofelia.job-exec.phpfpm_ldap_sync.schedule: "@every 1m"
|
||||
ofelia.job-exec.phpfpm_ldap_sync.no-overlap: "true"
|
||||
ofelia.job-exec.phpfpm_ldap_sync.command: "/bin/bash -c \"php /crons/ldap-sync.php || exit 0\""
|
||||
networks:
|
||||
@@ -200,7 +200,7 @@ services:
|
||||
- phpfpm
|
||||
|
||||
sogo-mailcow:
|
||||
image: ghcr.io/mailcow/sogo:5.12.4
|
||||
image: ghcr.io/mailcow/sogo:1.136
|
||||
environment:
|
||||
- DBNAME=${DBNAME}
|
||||
- DBUSER=${DBUSER}
|
||||
@@ -236,13 +236,13 @@ services:
|
||||
- sogo-userdata-backup-vol-1:/sogo_backup
|
||||
labels:
|
||||
ofelia.enabled: "true"
|
||||
ofelia.job-exec.sogo_sessions.schedule: "0 * * * * *"
|
||||
ofelia.job-exec.sogo_sessions.schedule: "@every 1m"
|
||||
ofelia.job-exec.sogo_sessions.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool -v expire-sessions $${SOGO_EXPIRE_SESSION} || exit 0\""
|
||||
ofelia.job-exec.sogo_ealarms.schedule: "0 * * * * *"
|
||||
ofelia.job-exec.sogo_ealarms.schedule: "@every 1m"
|
||||
ofelia.job-exec.sogo_ealarms.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-ealarms-notify -p /etc/sogo/cron.creds || exit 0\""
|
||||
ofelia.job-exec.sogo_eautoreply.schedule: "0 */5 * * * *"
|
||||
ofelia.job-exec.sogo_eautoreply.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds || exit 0\""
|
||||
ofelia.job-exec.sogo_backup.schedule: "0 0 0 * * *"
|
||||
ofelia.job-exec.sogo_eautoreply.schedule: "@every 5m"
|
||||
ofelia.job-exec.sogo_eautoreply.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/cron.creds || exit 0\""
|
||||
ofelia.job-exec.sogo_backup.schedule: "@every 24h"
|
||||
ofelia.job-exec.sogo_backup.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool backup /sogo_backup ALL || exit 0\""
|
||||
restart: always
|
||||
networks:
|
||||
@@ -252,7 +252,7 @@ services:
|
||||
- sogo
|
||||
|
||||
dovecot-mailcow:
|
||||
image: ghcr.io/mailcow/dovecot:2.3.21.1
|
||||
image: ghcr.io/mailcow/dovecot:2.35
|
||||
depends_on:
|
||||
- mysql-mailcow
|
||||
- netfilter-mailcow
|
||||
@@ -310,22 +310,22 @@ services:
|
||||
tty: true
|
||||
labels:
|
||||
ofelia.enabled: "true"
|
||||
ofelia.job-exec.dovecot_imapsync_runner.schedule: "0 * * * * *"
|
||||
ofelia.job-exec.dovecot_imapsync_runner.schedule: "@every 1m"
|
||||
ofelia.job-exec.dovecot_imapsync_runner.no-overlap: "true"
|
||||
ofelia.job-exec.dovecot_imapsync_runner.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu nobody /usr/local/bin/imapsync_runner.pl || exit 0\""
|
||||
ofelia.job-exec.dovecot_trim_logs.schedule: "0 * * * * *"
|
||||
ofelia.job-exec.dovecot_trim_logs.schedule: "@every 1m"
|
||||
ofelia.job-exec.dovecot_trim_logs.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/trim_logs.sh || exit 0\""
|
||||
ofelia.job-exec.dovecot_quarantine.schedule: "0 */20 * * * *"
|
||||
ofelia.job-exec.dovecot_quarantine.schedule: "@every 20m"
|
||||
ofelia.job-exec.dovecot_quarantine.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/quarantine_notify.py || exit 0\""
|
||||
ofelia.job-exec.dovecot_clean_q_aged.schedule: "0 0 0 * * *"
|
||||
ofelia.job-exec.dovecot_clean_q_aged.schedule: "@every 24h"
|
||||
ofelia.job-exec.dovecot_clean_q_aged.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/clean_q_aged.sh || exit 0\""
|
||||
ofelia.job-exec.dovecot_maildir_gc.schedule: "0 */30 * * * *"
|
||||
ofelia.job-exec.dovecot_maildir_gc.schedule: "@every 30m"
|
||||
ofelia.job-exec.dovecot_maildir_gc.command: "/bin/bash -c \"source /source_env.sh ; /usr/local/bin/gosu vmail /usr/local/bin/maildir_gc.sh\""
|
||||
ofelia.job-exec.dovecot_sarules.schedule: "0 0 0 * * *"
|
||||
ofelia.job-exec.dovecot_sarules.schedule: "@every 24h"
|
||||
ofelia.job-exec.dovecot_sarules.command: "/bin/bash -c \"/usr/local/bin/sa-rules.sh\""
|
||||
ofelia.job-exec.dovecot_fts.schedule: "0 0 0 * * *"
|
||||
ofelia.job-exec.dovecot_fts.schedule: "@every 24h"
|
||||
ofelia.job-exec.dovecot_fts.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/optimize-fts.sh\""
|
||||
ofelia.job-exec.dovecot_repl_health.schedule: "0 */5 * * * *"
|
||||
ofelia.job-exec.dovecot_repl_health.schedule: "@every 5m"
|
||||
ofelia.job-exec.dovecot_repl_health.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/repl_health.sh\""
|
||||
ulimits:
|
||||
nproc: 65535
|
||||
@@ -339,7 +339,7 @@ services:
|
||||
- dovecot
|
||||
|
||||
postfix-mailcow:
|
||||
image: ghcr.io/mailcow/postfix:3.7.11
|
||||
image: ghcr.io/mailcow/postfix:1.81
|
||||
depends_on:
|
||||
mysql-mailcow:
|
||||
condition: service_started
|
||||
|
||||
@@ -110,32 +110,32 @@ function backup() {
|
||||
docker run --name mailcow-backup --rm \
|
||||
-v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:ro,z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_vmail.tar.zst /vmail
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_vmail.tar.gz /vmail
|
||||
;;&
|
||||
crypt|all)
|
||||
docker run --name mailcow-backup --rm \
|
||||
-v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:ro,z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_crypt.tar.zst /crypt
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_crypt.tar.gz /crypt
|
||||
;;&
|
||||
redis|all)
|
||||
docker exec $(docker ps -qf name=redis-mailcow) redis-cli -a ${REDISPASS} --no-auth-warning save
|
||||
docker run --name mailcow-backup --rm \
|
||||
-v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:ro,z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_redis.tar.zst /redis
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_redis.tar.gz /redis
|
||||
;;&
|
||||
rspamd|all)
|
||||
docker run --name mailcow-backup --rm \
|
||||
-v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:ro,z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_rspamd.tar.zst /rspamd
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_rspamd.tar.gz /rspamd
|
||||
;;&
|
||||
postfix|all)
|
||||
docker run --name mailcow-backup --rm \
|
||||
-v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:ro,z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_postfix.tar.zst /postfix
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_postfix.tar.gz /postfix
|
||||
;;&
|
||||
mysql|all)
|
||||
SQLIMAGE=$(grep -iEo '(mysql|mariadb)\:.+' ${COMPOSE_FILE})
|
||||
@@ -154,7 +154,7 @@ function backup() {
|
||||
${SQLIMAGE} /bin/sh -c "mariabackup --host mysql --user root --password ${DBROOT} --backup --rsync --target-dir=/backup_mariadb ; \
|
||||
mariabackup --prepare --target-dir=/backup_mariadb ; \
|
||||
chown -R 999:999 /backup_mariadb ; \
|
||||
/bin/tar --warning='no-file-ignored' --use-compress-program='zstd --rsyncable' -Pcvpf /backup/backup_mariadb.tar.zst /backup_mariadb ;"
|
||||
/bin/tar --warning='no-file-ignored' --use-compress-program='gzip --rsyncable' -Pcvpf /backup/backup_mariadb.tar.gz /backup_mariadb ;"
|
||||
fi
|
||||
;;&
|
||||
--delete-days)
|
||||
@@ -170,19 +170,6 @@ function backup() {
|
||||
done
|
||||
}
|
||||
|
||||
function get_archive_info() {
|
||||
local backup_name="$1"
|
||||
local location="$2"
|
||||
|
||||
if [[ -f "${location}/${backup_name}.tar.zst" ]]; then
|
||||
echo "${backup_name}.tar.zst|zstd -d -T${THREADS}"
|
||||
elif [[ -f "${location}/${backup_name}.tar.gz" ]]; then
|
||||
echo "${backup_name}.tar.gz|pigz -d -p ${THREADS}"
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
function restore() {
|
||||
for bin in docker; do
|
||||
if [[ -z $(which ${bin}) ]]; then
|
||||
@@ -212,17 +199,10 @@ function restore() {
|
||||
case "$1" in
|
||||
vmail)
|
||||
docker stop $(docker ps -qf name=dovecot-mailcow)
|
||||
ARCHIVE_INFO=$(get_archive_info "backup_vmail" "${RESTORE_LOCATION}")
|
||||
if [[ -z "${ARCHIVE_INFO}" ]]; then
|
||||
echo -e "\e[31mError: No backup file found for vmail (searched for .tar.zst and .tar.gz)\e[0m"
|
||||
else
|
||||
ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
|
||||
DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
|
||||
fi
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_vmail.tar.gz
|
||||
docker start $(docker ps -aqf name=dovecot-mailcow)
|
||||
echo
|
||||
echo "In most cases it is not required to run a full resync, you can run the command printed below at any time after testing wether the restore process broke a mailbox:"
|
||||
@@ -238,50 +218,31 @@ function restore() {
|
||||
;;
|
||||
redis)
|
||||
docker stop $(docker ps -qf name=redis-mailcow)
|
||||
ARCHIVE_INFO=$(get_archive_info "backup_redis" "${RESTORE_LOCATION}")
|
||||
if [[ -z "${ARCHIVE_INFO}" ]]; then
|
||||
echo -e "\e[31mError: No backup file found for redis (searched for .tar.zst and .tar.gz)\e[0m"
|
||||
else
|
||||
ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
|
||||
DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
|
||||
fi
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_redis.tar.gz
|
||||
docker start $(docker ps -aqf name=redis-mailcow)
|
||||
;;
|
||||
crypt)
|
||||
docker stop $(docker ps -qf name=dovecot-mailcow)
|
||||
ARCHIVE_INFO=$(get_archive_info "backup_crypt" "${RESTORE_LOCATION}")
|
||||
if [[ -z "${ARCHIVE_INFO}" ]]; then
|
||||
echo -e "\e[31mError: No backup file found for crypt (searched for .tar.zst and .tar.gz)\e[0m"
|
||||
else
|
||||
ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
|
||||
DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
|
||||
fi
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_crypt.tar.gz
|
||||
docker start $(docker ps -aqf name=dovecot-mailcow)
|
||||
;;
|
||||
rspamd)
|
||||
ARCHIVE_INFO=$(get_archive_info "backup_rspamd" "${RESTORE_LOCATION}")
|
||||
if [[ -z "${ARCHIVE_INFO}" ]]; then
|
||||
echo -e "\e[31mError: No backup file found for rspamd (searched for .tar.zst and .tar.gz)\e[0m"
|
||||
elif [[ $(find "${RESTORE_LOCATION}" \( -name '*x86*' -o -name '*aarch*' \) -exec basename {} \; | sed 's/^\.//' | sed 's/^\.//') == "" ]]; then
|
||||
if [[ $(find "${RESTORE_LOCATION}" \( -name '*x86*' -o -name '*aarch*' \) -exec basename {} \; | sed 's/^\.//' | sed 's/^\.//') == "" ]]; then
|
||||
echo -e "\e[33mCould not find a architecture signature of the loaded backup... Maybe the backup was done before the multiarch update?"
|
||||
sleep 2
|
||||
echo -e "Continuing anyhow. If rspamd is crashing upon boot try remove the rspamd volume with docker volume rm ${CMPS_PRJ}_rspamd-vol-1 after you've stopped the stack.\e[0m"
|
||||
sleep 2
|
||||
docker stop $(docker ps -qf name=rspamd-mailcow)
|
||||
ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
|
||||
DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_rspamd.tar.gz
|
||||
docker start $(docker ps -aqf name=rspamd-mailcow)
|
||||
elif [[ $ARCH != $(find "${RESTORE_LOCATION}" \( -name '*x86*' -o -name '*aarch*' \) -exec basename {} \; | sed 's/^\.//' | sed 's/^\.//') ]]; then
|
||||
echo -e "\e[31mThe Architecture of the backed up mailcow OS is different then your restoring mailcow OS..."
|
||||
@@ -289,28 +250,19 @@ function restore() {
|
||||
echo -e "Skipping rspamd due to compatibility issues!\e[0m"
|
||||
else
|
||||
docker stop $(docker ps -qf name=rspamd-mailcow)
|
||||
ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
|
||||
DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_rspamd.tar.gz
|
||||
docker start $(docker ps -aqf name=rspamd-mailcow)
|
||||
fi
|
||||
;;
|
||||
postfix)
|
||||
docker stop $(docker ps -qf name=postfix-mailcow)
|
||||
ARCHIVE_INFO=$(get_archive_info "backup_postfix" "${RESTORE_LOCATION}")
|
||||
if [[ -z "${ARCHIVE_INFO}" ]]; then
|
||||
echo -e "\e[31mError: No backup file found for postfix (searched for .tar.zst and .tar.gz)\e[0m"
|
||||
else
|
||||
ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
|
||||
DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
|
||||
fi
|
||||
docker run -i --name mailcow-backup --rm \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:z \
|
||||
${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_postfix.tar.gz
|
||||
docker start $(docker ps -aqf name=postfix-mailcow)
|
||||
;;
|
||||
mysql|mariadb)
|
||||
@@ -353,19 +305,14 @@ function restore() {
|
||||
echo Restoring... && \
|
||||
gunzip < backup/backup_mysql.gz | mysql -uroot && \
|
||||
mysql -uroot -e SHUTDOWN;"
|
||||
else
|
||||
ARCHIVE_INFO=$(get_archive_info "backup_mariadb" "${RESTORE_LOCATION}")
|
||||
if [[ -n "${ARCHIVE_INFO}" ]]; then
|
||||
ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
|
||||
DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
|
||||
docker run --name mailcow-backup --rm \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/backup_mariadb/:rw,z \
|
||||
--entrypoint= \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
${SQLIMAGE} /bin/bash -c "shopt -s dotglob ; \
|
||||
/bin/rm -rf /backup_mariadb/* ; \
|
||||
/bin/tar --use-compress-program='${DECOMPRESS_PROG}' -Pxvf /backup/${ARCHIVE_FILE}"
|
||||
fi
|
||||
elif [[ -f "${RESTORE_LOCATION}/backup_mariadb.tar.gz" ]]; then
|
||||
docker run --name mailcow-backup --rm \
|
||||
-v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/backup_mariadb/:rw,z \
|
||||
--entrypoint= \
|
||||
-v ${RESTORE_LOCATION}:/backup:z \
|
||||
${SQLIMAGE} /bin/bash -c "shopt -s dotglob ; \
|
||||
/bin/rm -rf /backup_mariadb/* ; \
|
||||
/bin/tar -Pxvzf /backup/backup_mariadb.tar.gz"
|
||||
fi
|
||||
echo "Modifying mailcow.conf..."
|
||||
source ${RESTORE_LOCATION}/mailcow.conf
|
||||
@@ -416,8 +363,8 @@ elif [[ ${1} == "restore" ]]; then
|
||||
fi
|
||||
|
||||
echo "[ 0 ] - all"
|
||||
# find all files in folder with *.zst or *.gz extension, print their base names, remove backup_, remove .tar (if present), remove .zst/.gz
|
||||
FILE_SELECTION[0]=$(find "${FOLDER_SELECTION[${input_sel}]}" -maxdepth 1 \( -type d -o -type f \) \( -name '*.zst' -o -name '*.gz' -o -name 'mysql' \) -printf '%f\n' | sed 's/backup_*//' | sed 's/\.[^.]*$//' | sed 's/\.[^.]*$//' | sort -u)
|
||||
# find all files in folder with *.gz extension, print their base names, remove backup_, remove .tar (if present), remove .gz
|
||||
FILE_SELECTION[0]=$(find "${FOLDER_SELECTION[${input_sel}]}" -maxdepth 1 \( -type d -o -type f \) \( -name '*.gz' -o -name 'mysql' \) -printf '%f\n' | sed 's/backup_*//' | sed 's/\.[^.]*$//' | sed 's/\.[^.]*$//')
|
||||
for file in $(ls -f "${FOLDER_SELECTION[${input_sel}]}"); do
|
||||
if [[ ${file} =~ vmail ]]; then
|
||||
echo "[ ${i} ] - Mail directory (/var/vmail)"
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Test script for backup_and_restore.sh
|
||||
# Tests backward compatibility with .tar.gz and new .tar.zst format
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
BACKUP_IMAGE="${BACKUP_IMAGE:-ghcr.io/mailcow/backup:latest}"
|
||||
TEST_DIR="/tmp/mailcow_backup_test_$$"
|
||||
THREADS=2
|
||||
|
||||
echo "=== Mailcow Backup & Restore Test Suite ==="
|
||||
echo "Test directory: ${TEST_DIR}"
|
||||
echo "Backup image: ${BACKUP_IMAGE}"
|
||||
echo ""
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
echo "Cleaning up test files..."
|
||||
rm -rf "${TEST_DIR}"
|
||||
docker rmi mailcow-backup-test 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Create test directory structure
|
||||
mkdir -p "${TEST_DIR}"/{test_data,backup_zst,backup_gz,restore_zst,restore_gz,backup_large_zst,backup_large_gz}
|
||||
echo "Test data for mailcow backup compatibility test" > "${TEST_DIR}/test_data/test.txt"
|
||||
echo "Additional file to verify complete restore" > "${TEST_DIR}/test_data/test2.txt"
|
||||
|
||||
# Build test backup image with zstd support
|
||||
echo "=== Building backup image with zstd support ==="
|
||||
docker build -t mailcow-backup-test "${SCRIPT_DIR}/../data/Dockerfiles/backup/" || {
|
||||
echo "ERROR: Failed to build backup image"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Test 1: Create .tar.zst backup
|
||||
echo ""
|
||||
echo "=== Test 1: Creating .tar.zst backup ==="
|
||||
docker run --rm \
|
||||
-w /data \
|
||||
-v "${TEST_DIR}/test_data:/data:ro" \
|
||||
-v "${TEST_DIR}/backup_zst:/backup" \
|
||||
mailcow-backup-test \
|
||||
/bin/tar --use-compress-program="zstd --rsyncable -T${THREADS}" \
|
||||
-cvpf /backup/backup_test.tar.zst . \
|
||||
> /dev/null
|
||||
echo "✓ .tar.zst backup created: $(ls -lh ${TEST_DIR}/backup_zst/backup_test.tar.zst | awk '{print $5}')"
|
||||
|
||||
# Test 2: Create .tar.gz backup
|
||||
echo ""
|
||||
echo "=== Test 2: Creating .tar.gz backup (legacy) ==="
|
||||
docker run --rm \
|
||||
-w /data \
|
||||
-v "${TEST_DIR}/test_data:/data:ro" \
|
||||
-v "${TEST_DIR}/backup_gz:/backup" \
|
||||
mailcow-backup-test \
|
||||
/bin/tar --use-compress-program="pigz --rsyncable -p ${THREADS}" \
|
||||
-cvpf /backup/backup_test.tar.gz . \
|
||||
> /dev/null
|
||||
echo "✓ .tar.gz backup created: $(ls -lh ${TEST_DIR}/backup_gz/backup_test.tar.gz | awk '{print $5}')"
|
||||
|
||||
# Test 3: Test get_archive_info function
|
||||
echo ""
|
||||
echo "=== Test 3: Testing get_archive_info function ==="
|
||||
|
||||
# Extract and test the function directly
|
||||
get_archive_info() {
|
||||
local backup_name="$1"
|
||||
local location="$2"
|
||||
|
||||
if [[ -f "${location}/${backup_name}.tar.zst" ]]; then
|
||||
echo "${backup_name}.tar.zst|zstd -d -T${THREADS}"
|
||||
elif [[ -f "${location}/${backup_name}.tar.gz" ]]; then
|
||||
echo "${backup_name}.tar.gz|pigz -d -p ${THREADS}"
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# Test with .tar.zst
|
||||
result=$(get_archive_info "backup_test" "${TEST_DIR}/backup_zst")
|
||||
if [[ "${result}" =~ "zstd" ]]; then
|
||||
echo "✓ Correctly detects .tar.zst and returns zstd decompressor"
|
||||
else
|
||||
echo "✗ Failed to detect .tar.zst"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test with .tar.gz
|
||||
result=$(get_archive_info "backup_test" "${TEST_DIR}/backup_gz")
|
||||
if [[ "${result}" =~ "pigz" ]]; then
|
||||
echo "✓ Correctly detects .tar.gz and returns pigz decompressor"
|
||||
else
|
||||
echo "✗ Failed to detect .tar.gz"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test with no file
|
||||
result=$(get_archive_info "backup_test" "${TEST_DIR}")
|
||||
if [[ -z "${result}" ]]; then
|
||||
echo "✓ Correctly returns empty when no backup file found"
|
||||
else
|
||||
echo "✗ Should return empty but got: ${result}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test 4: Restore from .tar.zst
|
||||
echo ""
|
||||
echo "=== Test 4: Restoring from .tar.zst ==="
|
||||
docker run --rm \
|
||||
-w /restore \
|
||||
-v "${TEST_DIR}/backup_zst:/backup:ro" \
|
||||
-v "${TEST_DIR}/restore_zst:/restore" \
|
||||
mailcow-backup-test \
|
||||
/bin/tar --use-compress-program="zstd -d -T${THREADS}" -xvpf /backup/backup_test.tar.zst \
|
||||
> /dev/null 2>&1
|
||||
|
||||
if [[ -f "${TEST_DIR}/restore_zst/test.txt" ]] && \
|
||||
[[ -f "${TEST_DIR}/restore_zst/test2.txt" ]]; then
|
||||
echo "✓ Successfully restored from .tar.zst"
|
||||
else
|
||||
echo "✗ Failed to restore from .tar.zst"
|
||||
ls -la "${TEST_DIR}/restore_zst/" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test 5: Restore from .tar.gz
|
||||
echo ""
|
||||
echo "=== Test 5: Restoring from .tar.gz (backward compatibility) ==="
|
||||
docker run --rm \
|
||||
-w /restore \
|
||||
-v "${TEST_DIR}/backup_gz:/backup:ro" \
|
||||
-v "${TEST_DIR}/restore_gz:/restore" \
|
||||
mailcow-backup-test \
|
||||
/bin/tar --use-compress-program="pigz -d -p ${THREADS}" -xvpf /backup/backup_test.tar.gz \
|
||||
> /dev/null 2>&1
|
||||
|
||||
if [[ -f "${TEST_DIR}/restore_gz/test.txt" ]] && \
|
||||
[[ -f "${TEST_DIR}/restore_gz/test2.txt" ]]; then
|
||||
echo "✓ Successfully restored from .tar.gz (backward compatible)"
|
||||
else
|
||||
echo "✗ Failed to restore from .tar.gz"
|
||||
ls -la "${TEST_DIR}/restore_gz/" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test 6: Verify content integrity
|
||||
echo ""
|
||||
echo "=== Test 6: Verifying content integrity ==="
|
||||
original_content=$(cat "${TEST_DIR}/test_data/test.txt")
|
||||
zst_content=$(cat "${TEST_DIR}/restore_zst/test.txt")
|
||||
gz_content=$(cat "${TEST_DIR}/restore_gz/test.txt")
|
||||
|
||||
if [[ "${original_content}" == "${zst_content}" ]] && \
|
||||
[[ "${original_content}" == "${gz_content}" ]]; then
|
||||
echo "✓ Content integrity verified for both formats"
|
||||
else
|
||||
echo "✗ Content mismatch detected"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test 7: Compare compression ratios
|
||||
echo ""
|
||||
echo "=== Test 7: Compression comparison ==="
|
||||
zst_size=$(stat -f%z "${TEST_DIR}/backup_zst/backup_test.tar.zst" 2>/dev/null || stat -c%s "${TEST_DIR}/backup_zst/backup_test.tar.zst")
|
||||
gz_size=$(stat -f%z "${TEST_DIR}/backup_gz/backup_test.tar.gz" 2>/dev/null || stat -c%s "${TEST_DIR}/backup_gz/backup_test.tar.gz")
|
||||
improvement=$(echo "scale=2; (${gz_size} - ${zst_size}) * 100 / ${gz_size}" | bc)
|
||||
|
||||
echo " Small files - .tar.gz size: ${gz_size} bytes"
|
||||
echo " Small files - .tar.zst size: ${zst_size} bytes"
|
||||
echo " Small files - Improvement: ${improvement}% smaller with zstd"
|
||||
|
||||
# Test 8: Error handling - missing backup file
|
||||
echo ""
|
||||
echo "=== Test 8: Error handling - Missing backup file ==="
|
||||
result=$(get_archive_info "nonexistent_backup" "${TEST_DIR}/backup_zst")
|
||||
if [[ -z "${result}" ]]; then
|
||||
echo "✓ Correctly handles missing backup files"
|
||||
else
|
||||
echo "✗ Should return empty for missing files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test 9: Error handling - Empty directory
|
||||
echo ""
|
||||
echo "=== Test 9: Error handling - Empty directory ==="
|
||||
mkdir -p "${TEST_DIR}/empty_dir"
|
||||
result=$(get_archive_info "backup_test" "${TEST_DIR}/empty_dir")
|
||||
if [[ -z "${result}" ]]; then
|
||||
echo "✓ Correctly handles empty directories"
|
||||
else
|
||||
echo "✗ Should return empty for empty directories"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test 10: Priority test - .tar.zst preferred over .tar.gz
|
||||
echo ""
|
||||
echo "=== Test 10: Format priority - .tar.zst preferred ==="
|
||||
mkdir -p "${TEST_DIR}/both_formats"
|
||||
touch "${TEST_DIR}/both_formats/backup_test.tar.gz"
|
||||
touch "${TEST_DIR}/both_formats/backup_test.tar.zst"
|
||||
result=$(get_archive_info "backup_test" "${TEST_DIR}/both_formats")
|
||||
if [[ "${result}" =~ "zstd" ]]; then
|
||||
echo "✓ Correctly prefers .tar.zst when both formats exist"
|
||||
else
|
||||
echo "✗ Should prefer .tar.zst over .tar.gz"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test 11: Large file compression test
|
||||
echo ""
|
||||
echo "=== Test 11: Large file compression test ==="
|
||||
mkdir -p "${TEST_DIR}/large_data"
|
||||
# Create ~10MB of compressible data (log-like content)
|
||||
for i in {1..50000}; do
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: Processing email message $i from user@example.com to recipient@domain.com" >> "${TEST_DIR}/large_data/maillog.txt"
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] DEBUG: SMTP connection established from 192.168.1.$((i % 255))" >> "${TEST_DIR}/large_data/maillog.txt"
|
||||
done 2>/dev/null
|
||||
|
||||
# Get size (portable: works on Linux and macOS)
|
||||
if du --version 2>/dev/null | grep -q GNU; then
|
||||
original_size=$(du -sb "${TEST_DIR}/large_data" | cut -f1)
|
||||
else
|
||||
# macOS
|
||||
original_size=$(find "${TEST_DIR}/large_data" -type f -exec stat -f%z {} \; | awk '{sum+=$1} END {print sum}')
|
||||
fi
|
||||
echo " Original data size: $(echo "scale=2; ${original_size} / 1024 / 1024" | bc) MB"
|
||||
|
||||
# Backup with zstd
|
||||
docker run --rm \
|
||||
-w /data \
|
||||
-v "${TEST_DIR}/large_data:/data:ro" \
|
||||
-v "${TEST_DIR}/backup_large_zst:/backup" \
|
||||
mailcow-backup-test \
|
||||
/bin/tar --use-compress-program="zstd --rsyncable -T${THREADS}" \
|
||||
-cvpf /backup/backup_large.tar.zst . \
|
||||
> /dev/null 2>&1
|
||||
|
||||
# Backup with pigz
|
||||
docker run --rm \
|
||||
-w /data \
|
||||
-v "${TEST_DIR}/large_data:/data:ro" \
|
||||
-v "${TEST_DIR}/backup_large_gz:/backup" \
|
||||
mailcow-backup-test \
|
||||
/bin/tar --use-compress-program="pigz --rsyncable -p ${THREADS}" \
|
||||
-cvpf /backup/backup_large.tar.gz . \
|
||||
> /dev/null 2>&1
|
||||
|
||||
zst_large_size=$(stat -f%z "${TEST_DIR}/backup_large_zst/backup_large.tar.zst" 2>/dev/null || stat -c%s "${TEST_DIR}/backup_large_zst/backup_large.tar.zst" 2>/dev/null || echo "0")
|
||||
gz_large_size=$(stat -f%z "${TEST_DIR}/backup_large_gz/backup_large.tar.gz" 2>/dev/null || stat -c%s "${TEST_DIR}/backup_large_gz/backup_large.tar.gz" 2>/dev/null || echo "0")
|
||||
|
||||
if [[ ${zst_large_size} -gt 0 ]] && [[ ${gz_large_size} -gt 0 ]]; then
|
||||
large_improvement=$(echo "scale=2; (${gz_large_size} - ${zst_large_size}) * 100 / ${gz_large_size}" | bc)
|
||||
|
||||
echo " .tar.gz compressed: $(echo "scale=2; ${gz_large_size} / 1024 / 1024" | bc) MB"
|
||||
echo " .tar.zst compressed: $(echo "scale=2; ${zst_large_size} / 1024 / 1024" | bc) MB"
|
||||
echo " Improvement: ${large_improvement}% smaller with zstd"
|
||||
else
|
||||
echo " ✗ Failed to get file sizes"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $(echo "${large_improvement} > 0" | bc) -eq 1 ]]; then
|
||||
echo "✓ zstd provides better compression on realistic data"
|
||||
else
|
||||
echo "⚠ zstd compression similar or worse than gzip (unusual but not critical)"
|
||||
fi
|
||||
|
||||
# Test 12: Thread scaling test
|
||||
echo ""
|
||||
echo "=== Test 12: Multi-threading verification ==="
|
||||
# This test verifies that different thread counts work (not measuring speed difference)
|
||||
for thread_count in 1 4; do
|
||||
THREADS=${thread_count}
|
||||
result=$(get_archive_info "backup_test" "${TEST_DIR}/backup_zst")
|
||||
if [[ "${result}" =~ "-T${thread_count}" ]]; then
|
||||
echo "✓ Thread count ${thread_count} correctly configured"
|
||||
else
|
||||
echo "✗ Thread count not properly applied"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== All tests passed! ==="
|
||||
echo ""
|
||||
echo "Summary:"
|
||||
echo " ✓ zstd compression working"
|
||||
echo " ✓ pigz compression working (legacy)"
|
||||
echo " ✓ zstd decompression working"
|
||||
echo " ✓ pigz decompression working (backward compatible)"
|
||||
echo " ✓ Archive detection working"
|
||||
echo " ✓ Content integrity verified"
|
||||
echo " ✓ Format priority correct (.tar.zst preferred)"
|
||||
echo " ✓ Error handling for missing files"
|
||||
echo " ✓ Error handling for empty directories"
|
||||
echo " ✓ Multi-threading configuration verified"
|
||||
echo " ✓ Large file compression: ${large_improvement}% improvement"
|
||||
echo " ✓ Small file compression: ${improvement}% improvement"
|
||||
@@ -25,6 +25,6 @@ services:
|
||||
- /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysqld.sock
|
||||
|
||||
mysql-mailcow:
|
||||
image: alpine:3.22
|
||||
image: alpine:3.20
|
||||
command: /bin/true
|
||||
restart: "no"
|
||||
|
||||
Reference in New Issue
Block a user