Merge remote-tracking branch 'origin/nightly' into feature/sso
This commit is contained in:
commit
18783aa303
|
@ -14,7 +14,7 @@ jobs:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Mark/Close Stale Issues and Pull Requests 🗑️
|
- name: Mark/Close Stale Issues and Pull Requests 🗑️
|
||||||
uses: actions/stale@v7.0.0
|
uses: actions/stale@v8.0.0
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
||||||
days-before-stale: 60
|
days-before-stale: 60
|
||||||
|
|
|
@ -12,7 +12,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Run the Action
|
- name: Run the Action
|
||||||
uses: devops-infra/action-pull-request@v0.5.3
|
uses: devops-infra/action-pull-request@v0.5.5
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
|
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
|
||||||
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
|
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM clamav/clamav:1.0_base
|
FROM clamav/clamav:1.0.1-1_base
|
||||||
|
|
||||||
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import os
|
||||||
import json
|
import json
|
||||||
import asyncio
|
import asyncio
|
||||||
import redis
|
import redis
|
||||||
|
import platform
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
from logging.config import dictConfig
|
from logging.config import dictConfig
|
||||||
|
@ -370,7 +371,7 @@ class DockerUtils:
|
||||||
return exec_run_handler('utf8_text_only', sieve_return)
|
return exec_run_handler('utf8_text_only', sieve_return)
|
||||||
# api call: container_post - post_action: exec - cmd: sieve - task: print
|
# api call: container_post - post_action: exec - cmd: sieve - task: print
|
||||||
def container_post__exec__sieve__print(self, container_id, request_json):
|
def container_post__exec__sieve__print(self, container_id, request_json):
|
||||||
if 'username' in request.json and 'script_name' in request_json:
|
if 'username' in request_json and 'script_name' in request_json:
|
||||||
for container in self.docker_client.containers.list(filters={"id": container_id}):
|
for container in self.docker_client.containers.list(filters={"id": container_id}):
|
||||||
cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request_json['username'].replace("'", "'\\''") + "' '" + request_json['script_name'].replace("'", "'\\''") + "'"]
|
cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request_json['username'].replace("'", "'\\''") + "' '" + request_json['script_name'].replace("'", "'\\''") + "'"]
|
||||||
sieve_return = container.exec_run(cmd)
|
sieve_return = container.exec_run(cmd)
|
||||||
|
@ -380,7 +381,15 @@ class DockerUtils:
|
||||||
if 'maildir' in request_json:
|
if 'maildir' in request_json:
|
||||||
for container in self.docker_client.containers.list(filters={"id": container_id}):
|
for container in self.docker_client.containers.list(filters={"id": container_id}):
|
||||||
sane_name = re.sub(r'\W+', '', request_json['maildir'])
|
sane_name = re.sub(r'\W+', '', request_json['maildir'])
|
||||||
cmd = ["/bin/bash", "-c", "if [[ -d '/var/vmail/" + request_json['maildir'].replace("'", "'\\''") + "' ]]; then /bin/mv '/var/vmail/" + request_json['maildir'].replace("'", "'\\''") + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi"]
|
vmail_name = request_json['maildir'].replace("'", "'\\''")
|
||||||
|
cmd_vmail = "if [[ -d '/var/vmail/" + vmail_name + "' ]]; then /bin/mv '/var/vmail/" + vmail_name + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi"
|
||||||
|
index_name = request_json['maildir'].split("/")
|
||||||
|
if len(index_name) > 1:
|
||||||
|
index_name = index_name[1].replace("'", "'\\''") + "@" + index_name[0].replace("'", "'\\''")
|
||||||
|
cmd_vmail_index = "if [[ -d '/var/vmail_index/" + index_name + "' ]]; then /bin/mv '/var/vmail_index/" + index_name + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "_index'; fi"
|
||||||
|
cmd = ["/bin/bash", "-c", cmd_vmail + " && " + cmd_vmail_index]
|
||||||
|
else:
|
||||||
|
cmd = ["/bin/bash", "-c", cmd_vmail]
|
||||||
maildir_cleanup = container.exec_run(cmd, user='vmail')
|
maildir_cleanup = container.exec_run(cmd, user='vmail')
|
||||||
return exec_run_handler('generic', maildir_cleanup)
|
return exec_run_handler('generic', maildir_cleanup)
|
||||||
# api call: container_post - post_action: exec - cmd: rspamd - task: worker_password
|
# api call: container_post - post_action: exec - cmd: rspamd - task: worker_password
|
||||||
|
@ -477,7 +486,8 @@ async def get_host_stats(wait=5):
|
||||||
"swap": psutil.swap_memory()
|
"swap": psutil.swap_memory()
|
||||||
},
|
},
|
||||||
"uptime": time.time() - psutil.boot_time(),
|
"uptime": time.time() - psutil.boot_time(),
|
||||||
"system_time": system_time.strftime("%d.%m.%Y %H:%M:%S")
|
"system_time": system_time.strftime("%d.%m.%Y %H:%M:%S"),
|
||||||
|
"architecture": platform.machine()
|
||||||
}
|
}
|
||||||
|
|
||||||
redis_client.set('host_stats', json.dumps(host_stats), ex=10)
|
redis_client.set('host_stats', json.dumps(host_stats), ex=10)
|
||||||
|
|
|
@ -21,6 +21,7 @@ RUN groupadd -g 5000 vmail \
|
||||||
&& touch /etc/default/locale \
|
&& touch /etc/default/locale \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get -y --no-install-recommends install \
|
&& apt-get -y --no-install-recommends install \
|
||||||
|
build-essential \
|
||||||
apt-transport-https \
|
apt-transport-https \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
cpanminus \
|
cpanminus \
|
||||||
|
@ -61,6 +62,7 @@ RUN groupadd -g 5000 vmail \
|
||||||
libproc-processtable-perl \
|
libproc-processtable-perl \
|
||||||
libreadonly-perl \
|
libreadonly-perl \
|
||||||
libregexp-common-perl \
|
libregexp-common-perl \
|
||||||
|
libssl-dev \
|
||||||
libsys-meminfo-perl \
|
libsys-meminfo-perl \
|
||||||
libterm-readkey-perl \
|
libterm-readkey-perl \
|
||||||
libtest-deep-perl \
|
libtest-deep-perl \
|
||||||
|
@ -112,6 +114,8 @@ RUN groupadd -g 5000 vmail \
|
||||||
&& apt-get autoclean \
|
&& apt-get autoclean \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& rm -rf /tmp/* /var/tmp/* /root/.cache/
|
&& rm -rf /tmp/* /var/tmp/* /root/.cache/
|
||||||
|
# imapsync dependencies
|
||||||
|
RUN cpan Crypt::OpenSSL::PKCS12
|
||||||
|
|
||||||
COPY trim_logs.sh /usr/local/bin/trim_logs.sh
|
COPY trim_logs.sh /usr/local/bin/trim_logs.sh
|
||||||
COPY clean_q_aged.sh /usr/local/bin/clean_q_aged.sh
|
COPY clean_q_aged.sh /usr/local/bin/clean_q_aged.sh
|
||||||
|
|
|
@ -8492,6 +8492,7 @@ sub xoauth2
|
||||||
require HTML::Entities ;
|
require HTML::Entities ;
|
||||||
require JSON ;
|
require JSON ;
|
||||||
require JSON::WebToken::Crypt::RSA ;
|
require JSON::WebToken::Crypt::RSA ;
|
||||||
|
require Crypt::OpenSSL::PKCS12;
|
||||||
require Crypt::OpenSSL::RSA ;
|
require Crypt::OpenSSL::RSA ;
|
||||||
require Encode::Byte ;
|
require Encode::Byte ;
|
||||||
require IO::Socket::SSL ;
|
require IO::Socket::SSL ;
|
||||||
|
@ -8532,8 +8533,9 @@ sub xoauth2
|
||||||
|
|
||||||
$sync->{ debug } and myprint( "Service account: $iss\nKey file: $keyfile\nKey password: $keypass\n");
|
$sync->{ debug } and myprint( "Service account: $iss\nKey file: $keyfile\nKey password: $keypass\n");
|
||||||
|
|
||||||
# Get private key from p12 file (would be better in perl...)
|
# Get private key from p12 file
|
||||||
$key = `openssl pkcs12 -in "$keyfile" -nodes -nocerts -passin pass:$keypass -nomacver`;
|
my $pkcs12 = Crypt::OpenSSL::PKCS12->new_from_file($keyfile);
|
||||||
|
$key = $pkcs12->private_key($keypass);
|
||||||
|
|
||||||
$sync->{ debug } and myprint( "Private key:\n$key\n");
|
$sync->{ debug } and myprint( "Private key:\n$key\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,28 +64,40 @@ def refreshF2boptions():
|
||||||
global f2boptions
|
global f2boptions
|
||||||
global quit_now
|
global quit_now
|
||||||
global exit_code
|
global exit_code
|
||||||
|
|
||||||
|
f2boptions = {}
|
||||||
|
|
||||||
if not r.get('F2B_OPTIONS'):
|
if not r.get('F2B_OPTIONS'):
|
||||||
f2boptions = {}
|
f2boptions['ban_time'] = r.get('F2B_BAN_TIME')
|
||||||
f2boptions['ban_time'] = int
|
f2boptions['max_ban_time'] = r.get('F2B_MAX_BAN_TIME')
|
||||||
f2boptions['max_attempts'] = int
|
f2boptions['ban_time_increment'] = r.get('F2B_BAN_TIME_INCREMENT')
|
||||||
f2boptions['retry_window'] = int
|
f2boptions['max_attempts'] = r.get('F2B_MAX_ATTEMPTS')
|
||||||
f2boptions['netban_ipv4'] = int
|
f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW')
|
||||||
f2boptions['netban_ipv6'] = int
|
f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4')
|
||||||
f2boptions['ban_time'] = r.get('F2B_BAN_TIME') or 1800
|
f2boptions['netban_ipv6'] = r.get('F2B_NETBAN_IPV6')
|
||||||
f2boptions['max_attempts'] = r.get('F2B_MAX_ATTEMPTS') or 10
|
|
||||||
f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW') or 600
|
|
||||||
f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4') or 32
|
|
||||||
f2boptions['netban_ipv6'] = r.get('F2B_NETBAN_IPV6') or 128
|
|
||||||
r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False))
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
f2boptions = {}
|
|
||||||
f2boptions = json.loads(r.get('F2B_OPTIONS'))
|
f2boptions = json.loads(r.get('F2B_OPTIONS'))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print('Error loading F2B options: F2B_OPTIONS is not json')
|
print('Error loading F2B options: F2B_OPTIONS is not json')
|
||||||
quit_now = True
|
quit_now = True
|
||||||
exit_code = 2
|
exit_code = 2
|
||||||
|
|
||||||
|
verifyF2boptions(f2boptions)
|
||||||
|
r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False))
|
||||||
|
|
||||||
|
def verifyF2boptions(f2boptions):
|
||||||
|
verifyF2boption(f2boptions,'ban_time', 1800)
|
||||||
|
verifyF2boption(f2boptions,'max_ban_time', 10000)
|
||||||
|
verifyF2boption(f2boptions,'ban_time_increment', True)
|
||||||
|
verifyF2boption(f2boptions,'max_attempts', 10)
|
||||||
|
verifyF2boption(f2boptions,'retry_window', 600)
|
||||||
|
verifyF2boption(f2boptions,'netban_ipv4', 32)
|
||||||
|
verifyF2boption(f2boptions,'netban_ipv6', 128)
|
||||||
|
|
||||||
|
def verifyF2boption(f2boptions, f2boption, f2bdefault):
|
||||||
|
f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault
|
||||||
|
|
||||||
def refreshF2bregex():
|
def refreshF2bregex():
|
||||||
global f2bregex
|
global f2bregex
|
||||||
global quit_now
|
global quit_now
|
||||||
|
@ -147,6 +159,7 @@ def ban(address):
|
||||||
global lock
|
global lock
|
||||||
refreshF2boptions()
|
refreshF2boptions()
|
||||||
BAN_TIME = int(f2boptions['ban_time'])
|
BAN_TIME = int(f2boptions['ban_time'])
|
||||||
|
BAN_TIME_INCREMENT = bool(f2boptions['ban_time_increment'])
|
||||||
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
|
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
|
||||||
RETRY_WINDOW = int(f2boptions['retry_window'])
|
RETRY_WINDOW = int(f2boptions['retry_window'])
|
||||||
NETBAN_IPV4 = '/' + str(f2boptions['netban_ipv4'])
|
NETBAN_IPV4 = '/' + str(f2boptions['netban_ipv4'])
|
||||||
|
@ -174,20 +187,16 @@ def ban(address):
|
||||||
net = ipaddress.ip_network((address + (NETBAN_IPV4 if type(ip) is ipaddress.IPv4Address else NETBAN_IPV6)), strict=False)
|
net = ipaddress.ip_network((address + (NETBAN_IPV4 if type(ip) is ipaddress.IPv4Address else NETBAN_IPV6)), strict=False)
|
||||||
net = str(net)
|
net = str(net)
|
||||||
|
|
||||||
if not net in bans or time.time() - bans[net]['last_attempt'] > RETRY_WINDOW:
|
if not net in bans:
|
||||||
bans[net] = { 'attempts': 0 }
|
bans[net] = {'attempts': 0, 'last_attempt': 0, 'ban_counter': 0}
|
||||||
active_window = RETRY_WINDOW
|
|
||||||
else:
|
|
||||||
active_window = time.time() - bans[net]['last_attempt']
|
|
||||||
|
|
||||||
bans[net]['attempts'] += 1
|
bans[net]['attempts'] += 1
|
||||||
bans[net]['last_attempt'] = time.time()
|
bans[net]['last_attempt'] = time.time()
|
||||||
|
|
||||||
active_window = time.time() - bans[net]['last_attempt']
|
|
||||||
|
|
||||||
if bans[net]['attempts'] >= MAX_ATTEMPTS:
|
if bans[net]['attempts'] >= MAX_ATTEMPTS:
|
||||||
cur_time = int(round(time.time()))
|
cur_time = int(round(time.time()))
|
||||||
logCrit('Banning %s for %d minutes' % (net, BAN_TIME / 60))
|
NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter']
|
||||||
|
logCrit('Banning %s for %d minutes' % (net, NET_BAN_TIME / 60 ))
|
||||||
if type(ip) is ipaddress.IPv4Address:
|
if type(ip) is ipaddress.IPv4Address:
|
||||||
with lock:
|
with lock:
|
||||||
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
|
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
|
||||||
|
@ -206,7 +215,7 @@ def ban(address):
|
||||||
rule.target = target
|
rule.target = target
|
||||||
if rule not in chain.rules:
|
if rule not in chain.rules:
|
||||||
chain.insert_rule(rule)
|
chain.insert_rule(rule)
|
||||||
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + BAN_TIME)
|
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + NET_BAN_TIME)
|
||||||
else:
|
else:
|
||||||
logWarn('%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
|
logWarn('%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
|
||||||
|
|
||||||
|
@ -238,7 +247,8 @@ def unban(net):
|
||||||
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
|
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
|
||||||
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||||
if net in bans:
|
if net in bans:
|
||||||
del bans[net]
|
bans[net]['attempts'] = 0
|
||||||
|
bans[net]['ban_counter'] += 1
|
||||||
|
|
||||||
def permBan(net, unban=False):
|
def permBan(net, unban=False):
|
||||||
global lock
|
global lock
|
||||||
|
@ -332,7 +342,7 @@ def watch():
|
||||||
logWarn('%s matched rule id %s (%s)' % (addr, rule_id, item['data']))
|
logWarn('%s matched rule id %s (%s)' % (addr, rule_id, item['data']))
|
||||||
ban(addr)
|
ban(addr)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logWarn('Error reading log line from pubsub')
|
logWarn('Error reading log line from pubsub: %s' % ex)
|
||||||
quit_now = True
|
quit_now = True
|
||||||
exit_code = 2
|
exit_code = 2
|
||||||
|
|
||||||
|
@ -359,21 +369,30 @@ def snat4(snat_target):
|
||||||
chain = iptc.Chain(table, 'POSTROUTING')
|
chain = iptc.Chain(table, 'POSTROUTING')
|
||||||
table.autocommit = False
|
table.autocommit = False
|
||||||
new_rule = get_snat4_rule()
|
new_rule = get_snat4_rule()
|
||||||
for position, rule in enumerate(chain.rules):
|
|
||||||
match = all((
|
if not chain.rules:
|
||||||
new_rule.get_src() == rule.get_src(),
|
# if there are no rules in the chain, insert the new rule directly
|
||||||
new_rule.get_dst() == rule.get_dst(),
|
logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
|
||||||
new_rule.target.parameters == rule.target.parameters,
|
chain.insert_rule(new_rule)
|
||||||
new_rule.target.name == rule.target.name
|
else:
|
||||||
))
|
for position, rule in enumerate(chain.rules):
|
||||||
if position == 0:
|
if not hasattr(rule.target, 'parameter'):
|
||||||
if not match:
|
continue
|
||||||
logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
|
match = all((
|
||||||
chain.insert_rule(new_rule)
|
new_rule.get_src() == rule.get_src(),
|
||||||
else:
|
new_rule.get_dst() == rule.get_dst(),
|
||||||
if match:
|
new_rule.target.parameters == rule.target.parameters,
|
||||||
logInfo(f'Remove rule for source network {new_rule.src} to SNAT target {snat_target} from POSTROUTING chain at position {position}')
|
new_rule.target.name == rule.target.name
|
||||||
chain.delete_rule(rule)
|
))
|
||||||
|
if position == 0:
|
||||||
|
if not match:
|
||||||
|
logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
|
||||||
|
chain.insert_rule(new_rule)
|
||||||
|
else:
|
||||||
|
if match:
|
||||||
|
logInfo(f'Remove rule for source network {new_rule.src} to SNAT target {snat_target} from POSTROUTING chain at position {position}')
|
||||||
|
chain.delete_rule(rule)
|
||||||
|
|
||||||
table.commit()
|
table.commit()
|
||||||
table.autocommit = True
|
table.autocommit = True
|
||||||
except:
|
except:
|
||||||
|
@ -418,6 +437,8 @@ def autopurge():
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
refreshF2boptions()
|
refreshF2boptions()
|
||||||
BAN_TIME = int(f2boptions['ban_time'])
|
BAN_TIME = int(f2boptions['ban_time'])
|
||||||
|
MAX_BAN_TIME = int(f2boptions['max_ban_time'])
|
||||||
|
BAN_TIME_INCREMENT = bool(f2boptions['ban_time_increment'])
|
||||||
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
|
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
|
||||||
QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN')
|
QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN')
|
||||||
if QUEUE_UNBAN:
|
if QUEUE_UNBAN:
|
||||||
|
@ -425,7 +446,9 @@ def autopurge():
|
||||||
unban(str(net))
|
unban(str(net))
|
||||||
for net in bans.copy():
|
for net in bans.copy():
|
||||||
if bans[net]['attempts'] >= MAX_ATTEMPTS:
|
if bans[net]['attempts'] >= MAX_ATTEMPTS:
|
||||||
if time.time() - bans[net]['last_attempt'] > BAN_TIME:
|
NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter']
|
||||||
|
TIME_SINCE_LAST_ATTEMPT = time.time() - bans[net]['last_attempt']
|
||||||
|
if TIME_SINCE_LAST_ATTEMPT > NET_BAN_TIME or TIME_SINCE_LAST_ATTEMPT > MAX_BAN_TIME:
|
||||||
unban(net)
|
unban(net)
|
||||||
|
|
||||||
def isIpNetwork(address):
|
def isIpNetwork(address):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM php:8.1-fpm-alpine3.17
|
FROM php:8.2-fpm-alpine3.17
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced
|
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced
|
||||||
|
@ -12,7 +12,7 @@ ARG MEMCACHED_PECL_VERSION=3.2.0
|
||||||
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced
|
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced
|
||||||
ARG REDIS_PECL_VERSION=5.3.7
|
ARG REDIS_PECL_VERSION=5.3.7
|
||||||
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced
|
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced
|
||||||
ARG COMPOSER_VERSION=2.5.1
|
ARG COMPOSER_VERSION=2.5.5
|
||||||
|
|
||||||
RUN apk add -U --no-cache autoconf \
|
RUN apk add -U --no-cache autoconf \
|
||||||
aspell-dev \
|
aspell-dev \
|
||||||
|
@ -52,6 +52,7 @@ RUN apk add -U --no-cache autoconf \
|
||||||
libxpm-dev \
|
libxpm-dev \
|
||||||
libzip \
|
libzip \
|
||||||
libzip-dev \
|
libzip-dev \
|
||||||
|
linux-headers \
|
||||||
make \
|
make \
|
||||||
mysql-client \
|
mysql-client \
|
||||||
openldap-dev \
|
openldap-dev \
|
||||||
|
@ -75,7 +76,7 @@ RUN apk add -U --no-cache autoconf \
|
||||||
--with-webp \
|
--with-webp \
|
||||||
--with-xpm \
|
--with-xpm \
|
||||||
--with-avif \
|
--with-avif \
|
||||||
&& docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets zip bcmath gmp \
|
&& docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets sysvsem zip bcmath gmp \
|
||||||
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \
|
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \
|
||||||
&& docker-php-ext-install -j 4 imap \
|
&& docker-php-ext-install -j 4 imap \
|
||||||
&& curl --silent --show-error https://getcomposer.org/installer | php -- --version=${COMPOSER_VERSION} \
|
&& curl --silent --show-error https://getcomposer.org/installer | php -- --version=${COMPOSER_VERSION} \
|
||||||
|
@ -99,6 +100,7 @@ RUN apk add -U --no-cache autoconf \
|
||||||
libxml2-dev \
|
libxml2-dev \
|
||||||
libxpm-dev \
|
libxpm-dev \
|
||||||
libzip-dev \
|
libzip-dev \
|
||||||
|
linux-headers \
|
||||||
make \
|
make \
|
||||||
openldap-dev \
|
openldap-dev \
|
||||||
pcre-dev \
|
pcre-dev \
|
||||||
|
|
|
@ -24,7 +24,7 @@ server {
|
||||||
add_header X-Download-Options "noopen" always;
|
add_header X-Download-Options "noopen" always;
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
add_header X-Permitted-Cross-Domain-Policies "none" always;
|
add_header X-Permitted-Cross-Domain-Policies "none" always;
|
||||||
add_header X-Robots-Tag "none" always;
|
add_header X-Robots-Tag "noindex, nofollow" always;
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
|
||||||
fastcgi_hide_header X-Powered-By;
|
fastcgi_hide_header X-Powered-By;
|
||||||
|
|
|
@ -27,4 +27,5 @@
|
||||||
#197518 2 #Rackmarkt SL, Spain
|
#197518 2 #Rackmarkt SL, Spain
|
||||||
#197695 2 #Domain names registrar REG.RU Ltd, Russia
|
#197695 2 #Domain names registrar REG.RU Ltd, Russia
|
||||||
#198068 2 #P.A.G.M. OU, Estonia
|
#198068 2 #P.A.G.M. OU, Estonia
|
||||||
#201942 5 #Soltia Consulting SL, Spain
|
#201942 5 #Soltia Consulting SL, Spain
|
||||||
|
#213373 4 #IP Connect Inc
|
|
@ -8,7 +8,7 @@ VIRUS_FOUND {
|
||||||
}
|
}
|
||||||
# Bad policy from free mail providers
|
# Bad policy from free mail providers
|
||||||
FREEMAIL_POLICY_FAILURE {
|
FREEMAIL_POLICY_FAILURE {
|
||||||
expression = "-g+:policies & !DMARC_POLICY_ALLOW & !MAILLIST & ( FREEMAIL_ENVFROM | FREEMAIL_FROM ) & !WHITELISTED_FWD_HOST";
|
expression = "FREEMAIL_FROM & !DMARC_POLICY_ALLOW & !MAILLIST& !WHITELISTED_FWD_HOST & -g+:policies";
|
||||||
score = 16.0;
|
score = 16.0;
|
||||||
}
|
}
|
||||||
# Applies to freemail with undisclosed recipients
|
# Applies to freemail with undisclosed recipients
|
||||||
|
|
|
@ -159,8 +159,8 @@ BAZAAR_ABUSE_CH {
|
||||||
}
|
}
|
||||||
|
|
||||||
URLHAUS_ABUSE_CH {
|
URLHAUS_ABUSE_CH {
|
||||||
type = "url";
|
type = "selector";
|
||||||
filter = "full";
|
selector = "urls";
|
||||||
map = "https://urlhaus.abuse.ch/downloads/text_online/";
|
map = "https://urlhaus.abuse.ch/downloads/text_online/";
|
||||||
score = 10.0;
|
score = 10.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
SOGoFirstDayOfWeek = "1";
|
SOGoFirstDayOfWeek = "1";
|
||||||
|
|
||||||
SOGoSieveFolderEncoding = "UTF-8";
|
SOGoSieveFolderEncoding = "UTF-8";
|
||||||
SOGoPasswordChangeEnabled = YES;
|
SOGoPasswordChangeEnabled = NO;
|
||||||
SOGoSentFolderName = "Sent";
|
SOGoSentFolderName = "Sent";
|
||||||
SOGoMailShowSubscribedFoldersOnly = NO;
|
SOGoMailShowSubscribedFoldersOnly = NO;
|
||||||
NGImap4ConnectionStringSeparator = "/";
|
NGImap4ConnectionStringSeparator = "/";
|
||||||
|
|
|
@ -3176,8 +3176,10 @@ paths:
|
||||||
example:
|
example:
|
||||||
attr:
|
attr:
|
||||||
ban_time: "86400"
|
ban_time: "86400"
|
||||||
|
ban_time_increment: "1"
|
||||||
blacklist: "10.100.6.5/32,10.100.8.4/32"
|
blacklist: "10.100.6.5/32,10.100.8.4/32"
|
||||||
max_attempts: "5"
|
max_attempts: "5"
|
||||||
|
max_ban_time: "86400"
|
||||||
netban_ipv4: "24"
|
netban_ipv4: "24"
|
||||||
netban_ipv6: "64"
|
netban_ipv6: "64"
|
||||||
retry_window: "600"
|
retry_window: "600"
|
||||||
|
@ -3191,11 +3193,17 @@ paths:
|
||||||
description: the backlisted ips or hostnames separated by comma
|
description: the backlisted ips or hostnames separated by comma
|
||||||
type: string
|
type: string
|
||||||
ban_time:
|
ban_time:
|
||||||
description: the time a ip should be banned
|
description: the time an ip should be banned
|
||||||
type: number
|
type: number
|
||||||
|
ban_time_increment:
|
||||||
|
description: if the time of the ban should increase each time
|
||||||
|
type: boolean
|
||||||
max_attempts:
|
max_attempts:
|
||||||
description: the maximum numbe of wrong logins before a ip is banned
|
description: the maximum numbe of wrong logins before a ip is banned
|
||||||
type: number
|
type: number
|
||||||
|
max_ban_time:
|
||||||
|
description: the maximum time an ip should be banned
|
||||||
|
type: number
|
||||||
netban_ipv4:
|
netban_ipv4:
|
||||||
description: the networks mask to ban for ipv4
|
description: the networks mask to ban for ipv4
|
||||||
type: number
|
type: number
|
||||||
|
@ -4113,10 +4121,12 @@ paths:
|
||||||
response:
|
response:
|
||||||
value:
|
value:
|
||||||
ban_time: 604800
|
ban_time: 604800
|
||||||
|
ban_time_increment: 1
|
||||||
blacklist: |-
|
blacklist: |-
|
||||||
45.82.153.37/32
|
45.82.153.37/32
|
||||||
92.118.38.52/32
|
92.118.38.52/32
|
||||||
max_attempts: 1
|
max_attempts: 1
|
||||||
|
max_ban_time: 604800
|
||||||
netban_ipv4: 32
|
netban_ipv4: 32
|
||||||
netban_ipv6: 128
|
netban_ipv6: 128
|
||||||
perm_bans:
|
perm_bans:
|
||||||
|
|
|
@ -342,6 +342,10 @@ div.dataTables_wrapper div.dt-row {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.dataTables_wrapper span.sorting-value {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
div.dataTables_scrollHead table.dataTable {
|
div.dataTables_scrollHead table.dataTable {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,4 +66,6 @@ table tbody tr td input[type="checkbox"] {
|
||||||
padding: .2em .4em .3em !important;
|
padding: .2em .4em .3em !important;
|
||||||
background-color: #ececec!important;
|
background-color: #ececec!important;
|
||||||
}
|
}
|
||||||
|
.badge.bg-info .bi {
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,11 @@ legend {
|
||||||
background-color: #7a7a7a !important;
|
background-color: #7a7a7a !important;
|
||||||
border-color: #5c5c5c !important;
|
border-color: #5c5c5c !important;
|
||||||
}
|
}
|
||||||
|
.btn-dark {
|
||||||
|
color: #000 !important;;
|
||||||
|
background-color: #f6f6f6 !important;;
|
||||||
|
border-color: #ddd !important;;
|
||||||
|
}
|
||||||
.btn-check:checked+.btn-secondary, .btn-check:active+.btn-secondary, .btn-secondary:active, .btn-secondary.active, .show>.btn-secondary.dropdown-toggle {
|
.btn-check:checked+.btn-secondary, .btn-check:active+.btn-secondary, .btn-secondary:active, .btn-secondary.active, .show>.btn-secondary.dropdown-toggle {
|
||||||
border-color: #7a7a7a !important;
|
border-color: #7a7a7a !important;
|
||||||
}
|
}
|
||||||
|
@ -299,22 +304,22 @@ a:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
|
||||||
background-color: #7a7a7a !important;
|
background-color: #7a7a7a !important;
|
||||||
}
|
}
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before {
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before {
|
||||||
background-color: #7a7a7a !important;
|
background-color: #7a7a7a !important;
|
||||||
border: 1.5px solid #5c5c5c !important;
|
border: 1.5px solid #5c5c5c !important;
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before {
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before {
|
||||||
background-color: #949494;
|
background-color: #949494;
|
||||||
}
|
}
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
|
||||||
background-color: #444444;
|
background-color: #444444;
|
||||||
}
|
}
|
||||||
|
@ -327,7 +332,7 @@ table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
|
||||||
}
|
}
|
||||||
.btn.btn-outline-secondary {
|
.btn.btn-outline-secondary {
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
border-color: #7a7a7a !important;
|
border-color: #7a7a7a !important;
|
||||||
}
|
}
|
||||||
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
|
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
|
||||||
background-color: #9b9b9b !important;
|
background-color: #9b9b9b !important;
|
||||||
|
|
|
@ -239,7 +239,9 @@ function fail2ban($_action, $_data = null) {
|
||||||
$is_now = fail2ban('get');
|
$is_now = fail2ban('get');
|
||||||
if (!empty($is_now)) {
|
if (!empty($is_now)) {
|
||||||
$ban_time = intval((isset($_data['ban_time'])) ? $_data['ban_time'] : $is_now['ban_time']);
|
$ban_time = intval((isset($_data['ban_time'])) ? $_data['ban_time'] : $is_now['ban_time']);
|
||||||
|
$ban_time_increment = (isset($_data['ban_time_increment']) && $_data['ban_time_increment'] == "1") ? 1 : 0;
|
||||||
$max_attempts = intval((isset($_data['max_attempts'])) ? $_data['max_attempts'] : $is_now['max_attempts']);
|
$max_attempts = intval((isset($_data['max_attempts'])) ? $_data['max_attempts'] : $is_now['max_attempts']);
|
||||||
|
$max_ban_time = intval((isset($_data['max_ban_time'])) ? $_data['max_ban_time'] : $is_now['max_ban_time']);
|
||||||
$retry_window = intval((isset($_data['retry_window'])) ? $_data['retry_window'] : $is_now['retry_window']);
|
$retry_window = intval((isset($_data['retry_window'])) ? $_data['retry_window'] : $is_now['retry_window']);
|
||||||
$netban_ipv4 = intval((isset($_data['netban_ipv4'])) ? $_data['netban_ipv4'] : $is_now['netban_ipv4']);
|
$netban_ipv4 = intval((isset($_data['netban_ipv4'])) ? $_data['netban_ipv4'] : $is_now['netban_ipv4']);
|
||||||
$netban_ipv6 = intval((isset($_data['netban_ipv6'])) ? $_data['netban_ipv6'] : $is_now['netban_ipv6']);
|
$netban_ipv6 = intval((isset($_data['netban_ipv6'])) ? $_data['netban_ipv6'] : $is_now['netban_ipv6']);
|
||||||
|
@ -256,6 +258,8 @@ function fail2ban($_action, $_data = null) {
|
||||||
}
|
}
|
||||||
$f2b_options = array();
|
$f2b_options = array();
|
||||||
$f2b_options['ban_time'] = ($ban_time < 60) ? 60 : $ban_time;
|
$f2b_options['ban_time'] = ($ban_time < 60) ? 60 : $ban_time;
|
||||||
|
$f2b_options['ban_time_increment'] = ($ban_time_increment == 1) ? true : false;
|
||||||
|
$f2b_options['max_ban_time'] = ($max_ban_time < 60) ? 60 : $max_ban_time;
|
||||||
$f2b_options['netban_ipv4'] = ($netban_ipv4 < 8) ? 8 : $netban_ipv4;
|
$f2b_options['netban_ipv4'] = ($netban_ipv4 < 8) ? 8 : $netban_ipv4;
|
||||||
$f2b_options['netban_ipv6'] = ($netban_ipv6 < 8) ? 8 : $netban_ipv6;
|
$f2b_options['netban_ipv6'] = ($netban_ipv6 < 8) ? 8 : $netban_ipv6;
|
||||||
$f2b_options['netban_ipv4'] = ($netban_ipv4 > 32) ? 32 : $netban_ipv4;
|
$f2b_options['netban_ipv4'] = ($netban_ipv4 > 32) ? 32 : $netban_ipv4;
|
||||||
|
|
|
@ -821,20 +821,58 @@ function formatBytes($size, $precision = 2) {
|
||||||
}
|
}
|
||||||
return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
|
return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
|
||||||
}
|
}
|
||||||
function update_sogo_static_view() {
|
function update_sogo_static_view($mailbox = null) {
|
||||||
if (getenv('SKIP_SOGO') == "y") {
|
if (getenv('SKIP_SOGO') == "y") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $lang;
|
global $lang;
|
||||||
$stmt = $pdo->query("SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES
|
|
||||||
WHERE TABLE_NAME = 'sogo_view'");
|
$mailbox_exists = false;
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
if ($mailbox !== null) {
|
||||||
if ($num_results != 0) {
|
// Check if the mailbox exists
|
||||||
$stmt = $pdo->query("REPLACE INTO _sogo_static_view (`c_uid`, `domain`, `c_name`, `c_password`, `c_cn`, `mail`, `aliases`, `ad_aliases`, `ext_acl`, `kind`, `multiple_bookings`)
|
$stmt = $pdo->prepare("SELECT username FROM mailbox WHERE username = :mailbox AND active = '1'");
|
||||||
SELECT `c_uid`, `domain`, `c_name`, `c_password`, `c_cn`, `mail`, `aliases`, `ad_aliases`, `ext_acl`, `kind`, `multiple_bookings` from sogo_view");
|
$stmt->execute(array(':mailbox' => $mailbox));
|
||||||
$stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');");
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if ($row){
|
||||||
|
$mailbox_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$query = "REPLACE INTO _sogo_static_view (`c_uid`, `domain`, `c_name`, `c_password`, `c_cn`, `mail`, `aliases`, `ad_aliases`, `ext_acl`, `kind`, `multiple_bookings`)
|
||||||
|
SELECT
|
||||||
|
mailbox.username,
|
||||||
|
mailbox.domain,
|
||||||
|
mailbox.username,
|
||||||
|
IF(JSON_UNQUOTE(JSON_VALUE(attributes, '$.force_pw_update')) = '0',
|
||||||
|
IF(JSON_UNQUOTE(JSON_VALUE(attributes, '$.sogo_access')) = 1, password, '{SSHA256}A123A123A321A321A321B321B321B123B123B321B432F123E321123123321321'),
|
||||||
|
'{SSHA256}A123A123A321A321A321B321B321B123B123B321B432F123E321123123321321'),
|
||||||
|
mailbox.name,
|
||||||
|
mailbox.username,
|
||||||
|
IFNULL(GROUP_CONCAT(ga.aliases ORDER BY ga.aliases SEPARATOR ' '), ''),
|
||||||
|
IFNULL(gda.ad_alias, ''),
|
||||||
|
IFNULL(external_acl.send_as_acl, ''),
|
||||||
|
mailbox.kind,
|
||||||
|
mailbox.multiple_bookings
|
||||||
|
FROM
|
||||||
|
mailbox
|
||||||
|
LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username REGEXP CONCAT('(^|,)', mailbox.username, '($|,)')
|
||||||
|
LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username
|
||||||
|
LEFT OUTER JOIN grouped_sender_acl_external external_acl ON external_acl.username = mailbox.username
|
||||||
|
WHERE
|
||||||
|
mailbox.active = '1'";
|
||||||
|
|
||||||
|
if ($mailbox_exists) {
|
||||||
|
$query .= " AND mailbox.username = :mailbox";
|
||||||
|
$stmt = $pdo->prepare($query);
|
||||||
|
$stmt->execute(array(':mailbox' => $mailbox));
|
||||||
|
} else {
|
||||||
|
$query .= " GROUP BY mailbox.username";
|
||||||
|
$stmt = $pdo->query($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');");
|
||||||
|
|
||||||
flush_memcached();
|
flush_memcached();
|
||||||
}
|
}
|
||||||
function edit_user_account($_data) {
|
function edit_user_account($_data) {
|
||||||
|
|
|
@ -1281,11 +1281,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||||
), $_extra);
|
), $_extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_sogo_static_view($username);
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('mailbox_added', htmlspecialchars($username))
|
'msg' => array('mailbox_added', htmlspecialchars($username))
|
||||||
);
|
);
|
||||||
|
return true;
|
||||||
break;
|
break;
|
||||||
case 'mailbox_from_template':
|
case 'mailbox_from_template':
|
||||||
$stmt = $pdo->prepare("SELECT * FROM `templates`
|
$stmt = $pdo->prepare("SELECT * FROM `templates`
|
||||||
|
@ -3197,7 +3199,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('mailbox_modified', $username)
|
'msg' => array('mailbox_modified', $username)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
update_sogo_static_view($username);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
break;
|
break;
|
||||||
case 'mailbox_from_template':
|
case 'mailbox_from_template':
|
||||||
$stmt = $pdo->prepare("SELECT * FROM `templates`
|
$stmt = $pdo->prepare("SELECT * FROM `templates`
|
||||||
|
@ -5189,12 +5194,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_sogo_static_view($username);
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('mailbox_removed', htmlspecialchars($username))
|
'msg' => array('mailbox_removed', htmlspecialchars($username))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
break;
|
break;
|
||||||
case 'mailbox_templates':
|
case 'mailbox_templates':
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
@ -5400,7 +5408,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'mailbox', 'resource')) && getenv('SKIP_SOGO') != "y") {
|
if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'resource')) && getenv('SKIP_SOGO') != "y") {
|
||||||
update_sogo_static_view();
|
update_sogo_static_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ function init_db_schema() {
|
||||||
try {
|
try {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
|
|
||||||
$db_version = "14032023_1050";
|
$db_version = "14022023_1000";
|
||||||
|
|
||||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
@ -1111,7 +1111,7 @@ function init_db_schema() {
|
||||||
$stmt = $pdo->query("SHOW TABLES LIKE '" . $table . "'");
|
$stmt = $pdo->query("SHOW TABLES LIKE '" . $table . "'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
if ($num_results != 0) {
|
if ($num_results != 0) {
|
||||||
$stmt = $pdo->prepare("SELECT CONCAT('ALTER TABLE ', `table_schema`, '.', `table_name`, ' DROP FOREIGN KEY ', `constraint_name`, ';') AS `FKEY_DROP` FROM `information_schema`.`table_constraints`
|
$stmt = $pdo->prepare("SELECT CONCAT('ALTER TABLE `', `table_schema`, '`.', `table_name`, ' DROP FOREIGN KEY ', `constraint_name`, ';') AS `FKEY_DROP` FROM `information_schema`.`table_constraints`
|
||||||
WHERE `constraint_type` = 'FOREIGN KEY' AND `table_name` = :table;");
|
WHERE `constraint_type` = 'FOREIGN KEY' AND `table_name` = :table;");
|
||||||
$stmt->execute(array(':table' => $table));
|
$stmt->execute(array(':table' => $table));
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
|
@ -90,7 +90,7 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
|
||||||
unset($_SESSION['index_query_string']);
|
unset($_SESSION['index_query_string']);
|
||||||
if (in_array('mobileconfig', $http_parameters)) {
|
if (in_array('mobileconfig', $http_parameters)) {
|
||||||
if (in_array('only_email', $http_parameters)) {
|
if (in_array('only_email', $http_parameters)) {
|
||||||
header("Location: /mobileconfig.php?email_only");
|
header("Location: /mobileconfig.php?only_email");
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
header("Location: /mobileconfig.php");
|
header("Location: /mobileconfig.php");
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
const LOCALE = undefined;
|
||||||
|
const DATETIME_FORMAT = {
|
||||||
|
year: "numeric",
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit"
|
||||||
|
};
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// mailcow alert box generator
|
// mailcow alert box generator
|
||||||
window.mailcow_alert_box = function(message, type) {
|
window.mailcow_alert_box = function(message, type) {
|
||||||
|
|
|
@ -117,8 +117,8 @@ jQuery(function($){
|
||||||
data: 'tfa_active',
|
data: 'tfa_active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
|
||||||
else return '<i class="bi bi-x-lg"></i>';
|
else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -126,8 +126,8 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
|
||||||
else return '<i class="bi bi-x-lg"></i>';
|
else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -260,8 +260,8 @@ jQuery(function($){
|
||||||
data: 'tfa_active',
|
data: 'tfa_active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
|
||||||
else return '<i class="bi bi-x-lg"></i>';
|
else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -269,8 +269,8 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
|
||||||
else return '<i class="bi bi-x-lg"></i>';
|
else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -337,7 +337,7 @@ jQuery(function($){
|
||||||
data: 'keep_spam',
|
data: 'keep_spam',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function(data, type){
|
render: function(data, type){
|
||||||
return 'yes'==data?'<i class="bi bi-x-lg"></i>':'no'==data&&'<i class="bi bi-check-lg"></i>';
|
return 'yes'==data?'<i class="bi bi-x-lg"><span class="sorting-value">yes</span></i>':'no'==data&&'<i class="bi bi-check-lg"><span class="sorting-value">no</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -414,8 +414,8 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
|
||||||
else return '<i class="bi bi-x-lg"></i>';
|
else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -492,8 +492,8 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
|
||||||
else return '<i class="bi bi-x-lg"></i>';
|
else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,13 +1,3 @@
|
||||||
const LOCALE = undefined;
|
|
||||||
const DATETIME_FORMAT = {
|
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit"
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// Parse seconds ago to date
|
// Parse seconds ago to date
|
||||||
// Get "now" timestamp
|
// Get "now" timestamp
|
||||||
|
@ -43,7 +33,7 @@ $(document).ready(function() {
|
||||||
if (mailcow_info.branch === "master"){
|
if (mailcow_info.branch === "master"){
|
||||||
check_update(mailcow_info.version_tag, mailcow_info.project_url);
|
check_update(mailcow_info.version_tag, mailcow_info.project_url);
|
||||||
}
|
}
|
||||||
$("#maiclow_version").click(function(){
|
$("#mailcow_version").click(function(){
|
||||||
if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin" || mailcow_info.branch !== "master")
|
if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin" || mailcow_info.branch !== "master")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -889,13 +879,10 @@ jQuery(function($){
|
||||||
url: '/api/v1/get/rspamd/actions',
|
url: '/api/v1/get/rspamd/actions',
|
||||||
async: true,
|
async: true,
|
||||||
success: function(data){
|
success: function(data){
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
var total = 0;
|
var total = 0;
|
||||||
$(data).map(function(){total += this[1];});
|
$(data).map(function(){total += this[1];});
|
||||||
var labels = $.makeArray($(data).map(function(){return this[0] + ' ' + Math.round(this[1]/total * 100) + '%';}));
|
var labels = $.makeArray($(data).map(function(){return this[0] + ' ' + Math.round(this[1]/total * 100) + '%';}));
|
||||||
var values = $.makeArray($(data).map(function(){return this[1];}));
|
var values = $.makeArray($(data).map(function(){return this[1];}));
|
||||||
console.log(values);
|
|
||||||
|
|
||||||
var graphdata = {
|
var graphdata = {
|
||||||
labels: labels,
|
labels: labels,
|
||||||
|
@ -1011,12 +998,15 @@ jQuery(function($){
|
||||||
title: 'Score',
|
title: 'Score',
|
||||||
data: 'score',
|
data: 'score',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
|
class: 'text-nowrap',
|
||||||
createdCell: function(td, cellData) {
|
createdCell: function(td, cellData) {
|
||||||
$(td).attr({
|
$(td).attr({
|
||||||
"data-order": cellData.sortBy,
|
"data-order": cellData.sortBy,
|
||||||
"data-sort": cellData.sortBy
|
"data-sort": cellData.sortBy
|
||||||
});
|
});
|
||||||
$(td).html(cellData.value);
|
},
|
||||||
|
render: function (data) {
|
||||||
|
return data.value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1039,7 +1029,9 @@ jQuery(function($){
|
||||||
"data-order": cellData.sortBy,
|
"data-order": cellData.sortBy,
|
||||||
"data-sort": cellData.sortBy
|
"data-sort": cellData.sortBy
|
||||||
});
|
});
|
||||||
$(td).html(cellData.value);
|
},
|
||||||
|
render: function (data) {
|
||||||
|
return data.value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1363,6 +1355,12 @@ function update_stats(timeout=5){
|
||||||
$("#host_cpu_usage").text(parseInt(data.cpu.usage).toString() + "%");
|
$("#host_cpu_usage").text(parseInt(data.cpu.usage).toString() + "%");
|
||||||
$("#host_memory_total").text((data.memory.total / (1024 ** 3)).toFixed(2).toString() + "GB");
|
$("#host_memory_total").text((data.memory.total / (1024 ** 3)).toFixed(2).toString() + "GB");
|
||||||
$("#host_memory_usage").text(parseInt(data.memory.usage).toString() + "%");
|
$("#host_memory_usage").text(parseInt(data.memory.usage).toString() + "%");
|
||||||
|
if (data.architecture == "aarch64"){
|
||||||
|
$("#host_architecture").html('<span data-bs-toggle="tooltip" data-bs-placement="top" title="' + lang_debug.wip +'">' + data.architecture + ' ⚠️</span>');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#host_architecture").html(data.architecture);
|
||||||
|
}
|
||||||
|
|
||||||
// update cpu and mem chart
|
// update cpu and mem chart
|
||||||
var cpu_chart = Chart.getChart("host_cpu_chart");
|
var cpu_chart = Chart.getChart("host_cpu_chart");
|
||||||
|
|
|
@ -606,7 +606,7 @@ jQuery(function($){
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
responsivePriority: 6,
|
responsivePriority: 6,
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':(0==data?'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>':2==data&&'—');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -753,7 +753,7 @@ jQuery(function($){
|
||||||
data: 'attributes.gal',
|
data: 'attributes.gal',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -761,7 +761,7 @@ jQuery(function($){
|
||||||
data: 'attributes.backupmx',
|
data: 'attributes.backupmx',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -769,7 +769,7 @@ jQuery(function($){
|
||||||
data: 'attributes.relay_all_recipients',
|
data: 'attributes.relay_all_recipients',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -777,7 +777,7 @@ jQuery(function($){
|
||||||
data: 'attributes.relay_unknown_only',
|
data: 'attributes.relay_unknown_only',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -786,7 +786,7 @@ jQuery(function($){
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
responsivePriority: 4,
|
responsivePriority: 4,
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -925,9 +925,12 @@ jQuery(function($){
|
||||||
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
|
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
|
||||||
'</div>';
|
'</div>';
|
||||||
}
|
}
|
||||||
item.in_use = '<div class="progress">' +
|
item.in_use = {
|
||||||
|
sortBy: item.percent_in_use,
|
||||||
|
value: '<div class="progress">' +
|
||||||
'<div class="progress-bar-mailbox progress-bar progress-bar-' + item.percent_class + '" role="progressbar" aria-valuenow="' + item.percent_in_use + '" aria-valuemin="0" aria-valuemax="100" ' +
|
'<div class="progress-bar-mailbox progress-bar progress-bar-' + item.percent_class + '" role="progressbar" aria-valuenow="' + item.percent_in_use + '" aria-valuemin="0" aria-valuemax="100" ' +
|
||||||
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>';
|
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>'
|
||||||
|
};
|
||||||
item.username = escapeHtml(item.username);
|
item.username = escapeHtml(item.username);
|
||||||
|
|
||||||
if (Array.isArray(item.tags)){
|
if (Array.isArray(item.tags)){
|
||||||
|
@ -993,10 +996,11 @@ jQuery(function($){
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: lang.in_use,
|
title: lang.in_use,
|
||||||
data: 'in_use',
|
data: 'in_use.value',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
responsivePriority: 9,
|
responsivePriority: 9,
|
||||||
className: 'dt-data-w100'
|
className: 'dt-data-w100',
|
||||||
|
orderData: 24
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: lang.fname,
|
title: lang.fname,
|
||||||
|
@ -1097,7 +1101,7 @@ jQuery(function($){
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
responsivePriority: 4,
|
responsivePriority: 4,
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':(0==data?'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>':2==data&&'—');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1110,7 +1114,12 @@ jQuery(function($){
|
||||||
{
|
{
|
||||||
title: "",
|
title: "",
|
||||||
data: 'quota.sortBy',
|
data: 'quota.sortBy',
|
||||||
responsivePriority: 8,
|
defaultContent: '',
|
||||||
|
className: "d-none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "",
|
||||||
|
data: 'in_use.sortBy',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
className: "d-none"
|
className: "d-none"
|
||||||
},
|
},
|
||||||
|
@ -1163,13 +1172,13 @@ jQuery(function($){
|
||||||
|
|
||||||
item.attributes.quota = humanFileSize(item.attributes.quota);
|
item.attributes.quota = humanFileSize(item.attributes.quota);
|
||||||
|
|
||||||
item.attributes.tls_enforce_in = '<i class="text-' + (item.attributes.tls_enforce_in == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"></i>';
|
item.attributes.tls_enforce_in = '<i class="text-' + (item.attributes.tls_enforce_in == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"><span class="sorting-value">' + (item.attributes.tls_enforce_in == 1 ? '1' : '0') + '</span></i>';
|
||||||
item.attributes.tls_enforce_out = '<i class="text-' + (item.attributes.tls_enforce_out == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"></i>';
|
item.attributes.tls_enforce_out = '<i class="text-' + (item.attributes.tls_enforce_out == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"><span class="sorting-value">' + (item.attributes.tls_enforce_out == 1 ? '1' : '0') + '</span></i>';
|
||||||
item.attributes.pop3_access = '<i class="text-' + (item.attributes.pop3_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.pop3_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
|
item.attributes.pop3_access = '<i class="text-' + (item.attributes.pop3_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.pop3_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.pop3_access == 1 ? '1' : '0') + '</span></i>';
|
||||||
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') + '"></i>';
|
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') + '"></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') + '"></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') + '"></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>';
|
||||||
if (item.attributes.quarantine_notification === 'never') {
|
if (item.attributes.quarantine_notification === 'never') {
|
||||||
item.attributes.quarantine_notification = lang.never;
|
item.attributes.quarantine_notification = lang.never;
|
||||||
} else if (item.attributes.quarantine_notification === 'hourly') {
|
} else if (item.attributes.quarantine_notification === 'hourly') {
|
||||||
|
@ -1187,7 +1196,6 @@ jQuery(function($){
|
||||||
item.attributes.quarantine_category = lang.q_all;
|
item.attributes.quarantine_category = lang.q_all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (item.template.toLowerCase() == "default"){
|
if (item.template.toLowerCase() == "default"){
|
||||||
item.action = '<div class="btn-group">' +
|
item.action = '<div class="btn-group">' +
|
||||||
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
|
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
|
||||||
|
@ -1328,7 +1336,7 @@ jQuery(function($){
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
responsivePriority: 4,
|
responsivePriority: 4,
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':(0==data?'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>':2==data&&'—');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1439,7 +1447,7 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':(0==data?'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>':2==data&&'—');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1458,30 +1466,37 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
function draw_bcc_table() {
|
function draw_bcc_table() {
|
||||||
$.get("/api/v1/get/bcc-destination-options", function(data){
|
$.get("/api/v1/get/bcc-destination-options", function(data){
|
||||||
|
var optgroup = "";
|
||||||
// Domains
|
// Domains
|
||||||
var optgroup = "<optgroup label='" + lang.domains + "'>";
|
if (data.domains && data.domains.length > 0) {
|
||||||
$.each(data.domains, function(index, domain){
|
optgroup = "<optgroup label='" + lang.domains + "'>";
|
||||||
optgroup += "<option value='" + domain + "'>" + domain + "</option>";
|
$.each(data.domains, function(index, domain){
|
||||||
});
|
optgroup += "<option value='" + domain + "'>" + domain + "</option>";
|
||||||
optgroup += "</optgroup>";
|
|
||||||
$('#bcc-local-dest').append(optgroup);
|
|
||||||
// Alias domains
|
|
||||||
var optgroup = "<optgroup label='" + lang.domain_aliases + "'>";
|
|
||||||
$.each(data.alias_domains, function(index, alias_domain){
|
|
||||||
optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>";
|
|
||||||
});
|
|
||||||
optgroup += "</optgroup>"
|
|
||||||
$('#bcc-local-dest').append(optgroup);
|
|
||||||
// Mailboxes and aliases
|
|
||||||
$.each(data.mailboxes, function(mailbox, aliases){
|
|
||||||
var optgroup = "<optgroup label='" + mailbox + "'>";
|
|
||||||
$.each(aliases, function(index, alias){
|
|
||||||
optgroup += "<option value='" + alias + "'>" + alias + "</option>";
|
|
||||||
});
|
});
|
||||||
optgroup += "</optgroup>";
|
optgroup += "</optgroup>";
|
||||||
$('#bcc-local-dest').append(optgroup);
|
$('#bcc-local-dest').append(optgroup);
|
||||||
});
|
}
|
||||||
// Finish
|
// Alias domains
|
||||||
|
if (data.alias_domains && data.alias_domains.length > 0) {
|
||||||
|
optgroup = "<optgroup label='" + lang.domain_aliases + "'>";
|
||||||
|
$.each(data.alias_domains, function(index, alias_domain){
|
||||||
|
optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>";
|
||||||
|
});
|
||||||
|
optgroup += "</optgroup>"
|
||||||
|
$('#bcc-local-dest').append(optgroup);
|
||||||
|
}
|
||||||
|
// Mailboxes and aliases
|
||||||
|
if (data.mailboxes && Object.keys(data.mailboxes).length > 0) {
|
||||||
|
$.each(data.mailboxes, function(mailbox, aliases){
|
||||||
|
optgroup = "<optgroup label='" + mailbox + "'>";
|
||||||
|
$.each(aliases, function(index, alias){
|
||||||
|
optgroup += "<option value='" + alias + "'>" + alias + "</option>";
|
||||||
|
});
|
||||||
|
optgroup += "</optgroup>";
|
||||||
|
$('#bcc-local-dest').append(optgroup);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Recreate picker
|
||||||
$('#bcc-local-dest').selectpicker('refresh');
|
$('#bcc-local-dest').selectpicker('refresh');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1577,7 +1592,7 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':(0==data?'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>':2==data&&'—');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1674,7 +1689,7 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':0==data&&'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1781,7 +1796,7 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':0==data&&'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1916,7 +1931,7 @@ jQuery(function($){
|
||||||
data: 'sogo_visible',
|
data: 'sogo_visible',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function(data, type){
|
render: function(data, type){
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':0==data&&'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1935,7 +1950,7 @@ jQuery(function($){
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
responsivePriority: 6,
|
responsivePriority: 6,
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':0==data&&'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1951,6 +1966,10 @@ jQuery(function($){
|
||||||
table.on('responsive-resize', function (e, datatable, columns){
|
table.on('responsive-resize', function (e, datatable, columns){
|
||||||
hideTableExpandCollapseBtn('#tab-mbox-aliases', '#alias_table');
|
hideTableExpandCollapseBtn('#tab-mbox-aliases', '#alias_table');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
table.on( 'draw', function (){
|
||||||
|
$('#alias_table [data-bs-toggle="tooltip"]').tooltip();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function draw_aliasdomain_table() {
|
function draw_aliasdomain_table() {
|
||||||
// just recalc width if instance already exists
|
// just recalc width if instance already exists
|
||||||
|
@ -2030,7 +2049,7 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':0==data&&'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2166,7 +2185,7 @@ jQuery(function($){
|
||||||
data: 'active',
|
data: 'active',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
render: function (data, type) {
|
||||||
return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
|
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':0==data&&'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2322,16 +2341,19 @@ jQuery(function($){
|
||||||
// detect element visibility changes
|
// detect element visibility changes
|
||||||
function onVisible(element, callback) {
|
function onVisible(element, callback) {
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
element_object = document.querySelector(element);
|
let element_object = document.querySelector(element);
|
||||||
if (element_object === null) return;
|
if (element_object === null) return;
|
||||||
|
|
||||||
new IntersectionObserver((entries, observer) => {
|
let observer = new IntersectionObserver((entries, observer) => {
|
||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
if(entry.intersectionRatio > 0) {
|
if(entry.intersectionRatio > 0) {
|
||||||
callback(element_object);
|
callback(element_object);
|
||||||
|
observer.unobserve(element_object);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).observe(element_object);
|
})
|
||||||
|
|
||||||
|
observer.observe(element_object);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,20 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createSortableDate(td, cellData, date_string = false) {
|
||||||
|
if (date_string)
|
||||||
|
var date = new Date(cellData);
|
||||||
|
else
|
||||||
|
var date = new Date(cellData ? cellData * 1000 : 0);
|
||||||
|
|
||||||
|
var timestamp = date.getTime();
|
||||||
|
$(td).attr({
|
||||||
|
"data-order": timestamp,
|
||||||
|
"data-sort": timestamp
|
||||||
|
});
|
||||||
|
$(td).html(date.toLocaleDateString(LOCALE, DATETIME_FORMAT));
|
||||||
|
}
|
||||||
function draw_tla_table() {
|
function draw_tla_table() {
|
||||||
// just recalc width if instance already exists
|
// just recalc width if instance already exists
|
||||||
if ($.fn.DataTable.isDataTable('#tla_table') ) {
|
if ($.fn.DataTable.isDataTable('#tla_table') ) {
|
||||||
|
@ -156,6 +170,7 @@ jQuery(function($){
|
||||||
"tr" +
|
"tr" +
|
||||||
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
|
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
|
||||||
language: lang_datatables,
|
language: lang_datatables,
|
||||||
|
order: [[4, 'desc']],
|
||||||
ajax: {
|
ajax: {
|
||||||
type: "GET",
|
type: "GET",
|
||||||
url: "/api/v1/get/time_limited_aliases",
|
url: "/api/v1/get/time_limited_aliases",
|
||||||
|
@ -203,18 +218,16 @@ jQuery(function($){
|
||||||
title: lang.alias_valid_until,
|
title: lang.alias_valid_until,
|
||||||
data: 'validity',
|
data: 'validity',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
createdCell: function(td, cellData) {
|
||||||
var date = new Date(data ? data * 1000 : 0);
|
createSortableDate(td, cellData)
|
||||||
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: lang.created_on,
|
title: lang.created_on,
|
||||||
data: 'created',
|
data: 'created',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
createdCell: function(td, cellData) {
|
||||||
var date = new Date(data.replace(/-/g, "/"));
|
createSortableDate(td, cellData, true)
|
||||||
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,7 +105,8 @@
|
||||||
"timeout2": "Časový limit pro připojení k lokálnímu serveru",
|
"timeout2": "Časový limit pro připojení k lokálnímu serveru",
|
||||||
"username": "Uživatelské jméno",
|
"username": "Uživatelské jméno",
|
||||||
"validate": "Ověřit",
|
"validate": "Ověřit",
|
||||||
"validation_success": "Úspěšně ověřeno"
|
"validation_success": "Úspěšně ověřeno",
|
||||||
|
"tags": "Štítky"
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"access": "Přístupy",
|
"access": "Přístupy",
|
||||||
|
@ -333,7 +334,11 @@
|
||||||
"username": "Uživatelské jméno",
|
"username": "Uživatelské jméno",
|
||||||
"validate_license_now": "Ověřit GUID na licenčním serveru",
|
"validate_license_now": "Ověřit GUID na licenčním serveru",
|
||||||
"verify": "Ověřit",
|
"verify": "Ověřit",
|
||||||
"yes": "✓"
|
"yes": "✓",
|
||||||
|
"f2b_ban_time_increment": "Délka banu je prodlužována s každým dalším banem",
|
||||||
|
"f2b_max_ban_time": "Maximální délka banu (s)",
|
||||||
|
"ip_check": "Kontrola IP",
|
||||||
|
"ip_check_disabled": "Kontrola IP je vypnuta. Můžete ji zapnout v <br> <strong>System > Nastavení > Options > Přizpůsobení</strong>"
|
||||||
},
|
},
|
||||||
"danger": {
|
"danger": {
|
||||||
"access_denied": "Přístup odepřen nebo jsou neplatná data ve formuláři",
|
"access_denied": "Přístup odepřen nebo jsou neplatná data ve formuláři",
|
||||||
|
@ -536,7 +541,7 @@
|
||||||
"inactive": "Neaktivní",
|
"inactive": "Neaktivní",
|
||||||
"kind": "Druh",
|
"kind": "Druh",
|
||||||
"last_modified": "Naposledy změněn",
|
"last_modified": "Naposledy změněn",
|
||||||
"lookup_mx": "Cíl je regulární výraz který se shoduje s MX záznamem (<code>.*google\\.com</code> směřuje veškerou poštu na MX které jsou cílem pro google.com přes tento skok)",
|
"lookup_mx": "Cíl je regulární výraz který se shoduje s MX záznamem (<code>.*\\.google\\.com</code> směřuje veškerou poštu na MX které jsou cílem pro google.com přes tento skok)",
|
||||||
"mailbox": "Úprava mailové schránky",
|
"mailbox": "Úprava mailové schránky",
|
||||||
"mailbox_quota_def": "Výchozí kvóta schránky",
|
"mailbox_quota_def": "Výchozí kvóta schránky",
|
||||||
"mailbox_relayhost_info": "Aplikované jen na uživatelskou schránku a přímé aliasy, přepisuje předávající server domény.",
|
"mailbox_relayhost_info": "Aplikované jen na uživatelskou schránku a přímé aliasy, přepisuje předávající server domény.",
|
||||||
|
@ -650,7 +655,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "Přihlášení zpožděno o %s sekund.",
|
"delayed": "Přihlášení zpožděno o %s sekund.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Přihlásit",
|
"login": "Přihlásit",
|
||||||
"mobileconfig_info": "Ke stažení profilového souboru se přihlaste jako uživatel schránky.",
|
"mobileconfig_info": "Ke stažení profilového souboru se přihlaste jako uživatel schránky.",
|
||||||
"other_logins": "Přihlášení klíčem",
|
"other_logins": "Přihlášení klíčem",
|
||||||
|
|
|
@ -4,15 +4,15 @@
|
||||||
"app_passwds": "Administrer app-adgangskoder",
|
"app_passwds": "Administrer app-adgangskoder",
|
||||||
"bcc_maps": "BCC kort",
|
"bcc_maps": "BCC kort",
|
||||||
"delimiter_action": "Afgrænsning handling",
|
"delimiter_action": "Afgrænsning handling",
|
||||||
"eas_reset": "Nulstil EAS endheder",
|
"eas_reset": "Nulstil EAS enheder",
|
||||||
"extend_sender_acl": "Tillad at udvide afsenderens ACL med eksterne adresser",
|
"extend_sender_acl": "Tillad at udvide afsenderens ACL med eksterne adresser",
|
||||||
"filters": "Filtre",
|
"filters": "Filtre",
|
||||||
"login_as": "Login som mailboks bruger",
|
"login_as": "Login som mailboks bruger",
|
||||||
"prohibited": "Forbudt af ACL",
|
"prohibited": "Nægtet af ACL",
|
||||||
"protocol_access": "Ændre protokol adgang",
|
"protocol_access": "Skift protokol adgang",
|
||||||
"pushover": "Pushover",
|
"pushover": "Pushover",
|
||||||
"quarantine": "Karantæneaktioner",
|
"quarantine": "Karantænehandlinger",
|
||||||
"quarantine_attachments": "Karantæne vedhæftede filer",
|
"quarantine_attachments": "Karantænevedhæftede filer",
|
||||||
"quarantine_notification": "Skift karantænemeddelelser",
|
"quarantine_notification": "Skift karantænemeddelelser",
|
||||||
"ratelimit": "Satsgrænse",
|
"ratelimit": "Satsgrænse",
|
||||||
"recipient_maps": "Modtagerkort",
|
"recipient_maps": "Modtagerkort",
|
||||||
|
@ -20,12 +20,15 @@
|
||||||
"sogo_access": "Tillad styring af SOGo-adgang",
|
"sogo_access": "Tillad styring af SOGo-adgang",
|
||||||
"sogo_profile_reset": "Nulstil SOGo-profil",
|
"sogo_profile_reset": "Nulstil SOGo-profil",
|
||||||
"spam_alias": "Midlertidige aliasser",
|
"spam_alias": "Midlertidige aliasser",
|
||||||
"spam_policy": "Sortliste / hvidliste",
|
"spam_policy": "Sortliste/hvidliste",
|
||||||
"spam_score": "Spam-score",
|
"spam_score": "Spam-score",
|
||||||
"syncjobs": "Synkroniserings job",
|
"syncjobs": "Synkroniserings job",
|
||||||
"tls_policy": "TLS politik",
|
"tls_policy": "TLS politik",
|
||||||
"unlimited_quota": "Ubegrænset plads for mailbokse",
|
"unlimited_quota": "Ubegrænset plads for mailbokse",
|
||||||
"domain_desc": "Skift domæne beskrivelse"
|
"domain_desc": "Skift domæne beskrivelse",
|
||||||
|
"domain_relayhost": "Skift relæ host for et domæne",
|
||||||
|
"mailbox_relayhost": "Skift relæ-host for en postkasse",
|
||||||
|
"quarantine_category": "Skift kategorien for karantænemeddelelse"
|
||||||
},
|
},
|
||||||
"add": {
|
"add": {
|
||||||
"activate_filter_warn": "Alle andre filtre deaktiveres, når aktiv er markeret.",
|
"activate_filter_warn": "Alle andre filtre deaktiveres, når aktiv er markeret.",
|
||||||
|
@ -59,7 +62,7 @@
|
||||||
"gal": "Global adresseliste",
|
"gal": "Global adresseliste",
|
||||||
"gal_info": "GAL indeholder alle objekter i et domæne og kan ikke redigeres af nogen bruger. Information om ledig / optaget i SOGo mangler, hvis deaktiveret! <b> Genstart SOGo for at anvende ændringer. </b>",
|
"gal_info": "GAL indeholder alle objekter i et domæne og kan ikke redigeres af nogen bruger. Information om ledig / optaget i SOGo mangler, hvis deaktiveret! <b> Genstart SOGo for at anvende ændringer. </b>",
|
||||||
"generate": "generere",
|
"generate": "generere",
|
||||||
"goto_ham": "Lær som <span class=\"text-success\"><b>ham</b></span>",
|
"goto_ham": "Lær som <span class=\"text-success\"><b>ønsket</b></span>",
|
||||||
"goto_null": "Kassér e-mail i stilhed",
|
"goto_null": "Kassér e-mail i stilhed",
|
||||||
"goto_spam": "Lær som <span class=\"text-danger\"><b>spam</b></span>",
|
"goto_spam": "Lær som <span class=\"text-danger\"><b>spam</b></span>",
|
||||||
"hostname": "Vært",
|
"hostname": "Vært",
|
||||||
|
@ -80,7 +83,7 @@
|
||||||
"private_comment": "Privat kommentar",
|
"private_comment": "Privat kommentar",
|
||||||
"public_comment": "Offentlig kommentar",
|
"public_comment": "Offentlig kommentar",
|
||||||
"quota_mb": "Kvota (Mb)",
|
"quota_mb": "Kvota (Mb)",
|
||||||
"relay_all": "Send alle modtagere videre",
|
"relay_all": "Besvar alle modtager",
|
||||||
"relay_all_info": "↪ Hvis du vælger <b> ikke </b> at videresende alle modtagere, skal du tilføje et (\"blind\") postkasse til hver enkelt modtager, der skal videresendes.",
|
"relay_all_info": "↪ Hvis du vælger <b> ikke </b> at videresende alle modtagere, skal du tilføje et (\"blind\") postkasse til hver enkelt modtager, der skal videresendes.",
|
||||||
"relay_domain": "Send dette domæne videre",
|
"relay_domain": "Send dette domæne videre",
|
||||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Du kan definere transportkort til en tilpasset destination for dette domæne. Hvis ikke indstillet, foretages der et MX-opslag.",
|
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Du kan definere transportkort til en tilpasset destination for dette domæne. Hvis ikke indstillet, foretages der et MX-opslag.",
|
||||||
|
@ -101,7 +104,10 @@
|
||||||
"timeout2": "Timeout for forbindelse til lokal vært",
|
"timeout2": "Timeout for forbindelse til lokal vært",
|
||||||
"username": "Brugernavn",
|
"username": "Brugernavn",
|
||||||
"validate": "Bekræft",
|
"validate": "Bekræft",
|
||||||
"validation_success": "Valideret med succes"
|
"validation_success": "Valideret med succes",
|
||||||
|
"bcc_dest_format": "BCC-destination skal være en enkelt gyldig e-mail-adresse.<br>Hvis du har brug for at sende en kopi til flere adresser, kan du oprette et alias og bruge det her.",
|
||||||
|
"app_passwd_protocols": "Tilladte protokoller for app adgangskode",
|
||||||
|
"tags": "Tag's"
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"access": "Adgang",
|
"access": "Adgang",
|
||||||
|
@ -308,7 +314,10 @@
|
||||||
"username": "Brugernavn",
|
"username": "Brugernavn",
|
||||||
"validate_license_now": "Valider GUID mod licensserver",
|
"validate_license_now": "Valider GUID mod licensserver",
|
||||||
"verify": "Verificere",
|
"verify": "Verificere",
|
||||||
"yes": "✓"
|
"yes": "✓",
|
||||||
|
"ip_check_opt_in": "Opt-In for brug af tredjepartstjeneste <strong>ipv4.mailcow.email</strong> og <strong>ipv6.mailcow.email</strong> til at finde eksterne IP-adresser.",
|
||||||
|
"queue_unban": "unban",
|
||||||
|
"admins": "Administratorer"
|
||||||
},
|
},
|
||||||
"danger": {
|
"danger": {
|
||||||
"access_denied": "Adgang nægtet eller ugyldig formular data",
|
"access_denied": "Adgang nægtet eller ugyldig formular data",
|
||||||
|
@ -425,7 +434,8 @@
|
||||||
"username_invalid": "Brugernavn %s kan ikke bruges",
|
"username_invalid": "Brugernavn %s kan ikke bruges",
|
||||||
"validity_missing": "Tildel venligst en gyldighedsperiode",
|
"validity_missing": "Tildel venligst en gyldighedsperiode",
|
||||||
"value_missing": "Angiv alle værdier",
|
"value_missing": "Angiv alle værdier",
|
||||||
"yotp_verification_failed": "Yubico OTP verifikationen mislykkedes: %s"
|
"yotp_verification_failed": "Yubico OTP verifikationen mislykkedes: %s",
|
||||||
|
"webauthn_publickey_failed": "Der er ikke gemt nogen offentlig nøgle for den valgte autentifikator"
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"chart_this_server": "Diagram (denne server)",
|
"chart_this_server": "Diagram (denne server)",
|
||||||
|
@ -442,7 +452,8 @@
|
||||||
"solr_status": "Solr-status",
|
"solr_status": "Solr-status",
|
||||||
"started_on": "Startede den",
|
"started_on": "Startede den",
|
||||||
"static_logs": "Statiske logfiler",
|
"static_logs": "Statiske logfiler",
|
||||||
"system_containers": "System og Beholdere"
|
"system_containers": "System og Beholdere",
|
||||||
|
"error_show_ip": "Kunne ikke finde de offentlige IP-adresser"
|
||||||
},
|
},
|
||||||
"diagnostics": {
|
"diagnostics": {
|
||||||
"cname_from_a": "Værdi afledt af A / AAAA-post. Dette understøttes, så længe posten peger på den korrekte ressource.",
|
"cname_from_a": "Værdi afledt af A / AAAA-post. Dette understøttes, så længe posten peger på den korrekte ressource.",
|
||||||
|
@ -553,7 +564,11 @@
|
||||||
"title": "Rediger objekt",
|
"title": "Rediger objekt",
|
||||||
"unchanged_if_empty": "Lad være tomt, hvis uændret",
|
"unchanged_if_empty": "Lad være tomt, hvis uændret",
|
||||||
"username": "Brugernavn",
|
"username": "Brugernavn",
|
||||||
"validate_save": "Valider og gem"
|
"validate_save": "Valider og gem",
|
||||||
|
"admin": "Rediger administrator",
|
||||||
|
"lookup_mx": "Destination er et regulært udtryk, der matcher MX-navnet (<code>.*google\\.dk</code> for at dirigere al e-mail, der er målrettet til en MX, der ender på google.dk, over dette hop)",
|
||||||
|
"mailbox_relayhost_info": "Anvendt på postkassen og kun direkte aliasser, og overskriver et domæne relæ-host.",
|
||||||
|
"quota_warning_bcc": "Kvoteadvarsel BCC"
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"cancel": "Afbestille",
|
"cancel": "Afbestille",
|
||||||
|
@ -571,7 +586,7 @@
|
||||||
"header": {
|
"header": {
|
||||||
"administration": "Konfiguration og detailer",
|
"administration": "Konfiguration og detailer",
|
||||||
"apps": "Apps",
|
"apps": "Apps",
|
||||||
"debug": "Systemoplysninger",
|
"debug": "Information",
|
||||||
"email": "E-Mail",
|
"email": "E-Mail",
|
||||||
"mailcow_config": "Konfiguration",
|
"mailcow_config": "Konfiguration",
|
||||||
"quarantine": "Karantæne",
|
"quarantine": "Karantæne",
|
||||||
|
@ -586,7 +601,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "Login blev forsinket med% s sekunder.",
|
"delayed": "Login blev forsinket med% s sekunder.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"mobileconfig_info": "Log ind som postkassebruger for at downloade den anmodede Apple-forbindelsesprofil.",
|
"mobileconfig_info": "Log ind som postkassebruger for at downloade den anmodede Apple-forbindelsesprofil.",
|
||||||
"other_logins": "Nøgle login",
|
"other_logins": "Nøgle login",
|
||||||
|
@ -739,7 +754,10 @@
|
||||||
"username": "Brugernavn",
|
"username": "Brugernavn",
|
||||||
"waiting": "Venter",
|
"waiting": "Venter",
|
||||||
"weekly": "Ugentlig",
|
"weekly": "Ugentlig",
|
||||||
"yes": "✓"
|
"yes": "✓",
|
||||||
|
"goto_ham": "Lær som <b>ønsket</b>",
|
||||||
|
"catch_all": "Fang-alt",
|
||||||
|
"open_logs": "Åben logfiler"
|
||||||
},
|
},
|
||||||
"oauth2": {
|
"oauth2": {
|
||||||
"access_denied": "Log ind som mailboks ejer for at give adgang via OAuth2.",
|
"access_denied": "Log ind som mailboks ejer for at give adgang via OAuth2.",
|
||||||
|
@ -1030,7 +1048,7 @@
|
||||||
"spamfilter_table_empty": "Intet data at vise",
|
"spamfilter_table_empty": "Intet data at vise",
|
||||||
"spamfilter_table_remove": "slet",
|
"spamfilter_table_remove": "slet",
|
||||||
"spamfilter_table_rule": "Regl",
|
"spamfilter_table_rule": "Regl",
|
||||||
"spamfilter_wl": "Hvisliste",
|
"spamfilter_wl": "Hvidliste",
|
||||||
"spamfilter_wl_desc": "Hvidlistede e-mail-adresser til <b>aldrig</b> at klassificeres som spam. Wildcards kan bruges. Et filter anvendes kun på direkte aliaser (aliaser med en enkelt målpostkasse) eksklusive catch-aliaser og selve en postkasse.",
|
"spamfilter_wl_desc": "Hvidlistede e-mail-adresser til <b>aldrig</b> at klassificeres som spam. Wildcards kan bruges. Et filter anvendes kun på direkte aliaser (aliaser med en enkelt målpostkasse) eksklusive catch-aliaser og selve en postkasse.",
|
||||||
"spamfilter_yellow": "Gul: denne besked kan være spam, vil blive tagget som spam og flyttes til din junk-mappe",
|
"spamfilter_yellow": "Gul: denne besked kan være spam, vil blive tagget som spam og flyttes til din junk-mappe",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
|
@ -1066,5 +1084,11 @@
|
||||||
"quota_exceeded_scope": "Domænekvote overskredet: Kun ubegrænsede postkasser kan oprettes i dette domæneomfang.",
|
"quota_exceeded_scope": "Domænekvote overskredet: Kun ubegrænsede postkasser kan oprettes i dette domæneomfang.",
|
||||||
"session_token": "Form nøgle ugyldig: Nøgle passer ikke",
|
"session_token": "Form nøgle ugyldig: Nøgle passer ikke",
|
||||||
"session_ua": "Form nøgle ugyldig: Bruger-Agent gyldighedskontrols fejl"
|
"session_ua": "Form nøgle ugyldig: Bruger-Agent gyldighedskontrols fejl"
|
||||||
|
},
|
||||||
|
"datatables": {
|
||||||
|
"lengthMenu": "Vis _MENU_ poster",
|
||||||
|
"paginate": {
|
||||||
|
"first": "Først"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,10 +176,12 @@
|
||||||
"empty": "Keine Einträge vorhanden",
|
"empty": "Keine Einträge vorhanden",
|
||||||
"excludes": "Diese Empfänger ausschließen",
|
"excludes": "Diese Empfänger ausschließen",
|
||||||
"f2b_ban_time": "Bannzeit in Sekunden",
|
"f2b_ban_time": "Bannzeit in Sekunden",
|
||||||
|
"f2b_ban_time_increment": "Bannzeit erhöht sich mit jedem Bann",
|
||||||
"f2b_blacklist": "Blacklist für Netzwerke und Hosts",
|
"f2b_blacklist": "Blacklist für Netzwerke und Hosts",
|
||||||
"f2b_filter": "Regex-Filter",
|
"f2b_filter": "Regex-Filter",
|
||||||
"f2b_list_info": "Ein Host oder Netzwerk auf der Blacklist wird immer eine Whitelist-Einheit überwiegen. <b>Die Aktualisierung der Liste dauert einige Sekunden.</b>",
|
"f2b_list_info": "Ein Host oder Netzwerk auf der Blacklist wird immer eine Whitelist-Einheit überwiegen. <b>Die Aktualisierung der Liste dauert einige Sekunden.</b>",
|
||||||
"f2b_max_attempts": "Max. Versuche",
|
"f2b_max_attempts": "Max. Versuche",
|
||||||
|
"f2b_max_ban_time": "Maximale Bannzeit in Sekunden",
|
||||||
"f2b_netban_ipv4": "Netzbereich für IPv4-Banns (8-32)",
|
"f2b_netban_ipv4": "Netzbereich für IPv4-Banns (8-32)",
|
||||||
"f2b_netban_ipv6": "Netzbereich für IPv6-Banns (8-128)",
|
"f2b_netban_ipv6": "Netzbereich für IPv6-Banns (8-128)",
|
||||||
"f2b_parameters": "Fail2ban-Parameter",
|
"f2b_parameters": "Fail2ban-Parameter",
|
||||||
|
@ -215,7 +217,7 @@
|
||||||
"loading": "Bitte warten...",
|
"loading": "Bitte warten...",
|
||||||
"login_time": "Zeit",
|
"login_time": "Zeit",
|
||||||
"logo_info": "Die hochgeladene Grafik wird für die Navigationsleiste auf eine Höhe von 40px skaliert. Für die Darstellung auf der Login-Maske beträgt die skalierte Breite maximal 250px. Eine frei skalierbare Grafik (etwa SVG) wird empfohlen.",
|
"logo_info": "Die hochgeladene Grafik wird für die Navigationsleiste auf eine Höhe von 40px skaliert. Für die Darstellung auf der Login-Maske beträgt die skalierte Breite maximal 250px. Eine frei skalierbare Grafik (etwa SVG) wird empfohlen.",
|
||||||
"lookup_mx": "Ziel mit MX vergleichen (Regex, etwa <code>.*google\\.com</code>, um alle Ziele mit MX *google.com zu routen)",
|
"lookup_mx": "Ziel mit MX vergleichen (Regex, etwa <code>.*\\.google\\.com</code>, um alle Ziele mit MX *google.com zu routen)",
|
||||||
"main_name": "\"mailcow UI\" Name",
|
"main_name": "\"mailcow UI\" Name",
|
||||||
"merged_vars_hint": "Ausgegraute Reihen wurden aus der Datei <code>vars.(local.)inc.php</code> gelesen und können hier nicht verändert werden.",
|
"merged_vars_hint": "Ausgegraute Reihen wurden aus der Datei <code>vars.(local.)inc.php</code> gelesen und können hier nicht verändert werden.",
|
||||||
"message": "Nachricht",
|
"message": "Nachricht",
|
||||||
|
@ -498,6 +500,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
|
"architecture": "Architektur",
|
||||||
"chart_this_server": "Chart (dieser Server)",
|
"chart_this_server": "Chart (dieser Server)",
|
||||||
"containers_info": "Container-Information",
|
"containers_info": "Container-Information",
|
||||||
"container_running": "Läuft",
|
"container_running": "Läuft",
|
||||||
|
@ -534,7 +537,8 @@
|
||||||
"update_available": "Es ist ein Update verfügbar",
|
"update_available": "Es ist ein Update verfügbar",
|
||||||
"no_update_available": "Das System ist auf aktuellem Stand",
|
"no_update_available": "Das System ist auf aktuellem Stand",
|
||||||
"update_failed": "Es konnte nicht nach einem Update gesucht werden",
|
"update_failed": "Es konnte nicht nach einem Update gesucht werden",
|
||||||
"username": "Benutzername"
|
"username": "Benutzername",
|
||||||
|
"wip": "Aktuell noch in Arbeit"
|
||||||
},
|
},
|
||||||
"diagnostics": {
|
"diagnostics": {
|
||||||
"cname_from_a": "Wert abgeleitet von A/AAAA-Eintrag. Wird unterstützt, sofern der Eintrag auf die korrekte Ressource zeigt.",
|
"cname_from_a": "Wert abgeleitet von A/AAAA-Eintrag. Wird unterstützt, sofern der Eintrag auf die korrekte Ressource zeigt.",
|
||||||
|
@ -593,7 +597,7 @@
|
||||||
"inactive": "Inaktiv",
|
"inactive": "Inaktiv",
|
||||||
"kind": "Art",
|
"kind": "Art",
|
||||||
"last_modified": "Zuletzt geändert",
|
"last_modified": "Zuletzt geändert",
|
||||||
"lookup_mx": "Ziel mit MX vergleichen (Regex, etwa <code>.*google\\.com</code>, um alle Ziele mit MX *google.com zu routen)",
|
"lookup_mx": "Ziel mit MX vergleichen (Regex, etwa <code>.*\\.google\\.com</code>, um alle Ziele mit MX *google.com zu routen)",
|
||||||
"mailbox": "Mailbox bearbeiten",
|
"mailbox": "Mailbox bearbeiten",
|
||||||
"mailbox_quota_def": "Standard-Quota einer Mailbox",
|
"mailbox_quota_def": "Standard-Quota einer Mailbox",
|
||||||
"mailbox_relayhost_info": "Wird auf eine Mailbox und direkte Alias-Adressen angewendet. Überschreibt die Einstellung einer Domain.",
|
"mailbox_relayhost_info": "Wird auf eine Mailbox und direkte Alias-Adressen angewendet. Überschreibt die Einstellung einer Domain.",
|
||||||
|
@ -712,7 +716,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "Login wurde zur Sicherheit um %s Sekunde/n verzögert.",
|
"delayed": "Login wurde zur Sicherheit um %s Sekunde/n verzögert.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Anmelden",
|
"login": "Anmelden",
|
||||||
"mobileconfig_info": "Bitte als Mailbox-Benutzer einloggen, um das Verbindungsprofil herunterzuladen.",
|
"mobileconfig_info": "Bitte als Mailbox-Benutzer einloggen, um das Verbindungsprofil herunterzuladen.",
|
||||||
"other_logins": "Key Login",
|
"other_logins": "Key Login",
|
||||||
|
|
|
@ -178,10 +178,12 @@
|
||||||
"empty": "No results",
|
"empty": "No results",
|
||||||
"excludes": "Excludes these recipients",
|
"excludes": "Excludes these recipients",
|
||||||
"f2b_ban_time": "Ban time (s)",
|
"f2b_ban_time": "Ban time (s)",
|
||||||
|
"f2b_ban_time_increment": "Ban time is incremented with each ban",
|
||||||
"f2b_blacklist": "Blacklisted networks/hosts",
|
"f2b_blacklist": "Blacklisted networks/hosts",
|
||||||
"f2b_filter": "Regex filters",
|
"f2b_filter": "Regex filters",
|
||||||
"f2b_list_info": "A blacklisted host or network will always outweigh a whitelist entity. <b>List updates will take a few seconds to be applied.</b>",
|
"f2b_list_info": "A blacklisted host or network will always outweigh a whitelist entity. <b>List updates will take a few seconds to be applied.</b>",
|
||||||
"f2b_max_attempts": "Max. attempts",
|
"f2b_max_attempts": "Max. attempts",
|
||||||
|
"f2b_max_ban_time": "Max. ban time (s)",
|
||||||
"f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)",
|
"f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)",
|
||||||
"f2b_netban_ipv6": "IPv6 subnet size to apply ban on (8-128)",
|
"f2b_netban_ipv6": "IPv6 subnet size to apply ban on (8-128)",
|
||||||
"f2b_parameters": "Fail2ban parameters",
|
"f2b_parameters": "Fail2ban parameters",
|
||||||
|
@ -238,7 +240,7 @@
|
||||||
"loading": "Please wait...",
|
"loading": "Please wait...",
|
||||||
"login_time": "Login time",
|
"login_time": "Login time",
|
||||||
"logo_info": "Your image will be scaled to a height of 40px for the top navigation bar and a max. width of 250px for the start page. A scalable graphic is highly recommended.",
|
"logo_info": "Your image will be scaled to a height of 40px for the top navigation bar and a max. width of 250px for the start page. A scalable graphic is highly recommended.",
|
||||||
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*\\.google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
||||||
"main_name": "\"mailcow UI\" name",
|
"main_name": "\"mailcow UI\" name",
|
||||||
"merged_vars_hint": "Greyed out rows were merged from <code>vars.(local.)inc.php</code> and cannot be modified.",
|
"merged_vars_hint": "Greyed out rows were merged from <code>vars.(local.)inc.php</code> and cannot be modified.",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
|
@ -522,6 +524,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
|
"architecture": "Architecture",
|
||||||
"chart_this_server": "Chart (this server)",
|
"chart_this_server": "Chart (this server)",
|
||||||
"containers_info": "Container information",
|
"containers_info": "Container information",
|
||||||
"container_running": "Running",
|
"container_running": "Running",
|
||||||
|
@ -558,7 +561,8 @@
|
||||||
"update_available": "There is an update available",
|
"update_available": "There is an update available",
|
||||||
"no_update_available": "The System is on the latest version",
|
"no_update_available": "The System is on the latest version",
|
||||||
"update_failed": "Could not check for an Update",
|
"update_failed": "Could not check for an Update",
|
||||||
"username": "Username"
|
"username": "Username",
|
||||||
|
"wip": "Currently Work in Progress"
|
||||||
},
|
},
|
||||||
"diagnostics": {
|
"diagnostics": {
|
||||||
"cname_from_a": "Value derived from A/AAAA record. This is supported as long as the record points to the correct resource.",
|
"cname_from_a": "Value derived from A/AAAA record. This is supported as long as the record points to the correct resource.",
|
||||||
|
@ -617,7 +621,7 @@
|
||||||
"inactive": "Inactive",
|
"inactive": "Inactive",
|
||||||
"kind": "Kind",
|
"kind": "Kind",
|
||||||
"last_modified": "Last modified",
|
"last_modified": "Last modified",
|
||||||
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*\\.google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
||||||
"mailbox": "Edit mailbox",
|
"mailbox": "Edit mailbox",
|
||||||
"mailbox_quota_def": "Default mailbox quota",
|
"mailbox_quota_def": "Default mailbox quota",
|
||||||
"mailbox_relayhost_info": "Applied to the mailbox and direct aliases only, does override a domain relayhost.",
|
"mailbox_relayhost_info": "Applied to the mailbox and direct aliases only, does override a domain relayhost.",
|
||||||
|
@ -736,7 +740,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "Login was delayed by %s seconds.",
|
"delayed": "Login was delayed by %s seconds.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"mobileconfig_info": "Please login as mailbox user to download the requested Apple connection profile.",
|
"mobileconfig_info": "Please login as mailbox user to download the requested Apple connection profile.",
|
||||||
"other_logins": "Key login",
|
"other_logins": "Key login",
|
||||||
|
|
|
@ -141,9 +141,11 @@
|
||||||
"empty": "Sin resultados",
|
"empty": "Sin resultados",
|
||||||
"excludes": "Excluye a estos destinatarios",
|
"excludes": "Excluye a estos destinatarios",
|
||||||
"f2b_ban_time": "Tiempo de restricción (s)",
|
"f2b_ban_time": "Tiempo de restricción (s)",
|
||||||
|
"f2b_ban_time_increment": "Tiempo de restricción se incrementa con cada restricción",
|
||||||
"f2b_blacklist": "Redes y hosts en lista negra",
|
"f2b_blacklist": "Redes y hosts en lista negra",
|
||||||
"f2b_list_info": "Un host o red en lista negra siempre superará a una entidad de la lista blanca. <b>Las actualizaciones de la lista tardarán unos segundos en aplicarse.</b>",
|
"f2b_list_info": "Un host o red en lista negra siempre superará a una entidad de la lista blanca. <b>Las actualizaciones de la lista tardarán unos segundos en aplicarse.</b>",
|
||||||
"f2b_max_attempts": "Max num. de intentos",
|
"f2b_max_attempts": "Max num. de intentos",
|
||||||
|
"f2b_max_ban_time": "Max tiempo de restricción (s)",
|
||||||
"f2b_netban_ipv4": "Tamaño de subred IPv4 para aplicar la restricción (8-32)",
|
"f2b_netban_ipv4": "Tamaño de subred IPv4 para aplicar la restricción (8-32)",
|
||||||
"f2b_netban_ipv6": "Tamaño de subred IPv6 para aplicar la restricción (8-128)",
|
"f2b_netban_ipv6": "Tamaño de subred IPv6 para aplicar la restricción (8-128)",
|
||||||
"f2b_parameters": "Parametros Fail2ban",
|
"f2b_parameters": "Parametros Fail2ban",
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
"spam_policy": "Liste Noire/Liste Blanche",
|
"spam_policy": "Liste Noire/Liste Blanche",
|
||||||
"spam_score": "Score SPAM",
|
"spam_score": "Score SPAM",
|
||||||
"syncjobs": "Tâches de synchronisation",
|
"syncjobs": "Tâches de synchronisation",
|
||||||
"tls_policy": "Police TLS",
|
"tls_policy": "Politique TLS",
|
||||||
"unlimited_quota": "Quota illimité pour les boites de courriel",
|
"unlimited_quota": "Quota illimité pour les boites de courriel",
|
||||||
"domain_desc": "Modifier la description du domaine",
|
"domain_desc": "Modifier la description du domaine",
|
||||||
"domain_relayhost": "Changer le relais pour un domaine",
|
"domain_relayhost": "Changer le relais pour un domaine",
|
||||||
|
@ -106,7 +106,8 @@
|
||||||
"validate": "Valider",
|
"validate": "Valider",
|
||||||
"validation_success": "Validation réussie",
|
"validation_success": "Validation réussie",
|
||||||
"bcc_dest_format": "La destination Cci doit être une seule adresse e-mail valide.<br>Si vous avez besoin d'envoyer une copie à plusieurs adresses, créez un alias et utilisez-le ici.",
|
"bcc_dest_format": "La destination Cci doit être une seule adresse e-mail valide.<br>Si vous avez besoin d'envoyer une copie à plusieurs adresses, créez un alias et utilisez-le ici.",
|
||||||
"tags": "Etiquettes"
|
"tags": "Etiquettes",
|
||||||
|
"app_passwd_protocols": "Protocoles autorisés pour le mot de passe de l'application"
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"access": "Accès",
|
"access": "Accès",
|
||||||
|
@ -171,11 +172,13 @@
|
||||||
"edit": "Editer",
|
"edit": "Editer",
|
||||||
"empty": "Aucun résultat",
|
"empty": "Aucun résultat",
|
||||||
"excludes": "Exclure ces destinataires",
|
"excludes": "Exclure ces destinataires",
|
||||||
"f2b_ban_time": "Durée du bannissement(s)",
|
"f2b_ban_time": "Durée du bannissement (s)",
|
||||||
|
"f2b_ban_time_increment": "Durée du bannissement est augmentée à chaque bannissement",
|
||||||
"f2b_blacklist": "Réseaux/Domaines sur Liste Noire",
|
"f2b_blacklist": "Réseaux/Domaines sur Liste Noire",
|
||||||
"f2b_filter": "Filtre(s) Regex",
|
"f2b_filter": "Filtre(s) Regex",
|
||||||
"f2b_list_info": "Un hôte ou un réseau sur liste noire l'emportera toujours sur une entité de liste blanche. <b>L'application des mises à jour de liste prendra quelques secondes.</b>",
|
"f2b_list_info": "Un hôte ou un réseau sur liste noire l'emportera toujours sur une entité de liste blanche. <b>L'application des mises à jour de liste prendra quelques secondes.</b>",
|
||||||
"f2b_max_attempts": "Nb max. de tentatives",
|
"f2b_max_attempts": "Nb max. de tentatives",
|
||||||
|
"f2b_max_ban_time": "Max. durée du bannissement (s)",
|
||||||
"f2b_netban_ipv4": "Taille du sous-réseau IPv4 pour l'application du bannissement (8-32)",
|
"f2b_netban_ipv4": "Taille du sous-réseau IPv4 pour l'application du bannissement (8-32)",
|
||||||
"f2b_netban_ipv6": "Taille du sous-réseau IPv6 pour l'application du bannissement (8-128)",
|
"f2b_netban_ipv6": "Taille du sous-réseau IPv6 pour l'application du bannissement (8-128)",
|
||||||
"f2b_parameters": "Paramètres Fail2ban",
|
"f2b_parameters": "Paramètres Fail2ban",
|
||||||
|
@ -321,7 +324,9 @@
|
||||||
"admins": "Administrateurs",
|
"admins": "Administrateurs",
|
||||||
"api_read_only": "Accès lecture-seule",
|
"api_read_only": "Accès lecture-seule",
|
||||||
"password_policy_lowerupper": "Doit contenir des caractères minuscules et majuscules",
|
"password_policy_lowerupper": "Doit contenir des caractères minuscules et majuscules",
|
||||||
"password_policy_numbers": "Doit contenir au moins un chiffre"
|
"password_policy_numbers": "Doit contenir au moins un chiffre",
|
||||||
|
"ip_check": "Vérification IP",
|
||||||
|
"ip_check_disabled": "La vérification IP est désactivée. Vous pouvez l'activer sous<br> <strong>Système > Configuration > Options > Personnaliser</strong>"
|
||||||
},
|
},
|
||||||
"danger": {
|
"danger": {
|
||||||
"access_denied": "Accès refusé ou données de formulaire non valides",
|
"access_denied": "Accès refusé ou données de formulaire non valides",
|
||||||
|
@ -440,7 +445,12 @@
|
||||||
"username_invalid": "Le nom d'utilisateur %s ne peut pas être utilisé",
|
"username_invalid": "Le nom d'utilisateur %s ne peut pas être utilisé",
|
||||||
"validity_missing": "Veuillez attribuer une période de validité",
|
"validity_missing": "Veuillez attribuer une période de validité",
|
||||||
"value_missing": "Veuillez fournir toutes les valeurs",
|
"value_missing": "Veuillez fournir toutes les valeurs",
|
||||||
"yotp_verification_failed": "La vérification Yubico OTP a échoué : %s"
|
"yotp_verification_failed": "La vérification Yubico OTP a échoué : %s",
|
||||||
|
"webauthn_authenticator_failed": "L'authentificateur selectionné est introuvable",
|
||||||
|
"demo_mode_enabled": "Le mode de démonstration est activé",
|
||||||
|
"template_exists": "La template %s existe déja",
|
||||||
|
"template_id_invalid": "Le numéro de template %s est invalide",
|
||||||
|
"template_name_invalid": "Le nom de la template est invalide"
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"chart_this_server": "Graphique (ce serveur)",
|
"chart_this_server": "Graphique (ce serveur)",
|
||||||
|
@ -578,7 +588,7 @@
|
||||||
"unchanged_if_empty": "Si non modifié, laisser en blanc",
|
"unchanged_if_empty": "Si non modifié, laisser en blanc",
|
||||||
"username": "Nom d'utilisateur",
|
"username": "Nom d'utilisateur",
|
||||||
"validate_save": "Valider et sauver",
|
"validate_save": "Valider et sauver",
|
||||||
"lookup_mx": "La destination est une expression régulière qui doit correspondre avec le nom du MX (<code>.*google\\.com</code> pour acheminer tout le courrier destiné à un MX se terminant par google.com via ce saut).",
|
"lookup_mx": "La destination est une expression régulière qui doit correspondre avec le nom du MX (<code>.*\\.google\\.com</code> pour acheminer tout le courrier destiné à un MX se terminant par google.com via ce saut)",
|
||||||
"mailbox_relayhost_info": "S'applique uniquement à la boîte aux lettres et aux alias directs, remplace le relayhost du domaine."
|
"mailbox_relayhost_info": "S'applique uniquement à la boîte aux lettres et aux alias directs, remplace le relayhost du domaine."
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
|
@ -612,7 +622,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "La connexion a été retardée de %s secondes.",
|
"delayed": "La connexion a été retardée de %s secondes.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Connexion",
|
"login": "Connexion",
|
||||||
"mobileconfig_info": "Veuillez vous connecter en tant qu’utilisateur de la boîte pour télécharger le profil de connexion Apple demandé.",
|
"mobileconfig_info": "Veuillez vous connecter en tant qu’utilisateur de la boîte pour télécharger le profil de connexion Apple demandé.",
|
||||||
"other_logins": "Clé d'authentification",
|
"other_logins": "Clé d'authentification",
|
||||||
|
@ -1081,9 +1091,12 @@
|
||||||
"username": "Nom d'utilisateur",
|
"username": "Nom d'utilisateur",
|
||||||
"verify": "Vérification",
|
"verify": "Vérification",
|
||||||
"waiting": "En attente",
|
"waiting": "En attente",
|
||||||
"week": "Semaine",
|
"week": "semaine",
|
||||||
"weekly": "Hebdomadaire",
|
"weekly": "Hebdomadaire",
|
||||||
"weeks": "semaines"
|
"weeks": "semaines",
|
||||||
|
"months": "mois",
|
||||||
|
"year": "année",
|
||||||
|
"years": "années"
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
"cannot_delete_self": "Impossible de supprimer l’utilisateur connecté",
|
"cannot_delete_self": "Impossible de supprimer l’utilisateur connecté",
|
||||||
|
|
|
@ -175,10 +175,12 @@
|
||||||
"empty": "Nessun risultato",
|
"empty": "Nessun risultato",
|
||||||
"excludes": "Esclude questi destinatari",
|
"excludes": "Esclude questi destinatari",
|
||||||
"f2b_ban_time": "Tempo di blocco (s)",
|
"f2b_ban_time": "Tempo di blocco (s)",
|
||||||
|
"f2b_ban_time_increment": "Tempo di blocco aumenta ad ogni blocco",
|
||||||
"f2b_blacklist": "Host/reti in blacklist",
|
"f2b_blacklist": "Host/reti in blacklist",
|
||||||
"f2b_filter": "Filtri Regex",
|
"f2b_filter": "Filtri Regex",
|
||||||
"f2b_list_info": "Un host oppure una rete in blacklist, avrà sempre un peso maggiore rispetto ad una in whitelist. <b>L'aggiornamento della lista richiede alcuni secondi per la sua entrata in azione.</b>",
|
"f2b_list_info": "Un host oppure una rete in blacklist, avrà sempre un peso maggiore rispetto ad una in whitelist. <b>L'aggiornamento della lista richiede alcuni secondi per la sua entrata in azione.</b>",
|
||||||
"f2b_max_attempts": "Tentativi massimi",
|
"f2b_max_attempts": "Tentativi massimi",
|
||||||
|
"f2b_max_ban_time": "Tempo massimo di blocco (s)",
|
||||||
"f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)",
|
"f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)",
|
||||||
"f2b_netban_ipv6": "IPv6 subnet size to apply ban on (8-128)",
|
"f2b_netban_ipv6": "IPv6 subnet size to apply ban on (8-128)",
|
||||||
"f2b_parameters": "Parametri Fail2ban",
|
"f2b_parameters": "Parametri Fail2ban",
|
||||||
|
@ -211,7 +213,7 @@
|
||||||
"loading": "Caricamento in corso...",
|
"loading": "Caricamento in corso...",
|
||||||
"login_time": "Ora di accesso",
|
"login_time": "Ora di accesso",
|
||||||
"logo_info": "La tua immagine verrà ridimensionata a 40px di altezza, quando verrà usata nella barra di navigazione in alto, ed ad una larghezza massima di 250px nella schermata iniziale. È altamente consigliato l'utilizzo di un'immagine modulabile.",
|
"logo_info": "La tua immagine verrà ridimensionata a 40px di altezza, quando verrà usata nella barra di navigazione in alto, ed ad una larghezza massima di 250px nella schermata iniziale. È altamente consigliato l'utilizzo di un'immagine modulabile.",
|
||||||
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*\\.google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
||||||
"main_name": "Nome \"mailcow UI\"",
|
"main_name": "Nome \"mailcow UI\"",
|
||||||
"merged_vars_hint": "Greyed out rows were merged from <code>vars.(local.)inc.php</code> and cannot be modified.",
|
"merged_vars_hint": "Greyed out rows were merged from <code>vars.(local.)inc.php</code> and cannot be modified.",
|
||||||
"message": "Messaggio",
|
"message": "Messaggio",
|
||||||
|
@ -552,7 +554,7 @@
|
||||||
"hostname": "Hostname",
|
"hostname": "Hostname",
|
||||||
"inactive": "Inattivo",
|
"inactive": "Inattivo",
|
||||||
"kind": "Genere",
|
"kind": "Genere",
|
||||||
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*\\.google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
||||||
"mailbox": "Modifica casella di posta",
|
"mailbox": "Modifica casella di posta",
|
||||||
"mailbox_quota_def": "Default mailbox quota",
|
"mailbox_quota_def": "Default mailbox quota",
|
||||||
"mailbox_relayhost_info": "Applied to the mailbox and direct aliases only, does override a domain relayhost.",
|
"mailbox_relayhost_info": "Applied to the mailbox and direct aliases only, does override a domain relayhost.",
|
||||||
|
@ -674,7 +676,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "L'accesso è stato ritardato di %s secondi.",
|
"delayed": "L'accesso è stato ritardato di %s secondi.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"mobileconfig_info": "Please login as mailbox user to download the requested Apple connection profile.",
|
"mobileconfig_info": "Please login as mailbox user to download the requested Apple connection profile.",
|
||||||
"other_logins": "Key login",
|
"other_logins": "Key login",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
"bcc_maps": "BCC kartes",
|
"bcc_maps": "BCC kartes",
|
||||||
"filters": "Filtri",
|
"filters": "Filtri",
|
||||||
"recipient_maps": "Saņēmēja kartes",
|
"recipient_maps": "Saņēmēja kartes",
|
||||||
"syncjobs": "Sinhronizācijas uzdevumi"
|
"syncjobs": "Sinhronizācijas uzdevumi",
|
||||||
|
"spam_score": "Mēstules novērtējums"
|
||||||
},
|
},
|
||||||
"add": {
|
"add": {
|
||||||
"activate_filter_warn": "Visi pārējie filtri tiks deaktivizēti, kad aktīvs ir atzīmēts.",
|
"activate_filter_warn": "Visi pārējie filtri tiks deaktivizēti, kad aktīvs ir atzīmēts.",
|
||||||
|
@ -104,10 +105,10 @@
|
||||||
"host": "Hosts",
|
"host": "Hosts",
|
||||||
"import": "Importēt",
|
"import": "Importēt",
|
||||||
"import_private_key": "Importēt privātu atslēgu",
|
"import_private_key": "Importēt privātu atslēgu",
|
||||||
"in_use_by": "Tiek lietots ar",
|
"in_use_by": "Izmanto",
|
||||||
"inactive": "Neaktīvs",
|
"inactive": "Neaktīvs",
|
||||||
"link": "Saite",
|
"link": "Saite",
|
||||||
"loading": "Lūdzu uzgaidiet...",
|
"loading": "Lūgums uzgaidīt...",
|
||||||
"logo_info": "Jūsu attēls augšējā navigācijas joslā tiks palielināts līdz 40 pikseļiem un maks. sākumlapas platums par 250 pikseļi. Ir ļoti ieteicama pielāgojama grafikaYour image will be scaled to a height of 40px for the top navigation bar and a max. width of 250px for the start page. Ir ļoti ieteicama pielāgojamā grafika",
|
"logo_info": "Jūsu attēls augšējā navigācijas joslā tiks palielināts līdz 40 pikseļiem un maks. sākumlapas platums par 250 pikseļi. Ir ļoti ieteicama pielāgojama grafikaYour image will be scaled to a height of 40px for the top navigation bar and a max. width of 250px for the start page. Ir ļoti ieteicama pielāgojamā grafika",
|
||||||
"main_name": "\"mailcow UI\" nosaukums",
|
"main_name": "\"mailcow UI\" nosaukums",
|
||||||
"merged_vars_hint": "Pelēkās rindas tika apvienotas <code>vars.(local.)inc.php</code> un nevar tikt modificētas.",
|
"merged_vars_hint": "Pelēkās rindas tika apvienotas <code>vars.(local.)inc.php</code> un nevar tikt modificētas.",
|
||||||
|
@ -144,7 +145,10 @@
|
||||||
"ui_texts": "UI etiķetes un teksti",
|
"ui_texts": "UI etiķetes un teksti",
|
||||||
"unchanged_if_empty": "Ja nav veiktas izmaiņas, atstājiet tukšu",
|
"unchanged_if_empty": "Ja nav veiktas izmaiņas, atstājiet tukšu",
|
||||||
"upload": "Augšupielādēt",
|
"upload": "Augšupielādēt",
|
||||||
"username": "Lietotājvārds"
|
"username": "Lietotājvārds",
|
||||||
|
"generate": "izveidot",
|
||||||
|
"message": "Ziņojums",
|
||||||
|
"last_applied": "Pēdējoreiz pielietots"
|
||||||
},
|
},
|
||||||
"danger": {
|
"danger": {
|
||||||
"access_denied": "Piekļuve liegta, vai nepareizi dati",
|
"access_denied": "Piekļuve liegta, vai nepareizi dati",
|
||||||
|
@ -170,7 +174,7 @@
|
||||||
"is_alias": "%s jau ir zināms alias",
|
"is_alias": "%s jau ir zināms alias",
|
||||||
"is_alias_or_mailbox": "%s jau ir zināms alias, pastkastes vai alias addrese izvērsta no alias domēna.",
|
"is_alias_or_mailbox": "%s jau ir zināms alias, pastkastes vai alias addrese izvērsta no alias domēna.",
|
||||||
"is_spam_alias": "%s ir jau zināms spam alias",
|
"is_spam_alias": "%s ir jau zināms spam alias",
|
||||||
"last_key": "Pēdējā atslēga nevar būt dzēsta",
|
"last_key": "Pēdējo atslēgu nevar izdzēst, tā vietā jāatspējo divpakāpju pārbaude.",
|
||||||
"login_failed": "Ielogošanās neveiksmīga",
|
"login_failed": "Ielogošanās neveiksmīga",
|
||||||
"mailbox_invalid": "Pastkastes vārds ir nederīgs",
|
"mailbox_invalid": "Pastkastes vārds ir nederīgs",
|
||||||
"mailbox_quota_exceeded": "Kvota pārsniedz domēna limitu (max. %d MiB)",
|
"mailbox_quota_exceeded": "Kvota pārsniedz domēna limitu (max. %d MiB)",
|
||||||
|
@ -262,7 +266,8 @@
|
||||||
"title": "Labot priekšmetu",
|
"title": "Labot priekšmetu",
|
||||||
"unchanged_if_empty": "Ja neizmainīts atstājiet tukšu",
|
"unchanged_if_empty": "Ja neizmainīts atstājiet tukšu",
|
||||||
"username": "Lietotājvārds",
|
"username": "Lietotājvārds",
|
||||||
"validate_save": "Apstiprināt un saglabāt"
|
"validate_save": "Apstiprināt un saglabāt",
|
||||||
|
"last_modified": "Pēdējoreiz mainīts"
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"cancel": "Atcelt",
|
"cancel": "Atcelt",
|
||||||
|
@ -314,21 +319,21 @@
|
||||||
"bcc_destinations": "BCC galamērķi/s",
|
"bcc_destinations": "BCC galamērķi/s",
|
||||||
"bcc_info": "BCC kartes tiek izmantotas, lai klusu pārsūtītu visu ziņojumu kopijas uz citu adresi. Saņēmēja kartes tipa ieraksts tiek izmantots, kad vietējais galamērķis darbojas kā pasta adresāts. Sūtītāja kartes atbilst vienam un tam pašam principam. <br/>\r\n Vietējais galamērķis netiks informēts par piegādes neveiksmi. ",
|
"bcc_info": "BCC kartes tiek izmantotas, lai klusu pārsūtītu visu ziņojumu kopijas uz citu adresi. Saņēmēja kartes tipa ieraksts tiek izmantots, kad vietējais galamērķis darbojas kā pasta adresāts. Sūtītāja kartes atbilst vienam un tam pašam principam. <br/>\r\n Vietējais galamērķis netiks informēts par piegādes neveiksmi. ",
|
||||||
"bcc_local_dest": "Vietējais galamērķis",
|
"bcc_local_dest": "Vietējais galamērķis",
|
||||||
"bcc_map_type": "BCC tips",
|
"bcc_map_type": "BCC veids",
|
||||||
"bcc_maps": "BCC kartes",
|
"bcc_maps": "BCC kartes",
|
||||||
"bcc_rcpt_map": "saņēmēja karte",
|
"bcc_rcpt_map": "saņēmēja karte",
|
||||||
"bcc_sender_map": "Sūtītāja karte",
|
"bcc_sender_map": "Sūtītāja karte",
|
||||||
"bcc_to_rcpt": "Pārslēdzieties uz adresāta kartes tipu",
|
"bcc_to_rcpt": "Pārslēdzieties uz adresāta kartes tipu",
|
||||||
"bcc_to_sender": "Pārslēgties uz sūtītāja kartes tipu",
|
"bcc_to_sender": "Pārslēgties uz sūtītāja kartes tipu",
|
||||||
"bcc_type": "BCC tips",
|
"bcc_type": "BCC tips",
|
||||||
"deactivate": "Deaktivizēt",
|
"deactivate": "Deaktivēt",
|
||||||
"description": "Apraksts",
|
"description": "Apraksts",
|
||||||
"dkim_key_length": "DKIM atslēgas garums (bits)",
|
"dkim_key_length": "DKIM atslēgas garums (bits)",
|
||||||
"domain": "Domēns",
|
"domain": "Domēns",
|
||||||
"domain_admins": "Domēna administratori",
|
"domain_admins": "Domēna administratori",
|
||||||
"domain_aliases": "Domēna aliases",
|
"domain_aliases": "Domēna aliases",
|
||||||
"domain_quota": "Kvota",
|
"domain_quota": "Kvota",
|
||||||
"domain_quota_total": "Kopējā domēna kvota",
|
"domain_quota_total": "Kopējais domēna ierobežojums",
|
||||||
"domains": "Domēns",
|
"domains": "Domēns",
|
||||||
"edit": "Labot",
|
"edit": "Labot",
|
||||||
"empty": "Nav rezultātu",
|
"empty": "Nav rezultātu",
|
||||||
|
@ -341,7 +346,7 @@
|
||||||
"inactive": "Neaktīvs",
|
"inactive": "Neaktīvs",
|
||||||
"kind": "Veids",
|
"kind": "Veids",
|
||||||
"last_run": "Pēdējā norise",
|
"last_run": "Pēdējā norise",
|
||||||
"last_run_reset": "Nākamais grafiks",
|
"last_run_reset": "Ievietot sarakstā kā nākamo",
|
||||||
"mailbox_quota": "Maks. pastkastes izmērs",
|
"mailbox_quota": "Maks. pastkastes izmērs",
|
||||||
"mailboxes": "Pastkaste",
|
"mailboxes": "Pastkaste",
|
||||||
"max_aliases": "Maks. iespejamās aliases",
|
"max_aliases": "Maks. iespejamās aliases",
|
||||||
|
@ -374,7 +379,13 @@
|
||||||
"tls_enforce_out": "Piespiest TLS izejošajiem",
|
"tls_enforce_out": "Piespiest TLS izejošajiem",
|
||||||
"toggle_all": "Pārslēgt visu",
|
"toggle_all": "Pārslēgt visu",
|
||||||
"username": "Lietotājvārds",
|
"username": "Lietotājvārds",
|
||||||
"waiting": "Gaidīšana"
|
"waiting": "Gaidīšana",
|
||||||
|
"last_modified": "Pēdējoreiz mainīts",
|
||||||
|
"booking_0_short": "Vienmēŗ bezmaksas",
|
||||||
|
"daily": "Ik dienu",
|
||||||
|
"hourly": "Ik stundu",
|
||||||
|
"last_mail_login": "Pēdējā pieteikšanās pastkastē",
|
||||||
|
"mailbox": "Pastkaste"
|
||||||
},
|
},
|
||||||
"quarantine": {
|
"quarantine": {
|
||||||
"action": "Darbības",
|
"action": "Darbības",
|
||||||
|
@ -547,5 +558,14 @@
|
||||||
"waiting": "Waiting",
|
"waiting": "Waiting",
|
||||||
"week": "Nedēļa",
|
"week": "Nedēļa",
|
||||||
"weeks": "Nedēļas"
|
"weeks": "Nedēļas"
|
||||||
|
},
|
||||||
|
"datatables": {
|
||||||
|
"paginate": {
|
||||||
|
"first": "Pirmā",
|
||||||
|
"last": "Pēdējā"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"last_modified": "Pēdējoreiz mainīts"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,10 +168,12 @@
|
||||||
"empty": "Geen resultaten",
|
"empty": "Geen resultaten",
|
||||||
"excludes": "Exclusief",
|
"excludes": "Exclusief",
|
||||||
"f2b_ban_time": "Verbanningstijd (s)",
|
"f2b_ban_time": "Verbanningstijd (s)",
|
||||||
|
"f2b_ban_time_increment": "Verbanningstijd wordt verhoogd met elk verbanning",
|
||||||
"f2b_blacklist": "Netwerken/hosts op de blacklist",
|
"f2b_blacklist": "Netwerken/hosts op de blacklist",
|
||||||
"f2b_filter": "Regex-filters",
|
"f2b_filter": "Regex-filters",
|
||||||
"f2b_list_info": "Een host of netwerk op de blacklist staat altijd boven eenzelfde op de whitelist. <b>Het doorvoeren van wijzigingen kan enkele seconden in beslag nemen.</b>",
|
"f2b_list_info": "Een host of netwerk op de blacklist staat altijd boven eenzelfde op de whitelist. <b>Het doorvoeren van wijzigingen kan enkele seconden in beslag nemen.</b>",
|
||||||
"f2b_max_attempts": "Maximaal aantal pogingen",
|
"f2b_max_attempts": "Maximaal aantal pogingen",
|
||||||
|
"f2b_max_ban_time": "Maximaal verbanningstijd (s)",
|
||||||
"f2b_netban_ipv4": "Voer de IPv4-subnetgrootte in waar de verbanning van kracht moet zijn (8-32)",
|
"f2b_netban_ipv4": "Voer de IPv4-subnetgrootte in waar de verbanning van kracht moet zijn (8-32)",
|
||||||
"f2b_netban_ipv6": "Voer de IPv6-subnetgrootte in waar de verbanning van kracht moet zijn (8-128)",
|
"f2b_netban_ipv6": "Voer de IPv6-subnetgrootte in waar de verbanning van kracht moet zijn (8-128)",
|
||||||
"f2b_parameters": "Fail2ban",
|
"f2b_parameters": "Fail2ban",
|
||||||
|
@ -598,7 +600,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "Aanmelding vertraagd met %s seconden.",
|
"delayed": "Aanmelding vertraagd met %s seconden.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Aanmelden",
|
"login": "Aanmelden",
|
||||||
"mobileconfig_info": "Log in als mailboxgebruiker om het Apple-verbindingsprofiel te downloaden.",
|
"mobileconfig_info": "Log in als mailboxgebruiker om het Apple-verbindingsprofiel te downloaden.",
|
||||||
"other_logins": "Meld aan met key",
|
"other_logins": "Meld aan met key",
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"acl": {
|
"acl": {
|
||||||
"sogo_profile_reset": "Usuń profil SOGo (webmail)",
|
"sogo_profile_reset": "Usuń profil SOGo (webmail)",
|
||||||
"syncjobs": "Polecenie synchronizacji"
|
"syncjobs": "Polecenie synchronizacji",
|
||||||
|
"alias_domains": "Dodaj aliasy domen"
|
||||||
},
|
},
|
||||||
"add": {
|
"add": {
|
||||||
"active": "Aktywny",
|
"active": "Aktywny",
|
||||||
|
|
|
@ -539,7 +539,7 @@
|
||||||
"inactive": "Inactiv",
|
"inactive": "Inactiv",
|
||||||
"kind": "Fel",
|
"kind": "Fel",
|
||||||
"last_modified": "Ultima modificare",
|
"last_modified": "Ultima modificare",
|
||||||
"lookup_mx": "Destinația este o expresie regulată care potrivită cu numele MX (<code>.*google\\.com</code> pentru a direcționa toate e-mailurile vizate către un MX care se termină în google.com peste acest hop)",
|
"lookup_mx": "Destinația este o expresie regulată care potrivită cu numele MX (<code>.*\\.google\\.com</code> pentru a direcționa toate e-mailurile vizate către un MX care se termină în google.com peste acest hop)",
|
||||||
"mailbox": "Editează căsuța poștală",
|
"mailbox": "Editează căsuța poștală",
|
||||||
"mailbox_quota_def": "Cota implicită a căsuței poștale",
|
"mailbox_quota_def": "Cota implicită a căsuței poștale",
|
||||||
"mailbox_relayhost_info": "Aplicat numai căsuței poștale și aliasurilor directe, suprascrie un transport dependent de domeniu.",
|
"mailbox_relayhost_info": "Aplicat numai căsuței poștale și aliasurilor directe, suprascrie un transport dependent de domeniu.",
|
||||||
|
@ -656,7 +656,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "Conectarea a fost întârziată cu %s secunde.",
|
"delayed": "Conectarea a fost întârziată cu %s secunde.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Autentificare",
|
"login": "Autentificare",
|
||||||
"mobileconfig_info": "Autentificați-vă cu adresa de email pentru a descărca profilul de conexiune Apple.",
|
"mobileconfig_info": "Autentificați-vă cu adresa de email pentru a descărca profilul de conexiune Apple.",
|
||||||
"other_logins": "Autentificare cu cheie",
|
"other_logins": "Autentificare cu cheie",
|
||||||
|
|
|
@ -336,7 +336,9 @@
|
||||||
"validate_license_now": "Получить лицензию на основе GUID с сервера лицензий",
|
"validate_license_now": "Получить лицензию на основе GUID с сервера лицензий",
|
||||||
"verify": "Проверить",
|
"verify": "Проверить",
|
||||||
"yes": "✓",
|
"yes": "✓",
|
||||||
"queue_unban": "разблокировать"
|
"queue_unban": "разблокировать",
|
||||||
|
"f2b_ban_time_increment": "Время бана увеличивается с каждым баном",
|
||||||
|
"f2b_max_ban_time": "Максимальное время блокировки"
|
||||||
},
|
},
|
||||||
"danger": {
|
"danger": {
|
||||||
"access_denied": "Доступ запрещён, или указаны неверные данные",
|
"access_denied": "Доступ запрещён, или указаны неверные данные",
|
||||||
|
@ -655,7 +657,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "Вход был отложен на %s секунд.",
|
"delayed": "Вход был отложен на %s секунд.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Войти",
|
"login": "Войти",
|
||||||
"mobileconfig_info": "Пожалуйста, войдите в систему как пользователь почтового аккаунта для загрузки профиля подключения Apple.",
|
"mobileconfig_info": "Пожалуйста, войдите в систему как пользователь почтового аккаунта для загрузки профиля подключения Apple.",
|
||||||
"other_logins": "Вход с помощью ключа",
|
"other_logins": "Вход с помощью ключа",
|
||||||
|
|
|
@ -213,7 +213,7 @@
|
||||||
"loading": "Čakajte prosím ...",
|
"loading": "Čakajte prosím ...",
|
||||||
"login_time": "Čas prihlásenia",
|
"login_time": "Čas prihlásenia",
|
||||||
"logo_info": "Váš obrázok bude upravený na výšku 40px pre vrchný navigačný riadok a na maximálnu šírku 250px pre úvodnú stránku. Odporúča sa škálovateľná grafika.",
|
"logo_info": "Váš obrázok bude upravený na výšku 40px pre vrchný navigačný riadok a na maximálnu šírku 250px pre úvodnú stránku. Odporúča sa škálovateľná grafika.",
|
||||||
"lookup_mx": "Cieľ je regulárny výraz ktorý sa porovnáva s MX záznamom (<code>.*google\\.com</code> smeruje všetku poštu určenú pre MX ktoré sú cieľom pre google.com cez tento skok)",
|
"lookup_mx": "Cieľ je regulárny výraz ktorý sa porovnáva s MX záznamom (<code>.*\\.google\\.com</code> smeruje všetku poštu určenú pre MX ktoré sú cieľom pre google.com cez tento skok)",
|
||||||
"main_name": "\"mailcow UI\" názov",
|
"main_name": "\"mailcow UI\" názov",
|
||||||
"merged_vars_hint": "Sivé riadky boli načítané z <code>vars.(local.)inc.php</code> a nemôžu byť modifikované cez UI.",
|
"merged_vars_hint": "Sivé riadky boli načítané z <code>vars.(local.)inc.php</code> a nemôžu byť modifikované cez UI.",
|
||||||
"message": "Správa",
|
"message": "Správa",
|
||||||
|
@ -539,7 +539,7 @@
|
||||||
"inactive": "Neaktívny",
|
"inactive": "Neaktívny",
|
||||||
"kind": "Druh",
|
"kind": "Druh",
|
||||||
"last_modified": "Naposledy upravené",
|
"last_modified": "Naposledy upravené",
|
||||||
"lookup_mx": "Cieľ je regulárny výraz ktorý sa zhoduje s MX záznamom (<code>.*google\\.com</code> smeruje všetku poštu na MX ktoré sú cieľom pre google.com cez tento skok)",
|
"lookup_mx": "Cieľ je regulárny výraz ktorý sa zhoduje s MX záznamom (<code>.*\\.google\\.com</code> smeruje všetku poštu na MX ktoré sú cieľom pre google.com cez tento skok)",
|
||||||
"mailbox": "Upraviť mailovú schránku",
|
"mailbox": "Upraviť mailovú schránku",
|
||||||
"mailbox_quota_def": "Predvolená veľkosť mailovej schránky",
|
"mailbox_quota_def": "Predvolená veľkosť mailovej schránky",
|
||||||
"mailbox_relayhost_info": "Aplikované len na používateľské schránky a priame aliasy, prepisuje doménového preposielateľa.",
|
"mailbox_relayhost_info": "Aplikované len na používateľské schránky a priame aliasy, prepisuje doménového preposielateľa.",
|
||||||
|
@ -657,7 +657,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "Prihlásenie bolo oneskorené o %s sekúnd.",
|
"delayed": "Prihlásenie bolo oneskorené o %s sekúnd.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Prihlásenie",
|
"login": "Prihlásenie",
|
||||||
"mobileconfig_info": "Prosím, prihláste sa ako mailový používateľ pre stiahnutie požadovaného Apple profilu.",
|
"mobileconfig_info": "Prosím, prihláste sa ako mailový používateľ pre stiahnutie požadovaného Apple profilu.",
|
||||||
"other_logins": "Prihlásenie kľúčom",
|
"other_logins": "Prihlásenie kľúčom",
|
||||||
|
|
|
@ -618,7 +618,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "Av säkerhetsskäl har inloggning inaktiverats i %s sekunder.",
|
"delayed": "Av säkerhetsskäl har inloggning inaktiverats i %s sekunder.",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Logga in",
|
"login": "Logga in",
|
||||||
"mobileconfig_info": "Logga in som en användare av brevlåda för att ladda ner den begärda Apple-anslutningsprofilen.",
|
"mobileconfig_info": "Logga in som en användare av brevlåda för att ladda ner den begärda Apple-anslutningsprofilen.",
|
||||||
"other_logins": "Loggain med nyckel",
|
"other_logins": "Loggain med nyckel",
|
||||||
|
|
|
@ -656,7 +656,7 @@
|
||||||
"awaiting_tfa_confirmation": "В очікуванні підтвердження TFA"
|
"awaiting_tfa_confirmation": "В очікуванні підтвердження TFA"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "Увійти",
|
"login": "Увійти",
|
||||||
"other_logins": "Вхід за допомогою ключа",
|
"other_logins": "Вхід за допомогою ключа",
|
||||||
"password": "Пароль",
|
"password": "Пароль",
|
||||||
|
|
|
@ -213,7 +213,7 @@
|
||||||
"loading": "请等待...",
|
"loading": "请等待...",
|
||||||
"login_time": "登录时间",
|
"login_time": "登录时间",
|
||||||
"logo_info": "你的图片将会在顶部导航栏被缩放为 40px 高,在起始页被缩放为最大 250px 高。强烈推荐使用能较好适应缩放的图片。",
|
"logo_info": "你的图片将会在顶部导航栏被缩放为 40px 高,在起始页被缩放为最大 250px 高。强烈推荐使用能较好适应缩放的图片。",
|
||||||
"lookup_mx": "应当为一个正则表达式,用于匹配 MX 记录 (例如 <code>.*google\\.com</code> 将转发所有拥有以 google.com 结尾的 MX 记录的邮件)",
|
"lookup_mx": "应当为一个正则表达式,用于匹配 MX 记录 (例如 <code>.*\\.google\\.com</code> 将转发所有拥有以 google.com 结尾的 MX 记录的邮件)",
|
||||||
"main_name": "Mailcow UI 的名称",
|
"main_name": "Mailcow UI 的名称",
|
||||||
"merged_vars_hint": "灰色行来自 <code>vars.(local.)inc.php</code> 文件并且无法修改。",
|
"merged_vars_hint": "灰色行来自 <code>vars.(local.)inc.php</code> 文件并且无法修改。",
|
||||||
"message": "消息",
|
"message": "消息",
|
||||||
|
@ -544,7 +544,7 @@
|
||||||
"hostname": "主机名",
|
"hostname": "主机名",
|
||||||
"inactive": "禁用",
|
"inactive": "禁用",
|
||||||
"kind": "类型",
|
"kind": "类型",
|
||||||
"lookup_mx": "应当为一个正则表达式,用于匹配 MX 记录 (例如 <code>.*google\\.com</code> 将转发所有拥有以 google.com 结尾的 MX 记录的邮件)",
|
"lookup_mx": "应当为一个正则表达式,用于匹配 MX 记录 (例如 <code>.*\\.google\\.com</code> 将转发所有拥有以 google.com 结尾的 MX 记录的邮件)",
|
||||||
"mailbox": "编辑邮箱",
|
"mailbox": "编辑邮箱",
|
||||||
"mailbox_quota_def": "邮箱默认配额",
|
"mailbox_quota_def": "邮箱默认配额",
|
||||||
"mailbox_relayhost_info": "只适用于邮箱和邮箱别名,不会覆盖域名的中继主机。",
|
"mailbox_relayhost_info": "只适用于邮箱和邮箱别名,不会覆盖域名的中继主机。",
|
||||||
|
@ -661,7 +661,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "请在 %s 秒后重新登录。",
|
"delayed": "请在 %s 秒后重新登录。",
|
||||||
"fido2_webauthn": "使用 FIDO2/WebAuthn 登录",
|
"fido2_webauthn": "使用 FIDO2/WebAuthn Login 登录",
|
||||||
"login": "登录",
|
"login": "登录",
|
||||||
"mobileconfig_info": "请使用邮箱用户登录以下载 Apple 连接描述文件。",
|
"mobileconfig_info": "请使用邮箱用户登录以下载 Apple 连接描述文件。",
|
||||||
"other_logins": "Key 登录",
|
"other_logins": "Key 登录",
|
||||||
|
|
|
@ -213,7 +213,7 @@
|
||||||
"loading": "請稍等...",
|
"loading": "請稍等...",
|
||||||
"login_time": "登入時間",
|
"login_time": "登入時間",
|
||||||
"logo_info": "你的起始頁面圖片會在頂部導覽列的限制下被縮放為 40px 高,以及最大 250px 高度。強烈推薦使用能較好縮放的圖片。",
|
"logo_info": "你的起始頁面圖片會在頂部導覽列的限制下被縮放為 40px 高,以及最大 250px 高度。強烈推薦使用能較好縮放的圖片。",
|
||||||
"lookup_mx": "目的地是可以用來匹配 MX 紀錄的正規表達式 (<code>.*google\\.com</code> 會將所有 MX 結尾於 google.com 的郵件轉發到此主機。)",
|
"lookup_mx": "目的地是可以用來匹配 MX 紀錄的正規表達式 (<code>.*\\.google\\.com</code> 會將所有 MX 結尾於 google.com 的郵件轉發到此主機。)",
|
||||||
"main_name": "\"mailcow UI\" 名稱",
|
"main_name": "\"mailcow UI\" 名稱",
|
||||||
"merged_vars_hint": "灰色列來自 <code>vars.(local.)inc.php</code> 並且不能修改。",
|
"merged_vars_hint": "灰色列來自 <code>vars.(local.)inc.php</code> 並且不能修改。",
|
||||||
"message": "訊息",
|
"message": "訊息",
|
||||||
|
@ -540,7 +540,7 @@
|
||||||
"inactive": "停用",
|
"inactive": "停用",
|
||||||
"kind": "種類",
|
"kind": "種類",
|
||||||
"last_modified": "上次修改時間",
|
"last_modified": "上次修改時間",
|
||||||
"lookup_mx": "目的地是可以用來匹配 MX 紀錄的正規表達式 (<code>.*google\\.com</code> 會將所有 MX 結尾於 google.com 的郵件轉發到此主機。)",
|
"lookup_mx": "目的地是可以用來匹配 MX 紀錄的正規表達式 (<code>.*\\.google\\.com</code> 會將所有 MX 結尾於 google.com 的郵件轉發到此主機。)",
|
||||||
"mailbox": "編輯信箱",
|
"mailbox": "編輯信箱",
|
||||||
"mailbox_quota_def": "預設信箱容量配額",
|
"mailbox_quota_def": "預設信箱容量配額",
|
||||||
"mailbox_relayhost_info": "只會套用於信箱和直接別名,不會覆寫域名中繼主機。",
|
"mailbox_relayhost_info": "只會套用於信箱和直接別名,不會覆寫域名中繼主機。",
|
||||||
|
@ -655,7 +655,7 @@
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"delayed": "請在 %s 秒後重新登入。",
|
"delayed": "請在 %s 秒後重新登入。",
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn Login",
|
||||||
"login": "登入",
|
"login": "登入",
|
||||||
"mobileconfig_info": "請使用信箱使用者登入以下載 Apple 連接描述檔案。",
|
"mobileconfig_info": "請使用信箱使用者登入以下載 Apple 連接描述檔案。",
|
||||||
"other_logins": "金鑰登入",
|
"other_logins": "金鑰登入",
|
||||||
|
|
|
@ -61,7 +61,7 @@ elseif (isset($_GET['login'])) {
|
||||||
':remote_addr' => ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'])
|
':remote_addr' => ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'])
|
||||||
));
|
));
|
||||||
// redirect to sogo (sogo will get the correct credentials via nginx auth_request
|
// redirect to sogo (sogo will get the correct credentials via nginx auth_request
|
||||||
header("Location: /SOGo/so/${login}");
|
header("Location: /SOGo/so/{$login}");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,14 @@
|
||||||
<label for="f2b_ban_time">{{ lang.admin.f2b_ban_time }}:</label>
|
<label for="f2b_ban_time">{{ lang.admin.f2b_ban_time }}:</label>
|
||||||
<input type="number" class="form-control" id="f2b_ban_time" name="ban_time" value="{{ f2b_data.ban_time }}" required>
|
<input type="number" class="form-control" id="f2b_ban_time" name="ban_time" value="{{ f2b_data.ban_time }}" required>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="f2b_max_ban_time">{{ lang.admin.f2b_max_ban_time }}:</label>
|
||||||
|
<input type="number" class="form-control" id="f2b_max_ban_time" name="max_ban_time" value="{{ f2b_data.max_ban_time }}" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<input class="form-check-input" type="checkbox" value="1" name="ban_time_increment" id="f2b_ban_time_increment" {% if f2b_data.ban_time_increment == 1 %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="f2b_ban_time_increment">{{ lang.admin.f2b_ban_time_increment }}</label>
|
||||||
|
</div>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label for="f2b_max_attempts">{{ lang.admin.f2b_max_attempts }}:</label>
|
<label for="f2b_max_attempts">{{ lang.admin.f2b_max_attempts }}:</label>
|
||||||
<input type="number" class="form-control" id="f2b_max_attempts" name="max_attempts" value="{{ f2b_data.max_attempts }}" required>
|
<input type="number" class="form-control" id="f2b_max_attempts" name="max_attempts" value="{{ f2b_data.max_attempts }}" required>
|
||||||
|
|
|
@ -50,6 +50,12 @@
|
||||||
<p><b>{{ hostname }}</b></p>
|
<p><b>{{ hostname }}</b></p>
|
||||||
</div></td>
|
</div></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ lang.debug.architecture }}</td>
|
||||||
|
<td class="text-break"><div>
|
||||||
|
<p id="host_architecture">-</p>
|
||||||
|
</div></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>IPs</td>
|
<td>IPs</td>
|
||||||
<td class="text-break">
|
<td class="text-break">
|
||||||
|
@ -71,7 +77,7 @@
|
||||||
<td>Version</td>
|
<td>Version</td>
|
||||||
<td class="text-break">
|
<td class="text-break">
|
||||||
<div class="fw-bolder">
|
<div class="fw-bolder">
|
||||||
<p ><a href="#" id="maiclow_version">{{ mailcow_info.version_tag }}</a></p>
|
<p ><a href="#" id="mailcow_version">{{ mailcow_info.version_tag }}</a></p>
|
||||||
<p id="mailcow_update"></p>
|
<p id="mailcow_update"></p>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -613,7 +619,7 @@
|
||||||
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="rl_log" data-table="rl_log" href="#">{{ lang.datatables.expand_all }}</a></li>
|
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="rl_log" data-table="rl_log" href="#">{{ lang.datatables.expand_all }}</a></li>
|
||||||
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="rl_log" data-table="rl_log" href="#">{{ lang.datatables.collapse_all }}</a></li>
|
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="rl_log" data-table="rl_log" href="#">{{ lang.datatables.collapse_all }}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class="text-muted">{{ lang.admin.hash_remove_info }}</p>
|
<p class="text-muted">{{ lang.admin.hash_remove_info|raw }}</p>
|
||||||
<table id="rl_log" class="table table-striped dt-responsive w-100"></table>
|
<table id="rl_log" class="table table-striped dt-responsive w-100"></table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -121,25 +121,25 @@
|
||||||
<label class="control-label col-sm-2">{{ lang.user.quarantine_notification }}</label>
|
<label class="control-label col-sm-2">{{ lang.user.quarantine_notification }}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<div class="btn-group" data-acl="{{ acl.quarantine_notification }}">
|
<div class="btn-group" data-acl="{{ acl.quarantine_notification }}">
|
||||||
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary{% if quarantine_notification == 'never' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'never' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailbox }}"
|
data-item="{{ mailbox }}"
|
||||||
data-id="quarantine_notification"
|
data-id="quarantine_notification"
|
||||||
data-api-url='edit/quarantine_notification'
|
data-api-url='edit/quarantine_notification'
|
||||||
data-api-attr='{"quarantine_notification":"never"}'>{{ lang.user.never }}</button>
|
data-api-attr='{"quarantine_notification":"never"}'>{{ lang.user.never }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary{% if quarantine_notification == 'hourly' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'hourly' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailbox }}"
|
data-item="{{ mailbox }}"
|
||||||
data-id="quarantine_notification"
|
data-id="quarantine_notification"
|
||||||
data-api-url='edit/quarantine_notification'
|
data-api-url='edit/quarantine_notification'
|
||||||
data-api-attr='{"quarantine_notification":"hourly"}'>{{ lang.user.hourly }}</button>
|
data-api-attr='{"quarantine_notification":"hourly"}'>{{ lang.user.hourly }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary{% if quarantine_notification == 'daily' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'daily' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailbox }}"
|
data-item="{{ mailbox }}"
|
||||||
data-id="quarantine_notification"
|
data-id="quarantine_notification"
|
||||||
data-api-url='edit/quarantine_notification'
|
data-api-url='edit/quarantine_notification'
|
||||||
data-api-attr='{"quarantine_notification":"daily"}'>{{ lang.user.daily }}</button>
|
data-api-attr='{"quarantine_notification":"daily"}'>{{ lang.user.daily }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary{% if quarantine_notification == 'weekly' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'weekly' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailbox }}"
|
data-item="{{ mailbox }}"
|
||||||
data-id="quarantine_notification"
|
data-id="quarantine_notification"
|
||||||
|
@ -153,19 +153,19 @@
|
||||||
<label class="control-label col-sm-2">{{ lang.user.quarantine_category }}</label>
|
<label class="control-label col-sm-2">{{ lang.user.quarantine_category }}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<div class="btn-group" data-acl="{{ acl.quarantine_category }}">
|
<div class="btn-group" data-acl="{{ acl.quarantine_category }}">
|
||||||
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-secondary{% if quarantine_category == 'reject' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'reject' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailbox }}"
|
data-item="{{ mailbox }}"
|
||||||
data-id="quarantine_category"
|
data-id="quarantine_category"
|
||||||
data-api-url='edit/quarantine_category'
|
data-api-url='edit/quarantine_category'
|
||||||
data-api-attr='{"quarantine_category":"reject"}'>{{ lang.user.q_reject }}</button>
|
data-api-attr='{"quarantine_category":"reject"}'>{{ lang.user.q_reject }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-secondary{% if quarantine_category == 'add_header' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'add_header' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailbox }}"
|
data-item="{{ mailbox }}"
|
||||||
data-id="quarantine_category"
|
data-id="quarantine_category"
|
||||||
data-api-url='edit/quarantine_category'
|
data-api-url='edit/quarantine_category'
|
||||||
data-api-attr='{"quarantine_category":"add_header"}'>{{ lang.user.q_add_header }}</button>
|
data-api-attr='{"quarantine_category":"add_header"}'>{{ lang.user.q_add_header }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-secondary{% if quarantine_category == 'all' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'all' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailbox }}"
|
data-item="{{ mailbox }}"
|
||||||
data-id="quarantine_category"
|
data-id="quarantine_category"
|
||||||
|
@ -179,13 +179,13 @@
|
||||||
<label class="control-label col-sm-2" for="sender_acl">{{ lang.user.tls_policy }}</label>
|
<label class="control-label col-sm-2" for="sender_acl">{{ lang.user.tls_policy }}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<div class="btn-group" data-acl="{{ acl.tls_policy }}">
|
<div class="btn-group" data-acl="{{ acl.tls_policy }}">
|
||||||
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary{% if get_tls_policy.tls_enforce_in == '1' %} active"{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-light{% if get_tls_policy.tls_enforce_in == '1' %} btn-dark"{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailbox }}"
|
data-item="{{ mailbox }}"
|
||||||
data-id="tls_policy"
|
data-id="tls_policy"
|
||||||
data-api-url='edit/tls_policy'
|
data-api-url='edit/tls_policy'
|
||||||
data-api-attr='{"tls_enforce_in": {% if get_tls_policy.tls_enforce_in == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_in }}</button>
|
data-api-attr='{"tls_enforce_in": {% if get_tls_policy.tls_enforce_in == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_in }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary{% if get_tls_policy.tls_enforce_out == '1' %} active"{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-light{% if get_tls_policy.tls_enforce_out == '1' %} btn-dark"{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailbox }}"
|
data-item="{{ mailbox }}"
|
||||||
data-id="tls_policy"
|
data-id="tls_policy"
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation"><button class="nav-link" aria-controls="tab-resources" role="tab" data-bs-toggle="tab" data-bs-target="#tab-resources">{{ lang.mailbox.resources }}</button></li>
|
<li class="nav-item" role="presentation"><button class="nav-link" aria-controls="tab-resources" role="tab" data-bs-toggle="tab" data-bs-target="#tab-resources">{{ lang.mailbox.resources }}</button></li>
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" data-bs-target="#">{{ lang.mailbox.aliases }}</a>
|
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.aliases }}</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li role="presentation"><button class="dropdown-item" aria-selected="false" aria-controls="tab-mbox-aliases" role="tab" data-bs-toggle="tab" data-bs-target="#tab-mbox-aliases">{{ lang.mailbox.aliases }}</button></li>
|
<li role="presentation"><button class="dropdown-item" aria-selected="false" aria-controls="tab-mbox-aliases" role="tab" data-bs-toggle="tab" data-bs-target="#tab-mbox-aliases">{{ lang.mailbox.aliases }}</button></li>
|
||||||
<li role="presentation"><button class="dropdown-item" aria-selected="false" aria-controls="tab-domain-aliases" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domain-aliases">{{ lang.mailbox.domain_aliases }}</button></li>
|
<li role="presentation"><button class="dropdown-item" aria-selected="false" aria-controls="tab-domain-aliases" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domain-aliases">{{ lang.mailbox.domain_aliases }}</button></li>
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
<li class="dropdown-header">SMTP</li>
|
<li class="dropdown-header">SMTP</li>
|
||||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
|
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
|
||||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
|
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
<li class="dropdown-header">Sieve</li>
|
<li class="dropdown-header">Sieve</li>
|
||||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"sieve_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
|
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"sieve_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
|
||||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"sieve_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
|
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"sieve_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
|
||||||
|
@ -61,7 +62,7 @@
|
||||||
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
|
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group d-none d-lg-flex">
|
<div class="btn-group d-none d-lg-flex">
|
||||||
<a class="btn btn-sm btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
|
<a class="btn btn-sm btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
|
||||||
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
|
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="mailbox_table">{{ lang.datatables.expand_all }}</a></li>
|
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="mailbox_table">{{ lang.datatables.expand_all }}</a></li>
|
||||||
|
|
|
@ -12,11 +12,21 @@
|
||||||
<li><button class="dropdown-item" role="tab" aria-selected="false" aria-controls="tab-config-f2b" data-bs-toggle="tab" data-bs-target="#tab-user-settings">{{ lang.user.mailbox_settings }}</button></li>
|
<li><button class="dropdown-item" role="tab" aria-selected="false" aria-controls="tab-config-f2b" data-bs-toggle="tab" data-bs-target="#tab-user-settings">{{ lang.user.mailbox_settings }}</button></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
{% if acl.spam_alias == 1 %}
|
||||||
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="SpamAliases" role="tab" data-bs-toggle="tab" data-bs-target="#SpamAliases">{{ lang.user.spam_aliases }}</button></li>
|
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="SpamAliases" role="tab" data-bs-toggle="tab" data-bs-target="#SpamAliases">{{ lang.user.spam_aliases }}</button></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if acl.spam_score == 1 %}
|
||||||
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="Spamfilter" role="tab" data-bs-toggle="tab" data-bs-target="#Spamfilter">{{ lang.user.spamfilter }}</button></li>
|
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="Spamfilter" role="tab" data-bs-toggle="tab" data-bs-target="#Spamfilter">{{ lang.user.spamfilter }}</button></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if acl.syncjobs == 1 %}
|
||||||
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="Syncjobs" role="tab" data-bs-toggle="tab" data-bs-target="#Syncjobs">{{ lang.user.sync_jobs }}</button></li>
|
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="Syncjobs" role="tab" data-bs-toggle="tab" data-bs-target="#Syncjobs">{{ lang.user.sync_jobs }}</button></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if acl.app_passwds == 1 %}
|
||||||
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="AppPasswds" role="tab" data-bs-toggle="tab" data-bs-target="#AppPasswds">{{ lang.user.app_passwds }}</button></li>
|
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="AppPasswds" role="tab" data-bs-toggle="tab" data-bs-target="#AppPasswds">{{ lang.user.app_passwds }}</button></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if acl.pushover == 1 %}
|
||||||
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="Pushover" role="tab" data-bs-toggle="tab" data-bs-target="#Pushover">Pushover API</button></li>
|
<li class="nav-item" role="presentation"><button class="nav-link" role="tab" aria-selected="false" aria-controls="Pushover" role="tab" data-bs-toggle="tab" data-bs-target="#Pushover">Pushover API</button></li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -25,11 +35,11 @@
|
||||||
{% include 'user/tab-user-auth.twig' %}
|
{% include 'user/tab-user-auth.twig' %}
|
||||||
{% include 'user/tab-user-details.twig' %}
|
{% include 'user/tab-user-details.twig' %}
|
||||||
{% include 'user/tab-user-settings.twig' %}
|
{% include 'user/tab-user-settings.twig' %}
|
||||||
{% include 'user/SpamAliases.twig' %}
|
{% if acl.spam_alias == 1 %}{% include 'user/SpamAliases.twig' %}{% endif %}
|
||||||
{% include 'user/Spamfilter.twig' %}
|
{% if acl.spam_score == 1 %}{% include 'user/Spamfilter.twig' %}{% endif %}
|
||||||
{% include 'user/Syncjobs.twig' %}
|
{% if acl.syncjobs == 1 %}{% include 'user/Syncjobs.twig' %}{% endif %}
|
||||||
{% include 'user/AppPasswds.twig' %}
|
{% if acl.app_passwds == 1 %}{% include 'user/AppPasswds.twig' %}{% endif %}
|
||||||
{% include 'user/Pushover.twig' %}
|
{% if acl.pushover == 1 %}{% include 'user/Pushover.twig' %}{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,19 +12,19 @@
|
||||||
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.tag_handling }}:</div>
|
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.tag_handling }}:</div>
|
||||||
<div class="col-sm-9 col-12">
|
<div class="col-sm-9 col-12">
|
||||||
<div class="btn-group" data-acl="{{ acl.delimiter_action }}">
|
<div class="btn-group" data-acl="{{ acl.delimiter_action }}">
|
||||||
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-outline-secondary{% if get_tagging_options == 'subfolder' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if get_tagging_options == 'subfolder' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="delimiter_action"
|
data-id="delimiter_action"
|
||||||
data-api-url='edit/delimiter_action'
|
data-api-url='edit/delimiter_action'
|
||||||
data-api-attr='{"tagged_mail_handler":"subfolder"}'>{{ lang.user.tag_in_subfolder }}</button>
|
data-api-attr='{"tagged_mail_handler":"subfolder"}'>{{ lang.user.tag_in_subfolder }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-outline-secondary{% if get_tagging_options == 'subject' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if get_tagging_options == 'subject' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="delimiter_action"
|
data-id="delimiter_action"
|
||||||
data-api-url='edit/delimiter_action'
|
data-api-url='edit/delimiter_action'
|
||||||
data-api-attr='{"tagged_mail_handler":"subject"}'>{{ lang.user.tag_in_subject }}</button>
|
data-api-attr='{"tagged_mail_handler":"subject"}'>{{ lang.user.tag_in_subject }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-outline-secondary{% if get_tagging_options == 'none' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if get_tagging_options == 'none' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="delimiter_action"
|
data-id="delimiter_action"
|
||||||
|
@ -40,13 +40,13 @@
|
||||||
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.tls_policy }}:</div>
|
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.tls_policy }}:</div>
|
||||||
<div class="col-sm-9 col-12">
|
<div class="col-sm-9 col-12">
|
||||||
<div class="btn-group" data-acl="{{ acl.tls_policy }}">
|
<div class="btn-group" data-acl="{{ acl.tls_policy }}">
|
||||||
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-outline-secondary{% if get_tls_policy.tls_enforce_in == '1' %} active"{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-light{% if get_tls_policy.tls_enforce_in == '1' %} btn-dark"{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="tls_policy"
|
data-id="tls_policy"
|
||||||
data-api-url='edit/tls_policy'
|
data-api-url='edit/tls_policy'
|
||||||
data-api-attr='{"tls_enforce_in": {% if get_tls_policy.tls_enforce_in == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_in }}</button>
|
data-api-attr='{"tls_enforce_in": {% if get_tls_policy.tls_enforce_in == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_in }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-outline-secondary{% if get_tls_policy.tls_enforce_out == '1' %} active"{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-light{% if get_tls_policy.tls_enforce_out == '1' %} btn-dark"{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="tls_policy"
|
data-id="tls_policy"
|
||||||
|
@ -61,25 +61,25 @@
|
||||||
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.quarantine_notification }}:</div>
|
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.quarantine_notification }}:</div>
|
||||||
<div class="col-sm-9 col-12">
|
<div class="col-sm-9 col-12">
|
||||||
<div class="btn-group" data-acl="{{ acl.quarantine_notification }}">
|
<div class="btn-group" data-acl="{{ acl.quarantine_notification }}">
|
||||||
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-outline-secondary{% if quarantine_notification == 'never' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'never' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="quarantine_notification"
|
data-id="quarantine_notification"
|
||||||
data-api-url='edit/quarantine_notification'
|
data-api-url='edit/quarantine_notification'
|
||||||
data-api-attr='{"quarantine_notification":"never"}'>{{ lang.user.never }}</button>
|
data-api-attr='{"quarantine_notification":"never"}'>{{ lang.user.never }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-outline-secondary{% if quarantine_notification == 'hourly' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'hourly' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="quarantine_notification"
|
data-id="quarantine_notification"
|
||||||
data-api-url='edit/quarantine_notification'
|
data-api-url='edit/quarantine_notification'
|
||||||
data-api-attr='{"quarantine_notification":"hourly"}'>{{ lang.user.hourly }}</button>
|
data-api-attr='{"quarantine_notification":"hourly"}'>{{ lang.user.hourly }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-outline-secondary{% if quarantine_notification == 'daily' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'daily' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="quarantine_notification"
|
data-id="quarantine_notification"
|
||||||
data-api-url='edit/quarantine_notification'
|
data-api-url='edit/quarantine_notification'
|
||||||
data-api-attr='{"quarantine_notification":"daily"}'>{{ lang.user.daily }}</button>
|
data-api-attr='{"quarantine_notification":"daily"}'>{{ lang.user.daily }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-outline-secondary{% if quarantine_notification == 'weekly' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'weekly' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="quarantine_notification"
|
data-id="quarantine_notification"
|
||||||
|
@ -93,19 +93,19 @@
|
||||||
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.quarantine_category }}:</div>
|
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.quarantine_category }}:</div>
|
||||||
<div class="col-sm-9 col-12">
|
<div class="col-sm-9 col-12">
|
||||||
<div class="btn-group" data-acl="{{ acl.quarantine_category }}">
|
<div class="btn-group" data-acl="{{ acl.quarantine_category }}">
|
||||||
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-outline-secondary{% if quarantine_category == 'reject' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'reject' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="quarantine_category"
|
data-id="quarantine_category"
|
||||||
data-api-url='edit/quarantine_category'
|
data-api-url='edit/quarantine_category'
|
||||||
data-api-attr='{"quarantine_category":"reject"}'>{{ lang.user.q_reject }}</button>
|
data-api-attr='{"quarantine_category":"reject"}'>{{ lang.user.q_reject }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-outline-secondary{% if quarantine_category == 'add_header' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'add_header' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="quarantine_category"
|
data-id="quarantine_category"
|
||||||
data-api-url='edit/quarantine_category'
|
data-api-url='edit/quarantine_category'
|
||||||
data-api-attr='{"quarantine_category":"add_header"}'>{{ lang.user.q_add_header }}</button>
|
data-api-attr='{"quarantine_category":"add_header"}'>{{ lang.user.q_add_header }}</button>
|
||||||
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-outline-secondary{% if quarantine_category == 'all' %} active{% endif %}"
|
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'all' %} btn-dark{% endif %}"
|
||||||
data-action="edit_selected"
|
data-action="edit_selected"
|
||||||
data-item="{{ mailcow_cc_username }}"
|
data-item="{{ mailcow_cc_username }}"
|
||||||
data-id="quarantine_category"
|
data-id="quarantine_category"
|
||||||
|
|
|
@ -58,7 +58,7 @@ services:
|
||||||
- redis
|
- redis
|
||||||
|
|
||||||
clamd-mailcow:
|
clamd-mailcow:
|
||||||
image: mailcow/clamd:1.60
|
image: mailcow/clamd:1.61
|
||||||
restart: always
|
restart: always
|
||||||
depends_on:
|
depends_on:
|
||||||
- unbound-mailcow
|
- unbound-mailcow
|
||||||
|
@ -106,7 +106,7 @@ services:
|
||||||
- rspamd
|
- rspamd
|
||||||
|
|
||||||
php-fpm-mailcow:
|
php-fpm-mailcow:
|
||||||
image: mailcow/phpfpm:1.82
|
image: mailcow/phpfpm:1.83
|
||||||
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
|
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis-mailcow
|
- redis-mailcow
|
||||||
|
@ -179,7 +179,7 @@ services:
|
||||||
- phpfpm
|
- phpfpm
|
||||||
|
|
||||||
sogo-mailcow:
|
sogo-mailcow:
|
||||||
image: mailcow/sogo:1.115
|
image: mailcow/sogo:1.117
|
||||||
environment:
|
environment:
|
||||||
- DBNAME=${DBNAME}
|
- DBNAME=${DBNAME}
|
||||||
- DBUSER=${DBUSER}
|
- DBUSER=${DBUSER}
|
||||||
|
@ -201,7 +201,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/hooks/sogo:/hooks:Z
|
- ./data/hooks/sogo:/hooks:Z
|
||||||
- ./data/conf/sogo/:/etc/sogo/:z
|
- ./data/conf/sogo/:/etc/sogo/:z
|
||||||
- ./data/web/inc/init_db.inc.php:/init_db.inc.php:Z
|
- ./data/web/inc/init_db.inc.php:/init_db.inc.php:z
|
||||||
- ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z
|
- ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z
|
||||||
- ./data/conf/sogo/custom-theme.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/theme.js:z
|
- ./data/conf/sogo/custom-theme.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/theme.js:z
|
||||||
- ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js:z
|
- ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js:z
|
||||||
|
@ -226,7 +226,7 @@ services:
|
||||||
- sogo
|
- sogo
|
||||||
|
|
||||||
dovecot-mailcow:
|
dovecot-mailcow:
|
||||||
image: mailcow/dovecot:1.24
|
image: mailcow/dovecot:1.23
|
||||||
depends_on:
|
depends_on:
|
||||||
- mysql-mailcow
|
- mysql-mailcow
|
||||||
dns:
|
dns:
|
||||||
|
@ -439,7 +439,7 @@ services:
|
||||||
- acme
|
- acme
|
||||||
|
|
||||||
netfilter-mailcow:
|
netfilter-mailcow:
|
||||||
image: mailcow/netfilter:1.50
|
image: mailcow/netfilter:1.52
|
||||||
stop_grace_period: 30s
|
stop_grace_period: 30s
|
||||||
depends_on:
|
depends_on:
|
||||||
- dovecot-mailcow
|
- dovecot-mailcow
|
||||||
|
@ -524,7 +524,7 @@ services:
|
||||||
- watchdog
|
- watchdog
|
||||||
|
|
||||||
dockerapi-mailcow:
|
dockerapi-mailcow:
|
||||||
image: mailcow/dockerapi:2.01
|
image: mailcow/dockerapi:2.04
|
||||||
security_opt:
|
security_opt:
|
||||||
- label=disable
|
- label=disable
|
||||||
restart: always
|
restart: always
|
||||||
|
|
|
@ -205,8 +205,8 @@ DBUSER=mailcow
|
||||||
|
|
||||||
# Please use long, random alphanumeric strings (A-Za-z0-9)
|
# Please use long, random alphanumeric strings (A-Za-z0-9)
|
||||||
|
|
||||||
DBPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 | head -c 28)
|
DBPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
|
||||||
DBROOT=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 | head -c 28)
|
DBROOT=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
|
||||||
|
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
# HTTP/S Bindings
|
# HTTP/S Bindings
|
||||||
|
@ -261,7 +261,7 @@ COMPOSE_PROJECT_NAME=mailcowdockerized
|
||||||
# Switch here between native (compose plugin) and standalone
|
# Switch here between native (compose plugin) and standalone
|
||||||
# For more informations take a look at the mailcow docs regarding the configuration options.
|
# For more informations take a look at the mailcow docs regarding the configuration options.
|
||||||
# Normally this should be untouched but if you decided to use either of those you can switch it manually here.
|
# Normally this should be untouched but if you decided to use either of those you can switch it manually here.
|
||||||
# Please be aware that at least one of those variants should be installed on your maschine or mailcow will fail.
|
# Please be aware that at least one of those variants should be installed on your machine or mailcow will fail.
|
||||||
|
|
||||||
DOCKER_COMPOSE_VERSION=${COMPOSE_VERSION}
|
DOCKER_COMPOSE_VERSION=${COMPOSE_VERSION}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
[[ -f mailcow.conf ]] && source mailcow.conf
|
[[ -f mailcow.conf ]] && source mailcow.conf
|
||||||
[[ -f ../mailcow.conf ]] && source ../mailcow.conf
|
[[ -f ../mailcow.conf ]] && source ../mailcow.conf
|
||||||
|
|
||||||
POSTFIX=$(echo | openssl s_client -connect ${MAILCOW_HOSTNAME}:25 -starttls smtp 2>/dev/null | openssl x509 -inform pem -noout -enddate | cut -d "=" -f 2)
|
POSTFIX=$(echo | openssl s_client -connect ${MAILCOW_HOSTNAME}:${SMTP_PORT} -starttls smtp 2>/dev/null | openssl x509 -inform pem -noout -enddate | cut -d "=" -f 2)
|
||||||
DOVECOT=$(echo | openssl s_client -connect ${MAILCOW_HOSTNAME}:143 -starttls imap 2>/dev/null | openssl x509 -inform pem -noout -enddate | cut -d "=" -f 2)
|
DOVECOT=$(echo | openssl s_client -connect ${MAILCOW_HOSTNAME}:${IMAP_PORT} -starttls imap 2>/dev/null | openssl x509 -inform pem -noout -enddate | cut -d "=" -f 2)
|
||||||
NGINX=$(echo | openssl s_client -connect ${MAILCOW_HOSTNAME}:443 2>/dev/null | openssl x509 -inform pem -noout -enddate | cut -d "=" -f 2)
|
NGINX=$(echo | openssl s_client -connect ${MAILCOW_HOSTNAME}:${HTTPS_PORT} 2>/dev/null | openssl x509 -inform pem -noout -enddate | cut -d "=" -f 2)
|
||||||
echo TLS expiry dates:
|
|
||||||
echo Postfix: ${POSTFIX}
|
echo "TLS expiry dates:"
|
||||||
echo Dovecot: ${DOVECOT}
|
echo "Postfix: ${POSTFIX}"
|
||||||
echo Nginx: ${NGINX}
|
echo "Dovecot: ${DOVECOT}"
|
||||||
|
echo "Nginx: ${NGINX}"
|
||||||
|
|
|
@ -19,7 +19,7 @@ read -r -p "Are you sure you want to reset the mailcow administrator account? [y
|
||||||
response=${response,,} # tolower
|
response=${response,,} # tolower
|
||||||
if [[ "$response" =~ ^(yes|y)$ ]]; then
|
if [[ "$response" =~ ^(yes|y)$ ]]; then
|
||||||
echo -e "\nWorking, please wait..."
|
echo -e "\nWorking, please wait..."
|
||||||
random=$(</dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-16})
|
random=$(</dev/urandom tr -dc _A-Z-a-z-0-9 2> /dev/null | head -c${1:-16})
|
||||||
password=$(docker exec -it $(docker ps -qf name=dovecot-mailcow) doveadm pw -s SSHA256 -p ${random} | tr -d '\r')
|
password=$(docker exec -it $(docker ps -qf name=dovecot-mailcow) doveadm pw -s SSHA256 -p ${random} | tr -d '\r')
|
||||||
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM admin WHERE username='admin';"
|
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM admin WHERE username='admin';"
|
||||||
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM domain_admins WHERE username='admin';"
|
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM domain_admins WHERE username='admin';"
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# renovate: datasource=github-releases depName=nextcloud/server versioning=semver extractVersion=^v(?<version>.*)$
|
# renovate: datasource=github-releases depName=nextcloud/server versioning=semver extractVersion=^v(?<version>.*)$
|
||||||
NEXTCLOUD_VERSION=25.0.3
|
NEXTCLOUD_VERSION=26.0.1
|
||||||
|
|
||||||
for bin in curl dirmngr; do
|
echo -ne "Checking prerequisites..."
|
||||||
if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi
|
sleep 1
|
||||||
|
for bin in curl dirmngr tar bzip2; do
|
||||||
|
if [[ -z $(which ${bin}) ]]; then echo -ne "\r\033[31mCannot find ${bin}, exiting...\033[0m\n"; exit 1; fi
|
||||||
done
|
done
|
||||||
|
echo -ne "\r\033[32mFound all prerequisites! Continuing...\033[0m\n"
|
||||||
|
|
||||||
[[ -z ${1} ]] && NC_HELP=y
|
[[ -z ${1} ]] && NC_HELP=y
|
||||||
|
|
||||||
|
@ -94,8 +97,12 @@ elif [[ ${NC_UPDATE} == "y" ]]; then
|
||||||
echo -e "\033[31mError: Nextcloud occ not found. Is Nextcloud installed?\033[0m"
|
echo -e "\033[31mError: Nextcloud occ not found. Is Nextcloud installed?\033[0m"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if ! grep -q 'installed: true' <<<$(docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) bash -c "/web/nextcloud/occ --no-warnings status"); then
|
if grep -Pq 'This version of Nextcloud is not compatible with (?:PHP)?(?>=?)(?:PHP)?(?>.+)' <<<$(docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) bash -c "/web/nextcloud/occ --no-warnings status"); then
|
||||||
echo "Nextcloud seems not to be installed."
|
echo -e "\033[31mError: This version of Nextcloud is not compatible with the current PHP version of php-fpm-mailcow, we'll fix it\033[0m"
|
||||||
|
wget -q https://raw.githubusercontent.com/nextcloud/server/v26.0.0/lib/versioncheck.php -O ./data/web/nextcloud/lib/versioncheck.php
|
||||||
|
echo -e "\e[33mPlease restart the update again.\e[0m"
|
||||||
|
elif ! grep -q 'installed: true' <<<$(docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) bash -c "/web/nextcloud/occ --no-warnings status"); then
|
||||||
|
echo -e "\033[31mError: Nextcloud seems not to be installed.\033[0m"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) bash -c "php /web/nextcloud/updater/updater.phar"
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) bash -c "php /web/nextcloud/updater/updater.phar"
|
||||||
|
@ -119,7 +126,7 @@ elif [[ ${NC_INSTALL} == "y" ]]; then
|
||||||
&& chmod +x ./data/web/nextcloud/occ
|
&& chmod +x ./data/web/nextcloud/occ
|
||||||
|
|
||||||
echo -e "\033[33mCreating 'nextcloud' database...\033[0m"
|
echo -e "\033[33mCreating 'nextcloud' database...\033[0m"
|
||||||
NC_DBPASS=$(</dev/urandom tr -dc A-Za-z0-9 | head -c 28)
|
NC_DBPASS=$(</dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
|
||||||
NC_DBUSER=nextcloud
|
NC_DBUSER=nextcloud
|
||||||
NC_DBNAME=nextcloud
|
NC_DBNAME=nextcloud
|
||||||
|
|
||||||
|
@ -135,7 +142,7 @@ elif [[ ${NC_INSTALL} == "y" ]]; then
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "\033[33mInstalling Nextcloud...\033[0m"
|
echo -e "\033[33mInstalling Nextcloud...\033[0m"
|
||||||
ADMIN_NC_PASS=$(</dev/urandom tr -dc A-Za-z0-9 | head -c 28)
|
ADMIN_NC_PASS=$(</dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
|
||||||
|
|
||||||
echo -ne "[1/4] Setting correct permissions for www-data"
|
echo -ne "[1/4] Setting correct permissions for www-data"
|
||||||
docker exec -it $(docker ps -f name=php-fpm-mailcow -q) /bin/bash -c "chown -R www-data:www-data /web/nextcloud"
|
docker exec -it $(docker ps -f name=php-fpm-mailcow -q) /bin/bash -c "chown -R www-data:www-data /web/nextcloud"
|
||||||
|
@ -215,5 +222,4 @@ elif [[ ${NC_RESETPW} == "y" ]]; then
|
||||||
read -p "Enter the username: " NC_USER
|
read -p "Enter the username: " NC_USER
|
||||||
done
|
done
|
||||||
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ user:resetpassword ${NC_USER}
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ user:resetpassword ${NC_USER}
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
77
update.sh
77
update.sh
|
@ -176,18 +176,19 @@ remove_obsolete_nginx_ports() {
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_docker_compose_command(){
|
detect_docker_compose_command(){
|
||||||
if ! [ "${DOCKER_COMPOSE_VERSION}" == "native" ] && ! [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then
|
if ! [[ "${DOCKER_COMPOSE_VERSION}" =~ ^(native|standalone)$ ]]; then
|
||||||
if docker compose > /dev/null 2>&1; then
|
if docker compose > /dev/null 2>&1; then
|
||||||
if docker compose version --short | grep "2." > /dev/null 2>&1; then
|
if docker compose version --short | grep "2." > /dev/null 2>&1; then
|
||||||
DOCKER_COMPOSE_VERSION=native
|
DOCKER_COMPOSE_VERSION=native
|
||||||
COMPOSE_COMMAND="docker compose"
|
COMPOSE_COMMAND="docker compose"
|
||||||
echo -e "\e[31mFound Docker Compose Plugin (native).\e[0m"
|
echo -e "\e[31mFound Docker Compose Plugin (native).\e[0m"
|
||||||
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
|
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
|
||||||
|
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' $SCRIPT_DIR/mailcow.conf
|
||||||
sleep 2
|
sleep 2
|
||||||
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
|
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
||||||
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
|
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
elif docker-compose > /dev/null 2>&1; then
|
elif docker-compose > /dev/null 2>&1; then
|
||||||
|
@ -197,26 +198,60 @@ if ! [ "${DOCKER_COMPOSE_VERSION}" == "native" ] && ! [ "${DOCKER_COMPOSE_VERSIO
|
||||||
COMPOSE_COMMAND="docker-compose"
|
COMPOSE_COMMAND="docker-compose"
|
||||||
echo -e "\e[31mFound Docker Compose Standalone.\e[0m"
|
echo -e "\e[31mFound Docker Compose Standalone.\e[0m"
|
||||||
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
|
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
|
||||||
|
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' $SCRIPT_DIR/mailcow.conf
|
||||||
sleep 2
|
sleep 2
|
||||||
echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
|
echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
||||||
echo -e "\e[31mPlease update/install regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
|
echo -e "\e[31mPlease update/install regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
echo -e "\e[31mCannot find Docker Compose.\e[0m"
|
echo -e "\e[31mCannot find Docker Compose.\e[0m"
|
||||||
echo -e "\e[31mPlease install it regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
|
echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
elif [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then
|
elif [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then
|
||||||
COMPOSE_COMMAND="docker compose"
|
COMPOSE_COMMAND="docker compose"
|
||||||
|
# Check if Native Compose works and has not been deleted
|
||||||
|
if ! $COMPOSE_COMMAND > /dev/null 2>&1; then
|
||||||
|
# IF it not exists/work anymore try the other command
|
||||||
|
COMPOSE_COMMAND="docker-compose"
|
||||||
|
if ! $COMPOSE_COMMAND > /dev/null 2>&1 || ! $COMPOSE_COMMAND --version | grep "^2." > /dev/null 2>&1; then
|
||||||
|
# IF it cannot find Standalone in > 2.X, then script stops
|
||||||
|
echo -e "\e[31mCannot find Docker Compose or the Version is lower then 2.X.X.\e[0m"
|
||||||
|
echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# If it finds the standalone Plugin it will use this instead and change the mailcow.conf Variable accordingly
|
||||||
|
echo -e "\e[31mFound different Docker Compose Version then declared in mailcow.conf!\e[0m"
|
||||||
|
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable from native to standalone\e[0m"
|
||||||
|
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' $SCRIPT_DIR/mailcow.conf
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then
|
elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then
|
||||||
COMPOSE_COMMAND="docker-compose"
|
COMPOSE_COMMAND="docker-compose"
|
||||||
|
# Check if Standalone Compose works and has not been deleted
|
||||||
|
if ! $COMPOSE_COMMAND > /dev/null 2>&1 && ! $COMPOSE_COMMAND --version > /dev/null 2>&1 | grep "^2." > /dev/null 2>&1; then
|
||||||
|
# IF it not exists/work anymore try the other command
|
||||||
|
COMPOSE_COMMAND="docker compose"
|
||||||
|
if ! $COMPOSE_COMMAND > /dev/null 2>&1; then
|
||||||
|
# IF it cannot find Native in > 2.X, then script stops
|
||||||
|
echo -e "\e[31mCannot find Docker Compose.\e[0m"
|
||||||
|
echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# If it finds the native Plugin it will use this instead and change the mailcow.conf Variable accordingly
|
||||||
|
echo -e "\e[31mFound different Docker Compose Version then declared in mailcow.conf!\e[0m"
|
||||||
|
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable from standalone to native\e[0m"
|
||||||
|
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' $SCRIPT_DIR/mailcow.conf
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,8 +361,12 @@ while (($#)); do
|
||||||
echo -e "\e[32mRunning in forced mode...\e[0m"
|
echo -e "\e[32mRunning in forced mode...\e[0m"
|
||||||
FORCE=y
|
FORCE=y
|
||||||
;;
|
;;
|
||||||
|
-d|--dev)
|
||||||
|
echo -e "\e[32mRunning in Developer mode...\e[0m"
|
||||||
|
DEV=y
|
||||||
|
;;
|
||||||
--help|-h)
|
--help|-h)
|
||||||
echo './update.sh [-c|--check, --ours, --gc, --nightly, --prefetch, --skip-start, --skip-ping-check, --stable, -f|--force, -h|--help]
|
echo './update.sh [-c|--check, --ours, --gc, --nightly, --prefetch, --skip-start, --skip-ping-check, --stable, -f|--force, -d|--dev, -h|--help]
|
||||||
|
|
||||||
-c|--check - Check for updates and exit (exit codes => 0: update available, 3: no updates)
|
-c|--check - Check for updates and exit (exit codes => 0: update available, 3: no updates)
|
||||||
--ours - Use merge strategy option "ours" to solve conflicts in favor of non-mailcow code (local changes over remote changes), not recommended!
|
--ours - Use merge strategy option "ours" to solve conflicts in favor of non-mailcow code (local changes over remote changes), not recommended!
|
||||||
|
@ -338,6 +377,7 @@ while (($#)); do
|
||||||
--skip-ping-check - Skip ICMP Check to public DNS resolvers (Use it only if you´ve blocked any ICMP Connections to your mailcow machine)
|
--skip-ping-check - Skip ICMP Check to public DNS resolvers (Use it only if you´ve blocked any ICMP Connections to your mailcow machine)
|
||||||
--stable - Switch your mailcow updates to the stable (master) branch. Default unless you changed it with --nightly.
|
--stable - Switch your mailcow updates to the stable (master) branch. Default unless you changed it with --nightly.
|
||||||
-f|--force - Force update, do not ask questions
|
-f|--force - Force update, do not ask questions
|
||||||
|
-d|--dev - Enables Developer Mode (No Checkout of update.sh for tests)
|
||||||
'
|
'
|
||||||
exit 1
|
exit 1
|
||||||
esac
|
esac
|
||||||
|
@ -597,7 +637,7 @@ for option in ${CONFIG_ARRAY[@]}; do
|
||||||
echo "Adding new option \"${option}\" to mailcow.conf"
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
echo '# Password hash algorithm' >> mailcow.conf
|
echo '# Password hash algorithm' >> mailcow.conf
|
||||||
echo '# Only certain password hash algorithm are supported. For a fully list of supported schemes,' >> mailcow.conf
|
echo '# Only certain password hash algorithm are supported. For a fully list of supported schemes,' >> mailcow.conf
|
||||||
echo '# see https://mailcow.github.io/mailcow-dockerized-docs/models/model-passwd/' >> mailcow.conf
|
echo '# see https://docs.mailcow.email/models/model-passwd/' >> mailcow.conf
|
||||||
echo "MAILCOW_PASS_SCHEME=BLF-CRYPT" >> mailcow.conf
|
echo "MAILCOW_PASS_SCHEME=BLF-CRYPT" >> mailcow.conf
|
||||||
fi
|
fi
|
||||||
elif [[ ${option} == "ADDITIONAL_SERVER_NAMES" ]]; then
|
elif [[ ${option} == "ADDITIONAL_SERVER_NAMES" ]]; then
|
||||||
|
@ -617,7 +657,7 @@ for option in ${CONFIG_ARRAY[@]}; do
|
||||||
echo '# Optional: Leave empty for none' >> mailcow.conf
|
echo '# Optional: Leave empty for none' >> mailcow.conf
|
||||||
echo '# This value is only used on first order!' >> mailcow.conf
|
echo '# This value is only used on first order!' >> mailcow.conf
|
||||||
echo '# Setting it at a later point will require the following steps:' >> mailcow.conf
|
echo '# Setting it at a later point will require the following steps:' >> mailcow.conf
|
||||||
echo '# https://mailcow.github.io/mailcow-dockerized-docs/troubleshooting/debug-reset_tls/' >> mailcow.conf
|
echo '# https://docs.mailcow.email/troubleshooting/debug-reset_tls/' >> mailcow.conf
|
||||||
echo 'ACME_CONTACT=' >> mailcow.conf
|
echo 'ACME_CONTACT=' >> mailcow.conf
|
||||||
fi
|
fi
|
||||||
elif [[ ${option} == "WEBAUTHN_ONLY_TRUSTED_VENDORS" ]]; then
|
elif [[ ${option} == "WEBAUTHN_ONLY_TRUSTED_VENDORS" ]]; then
|
||||||
|
@ -727,15 +767,17 @@ elif [ $NEW_BRANCH == "nightly" ] && [ $CURRENT_BRANCH != "nightly" ]; then
|
||||||
git checkout -f ${BRANCH}
|
git checkout -f ${BRANCH}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "\e[32mChecking for newer update script...\e[0m"
|
if [ ! $DEV ]; then
|
||||||
SHA1_1=$(sha1sum update.sh)
|
echo -e "\e[32mChecking for newer update script...\e[0m"
|
||||||
git fetch origin #${BRANCH}
|
SHA1_1=$(sha1sum update.sh)
|
||||||
git checkout origin/${BRANCH} update.sh
|
git fetch origin #${BRANCH}
|
||||||
SHA1_2=$(sha1sum update.sh)
|
git checkout origin/${BRANCH} update.sh
|
||||||
if [[ ${SHA1_1} != ${SHA1_2} ]]; then
|
SHA1_2=$(sha1sum update.sh)
|
||||||
echo "update.sh changed, please run this script again, exiting."
|
if [[ ${SHA1_1} != ${SHA1_2} ]]; then
|
||||||
chmod +x update.sh
|
echo "update.sh changed, please run this script again, exiting."
|
||||||
exit 2
|
chmod +x update.sh
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! $FORCE ]; then
|
if [ ! $FORCE ]; then
|
||||||
|
@ -902,9 +944,6 @@ else
|
||||||
echo -e "\e[33mCannot determine current git repository version...\e[0m"
|
echo -e "\e[33mCannot determine current git repository version...\e[0m"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set DOCKER_COMPOSE_VERSION
|
|
||||||
sed -i 's/^DOCKER_COMPOSE_VERSION=$/DOCKER_COMPOSE_VERSION='$DOCKER_COMPOSE_VERSION'/g' mailcow.conf
|
|
||||||
|
|
||||||
if [[ ${SKIP_START} == "y" ]]; then
|
if [[ ${SKIP_START} == "y" ]]; then
|
||||||
echo -e "\e[33mNot starting mailcow, please run \"$COMPOSE_COMMAND up -d --remove-orphans\" to start mailcow.\e[0m"
|
echo -e "\e[33mNot starting mailcow, please run \"$COMPOSE_COMMAND up -d --remove-orphans\" to start mailcow.\e[0m"
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue