mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2025-07-30 00:02:38 -04:00
Compare commits
21 Commits
fd206a7ef6
...
b5a1a18b04
Author | SHA1 | Date | |
---|---|---|---|
|
b5a1a18b04 | ||
|
b4eeb0ffae | ||
|
48549ead7f | ||
|
01b0ad0fd9 | ||
|
2b21501450 | ||
|
b491f6af9b | ||
|
942ef7c254 | ||
|
1ee3bb42f3 | ||
|
25007b1963 | ||
|
f442378377 | ||
|
333b7ebc0c | ||
|
5896766fc3 | ||
|
89540aec28 | ||
|
b960143045 | ||
|
6ab45cf668 | ||
|
38497b04ac | ||
|
efab11720d | ||
|
40fdf99a55 | ||
|
d4dd1e37ce | ||
|
a8dfa95126 | ||
|
4f109c1a94 |
@ -1,7 +1,8 @@
|
|||||||
FROM alpine:3.17
|
FROM alpine:3.19
|
||||||
|
|
||||||
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
|
ARG PIP_BREAK_SYSTEM_PACKAGES=1
|
||||||
RUN apk upgrade --no-cache \
|
RUN apk upgrade --no-cache \
|
||||||
&& apk add --update --no-cache \
|
&& apk add --update --no-cache \
|
||||||
bash \
|
bash \
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
FROM alpine:3.17
|
FROM alpine:3.19
|
||||||
|
|
||||||
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
|
ARG PIP_BREAK_SYSTEM_PACKAGES=1
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN apk add --update --no-cache python3 \
|
RUN apk add --update --no-cache python3 \
|
||||||
@ -9,12 +10,13 @@ RUN apk add --update --no-cache python3 \
|
|||||||
openssl \
|
openssl \
|
||||||
tzdata \
|
tzdata \
|
||||||
py3-psutil \
|
py3-psutil \
|
||||||
|
py3-redis \
|
||||||
|
py3-async-timeout \
|
||||||
&& pip3 install --upgrade pip \
|
&& pip3 install --upgrade pip \
|
||||||
fastapi \
|
fastapi \
|
||||||
uvicorn \
|
uvicorn \
|
||||||
aiodocker \
|
aiodocker \
|
||||||
docker \
|
docker
|
||||||
aioredis
|
|
||||||
RUN mkdir /app/modules
|
RUN mkdir /app/modules
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /app/
|
COPY docker-entrypoint.sh /app/
|
||||||
|
@ -5,16 +5,63 @@ import json
|
|||||||
import uuid
|
import uuid
|
||||||
import async_timeout
|
import async_timeout
|
||||||
import asyncio
|
import asyncio
|
||||||
import aioredis
|
|
||||||
import aiodocker
|
import aiodocker
|
||||||
import docker
|
import docker
|
||||||
import logging
|
import logging
|
||||||
from logging.config import dictConfig
|
from logging.config import dictConfig
|
||||||
from fastapi import FastAPI, Response, Request
|
from fastapi import FastAPI, Response, Request
|
||||||
from modules.DockerApi import DockerApi
|
from modules.DockerApi import DockerApi
|
||||||
|
from redis import asyncio as aioredis
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
dockerapi = None
|
dockerapi = None
|
||||||
app = FastAPI()
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app: FastAPI):
|
||||||
|
global dockerapi
|
||||||
|
|
||||||
|
# Initialize a custom logger
|
||||||
|
logger = logging.getLogger("dockerapi")
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
# Configure the logger to output logs to the terminal
|
||||||
|
handler = logging.StreamHandler()
|
||||||
|
handler.setLevel(logging.INFO)
|
||||||
|
formatter = logging.Formatter("%(levelname)s: %(message)s")
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
logger.info("Init APP")
|
||||||
|
|
||||||
|
# Init redis client
|
||||||
|
if os.environ['REDIS_SLAVEOF_IP'] != "":
|
||||||
|
redis_client = redis = await aioredis.from_url(f"redis://{os.environ['REDIS_SLAVEOF_IP']}:{os.environ['REDIS_SLAVEOF_PORT']}/0")
|
||||||
|
else:
|
||||||
|
redis_client = redis = await aioredis.from_url("redis://redis-mailcow:6379/0")
|
||||||
|
|
||||||
|
# Init docker clients
|
||||||
|
sync_docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
|
||||||
|
async_docker_client = aiodocker.Docker(url='unix:///var/run/docker.sock')
|
||||||
|
|
||||||
|
dockerapi = DockerApi(redis_client, sync_docker_client, async_docker_client, logger)
|
||||||
|
|
||||||
|
logger.info("Subscribe to redis channel")
|
||||||
|
# Subscribe to redis channel
|
||||||
|
dockerapi.pubsub = redis.pubsub()
|
||||||
|
await dockerapi.pubsub.subscribe("MC_CHANNEL")
|
||||||
|
asyncio.create_task(handle_pubsub_messages(dockerapi.pubsub))
|
||||||
|
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
# Close docker connections
|
||||||
|
dockerapi.sync_docker_client.close()
|
||||||
|
await dockerapi.async_docker_client.close()
|
||||||
|
|
||||||
|
# Close redis
|
||||||
|
await dockerapi.pubsub.unsubscribe("MC_CHANNEL")
|
||||||
|
await dockerapi.redis_client.close()
|
||||||
|
|
||||||
|
app = FastAPI(lifespan=lifespan)
|
||||||
|
|
||||||
# Define Routes
|
# Define Routes
|
||||||
@app.get("/host/stats")
|
@app.get("/host/stats")
|
||||||
@ -145,52 +192,6 @@ async def post_container_update_stats(container_id : str):
|
|||||||
stats = json.loads(await dockerapi.redis_client.get(container_id + '_stats'))
|
stats = json.loads(await dockerapi.redis_client.get(container_id + '_stats'))
|
||||||
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
||||||
|
|
||||||
# Events
|
|
||||||
@app.on_event("startup")
|
|
||||||
async def startup_event():
|
|
||||||
global dockerapi
|
|
||||||
|
|
||||||
# Initialize a custom logger
|
|
||||||
logger = logging.getLogger("dockerapi")
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
# Configure the logger to output logs to the terminal
|
|
||||||
handler = logging.StreamHandler()
|
|
||||||
handler.setLevel(logging.INFO)
|
|
||||||
formatter = logging.Formatter("%(levelname)s: %(message)s")
|
|
||||||
handler.setFormatter(formatter)
|
|
||||||
logger.addHandler(handler)
|
|
||||||
|
|
||||||
logger.info("Init APP")
|
|
||||||
|
|
||||||
# Init redis client
|
|
||||||
if os.environ['REDIS_SLAVEOF_IP'] != "":
|
|
||||||
redis_client = redis = await aioredis.from_url(f"redis://{os.environ['REDIS_SLAVEOF_IP']}:{os.environ['REDIS_SLAVEOF_PORT']}/0")
|
|
||||||
else:
|
|
||||||
redis_client = redis = await aioredis.from_url("redis://redis-mailcow:6379/0")
|
|
||||||
|
|
||||||
# Init docker clients
|
|
||||||
sync_docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
|
|
||||||
async_docker_client = aiodocker.Docker(url='unix:///var/run/docker.sock')
|
|
||||||
|
|
||||||
dockerapi = DockerApi(redis_client, sync_docker_client, async_docker_client, logger)
|
|
||||||
|
|
||||||
logger.info("Subscribe to redis channel")
|
|
||||||
# Subscribe to redis channel
|
|
||||||
dockerapi.pubsub = redis.pubsub()
|
|
||||||
await dockerapi.pubsub.subscribe("MC_CHANNEL")
|
|
||||||
asyncio.create_task(handle_pubsub_messages(dockerapi.pubsub))
|
|
||||||
|
|
||||||
@app.on_event("shutdown")
|
|
||||||
async def shutdown_event():
|
|
||||||
global dockerapi
|
|
||||||
|
|
||||||
# Close docker connections
|
|
||||||
dockerapi.sync_docker_client.close()
|
|
||||||
await dockerapi.async_docker_client.close()
|
|
||||||
|
|
||||||
# Close redis
|
|
||||||
await dockerapi.pubsub.unsubscribe("MC_CHANNEL")
|
|
||||||
await dockerapi.redis_client.close()
|
|
||||||
|
|
||||||
# PubSub Handler
|
# PubSub Handler
|
||||||
async def handle_pubsub_messages(channel: aioredis.client.PubSub):
|
async def handle_pubsub_messages(channel: aioredis.client.PubSub):
|
||||||
|
@ -5,7 +5,7 @@ ARG DEBIAN_FRONTEND=noninteractive
|
|||||||
# renovate: datasource=github-tags depName=dovecot/core versioning=semver-coerced extractVersion=(?<version>.*)$
|
# renovate: datasource=github-tags depName=dovecot/core versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||||
ARG DOVECOT=2.3.21
|
ARG DOVECOT=2.3.21
|
||||||
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=(?<version>.*)$
|
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||||
ARG GOSU_VERSION=1.16
|
ARG GOSU_VERSION=1.17
|
||||||
ENV LC_ALL C
|
ENV LC_ALL C
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
FROM alpine:3.17
|
FROM alpine:3.19
|
||||||
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
ARG PIP_BREAK_SYSTEM_PACKAGES=1
|
||||||
ENV XTABLES_LIBDIR /usr/lib/xtables
|
ENV XTABLES_LIBDIR /usr/lib/xtables
|
||||||
ENV PYTHON_IPTABLES_XTABLES_VERSION 12
|
ENV PYTHON_IPTABLES_XTABLES_VERSION 12
|
||||||
ENV IPTABLES_LIBDIR /usr/lib
|
ENV IPTABLES_LIBDIR /usr/lib
|
||||||
@ -14,6 +15,7 @@ RUN apk add --virtual .build-deps \
|
|||||||
openssl-dev \
|
openssl-dev \
|
||||||
&& apk add -U python3 \
|
&& apk add -U python3 \
|
||||||
iptables \
|
iptables \
|
||||||
|
iptables-dev \
|
||||||
ip6tables \
|
ip6tables \
|
||||||
xtables-addons \
|
xtables-addons \
|
||||||
nftables \
|
nftables \
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
FROM alpine:3.17
|
FROM alpine:3.19
|
||||||
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
|
ARG PIP_BREAK_SYSTEM_PACKAGES=1
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
#RUN addgroup -S olefy && adduser -S olefy -G olefy \
|
#RUN addgroup -S olefy && adduser -S olefy -G olefy \
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
FROM php:8.2-fpm-alpine3.17
|
FROM php:8.2-fpm-alpine3.19
|
||||||
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
||||||
ARG APCU_PECL_VERSION=5.1.22
|
ARG APCU_PECL_VERSION=5.1.23
|
||||||
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced extractVersion=(?<version>.*)$
|
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||||
ARG IMAGICK_PECL_VERSION=3.7.0
|
ARG IMAGICK_PECL_VERSION=3.7.0
|
||||||
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
||||||
@ -10,9 +10,9 @@ ARG MAILPARSE_PECL_VERSION=3.1.6
|
|||||||
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
||||||
ARG MEMCACHED_PECL_VERSION=3.2.0
|
ARG MEMCACHED_PECL_VERSION=3.2.0
|
||||||
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$
|
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||||
ARG REDIS_PECL_VERSION=6.0.1
|
ARG REDIS_PECL_VERSION=6.0.2
|
||||||
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced extractVersion=(?<version>.*)$
|
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||||
ARG COMPOSER_VERSION=2.6.5
|
ARG COMPOSER_VERSION=2.6.6
|
||||||
|
|
||||||
RUN apk add -U --no-cache autoconf \
|
RUN apk add -U --no-cache autoconf \
|
||||||
aspell-dev \
|
aspell-dev \
|
||||||
|
@ -4,7 +4,7 @@ LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
|||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ARG SOGO_DEBIAN_REPOSITORY=http://packages.sogo.nu/nightly/5/debian/
|
ARG SOGO_DEBIAN_REPOSITORY=http://packages.sogo.nu/nightly/5/debian/
|
||||||
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
|
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
|
||||||
ARG GOSU_VERSION=1.16
|
ARG GOSU_VERSION=1.17
|
||||||
ENV LC_ALL C
|
ENV LC_ALL C
|
||||||
|
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
|
@ -3,7 +3,7 @@ FROM solr:7.7-slim
|
|||||||
USER root
|
USER root
|
||||||
|
|
||||||
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=(?<version>.*)$
|
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||||
ARG GOSU_VERSION=1.16
|
ARG GOSU_VERSION=1.17
|
||||||
|
|
||||||
COPY solr.sh /
|
COPY solr.sh /
|
||||||
COPY solr-config-7.7.0.xml /
|
COPY solr-config-7.7.0.xml /
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.17
|
FROM alpine:3.19
|
||||||
|
|
||||||
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
FROM alpine:3.17
|
FROM alpine:3.19
|
||||||
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
RUN apk add --update \
|
RUN apk add --update \
|
||||||
|
@ -49,13 +49,14 @@ $from = $headers['From'];
|
|||||||
$empty_footer = json_encode(array(
|
$empty_footer = json_encode(array(
|
||||||
'html' => '',
|
'html' => '',
|
||||||
'plain' => '',
|
'plain' => '',
|
||||||
|
'skip_replies' => 0,
|
||||||
'vars' => array()
|
'vars' => array()
|
||||||
));
|
));
|
||||||
|
|
||||||
error_log("FOOTER: checking for domain " . $domain . ", user " . $username . " and address " . $from . PHP_EOL);
|
error_log("FOOTER: checking for domain " . $domain . ", user " . $username . " and address " . $from . PHP_EOL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("SELECT `plain`, `html`, `mbox_exclude` FROM `domain_wide_footer`
|
$stmt = $pdo->prepare("SELECT `plain`, `html`, `mbox_exclude`, `skip_replies` FROM `domain_wide_footer`
|
||||||
WHERE `domain` = :domain");
|
WHERE `domain` = :domain");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':domain' => $domain
|
':domain' => $domain
|
||||||
|
@ -567,6 +567,14 @@ rspamd_config:register_symbol({
|
|||||||
if footer and type(footer) == "table" and (footer.html and footer.html ~= "" or footer.plain and footer.plain ~= "") then
|
if footer and type(footer) == "table" and (footer.html and footer.html ~= "" or footer.plain and footer.plain ~= "") then
|
||||||
rspamd_logger.infox(rspamd_config, "found domain wide footer for user %s: html=%s, plain=%s, vars=%s", uname, footer.html, footer.plain, footer.vars)
|
rspamd_logger.infox(rspamd_config, "found domain wide footer for user %s: html=%s, plain=%s, vars=%s", uname, footer.html, footer.plain, footer.vars)
|
||||||
|
|
||||||
|
if footer.skip_replies then
|
||||||
|
in_reply_to = task:get_header_raw('in-reply-to')
|
||||||
|
if in_reply_to then
|
||||||
|
rspamd_logger.infox(rspamd_config, "mail is a reply - skip footer")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local envfrom_mime = task:get_from(2)
|
local envfrom_mime = task:get_from(2)
|
||||||
local from_name = ""
|
local from_name = ""
|
||||||
if envfrom_mime and envfrom_mime[1].name then
|
if envfrom_mime and envfrom_mime[1].name then
|
||||||
|
@ -478,16 +478,24 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
$DOMAIN_DEFAULT_ATTRIBUTES = null;
|
||||||
|
if ($_data['template']){
|
||||||
|
$DOMAIN_DEFAULT_ATTRIBUTES = mailbox('get', 'domain_templates', $_data['template'])['attributes'];
|
||||||
|
}
|
||||||
|
if (empty($DOMAIN_DEFAULT_ATTRIBUTES)){
|
||||||
|
$DOMAIN_DEFAULT_ATTRIBUTES = mailbox('get', 'domain_templates')[0]['attributes'];
|
||||||
|
}
|
||||||
|
|
||||||
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
|
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
|
||||||
$description = $_data['description'];
|
$description = $_data['description'];
|
||||||
if (empty($description)) $description = $domain;
|
if (empty($description)) $description = $domain;
|
||||||
$tags = (array)$_data['tags'];
|
$tags = (isset($_data['tags'])) ? (array)$_data['tags'] : $DOMAIN_DEFAULT_ATTRIBUTES['tags'];
|
||||||
$aliases = (int)$_data['aliases'];
|
$aliases = (isset($_data['aliases'])) ? (int)$_data['aliases'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_num_aliases_for_domain'];
|
||||||
$mailboxes = (int)$_data['mailboxes'];
|
$mailboxes = (isset($_data['mailboxes'])) ? (int)$_data['mailboxes'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_num_mboxes_for_domain'];
|
||||||
$defquota = (int)$_data['defquota'];
|
$defquota = (isset($_data['defquota'])) ? (int)$_data['defquota'] : $DOMAIN_DEFAULT_ATTRIBUTES['def_quota_for_mbox'] / 1024 ** 2;
|
||||||
$maxquota = (int)$_data['maxquota'];
|
$maxquota = (isset($_data['maxquota'])) ? (int)$_data['maxquota'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_quota_for_mbox'] / 1024 ** 2;
|
||||||
$restart_sogo = (int)$_data['restart_sogo'];
|
$restart_sogo = (int)$_data['restart_sogo'];
|
||||||
$quota = (int)$_data['quota'];
|
$quota = (isset($_data['quota'])) ? (int)$_data['quota'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_quota_for_domain'] / 1024 ** 2;
|
||||||
if ($defquota > $maxquota) {
|
if ($defquota > $maxquota) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@ -520,11 +528,11 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$active = intval($_data['active']);
|
$active = (isset($_data['active'])) ? intval($_data['active']) : $DOMAIN_DEFAULT_ATTRIBUTES['active'];
|
||||||
$relay_all_recipients = intval($_data['relay_all_recipients']);
|
$relay_all_recipients = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : $DOMAIN_DEFAULT_ATTRIBUTES['relay_all_recipients'];
|
||||||
$relay_unknown_only = intval($_data['relay_unknown_only']);
|
$relay_unknown_only = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : $DOMAIN_DEFAULT_ATTRIBUTES['relay_unknown_only'];
|
||||||
$backupmx = intval($_data['backupmx']);
|
$backupmx = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : $DOMAIN_DEFAULT_ATTRIBUTES['backupmx'];
|
||||||
$gal = intval($_data['gal']);
|
$gal = (isset($_data['gal'])) ? intval($_data['gal']) : $DOMAIN_DEFAULT_ATTRIBUTES['gal'];
|
||||||
if ($relay_all_recipients == 1) {
|
if ($relay_all_recipients == 1) {
|
||||||
$backupmx = '1';
|
$backupmx = '1';
|
||||||
}
|
}
|
||||||
@ -625,9 +633,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!empty(intval($_data['rl_value']))) {
|
$_data['rl_value'] = (isset($_data['rl_value'])) ? intval($_data['rl_value']) : $DOMAIN_DEFAULT_ATTRIBUTES['rl_value'];
|
||||||
|
$_data['rl_frame'] = (isset($_data['rl_frame'])) ? intval($_data['rl_frame']) : $DOMAIN_DEFAULT_ATTRIBUTES['rl_frame'];
|
||||||
|
if (!empty($_data['rl_value']) && !empty($_data['rl_frame'])){
|
||||||
ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $domain));
|
ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $domain));
|
||||||
}
|
}
|
||||||
|
$_data['key_size'] = (isset($_data['key_size'])) ? intval($_data['key_size']) : $DOMAIN_DEFAULT_ATTRIBUTES['key_size'];
|
||||||
|
$_data['dkim_selector'] = (isset($_data['dkim_selector'])) ? intval($_data['dkim_selector']) : $DOMAIN_DEFAULT_ATTRIBUTES['dkim_selector'];
|
||||||
if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
|
if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
|
||||||
if (!empty($redis->hGet('DKIM_SELECTORS', $domain))) {
|
if (!empty($redis->hGet('DKIM_SELECTORS', $domain))) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@ -1006,11 +1018,21 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (empty($name)) {
|
||||||
|
$name = $local_part;
|
||||||
|
}
|
||||||
|
$MAILBOX_DEFAULT_ATTRIBUTES = null;
|
||||||
|
if ($_data['template']){
|
||||||
|
$MAILBOX_DEFAULT_ATTRIBUTES = mailbox('get', 'mailbox_templates', $_data['template'])['attributes'];
|
||||||
|
}
|
||||||
|
if (empty($MAILBOX_DEFAULT_ATTRIBUTES)){
|
||||||
|
$MAILBOX_DEFAULT_ATTRIBUTES = mailbox('get', 'mailbox_templates')[0]['attributes'];
|
||||||
|
}
|
||||||
$password = $_data['password'];
|
$password = $_data['password'];
|
||||||
$password2 = $_data['password2'];
|
$password2 = $_data['password2'];
|
||||||
$name = ltrim(rtrim($_data['name'], '>'), '<');
|
$name = ltrim(rtrim($_data['name'], '>'), '<');
|
||||||
$tags = $_data['tags'];
|
$tags = (isset($_data['tags'])) ? $_data['tags'] : $MAILBOX_DEFAULT_ATTRIBUTES['tags'];
|
||||||
$quota_m = intval($_data['quota']);
|
$quota_m = (isset($_data['quota'])) ? intval($_data['quota']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['quota']) / 1024 ** 2;
|
||||||
if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
|
if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@ -1019,9 +1041,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (empty($name)) {
|
|
||||||
$name = $local_part;
|
|
||||||
}
|
|
||||||
if (isset($_data['protocol_access'])) {
|
if (isset($_data['protocol_access'])) {
|
||||||
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
||||||
$_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
|
$_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
|
||||||
@ -1029,7 +1049,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
$_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||||
$_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
$_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||||
}
|
}
|
||||||
$active = intval($_data['active']);
|
$active = (isset($_data['active'])) ? intval($_data['active']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['active']);
|
||||||
$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
||||||
$tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
|
$tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
|
||||||
$tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
|
$tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
|
||||||
@ -1227,12 +1247,29 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$_data['quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
|
$_data['quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
|
||||||
$_data['quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
|
$_data['quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
|
||||||
$_data['app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
|
$_data['app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
$_data['spam_alias'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_spam_alias']);
|
||||||
|
$_data['tls_policy'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_tls_policy']);
|
||||||
|
$_data['spam_score'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_spam_score']);
|
||||||
|
$_data['spam_policy'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_spam_policy']);
|
||||||
|
$_data['delimiter_action'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_delimiter_action']);
|
||||||
|
$_data['syncjobs'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_syncjobs']);
|
||||||
|
$_data['eas_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_eas_reset']);
|
||||||
|
$_data['sogo_profile_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_sogo_profile_reset']);
|
||||||
|
$_data['pushover'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_pushover']);
|
||||||
|
$_data['quarantine'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine']);
|
||||||
|
$_data['quarantine_attachments'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_attachments']);
|
||||||
|
$_data['quarantine_notification'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_notification']);
|
||||||
|
$_data['quarantine_category'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_category']);
|
||||||
|
$_data['app_passwds'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_app_passwds']);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
$stmt = $pdo->prepare("INSERT INTO `user_acl`
|
$stmt = $pdo->prepare("INSERT INTO `user_acl`
|
||||||
(`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`,
|
(`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`,
|
||||||
`pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`)
|
`pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`)
|
||||||
VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset,
|
VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset,
|
||||||
:pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds) ");
|
:pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds) ");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':username' => $username,
|
':username' => $username,
|
||||||
':spam_alias' => $_data['spam_alias'],
|
':spam_alias' => $_data['spam_alias'],
|
||||||
@ -1251,31 +1288,17 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
':app_passwds' => $_data['app_passwds']
|
':app_passwds' => $_data['app_passwds']
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
else {
|
catch (PDOException $e) {
|
||||||
$stmt = $pdo->prepare("INSERT INTO `user_acl`
|
$_SESSION['return'][] = array(
|
||||||
(`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`,
|
'type' => 'danger',
|
||||||
`pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`)
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset,
|
'msg' => $e->getMessage()
|
||||||
:pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds) ");
|
);
|
||||||
$stmt->execute(array(
|
return false;
|
||||||
':username' => $username,
|
|
||||||
':spam_alias' => 0,
|
|
||||||
':tls_policy' => 0,
|
|
||||||
':spam_score' => 0,
|
|
||||||
':spam_policy' => 0,
|
|
||||||
':delimiter_action' => 0,
|
|
||||||
':syncjobs' => 0,
|
|
||||||
':eas_reset' => 0,
|
|
||||||
':sogo_profile_reset' => 0,
|
|
||||||
':pushover' => 0,
|
|
||||||
':quarantine' => 0,
|
|
||||||
':quarantine_attachments' => 0,
|
|
||||||
':quarantine_notification' => 0,
|
|
||||||
':quarantine_category' => 0,
|
|
||||||
':app_passwds' => 0
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$_data['rl_frame'] = (isset($_data['rl_frame'])) ? $_data['rl_frame'] : $MAILBOX_DEFAULT_ATTRIBUTES['rl_frame'];
|
||||||
|
$_data['rl_value'] = (isset($_data['rl_value'])) ? $_data['rl_value'] : $MAILBOX_DEFAULT_ATTRIBUTES['rl_value'];
|
||||||
if (isset($_data['rl_frame']) && isset($_data['rl_value'])){
|
if (isset($_data['rl_frame']) && isset($_data['rl_value'])){
|
||||||
ratelimit('edit', 'mailbox', array(
|
ratelimit('edit', 'mailbox', array(
|
||||||
'object' => $username,
|
'object' => $username,
|
||||||
@ -1524,10 +1547,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
|
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
|
||||||
if (isset($_data['protocol_access'])) {
|
if (isset($_data['protocol_access'])) {
|
||||||
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
||||||
$attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
|
$attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
|
||||||
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
|
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
|
||||||
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
|
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||||
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
|
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$attr['imap_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
|
$attr['imap_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
|
||||||
@ -3411,6 +3434,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$footers = array();
|
$footers = array();
|
||||||
$footers['html'] = isset($_data['html']) ? $_data['html'] : '';
|
$footers['html'] = isset($_data['html']) ? $_data['html'] : '';
|
||||||
$footers['plain'] = isset($_data['plain']) ? $_data['plain'] : '';
|
$footers['plain'] = isset($_data['plain']) ? $_data['plain'] : '';
|
||||||
|
$footers['skip_replies'] = isset($_data['skip_replies']) ? (int)$_data['skip_replies'] : 0;
|
||||||
$footers['mbox_exclude'] = array();
|
$footers['mbox_exclude'] = array();
|
||||||
if (isset($_data["mbox_exclude"])){
|
if (isset($_data["mbox_exclude"])){
|
||||||
if (!is_array($_data["mbox_exclude"])) {
|
if (!is_array($_data["mbox_exclude"])) {
|
||||||
@ -3460,12 +3484,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("DELETE FROM `domain_wide_footer` WHERE `domain`= :domain");
|
$stmt = $pdo->prepare("DELETE FROM `domain_wide_footer` WHERE `domain`= :domain");
|
||||||
$stmt->execute(array(':domain' => $domain));
|
$stmt->execute(array(':domain' => $domain));
|
||||||
$stmt = $pdo->prepare("INSERT INTO `domain_wide_footer` (`domain`, `html`, `plain`, `mbox_exclude`) VALUES (:domain, :html, :plain, :mbox_exclude)");
|
$stmt = $pdo->prepare("INSERT INTO `domain_wide_footer` (`domain`, `html`, `plain`, `mbox_exclude`, `skip_replies`) VALUES (:domain, :html, :plain, :mbox_exclude, :skip_replies)");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':domain' => $domain,
|
':domain' => $domain,
|
||||||
':html' => $footers['html'],
|
':html' => $footers['html'],
|
||||||
':plain' => $footers['plain'],
|
':plain' => $footers['plain'],
|
||||||
':mbox_exclude' => json_encode($footers['mbox_exclude']),
|
':mbox_exclude' => json_encode($footers['mbox_exclude']),
|
||||||
|
':skip_replies' => $footers['skip_replies'],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
catch (PDOException $e) {
|
catch (PDOException $e) {
|
||||||
@ -4622,7 +4647,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("SELECT `html`, `plain`, `mbox_exclude` FROM `domain_wide_footer`
|
$stmt = $pdo->prepare("SELECT `html`, `plain`, `mbox_exclude`, `skip_replies` FROM `domain_wide_footer`
|
||||||
WHERE `domain` = :domain");
|
WHERE `domain` = :domain");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':domain' => $domain
|
':domain' => $domain
|
||||||
|
@ -3,7 +3,7 @@ function init_db_schema() {
|
|||||||
try {
|
try {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
|
|
||||||
$db_version = "21112023_1644";
|
$db_version = "08012024_1442";
|
||||||
|
|
||||||
$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));
|
||||||
@ -273,6 +273,7 @@ function init_db_schema() {
|
|||||||
"html" => "LONGTEXT",
|
"html" => "LONGTEXT",
|
||||||
"plain" => "LONGTEXT",
|
"plain" => "LONGTEXT",
|
||||||
"mbox_exclude" => "JSON NOT NULL DEFAULT ('[]')",
|
"mbox_exclude" => "JSON NOT NULL DEFAULT ('[]')",
|
||||||
|
"skip_replies" => "TINYINT(1) NOT NULL DEFAULT '0'"
|
||||||
),
|
),
|
||||||
"keys" => array(
|
"keys" => array(
|
||||||
"primary" => array(
|
"primary" => array(
|
||||||
|
@ -588,10 +588,19 @@
|
|||||||
"disable_login": "Login verbieten (Mails werden weiterhin angenommen)",
|
"disable_login": "Login verbieten (Mails werden weiterhin angenommen)",
|
||||||
"domain": "Domain bearbeiten",
|
"domain": "Domain bearbeiten",
|
||||||
"domain_admin": "Domain-Administrator bearbeiten",
|
"domain_admin": "Domain-Administrator bearbeiten",
|
||||||
"domain_footer": "Domain wide footer",
|
"domain_footer": "Domänenweite Fußzeile",
|
||||||
"domain_footer_html": "HTML footer",
|
"domain_footer_html": "Fußzeile im HTML Format",
|
||||||
"domain_footer_info": "Domain wide footer werden allen ausgehenden E-Mails hinzugefügt, die einer Adresse innerhalb dieser Domain gehört.<br>Die folgenden Variablen können für den Footer benutzt werden:",
|
"domain_footer_info": "Domänenweite Footer (Domain wide footer) werden allen ausgehenden E-Mails hinzugefügt, die einer Adresse innerhalb dieser Domain gehört.<br>Die folgenden Variablen können für die Fußzeile benutzt werden:",
|
||||||
"domain_footer_plain": "PLAIN footer",
|
"domain_footer_info_vars": {
|
||||||
|
"auth_user": "{= auth_user =} - Angemeldeter Benutzername vom MTA",
|
||||||
|
"from_user": "{= from_user =} - Absender Teil der E-Mail z.B. für \"moo@mailcow.tld\" wird \"moo\" zurückgeben.",
|
||||||
|
"from_name": "{= from_name =} - Namen des Absenders z.B. für \"Mailcow <moo@mailcow.tld>\", wird \"Mailcow\" zurückgegeben.",
|
||||||
|
"from_addr": "{= from_addr =} - Adresse des Absenders.",
|
||||||
|
"from_domain": "{= from_domain =} - Domain des Absenders",
|
||||||
|
"custom": "{= foo =} - Wenn die Mailbox das benutzerdefinierte Attribut \"foo\" mit dem Wert \"bar\" hat, wird \"bar\" zurückgegeben."
|
||||||
|
},
|
||||||
|
"domain_footer_plain": "Fußzeile im PLAIN Format",
|
||||||
|
"domain_footer_skip_replies": "Ignoriere Footer bei Antwort E-Mails",
|
||||||
"domain_quota": "Domain Speicherplatz gesamt (MiB)",
|
"domain_quota": "Domain Speicherplatz gesamt (MiB)",
|
||||||
"domains": "Domains",
|
"domains": "Domains",
|
||||||
"dont_check_sender_acl": "Absender für Domain %s u. Alias-Domain nicht prüfen",
|
"dont_check_sender_acl": "Absender für Domain %s u. Alias-Domain nicht prüfen",
|
||||||
@ -680,11 +689,7 @@
|
|||||||
"unchanged_if_empty": "Unverändert, wenn leer",
|
"unchanged_if_empty": "Unverändert, wenn leer",
|
||||||
"username": "Benutzername",
|
"username": "Benutzername",
|
||||||
"validate_save": "Validieren und speichern",
|
"validate_save": "Validieren und speichern",
|
||||||
"pushover_sound": "Ton",
|
"pushover_sound": "Ton"
|
||||||
"domain_footer_info_vars": {
|
|
||||||
"auth_user": "{= auth_user =} - Angemeldeter Benutzername vom MTA",
|
|
||||||
"from_user": "{= from_user =} - Von Teil des Benutzers z.B. \"moo@mailcow.tld\" wird \"moo\" zurückgeben."
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"fido2": {
|
"fido2": {
|
||||||
"confirm": "Bestätigen",
|
"confirm": "Bestätigen",
|
||||||
@ -1088,6 +1093,7 @@
|
|||||||
"verified_yotp_login": "Yubico-OTP-Anmeldung verifiziert"
|
"verified_yotp_login": "Yubico-OTP-Anmeldung verifiziert"
|
||||||
},
|
},
|
||||||
"tfa": {
|
"tfa": {
|
||||||
|
"authenticators": "Authentikatoren",
|
||||||
"api_register": "%s verwendet die Yubico-Cloud-API. Ein API-Key für den Yubico-Stick kann <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">hier</a> bezogen werden.",
|
"api_register": "%s verwendet die Yubico-Cloud-API. Ein API-Key für den Yubico-Stick kann <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">hier</a> bezogen werden.",
|
||||||
"confirm": "Bestätigen",
|
"confirm": "Bestätigen",
|
||||||
"confirm_totp_token": "Bitte bestätigen Sie die Änderung durch Eingabe eines generierten Tokens",
|
"confirm_totp_token": "Bitte bestätigen Sie die Änderung durch Eingabe eines generierten Tokens",
|
||||||
|
@ -600,6 +600,7 @@
|
|||||||
"custom": "{= foo =} - If mailbox has the custom attribute \"foo\" with value \"bar\" it returns \"bar\""
|
"custom": "{= foo =} - If mailbox has the custom attribute \"foo\" with value \"bar\" it returns \"bar\""
|
||||||
},
|
},
|
||||||
"domain_footer_plain": "PLAIN footer",
|
"domain_footer_plain": "PLAIN footer",
|
||||||
|
"domain_footer_skip_replies": "Ignore footer on reply e-mails",
|
||||||
"domain_quota": "Domain quota",
|
"domain_quota": "Domain quota",
|
||||||
"domains": "Domains",
|
"domains": "Domains",
|
||||||
"dont_check_sender_acl": "Disable sender check for domain %s (+ alias domains)",
|
"dont_check_sender_acl": "Disable sender check for domain %s (+ alias domains)",
|
||||||
@ -1099,6 +1100,7 @@
|
|||||||
"verified_yotp_login": "Verified Yubico OTP login"
|
"verified_yotp_login": "Verified Yubico OTP login"
|
||||||
},
|
},
|
||||||
"tfa": {
|
"tfa": {
|
||||||
|
"authenticators": "Authenticators",
|
||||||
"api_register": "%s uses the Yubico Cloud API. Please get an API key for your key <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">here</a>",
|
"api_register": "%s uses the Yubico Cloud API. Please get an API key for your key <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">here</a>",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"confirm_totp_token": "Please confirm your changes by entering the generated token",
|
"confirm_totp_token": "Please confirm your changes by entering the generated token",
|
||||||
|
@ -305,6 +305,14 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-4">
|
||||||
|
<label class="control-label col-sm-2" for="domain_footer_skip_replies">{{ lang.edit.domain_footer_skip_replies }}:</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="form-check">
|
||||||
|
<label><input type="checkbox" class="form-check-input" value="1" id="domain_footer_skip_replies" name="skip_replies"{% if domain_footer.skip_replies == '1' %} checked{% endif %}></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<label class="control-label col-sm-2" for="domain_footer_html">{{ lang.edit.domain_footer_html }}:</label>
|
<label class="control-label col-sm-2" for="domain_footer_html">{{ lang.edit.domain_footer_html }}:</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
@ -155,7 +155,7 @@
|
|||||||
|
|
||||||
{% if pending_tfa_authmechs["totp"] is defined and pending_tfa_authmechs["u2f"] is not defined %}
|
{% if pending_tfa_authmechs["totp"] is defined and pending_tfa_authmechs["u2f"] is not defined %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if pending_tfa_authmechs["totp"] %}active{% endif %}" href="#tfa_tab_totp" data-bs-toggle="tab" id="pending_tfa_tab_totp"><i class="bi bi-clock-history"></i> Time based OTP</a>
|
<a class="nav-link {% if pending_tfa_authmechs["totp"] %}active{% endif %}" href="#tfa_tab_totp" data-bs-toggle="tab" id="pending_tfa_tab_totp"><i class="bi bi-clock-history"></i> Time-based OTP</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@ -173,7 +173,7 @@
|
|||||||
<form role="form" method="post" id="webauthn_auth_form">
|
<form role="form" method="post" id="webauthn_auth_form">
|
||||||
<legend class="mt-2 mb-2">
|
<legend class="mt-2 mb-2">
|
||||||
<i class="bi bi-shield-fill-check"></i>
|
<i class="bi bi-shield-fill-check"></i>
|
||||||
Authenticators
|
{{ lang.tfa.authenticators }}
|
||||||
<hr />
|
<hr />
|
||||||
</legend>
|
</legend>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
@ -216,7 +216,7 @@
|
|||||||
<form role="form" method="post">
|
<form role="form" method="post">
|
||||||
<legend class="mt-2 mb-2">
|
<legend class="mt-2 mb-2">
|
||||||
<i class="bi bi-shield-fill-check"></i>
|
<i class="bi bi-shield-fill-check"></i>
|
||||||
Authenticate
|
{{ lang.tfa.authenticators }}
|
||||||
<hr />
|
<hr />
|
||||||
</legend>
|
</legend>
|
||||||
<div class="collapse show pending-tfa-collapse" id="collapseYubiTFA">
|
<div class="collapse show pending-tfa-collapse" id="collapseYubiTFA">
|
||||||
@ -244,7 +244,7 @@
|
|||||||
<form role="form" method="post">
|
<form role="form" method="post">
|
||||||
<legend class="mt-2 mb-2">
|
<legend class="mt-2 mb-2">
|
||||||
<i class="bi bi-shield-fill-check"></i>
|
<i class="bi bi-shield-fill-check"></i>
|
||||||
Authenticators
|
{{ lang.tfa.authenticators }}
|
||||||
<hr />
|
<hr />
|
||||||
</legend>
|
</legend>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
|
@ -2,7 +2,7 @@ version: '2.1'
|
|||||||
services:
|
services:
|
||||||
|
|
||||||
unbound-mailcow:
|
unbound-mailcow:
|
||||||
image: mailcow/unbound:1.18
|
image: mailcow/unbound:1.19
|
||||||
environment:
|
environment:
|
||||||
- TZ=${TZ}
|
- TZ=${TZ}
|
||||||
volumes:
|
volumes:
|
||||||
@ -107,7 +107,7 @@ services:
|
|||||||
- rspamd
|
- rspamd
|
||||||
|
|
||||||
php-fpm-mailcow:
|
php-fpm-mailcow:
|
||||||
image: mailcow/phpfpm:1.85
|
image: mailcow/phpfpm:1.86
|
||||||
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
|
||||||
@ -398,7 +398,7 @@ services:
|
|||||||
condition: service_started
|
condition: service_started
|
||||||
unbound-mailcow:
|
unbound-mailcow:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
image: mailcow/acme:1.85
|
image: mailcow/acme:1.86
|
||||||
dns:
|
dns:
|
||||||
- ${IPV4_NETWORK:-172.22.1}.254
|
- ${IPV4_NETWORK:-172.22.1}.254
|
||||||
environment:
|
environment:
|
||||||
@ -434,7 +434,7 @@ services:
|
|||||||
- acme
|
- acme
|
||||||
|
|
||||||
netfilter-mailcow:
|
netfilter-mailcow:
|
||||||
image: mailcow/netfilter:1.54
|
image: mailcow/netfilter:1.55
|
||||||
stop_grace_period: 30s
|
stop_grace_period: 30s
|
||||||
depends_on:
|
depends_on:
|
||||||
- dovecot-mailcow
|
- dovecot-mailcow
|
||||||
@ -457,7 +457,7 @@ services:
|
|||||||
- /lib/modules:/lib/modules:ro
|
- /lib/modules:/lib/modules:ro
|
||||||
|
|
||||||
watchdog-mailcow:
|
watchdog-mailcow:
|
||||||
image: mailcow/watchdog:2.00
|
image: mailcow/watchdog:2.01
|
||||||
dns:
|
dns:
|
||||||
- ${IPV4_NETWORK:-172.22.1}.254
|
- ${IPV4_NETWORK:-172.22.1}.254
|
||||||
tmpfs:
|
tmpfs:
|
||||||
@ -529,7 +529,7 @@ services:
|
|||||||
- watchdog
|
- watchdog
|
||||||
|
|
||||||
dockerapi-mailcow:
|
dockerapi-mailcow:
|
||||||
image: mailcow/dockerapi:2.06
|
image: mailcow/dockerapi:2.07
|
||||||
security_opt:
|
security_opt:
|
||||||
- label=disable
|
- label=disable
|
||||||
restart: always
|
restart: always
|
||||||
@ -564,7 +564,7 @@ services:
|
|||||||
- solr
|
- solr
|
||||||
|
|
||||||
olefy-mailcow:
|
olefy-mailcow:
|
||||||
image: mailcow/olefy:1.11
|
image: mailcow/olefy:1.12
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
- TZ=${TZ}
|
- TZ=${TZ}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user